Dlaczego zatwierdzenia git nie zawierają nazwy gałęzi, w której zostały utworzone?

20

Podczas pracy z git w zespole używającym gałęzi funkcji często trudno mi zrozumieć strukturę gałęzi w historii.

Przykład:

Powiedzmy, że istniała funkcja gałęzi / make-coffee , a usuwanie błędów było kontynuowane na master równolegle do gałęzi funkcji.

Historia może wyglądać następująco:

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

Problem

Na pierwszy rzut oka trudno mi stwierdzić, po której stronie jest gałąź funkcji. Zwykle muszę przejrzeć kilka komentarzy po obu stronach, aby dowiedzieć się, który jest który. Staje się to bardziej skomplikowane, jeśli istnieje wiele gałęzi elementów równolegle (szczególnie jeśli dotyczą one blisko powiązanych elementów) lub jeśli nastąpiło scalenie w obu kierunkach między gałęzią elementów a wzorcem.

Dla kontrastu w Subversion jest to znacznie łatwiejsze, ponieważ nazwa gałęzi jest częścią historii - więc mogę od razu powiedzieć, że zatwierdzenie zostało pierwotnie dokonane na „feature / make-coffee”.

Git mógłby to ułatwić, włączając nazwę bieżącego oddziału do metadanych zatwierdzenia podczas tworzenia zatwierdzenia (wraz z autorem, datą itp.). Jednak git tego nie robi.

Czy istnieje jakiś fundamentalny powód, dla którego tak się nie dzieje? A może po prostu nikt nie chciał tej funkcji? Jeśli to drugie, czy istnieją inne sposoby zrozumienia celu historycznych gałęzi bez poznania nazwy?

Śleske
źródło
1
Powiązane pytanie: znalezienie gałęzi, z której pochodzi zatwierdzenie . Chodzi o to, jak znaleźć te informacje, mimo że git nie rejestruje ich wprost.
sleske
1
Uwaga do siebie: Co ciekawe, w Mercurial commit ma zawierać nazwę oddziału. Wygląda więc na to, że twórcy Mercurial podjęli inną decyzję projektową niż deweloperzy git. Aby uzyskać szczegółowe informacje, patrz np. Felipec.wordpress.com/2012/05/26/ ...
śleske,

Odpowiedzi:

14

Prawdopodobnie dlatego, że nazwy oddziałów mają znaczenie tylko w jednym repozytorium. Jeśli jestem w make-coffeezespole i prześlę wszystkie moje zmiany za pośrednictwem strażnika, moja mastergałąź może zostać przyciągnięta do make-coffee-guigałęzi strażnika , który połączy się ze swoją make-coffee-backendgałęzią, zanim przejdzie do make-coffeegałęzi, która zostanie scalona z mastergałęzią centralną .

Nawet w obrębie jednego repozytorium nazwy oddziałów mogą się zmieniać w miarę ewolucji przepływu pracy. mastermoże się później zmienić developmentna przykład w celu wywołania

Jak wspomniał CodeGnome, git ma silną filozofię projektowania polegającą na tym, że nie zapisuje czegoś w danych, jeśli nie jest to potrzebne. Oczekuje się, że użytkownicy skorzystają z opcji git logi git diffwyprowadzą dane według własnych upodobań. Zalecam wypróbowanie go, dopóki nie znajdziesz formatu, który będzie dla Ciebie lepszy. git log --first-parent, na przykład, nie pokaże zatwierdzeń z łączonego oddziału.

Karl Bielefeldt
źródło
2
Należy jednak zauważyć, że pierwszy rodzic jest zwykle niewłaściwy. Ponieważ zwykle ktoś po prostu przyciąga mistrza do tego, nad czym pracuje, i wypycha, czyniąc swoją pracę pierwszym rodzicem, a mistrzem drugiego.
Jan Hudec
1
@JanHudec: Właściwie to zależy :-). Jeśli osoba wykonująca pracę połączy ją, to tak. Jeśli scalenie nastąpi później, może po przeglądzie, bardziej prawdopodobne jest, że recenzent wypisał wzorzec i scali gałąź funkcji w wzorzec, przetestuje ją i pcha.
sleske
5

Śledź historię oddziału za pomocą --no-ff

W Git, zatwierdzenie ma przodków, ale „gałąź” jest tak naprawdę tylko obecnym szefem jakiejś linii rozwoju. Innymi słowy, zatwierdzenie jest migawką działającego drzewa w pewnym momencie i może należeć do dowolnej liczby gałęzi jednocześnie. Jest to część tego, co sprawia, że ​​rozgałęzienia Git są tak lekkie w porównaniu do innych DVCS.

Zatwierdzenia Git nie niosą informacji o oddziale, ponieważ nie są one niezbędne do historii Git. Jednak połączenia, które nie są szybkie, mogą z pewnością zawierać dodatkowe informacje o tym, który oddział został scalony. Możesz upewnić się, że twoja historia zawiera te informacje, zawsze przekazując --no-ffflagę do twoich połączeń. git-merge (1) mówi:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

Generalnie spowoduje to utworzenie wiadomości scalającej podobnej do Merge branch 'foo', dzięki czemu zwykle można znaleźć informacje o „gałęziach przodków” w linii podobnej do następującej:

$ git log --regexp-ignore-case --grep 'merge branch'
CodeGnome
źródło
Dzięki, ale to (głównie) nie odpowiada na moje pytanie. Nie pytam, jakie są inne sposoby znalezienia oryginalnej gałęzi, ale dlaczego informacje nie są uwzględnione jako zwykłe metadane - to raczej pytanie projektowe.
sleske
1
@sleske Myślę, że moja odpowiedź była responsywna: Git go nie śledzi, ponieważ historia Git go nie potrzebuje; Nie sądzę, żeby stało się to bardziej fundamentalne niż to. Trzeba będzie spojrzeć na źródło, aby poznać szczegóły, ale historia jest skutecznie obliczana wstecz od końca bieżącej gałęzi. Zawsze możesz porównać to z niektórymi innymi systemami DVCS, które traktują gałęzie jak obiekty najwyższej klasy, i przekonaj się, czy bardziej podoba ci się ta filozofia projektowania. YMMV.
CodeGnome
1
Ten ostatni powinien być git log --merges.
Dan
3

Najprostsza odpowiedź jest taka, że ​​nazwy gałęzi są ulotne. Co by było, gdyby, powiedzmy, zmienić nazwę oddziału (git branch -m <oldname> <newname> )? Co stałoby się ze wszystkimi zobowiązaniami wobec tego oddziału? A jeśli dwie osoby mają oddziały o tej samej nazwie w różnych lokalnych repozytoriach?

Jedyną rzeczą, która ma znaczenie w git, jest suma kontrolna samego zatwierdzenia. Jest to podstawowa jednostka śledzenia.

Informacja jest tam, po prostu jej nie pytasz i nie jest dokładnie tam.

Git przechowuje sumę kontrolną głowy każdego oddziału w .git/refs/heads. Na przykład:

... /. git / refs / heads $ ls test 
-rw-rw-r-- 1 michealt michealt 41 30 września 11:50 test
... /. git / refs / heads $ cat test 
87111111111111111111111111111111111111d4

(tak, spycham sumy kontrolne git, to nie jest specjalne, ale są to prywatne repozytoria, na które patrzę w tej chwili, w których nie trzeba mieć przypadkowego wycieku).

Patrząc na to i śledząc wstecz wszystkie zatwierdzenia, które mają to jako rodzic, rodzic-rodzic lub rodzic-rodzic ... możesz dowiedzieć się, w jakich gałęziach znajduje się dane zatwierdzenie. To tylko duży wykres do renderowania.

Przechowywanie tam, gdzie konkretnie jest nazwa gałęzi (która może ulec zmianie, jak wspomniano powyżej), zatwierdzenie znajduje się w samym zatwierdzeniu, jest dodatkowym narzutem na zatwierdzeniu, które mu nie pomaga. Przechowuj elementy nadrzędne zatwierdzenia i jego dobra.

Możesz zobaczyć gałęzie, uruchamiając polecenie git log z odpowiednią flagą.

git log - oddziały - źródło --pretty = oneline --graph
git log --all --source --pretty = oneline --graph

Istnieje wiele różnych sposobów wybierania tego, co chcesz - spójrz do dokumentacji dziennika git - -allsekcji i kilku poniższych opcji.

* 87111111111111111111111111111111111111d4 test Połącz gałąź „test1” z testem
| \  
| * 42111111111111111111111111111111111111e8 aktualizacja test1: dodaj elementy
* | dd11111111111111111111111111111111111159 test Połącz gałąź „test3” z testem
| \ \  

„Test”, „test1” i „test2” są gałęziami, do których zostały zobowiązane.

Zauważ, że dokumentacja dziennika git jest ogromna i całkiem możliwe jest uzyskanie z niej prawie wszystkiego, co chcesz.


źródło
3

Dlaczego polecenia git nie zawierają nazwy gałęzi, w której zostały utworzone?

Tylko decyzja projektowa. Jeśli potrzebujesz tych informacji, możesz dodać haczyk przygotuj-zatwierdzenie-msg lub zatwierdzenie-msg, aby wymusić to w pojedynczym repozytorium.

Po katastrofie BitKeepera Linus Torvalds opracował git, aby pasował do procesu rozwoju jądra Linuksa. Tam, dopóki łatka nie zostanie zaakceptowana, jest ona kilkakrotnie poprawiana, edytowana, polerowana (przez pocztę), podpisywana (= edycja zatwierdzenia), wybierana przez wiarę, wędrowanie do oddziałów porucznika może być często zmieniane, więcej edycji, wiśnia - wybiera i tak dalej, aż w końcu zostaną połączone przez Linusa.

W takim przepływie pracy może nie istnieć określone pochodzenie zatwierdzenia, a często zatwierdzenie jest właśnie tworzone w jakiejś tymczasowej gałęzi debugowania w jakimś nieistotnym prywatnym repozytorium losowym ze śmiesznymi nazwami gałęzi, gdy git jest dystrybuowany.

Być może ta decyzja projektowa wydarzyła się przypadkowo, ale dokładnie pasuje do procesu rozwoju jądra Linux.

villekulla
źródło
2

Ponieważ w Git zatwierdzenia, takie jak „zaparz kawę”, są uważane za część obu gałęzi, gdy gałąź funkcji jest scalona. Istnieje nawet polecenie, aby to sprawdzić:

% git branch --contains @
  feature/make-coffee
  master

Ponadto gałęzie są tanie, lokalne i eteryczne; można je łatwo dodawać, usuwać, zmieniać nazwy, wypychać i usuwać z serwera.

Git działa zgodnie z zasadą, że wszystko można zrobić, dlatego możesz łatwo usunąć gałąź ze zdalnego serwera i łatwo przepisać historię.

Powiedzmy, że byłem w gałęzi „master” i dokonałem dwóch zatwierdzeń: „zrób kawę” i „dodaj mleko i cukier”, a następnie zdecydowałem się użyć do tego nowej gałęzi, więc resetuję „master” z powrotem do „pochodzenia” /mistrz'. Nie ma problemu, cała historia jest wciąż czysta: „rób kawę” i „dodaj mleko i cukier” nie są częścią master, tylko funkcja / robienie kawy.

Mercurial jest przeciwieństwem; nie chce niczego zmieniać. Gałęzie są stałe, historia pisania nie jest mile widziana, nie można po prostu usunąć gałęzi z serwera.

W skrócie: Git pozwala ci robić wszystko, Mercurial chce ułatwić ci wszystko (i naprawdę utrudnia ci robienie tego, co chcesz).

FelipeC
źródło