Можно ли исключить определенные коммиты при выполнении слияния git?
Скажем, что я хочу объединиться из ветки релиза в главную ветку, и в ветке релиза есть некоторые коммиты, которые я не хочу включать в главную ветвь. Есть ли способ выполнить слияние, чтобы одно или несколько из этих коммитов не были объединены?
Моя стратегия состоит в том, чтобы сделать следующее (в главном):
git merge --no-commit release-branch
# Resolve conflicts and apply reverse patch of the commits that I don't want included
git commit # Edit commit message so that it lists the commits that have been reverse-patched
Есть ли лучший способ сделать это?
Ответы
Ответ 1
Создайте новую ветвь, перетащите ветвь в интерактивном режиме и отбросьте, что вы не хотите, а затем слейте ее.
Вы не можете принимать изменения из середины ветки без повторной перемотки, но правильная вещь случится, когда она увидит те же изменения в более позднем слиянии (например, из набора вишни и чего нет).
Ответ 2
Я нашел решение, которое работает для меня в книге Pro Git.
Предположим, вы хотите исключить файл config.php
.
На ветке A:
-
Создайте файл с именем .gitattributes
в том же каталоге, с этой строкой: config.php merge=ours
. Это сообщает Git, какую стратегию использовать при слиянии файла. В этом случае он всегда сохраняет вашу версию, т.е. версию на ветке, в которую вы сливаетесь.
-
Добавить файл .gitattributes
и зафиксировать
На ветке B: повторите шаги 1-2
Попробуйте слить сейчас. Ваш файл должен быть оставлен нетронутым.
Ответ 3
Если у вас есть ветка поддержки, где вы исправляете ошибки и создаете новые версии. На мастере у вас есть следующая версия, в которой вы также часто создаете новые версии.
Каждый раз, когда вы создаете новую версию, вы меняете версию в каком-то файле, фиксируете этот новый файл, создаете тег и нажимаете. Теперь слияние с поддержкой на master всегда будет иметь конфликты в файле, содержащем информацию о версии.
Если файл, содержащий информацию о версии только, содержит информацию о версии, вы можете пойти с ответом fcurella. Но если он действительно может содержать также объединенную информацию (pom.xml, gradle.properties, MANIFEST.MF,...), вы должны выполнить некоторые дополнительные действия.
Давайте рассмотрим следующий пример
C---D*---E---F* support
/
A---B---G---H*---I master
где фиксации со звездами содержат только изменения из-за изменений версии, которые следует игнорировать при слиянии.
Чтобы объединить поддержку в master без конфликтов слияния из-за версий, вы можете выполнить одно из следующих действий:
Множественное слияние совершает
git checkout master
git merge C
git merge D -s ours
git merge E
git merge F -s ours
С аргументом -s ours
мы говорим git только для записи слияния без изменения рабочего пространства. Это сопоставимо с опцией --record-only
svn.
Вышеупомянутое приведет к следующему макету
-------------C---D*---E---F* support
/ \ \ \ \
A---B---G---H*---I---J---K----L---M master
Выполнение одного слияния с использованием вишневого выбора
git checkout master
git merge support -s ours --no-commit
git cherry-pick C E --no-commit
git commit -m 'merged support into master'
сначала мы начинаем слияние, но записываем только то, что мы объединяем, не изменяя рабочее пространство и не совершаем слияние. Затем мы собираем вишни, чтобы слить, опять же без фиксации. Наконец, мы совершаем слияние.
Вышеупомянутое приведет к следующему макету
C---D*---E---F* support
/ \
A---B---G---H*---I---J master
Можно даже автоматизировать сбор вишни.
git checkout master
git merge support -s ours --no-commit
for id in `git log support --reverse --not HEAD --format="%H [%an] %s" |
grep -v "bump version" |
sed "s/\(\w*\)\s.*/\1/g"`
do
git cherry-pick --no-commit $id
done
git commit -m 'merged support into master'
Ответ 4
Причина, по которой это не может быть сделано напрямую, заключается в том, что каждая фиксация содержит ссылки на родительские коммиты (обычно один, но несколько для слияний). Таким образом, если у вас есть одна фиксация (по сумме SHA1), вся история также фиксируется, поскольку родители также содержат ссылки на своих родителей и так далее. Таким образом, единственный способ уйти от патчей в истории - написать новый. git rebase -i на вновь созданной ветке, вероятно, является самым простым способом достижения этого.
Ответ 5
Также возможно изменить файл .git/info/attributes и сохранить его в папке .git вместо добавления файлов .gitattribute по всему, что в конечном итоге потребует добавления их в исходный код.
Ответ 6
Основной вопрос: как вы хотите представить коммиты, которые хотите пропустить?
- скрытно скрывать их (не мой любимый)
- явно пропустить их
- явно отменить их
К сожалению нет. 2 невозможно выразить на графике истории.
Нет. 1 возможно, но я бы никогда этого не делал: фиксация слияния может содержать изменения. - Обычно фиксация слияния указывает на результат слияния еще двух ветвей: все вещи, разработанные в этих ветвях, должны быть в коде после слияния (т.е. В коде, на который указывает слияние слиянием). И больше ничего не должно быть в этой фиксации.
Но удивите, удивите, вы можете изменить всю базу кода и представить ее как слияние. Эффект слияния двояка: он объединяет дерево истории и должен объединять две базы кода. Первое, что он делает точно (в противном случае никто не называет это слиянием), поскольку последний может потерпеть неудачу, например. когда возник конфликт слияния, и он был разрешен неправильно (тогда базы кода не были объединены должным образом).
Некоторые из других ответов говорят об этом. Я рекомендую явный способ: merge plus revert commits.
Ответ 7
Если вы хотите исключить некоторые коммиты, которые находятся в конце, вы можете просто зафиксировать определенный номер фиксации:
git checkout partlyMergedFrom
git whatchanged
--> find the commit hash up to where you want to merge
git checkout partlyMergedInto
git merge e40a0e384f58409fe3c864c655a8d252b6422bfc
git whatchanged
--> check that you really got all the changes you want to have