Najlepsza strategia rozgałęziania przy ciągłej integracji?

100

Jaka jest najlepsza strategia rozgałęziania do zastosowania, gdy chcesz przeprowadzić ciągłą integrację?

  1. Rozgałęzienie wydania: rozwijaj na pniu, zachowaj gałąź dla każdego wydania.
  2. Rozgałęzianie funkcji: rozwijaj każdą funkcję w oddzielnej gałęzi, scalaj tylko wtedy, gdy jest stabilna.

Czy ma sens jednoczesne stosowanie obu tych strategii? Tak jak w przypadku każdej wersji, ale tworzysz również gałąź dla dużych funkcji? Czy jedna z tych strategii lepiej współgra z ciągłą integracją? Czy korzystanie z ciągłej integracji miałoby sens nawet w przypadku niestabilnego pnia?

KingNestor
źródło
2
Uwaga dodatkowa: niektórzy twierdzą, że nawet po wprowadzeniu nowych funkcji wszystko powinno być zawsze stabilne. Z drugiej strony może to być nieco idealistyczne.
Keith Pinson

Odpowiedzi:

21

Temat jest dla mnie bardzo interesujący, ponieważ w mojej codziennej pracy w dużym stopniu polegam na oddziałach.

  • Pamiętam, jak Mark Shuttleworth zaproponował model utrzymujący główną gałąź w nienaruszonym stanie, jednocześnie wychodząc poza konwencjonalne CI. Opublikowałem o tym tutaj .
  • Ponieważ jestem zaznajomiony z tempomatem, ja też napisał o oddziałach zadaniowych i CI tutaj . To samouczek krok po kroku wyjaśniający, jak to zrobić za pomocą Plastic SCM .
  • Wreszcie, znalazłem kilka tematów dotyczących CI (i potencjalnie mówiąc o rozgałęzieniach) w książce Duvalla o CI również bardzo interesujących .

Mam nadzieję, że linki okażą się interesujące.

pablo
źródło
Dodaliśmy obsługę Bamboo do wykonywania gałęzi na zadanie codicesoftware.blogspot.com/2012/02/… i wygląda na to, że ich najnowsza wersja zrobi to natywnie z kilkoma kontrolkami wersji, w tym dvcs.
pablo
20

Odpowiedź zależy od wielkości Twojego zespołu i jakości kontroli źródła oraz możliwości prawidłowego scalania złożonych zestawów zmian. Na przykład w pełnej gałęzi kontroli źródeł, takiej jak CVS lub SVN, scalanie może być trudne i możesz być lepszy z pierwszym modelem, podczas gdy przy użyciu bardziej złożonego systemu, takiego jak IBM ClearCase i przy większym rozmiarze zespołu, możesz być lepszy z drugim model lub połączenie obu.

Osobiście oddzieliłbym model gałęzi funkcji, w którym każda główna cecha jest rozwijana w oddzielnej gałęzi, z podgałęziami zadań dla każdej zmiany dokonanej przez indywidualnego programistę. Gdy funkcje się stabilizują, są łączone z pnia, który utrzymujesz w miarę stabilny i przez cały czas przechodzisz wszystkie testy regresji. Gdy zbliżasz się do końca cyklu wydania i wszystkie gałęzie funkcji zostaną scalone, stabilizujesz i rozgałęziasz gałąź systemu wydań, w której robisz tylko poprawki błędów stabilności i niezbędne backporty, podczas gdy trunk jest używany do tworzenia następnego wydania i znowu ty rozgałęzić się na nowe gałęzie funkcji. I tak dalej.

W ten sposób trunk zawiera zawsze najnowszy kod, ale udaje Ci się utrzymać go w miarę stabilny, tworząc stabilne etykiety (znaczniki) przy głównych zmianach i łączeniach funkcji, gałęzie funkcji są rozwijane w szybkim tempie z ciągłą integracją, a poszczególne podgałęzie zadań mogą być często odświeżono z gałęzi funkcji, aby wszyscy pracujący nad tą samą funkcją były zsynchronizowani, jednocześnie nie wpływając na inne zespoły pracujące nad różnymi funkcjami.

Jednocześnie masz w historii zestaw gałęzi wydań, w których możesz zapewnić backporty, wsparcie i poprawki dla swoich klientów, którzy z jakiegokolwiek powodu pozostają przy poprzednich wersjach produktu lub nawet najnowszej wydanej wersji. Podobnie jak w przypadku łącza trunk, nie konfiguruje się ciągłej integracji w gałęziach wydania, są one starannie integrowane po przejściu wszystkich testów regresji i innych kontroli jakości wydania.

Jeśli z jakiegoś powodu dwie funkcje są współzależne i wymagają wzajemnych zmian, możesz rozważyć opracowanie obu w tej samej gałęzi funkcji lub wymagać, aby funkcje regularnie łączyły stabilne części kodu z linią główną, a następnie odświeżały zmiany z trunk do wymiany kodu między gałęziami linii głównej. Lub jeśli chcesz odizolować te dwie funkcje od innych, możesz utworzyć wspólną gałąź, z której możesz rozgałęzić te gałęzie i której możesz użyć do wymiany kodu między funkcjami.

Powyższy model nie ma większego sensu w przypadku zespołów poniżej 50-ego roku życia i systemu kontroli wersji bez rzadkich gałęzi i odpowiednich możliwości łączenia, takich jak CVS lub SVN, co sprawiłoby, że cały ten model byłby koszmarem konfiguracji, zarządzania i integracji.

Jiri Klouda
źródło
5
Nie jestem pewien, czy się zgodzę, że to, co opisujesz, nie ma sensu dla zespołów poniżej 50-go roku życia. Widzę również korzyści dla znacznie mniejszych zespołów. +1
Aardvark
2
Oczywiście są korzyści dla zespołów dowolnej wielkości. Pytanie brzmi, przy jakiej wielkości zespołu korzyści przewyższają koszty związane z ciężkim procesem.
Jiri Klouda,
Jest to podobne do modelu GitFlow i / lub GitHubFlow. Nie sądzę, żeby te modele ułatwiały Continuous Integration (CI). Moim zdaniem Trunk Based Development to znaczące ulepszenie tych modeli.
Yani
Możesz zobaczyć, że ten komentarz faktycznie poprzedza oryginalne wydanie git flow. Nie do końca wiem, co masz na myśli mówiąc „lepiej”. Wspierałem zespoły złożone z 1, 5, 25, 150, 1000 i 20 000 programistów pracujących nad projektami, które były do ​​pewnego stopnia zintegrowane. Wymagania są różne, a „lepsze” jest pojęciem bardzo względnym. Czy kiedykolwiek musisz cofnąć kod? Poprawki bezpieczeństwa? Jeśli nie, to twoje życie jest proste. SaaS jest bezpośrednim wynikiem ograniczeń nałożonych przez rozwój oparty na magistrali. Flagi funkcji są tak samo złożone, jak gałęzie funkcji. Z wyjątkiem tego, że dowiadujesz się od klientów tylko wtedy, gdy pęka ich permutacja.
Jiri Klouda
9

Osobiście uważam, że stabilny pień i rozgałęzianie są dużo czystsze. W ten sposób testerzy i im podobni mogą pozostać przy jednej „wersji” i aktualizować z linii głównej, aby przetestować każdą funkcję, która jest kompletna.

Ponadto, jeśli wielu programistów pracuje nad różnymi funkcjami, wszyscy mogą mieć własne oddzielne gałęzie, a następnie połączyć się z linią główną po zakończeniu i wysłać funkcję do przetestowania bez konieczności przełączania się testera na wiele gałęzi w celu przetestowania różnych funkcji.

Jako dodatkowy bonus, istnieje pewien poziom testów integracyjnych, który jest wykonywany automatycznie.

Adnan
źródło
Czy nadal rozgałęziasz i tagujesz dla każdego głównego wydania? Albo po prostu tag?
KingNestor
1
Działa dobrze z CI, o ile gałęzie funkcji są połączone w trunk z pewną dyscypliną, aby nie mieć zepsutych kompilacji. Robię gałąź i tag dla każdego wydania produkcyjnego, które będzie używane tylko do naprawiania błędów. Można to natychmiast połączyć ze stabilnym pniem.
Adnan
@king Powiedziałbym, że prawdopodobnie zależy to od tego, co nazywasz wydaniem głównym, ale w każdym przypadku możesz tagować i rozgałęziać później, kiedy tego potrzebujesz (na podstawie tagu :))
eglasius
5

Myślę, że każda strategia może być używana z ciągłym rozwojem, pod warunkiem, że pamiętasz jedną z kluczowych zasad, które każdy programista zobowiązuje się każdego dnia do linii głównej / głównej.

http://martinfowler.com/articles/continuousIntegration.html#EveryoneCommitsToTheMainlineEveryDay

EDYTOWAĆ

Czytałem trochę tę książkę o CI, a autorzy sugerują, że rozgałęzianie według wydania jest ich preferowaną strategią rozgałęziania. Muszę się zgodzić. Rozgałęzianie według funkcji nie ma dla mnie sensu, gdy używam CI.

Spróbuję wyjaśnić, dlaczego myślę w ten sposób. Powiedzmy, że trzech programistów bierze jedną gałąź, aby pracować nad funkcją. Ukończenie każdej funkcji zajmie kilka dni lub tygodni. Aby zapewnić ciągłą integrację zespołu, muszą zobowiązać się do pracy w głównej gałęzi co najmniej raz dziennie. Gdy tylko zaczną to robić, tracą korzyści z tworzenia gałęzi funkcji. Ich zmiany nie są już oddzielone od wszystkich innych zmian deweloperskich. Skoro tak jest, po co w ogóle zawracać sobie głowę tworzeniem gałęzi funkcji?

Używanie rozgałęziania według wydania wymaga znacznie mniej łączenia między gałęziami (zawsze dobrze), zapewnia, że ​​wszystkie zmiany zostaną zintegrowane jak najszybciej i (jeśli zostaną wykonane poprawnie), że Twój kod będzie zawsze gotowy do wydania. Wadą rozgałęziania według wydania jest to, że musisz być znacznie bardziej ostrożny ze zmianami. Np. Duża refaktoryzacja musi być wykonywana przyrostowo, a jeśli już zintegrowałeś nową funkcję, której nie chcesz w następnej wersji, musisz ją ukryć za pomocą jakiegoś mechanizmu przełączania funkcji .

KOLEJNA EDYCJA

Na ten temat jest więcej niż jedna opinia. Oto post na blogu, który jest profesjonalnym odgałęzieniem z CI

http://jamesmckay.net/2011/07/why-does-martin-fowler-not-understand-feature-branches/

Phil Hale
źródło
interesujące, nie mogę już znaleźć tego posta.
Jirong Hu
5

Gałęzie wydania są bardzo przydatne, a nawet absolutnie wymagane, jeśli chcesz utrzymywać kilka wersji swojej aplikacji.

Gałęzie funkcji również są bardzo wygodne, zwłaszcza jeśli jeden programista musi popracować nad ogromną zmianą, podczas gdy inni nadal wydają nowe wersje.

Dlatego dla mnie używanie obu mechanizmów jest bardzo dobrą strategią.

Ciekawy link z Book of SVN .

SirFabel
źródło
4

Niedawno polubiłem ten model , używając git. Chociaż Twoje pytanie jest oznaczone jako „svn”, nadal możesz mieć z niego jakiś użytek.

Ciągła integracja może do pewnego stopnia zdarzyć się w gałęzi „deweloperskiej” (lub jakkolwiek to nazwiesz) w tym modelu, chociaż posiadanie długo działających gałęzi funkcji dla przyszłych wydań nie uczyniłoby jej tak sztywną, aby uwzględniać każdą zmianę zachodzącą gdzieś w kodzie. Pozostaje pytanie, czy naprawdę tego chcesz. Martin Fowler tak.

hermannloose
źródło
2

Ciągła integracja nie powinna być żadnym czynnikiem przy określaniu strategii tworzenia gałęzi. Twoje podejście do rozgałęziania powinno być wybrane na podstawie Twojego zespołu, opracowywanego systemu i dostępnych narzędzi.

Powiedziawszy to ...

  • nie ma powodu, dla którego CI nie może być używane w obu opisanych przez ciebie podejściach
  • te podejścia działają całkiem dobrze w połączeniu
  • żaden z nich nie działa „lepiej” niż drugi
  • CI ma sens w przypadku niestabilnego pnia

Na wszystko to odpowiadało czwarte pytanie na stronie, z której wziąłeś diagramy: http://blogs.collab.net/subversion/2007/11/branching-strat/

Zac Thompson
źródło
2

Dopóki rozumiesz zasady, zawsze możesz wymyślić na nowo najlepsze praktyki. Jeśli nie rozumiesz zasad, najlepsze praktyki zaprowadzą Cię aż tak daleko, zanim rozpadną się z powodu sprzecznych wymagań zewnętrznych.

Aby uzyskać najlepsze wprowadzenie do modelu głównego, przeczytaj to: https://web.archive.org/web/20120304070315/http://oreilly.com/catalog/practicalperforce/chapter/ch07.pdf

Przeczytaj link. Gdy już opanujesz podstawy, przeczytaj następujący artykuł czcigodnego Henrika Kniberga. Pomoże Ci to powiązać model Mainline z ciągłą integracją.

http://www.infoq.com/articles/agile-version-control

zvolkov
źródło
Rozdział O'Reilly nie jest już dostępny
Jason S
1

Kiedy zakładaliśmy nasz zespół, odziedziczyliśmy strategię opartą na wydaniach od dostawcy, który pierwotnie opracował system, za który mieliśmy być odpowiedzialni. Działało to do czasu, gdy nasi klienci zażądali, aby kilka opracowanych funkcji nie było włączanych do wydania (fyi ~ 250 tys. Linii kodu, ~ 2500 plików, Scrum z XP SDLC).

Następnie zaczęliśmy przyglądać się gałęziom opartym na funkcjach. To również działało przez jakiś czas - jak 2 miesiące, do momentu, gdy zdaliśmy sobie sprawę, że nasz proces testowania regresji zajmie ponad 2 tygodnie, co w połączeniu z niepewnością co do tego, co zostanie wydane, stworzyło ogromną niedogodność.

Ostatni "gwóźdź do trumny" czystych strategii SC przyszedł, kiedy zdecydowaliśmy, że powinniśmy mieć 1. stabilny pień i 2. Produkcja powinna zawierać BINARIE przetestowane pod kątem ST, UAT i regresji (nie tylko źródło - pomyśl CC).

To doprowadziło nas do opracowania strategii, która jest hybrydą między strategiami SC opartymi na funkcjach i wydaniach.

Więc mamy bagażnik. Każdy sprint rozgałęziamy gałąź sprintu (dla osób nie-zwinnych - sprint to tylko czasowy wysiłek programistyczny ze zmiennym wyjściem na podstawie złożoności). Z gałęzi sprintu tworzymy gałęzie funkcji i rozpoczyna się w nich równoległy rozwój. Gdy funkcje zostaną ukończone i przetestowane przez system, a my otrzymamy zamiar ich wdrożenia, są one scalane z gałęzią sprintu - niektóre mogą płynąć przez kilka sprintów, zwykle tych bardziej złożonych. Gdy sprint dobiega końca, a funkcje są kompletne ... „zmieniamy nazwę” gałęzi sprintu na „regresja” (dzięki temu CruiseControl może ją przejąć bez żadnej rekonfiguracji), a następnie rozpoczyna się testowanie regresji / integracji na zbudowanym w CC UCHO. Kiedy to wszystko jest zrobione, trafia do produkcji.

Krótko mówiąc, gałęzie oparte na funkcjach są używane do tworzenia, testowania systemu i funkcjonalności UAT. Gałąź sprintu (tak naprawdę gałąź wydania) służy do selektywnego łączenia funkcji na żądanie i testów integracji.

Teraz jest pytanie do społeczności - oczywiście mamy problemy z ciągłą integracją z powodu faktu, że rozwój odbywa się w wielu gałęziach i narzutów związanych z rekonfiguracją CruiseControl. Czy ktoś może zasugerować i poradzić?

XAvatar
źródło
Niekoniecznie zgadzam się z wnioskami, ale dziękuję za dyskusję o Twoim procesie. Nie ma jednego uniwersalnego rozwiązania.
RaoulRubin
0

Tak jak ja to widzę, chcesz mieć ograniczony zestaw gałęzi, na których możesz się skupić. Ponieważ chcesz, aby testy, wskaźniki jakości kodu i wiele interesujących rzeczy były uruchamiane z kompilacjami, zbyt wiele raportów prawdopodobnie spowoduje, że przegapisz informacje.

Kiedy i co rozgałęzić, zwykle zależy od wielkości zespołu i wielkości rozwijanych funkcji. Myślę, że nie ma złotej zasady. Upewnij się, że korzystasz ze strategii, dzięki której możesz uzyskać informacje zwrotne wcześnie / często, co obejmuje zapewnienie jakości od samego początku funkcji. Jakość oznacza, że ​​w miarę automatyzacji w miarę rozwoju zespołu, jeśli rozgałęziasz się na duży zestaw funkcji, który buduje zespół, musisz mieć również udział w zespole.

ps Skąd masz te odniesienia do podejścia? - nie uważa, że ​​te wykresy przedstawiają wszystkie opcje

Aktualizacja 1: Rozwiń, dlaczego powiedziałem, że to nie jest złota zasada. Zasadniczo dla stosunkowo małych zespołów uważam, że najlepiej jest stosować podejście polegające na mieszaniu. Gałęzie funkcji są tworzone, jeśli jest to coś długiego, a część zespołu będzie nadal dodawać mniejsze funkcje.

eglasius
źródło
Ma też trochę więcej. Ale wydaje mi się, że rozgałęzianie funkcji i rozgałęzianie zwolnień są 2 najbardziej powszechnymi.
KingNestor
0

Dave Farley , autor Continuous Delivery , nazwał Trunk Based Development (TBD) podstawą ciągłej integracji (CI) i ciągłego dostarczania (CD). On mówi:

Każda forma rozgałęzienia jest sprzeczna z ciągłą integracją.

Mówi też:

Rozgałęzianie funkcji jest bardzo przyjemne z punktu widzenia indywidualnego programisty, ale nie jest optymalne z punktu widzenia zespołu. Wszyscy chcielibyśmy móc ignorować to, co robią wszyscy inni i kontynuować naszą pracę. Niestety kod nie jest taki. Nawet w bardzo dobrze opracowanych bazach kodu z piękną separacją problemów i cudownie luźno powiązanymi komponentami, niektóre zmiany wpływają na inne części systemu.

Programowanie oparte na magistrali (TBD) to praktyka polegająca na integracji zmian kodu w magistrali (czyli głównej, głównej) co najmniej raz dziennie - najlepiej kilka razy dziennie. Continuous Integration (CI) to podobna praktyka, z tym wyjątkiem, że obejmuje również weryfikację zmian kodu za pomocą testów automatycznych. Najlepszą strategią rozgałęziania jest praca bezpośrednio z linii głównej i przeglądanie kodu poprzez programowanie w parach . Jeśli z jakiegoś powodu nie możesz sparować lub po prostu naprawdę chcesz się rozgałęzić, upewnij się, że twoje gałęzie są krótkotrwałe (mniej niż jeden dzień).

Pracuję na Trunk, „master” w moich repozytoriach GIT. Zobowiązuję się do lokalnego masteringu i natychmiast wysyłam, gdy jestem podłączony do sieci, do mojego centralnego repozytorium master, w którym działa CI. Otóż ​​to!

W przypadku dużych funkcji (tj. Takich, które trwają dłużej niż jeden dzień), spróbuj podzielić je na małe fragmenty logiki, które można zintegrować z magistralą bez uszkadzania oprogramowania. Można również użyć technik, takich jak oznaczanie funkcji i rozgałęzianie według abstrakcji, które umożliwiają wdrażanie niepełnej pracy bez wpływu na użytkowników końcowych.

Używam branch by abstract, dark release, a czasem flag cech. W zamian otrzymuję szybką, ostateczną (przynajmniej jeśli chodzi o jakość moich testów) informację zwrotną.

Yani
źródło
Dave Farley i Jez Humble po prostu mylą się co do rozgałęziania. Powodem tego jest to, że koduje ważne założenie „nigdy nie będziesz musiał manipulować kodem na poziomie funkcji, a jeśli, to okaże się, że jest to kosztowna operacja” i opierają swoją ocenę na innym założeniu „scalanie jest zbyt kosztowne z automatycznym łączy się prawie niemożliwe na dużą skalę ”. Jeśli te dwa założenia nie są prawdziwe, jeśli żyjesz w świecie, w którym łączenie jest tanie, ale musisz manipulować kodem na poziomie funkcji, aby uzyskać porty tylne i poprawki bezpieczeństwa, to ich oświadczenia się załamują. Jest to jednak rzadki przypadek.
Jiri Klouda,
Niektóre firmy muszą również przenieść funkcje do przyszłych wydań, po tym, jak te funkcje napotkają na przeszkody we wdrażaniu i wstrzymują wydanie. Czasami istnieje opcja pozostawienia kodu, tak jak w produktach SaaS, ale jeśli kod zostanie udostępniony klientom, może to nie być opcja, ponieważ mogą go przeanalizować konkurenci. Tak wiele kodu w dzisiejszych czasach nie jest kompilowanych, a nawet jeśli tak jest, flagi definicji / funkcji w kodzie są na tym samym poziomie złożoności co gałęzie.
Jiri Klouda
-3

Myślę, że narzędzia, których używasz, mają tutaj duży wpływ.

  • Jeśli używasz subversion, trzymaj się opcji 1 i zwolnij z gałęzi.
  • Jeśli używasz GIT, opcja 2 będzie dla Ciebie dobra.
Tony Zampogna
źródło
2
Rozgałęzianie funkcji można łatwo osiągnąć za pomocą dowolnego SCM
hdost