当上游重写历史记录时,我怎样才能改变我所有的本地Git分支(和标签)?

时间:2011-07-12 00:14:48

标签: git git-rebase

特定(嵌入式)linux内核repo的维护者修改了一堆古老的提交以清理历史记录。因此,所有提交都有不同的SHA。

当我从这个重写的历史记录中获取git时,我需要将我的本地分支重新定位到本地跟踪分支入口点,该入口点对应于我自己的分支开始的本地树中的点。标准解决方案:

git rebase --onto SHAxx master ownbranch

(SHAxx对应于下图中的遥控器/ origin / master的c2。)

但是,当我有几个自己的分支在master中有一个单独的祖先时,我必须为每个分支应用一个rebase。相反,我想在一次操作中将所有带有任何关联标签的分支转移到获取的跟踪分支中的新入口点。

图形化,在获取之后,在任何操作之前的状态(简化 - 超越左侧是深度主历史记录):

    c1'--c2'--c3'--c4'--c5'--c6'--c7--c8--c9 remotes/origin/master
   /
--o--c1--c2--c3--c4--c5--c6 master
           \
            o---o---o---o---o  branch1
                     \
                      o---o  branch2 (etc.)

准确地说:当我自己的工作从主提交c2开始时,我想将我自己的子树及其所有标签(如果存在)在一个动作中重新绑定到遥控器/ origin / master的c2'上(与其不同的SHA进行比较)掌握c2)。

当时我可以完全删除master并使用我自己的工作制作遥控器/ origin /掌握新的主人:

    c1--c2--c3--c4--c5--c6  (old master, not referenced anymore)
   /
--o--c1'--c2'--c3'--c4'--c5'--c6'--c7--c8--c9 master = remotes/origin/master
            \
             o---o---o---o---o  branch1
                      \
                       o---o  branch2 (etc.)

然后我将测试构建过程是否产生与之前相同的结果,如果确定:继续将合并的主更新递增(例如,每个子索引在2.6.nn中的步骤)到我自己的(特定于板)分支中。

还是有其他/更好的方法来实现相同的结果吗?

可能的解决方案显示在Rebasing a branch including all its children,但标签不会移动。

2 个答案:

答案 0 :(得分:3)

下面,介绍了一系列使用相对较新的git replace命令的步骤。使用此命令而不是rebase --onto ...,不会出现由于自己与master合并而产生的麻烦 - 可能需要解决冲突的合并,因为rebase实际上''重放''提交。

备注:最好克隆重写历史记录的远程仓库并在此处插入您自己的分支,而不是像往常一样将此远程仓库提取到您的本地仓库中,然后重新绑定您自己的分支。主要优点:当在重写的仓库中删除或重命名时,任何不属于您自己的旧东西都不会出现在新克隆的仓库中。将重写的repo提取到本地仓库时,在新历史记录中重命名的分支将导致进一步存在旧命名的分支。

建议程序

  • 使用重写的历史记录克隆远程仓库,可能只是与您的工作相关的分支 - 这有助于检查下一步操作。
  • 指定remote add tmp,指定当前本地仓库的路径。
  • 本地仓库中的
  • :在分支的起点(与主人共享的点)添加标签(例如 ownstart )。
  • 从此tmp遥控器(某些git fetch tmp <branch>:<branch>)获取您自己的分支。 很多(重复的)提交与分支主机并行可能会出现在标签ownstart下面。这将在下一步之后消失;或者,您可以通过移植物和移植物在您自己的分支标签上创建一个新根。在执行获取之前git filter-branch。
  • 寻找新的相应起点,其中ownstart在重写的历史记录中具有等效的提交,并按如下方式应用其SHA:git replace ownstart SHA。这将创建所有本地作品的虚假连接,从此点到新历史记录中的相应条目,并让其余的历史记录“在' ownstart 下面消失,因为引用失败。

注1 :这些操作之后的任何日志都应该已经显示了所需的提交链(例如,使用gitk)。然而,被替换的提交没有融合在一起:它们仍然是分开的,现在与重写的历史有共同的祖先。这是设计所固有的,不会影响您自己工作的(正确)整体整合。可以(甚至建议 - 参见注释2)通过执行git filter-branch -- --master..ownstart --all来删除这些双打(这可能非常耗时)。它将改变您所有工作的SHA,但上游提交链不受影响。 git filter-branch操作会创建备份分支。 filter-branch联机帮助页的尾部建议克隆操作以获取没有这些备份的新回购(在本地克隆时使用--no-hardlinks)。但是,这会在分配另一个上游原点的同时转换所有自己的分支跟踪遥控器。

注意2 :在执行了测试序列后,我自己的分支(来自abitrary主提交)中的某个提交的任何合并都会自动重新链接到相应的重写历史提交之后执行了git filter-branch命令,如上所述。太棒了。然而,在另一个测试中,这个合并已经“消失”了。它可以通过发出带有SHA的git replace命令绑定到重写的历史记录,其中合并的主端父级等于主分支的适当提交。然后必须重复git-filter-branch

答案 1 :(得分:1)

是的,这是可能的。当您执行git log时,您应该看到2个具有相同日期时间和用户的提交--all --describe。您可以制作一个脚本,将所有分支逐个重置到新位置。

使用标签,您可以删除并重新创建

希望这有帮助