Weźmy taką sytuację – wysłaliście swój kod do review a tam koledzy zgłaszają poprawki. Ot codzienność. Wrzucacie zatem poprawki w kolejny commit, powiedzmy pod nazwą “Fixes in relation to the code review” a później jeszcze drugi trzeci, bo poprawek jest więcej. Każdy zbiór poprawek wrzucacie w osobnym commicie aby było czytelniej – nie żadne tam amendy.
W końcu historia w Waszym repo wygląda mniej więcej tak:
W końcu gdy Wasze zmiany zostaną zaakceptowane zabieracie się za squash
czyli scalenie wszystkich commitów w jeden. Co w tym przypadku będzie przebiegało następująco:
git rebase -i master
Wynikiem będzie następująca lista git-rebase-todo
:
Chcielibyśmy by z tych czterech commitów został nam tylko pierwszy. W takim wypadku możemy wyedytować tę listę i napisać coś takiego:
W kolejnym kroku możemy dodatkowo pozbyć się śladów tych tymczasowych commitów:
Wówczas na koniec nasz git log
będzie wyglądał następująco:
Jak to zrobić lepiej? – git commit –fixup
Wyobraźcie sobie, że w takiej sytuacji wcale nie musicie edytować git-rebase-todo
, bo jest narzędzie, które wszystko co trzeba zrobić automatycznie.
Wróćmy zatem do momentu, gdy wrzucamy pierwsze poprawki do review i zamiast zrobić zwykły git commit
użyjmy bohatera dzisiejszego artykułu czyli:
git commit --fixup 1f6fa91
Gdzie hash – 1f6fa91
, który widzicie odpowiada hashowi commita do którego dodajecie poprawki. Wówczas nasz git log
będzie wyglądał następująco:
Dodajmy pozostałe commity i wówczas będzie to wyglądało tak:
Jak fajnie! Nie trzeba już wymyślać nazw commitów – nazwy tworzą się same.
A teraz zwykły rebase?
Ostatecznie możemy teraz te commity scalić w jeden, tak jak robiliśmy to wcześniej, ale nie o to chodzi:) Teraz mamy do dyspozycji komendę:
git rebase --interactive --autosquash master
Wówczas pojawi nam się okienko z git-rebase-todo
i możemy je edytować albo zostawić tak jak jest i wówczas na koniec nasz git log
wygląda następująco:
Ale to nie jedyne fajne zastosowanie git commit –fixup
Inna sytuacja – zabieracie się do pracy nad jakimś zadaniem, ale wcześniej znaleźliście parę miejsc w kodzie, które można by ulepszyć i zdecydowanie powinny się znaleźć w osobnym commicie. Robicie zatem refaktoring, dodajecie commit z nim związany i ruszacie dalej z kopyta do pracy nad daną funkcjonalnością. Kodujecie, kodujecie, kodujecie i nagle pach! Jeszcze jedno miejsce, gdzie przydałby się refaktoring. No ale głupio tak wrzucić to do bieżącego commita, który dotyczy zadania nad którym pracujecie. Można wtedy utworzyć dodatkowy commit a następnie za pomocą git rebase
scalić go z tym pierwszym dotyczącym refaktoringu. Strasznie dużo roboty!
Da się inaczej? Da!
Niech nasz git log
wygląda następująco:
Ponieważ chcemy nasz kolejny commit tak naprawdę podpiąć pod ten związany z refaktoringiem, możemy zrobić tak:
git commit --fixup 6345e1
Znowu wykorzystujemy hash aby powiedzieć gitowi do jakiego commita ma podpiąć ten nowy. Co się teraz stanie z historią commitów:
Może się wydawać, że ten commit wskoczył w to samo miejsce co normalny, zwykły commit. Ale… git sobie z tym bardzo zręcznie poradzi jeśli tylko następnie użyjemy znanej nam już komendy:
git rebase --interactive --autosquash master
I git-rebase-todo
będzie miało commity w jak najbardziej prawidłowej kolejności:
W efekcie uzyskamy następującą historię:
Uwaga! Możliwe, że pojawią nam się tutaj konflikty, ale to nic strasznego – rozwiązujemy je tak jak normalne konflikty.
Porada
Nie musimy zawsze wpisywać --autosquash
, gdy chcemy skorzystać z tej funkcjonalności. Zamiast tego możemy skonfigurować gita aby robił scalał commity oznaczone jako fixup
automatycznie. Wystarczy wykorzystać następującą komendę:
git config rebase.autosquash true