git cherry-pick mówi „… 38c74d to połączenie, ale nie podano opcji -m”

518

Wprowadziłem kilka zmian w mojej gałęzi master i chcę wprowadzić je wcześniej. kiedy wybieram następujące zatwierdzenia, utknąłem na fd9f578, gdzie git mówi:

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

Co git próbuje mi powiedzieć i czy wybranie właściwego rozwiązania jest tutaj przydatne? Gałąź główna zawiera zmiany w plikach, które zostały zmodyfikowane w gałęzi upstream, więc jestem pewien, że wystąpią pewne konflikty scalania, ale nie są one takie złe, aby je wyjaśnić. Wiem, które zmiany są potrzebne gdzie.

To są zobowiązania, które chcę wprowadzić na początku.

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...
wufoo
źródło

Odpowiedzi:

606

Sposób, w jaki działa cherry-pick, polega na pobraniu różnic, które reprezentuje zestaw zmian (różnica między działającym drzewem w tym punkcie a drzewem roboczym jego rodzica) i zastosowaniu go do bieżącej gałęzi.

Tak więc, jeśli zatwierdzenie ma dwoje lub więcej rodziców, reprezentuje również dwa lub więcej różnic - które należy zastosować?

Próbujesz wybrać wiśni fd9f578, która była połączeniem z dwojgiem rodziców. Musisz więc powiedzieć komendzie cherry-pick, z której należy obliczyć różnicę, używając -mopcji. Na przykład, git cherry-pick -m 1 fd9f578aby użyć rodzica 1 jako podstawy.

Nie mogę powiedzieć na pewno o twojej konkretnej sytuacji, ale używanie git mergezamiast git cherry-pickjest ogólnie wskazane. Kiedy wybrałeś zatwierdzenie scalania, powoduje ono zwinięcie wszystkich zmian dokonanych w obiekcie nadrzędnym, którego nie określiłeś -mw tym zatwierdzeniu . Tracicie całą ich historię i glom razem wszystkie ich różnice. Twoja decyzja.

Borealid
źródło
3
@wufoo Prawdopodobnie powinieneś także dowiedzieć się więcej git rebase- to jak scalenie, ale zamiast zintegrować dwie gałęzie, przeszczepia jedną, aby usiąść na drugiej.
Borealid
91
skąd znasz numer rodzica?
Anentropic
66
@Anentropic 1 to „pierwszy rodzic”, 2 to „drugi rodzic” i tak dalej. Kolejność jest taka, w jakiej są wymienione w zatwierdzeniu (oglądane przez git showi tym podobne).
Borealid
2
@lkraav Mógłbyś także zrobić, git reset --hard HEAD@{1}aby odzyskać swoje brakujące zatwierdzenie. git resetnie ogranicza się do cofania się w historii. git checkout -b mybranch HEAD@{1}też by działał.
Borealid,
4
OSTRZEŻENIE: git mergemoże mieć niezamierzone konsekwencje. To polecenie doda wszystkie inne (starsze) zatwierdzenia, które istnieją w gałęzi nadrzędnej. Zwykle ludzie wybierają wiśniowe wybieranie, ponieważ nie chcą innych zobowiązań. Upewnij się, że dokładnie sprawdzasz, czy wprowadzasz tylko te zmiany, które chcesz!
Kay V
52

-m oznacza numer rodzica.

Z git doc:

Zwykle nie można wybrać scalenia, ponieważ nie wiadomo, którą stronę scalenia należy uznać za linię główną. Ta opcja określa numer nadrzędny (od 1) linii głównej i pozwala cherry-pick odtworzyć zmianę w stosunku do określonego elementu nadrzędnego.

Na przykład, jeśli twoje drzewo zatwierdzeń jest jak poniżej:

- A - D - E - F -   master
   \     /
    B - C           branch one

następnie git cherry-pick Ebędzie produkować kwestię Ci zmierzyć.

git cherry-pick E -m 1oznacza używanie D-E, podczas gdy git cherry-pick E -m 2oznacza używanie B-C-E.

gavincook
źródło
32

@ Odpowiedź Borealid jest poprawna, ale załóżmy, że nie zależy ci na zachowaniu dokładnej historii scalania gałęzi i po prostu chcesz wybrać jej zlinearyzowaną wersję. Oto prosty i bezpieczny sposób, aby to zrobić:

Stan początkowy: jesteś na gałęzi Xi chcesz wybijać zatwierdzenia Y..Z.

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (opcjonalny) git branch -D tempZ

To polega na stworzeniu gałęzi tempZopartej na Z, ale z historią od Yzlinearyzowania, a następnie wybranie go na kopię Xtzw newX. (Bezpieczniej jest to zrobić w nowej gałęzi, niż mutować X.) Oczywiście w kroku 4 mogą wystąpić konflikty, które będziesz musiał rozwiązać w zwykły sposób ( cherry-pickdziała bardzo podobnie rebasepod tym względem). Na koniec usuwa tempZgałąź tymczasową .

Jeśli krok 2 wyświetla komunikat „Aktualna gałąź temp. Z jest aktualna”, to Y..Zjest już liniowy, więc po prostu zignoruj ​​ten komunikat i przejdź do kroku 3.

Następnie sprawdź newXi sprawdź, czy zrobiłeś to, co chciałeś.

(Uwaga: nie jest to to samo, co proste git rebase Xna gałęzi Z, ponieważ nie zależy w żaden sposób od relacji między Xi Y; mogą występować między wspólnym przodkiem a Ytym, czego nie chciałeś).

Daira Hopwood
źródło
1
git rebase YmówiCurrent branch tempZ is up to date
Basilevs,
Myślę, że to oznacza, że Y..Zbyło to już liniowe. Możesz więc zignorować tę wiadomość i przejść do kroków 3 i 4.
Daira Hopwood
1
Ciekawy pomysł, musiałem narysować go na papierze, aby w pełni docenić, co się dzieje = D
Chris
2
Znakomity. git cherry-pick dla całego zakresu skarżył się albo na brak opcji -m, albo na jej dostarczenie. Twoje rozwiązanie było złote. (Jedna sugestia: usuń gałąź tempZ później)
Otheus
1
to jest niesamowite! Walczyłem z kilofem i tylko to miało sens. Miałem trochę kłopotów z wybranymi literami (niektóre gałęzie i zatwierdzenia są dużymi literami, a niektóre gałęzie są małe)
pcarvalho 30.10.19
19

Uproszczać. Cherry-pick the commits. Nie wybieraj scalania.

Oto przepis zaakceptowanej odpowiedzi, który idealnie wyjaśnia zalety / ryzyko możliwych podejść:

Próbujesz wybrać fd9f578, który był połączeniem dwojga rodziców.

Zamiast wybierania scalenia, najprostszą rzeczą jest wybranie zatwierdzenia (ów), które faktycznie chcesz z każdej gałęzi scalania.

Ponieważ już się połączyłeś, prawdopodobnie wszystkie pożądane zmiany znajdują się na liście. Wybierz je bezpośrednio i nie musisz zadzierać z zatwierdzaniem scalania.

wyjaśnienie

Sposób, w jaki działa cherry-pick, polega na pobraniu różnicy reprezentowanej przez zestaw zmian (różnica między drzewem roboczym w tym punkcie a drzewem roboczym jego rodzica) i zastosowaniu zestawu zmian do bieżącej gałęzi.

Jeśli zatwierdzenie ma dwóch lub więcej rodziców, jak ma to miejsce w przypadku scalania, zatwierdzenie to również reprezentuje dwa lub więcej różnic. Błąd występuje z powodu niepewności, w odniesieniu do której należy zastosować różnicę.

alternatywy

Jeśli zdecydujesz, że musisz dołączyć scalenie vs wybranie odpowiednich zatwierdzeń, masz dwie opcje:

  1. (Bardziej skomplikowane i niejasne; również odrzuca historię) możesz wskazać, który rodzic powinien zastosować.

    • Skorzystaj z -mopcji, aby to zrobić. Na przykład git cherry-pick -m 1 fd9f578użyje pierwszego elementu nadrzędnego wymienionego w scaleniu jako podstawy.

    • Weź również pod uwagę, że wybranie zatwierdzenia scalania powoduje zwinięcie wszystkich zmian dokonanych w obiekcie nadrzędnym, którego nie określiłeś -mw tym zatwierdzeniu . Tracicie całą ich historię i glom razem wszystkie ich różnice. Twoja decyzja.

  2. (Prostszy i bardziej znany; zachowuje historię), którego możesz użyć git mergezamiast git cherry-pick.

    • Jak zwykle git merge, spróbuje zastosować wszystkie zatwierdzenia, które istnieją w łączonej gałęzi i wypisać je indywidualnie w dzienniku git.
Kay V.
źródło
2

Uproszczenie metody @Daira Hopwood jest dobre do wybrania jednego zatwierdzenia. Nie potrzebujesz tymczasowych oddziałów.

W przypadku autora:

  • Z jest pożądane zatwierdzenie (fd9f578)
  • Y jest wcześniej zatwierdzone
  • X obecny działający oddział

następnie wykonaj:

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit
efemerydy
źródło
2
To oczywiście traci metadane związane z pierwotnym zatwierdzeniem. Myślę, że to kwestia opinii, czy to jest prostsze. Używam go czasami, gdy chcę stracić metadane i zachować tylko ogólne zmiany kodu. Zauważ, że działa, nawet jeśli Y nie jest bezpośrednim rodzicem Z (w takim przypadku zmiany zostaną zmiażdżone).
Daira Hopwood