git - pomijanie określonych zatwierdzeń podczas scalania

200

Używam Gita od około roku i uważam, że to fantastyczne, ale właśnie zacząłem od drugiej wersji projektu i założyłem dla niego nową gałąź. Walczę trochę z najlepszym sposobem radzenia sobie z przyszłymi sprawami.

Mam dwie gałęzie o nazwie powiedz master10 (dla v1) i master20 (dla v2). Robiłem poprawki błędów w wersji 1 na gałęzi master10 i opracowywałem nowe rzeczy z master20. Ilekroć poprawiam błąd, łączę go z v2, sprawdzając master20 i robiąc to git merge master10. Na razie w porządku.

Teraz jednak wprowadziłem zmianę w wersji 1, której nie chcę w wersji 2, ale chcę nadal scalać inne poprawki błędów. Jak mam powiedzieć Gitowi, aby pomijał ten konkretny zatwierdzenie (lub zakres zatwierdzeń), ale że dalej chcę scalić inne poprawki błędów.

Myślałem, że git rebasemoże być tym, czego potrzebuję, ale przeczytałem dokument, a moja głowa prawie wybuchła.

Myślę, że to, czego chcę, to coś w rodzaju polecenia „git sync”, które mówi gitowi, że dwie gałęzie są teraz zsynchronizowane, aw przyszłości scalą tylko zatwierdzenia od tego punktu synchronizacji.

Każda pomoc doceniona.

Brad Robinson
źródło

Odpowiedzi:

289

Jeśli chcesz na przykład połączyć większość, ale nie wszystkie zatwierdzenia w gałęzi „Maintenance” z „master”, możesz to zrobić. Wymaga to trochę pracy - jak wspomniano powyżej, zwykłym przypadkiem użycia jest scalenie wszystkiego z gałęzi --- ale czasami zdarza się, że dokonałeś zmiany w wersji wydania, która nie powinna być zintegrowana z powrotem (może ten kod zostały już zastąpione mistrzem), więc jak to reprezentujesz? Tutaj idzie...

Załóżmy więc, że w konserwacji zastosowano 5 zmian, a jednej z nich (keep ~ 3) nie można ponownie połączyć w master, chociaż wszystkie pozostałe powinny być. Robisz to w trzech etapach: faktycznie scalasz wszystko przed tym, powiedz gitowi, aby oznaczył keep ~ 3 jako scalone, nawet jeśli tak nie jest, a następnie scal resztę. Magia to:

bash <master>$ git merge maint~4
bash <master>$ git merge -s ours maint~3
bash <master>$ git merge maint

Pierwsze polecenie scala wszystko, zanim kłopotliwe utrzymanie zostanie zatwierdzone na master. Domyślny komunikat w dzienniku scalania wyjaśni, że scalasz „gałąź 'Maintenance' (część początkowa)”.

Drugie polecenie łączy kłopotliwe zatwierdzenie ~ 3, ale opcja „-s nasz” mówi gitowi, aby użył specjalnej „strategii scalania”, która w rzeczywistości działa po prostu utrzymując drzewo, w które się scalasz, i ignorując zatwierdzenie (s) ) łączysz się całkowicie. Ale nadal powoduje to, że nowe scalenie zatwierdza HEAD i utrzymuje ~ 3 jako rodziców, więc wykres zmian mówi teraz, że keep ~ 3 jest scalony. Tak więc w rzeczywistości prawdopodobnie chcesz użyć opcji -m również do 'git merge', aby wyjaśnić, że zatwierdzenie keep ~ 3 jest faktycznie ignorowane!

Ostatnie polecenie po prostu scala resztę keep (maint ~ 2..maint) w master, aby wszyscy byli ponownie zsynchronizowani.

araqnid
źródło
5
Myślę, że jeśli chcesz odłożyć scalenie tego zatwierdzenia, nie masz innego wyboru, jak go pominąć (scalić-nasz), a następnie zastosować go za pomocą polecenia cherry-pick. Gdy zatwierdzenie jest osiągalne z poziomu master, nie można go ponownie scalić - unikanie podwójnego scalenia tej samej zmiany jest jednym z głównych celów git.
araqnid
3
Jeśli chodzi o przykład twojego oddziału: podejrzewam, że po scaleniu tego oddziału jesteś w dokładnie takiej samej sytuacji, jak po drugim kroku mojego postu. Utworzenie dodatkowych gałęzi nie ma znaczenia dla relacji zatwierdzania.
araqnid
5
Zainteresowany, jeśli chcesz po prostu pominąć jedną zmianę, dlaczego nie zrobiłbyś pojedynczego scalenia, a następnie cofnąłby ten jeden zestaw zmian, zamiast wykonać trzy scalenia? Spowodowałoby to zmniejszenie liczby zestawów zmian w repozytorium i bardziej wyraźną historię.
Mark Booth
3
Często łatwiej jest jednoznacznie nazwać commity. Wystarczy więc przejrzeć dziennik git oddziału, który ma zostać scalony, i zanotować skróty zatwierdzenia, które nie powinny zostać scalone, i poprzednie - zamiast liczenia zatwierdzeń…
zwirbeltier
14
@MarkBooth: Zatwierdzenie, które chcesz pominąć, może być w dużym konflikcie z gałęzią, w której chcesz się połączyć. Łatwiej jest po prostu pominąć to niż naprawić konflikty, a następnie cofnąć tę zmianę i naprawić konflikty ponownie
SztupY
39

IMHO, najbardziej logiczną rzeczą do zrobienia, jest scalenie wszystkiego, a następnie użycie git revert (commit_you_dont_want), aby go usunąć .

Przykład:

git merge master
git revert 12345678

Jeśli masz wiele zatwierdzeń „zignoruj” lub chcesz edytować komunikat przywrócenia:

git merge master
git revert -n 123456
git revert -n abcdef
git commit -m "... Except commits 123456 and abcdef"

Twoja historia może wyglądać następująco:

| ... Except 123456 and abcdef
|\ Merge branch 'master' into 'your_branch'

Jeśli masz konflikty dotyczące TYLKO tych zatwierdzeń „zignoruj”, możesz użyć:

git merge master -X ours

Twoja wersja pozostanie niezmienna w stosunku do drugiej. Nawet bez komunikatów o błędach możesz nadal „cofnąć” te niechciane zatwierdzenia, ponieważ mogą one zawierać inne zmiany, które nie spowodowały konfliktu, i nadal ich nie chcesz.

Jeśli masz konflikty obejmujące TYLKO zatwierdzenia „ignoruj”, powinieneś je rozwiązać ręcznie i prawdopodobnie będziesz musiał rozwiązać je ponownie podczas cofania.

Alexandre T.
źródło
2
Jeśli następnie chcesz scalić te wycofane zatwierdzenia z gałęzią, czy Git nadal je zignoruje?
Anriëtte Myburgh
@ AnriëtteMyburgh Możesz cofnąć zatwierdzenia zamiany, aby później połączyć je w coś, czego tak naprawdę nie możesz zrobić tak łatwo ze strategią „scal nasze-nasze”.
Lily Chung
Dzięki, to jest dokładnie to, czego potrzebowałem, aby mieć kilka starszych zatwierdzeń w gałęzi funkcji, których nie chciałem w master i grupie, którą chciałem w master. Ładnie i czysto.
Vale Trujillo
17

Zatwierdzenia obejmują pochodzenie. Nie można scalić zatwierdzenia bez scalenia wcześniejszych zatwierdzeń.

Oczywiście możesz je wybrać. To drobny przepływ, gdy masz gałąź w trybie konserwacji.

Dustin
źródło
1
Dzięki, Cherry Pick wykona pracę. Nie tak miło, jak się spodziewałem, ale się uda.
Brad Robinson,
3

Rodzaj reklamy mojego projektu, który zasadniczo otacza proces opisany przez @araqnid.

To rodzaj pomocnika, który wprowadza następujący przepływ GIT:

  • istnieje codzienne / cotygodniowe powiadomienie o oczekujących połączeniach z oddziałów serwisowych do działu dev / master
  • opiekun oddziału sprawdza status i decyduje, czy wszystkie zatwierdzenia są wymagane i albo blokuje niektóre z nich, albo prosi programistów, aby się zablokowali. Na koniec oddział obsługi technicznej zostaje połączony z upsteam.

Cytat ze strony projektu:

W zależności od przepływu pracy można mieć oddziały obsługowe lub specyficzne dla klienta wraz z odgałęzieniem głównym. Oddziały te nazywane są również oddziałami LTS.

Często poprawki trafiają do gałęzi, w których zgłoszono błąd, a następnie zatwierdzenie jest ponownie łączone z gałęzią główną.

Ogólna praktyka polega na tym, aby wszystkie gałęzie były idealnie zsynchronizowane z masterem, tzn. Chcesz zobaczyć wyraźną różnicę między konkretną gałąź i masterem, aby zrozumieć, czy master zawiera wszystkie funkcje i poprawki błędów.

Czasami jednak nie chcesz konkretnych zatwierdzeń, ponieważ są one specyficzne dla klienta i nie będą widoczne dla innych użytkowników. Lub twoja gałąź główna rozdzieliła się tak bardzo, że wymaga zupełnie innego podejścia do rozwiązania problemu, a nawet lepiej, problem już tam nie występuje.

Również w przypadku wyboru typu „wiśnia” z mastera do działu obsługi technicznej wynikowe zatwierdzenie zostanie zablokowane w master.

Dmytro
źródło
0

Utwórz trzecią gałąź dla zmian, które chcesz w master10, ale nie w master20. Zawsze uważaj master10 za „master”, najbardziej stabilną gałąź ze wszystkich. Gałąź, z którą wszystkie inne gałęzie chcą się zawsze synchronizować.

wilhelmtell
źródło
Myślę, że to może zadziałać, ale już znalazłem się w tym stanie, a trzecia gałąź prawdopodobnie jeszcze bardziej mnie zdezorientuje. :)
Brad Robinson
0

Zamiast tego revertlub cherry-pickw tym przypadku musisz poprosić gita, aby uznał zmiany, które pomijasz, za starsze od tych, które wprowadziłeś.

Więc:

  1. scal ostatnie zatwierdzenie przed zatwierdzeniami, które chcesz pominąć. To oczywiście scali wszystkie zobowiązania wcześniej. git merge ccc
  2. Scal zatwierdzenia, które chcesz pominąć. git merge fff --no-commit
  3. wprowadzać wszelkie fuzje, wycofywać wszystkie zmiany, cofać wszystkie zmiany. (Być może istnieją do tego głupie polecenia, ale po prostu wykonałbym tę część w interfejsie użytkownika - ale wiesz jak)
  4. zakończ puste połączenie git merge --continue
  5. Scalaj zatwierdzenia PO tym, który chciałeś pominąć. git merge source-branch-head

Po kroku 4 git uzna, że ​​twoja gałąź jest nowsza niż to zatwierdzenie, ponieważ już sobie z tym poradziłeś (wybierając zachowanie TWOICH wersji rzeczy).

Jason Kleban
źródło