Pygit2: Почему слияние оставляет ветвь в нечистом состоянии?
В настоящее время я использую Pygit 0.24.1 (вместе с libgit 0.24.1), работая над хранилищем, где у меня есть две ветви (скажем, prod
а также dev
).
Каждое изменение сначала вносится в dev
ветка и толкнул в удаленном хранилище. Для этого у меня есть этот кусок кода:
repo = Repository('/foo/bar')
repo.checkout('refs/heads/dev')
index = repo.index
index.add('any_file')
index.write()
tree = index.write_tree()
author = Signature('foo', 'foo@bar')
committer = Signature('foo', 'foo@bar')
repo.create_commit('refs/heads/dev', author, committer, 'Just another commit', tree, [repo.head.get_object().hex])
up = UserPass('foo', '***')
rc = RemoteCallbacks(credentials=up)
repo.remotes['origin'].push(['refs/heads/dev'], rc)
Это работает довольно хорошо, я вижу локальный коммит, а также удаленный коммит, и локальное репо остается чистым:
нечего коммитить, рабочий каталог чистый
Далее я выезжаю на prod
филиал, и я хочу объединить коммит HEAD на dev
, Для этого я использую этот другой кусок кода (при условии, что я всегда начинаю извлекать на dev
ветка):
head_commit = repo.head
repo.checkout('refs/heads/prod')
prod_branch_tip = repo.lookup_reference('HEAD').resolve()
prod_branch_tip.set_target(head_commit.target)
rc = RemoteCallbacks(credentials=up)
repo.remotes['origin'].push(['refs/heads/prod'], rc)
repo.checkout('refs/heads/dev')
Я на самом деле вижу, как ветка сливается как локально, так и удаленно, но после выполнения этого фрагмента кода зафиксированный файл всегда остается в измененном состоянии в ветке. dev
,
На ветке dev
Изменения, которые необходимо зафиксировать: (используйте "git reset HEAD ..." для удаления)
модифицировано: any_file
Я полностью уверен, что никто не модифицирует этот файл. На самом деле, git diff
ничего не показывает Эта проблема возникает только с уже зафиксированными файлами (т. Е. С файлами, которые были зафиксированы хотя бы один раз ранее). Когда файлы новые, это работает отлично и оставляет файл в чистом состоянии.
Я уверен, что мне не хватает некоторых деталей, но я не могу выяснить, что это такое. Почему файл остается измененным?
РЕДАКТИРОВАТЬ: Просто чтобы уточнить, моя цель заключается в слиянии FF (Fast-Forward). Я знаю, что в документации Pygit2 есть некоторая документация о слиянии без FF, но я бы предпочел первый метод, потому что он сохраняет хеши фиксации через ветви.
РЕДАКТИРОВАТЬ 2: После комментария @ Леон, я дважды проверил, и действительно, git diff
пока не показывает вывод git diff --cached
показывает содержимое файла до его отправки. Это странно, так как я вижу, что изменение успешно зафиксировано в локальном и удаленном репозиториях, но похоже, что после этого файл снова изменяется на предыдущий контент...
Пример тому:
- Когда файл с содержимым '12345' зафиксирован + нажат, я заменяю эту строку на '54321'
- Я запускаю код выше
git log
показывает файл, зафиксированный правильно, на удаленном репозитории я вижу файл с содержимым "54321", в то время как локальноgit diff --cached
показывает это:@@ -1 +1 @@ -54321 +12345
1 ответ
Я бы объяснил наблюдаемую проблему следующим образом:
head_commit = repo.head
# This resets the index and the working tree to the old state
# and records that we are in a state corresponding to the commit
# pointed to by refs/heads/prod
repo.checkout('refs/heads/prod')
prod_branch_tip = repo.lookup_reference('HEAD').resolve()
# This changes where refs/heads/prod points. The index and
# the working tree are not updated, but (probably due to a bug in pygit2)
# they are not marked as gone-out-of-sync with refs/heads/prod
prod_branch_tip.set_target(head_commit.target)
rc = RemoteCallbacks(credentials=up)
repo.remotes['origin'].push(['refs/heads/prod'], rc)
# Now we must switch to a state corresponding to refs/heads/dev. It turns
# out that refs/heads/dev points to the same commit as refs/heads/prod.
# But we are already in the (clean) state corresponding to refs/heads/prod!
# Therefore there is no need to update the index and/or the working tree.
# So this simply changes HEAD to refs/heads/prod
repo.checkout('refs/heads/dev')
Решение состоит в том, чтобы перемотать ветку вперед, не проверяя ее. Следующий код лишен описанной проблемы:
head_commit = repo.head
prod_branch_tip = repo.lookup_branch('prod')
prod_branch_tip.set_target(head_commit.target)
rc = RemoteCallbacks(credentials=up)
repo.remotes['origin'].push(['refs/heads/prod'], rc)