Git - Как выборочно применять изменения из одной ветки в другую?

Можно ли с помощью Git выборочно применять изменения из одной ветки к другой?

В частности, я использую общедоступную dev ветку для GitHub и частную master ветку для развертывания. Когда изменения вносятся в одну ветвь, их нужно будет применить к другой, но некоторые строки кода должны оставаться разными. В моем случае это несколько классов css и лента.

Я новичок в Git, но я провел свое исследование:

  • Можно использовать git merge --no-commit --no-ff, за которым следует git mergetool, чтобы выбрать то, что я хочу в случае конфликта. Проблема в том, что он работает только в случае конфликтов. Git не может автоматически объединиться, поэтому то, что я хочу сохранить другим, заменяется до того, как я получу возможность использовать свой mergetool.

  • git difftool --cached полезен, поскольку позволяет мне видеть различия, но мне нужно скопировать то, что я хочу сохранить, и вручную заменить его текстовым редактором, так как я не могу просто выбрать и сохранить, как с помощью mergetool.

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

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

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


person toucanb    schedule 13.03.2014    source источник
comment
Итак, по сути, вам может иногда понадобиться только некоторая часть фиксации, которая может быть от нескольких строк в одном файле до нескольких файлов из многих в фиксации?   -  person Nikhil Gupta    schedule 13.03.2014
comment
Мне нужно, чтобы несколько строк кода были разными при слиянии, например, белый фон в одной ветке и черный фон в другой. В том же файле могут быть другие изменения, которые я хотел бы объединить, чтобы исключения файлов не решали все ситуации.   -  person toucanb    schedule 13.03.2014
comment
Возможный дубликат Как объединить отдельные файлы с помощью git-merge?   -  person Inigo    schedule 01.05.2018


Ответы (3)


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

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

person Nikhil Gupta    schedule 13.03.2014
comment
Выполнение git checkout -p branchname, как описано в вашей ссылке, помогло! Это позволяет мне интерактивно получать выборочные изменения из другой ветки без слияния. Cherry-pick тоже может работать, но вносит изменения только за коммиты. - person toucanb; 14.03.2014
comment
: / Очевидно, есть способ - это может быть непросто. - person Att Righ; 22.05.2020

Еще я узнал о патчах:

Чтобы создать патч: git diff dev > master.patch

Чтобы применить: patch < master.patch

person toucanb    schedule 13.03.2014
comment
Спасибо - проголосовали за! Но одно замечание - поскольку мой git настроен так, чтобы помещать выбрасываемые воображаемые имена каталогов a/ и b/ в мой diff, вторая команда для меня немного отличается: patch -p1 < master.patch - person Brandon Rhodes; 26.03.2015

Воспользуйтесь тем фактом, что создание веток git дешево и не должно влиять на фактическое содержимое рабочего каталога.

  1. Проверьте исходную ветку dev.
  2. Создайте временную ветку. Он будет указывать на ту же фиксацию, что и dev: checkout -b for_master

    Предположительно, вы знаете (или можете легко узнать), какая фиксация перед веткой dev является последней перед изменениями, которые вы (частично) хотите. В этом примере предположим, что эта фиксация имеет хэш 1457B4 («последний перед», понятно?).

  3. Сбросьте ветку for_master на этот коммит: git reset 1457B4. (Не используйте переключатель --hard!)

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

  4. Используя интерактивную постановку (git add -p и / или git add -e), создайте фиксацию (или несколько, если хотите), которая содержит все и только изменения, которые вы хотите применить к своей master ветке.

    Запишите хэш последнего коммита (или дайте ему тег). В этом примере я скажу, что его хэш равен C0DA.

  5. Проверьте master.

  6. Черри выберите коммит (и), который вы только что сделали: git cherry-pick 1457B4..C0DA.

    (Обратите внимание, что выбор вишневого диапазона доступен только после версии git 1.7.2. В противном случае вам нужно будет индивидуально выбрать все коммиты, сделанные на шаге 4.)

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

Этот процесс является своего рода обратным использованию git checkout -p, как указано в выбранном ответе. Это может быть полезно для создания cherry-pick-способных коммитов между двумя ветвями, которые имеют общий код, но также имеют много различий (например, между двумя основными версиями проекта), и вы не хотите тратить много времени на игнорирование нерелевантные файлы при звонке на git checkout -p.

Лично мне было удобно использовать два разных каталога рабочего дерева для одного и того же репозитория (один для исходной ветки и один для конечной) и переключаться между двумя командными оболочками, одна из которых использует каталог исходной ветки (рабочее дерево), а другая - назначения. Но если вам неудобно пользоваться функцией git worktree, возможно, это не для вас.

person Wilson F    schedule 01.11.2018
comment
Отличная техника. Помог мне перестроить серию отдельных PR с четко определенными рамками из нескольких недель беспорядочных коммитов, охватывающих несколько функций в одной ветке (позор мне - было бы кошмаром пересматривать!). Спасибо! - person Matt Wanchap; 02.03.2021