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ć?

git status w cmder

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.

Tryby pliku w Git repozytorium

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

git add -i czyli dodawanie do staged

W tym trybie interaktywnym mamy wiele opcji. W tym przypadku interesuje mnie opcja "patch".

Dodanie pliku do staged

Wybieram opcją "1" plik, który chce rozbić. 

Patch git add

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ć.

git add -i pomoc

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.

Ignorowanie kolejnej zmiany w Git

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.

git status czyli co jest i czego nie ma w staged

Pozostaje mi zrobić commita.

git commit

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.

git add -i zmiana koloru w system.xml

Teraz jak widzisz, Git nie wydzielił za nas fragmentów. Co ciekawe, gdy skorzystasz z pomocy "?" to zobaczysz, że mamy nową opcję.

pomoc i split w git add -i

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.

Wybór fragmentu kodu

W taki sposób mogę zrobić commita tylko do tej zmiany

Kolejny commit

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.

git add -p Patch Git