(Schwern’s answer points out the issue with have 2 different locals…this answer is in addition to that answer NOT a substitute for that answer).
……….
For future readers:
Take a look at this other SOF answer:
Merge development branch with master
From that answer : it looks like it has to do with whether you «pull» the second branch. Notice there are 2 pulls in the answer above.
By doing a pull (and thus («kinda») getting local copies of each branch)…by doing a pull on both branches, you avoid the «not something we can merge» «did you mean this?» error messages.
The «kinda» part is that you don’t have distinct copies of each branch, you are using git to perform a switch-the-current-branch in the same local directory.
….
Now I am going to post here the code that I am using, but that I reasoned from the answer I include with my answer. In the below my goal is to merge develop into master.
REM below shows the branches
git branch -a
REM below shows the branch are you on
git branch
REM below does a checkout on develop
git checkout develop
REM below, now pull the "develop" branch so that it is local
git pull
REM below does a checkout on master
git checkout master
REM below, now pull the "master" branch so that it is local
git pull
REM below shows the branch are you on, a redundant check just to make sure you're on master
git branch
REM now you should be on the master branch, and the below is going to merge develop into (the branch you are already on), aka master
git merge develop
REM git push origin master
REM the below makes it REAL on the remote server
git push -u origin master
You have encountered a merge conflict. It means that Git cannot automatically determine how to merge the two branches. Git is asking you to do the merge manually, and gives you some help along the way by telling you what files it cannot automatically merge, and what changes specifically in these files that it has trouble with.
Run git status
. It will output a list of what files are unmerged. These files will contain conflict markers that look similar to this:
foo
<<<<<<< HEAD
BAR
=======
bar baz
>>>>>>> foo
qux
This means that HEAD
(or, the commit or branch you are currently on) has changed a line to BAR
, and the branch foo
has changed the same line to bar baz
.
Edit each of these conflicts to your liking, making sure that you have no more conflict markers left. For example, if you preferred the BAR
version in the above example, you would simply edit the file so that it looked like:
foo
BAR
qux
Save each file and add it as you go.
# (edit <file>)
git add <file>
There are tools available that do the file editing part for you, some find them easier to use than to edit the files manually.
When you are done, run git status
to make sure that you have no more unmerged files. Then, run git commit
to finish the merge if you are happy with the result.
Git — Basic Branching and Merging provides some more information about merge conflicts.
A different and often* saner way to go about this is to first rebase the other branch (in this case sidebar
) on top of the branch you are merging it into (in this case master
):
git checkout sidebar
git rebase master
You will likely still have conflicts, but fixing them here is sometimes easier. The procedure is the same as described above, edit the files, add them, commit. When done, run git rebase --continue
to continue the rebase procedure.
Then, finally you can merge the branch with no conflicts:
git checkout master
git merge --no-ff sidebar
The --no-ff
is optional; with it you will get a merge commit to denote that you merged a branch, without it your history will be linear with no merge commit.
A benefit of rebasing before merging is that there will never be merge conflicts in the actual merge, meaning that the merge commit never introduces a change other than what is already introduced by the commits in the branch being merged. This makes the history easier to understand.
A downside to rebasing is that commits are applied on top of a new state of the code. This has the implication that you need to check each commit to see that it still does the right thing. It is a good idea to spend a little time doing this in order to avoid future surprises.
*
Avoid or at least use caution when rebasing branches that have merges. Rebase eats merges. It is also a good idea to avoid rebasing another person’s commits. The author of a change is usually the person who knows best how to properly resolve any merge conflicts caused, so if possible, conflict resolution is best delegated.
(Schwern’s answer points out the issue with have 2 different locals…this answer is in addition to that answer NOT a substitute for that answer).
……….
For future readers:
Take a look at this other SOF answer:
Merge development branch with master
From that answer : it looks like it has to do with whether you «pull» the second branch. Notice there are 2 pulls in the answer above.
By doing a pull (and thus («kinda») getting local copies of each branch)…by doing a pull on both branches, you avoid the «not something we can merge» «did you mean this?» error messages.
The «kinda» part is that you don’t have distinct copies of each branch, you are using git to perform a switch-the-current-branch in the same local directory.
….
Now I am going to post here the code that I am using, but that I reasoned from the answer I include with my answer. In the below my goal is to merge develop into master.
REM below shows the branches
git branch -a
REM below shows the branch are you on
git branch
REM below does a checkout on develop
git checkout develop
REM below, now pull the "develop" branch so that it is local
git pull
REM below does a checkout on master
git checkout master
REM below, now pull the "master" branch so that it is local
git pull
REM below shows the branch are you on, a redundant check just to make sure you're on master
git branch
REM now you should be on the master branch, and the below is going to merge develop into (the branch you are already on), aka master
git merge develop
REM git push origin master
REM the below makes it REAL on the remote server
git push -u origin master
Системы контроля версий предназначены для управления дополнениями, вносимыми в проект множеством распределенных авторов (обычно разработчиков). Иногда один и тот же контент могут редактировать сразу несколько разработчиков. Если разработчик A попытается изменить код, который редактирует разработчик B, может произойти конфликт. Для предотвращения конфликтов разработчики работают в отдельных изолированных ветках. Основная задача команды git merge
заключается в слиянии отдельных веток и разрешении любых конфликтующих правок.
Общие сведения о конфликтах слияния
Слияние и конфликты являются неотъемлемой частью работы с Git. В других инструментах управления версиями, например SVN, работа с конфликтами может быть дорогой и времязатратной. Git позволяет выполнять слияния очень просто. В большинстве случаев Git самостоятельно решает, как автоматически интегрировать новые изменения.
Обычно конфликты возникают, когда два человека изменяют одни и те же строки в файле или один разработчик удаляет файл, который в это время изменяет другой разработчик. В таких случаях Git не может автоматически определить, какое изменение является правильным. Конфликты затрагивают только того разработчика, который выполняет слияние, остальная часть команды о конфликте не знает. Git помечает файл как конфликтующий и останавливает процесс слияния. В этом случае ответственность за разрешение конфликта несут разработчики.
Типы конфликтов слияния
Конфликт во время слияния может произойти в двух отдельных точках — при запуске и во время процесса слияния. Далее рассмотрим, как разрешать каждый из этих конфликтных сценариев.
Git прерывает работу в самом начале слияния
Выполнение команды слияния прерывается в самом начале, если Git обнаруживает изменения в рабочем каталоге или разделе проиндексированных файлов текущего проекта. Git не может выполнить слияние, поскольку иначе эти ожидающие изменения будут перезаписаны новыми коммитами. Такое случается из-за конфликтов не с другими разработчиками, а с ожидающими локальными изменениями. Локальное состояние необходимо стабилизировать с помощью команд git stash
, git checkout
, git commit
или git reset
. Если команда слияния прерывается в самом начале, выдается следующее сообщение об ошибке:
error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)
Git прерывает работу во время слияния
Сбой В ПРОЦЕССЕ слияния говорит о наличии конфликта между текущей локальной веткой и веткой, с которой выполняется слияние. Это свидетельствует о конфликте с кодом другого разработчика. Git сделает все возможное, чтобы объединить файлы, но оставит конфликтующие участки, чтобы вы разрешили их вручную. При сбое во время выполнения слияния выдается следующее сообщение об ошибке:
error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)
Создание конфликта слияния
Чтобы лучше разобраться в конфликтах слияния, в следующем разделе мы смоделируем конфликт для дальнейшего изучения и разрешения. Для запуска моделируемого примера будет использоваться интерфейс Git c Unix-подобной командной строкой.
$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "this is some content to mess with" > merge.txt
$ git add merge.txt
$ git commit -am"we are commiting the inital content"
[main (root-commit) d48e74c] we are commiting the inital content
1 file changed, 1 insertion(+)
create mode 100644 merge.txt
С помощью приведенной в этом примере последовательности команд выполняются следующие действия.
- Создается новый каталог с именем
git-merge-test
, выполняется переход в этот каталог и инициализация его как нового репозитория Git. - Создается новый текстовый файл
merge.txt
с некоторым содержимым. - В репозиторий добавляется файл
merge.txt
и выполняется коммит.
Теперь у нас есть новый репозиторий с одной веткой main
и непустым файлом merge.txt
. Далее создадим новую ветку, которая будет использоваться как конфликтующая при слиянии.
$ git checkout -b new_branch_to_merge_later
$ echo "totally different content to merge later" > merge.txt
$ git commit -am"edited the content of merge.txt to cause a conflict"
[new_branch_to_merge_later 6282319] edited the content of merge.txt to cause a conflict
1 file changed, 1 insertion(+), 1 deletion(-)
Представленная выше последовательность команд выполняет следующие действия.
- Создает новую ветку с именем
new_branch_to_merge_later
и выполняет переход в нее. - Перезаписывает содержимое файла
merge.txt
. - Выполняет коммит нового содержимого.
В этой новой ветке new_branch_to_merge_later
мы создали коммит, который переопределил содержимое файла merge.txt
.
git checkout main
Switched to branch 'main'
echo "content to append" >> merge.txt
git commit -am"appended content to merge.txt"
[main 24fbe3c] appended content to merge.tx
1 file changed, 1 insertion(+)
Эта последовательность команд выполняет переключение на ветку main
, добавляет содержимое в файл merge.txt
и делает коммит. После этого в нашем экспериментальном репозитории находятся два новых коммита, первый — в ветке main
, а второй — в ветке new_branch_to_merge_later
. Теперь запустим команду git merge new_branch_to_merge_later
и посмотрим, что из этого выйдет!
$ git merge new_branch_to_merge_later
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.
БАХ! 💥 Возник конфликт. Хорошо, что система Git сообщила нам об этом.
Выявление конфликтов слияния
Как мы убедились на выполняемом примере, Git выводит небольшое описательное сообщение о возникновении КОНФЛИКТА. Чтобы получить более глубокое понимание проблемы, можно запустить команду git status
.
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: merge.txt
Вывод команды git status
говорит о том, что из-за конфликта не удалось слить пути. Теперь файл merge.text
отображается как измененный. Давайте изучим этот файл и посмотрим, что изменилось.
$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later
Для просмотра содержимого файла merge.txt
воспользуемся командой cat
. Видно, что в файле появились новые странные дополнения:
<<<<<<< HEAD
=======
>>>>>>> new_branch_to_merge_later
Эти новые строки можно рассматривать как «разделители конфликта». Строка =======
является «центром» конфликта. Все содержимое между этим центром и строкой <<<<<<< HEAD
находится в текущей ветке main, на которую ссылается указатель HEAD
. А все содержимое между центром и строкой >>>>>>> new_branch_to_merge_later
является содержимым ветки для слияния.
Разрешение конфликтов слияния с помощью командной строки
Самый простой способ разрешить конфликт — отредактировать конфликтующий файл. Откройте файл merge.txt
в привычном редакторе. В нашем примере просто удалим все разделители конфликта. Измененное содержимое файла merge.txt
будет выглядеть следующим образом:
this is some content to mess with
content to append
totally different content to merge later
После редактирования файла выполните команду git add merge.txt
, чтобы добавить новое объединенное содержимое в раздел проиндексированных файлов. Для завершения слияния создайте новый коммит, выполнив следующую команду:
git commit -m "merged and resolved the conflict in merge.txt"
Git обнаружит, что конфликт разрешен, и создаст новый коммит слияния для завершения процедуры слияния.
Команды Git, с помощью которых можно разрешить конфликты слияния
Общие инструменты
Команда status часто используется во время работы с Git и помогает идентифицировать конфликтующие во время слияния файлы.
При передаче аргумента --merge
для команды git log
будет создан журнал со списком конфликтов коммитов между ветками, для которых выполняется слияние.
Команда diff
помогает найти различия между состояниями репозитория/файлов. Она полезна для выявления и предупреждения конфликтов слияния.
Инструменты для случаев, когда Git прерывает работу в самом начале слияния
Команда checkout
может использоваться для отмены изменений в файлах или для изменения веток.
Команда reset
может использоваться для отмены изменений в рабочем каталоге или в разделе проиндексированных файлов.
Инструменты для случаев, когда конфликты Git возникают во время слияния
При выполнении команды git merge
с опцией --abort
процесс слияния будет прерван, а ветка вернется к состоянию, в котором она находилась до начала слияния.
Команду git reset
можно использовать для разрешения конфликтов, возникающих во время выполнения слияния, чтобы восстановить заведомо удовлетворительное состояние конфликтующих файлов.
Резюме
Конфликты слияния могут пугать. К счастью, Git предлагает мощные инструменты их поиска и разрешения. Большую часть слияний система Git способна обрабатывать самостоятельно с помощью функций автоматического слияния. Конфликт возникает, когда в двух ветках была изменена одна и та же строка в файле или когда некий файл удален в одной ветке и отредактирован в другой. Как правило, конфликты возникают при работе в команде.
Существует множество способов разрешения конфликтов слияния. В этой статье мы рассмотрели немалое количество инструментов командной строки, которые предоставляет Git. Более подробную информацию об этих инструментах см. на отдельных страницах для команд git log
, git reset
, git status
, git checkout
и git reset
. Помимо этого многие сторонние инструменты также предлагают оптимизированные функции, поддерживающие работу с конфликтами слияния.
Время на прочтение
8 мин
Количество просмотров 152K
Предлагаю читателям «Хабрахабра» перевод публикации «Painless Merge Conflict Resolution in Git»
из блога blog.wuwon.id.au.
В моей повседневной работе, часто приходится иметь дело со множеством git ветвей (branch). Это могут быть ветви промежуточных релизов, ветви с устаревшим API находящиеся на поддержке для некоторых клиентов, или ветви с экспериментальными свойствами. Лёгкость создания ветвей в модели Git так и соблазняет разработчиков создавать все больше и больше ветвей, и как правило бремя от большого количества ветвей становится очень ощутимым, когда приходится все эти ветви поддерживать и периодически делать слияния (merge) с другими ветвями.
Слияния очень важны для поддержания кода в актуальном состоянии, и как правило ошибка сделанная при слиянии может привести к большей головной боли, нежели ошибка сделанная при простом коммите. К сожалению ошибки слияния далеко не редкость, потому что во-первых слияния имеют несколько родительских ветвей. Даже при анализе истории слияния ветвей, бывает очень трудно понять, какие же изменения были сделаны для разрешения конфликта. Во-вторых, отмена неудачного слияния может превратиться в большую головную боль. В-третьих, большая часть конфликтов слияния происходит при работе с чужим кодом, потому что само понятие ветвей подразумевает множество пользователей, т.е. далеко не всегда слияние производит тот же человек который работал с той или иной веткой. В сухом остатке, сделать ошибку при слиянии очень легко, её трудно исправить и трудно найти. Таким образом время потраченное на изучение и понимание процесса слияния ветвей, окупится с лихвой.
Удивительно, но я обнаружил, что многие доступные инструменты и интерфейсы предназначенные для выполнения слияний, не достаточно хорошо оснащены для эффективного выполнения этого процесса. Часто программист просто надеется что команда git merge сделает за него всю работу. Но когда все-таки происходит конфликт, то обычно стратегия слияния заключается в беглом просмотре кода вокруг строки конфликта, и интуитивном угадывании что именно данный кусок кода предпочтительней другого.
В данной статье я надеюсь продемонстрировать что процесс разрешения конфликтов может быть пошагово точным, при котором отпадает необходимость что-либо там угадывать.
Голубые Розы (Roses are Blue)
Давайте предположим что вашей команде поручили писать поэмы в отведённом для этих целей репозитории. (Какой кошмар!) А вам доверили самое главное — делать слияния последних фиксов из ветки master в ветку beta. Итак, вы переключаетесь в ветку beta и выполняете следующую команду:
$ git merge master
Auto-merging roses.txt
CONFLICT (content): Merge conflict in roses.txt
Automatic merge failed; fix conflicts and then commit the result.
Ого, это конфликт. Вы решаете просмотреть файл на который ссылается git:
$ cat roses.txt
<<<<<<< HEAD
roses are #ff0000
violets are #0000ff
all my base
are belong to you
=======
Roses are red,
Violets are blue,
All of my base
Are belong to you.
>>>>>>> master
(Listing 1)
Замечательно! Весь файл, как показывает Listing 1, находится в конфликтном состоянии. Какой же вариант файла является более корректным? Оба варианта выглядят корректно. Верхний вариант написан в хакер-стиле с элементами цветовой кодировки в стиле HTML и с использованием только строчных букв. Нижний вариант выглядит более натурально, с использованием пунктуации и заглавных букв.
Если бы это был ваш проект, вы бы могли просто выбрать один вариант и покончить с этим слиянием. Но проблема в том, что это не ваша поэма, вы никогда не читали эту поэму раньше, не были ответственны за написание или редактирование, и вы отлично понимаете что в случае не верного решения чья-то тяжёлая работа может кануть в небытие. Однако вас всё же назначили ответственным по слиянию этих веток. Что же вам делать?
Назад к Базе (Back to Base)
Хитрость заключается в том, что Listing 1 не даёт вам полную информацию, необходимую для совершения корректного слияния. На самом деле, в процессе слияния участвуют четыре важных части информации (состояния), три из которых просто необходимы для успешного разрешения конфликта. В случае Listing 1, Git предоставил вам только два состояния.
Следующая диаграмма иллюстрирует эти четыре состояния:
Состояния (B) и © относятся к текущим положениям (head) веток master и beta соответственно, эти два состояния как раз таки и отражены в Listing 1. Состояние (D) это результат слияния, то что вы хотите получить/сгенерировать в конечном итоге (в большинстве случаев Git автоматически генерирует состояние (D)). Состояние (А) на самом верху, представляет собой базу (основу) слияния веток master и beta. База слияния (A) это последний общий предок веток master и beta, и пока предположим что это база слияния уникальна. Как мы увидим позже состояние (A) играет ключевую роль в разрешении конфликтов. На диаграмме я также отразил дельты 1 и 2, которые представляют изменения между состояниями (A)-(B), и (A)-© соответственно. Зная состояния (A), (B) и © дельты 1 и 2 могут быть легко получены (вычислены). Обратите внимание, что дельты 1 и 2 могут состоять из более чем одного коммита. Но для наших целей будем считать что все дельты монолитны.
Чтобы понять, как получить состояние (D), вы должны понимать что же операция слияния пытается сделать. Состояние (D) должно представлять собой сочетание изменений, внесённых в ветку master и beta соответственно. Т.е. другими словами сочетание дельт 1 и 2. Идея проста на поверхности и большую часть времени не требует вмешательства со стороны человека, за исключением особых случаев когда дельты затрагивают наслаиваемые (пересекающиеся) части файла. В такой ситуации вам требуется помочь машине сгенерировать результат (D), путём сравнения дельт 1 и 2.
Определение Отличий (Identifying the Differences)
Для того чтобы найти изменения внесённые в каждую ветку, необходимо знать как выглядит база слияния, состояние (A). Самый простой механизм получения информации о базе слияния, это установка опции merge.conflictstyle в значение diff3
$ git config merge.conflictstyle diff3
После включения этой опции, попробуйте заново сделать слияние (git reset —hard; git merge master) и проинспектируйте конфликтующий файл ещё раз:
$ cat roses.txt
<<<<<<< HEAD
roses are #ff0000
violets are #0000ff
all my base
are belong to you
|||||||
roses are red
violets are blue
all my base
are belong to you
=======
Roses are red,
Violets are blue,
All of my base
Are belong to you.
>>>>>>> master
(Listing 2)
Теперь мы видим третий фрагмент посередине, который и является базой слияния или состояние (A). Изменения видны как на ладони: в ветке beta (HEAD) человеческие названия цветов были заменены на HTML коды, а в ветку master добавили капитализацию и пунктуацию. Основываясь на этих знаниях, мы теперь знаем что результат должен включать в себя капитализацию, пунктуацию и HTML коды цветов.
В принципе на этом можно было бы и закончить, потому что результат достигнут. Но есть решение и получше.
Графическое Слияние (GUI Merging)
Хотя и простое текстовое представление конфликта слияния делает свою работу в простых случаях, на практике конфликты могут быть более радикальными и сложными. В таких случаях могут помочь графические инструменты. Мой выбор пал на простой инструмент написанный на Python под названием meld, но может подойти любой другой графический инструмент, способный представить слияние в трёх-колоночном виде.
Для использования графического инструмента (он должен быть установлен), после того как git пожаловался что есть конфликт, введите следующую команду:
$ git mergetool
Последует вопрос какой программой для слияния вы хотели бы воспользоваться, просто введите meld и нажмите Enter. Вот как окно программы может выглядеть (подразумевается опция merge.conflictstyle не была включена):
Несмотря на то что информация представлена бок о бок, она не отображает нужные фрагменты которые были в Listing 2. Мы не видим здесь фрагмента базы слияния (состояния (A)), что мы видим это файл roses.txt.LOCAL.2760.txt в левой колонке и файл roses.txt.REMOTE.2760.txt в правой колонке и файл посередине это неудачное слияние. Т.е. по сути нам представили состояния (B), © и несостоявшееся состояние (D), но состояние (A) отсутствует…
Правда отсутствует? Давайте проверим, в старом добром терминале:
$ ls -1
roses.txt
roses.txt.BACKUP.2760.txt
roses.txt.BASE.2760.txt
roses.txt.LOCAL.2760.txt
roses.txt.REMOTE.2760.txt
Видим интересующий нас файл: roses.txt.BASE.2760.txt. Это и есть файл базы слияния. Теперь нам осталось всего лишь найти изменения внесённые в ветки master и beta, по отношению к базе. Мы можем сделать это двумя отдельными вызовами meld:
$ meld roses.txt.LOCAL.2760.txt roses.txt.BASE.2760 &
$ meld roses.txt.BASE.2760 roses.txt.REMOTE.2760.txt &
(Кто-то может подметить что было бы более разумно, поменять порядок аргументов в первом вызове, для того чтобы файл базы находился в левой колонке в обоих случаях, но именно такой порядок сохраняет подобие трёх-колоночного вида, при котором база остаётся по середине.) Результат выполнения — два окна как показано ниже:
При чтении первого окна справа налево и второго окна слева направо, становится ясно как день, какие изменения произошли в каждой ветке. Так как meld любезно подсветил все изменения, теперь практически не возможно пропустить даже мелко заметные правки (Кто-нибудь заметил добавление предлога «of» при просмотре текстового представления разрешения конфликта Listing 1 или даже Listing 2?)
Вооружившись этими знаниями, мы теперь можем вернуться к трёх-колоночному представлению и сделать изменения. Моя стратегия ручного слияния это взять весь текст из ветки с более весомыми изменениями (в данном случае master/REMOTE т.е. beta), и поверх него производить пошаговые правки, т.е. вносить изменения сделанные в другой ветке (master). Вот что получилось:
А теперь всё вместе (All Together Now)
Надеюсь, вы найдёте этот трёх-окошечный метод разрешения конфликтов, таким же полезным каким нахожу его я. Но согласитесь что запускать новые вызовы meld вручную каждый раз при разрешении конфликтов, не очень то и удобно. Выход, это настроить git таким образом чтобы все три окна открывались автоматически при вызове команды git mergetool. Для этого можно создать выполняемый скрипт, который должен находится в переменной окружения PATH (например $HOME/bin/gitmerge), со следующим содержимым:
#!/bin/sh
meld $2 $1 &
sleep 0.5
meld $1 $3 &
sleep 0.5
meld $2 $4 $3
И добавьте следующее в ваш ~/.gitconfig файл:
[merge]
tool = mymeld
[mergetool "mymeld"]
cmd = $HOME/bin/gitmerge $BASE $LOCAL $REMOTE $MERGED
Теперь, когда вы в следующий раз будете запускать команду git mergetool для разрешения конфликта, откроются все три окна:
Окно дифа между BASE и LOCAL
Окно дифа между BASE и REMOTE
Окно трёх-колоночного вида
После того как вы привыкните к такому разрешению конфликтов с использованием трёх вышеупомянутых окон, вы скорее всего обнаружите, что процесс стал более методичным и механическим. В большинстве случаев, вам даже не придётся читать и понимать куски кода из каждой ветки, для того чтобы понять какой же вариант применить для слияния. Вам больше не понадобится догадываться, потому что вы будете гораздо более уверенным в корректности вашего комита. Из-за этой уверенности, появится чувство что разрешение конфликтов превратилось в увлекательное занятие.
Бонус от переводчика
Для тех кто пользуется tmux и n?vim, предлагаю следующий скрипт gitmerge:
#!/bin/sh
sn=gitmerge
tmux new-session -d -s "$sn" -n "diff3" "nvim -d $2 $4 $3"
tmux split-window -t "$sn:1" -v "nvim -d $2 $1"
tmux split-window -t "$sn:1" -h "nvim -d $1 $3"
Примечание: если вы не используете эту опцию в своем ~/.tmux.conf, то вам надо поменять в двух последних строках "$sn:1"
на "$sn:0"
Соответственно добавьте следующее в ваш ~/.gitconfig
[mergetool "gitmerge"]
cmd = $HOME/bin/gitmerge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
[merge]
tool = gitmerge
Воркфлоу разрешения конфликта будет выглядеть так:
Пока игнорируем вопрос (Was the merge successful [y/n]?) и переключаемся в сессию под названием gitmerge (сочетание TMUXPREFIX + s):
Видим наше трёх-оконное представление на одном экране. Цифрами обозначены сплиты (panes) tmux’a, буквами соответствующие состояния. Делаем правки для разрешения конфликта, т.е. редактируем состояние (D) и сохраняем. После этого возвращаемся обратно в исходную сессию tmux’a и подтверждаем что слияние произошло успешно.
git rebase master
Лично я предпочитаю и считаю более правильным делать сначала rebase master в ветке beta, и только после этого переключаться в master и делать git merge beta. В принципе воркфлоу не сильно отличается, за исключением трёх-оконного вида.
Переключаемся в сессию gitmerge
Обратите внимание, что состояния (B) и © поменялись местами:
Рекомендую всем поиграться с примером репозитария хотя бы один раз, сделать разрешение конфликта по вышеописанной схеме. Лично я больше не гадаю а что же выбрать «Accept theirs» или «Accept yours».