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


728

У меня есть две ветви от моего хозяина:

  • v2.1 : (версия 2) я работаю в течение нескольких месяцев
  • WSS : что я создал вчера, чтобы добавить одну особенность для моего мастера (в производстве)

Есть ли способ скопировать вчерашние коммиты из wss в v2.1?


Просто скопировать коммиты (или диапазон коммитов) из одной ветки в другую этот ответ помог мне лучше всего: stackoverflow.com/questions/1994463/…
caramba

Ответы:


566

Вы действительно должны иметь рабочий процесс, который позволяет вам делать все это путем слияния:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (wss)

Так что все, что вам нужно сделать, это git checkout v2.1и git merge wss. Если по какой-то причине вы действительно не можете этого сделать и не можете использовать git rebase для перемещения ветки wss в нужное место, команда для получения одного коммита и его применения в другом месте - это git cherry-pick . Просто отметьте ветку, в которой вы хотите ее применить, и запустите git cherry-pick <SHA of commit to cherry-pick>.

Некоторые из способов rebase могут спасти вас:

Если ваша история выглядит так:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

Вы можете использовать git rebase --onto v2 v2-only wssдля перемещения WSS непосредственно на v2:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

Тогда вы можете слить! Если вы действительно, действительно, действительно не можете добраться до точки, где вы можете объединиться, вы все равно можете использовать rebase для эффективного выполнения нескольких вишневых выборов одновременно:

# wss-starting-point is the SHA1/branch immediately before the first commit to rebase
git branch wss-to-rebase wss
git rebase --onto v2.1 wss-starting-point wss-to-rebase
git checkout v2.1
git merge wss-to-rebase

Примечание: причина того, что для этого требуется дополнительная работа, заключается в том, что он создает дублирующие коммиты в вашем хранилище. Это на самом деле не очень хорошая вещь - весь смысл простого ветвления и объединения состоит в том, чтобы иметь возможность делать все, делая коммиты в одном месте и объединяя их там, где они нужны. Двойные коммиты означают намерение никогда не объединять эти две ветви (если вы решите, что захотите позже, вы получите конфликты).


1
Не могу согласиться с этим ответом. +1. См. Также мой старый ответ, иллюстрирующий последствия сбора вишни: stackoverflow.com/questions/881092/…
VonC

18
Превосходный ответ о том, как сделать это правильно ! Хотел бы я дважды проголосовать за усилия по созданию диаграмм ASCII.
получил

@VonC: Спасибо за поддержку и дополнительную информацию о том, почему бы не выбрать вишню - я знаю, что немного сэкономил там. @gotgenes: спасибо! Я думаю, что это того стоит, просто посмотрите на страницу руководства git-rebase. Нет лучшего способа объяснить это.
Каскабель

Что касается того, почему вы не можете слиться - Git merging не очень хорошо работает с git-svn. Чтобы скопировать серию коммитов из одной ветки SVN в другую, я закончил тем, что выбирал их, а затем выполнил интерактивное перебазирование / перефразирование, чтобы удалить неправильные git-svn-idссылки перед dcommitповторным использованием. Хотя я, вероятно, мог бы пропустить шаг выбора вишни и просто использовать ребаз.
Боб

1
Вот мой вариант использования: исправления критических ошибок были зафиксированы в функциональной ветке. Мне нужно, чтобы мастер начал работать. Это спасет мою задницу.
Капитан Гипертекст

911

использование

git cherry-pick <commit>

применить <commit>к вашей текущей ветви .

Я сам, вероятно, перепроверю коммиты, которые я выберу, gitkи выделю их, щелкнув правой кнопкой мыши на записи коммита.


Если вы хотите работать более автоматически (со всеми его опасностями) и предполагая, что все коммиты со вчерашнего дня произошли на wss, вы можете сгенерировать список коммитов, использующих git log--prettyпредложением Jefromi)

git log --reverse --since=yesterday --pretty=%H

так что все вместе, если вы используете bash

for commit in $(git log --reverse --since=yesterday --pretty=%H);
do
    git cherry-pick $commit
done

Если здесь что-то пойдет не так (есть большой потенциал), у вас возникли проблемы, так как это работает на кассе в реальном времени, так что либо делайте ручные вишневые пики, либо используйте rebase, как предложено Jefromi.


Все заполнители для опции --pretty находятся на странице руководства git-log. Вы можете получить любой формат, который вы хотите - особенно полезный для получения полей, которые вы хотите для скрипта, в легко разбираемой форме.
Каскабель

Я также хотел бы отметить, что, если вы действительно хотите создавать дублирующие коммиты, метод, использованный git rebaseв моем ответе, является более надежным. В частности, при использовании цикла for, подобного этому, в случае сбоя одного из вишневых пиков он все равно попытается выполнить все остальные. Это ... очень очень не хорошо, скажем так.
Каскабель

2
Согласовано. Вот почему я никогда не использую это, но делаю это вручную. Но вишневый пик - все еще ответ, по крайней мере, на заголовок вопроса. Я изменил ответ.
Бенджамин Банье

1
Кто-то зафиксировал старую / неправильную ветку, и cherry-pick позволил мне поместить этот коммит в правильную ветвь (при этом сохраняя его в качестве коммиттера). Отлично.
Патрик

8
Редкий взгляд, gitответ, который прост и прямо к решению, вместо того, чтобы бродить по хитросплетениям хитрости, чтобы доказать, насколько хорошо ответчик знает это.
Przemek D

74

git cherry-pick : Применить изменения, внесенные некоторыми существующими коммитами

Предположим, что у нас есть ветвь A с (X, Y, Z) коммитами. Нам нужно добавить эти коммиты в ветви B . Мы собираемся использовать cherry-pickоперации.

Когда мы используем cherry-pick, мы должны добавить фиксации на ветвь B в том же хронологическом порядке , что коммиты появляются в филиале A .

cherry-pick действительно поддерживает диапазон коммитов, но если у вас есть коммиты слияния в этом диапазоне, это становится действительно сложным

git checkout B
git cherry-pick SHA-COMMIT-X
git cherry-pick SHA-COMMIT-Y
git cherry-pick SHA-COMMIT-Z

Пример рабочего процесса:

введите описание изображения здесь

Мы можем использовать cherry-pickс опциями

-e или --edit : с этой опцией, git cherry-pick позволит вам редактировать сообщение о коммите перед его фиксацией.

-n или --no-commit : Обычно команда автоматически создает последовательность коммитов. Этот флаг применяет изменения, необходимые для выбора каждого именованного коммита, в ваше рабочее дерево и индекс без каких-либо коммитов. Кроме того, когда используется эта опция, ваш индекс не должен соответствовать фиксации HEAD. Выбор вишни выполняется против начального состояния вашего индекса.

Здесь интересная статья, касающаяся cherry-pick.


19

Вы можете создать патч из коммитов, которые хотите скопировать, и применить патч к целевой ветке.


16
Даже если вы по какой-то причине действительно хотите использовать патч (ы) вместо cherry-pick (s) / rebase, простой способ сделать это с помощью git format-patch <revision range>и git am *.patch.
Каскабель

Требуется checkoutв другую ветку.
CoolMind

12

Или, если Вы немного меньше на стороне евангелиста, Вы можете сделать немного безобразно, как я использую. В deploy_template есть коммиты, которые я хочу скопировать на мой мастер в качестве ветки deploy

git branch deploy deploy_template
git checkout deploy
git rebase master

Это создаст новое развертывание ветки (я использую -f, чтобы перезаписать существующую ветку развертывания) на deploy_template, затем перебазирую эту новую ветку на master, оставив deploy_template нетронутым.


1

Для простого случая просто скопировать последний коммит из ветки wss в v2.1, вы можете просто взять идентификатор фиксации ( git log --oneline | head -n 1) и сделать:

git checkout v2.1
git merge <commit>

Это требует проверки в другую ветку.
CoolMind

1

Команда cherry-pick может прочитать список коммитов из стандартного ввода.

Следующая команда cherry-picks выполняет коммиты, созданные пользователем John, которые существуют в ветви "velop ", но не в ветви" release ", и делают это в хронологическом порядке.

git log develop --not release --format=%H --reverse --author John | git cherry-pick --stdin
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.