gpt4 book ai didi

git - 使两个分支相同

转载 作者:行者123 更新时间:2023-12-02 07:06:32 25 4
gpt4 key购买 nike

我有两个分支——A 和 B。B 是从 A 创建的。

两个分支的工作并行进行。在分支 A 上的工作很糟糕(导致无法工作的版本),而在分支 B 上的工作很好。在此期间,分支 B 有时会 merge 到分支 A(但不是相反)。

现在我想让分支 A 与分支 B 相同。我不能使用 git revert,因为我需要还原太多提交 - 我只想还原在分支 A 上完成的提交,但不是 merge 分支 B 的结果.

我找到的解决方案是将分支 B 克隆到另一个文件夹中,从分支 A 的工作文件夹中删除所有文件,从临时分支 B 文件夹中复制文件并添加所有未跟踪的文件。

是否有执行相同操作的 git 命令?我错过了一些 git revert 开关?

最佳答案

有很多方法可以做到这一点,你应该使用哪一种取决于你想要什么结果,特别是你和任何与你合作的人(如果这是一个共享存储库)希望在 future 看到什么。
执行此操作的三种主要方法:

  • 别打扰。放弃分支 A ,创建一个新的 A2 ,然后使用它。
  • 使用 git reset 或等效于将 A 重新指向别处。
    从长远来看,方法 1 和 2 实际上是相同的。例如,假设您从放弃 A 开始。每个人都在 A2 上开发一段时间。然后,一旦每个人都在使用 A2 ,就完全删除名称 A 。现在 A 消失了,您甚至可以将 A2 重命名为 A(当然,其他使用它的人都必须进行相同的重命名)。在这一点上,使用方法 1 的情况和使用方法 2 的情况有什么不同? (有一个地方您可能仍然可以看到差异,这取决于您的“长期运行”有多长以及旧的 reflog 何时过期。)
  • 使用特殊策略进行 merge (参见下面的“替代 merge 策略”)。你想要的是 -s theirs ,但它是 doesn't exist ,你必须伪造它。

  • 旁注:从哪里“创建”分支基本上是无关紧要的:git 不跟踪这些事情,一般来说以后不可能发现它,所以它对你来说也可能无关紧要。 (如果它真的对你很重要,你可以对你如何操作分支施加一些限制,或者用标签标记它的“起点”,以便你以后可以机械地恢复这些信息。但这通常表明你一开始就做错了——或者至少,期待一些 git 没有提供的东西。另见下面的脚注 1。)
    分支的定义(另见 What exactly do we mean by branch? )
    git 中的一个分支——或者更准确地说,一个分支名称——只是一个指向提交图中某个特定提交的指针。其他引用(如标记名称)也是如此。例如,与标记相比,分支的特殊之处在于,当您在分支上并进行新提交时,git 会自动更新分支名称,以便它现在指向新的提交。
    例如,假设我们有一个看起来像这样的提交图,其中 o 节点(以及标记为 * 的节点)代表提交, A 和 0x2518122413 是分支
    o <- * <- o <- o <- o <- o   <-- A
    \
    o <- o <- o <-- B
    BA 分别指向分支的最顶端提交,或者更准确地说,通过从某个提交开始并返回所有可到达的提交而形成的分支数据结构,每个提交都指向某个父提交。
    如果您使用 B 以便您位于分支 git checkout B 上,并进行新提交,则新提交将使用前一个提示 B 作为其(单个分支)父级,并且 git 名称下存储的 5x2133143 更改了 B 指向新的最尖端提交:
    o <- * <- o <- o <- o <- o   <-- A
    \
    o <- o <- o <- o <-- B
    标记为 B 的提交是两个分支提示的 merge 基础。此提交以及所有较早的提交都在两个分支上。1 merge 基础对于 merge (duh :-) )很重要,但对于 B 和其他发布管理类型的操作也很重要。
    您提到分支 * 偶尔会 merge 回 git cherry :
    git checkout A; git merge B
    这会生成一个新的 merge 提交,这是一个具有 two2 父项的提交。第一个父级是当前分支的前一个提示,即 B 的前一个提示,第二个父级是命名提交,即分支 A 的最尖端提交。更紧凑地重绘上面的内容(但添加更多 A 使 B 更好地排列),我们开始:
    o--*--o--o--o--o      <-- A
    \
    o---o--o---o <-- B
    并最终得到:
    o--*--o--o--o--o--o   <-- A
    \ /
    o---o--o---* <-- B
    我们将 - 移动到新的 merge 基 o* (实际上是 A 的尖端)。大概我们然后向 B 添加更多提交,并可能再 merge 几次:
    ...---o--...--o--o    <-- A
    / /
    ...-o--...--*--o--o <-- B
    git 默认使用 B 做什么
    要进行 merge ,您需要检查一些分支(在这些情况下为 B),然后运行 ​​ git merge <thing> 并至少给它一个参数,通常是另一个分支名称,如 A 。 merge 命令首先将名称转换为提交 ID。分支名称变成分支上最尖端提交的 ID。
    接下来, git merge 找到 merge 基。这些是我们一直用 B 标记的提交。 merge 基础的技术定义是提交图中的最低公共(public)祖先(在某些情况下可能不止一个),但为了简单起见,我们将在这里使用“标记为 git merge 的提交”。
    最后,对于普通 merge ,git 运行两个 * 命令。3 第一个 * 将提交 git diffgit diff 进行比较,即当前分支的提交。第二个差异比较提交 * 与参数提交,即另一个分支的提示(你可以命名一个特定的提交,它不需要是分支的提示,但在我们的例子中,我们将 HEAD merge 到 0x2518131241获取这两个分支提示提交)。
    当 git 发现一些文件被修改时,与 merge 基础版本相比,在两个分支中,git 尝试以半智能(但不是真正智能)的方式组合这些更改:如果两个更改都将相同的文本添加到同一区域, git 保留一份添加的副本。如果两个更改都删除了同一区域中的相同文本,则 git 只会删除该文本一次。如果两个更改都修改了同一区域中的文本,则会发生冲突,除非修改完全匹配(然后您将获得一份修改副本)。如果一侧进行了一项更改而另一侧进行了不同的更改,但这些更改似乎没有重叠,则 git 会同时进行这两项更改。这就是三路 merge 的本质。
    最后,假设一切顺利,git 会进行一个新的提交,该提交有两个(或更多,正如我们在脚注 2 中已经指出的那样)。与这个新提交相关的工作树是 git 在进行三向 merge 时提出的。
    替代 merge 策略
    虽然 * 的默认 B 策略有 A 选项 git merge 和 0x251812241313141 我们不想要的。这些只是说在发生冲突的情况下,git 应该通过选择“我们的更改”( recursive)或“他们的更改”( -X)来自动解决该冲突。 ours 命令完全有另一种策略, theirs :这个策略说,不要将 merge 基础与两个提交进行比较,只需使用我们的源树。换句话说,如果我们在分支 -X ours 上运行 -X theirs ,git 将进行新的 merge 提交,第二个父项是分支 merge 的尖端,但源树尖端与 .81231413413413413131351313513135131351313513135135135135135135135135135135135143513513513513513512512512512512512512512512512222231231231312313123123123123123143123143123141223141222314122314122313141 分支相匹配。也就是说,新提交的代码将与其父提交的代码完全匹配。
    this other answer 中所述,有多种方法可以强制 git 有效地实现 -s ours 。我认为最简单的解释是这个序列:
    git checkout A
    git merge --no-commit -s ours B
    git rm -rf . # make sure you are at the top level!
    git checkout B -- .
    git commit
    第一步是确保我们像往常一样位于分支 A 上。第二个是启动 merge ,但避免提交结果( git merge -s ours B)。为了使 git 的 merge 更容易——这不是必需的,它只是让事情更快更安静——我们使用 B 以便 git 可以完全跳过差异步骤,我们避免所有 merge 冲突的投诉。
    在这一点上,我们得到了诀窍。首先我们删除整个 merge 结果,因为它实际上毫无值(value):我们不想要来自 A 的提示提交的工作树,而是来自 -s theirs 的提示的工作树。然后我们从 A 的尖端检查每个文件,使其准备好提交。
    最后,我们提交新的 merge ,它的第一个父级是 --no-commit 的旧尖端,第二个父级是 -s ours 的尖端,但具有来自提交 A 的树。
    如果提交之前的图表是:
    ...---o--...--o--o    <-- A
    / /
    ...-o--...--*--o--o <-- B
    那么新图现在是:
    ...---o--...--o--o--o   <-- A
    / / /
    ...-o--...--o--o--* <-- B
    新的 merge 基点和往常一样是 B 的尖端,从提交图的角度来看,这个 merge 看起来和任何其他 merge 完全一样。不寻常的是 B 尖端的新 merge 的源树与 A 尖端的源树完全匹配。

    1在这种特殊情况下,由于两个分支一直保持独立(从未 merge ),因此这也可能是创建两个分支之一(甚至两个分支都创建的地方)的点,尽管您无法证明这一点点(因为过去有人可能使用 B 或其他各种技巧来移动分支标签)。然而,一旦我们开始 merge , merge 基地显然不再是起点,一个合理的起点变得更加难以定位。
    2从技术上讲, merge 提交是具有两个或多个父项的任何提交。 Git 调用与两个以上父级 merge 的“ Octopus merge ”。根据我的经验,除了在 git 本身的 git 存储库中,它们并不常见,最终,它们实现了与多个普通双父 merge 相同的事情。
    3差异通常在某种程度上在内部完成,而不是运行实际命令。这允许许多快捷优化。这也意味着如果您编写自定义 merge 驱动程序,除非 git 发现文件在两个差异中都被修改,否则不会运行该自定义 merge 驱动程序。如果它仅在两个差异之一中进行了修改,则默认 merge 仅采用修改后的一个。

    关于git - 使两个分支相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36320517/

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