Dlaczego git fast-forward łączy się domyślnie?

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

Rozpocząłem nowy projekt używając Gita i ukończyłem pierwszą funkcjonalność. Podczas scalania tej funkcji zdałem sobie sprawę, że git używa fast-forward, tzn. stosuje moje zmiany bezpośrednio do gałęzi master, jeśli to możliwe i zapomina o mojej gałęzi.

Myśląc w przyszłość: tylko ja pracuję nad tym projektem. Jeśli używam domyślnego podejścia Gita (fast-forward scalanie), moja historia spowodowałaby jedną wielką gałąź master. Nikt nie wie, że używałem oddzielnej gałęzi dla każdej funkcji, ponieważ w końcu będę miał tylko tę gigantyczną gałąź master. Czy to nie wygląda nieprofesjonalnie?

Przez to rozumowanie, nie chcę fast-forward scalanie i nie widzę, dlaczego jest to domyślne. Co w tym dobrego?

Author: Nick Volynkin, 2010-05-17

2 answers

Fast-forward merging ma sens dla krótkotrwałych gałęzi, ale w bardziej złożonej historii, fast-forward merging może ułatwić zrozumienie historii i ułatwić przywrócenie grupy zatwierdzeń.

Ostrzeżenie: Nie-szybkie przekazywanie ma również potencjalne skutki uboczne. Proszę przejrzeć https://sandofsky.com/blog/git-workflow.html , unikaj 'no-ff' z jego "Checkpoint commits", które łamią bisect lub winę, i uważnie rozważ czy powinno to być domyślne podejście dla master.

alt text
(od nvie.com, Vincent Driessen , post "udany model rozgałęziania Gita")

Włączenie gotowej funkcji w rozwijaniu

Gotowe funkcje mogą być scalone w gałąź develop, aby dodać je do nadchodzącego wydania:

$ 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

Znacznik --no-ff powoduje, że połączenie zawsze tworzy nowe Zatwierdź obiekt, nawet jeśli scalanie może być wykonane z przewijaniem do przodu. Pozwala to uniknąć utraty informacji o historycznym istnieniu gałęzi funkcji i grupuje wszystkie commity, które razem dodały tę funkcję.

Jakub Narębski również wspomina o config merge.ff:

Domyślnie, Git nie tworzy dodatkowego commita scalającego podczas łączenia commita, który jest potomkiem bieżącego commita. Zamiast tego końcówka bieżąca gałąź jest szybko przekazywana.
Po ustawieniu na false, ta zmienna każe Gitowi utworzyć dodatkowy commit scalający w takim przypadku (co odpowiada opcji --no-ff z linii poleceń).
Po ustawieniu na " only" dozwolone są tylko takie fast-forward merges (co odpowiada opcji --ff-only z wiersza poleceń).


Przewijanie do przodu jest domyślne, ponieważ:

  • krótkotrwałe gałęzie są bardzo łatwe w tworzeniu i użyciu w Git
  • krótkotrwałe gałęzie często izolują wiele commitów, które mogą być dowolnie reorganizowane w obrębie tej gałęzi
  • te commity są w rzeczywistości częścią głównej gałęzi: po reorganizacji, główna gałąź jest szybko przekazywana, aby je włączyć.

Ale jeśli przewidujesz iteracyjny obieg pracy nad jedną gałęzią tematu/funkcji (tzn. scalam, potem wracam do tej gałęzi funkcji i dodaję kilka kolejnych commitów), to jest przydatne, aby włączyć tylko scalanie w głównej gałęzi, a nie wszystkie pośredni commit gałęzi feature.

W tym przypadku możesz ustawić tego rodzaju plik konfiguracyjny :

[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ę jakiś sens w przewijaniu do przodu dla gałęzi [krótkotrwałych], ale zrobienie z niej domyślnej akcji oznacza, że git zakłada Ciebie... często mają [krótkotrwałe] gałęzie. Rozsądne?

Jefromi odpowiada:

Myślę, że żywotność gałęzi znacznie różni się od użytkownika do użytkownika. Wśród doświadczonych użytkowników prawdopodobnie istnieje tendencja do posiadania znacznie krótszych gałęzi.

Dla mnie, krótkotrwała gałąź to gałąź, którą tworzę w celu ułatwienia pewnej operacji (rebasing, prawdopodobnie lub szybkie łatanie i testowanie), a następnie natychmiast usuwam, gdy skończę.
Oznacza to, że prawdopodobnie powinien zostać wchłonięty do gałęzi tematycznej, z której został rozwidlony, a gałąź tematyczna zostanie scalona jako jedna gałąź. Nikt nie musi wiedzieć co zrobiłem wewnętrznie w celu stworzenia serii commitów implementujących daną funkcjonalność.

Bardziej ogólnie dodaję:

To naprawdę zależy od Twojego przepływu pracy nad rozwojem :

  • jeśli jest liniowa, jedna gałąź ma sens.
  • jeśli trzeba wyodrębnić funkcje i pracować nad nimi przez długi czas i wielokrotnie łączyć je, kilka gałęzi ma sens.

Zobacz "Kiedy należy branch?"

Właściwie, jeśli weźmiemy pod uwagę model Mercurial branch, jest on podstawą na repozytorium można utworzyć jedną gałąź, anonimowe głowy, zakładki, a nawet nazwane gałęzie )
Zobacz "Git i Mercurial-porównanie i kontrast" .

Mercurial domyślnie używa anonimowych, lekkich linii kodowych, które w swojej terminologii nazywane są "głowami".
Git używa lekkich nazwanych gałęzi, z mapowaniem injekcyjnym do mapowania nazw gałęzi w zdalnym repozytorium do nazw gałęzi zdalnego śledzenia.
Git "zmusza" cię do nazywania gałęzi (z wyjątkiem jednej gałęzi bez nazwy, co jest sytuacją nazywaną " wolnostojąca Głowa"), ale myślę, że działa to lepiej z przepływami pracy o dużym natężeniu, takimi jak przepływ pracy w gałęzi tematycznej, co oznacza wiele gałęzi w jednym paradygmacie repozytorium.

 688
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:34

Pozwól mi rozwinąć trochę na VonC ' S bardzo wyczerpująca odpowiedź :


Po pierwsze, o ile dobrze pamiętam, fakt, że Git domyślnie nie tworzy merge commits W przypadku fast-forward pochodzi z rozważenia jednodrzwiowych "równych repozytoriów", gdzie mutual pull jest używany do synchronizacji tych dwóch repozytoriów (obieg pracy można znaleźć jako pierwszy przykład w większości dokumentacji użytkownika, w tym "The Git User' s Manual " i " Version Control by Example"). W tym przypadku nie używasz pull do scalania w pełni zrealizowanej gałęzi, używasz jej do nadążania za innymi pracami. Nie chcesz, aby efemeryczny i nieistotny fakt, gdy zdarzy ci się zrobić synchronizację zapisane i przechowywane w repozytorium, zapisane na przyszłość.

Zauważ, że przydatność gałęzi funkcji i posiadania wielu gałęzi w jednym repozytorium pojawiła się dopiero później, z bardziej powszechnym wykorzystaniem VCS z dobrą obsługą scalania i z próbowaniem różnych przepływów pracy opartych na scalaniu. Dlatego na przykład Mercurial pierwotnie obsługiwał tylko jedną gałąź na repozytorium (Plus anonimowe wskazówki dotyczące śledzenia zdalnych gałęzi), jak widać w starszych wersjach "Mercurial: the Definitive Guide".


Po drugie, stosując się do najlepszych praktyk używania gałęzi funkcji, mianowicie, że gałęzie funkcji powinny zaczynać się od stabilnej wersji (zwykle od ostatniego wydania), aby móc wybrać i wybrać, które funkcje do włączenia, wybierając, które gałęzie funkcji do merge, zazwyczaj nie jesteś w sytuacji szybkiego przewijania ... co sprawia, że ta kwestia jest dyskusyjna. Musisz się martwić o utworzenie prawdziwego scalenia, a nie fast-forward podczas scalania pierwszej gałęzi (zakładając, że nie umieścisz zmian z pojedynczymi zatwierdzeniami bezpośrednio na 'master'); wszystkie inne późniejsze scalenia są oczywiście w sytuacji non fast-forward.

HTH

 40
Author: Jakub Narębski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-25 16:19:00