Automatyczne cofanie zatwierdzeń, które zakończyły się niepowodzeniem

43

Kolega powiedział mi, że on myśli w tworzeniu naszego serwera CI zobowiązuje do zawróconych że nieudanych kompilacji, więc HEADw masterjest zawsze stabilny (jak w zdaniu zbudować co najmniej).

Czy jest to najlepsza praktyka, czy może być bardziej problematyczna niż pozostawienie masterzepsucia, dopóki programista go nie naprawi?

Uważam, że cofnięcie zatwierdzenia skomplikuje zadanie odczytania zatwierdzenia i poprawki (programista będzie musiał cofnąć przywrócenie, a następnie zatwierdzić poprawkę, co również zaśmieci git log) i powinniśmy po prostu zostawić zatwierdzenie, a następnie zatwierdzić naprawić. Chociaż widzę pewne zalety posiadania masterstabilnego, to przywrócenie błędów nie przekonuje mnie.

edycja: Nie ma znaczenia, czy to jest, masterczy jakakolwiek inna gałąź programistyczna, ale pytanie pozostaje takie samo: czy system CI powinien przywrócić zatwierdzenie, które nie powiodło się w kompilacji?

kolejna (długa) edycja: Ok, używamy gitw dziwny sposób. Uważamy, że koncepcja oddziałów jest sprzeczna z rzeczywistym CI, ponieważ zobowiązanie do oddziału izoluje cię od innych programistów i ich zmian, a także dodaje czasu na konieczność ponownej integracji oddziału i radzenia sobie z możliwymi konfliktami. Jeśli wszyscy zobowiązują się do mastertego, konflikty zostają zredukowane do minimum, a każde zatwierdzenie przechodzi wszystkie testy.

Oczywiście, to zmusza cię do pchania tylko stabilnego (lub psujesz kompilację) i programowania z większą ostrożnością, aby nie zerwać wstecznej kompatybilności lub przełączać funkcje podczas wprowadzania nowych funkcji.

Istnieją pewne kompromisy podczas wykonywania CI w ten lub inny sposób, ale to nie wchodzi w zakres pytania (patrz powiązane pytanie na ten temat). Jeśli wolisz, mogę przeredagować pytanie: mały zespół programistów pracuje razem w gałęzi funkcji. Jeśli jeden programista popełnia coś, co psuje kompilację dla tej gałęzi, czy system CI powinien cofnąć zatwierdzenie, czy nie?

Carlos Campderrós
źródło
38
Nieudane kompilacje nigdy nie powinny były mastersię zaczynać. Do tego służą gałęzie programowania i funkcji. Zmiany te przechodzą następnie w coś w rodzaju gałęzi integracji, w której można przetestować, czy wszystkie nowe funkcje kilku programistów będą ze sobą współpracować i tylko wtedy, gdy zostanie to przetestowane, może przejść w tryb master. Lub przynajmniej jeden z możliwych przepływów pracy.
thorsten müller,
1
@ thorstenmüller dobrze wyobraź sobie, że jest to gałąź rozwoju, z której korzystają wszyscy programiści. Czy system CI powinien wycofać zatwierdzenia, które nie powiodły się w kompilacji?
Carlos Campderrós,
7
Wygląda na to, że używasz git w dziwny sposób. Zasadniczo ludzie powinni pracować nad własnymi repozytoriami w swoich oddziałach i tylko wtedy, gdy CI dla swojej osobistej wersji wypychają do głównego, sprawdzają, czy zmiany są OK.
Wilbert,
4
> „konflikty zostały zredukowane do minimum”; w czasie łączenia pojawia się mniej konfliktów, ale znacznie więcej problemów ze złymi połączeniami. Rozwiązaniem jest ciągłe łączenie od głównego do swojego oddziału w ramach procesu, a nie nierozgałęzienie.
deworde
2
... Dlaczego nie sprawić, by tak słabe kompilacje nie były przyjmowane jako master na początek?
user253751,

Odpowiedzi:

55

Byłbym przeciwny robieniu tego z następujących powodów:

  • Za każdym razem, gdy konfigurujesz zautomatyzowane narzędzie do zmiany kodu w Twoim imieniu , istnieje ryzyko, że popełni błąd, lub że pojawi się sytuacja, w której będziesz go potrzebować, aby przestać wprowadzać zmiany (np. Najnowsza wersja Google Mock miał w tym błąd, więc nie oznacza to awarii Twojego kodu) i musisz zmarnować czas na jego ponowną konfigurację. Ponadto zawsze istnieje niewielkie ryzyko niepowodzenia kompilacji z powodu błędu w systemie kompilacji, a nie błędu w kodzie. Dla mnie CI polega na uzyskaniu pewności, że mój kod jest poprawny; to tylko zmieniłoby to w inne źródło potencjalnych problemów, o które musiałbym się martwić.

  • Rodzaje błędów, które psują „kompilację”, powinny być głupimi błędami, których naprawienie zajmuje bardzo mało czasu (jak wskazałeś w komentarzu, jest to prawdą dla ciebie). Jeśli bardziej subtelne i skomplikowane błędy regularnie przekształcają się w master, wówczas poprawnym rozwiązaniem nie jest „poprawianie go szybciej”, należy zachować ostrożność podczas przeglądania gałęzi funkcji przed ich scaleniem.

  • Pozostawienie mistrza niezdatnego do zbudowania na kilka minut, dopóki błąd zostanie naprawiony poprawnie, nikomu nie zaszkodzi. To nie jest tak, że CEO osobiście sprawdzi kod główny i opublikuje kod prosto do klientów w dowolnym przypadkowym momencie (przynajmniej, mam nadzieję, nie bez twojego zaangażowania). W bardzo rzadkich przypadkach, gdy trzeba wydać coś, zanim będzie można naprawić błąd, wówczas można łatwo podjąć decyzję, aby przywrócić ręcznie przed publikacją.

Ixrec
źródło
1
Poza tym tylko udane kompilacje powinny wyzwalać tworzenie „zrzutów kompilacji”, które można wdrożyć. Jeśli kompilacja się nie powiedzie, nie powinno być możliwości wdrożenia kompilacji do wdrożenia, więc nie powinno być ryzyka, że ​​ktoś opublikuje zły kod klientom.
Mark Freedman
1
jest zdecydowanie inna opcja, która jest używana i lepsza niż ta, którą myślę i jest intensywnie używana (używamy jej na Twitterze). nie umieszczaj nieudanych kompilacji na wzorcu ORAZ głupie błędy są również łatwe do naprawienia. Zobacz moją pełną odpowiedź poniżej.
Dean Hiller
26

Najpierw ustalmy warunki.

Osobiście używam terminów Continuous Build i Continuous Integration, aby rozróżnić dwa różne scenariusze:

  • Ciągła kompilacja: narzędzie, które okresowo sprawdza, czy repozytorium zmieniło się od ostatniej kompilacji, i kompiluje / testuje, jeśli tak się stało.
  • Ciągła integracja: narzędzie, które pobiera żądania ściągania i sprawdza je względem najnowszej wersji, zanim zostaną widoczne.

Ta ostatnia, Continuous Integration, oznacza, że ​​repozytorium, które chroni, jest zawsze zielone 1 : jest zdecydowanie lepsze.

Twoje pytanie naprawdę ma sens tylko w przypadku Continuous Build, więc odpowiem, zakładając, że to Twoja konfiguracja.

1 : Przyczyny środowiskowe mogą również popsuć kompilację, na przykład test z zakodowanym rokiem (2015) może zacząć się nie udać w styczniu 2016 r., Dysk może się zapełnić ... I oczywiście jest plaga niestabilności testy. Wyniosle ignoruję te kwestie tutaj; inaczej nigdzie się nie dostaniemy.


Jeśli masz konfigurację kompilacji ciągłej, możesz rzeczywiście zautomatyzować odwracanie zatwierdzeń, które mogły ją zepsuć, jednak istnieje kilka subtelności.

  • Nie można tak naprawdę usunąć rozkazów: inni współpracownicy mogliby je już sprawdzić i odepchną ich przy następnej próbie zatwierdzenia. Zamiast tego odwrócenie powinno oznaczać różnicę odwrotną . Och, a współpracownicy będą cię nienawidzić za cofanie ich pracy, gdy będzie to poprawne, ponieważ będą musieli znaleźć sposób, aby odepchnąć ją z powrotem ...
  • Nie można tak naprawdę tylko usunąć ostatniego zatwierdzenia (jest to scalenie), ale trzeba usunąć wszystkie zatwierdzenia ... do pewnego momentu. Na przykład ostatnie znane dobre zatwierdzenie (uwaga przy ładowaniu systemu do systemu).
  • Musisz pomyśleć o przyczynach zewnętrznych (problemach środowiskowych) i unikać konfiguracji, która przywraca wszystko do dnia 0. Na szczęście powrót do ostatniego znanego dobrego zatwierdzenia pomija ten problem.
  • Musisz pomyśleć, że ostatnia znana dobra kompilacja może już nie być kompilowana (problemy środowiskowe), w takim przypadku prawdopodobne jest, że wszystkie dalsze zatwierdzenia zostaną cofnięte. Idealnie byłoby, gdyby w przypadku awarii, a przed przywróceniem, sprawdziłeś ostatnią znaną dobrą wersję i przetestowałeś ją ponownie. Jeśli mija, cofnij się, w przeciwnym razie podnieś alert.

Zauważ, że z tym systemem, w przypadku niestabilnego testu lub współpracownika często popełniającego bzdury, wiele dobrych popełnień zostanie odwróconych. Twoi współpracownicy będą cię wtedy nienawidzić.


Mam nadzieję, że moja opowieść grozy ujawniła problemy zezwalające na zepsute repozytorium, a teraz zaimplementujesz odpowiedni potok ciągłej integracji, w którym PR nigdy nie jest bezpośrednio wypychany do repozytorium, ale w kolejce do scalenia w kolejce roboczej i zintegrowany pojedynczo ( lub przez roll-upy):

  • pobierz lokalnie szef repozytorium
  • zastosuj prośby o pociągnięcie
  • buduj i testuj
  • w przypadku sukcesu przepchnij do repozytorium, w przeciwnym razie oznacz jako niepowodzenie
  • przejdź do następnych wniosków

Po próbie obu jest to zdecydowanie lepsze.

Matthieu M.
źródło
2
To rzeczywiście właściwa odpowiedź - właściwym rozwiązaniem jest zapobieganie, aby złe zmiany kiedykolwiek dotarły do ​​głównej gałęzi, nie pozwalały im wylądować, a następnie musiały poradzić sobie z ich wycofaniem.
Daniel Pryden,
Myślę, że problem polega na tym, że pytający uważa, że ​​podane koszty „odizolowania cię od innych programistów i ich zmian” przeważają nad korzyściami. Podane koszty to zwiększone niebezpieczeństwo nietrywialnych fuzji w miarę rozłączania się dwóch osób. IMO korzyść z izolacji od uszkodzonego kodu jest oczywista. Pytający chce zastosować strategię „optymistyczną”, w której uszkodzony kod jest dostępny masterdo pobrania , a następnie naprawić tę sytuację po niepowodzeniu testów. Wszyscy inni stosują strategię „pesymistyczną”, jak radzisz, i udostępniają tylko kod do pobrania.
Steve Jessop
(gdzie przez „dostępny do ściągnięcia” mam na myśli „ściągnij z master”, co jest idealną rzeczą, którą programiści mogą zrobić chcąc nie chcąc, ale aby to osiągnąć, musisz opóźnić przybycie zatwierdzeń, masterzanim zostaną przetestowane i zaliczyć. Jeśli deweloper chce nie wybieram testowanego lub przetestowanego i nieudanego kodu, który też jest w porządku, a kod jest w tym sensie „dostępny”, po prostu nie o to mi chodzi)
Steve Jessop
Właściwym rozwiązaniem jest zapobieganie dotarciu złych zmian do ŻADNEGO oddziału. Nieudane zatwierdzenia nigdy nie powinny być nigdy upubliczniane.
Miles Rout
5

Czy to najlepsza praktyka, czy może być bardziej problematyczna niż pozostawienie zepsutego wzorca, dopóki programista go nie naprawi?

To jest problematyczne. Osoba decydująca: „szef HEAD jest zepsuty; cofnę górną zmianę” jest całkowicie inna niż robi to samo system CI.

Oto kilka wad:

  • Błędy w procesie automatycznego cofania psują repozytorium;

  • zakłada to, że jeden zestaw zmian (najwyższy) zepsuł kompilację (co jest nierealne)

  • Opiekunowie będą mieli więcej do zrobienia, aby rozwiązać problem, niż tylko dochodzenie i zatwierdzenie (będą też musieli spojrzeć na odwrotną historię)

Uważamy, że koncepcja oddziałów jest sprzeczna z rzeczywistym CI, ponieważ zobowiązanie do oddziału izoluje cię od innych programistów i ich zmian, a także dodaje czasu na konieczność ponownej integracji oddziału i radzenia sobie z możliwymi konfliktami.

To przekonanie (gałęzie vs. CI) jest nieprawidłowe. Zastanów się nad utrzymaniem jednej stabilnej gałęzi, w której zatwierdzasz tylko zestawy testów przetestowane przez jednostkę . Reszta (oddziały funkcji i oddziały lokalne) powinna ponosić odpowiedzialność każdego programisty, a nie w jakikolwiek sposób uwzględniać twoje zasady CI.

W gałęziach funkcji chcesz być odizolowany od innych programistów. Pozwala to na:

  • wykonać kodowanie eksploracyjne

  • eksperymentuj z bazą kodu

  • wykonać częściowe zatwierdzenia (efektywnie zatwierdzić niedziałający kod), aby skonfigurować punkty kopii zapasowej (na wypadek, gdybyś spieprzył), aby stworzyć bardziej sensowną historię zmian (za pomocą komunikatów zatwierdzania), a także wykonać kopię zapasową pracy i całkowicie przejść do czegoś innego (w czas potrzebny na napisanie „git commit && git checkout”)

  • wykonuj zadania o niskim priorytecie, które zajmują dużo czasu (np. chcesz wykonać refaktoryzację, która zmienia wszystkie 80 klas warstwy danych: zmieniasz dwie dziennie, dopóki nie zmienisz wszystkich z nich, a kod się kompiluje (ale możesz to zrobić bez wpływu na nikogo, dopóki nie możesz dokonać pojedynczego zatwierdzenia).

Jeśli jeden programista popełnia coś, co psuje kompilację dla tej gałęzi, czy system CI powinien cofnąć zatwierdzenie, czy nie?

Nie powinno. Za zatwierdzenie stabilnego kodu w oddziale CI odpowiada osoba odpowiedzialna, a nie zautomatyzowany system.

utnapistim
źródło
2

Sugerowałbym użycie środowiska Gerrit + Jenkins, aby utrzymać gałąź główną zawsze w dobrej formie. Ludzie przekazują swój nowy kod Gerritowi, który uruchamia zadanie Jenkinsa, aby pobrać tę łatkę, kompilacje, testy i tak dalej. Jeśli inni programiści, tacy jak twoja łatka, i Jenkins pomyślnie wykonają zadanie, Gerrit połączy ten fragment kodu z twoją główną gałęzią.

Jest to podobne środowisko opisane przez @ brian-vandenberg

Oprócz utrzymywania oddziału w dobrej kondycji dodajesz również krok przeglądu kodu, który poprawia jakość kodu i wymianę wiedzy na temat twojego oprogramowania.

[1] Jenkins https://jenkins-ci.org/

[2] Gerrit https://www.gerritcodereview.com/

Gustavo Coelho
źródło
1

CI nigdy nie powinien zmieniać historii zatwierdzania repozytorium.

Prawidłowe rozwiązanie polega na tym, aby żadne zmiany nie były dodawane do gałęzi głównej, jeśli nie zostały przetestowane i zweryfikowane.

Czy pracujesz nad gałęziami funkcji, czy CI działa na nich automatycznie, a jeśli kompilacje nie powiodą się, nie łącz ich w master.

Możesz mieć dodatkową kompilację, która testuje scalanie, jeśli są one istotne, uruchamiając gałąź gałęzi funkcji, a podczas kompilacji scalając master / integrację / cokolwiek z gałęzią lokalną, a następnie uruchamiając testy.

Daenyth
źródło
1
To w żaden sposób nie odpowiada na pytanie. Jeśli kompilacja nie powiedzie się w gałęzi funkcji, czy CI powinien cofnąć zatwierdzenie?
Carlos Campderrós,
Co się stanie, jeśli kompilacja powiedzie się w gałęzi funkcji, ale zakończy się niepowodzeniem po scaleniu?
Matthieu M.,
@MatthieuM. scalanie jest zatwierdzeniem, czy łączący się krok CI powinien przywrócić kompilację?
Carlos Campderrós,
@ CarlosCampderrós: ​​Osobiście nigdy nie miałbym konfiguracji, która próbuje przywrócić zatwierdzenia; o wiele za skomplikowane.
Matthieu M.,
Zwróciłem się do komentarzy.
Daenyth,
1

Używamy Jenkinsa do naszego serwera kompilacji i używamy modelu gatekeeper do wypychania commits - gdzie kombinacja Jenkins i wyzwalaczy zatwierdzania (które zapewniają, że recenzenci wykonali swoją pracę) jest strażnikiem.

Zatwierdzenia są wypychane pośrednio przez curl do Jenkins, gdzie klonuje repozytorium główne, a następnie pobiera zatwierdzenia (s) do scalenia i wykonuje wszystkie wymagane kompilacje (dla Linux / solaris). Jeśli wszystkie kompilacje zakończą się, zatwierdzenie zostanie wypchnięte.

Pozwala to uniknąć wielu, jeśli nie wszystkich, problemów omówionych do tej pory:

  • zmiana historii
  • poprawianie historii, jeśli jesteś twórcą, który musi naprawić awarię
  • niestabilność (w postaci zepsutych kompilacji) nigdy nie jest wprowadzana

Pozwala nam również bezpośrednio egzekwować inne wymagania, takie jak testy jednostkowe zakończone pomyślnie.

Brian Vandenberg
źródło
re: opinia, czy mógłbyś skomentować to, co ci się nie podoba w mojej odpowiedzi?
Brian Vandenberg
0

Ile razy otrzymywałeś ten automatyczny e-mail z informacją, że ostatnie zatwierdzenie złamało kompilację? Ile razy to jest złe? Ale teraz musisz sprawdzić, czy to naprawdę ty, czy ktoś inny, kto popełnił kolejny błąd w tym samym czasie. A może było to coś ekologicznego.

Jeśli system nie wie na pewno, to na pewno nie chcę go zautomatyzować.

Moher
źródło
0

Pytanie jest błędne. Szanuję jednak to oświadczenie

„Uważamy, że koncepcja oddziałów jest sprzeczna z rzeczywistym CI, ponieważ zaangażowanie w oddział izoluje cię od innych programistów i ich zmian”

Powinieneś jednak wykonać te kroki

  • pracować poza master, jeśli chcesz (to jest w porządku i wyciągaj zmiany od wszystkich), ALE NIE zobowiązuj się do masterowania lokalnie
  • TYLKO ZANIM zamierzasz zatwierdzić swoje zmiany w master, utwórz gałąź za pomocą subm_XXXXXX
  • Poproś, aby Twoja automatyczna kompilacja odebrała wszystkie kompilacje gałęzi subm_XXX
  • Opcja 1: buduj przerwy lub scalaj przerwy ... zmiana odrzucona i nigdy nie wyląduje na kapitanie
  • Opcja 2: kompilacja działa, Jenkins popycha mistrza i aktualizuje go

PONADTO to, co robimy, polega na zaczepieniu git, aby KAŻDY faktycznie nie zobowiązał się do opanowania. Działa świetnie .... ŻADNE zepsute wersje nigdy, ani ŻADNE cofanie zobowiązań od mistrza.

później Dean

Dean Hiller
źródło