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

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

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

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

12 ответов

Решение

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

- 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

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

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

git cherry-pick <commit>

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

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


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

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.

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,

Предположим, я зафиксировал изменения в главной ветке. Я получу идентификатор фиксации (xyz) фиксации, теперь мне нужно перейти в ветку, для которой мне нужно отправить свои фиксации.

Идентификатор одиночной фиксации xyx

git checkout branch-name
git cherry-pick xyz
git push origin branch-name

Множественные идентификаторы фиксации xyz abc qwe

git checkout branch-name
git cherry-pick xyz abc qwe
git push origin branch-name

Уже упомянутые ответы охватывают большую часть вопросов, но, похоже, не хватает одного --no-commit особенность инж.

Предположим, у вас есть несколько коммитов в функциональной ветке, и вы хотите «объединить» их все в один коммит и поместить их в свою основную ветку. В этом случае вам нужно:

      git checkout <branch-on-which-to-add-features>
git cherry-pick --no-commit <commit-hash>
git cherry-pick --no-commit <commit-hash>
.
.
.

И, наконец, после того, как вы отредактировали все необходимые функции, вы можете сделать финальную фиксацию:

      git commit -m "Some message for the merge commit"

В идеале, как упоминалось в @Cascabel , вы должны использовать merge или же rebase. Но если вы чувствуете, что другого выбора нет, вам может сойти с рук cherry-picking.

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

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

git branch deploy deploy_template
git checkout deploy
git rebase master

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

Вот еще один подход.

git checkout {SOURCE_BRANCH}               # switch to Source branch.
git checkout {COMMIT_HASH}                 # go back to the desired commit.
git checkout -b {temp_branch}              # create a new temporary branch from {COMMIT_HASH} snapshot.
git checkout {TARGET_BRANCH}               # switch to Target branch.
git merge {temp_branch}                    # merge code to your Target branch.
git branch -d {temp_branch}                # delete the temp branch.

Безопаснее использовать встроенный git gui для выбора конкретных коммитов:

Например: скопируйте один коммит из devответвление к mainответвляться:

      git checkout main
gitk --all

Затем щелкните правой кнопкой мыши нужный коммит и выберите Cherry-pick this commit

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

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

git log develop --not release --format=%H --reverse --author John | git cherry-pick --stdin

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

git checkout v2.1
git merge <commit>

Копирование коммитов из WSS филиала в v2.1 филиал

  1. git checkout wss

  2. git merge v2.1

Меня устраивает.

Другие вопросы по тегам