Pygit2:为什么合并离开分支处于不干净状态?
Pygit2: Why does merge leave branch in an unclean state?
我目前正在 运行 宁 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)
这工作得很好,我可以看到本地提交和远程提交,本地仓库保持干净:
nothing to commit, working directory clean
接下来,我签出到 prod
分支,我想合并 dev
上的 HEAD 提交。为此,我使用了另一段代码(假设我总是开始签出到 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')
我实际上可以看到分支在本地和远程都被合并了,但是在这段代码 运行s 之后,提交的文件总是保留在 已修改 分支上的状态 dev
。
On branch dev
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: any_file
不过,我完全确定没有人在修改该文件。实际上,git diff
什么也没有显示。这个问题只发生在已经提交的文件上(即,之前至少提交过一次的文件)。当文件是新文件时,这可以完美地工作并使文件处于干净状态。
我确定我遗漏了一些细节,但我无法找出是什么。为什么文件保留为 已修改?
编辑:澄清一下,我的目标是进行 FF(快进)合并。我知道 Pygit2 文档中有一些关于进行非 FF 合并的文档,但我更喜欢第一种方法,因为它通过分支保留提交哈希。
编辑 2:在@Leon 发表评论后,我仔细检查了一下,确实,git diff
没有显示输出,而 git diff --cached
显示了文件的内容在 提交之前。这很奇怪,因为我可以看到更改已成功提交到本地和远程存储库,但之后文件似乎再次更改为以前的内容...
一个例子:
- 提交+推送内容为“12345”的文件后,我将该字符串替换为“54321”
- 我运行上面的代码
git log
显示正确提交的文件,在远程回购上我看到内容为“54321”的文件,而本地 git diff --cached
显示:
@@ -1 +1 @@
-54321
+12345
我将对观察到的问题进行如下解释:
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)
我目前正在 运行 宁 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)
这工作得很好,我可以看到本地提交和远程提交,本地仓库保持干净:
nothing to commit, working directory clean
接下来,我签出到 prod
分支,我想合并 dev
上的 HEAD 提交。为此,我使用了另一段代码(假设我总是开始签出到 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')
我实际上可以看到分支在本地和远程都被合并了,但是在这段代码 运行s 之后,提交的文件总是保留在 已修改 分支上的状态 dev
。
On branch dev
Changes to be committed: (use "git reset HEAD ..." to unstage)
modified: any_file
不过,我完全确定没有人在修改该文件。实际上,git diff
什么也没有显示。这个问题只发生在已经提交的文件上(即,之前至少提交过一次的文件)。当文件是新文件时,这可以完美地工作并使文件处于干净状态。
我确定我遗漏了一些细节,但我无法找出是什么。为什么文件保留为 已修改?
编辑:澄清一下,我的目标是进行 FF(快进)合并。我知道 Pygit2 文档中有一些关于进行非 FF 合并的文档,但我更喜欢第一种方法,因为它通过分支保留提交哈希。
编辑 2:在@Leon 发表评论后,我仔细检查了一下,确实,git diff
没有显示输出,而 git diff --cached
显示了文件的内容在 提交之前。这很奇怪,因为我可以看到更改已成功提交到本地和远程存储库,但之后文件似乎再次更改为以前的内容...
一个例子:
- 提交+推送内容为“12345”的文件后,我将该字符串替换为“54321”
- 我运行上面的代码
git log
显示正确提交的文件,在远程回购上我看到内容为“54321”的文件,而本地git diff --cached
显示:@@ -1 +1 @@ -54321 +12345
我将对观察到的问题进行如下解释:
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)