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 показывает содержимое файла до его отправки. Это странно, так как я вижу, что изменение успешно зафиксировано в локальном и удаленном репозиториях, но похоже, что после этого файл снова изменяется на предыдущий контент...

Пример тому:

  1. Когда файл с содержимым '12345' зафиксирован + нажат, я заменяю эту строку на '54321'
  2. Я запускаю код выше
  3. 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)
Другие вопросы по тегам