Jak wybrać wiele zatwierdzeń


873

Mam dwie gałęzie. Popełnić ajest szef jednego, a druga ma b, c, d, ei fna górze a. Chcę przenieść c, d, ea fdo pierwszego oddziału bez popełnienia b. Korzystanie wiśnia odebrać to jest proste: Zamówienie pierwszy oddział cherry-pick jeden po drugim cdo fi rebase drugą gałąź na początku. Ale czy jest jakiś sposób, aby wybrać wszystko c- fjednym poleceniem?

Oto wizualny opis scenariusza (dzięki JJD ):

wprowadź opis zdjęcia tutaj


3
baza, o której wspomniałeś, nie ma tak naprawdę znaczenia dla pytania, prawda? (Rozumiem, że możesz chcieć boprzeć się fpóźniej, ale to nie ma nic wspólnego z wybieraniem czereśni).
Superole

Odpowiedzi:


1280

Git 1.7.2 wprowadził możliwość wybrania szeregu zatwierdzeń. Z informacji o wersji :

git cherry-picknauczył się wybierać zakres zatwierdzeń (np. cherry-pick A..Bi cherry-pick --stdin), podobnie jak git revert; nie obsługują one jednak lepszej kontroli sekwencjonowania rebase [-i].

Aby wybrać wszystkie zatwierdzenia od zatwierdzenia Ado zatwierdzenia B(gdzie Ajest starsze niż B), uruchom:

git cherry-pick A^..B

Jeśli chcesz zignorować samą A, uruchom:

git cherry-pick A..B

(Podziękowania w komentarzach dla Damiana, JB Rainsbergera i sschaefa)


249
W formularzu „cherry-pick A..B” A powinno być starsze niż B. Jeśli są w niewłaściwej kolejności, polecenie po cichu się nie powiedzie.
damian

294
Nie będzie to również wybór A, ale wszystko po A do B. włącznie
JB Rainsberger

454
Aby dołączyć typ „just”git cherry-pick A^..B
kiritsuku,

17
Jeśli masz git 1.7.1 lub wcześniejszy i nie możesz go zaktualizować, możesz dość szybko wybrać je w kolejności, uruchamiając git cherry-pick f~3następnie git cherry-pick f~2itd. Aż do git cherry-pick f(naciśnięcie strzałki w górę powoduje pobranie poprzedniego polecenia, dzięki czemu mogę szybko zmienić numer i uruchomić powinien być podobny w większości konsol).
David Mason

19
Warto wiedzieć, że ta składnia działa również z nazwami gałęzi. git cherry-pick master..somebranchwybierze wszystkie zatwierdzenia w somebranch od czasu master (zakładając, że jest już oparte na master) i zastosuje je do twojej aktualnej gałęzi.
Tor Klingberg,

102

Najprostszym sposobem na to jest ontoopcja rebase. Załóżmy, że oddział, który kończy się w bieżące anazywa mybranch i jest to oddział, który chcesz przenieść c- fna.

# checkout mybranch
git checkout mybranch

# reset it to f (currently includes a)
git reset --hard f

# rebase every commit after b and transplant it onto a
git rebase --onto a b

1
Dziękuję Ci! Czy możesz również dodać git checkout secondbranch && git rebase mybranchpełną odpowiedź
tig

1
Ta odpowiedź bardzo pomogła mi ustalić, które zatwierdzenie jest w tym scenariuszu. I: możesz także użyć rebasetrybu interaktywnego. Dzięki, @Charles!
Oliver

1
Piękno tego podejścia polega na tym, że można użyć --interactivedo usunięcia niektórych zatwierdzeń z sekwencji lub zmiany ich kolejności przed „wybraniem czereśni”. +1
Michael Merickel

jest to genialne polecenie, trochę trudne do obejścia, ale działa cuda.
Valerio

Dzikie, że musisz podać zatwierdzenie, którego nie chcesz rebase jako jeden z argumentów ( bw tym przykładzie), ale tak, to zadziałało dla mnie.
asontu

85

Lub żądany liniowiec:

git rebase --onto a b f

5
To najlepsza odpowiedź, choćby ze względu na zwięzłość.
Nate Chandler

9
Pozytywne, ale pozostawi cię w stanie odłączonym HEAD, jeśli f jest zatwierdzeniem (w przeciwieństwie do gałęzi) - należy edytować, aby dodać, że należy sprawdzić gałąź, jak w odpowiedzi poniżej
Mr_and_Mrs_D

68

Możesz użyć szeregowej kombinacji git rebasei, git branchaby zastosować grupę zatwierdzeń do innego oddziału. Jak już napisano przez wolfc, pierwsze polecenie faktycznie kopiuje zatwierdzenia. Jednak zmiana nie jest widoczna, dopóki nie dodasz nazwy gałęzi do najwyższego zatwierdzenia grupy.

Otwórz zdjęcie w nowej karcie ...

Przepływ pracy

Aby podsumować polecenia w formie tekstowej:

  1. Otwarte gitk jako niezależny proces przy pomocy polecenia: gitk --all &.
  2. Uruchom git rebase --onto a b f.
  3. Prasa F5w gitk . Nic się nie zmienia. Ale nie HEADjest zaznaczone.
  4. Biegać git branch selection
  5. Prasa F5w gitk . Pojawi się nowy oddział z jego zatwierdzeniami.

To powinno wyjaśnić rzeczy:

  • Zatwierdź ajest nowym miejscem docelowym grupy.
  • Zatwierdzenie bto zatwierdzenie przed pierwszym zatwierdzeniem w grupie (wyłączne).
  • Zatwierdzenie fjest ostatnim zatwierdzeniem grupy (włącznie).

Następnie można użyć git checkout feature && git reset --hard bdo usunięcia zatwierdzeń cdo fz featureoddziału.

Oprócz tej odpowiedzi napisałem post na blogu, który opisuje polecenia w innym scenariuszu, które powinny pomóc w ogólnym użyciu.


2
Jeśli mybranch (a..f popełnia) nie jest już potrzebny, można to uprościć do: git rebase --onto a b mybranchi btw - do jakiego programu te fajne zdjęcia git?
Mr_and_Mrs_D

2
@Mr_and_Mrs_D Dziękujemy za komentarz. Myślę, że użyłem cacoo.com do narysowania zdjęć.
JJD

48

Aby zastosować komentarze JB Rainsbergera i sschaefa, aby udzielić konkretnej odpowiedzi na pytanie ... Aby użyć zakresu wybierania wiśni w tym przykładzie:

git checkout a
git cherry-pick b..f

lub

git checkout a
git cherry-pick c^..f

3
Używam git 2.7.0.windows.1i zauważyłem, że kiedy próbuję wybrać zakres zatwierdzeń z wiśniowego wyboru, wszystko jest w porządku, ale git nie mówi ci nigdzie, co musisz zrobić, git cherry-pick --continue | --abort | --quitzanim spróbujesz ponownie zatwierdzić / cherry-pick. Jeśli więc wybierzesz zakres zatwierdzeń, będziesz musiał uruchamiać się za git cherry-pick --continuekażdym razem, gdy będziesz gotowy (rozwiązywać konflikty itp.) Z zatwierdzeniem z danego zakresu.
kuskmen

Zrobiłem dokładnie to samo, ale fatalnie: Nie mogę znaleźć „a..b”
Amit Karnik

Nie wiem, gdzie się mylę, ale kiedy robię po swojej stronie „pick-cherry-pick c ^ .. f”, obejmuje to zatwierdzenie f, ale nie zatwierdzenie c. Ale jak czytam wszędzie, należy zdefiniować c i f jako włącznie. A może się mylę?
Samuel

@Samuel tak, to prawda. ^Po c rzeczywiście oznacza „popełnienia przed c”, który jest w tym przypadku b. Dlatego c^..fjest synonimem b..f. Spróbuj zrobić git log c^..fi powinieneś zobaczyć zatwierdzenia od c do f, dokładnie tak, jakbyś to zrobiłgit log b..f
Andy

40

Jeśli masz wybiórcze wersje do scalenia, powiedz A, C, F, J z A, B, C, D, E, F, G, H, I, J zatwierdza, po prostu użyj poniższego polecenia:

git cherry-pick ACFJ


1
ładne i proste
spinup

21
git rev-list --reverse b..f | xargs -n 1 git cherry-pick

2
Działa idealnie, jeśli nie ma konfliktów, w przeciwnym razie „zmiana bazy na” może być łatwiejsza, ponieważ nie będziesz musiał dowiedzieć się, gdzie się zatrzymał i ponownie zastosuje pozostałe łatki.
Ruslan Kabalin

6
Dodaj komentarze wyjaśniające, co to robi
Mr_and_Mrs_D

7
ponieważ nikt nie wyjaśnił ... git rev-list wypisuje wszystkie wersje z gałęzi b do f (odwróconej), więc kiedy każda linia (skrót zatwierdzenia) zostanie przekazana w kolejności, wybierze każdą z nich na bieżącą HEAD git. tj.git cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
coderatchet

8

Aby wybrać Cherry od identyfikatora zatwierdzenia do końca gałęzi, możesz użyć:

git cherry-pick commit_id^..branch_name


To jest już część odpowiedzi stackoverflow.com/a/31640427/96823
tig

1
Ta odpowiedź jest inna i była dla mnie pomocna. Określa nazwę oddziału, a nie ostateczne zatwierdzenie SHA.
Subtletree

7

Innym wariantem wartym wspomnienia jest to, że jeśli chcesz ostatnich nzatwierdzeń z gałęzi, ~składnia może być przydatna:

git cherry-pick some-branch~4..some-branch

W takim przypadku powyższe polecenie wybrałoby 4 ostatnie zatwierdzenia z gałęzi o nazwie some-branch(chociaż można również użyć skrótu zatwierdzenia zamiast nazwy gałęzi)


1
BARDZO przydatna odpowiedź, dziękuję! :)
Jacek Dziurdzikowski

3

W rzeczywistości najprostszym sposobem na to może być:

  1. zapisz bazę scalającą między dwoma gałęziami: MERGE_BASE=$(git merge-base branch-a branch-b)
  2. przewiń do przodu lub ponownie ustaw bazę starszej gałęzi na nowszą gałąź
  3. przekształć wynikową gałąź w siebie, zaczynając od podstawy scalania od kroku 1 i ręcznie usuń niepotrzebne zatwierdzenia:

    git rebase ${SAVED_MERGE_BASE} -i
    

    Alternatywnie, jeśli jest tylko kilka nowych zatwierdzeń, pomiń krok 1 i po prostu użyj

    git rebase HEAD^^^^^^^ -i
    

    w pierwszym kroku, używając wystarczającej ilości, ^aby przejść obok bazy scalania.

Zobaczysz coś takiego w interaktywnej bazie danych:

pick 3139276 commit a
pick c1b421d commit b
pick 7204ee5 commit c
pick 6ae9419 commit d
pick 0152077 commit e
pick 2656623 commit f

Następnie usuń wiersze b (i dowolne inne)



0

Oto skrypt, który pozwoli ci wybrać wiele zatwierdzeń z rzędu, po prostu mówiąc skryptowi, które źródła i gałęzie docelowe dla wyborów cherry i liczbę zatwierdzeń:

https://gist.github.com/nickboldt/99ac1dc4eb4c9ff003a1effef2eb2d81

Aby wybrać z gałęzi do mistrza (używa bieżącej gałęzi jako źródła):

./gcpl.sh -m

Aby wybrać 5 ostatnich zatwierdzeń z oddziału 6.19.x do opanowania:

./gcpl.sh -c 5 -s 6.19.x -t master

Dlaczego ten skrypt byłby potrzebny, skoro możesz to zrobić bezpośrednio z Git? ...
code_dredd

Mniej pisania, a mój skrypt automatycznie wybiera zatwierdzenia dla ciebie, więc nie musisz wybierać każdego z nich za pomocą SHA. W każdym razie YMMV.
nickboldt
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.