【问题标题】:Pygit2: Why does merge leave branch in an unclean state?Pygit2:为什么合并会使分支处于不干净状态?
【发布时间】:2016-07-15 19:45:11
【问题描述】:

我目前正在运行 Pygit 0.24.1(以及 libgit 0.24.1),在我有两个分支(比如 proddev)的存储库上工作。

每个更改首先提交到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)

这很好用,我可以看到本地提交和远程提交,并且本地 repo 保持干净:

没有什么要提交的,工作目录干净

接下来,我检查到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')

我实际上可以看到分支正在本地和远程合并,但是在这段代码运行之后,提交的文件始终保持在分支@上的 已修改状态987654329@.

在分支开发上

要提交的更改: (使用“git reset HEAD ...”取消暂存)

修改:any_file

不过,我完全确定没有人修改该文件。实际上,git diff 什么也没显示。此问题仅发生在已提交的文件(即之前至少提交过一次的文件)中。当文件是新文件时,它可以完美运行并使文件保持干净状态。

我确定我遗漏了一些细节,但我无法找出它是什么。为什么文件被修改

编辑:澄清一下,我的目标是进行 FF(Fast-Forward)合并。我知道 Pygit2 文档中有一些关于进行非 FF 合并的文档,但我更喜欢第一种方法,因为它通过分支保持提交哈希。

编辑 2:@Leon 发表评论后,我仔细检查了一遍,确实,git diff 没有显示输出,而 git diff --cached 显示文件提交之前的内容.这很奇怪,因为我可以看到在本地和远程存储库上成功提交了更改,但看起来之后文件再次更改为以前的内容......

一个例子:

  1. 提交并推送内容为“12345”的文件后,我将该字符串替换为“54321”
  2. 我运行上面的代码
  3. git log 显示正确提交的文件,在远程仓库中我看到内容为“54321”的文件,而本地 git diff --cached 显示:

    @@ -1 +1 @@
    -54321
    +12345
    

【问题讨论】:

  • 实际上,一个 git diff 什么都不显示”。您的意思是“git diff --staged什么都不显示”吗?
  • @Leon 请看一下EDIT 2,因为我做了一些额外的测试并帮助我走得更远。

标签: python git python-2.7 libgit2 pygit2


【解决方案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)

【讨论】:

  • 这行得通,谢谢。所以我的代码和你的代码之间唯一的显着区别是结帐以及prod_branch_tip 是如何解决的。理解为什么这种方法会有所作为有点棘手,关于这个的文档不是很解释,所以我会做一些额外的测试来更好地理解正在发生的事情。无论如何,您的答案是正确的,所以我将其标记为这样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-21
  • 1970-01-01
  • 2015-03-15
  • 2017-02-12
  • 1970-01-01
相关资源
最近更新 更多