Rozgałęziać się czy nie rozgałęziać?


84

Do niedawna mój przepływ pracy programistycznej był następujący:

  1. Uzyskaj tę funkcję od właściciela produktu
  2. Utwórz oddział (jeśli funkcja jest dłuższa niż 1 dzień)
  3. Zaimplementuj w oddziale
  4. Scal zmiany z gałęzi głównej do mojej gałęzi (aby zmniejszyć konflikty podczas scalania wstecznego)
  5. Scal moją gałąź z powrotem do głównej gałęzi

Czasami były problemy z łączeniem, ale ogólnie mi się podobało.

Ale ostatnio widzę coraz więcej zwolenników pomysłów, aby nie tworzyć oddziałów, ponieważ utrudnia to praktykę ciągłej integracji, ciągłej dostawy itp. I to szczególnie zabawne wydaje się od osób z rozproszonym doświadczeniem VCS, które tak wiele mówiły o wielkich połączonych implementacjach Git, Mercurial itp.

Pytanie brzmi: czy powinniśmy obecnie korzystać z oddziałów?


2
Jestem pewien, że jest to odpowiednia platforma do tego, ale tak, rozgałęziłbym się. Ale może powinieneś pomyśleć o ponownym scaleniu niektórych
zestawów

1
Wygląda na to, że potrzebują lepszych strategii łączenia.
b01

1
Zawsze widziałem wszystkie zatwierdzenia jako połączenie, nawet jeśli tylko z lokalnego na zdalny. Scalanie z gałęzi jest takie samo, tylko większe zestawy zmian, więc nie rozumiem, jaki jest argument. Czy ktoś dokonał jakiegokolwiek rzeczywistego profilowania wydajności którejkolwiek z tych technik, czy też jest to tylko optymalizacja przedwczesna?
tylermac,


7
Nie przesyłaj tego samego postu dosłownie do wielu witryn Stack Exchange.
Adam Lear

Odpowiedzi:


64

Chyba, że wszyscy pracujemy na tym samym drzewie roboczym, to za pomocą oddziałów, czy je tak nazwać, czy nie. Za każdym razem, gdy programista sprawdza swoje działające drzewo, tworzy osobną lokalną gałąź rozwoju i za każdym razem, gdy się rejestruje, dokonuje scalenia. W przypadku większości zespołów pytanie nie brzmi, czy korzystasz z oddziałów, ile jest pytań i w jakim celu ?

Jedynym sposobem na prawdziwie „ciągłą” integrację jest, aby każdy mógł pracować z tego samego drzewa roboczego. W ten sposób natychmiast wiesz, czy Twoje zmiany negatywnie wpływają na czyjeś zachowanie. Oczywiście, to nie do utrzymania. Potrzebujesz pewnego stopnia izolacji w oddziale, aby cokolwiek osiągnąć, nawet jeśli ta „gałąź” jest tylko lokalnym katalogiem roboczym. Potrzebna jest odpowiednia równowaga integracji i izolacji.

Z mojego doświadczenia wynika, że korzystanie z większej liczby gałęzi poprawia stopień integracji, ponieważ integracja jest wykonywana dokładnie z osobami, które należy wykonać, a wszyscy inni mogą łatwiej izolować niepowiązane problemy, jeśli jest to wymagane.

Na przykład ostatni dzień spędziłem na śledzeniu trzech niedawno wprowadzonych błędów integracyjnych w naszej kompilacji, które blokowały moją „prawdziwą” pracę. Czy po dołożeniu należytej staranności w zgłaszaniu tych błędów osobom, które muszą je naprawić, mam teraz tylko poczekać, aż skończą, aby kontynuować moją pracę? Oczywiście nie. Utworzyłem tymczasową lokalną gałąź, która przywraca te zmiany, dzięki czemu mogę mieć stabilną linię bazową do pracy, jednocześnie otrzymując najnowsze zmiany z poprzedniej wersji.

Bez możliwości utworzenia nowej gałęzi w tym celu zostałbym zredukowany do jednej z trzech opcji: albo cofnij zmiany w centralnym repozytorium, ręcznie zachowaj łatki, które cofają je w moim działającym drzewie i spróbuj nie przypadkowo je sprawdzić lub wróć do wersji przed wprowadzeniem tych błędów. Pierwsza opcja prawdopodobnie przerwie jakąś inną zależność. Druga opcja to dużo pracy, więc większość ludzi wybiera trzecią opcję, która zasadniczo uniemożliwia wykonanie większej ilości prac integracyjnych do czasu usunięcia wcześniej znalezionych błędów.

Mój przykład używał prywatnego oddziału lokalnego, ale ta sama zasada dotyczy oddziałów współdzielonych. Jeśli udostępniam swój oddział, być może 5 innych osób będzie w stanie kontynuować swoje podstawowe zadania zamiast wykonywać redundantne prace integracyjne, a zatem w sumie wykonywane są bardziej przydatne prace integracyjne. Problem z rozgałęzianiem i ciągłą integracją nie polega na tym, ile masz gałęzi, ale na tym, jak często je łączysz.


1
Jeśli odwrócisz niechciane zatwierdzenia w nowej gałęzi, czy to nie odwróci ich w gałęzi głównej po scaleniu? Osobiście rozgałęziałbym się od punktu przed niepożądanymi zmianami i wybieram zmiany, na których polegam, do nowej gałęzi.
Anthony

@anthony Najprawdopodobniej wyczyścisz swoją historię (usuniesz zmiany) przed połączeniem. Ktoś przeciwko przepisywaniu historii prawdopodobnie lepiej będzie postępować zgodnie z tą metodą.
idbrii

Jeśli wyjmiesz rozgałęzienia i przepisywanie historii, po co w ogóle korzystać z Git?
everton

80

pytanie brzmi: czy powinniśmy obecnie korzystać z oddziałów?

Około pół roku temu zostałem przydzielony do badania, aby odpowiedzieć na to pytanie. Oto podsumowanie na podstawie zbadanych referencji (wymienionych poniżej)

  • nie ma wspólnie uzgodnionej „najlepszej” strategii rozgałęziania mającej zastosowanie do każdego projektu
    • wydaje się, że większość zasobów zgadza się, że wybór strategii produkcyjnej zależy od konkretnej specyfiki projektu
    • dygresja. Na podstawie powyższego wygląda na to, że wszelkie zmiany w strategii rozgałęzienia projektu muszą zostać przetestowane, zmierzone i porównane z innymi przetestowanymi opcjami
  • popularna opinia mówi, że połączenie z Subversion wymaga dużego wysiłku. Wszyscy, którzy porównali SVN i Git, zauważają, że scalanie jest znacznie łatwiejsze dzięki Git
  • ważnym czynnikiem wydaje się być to, czy uwolnienia produkcyjne pochodzą z pnia czy gałęzi. Zespoły wykonujące wydania prod z pnia (które wydają się nie być dość popularnym sposobem) są zasadniczo zabronione w stosowaniu niestabilnej strategii pnia . Zespoły wykonujące wydania produktów z oddziałów mają więcej opcji rozgałęziania do wyboru.
  • popularnymi strategiami wydają się być stabilny pień, niestabilny pień i gałąź rozwoju (integracji)

Bibliografia

  • http://msdn.microsoft.com/en-us/library/aa730834%28v=vs.80%29.aspx

    ... Wybór najlepszej strategii rozgałęziania jest działaniem równoważącym. Musisz zmniejszyć zyski wydajności w stosunku do zwiększonego ryzyka. Jednym ze sposobów walidacji wybranej strategii jest rozważenie scenariusza zmian. Na przykład, jeśli zdecydujesz się wyrównać gałęzie z architekturą systemu (na przykład gałąź reprezentuje komponent systemu) i oczekujesz znacznych zmian architektonicznych, być może będziesz musiał zrestrukturyzować swoje gałęzie oraz powiązane procesy i zasady przy każdej zmianie. Wybór nieodpowiedniej strategii rozgałęziania może spowodować narzuty procesowe i długie cykle integracji i wydawania, które są frustrujące dla całego zespołu ...

  • http://www.cmcrossroads.com/bradapp/acme/branching/

    ... Częsta, stopniowa integracja jest jednym z drogowskazów sukcesu, a jej brak często charakteryzuje porażkę. Obecne metody zarządzania projektami mają tendencję do unikania ścisłych modeli wodospadu i obejmują spiralne modele iteracyjnego / przyrostowego rozwoju i ewolucyjnego dostarczania. Przyrostowe strategie integracji, takie jak Merge Early i Często i ich warianty, są formą zarządzania ryzykiem, które próbuje wypłukać ryzyko na wcześniejszym etapie cyklu życia, gdy jest więcej czasu na zareagowanie na nie. Regularność rytmu między integracjami jest postrzegana przez [Boocha], [McCarthy] i [McConnell] jako wiodący wskaźnik stanu zdrowia projektu (jak „puls” lub „bicie serca”).  
     
    Nie tylko wczesna i częsta integracja ujawnia ryzyko wcześniej i w mniejszych „kawałkach”, ale także komunikuje zmiany między członkami drużyny ...

  • http://www.codinghorror.com/blog/2007/10/software-branching-and-parallel-universes.html

    ... W większości systemów kontroli źródła możesz tworzyć setki oddziałów bez żadnych problemów z wydajnością; to mentalny koszt śledzenia wszystkich gałęzi, o które naprawdę musisz się martwić ... Rozgałęzienie to złożona bestia. Istnieje wiele sposobów na rozgałęzienie i nikt nie jest w stanie powiedzieć, czy robisz to dobrze, czy źle ...

  • http://www.lostechies.com/blogs/derickbailey/archive/2010/02/24/branching-strategies-when-to-branch-and-merge.aspx

    ... Istnieje wiele aspektów systemu, które należy wziąć pod uwagę podczas rozgałęziania kodu ... Ostatecznie, celem jest zapewnienie piaskownicy dla kontekstu, w którym kod jest pisany. Zrozumienie dostępnych opcji, kiedy każda opcja najlepiej pasuje do danej sytuacji, a koszt tych opcji pomoże ci zdecydować, jak i kiedy rozgałęzić ...

  • http://www.snuffybear.com/ucm_branch.htm
    Uwaga: biorąc pod uwagę inne wymienione tutaj odniesienia, twierdzenie autora, że „w tym artykule opisano trzy kluczowe modele rozgałęziające stosowane w projektach inżynierii oprogramowania” nie wydaje się uzasadnione. Zastosowana terminologia nie wygląda na rozpowszechnioną ( EFIX , Model-1,2,3 itd.).

  • http://svn.haxx.se/users/archive-2007-10/att-0101/SCMBranchingModels-talkback.pdf
    Odnośnik przedstawia interesujący przykład trudności w komunikowaniu strategii rozgałęziania.

  • http://simpleprogrammer.com/2010/06/04/simple-branching-strategy-part-1-back-to-basics/
    ... Uprość to. Moim zdaniem praca bezpośrednio z pnia jest zdecydowanie najlepszym podejściem.  
     
    To prawie brzmi jak herezja, kiedy faktycznie wpisuję ją na ekranie, ale jeśli wytrzymasz przez chwilę, nie tylko pokażę ci, dlaczego uważam, że jest to niezbędne dla procesu zwinnego, ale pokażę, jak aby działało ...  
     
    ... Gdybym musiał oprzeć moje rozumowanie na jednym solidnym argumencie, byłaby to wartość ciągłej integracji. W przeszłości pisałem na blogu o wartości CI i najlepszych praktykach . Jestem wielkim orędownikiem CI ...  
     
    ... Naprawdę trzeba zadać sobie pytanie tutaj: „Czy wszystko napowietrznej jesteś ponoszenia z robienie skomplikowanych rozgałęzienia i łączenie strategii wynikającej z rzeczywistej wartości, która nie istnieje na bardziej prosty strategii?” ...  
     
    .. Strategia, którą skutecznie stosowałem w przeszłości i rozwijałem się z czasem. Podsumuję to krótko tutaj.

  • http://www.codelathe.com/blog/index.php/2009/07/02/a-svn-branching-strategy-that-works/
    ... Wreszcie pamiętaj, że nie ma idealnej strategii rozgałęziania i łączenia. To zależy w dużej mierze od twojego unikalnego środowiska programistycznego ...

  • http://blog.perforce.com/blog/?cat=62
    ... Najgorszym scenariuszem jest wprowadzenie problemu „scalania semantycznego”, w którym wynik automatycznego scalania jest nieprawidłowy, ale kompiluje się OK i przemyka testowanie, być może nawet wystarczająco długo, by być zauważalnym przez klienta błędem. Eek!  
     
    Dodając zniewagę do obrażeń, ponieważ mogą one dłużej uniknąć wykrycia, problemy scalania semantycznego są trudniejsze do naprawienia później, ponieważ zmiana nie jest już świeża w umyśle twórcy, który ją wprowadził. (Zazwyczaj najlepiej scalić zmiany wkrótce po ich wprowadzeniu, najlepiej przez programistę, który je wprowadził, jeśli jest to praktyczne) ...

  • https://stackoverflow.com/questions/34975/branching-strategies
    Członkowie społeczności dzielą się różnymi doświadczeniami w różnych projektach przy użyciu różnych strategii rozgałęziania. Brak uzgodnionego konsensusu w sprawie „najlepszego” lub „najgorszego”.

  • http://www.stickyminds.com/s.asp?F=S16454_COL_2
    Zasadniczo krótkie streszczenie rzeczy przedstawione w http://oreilly.com/catalog/practicalperforce/chapter/ch07.pdf

    • http://www.stickyminds.com/s.asp?F=S16511_COL_2
      ... Istnieją trzy typowe podejścia do decydowania, kiedy i jak wykonać oddział:
      • Utwórz gałąź wydania po zakończeniu funkcji i zaplanuj naprawienie problemów z ostatniej chwili w tym wierszu kodu. W tym przypadku gałąź wydania jest tak naprawdę „wierszem kodu przygotowawczego do wydania”, jak opisano w wzorcach zarządzania konfiguracją oprogramowania , ponieważ oczekuje się, że nadal jest wiele do zrobienia.
      • Zmień styl pracy, aby uniknąć końcowej pracy integracyjnej, pracując poza aktywną linią programistyczną.
      • Rozgałęzienie dla nowej pracy poprzez utworzenie gałęzi zadania i scalenie tej pracy w aktywną linię programistyczną po zakończeniu wydania.
        ... Uzasadnieniem dla rozgałęzień jest izolacja kodu na końcu wydania, aby mógł się ustabilizować. Izolacja poprzez rozgałęzienie często maskuje problem z jakością, który ostatecznie przejawia się w dodatkowym koszcie utrzymania równoległych strumieni przed wydaniem produktu. Rozgałęzienie jest łatwe. Raczej jest to łączenie i poznawczy narzut związany ze zrozumieniem, jak zmiany przepływają między gałęziami, które są trudne, dlatego ważne jest, aby wybrać proces, który minimalizuje koszty rozgałęzień i scalania ...
  • http://nvie.com/posts/a-successful-git-branching-model/ Strategia zorientowana na Git.
    ... Uważamy origin / master za główną gałąź, w której kod źródłowy HEAD zawsze odzwierciedla stan gotowości do produkcji .  
     
    Uważamy pochodzenie / rozwój za główną gałąź, w której kod źródłowy HEAD zawsze odzwierciedla stan z najnowszymi dostarczonymi zmianami programistycznymi dla następnej wersji. Niektórzy nazywają to „gałęzią integracji”. To tutaj budowane są automatyczne kompilacje nocne.

  • http://svnbook.red-bean.com/en/1.5/svn.branchmerge.html
    ... zasady projektu różnią się znacznie w zależności od tego, kiedy należy utworzyć gałąź funkcji. Niektóre projekty nigdy nie używają gałęzi funkcji: commits do / trunk są dostępne dla wszystkich. Zaletą tego systemu jest to, że jest prosty - nikt nie musi się uczyć o rozgałęzianiu lub scalaniu. Wadą jest to, że kod trunk jest często niestabilny lub nie nadaje się do użytku. Inne projekty wykorzystują gałęzie do skrajności: żadna zmiana nigdy nie jest bezpośrednio związana z pniem. Nawet najbardziej trywialne zmiany są tworzone w krótkotrwałej gałęzi, dokładnie sprawdzane i łączone w pień. Następnie gałąź jest usuwana. System ten gwarantuje wyjątkowo stabilny i użyteczny bagażnik przez cały czas, ale kosztem ogromnegokoszty ogólne.  
     
    Większość projektów stosuje podejście zorientowane na środek drogi. Zazwyczaj nalegają, aby / trunk kompilował i przechodził testy regresji przez cały czas. Gałąź funkcji jest wymagana tylko wtedy, gdy zmiana wymaga dużej liczby zatwierdzeń destabilizujących. Dobrą zasadą jest zadawanie tego pytania: jeśli programista pracował kilka dni w odosobnieniu, a następnie dokonał dużej zmiany naraz (tak aby / trunk nigdy nie był destabilizowany), czy byłaby to zbyt duża zmiana, aby ją przejrzeć? Jeśli odpowiedź na to pytanie brzmi „tak”, zmianę należy opracować w gałęzi funkcji. Ponieważ programista dokonuje przyrostowych zmian w oddziale, mogą być łatwo przeglądane przez współpracowników.  
     
    Wreszcie pojawia się kwestia tego, jak najlepiej utrzymywać gałąź funkcji w „synchronizacji” z pniem w miarę postępu pracy. Jak wspomnieliśmy wcześniej, istnieje ogromne ryzyko związane z pracą w oddziale przez tygodnie lub miesiące; zmiany pnia mogą nadal napływać do tego stopnia, że ​​dwie linie rozwoju różnią się tak bardzo, że może stać się koszmarem próbującym połączyć gałąź z powrotem do pnia.  
     
    Takiej sytuacji najlepiej uniknąć, regularnie łącząc zmiany pnia z oddziałem. Wymyśl polisę: raz w tygodniu połącz wartości pnia zeszłego tygodnia z oddziałem ...

  • http://thedesignspace.net/MT2archives/000680.html
    ... Ta sekcja samouczka Eclipse CVS jest oparta na artykule Paula Glezena na stronie internetowej Eclipse: Rozgałęzianie za pomocą Eclipse i CVS i jest używana za jego zgodą na warunkach licencja EPL. Zmiany, które wprowadzam w jego wersji, polegają głównie na rozszerzeniu jej o kolejne obrazy i wyjaśnienia krok po kroku oraz zintegrowanie z własnymi samouczkami dla początkujących, aby uczynić ją bardziej dostępną dla początkujących i projektantów. Doświadczeni programiści prawdopodobnie wolą pracować od wersji Paula ...

  • http://learnsoftwareprocesses.com/2007/12/29/common-branching-strategies/
    ... Oto niektóre z typowych modeli rozgałęziających:  

    1. Model międzygałęziowy: Jedną z najczęstszych strategii rozgałęziania jest dostosowanie oddziałów do wersji produktów. Oddział posiada wszystkie zasoby programistyczne dla jednej wersji. Czasami aktualizacje muszą zostać scalone z jednej wersji do drugiej, ale zwykle nigdy się nie łączą. Oddziały zostaną wycofane po wycofaniu wersji.  
    2. Oddziały na promocję: Innym bardzo popularnym podejściem jest dostosowanie oddziałów do poziomów promocji zasobów oprogramowania. Konkretna wersja programistyczna jest podzielona na gałąź Test, w której przeprowadzana jest cała integracja i testy systemu. Po zakończeniu testowania zasoby programistyczne są rozgałęzione do działu produkcji i ostatecznie wdrożone.  
    3. Oddział według zadania: Aby uniknąć nakładania się zadań (lub działań) i utraty wydajności, możesz odizolować je w osobnym oddziale. Należy pamiętać, że są to oddziały krótkoterminowe, które należy połączyć natychmiast po zakończeniu zadania, ponieważ w przeciwnym razie wymagany wysiłek scalania może przekroczyć korzyści produktywności wynikające z ich utworzenia.  
    4. Odgałęzienie na komponent: Można wyrównać każdą gałąź z architekturą systemu. W tej strategii rozgałęziasz poszczególne komponenty (lub podsystemy). Następnie każdy zespół opracowujący komponent decyduje, kiedy ponownie połączyć swój kod z linią programistyczną, która służy jako gałąź integracji. Ta strategia może działać dobrze, jeśli architektura systemu jest na miejscu, a poszczególne komponenty mają dobrze zdefiniowane interfejsy. Fakt, że tworzysz komponenty w gałęziach, umożliwia bardziej szczegółową kontrolę nad zasobami programistycznymi.  
    5. Branża według technologii: kolejna strategia rozgałęziania dostosowana do architektury systemu. W tym przypadku gałęzie są dostosowane do platform technologicznych. Wspólny kod jest zarządzany w oddzielnej gałęzi. Ze względu na wyjątkowy charakter zasobów programistycznych zarządzanych w oddziałach, prawdopodobnie nigdy nie łączą się ...
  • http://msdn.microsoft.com/en-us/library/bb668955.aspx
    ... Zapoznaj się z wytycznymi dotyczącymi rozgałęziania i łączenia w „Wytycznych dotyczących kontroli źródła” w niniejszym przewodniku, aby uzyskać podsumowanie wytycznych dotyczących rozgałęziania i łączenia. ... Rozgałęziając, weź pod uwagę następujące kwestie:

    • Nie rozgałęziaj, chyba że zespół programistów musi jednocześnie pracować nad tym samym zestawem plików. Jeśli nie masz co do tego pewności, możesz oznaczyć kompilację i utworzyć gałąź z tej kompilacji w późniejszym terminie. Scalanie gałęzi może być czasochłonne i złożone, zwłaszcza jeśli między nimi zachodzą znaczące zmiany.
    • Ułóż drzewa gałęzi w taki sposób, aby wystarczyło scalić je wzdłuż hierarchii (w górę i w dół drzewa gałęzi), a nie w całej hierarchii. Rozgałęzienie w hierarchii wymaga użycia bezpodstawnego scalenia, które wymaga bardziej ręcznego rozwiązywania konfliktów.
    • Hierarchia rozgałęzień oparta jest na nadrzędnym i podrzędnym odgałęzieniu, które mogą różnić się od fizycznej struktury kodu źródłowego na dysku. Planując połączenia, pamiętaj o logicznej strukturze gałęzi, a nie o strukturze fizycznej na dysku.
    • Nie rozgałęziaj się zbyt głęboko. Ponieważ wykonanie każdego scalenia i rozwiązanie konfliktu zajmuje dużo czasu, głęboka struktura rozgałęzień może oznaczać, że zmiany w gałęzi potomnej mogą zająć bardzo dużo czasu, zanim zostaną przeniesione do gałęzi głównej. Może to negatywnie wpłynąć na harmonogramy projektów i wydłużyć czas usuwania błędów.
    • Oddział na wysokim poziomie i dołącz pliki konfiguracyjne i źródłowe.
    • Rozwijaj swoją strukturę rozgałęzień w czasie.
    • Scalanie wymaga co najmniej jednego programisty do wykonania scalenia i rozwiązania konfliktów. Połączone źródło musi zostać gruntownie przetestowane, ponieważ podejmowanie złych decyzji dotyczących scalania, które mogą destabilizować kompilację, jest rzadkie.
    • Scalanie w hierarchii gałęzi jest szczególnie trudne i wymaga ręcznej obsługi wielu konfliktów, które w innym przypadku mogłyby być obsługiwane automatycznie.  
      Decyzję o utworzeniu oddziału można sprowadzić do tego, czy koszt łączenia konfliktów w czasie rzeczywistym jest wyższy niż narzut kosztów łączenia konfliktów między oddziałami ...
  • http://kashfarooq.wordpress.com/2009/11/23/bazaar-branching-strategy-with-a-subversion-trunk/

  • http://social.msdn.microsoft.com/Forums/en/tfsversioncontrol/thread/f127676c-8f05-410c-9a30-0eb43a26a9fa
    omówienie najlepszych praktyk dotyczących wydania strategii izolacji gałęzi izolacji w przypadku ewoluujących systemów.

  • http://branchingguidance.codeplex.com/
    „Wskazówki dotyczące rozgałęziania serwera Microsoft Team Foundation Server” - obszerny i szczegółowy dokument z zaleceniami dostosowanymi do różnych projektów: tutaj wersja HTML . Udowadnia, że ​​Microsoft nie wierzy w strategie rozgałęziania w jednym uniwersalnym podejściu.

  • https://stackoverflow.com/questions/597707/best-branching-strategy-when-doing-continuous-integration
    Jaka jest najlepsza strategia rozgałęziania, gdy chcesz wykonywać ciągłą integrację? ... Odpowiedź zależy od wielkości zespołu i jakości kontroli źródła oraz możliwości scalania poprawnie złożonych zestawów zmian ...

  • http://codicesoftware.blogspot.com/2010/03/branching-strategies.html
    ... CVS i SVN zniechęcały do ​​całej strategii rozgałęziania / łączenia, ponieważ nie były w stanie tego zrobić ... ... Prosta zasada: utwórz gałąź zadań dla każdej nowej funkcji lub poprawki, którą zaimplementujesz ... Może to brzmieć jak przesada dla użytkowników SVN / CVS, ale wiesz, że każdy nowoczesny SCM pozwoli ci utworzyć gałęzie w ciągu sekundy, więc nie ma prawdziwego narzutu.  
     
    Ważna uwaga: jeśli przyjrzysz się temu uważnie, zobaczysz, że mówię o używaniu gałęzi zadań jako list zmian bogatych ...

  • http://publib.boulder.ibm.com/infocenter/cchelp/v7r0m1/index.jsp?topic=/com.ibm.rational.clearcase.cc_proj.doc/c_bntr_plnbrstrat.htm
    ... Rozwój ma wpływ na zasady rozgałęziania cele projektu i zapewnia mechanizm kontroli ewolucji bazy kodu. Istnieje tyle odmian zasad rozgałęziania, ile organizacji używających kontroli wersji produktu Rational ClearCase. Ale są też podobieństwa, które odzwierciedlają powszechne przestrzeganie najlepszych praktyk ...

  • http://blogs.open.collab.net/svn/2007/11/branching-strat.html
    ... Model Subversion (lub dokładniej ogólny model open source) jest pokazany w niestabilnym modelu pnia. .

  • http://en.wikipedia.org/wiki/Trunk_%28software%29
    W dziedzinie rozwoju oprogramowania pień odnosi się do nienazwanej gałęzi (wersji) drzewa plików pod kontrolą wersji . Pień zwykle ma stanowić podstawę projektu, w ramach którego postępuje rozwój. Jeśli programiści pracują wyłącznie na pniu, zawsze zawiera najnowszą najnowszą wersję projektu, ale może być również najbardziej niestabilną wersją. Innym podejściem jest oddzielenie gałęzi od pnia, wprowadzenie zmian w tej gałęzi i scalenie zmian z powrotem do pnia, gdy gałąź okaże się stabilna i działa. W zależności od trybu programowania i zatwierdzeniazasady pień może zawierać najbardziej stabilną lub najmniej stabilną lub pośrednią wersję.  
     
    Często główne prace programistyczne mają miejsce w pniu, a stabilne wersje są rozgałęzione, a sporadyczne poprawki błędów są łączone z gałęzi do pnia. Kiedy opracowywanie przyszłych wersji odbywa się w gałęziach innych niż pień, zwykle dzieje się tak w przypadku projektów, które nie zmieniają się często lub gdy oczekuje się, że zmiana zajmie dużo czasu, zanim będzie gotowa do włączenia do pnia. .

  • http://www.mcqueeney.com/roller/page/tom/20060919
    ... Są to notatki z webinaru na temat najlepszych praktyk Subversion , przeprowadzonego 30 sierpnia 2006 przez CollabNet. ... Dwie strategie organizacyjne: niestabilny pień vs. stabilny pień ... ... PREFERUJ niestabilny pień, jeśli to możliwe ...

  • https://stackoverflow.com/questions/153812/subversion-is-trunk-really-the-best-place-for-the-main-development
    W SVN trunk jest zalecanym miejscem dla głównego rozwoju i używam tej konwencji dla wszystkich moich projektów. Oznacza to jednak, że pień jest czasami niestabilny, a nawet zepsuty ... ... czy nie lepiej byłoby zrobić „dziki rozwój” na jakiejś gałęzi, takiej jak / branch / dev, i połączyć się z pniem tylko, gdy kompilacja jest rozsądna solidny?

    • ... Tu właśnie ma nastąpić ciągły rozwój pnia. Naprawdę nie powinieneś mieć problemu z „uszkodzonym” kodem, jeśli wszyscy testują ich zmiany przed ich zatwierdzeniem. Dobrą zasadą jest wykonanie aktualizacji (pobranie całego najnowszego kodu z repozytoriów) po zakodowaniu zmian. Następnie zbuduj i wykonaj testy jednostkowe. Jeśli wszystko się kompiluje i działa, powinieneś to sprawdzić ...
    • ... Nie, bagażnik nie jest najlepszym miejscem. W naszej organizacji zawsze stosujemy takie podejście: Trunk zawiera kod wydania, więc zawsze się kompiluje. Z każdym nowym wydaniem / kamieniem milowym otwieramy nowy oddział. Za każdym razem, gdy deweloper jest właścicielem elementu, tworzy nowy oddział do tej gałęzi wydania i łączy go z gałęzią wersji dopiero po przetestowaniu. Gałąź wydania jest połączona w pień po testowaniu systemu ...
  • http://blog.yclian.com/2009/03/working-on-branches-and-stable-trunk.html
    ... Kiedyś pracowałem na pniu, ponieważ dla wszystkich projektów, nad którymi pracowałem, to albo byłem jedyny programista lub zespół zapewnił, że każdy kod odprawy zdał testy lokalne. W przeciwnym razie stworzyliśmy (nadal) gałęzie dla poprawek błędów, duży kod dla nowych funkcji itp.  
     
    Około 2 miesiące temu miałem krótką sesję git z Kamalem i podzielił się ze mną ideą historii / gałęzi . A kiedy mój zespół zaczął się rozwijać z większą liczbą deweloperów, odczuwam potrzebę zachęcania do dalszego rozwoju i teraz stało się to regułą. W przypadku projektu ze zautomatyzowanymi testami zdefiniowanymi z ustawieniem CI zagwarantowany jest stabilny bagażnik i ta praktyka może do niego bardzo dobrze wpasować.  
     
    Nie używamy git, ale Subversion, ponieważ tak się zaczęliśmy i nadal czujemy się z tym dobrze (przez większość czasu) ...

  • http://www.ericsink.com/scm/scm_branches.html
    Jest to część książki online o nazwie Source Control HOWTO , przewodnika po najlepszych praktykach kontroli źródła, kontroli wersji i zarządzania konfiguracją ...  
     
    ... Preferowane rozgałęzienie Erica Ćwicz ... Zachowaj „zasadniczo niestabilny” bagażnik. Czyń swój aktywny rozwój w bagażniku, którego stabilność wzrasta w miarę zbliżania się do wydania. Po wysyłce utwórz gałąź serwisową i zawsze utrzymuj ją bardzo stabilną ...  
     
    ... W następnym rozdziale zagłębię się w temat łączenia gałęzi ...

  • http://marc.info/?l=forrest-dev&m=112504297928196&w=2
    Poczta początkowa wątku omawiającego strategie rozgałęziania dla projektu Apache Forrest

    • zauważ, że obecnie projekt wydaje się wykorzystywać niestabilny model pnia z gałęziami wydania:
    • „Prace nad rozwojem są wykonywane na pniu SVN ... Istnieją„ gałęzie wydania ”SVN, np. Forrest_07_branch.” ( wytyczne projektu )
    • „Budowanie pakietów kandydujących do wydania ... 17. Utwórz gałąź obsługi w SVN ...” ( Jak zwolnić )
  • Dokumenty rozgałęziające O'Reilly CVS:
    http://commons.oreilly.com/wiki/index.php/Essential_CVS/Using_CVS/Tagging_and_Branching#Basically_stable

    • ... Zasadniczo stabilna filozofia rozgałęziania stanowi, że bagażnik powinien zawierać dane projektu, które są zawsze bliskie gotowości do wydania ... bagażnik samochodowy. Takie łagodne podejście wymaga rozgałęzienia kandydata do wydania i poddania go pełnej analizie jakości przed publikacją ...
    • ... Zasadniczo niestabilna filozofia mówi, że pień powinien zawierać najnowszy kod, niezależnie od jego stabilności, oraz że kandydaci do wydania powinni być rozgałęzieni w celu zapewnienia jakości.
       
       
      ... Bardziej łagodne odmiany pozwalają również na rozgałęzienia kodu eksperymentalnego, refaktoryzacji i innych kodów specjalnych. Scalanie gałęzi z powrotem do pnia odbywa się przez kierowników oddziału. ...
      • Uwaga: powyższe zasoby nie pojawiły się w żadnym z przeprowadzonych przeze mnie wyszukiwań (wytyczne dotyczące CVS nie są już popularne?)
  • Najlepsze praktyki w SCM (artykuł perforce) na
    stronie http://www.perforce.com/perforce/papers/bestpractices.html
    ... sześć ogólnych obszarów wdrażania SCM i niektóre gruboziarniste najlepsze praktyki w każdym z tych obszarów. Poniższe rozdziały wyjaśniają każdy element ...
    Obszary robocze, kodele, rozgałęzienia, zmiana propagacji, kompilacje, proces ...


37
Wierzę, że to najdłuższa odpowiedź, jaką widziałem w każdym pytaniu dotyczącym wymiany stosów!
John Fisher

2
@JohnFisher dobrze według JIRA , wtedy spędziłem 6 godzin na kompilacji i podsumowaniu tych referencji :)
gnat

2
Brakuje jakiegoś podsumowania, które powinno wskazywać, czy używać nowych gałęzi dla nowych funkcji. Twoja odpowiedź jest tylko sumą linków do różnych artykułów - niektóre z nich mówią jedno, a inne wręcz przeciwnie. Twoja odpowiedź jest dość długa, więc mogłem się zgubić.
BЈовић

3
Podsumowanie @ BЈовић znajduje się na początku odpowiedzi: „nie ma wspólnie uzgodnionej„ najlepszej ”strategii rozgałęziania mającej zastosowanie do każdego projektu. * większość zasobów wydaje się zgadzać, że wybór strategii produkcyjnej zależy od konkretnej specyfiki projektu ”
gnat

2
czytanie dodatkowe: Google's vs Facebook's Trunk Based Development „Oni [Google i Facebook] nie łączą bólu, ponieważ z reguły programiści nie łączą się z / z oddziałów. Przynajmniej do centralnego serwera repo nie są. Na stacjach roboczych , programiści mogą łączyć się z lokalnymi oddziałami i dokonywać zmian, kiedy wypychają coś, co „zrobiono” z powrotem do centralnego repozytorium ... ”
wtorek,

7

Jeśli masz kilka zespołów pracujących nad różnymi funkcjami jednocześnie, nie można pominąć rozgałęziania. Powinieneś udostępnić (częściowo zaimplementowany) kod członkom zespołu, uniemożliwiając innym zespołom uzyskanie niedokończonych funkcji.

Oddziały są najłatwiejszym sposobem na osiągnięcie tego.

Chociaż dobrze jest skrócić cykl życia gałęzi i unikać pracy nad tym samym modułem w dwóch gałęziach jednocześnie - wtedy nie będzie żadnych konfliktów \ problemów z scalaniem.


5

Ale ostatnio widzę coraz więcej zwolenników idei, aby nie tworzyć oddziałów, ponieważ utrudnia to praktykę ciągłej integracji, ciągłej dostawy itp.

Dobrze to robi trudniej praktykować ciągłej integracji, ciągłą dostawę, etc dla ciebie konkretnie?

Jeśli nie, nie widzę powodu, aby zmienić sposób pracy.

Oczywiście dobrą praktyką jest śledzenie tego, co się dzieje i ewolucji obecnych najlepszych praktyk. Ale nie sądzę, że musimy porzucić nasze procesy / narzędzia / co tylko dlatego, że X (i / lub Y i / lub Z) powiedziały, że nie są już modne :-)


Oczywiście, że tak! Jest to kwestia priorytetów: rozgałęzienie (izolacja funkcji) vs. łatwa integracja, dostawa itp.
SiberianGuy,

1
to tylko kwestia używanego narzędzia CI. Co powstrzymuje Cię przed robieniem kompilacji i „ciągłym dostarczaniem” z oddziału?
Shaddix

@Shaddix, zazwyczaj trudno jest dostarczyć z oddziału. Na przykład, jak dostarczyłbyś z gałęzi funkcji?
SiberianGuy,

1
Jaki jest problem, jeśli masz rozgałęziony cały kod źródłowy (jak w DVCS)?
Shaddix,

1
@Shaddix, im więcej kodu rozgałęzisz, tym więcej konfliktów napotkasz podczas łączenia
SiberianGuy,

4

Co za interesujący zestaw odpowiedzi. Przez ponad 20 lat nigdy nie pracowałem w firmie, która używała więcej niż trywialnego zastosowania rozgałęziania (ogólnie tylko w wersjach branżowych).

Większość miejsc, w których pracowałam, polegają na dość szybkich odprawach i szybkim wykrywaniu / rozwiązywaniu kolizji - zwinna metodologia uczy, że możesz szybciej rozwiązywać problemy, jeśli zauważysz je, podczas gdy obie strony aktywnie myślą o tym fragmencie kodu.

Z drugiej strony, nie używałem dużo git i być może to włączenie tagu git miało wpływ na te odpowiedzi - rozumiem, że rozgałęzienie / scalenie jest dane z git, ponieważ jest takie łatwe.


2
+1, Te dunny git'era stają się coraz bardziej fanatyczne w kwestii dyskusyjnej wyższości git nad innymi konfiguracjami kontroli wersji / CI.
wałek klonowy

3

Tak, powinieneś używać gałęzi do izolowania wszelkich (przynajmniej średnich) prac rozwojowych. Zobacz „ Kiedy należy rozgałęzić? ”.

Problemem jest raczej użycie szybkiego przewijania do przodu (które obejmuje historię rozgałęzienia w innym), pod warunkiem, że najpierw zmiażdżysz wszystkie „pośrednie zatwierdzenia punktu kontrolnego” (co może być problemem w przypadku wycofania lub git bisect).
Zobacz „ Zrozumienie przepływu pracy Git ”, aby odróżnić gałęzie prywatne (nieprzeznaczone do wypychania) od gałęzi publicznych, które zostaną zakończone przez połączenie ff (szybkie przewijanie do przodu) pod warunkiem, że wykonasz niezbędne porządki w łączonym oddziale .
Zobacz także „ Dlaczego git domyślnie korzysta z szybkiego łączenia do przodu? ”.


2

Powinieneś bezwzględnie używać oddziałów. Jest w tym wiele mocnych stron.

  • Możesz sprawdzać swoją pracę w ruchu, jeśli obawiasz się utraty pracy z powodu awarii HD, utraty laptopa itp. I nie spowoduje to uszkodzenia głównego CI.
  • Nadal możesz wykonywać CI, po prostu skonfiguruj swój lokalny CI, aby obserwować swój oddział.
  • Jeśli funkcja nagle się zawiesi (to się nigdy nie zdarza), możesz po prostu ją zaparkować.

Zbyt trudne nigdy nie jest wymówką. Zawsze trzeba więcej wysiłku, aby zrobić to dobrze.


2
Chcę to zagłosować nie dlatego, że jestem przeciwny rozgałęzianiu, ale dlatego, że sugerujesz, że powinny być używane CAŁOŚĆ.
wałek klonowy

Gdzie to powiedział, czy to edytował czy coś?
b01,

skonfiguruj swój lokalny CI, aby obserwować oddział pod kątem krótkotrwałych oddziałów (2-5 dni), co może być dość dużym obciążeniem. Zostałem tam zrobiony
gnat

1
Odpowiadałem na pytanie o korzystanie z gałęzi ogólnie lub w zasadzie nigdy z nich nie korzystałem. Podobnie jak w przypadku każdej reguły lub polityki, należy brać pod uwagę dobry osąd. Nie współpracuję przy wielu moich projektach, ale nadal liberalnie używam gałęzi przede wszystkim do trzeciej kuli, o której wspomniałem. Podobnie jak w przypadku pierwszego pocisku, ile razy otrzymałeś pilną prośbę o udostępnienie funkcji / poprawki na żywo, ale potem wchodzisz i masz około 3 w połowie ukończonych funkcji w trybie głównym.
Bill Leeper

To nie robi CI. I w CI oznacza integrację - integrację pracy wszystkich programistów, tj. Łączenie. Nie ma nic złego w uruchamianiu testów lokalnych dla każdego zatwierdzenia, ale to to samo.
bdsl

2

Jeśli dwa zespoły pracują nad własnym oddziałem, nie zobaczą zmian drugiego zespołu, nawet jeśli oba zintegrują masteroddział. Oznaczałoby to, że ich gałęzie rozwoju rozpadną się, a jeśli jeden z zespołów się połączy master, drugi zespół będzie musiał dokonać wielu zmian.

Więc nawet jeśli masz rozgałęzienia dla funkcji, zachęcam do wykonania „backports” wszystkich refaktoryzacji do gałęzi master i zachowania gałęzi tylko dla nowych funkcji.

  • Refaktoryzacje backportu

Myślę, że czasami łatwiejsze jest użycie przełączników funkcji, aby wyłączyć nowe, niesprawdzone funkcje, które nie powinny jeszcze wejść do produkcji. W ten sposób wszystkie inne zespoły zobaczą zmiany i nie będzie konieczności łączenia się z Wielkim Wybuchem.

  • Użyj przełączników funkcji

2

Właśnie to przeszliśmy (ponownie). Najpierw odbyliśmy całą debatę GIT / SVN, która doprowadziła nas ogólnie do rozgałęzień.

Wszystkie większe firmy stosują strategię opartą na pniu, w której wszyscy pracują w tym samym oddziale, a od tego oddziału odbywa się ciągła integracja. Unikanie konfliktu odbywa się za pomocą modularyzacji kodu, przełączania funkcji i sprytnego oprzyrządowania. Brzmi to trudnie ... bo tak jest. Ale jeśli prowadzisz tę debatę, to dlatego, że padłeś ofiarą ludzkich fantazji na temat rozgałęziania się. Niektórzy twierdzą, że używają tutaj narzędzia SCM do wstawiania z w pełni zgodnym z Sarbanes-Oxley mechanizmem rozgałęziania promocji i wszystko jest genialne. Albo kłamią, oszukują samych siebie, albo nie pracują na tej samej skali systemu, co ty.

Rozgałęzianie i łączenie jest trudne. Zwłaszcza jeśli masz firmę, która regularnie zmienia zdanie i wymaga wycofania itp.

To zdanie może uratować ci życie: To, co jest w SCM, nie jest tym samym, co w twoich artefaktach!

Jeśli masz problemy z rozgałęzianiem, to dlatego, że niewłaściwie używasz SCM. Wszyscy robimy to od lat. Masz system, w którym SCM jest używany do określenia, co trafi do ostatecznej wersji.

To nie jest zadanie SCM. SCM to uwielbiony serwer plików. Zadanie określania, które pliki z SCM trafiają do twojej kompilacji, należy do narzędzi kompilacji.

Moduł A jest w trakcie opracowywania i wchodzi w skład cotygodniowego wydania. Moduł B jest modułem A, ale zawiera projekt X i jest nad nim pracowany, w tej samej gałęzi, ale nie jest wbudowany w wydanie. W pewnym momencie w przyszłości chcesz wydać projekt X. Więc powiedz swojemu narzędziu do budowania, aby przestało wstawiać moduł A i zaczęło wkładać moduł B.

Będzie dużo płaczu i załamywania rąk. Co za wulgarne i ogólne wycie. Taki jest poziom emocji otaczających coś tak prostego jak repozytorium plików, bez względu na to, jak sprytne.

Ale jest twoja odpowiedź.


1

Głównym problemem związanym z rozgałęzianiem jest trudność z ponownym połączeniem z główną gałęzią po zakończeniu programowania. Scalanie może być procesem ręcznym i podatnym na błędy, dlatego należy go unikać przez większość czasu.

Niektóre znaczące wyjątki, w których wolę rozgałęzianie, dotyczą masowego refaktoryzacji, gigantycznych elementów, które rozwijają się dłużej niż sprint, lub zakłócających funkcji, które mogłyby zakłócić rozwój innych cech podczas większości tego sprintu.


4
Wygląda na to, że potrzebujesz lepszej praktyki opracowywania nowych funkcji. Osobiście lubię budować swoje projekty, aby łatwo było izolować funkcje, zwykle w osobnym pliku / klasie / lub czymkolwiek. W ten sposób dodanie lub usunięcie kodu nie spowoduje poważnych zakłóceń w dostawie ani problemów podczas scalania nowego kodu lub wyciągania starego kodu. Działa to dobrze również podczas programowania z wieloma programistami. Ale rozumiem, czy pracujesz nad projektem, który mógł nie zostać przez Ciebie rozpoczęty, lub nie masz prawdziwego zdania, w jaki sposób projekt będzie kontynuowany.
b01

1
@ b01, To prawie na miejscu. Nikt nie może wymyślić idealnego projektu, gdy wymagania zmieniają się i zmieniają szybciej niż dziecko z ADHD po pęknięciu. Innym razem próbujesz refaktoryzować starszy kod, aby poprawić projekt, i taka sytuacja zdarza się od czasu do czasu. To nie jest najgorszy problem, jaki może mieć zespół, i jest o wiele lepszy niż w niektórych miejscach, w których pracowałem, gdzie nawet sugerowanie refaktoryzacji na spotkaniu sprawi, że zabijesz się kijem baseballowym jak scena z The Untouchables.
wałek klonowy

Całkowicie się nie zgadzam. Jeśli dzielisz według gałęzi jakości i często scalasz (codziennie jest to dobre), unikniesz prawie wszystkich połączeń „ręcznych i podatnych na błędy”.
Paul Nathan

@Paul, Zaufaj mi, że nie działa dla wszystkich projektów lub technologii. Pomyśl o zwykłym pliku konfiguracyjnym XML, takim jak w Struts, w którym każdy codziennie zanurza się w nim. Ale nie, twoja droga działa cały czas i całkowicie zasłużyłem na głosowanie. Dzięki.
wałek klonowy

1
@maple_shaft meta-podpowiedź, jeśli weźmiesz pod uwagę tagi (git) i opublikujesz coś, co typowy użytkownik tych tagów uznałby za negatywny, oczekuj przelotnych ocen. Flybys są prawie zawsze nieuzasadnioną reakcją na zranienie w wyniku komentarza, który bierzesz osobiście. Uważaj to za dobre, ponieważ poprawia twój przedstawiciel przez dach.
Bill K

1

Polecam tego rodzaju schemat oddziału:

wydanie - test - rozwój

Następnie od rozwoju, gałąź według programisty i / lub według funkcji.

Każdy z deweloperów ma gałąź, z którą można się rutynowo łączyć, a następnie rutynowo wchodzić w gałąź rozwoju - najlepiej codziennie (pod warunkiem, że się kompiluje).

Ten rodzaj schematu działa naprawdę dobrze z wieloma programistami i wieloma projektami na tej samej bazie kodu.


0

Mamy zrobić użyciu oddziałów, ale nie na poziomie funkcji ziarnistej. Używamy gałęzi do każdego sprintu. Rozgałęzienie w istocie nie jest złą rzeczą IMO, ponieważ symuluje koncepcję SOC w warstwie lub warstwie sprintu. Możesz łatwo rozpoznać i zarządzać, która gałąź należy do której funkcji lub sprintu.

IMHO, więc odpowiedź brzmi: TAK . Nadal powinniśmy używać rozgałęzień.


0

Proces w mojej organizacji w szerokim zakresie korzysta z oddziałów i (proces wygląda trochę jak) ciągłej integracji.

W widoku wysokiego poziomu programiści nie martwią się zbytnio o połączenie z linią główną, po prostu zobowiązują się do oddziału. (częściowo) zautomatyzowany proces sprawdza, które funkcje mają zostać wprowadzone do głównej linii, łączy te gałęzie i tworzy produkt. Proces działa, ponieważ faktycznie integrujemy ten proces scalania z narzędzia do śledzenia problemów, aby narzędzie kompilacji wiedziało, które gałęzie scalić.


Ten proces wygląda na przerwany, jeśli programista dokonał zmiany istniejącego kodu w jednej gałęzi, a programista w oddzielnej gałęzi napisał coś, co opiera się na starej wersji kodu.
bdsl

@bdsl: jest to problem, który może pojawić się w dowolnej strategii rozgałęziania (w tym bez rozgałęziania), ilekroć masz wielu programistów w tej samej bazie kodu. w tej organizacji (od tamtej pory przeniosłem się), byliśmy na tyle małym zespołem, że wszyscy mieliśmy całkiem niezły pomysł, co planuje reszta z nas, więc ostrzegaliśmy się, gdy niektóre z naszych zmian prawdopodobnie w konflikcie. W każdym razie ciągła integracja bardzo pomogła złapać tego rodzaju problemy w ciągu kilku minut lub godzin od wprowadzenia konfliktu.
SingleNegationElimination

Tak, ale wydaje się znacznie mniej prawdopodobne, jeśli refaktoryzacja zostanie połączona z linią główną tego samego dnia, w którym została wykonana, zamiast czekać, aż nowa funkcja będzie gotowa.
bdsl

@bdsl nie zawsze jest to opcja; możesz zawsze potrzebować „dobrej, działającej gałęzi”, na przykład do wysyłania awaryjnych napraw błędów. Alternatywna technika, polegająca na regularnym łączeniu głównej linii z funkcją, jest zwykle OK., A moja silna rekomendacja bez względu na strategię rozgałęziania.
SingleNegationElimination
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.