git branch, fork, fetch, merge, rebase e clone, quali sono le differenze?

Qualcuno può aiutarmi a capire la differenza tra un ramo, una forchetta e un clone in Git?

Allo stesso modo, cosa significa quando faccio un git fetch piuttosto che un git pull ?

Inoltre, che cosa significa rebase in confronto a merge ?

Come posso distruggere i singoli commit da soli?

Come vengono utilizzati, perché vengono utilizzati e cosa rappresentano?

    In che modo GitHub figura?

    Un clone è semplicemente una copia di un repository. In superficie, il suo risultato è equivalente a svn checkout , in cui si scarica il codice sorgente da qualche altro repository. La differenza tra VCS centralizzato come Subversion e DVCS come Git è che in Git, quando si clona, ​​si sta effettivamente copiando l’intero repository sorgente, inclusa tutta la cronologia e le diramazioni. Ora hai un nuovo repository sul tuo computer e qualsiasi commit effettuato entri in quel repository. Nessuno vedrà alcuna modifica fino a quando non si invierà tali commit a un altro repository (o a quello originale) o fino a quando qualcuno non effettuerà il commit dal repository, se è pubblicamente accessibile.

    Un ramo è qualcosa che si trova all’interno di un repository. Concettualmente, rappresenta un filo di sviluppo. Di solito hai un ramo master, ma potresti anche avere un ramo su cui stai lavorando su alcune feature xyz, e un altro per correggere bug abc. Quando hai estratto un ramo, qualsiasi commit effettuato rimarrà su quel ramo e non verrà condiviso con altri rami finché non li unisci o li rebase sul ramo in questione. Certo, Git sembra un po ‘strano quando si tratta di filiali finché non si guarda al modello sottostante di come vengono implementati i rami. Piuttosto che spiegarlo da solo (ho già detto troppo, mi pare), collegherò alla spiegazione “informatica” di come Git modella i rami e il commit, presi dal sito web Git:

    http://eagain.net/articles/git-for-computer-scientists/

    Un fork non è un concetto Git in realtà, è più un’idea politica / sociale. Cioè, se alcune persone non sono contente del modo in cui un progetto sta andando, possono prendere il codice sorgente e lavorarci separatamente dagli sviluppatori originali. Questo sarebbe considerato una forchetta. Git rende facile biforcarsi perché tutti hanno già una propria copia “master” del codice sorgente, quindi è semplice come tagliare i legami con gli sviluppatori del progetto originale e non richiede la cronologia di esportazione da un repository condiviso come potrebbe essere necessario fare con SVN .

    EDIT: poiché non ero a conoscenza della definizione moderna di “fork” usata da siti come GitHub, per favore guarda i commenti e anche la risposta di Michael Durrant sotto la mia per maggiori informazioni.

    Idiota

    La mia risposta include github come molte persone hanno chiesto anche a questo.

    Repository locali

    git (localmente) ha una directory (.git) su cui si impegnano i file e questo è il tuo ‘repository locale’. Questo è diverso da sistemi come svn in cui si aggiunge e si esegue immediatamente il commit al repository remoto.

    git memorizza ogni versione di un file che cambia salvando l’intero file. È anche diverso da svn in questo senso, dato che puoi andare a qualsiasi versione individuale senza “ricrearla” attraverso i cambiamenti delta.

    git non “blocca” i file e quindi evita la funzionalità di “lock esclusivo” per una modifica (i sistemi più vecchi come pvcs vengono in mente), quindi tutti i file possono sempre essere modificati, anche quando non sono in linea. Effettivamente fa un ottimo lavoro di unire le modifiche ai file (all’interno dello stesso file!) Insieme durante pull o fetch / push verso un repository remoto come github. L’unica volta che devi fare modifiche manuali (in realtà modificando un file) è se due modifiche riguardano la stessa linea (s) di codice.


    filiali

    I rami consentono di conservare il codice principale (il ramo “master”), creare una copia (un nuovo ramo) e quindi lavorare all’interno di quel nuovo ramo. Se il lavoro richiede un po ‘di tempo o il master riceve molti aggiornamenti dal momento in cui è stato creato il ramo, è necessario eseguire l’unione o la ridefinizione (spesso preferibile per una cronologia migliore e conflitti più facili da risolvere) rispetto al ramo principale. Al termine, unisci le modifiche apportate nel ramo al repository principale. Molte organizzazioni utilizzano i rami per ogni pezzo di lavoro, indipendentemente dal fatto che si tratti di elementi di funzionalità, bug o lavori di routine. Altre organizzazioni utilizzano solo le filiali per modifiche importanti come gli aggiornamenti della versione. Forcella: con un ramo controlli e gestisci il ramo, mentre con una forchetta qualcun altro controlla di accettare il codice.
    A grandi linee, ci sono due approcci principali per fare rami. Il primo consiste nel mantenere la maggior parte delle modifiche sul ramo principale, utilizzando solo le diramazioni per le cose più grandi e più lunghe come le modifiche alla versione in cui si desidera avere due rami disponibili per esigenze diverse. Il secondo consiste nel fare fondamentalmente un ramo per ogni richiesta di funzionalità, correzione di bug o lavoretti e quindi decidere manualmente quando unire questi rami nel ramo principale principale. Anche se questo sembra noioso, questo è un approccio comune ed è quello che attualmente uso e raccomando perché mantiene il master branch clean ed è il master che promuoviamo per la produzione, quindi vogliamo solo un codice completo, testato, tramite il rebasing e fusione di filiali.

    Il modo standard per portare un ramo “in” al master è fare una merge . I rami possono anche essere rebase d per “ripulire” la cronologia. Non influisce sullo stato attuale e viene eseguito per fornire una cronologia “più pulita”. Fondamentalmente l’idea è che ti sei ramificato da un certo punto (di solito dal master). Dal momento che lo stesso “master” ramificato si è spostato in avanti. Quindi sarebbe più pulito se tutte le modifiche che hai fatto in un ramo sono giocate contro il master più recente con tutte le sue modifiche. Quindi il processo è: salva le modifiche; ottenere il “nuovo” master e quindi riapplicare nuovamente le modifiche a tale scopo. Tieni presente che rebase, proprio come l’unione, può generare conflitti che devi risolvere manualmente (modificare).

    Una “linea guida” da tenere presente: solo rebase se il ramo è locale e non lo hai ancora spinto a remoto! Ciò è principalmente dovuto al fatto che la ridefinizione può alterare la cronologia che altre persone vedono e che possono includere i propri commit.

    Tracciamento dei rami

    Questi sono i rami che sono denominati origine / nome_società (in contrapposizione a solo nome_riga). Quando si spinge e si estrae il codice da / per archivi remoti, questo è in realtà il meccanismo attraverso il quale ciò accade. Per esempio, quando metti un ramo chiamato “building_groups”, il tuo ramo va prima verso origin / building_groups e poi va al repository remoto (in realtà si tratta di una semplificazione eccessiva ma abbastanza buono per ora). Allo stesso modo, se git fetch building_groups un git fetch building_groups il file che viene richiamato viene inserito nel tuo ramo origin / building_groups. È quindi ansible scegliere di unire questo ramo nella copia locale. La nostra pratica è di fare sempre un git fetch e un’unione manuale piuttosto che una semplice git pull (che fa entrambe le cose sopra in un solo passaggio).

    Fetch nuovi rami.

    Ottenere nuovi rami: nel punto iniziale di un clone avrai tutti i rami. Tuttavia, se altri sviluppatori aggiungono succursali e le spingeranno al remoto, ci sarà bisogno di un modo per “sapere” su quei rami e sui loro nomi per poterli localizzare localmente. Questo viene fatto tramite un git fetch che otterrà tutti i rami nuovi e modificati nel repository locale usando i rami di tracciamento (ad es. Origine /). Una volta fetch , uno può git branch --remote per elencare i rami di tracciamento e git checkout [branch] per passare effettivamente a qualsiasi dato.

    Fusione

    L’unione è il processo di combinazione delle modifiche al codice da diversi rami o da diverse versioni dello stesso ramo (ad esempio quando un ramo locale e un remoto non sono sincronizzati). Se uno ha sviluppato un lavoro in una filiale e il lavoro è completo, pronto e testato, allora può essere unito al ramo master . Questo viene fatto da git checkout master per passare al ramo master , quindi git merge your_branch . L’unione porterà tutti i diversi file e anche le diverse modifiche agli stessi file insieme. Ciò significa che in realtà cambierà il codice all’interno dei file per unire tutte le modifiche. Quando si esegue il checkout del master , si consiglia inoltre di eseguire un git pull origin master per ottenere la versione più recente del master remoto unito al master locale. Se il master remoto è cambiato, ovvero moved forward , verranno visualizzate le informazioni che riflettono quella durante quella git pull . Se questo è il caso (master modificato), si consiglia di eseguire il git checkout your_branch e quindi rebase a master in modo che le modifiche vengano effettivamente “riprodotte” in cima al “nuovo” master. Quindi continuerai con il master aggiornato come mostrato nel prossimo paragrafo.

    Se non ci sono conflitti, nel master verranno aggiunte le nuove modifiche. Se ci sono conflitti, ciò significa che gli stessi file hanno delle modifiche attorno a linee di codice simili che non possono automaticamente unire. In questo caso git merge new_branch segnalerà che c’è conflitto (i) da risolvere. Li risolvi modificando i file (che avranno entrambe le modifiche), selezionando le modifiche che desideri, eliminando letteralmente le linee delle modifiche che non vuoi e salvando il file. Le modifiche sono contrassegnate da separatori come ======== e <<<<<<<<

    Una volta risolti eventuali conflitti, ancora una volta git add e git commit queste modifiche per continuare l'unione (riceverai feedback da git durante questo processo per guidarti). Quando il processo non funziona bene, scoprirai che git merge --abort è molto utile per ripristinare le cose.

    Rebasing interattivo e schiacciamento / riordinamento / rimozione dei commit

    Se hai lavorato con molti piccoli passi, ad esempio ti impegni a scrivere codice come "work in progress" ogni giorno, potresti voler "spremere" quei piccoli commit in qualche commit più grande. Questo può essere particolarmente utile quando si desidera eseguire revisioni del codice con i colleghi. Non vuoi riprodurre tutti i "passi" che hai compiuto (tramite commit), vuoi solo dire che qui è l'effetto finale (diff) di tutte le mie modifiche per questo lavoro in un commit. Il fattore chiave da valutare quando si valuta se fare questo è se i commit multipli sono contro lo stesso file o file più di una volta (meglio schiacciare i commit in quel caso). Questo viene fatto con lo strumento rebasing interattivo. Questo strumento ti consente di schiacciare i commit, eliminare i commit, i messaggi di reword, ecc. Ad esempio git rebase -i HEAD~10 Nota che è un ~ NOT a - visualizza quanto segue:
    rebasing interattivo in Git Fai attenzione però e usa questo strumento "cautamente". Effettua uno schiacciamento / eliminazione / riordino alla volta, esci e salva quel commit, quindi rientra nello strumento. Se i commit non sono contigui puoi riordinarli (e poi schiacciare se necessario). Puoi anche eliminare i commit qui, ma devi davvero essere sicuro di ciò che stai facendo quando lo fai!

    forchette

    Esistono due approcci principali alla collaborazione nei repository git. Il primo, dettagliato sopra è direttamente tramite le filiali che la gente tira e spinge da / verso. Questi collaboratori hanno le loro chiavi SSH registrate nel repository remoto. Ciò consentirà loro di inviare direttamente a quel repository. Lo svantaggio è che devi mantenere l'elenco degli utenti. L'altro approccio - forking - consente a chiunque di "forgiare" il repository, basandosi essenzialmente su una copia locale nel proprio account git repository. Possono quindi apportare modifiche e al termine inviare una "richiesta pull" (in realtà è più una "spinta" da loro e una richiesta "pull" per il gestore del repository effettivo) per ottenere il codice accettato.
    Questo secondo metodo, utilizzando i fork, non richiede a qualcuno di mantenere un elenco di utenti per il repository.


    Github

    github (un repository remoto) è un'origine remota che normalmente spinga e trascini le modifiche apportate a se hai (o sei aggiunto a) un tale repository, quindi local e remote sono in realtà abbastanza distinti. Un altro modo di pensare a un repository remoto è che si tratta di una struttura di directory .git che risiede su un server remoto.

    Quando si "forchetta" - nella guida del browser Web di github è ansible fare clic su inserisci la descrizione dell'immagine qui - crei una copia ("clone") del codice nel tuo account github. Può essere un po 'impercettibile la prima volta che lo fai, quindi continua ad assicurarti di controllare in quale repository è elencato un codice base - o il proprietario originale o "forked from" e tu, ad esempio inserisci la descrizione dell'immagine qui
    Una volta ottenuta la copia locale, è ansible apportare le modifiche desiderate (tirando e spingendole su una macchina locale). Quando hai finito, invii una "richiesta di pull" al proprietario / amministratore del repository originale (sembra divertente ma in realtà fai clic su questo: - inserisci la descrizione dell'immagine qui ) e lo "tirano" dentro
    Più comune per un team che lavora insieme sul codice è quello di "clonare" il repository (fare clic sull'icona "copia" nella schermata principale del repository). Quindi, digita git clone localmente [incolla] Questo ti imposterà localmente e potrai anche spingere e tirare nella posizione github (condivisa).

    cloni

    Come indicato nella sezione su github, un clone è una copia di un repository. Quando si dispone di un repository remoto si emette il comando git clone sul suo URL e si finisce con una copia locale o clone del repository. Questo clone ha tutto , i file, il ramo principale, gli altri rami, tutti i commit esistenti, l'intero shebang. È questo clone che si aggiunge e si impegna contro e quindi lo stesso repository remoto è ciò a cui si impongono tali commit. È questo concetto locale / remoto che rende git (e sistemi simili ad esso come Mercurial) un DVCS ( Distributed Version Control System) in contrapposizione ai più tradizionali CVS (Code Versioning Systems) come SVN, PVCS, CVS, ecc. Dove ti impegni direttamente nel repository remoto.

    visualizzazione

    La visualizzazione dei concetti principali può essere vista a
    http://marklodato.github.com/visual-git-guide/index-en.html e
    http://ndpsoftware.com/git-cheatsheet.html#loc=index

    Se vuoi una visualizzazione visiva di come funzionano i cambiamenti, non puoi battere lo strumento visivo gitg (gitx per mac) con una gui che chiamo 'la mappa della metropolitana' (specialmente la metropolitana di Londra), ottima per mostrare chi ha fatto cosa, come le cose cambiano, divergono e si fondono, ecc.

    Puoi anche usarlo per aggiungere, commettere e gestire le tue modifiche!

    interfaccia gitg / gitx

    Sebbene gitg / gitx sia abbastanza minimale, negli ultimi 2-3 anni (2009-2012) il numero di strumenti di GUI continua ad espandersi. Molti utenti Mac usano il forkbone di gitx di brotherbard e per Linux una big opzione è smart-git con un'interfaccia intuitiva ma potente:

    smart-git GUI

    Nota che anche con uno strumento gui, probabilmente eseguirai molti comandi sulla riga di comando.
    Per questo ho i seguenti alias nel mio file ~ / .bash_aliases (che viene chiamato dal mio file ~ / .bashrc per ogni sessione terminale:

     # git alias gst='git status' # Warning: gst conflicts with gnu-smalltalk (when used). alias gb='git branch' alias gco='git checkout' alias gcob='git checkout -b ' alias ga='git add ' alias gc='git commit' alias gg='git grep ' # A great very FAST search option, easier then `find` 

    Infine, 6 salvavita chiave:

    1) Fai confusione con la tua filiale locale e semplicemente vuoi tornare a quello che hai avuto l'ultima volta che hai fatto un tiro di git:

     git reset --hard origin/master # You will need to be comfortable doing this! 

    2) Inizi ad apportare modifiche localmente, modifichi una mezza dozzina di file e poi, oh crap, sei ancora nel ramo principale (o in un altro):

     git checkout -b new_branch_name # just create a new branch git add . # add the changes files git commit -m"your message" # and commit them 

    3) Si incasina un particolare file nel ramo attuale e si vuole sostanzialmente "resettare" quel file (perdere le modifiche) a come era l'ultima volta che lo si è estratto dal repository remoto: git checkout your/directories/filename Questo in realtà resetta il file (come molti comandi git non ha un nome appropriato per quello che sta facendo qui).

    4) Apporti alcune modifiche a livello locale, vuoi assicurarti di non perderle mentre esegui un reset o rebase git: spesso faccio una copia manuale dell'intero progetto ( cp -r ../my_project ~/ ) quando Non sono sicuro di poter incasinare o perdere importanti cambiamenti.

    5) Stai ridefinendo ma le cose si incasinano:

     git rebase --abort # To abandon interactive rebase and merge issues 

    6) Aggiungi il tuo ramo git al tuo prompt PS1 (vedi https://unix.stackexchange.com/a/127800/10043 ), ad es. inserisci la descrizione dell'immagine qui
    Il ramo è selenium_rspec_conversion

    Ecco l’immagine di Oliver Steele di come tutto combacia:

    inserisci la descrizione dell'immagine qui

    Giusto per aggiungere agli altri, una nota specifica per il biforcarsi.

    È bello rendersi conto che tecnicamente, la clonazione del pronti contro termine e il fork del repository sono la stessa cosa. Fare:

     git clone $some_other_repo 

    e puoi toccare te stesso sul retro — hai appena biforcato qualche altro repo.

    Git, come VCS, è in realtà tutto basato sulla biforcazione della clonazione . A parte “basta sfogliare” l’interfaccia utente remota come cgit, c’è pochissimo a che fare con git repo che non prevede la clonazione del repository ad un certo punto.

    Però,

    • quando qualcuno dice che ho fatto il fork repo X , vogliono dire che hanno creato un clone del repository da qualche altra parte con l’intenzione di esporlo ad altri, per esempio per mostrare alcuni esperimenti, o per applicare un diverso meccanismo di controllo dell’accesso (per esempio per permettere alle persone senza Accesso Github ma con account interno aziendale per collaborare).

      Fatti che: il repository è probabilmente creato con un altro comando diverso da git clone , che probabilmente è ospitato da qualche parte su un server anziché sul laptop di qualcuno, e probabilmente ha un formato leggermente diverso (è un “bare repo”, cioè senza lavoro albero) sono tutti solo dettagli tecnici.

      Il fatto che con tutta probabilità contenga diversi set di rami, tag o commit è probabilmente il motivo per cui l’hanno fatto in primo luogo.

      (Quello che fa Github quando fai clic su “fork”, è solo la clonazione con lo zucchero aggiunto: clona il repository per te, lo mette sotto il tuo account, registra il “fork from” da qualche parte, aggiunge il nome remoto “upstream” e, soprattutto, suona la bella animazione).

    • Quando qualcuno dice che ho clonato il repo X , significano che hanno creato un clone del repository localmente sul loro laptop o desktop con l’intenzione di studiarlo, giocarci, contribuirvi o creare qualcosa dal codice sorgente in esso contenuto.

    La bellezza di Git è che rende tutto questo perfettamente compatibile: tutti questi repos condividono la parte comune della block commit chain, quindi è ansible in modo sicuro (vedi nota sotto) unire le modifiche avanti e indietro tra tutti questi reposli come meglio credi.


    Nota: “sicuro” se non si riscrive la parte comune della catena e fintanto che le modifiche non sono in conflitto.

    Fork vs. Clone – due parole che significano entrambe copia

    Si prega di vedere questo diagramma. (Originariamente da http://www.dataschool.io/content/images/2014/Mar/github1.png ).

     .-------------------------. 1. Fork .-------------------------. | Your GitHub repo | <-------------- | Joe's GitHub repo | | github.com/you/coolgame | | github.com/joe/coolgame | | ----------------------- | 7. Pull Request | ----------------------- | | master -> c224ff7 | --------------> | master -> c224ff7 (c) | | anidea -> 884faa1 (a) | | anidea -> 884faa1 (b) | '-------------------------' '-------------------------' | ^ | 2. Clone | | | | | | | | | | | 6. Push (anidea => origin/anidea) v | .-------------------------. | Your computer | 3. Create branch 'anidea' | $HOME/coolgame | | ----------------------- | 4. Update a file | master -> c224ff7 | | anidea -> 884faa1 | 5. Commit (to 'anidea') '-------------------------' (a) - after you have pushed it (b) - after Joe has accepted it (c) - eventually Joe might merge 'anidea' (make 'master -> 884faa1') 

    Forchetta

    • Una copia sul repository remoto (cloud) che la collega a quella di Joe
    • Una copia è quindi ansible clonare al repository locale e F *% $ – up
    • Quando hai finito puoi tornare al tuo telecomando
    • Puoi quindi chiedere a Joe se vuole utilizzarlo nel suo progetto facendo clic su pull-request

    Clone

    • una copia al tuo repo locale (hard disk)