Попытка git merge прекращает работу без ошибок
C:\Users\danie01\fox (fox-45481 -> origin)
λ git merge feature/master-stg
error: The following untracked working tree files would be overwritten by merge:
blah/blah/blahblah.cpp
... (many files)
common/wizard/wizpa
Aborting
C:\Users\danie01\fox (fox-45481 -> origin)
λ
Прошло очень много времени с тех пор, как я ранее слился. Далее, последний коммит в этой ветке был слиянием.
Интересно, что окончательный файл в этом списке обрезается (у него нет расширения файла или даже полного имени файла) - может ли это быть проблемой с моим буфером?
Я только недавно проверил это из удаленной ветки; У меня нет разрешения на слияние с удаленной веткой, и мне нужно создать запрос на слияние. Может ли быть так, что git пытается слиться непосредственно с удаленной веткой?
Что здесь можно сделать? Я в растерянности.
2 ответа
Может ли быть так, что git пытается слиться непосредственно с удаленной веткой?
Нет, это не то, как Git выполняет слияния.
(Между прочим, ваша строка темы неверна, так как слияние прерывается с ошибкой, сообщающей, что некоторые неотслеживаемые файлы будут перезаписаны.)
Интересно, что окончательный файл в этом списке обрезается (у него нет расширения файла или даже полного имени файла) - может ли это быть проблемой с моим буфером?
Я не уверен, что вы подразумеваете под этим, но, конечно, имена файлов в выводе не должны быть усечены.
Обратите внимание, что когда вы просите Git выполнить слияние, он должен манипулировать несколькими различными элементами. Все коммиты заморожены (только для чтения) и по сути постоянны 1, поэтому они не являются проблемой. Но есть две вещи, которые не заморожены и поэтому могут быть перезаписаны:
Ваш текущий индекс содержания. Ваш индекс содержит одну - или иногда (во время неполного слияния) более одной - запись для каждого отслеживаемого файла в рабочем дереве. Фактически, это и есть отслеживаемый файл: это файл, который сейчас находится в рабочем дереве, а также в индексе. 2
Ваш текущий контент рабочего дерева. Git не использует это напрямую - он у вас есть, но различные операции, конечно, будут перезаписывать файлы в рабочем дереве. Например,
git checkout
какой-то другой ветви, очевидно, придется перезаписать хотя бы несколько файлов, если другая ветвь имеет другое содержимое файла.
Между этими двумя вещами вам легко создавать неотслеживаемые файлы. Не отслеживаемый файл - это просто файл, который существует в вашем рабочем дереве прямо сейчас, но сейчас его нет в вашем индексе. Каждый такой файл можно либо игнорировать, либо не игнорировать, но в любом случае он не отслеживается. Если это не игнорируется, git status
будет жаловаться на это.
Перед началом слияния рекомендуется убедиться в двух вещах: во-первых, что вы еще не находитесь в середине какой-либо другой операции, и во-вторых, что HEAD
commit, index и work-tree все совпадают с точки зрения всех ваших отслеживаемых файлов. git merge
Команда делает большую часть этого автоматически, но это никогда не плохая идея для запуска git status
сначала и убедитесь, что он говорит nothing to commit, working tree clean
,
Это нормально, если он также жалуется на различные неотслеживаемые файлы, так как у нас есть возможность разобраться с ними в одно мгновение. Теперь, когда вы уверены, что нет выполняемой работы, которая может быть потеряна, введите команду слияния:
λ git merge feature/master-stg
Что делает Git сейчас:
- Посмотрите хэш-идентификатор текущего коммита (
git rev-parse HEAD
). - Посмотрите хэш-идентификатор указанного коммита (
git rev-parse feature/master-stg
). - использование
git merge-base --all
найти базу (ы) слияния этих двух коммитов. База слияния - это коммит, а иногда и более одного коммита, который находится в обеих ветвях и является лучшим таким коммитом.
В идеале, есть только один базовый коммит. Вы можете проверить, так ли это, запустив:
git merge-base --all HEAD feature/master-stg
Если он выводит только один хэш-идентификатор, это - (единственный) базовый коммит слияния. Получение нескольких баз слияний здесь редко, и если это случается, это требует дополнительного обсуждения, но так как это редко (и, вероятно, не происходит здесь), мы можем просто предположить, что есть только одна база слияний.
В некоторых случаях есть только одна база слияния, и это тот же идентификатор хеша, что и текущий (HEAD
) совершать. Эти случаи, как правило, очень легко обрабатываются, и Git по умолчанию выполняет операцию ускоренной перемотки вместо слияния. Вероятно, у вас не такой случай (но это может быть - нет доказательств здесь, так или иначе). Я предполагаю, что Git выполняет реальное слияние, поскольку проблема будет одинаковой в любом случае, а решение будет таким же.
1 Файлы внутри коммита определенно заморожены, но они существуют в этой форме, потому что коммит существует. Если вам удастся заставить Git забыть об этом коммите, сам коммит со временем исчезнет. Это очень трудно сделать, поэтому коммиты в основном постоянны. Однако они полностью доступны только для чтения: ничто в любом коммите, идентифицируемом по его хэш-идентификатору, никогда не может измениться.
2 Технически вы можете удалить копию рабочего дерева, оставив индексную копию на месте. Я думаю, это все еще будет "отслеживаемый файл", хотя номенклатура становится немного шаткой. (Как можно отследить файл, если этот файл не существует?)
Как Git выполняет реальное слияние
Теперь, когда Git знает три входа для слияния: базовый коммит, --ours
или же HEAD
совершать, а другой или --theirs
совершать, из feature/master-stg
Git, по сути, будет работать два git diff
команды:
git diff --find-renames <hash-of-base> HEAD # what we changed
git diff --find-renames <hash-of-base> feature/master-stg # what they changed
Работа по слиянию теперь довольно проста и довольно очевидна. Вот что нужно будет сделать:
- Начните со всех файлов, которые были в коммите слияния.
- Затем, если мы изменили или создали или удалили (и / или переименовали) файл, и они не коснулись файла, используйте наше изменение.
- Если они изменили или создали или удалили (и / или переименовали) файл, и мы не трогали файл, используйте их изменение.
- Если мы и они оба изменили или создали или удалили (и / или переименовали) один и тот же файл, объедините эти два отдельных набора изменений.
В простых случаях сделать все это довольно просто. Например, возможно, мы оба коснулись README.md
, но по-разному; мы изменились a/main.py
и они не сделали; и они изменились b/prog.cc
а мы нет Результатом слияния будут все базовые файлы, кроме README.md
, который имеет объединенные изменения, наш a/main.py
, и их b/prog.cc
,
Если все идет хорошо, Git фиксирует полученные файлы, попутно помещая их в ваш индекс и рабочее дерево. Новый коммит обновляет текущую ветку, так что любая ветка HEAD
имена, теперь имена нового коммита. Первый родитель нового коммита - это предыдущий совет текущей ветви, а второй родитель нового коммита - другой коммит (тот, который все еще идентифицируется feature/master-stg
, в этом случае). Поскольку новый коммит имеет двух родителей, это коммит слияния.
В сложных случаях что-то идет не так, и слияние либо останавливается посередине (что является самым запутанным случаем), либо никогда не начинается. У вас есть последний случай: слияние никогда не начинается.
У вас есть неотслеживаемые файлы, которые они имеют в своем коммите
Что здесь не так, так это то, что в коммите feature/master-stg
- у них есть некоторые файлы, которые:
- не находятся в коммите слияния, и
- также не находятся в вашем коммите HEAD.
Git распечатал полный список этих файлов:
blah/blah/blahblah.cpp ... (many files) common/wizard/wizpa
в git diff --find-renames <hash of merge base> feature/master-sta
вывод, они добавили эти файлы. Вы можете подтвердить это, запустив тот же git diff
себя, возможно, с --name-status
так что это короче и более читабельно.
У вас нет этих файлов в вашем HEAD
commit, но у вас есть те же самые файлы в вашем рабочем дереве прямо сейчас.
Чтобы Git выполнил слияние и получил окончательный результат, Git должен будет перезаписать ваши файлы рабочего дерева. Поскольку они не находятся в вашем индексе и не в вашем коммите, Git не может быть уверен, что можно уничтожить единственную их копию, находящуюся в рабочем дереве. Git поэтому прерывает слияние, никогда не запуская его вообще.
Решение состоит в том, чтобы сделать именно то, что сказал или должен был сказать Гит (возможно, это потеряно в части "бла-бла"):
Пожалуйста, переместите или удалите их, прежде чем объединить.
По сути, Git чувствует необходимость перезаписать эти файлы. Если это так, то любое содержимое, которое у вас есть, будет безвозвратно - или, по крайней мере, Git не сможет его вернуть. Таким образом, вы должны сохранить содержимое в другом месте, если они являются ценными.
Я думаю, что git пытается сказать вам, что, запустив слияние, некоторые файлы, которые в текущем рабочем дереве не отслеживаются, в другой ветви отслеживаются, и поэтому они будут перезаписаны, если вы объедините. Я думаю, вы могли бы просто удалить их из рабочего дерева, чтобы слияние прошло.