Alle Dateien in pl geprüft2
[gitmagic.git] / szl / grandmaster.txt
blob32860b4609d7576b9bbf8c4b5b8dbd7f3a02a652
1 == Git dla zaawansowanych ==
3 W międzyczasie powinnaś umieć odnaleźć się na stronach *git help* i rozumieć większość zagadnień. Mimo to może okazać się dość mozolne odnalezienie odpowiedniej komendy dla rozwiązania pewnych zadań. Może uda mi się zaoszczędzić ci trochę czasu: poniżej znajdziesz kilka recept, które były mi przydatne w przeszłości.
5 === Publikowanie kodu źródłowego ===
7 Git zarządza w moich projektach dokładnie tymi danymi, które chcę archiwizować i dać do dyspozycji innym użytkownikom. Aby utworzyć archiwum tar kodu źródłowego, używam polecenia
9  $ git archive --format=tar --prefix=proj-1.2.3/ HEAD
11 === Zmiany dla 'commit' ===
13 Powiadomienie Gita o dodaniu, skasowaniu czy zmianie nazwy plików może okazać sie przy niektórych projektach dość uciążliwą pracą. Zamiast tego można skorzystać z:
15  $ git add . 
16  $ git add -u
18 Git przyjży się danym w aktualnym katalogu i odpracuje sam szczegóły. Zamiast tego drugiego polecenia możemy użyć `git commit -a`, jeśli i tak mamy zamiar przeprowadzić 'comit'.  Sprawdź też *git help ignore*, by dowiedzieć się jak zdefiniować dane, które powinny być zignorowane.
20 Można to także wykonać za jednyym zamachem:
22  $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove
24 Opcje *-z* i *-0* zapobiegą przed niechcianymi efektmi ubocznymi przez niestandardowe znaki w nazwach plików. Ale ponieważ to polecenie dodaje również pliki które powinny być zignorowane, można dodać do niego jeszcze opcje `-x` albo `-X` 
26 === Mój 'commit' jest za duży! ===
28 Od dłuższego czasu nie pamiętałeś o wykonaniu 'commit'? Tak namiętnie programowałeś, że zupełnie zapomniałeś o kontroli kodu źródłowego? Przeprowadzasz serię niezależnych zmian, bo jest to w twoim stylu?
30 Nie ma sprawy, wpisz polecenie:
32  $ git add -p
34 Dla każdej zmiany, której dokonałeś Git pokaże ci pasaże z kodem, który uległ zmianom i spyta cię, czy mają zostać częścią następnego 'commit'. Odpowiedz po prostu "y" dla tak, albo "n" dla nie. Dysponujesz jeszcze innymi opcjami, na przykład dla odłożenie w czasie decyzji, wpisz "?", by dowiedzieć się więcej.
36 Jeśli jesteś już zadowolony z wyniku, wpisz:
38  $ git commit
40 by dokonać wybranych zmian. Uważaj tylko, by nie skorzystać z opcji *-a*, ponieważ wtedy git dokona 'commit' zawierający wszystkie zmiany.
42 A co, jeśli pracowałeś nad wieloma danymi w wielu różnych miejscach? Sprawdzenie każdej danej z osobna jest frustrujące i męczące zarówno. W takim wypadku skorzystaj z *git add -i*, obsługa tego polecenia może nie jest zbyt łatwa, za to jednak bardzo elastyczna. Kilkoma naciśnięciami klawiszy możesz wiele zmienionych plików dodać ('stage') albo usunąć z 'commit' ('unstage'), jak również sprawdzić, czy dodać zmiany dla poszczególnych plików. Alternaywnie możesz skorzystać z *git commit \--interactive*, polecenie to wykona automatycznie 'commit' gdy skończysz.
44 === Index: rusztowanie Gita ===
46 Do tej pory staraliśmy się omijać sławny 'index', jednak przyszedł czas się nim zająć, aby móc wyjaśnić wszystko to co poznaliśmy do tej pory. Index jest tymczasowym rusztowaniem Git rzadko wymienia dane bezpośrednio między twoim projektem a swoją historią wersji. Raczej zapisuje on dane najpierw w indexie, dopiero po tym kopiuje dane z indexu na ich właściwe miejsce przeznaczenia.
48 Na przykład polecenie *commit -a* jest właściwie procesem dwustopniowym. Pierwszy krok to stworzenie obrazu bieżącego statusu każdego monitorowanego pliku do indeksu.  Drugim krokiem jest trwałe zapamiętanie obrazu do indeksu. Wykonanie 'commit' bez opcji *-a* wykona jedynie drugi wspomniany krok i ma jedynie sens, jeśli poprzednio wykonano komendę, która dokonała odpowiednich zmian w indexie, na przykład *git add*.
50 Normalnie możemy ignorować indeks i udawać, że czytamy i zapisujemy bezpośrednio z historii. W tym wypadku chcemy posiadać jednak większą kontrolę, więc manipulujemy indeks. Tworzymy obraz niektórych, jednak nie wszystkich zmian w indeksie i zapamiętujemy trwale starannie dobrany obraz.
52 === Nie trać głowy ===
54 Identyfikator 'HEAD' zachowuje się jak kursor, który zwykle wskazuje na najmłodszy 'commit' i z każdym nowym 'commit' zostaje przesunięty do przodu. Niektóre komendy Gita pozwolą ci nim manipulować. Na przyklad:
56  $ git reset HEAD~3
58 przesunie identyfikator 'HEAD' o 3 'commits' spowrotem. Spowoduje to, że wszystkie następne komendy Gita będą reagować, jakby tych trzech ostatnich 'commits' wogóle nie było, podczas gdy twoje dane zostaną w przyszłości. Na stronach pomocy Gita znajdziesz więcej takich zastosowań.
60 Ale jak teraz wrócić znów do przyszłości? Poprzednie 'commits' nic nie wiedzą o jej istnieniu.
62 Jeśli posiadasz klucz SHA1 orginalnego 'HEAD', wtedy możesz wrócić komendą:
64  $ git reset 1b6d
66 Wyobraź jednak sobie, że nigdy go nie notowałeś? Nie ma sprawy: Przy wykonywaniu takich poleceń Git archiwizuje orginalny HEAD jako indentyfikator o nazwie ORIG_HEAD a ty możesz bezproblemowo wrócić używając:
68  $ git reset ORIG_HEAD
70 === Łowcy głów ===
72 Może się zdarzyć, że ORIG_HEAD nie wystarczy. Może właśnie spostrzegłeś, iż dokonałeś kapitalnego błędu i musisz wrócić się do bardzo starego 'commit' w zapomnianym 'branch'.
74 Standardowo Git zapamiętuje 'commit' przez przynajmniej 2 tygodnie, nawet jeśli poleciłeś zniszczyć 'branch' w którym istniał. Problemem staje się tutaj odnalezienie odpowieniego klucza SHA1. Możesz po kolei testować wszystkie klucze SHA1 w `.git/objects` i w ten sposób próbować odnaleźć szukany 'commit'. Istnieje jednak na to dużo prostszy sposób.
76 Git zapamiętuje każdy obliczony klucz SHA1 dla odpowiednich 'commit' w `.git/logs`. Podkatalog `refs` zawieza przebieg wszystkich aktywności we wszystkich 'branches', podczas gdy plik `HEAD` wszystkie klucze SHA1 które kiedykolwiek posiadał.  Ostatnie możemy zastosować do odnalezienia kluczy SHA1 tych 'commits' które znajdowały się w nieuważnie usuniętym 'branch'.
78 Polecenie 'reflog' daje nam do dyspozycji przyjazny interfejs do tych właśnie logów. Wypróbuj polecenie:
80  $ git reflog
82 Zamiast kopiować i wklejać klucze z 'reflog', możesz:
84  $ git checkout "@{10 minutes ago}"
86 Albo przywołaj 5 z ostatnio oddwiedzanych 'commits' za pomocą:
88  $ git checkout "@{5}"
90 Jeśli chciałbyś pogłębić wiedze na ten temat przeczytaj sekcję ``Specifying Revisions`` w  *git help rev-parse*.
92 Byś może zechcesz zmienić okres karencji dla przeznaczonych na stracenie 'commits'. Na przyklad:
94  $ git config gc.pruneexpire "30 days" 
96 znaczy, że skasowany 'commit' zostanie nieuchronnie utracony dopiero po 30 dniach od wykonania polecenia *git gc*.
98 Jeśli chcałbyś zapobiec automatyycznemu wykonywaniu *git gc*:
100  $ git config gc.auto 0 
102 wtedy 'commits' będą tylko wtedy usuwane, gdy ręcznie wykonasz polecenie *git gc*.
104 === Budować na bazie Gita ===
106 W prawdziwym unixowym świecie sama konstrukcja Gita pozwala na wykorzystanie go, jako komponent niskiego poziomu, przez inne aplikacje, jak na przykład interfejsy graficzne i aplikacje internetowe, alternatywne narzędzia konsoli, narzędzia patchujące, narzędzia pomocne w importowaniu i konwertowaniu i tak dalej. Nawek same polecenia git są czasami malutkimi skryptami, jak krasnoludki na ramieniu olbrzyma. Przykładając trochę ręki możesz adoptować Git do twoich własnych potrzeb.
108 Prostą sztuczką może być korzystanie z zintegrowanej w git funkcji aliasu, by skrócić najczęściej stosowane polecenia:
110  $ git config --global alias.co checkout
111  $ git config --global --get-regexp alias  # wyświetli aktualne aliasy
112  alias.co checkout
113  $ git co foo                              # to samo co 'git checkout foo' 
115 Czymś troszeczkę innym będzie zapis nazwy aktualnego 'branch' w prompcie lub jako nazwy okna. Polecenie:
117  $ git symbolic-ref HEAD 
119 pokaże nazwę aktualnego 'branch'. W praktyce chciałbyś raczej usunąć "refs/heads/" i ignorować błędy:
121  $ git symbolic-ref HEAD 2> /dev/null | cut -b 12- 
123 Podkatakog +contrib+ jest wielkim znaleziskiem narzędzi zbudowanych dla git. Z czasem niektóre z nich mogą uzyskać status oficjalnych poleceń. W dystrybucji Debian i Ubuntu znajdziemy ten katalog pod +/usr/share/doc/git-core/contrib+.
125 Ulubionym przedstawicielem jest +workdir/git-new-workdir+. Poprzez sprytne przelinkowania skrypt ten tworzy nowy katalog roboczy, który dzieli swoją historię wersji z orginalnym repozytorium:
127  $ git-new-workdir istniejacy/repo nowy/katalog
129 Ten nowy katalog i znajdujące się w nim pliki można sobie wyobrazić jako klon, z tą różnicą, że ze względu na wspólną niepodzieloną historie obje wersje pozostaną zsynchronizowane.  Synchronizacja za pomocą  'merge', 'push', czy 'pull' nie będzie konieczna.
131 === Śmiałe wyczyny ===
133 Obecnie Git dość dobrze chroni użytkownika przed przypadkowym zniszczeniem danych. Ale, jeśli wiemy co robić, możemy obejść środki ochrony najczęściej stosowanych poleceń.
135 *Checkout*: nie wersjonowane zmiany doprowadzą do niepowodzenia polecenia 'checkout'. Aby mimo tego zniszczyć zmiany i przywołać istniejący 'commit', możemy skorzystać z opcji 'force':
137  $ git checkout -f HEAD^ 
139 Jeśli poleceniu 'checkout' podamy inną ścieżkę, środki ochrony nie znajdą zastosowania. Podana ścieżka zostanie bez pytania zastąpiona. Bądź ostrożny stosując 'checkout' w ten sposób.
141 *reset*: reset odmówi pracy, jeśli znajdzie niewersjonowane zmiany.  By zmusić go do tego, możesz użyć:
143  $ git reset --hard 1b6d 
145 *Branch*: Skasowanie 'branches' też się nie powiedzie, jeśli mogłyby przez to zostać utracone zmiany. By wymusić skasowanie, podaj:
147  $ git branch -D martwy_branch # zamiast -d
149 Również nie uda się próba przesunięcia 'branch' poleceniem 'move', jeśliby miałoby to oznaczać utratę danych. By wymusić przesunięcie, podaj:
151  $ git branch -M źródło cel # zamiast -m
153 Inaczej niż w przypadku 'checkout' i 'reset', te oba polecenia przesuną zniszczenie danych. Zmiany te zostaną zapisane w podkatalogu .git i mogą znów zostać przywrócone, jeśli znajdziemy odpowiedni kluch SHA1 w `.git/logs` (zobacz "Łowcy głów" powyżej).  Standardowo dane te pozostają jeszcze przez 2 tygodnie.
155 *clean*: Różnorakie polecenia Git nie chcą się zadziałać, ponieważ podejżewają konflikty z niewersjonowanymi danymi. Jeśli jesteś pewny, że wszystkie niezwersjonowane pliki i katalogi są zbędne, skasujesz je bezlitośnie poleceniem: 
157  $ git clean -f -d 
159 Następnym razem te uciążliwe polecenia zaczną znów być posłuszne.
161 === Zapobiegaj złym 'commits' ===
163 Głupie błędy zaśmiecają moje repozytoria. Najbardziej fatalny jest brak plików z powodu zapomnianych *git add*. Mniejszymi usterkami mogą być spacje na końcu linii i nierozwiązane konflikty poleceń 'merge': mimo iż nie są groźne, życzyłbym sobie, by nigdy nie wystąpiły publicznie.
165 Gdybym tylko zabezpieczył się wcześniej, stosując prosty _hook_, który alarmowałby mnie przy takich problemach.
167  $ cd .git/hooks
168  $ cp pre-commit.sample pre-commit  # Starsze wersje Gita wymagają jeszcze: chmod +x pre-commit
170 I już 'commit' przerywa, jeśli odkryje niepotrzebne spacje na końcu linii albo nierozwiązane konflikty 'merge'.
172 Na początku *pre-commit* tego 'hook' umieściłbym dla ochrony przed rozdrobnieniem:
174  if git ls-files -o | grep '\.txt$'; then
175    echo FAIL! Untracked .txt files.
176    exit 1
177  fi 
179 Wiele operacji Gita pozwala na używanie 'hooks'; zobacz też: *git help hooks*.  We wcześniejszcm rozdziale "Git poprzez http" przytoczyliśmy przykład 'hook' dla *post-update*, który wykonywany jest zawsze, jeśli znacznik 'HEAD' zostaje przesunięty. Ten przykładowy skrypt 'post-update' aktualizuje dane, które potrzebne są do komunikacji poprzez 'Git-agnostic transports', jak na przykład HTTP.