Filialele înmulțesc funcționalitatea de bază oferită de comitete, permițând utilizatorilor să-și schimbe istoricul. Crearea unei noi sucursale este asemănătoare cu solicitarea unui nou mediu de dezvoltare, completat cu un director de lucru izolat, zona de așteptare și istoricul proiectului.
Acest lucru vă oferă aceleași liniște ca și comiterea unei copii "sigure" a proiectului dvs., dar acum aveți capacitatea suplimentară de a lucra în mai multe variante în același timp. Filialele permit a fluxul de lucru neliniar-capacitatea de a dezvolta caracteristici independente în paralel. Așa cum vom descoperi mai târziu, un flux de lucru neliniar este un precursor important al naturii distribuite a modelului de colaborare al lui Git.
Spre deosebire de SVN sau CVS, implementarea ramurii Git este incredibil de eficientă. SVN permite filialele prin copierea întregului proiect într-un folder nou, la fel cum ați proceda fără software de control al reviziilor. Acest lucru face ca fuzionarea să fie neclară, predispusă la erori și lentă. În schimb, ramurile Git sunt pur și simplu un indicator al unei comiteri. Deoarece acestea lucrează la nivel de comitet în loc direct la nivelul fișierului, ramurile Git fac mult mai ușor combinarea istoriilor divergente. Acest lucru are un impact dramatic asupra fluxurilor de lucru ramificate.
Git separă funcționalitatea ramificațiilor în câteva comenzi diferite. git ramură
comanda este utilizată pentru înregistrarea, crearea sau ștergerea sucursalelor.
În primul rând, va trebui să puteți vizualiza sucursalele existente:
git ramură
Aceasta va afișa toate sucursalele dvs. actuale, împreună cu un asterisc în dreptul celui care este "verificat" (mai târziu, mai târziu):
* master-some-feature rapid-bug-fix
maestru
ramură este ramura implicită a lui Git, care este creată cu prima comitere în orice depozit. Mulți dezvoltatori folosesc această ramură drept "principala" istorie a proiectului - o ramură permanentă care conține toate schimbările majore pe care le trece.
Puteți crea o nouă filă prin trecerea numelui filialei la același git ramură
comanda:
git ramură
Acest lucru creează un indicator pentru curent CAP
, dar nu nu treceți la noua ramură (veți avea nevoie Git checkout
pentru asta). Imediat după ce ați solicitat o nouă filială, magazia dvs. va arăta mai degrabă după cum urmează.
Sucursala dvs. curentă (maestru
) și noua ramură (unele feature
), ambele fac referire la acelasi angajament, dar orice nou angajat pe care il inregistrati va fi exclusiv pentru sucursala actuala. Din nou, aceasta vă permite să lucrați în paralel cu caracteristici independente, menținând în același timp istorii sensibile. De exemplu, dacă sucursala dvs. a fost unele feature
, istoria dvs. ar arăta după cum urmează după ce ați făcut un instantaneu.
unele feature
ramură Noul CAP
(marcată de comiterea evidențiată) există numai în unele feature
ramură. Nu va apărea în jurnalul de ieșire din maestru
, și nici modificările sale nu vor apărea în directorul de lucru după ce ați făcut check out maestru
.
De fapt, puteți vedea noua ramură în baza de date internă prin deschiderea fișierului .git / ref / capete /
. Fișierul conține ID-ul comitetului de referință și este singura definiție a unei sucursale Git. Acesta este motivul pentru care ramurile sunt atât de ușoare și ușor de gestionat.
În cele din urmă, puteți șterge sucursalele prin -d
steag:
git branch -d
Dar, dedicarea lui Git de a nu-ți pierde niciodată munca nu-l împiedică să înlăture ramurile cu comitete neschimbate. Pentru a forța ștergerea, utilizați -D
în locul:
git ramură -D
Schimbările neschimbate vor fi pierdute, deci fii foarte atent cu această comandă.
Desigur, crearea ramurilor este inutilă fără capacitatea de a comuta între ele. Git numește această "verificare" a unei filiale:
Git checkout
După verificarea ramurii specificate, directorul dvs. de lucru este actualizat pentru a se potrivi cu comitetul specificat al ramurii. In plus CAP
este actualizat pentru a indica noua ramificație și toate comitetele noi vor fi stocate pe noua ramură. Vă puteți gândi să verificați o sucursală ca trecerea la un nou dosar de proiect - cu excepția faptului că va fi mult mai ușor să trageți modificările înapoi în proiect.
Având în vedere acest lucru, este de obicei o idee bună să aveți a curat înainte de a verifica o ramură. Un director curat există atunci când nu există modificări neangajate. Dacă nu este cazul, Git checkout
are potențialul de a vă suprascrie modificările.
Ca și în cazul unei revizuiri "sigure", sunteți liber să experimentați o nouă filială fără teama de a distruge funcționalitatea existentă. Dar, acum aveți o istorie dedicată cu care să lucrați, astfel încât să puteți înregistra progresul unui experiment folosind același lucru adăugați git
și git comite
comenzi de la mai devreme în carte.
Această funcție va deveni și mai puternică odată ce vom învăța cum să îmbinam istoriile divergente înapoi în ramura "principală" (de ex., maestru
). O să ajungem la asta într-un moment, dar mai întâi, există un caz de utilizare important Git checkout
care trebuie să fie luate în considerare ...
Git vă permite, de asemenea, să utilizați Git checkout
cu etichete și coduri de comitet, dar acest lucru vă pune într-un stare detașată HEAD. Aceasta înseamnă că nu mai sunteți pe o ramură - vizionați direct o comitet.
Puteți să vă uitați în jur și să adăugați comitete noi, ca de obicei, dar din moment ce nu există nici o sucursală care să indice adăugările, veți pierde toate lucrările dvs. de îndată ce reveniți la o filială reală. Din fericire, crearea unei noi sucursale într-o detașată CAP
starea este destul de ușoară:
git checkout -b
Aceasta este o scurtătură pentru git ramură
urmat de Git checkout
. După care veți avea o nouă referință ramificată strălucitoare la fostul detașat CAP
. Aceasta este o procedură foarte utilă pentru a elimina experimentele de la vechile revizuiri.
Îmbinarea este procesul de tragere a comitetelor de la o ramură la alta. Există multe modalități de combinare a sucursalelor, dar scopul este întotdeauna să împărtășiți informații între sucursale. Acest lucru face ca una dintre cele mai importante caracteristici ale Git să fie îmbinată. Cele două metode de îmbinare cele mai comune sunt:
Ambele utilizează aceeași comandă, git merge
, dar metoda este determinată automat pe baza structurii istoriei dvs. In fiecare caz, ramura în care doriți să fuzionați trebuie să fie verificată, iar ramura țintă va rămâne neschimbată. Următoarele două secțiuni prezintă două posibile scenarii de fuziune pentru următoarele comenzi:
git checkout master git îmbină câteva funcții
Din nou, aceasta combină funcția unele feature
ramură în maestru
ramură, lăsându-l pe fostul neatins. De obicei, ați rula aceste comenzi după ce ați terminat o caracteristică și doriți să o integrați în proiectul stabil.
Primul scenariu arată astfel:
Am creat o sucursală pentru a dezvolta o nouă caracteristică, a adăugat două comitete și acum este gata să fie integrată în baza de cod principală. În loc să rescrii cele două comitete care lipsesc de la maestru
, Git poate să "avanseze rapid" maestru
indicatorul sucursalei pentru a se potrivi locației unele feature
.
După fuzionare, maestru
ramura conține toată istoria dorită, iar ramura de caracteristică poate fi ștearsă (dacă nu doriți să continuați să dezvoltați). Acesta este cel mai simplu tip de îmbinare.
Desigur, am fi putut face cele două comitete direct pe maestru
ramură; totuși, folosirea unei ramuri de funcții dedicate ne-a oferit un mediu sigur pentru a experimenta codul nou. Dacă nu s-a dovedit a fi corect, am fi putut șterge pur și simplu ramificația (spre deosebire de resetare / revenire). Sau, dacă am adăugat o grămadă de comitete intermediare care conțineau cod rupt, am putea să-l curățăm înainte de a le uni maestru
(vezi Rebasing below). Pe măsură ce proiectele devin mai complicate și dobândesc mai mulți colaboratori, acest tip de dezvoltare ramificată face Git un instrument organizațional fantastic.
Dar nu toate situațiile sunt destul de simple pentru o comitere rapidă. Rețineți că principalul avantaj al ramurilor este capacitatea de a explora simultan multe linii independente de dezvoltare. În consecință, veți întâlni adesea un scenariu care arată după cum urmează:
Acest lucru a început ca o îmbinare rapidă înainte, dar am adăugat o comitet la maestru
în timp ce noi eram încă în curs de dezvoltare unele feature
. De exemplu, am fi putut să nu mai lucrăm la această caracteristică pentru a repara o eroare sensibilă la timp. Bineînțeles, bug-fix-ul ar trebui să fie adăugat la depozitul principal cât mai curând posibil, așa că vom rezista în scenariul prezentat mai sus.
Îmbinând suita de elemente în maestru
în acest context rezultă o îmbinare cu 3 căi. Acest lucru este realizat folosind aceleași comenzi ca și fuzionarea rapidă din secțiunea anterioară.
Git nu poate răspunde rapid maestru
pointer la unele feature
fără a se retrage. În schimb, generează un nou îmbinare comite care reprezintă imaginea combinată a ambelor ramuri. Rețineți că această nouă comitet are Două părintele se angajează, oferindu-i acces la ambele istorii (într-adevăr, alergând git log
după ce fuzionarea în trei direcții arată comitete de la ambele ramuri).
Numele acestui algoritm de îmbinare provine de la metoda internă utilizată pentru a crea comitetul de îmbinare. Git se uită la Trei se angajează să genereze starea finală a fuzionării.
Dacă încercați să combinați două ramuri care fac modificări diferite ale aceleiași porțiuni de cod, Git nu va ști ce versiune să utilizeze. Aceasta se numește a combinați conflictul. Evident, acest lucru nu se poate întâmpla niciodată în timpul unei fuziuni rapide. Când Git întâlnește un conflict de fuzionare, veți vedea următorul mesaj:
Auto-fuziune index.html CONFLICT (conținut): Merge conflictul înAmestecarea automată eșuată; remediați conflictele și apoi angajați rezultatul.
În loc să adăugați automat comitetul de fuziune, Git se oprește și vă întreabă ce să faceți. Alergare git status
în această situație se va întoarce ceva de genul:
# Pe maestru de ramură # Trasee dezmembrate: # # ambele modificate:
Fiecare fișier cu un conflict este stocat în secțiunea "Căi neschimbate". Git adnotă aceste fișiere pentru a vă arăta conținutul din ambele versiuni:
<<<<<<< HEAD This content is from the current branch. ======= This is a conflicting change from another branch. >>>>>>> ceva-caracteristică
Partea din fața instanței =======
este din maestru
ramură, iar restul este din ramura pe care încercați să o integrați.
Pentru a rezolva conflictul, eliminați <<<<<<
, =======
, și >>>>>>>
notație și modificați codul la ceea ce doriți să păstrați. Apoi, spune-i lui Git că ai terminat de rezolvat conflictul cu adăugați git
comanda:
adăugați git
Asta e corect; tot ce trebuie să faceți este să așezați fișierul în conflict pentru ao marca ca rezolvată. În cele din urmă, finalizați îmbinarea în trei direcții generând comitetul de îmbinare:
git comite
Mesajul jurnal este însămânțat cu o notificare de îmbinare împreună cu o listă de "conflicte", care poate fi utilă în special atunci când încercați să aflați unde a avut loc ceva în proiect.
Și asta e tot ce trebuie să fuzionăm în Git. Acum, că avem o înțelegere a mecanismelor din spatele ramurilor Git, putem analiza în profunzime modul în care utilizatorii veterani Git folosesc ramurile în fluxul lor de lucru de zi cu zi.
Fluxurile de lucru prezentate în această secțiune reprezintă semnul distinctiv al controlului reviziilor bazate pe Git. Natura ușoară și ușor de îmbinat a implementării ramurii Git le face unul dintre cele mai productive instrumente din arsenalul de dezvoltare software.
Toate fluxurile de lucru ramificate se învârt în jurul valorii de git ramură
, Git checkout
, și git merge
comenzile prezentate mai devreme în acest capitol.
Adesea, este util să acordați o semnificație specială diferitelor ramuri pentru a organiza un proiect. Această secțiune prezintă cele mai frecvente tipuri de ramuri, dar rețineți că aceste distincții sunt pur superficiale - la Git, o ramură este o ramură.
Toate filialele pot fi clasificate ca fiind permanent ramuri sau subiecte ramase. Primul conține istoricul principal al unui proiect (de ex., maestru
), în timp ce acestea din urmă sunt sucursale temporare folosite pentru implementarea unui anumit tip subiect, apoi aruncate (de ex., unele feature
).
Ramurile permanente sunt sângele vieții oricărui depozit. Acestea conțin fiecare punct important al unui proiect software. Majoritatea dezvoltatorilor folosesc maestru
exclusiv pentru codul stabil. În aceste fluxuri de lucru, tu nu să se angajeze direct pe maestru
-este doar o sucursală de integrare pentru caracteristici completate care au fost construite în ramuri de teme dedicate.
În plus, mulți utilizatori adaugă un al doilea strat de abstractizare într-o altă ramură de integrare (convențional numită dezvolta
, deși orice nume va fi suficient). Acest lucru eliberează maestru
ramură pentru într-adevăr codul stabil (de ex., angajamentele publice) și utilizările dezvolta
ca ramură de integrare internă pentru a se pregăti pentru eliberarea publică. De exemplu, următoarea diagramă prezintă câteva caracteristici integrate în dezvolta
, apoi o fuziune unică, finală maestru
, care simbolizează o eliberare publică.
maestru
ramură exclusiv pentru eliberarea publică Ramurile de subiecte se încadrează în general în două categorii: filiale și rapoarte de remediere rapidă. Ramurile de funcții sunt ramuri temporare care încorporează o nouă caracteristică sau un refactor, protejând proiectul principal de codul netestat. Ele provin de obicei dintr-o altă ramură de caracteristici sau dintr-o ramură de integrare, dar nu ramura "super stabilă".
Rapoartele cu replici rapide sunt similare în natură, dar provin din ramura publică de eliberare (de ex., maestru
). În loc de a dezvolta noi caracteristici, acestea sunt pentru patching rapid linia principală de dezvoltare. De obicei, aceasta înseamnă remedierea erorilor și alte actualizări importante care nu pot aștepta până la următoarea lansare majoră.
maestru
cu o ramură de remediere rapidă Din nou, semnificațiile atribuite fiecăreia dintre aceste ramuri sunt pur convenționale - Git nu vede nicio diferență între maestru
, dezvolta
, caracteristici și remedierile rapide. În acest sens, nu vă fie frică să le adaptați la scopurile proprii. Frumusețea lui Git este flexibilitatea sa. Când înțelegeți mecanica din spatele ramurilor Git, este ușor să creați fluxuri de lucru noi care să se potrivească proiectului și personalității dvs..
Rebasing este procesul de mutare a unei sucursale la o nouă baza. Capacitățile de reabilitare ale Git fac ramurile mai flexibile, permițând utilizatorilor să-și organizeze manual sucursalele. Ca fuzionarea, git rebase
cere ca ramura să fie verificată și ia noua bază ca argument:
git checkout unele-caracteristica git rebase maestru
Aceasta mișcă întregul unele feature
ramificați pe vârful lui maestru
:
unele feature
pe maestru
ramură După refacere, ramura de caracteristică este a extensie liniară de maestru
, care este o modalitate mult mai curată de a integra schimbările de la o ramură la alta. Comparați această istorie liniară cu o îmbinare de maestru
în unele feature
, care are ca rezultat exact aceeași bază de cod în imaginea finală:
maestru
în unele feature
cu o îmbinare cu 3 căi Din moment ce istoria a diferit, Git trebuie să utilizeze o comitet de îmbinare suplimentară pentru a combina sucursalele. A face acest lucru de multe ori pe parcursul dezvoltării unei caracteristici de lungă durată poate duce la o istorie foarte murdară.
Aceste comitete suplimentare de fuziune sunt inutile - există doar pentru a trage schimbări maestru
în unele feature
. În mod tipic, veți dori ca fuzionarea să se angajeze însemna ceva, cum ar fi finalizarea unei noi caracteristici. Acesta este motivul pentru care mulți dezvoltatori aleg să facă schimbări cu git rebase
, deoarece are ca rezultat o istorie complet liniară în ramura caracteristică.
Rebasingul interactiv merge cu un pas mai departe și vă permite Schimbare se angajează în timp ce le deplasați la noua bază. Puteți specifica o rebază interactivă cu -eu
steag:
git rebase -i master
Acest lucru cuprinde un editor de text, cu un rezumat al fiecărui comitet în ramura de caracteristici, împreună cu o comandă care determină Cum ar trebui transferat la noua bază. De exemplu, dacă aveți două comitete pe o sucursală de caracteristici, puteți specifica o rebază interactivă, după cum urmează:
alege 58dec2a În primul rând se angajează pentru squash-ul de noi caracteristici 6ac8a9f Al doilea angajament pentru o nouă caracteristică
Valoarea implicită alege
comanda mută prima comitere la noua bază ca și cea normală git rebase
, dar apoi suc de fructe
comanda îi spune lui Git să combine al doilea comitet cu cel precedent, astfel încât să încheiați cu un comitet care conține toate modificările:
unele feature
ramură Git oferă mai multe comenzi de rebazare interactive, fiecare dintre acestea fiind rezumate în secțiunea de comentarii a listei de configurații. Punctul este rebasingul interactiv vă permite complet rescrieți istoricul unei sucursale la specificațiile dvs. exacte. Acest lucru înseamnă că puteți adăuga cât mai multe comenzi intermediare unei ramuri de funcții după cum aveți nevoie, apoi mergeți înapoi și fixați-le într-o progresie semnificativă după.
Alți dezvoltatori vor crede că sunteți un programator genial și știți exact cum să implementați întreaga caracteristică într-o singură lovitură. Acest tip de organizație este foarte important pentru a asigura că proiectele mari au o istorie navigabilă.
Rebasingul este un instrument puternic, dar trebuie să fii politicos în rescrierea istoriei. Ambele tipuri de rebalizări nu sunt de fapt mișcare comitetele existente - acestea crea cele noi (marcate cu un asterisc în diagrama de mai sus). Dacă inspectați comitetele care au fost supuse unei rebate, veți observa că au coduri de identitate diferite, chiar dacă acestea reprezintă același conținut. Aceasta înseamnă rebasing distruge existente se angajează în procesul de "mișcare" a acestora.
Așa cum vă puteți imagina, acest lucru are consecințe dramatice pentru fluxurile de lucru colaborative. Distrugerea unei comitete publice (de ex maestru
ramură) este ca și cum ar trebui să distrugem baza muncii tuturor celorlalți. Git nu va avea nici o idee cum să combine toate schimbările tuturor, și veți avea o mulțime de scuze de făcut. Vom analiza mai profund acest scenariu după ce vom învăța cum să comunicați cu depozitele de la distanță.
Deocamdată, respectați regula de aur a rebalizării: să nu renovați niciodată o ramură care a fost împinsă într-un depozit public.
Această lecție reprezintă un capitol din Git Succinct, o carte electronică gratuită de la echipa de la Syncfusion.