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

Ситуация:

  • мастер в 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?

Ответ 1

Это классический случай rebase --onto:

 # let 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.

Ответ 2

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

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

Ответ 3

Простейшая вещь, которую вы можете сделать, - это вишня, выбирающая диапазон. Он делает то же самое, что и rebase --onto, но легче для глаз:)

git cherry-pick quickfix1..quickfix2

Ответ 4

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

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

Ответ 5

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

Ответ 6

Единственный рабочий способ, который я нашел:

git show>~/some_file.txt
git checkout master
git checkout -b new_branch
git apply -stat ~/some_file.txt
git apply -check ~/some_file.txt
git apply ~/some_file.txt

Затем вам нужно снова зафиксировать изменения, но это намного проще, чем сделать это вручную...