Begynderguide til interaktiv rebasering

Først i år lavede jeg en interaktiv rebase for første gang, og jeg var imponeret over, hvad man kan gøre med den. Jeg syntes også, at det var lidt kompliceret i starten. Forhåbentlig vil denne vejledning hjælpe med at fjerne noget usikkerhed omkring det.

Og fordi det er så kraftfuldt, og fordi man i det væsentlige kan omskrive historien, skal jeg også give en lille advarsel, før vi begynder: Der er mange skoler af tanker om Git og om, hvorvidt rebasing er en god idé eller ej. Dette indlæg vil ikke dykke ned i disse diskussioner og er udelukkende beregnet til at gennemgå det grundlæggende i at bruge interaktiv rebasing.

TL;DR

  • Interaktiv rebasing kan bruges til at ændre commits på mange måder, såsom redigering, sletning og squashing.
  • For at fortælle Git, hvor Git skal starte den interaktive rebasering, skal du bruge SHA-1 eller indekset for den commit, der går umiddelbart forud for den commit, du vil ændre.
  • Under en interaktiv rebasering, når Git holder pause ved en commit, du har markeret for at redigere, er arbejdsgangen ikke anderledes end en normal commit-proces – du iscenesætter filer og commiterer dem derefter. Den eneste forskel er, at du bruger kommandoen git commit --amend i stedet for git commit.
  • Interaktiv rebasing vil skabe nye SHA-1’er, derfor er det bedst at bruge interaktiv rebasing på commits, du ikke har skubbet til en fjerngren.

Problemet

I dette eksempel vil vi gennemgå en situation, hvor vi har arbejdet i en feature-gren, og vi har et par commits, som vi gerne vil ændre eller slette. Sådan ser vores git-log ud:

Fra git-loggen ovenfor er her de to commits, som vi ønsker at ændre:
4a4d705 – I dette commit begik vi ved et uheld en fusionskonflikt
6c01350 – I dette commit fjernede vi fusionskonflikten

Det vi gerne vil gøre er at gå tilbage i tiden til 4a4d705, fjerne fusionskonflikten i commit’et og derefter slette 6c01350, da fusionskonflikten er løst, og vi ikke længere har brug for dette commit. Dette vil være en forbedring af vores commit-historik af to grunde:

  1. Vi vil ikke have ødelagte commits (sammenlægnings-konflikter)
  2. Vi vil kun have meningsfulde commits, ingen commits, der udelukkende er relateret til at rette en overset sammenlægnings-konflikt

Løsningen

Denne situation er en god kandidat til interaktiv rebasing. Scott Chacon beskriver i sin bog Pro Git interaktiv rebasing på følgende måde: “Nogle gange kan den ting, der er rettet … ikke ændres til det ikke helt perfekte commit, som det retter, fordi det commit ligger dybt begravet i en patch-serie. Det er præcis, hvad interaktiv rebasering er beregnet til: Brug den efter masser af , ved at omarrangere og redigere commits, og ved at presse flere commits sammen til ét.”

Hvilke commits vil vi ændre?

For at starte en interaktiv rebasering skal vi fortælle Git, hvilke commits vi vil ændre. Det gør vi ved at henvise til den commit, der ligger umiddelbart forud for den tidligste commit, vi ønsker at ændre. Eller, sagt med andre ord, vi refererer “den sidste commit ønsker at beholde som den er”, ifølge Scott Chacon.

Lad os se på vores eksempel for at få en bedre forståelse. Der er to måder at henvise til dette commit på:
Med SHA-1 – Det sidste commit, vi ønsker at bevare som-er, har en SHA-1 på 528f82e, så vi kan sende dette ind i vores interaktive rebase-kommando.
Med indeks – Den sidste commit, vi ønsker at bevare som-er, har en indeksposition på 3 (Git bruger nulbaseret indeksering), så vi kan sende HEAD~3 til vores interaktive rebase-kommando.

Bemærkning – Hvis du kun har nogle få commits, som du skal interaktivt rebase, er det nok nemmere for de fleste at bruge indekset. Men hvis du har mange commits, er det sandsynligvis nemmere at bruge SHA-1, så du ikke behøver at tælle hele vejen ned i git-loggen.

Start interactive rebasing

Baseret på vores eksempel vil vi køre enten:

$ git rebase -i 528f82e

Og

$ git rebase -i HEAD~3

Hvilket åbner dette vindue i Vim:

Bemærk, at commits er i den modsatte rækkefølge af git log. I git log er den seneste commit øverst i git log. I denne visning er den seneste commit nederst. Bemærk også, at kommentarerne nedenfor giver en nyttig liste over de gyldige kommandoer, vi kan bruge på hvert commit.

Hvis du ikke kender Vim, skal du blot klikke på hvert ord pick, som du vil redigere, og derefter trykke på <i>-tasten (for indsætningstilstand). Når du er færdig med at skrive, skal du trykke på tasten <esc> for at forlade indsætningstilstanden.

I vores eksempel har vi ændret kommandoen til edit for den commit, vi ønsker at ændre, og vi har ændret kommandoen til drop for den commit, vi ønsker at slette. Derefter kører vi :wq for at gemme og afslutte Vim-vinduet.

Ændre commit

Tilbage i terminalen ser vi denne meddelelse:

Det giver mening, at vi er stoppet ved 4a4d705. Dette er det ældste commit i den serie af commits, som vi ønsker at ændre. Vi begynder med dette commit og arbejder os gennem hvert enkelt commit indtil det seneste.

Som en påmindelse var det commit med den sammenlægningskonflikt, som vi ved et uheld begik. Når vi åbner vores editor, kan vi se sammenlægningskonflikten der:

Så vi retter sammenlægningskonflikten i filen, men hvad gør vi nu? Når vi er i tvivl, git status:

Cool! Dette er faktisk nyttigt. Vi kan se, at vi i øjeblikket redigerer 4a4d705, og vi kan se de næste to commits, som der skal handles på efter denne.

Resten af meddelelsen forklarer os en velkendt arbejdsgang. Git fortæller os, at hvis vi ønsker at ændre det commit, vi kører git commit --amend. Dette vil i det væsentlige fungere som vores typiske git commit, som vi bruger i et normalt arbejdsflow. Nederst i denne meddelelse kan vi se, at vores fil blev ændret, hvilket afspejler de ændringer, vi lige har foretaget for at fjerne sammenlægningskonflikten. Vi er nødt til at stable filen, før vi commiterer den. Dette adskiller sig ikke fra en normal arbejdsgang.

Det eneste vi gør er git add tempChanger.js for at stage den redigerede fil og derefter git commit --amend for at committe den stagede fil! Dette vil nu åbne et Vim-vindue igen med commit-meddelelsen:

Vi kan enten redigere commit-meddelelsen eller lade den stå som den er. Lad os vælge at beholde commit-meddelelsen som den er, og vi skriver :wq for at gemme og afslutte vinduet.

Vi har nu redigeret vores gamle commit. Så hvad nu? Kør git status:

Fortsæt interaktiv rebasering

Vi har ikke andet at ændre i commit’et, så lad os fortsætte!

Vi kører git rebase --continue og ser følgende besked:

Woah, er vi færdige? Men hvad med de to andre commits? Tja, den næste commit, der skulle handles på, var 6c01350. Denne commit markerede vi til sletning (drop), da vi startede den interaktive rebasering. Git slettede den automatisk og gik videre til den næste commit, 41aa9d2. Denne blev aldrig ændret i den første interaktive rebasering. Dens standardkommando var pick, hvilket betyder, at den commit vil blive brugt. Git anvendte dette commit, og da det var det sidste commit, blev den interaktive rebasering afsluttet.

Bemærk, at hvis vi havde flere commits at redigere, ville vi blot være gået videre til det næste commit og have startet processen med at ændre det, ligesom vi gjorde ovenfor. Cyklussen fortsætter, indtil der ikke er nogen commits tilbage.

Udkastknappen

Det er værd at bemærke, at hvis vi på et hvilket som helst tidspunkt i vores interaktive rebase laver fejl og ikke ved, hvordan vi skal rette dem, kan vi altid afbryde. På et hvilket som helst tidspunkt kan vi køre git rebase --abort i terminalen, og den interaktive rebasering vil blive afbrudt uden at nogen ændringer er gemt. Vi skal så starte den interaktive rebase forfra igen.

Efter den interaktive rebase

Vores git-log ser nu sådan ud:

Du vil bemærke, at et par ting er ændret i forhold til før vi startede den interaktive rebase:

  • Vi har ikke længere commit 6c01350 med commit-meddelelsen “Remove merge conflict”. Dette er den commit, vi slettede i vores interaktive rebasering.
  • Vores commit, vi redigerede, 4a4d705, har en anden SHA-1, 2b7443d.
  • Vores seneste commit fra vores oprindelige git-log, 41aa9d2, har også en ny SHA-1, 2b95e92. Dette commit blev ikke ændret, men blev blot anvendt på det commit, der lå før det 2b7443d.

Sidegevinster af interaktiv rebasering

For de to seneste commits i vores git-log, fordi de har nye SHA-1’er, ser Git dem som helt nye commits. Dette gælder selv for vores sidste commit, 2b95e92, hvor hverken commit-meddelelsen eller filerne ændrede sig overhovedet. Dette bringer et vigtigt punkt op med interaktiv rebasing: Hvis du ændrer et commit, vil dette commit og alle efterfølgende commits få nye SHA-1’er.

Dette vil ikke påvirke noget, hvis de commits, du har ændret, ikke er blevet skubbet til en fjerngren. Men hvis du faktisk gennemførte en interaktiv rebasering på commits, der allerede var skubbet til en fjerngren, og derefter skubbede din gren igen, ville du se:

Teknisk set kunne du komme udenom dette ved at bruge git push --force, men det er meget farligt. Hvis den eksterne gren har commits fra andre personer, men din lokale gren ikke har disse commits endnu, vil du effektivt slette deres commits.

En anden løsning er at bruge git push --force-with-lease, som kun vil ændre dine commits, men ikke commits tilhørende andre, selvom dette også kan være problematisk. Hvis en anden udvikler for eksempel allerede har de commits, der fik nye SHA-1’er på deres lokale gren, vil de, når de trækker den eksterne gren, få sammenføjningskonflikter med hver af disse commits.

Hvornår man skal bruge --force-with-lease ligger uden for rammerne af dette blogindlæg, men det vil være bedst at rådføre sig med andre medlemmer af dit team, før du gør det. Du kan læse mere om git push --force-with-lease her.

Det vigtigste at tage med fra dette afsnit er, at det er meget nemmere og mere sikkert at bruge interaktiv rebasing på commits, der endnu ikke er blevet skubbet til en fjerngren.

Skrevet af Blake DeBoer. Oprindeligt udgivet på Dev.to

Senior, Lead, eller Principal udvikler i NYC? Stride ansætter! Ønsker du at opgradere dit tekniske team? Se, hvordan vi gør det! www.stridenyc.com

Tags

Tilmeld dig Hacker Noon

Opret din gratis konto for at låse op for din brugerdefinerede læseoplevelse.

Leave a Reply