This topic created in 4360 days ago, the information mentioned may be changed or developed.
本地仓库A 中心仓库B 远端仓库C
流程就是 A 开发好, push 到 B, C 再 从B pull 下来。
但 A 不小心删了个文件,然后就 commit push 到B了,
此时 A B 的 commit log 大概是这样的,
aaaaaaa
|
bbbbbbb
aaaaaa 就是这个最新的commit
发现不对, 在A执行了 git reset HEAD^ , 然后把误删除的文件checkout 回来,再commit
此时push 就提示和B冲突了, 这个很好理解
但我 git push -f ,强制推送了
A B 的 commit log 成了这样
ccccccc
|
bbbbbbb
因为 aaaa 的commit 被reset 并且 强制推送覆盖了。
但现在到 C来操作, 从 B pull 下来的 commit log 是
aaaaaaa
|
bbbbbbb
并且 提示 此时的状态和B 是 already up-to-date
但 C 中还是 文件被删除的状态……
9 replies • 2014-06-08 01:01:59 +08:00
 |
|
1
delo Jun 6, 2014 via iPhone
C处clone一份是怎样的?一般push到中心仓库的commit就不要再改动了吧,宁愿重新把文件手动加回来再commit一次。看看大家有啥好办法
|
 |
|
2
wwqgtxx Jun 6, 2014 via Android
强制覆盖push貌似是不能直接pull更新的吧 你可以试试在C端重新clone一遍
|
 |
|
3
czheo Jun 6, 2014 via iPhone
push到中心的commit不应该被删除,你应该在aaaa的基础上添加回被删除的文件,然后做新的commit push上去 xxxx <==添加回被删文件 | aaaa | bbbb
|
 |
|
4
123123 Jun 6, 2014
如果只有两个人用仓库还好。 B 只要 fetch 一下,然后直接 reset hard 到最新节点就好了
|
 |
|
5
xcatliu Jun 6, 2014
C 直接重新 clone 吧。。
别用 force push 了,要回退就 revert 再提交
|
 |
|
6
skydiver Jun 7, 2014
@ 123123 应该是 C 只要 fetch 一下,然后直接 reset hard 到最新节点就好了
|
 |
|
7
neevek Jun 7, 2014 1
根据你的描述不应该会出现aleady up-to-date。
如果B的log是: ccccccc | bbbbbbb
C的log是: aaaaaaa | bbbbbbb
意味着这时候B和C的common ancestor是bbbbbbb,也就是当C从B pull的时候不是fast-forward,原来A提交的aaaaaaa会被当成是C提交的,换言之,文件(假设文件名为file.txt)是在C中被删除的,A没有对file.txt做任何修改。这时候merge B和C最终会导致file.txt文件被删除,并且会产生一个merge commit,这个时候C的log应该是这样的: Merge commit | ccccccc | aaaaaaa | bbbbbbb
楼主没有直接问问题,我假设楼主希望C跟B合并之后,C中的file.txt没被删除。假设当前在C,这时候需要执行以下命令(执行命令之前,如果你已经执行过git merge或者不带任何参数的git pull,那请回退到合并之前的历史,如:git reset --hard HEAD@{1}):
注:假设upstream是origin,分支名是master
git pull --rebase origin master 或者 git fetch origin master git rebase --onto origin/master HEAD~0 master
上面这两组命令在这个场景下是等价的,但是用下面这一组命令来解释会更加容易理解。 这里第一个参数origin/master表示我想基于origin/master来replay当前分支的commit,这个时候origin/master其实就是B。HEAD~0实际上等价于HEAD,写成HEAD~0只是为了强调我只有当前分支最新1个commit(这个commit就是aaaaaaa)需要replay到origin/master上。最后的master表示rebase的结果是应用到master分支上的,最终的结果就是file.txt回来了,commit历史会变成: ccccccc | bbbbbbb
没错,aaaaaaa不见了,因为rebase origin/master(等价于based on B中的ccccccc)实际上就是拿C中的aaaaaaa和B中的ccccccc做比较,最终发现ccccccc中增加了file.txt,所以保留了file.txt,所以相当于aaaaaaa这个提交神马都没做,所以这个commit就被去除了。
另外,假设在rebase B之前,在C上面做过一次提交,那上面的HEAD~0改成HEAD~1就可以了。
oh, my god....好长
|
 |
|
8
neevek Jun 7, 2014
发现不能编辑回复。。。只能再写一个回复更正上一个回复了。
前面关于HEAD~0的描述是错误的(最后3段),HEAD~0在这里实际上exclusive的,也就是HEAD~N往回数N个commit(这里HEAD~0就是0个commit,即完全忽略),然后对这些commit生成patch,replay到origin/master上,所以下面这个命令的意思是:完全忽略在C上面的从HEAD数到与B的common ancestor的位置的所有commit,楼主的情况就只有那个删除file.txt的commit,然后replay到origin/master上面,最终结果就是把B那个checkout回file.txt的commit合并回来了,丢掉已在C上面的删除file.txt的commit。
git rebase --onto origin/master HEAD~0 master
|
 |
|
9
undeadking Jun 8, 2014
在多人协作的情况下还用git push -f ,纯粹作死,会把其他人都害了的.
让远端回滚到强制push之前吧,冲突必须要解决,别想偷懒
|