Efektywne polecenia Git
Istnieją przynajmniej trzy bardzo ważne rzeczy, o których każdy szanujący się programista powinien mieć dobre pojęcie. Jest to: dobra znajomość swojego edytora kodu, jeszcze lepsze zrozumienie systemu kontroli wersji oraz podstawowa znajomość dowolnego języka skryptowego. Obecnie nasze IDE staje się często takim scyzorykiem szwajcarskim, który wykorzystujemy (jeśli znamy go dosyć dobrze) praktycznie wszędzie. Czasami jednak okazuje się, że niekoniecznie zapewnia ono wszystko, czego moglibyśmy potrzebować. Często to właśnie te podstawowe narzędzia, do których dostęp (poprzez pewną nakładkę-interfejs) zapewnia nam IDE, pozwalają nam na znacznie większą kontrolę w realizacji postawionych celów.
Tak więc, dobra znajomość systemu kontroli wersji oraz jego standardowego klienta pozwoli Ci na zwiększenie produktywności w wielu przypadkach. Dodatkowym plusem jest to, że wiedzę tą wykorzystasz również po zmianie swojego ulubionego IDE. W przypadku innego środowiska interfejs niekoniecznie musi być taki sam, a znajomość podstawowego klienta systemu kontroli wersji zapewni Ci zachowanie dotychczasowej produktywności.
Dzisiaj pokażę Ci najbardziej użyteczne polecenia gitowe, których sam używam w codziennej pracy. Pominę w tym miejscu podstawowe komendy, dlatego jeśli nie masz jeszcze podstawowej wiedzy o Gicie, polecam krótki przewodnik Rogera Dudlera. Wracając do tematu, każde polecenie można wpisać na stronie explainshell (niestety jedynie w języku angielskim), aby otrzymać dokładniejszy opis poszczególnych elementów komendy (bez kontekstu). Dokumentację Gita (również w języku angielskim) można znaleźć tutaj.
Polecenie | Opis | Uwaga |
---|---|---|
git log --pretty=format:"%h | A: %aN/%ad | C: %cN/%cd | %s" --date=format:"%y-%m-%d %H:%M:%S"
|
Wyświetla sformatowane logi commitów:
| |
git log --all --graph --decorate --oneline
| Wyświetla ładnie sformatowaną historię commitów w jednej linii wraz z grafem w formie tekstowej. | |
git log [a]..[b]
|
Pokazuje commity pomiędzy dwoma tagami/commitami/gałęziami:
| |
git reflog
|
Wyświetla logi odniesienia lokalnego repozytorium oraz aktualizacje końcówki gałęzi (HEAD). Przydatne w celu:
| |
git diff [a]..[b] --name-only
|
Wyświetla nazwy plików, które zostały zmienione pomiędzy a i b. Przydatne do:
| |
git pull --rebase origin master
| Zaciąga mastera z repozytorium zdalnego (w domyśle origin) i rebase'uje zmiany względem niego. |
|
git merge -X [theirs|ours] feature
| Merguje gałąź z funkcjonalnością (feature) z obecną gałęzią przy wykorzystaniu standardowej strategii rekursywnej i w przypadku konfliktów, aplikuje nasze/ich (feature) zmiany. | Konflikty są pomocne w prawidłowym utrzymywaniu i mergowaniu przecinających się funkcji. |
git checkout feature && git merge -s ours master && git checkout master && git merge feature
|
Nadpisuje mastera branchem feature bez zmiany historii:
| |
git commit --date=relative.1.day.ago
| Zacommitowanie z datą autora ustawioną wstecz o jeden dzień. | |
git commit --date "$(date -d 24hours)"
|
Zacommitowanie z datą autora ustawioną w przód o jeden dzień:
| |
git commit --amend
|
Dodaj zmiany poleceniem (git add ) przed wykonaniem tego polecania w celu ponownego użycia ostatniego commita (np. gdy zapomniałeś/aś czegoś dodać bądź usunąć):
| Zmienia historię. |
git rebase --committer-date-is-author-date HEAD~1
| Wywołuje nieinteraktywny rebase w celu zmiany daty zatwierdzenia na datę autora ostatniego commita. | Zmienia historię. |
git reset --hard [commit]
|
Resetuje indeks i drzewo robocze do określonego punktu. Użyj:
| Może zmienić historię. |
git reset --soft HEAD~
| Usuwa ostatniego commita i zachowuje zacommitowane pliki. | Zmienia historię. |
git revert [commit]
|
Cofa konkretnego commita poprzez dodanie nowego. Użyj:
| Może spowodować konflikty. |
git checkout inny-branch -- path/to/a/file
| Kopiuje plik z gałęzi inny-branch do obecnego drzewa roboczego. | |
git stash [|apply|pop|list|drop]
| Wygodny sposób na tymczasowe przechowanie niedokończonej (dodanej poleceniem git add ) pracy podczas przełączania gałęzi. | |
git checkout .
| Cofa zmiany niedodane do przyszłego commita. | |
git clean -df
|
Usuwa nieśledzone (untracked) pliki i foldery (
-x
usuwa również pliki ignorowane).
|
Może usunąć pliki nieprzeznaczone do usunięcia. Rozważ użycie:
|
git rebase -i [commit]
|
Uruchamia interaktywny rebase do zdefiniowanego commita lub brancha. Co więcej:
| Zmienia historię. |
git cherry-pick -x [commit]
| Aplikuje wybrany commit do obecnej gałęzi z dodatkowym komunikatem o źródle commita. Użyj:
| Może skutkować konfliktami. |
git filter-branch --env-filter 'export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"'
| Przepisuje całą gałąź resetując datę commita do daty autora. | Zmienia historię. |
git bisect start git bisect bad [|bad_commit] git bisect good [|good_commit] git bisect reset
| Metoda bisekcji pomaga znaleźć źródło błędu wykrytego podczas testów regresji, za pomocą zasady dziel i zwyciężaj:
| |
gitk --follow [filename]
|
Wyświetla listę commitów dla danej ścieżki/pliku w postaci grafu, podążając za zmianami nazw plików. Przydatne do:
|
Różnica między ^
i ~
w połączeniu z danym commitem jest niewielka, ale zauważalna:
- commit~ to nawiązanie do pierwszego rodzica danego commita;
- commit~2 to nawiązanie do commita który jest pierwszym rodzicem pierwszego rodzica danego commita;
- commit^ to nawiązanie do pierwszego rodzica danego commita;
- commit^2 to nawiązanie do drugiego rodzica danego commita.
W przypadku pojawienia się błędu podczas używania HEAD^1, twoja powłoka być może interpretuje znak ^
jako kontynuacja nowej linii. W takim przypadku użyj "HEAD^".
Oto ilustracja autorstwa Jona Loeligera. Oba commity B i C są rodzicami commita A. Commity-rodzice są uporządkowane od lewej do prawej.
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2 = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
Istnieją również inne sposoby odwoływania się do wersji, takie jak master@{yesterday}
, @{push}
, /"naprawiono jakiś błąd"
. Możesz przeczytać więcej na ten temat w dokumentacji o git rev-parse. Ostatnią rzeczą, na którą chciałbym zwrócić uwagę, jest to, że istnieje różnica między zakresem zdefiniowanym przez podwójne kropki i potrójne kropki. Spójrz na wykresy na blogu Chucka Lu, aby zauważyć rozbieżność.