git commit —fixup=...

Czasami zdarza się, że zatwierdziłem jakieś zmiany, ale coś tam jednak wymaga poprawy. Pewnie skorzystam z git rebase -i, tym niemniej po takich poprawkach uporządkowanie commitów wymaga trochę pracy i tu z pomocą przychodzi opcja --fixup.

Załóżmy, że mam jakieś repozytorium git:

$ git log --oneline
63594c0 (HEAD -> master) Initial

W przykładzie jest tylko jeden commit, ale to nie istotne.

Zaczynam więc standardowo:

$ git switch -c feature-1
$ nano README.md       # Tu wpisuję treść mojego README
$ git add README.md
$ git commit -m "Dodano README.md"

W wyniku tych działań mam coś takiego:

$ git log --oneline 
87aeca8 (HEAD -> feature-1) Dodano README.md
63594c0 (master) Initial

Powiedzmy, że jednak odkrywam, że w README zrobiłem paskudny błąd ortograficzny:

$ nano README.md     # poprawiam wstydliwy błąd
$ git add README.md
$ git commit --amend

Ponowne sprawdzenie logu:

$ git log --oneline 
6f3d411 (HEAD -> feature-1) Dodano README.md
63594c0 (master) Initial

Jak widać ostatni commit został przepisany (87aeca8 został zastąpiony przez 6f3d411). Efekt w postaci poprawionego błędu i czystej historii commitów został osiągnięty.

To jest ten prostszy przypadek ale co, jeśli błąd w README.md uświadomię sobie dopiero po jakimś czasie, gdy już zdążyłem dodać inne commity. Np mam taką historię:

$ git log --oneline 
6e8a8dd (HEAD -> feature-1) Dodano main.c
6f3d411 Dodano README.md
63594c0 (master) Initial

I dopiero teraz stwierdzam konieczność poprawienia pliku README.md. Opcja --amend już nie zadziała i trzeba skorzystać z dobrodziejstw git rebase -i. “Rebase” pozwoli ponownie przeedytować istniejące commity, choć każdy kto to robił wie, że będzie trochę zabawy. I tu wracam do wspomnianej opcji --fixup operacji commit.

Mogę zrobić następującą rzecz:

$ nano README.md     # poprawiam (kolejny pewnie) błąd ortograficzny
$ git add README.md
$ git commit --fixup=6f3d411   # wskazuję poprawiany commit

Poprawiany commit, to ten z opisem “Dodano README.md”. Polecenie nie pyta mnie nawet o komentarz i mam następującą historię:

$ git log --oneline 
9fadf75 (HEAD -> feature-1) fixup! Dodano README.md
6e8a8dd Dodano main.c
6f3d411 Dodano README.md
63594c0 (master) Initial

I teraz ta fajna część:

$ git rebase -i --autosquash master

Otwiera się edytor umożliwiający ustawienie poleceń odnośnie commitów następujących po master (commity pojawiają się od najstarszego do najnowszego):

pick 6f3d411 Dodano README.md
fixup 9fadf75 fixup! Dodano README.md
pick 6e8a8dd Dodano main.c

Widać, że “fixup! Dodano README.md” zostało umieszczone zaraz po “Dodano README.md” i ma automatycznie (dzięki opcji --autosquash) wybrane polecenie fixup. Po zamknięciu edytora powstaje taka oto historia commitów:

$ git log --oneline 
8abcc8e (HEAD -> feature-1) Dodano main.c
3c9672d Dodano README.md
63594c0 (master) Initial

Commity powyżej “63594c0” zostały przepisane, w tym “Dodano README.md” zebrał zmiany, które dodałem w “fixup! Dodano README.md”.

Błędy poprawione, historia czysta. Można robić git merge.

Kontakt ze mną: @ark_r@mastodon.social