我怎样才能更好地处理在git中污染“封闭”分支的提交?

时间:2011-04-12 17:56:20

标签: git version-control git-branch

我们刚接触到我公司的git,从Subversion开始git,周末我们遇到了我们的存储库中有一个分支的情况,我们在那里提交了一个分支的公共版本。我想要那里。我们有:

A -> B

然后得到了错误的提交将分支放在:

A -> B -> C -> D

C和D应该永远不会在那个分支上。问题是这个分支是“关闭” - 这是我们软件的发布版本,不应该有任何新的提交到这个分支。

在Subversion中,出现这种情况的唯一方法就是提交!D和!C以便最终得到:

A -> B -> C -> D -> !D -> !C

让我回到B但是让我继续前进分支的时间线,所以任何拥有与主存储库同步的分支的远程的人都会得到C和D然后让它们撤消到逻辑上结束类似版本的B(但不是B - 称之为B')。

我遇到this solution for reverting commits in git似乎很理想:它会将我们的公共存储库放回A -> B。但这意味着在任何人的工作机器上任何克隆这个分支将是非常不正确的,每个人都需要重新克隆。我的修复相当于:

git checkout thebranch
git reset --hard <<commit # associated with commit B>>
git push --force

我最终走上了上述链接的路线,引起了轰动:

a)您可以使用这样的git在公共存储库中丢弃提交历史记录,从字面上重写提交现实;

b)每个人都必须重新克隆,这样他们就不会冒险将C -> D重新注入分支(或我们想要创建的那个分支的新分支)。

我认为我应该做完了:

git revert HEAD~2
git commit
git push

但是这会将分支保留为A -> B -> C -> D -> E,并且它实际上不应该有C -> D -> E,因为它应该被关闭。

我有三个问题:

  1. 我怎样才能更好地处理清理工作?使用revert代替reset?分枝污染的最佳做法是什么?
  2. 还原分支push --force是否真的破坏了公共存储库中的历史记录?或者git回滚到B但保留了C -> D的记录,并且在某些时候我的回复已经回到了B?它肯定不会在提交日志中显示恢复,但是我的操作记录可能会保留在其他地方吗?
  3. 你如何处理git中的“封闭”分支,以至于这些变化首先不可能在那里进行?我们确实在提交B处将一个标记应用于存储库,并且人们应该使用branch +标记来获取发布的源代码,但是如果更改显示在不应该具有的分支行上,这仍然是一件可怕的事情。在提交B之后对其进行更改。并且从分支机构分支修补程序版本的人可能很容易错过标记并将C -> D拉入其新分支。

2 个答案:

答案 0 :(得分:5)

您应该使用标签进行发布(“封闭分支”)和分支进行开发(“开放分支”)。这是解决问题的替代解决方案(您可以只使用已发布代码的标记)以及将来防止此问题的方法。

在开发v3.1时,您可以使用v3.1分支。 v3.1完成后,标记最后一次提交并将分支重命名为下一个开发分支(v3.2)。记住:Git不是Svn!分支只是提交的指针。删除分支不会删除提交(但如果这些提交未包含在另一个分支中,它们将悬空,因此您应该在删除分支之前创建标记)。

如果要开发v3.1(v3.1.1)的补丁,那么在标签v3.1上创建一个分支:

git checkout -b v3.1.1 v3.1

对于您的开发人员来说这将更加清晰(分支机构用于开发,标签用于发布)并防止此问题再次出现。


  

恢复分支的推力是否真的破坏了公共存储库的历史记录?

没有。如果您为commit D创建了一个标记或分支,那么该分支仍然可以。使用git reflog查看头部的最新更改。那些承诺应该在那里。 (或git fsck。)


对于不使用其他版本控制系统作为理解基础的git的良好讨论,请尝试PeepCode's Git Internals。这不是免费的,但我认为除了集中版本控制之外,理解git要好得多。 (Git Community Book看起来像是一个很好的自由选择。)

答案 1 :(得分:1)

关于第2点:否;重置分支(本地或服务器上)永远不会破坏历史记录。在git中,分支类似于仅指向特定提交的标签(当签出分支并进行新提交时,标签会自动向前移动)。重置分支只意味着标签向后移动;提交本身仍然存在,但如果没有其他分支指向它们,则变为“不可见”。在这种情况下,可以使用git reflog恢复它们,它将显示所有提交的哈希值,即使是那些没有分支的哈希值。然后,您将看到“已删除”提交仍然存在。唯一可以摧毁它们的是git gc(它也是由git本身偶尔运行的),它会删除未引用的提交。

当您将分支重置为较早的点并强制推送它时,其他开发人员可以使用git fetch -f origin branchname:branchname重置其分支;没有必要重新克隆(但是,他们应该先检查一个不同的分支,以防止索引被强制获取搞砸)。但是,这将导致他们“失去”提交(再次,他们可以找到git reflog),如果他们已经提交到你不小心推动的分支。这对你来说可能不是问题,因为无论如何都应该关闭分支,但是如果它发生了,它们可以在强制获取之前创建一个新的分支;那么新分支仍将指向他们最新的提交,git rebase可以将提交移植到正确的分支上。