Jakie modele rozgałęzień Git działają dla Ciebie?


378

Nasza firma obecnie używa prostego modelu rozgałęziania magistrali / wydania / poprawek i chciałaby uzyskać porady na temat tego, które modele rozgałęziania najlepiej sprawdzają się w Twojej firmie lub w procesie rozwoju.

  1. Przepływy pracy / modele rozgałęziające

    Poniżej znajdują się trzy główne opisy tego, które widziałem, ale są one częściowo sprzeczne ze sobą lub nie idą wystarczająco daleko, aby rozwiązać kolejne problemy, na które natrafiliśmy (jak opisano poniżej). Dlatego nasz zespół do tej pory domyślał się nie tak świetnych rozwiązań. Robisz coś lepszego?

  2. Scalanie vs rebasing (historia splątana vs sekwencyjna)

    Czy powinienem pull --rebasealbo poczekać z połączeniem z powrotem do głównej linii, aż twoje zadanie zostanie zakończone? Osobiście skłaniam się ku scaleniu, ponieważ zachowuje to wizualną ilustrację, na podstawie której zadanie zostało uruchomione i zakończone, a nawet wolę merge --no-ffdo tego celu. Ma jednak inne wady. Również wielu nie zdawało sobie sprawy z użytecznej właściwości scalania - że nie jest on przemienny (scalenie gałęzi tematycznej w master nie oznacza scalenia master do gałęzi tematycznej).

  3. Szukam naturalnego przepływu pracy

    Czasami zdarzają się błędy, ponieważ nasze procedury nie wychwytują konkretnej sytuacji za pomocą prostych zasad. Na przykład poprawka potrzebna do wcześniejszych wydań powinna oczywiście opierać się na poziomie niższego szczebla, aby umożliwić połączenie go ze wszystkimi gałęziami (czy użycie tych terminów jest wystarczająco jasne?). Jednak zdarza się, że poprawka przenosi się do wzorca, zanim deweloper zda sobie sprawę, że powinna była zostać umieszczona dalej niżej, a jeśli jest już wypchnięta (jeszcze gorzej, scalona lub coś na jej podstawie), wówczas pozostała opcja to wybranie wiśni, z związane z tym niebezpieczeństwa. Jakich prostych zasad używasz?Uwzględniono także niezręczność jednej gałęzi tematycznej, koniecznie wykluczając inne gałęzie tematyczne (zakładając, że są one rozgałęzione od wspólnej linii bazowej). Deweloperzy nie chcą kończyć funkcji, aby rozpocząć kolejną, mając wrażenie, że napisanego właśnie kodu już nie ma

  4. Jak uniknąć tworzenia konfliktów scalania (ze względu na cherry-pick)?

    Co wydaje się pewnym sposobem na utworzenie konfliktu scalania jest wybranie między oddziałami, aby nigdy więcej nie mogły zostać połączone? Czy zastosowanie tego samego zatwierdzenia podczas przywracania (jak to zrobić?) W którejkolwiek gałęzi mogłoby rozwiązać tę sytuację? To jeden z powodów, dla których nie odważę się naciskać na przepływ pracy w dużej mierze oparty na scalaniu.

  5. Jak rozłożyć na aktualne gałęzie?

    Zdajemy sobie sprawę, że składanie zakończonej integracji z gałęzi tematów byłoby niesamowite, ale często praca naszych programistów nie jest jasno zdefiniowana (czasami tak prosta, jak „grzebanie się”), a jeśli jakiś kod już przeszedł do tematu „misc”, zgodnie z powyższym pytaniem nie można go stamtąd wyciągnąć. Jak pracujesz z definiowaniem / zatwierdzaniem / ukończeniem / wydaniem gałęzi tematycznych?

  6. Właściwe procedury, takie jak przegląd kodu i stopniowanie, byłyby oczywiście cudowne.

    Ale po prostu nie możemy utrzymać rzeczy na tyle nierozpoznanych, by sobie z tym poradzić - jakieś sugestie? gałęzie integracji, ilustracje?

Poniżej znajduje się lista powiązanych pytań:

Sprawdź także, co pisze Plastic SCM na temat rozwoju opartego na zadaniach , a jeśli Plastic nie jest twoim wyborem, zapoznaj się z modelem rozgałęziającym nvie i jego skryptami pomocniczymi .


2
Hah, dziękuję, rzeczywiście ma ... Przeczytałem większość tego ... rzeczy :-). To coś, z czego jestem znany - nie zadowalać się miernym rozwiązaniem, ale kontynuować poszukiwanie ideału. Często jest to błąd, ale w tym przypadku wiele jest zagrożonych, a dostępne rozwiązania są po prostu zbyt niechlujne lub słabe, że muszę nadal szukać. Postanowiłem więc wymienić wszystkie problemy, które mam z tym związane.
HiQ CJ,

Blog Plastic SCM wrzucił swoją opinię do dyskusji, jest przynajmniej wnikliwa: codicesoftware.blogspot.com/2010/08/…
HiQ CJ

1
Musisz zachować ostrożność, używając „merge --no-ff”, sprawdź to, aby zapoznać się z pewnymi zastrzeżeniami sandofsky.com/blog/git-workflow.html
Doppelganger

1
@Doppelganger Byłbym zainteresowany tym, w jaki sposób --no-ff rzekomo przyczynia się do problemu opisanego w linku, który publikujesz. Dla mnie opisany problem polega na niepowodzeniu dwusiecznej z zatwierdzeniami punktu kontrolnego i niepowodzeniu git winy, aby pomóc w tym przypadku - ale nie widzę, jak „--no-ff” zmienia cokolwiek, w przeciwieństwie do nieużywania go. Autor skarży się, że scalenie z --no-ff nie powoduje modyfikacji pliku - ale bez niego plik również nie zostałby zmodyfikowany, zobaczyłbyś tylko starsze zatwierdzenie w swojej historii, prawda?
kodowanie

Inny model rozgałęziający: model kaktusowy barro.github.io/2016/02/... , model główny bitsnbites.eu/a-stable-mainline-branching-model-for-git . Oba modele rozgałęziające oferują inne podejście niż gitflow.
Mathieu Momal,

Odpowiedzi:


90

Najbardziej niepokojącą cechą, którą nowi programiści DVCS muszą sobie uświadomić, jest proces publikacji :

  • możesz importować (pobierać / wyciągać) dowolne potrzebne repozytorium
  • możesz publikować (wypychać) dowolne repozytorium, które chcesz

Dzięki temu możesz przestrzegać kilku zasad, aby ułatwić sobie pytania:

Teraz:

Przepływy pracy / modele rozgałęziające :

każdy przepływ pracy służy do obsługi procesu zarządzania wersjami i jest dostosowany do każdego projektu.
To, co mogę dodać do przepływu pracy, o którym wspominasz, to: każdy programista nie powinien tworzyć gałęzi funkcji, tylko gałąź „bieżącego dewelopera”, ponieważ prawda jest taka: programista często nie wie, co dokładnie wytworzy jego gałąź: jeden funkcja, kilka (ponieważ okazało się, że jest to zbyt skomplikowana funkcja), brak (ponieważ nie jest gotowy na wydanie), kolejna funkcja (ponieważ oryginalna „zmieniła kształt”), ...

Tylko „integrator” powinien ustanowić oficjalne gałęzie funkcji na „centralnym” repozytorium, które następnie mogą zostać pobrane przez programistów w celu zmiany / scalenia części ich pracy, która pasuje do tej funkcji.

Scalanie vs rebasing (historia splątana vs sekwencyjna) :

Podoba mi się moja odpowiedź, o której wspomniałeś („ Opis przepływu pracy dla użycia gita do tworzenia własnego ”)

Szukam naturalnego przepływu pracy :

w przypadku poprawek może pomóc powiązać każdą poprawkę z biletem ze śledzenia błędów, co pomaga deweloperowi zapamiętać, gdzie (tj. w której gałęzi, tj. dedykowanej gałęzi „dla poprawek”) powinien dokonać takich modyfikacji.
Wtedy haki mogą pomóc chronić centralne repozytorium przed wypchnięciami przed niepotwierdzonymi poprawkami lub gałęziami, z których nie należy naciskać. (tutaj nie ma konkretnego rozwiązania, wszystko to musi być dostosowane do twojego środowiska)

Jak uniknąć tworzenia konfliktów scalania (ze względu na cherry-pick)?

Jak stwierdził Jakub Narębski w swojej odpowiedzi , zbieranie wiśni powinno być zarezerwowane na rzadkie sytuacje, w których jest to wymagane.
Jeśli twoja konfiguracja wymaga dużo zbierania wiśni (tj. „To nie jest rzadkie”), to coś jest nie tak.

Czy zastosowałbym to samo zatwierdzenie podczas cofania (jak to zrobić?)

git revert powinien się tym zająć, ale to nie jest idealne.

Jak rozłożyć na aktualne gałęzie?

Tak długo, jak gałąź nie została jeszcze wszędzie wypchnięta, programista powinien reorganizować swoją historię commits (kiedy zobaczy, że rozwój nabiera bardziej definitywnego i stabilnego kształtu), w następujący sposób:

  • w razie potrzeby kilka oddziałów (jeden według wyraźnie określonej funkcji)
  • spójny zestaw zatwierdzeń w ramach jednej gałęzi (patrz Przycinanie Git Checkins )

Odpowiednie procedury, takie jak przegląd kodu i stopniowanie?

Repozytorium integracji (w dedykowanej integracji) repo może pomóc deweloperowi w:

  • oprzeć swój rozwój na tej gałęzi zdalnej integracji (pull --rebase)
  • rozwiązać lokalnie
  • popchnij rozwój do tego repozytorium
  • sprawdź u integratora, który nie powoduje bałaganu;)

@UncleCJ: jak widać, nie jest to dokładnie ostateczna odpowiedź na twoje „ostateczne pytanie”;)
WONC

Rozumiem i mam również poczucie ironii, jest w porządku ;-)
HiQ CJ

3
@UncleCJ upstream jest tam, gdzie regularnie pobierasz, z mojego postu, gdziekolwiek kończą się wszystkie zatwierdzenia (wersja wydania lub pień w języku SVN). Downstream to wszyscy poniżej nich. Wysyłanie rzeczy w górę to proces scalania ich z repozytorium wydania (jak linux-2.6), a w dół to zmiany, które wychodzą, lub z twojego repozytorium, jak powiedział kierownik rozwoju takiej funkcji dla twoich stworów ... I wredna drużyna.

2
@UncleCJ: „Nadal uważam, że trudno jest przycinać swoje kontrole, aby uzyskać ściśle sekwencyjną historię”: łatwiej jest z Git1.7 i jego rebase --interactive --autosquashautomatyczne przenoszenie powoduje, że wszystkie zatwierdzenia zaczynają się od tego samego początku kolejnej wiadomości zatwierdzenia. Jeśli te zatwierdzenia używają numeru biletu (na przykład), nawet jeśli poprawki związane z tym biletem nie były w tym czasie wykonywane sekwencyjnie, autosquash pozwala na szybką zmianę kolejności tych zatwierdzeń.
VCC

1
@UncleCJ: „ściśle sekwencyjna historia (czy jest to konieczne czy nie ?!)”: nie zawsze jest konieczna, ale pomaga śledzić zależności funkcjonalne ( stackoverflow.com/questions/881092/... ) i konflikty semantyczne ( stackoverflow.com/questions / 2514502 /… )
WONC

21

Myślę, i mogę się mylić, że jedną z rzeczy, które są najbardziej niezrozumiane w git, jest jego rozproszony charakter. To sprawia, że ​​zupełnie inaczej jest mówić o wywrotowym sposobie działania, chociaż możesz naśladować zachowanie SVN, jeśli chcesz. Problemem jest prawie każdy przepływ pracy, co jest świetne, ale także wprowadza w błąd.

Jeśli dobrze rozumiem rozwój jądra (skupię się na tym), każdy ma swoje własne repozytorium git do rozwijania jądra. Istnieje jedno repozytorium, linux-2.6.git, pod opieką Torvaldsa, które działa jako repozytorium wydań. Ludzie klonują stąd, jeśli chcą rozpocząć tworzenie funkcji przeciwko gałęzi „release”.

Inne repozytoria wykonują pewne prace programistyczne. Chodzi o to, aby sklonować z Linuksa 2.6, rozgałęziać się tyle razy, ile chcesz, aż do momentu, gdy uzyskasz działającą „nową” funkcję. Następnie, gdy będzie gotowy, możesz udostępnić go osobie uważanej za zaufaną, która wyciągnie tę gałąź z repozytorium do swojej i połączy z głównym nurtem. W jądrze Linuksa dzieje się to na kilku poziomach (zaufani porucznicy), dopóki nie osiągnie linux-2.6.git, w którym to momencie staje się „jądrem”.

Teraz jest to mylące. Nazwy oddziałów wcale nie muszą być spójne w repozytoriach. Mogę więc git pull origin master:vanilla-codeuzyskać gałąź od originmistrza w gałęzi w moim repozytorium o nazwie vanilla-code. Pod warunkiem, że wiem, co się dzieje, to naprawdę nie ma znaczenia - jest dystrybuowane w tym sensie, że wszystkie repozytoria są równorzędne, a nie tylko współużytkowane przez kilka komputerów, takich jak SVN.

Mając to na uwadze:

  1. Myślę, że od każdego programisty zależy, w jaki sposób rozgałęziają się. Wszystko czego potrzebujesz to centralne repozytorium do zarządzania wydaniami itp. Trunk może być head. Wersjami mogą być tagi lub gałęzie, a poprawki są prawdopodobnie gałęziami same w sobie. W rzeczywistości prawdopodobnie wydawałbym wydania jako gałęzie, abyś mógł je ciągle łatać.
  2. Scaliłbym, a nie rebase. Jeśli na przykład wziąć repozytorium, klon to, oddział i zrobić dev, a następnie wyciągnąć z listy originnależy w repozytorium, prawdopodobnie uczynić kolejny oddział i scalania ostatni masterw yourbranchtak, że ktoś inny może pociągnąć zmiany z jak najmniejszym wysiłku, jak możliwy. Z mojego doświadczenia wynika, że ​​bardzo rzadko trzeba naprawdę bazować.
  3. Myślę, że chodzi o zrozumienie, w jaki sposób działa Git i co może zrobić. Zajmuje to trochę czasu i dużo dobrej komunikacji - dopiero zacząłem naprawdę rozumieć, co się dzieje, kiedy zacząłem używać git z innymi programistami, a nawet teraz nie jestem pewien.
  4. Konflikty scalania są przydatne. Wiem, wiem, chcesz, żeby to wszystko działało, ale faktem są zmiany w kodzie i musisz scalić wyniki w coś, co działa. Konflikty scalania są w rzeczywistości tylko programowaniem. Nigdy nie znalazłem łatwego wyjaśnienia, co z nimi zrobić, więc oto: zanotuj pliki, które mają konflikty scalania, przejdź i zmień je na takie, jakie powinny być, git add .a następnie git commit.
  5. Jednak to pasuje. Jak powiedziałem, repozytorium git dla każdego użytkownika jest własne, a nazwy oddziałów nie muszą być takie same . Jeśli masz na przykład repozytorium przemieszczania, możesz wymusić schemat nazewnictwa, ale nie musisz tego robić dla każdego programisty, tylko w repozytorium wydania.
  6. To jest etap scalania. Łączymy się z gałęziami wydań itp. Tylko wtedy, gdy uważamy kod za sprawdzony / przeszedł testy jakości.

Mam nadzieję że to pomogło. Zdaję sobie sprawę, że VonC właśnie opublikował bardzo podobne wyjaśnienie ... Nie mogę pisać wystarczająco szybko!

Edytuj dalsze przemyślenia na temat używania gita w środowisku komercyjnym, ponieważ wydaje się to istotne dla PO z komentarzy:

  • Repozytorium wydań, jak to nazwiemy product.git, jest dostępne dla wielu starszych programistów / osób technicznych odpowiedzialnych za opiekę nad samym produktem. Są one analogiczne do roli opiekunów w OSS.
  • Ci programiści prawdopodobnie również częściowo prowadzą rozwój nowych wersji, więc mogą również samodzielnie kodować i utrzymywać repozytoria varios. Mogą zarządzać repozytoriami przemieszczania dla naprawdę nowych funkcji, a także mogą mieć własne repozytoria.
  • Poniżej znajdują się programiści odpowiedzialni za tworzenie poszczególnych bitów. Na przykład ktoś może być odpowiedzialny za działanie interfejsu użytkownika. Dlatego zarządzają repozytorium UI.git.
  • Poniżej znajdują się faktyczni programiści, którzy opracowują funkcje jako swoją codzienną pracę.

Co się dzieje? Cóż, wszyscy ściągają na początku każdego dnia ze źródła „upstream”, tj. Repozytorium wydań (które prawdopodobnie będzie również zawierało najnowszy materiał z rozwoju z poprzednich dni). Każdy robi to bezpośrednio. To przejdzie do oddziału w ich repozytorium, prawdopodobnie o nazwie „master”, a może jeśli to ja o nazwie „najnowsze”. Następnie programista wykona trochę pracy. Ta praca może być czymś, czego nie są pewni, więc tworzą gałąź, wykonują pracę. Jeśli to nie zadziała, mogą usunąć gałąź i wrócić. Jeśli tak, będą musieli połączyć się z główną gałęzią, nad którą aktualnie pracują. Powiemy, że pracuje nad latest-uitym programista interfejsu użytkownika, git checkout latest-uia potem następujegit merge abc-ui-mywhizzynewfeature. Następnie mówi swojemu szefowi technicznemu (prowadzącemu do interfejsu użytkownika) hej, wykonałem takie zadanie, odciągnij ode mnie. Tak robi interfejs użytkownika git pull user-repo lastest-ui:lastest-ui-suchafeature-abc. Kierownik interfejsu użytkownika następnie patrzy na to w tej gałęzi i mówi, właściwie to bardzo dobrze, połączę to ui-latest. Mógłby wtedy powiedzieć wszystkim pod nim, aby wyciągnęli go z ui-latestgałęzi lub jakiejkolwiek nazwy, którą im nadali, tak więc twórcy badają tę funkcję. Jeśli zespół jest szczęśliwy, kierownik interfejsu użytkownika może poprosić lidera testowego o pobranie go i scalenie zmian. Rozchodzi się to do każdego (poniżej zmiany), który go testuje i przesyła raporty o błędach itp. Wreszcie, jeśli funkcja przejdzie testy itp., Jeden z najlepszych potencjalnych klientów technicznych może połączyć ją z bieżącą wersją roboczą programu, w którym to momencie wszystkie zmiany są następnie propagowane z powrotem w dół. I tak dalej.

Nie jest to „tradycyjny” sposób pracy i jest zaprojektowany tak, aby był „sterowany równorzędnie”, a nie „hierarchiczny” jak SVN / CVS. Zasadniczo każdy ma dostęp dostępu, ale tylko lokalnie. Jest to dostęp do repozytorium i repozytorium, które wyznaczasz jako repozytorium wydania, które umożliwia korzystanie z hierarchii.


Dziękuję bardzo za wyczerpującą odpowiedź (i głosy), przeczytam ją jeszcze kilka razy, aby wyciągnąć z niej użyteczne informacje. Jesteśmy jednak firmą, a nie komitetem ds. Rozwoju OSS ;-), i muszę pomóc moim programistom w bardziej przejrzystych wskazówkach niż „błąkać się, jak chcesz we własnym repozytorium”. Zobaczmy, dokąd prowadzi ten post, czuję dobry moment, nie przestawaj!
HiQ CJ

@VonC Dzięki. @ UncleCJ to prawda, ale masz, jestem pewien, masz menedżerów wydań itp. Każdy, kto ma dostęp do repozytorium, może robić te rzeczy. Jeśli chodzi o rozwój, dlaczego nie dać programistom swobody, w granicach rozsądku, do odejścia? Pod warunkiem, że dysponujesz protokołem do uzgadniania połączeń, a twoje centralne repozytorium (-a) są nazywane tak, jak chcesz, nie ma problemu. Powiedziawszy to, wspólny schemat nazewnictwa nie jest złym pomysłem. Zazwyczaj używam podgałęzi inicjały-wersja-funkcja-dla oddziałów osobistych i wersji dla oddziałów.

@UncleCJ Dodałem przykład, jak może to działać w firmie. Zasadniczo role OSS zastąpiono menedżerami, ale masz pomysł. Ma to dodatkową zaletę w stosunku do SVN, że twoi deweloperzy mogą również pracować offline (potrzebują tylko sieci do ściągania / pchania) i myślę, że ułatwia testowanie funkcji, jeśli dobrze je zaimplementujesz.

Wow, to naprawdę świetny przykład, możemy zacząć używać czegoś takiego do ukończenia szkoły. Nie chodziło mi tak bardzo o to, że ponieważ nie tworzymy OSS, wszyscy muszą być regulowani, w rzeczywistości jesteśmy dość małym i płaskim zespołem, ale musimy starać się efektywnie współpracować według napiętego harmonogramu, a także uczyć się jako zespół . Właśnie dlatego zadaję te głupie pytania, aby później pomóc pozostałej części zespołu :-). Z #git zdałem sobie również sprawę, że źle zdefiniowana linia bazowa w połączeniu z naciskiem na skrócenie czasu realizacji powoduje, że potykamy się na nogach ... wrócimy później.
HiQ CJ,

To jest w porządku - byłem tam niedawno, i właśnie tak wybrałem ten przykład, próbując go i wiele nie udając ... a także dostosowując się do sposobów działania projektu OSS. Myślę, że prawdziwym biggiem jest to, że nie ma znaczenia, jak się rozgałęziasz i gdzie są twoje repozytoria ... możesz je zdefiniować w dowolny sposób, co było dla mnie naprawdę szokujące! Ale pozwala ci robić ciekawe rzeczy. W każdym razie, powodzenia i miłej zabawy!

9

Model, który wykorzystałem z dobrymi wynikami, jest następujący:

„Błogosławione” repozytorium, które wszyscy popychają i wyciągają do / z, w zasadzie topologii klient-serwer.

Nie ma gałęzi master, więc żaden programista nie może wypchnąć żadnego kodu do „mainline”.

Wszystkie zmiany dotyczą gałęzi tematycznych. Nazwaliśmy przestrzeń nazw, aby łatwo wykryć, kto jest za to odpowiedzialny: jn / newFeature lub jn / issue-1234

Istnieje również mapowanie prawie 1 do 1 między gałęziami a kartami Kanban / Scrum na tablicy.

Aby zwolnić gałąź, jest ona wypychana do błogosławionej repozytorium, a karta Kanban jest przenoszona do gotowości do przeglądu.

Następnie, jeśli oddział zostanie zaakceptowany przez przegląd, jest on kandydatem do wydania.

Wydanie następuje, gdy zestaw zaakceptowanych gałęzi jest scalany ze sobą i oznaczany numerem wersji.

Przesuwając nowy tag do błogosławionej repozytorium, istnieje nowa możliwa podstawa dla nowych funkcji.

Aby uniknąć konfliktów scalania, programiści proszeni są o aktualizację (scalenie) swoich niewydanych gałęzi do najnowszego tagu wydania.


2

Osobiście staram się zachować tylko kod gotowy do wydania w gałęzi master.

Kiedy pracuję nad nową funkcją lub poprawką, robię to w oddziale. Testuję także w oddziale. Jeśli wszystko się powiedzie, tylko wtedy scalam / rebase z powrotem w master.

Staram się również używać typowych konwencji nazewnictwa gałęzi, takich jak:

  • bugfix / recursive_loop
  • bugfix / sql_timeout
  • feature / new_layout
  • funkcja / ulepszone wyszukiwanie
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.