【问题标题】:Git revision range since last merge, including that merge自上次合并以来的 Git 修订范围,包括该合并
【发布时间】:2020-08-29 23:17:05
【问题描述】:

假设我在 Git 中有以下情况。

基本上,有人从 master 分支出来,然后合并到他们的分支(一次或多次)。

*   <- 'master'
| * <- 'topic'
| *
|/|
* |
| * <- 'topic' created
|/
*

我可以使用 Git 修订范围来获取自“master”和“topic”之间的最后一个共同祖先以来关于“topic”的提交。在这种情况下,它将是 'topic' 和 'topic~'。

背景:我正在尝试在“master”上创建一个新的(非合并)提交,其中包含“topic”的所有更改,同时避免解决已经在“topic”上解决的冲突。我正在考虑“格式补丁”,然后是“am”或者“cherry-pick”和“--no-commit”。由于合并提交,变基给我带来了挑战。

谢谢

【问题讨论】:

  • ...因为反向合并很糟糕。

标签: git merge branch patch cherry-pick


【解决方案1】:

在某些情况下,答案只是你不能这样做。这不是一个,但是用gitrevisions 语法拼出来是很棘手的。

它可能也无助于你的最终目标:

我正在尝试在“主”上创建一个新的(非合并)提交,其中包含“主题”的所有更改...

你可能想要:

git checkout master
git merge --squash topic

在此之后,与名称 topic 做的唯一明智的事情就是完全删除它。

之后,到 gitrevisions

让我们为绘图中的每个提交分配字母名称。这又是你的图表——请注意,我假设这是经过修剪或手工编辑的git log --graph --oneline 输出:

F   <- 'master'
| E <- 'topic'
| D
|/|
C |
| B <- 'topic' created
|/
A

我只是用一个字母替换了每个*,这样我们就可以对每个提交进行讨论。

提交F 只能从master 访问。它有一个单亲,C。提交E 只能从topic 访问,并且有一个单亲D。提交D 只能从主题访问,但它是与父级CB 的合并提交,C 是第一个父级。1 提交C 本身是一个普通的单-parent 与父 A 提交; commit B 是一个普通的单父提交,父 A;并且 commit A 是根本没有父级的根提交。

该图可能具有误导性,因为名称 topic 很可能是在名称 master 标识提交 A 时创建的,当时 topic 命名提交 @987654346 @。所以“topic created”应该指向A,即使A 显然是从master 的尖端直接向下射击:我们从提交F 开始,去提交C,然后去提交A

选择提交EDB 很简单:这只是topic ^master,您可以拼写为master..topic。由名称master 选择的提交集是{F, C, A}。由名称topic 选择的提交集是{E, D, C, B, A}。从第二个集合中减去(或排除)第一个集合产生集合{E, D, B}

要选择提交 ED,请考虑,例如:

git rev-list topic ^topic^^@

也就是说,我们希望可以从topic{E, D, C, B, A} 访问修订,正如我们已经看到的那样—但不包括合并提交D 的所有父母。语法rev^@ 的意思正是给定版本的所有父项,所以^rev^@ 表示排除给定版本的所有父项。在这种情况下,rev 部分是topic^,所以我们最终得到^topic^^@。这些帽子或插入符号^ 符号中的每一个都在做不同的事情:

  • 前导^表示不是
  • ^ 紧随主题之后,在topic^ 中,表示第一个父级;和
  • 末尾的^@ 序列表示所有的父母

请注意,您也可以拼写此 ^topic~1^@^topic~^@

要选择提交 EB 但完全排除 D,您可以使用以下事实:当 git rev-list 遍历图表时,它可以让您排除基于其输出的提交在某些标准上。由于我们知道master..topic 会遍历EDB,因此我们可以使用该语法但添加--no-merges。并非每个命令都支持这种语法,但 git rev-list 支持,您可以使用 git rev-list 本身生成原始哈希 ID 列表,然后您可以将其提供给大多数 Git 命令。

最后,考虑按名称或相关说明符列出您想要的每个提交,并添加--no-walk

git rev-list --no-walk topic topic~2

例如表示提交ECtopic 本身意味着提交 E。波浪号和数字后缀向后计数 first-parent 步数。 E 的第一个也是唯一一个父级是 DD 有两个父级。 Dfirst 父级是 CDsecond 父级是 B,所以 topic^^topic~2 表示提交 @987654408 @。

要通过相对名称选择B,我们需要E 的第一个父级的第二个父级,所以topic^^2 也可以做到这一点。也就是说,topic^——或者如果我们愿意,topic^1topic~topic~1——最初选择提交 D,但添加后缀 ^2 后立即移动到 second D 的父级 B

(如果父母是正常顺序——所以D第一个父母是B,它的第二个C——我们' d 使用不同的相对名称。)

在所有这些情况下,--no-walk 意味着我们的每个选择器不应该选择那个提交及其祖先,而应该只选择那个提交。


1这很不寻常:通常C 将是第二个父级。 git log --graph --oneline 会将这个第二父母描绘为:

F   <- 'master'
| E <- 'topic'
| D
| |\
| |/
|/|
C |
| B <- 'topic' created
|/
A

也就是说,git log --graph 总是将 first 父级放在左侧,其他父级放在右侧,即使这意味着它必须在下一行中立即重新转向左侧。

【讨论】:

  • 非常感谢托雷克。我会尝试“合并--squash”。我已经使用 Git 工作了几年了,但我完全错过了这个选项。关于您彻底回答的其余部分,您对图表的猜测是正确的。我永远不会再改变父母的顺序。不知道 Git 如何将第一父母绘制到左侧等的规则。事实上,我想下次我只会复制粘贴:) 你对获取提交 E 和 D 有效输入格式的表达式的想法-修补?我不这么认为,因为文档说它必须是 ,对吧?
  • git format-patch 是一种特殊情况,因为它是最古老的 Git 命令之一。它也无法格式化合并(!),所以无论如何这些都出来了。一个技巧是在一次提交上重复调用它,每次 X^..X。至于合并边界处的第一次与非首次提交:很多时候都没有关系,但有时确实如此,棘手的范围表达式就是其中之一:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 2017-09-09
相关资源
最近更新 更多