Разрешение конфликтов не приводит к изменениям - PullRequest
0 голосов
/ 28 января 2020

Допустим, у меня есть ветвь master и ветвь feature-a. feature-a готов к рассмотрению, но все заняты. Мне нужно запустить feature-b, но feature-b зависит от кода, сделанного в feature-a.

Так что до сих пор я разветвлялся feature-b с feature-a, а затем объединял любые изменения это может произойти с feature-a.

Теперь предположим, что кто-то освобождается и передает feature-a, поэтому feature-a объединяется с master.

Теперь пришло время синхронизировать c feature-b с master. Независимо от того, перебрасываю ли я или объединяю master до feature-b, часто я сталкиваюсь с конфликтами, которые при разрешении не приводят к изменениям в фиксации, что означает, что я не могу зафиксировать.

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

  1. Слияние мастера с функцией b, вызывающее конфликты слияния.
  2. Внесение другого изменения в середине разрешения (например, комментарий или что-то еще)
  3. Разрешить конфликты (приводящие только к одному изменению, комментарий)
  4. Фиксация

Это кажется мне помешавшим: think_face:

Делает Кто-нибудь знает лучший способ разрешения конфликтов / управления моими филиалами в описанной выше ситуации?

1 Ответ

0 голосов
/ 28 января 2020

Нарисуйте коммиты у вас есть. На самом деле, буквально, нарисуйте график коммитов, на бумаге или на доске или что-то еще (или пусть git log --decorate --oneline --graph нарисует его для вас, но вы получите больше от этого, если вы сделаете это вручную). В конечном итоге вы получите нечто, похожее на это:

...--o--o--*   <-- master
            \
             A--B--C--D   <-- feature-a
                       \
                        E--F--G   <-- feature-b

до того, как кто-то еще освободится и слит feature-a. (Буквы обозначают необработанные идентификаторы ha sh.) Затем кто-то еще освобождается и сливается feature-a. Итак, draw that:

...--o--o--*------------M   <-- master
            \          /
             A--B--C--D   <-- feature-a
                       \
                        E--F--G   <-- feature-b

Если они произвели слияние каким-либо другим способом или если другие коммиты были объединены первыми, нарисуйте that . Нарисуйте фактический график! Это важно, потому что именно так работает Git.

Теперь рассмотрим, что вы хотели бы , чтобы получить в качестве окончательного результата слияния. Вы бы предпочли:

...--o--o--*------------M---------M2   <-- master
            \          /         /
             A--B--C--D         /
                       \       /
                        E--F--G

или:

...--o--o--*------------M---------M2   <-- master
            \          / \       /
             A--B--C--D   E'-F'-G'   <--- feature-b
                       \
                        E--F--G   [abandoned, do not use]

или что-то еще целиком?

Звучит так, будто вы выберете второй вариант, который наиболее легко получить с помощью git rebase: перебазировать копий коммитов. Нам нужно скопировать E в новый коммит E', который похож на E, но идет после M (использует M в качестве предшественника и по сравнению с M, делает те же самые изменения как E по сравнению с D). Затем нам нужно скопировать F в F' и G в G'.

Если вы просто запускаете git rebase master, Git иногда 1 выбирает слишком много совершает копирование. В частности, он может - не в примере, который я нарисовал здесь, а в других случаях - решить, что он должен сначала скопировать A, B, C и D.

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

Команда git rebase имеет ответ на этот вопрос: в середине перебазирования после разрешения этих конфликтов вы запускаете git rebase --skip. Но зачастую проще выполнить перебазирование таким образом, чтобы Git «предварительно пропустил» четыре коммита, которые вы не хотите скопировать. Для этого вы можете использовать, например, git rebase --onto:

git rebase --onto master feature-a

, предполагая, что ваше имя feature-a по-прежнему выбирает commit D. (Помните, что имена ветвей перемещаются с течением времени, в то время как коммиты сами, как определено их идентификаторами ha sh, никогда не меняются.)

--onto сообщает rebase, куда помещать копии : после M. Часть feature-a сообщает Git, что не копировать: фиксация, идентифицируемая feature-a, и любые более ранние фиксации, достижимые, начиная с этой фиксации и работая в обратном направлении через граф. (Копируемые коммиты - это всегда те, которые заканчиваются там, где сейчас находится HEAD, а имя ветки должно быть перемещено в конце процесса, чтобы отказаться от старых коммитов в пользу новой и улучшенной цепочки. , это ветка name , в которой вы сейчас находитесь.)

Рисование графика - ключ ко многим операциям Git.


1 Это зависит как от графика , так и от результатов выполнения git patch-id для каждого коммита. На приведенном здесь графике, на котором feature-a буквально объединены как есть, Git будет знать, что не следует копировать A-B-C-D, поскольку эти коммиты, с какими бы ни были их необработанные идентификаторы ha sh, достижимы из имя master, работающее по второму родителю коммита слияния M. Так что это не правильный график.

...