git - пропускает определенные коммиты при слиянии

200

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

У меня есть две ветви, называемые скажем master10 (для v1) и master20 (для v2). Я делал исправления ошибок в v1 на ветке master10 и разрабатывал новые вещи для master20. Всякий раз, когда я исправляю ошибку, я объединяю ее с версией v2, проверяя master20 и делая git merge master10. Все идет нормально.

Однако теперь я внес в v1 изменение, которое не требуется в v2, но я хочу продолжить объединение других исправлений ошибок. Как мне сказать Git пропустить этот конкретный коммит (или диапазон коммитов), но в дальнейшем я все еще хочу объединить другие исправления ошибок.

Я подумал, git rebaseчто это то, что мне нужно, но прочитал документ, и моя голова чуть не взорвалась.

Я думаю, что мне нужно что-то вроде команды «git sync», которая сообщает git, что две ветви сейчас синхронизированы и в будущем объединяют только коммиты с этой точки синхронизации.

Любая помощь приветствуется.

Брэд Робинсон
источник

Ответы:

289

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

Итак, давайте предположим, что к maint применено 5 изменений, и одно из них (maint ~ 3) не должно быть объединено с master, хотя все остальные должны быть. Вы делаете это в три этапа: на самом деле объединяйте все до этого, говорите git пометить maint ~ 3 как слитые, даже если это не так, и затем объединяйте остальные. Магия это:

bash <master>$ git merge maint~4
bash <master>$ git merge -s ours maint~3
bash <master>$ git merge maint

Первая команда объединяет все до того, как ваша проблемная мэйнт фиксируется на мастере. Сообщение в журнале слияния по умолчанию объяснит, что вы объединяете "ветку 'maint' (ранняя часть)".

Вторая команда объединяет проблемный коммит maint ~ 3, но опция «-s ours» говорит git использовать специальную «стратегию слияния», которая, фактически, работает просто, сохраняя дерево, в которое вы сливаетесь, и игнорируя коммиты Вы полностью объединены. Но он все еще делает новый коммит слияния с HEAD и maint ~ 3 в качестве родителей, поэтому график изменений теперь говорит, что maint ~ 3 объединен. Так что на самом деле вы, вероятно, захотите использовать опцию -m и для «git merge», чтобы объяснить, что этот коммит maint ~ 3 фактически игнорируется!

Последняя команда просто объединяет оставшуюся часть maint (maint ~ 2..maint) в master, чтобы вы снова синхронизировались.

araqnid
источник
5
Я думаю, что если вам нужно отложить объединение этого коммита, у вас нет другого выбора, кроме как пропустить его (merge -s ours), а затем применить его с помощью команды cherry-pick. Как только коммит становится доступным от мастера, он не может быть снова объединен - ​​избегание объединения одного и того же изменения дважды - одна из главных целей git.
araqnid
3
Что касается примера вашего филиала: я подозреваю, что после того, как вы объединили филиал, вы находитесь в точно такой же ситуации, как и после второго шага моего поста. Создание дополнительных веток не имеет значения для отношений фиксации.
araqnid
5
Просто ради интереса, если вы просто хотите пропустить одно изменение, почему бы вам просто не сделать одно слияние, а затем отменить это одно изменение, а не выполнить три слияния? Это приведет к тому, что в хранилище будет зафиксировано меньше наборов изменений и более явная история.
Марк Бут
3
Часто проще явно назвать коммиты. Так что вам просто нужно просмотреть журнал git ветки, подлежащей слиянию, и записать хэши коммитов, которые не должны быть объединены, и
предыдущий
14
@MarkBooth: коммит, который вы хотите пропустить, может находиться в колоссальном конфликте с веткой, в которую вы хотите слиться. Проще просто пропустить ее, вместо того, чтобы исправлять конфликты, а затем возвращать это изменение и снова исправлять конфликты
SztupY
39

ИМХО, самое логичное, что нужно сделать, это объединить все, а затем использовать git revert (commit_you_dont_want) для его удаления .

Пример:

git merge master
git revert 12345678

Если у вас есть несколько коммитов "to-ignore" или вы хотите отредактировать сообщение об отмене:

git merge master
git revert -n 123456
git revert -n abcdef
git commit -m "... Except commits 123456 and abcdef"

Тогда ваша история может выглядеть так:

| ... Except 123456 and abcdef
|\ Merge branch 'master' into 'your_branch'

Если у вас есть конфликты, связанные ТОЛЬКО с этими фиксациями «игнорировать», вы можете использовать:

git merge master -X ours

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

Если у вас есть конфликты, связанные НЕ ТОЛЬКО с фиксацией «игнорировать», вы должны разрешить их вручную, и вам, вероятно, придется разрешать их снова во время возврата.

Александр Т.
источник
2
Если затем вы захотите объединить эти отозванные коммиты в ветке под вопросом, будет ли Git игнорировать их?
Анриетт Майбург
@ AnriëtteMyburgh Вы можете отменить коммиты реверсии, чтобы потом объединить их - то, что вы на самом деле не можете сделать так же легко со стратегией «слияния наших».
Лили Чунг
Спасибо, это именно то, что мне было нужно, чтобы в ветке функций было несколько старых коммитов, которые я не хотел в мастере, и куча, которую я хотел в мастере. Красиво и чисто.
Вале Трухильо
17

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

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

Dustin
источник
1
Спасибо, вишня выберет эту работу. Не так хорошо, как я надеялся, но это подойдет.
Брэд Робинсон
3

Своего рода реклама моего проекта, которая в основном оборачивает процесс, описанный @araqnid.

Это своего рода помощник, который вводит следующий поток GIT:

  • есть ежедневное / еженедельное уведомление об ожидающих слияниях из ветвей обслуживания в ветку dev / master
  • сопровождающий филиала проверяет статус и сам решает, требуются ли все коммиты, и либо блокирует некоторые из них, либо просит разработчиков заблокировать себя. В конце ветвь обслуживания объединяется в upsteam.

Цитата со страницы проекта:

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

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

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

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

Также в случае выбора вишни из мастера в ветвь обслуживания полученный коммит должен быть заблокирован в мастере.

Дмитро
источник
0

Создайте третью ветку для изменений, которые вы хотите в master10, но не в master20. Всегда считайте master10 своим "хозяином", самой стабильной веткой из всех. Ветвь, с которой все остальные ветви должны постоянно синхронизироваться.

wilhelmtell
источник
Я думаю, это может сработать, но я уже погрузился в это состояние, и третья ветвь, вероятно, смутит меня еще больше. :)
Брэд Робинсон
0

Вместо revertили cherry-pickдля этого случая вам нужно получить git, чтобы учесть изменения, которые вы пропускаете, старше, чем те, которые вы сделали.

Так:

  1. объединить последний коммит до коммитов, которые вы хотите пропустить. Это, конечно, объединит все коммиты ранее. git merge ccc
  2. объединить коммиты, которые вы хотите пропустить. git merge fff --no-commit
  3. Произведите слияние, отмените все изменения, отмените все изменения. (Возможно, для этого есть надежные команды, но я бы просто выполнил эту часть в пользовательском интерфейсе - как вы знаете, как)
  4. завершить пустое слияние git merge --continue
  5. объединить коммиты ПОСЛЕ того, кого вы хотели пропустить. git merge source-branch-head

После шага 4 git будет считать вашу ветку более новой, чем эта фиксация, поскольку вы уже имели дело с ней (решив сохранить ВАШИ версии вещей).

Джейсон Клебан
источник