gpt4 book ai didi

git - 有没有一种方法可以与策略“我们的” merge 而不产生新的提交?

转载 作者:行者123 更新时间:2023-12-04 14:26:56 25 4
gpt4 key购买 nike

我需要做的是关闭一个分支,并使另一个分支的尖端(最后一次提交)看起来像与该分支合并,而无需实际更改其内容。我试过了

git merge -s ours other_branch --squash


但是什么也没发生(在我阅读 what squash actually does之后才有意义)

即在命令之前

  * other_branch
/
*---* HEAD


命令后的预期结果

  * other_branch
/ \
*---* HEAD


注意:这里所说的内容是指提交的东西:元数据会随着我要实现的操作实际上是在提交中添加一个父对象而发生变化;我知道这正在改变历史,至少会影响阴影。

最佳答案

PetSerAl's comment具有(可以使用)命令(或至少是“ a”)来实现所需的功能。唯一缺少的是对原因的解释:

git reset --soft $(git log --format=%B -n 1 | \
git commit-tree HEAD^{tree} -p HEAD^ -p other_branch)


作品。我会讲一点,但首先...

字面答案

但是,所询问的问题的字面上答案是“否”。由于可以删除主题行,因此我引用它:


有没有一种方法可以与策略“我们的”合并而不产生新的提交?


在Git中,“合并”一词可指两件事:合并的行为或先前合并行为的结果。其中第一个是动词,用于合并;第二个是形容词,合并提交,或者甚至是名词,合并。合并提交是两个父母(或更多,但我们只真正关心两个)的一次提交。

运行 git merge --squash告诉Git执行合并(即,做动词部分),但是最后,在进行新提交时,进行普通的非合并提交,即,抑制形容词合并效果。这样做的重点是,当您有一系列提交时,例如,“分支”的含义不只是“指向特定提交的名称”(请参见 What exactly do we mean by "branch"?

运行 git merge -s ours告诉Git执行伪造的合并动作(即,假装做一个动词合并,但实际上什么也没做),结果是合并一个形容词/名词提交。由于动词形式不存在,因此剩下的唯一内容就是后效应。这就是为什么在这里使用 --squash没用的原因:您建议同时消除动词和名词,而且一无所有。



1出于特殊原因, git merge --squash也具有设置 --no-commit参数的副作用,因此您必须在最后手动运行 git commit。请注意,也可以使用 --no-commit运行真正的合并(进行合并提交),这也使您可以手动运行 git commit。否则它可能由于冲突而停止,您必须解决该冲突,从而使您手动完成提交。最新版本的Git已添加 git merge --continue,以使您感觉不太尴尬,但它仅运行 git commit



Git有 --amend,但不能完全达到目标

该图显示了您想要的内容(例如,如果Git支持的话,可能会拼写为 git commit --amend --add-parent),但不会产生关键的洞察力,实际上, git commit --amend只是一个很小的谎言,或者可能是巨大的谎言,例如它不会更改提交,而只是使用不寻常的父哈希进行新的提交。

正常的 git commit流程执行一堆步骤,就像它们一次完成一样,因此它们要么全部正确完成,要么什么都没有发生(或者至少看起来没有发生)。这些步骤是:


获取当前提交的哈希ID( git rev-parse HEAD)。称为P:现有的 HEAD将是新提交的父级。 (如果要完成合并,则 MERGE_HEAD也将存在,并且 git commit会读取它以获取更多的父对象。不过,这只是为了完成合并。)
编写当前索引以创建一个 tree对象( git write-tree)。将此称为树哈希ID。 (这可能与先前的某些提交不是同一棵树。)
获取您的姓名和电子邮件地址以及当前时间作为提交者。通常,也将它们用作作者(您可以覆盖它们)。
获取提交消息。
用所有这些信息(在步骤3中获得的 tree T, parent P, authorcommitter)写出新的提交,并在步骤4中获得提交消息。结果是新的提交哈希C 。
将新的哈希C写入当前的分支名称,以便 git rev-parse HEAD现在生成C。


使用 git commit --amend可以在步骤1处更改过程:Git读取当前提交的父哈希(而不是将 HEAD作为父提交)(如果您要进行 --amend合并,则可能有多个)。 ,并在步骤5中使用它们。

效果是将当前提交搁置一旁:

...--o--o--*   <-- master (HEAD)


变成:

          *   [the commit that was HEAD before]
/
...--o--o--@ <-- master (HEAD)


您想让Git做些什么。

为什么(以及如何)shell命令起作用

Git的 commit-tree命令产生新的提交对象。就像上面的六步提交序列的第5步。但是它还没有树,也没有准备好预先计算的父提交哈希,因此将其作为命令行参数:

git commit-tree tree-hash -p parent-hash-1 -p parent-hash-2

在这种情况下。我们想要的 tree-hashgit merge -s ours一样,是当前提交的同一棵树。我们可以使用 HEAD^{tree}为该树命名,这在 the gitrevisions documentation中进行了描述。我们要从当前提交的父级开始的两个父级哈希。 (我们可以假设只有一个这样的父级。)再次,gitrevisions语法为我们提供了一种编写方法:我们可以使用 parent^1parent~1,或者从任何一个表达式中省略 1。我们想要的另一个父哈希是 other_branch指向的提交,因此我们可以将其命名。这给了我们:

git commit-tree HEAD^{tree} -p HEAD^ -p other_branch


该命令从其标准输入中读取提交消息。如果要保留当前提交中的提交消息,可以使用 git log提取该消息: --format=%B告诉 git log通过将其主题和正文打印为文本来显示每个提交,而 -n 1告诉< cc>仅显示一次提交。默认情况下, git log提交的第一个提交是 git log提交。因此,这给了我们:

git log --format=%B -n 1 |


部分-我们将 HEAD的标准输出传递给 git log的标准输入。

提交后, git commit-tree要做的是将其哈希ID打印到其自己的标准输出中。因此,如果我们仅自己运行该管道,就会看到打印了新的提交哈希,但不会将其存储在任何地方。我们需要做的是更改当前分支名称(无论是什么名称)以指向新的提交。并且 git commit-tree会这样做,因此:

git reset --soft $(...)


git reset --soft commit-hash构造是最后一位:shell认为这意味着运行给定命令,捕获其标准输出,然后将该标准输出文本视为 $(...)的命令参数。由于只有一个输出字(新提交的哈希),因此它将在新提交ID上运行 git reset --soft

关于git - 有没有一种方法可以与策略“我们的” merge 而不产生新的提交?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48560351/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com