Git重置——硬推到远程存储库

我有一个存储库,它有一些糟糕的提交(在这个例子中是D, E和F)。

A-B-C-D-E-F master和origin/master

我已经专门用git reset --hard修改了本地存储库。我在重置之前采取了一个分支,所以现在我有一个回购,看起来像:

A-B-C master
\ D-E-F old_master


A-B-C-D-E-F origin/master

现在我需要那些糟糕的提交的一些部分,所以我选择了我需要的比特,并进行了一些新的提交,所以现在我在本地有以下内容:

A-B-C-G-H master
\ D-E-F old_master

现在我想把这种状态推到远程回购。然而,当我试图做git push Git礼貌地给我刷掉:

$ git push origin +master:master --force
Total 0 (delta 0), reused 0 (delta 0)
error: denying non-fast forward refs/heads/master (you should pull first)
To git@git.example.com:myrepo.git
! [remote rejected] master -> master (non-fast forward)
error: failed to push some refs to 'git@git.example.com:myrepo.git'

我如何让远程回购采取本地回购的当前状态?

320849 次浏览

如果强制推送没有帮助(git push --force origingit push --force origin master应该足够了),这可能意味着远程服务器拒绝非快进推送,通过receive.denyNonFastForwards配置变量(参见git配置 manpage的描述),或通过更新/预接收钩子。

对于旧的Git,你可以通过删除git push origin :master(注意分支名之前的:),然后重新创建git push origin master给定分支来解决这个限制。

如果你不能改变这一点,那么唯一的解决方案将不是重写历史create a commit reverting在D-E-F中的变化:

A-B-C-D-E-F-[(D-E-F)^-1]   master


A-B-C-D-E-F                origin/master

为了补充Jakub的回答,如果你可以通过ssh访问远程git服务器,你可以进入git远程目录并设置:

user@remote$ git config receive.denyNonFastforwards false

然后返回到本地回购,再次尝试使用--force进行提交:

user@local$ git push origin +master:master --force

最后将服务器的设置恢复到原来的保护状态:

user@remote$ git config receive.denyNonFastforwards true

与其修复“主”分支,不如通过重命名分支来与“所需的主”进行交换。看到https://stackoverflow.com/a/2862606/2321594。这样,您甚至不会留下多个恢复日志的任何痕迹。

对我来说,整个重置git的工作看起来非常复杂。

所以我做了一些沿着线让我的src文件夹在我有几个提交前的状态

# reset the local state
git reset <somecommit> --hard
# copy the relevant part e.g. src (exclude is only needed if you specify .)
tar cvfz /tmp/current.tgz --exclude .git  src
# get the current state of git
git pull
# remove what you don't like anymore
rm -rf src
# restore from the tar file
tar xvfz /tmp/current.tgz
# commit everything back to git
git commit -a
# now you can properly push
git push

通过这种方式,src中的事务状态保存在tar文件中,git被迫接受这种状态,而不需要太多的修改,基本上src目录被替换为它在几次提交前的状态。

对于GitHub的用户来说,这对我来说很管用:

  1. 在任何您希望进行更改的分支保护规则中,确保启用了允许用力推
  2. git reset --hard <full_hash_of_commit_to_reset_to>
  3. git push --force

这将“纠正”你的本地机器和GitHub服务器上的分支历史,但是自从错误提交以来,任何已经将这个分支与服务器同步的人都将在他们的本地机器上拥有历史。如果他们有权限直接推送到分支,那么这些提交将在同步时显示出来。

所有其他人需要做的是上面的git reset命令来“纠正”本地机器上的分支。当然,他们需要警惕任何本地提交到这个分支目标哈希。在必要的时候选择/备份并重新应用它们,但是如果你在一个受保护的分支中,那么可以直接提交给它的人数可能是有限的。