`git push --force`的其他后果?

时间:2014-01-21 13:29:28

标签: git version-control

有关强制git push的问题和答案并不难找到(heretwo)。标准答案是这样的:

  

如果您必须强制使用git push,技术上您可以使用--force选项,但在程序上您不应该,因为有人可能已经拉了一个小猫会死的地方。

我认为这是一般的圣人建议 - 更安全的路线是再次提交,修复你所破坏的任何东西。但是,让我们说,例如我知道(神奇地)没有人拉过提交。或者更好的是,这是一个私人回购,因此首先没有打破别人克隆的危险。

--force推动是否有其他 [负面]后果,特别是技术后果?也许它会导致遥控器上出现一些额外的垃圾,或者它破坏了X Corps分析工具的1.2.3版本,或者它会让以后更加混乱,等等。任何事情?

编辑1:我有自己的轶事证据表明,{{1}推送私人仓库并不会似乎导致任何问题。不过,我对感知不感兴趣;我正在寻找参考和/或证明。

3 个答案:

答案 0 :(得分:10)

强制推动只是告诉遥控器移动给定的标签,即使移动不是快进操作。 1 非快进能(不一定) )导致“废弃”提交:从某个引用无法访问的提交。

(当在其他地方引用的图形的一部分上发生标签动作时,执行此操作。例如,如果分支xyzzy指向提交D按顺序:

A-B-C-E  <-- plugh
   \ /
    D    <-- xyzzy

然后标签xyzzy会发生什么变得无关紧要,因为标签plugh使提交D可达。因此,以非快进方式移动xyzzy,例如,指向提交C,根本不会影响提交D。同样,完全删除标签xyzzy也是无害的,至少在提交图结构方面是这样。)

远程裸存储库(通常推送的存储库)通常不会记录所有ref更新,因此这往往会触发任何放弃的提交的快速垃圾收集。 (请注意,如果将它们保存在您自己的存储库中,您可以稍后恢复gc'ed提交 - 但这需要您再次通过网络发送数据,并且如果您自己的存储库被损坏,则会使您面临数据丢失风险,比如说,电源故障或电脑着火。)

如果你有一些第三方软件认为(部分或全部)分支标签只是快速前进,那么软件可能会以有趣的方式失败。我知道没有这样的软件,如果它存在,我会称之为“破碎”,但人们往往会写出破碎的代码然后依赖它。


1 旧版本的git允许标签在没有强制推动的情况下移动,如果移动是快进的话,就像预期分支标签移动一样。较新的版本(我认为在1.8.2中引入,但只是从内存中引入)拒绝任何标记动作,除非你使用force。当然你总是可以删除,然后重新创建(可能在不同的点)标签,内置的钩子就可以了。因此,即使没有力量,还有其他方式可以以任意方式移动标记或分支。只需确保要保留的提交图部分在每个操作中都有某些标签。


至于稍后制作(你自己的)变装更难:是的,它可以具有这种效果,因为你可能会从“桌面”强制推送,因此,实际上,重新排列“共享 - 裸露” -repo”。之后,在“笔记本电脑”上,您可能无法记住只有哪个提交您重新定位,并且弄清楚它可能有点棘手,特别是在一个大型,高度活跃的存储库中。

幸运的是,即将发布的新git版本有一个新功能,它使用您的reflog来确定是否以及何时发生了“上游rebase”。也就是说,在上面的情况下,你可以(在“笔记本电脑上”)让git自动发现哪些提交在shared-bare-repo中被重新定位,并且“重新设置”你的笔记本电脑工作。 (这是今天与git pull --rebase一起使用的方法的概括,在git 1.8.x中。)

答案 1 :(得分:7)

补充torek的优秀答案:

强制推送可能会导致以后的合并出现问题。

问题:

如果强制推送分支A,则从该分支中​​删除一些现有提交(否则您不需要强制执行)。如果(如torek的回答中所述)这些提交也是从另一个分支B引用的,那么它们将保留在该分支中。如果稍后稍后合并两个分支A和B,A将包含“新”(强制)提交和B“旧”提交。

在这种情况下git merge可能不会做你想要的。在最好的情况下,您将遇到合并冲突。最糟糕的情况是,你不会,但结果仍然是错误的。例如,如果使用git rebase -i从A中删除了提交c1,如果c1也在B中,则在合并A和B时将重新引入。这可能会默默地重新引入错误: - (。< / p>

因此,如果强制推送,请确保您删除的提交未被其他分支/标记引用(或强制推送这些分支/标记)。


已删除提交“返回”的插图

运行下面的bash脚本。该脚本创建一个git存储库,并使用以下提交分支master,branch1:

  • 良好提交(branch1)
  • 错误提交(主)
  • 初始

然后呢:

  • 使用git reset --hard来丢弃来自主
  • 的“错误提交”
  • 将branch1合并为主

脚本输出:

Initialized empty Git repository in ....
[... creating commits ...]
### Bad commit in history:
* 7549dcc (HEAD, master) bad commit
* 31afec8 Initial
### Removing bad commit:
HEAD is now at 31afec8 Initial
### Bad commit no longer in history:
31afec8 (HEAD, master) Initial
### Merging branch1:
Updating 31afec8..be801e5
Fast-forward
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b
 create mode 100644 c
### Bad commit is back!
be801e5 (HEAD, master, branch1) good commit
7549dcc bad commit
31afec8 Initial

如您所见,使用git reset --hard从主服务器中删除了“错误提交”。但是,“bad commit”仍然包含在branch1中,所以当branch1合并为master时,“bad commit”会返回。

注意:此示例实际上并不强制推送,但如果您使用上游仓库,则必须在删除错误提交后强制推送 - 结果将是相同的。

剧本:

#!/bin/bash
set -e
if [ -e gitrepo ]; then echo "Please remove gitrepo"; exit 1; fi

git init gitrepo; cd gitrepo; git config core.pager cat
touch a; git add a; git commit -m Initial
touch b; git add b; git commit -m "bad commit"
git checkout -b branch1; touch c; git add c; git commit -m "good commit"
git checkout master

echo "### Bad commit in history: "
git log --oneline --decorate

echo "### Removing bad commit: "
git reset --hard HEAD~1

echo "### Bad commit no longer in history: "
git log --oneline --decorate

echo "### Merging branch1: "
git merge branch1

echo "### Bad commit is back!"
git log --oneline --decorate

答案 2 :(得分:2)

我一直在我的私人存储库中使用--force而没有不良副作用,因为我知道何时强制进行更改以及对我的代码产生的后果。

--force的唯一问题是它更改了上游存储库中的历史记录,并且有人可能在更改历史记录之前更改了存储库的状态。这会导致问题 - 这就是为什么它不是推荐的解决方案。但即使这样 - 这些问题可以修复,它们只需要做一些工作。

所以回答这个问题 - 如果你只是想在私人仓库中与自己分享代码而没有其他人会受到这些变化的影响,那么就没有其他副作用。