git pull -X их локальный мастер все еще имеет конфликты

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

$ git merge -s recursive -X theirs local/master

CONFLICT (rename/delete): rcS.d/S08kmod deleted in HEAD and renamed in local/master. Version local/master of rcS.d/S08kmod left in tree.
Auto-merging php5/cli/conf.d/20-xdebug.ini
CONFLICT (add/add): Merge conflict in php5/cli/conf.d/20-xdebug.ini
Auto-merging apt/sources.list
CONFLICT (rename/rename): Rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf.conf" in branch "HEAD" rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf" in "local/master"

Используя тягу:

$ git pull local master
From ssh://192.168.1.101/etc
 * branch            master     -> FETCH_HEAD
warning: Cannot merge binary files: console-setup/cached_UTF-8_del.kmap.gz (HEAD vs. ada82813d27e5bef846ee086d07a87a82cfbb020)
CONFLICT (rename/delete): rcS.d/S08kmod deleted in HEAD and renamed in ada82813d27e5bef846ee086d07a87a82cfbb020. Version ada82813d27e5bef846ee086d07a87a82cfbb020 of rcS.d/S08kmod left in tree.
CONFLICT (add/add): Merge conflict in php5/cli/conf.d/20-xdebug.ini
CONFLICT (rename/rename): Rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf.conf" in branch "HEAD" rename "apache2/sites-available/default-ssl"->"apache2/sites-available/default-ssl.conf" in "ada82813d27e5bef846ee086d07a87a82cfbb020"

Я также попробовал:

git merge --allow-unrelated-histories --strategy-option theirs local/master

Но это же конфликты.

Использовал git v2.8.1 на первом примере. Обновлен до GIT v2.9.2 перед вторым примером.

Мой пример использования: я следую за изменениями обновления Debian в /etc с помощью GIT (точнее с ETCKEEPER). Теперь после обновления внесены некоторые изменения, и я хотел бы принять все изменения, сделанные Debian. Конечно, я верю в изменения, внесенные обновлением Debian, поэтому я хотел бы перезаписать (объединить) все сделанные изменения без какого-либо взаимодействия.

Любая идея, как решить их конфликты модификации автоматически?

1 ответ

Вы ожидаете больше -X theirs чем может доставить Git.

Помните сначала, что git merge с обычной (рекурсивной) стратегией:

  • находит базу слияния; 1
  • отличает базу слияния от текущего коммита tip, чтобы получить "наши" изменения; а также
  • Различает базу слияния против коммита, который вы называете - обычно это кончик какой-то другой ветки, но вы можете назвать любой коммит - чтобы получить "их" изменения.

У двух различий есть ряд различий, показывающих, "что мы сделали" и "что они сделали", и теперь Git попытается объединить их, чтобы мы получили одну копию каждого изменения. Это означает, что если мы исправили написание слова в строке 49 некоторого файла, а они этого не сделали, мы получим наше исправление. Если они исправили орфографию, а мы нет, мы получим их исправление. Если мы оба сделали одно и то же исправление орфографии, мы получаем исправление один раз, а не два, несмотря на то, что "исправить орфографию" представляется как:

"Сначала удалите старую строку. Затем вставьте новую, другую строку".

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

Если два блока различий в двух разных разностях вносят разные изменения в одну и ту же исходную область источника, Git обычно просто объявляет конфликт слияния. Он продолжает делать все возможное, но он запоминает конфликт и останавливается в конце слияния, оставляя конфликт присутствующим как в рабочем дереве (в привычном <<<<<<< ... >>>>>>> форма) и в указателе.

Также известный как "промежуточная область" или "кэш", индекс обычно имеет одну запись на файл рабочего дерева 2, но во время конфликтующего слияния вместо этого он имеет до трех записей для каждого такого файла: по одной от слияния база, одна из "наших" и одна из "их". "Обычная" (без конфликта) запись помещается в "промежуточный слот ноль", но этот слот не используется для этого файла, на этот раз. Вместо этого базовая версия файла помещается в промежуточный слот 1, а две другие версии - в слоты 2 и 3 (мы можем использовать --ours а также --theirs чтобы получить их, а не запоминать эти номера слотов, но они задокументированы в gitrevisions если вы хотите посмотреть их в любое время). Мы должны разрешить конфликт - часто, просто отредактировав файл в рабочем дереве, - и затем сказать Git заменить три копии в "незакрытых" слотах индекса на одну обычную копию, "готовую для перехода в следующий коммит "этап нулевой слот.


1 Предполагается, что существует единый коммит на основе слияния. Если есть несколько баз слияния, действие зависит от стратегии. "Рекурсивная" стратегия по умолчанию находит все базы слияния и объединяет их для создания единой "виртуальной базы слияния". Стратегия "разрешения" просто выбирает одну базу слияния случайно (по-видимому). Стратегия "осьминог" объявляет неудачу слияния.

2 Точнее, есть одна запись для отслеживаемого файла, со специальной записью для файла, который находится в HEAD зафиксировать, но планируется удалить из-за git rm, Поистине неотслеживаемые файлы вообще не имеют промежуточных слотов индекса.


-X ours а также -X theirs

Какие -X означает следующее: вместо того, чтобы объявить конфликт в данном конкретном случае (конфликтующие различия), просто возьмите либо наше изменение (-X ours) или их изменение (-X theirs), отбрасывая другой дифференциал.

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

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

Конфликты файлов

Это хорошо, насколько это возможно, но он обрабатывает только различия в различий. Конфликты, которые вы видите, являются несовместимыми изменениями файла:

CONFLICT (rename/delete): rcS.d/S08kmod deleted in HEAD and renamed
 in local/master. Version local/master of rcS.d/S08kmod left in tree.

В этом случае один git diff (чтобы найти "наши" изменения) обнаружили, что мы (HEAD) удалено rcS.d/S08kmod целиком, пока они (local/master) переименовал файл. В любом конфликте delete-file-vs-rename-file Git сохраняет файл под новым именем, так как нам гораздо легче потом удалить его (git rm newname) чем мы должны выяснить, каково было новое имя, и получить нашу или другую версию файла.

Auto-merging php5/cli/conf.d/20-xdebug.ini

(этот прошел хорошо, возможно, используя -X theirs разрешить конфликты различий)

CONFLICT (add/add): Merge conflict in php5/cli/conf.d/20-xdebug.ini

Здесь база слияния не имеет файла с именем php5/cli/conf.d/20-xdebug.ini, Git оставляет обе версии в индексе; мы можем использовать git checkout --ours положить наши в дерево работы, и git checkout --theirs положить их в дерево работы. К сожалению, мы все еще должны объединить и разрешить этот файл вручную. Я не проверял, что здесь делает Git версии 2.8 (в последнее время над разрешением конфликтов с добавлением / добавлением выполнялась некоторая работа).

Auto-merging apt/sources.list

(еще одно автоматическое объединение прошло успешно, возможно, снова используя -X)

CONFLICT (rename/rename): Rename "apache2/sites-available/default-ssl"->
"apache2/sites-available/default-ssl.conf.conf" in branch "HEAD"
rename "apache2/sites-available/default-ssl"->
"apache2/sites-available/default-ssl.conf" in "local/master"

В этом случае файл в базе слияния (под именем apache2/sites-available/default-ssl.conf.conf), судя по двум различиям, наши изменения были переименованы по- разному в сравнении с их изменениями. Я снова не уверен, что, если что-то, Git делает с изменениями в файле, хотя логически, -X theirs следует подать заявку и принять "свои" разногласия в любой точке, где наши и их конфликтуют. Однако Git не знает, какое окончательное имя использовать для файла, поэтому он объявляет конфликт.

После объявления этих конфликтов Git останавливается и заставляет пользователя вручную решить оставшиеся проблемы, как обычно. Ты можешь git add или же git rm какую версию (ы) каждого файла вы хотите, а затем git commit результат. Конечно, в любое время вы используете -X theirs или же -X ours, было бы разумно каким-то образом протестировать рабочее дерево (с помощью различий в глазах, или запустив ручные или автоматические тесты, или что-то еще) перед фиксацией.

Другие вопросы по тегам