git - 如何强制Git push?

  显示原文与译文双语对照的内容

我已经设置了远程 non-bare"主要"仓库并将它的克隆到我的计算机。 我做了一些本地更改,更新了本地存储库,并将更改推回到远程仓库。 那时一切都很好。

现在,我不得不更改远程仓库中的内容。 然后我在本地仓库里修改了一些东西。 我意识到对远程仓库的更改不需要。 所以我尝试从本地仓库 git push 到我的远程仓库,但我遇到了一个错误:

为了防止你丢失历史记录,non-fast-forward更新被拒绝在再次推送前合并远程更改。 '关于fast-forwards的说明'于details,看到相关的部分,

我认为这可能是一个

 
git push --force

 

将强制我的本地副本将更改推送到远程副本并使它的相同。 它强制更新,但是当我回到远程存储库并进行提交时,我注意到文件包含了过期的更改( 主远程仓库以前拥有的) 。

就像我在注释中提到的,其中一个答案是:

[I] 试图强制,但是当回到主服务器来保存更改时,我得到了过时的暂存。 因此,当我提交的仓库不一样时。 当我再次尝试使用 git push 时,我得到了同样的错误。

我该如何解决此问题?

时间:

只需:


git push origin master --force

或者如果你有一个特定的仓库:


git push https://git.... --force

可能不合适,但是如果有人在这里页面上 stumbles,认为他们可能想要一个简单的解决方案。。

短标志

还要注意 -f--force的缩写,所以


git push origin master -f

也将工作。

如果 push --force 不工作,你可以做 push --delete 。 查看 2 nd 这里实例上的行:


git reset --hard HEAD~3 # reset current branch to 3 commits ago
git push origin master --delete # do a very very bad bad thing
git push origin master # regular push

但是小心。。

从不返回公共git历史 !

换句话说:

  • 不允许 force 推送公用存储库。
  • 不要这样或者任何能打断某人的东西。
  • 永远别在一个回购 reset 或者 rewrite 历史,可能有人已经采集了。

当然,即使对于这个规则也有例外例外,但在大多数情况下它不需要做它,并且会给其他人带来问题。

改为还原。

地方而推到一个公共回购,和永远 careful. 正在恢复:


git revert -n HEAD~3..HEAD # prepare a new commit reverting last 3 commits
git commit -m"sorry - revert last 3 commits because I was not careful"
git push origin master # regular push

实际上,两个起源头( 邪恶处重置,从恢复和) 将包含相同的文件。


编辑以在 push --force 周围添加更新的信息和更多参数

考虑使用租约而不是强制来推动强制,但仍然希望恢复

push --force 可能带来的另一个问题是在你做任何事情之前,但你已经获取了。 在其他网站上,如果你推弹力你重新设定基址你现在要 版本替换 work.

git push --force-with-lease 建议最新 1.8.5最新版本中引入(感谢 @VonC 对问题的评论) 试图解决这个具体问题。 基本上,它将带来一个错误,并且不会推送如果远程更改的,因为你最新取得的。

如果你真的确信需要一个 push --force,但仍然想避免更多的问题,这是很好的。 我认为它应该是默认的push --force 行为。 但这还远远不是强制 push的借口。 人谁招徕,然后你的rebase 仍然会有很多麻烦,这可以很容易地避免已经恢复如果你有 他途。

既然我们谈论的是 git --push 实例。。

为什么有人想要强制?

@linquize 为评论带来了一个不错的强制示例: 敏感数据 。你错误地泄露了不应该被推送的数据。 如果在top,上已经足够快,可以 "修复" * 它通过强制一个 push.

仍将在远程 *的数据,除非你也做一个垃圾收集或者干净它不知 。 另外还有明显的潜在可以帮助产品传播被别人谁有招徕它已经,但你应该清楚了。

要了解强制推送的,请参阅其他答案

这个答案解释说。因为他原来的海报问题是根本不是的方式是强迫力推,而是,他目前正致力于一个 non-bare 回购( 而不是一个光秃秃的仓库) 。

就像其他答案中提到 1 通常,推送至non-bare档案库是不建议这样做,因为尽管可以更新远程分支参考建议通过牵引,最新推实际上并不会更新该工作目录的索引/staging-area远程non-bare回购也不会来了

这就是说,在工作副本和远程回购仍将设置为该版本的就已经存在的文件的索引/staging-area HEAD 之前你推送,而符号引用将被设置为新推的尖端的分支。 在你 question, 所以它将表现为之前的提交是修改仍然在你stated:舞台,它匹配你

我注意到这些文件包含了过时的更改( 主远程仓库以前拥有的) 。

1参见的vonc的回答。

如何重现问题

首先,创建一个新的non-bare Git仓库,并填充一些文件:


mkdir main
cd main
git init
echo hello> hello.txt
git add. 
git commit -m"Hello"

echo bye> bye.txt
git add. 
git commit -m"Bye"

当前版本的Git将不允许你在默认情况下推送到non-bare知识库,因此你需要配置这里存储库才能允许它:


git config receive.denyCurrentBranch warn

接下来,创建另一个克隆,并进行硬重置一次提交,然后按:


$ cd.. 
$ git clone main second
$ git reset --hard head^
$ git push --force
Total 0 (delta 0), reused 0 (delta 0)
remote: warning: updating the current branch
To main
 + 3c3ee2b...2f34b62 master -> master (forced update)

现在回到主仓库,检查日志和文件状态。 你会看到,即使主分支被设置回原来的提交,临时区域仍然有来自在分支中被强制推送的第二个提交的更改:


$ cd.. /main
$ git log --oneline --decorate
2f34b62 (HEAD, master) Add hello.txt

$ git status
On branch master
Changes to be committed:
 (use"git reset HEAD <file>..." to unstage)

 new file: bye.txt

解决方案

如果你想在工作副本和索引/staging-area ( 由符号引用 HEAD 表示) non-bare远程,使它的与当前提交的当前分支中的,那么可以直接要做的只是做一个硬复位到 HEAD:


git reset --hard HEAD

你的分支的回购和符号references,最后,建议推只针对裸档案库 intead non-bare的repo,正因为如此非常的sync. working-copy和索引值不同步的问题,

将non-bare仓库转换为裸机存储库的简单方法是简单地 reclone:


git clone --bare originalRepo bareRepo
cd bareRepo
git remote rm origin

文档

git-config(1) 手册页 ( 强调挖掘):


receive.denyCurrentBranch

如果设置为真或者"拒绝",git-receive-pack将拒绝对non-bare存储库当前签出分支的引用更新。 这样的推有可能是危险的,因为它将头部与索引和工作树同步。 如果设置为"警告",则打印到stderr的警告的警告,但允许继续。 如果设为假或者"忽略",则允许这样的推。 默认为"拒绝"。

年3 月上这里设置已经被用于 Git 因为新版 1.6.2,其中被释放 th 2009.就像上面的文档状态所示,设置默认为拒绝推送,甚至 force-pushes 。

强制推的演示无法解决原海报问题的问题

因为这里似乎有很多混淆,我将演示 force-pushing 不是正确的解决方案来解决你的问题。

第一,创建一个主要回购就像在前面的再现上的步骤之后,还有第二后的克隆主回收员但是这一次,请不要设置receive.denyCurrentBranch 。 这里设置将拒绝于主,甚至 force-pushes,推送到远程 repo,并已经被 non-bare默认设置,因为Git版本 1.6.2

接下来,从第二个克隆,尝试强制推送到主仓库:


$ git push --force
Total 0 (delta 0), reused 0 (delta 0)
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
error:
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.
error:
error: To squelch this message and still keep the default behaviour, set
error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To main
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'main'

或者 git push origin master --force :


$ git push origin master --force
Total 0 (delta 0), reused 0 (delta 0)
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
error:
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.
error:
error: To squelch this message and still keep the default behaviour, set
error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To main
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'main'

就像你将看到的上,无论怎么样我都要试图强迫推到non-bare远程回购默认情况下,Git不会允许它。 甚至当你在 force-pushing,receive.denyCurrentBranch 设置为允许远程non-bare回购的索引和工作树,这使得它仍然不联系


git reset --hard HEAD

信息的符号 HEAD non-bare时所进行的工作的远程复制和索引/staging-area成为脱离 sync. reference,正确的解决方案

首先,我不会直接在"主要"仓库中做任何更改。 如果你真的想要有一个"主要"仓库,那么你应该只对它进行推送,不要直接改变它。

关于你正在获取的错误,你是否尝试过从本地存储库 git pull,然后将 git push 发送到主仓库? 在"主要"repo,什么你正在从事( 如果我理解得很好) 是强行推送,然后丢失所做的更改。 你应该首先在本地合并更改。

这个答案解释了强制推 。 最初的海报问题不是强制推动自己,而是推到non-bare仓库( 而不是一个光秃秃的仓库),如我的其他答案

你有 4种方法来强制使用 Git


git push <remote> <branch> -f
git push origin master -f # Example

git push <remote> -f
git push origin -f # Example

git push -f

git push <remote> <branch> --force-with-lease

如果你想要对每个命令进行更详细的解释,那么请查看下面的long我的长答案answers部分。

警告: 力推动将覆盖远程分支与分支,你在推动的状态。 确保在使用之前确实要这样做,否则,你可能会覆盖你想要保留的提交。

强制推送细节

指定远程和分支

你可以完全指定特定分支和远程。 -f 标志是 --force的短版本


git push <remote> <branch> --force
git push <remote> <branch> -f

忽略分支

当忽略分支分支时,Git会根据你的配置设置来计算出来。 在 2.0之后的Git版本中,一个新的存储库将有默认设置来推动当前的checked-out分支:


git push <remote> --force

在 2.0之前,新的档案库将有默认设置来推动多个本地分支。 相关设置是 remote.<remote>.pushpush.default 设置( 见下文) 。

省略远程和分支

当远程和分支都被忽略时,仅 git push --force的行为由你的push.default Git配置设置决定:

 
git push --force

 
  • 就 Git 2.0而言,默认的设置 simple 将把当前分支推到上游远程 counter-part 。 远程设置由分支设置的branch.<remote>.remote 决定,默认为原始仓库。

  • 在Git版本 2.0之前,默认设置 matching,基本上只是将你的本地分支推送到远程( 默认为原点) 上具有相同名称的分支。

你可以阅读更多通过阅读 git help config 或者 push.default 设置的在线版本,git-config(1) 手册页面

使用 --force-with-lease 强制更安全地推送

动力推动以"租用"允许力量把失败如果有新的提交在远程不是你期望( 从技术上讲,如果你还没有将它们提取到remote-tracking分支),它是有用的,如果你不想要会无意改写他人提交的其它你所甚至没有了解的东西,你就会想改写你的独立存在,


git push <remote> <branch> --force-with-lease

你的force-pushed ones,,但是要注意,因为这仍然是一个力推,它仍然可以是一个问题的合作者的如果,他们无法或者不愿意为重新同步现有 commits.

你可以通过阅读以下任一内容了解有关如何使用 --force-with-lease的更多详细信息:

我建议你:

  • 仅推送到主仓库

  • 确保主存储库是一个裸机,以便主仓库工作目录树不会与它的.git 库同步。 查看"如何将本地git存储库推送到另一台计算机? "

  • 如果你需要在主( 裸) 仓库中进行修改,请克隆它( 在主服务器上),做你的修改并向它推送

换句话说,保留一个裸回购这两个从主服务器和本地计算机中访问到的配置,为了有一个单一的上游仓库从/到拉/拉。

...