git add -iTrik. 1 W tym wpisie pokaże ci jak, możesz decydować o tym, co wejdzie do danego commita, a co nie. Same polecenia Git to potężne narzędzia i tak może to wszystko zrobić w konsoli.
Dlaczego chciałbyś rozbijać swoje zmiany na pojedyncze commity? Otóż duże commity, które zawierają wiele zmian, są antywzorcem. Gdybyś chciał cofnąć konkretną zmianę, która siedzi częściowo w jednym commicie, to możesz sobie wyobrazić, ile problemów to stworzy.
Dlatego warto robić jeden commit to jednej konkretnej wspólnej zmiany. Zobaczmy, jak to możesz zrobić w konsoli i przy użyciu Git.
W swoim repozytorium Git mam taki plik XML. Nazywa się on system.xml
<?xml version="1.0" encoding="utf-8"?>
<System>
<Admins>
<User>Czarek</User>
<User>Czarek</User>
</Admins>
<Moderators>
<User>Paweł</User>
</Moderators>
<Users>
<User>Kamil</User>
</Users>
<Colors>
<Reds>
<Value>#c36c6c</Value>
</Reds>
<Blues>
<Value>#48669c</Value>
</Blues>
</Colors>
<Money>
</Money>
<DecimalFormat>
</DecimalFormat>
</System>
Teraz chciałbym w jednym commit zrobić taką zmianę i nazwą ją bym "Deleting Money i DecimalFormat".
<?xml version="1.0" encoding="utf-8"?>
<System>
<Admins>
<User>Czarek</User>
<User>Czarek</User>
</Admins>
<Moderators>
<User>Paweł</User>
</Moderators>
<Users>
<User>Kamil</User>
</Users>
<Colors>
<Reds>
<Value>#c36c6c</Value>
</Reds>
<Blues>
<Value>#48669c</Value>
</Blues>
</Colors>
</System>
A drugim commicie usunąć powtórzony rekord Admin Cezary. Nazwałbym ten commit "Removing Duplication of Admin XmlElement"
<?xml version="1.0" encoding="utf-8"?>
<System>
<Admins>
<User>Czarek</User>
</Admins>
<Moderators>
<User>Paweł</User>
</Moderators>
<Users>
<User>Kamil</User>
</Users>
<Colors>
<Reds>
<Value>#c36c6c</Value>
</Reds>
<Blues>
<Value>#48669c</Value>
</Blues>
</Colors>
<Money>
</Money>
<DecimalFormat>
</DecimalFormat>
</System>
Jak to zrobić? Oczywiście możesz wprowadzić jedną zmianę do pliku zrobić commita, a potem zrobić drugą zmianę i zrobić kolejnego commita.
Często jednak jako programista pracujemy równocześnie nad wieloma problemami naraz, więc wyobraźmy sobie, że mam już za edytowany plik w taki sposób.
<?xml version="1.0" encoding="utf-8"?>
<System>
<Admins>
<User>Czarek</User>
</Admins>
<Moderators>
<User>Paweł</User>
</Moderators>
<Users>
<User>Kamil</User>
</Users>
<Colors>
<Reds>
<Value>#c36c6c</Value>
</Reds>
<Blues>
<Value>#48669c</Value>
</Blues>
</Colors>
</System>
Teraz chcemy skorzystać z Git-a w taki sposób, aby wydzielić nasze zmiany w tym jednym pliku na dwa commity. Jak to można zrobić?
Gdy wybierzemy opcję git status. Dostaniemy informację o tym, że nasz plik system.xml został zmodyfikowany.
W repozytorium Git plik może być w trzech fazach. Na razie nasz plik system.xml istnieje w folderze pracy, ale nie jest on przygotowany "staged" do commita.
Oczywiście możemy wpisać polecenie git add, a potem git commit, ale chcemy wydzielić nasze zmiany na dwa commit-y. Jak to zrobić.
Skorzystajmy z polecenia git add -i
W tym trybie interaktywnym mamy wiele opcji. W tym przypadku interesuje mnie opcja "patch".
Wybieram opcją "1" plik, który chce rozbić.
Jak widzisz, Git jest na tyle inteligenty, że rozbił już on moje zmiany. Nie zawsze tak jest i to też omówimy. Pyta on się mnie czy ta zmiana powinna przejść do trybu Staged.
Mogę wybrać "y" jako Tak i opcję "n" jako Nie. Co jednak robią pozostałe opcje? Zawsze możesz wybrać opcję "?" i sprawdzić.
q : sprawi, że wyjdziemy z tego procesu i nie zrobimy absolutnie nic
a : wszystkie wydzielone zmiany z tego pliku zostaną automatycznie scalone i dodane
d : nie dodaje do trybu stage zmian z tego pliku
g : pozwala na wybrać odpowiedni fragment kodu do procesu stage
/ : używając regex możesz dodać odpowiedni fragment do procesu stage
j : zostaw ten fragment na później. Chce zobaczyć kolejny fragment, na którym nie wykonałem decyzji
J : zostaw to na później chce zobaczyć kolejny fragment
e : manualnie z edytuj obecny fragment
W tym przypadku interesuje nas opcja "n". Nie chcemy na razie dodać tego fragmentu do staged.
Drugi fragment mnie interesuje, więc wybieram opcję "y". Teraz gdy wybiorę opcję "git status", to mogę zobaczyć, że tylko fragment system.xml został wysłany do trybu staged.
Pozostaje mi zrobić commita.
Teraz analogicznie mogę dodać kolejną zmianę do trybu staged i zrobić commita.
Powiedzmy jednak, że chce skasować Moderatorów i usunąć kolor czerwony z mojego pliku XML.
<?xml version="1.0" encoding="utf-8"?>
<System>
<Admins>
<User>Czarek</User>
</Admins>
<Users>
<User>Kamil</User>
</Users>
<Colors>
<Blues>
<Value>#48669c</Value>
</Blues>
</Colors>
</System>
Postarałem się też, aby to zmianę wykonać za jednym zapisem pliku. Dlaczego? To spowoduje pewien problem.
Teraz jak widzisz, Git nie wydzielił za nas fragmentów. Co ciekawe, gdy skorzystasz z pomocy "?" to zobaczysz, że mamy nową opcję.
Pojawiła się opcja split. Skorzystajmy z niej, aby wydzielić nasze zmiany na inne fragmenty. Zobaczysz, że ta jedna zmiana została wydzielona na 2 fragmenty. Dodatkowo mamy 1 fragment, który nie dodaliśmy do commitu poprzednim razem.
Teraz tak jak zrobiliśmy, to wcześniej możemy określić które zmiany mają dostać się do trybu staged. Mogę np. tę zmianę odrzucić i dodać tylko zmianę związaną z moderatorami.
W taki sposób mogę zrobić commita tylko do tej zmiany
Myślę, że na podstawie tych przykładów już wiesz jak dodawać tylko wybrane zmiany do commit-a. Miłego Git-owania.
Warto zaznaczyć, że cały proces można przyspieszyć poleceniem "git add -p", który od razu przejdzie do procesu dodawania tylko fragmentów kodu.