如何将父级添加到 git 中的提交?

How do I add a parent to a commit in git?

我最近重新分支 - 也就是说,在 master 之外创建了一个新分支并合并到一个功能分支中,例如TASK-123,新分支 TASK-123-b,替换了合并到其中的特性分支。每当功能分支与 master.

冲突时,这是我们 git 工作流程中的常规操作

当我将TASK-123合并到TASK-123-b时,当然有一个合并冲突,我已经解决并提交了。新分支 TASK-123-b 和合并到 TASK-123 的提交只有一个父分支:master

如何修改提交,使 masterTASK-123 都是它的父项?我假设 git rebase 会涉及,但除此之外我不知道如何将父 branch/commit 添加到提交中。

我的提交历史目前是这样的:

    master -*---*-----* ...
             \         \
  TASK-123    *---*-*   \
                         \   
TASK-123-b                * ...

我希望我的提交历史看起来像这样:

    master -*---*-----* ...
             \         \
  TASK-123    *---*-*   \
                     \   \   
TASK-123-b            \---* ...

注意:我还没有将 TASK-123-b 推送到远程,因此对其进行变基提交应该不会给我的同事带来任何问题。

您需要重新将 TASK-123 合并到 TASK-123-b 中,因为它看起来不像您希望的那样工作。为此,在合并之前在 TASK-123-b 中找到提交哈希,并在那里重置分支指针:

$ git checkout -B TASK-123-b abc123

然后重复合并:

$ git merge TASK-123

如果您重置分支指针,旧的合并提交将被孤立并且不会显示在日志中,除非您特别将其作为参数提及。如果你想找回它,散列将被记录在 reflog 中,或者你可以将散列复制到某个地方,然后在你决定需要时使用 checkout -B 命令将它放回原处。

如果不想再次解决冲突,那就不要重新设置分支指针,重新合并即可:

$ git checkout TASK-123-b
$ git merge TASK-123

并删除旧分支:

$ git branch -d TASK-123

为了便于解释,假设您的提交是这样标识的:

    master -a---c-----f-----h ...
             \         \
  TASK-123    b---d-e   \
                         \   
TASK-123-b                g---i ...

TL;DR

  1. Rebase,删除合并提交(提交g),并在合并前编辑提交(提交f)。

  2. 不要在 f 上执行 git commit --amend,而是执行 git merge e --no-commit.

  3. 使用git checkout g -- .检查提交g中的所有文件。

  4. 提交并继续变基进程。


详细解答

如果你的提交树可以这样表示:

First,在合并提交之前使用提交哈希第二次变基(合并提交是 g,因此将使用的提交哈希是 <commit-c-sha>)

$ git rebase --interactive <commit-c-sha>

这将生成如下待办事项列表:

pick <commit-f-sha>  <commit-f-message>   -----> change this to edit
pick <commit-g-sha>  <commit-g-message>   -----> remove this line
pick <commit-i-sha>  <commit-i-message>
...

因此您的待办事项列表将如下所示:

edit <commit-f-sha>  <commit-f-message>
pick <commit-i-sha>  <commit-i-message>
...

其次,创建一个没有提交的合并。

$ git merge <commit-e-sha> --no-commit

在这里,我们实际上不想编辑 提交f。相反,我们为提交 g 替换准备了一个提交。

这为我们提供了合并提交格式和在合并提交上做一些工作的灵活性(例如:修改文件、修改提交属性等)。

第三次,我们在不移动 HEAD.

的情况下检出了从提交 g 到当前索引的所有文件
$ git checkout <commit-g-sha> -- .

这确保提交的文件与提交的文件完全相同 g

第四,坚持改变并继续变基进程。例如:

$ git commit
$ git rebase --continue

您可以添加任何提交选项(但不要添加 --amend)或将其替换为 git commit-tree 命令。

在此之后,提交 g 将有两个父项,并且 g 之后的所有提交也都在后面。

    master -a---c-----f-----h ...
             \         \
  TASK-123    b---d-e   \
                     \   \   
TASK-123-b            \---g---i ... and all of the following commits

备注1:指定时间戳

当您进行提交时,git 默认情况下使用当前时间设置提交日期。如果要指定时间戳,可以检查 GIT_AUTHOR_DATE & GIT_COMMITTER_DATE 变量和 --date 选项

参考:https://git-scm.com/docs/git-commit#_date_formats


备注2:Commit-Tree(还没试过)

如果您想要一种更灵活的方式来指定提交父级,您可以执行 checkout 并使用 commit-tree 命令而不是 merge 创建提交-> checkout -> commit 模式。