Git从分支中减去推送的提交数

问题描述 投票:0回答:1

我在同一分支上为某个模块进行了一些代码的共同开发,而在同一分支上我也与同事的模块进行了集成。基本上,我最终使两个模块相互交谈时,同时修改了两个模块的代码。现在,我想将所有代码一起提交,但不希望从分支中合并内容。

  • 假设我的模块是“ Apple”,是在A分支上开发的
  • 我的同事的代码是在分支B上开发的“香蕉”
  • 我想在分支C中集成“鸡尾酒”

所以基本上,我在A上进行了开发,从B挑选了我想要的更改,并且已经进行了测试。现在,我想分开提交,以便分支A仅包含“ Apple”,分支B仅包含“ Banana”,而分支C包含集成代码。我不想重命名分支,因此我已经通过cherry-pick将所有更改从分支A复制到了C。另外,我已经挑选了从分支A到B的相关更改。

现在剩下要做的就是从分支A中减去提交,这样就只剩下“ Apple”了。我正在寻找做到这一点的最佳方法。我不相信git revert是正确的选择,而且我想我可以做一个交互式的变基并删除不需要的A提交,但是我正在寻找验证这是正确的方向,或者需要其他条件。

git branch git-branch git-rebase
1个回答
0
投票

分支名称并不重要,除了人类。 (您是人吗?😀如果是这样,我们可能会遇到一点障碍。)

对Git重要的是commits。在存储库中提交历史记录。每个提交都有一个唯一的哈希ID,这些哈希ID是Git查找提交的方式(我们将在稍后看到一个重要的例外)。哈希ID大而丑陋,并且look是随机的,基本上是人类无法使用的,这就是为什么我们使用分支名称的原因。每个提交都包含所有文件的完整快照(嗯,所有显示在该提交中的所有文件)。而且,每个提交都保存一些元数据(有关提交的信息),例如创建者,创建时间以及对它的直接父提交的原始哈希ID(对于Git本身而言非常重要)。因此,这使Git从

last

提交开始并向后工作。也就是说,假定哈希为H的提交是某个链中的

last

,如标记为branch-A的分支名称:
... <-F <-G <-H <--branch-A

<< [name
branch-A保存链中最后一次提交的哈希ID,即,提交H。提交H本身保存较早提交G的哈希ID,该哈希ID保存较早提交F的哈希ID,依此类推。

诀窍是name包含

last

提交的哈希ID。没有其他简单的方法可以找到最后一个!最后一个找到倒数第二个,找到倒数第二个,依此类推,但不仅仅是人需要名称:Git也需要它来查找last提交。 因此,基本上,我在A上进行了开发,从B挑选了我想要的更改,并且已经进行了测试集成。
当您使用git cherry-pick时,您正在告诉Git进行一次[[copy(其影响以及其中的某些元数据)。因此,您和从事B工作的人都是从某个常见的起点开始的,例如commit H:

I--J <-- branch-A / ...--G--H <-- common-starting-point \ K <-- branch-B

您提到您使用git cherry-pick从另一个分支copy

进行某些提交。将K复制到一个新的提交中,我将其称为K',以表明它与K的相似程度,从而得出:
          I--J--K'  <-- branch-A
         /
...--G--H   <-- common-starting-point
         \
          K   <-- branch-B

请注意,name

branch-A现在如何指向新的
last
提交,即现在的K'。提交K'具有所有内容的完整快照,但是将K'J进行比较,您会看到与KH进行比较时看到的相同的[[change。除非您告诉Git进行更改,否则K'的作者和日志消息也将与H的作者和日志消息匹配。当然,K'的父哈希是J,而K的父哈希是H

您也可以添加更多提交,就像您可能做的一样: I--J--K'--L <-- branch-A / ...--G--H <-- common-starting-point \ K <-- branch-B 现在剩下要做的就是从分支A中减去提交,这样就只剩下“ Apple”了。我正在寻找执行此操作的最佳方法。

不一定有

best
方式。但是,Git很大程度上是为
add提交到分支而构建的,而为

remove

从分支提交则更少。如果确实要删除提交,则可以告诉Git强制

name向后移动。不再是last的提交现在无法找到。例如,如果我们强制名称branch-A向后移动以指向提交I,则会得到: J--K'--L [abandoned] / I <-- branch-A / ...--G--H <-- common-starting-point \ K <-- branch-B 使用Git的常规提交查看工具,例如git log,我们将不再see J以及K'L,所以看起来它们已经消失了。1] >查看者从

last

提交(按分支名称找到)开始,然后向后工作。

无论如何,这里最大的问题是Git是为add提交而构建的。您可以使自己的Git向后移动自己的分支名称,例如使用git resetgit branch -f,但这不会使提交了提交的<< other >> Git,将向后命名。

1

如果我们让他们在此[[unreachable状态停留足够长的时间,则提交JK'最终将成为垃圾收集。 Git偶尔会自行运行的git gc命令通常会在这种情况下运行至少30天,因此您至少需要30天,再加上Git运行需要多长时间git gc本身,可以改变主意并让他们回来。
一个简单的解决方案

处理此问题的简单方法是使用新名称。由于Git不在乎名称,因此我们可以将其称为neo-A而不是branch-A。我们将设置neo-A指向您最初开始的现有提交H I--J--K'--L <-- branch-A / ...--G--H <-- common-starting-point, neo-A \ K <-- branch-B 现在,到neo-A,我们将


添加

一次提交。我们看一下现有的提交。 I是我们喜欢的一个,因此我们可以复制它,也可以直接使用它,因为它很好。让我们直接使用后者,方法是使neo-aL方向前进一步,这是Git“喜欢”分支名称的方式。 (当然,向L而不是K方向移动很重要,但这很容易,因为我们处于控制之中。)

J--K'--L <-- branch-A / I <-- neo-A / ...--G--H <-- common-starting-point \ K <-- branch-B

HL方向的下一个提交是提交J。那也很好:我们可以通过将名称neo-A前进到J一步,给出:

K'--L <-- branch-A / I--J <-- neo-A / ...--G--H <-- common-starting-point \ K <-- branch-B
K'是个问题:我们不想要它。所以我们只是不前进。我们确实需要L,现在我们

必须

复制它,因为现有的L指向K',而我们想要一个新的指向J。因此,我们这次需要使用git cherry-pick来生成: K'--L <-- branch-A / I--J--L' <-- neo-A / ...--G--H <-- common-starting-point \ K <-- branch-B
我们会继续,但是我们已经完成了所有提交,也就是说,我们已经完成了。

我们现在可以安全地git pushneo-A

名称
。然后,我们只需要说服所有人停止使用

old

名称。更容易做到这一点
上面的缺点是我们必须一次一步地“向前移动名称”。如果我们可以创建neo-A并让Git完成所有工作,那就太好了。事实证明,我们

can

git rebase命令具有我们喜欢的所有设备。

我们要做的是:创建指向

相同

neo-A并提交为branch-A

运行git rebase -i <hash of common starting point H>将我们[[不需要

想要的提交]的pick更改为drop

并且Git将自动倒带neo-A,然后向前或向后跳过提交。最终结果就是我们得出的结果:

    K'--L <-- branch-A / I--J--L' <-- neo-A (HEAD) / ...--G--H <-- common-starting-point \ K <-- branch-B
  • 这是有效的,因为在完成复制后,Git强制name neo-A移动到最后复制的提交,在这种情况下为L'
  • 这会在任何名称为neo-A
  • other
Git中产生问题,但是我们只是将其组合起来,所以其他Git都没有。因此,现在git push是安全的。我们会将新的提交(例如L')发送到另一个Git,然后要求他们将名称neo-A设置为指向链中的最后一个提交L',就像我们的名字一样。只要没有人参与,我们就不会

需要新名称

[如果愿意,我们可以直接用git rebase -i本身执行branch-A。结果将是:

K'--L [abandoned] / I--J--L' <-- branch-A (HEAD) / ...--G--H <-- common-starting-point \ K <-- branch-B 然后我们可以使用git push --force或等价于

demand

,另一个Git放弃其提交LK',并使名称branch-A指向提交L'。假设他们服从了-他们[[可以拒绝了-我们现在将他们的branch-A移动了。

这里唯一真正的问题是,某些讨厌的人可能已经将[branch-A]复制到了另一个Git存储库。该人可能希望他们的branch-A副本仅在正常的正向添加-新提交方向上移动。这是使用不同分支名称的真正原因:避免混淆对分支名称有期望的人。

如果没有人在这里造成混淆,或者如果所有其他人都事先知道可能会发生这种情况,请随时倒带并强制推送现有的分支名称。
© www.soinside.com 2019 - 2024. All rights reserved.