Как выборочно объединить или выбрать изменения из другой ветки в Git? - PullRequest
1311 голосов
/ 16 января 2009

Я использую git для нового проекта, который имеет две параллельные - но в настоящее время экспериментальные - ветви разработки:

  • master: импорт существующей кодовой базы плюс несколько модов, в которых я, как правило, уверен
  • exp1: экспериментальная ветка № 1
  • exp2: экспериментальная ветка № 2

exp1 и exp2 представляют два очень разных архитектурных подхода. Пока я не продвинусь дальше, у меня нет никакого способа узнать, какой из них (если любой) будет работать. Когда я делаю успехи в одной ветке, у меня иногда есть правки, которые были бы полезны в другой ветке, и я хотел бы объединить только те.

Каков наилучший способ объединения выборочных изменений из одной ветви разработки в другую, оставляя после себя все остальное?

Подходы, которые я рассмотрел:

  1. git merge --no-commit с последующей ручной постановкой большого количества правок, которые я не хочу делать общими для ветвей.

  2. Ручное копирование общих файлов во временный каталог, затем git checkout для перемещения в другую ветвь и последующее ручное копирование из временного каталога в рабочее дерево.

  3. Вариант вышеизложенного. Оставьте пока ветки exp и используйте два дополнительных локальных репозитория для экспериментов. Это значительно упрощает ручное копирование файлов.

Все три из этих подходов кажутся утомительными и подверженными ошибкам. Я надеюсь, что есть лучший подход; что-то похожее на параметр пути фильтра, что сделает git-merge более избирательным.

Ответы [ 25 ]

3 голосов
/ 02 апреля 2019

А как насчет git reset --soft branch? Я удивлен, что никто еще не упомянул об этом.

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

3 голосов
/ 16 октября 2018

Если у вас не слишком много файлов, которые были изменены, это не оставит вам лишних коммитов.

1. Дубликат ветки временно
$ git checkout -b temp_branch

2. Сбросить до последнего требуемого коммита
$ git reset --hard HEAD~n, где n - количество коммитов, которое вам нужно вернуть

3. Оформить заказ на каждый файл из оригинальной ветки
$ git checkout origin/original_branch filename.ext

Теперь вы можете зафиксировать и принудительно нажать (чтобы перезаписать удаленный), если необходимо.

3 голосов
/ 22 ноября 2017

Простой подход для выборочного слияния / фиксации по файлу:

git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes

2 голосов
/ 06 ноября 2018

Если вам нужно только объединить определенный каталог и оставить все остальное без изменений, но при этом сохранить историю, вы можете попробовать это ... создать новый target-branch из master перед началом эксперимента.

Следующие шаги предполагают, что у вас есть две ветви target-branch и source-branch, а каталог dir-to-merge, который вы хотите объединить, находится в source-branch. Также предположим, что у вас есть другие каталоги, такие как dir-to-retain в цели, которые вы не хотите изменять и сохранить историю. Кроме того, предполагается, что есть конфликты слияния в dir-to-merge.

git checkout target-branch
git merge --no-ff --no-commit -X theirs source-branch
# the option "-X theirs", will pick theirs when there is a conflict. 
# the options "--no--ff --no-commit" prevent a commit after a merge, and give you an opportunity to fix other directories you want to retain, before you commit this merge.

# the above, would have messed up the other directories that you want to retain.
# so you need to reset them for every directory that you want to retain.
git reset HEAD dir-to-retain
# verify everything and commit.
2 голосов
/ 07 октября 2017

Когда между текущими коммитами двух ветвей изменилось всего несколько файлов, я вручную объединяю изменения, просматривая разные файлы.

git difftoll <branch-1>..<branch-2>

...