Dlaczego git domyślnie wykonuje operacje szybkiego przewijania do przodu?

641

Pochodzę z rtęci, używam gałęzi do organizowania funkcji. Oczywiście chcę zobaczyć ten przepływ pracy również w mojej historii.

Rozpocząłem nowy projekt za pomocą git i zakończyłem swoją pierwszą funkcję. Podczas łączenia tej funkcji zdałem sobie sprawę, że git używa szybkiego przewijania do przodu, tzn. Jeśli to możliwe, stosuje moje zmiany bezpośrednio do gałęzi master i zapomina o mojej gałęzi.

Pomyślmy więc o przyszłości: tylko ja pracuję nad tym projektem. Jeśli użyję domyślnego podejścia git (łączenie w przód), moja historia zaowocuje jedną gigantyczną gałęzią master. Nikt nie wie, że użyłem osobnej gałęzi dla każdej funkcji, ponieważ w końcu będę miał tylko tę gigantyczną gałąź główną. Czy to nie będzie wyglądać nieprofesjonalnie?

Zgodnie z tym rozumowaniem nie chcę łączenia szybkiego i nie mogę zrozumieć, dlaczego jest to ustawienie domyślne. Co w tym takiego dobrego?

Florian Pilz
źródło
38
Uwaga: patrz także sandofsky.com/blog/git-workflow.html i unikaj „ no-ff” z „zatwierdzeniem punktu kontrolnego”, który łamie bisect lub winę.
VonC
15
żałujesz, że używasz git w projekcie jednoosobowym?
HaveAGuess,
27
Absolutnie nie! W moim folderze roboczym mam 7 jednoosobowych projektów, w których korzystam z git. Pozwólcie, że sformułuję to: zacząłem wiele projektów, odkąd zadałem to pytanie, a wszystkie z nich są wersjonowane przez git. O ile mi wiadomo, tylko git i mercurial obsługują lokalne wersje, co jest dla mnie niezbędne, odkąd się do tego przyzwyczaiłem. Łatwo go skonfigurować i zawsze masz przy sobie całą historię. W projektach grupowych jest jeszcze lepiej, ponieważ możesz zatwierdzać bez ingerowania w swój kod pracy w toku. Ponadto używam github do udostępniania niektórych moich projektów (np. Mikro-optparse), gdzie git jest wymagany.
Florian Pilz,
7
@Cawas prawda, -no-ffrzadko jest dobrym pomysłem, ale nadal może pomóc zachować wewnętrzną historię funkcji, jednocześnie rejestrując tylko jedno zatwierdzenie w głównej gałęzi. Ma to sens w przypadku długiej historii funkcji, gdy od czasu do czasu scalasz jej postęp w głównej gałęzi.
VCC
12
Nawiasem mówiąc, na twoje pytanie „Czy to [historia gałęzi liniowej] nie wygląda nieprofesjonalnie?”. Nie ma nic nieprofesjonalnego w używaniu systemu kodu źródłowego z jego domyślnymi ustawieniami. Tu nie chodzi o profesjonalizm. Chodzi o określenie, którą filozofię rozgałęziania subskrybujesz. Na przykład @VonC powiązał z artykułem sandofsky'ego, w którym popiera szybkie przewijanie do przodu jako lepsze podejście. Niewłaściwe lub złe, tylko różne filozofie dla różnych kontekstów.
Marplesoft,

Odpowiedzi:

718

Scalanie do przodu ma sens w przypadku krótkotrwałych gałęzi, ale w bardziej złożonej historii scalanie bez szybkiego przewijania może ułatwić zrozumienie historii i ułatwić przywrócenie grupy zatwierdzeń.

Ostrzeżenie : niezwiązane z szybkim przekazywaniem ma również potencjalne skutki uboczne. Zapoznaj się z https://sandofsky.com/blog/git-workflow.html , unikaj „no-ff” z jego „punktami kontrolnymi zatwierdzeń”, które łamią bisect lub winę, i dokładnie zastanów się, czy to powinno być twoje domyślne podejście master.

alternatywny tekst
(Od nvie.com , Vincent Driessen , post „ Udany model rozgałęziania Git ”)

Włączanie gotowej funkcji przy programowaniu

Gotowe funkcje można połączyć z gałęzią programistyczną, aby dodać je do nadchodzącej wersji:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

--no-ffFlaga powoduje seryjnej zawsze utworzyć nowy popełnić obiektu, nawet jeśli seryjnej mogą być wykonywane szybko do przodu. Pozwala to uniknąć utraty informacji o historycznym istnieniu gałęzi obiektów i grupuje wszystkie zatwierdzenia, które razem dodały obiekt.

Jakub Narębski również wspomina się configmerge.ff :

Domyślnie Git nie tworzy dodatkowego zatwierdzenia scalania podczas scalania zatwierdzenia będącego potomkiem bieżącego zatwierdzenia. Zamiast tego wierzchołek bieżącej gałęzi jest przewijany do przodu.
Po ustawieniu na falseta zmienna mówi Gitowi, aby w takim przypadku utworzył dodatkowe zatwierdzenie scalania (równoważne z podaniem --no-ffopcji z wiersza poleceń).
Po ustawieniu na „ only” dozwolone są tylko takie szybkie przewijanie do przodu (co odpowiada --ff-onlyopcji z linii poleceń).


Szybkie przewijanie do przodu jest domyślne, ponieważ:

  • Krótkotrwałe gałęzie są bardzo łatwe do utworzenia i użycia w Git
  • krótkotrwałe gałęzie często izolują wiele zmian, które można dowolnie zreorganizować w ramach tej gałęzi
  • te zatwierdzenia są w rzeczywistości częścią głównej gałęzi: po reorganizacji główna gałąź jest szybko przekazywana, aby je uwzględnić.

Ale jeśli spodziewasz się iteracyjnego przepływu pracy dla jednej gałęzi tematów / funkcji (tj. Scalam, a następnie wrócę do tej gałęzi funkcji i dodam więcej zatwierdzeń), to przydatne jest włączenie tylko scalania w gałęzi głównej, a nie wszystkie pośrednie zatwierdzenia gałęzi cech.

W takim przypadku możesz zakończyć konfigurowanie tego rodzaju pliku konfiguracyjnego :

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

OP dodaje w komentarzach:

Widzę trochę sensu w przewijaniu do przodu dla [krótkotrwałych] gałęzi, ale ustawienie domyślnej akcji oznacza, że ​​git zakłada, że ​​... często masz [krótkotrwałe] gałęzie. Rozsądny?

Jefromi odpowiada:

Myślę, że czas życia oddziałów różni się znacznie w zależności od użytkownika. Jednak wśród doświadczonych użytkowników prawdopodobnie istnieje tendencja do posiadania znacznie krótszych oddziałów.

Dla mnie gałąź krótkotrwała to taka, którą tworzę, aby ułatwić pewną operację (bazowanie, prawdopodobnie lub szybkie łatanie i testowanie), a następnie natychmiast usuwam, gdy skończę.
Oznacza to, że prawdopodobnie powinien zostać zaabsorbowany w gałęzi tematycznej, z której rozwidlił się , a gałąź tematyczna zostanie scalona jako jedna gałąź. Nikt nie musi wiedzieć, co zrobiłem wewnętrznie, aby utworzyć serię zatwierdzeń implementujących daną funkcję.

Ogólniej dodaję:

to naprawdę zależy od przepływu pracy programisty :

  • jeśli jest liniowy, jedna gałąź ma sens.
  • Jeśli chcesz wyodrębnić funkcje i pracować nad nimi przez długi okres czasu i wielokrotnie je scalać, kilka gałęzi ma sens.

Zobacz „ Kiedy należy rozgałęzić?

W rzeczywistości, jeśli weźmie się pod uwagę model gałęzi Mercurial, jest on w centrum jednej gałęzi na repozytorium (nawet jeśli można tworzyć anonimowe nagłówki, zakładki, a nawet nazwane gałęzie )
Patrz „Git i Mercurial - Porównaj i skontrastuj” .

Mercurial domyślnie stosuje anonimowe lekkie linie kodowe, które w swojej terminologii nazywane są „główkami”.
Git używa lekkich nazwanych gałęzi z iniekcyjnym mapowaniem do mapowania nazw gałęzi w zdalnym repozytorium na nazwy gałęzi zdalnego śledzenia.
Git „zmusza” cię do nazywania gałęzi (no, z wyjątkiem pojedynczej gałęzi bez nazwy, co jest sytuacją zwaną „ odłączoną HEAD ”), ale myślę, że działa to lepiej w przypadku przepływów pracy obciążających gałęzie, takich jak przepływ pracy gałęzi tematu, co oznacza wiele oddziałów w jednym paradygmacie repozytorium.

VonC
źródło
Wow, to było szybkie. ;) Wiem o opcji --no-ff, ale dowiaduję się o przewijaniu do przodu dopiero po zepsuciu mojej funkcji. Widzę trochę sensu w przewijaniu do przodu w przypadku krótko żyjących gałęzi, ale ustawienie domyślnej akcji oznacza, że ​​git zakłada, że ​​najczęściej masz tak krótko żyjące gałęzie. Rozsądny?
Florian Pilz
@Florian: Uważam, że jest to rozsądny pogląd na ten proces. Dodałem przykład konfiguracji, która skonfiguruje sposób, w jaki chcesz zarządzać scalaniem z master.
VonC
Dzięki, plik konfiguracyjny powinien pomóc uniknąć takich problemów. :) Zastosował tę konfigurację tylko lokalnie z „git config branch.master.mergeoptions '--no-ff'”
Florian Pilz
2
@BehrangSaeedzadeh: rebasing to inny temat (o którym nie wspomniano na tej stronie): dopóki nie wypchniesz swojego featureoddziału do publicznego repozytorium, możesz bazować na nim mastertyle razy, ile chcesz. Zobacz stackoverflow.com/questions/5250817/…
VonC
4
@BehrangSaeedzadeh: sama baza danych nie uczyni historii liniową. To, jak integrujesz zmiany swojego featureoddziału z powrotem master, sprawia, że ​​wspomniana historia jest liniowa, czy nie. Proste szybkie łączenie sprawi, że będzie liniowe. Ma to sens, jeśli wyczyściłeś historię tego featureoddziału przed scaleniem do przodu, pozostawiając tylko znaczące zatwierdzenia, jak wspomniano w stackoverflow.com/questions/7425541/... .
VonC,
42

Pozwól mi rozwinąć trochę na VonC „s bardzo wyczerpującą odpowiedź :


Po pierwsze, jeśli dobrze to pamiętam, fakt, że Git domyślnie nie tworzy zatwierdzeń scalania w przypadku szybkiego przewijania , wynika z rozważenia „równych repozytoriów” jednej gałęzi, w których do synchronizacji tych dwóch repozytoriów używa się wzajemnego ściągania (a przepływ pracy można znaleźć jako pierwszy przykład w dokumentacji większości użytkowników, w tym w „Podręczniku użytkownika Git” i „Kontrola wersji według przykładów”). W tym przypadku nie używasz pull do scalenia w pełni zrealizowanej gałęzi, używasz jej do nadążania za innymi pracami. Nie chcesz mieć efemerycznego i nieistotnego faktu, gdy akurat synchronizacja jest zapisywana i przechowywana w repozytorium, zapisanym na przyszłość.

Zauważ, że użyteczność gałęzi funkcji i posiadania wielu gałęzi w pojedynczym repozytorium pojawiła się dopiero później, z bardziej rozpowszechnionym użyciem VCS z dobrą obsługą scalania i próbowaniem różnych przepływów pracy opartych na scalaniu. Dlatego na przykład Mercurial początkowo obsługiwał tylko jedną gałąź w repozytorium (plus anonimowe wskazówki dotyczące śledzenia zdalnych gałęzi), jak widać w starszych wersjach „Mercurial: The Definitive Guide”.


Po drugie, kiedy po najlepszych praktyk wykorzystania oddziałów fabularnych , a mianowicie, że gałęzie fabularne powinny początek od stabilnej wersji (zwykle od ostatniego wydania), aby móc cherry-pick and wybrać, które funkcje do włączenia przez Wybieranie funkcji oddziałów scalić, ci zwykle nie znajdują się w sytuacji szybkiego przewijania do przodu ... co sprawia, że ​​ten problem jest dyskusyjny. Musisz się martwić tworzeniem prawdziwego scalenia, a nie przewijaniem do przodu podczas scalania pierwszej gałęzi (zakładając, że nie wprowadzasz zmian pojedynczego zatwierdzenia bezpośrednio w 'master'); wszystkie inne późniejsze fuzje odbywają się oczywiście w sytuacji bez szybkiego przewijania.

HTH

Jakub Narębski
źródło
Odnośnie gałęzi funkcji ze stabilnych wydań: Co jeśli funkcja, którą opracowuję dla następnej wersji, zależy od zmian w innej funkcji, którą już opracowałem i połączyłem w master? Z pewnością oznacza to, że muszę utworzyć tę drugą gałąź funkcji z poziomu głównego?
dOxxx
1
@dOxxx: Tak, są wyjątki, takie jak np. gdzie jedna gałąź opiera się na drugiej (bezpośrednio lub po scaleniu poprzedniej w master).
Jakub Narębski