Skriv om historien med Git Rebase

I den grunnleggende Git-arbeidsflyten utvikler du en ny funksjon i en dedikert faggren, og legger den sammen igjen i en produksjonsgren når den er ferdig. Dette gjør git fusjon et integrert verktøy for å kombinere grener. Det er imidlertid ikke den eneste Git tilbyr.

Kombinerer grener ved å slå dem sammen

Som et alternativ til ovenstående scenario kan du kombinere grener med git rebase kommando. I stedet for å knytte grenene sammen med et fusjonssammenheng, flytter gjenopprettelse hele funksjonen grenen til spissen av herre som vist under.

Kombinerer grener med git rebase

Dette tjener samme formål som git fusjon, integrering forplikter seg fra forskjellige grener. Men det er to grunner til at vi kanskje vil velge en rebase over en fusjon:

  • Det resulterer i en lineær prosjekthistorie.
  • Det gir oss muligheten til å rydde opp lokale forpliktelser.

I denne opplæringen vil vi undersøke disse to vanlige tilfellene av git rebase. Dessverre fordelene med git rebase kom på en avgang. Når det brukes feil, kan det være en av de farligste operasjonene du kan utføre i et Git-arkiv. Så, vi vil også ta et forsiktig utseende på farene ved gjenoppretting.

Forutsetninger

Denne opplæringen tar utgangspunkt i at du er kjent med de grunnleggende Git-kommandoene og samarbeidsprosessene. Du bør være komfortabel oppføring og begå øyeblikksbilder, utvikle funksjoner i isolerte grener, slå sammen grener sammen og skyve / trekke grener til / fra eksterne lagre.

1. Tilbakestilling for en lineær historie

Den første brukssaken vi vil utforske innebærer en divergerende prosjekthistorikk. Tenk på et lager der produksjonsgrenen din har flyttet fremover mens du utviklet en funksjon:

Å rebase trekk gren på herre gren, ville du kjøre følgende kommandoer:

git checkout funksjon git rebase master

Dette transplanterer trekk gren fra sin nåværende beliggenhet til toppen av herre gren:

Det er to scenarier hvor du vil gjøre dette. Først, hvis funksjonen var avhengig av det nye begår seg i herre, det ville nå få tilgang til dem. For det andre, hvis funksjonen var fullført, ville den nå bli konfigurert for å gå videre sammen herre. I begge tilfeller resulterer gjenoppretting i en lineær historie, mens git fusjon ville resultere i unødvendige sammenslåingsforpliktelser.

For eksempel, vurder hva som ville skje hvis du integrerte oppstrømmen forplikter seg til en fusjon i stedet for en tilbakekomst:

git checkout funksjonen Git Merge Master 

Dette ville ha gitt oss en ekstra fletteforpliktelse i trekk gren. I tillegg vil dette skje hver gang du ønsker å innlemme oppstrøms forpliktelser i funksjonen din. Til slutt vil prosjekthistorikken din være full av meningsløse sammenføyningsforpliktelser.

Integrering oppstrøms forplikter seg til å slå sammen

Den samme fordelen kan sees ved sammenslåing i den andre retningen. Uten en rebase, integrering av ferdig trekk grenen inn i herre krever en fletteforpliktelse. Selv om dette faktisk er en meningsfylt sammenslåing (i den forstand at den representerer en fullført funksjon), er den resulterende historien full av gafler:

Integrerer en ferdig funksjon med en fusjon

Når du reagerer før du slår sammen, kan Git spole fremover herre til spissen av trekk. Du finner en lineær historie om hvordan prosjektet ditt har utviklet seg i git logg output-den forplikter seg i trekk er pent gruppert sammen på toppen av forpliktelsene i herre. Dette er ikke nødvendigvis tilfelle når grener er bundet sammen med et sammenslåingsforpliktelse.

Tilbakestilling før sammenslåing

Løse konflikter

Når du kjører git rebase, Git tar hver forpliktelse i grenen og beveger dem, en for en, på den nye basen. Hvis noen av disse forbinder, endrer samme linje (r) av kode som oppstrømsforbindelsen, vil det føre til konflikt.

De git fusjon Kommandoen lar deg løse alle grenens konflikter ved slutten av sammenslåingen, noe som er et av de primære formålene med en sammenslåing. Det virker imidlertid litt annerledes når du reagerer. Konflikter er løst på grunnlag av hverandre. Så hvis git rebase finner konflikt, vil det stoppe tilbakekallingsprosedyren og vise en advarselsmelding:

Automatisk sammensmelting readme.txt CONFLICT (innhold): Slå sammen konflikt i readme.txt Kunne ikke slå sammen i endringene ... Når du har løst dette problemet, kjør "git rebase - continue". Hvis du foretrekker å hoppe over denne oppdateringen, kjør du "git rebase - skip" i stedet. For å sjekke ut den opprinnelige grenen og stoppe gjenoppretting, kjør "git rebase --abort". 

Visuelt, dette er hva prosjektloggen din ser ut når git rebase møter en konflikt:

Konfliktene kan inspiseres ved å løpe git status. Utgangen ser veldig ut som en flettekonflikt:

Unmerged paths: (bruk "git reset HEAD ... "til unstage) (bruk" git add ... "for å markere oppløsning) begge endret: readme.txt ingen endringer lagt til for å begå (bruk" git add "og / eller" git commit -a ") 

For å løse konflikten, åpne den konfliktfile filen (readme.txt i eksempelet ovenfor), finn de berørte linjene, og rediger dem manuelt til ønsket resultat. Deretter forteller Git at konflikten er løst ved å lagre filen:

git legg til readme.txt 

Vær oppmerksom på at dette er nøyaktig samme måte du markerer en git fusjon konflikt som løst. Men husk at du er midt i en rebase-du vil ikke glemme resten av begjærene som må flyttes. Det siste trinnet er å fortelle Git å fullføre gjenoppretting med --Fortsette alternativ:

git rebase - fortsette 

Dette vil flytte resten av forpliktelsene, en for en, og hvis noen andre konflikter oppstår, må du gjenta denne prosessen på nytt..

Hvis du ikke vil løse konflikten, kan du velge enten --hoppe eller --avbryte flagg. Sistnevnte er spesielt nyttig hvis du ikke har noen anelse om hva som skjer, og vil bare komme tilbake til sikkerhet.

# Ignorer forpligningen som forårsaket konflikten git rebase - skip # Abort hele rebasen og gå tilbake til tegnebrettet git rebase --abort 

2. Tilbakestilling for å rydde opp lokale forpliktelser

Så langt har vi bare brukt git rebase å flytte grener, men det er mye kraftigere enn det. Ved å passere -Jeg flagg, kan du starte en interaktiv, nybegynnende økt. Interaktiv gjenoppretting lar deg definere nøyaktig hvordan hver commit blir flyttet til den nye basen. Dette gir deg muligheten til å rydde opp en funksjonens historie før du deler den med andre utviklere.

For eksempel, la oss si at du er ferdig med å jobbe på din trekk gren og du er klar til å integrere den i herre. For å starte en interaktiv gjentatt økt, kjør følgende kommando:

git checkout funksjon git rebase -i master 

Dette åpner en redaktør som inneholder alle forpliktelsene i trekk som er i ferd med å bli flyttet:

velg 5c43c2b [Beskrivelse for eldste commit] velg b8f3240 [Beskrivelse for 2. eldste commit] velg c069f4a [Beskrivelse for siste commit] 

Denne oppføringen definerer hva trekk gren kommer til å ligne etter rebasen. Hver linje representerer en commit og plukke kommandoen før hver forpliktelse har definert hva som skal skje i løpet av tilbakemeldingen. Legg merke til at begjærene er oppført fra eldste til siste. Ved å endre denne oppføringen får du full kontroll over prosjekthistorikken din.

Hvis du vil endre rekkefølgen på forpliktelsene, kan du bare ordne linjene på nytt. Hvis du vil endre en kommandos melding, bruker du omformulere kommando. Hvis du vil kombinere to forpliktelser, endrer du plukke kommandoen til squash. Dette vil rulle alle endringene i den forpliktelsen til den over den. For eksempel, hvis du squashed den andre begå i ovennevnte oppføring, vil trekk gren vil se ut som følgende etter lagring og lukking av redaktøren:

Squashing den andre plikten med en interaktiv rebase

De redigere kommandoen er spesielt kraftig. Når den når det angitte forbudet, vil Git sette pause på tilbakekallingsprosedyren, omtrent som når den møter en konflikt. Dette gir deg muligheten til å endre innholdet i forplikten med git commit --amend eller til og med legge til flere forpliktelser med standarden git add/git commit kommandoer. Eventuelle nye forpliktelser du legger til, vil være en del av den nye grenen.

Interaktiv gjenoppretting kan ha en dyp innvirkning på utviklingsarbeidet. I stedet for å bekymre seg for å bryte opp endringene i innkapslede forpliktelser, kan du fokusere på å skrive koden din. Hvis du endte opp med å begå hva som skulle være en enkelt endring i fire separate stillbilder, er det ikke et problem med omskrivning av historie med git rebase -i og squash dem alle til en meningsfull begå.

3. Farer ved gjenoppretting

Nå som du har forståelse for git rebase, vi kan snakke om når vi ikke skal bruke den. Internt tilbakeleverer faktisk ikke flytte forplikter seg til en ny avdeling. I stedet skaper det splitter nye forpliktelser som inneholder de ønskede endringene. Med dette er tankene, er rebasing bedre visualisert som følgende:

Etter tilbakemeldingen går den inn i trekk vil ha forskjellige forpliktelser. Dette betyr at vi ikke bare flyttet en gren - vi har bokstavelig talt omskrevet vår prosjekthistorie. Dette er en svært viktig bivirkning av git rebase.

Når du jobber alene på et prosjekt, er omskrivning av historie ikke en stor sak. Men så snart du begynner å jobbe i et samarbeidsmiljø, kan det bli veldig farlig. Hvis du skriver om, forplikter andre utviklere å bruke (for eksempel forplikter seg på herre gren), det vil se ut som om de begår forsvunnet neste gang de prøver å trekke inn arbeidet ditt. Dette resulterer i et forvirrende scenario som er vanskelig å gjenopprette fra.

Med dette er tankene, bør du aldri glemme forpliktelser som har blitt presset til et offentligt arkiv med mindre du er positiv at ingen har basert sitt arbeid av dem.

Konklusjon

Denne opplæringen introduserte de to vanligste brukssakene til git rebase. Vi snakket mye om å flytte grener rundt, men husk at gjenoppretting egentlig handler om å kontrollere prosjekthistorikken. Kraften til omskrivning forplikter seg etter at friheten gjør at du fokuserer på utviklingsoppgaver i stedet for å bryte ned arbeidet ditt i isolerte stillbilder.

Legg merke til at gjenoppretting er et helt valgfritt tillegg til Git-verktøykassen. Du kan fortsatt gjøre alt du trenger med vanlig gammel git fusjon kommandoer. Faktisk er dette sikrere, da det unngår muligheten for å omskrive offentlig historie. Men hvis du forstår risikoen, git rebase kan være en mye renere måte å integrere grener i forhold til fusjonerende forpliktelser.