Git: как обновить ветку, созданную слиянием

mpasko256 спросил: 28 апреля 2018 в 09:43 в: git

Предположим, что у меня есть 2 ветви: v1.0 и development. Наш процесс состоит в создании локальной ветви с использованием:

git merge-base v1.0 development
git checkout <commit-hash>
git checkout -b <new-branch-name>

Предположим, что один из моих коллег следит за тем же процессом и недавно внес изменения:

git checkout v1.0
git merge <his-local-branch-name>
git push
git checkout development
git merge <his-local-branch-name>
git push

Мой вопрос в том, как я могу легко обновить локальную ветвь с его недавними изменениями?

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

Но существует ли это какой-то простой способ? Я думал о чем-то вроде git merge <last-commit-hash>, но он генерирует много конфликтов.

1 ответ

Есть решение
Mark Adelsberger ответил: 28 апреля 2018 в 11:56

Хорошо ... так звучит, что development - долгоживущая ветвь, представляющая предыдущую версию (ы) - очень похож на master в gitflow.

И похоже, что v1.0 - долгоживущая ветвь, в которой вы собираете следующую версию, подобно develop в gitflow.

И заданный локальный ветвь может быть как ветвь функции (в этом случае вы объедините ее в v1.0) или как исправление (в этом случае вы объедините его как с v1.0, так и с кодом development). Странно, что вы всегда создаете локальные ветви, чтобы они могли сливаться с обоими. (Значит, вы не знаете, на время создания филиала, будет ли вы сливаться с development? Потому что, если это не так, то каждая ветка "начнется" на базе слияния, похоже, имеет некоторые ненужные затраты на разрешение слияния ... Но я отвлекся.)

Давайте рассмотрим ваш сценарий с картинками. Вы начинаете с

A -- x <--(development)
 \
  Z <--(v1.0)

и создаете локальную ветвь

A -- x <--(development)
|\
| Z <--(v1.0)
 \
  B -- C <--(feature)

, и ваш коллега создает локальную ветвь

A -- x <--(development)
|\
| x -- O <--(hotfix)
|\
| Z <--(v1.0)
 \
  B -- C <--(feature)

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

Итак, ваш коллега сливается с обеими длинными ветвями.

A -- x -- M <--(development)
|\       /
| x --- O <--(hotfix)
|\       \
| Z ----- M <--(v1.0)
 \
  B -- C <--(feature)

Обратите внимание, что с этой точки вперед O является базой слияния для development и v1.0. Но ваш филиал был создан, когда база слияния была A, поэтому теперь мы дошли до вашего вопроса: как получить hotfix в вашу ветку.

К настоящему времени hotfix является неотъемлемой частью общей истории, поэтому вы, вероятно, не хотите делать что-либо, что перезаписывает и / или дублирует изменения от своих коммитов.

Вероятно, вы не хотите merge v1.0 в ваш филиал, потому что перемещение Z в вашу ветку будет работать против зерна, создавшего ветвь в базе слияния.

Итак, вы на самом деле просто хочу объединить O в вашу ветку. Теперь давайте немного переключим передачи и посмотрим, как будет выглядеть ваше местное репо, если я беру ваш термин "локальные ветви" буквально (это означает, что у вас нет ветви hotfix):

A -- x -- M <--(development)
|\       /
| x --- O
|\       \
| Z ----- M <--(v1.0)
 \
  B -- C <--(feature)

Теперь, учитывая, что feature является также локальным (только присутствующим в вашем репо), один из вариантов - переустановить его на новую базу слияния - и это похоже на то, что оно остается в духе вашего рабочего процесса.

git rebase $(git merge-base development v1.0) feature

предоставит вам

A -- x -- M <--(development)
|\       /
| x --- O -- B' -- C' <--(feature)
 \       \
  Z ----- M <--(v1.0)

В этот момент B' и C' являются непроверенными состояниями кода. В идеале вы должны проверить их оба и устранить любые проблемы (хотя, если есть проблемы в B', это проще сказать, чем сделать), так что вы все равно будете иметь чистую историю.

Другой вариант, который позволит избежать проблемы "непроверенных коммитов", но создать "беспорядочную" (хотя и более точную) историю, состоит в том, чтобы просто объединить базу слияния в вашу ветку.

git checkout feature
git merge $(git merge-base v1.0 development)

Что дает вам что-то вроде

A -- x -- M <--(development)
|\       /
| x --- O -----------
|\       \           \
| Z ----- M <--(v1.0) \
 \                     \
  B -- C -------------- M <--(feature)

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

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