Git Merge Conflict: Добавить Изменения, которые будут приняты после разрешения?

Я часто сталкиваюсь со следующей проблемой конфликта слияний и решаю ее, но я хотел бы спросить, правильное ли мое решение. Лично я не вижу никаких проблем, учитывая, что функциональные тесты проходят, но было бы хорошо иметь представление об этом.

Итак, допустим, у нас есть две ветви:

  1. develop
  2. feature

Я меняю код в feature филиал, а затем создать пиар, чтобы слить в develop, Тем не мение, Githubили BitbucketДифференцирующий инструмент предполагает, что у нас есть конфликт слияния; довольно распространенная ситуация в кодировании.

Затем я предпринимаю следующие шаги:

  1. git checkout develop а также git pull origin develop

  2. git checkout feature а потом git pull origin feature

  3. git merge develop, чтобы обновить мою текущую ветку. Эти шаги помогают мне определить файлы, в которых происходят конфликты.
  4. Затем я исправляю конфликты вручную и вижу:

`У тебя есть незавершенные пути.
(исправить конфликты и запустить «git commit»)

Изменения должны быть совершены:

modified:   app/BlablaFile.php
modified:   app/Blabla2File.php
renamed:    app/OldName.php -> app/NewName.php

а потом:

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:   app/UnmergedFile.php

это в основном список файлов, которые я отредактировал для разрешения конфликта слияния.

Вопрос должен я только git add app/UnmergedFile.php а потом git commit -m "Updated app/UnmergedFile.php"? Или я должен git add также файлы, которые включены в Changes to be committed: раздел?

Я обычно делаю первый, но было бы хорошо иметь другую мысль.

0

Решение

TL; DR: вам не нужно повторно добавлять файлы, которые находятся в «изменениях, которые будут зафиксированы».

«Индекс» Гита

У Git есть вещь, называемая по-разному: индекс или плацдарм, или иногда даже кэш (как в git diff --cached). Это не очень хорошо объяснено, отчасти потому, что это сложно. К счастью, использование индекса довольно просто, за исключением (увы) во время слияния. 🙂

Что в индексе лучше всего описано как следующий коммит вы сделаете. Это также помогает помнить, что Git всегда имеет текущий коммит, названный HEADи (кроме как в --bare хранилища), работа дерево или же рабочее дерево, где ваши файлы готовы для просмотра, компиляции, редактирования и всего, что вы делаете со своими файлами.

Первоначально ваше рабочее дерево, индекс и HEAD зафиксировать все совпадения (когда вы впервые клонируете репозиторий). Вы не можете касаться файлов непосредственно в индексе, поэтому вы вносите какие-либо изменения или даже создаете новые файлы в рабочем дереве, где вы выполняете всю свою работу. Затем, чтобы поместить измененный файл обратно в индекс, вы запускаете git add по пути, так что Git копирует измененный файл в индекс. Чтобы поместить новый файл в индекс, вы также запускаете git add на пути.

Если бы вы были по какой-то причине, чтобы все взволнованы и бежать git commit прямо сейчас Git прочитает ваш текущий индекс и упакует его как новый коммит. Новый коммит будет иметь в качестве своего снимка рабочего дерева каждый файл, который сейчас находится в индексе, в состоянии, в котором он сейчас находится, в индексе.

Если это состояние Матчи HEAD совершить, git commit просто говорит: «Ха? Почему ты пытаешься сделать новый коммит сейчас?» По-видимому, к этому моменту вы что-то изменили в индексе. git status покажет вам, что в индексе это отличный от HEAD commit: это «изменения, которые нужно совершить».

сращивание

Бег git merge иногда раскрывает секрет об индексе. Каждая запись в индекс на самом деле имеет четыре игровые автоматы, которые пронумерованы. Обычно вы видите только нулевой слот, который зарезервирован для «обычных» файлов, готовых к фиксации.

Слияние предназначено для скомбинировать два (или иногда больше, но давайте придерживаться двух) наборов изменений. Например, возможно, вы и Боб начали с одних и тех же файлов. Затем вы внесли некоторые изменения в некоторые файлы, и git addи сделал новые снимки источника. Тем временем Боб внес некоторые изменения в некоторые файлы — может быть, те же файлы, даже — и также git addи настало время, и теперь пришло время объединить ваши изменения и изменения Боба.

Чтобы выполнить слияние, чтобы объединить некоторые файлы, Git сначала находит объединить базу, то есть момент, когда вы с Бобом были синхронизированы. Затем Git запускает два git diffs: один из этой базы слияния в ваш последний коммит и один из той же базы слияния в бобПоследний коммит. Это показывает «что ты изменил» и «что изменил Боб».

Git делает все возможное, чтобы скомбинировать эти изменения (включая, как в этом случае, выяснение и последующее переименование файла, и выяснение, что делать, если только один вы переименовали какой-то файл — но большинство конфликтов слияния не включают переименования файлов, если вы не пишете много кода Java …). Иногда, однако, Git не может сделать это самостоятельно. В этом конкретном случае Git возвращает вам работу по слиянию, и в этот момент вы видите все игровые автоматы в указателе.

Слот индекса 1 — это место, где Git хранит база версия файла. Это общая версия, с которой вы оба начали.

Индекс слот 2 является HEAD или же --ours версия файла. (Это также иногда называют «локальной» версией.)

Индексный слот 3 является другим или --theirs (или иногда «удаленная») версия файла.

Это почти все, что нужно сделать: три слота содержат три версии, и в итоге вы получите «неразделенные пути». Файл в вашем рабочем дереве содержит первоначальные усилия Git по слиянию, а также маркеры конфликтов и некоторые сочетания --ours а также --theirs версия. Если вы установите merge.conflictstyle в diff3, Git также будет включать в себя части из база версия файла, хранящаяся в индексном слоте 1. Теперь вы должны решить слияние.

После того, как вы выяснили правильное разрешение и обновили версию файла рабочего дерева, вы должны git add путь. Это сохраняет версию рабочего дерева в нулевом слоте индекса, стирая три записи в слотах 1-3. Поскольку нулевой слот содержит нормальную версию для фиксации, файл теперь готов к фиксации.

Для файлов, где не было никаких изменений, или же только один из вас что-то изменил, или же где Git считает, что правильно совмещал ваши изменения и изменения Боба, те файлы уже обновлены как в рабочем дереве, так и в (нулевой слот) индекса. Если результат отличается от текущего HEAD совершить, git status показывает файл как «изменения, которые должны быть зафиксированы».

Последние биты

Я сказал выше, что это почти все, что нужно сделать Последние несколько вещей, которые следует помнить о слотах индекса:

  • Некоторые слоты могут быть пустыми. Предположим, что вы оба а также Боб добавил файл. В этом случае вы получите «добавить / добавить конфликт». Какая версия файла является общей базовой версией? Там нет, конечно: вы оба добавили новый файл. Таким образом, в этом случае базовый слот — слот 1 — пуст.

    То же самое происходит, если вы удаляете файл, а Боб меняет его. В этом случае --ours Слот, слот 2, пуст, а слоты 1 и 3 содержат базовую версию и версию Боба. Вам решать, сохранить ли версию Боба, удалить файл или использовать третий вариант, но опять-таки заполняются только два из трех слотов.

  • Если один или оба из вас переименовывает файл, версии файлов в трех слотах могут исходить из файлов, которые имели разные имена в предыдущих коммитах. Например, ваш вывод показывает:

        renamed:    app/OldName.php -> app/NewName.php
    

    Здесь не было никакого конфликта, но если бы был, по крайней мере, один из слотов для app/NewName.php будет заполнен из версии какого-то другого коммита app/OldName.php,

    Это в основном имеет значение, когда вы смотрите на старую версию. Если в отдельном клоне или рабочем дереве вы извлекаете один из коммитов, где файл еще не переименован, или если вы используете git show <commit>:app/OldName.php чтобы просмотреть файл без проверки — вы должны использовать старый Имя везде, где оно имеет старое имя. Но если вы используете git checkout --ours или же git checkout --theirs чтобы извлечь только одну из этих двух версий в рабочее дерево, вы должны использовать новый имя, потому что индекс теперь хранит файл под новым именем.

  • если ты делать использование git checkout --ours или же git checkout --theirs чтобы получить вашу версию файла Боба или, соответственно, Боба, это не разрешает файл, но делает попытку Git слить их в рабочее дерево. Если вы хотите восстановить попытку Git объединить их, используйте git checkout -m, Обратите внимание, что все они перезаписывают версию файла рабочего дерева, оставляя только три неразрешенных слота индекса.

  • Странно, однако, если вы git checkout <commit-id> -- <path> получить старую версию файла из какого-то конкретного коммита, который перезаписывает индекс: он копирует версию файла коммита в нулевой слот индекса, забивая записи слота 1-3. Файл теперь выглядит решенным! Опять же, вы можете восстановить неразрешенное состояние с помощью git checkout -m, (Конечно, это переписывает версию дерева работ.)

  • Точно так же, если вы по ошибке решите файл с git add когда это не довольно сделано еще, вы можете git checkout -m чтобы разрешить это — но, конечно, это переписывает версию рабочего дерева. Если вы в основном закончили с разрешением, вы могли бы также закончить разрешение и повторноgit add результат. Это заменяет запись индекса нулевого слота версией, только что скопированной из рабочего дерева: файл остается разрешенным, но версия, готовая для следующей фиксации, изменяется на последнюю git addверсия

2

Другие решения

Я обычно делаю последнее и не сталкивался с этим.

Я думаю, это зависит от того, чего вы собираетесь достичь.

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

0

Файлы, названные в списке «изменения должны быть зафиксированы», уже находятся в промежуточной области (также называемой индексом).
Git add — это то, что вы используете для помещения своей работы в индекс, что говорит git, что вы хотите, чтобы они были включены в коммит.
Таким образом, добавление мерзавцев из уже подготовленных файлов будет излишним.

Дополнительное добавление файлов в список «для передачи» необходимо только в том случае, если файлы перечислены в обоих списках (что иногда происходит, если вы создаете файлы, а затем модифицируете их еще больше).

0
По вопросам рекламы [email protected]