Как переместить определенные коммиты на основе другой ветки в git?


381

Ситуация:

  • мастер в X
  • quickfix1 в X + 2 коммитов

Такой что:

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

Затем я начал работать с quickfix2, но случайно взял в качестве источника ветку quickfix1, а не мастер. Теперь quickfix2 находится на X + 2 коммитов + 2 соответствующих коммитов.

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

Теперь я хочу иметь ветку с quickfix2, но без двух коммитов, которые относятся к quickfix1.

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

Я пытался создать патч из определенной ревизии в quickfix2, но патч не сохраняет историю коммитов. Есть ли способ сохранить мою историю коммитов, но иметь ветку без изменений в quickfix1?



8
@Kevin Этот вопрос касается только перемещения коммитов из одной ветки в другую, в этом есть дополнительное требование не включать коммиты quickfix1. (Обратите внимание также на разницу в ответах.)
— Скотт Уэлдон

Ответы:


372

Это классический случай 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 

Так что вы должны идти от

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

чтобы:

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

Лучше всего это делать на чистом рабочем дереве.
Смотритеgit config --global rebase.autostash true , особенно после Git 2.10 .


24
Помните, что эти шаги изменят историю quickfix2, поэтому, если вы уже поделились веткой, вместо этого используйте cherry-picking (см. Следующие ответы).
— Макс Черняк

Только для записей: с журналом SmartGit просто перетащите q2aна Xи выберите Rebase 2 commits из вариантов появившегося диалога.
— Томас С.

1
@ThomasS. Интересно. Это хорошая реализация GUI git rebase --onto.
— VonC

1
Я должен признать, я делаю глупые вещи, такие как фиксация на неправильной ветке чаще, чем я действительно должен, графический интерфейс просмотра журнала SmartGit спасал меня много раз в одной и той же ситуации.
— WORMSS

1
@Cosine Согласен. Я отредактировал свой ответ, добавив ссылку на rebase.autostashконфигурацию: это позволит избежать потери выполняемой работы в рабочем дереве при выполнении ребазирования.
— VonC

155

Вы можете использовать, git cherry-pickчтобы просто выбрать коммит, который вы хотите скопировать.

Вероятно, лучший способ - создать ветку из master, а затем использовать в этой ветке git cherry-pick2 коммита из quickfix2, которые вы хотите.


Это также лучший вариант, если вы хотите переместить только один коммит. Спасибо.
— Алекс

142

Самое простое, что вы можете сделать, это выбрать диапазон вишни. Он делает то же самое, что и rebase --ontoдля глаз:

git cherry-pick quickfix1..quickfix2

6
кроме того, он не теряет исходные коммиты, IIUC, поэтому кажется предпочтительным для таких игр, как я;) или rebase --ontoтакже сохраняет оригинальные изменения?
— akavel

6
как rebaseи cherry-pickдать вам новые ключи SHA. Это потому, что каждый коммит является уникальным снимком репозитория.
— Кристоф

6
@Akavel имел в виду, что cherry-pick сохранит первоначальные коммиты в своей ветке, что верно
— Mr_and_Mrs_D

4
Для чего бы это ни стоило, я попытался cherry-pickдиапазон, как в этом ответе, и это смутило мой репо. Я должен был сделать отдельные cherry-picks для каждого коммита. (И, может быть, само собой разумеется, но в случае, если кто-то борется, вы должны cherry-pickв хронологическом порядке, что ваши коммиты были применены.)
— Карменизм

3
git checkoutимеет решающее значение здесь. какая у тебя ГОЛОВА :)?
— Славомир Ленарт

28

Я считаю, что это:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2

3
cherry-pickработает с хешами коммитов, поэтому, если вы просто хотите взять коммит из какого-то места и поместить его в другое место, это путь. Просто убедитесь, что вы делаете checkout <branch>правильную ветку в первую очередь.
— Джон Лейдгрен

-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]

Другие более полезные команды здесь с объяснением: Git Guide

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.