Git 分支被撕成 2 个具有单独名称的部分。如何在 1 个分支中将它们缝合在一起?

Git branch is torn in 2 parts having individual names. How to sew them together in 1 branch?

这是我的本地 Git 存储库的结构。可以看到,分支 masterremotes/tpt3/master 之间存在不连续性间隙。但是必须只有 1 个连续分支,这样 master 的提交应该在 remotes/tpt3/master 的最后一次提交之后进行,并且只有 1 个分支必须包含所有这些提交。 当我尝试使用命令时:

$git rebase --onto remotes/tpt3/master master

导致如下错误结果。 首先,master应该在remotes/tpt3/master之后。 其次,master 的提交在某处消失了。

您能告诉我应该使用哪个 Git 命令从 masterremotes/tpt3/master 中创建 1 个连续分支吗?

最重要的是:您将在此处使用的命令是:

git add              # insert arguments as needed here
git commit
git replace --graft master~2 tpt3/master

(在此处检查结果以确保一切正常)

git filter-branch -- master

(再检查结果)

git for-each-ref --format="%(refname)" refs/original | xargs git update-ref -d

(再次检查),并且:

git reset HEAD~

master 中删除 F' 提交(见下文),然后 git push tpt3 master

在做任何事情之前请仔细阅读以下内容,并考虑在开始之前备份您的存储库!


旁注:gitk 是一个有用的(虽然不是很好)提交 viewer 但是 gitk 图片对于 Whosebug 上的问题来说很糟糕。我在这里重新输入了第一张图片中的一些关键位,尽管我可能插入了任意数量的印刷错误:

- Local uncommitted changes, not checked in to index
* (master) Commit 22.10.21. Just verified Fe-Fe nuc...
* Initial commit.t Np=100100000 TITAN YEILD COUNT=9...

* (remotes/tpt3/master) After quarantine. STEP #29
* After Quarantine. STEP #28
* After Quarantine. STEP #27

这表示在两个单独的(不相交的)DAG 中总共有五个提交。两个图中的每一个都包含以线性方式排列的两个或三个提交。 (注意:第二张图片显示第一张图片是谎言,所以买者自负:我是在骗人。你需要用你自己的大脑来处理以下内容。 )

如果我们为每个提交分配字母代码,并且如果我们将未提交的工作变成当前分支上的第三次提交,我们将得到:

F: Local uncommitted changes, not checked in to index
E: (master) Commit 22.10.21. Just verified Fe-Fe nuc...
D: Initial commit.t Np=100100000 TITAN YEIDL COUNT=9...

C: (remotes/tpt3/master) After quarantine. STEP #29
B: After Quarantine. STEP #28
A: After Quarantine. STEP #27

两个提交图是:

A <-B <-C   <-- remotes/tpt3/master

D <-E <-F   <-- master

您似乎想要:

A <-B <-C   <-- remotes/tpt3/master
         \
          D <-E <-F   <-- master

你不能相当得到这个因为提交DE已经存在因此不能改变,但是它们可以 复制 到新的改进提交,否则它们分别与 DE 非常相似。 (提交 F 实际上还不存在,但你需要创建它,以保存工作树的内容,除非你在单独的克隆或添加的工作树中完成所有工作,这两者都不多好处:只需提交 F 然后我们将以与 DE 相同的方式复制它。然后您可以启动提交 F'——复制——关闭使用 git reset.)

您可以几乎,但不完全是,使用git rebase 进行新的改进提交。您已经尝试过了,但使用了错误的命令:

$git rebase --onto remotes/tpt3/master master

git rebase 所做的可以被认为是(并且取决于您的 Git 版本,现在 ,或者近似)重复 cherry-picking.每个 cherry-pick 操作复制一个提交。这个过程的关键部分是:

  1. git rebase 必须列出所有要复制的提交。这就是你不正确的论点现在正在咬你的地方,因为 。 运行 git rebase --onto remotes/tpt3/master 要求您然后列出哪些提交 不从当前分支复制 ;你说 不要复制任何提交,包括 master 上的最新提交,这会导致复制 no 提交。通过使用 git rebase remotes/tpt3/master 来解决这个问题将尝试 cherry-pick(复制)所有 master 分支提交,这更接近您想要的。由于下面的第 3 步,它仍然无法正常工作。

  2. rebase 代码现在执行 detached HEAD 样式检查或切换到目标(--onto 或其他指定)提交。在这种情况下,您想使用 remotes/tpt3/master 提交,After quarantine. STEP #29.

  3. rebase 代码现在重复 运行s git cherry-pick 或等效代码。每个 cherry-pick 将提交变成 change-set,然后将 change-set 复制到当前提交之上并提交结果。对于三个 to-be-copied 提交中的两个 EF,这是正确的操作。但是,commit D 没有 parent,因此 cherry-pick 将简单地将每个文件 in commit D 视为 added-from-scratch .这很可能会造成一大堆 add/add 冲突:每个“复制”步骤实际上是一个 three-way 合并,而这个合并很可能在这里出错。

  4. 最后,复制了所有提交,git rebase wrests 你所在的分支的分支名称 before 步骤 2所以它现在指向 current 提交,这是 last-copied 提交或者 - 在你复制 no 提交的情况下 -提交 Git 在步骤 2 中签出。

解决这个特定问题的方法——第 3 步将每个提交都视为 add/add conflict-is 可能 以使用 git replace 来做一个嫁接,让Git假装提交D有提交C作为parent。移植物就位后,您将:

A--B--C   <-- remotes/tpt3/master
       :
        D--E--F   <-- master

这种模糊的假装 link 不会 完全 完成工作,但使用 git filter-branchthe new git filter-repo 可以“巩固”通过用新的提交 D'E'F' 替换提交 DEF 来将图形放置到位——除了因为它们本身具有不同的哈希 ID1 并分别返回 CD'E'——否则与 D 相同、EF:它们具有相同的快照,并且基本相同的元数据阿塔也就是说,post-filter-branch / filter-repo,你现在有:

A--B--C   <-- remotes/tpt3/master
       \
        D'-E'-F'  <-- master

这就是你想要的。您现在可以 运行 git push tpt3 master 安全;这将添加三个提交。

由于您可能只需要两次提交加上未提交的更改,我们现在可以使用 git reset 将提交 F' 关闭 master。请注意,提交 F' 继续存在于您的存储库中(提交 D-E-F 也是如此)一段时间,但是没有简单的方法 找到 提交,您赢了看不到他们。就好像它们从未存在过一样。最终——在 30 天或更长时间后——Git 会注意到它们没有被使用并真正丢弃它们。

所以,此时你只需 运行:

git reset HEAD~

告诉Git:

  1. 将当前分支名称后移一位;
  2. 也重置其索引,但保持工作树不变。

您现在将拥有:

A--B--C   <-- remotes/tpt3/master
       \
        D'-E'  <-- master

未提交的工作,如您所愿。


1由于提交哈希 ID 提交的真实名称,这例如,意味着 D'D 完全不同。 Git 对它们具有相同的快照和大部分相同的元数据这一事实不感兴趣——至少在这个级别不感兴趣——因为 Git 只关心 哈希 ID 这个级别。所以这有点像那个老笑话,"Other than that, Mrs Lincoln, how was the play?"——除了在这种情况下,安倍已经被一个没有人(除了林肯夫人)可以检测到的克隆人所取代。