Git reset –hard和一个远程存储库


Git reset --hard and a remote repository

我有一个存储库,其中有一些错误的提交(本例中是D、E和F)。

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

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

1
2
3
4
A-B-C master  
     \ D-E-F old_master

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

现在,我需要这些糟糕的提交中的一些部分,所以我挑选了我需要的部分,并做出了一些新的提交,所以现在我在本地有了以下内容:

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

现在我想把这种情况推到远程回购上。然而,当我试图做一个git pushgit时,礼貌地拒绝了我:

1
2
3
4
5
6
$ 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 [email protected]:myrepo.git  
! [remote rejected] master -> master (non-fast forward)  
error: failed to push some refs to '[email protected]:myrepo.git'

如何让远程回购获得本地回购的当前状态?


如果强制推不起作用("git push --force origin"或"git push --force origin master"应该足够了),则可能意味着远程服务器拒绝通过receive.denynonfastforwards配置变量(请参阅git config manpage了解说明)或通过更新/预接收挂钩进行非快速推送。

使用较旧的Git,您可以通过删除"git push origin :master"(请参见分支名称前的":",然后重新创建"git push origin master"给定分支来绕过这一限制。

如果您无法更改此项,那么唯一的解决方案将是重写历史记录以在D-E-F中创建一个提交恢复更改:

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

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


为了补充Jakub的答案,如果您可以在ssh中访问远程git服务器,则可以进入git远程目录并设置:

1
user@remote$ git config receive.denyNonFastforwards false

然后回到您的本地回购,再次尝试执行您与--force的承诺:

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

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

1
user@remote$ git config receive.denyNonFastforwards true


与修复"主"分支不同,通过重命名分支,可以更容易地将其与"所需的主"进行交换。请参阅https://stackoverflow.com/a/2862606/2321594。这样,您甚至不会留下多个还原日志的任何跟踪。


对我来说,整个Git重置业务看起来要复杂得多。

所以我做了一些事情,让我的SRC文件夹处于几天前提交的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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目录被它之前提交过的状态所替换。