Interaktiv rebase: rydd før du deler
Den interaktive leksjonen trenger JavaScript. Teksten under er hele leksjonen.
Etter leksjonen kan du
- lese planen fra
git rebase -iog forklare hvorfor den eldste commiten står øverst forstå - bruke reword, squash, fixup, drop og ny rekkefølge til å rydde en privat branch, og kontrollere resultatet med
git diff ORIG_HEAD HEADanvende - bruke
git commit --fixupoggit rebase -i --autosquashtil å smelte en senere rettelse inn i riktig commit anvende - avgjøre om commits kan ryddes med interaktiv rebase eller må angres med revert fordi de er delt vurdere
Forstå: Historien du forteller
Før du deler en branch, bør du lese historien den forteller. Her står det: legg til søkefelt, rett skrivefeil, legg til debug-utskrift, og en commit som bare heter results. Det viser hvordan du jobbet, ikke hva som endret seg. En leser vil heller se to ryddige commits.
git rebase -i main åpner en plan i editoren, med én linje per commit på branchen. Hver linje starter med pick: spill av denne commiten som den er. Hvilken commit står øverst?
Du endrer ordet først på linjen. Fixup smelter commiten inn i den over og kaster sin egen melding. Squash gjør det samme, men lar deg slå sammen meldingene.
Drop fjerner commiten og endringen dens, her debug-utskriften. Reword beholder endringen, men lar deg skrive en bedre melding, her for results.
Git spiller av planen ovenfra. Rettelsen er smeltet inn i søkefeltet, debug-commiten er borte, og den siste commiten har en tydelig melding. Som ved en vanlig rebase er dette nye commits. De gamle er stiplet: ingen branch peker på dem.
Ofte oppdager du en feil senere, når andre commits allerede ligger oppå. Da lager git commit --fixup en commit med en melding som starter med fixup og navnet på målet. Det er en lapp til Git: dette hører hjemme i den commiten.
git rebase -i --autosquash main leser disse lappene. Den flytter hver fixup-linje rett under målet sitt og merker den fixup, så planen er ferdig. Du trenger bare å lagre.
Rydd bare commits som fortsatt er private, før du pusher eller lager en pull request. Og sjekk resultatet. git diff ORIG_HEAD HEAD viser hvordan innholdet endret seg. Har du bare skrevet om meldinger, slått sammen eller byttet rekkefølge, skal den ikke vise noe.
Se demo: Rydd en søke-branch
Vi står på den private branchen search. Loggen viser fire commits oppå snapshotet, med den nyeste øverst.
$ git log --oneline
Planen åpnes med git rebase -i main. Vi setter fixup på skrivefeilen, drop på debug-utskriften og reword på results. Etterpå ber Git om den nye meldingen.
$ git rebase -i main
To ryddige commits, begge med nye ID-er. De gamle fire ligger stiplet i grafen.
$ git log --oneline
Nå sjekker vi hva som endret seg i innholdet. Bare debug.txt er borte. Fixup og reword rørte ikke koden. Hadde vi droppet feil commit, ville git reset --hard ORIG_HEAD tatt oss tilbake.
$ git diff --stat ORIG_HEAD HEAD
Senere forbedrer vi søkefeltet. Endringen hører hjemme i den første commiten, ikke i en ny commit på toppen.
$ echo 'Search box with hint text' > search.txt && git add search.txt
git commit --fixup tar imot commiten som skal rettes. Her er det HEAD~1. Se på meldingen Git skriver.
$ git commit --fixup HEAD~1
Nå kjører vi git rebase -i --autosquash main. Planen er allerede ferdig: fixup-linjen står rett under målet sitt. Vi lagrer den bare.
$ git rebase -i --autosquash main
To commits igjen. Forbedringen bor nå inne i Add search box, og ingen kan se at den kom senere.
$ git log --oneline
Oppgaver
- Les historien branchen forteller, med én linje per commit.
- Rydd branchen: smelt skrivefeilrettingen inn i søkefelt-commiten, fjern debug-commiten og gi
resultsmeldingenAdd search results. - Sammenlign innholdet før og etter ryddingen.
- Lagre den stagede endringen som en fixup av commiten
Add search box. - Smelt fixup-commiten inn i målet sitt.
Øv: Overfør: en rapport i fem commits
Du står på report, en privat branch med fem commits. Ingen demo denne gangen.
Oppgaver
- Slå sammen
Add chartogAdd chart captiontil én commit med meldingenAdd chart with caption. - Flytt
Write methodforanWrite results, slik at rapporten kommer i naturlig rekkefølge. intro.txtinneholder skrivefeilen Introductoin. Rett den, og smelt rettelsen inn i commitenWrite intro, slik at det ikke blir igjen noen ekstra commit.
Sjekk deg selv: Hent det fram igjen
Du har slått sammen to commits med squash og gitt en tredje ny melding med reword. Hva viser git diff ORIG_HEAD HEAD?
- Ingenting, innholdet er det samme som før
- Endringene fra de to commitene du slo sammen
- Den gamle og den nye meldingen
Du vil smelte en commit inn i den over, og du vil ikke beholde meldingen dens. Hvilket ord bruker du?
- squash
- fixup
- drop
Du har tre commits og bruker reword på den midterste. Hvilke commits får nye ID-er?
- Bare den midterste, for det var bare den som endret seg
- Den midterste og den etter, mens den første beholder ID-en sin
- Ingen, for innholdet i filene er det samme
git log --oneline --decorate på main viser (HEAD -> main, origin/main) på den nyeste commiten, og en debug-commit to linjer lenger ned. Hvordan blir du kvitt debug-commiten?
- Interaktiv rebase med drop, og så
git push --force-with-lease git revertpå debug-commiten, og så en vanliggit pushgit reset --hardtil commiten før den, og så force-push
Repetisjon fra «Gode commits»: du gir commiten stuff, som legger til en pristabell, ny melding med reword. Hvilken emnelinje er best?
- Added price table
- Add price table
- Update stuff
Vanlige misforståelser
- «Planen viser den nyeste commiten øverst, som
git log.» Den eldste står øverst, fordi Git spiller av planen ovenfra og ned. - «Interaktiv rebase redigerer commitene der de står.» Fra første endrede linje og nedover blir hver commit en ny commit med ny ID.
- «Squash og fixup er det samme.» Begge smelter en commit inn i den over. Squash lar deg slå sammen meldingene, fixup beholder bare meldingen til målet.
Les mer
Planen er et manus
git rebase -i <base> skriver en huskeliste for commitene i base..HEAD, med den eldste først, og åpner den i editoren. Når du lagrer og lukker, kjører Git den ovenfra og ned. En ekte plan for en branch med tre commits:
pick c6766f7 # Add search box
pick 00d10e3 # Rename button
pick 1218aec # Add search results
# Rebase a5ea1be..1218aec onto a5ea1be (3 commands)
Det er ID-en som teller. Emnelinjen etter den står der bare for å hjelpe deg. Eldre Git-versjoner viser den uten #. Basen kan være en branch (git rebase -i main) eller et antall (git rebase -i HEAD~3 tar de tre siste commitene). git rebase -i --root tar med den aller første commiten også.
| Ord | Kort | Hva det gjør |
|---|---|---|
| pick | p | Bruk commiten som den er |
| reword | r | Bruk endringen, stopp for å skrive ny melding |
| edit | e | Bruk commiten, og stopp så du kan endre eller dele den |
| squash | s | Smelt inn i commiten over, slå sammen begge meldingene |
| fixup | f | Smelt inn i commiten over, behold bare meldingen over (fixup -C beholder denne commitens melding i stedet) |
| exec | x | Kjør en skallkommando. Rebasen stopper hvis den feiler |
| break | b | Stopp her. git rebase --continue går videre |
| drop | d | Utelat commiten |
Å slette en linje har samme virkning som drop, og Git advarer deg ikke. Sett git config rebase.missingCommitsCheck error hvis du vil at Git skal nekte en plan der en linje har forsvunnet. Mens en rebase står stille, kan du endre resten av planen med git rebase --edit-todo.
Stopp og endre en commit: edit
edit legger på commiten og stopper, med den commiten som HEAD. Endre filer, kjør git commit --amend, og avslutt med git rebase --continue.
Du kan også dele en commit. Angre commiten, men behold endringene, med en mixed reset, og commit så delene hver for seg:
$ git rebase -i main # mark "Add a and b" with edit
Stopped at fce6fb0... # Add a and b
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
$ git reset HEAD^
$ git add a.txt && git commit -m "Add a"
$ git add b.txt && git commit -m "Add b"
$ git rebase --continue
Successfully rebased and updated refs/heads/big.
$ git log --oneline
016f3d8 Add b
7170811 Add a
a5ea1be Initial snapshot
git reset HEAD^ uten --hard flytter bare HEAD, som står løsrevet under rebasen, og staging-området. Filene dine blir som de er.
Forbered rettelser mens du jobber
git commit kan skrive planlinjene for deg. Commit-meldingen forteller --autosquash hvor commiten hører hjemme:
| Kommando | Melding | Senere i planen |
|---|---|---|
git commit --fixup=<commit> |
fixup! <subject> |
fixup: behold målets melding |
git commit --squash=<commit> |
squash! <subject> |
squash: slå sammen meldingene |
git commit --fixup=amend:<commit> |
amend! <subject> |
fixup -C: endring og ny melding |
git commit --fixup=reword:<commit> |
amend! <subject> |
bare ny melding, ingen endring |
Deretter flytter git rebase -i --autosquash main hver linje inn under målet sitt. git config rebase.autoSquash true gjør --autosquash til standard for interaktive rebaser.
Sjekk at du bare endret det du mente
git diff ORIG_HEAD HEAD sammenligner innholdet før og etter. Den skal være tom når du bare har skrevet om meldinger, byttet rekkefølge eller slått sammen commits. Viser den noe du ikke mente, må du se nærmere etter. For å sammenligne commit for commit bruker du git range-diff. Her ble Rename button smeltet inn i Add search box:
$ git range-diff main ORIG_HEAD HEAD
1: c6766f7 ! 1: c463304 Add search box
@@ search.html (new)
+<form>
+ <label>Search</label>
+ <input name=q>
-+ <button>Go</button>
++ <button>Search</button>
+</form>
2: 00d10e3 < -: ------- Rename button
3: 1218aec = 2: 1bb4102 Add search results
! merker en commit der endringen er forskjellig, med en diff av de to diffene under. < betyr at den gamle commiten ikke lenger har noen motpart, og = betyr at endringen er identisk.
Angre en opprydding
Mens rebasen pågår, setter git rebase --abort alt tilbake. Når den er ferdig, ligger branchens gamle tupp i branchens reflog og som regel i ORIG_HEAD, så git reset --hard ORIG_HEAD tar deg tilbake, så lenge du ikke har arbeid som ikke er committet. En reset under rebasen, som i delingseksempelet over, flytter ORIG_HEAD. Da finner du den gamle tuppen i branchens reflog, som leksjonen «Reflog» viser.
Tommelfingerregel
Rydd før du deler. Hvordan du pusher en omskrevet branch som bare er din, viser leksjonen «Rebase». Rydd aldri main eller andre brancher som andre bruker.
Per-Arne's Git Good!