Aby rozwinąć odpowiedź Bena Jacksona , która jest w porządku, przyjrzyjmy się uważnie pierwotnemu pytaniu. (Zobacz jego odpowiedź, aby dowiedzieć się, dlaczego zawracasz sobie głowę typowymi pytaniami; to więcej o tym, co się dzieje ).
Nie mam doświadczenia z kontrolą wersji i rozumiem, że „zatwierdzanie” to zasadniczo tworzenie kopii zapasowej podczas aktualizowania nowej „bieżącej” wersji tego, nad czym pracujesz.
To nie jest całkiem w porządku. Kopie zapasowe i kontrola wersji są z pewnością powiązane - dokładnie, jak bardzo zależy od pewnych rzeczy, które w pewnym stopniu są kwestiami opinii - ale z pewnością istnieją pewne różnice, choćby celowe: kopie zapasowe są zwykle zaprojektowane do odzyskiwania po awarii (awaria maszyny, pożar niszczy cały budynek wraz ze wszystkimi nośnikami pamięci itp.). Kontrola wersji jest zwykle zaprojektowana dla bardziej szczegółowych interakcji i oferuje funkcje, których nie ma w przypadku kopii zapasowych. Kopie zapasowe są zwykle przechowywane przez jakiś czas, a następnie odrzucane jako „zbyt stare”: aktualna kopia zapasowa to wszystko, co się liczy. Kontrola wersji normalnie zapisuje na zawsze każdą zatwierdzoną wersję.
Nie rozumiem, do czego służy inscenizacja z praktycznego punktu widzenia. Czy wystawianie czegoś, co istnieje tylko z nazwy, czy służy celowi? Kiedy się zgodzisz, i tak zrobisz wszystko, prawda?
Tak i nie. Projekt Gita jest tutaj dość osobliwy. Istnieją systemy kontroli wersji, które nie wymagają oddzielnego etapu przejściowego. Na przykład Mercurial, który pod względem użytkowania jest bardzo podobny do Gita, nie wymaga oddzielnego hg addkroku, poza pierwszym, który wprowadza całkowicie nowy plik. W przypadku Mercurial używasz hgpolecenia, które wybiera zatwierdzenie, następnie wykonujesz swoją pracę, następnie uruchamiasz hg commiti gotowe. W Git używaszgit checkout , 1, potem wykonujesz swoją pracę, potem uruchamiasz git add, a potem git commit. Dlaczego dodatkowy git addkrok?
Sekretem jest to, co Git nazywa różnie indeksem lub obszarem lub czasami - rzadko w dzisiejszych czasach - pamięcią podręczną . To są wszystkie nazwy dla tej samej rzeczy.
Edycja: Myślę, że mogę mylić terminologię. Czy plik „przemieszczany” to to samo, co plik „śledzony”?
Nie, ale te są powiązane. ZAŚledzone plik jest jeden, który istnieje w indeksie jest git. Aby właściwie zrozumieć indeks, dobrze jest zacząć od zrozumienia zatwierdzeń.
Od wersji 2.23 Gita możesz używać git switchzamiast git checkout. W tym konkretnym przypadku te dwie komendy robią dokładnie to samo. Nowe polecenie istnieje, ponieważ git checkoutzostało przepełnione zbyt wieloma rzeczami; zostały podzielone na dwie oddzielne komendy,git switch oraz git restore, aby ułatwić i bezpieczniej korzystać z Gita.
Commits
W Git, zatwierdzenie zapisuje pełną migawkę każdego pliku pliku, o którym Git wie. (O jakich plikach wie Git? Zobaczymy to w następnej sekcji.) Te migawki są przechowywane w specjalnej, tylko do odczytu, skompresowanej i pozbawionej duplikatów postaci, którą może odczytać tylko sam Git. . (W każdym zatwierdzeniu jest więcej rzeczy niż tylko ta migawka, ale to wszystko, co tutaj omówimy).
Usuwanie duplikatów pomaga w spacji: zwykle zmieniamy tylko kilka plików, a następnie wykonujemy nowe zatwierdzenie. Zatem większość plików w zatwierdzeniu jest w większości taka sama, jak pliki w poprzednim zatwierdzeniu. Po prostu ponownie wykorzystując te pliki bezpośrednio, Git oszczędza dużo miejsca: jeśli dotknęliśmy tylko jednego pliku, nowe zatwierdzenie zajmuje tylko miejsce na jedną nową kopię. Nawet wtedy jest skompresowany - czasami bardzo skompresowany, choć w rzeczywistości dzieje się to później - dzięki czemu .gitkatalog może być faktycznie mniejszy niż zawarte w nim pliki, gdy zostaną rozszerzone do zwykłych plików codziennego użytku. Usuwanie duplikatów jest bezpieczne, ponieważ zatwierdzone pliki są zamrożone na zawsze. Nikt nie może go zmienić, więc zatwierdzenie jest bezpieczne, jeśli zależy od kopii innych.
Ponieważ przechowywane pliki są w tym specjalnym, zamrożonym na zawsze formacie, dostępnym tylko dla Git, Git musi rozszerzyć każdy plik do zwykłej codziennej kopii. Ta zwykła kopia nie jest kopią Gita : jest twoją kopią, którą możesz robić, co chcesz. Git po prostu do nich napisze, gdy mu to powiesz, abyś miał swoje kopie do pracy. Te użyteczne kopie znajdują się w twoim drzewie roboczym lub roboczym .
Oznacza to, że kiedy sprawdzasz jakieś konkretne zatwierdzenie, automatycznie pojawiają się dwa kopie każdego pliku:
Git ma zamrożoną kopię przez cały czas Git-ified w bieżącym zatwierdzeniu . Nie możesz zmienić tej kopii (chociaż możesz oczywiście wybrać inny zatwierdzenie lub utworzyć nowe zatwierdzenie).
W swoim drzewie roboczym masz kopię w normalnym formacie. Możesz zrobić wszystko, co chcesz, używając dowolnego polecenia na swoim komputerze.
Inne systemy kontroli wersji (w tym Mercurial, jak wspomniano powyżej) zatrzymują się tutaj, z tymi dwoma kopiami. Po prostu zmodyfikuj swoją kopię drzewa roboczego, a następnie zatwierdź. Git ... nie.
Indeks
Pomiędzy tymi dwiema kopiami Git przechowuje trzecią kopię 2 każdego pliku. Ta trzecia kopia jest w formacie zamrożonym , ale w przeciwieństwie do kopii zamrożonej w zatwierdzeniu możesz ją zmienić. Aby to zmienić, używasz git add.
Te git addśrodki dowodzenia zrobić kopię indeksu pliku dopasować kopię praca drzewo . Oznacza to, że mówisz Gitowi: zastąp zamrożoną, pozbawioną duplikatów kopię, która jest teraz w indeksie, kompresując moją zaktualizowaną kopię drzewa roboczego, usuwając jej duplikaty i przygotowując ją do zamrożenia w nowym zatwierdzeniu. Jeśli nie używasz git add, indeks nadal zawiera kopię zamrożonego formatu z bieżącego zatwierdzenia.
Po uruchomieniu git commitGit pakuje wszystko, co jest w indeksie, a następnie używa jako nowej migawki. Ponieważ jest już w zamrożonym formacie i wstępnie zduplikowany, Git nie musi wykonywać dużo dodatkowej pracy.
To wyjaśnia również, o co chodzi w nieśledzonych plikach . Nieśledzony plik to plik, który znajduje się w twoim drzewie roboczym, ale nie znajduje się teraz w indeksie Git . Nie ma znaczenia, w jaki sposób plik został zlikwidowany w tym stanie. Może skopiowałeś go z innego miejsca na swoim komputerze, do swojego drzewa roboczego. Może stworzyłeś to świeżo tutaj. Może w indeksie Gita była kopia, ale usunąłeś tę kopię za pomocągit rm --cached . Tak czy inaczej, istnieje kopia w twoim drzewie roboczym, ale nie ma kopii w indeksie Gita. Jeśli zrobisz teraz nowe zatwierdzenie, ten plik nie będzie w nowym zatwierdzeniu.
Zauważ, że git checkoutpoczątkowo wypełnia indeks Gita z zatwierdzonego zatwierdzenia. Więc indeks zaczyna się dopasowywać do zatwierdzenia. Git również wypełnia twoje drzewo robocze z tego samego źródła. Tak więc początkowo wszystkie trzy pasują. Kiedy zmieniasz pliki w swoim drzewie roboczym i git addje, teraz indeks i drzewo robocze są zgodne. Następnie uruchamiasz git commiti Git tworzy nowe zatwierdzenie z indeksu, a teraz wszystkie trzy pasują ponownie.
Ponieważ Git tworzy nowe zatwierdzenia z indeksu, możemy przedstawić to w ten sposób: indeks Gita przechowuje następny commit, który planujesz wykonać. To ignoruje rozszerzoną rolę, jaką odgrywa indeks Gita podczas scalania z konfliktem, ale i tak chcielibyśmy to na razie zignorować. :-)
To wszystko - ale wciąż jest to dość skomplikowane! Jest to szczególnie trudne, ponieważ nie ma łatwego sposobu, aby dokładnie sprawdzić, co znajduje się w indeksie Gita. 3 Ale jest polecenie Git, które mówi ci, co się dzieje, w bardzo przydatny sposób, i to polecenie jest git status.
2 Technicznie rzecz biorąc, to wcale nie jest kopia . Zamiast tego jest to odniesienie do pliku Git-ified, wstępnie zdeduplikowanego i wszystkiego. Jest tu również więcej rzeczy, takich jak tryb, nazwa pliku, numer tymczasowy i niektóre dane z pamięci podręcznej, aby Git działał szybko. Ale jeśli nie zaczniesz pracować z niektórymi poleceniami niskiego poziomu Gita - git ls-files --stageigit update-index w szczególności-można tylko myśleć o nim jako kopia.
3git ls-files --stage komenda pokaże nazwy i numery inscenizacji każdego pliku indeksu git, ale zwykle nie jest to bardzo przydatne w każdym razie.
git status
Plik git status rzeczywistości polecenie działa, uruchamiając dwa oddzielne git diffpolecenia (a także wykonując inne przydatne rzeczy, takie jak wskazanie, w której gałęzi się znajdujesz).
Pierwsza git diffporównuje aktualne zatwierdzenie - które, pamiętaj, jest zamrożone na zawsze - z tym, co znajduje się w indeksie Gita. W przypadku plików, które są takie same , Git w ogóle nic nie powie. W przypadku plików, które są różne , Git poinformuje Cię, że ten plik jest przygotowywany do zatwierdzenia . Obejmuje to wszystkie nowe pliki, jeśli popełnić nie ma sub.pyw nim, ale indeks musi miećsub.py w nim, a następnie ten plik zostanie dodana i żadnych usuniętych plików, które były (i są) w popełnić, ale nie są w indeks już ( git rmbyć może).
Drugi git diffporównuje wszystkie pliki w indeksie Gita z plikami w twoim drzewie roboczym. W przypadku plików, które są takie same , Git nic nie mówi. W przypadku plików, które są różne , Git poinformuje Cię, że ten plik nie jest przygotowywany do zatwierdzenia . W przeciwieństwie do pierwszego porównania, ta konkretna lista nie zawiera plików, które są całkowicie nowe: jeśli plik untrackedistnieje w twoim drzewie roboczym, ale nie w indeksie Git, Git po prostu dodaje go do listy nieśledzonych plików . 4
Na końcu, po zgromadzeniu tych nieśledzonych plików na liście, git statusogłosi również nazwy tych plików, ale jest specjalny wyjątek: jeśli nazwa pliku jest wymieniona w .gitignorepliku, to pomija tę ostatnią listę. Zwróć uwagę, że umieszczenie śledzonego pliku - takiego, który jest w indeksie Gita - w a .gitignorenie ma tu żadnego wpływu : plik znajduje się w indeksie, więc jest porównywany i zatwierdzany, nawet jeśli jest wymieniony w .gitignore. Plik ignorowania pomija tylko skargi dotyczące „pliku nieśledzonego”. 5
4 W przypadku korzystania z krótkiej wersji git status- git status -s—nieśledzone pliki nie są tak oddzielone, ale zasada jest taka sama. Gromadzenie plików w ten sposób pozwala również git statuspodsumować kilka nazw plików bez śledzenia, czasami po prostu drukując nazwę katalogu. Aby uzyskać pełną listę, użyj git status -ualllub git status -u.
5 Wyświetlanie pliku powoduje również masowe dodawanie wielu operacji na plikach , takich jak git add .lub git add *pomijanie nieśledzonego pliku. Ta część staje się trochę bardziej skomplikowana, ponieważ możesz użyć git add --forcedo dodania pliku, który normalnie zostałby pominięty. Istnieją inne, zwykle drobne, specjalne przypadki, które sumują się do tego: plik .gitignoremoże być lepiej nazwany .git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-themlub coś równie nieporęcznego. Ale to zbyt śmieszne, więc .gitignoretak jest.
git add -u, git commit -a Itp
Jest kilka przydatnych skrótów, o których warto wiedzieć:
git add .doda wszystkie zaktualizowane pliki w bieżącym katalogu i dowolnym podkatalogu. Szanuje to .gitignore, więc jeśli plik, który obecnie nie jest śledzony, nie jest przedmiotem reklamacji git status, nie zostanie automatycznie dodany.
git add -uautomatycznie doda wszystkie zaktualizowane pliki w dowolnym miejscu twojego drzewa roboczego . 6 Dotyczy to tylko śledzonych plików. Zauważ, że jeśli usunąłeś kopię drzewa roboczego, spowoduje to również usunięcie kopii indeksu ( git addrobi to jako część jego dopasowania indeksu do drzewa roboczego ).
git add -Ajest jak bieganie git add .z najwyższego poziomu twojego drzewa roboczego (ale zobacz przypis 6).
Poza tym możesz biegać git commit -a, co z grubsza odpowiada 7 bieganiu, git add -ua następnie git commit. Oznacza to, że uzyskujesz to samo zachowanie, które jest wygodne w Mercurial.
Generalnie odradzam git commit -awzorzec: uważam, że lepiej jest git statusczęsto go używać , uważnie przyjrzeć się wynikowi , a jeśli stan nie jest taki, jakiego się spodziewałeś, dowiedz się, dlaczego tak jest. Używając git commit -a, zbyt łatwo jest przypadkowo zmodyfikować plik i zatwierdzić zmianę, której nie zamierzałeś zatwierdzić. Ale to głównie kwestia gustu / opinii.
6 Jeśli Twoja wersja Gita jest starsza niż Git 2.0, bądź ostrożny: git add -udziała tylko w bieżącym katalogu i podkatalogach, więc najpierw musisz wspiąć się na najwyższy poziom swojego drzewa roboczego. Plikgit add -AOpcja ma podobny problem.
7 Mówię z grubsza równoważne, ponieważ git commit -afaktycznie działa poprzez utworzenie dodatkowego indeksu i użycie tego innego indeksu do wykonania zatwierdzenia. Jeśli zatwierdzenie zadziała , uzyskasz taki sam efekt jak zrobienie git add -u && git commit. Jeśli zatwierdzenie nie zadziała - jeśli sprawisz, że Git pominie zatwierdzenie na dowolny z wielu sposobów, które możesz to zrobić - wtedy żadne pliki nie są git addpóźniej -edowane, ponieważ Git wyrzuca tymczasowy dodatkowy indeks i wraca do używania indeksu głównego .
Istnieją dodatkowe komplikacje, które pojawiają się, jeśli używasz git commit --onlytutaj. W tym przypadku Git tworzy trzeci indeks i sprawy stają się bardzo skomplikowane, szczególnie jeśli używasz punktów zaczepienia przed zatwierdzeniem. To kolejny powód, aby używać oddzielnych git addoperacji.