Как работает выбор и возврат?

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

В дальнейшем «-» означает diff (аналогично взятию разности наборов в математике, но «A-B» означает те, что в A, но не в B, и минус те, что в B, а не в A), а «+» означает patch (т. е. взятие непересекающихся union в математике. Раньше я не использовал patch, поэтому не уверен).

Из «Контроля версий с Git», автор Loeliger, 2ed

  1. #P4#
    #P5# #P6# #P7#
  2. #P8#
    #P9# #P10# #P11#

person Tim    schedule 03.01.2016    source источник
comment
У вас есть отличные вопросы, вы должны посмотреть эту серию: shop.oreilly.com/product/0636920024774.do многому вас научит   -  person CodeWizard    schedule 03.01.2016


Ответы (3)


выбор вишни

Верно ли, что F' = (F-B) + Z?

Нет, это также внесет изменения, внесенные в C, D и E.

git-cherry-pick работает, изолируя уникальные изменения в коммите, которые будут отобраны (например, F-E в этом примере, игнорируя дополнительных предков, включая базу слияния), и применяя их к цели.

Это делается не с помощью патч-приложения, а с использованием трехстороннего алгоритма слияния: родитель выбранной фиксации будет использоваться в качестве общего предка, а выбранная фиксация будет одной стороной слияния. , с целью в качестве другой стороны. Результатом этого являются изменения, которые были включены в выбранный коммит и в цель.

Например, если E является родителем коммита, который нужно выбрать, и его содержимое (действующее как общий предок):

Line 1
Line 2
Line 3
Line 4
Line 5

Например, если F — это коммит, который нужно выбрать, и его содержимое:

Line 1
Line 2
Line Three
Line 4
Line 5

И цель вишневого выбора Z:

LINE 1
Line 2
Line 3
Line 4
Line 5!

Затем результаты трехстороннего слияния (с аннотациями о том, откуда взялась каждая строка):

LINE 1
Line 2
Line Three
Line 4
Line 5!

возвращаться

Верно ли, что D' = G - D?

Да грубо говоря. Изменения, которые были уникальными для D, были удалены из G. Как и git-cherry-pick, git-revert реализовано с использованием трехстороннего слияния, хотя на этот раз фиксация для возврата рассматривается как общий предок, одна сторона — текущая фиксация, а другая — родительская фиксация для возврата.

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

Если содержимое D, коммит для возврата действует как общий предок, и его содержимое:

Line 1
Line 2
Line THREE
Line 4
Line FIVE

И содержимое C (родителя D):

Line 1
Line 2
Line 3
Line 4
Line 5

И содержимое G было изменено дальше, и его содержимое таково:

Line One
Line 2
Line THREE
Line 4
Line FIVE

Тогда результаты трехстороннего слияния будут такими:

Line One
Line 2
Line 3
Line 4
Line 5

Это результат использования уникальных строк в родительском C и целевом G.

Объединить коммиты

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

Конфликты

Конечно, любой из этих механизмов может вызывать конфликты. Например, если текущий конфликт был дальше изменен, вам придется разрешать конфликты. Например, если в примере с откатом (выше) последующая фиксация также изменила строку 5, то G на самом деле была такой:

Line One
Line 2
Line THREE
Line 4
LINE FIVE!

Тогда был бы конфликт. Рабочий каталог (объединенный файл) будет:

Line One
Line 2
Line 3
Line 4
<<<<<<<
LINE FIVE!
=======
Line 5
>>>>>>>

И вам нужно будет решить, хотите ли вы исходное изменение (Line 5) или новейшее изменение (LINE FIVE!).

person Edward Thomson    schedule 03.01.2016
comment
Здесь также стоит добавить, что вы не можете выбрать или отменить фиксацию слияния, если вы не укажете git, какой из нескольких родительских коммитов использовать в качестве (предполагаемого единственного) узла-предшественника. При выборе E или возврате D вам не нужно этого делать, поскольку у них уже есть только один предшествующий узел. - person torek; 03.01.2016
comment
@torek Очень даже так. Я надеялся, что смогу скрыть это различие. :) Я обновил свой ответ, чтобы попытаться прояснить это. - person Edward Thomson; 03.01.2016
comment
Это действительно потрясающий ответ! - person Samuel; 14.08.2017
comment
Но что, если строка 6 была добавлена ​​в фиксацию D. Будет ли это отменено, поскольку фиксация G также унаследовала бы эту строку, а строка 6 не является какой-то идентичной строкой, которая будет найдена в фиксации C? То же самое происходит и при выборе вишни Commit F, если какая-то строка 6 была добавлена ​​в Common Ancestor E. - person Ruraloville; 20.08.2019

Это очень просто понять так:

cherry-pick

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


revert

Отмените любую фиксацию. он «отменит» любые изменения, сделанные в фиксации, отменив их, если вы знаете, что такое патч, чтобы вы могли видеть, что он меняет знак в патче - becommig + и наоборот. ваши изменения «отменяются», и изменения отменяются.

Команда git revert отменяет зафиксированный моментальный снимок.

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

Это prevents Git from losing history, которое важно для целостности вашей истории изменений и для надежного сотрудничества.


Верно ли, что F' = (F-B) + Z?

Это просто означает, что теперь в нижней ветке у вас также есть патч, созданный в коммите F, ваша нижняя ветка содержит его изменения + изменения, которые были сделаны в коммите F (и только их, никаких других коммитов рядом с Ф)


Верно ли, что D' = G – D?

Не совсем - это означает, что теперь у вас есть коммит D, и после нескольких коммитов у вас есть отмена этого коммита, в репозитории у вас все еще есть 2 коммита, но код не изменится (изменить + отменить на 2 отдельных коммитах)

person CodeWizard    schedule 03.01.2016
comment
Спасибо. Мне до сих пор не ясно, из чего состоят F' и D' и как они создаются из существующих коммитов. (1) В операции выбора вишни являются общими предками F и Z, например. Б, участвует? (2) Как участвует G в обратном режиме? - person Tim; 03.01.2016
comment
Решение вашего 2 Q: D' - это отмена D, что означает, что любое изменение, которое было сделано в D, теперь отменено в D' - у вас есть 2 коммита. один является исходным, а второй - отменой этой фиксации. ваш код вернулся в свое состояние перед фиксацией D, но у вас есть 2 коммита. D = изменения D' = отменить изменения. имеет смысл для вас сейчас? - person CodeWizard; 03.01.2016
comment
В обратной операции, как участвует G? G не развивается, это последний коммит с рисунка 10-8, D' просто фиксируется после него (рисунок 10-9) - person CodeWizard; 03.01.2016
comment
Спасибо. Но все же нет. - person Tim; 03.01.2016
comment
Что еще вы не понимаете? - person CodeWizard; 03.01.2016
comment
(возврат) Посмотрите на это так: вы что-то зафиксировали в своем репозитории, и после того, как X зафиксирует вас раньше, вы сожалеете и хотите удалить эту фиксацию. вы просто используете git revert <SHA-1>, а git отменяет все изменения, сделанные в этом коммите. имеет больше смысла? - person CodeWizard; 03.01.2016
comment
Команда git revert отменяет зафиксированный моментальный снимок. Но вместо того, чтобы удалить фиксацию из истории проекта, он выясняет, как отменить изменения, внесенные фиксацией, и добавляет новую фиксацию с полученным содержимым. Это предотвращает потерю Git истории, что важно для целостности вашей истории изменений и для надежного сотрудничества. - person CodeWizard; 03.01.2016

С Git 2.29 (4 квартал 2020 г.) исправлена ​​аналогичная ситуация.

См. коммит 087c616, коммит 409f066, (20 сентября 2020 г.), автор Брайан М. carlson (bk2204).
(Объединено Junio ​​C Hamano -- gitster --< /a> в commit c5a8f1e, 29 сентября 2020 г.)

docs: объясните, почему возвраты не всегда применяются при слиянии

Подписано: Брайан М. Карлсон

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

У нас уже есть документация о том, как это работает, в git merge. (man), но это видно по частоте с чем это спрошено, что трудно понять.
Мы также не объясняем пользователям, что им лучше сделать в этом случае rebase, который сделает то, что они задумали.
Добавим запись в FAQ, сообщая пользователям, что происходит, и советуя им использовать rebase здесь.

gitfaq теперь включает в свою справочную страницу:

Если я внесу изменения в две ветки, но верну их в одну, почему слияние этих веток включает изменение?

По умолчанию, когда Git выполняет слияние, он использует стратегию, называемую рекурсивной стратегией, которая выполняет причудливое трехстороннее слияние.
В таком случае, когда Git выполняет слияние, он учитывает ровно три момента: два головки и третья точка, называемая базой слияния, которая обычно является общим предком этих коммитов.
Git вообще не учитывает историю или отдельные коммиты, которые произошли в этих ветвях. .

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

Если это проблема для вас, вы можете вместо этого выполнить перебазирование, перебазировав ветку с возвратом на другую ветку.
Перебазирование в этом сценарии отменит изменение, потому что перебазирование применяется к каждому отдельному коммиту, включая revert.
Обратите внимание, что перебазирование переписывает историю, поэтому вам следует избегать перебазирования опубликованных веток, если вы не уверены, что вам это удобно.
См. раздел NOTES в git rebase для более подробной информации.

person VonC    schedule 01.10.2020