Родительский номер основной линии при фиксации слияния при выборе вишни

Предположим, это моя история git

  Z
 /
A -- C -- D
 \  /      
  B

Моя ГОЛОВА в настоящее время находится в Z. Я хочу выбрать B и C. Если я правильно понимаю, я должен сделать это:

git cherry-pick B
git cherry-pick C -m 1
git commit --allow-empty

В моем случае это сработало, потому что C не работает (отсюда и пустой коммит впоследствии, мне нужен коммит по другим причинам), но мне интересно, что делает параметр после -m. Вот что я прочитал в документах:

-m родительский номер

--mainline parent-number

Обычно вы не можете выбрать слияние, потому что вы не знаете, какую сторону слияния следует считать основной линией. Эта опция задает номер родителя (начиная с 1) основной ветки и позволяет функции Cherry-pick воспроизвести изменение относительно указанного родителя.

В моем случае у C есть два родителя, но как мне узнать, какой из них 1 и 2, и, что более важно, когда имеет значение, когда я выбираю 1 или 2?


person rink.attendant.6    schedule 20.10.2016    source источник
comment
Кажется, это в основном дубликат stackoverflow.com/questions/9229301/ ... или ваш вопрос действительно о том, можете ли вы определить родителя число из этого графического рисунка? (ответ: нет) или: есть ли какой-то детерминизм в отношении 1-го и 2-го родителя при слиянии? (ответ: да, в комментарии недостаточно места для большего).   -  person torek    schedule 20.10.2016
comment
Как вы хотите, чтобы ваша результирующая история выглядела? Вы хотите, чтобы у C' были родители Z и B'? Зачем вам выбирать C, если вы уже выбрали B?   -  person Scott Weldon    schedule 20.10.2016
comment
@ScottWeldon Я хочу, чтобы моя результирующая история в этой ветке была A -- Z -- B' -- C' (если C' проще иметь несколько родителей, это тоже работает). Мне нужно выбрать эту фиксацию для информации об авторе, несмотря на то, что она пуста   -  person rink.attendant.6    schedule 21.10.2016
comment
@torek На самом деле я прочитал этот вопрос перед публикацией этого, и в ответе говорится, что коммит слияния представляет несколько разных различий и имеет несколько родителей с примером -m 1, но на самом деле не раскрывает в чем разница. Я думаю, было бы очень полезно расширить ваш второй вопрос и, возможно, показать различия между 1-м и 2-м родителем.   -  person rink.attendant.6    schedule 21.10.2016


Ответы (2)


Мое понимание, основанное на этом ответе, заключается в том, что родительский элемент 1 – это объединяемая ветвь, а родительский 2 – объединяемая ветвь. Итак, в вашем случае родитель 1 - это A, а родитель 2 - B. Поскольку вишневый выбор действительно применяет разницу между двумя коммитами, вы используете -m 1 для применения только изменений из B (поскольку разница между A и C содержит изменения из B). В вашем случае это, вероятно, не имеет значения, так как у вас нет коммитов между A и C.

Так что да, -m 1 — это то, что вам нужно, и это верно, даже если между A и C были дополнительные коммиты.

Если вы хотите, чтобы новая история немного больше походила на исходную, есть еще один способ сделать это:

git cherry-pick B
git checkout Z
git merge --no-ff --no-commit B
git commit --author="Some Dev <[email protected]>" --date="<commit C author date>"

(При необходимости вы можете создать новую ветку для B перед сбором вишен.)

Это сохранит информацию об авторе и даст вам историю, которая выглядит следующим образом:

    B'
   /  \
  Z -- C'
 /
A -- C -- D
 \  /      
  B
person Scott Weldon    schedule 21.10.2016
comment
Это правильно: первый родитель любого нормального слияния — это ветвь, в которой вы находитесь во время слияния, так что -m 1 всегда дает изменения, внесенные в результате слияния. Однако невозможно сказать что-либо только по графическому рисунку, так как эта информация теряется в процессе двумерной визуализации. (То есть мы можем рисовать граф так, как нам нравится: топология графа не имеет родительского порядка. Родительский порядок — это то, что добавил Git. Нам потребуется возможность прикреплять маленькие счетные числа к каждой исходящей дуге. из каждой вершины, чтобы представить концепцию числа родителей Git.) - person torek; 21.10.2016
comment
@torek Хорошая мысль о графике. Обычно я предполагаю, что когда он нарисован в виде треугольника (а не ромба, как в вашем ответе), автор указывает, какая ветвь была объединена с какой. - person Scott Weldon; 21.10.2016
comment
Обратите внимание, что родительский заказ также отображается в строке Merge: с git show <commit>. - person boweeb; 08.04.2019

Я проголосовал за ответ Скотта Велдона, что правильно, но я просто хочу добавить попытку рисования ASCII, включающего родительский нумерация. Дан график, который выглядит следующим образом:

       B
      / \
...--A   D--...
      \ /
       C

мы можем сказать, что узел D является фиксацией слияния, но мы не можем сказать, является ли узел B или C первым родителем узла D. Один из двух обязательно является первым родителем, а другой - вторым. Поэтому, если нам нужно знать, мы должны пометить рисунок, что занимает больше места. Вот одна из таких попыток.

         B
       /   \²
...--A       D--...
       \   /¹
         C

Теперь мы видим, что по какой-то причине1 я нарисовал график «вверх ногами»: этот коммит C на самом деле является первым родителем D, а коммит B — вторым родителем.

Можно создавать произвольные слияния с помощью команд более низкого уровня («сантехника»). В частности, git commit-tree просто принимает столько -p аргументов, сколько вы хотите ему передать, в том порядке, в котором вы их даете, и создает новую фиксацию с данными фиксациями в качестве родительских. Дайте ему один -p, и он сделает обычную фиксацию с одним родителем. Не дайте ему -p аргументов, и он сделает корневую фиксацию. Дайте ему 155 различных -p аргументов (все должны, конечно, разрешаться в действительные идентификаторы коммитов), и он сделает один массовый коммит слияния осьминога.

Однако команда git merge всегда делает новую фиксацию с первым родителем, являющимся текущим HEAD (отсюда и текущая ветвь, если она находится на ветке). Второй родитель для стандартного слияния с двумя родителями происходит от .git/MERGE_HEAD, в который git merge записывает другой идентификатор коммита. Если слияние конфликтует или окончательная фиксация слияния задерживается на --no-commit, этот MERGE_HEAD файл фактически является единственным местом, где доступен идентификатор фиксации.

(Когда git merge выполняет слияние осьминога, используя стратегию -s octopus — эта стратегия принудительно используется для таких слияний — и несколько дополнительных родителей, она прерывается и вообще не оставляет следов, если есть конфликты слияния, поэтому случай конфликта никогда не возникает. У меня есть не пробовал комбинировать --no-commit со слиянием осьминога, но это, по логике, оставило бы родителей со 2-го по N-й в MERGE_HEAD, если Git вообще это позволяет.)


1Упрямство.

person torek    schedule 21.10.2016
comment
Итак, если бы я хотел знать, какие числа принадлежат каким родителям, я бы использовал git cat-file -p D-sha1-hash, а первый родитель в файле - 1, а следующий - 2 и ...? - person Brandon; 12.02.2021
comment
@Brandon: Это, безусловно, сработает (и покажет вам, как именно кодируются коммиты, что тоже неплохо). Однако Git сохраняет родительский порядок и в другом выводе, поэтому git rev-parse <hash>^@ также печатает их по порядку (и больше подходит для написания сценариев, если вы это делаете). - person torek; 12.02.2021
comment
Существует также метод суффикса шляпа-и-цифры для разбора их по одному: git rev-parse <hash>^1, git rev-parse <hash>^2 и так далее. Числа здесь в десятичном формате, поэтому, если у вас есть 66-родительский слияние Cthulhu, вы должны использовать ^9, а затем ^10 и ^11 и так далее до ^66. - person torek; 12.02.2021