在有人将基准或重置推送到已发布的分支后,如何恢复/重新同步?

问题描述 投票:86回答:3

[我们都听说过,切勿为已发布的工作重新定级,这很危险,等等。但是,如果重新发布is,我还没有看到有关如何处理这种情况的任何方法。

现在,请注意,仅当存储库仅由已知的(最好是少数)人员克隆时,这才真正可行,因此,推动重新设置或重置的人员可以通知其他所有人,接下来他们将需要注意他们提取(!)的时间。

如果您在foo上没有本地提交,并且得到重新设置,我见过的一个显而易见的解决方案将起作用:

git fetch
git checkout foo
git reset --hard origin/foo

这将根据远程存储库简单地丢弃foo的本地状态,以支持其历史记录。

但是,如果有人对该分支机构进行了实质性的本地变更,该人如何处理?

git rebase git-rebase git-reset
3个回答
75
投票

在大多数情况下,重推基础之后恢复同步实际上并不那么复杂。

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

即首先,您要为远程分支的原始位置设置一个书签,然后使用该书签将您从该点开始的本地提交重播到重新建立基础的远程分支上。

重装就像暴力:如果不能解决您的问题,您只需要更多。 ☺

当然,如果您查找重新基准化前的origin/foo提交ID,并使用它,当然也可以不使用书签。

这也是您处理忘记制作书签[[之前的情况。没有任何损失–您只需要检查远程分支的引用日志:

git reflog show origin/foo | awk ' PRINT_NEXT==1 { print $1; exit } /fetch: forced-update/ { PRINT_NEXT=1 }'
这将在最近一次更改其历史记录的获取之前打印origin/foo指向的提交ID。

您可以然后简单地

git rebase --onto origin/foo $commit foo


11
投票
我想说git-rebase手册页的recovering from upstream rebase部分几乎涵盖了所有这些。

与从自己的基准库中恢复实际上没有什么不同-您移动一个分支,并将其历史记录中的所有分支基准都重新建立到新位置。


11
投票
[从git 1.9 / 2.0 Q1 2014开始,您无需标记先前的分支原点,就可以将其基于重新编写的上游分支,如Aristotle Pagaltzisanswer中所述:参见commit 07d406bcommit d96855f

[使用topic创建的git checkout -b topic origin/master分支后,可能已经重绕并重建了远程跟踪分支origin/master的历史,从而导致了这种形状的历史:

o---B1 / ---o---o---B2--o---o---o---B (origin/master) \ B3 \ Derived (topic)

其中origin/master过去指向提交B3B2B1,现在它指向B,并且当topic处于以下位置时,您的origin/master分支从其顶部开始B3

此模式使用origin/master的引用日志找到B3作为分支点,因此topic可以在更新的origin/master之上重新建立基础:]

$ fork_point=$(git merge-base --fork-point origin/master topic) $ git rebase --onto origin/master $fork_point topic
这就是git merge-base命令具有新选项的原因:

git merge-base

找到分支(或导致--fork-point:: 的任何历史记录)从另一个分支(或任何参考)<commit>分叉的点。这不仅查找两个提交的共同祖先,而且

还考虑了<ref>的引用日志,以查看导致<ref>的历史是否是从分支<commit>的早期版本中派生的。 。


“ [<ref>”命令使用该分支工作所基于的“ git pull --rebase”分支(通常是远程跟踪分支)的reflog条目来计算要重新建立分支的分支点。撤消并重建“基础”分支的情况。

例如,如果历史记录看起来像在哪里:

    base”分支的当前尖端位于base,但较早的提取发现它的尖端曾经是B,然后是B3,然后是B2在进入当前提交之前,然后
  • 基于最新“基础”重新分支的分支基于提交B1
  • 它尝试通过遍历“ B3”(即B3git rev-list --reflog baseBB1)的输出来查找B2,直到找到作为当前祖先的提交为止提示“ B3”。
  • 内部,Derived (topic)可以一次计算。我们想要get_merge_bases_many()与虚拟合并提交之间的合并基础,该合并提交将合并所有[Derived]的历史提示。当存在这样的提交时,我们应该得到一个单一的结果,该结果与“ base (origin/master)”的引用条目之一完全匹配。


    Git 2.1(2014年第3季度)将对此功能进行增强:请参见base by commit 1e0dacd

    正确处理具有以下拓扑的方案:

    John Keeping (johnkeeping)

    其中:

      [johnkeeping C --- D --- E <- dev / B <- master@{1} / o --- B' --- C* --- D* <- master 的固定版本,与B'补丁不相同;
    • [BB分别与C*D*修补相同,并且冲突如果以错误的顺序应用,则按文本;
  • [C从文字上取决于D
  • E的正确结果是D被标识为git rebase master devB的分叉点,因此devmasterC是需要提交的提交回放到D上;但是EmasterCD的补丁相同,因此可以将其删除,因此最终结果是:
  • C*

    [如果未识别出分叉点,则将D*拾取到包含o --- B' --- C* --- D* --- E  <- dev
    的分支上会导致冲突,如果未正确识别补丁相同的提交,则将B拾取到包含B'的分支上(或等价C)会导致冲突。


    当在2.20年代用C重写命令时,“ [D”的“ D*”模式已退回,并已通过Git 2.27(2020年第二季度)更正。”>

    请参阅--fork-pointgit rebase(2019年12月9日)。

    [(由commit f08132fJunio C Hamano (gitster)中合并,2020年3月27日)>

    [gitsterJunio C Hamano -- gitster --回归修复

    签名人:Alex Torok[jc:修改了补丁,并使用了Alex的测试]签字人:Junio C Hamano

    gitster”过去工作正常,因为它内部称为“ commit fb4175b”,它知道如何处理短refname,并在调用基础的rebase函数之前将其变为完整的refname。

    用C重写命令后,这不再是正确的,因为直接对rebase的内部调用不会忽略短引用。

    将在“ git merge-base”中使用的“ dwim refname参数移到完整的refname”逻辑到基础的--fork-point函数,以便在执行“ git rebase”时该函数的另一个调用者能够正常工作修复此回归的方法相同。

    © www.soinside.com 2019 - 2024. All rights reserved.