Jak przenieść niektóre commity na podstawie innej gałęzi w git?

381

Sytuacja:

  • mistrz jest na X
  • quickfix1 jest w X + 2 zatwierdza

Tak, że:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Potem zacząłem pracować nad Quickfix2, ale przez przypadek wziąłem Quickfix1 jako gałąź źródłową do skopiowania, a nie master. Teraz Quickfix2 jest na X + 2 zatwierdzeń + 2 odpowiednie zatwierdzenia.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Teraz chcę mieć gałąź z Quickfix2, ale bez 2 zatwierdzeń, które należą do Quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Próbowałem utworzyć łatkę z pewnej wersji w Quickfix2, ale łatka nie zachowuje historii zmian. Czy istnieje sposób, aby zapisać moją historię zatwierdzeń, ale mieć gałąź bez zmian w Quickfix1?

Alex Yarmula
źródło
8
@Kevin To pytanie dotyczy tylko przenoszenia zatwierdzeń z jednej gałęzi do drugiej, dodatkowo wymaga to nie włączania zatwierdzeń quickfix1. (Zwróć też uwagę na różnicę w odpowiedziach).
Scott Weldon,

Odpowiedzi:

372

Jest to klasyczny przypadek rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Więc powinieneś odejść

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

do:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Najlepiej zrobić to na czysto działającym drzewie.
Zobaczgit config --global rebase.autostash true , szczególnie po Git 2.10 .

VonC
źródło
24
Uważaj, aby te kroki zmodyfikowały historię Quickfix2, więc jeśli już udostępniasz gałąź, użyj zamiast tego wybrania wiśniowego (patrz poniższe odpowiedzi).
Max Chernyak
Wystarczy do ewidencji: z SmartGit za dziennika wystarczy przeciągnąć q2ana Xi wybierz rebase 2 rewizje z opcji w oknie dialogowym występującego.
Thomas S.
1
@ThomasS. Ciekawy. To ładna implementacja GUI git rebase --onto.
VonC
1
Muszę przyznać, że robię głupie rzeczy, takie jak popełnianie błędów w niewłaściwym oddziale częściej, niż powinienem, GUI widoku dziennika SmartGit uratowało mnie tyle razy w tej samej sytuacji.
WORMSS,
1
@Cosine uzgodnione. Zredagowałem swoją odpowiedź, aby dodać odniesienie do rebase.autostashkonfiguracji: pozwoli to uniknąć utraty pracy w drzewie roboczym podczas wykonywania zmiany bazy.
VonC
155

Możesz użyć, git cherry-pickaby wybrać zatwierdzenie, które chcesz skopiować.

Prawdopodobnie najlepszym sposobem jest utworzenie gałęzi z poziomu głównego, a następnie użycie w tej gałęzi git cherry-pickdwóch zatwierdzeń z Quickfix2, które chcesz.

DJ.
źródło
Jest to również najlepsza opcja, jeśli chcesz przenieść tylko jeden zatwierdzenie. Dzięki.
Alex
142

Najprostszą rzeczą, jaką możesz zrobić, jest wybór zakresu. Robi to samo, rebase --ontoale jest łatwiejszy dla oczu :)

git cherry-pick quickfix1..quickfix2
Christoph
źródło
6
nie traci też pierwotnych zatwierdzeń, IIUC, więc wydaje się być lepszym rozwiązaniem dla takich „bezpiecznych zabaw” jak ja;) czy rebase --ontoteż zachowuje oryginalne zmiany?
akavel
6
oba rebasei cherry-pickdają ci nowe klucze SHA. To dlatego, że każde zatwierdzenie jest unikalną migawką repozytorium.
Christoph
6
@Akavel miał na myśli to, że cherry-pick zachowa oryginalne zatwierdzenia w swojej gałęzi, co jest prawdą
Mr_and_Mrs_D
4
Niezależnie od tego, co jest tego warte, starałem się cherry-pickosiągnąć zakres jak w tej odpowiedzi i to pomieszało moje repo. Musiałem robić indywidualne cherry-pickdla każdego zatwierdzenia. (I być może jest to oczywiste, ale na wypadek, gdyby ktoś walczył, musisz cherry-pickw porządku chronologicznym, aby twoje zobowiązania zostały zastosowane.)
karmenizm
3
git checkoutma tutaj kluczowe znaczenie. jaka jest twoja GŁOWA :)?
Sławomir Lenart
28

Wierzę, że to:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
źródło
3
cherry-pickdziała z hashami zatwierdzania, więc jeśli chcesz po prostu pobrać gdzieś zatwierdzenie i umieścić go gdzie indziej, jest to właściwa droga. Tylko upewnij się, że wykonujesz checkout <branch>najpierw prawidłową gałąź.
John Leidegren,
-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Inne bardziej przydatne polecenia tutaj z wyjaśnieniem: Git Guide

Suseł
źródło