How do I recover/resynchronise after someone pushes a rebase or a reset to a published branch?
我们都听说过,一个人不应该把已发表的作品重新编好,这很危险,等等。但是,我没有看到任何关于如何处理这种情况的食谱,以防重新编好的作品被出版。
现在,请注意,只有当存储库仅由已知(最好是较小的)人员组克隆时,这才真正可行,这样,无论谁推动了REBASE或RESET,都可以通知其他人,他们下次获取时都需要注意!!).
如果您在
1 2 3 | git fetch git checkout foo git reset --hard origin/foo |
根据远程存储库,这只会简单地放弃本地的
但是,如果在该分支机构上进行了实质性的本地更改,如何处理这种情况呢?
在大多数情况下,在推压钢筋后恢复同步并没有那么复杂。
1 2 3 4 5 | git checkout foo git branch old-foo origin/foo # BEFORE fetching!! git fetch git rebase --onto origin/foo old-foo foo git branch -D old-foo |
例如,首先为远程分支原来所在的位置设置一个书签,然后使用该书签将本地提交从该点开始重放到重新平衡的远程分支上。
重新平衡就像暴力:如果它不能解决你的问题,你只需要更多。?
当然,如果您查找pre-rebase
这也是处理提取前忘记制作书签的情况的方法。不会丢失任何内容–您只需检查远程分支的reflog:
1 2 3 | git reflog show origin/foo | awk ' PRINT_NEXT==1 { print $1; exit } /fetch: forced-update/ { PRINT_NEXT=1 }' |
号
这将打印
你可以简单地
1 | git rebase --onto origin/foo $commit foo |
我想说,Git Rebase手册页的"从上游恢复钢筋"部分几乎涵盖了所有这些内容。
这和从自己的重新平衡中恢复没有什么不同——你移动一个分支,然后将历史上所有拥有它的分支重新平衡到它的新位置。
从2014年第1季度的git 1.9/2.0开始,您不必在重写的上游分支上重新标记以前的分支来源,如亚里士多德·帕戈尔茨兹的回答所述:请参见提交07D406B和提交D96855F:
After working on the
topic branch created withgit checkout -b topic origin/master , the history of remote-tracking branchorigin/master may have been rewound and rebuilt, leading to a history of this shape:
号
1 2 3 4 5 6 7 | o---B1 / ---o---o---B2--o---o---o---B (origin/master) \ B3 \ Derived (topic) |
。
where
origin/master used to point at commitsB3 ,B2 ,B1 and now it points atB , and yourtopic branch was started on top of it back whenorigin/master was atB3 .This mode uses the reflog of
origin/master to findB3 as the fork point, so that thetopic can be rebased on top of the updatedorigin/master by:
号
1 2 | $ fork_point=$(git merge-base --fork-point origin/master topic) $ git rebase --onto origin/master $fork_point topic |
这就是为什么
1 | --fork-point:: |
。
Find the point at which a branch (or any history that leads to
) forked from another branch (or any reference) .
This does not just look for the common ancestor of the two commits, but also takes into account the reflog ofto see if the history leading to forked from an earlier incarnation of the branch .
号
The"
git pull --rebase " command computes the fork point of the branch being rebased using the reflog entries of the"base " branch (typically a remote-tracking branch) the branch's work was based on, in order to cope with the case in which the"base" branch has been rewound and rebuilt.
号
例如,如果历史看起来像:
- the current tip of the"
base " branch is atB , but earlier fetch observed that its tip used to beB3 and thenB2 and thenB1
before getting to the current commit, and- the branch being rebased on top of the latest"base" is based on commit
B3 ,it tries to find
B3 by going through the output of"git rev-list --reflog base " (i.e.B ,B1 ,B2 ,B3 ) until it finds a commit that is an ancestor of the current tip"Derived (topic) ".Internally, we have
get_merge_bases_many() that can compute this with one-go.
We would want a merge-base betweenDerived and a fictitious merge commit that would result by merging all the historical tips of"base (origin/master) ".
When such a commit exist, we should get a single result, which exactly match one of the reflog entries of"base ".
号
Git 2.1(2014年第3季度)将使此功能更加强大:请参阅Commit 1e0dacd by John Keeping(
正确处理具有以下拓扑的场景:
1 2 3 4 5 | C --- D --- E <- dev / B <- master@{1} / o --- B' --- C* --- D* <- master |
。
哪里:
B' 是B 的固定版本,与B 不完全相同;C* 和D* 是分别与C 和D 相同的补丁,存在冲突。如果按错误的顺序应用,则为文本;E 在文本上取决于D 。
1 | o --- B' --- C* --- D* --- E <- dev |
如果分叉点未被识别,则在包含