假设我在 Git 中有以下情况。
基本上,有人从主分支出来,然后合并到他们的分支(一次或多次)。
* <- 'master'
| * <- 'topic'
| *
|/|
* |
| * <- 'topic' created
|/
*
我可以使用 Git 修订范围来遵守自"master"和"主题"之间的最后一个共同祖先以来对"主题"的提交。在这种情况下,它将是"主题"和"主题~"。
背景:我正在尝试在"master"上创建一个新的(非合并)提交,其中包含"主题"的所有更改,同时避免解决已经在"主题"上解决的冲突。我在考虑"格式补丁",然后是"am",或者可能是带有"--no-commit"的"樱桃选择"。由于合并提交,变基给我带来了挑战。
谢谢
在某些情况下,答案是你不能那样做。 这不是一个,但用 gitrevisions 语法拼写出来是很棘手的。
它也可能无助于您的最终目标:
我正在尝试在"主"上创建一个新的(非合并)提交,其中包含"主题"中的所有更改......
您可能希望:
git checkout master
git merge --squash topic
之后,对名称topic
唯一明智的做法是完全删除它。
继续,到 gitrevisions
让我们为图形中的每个提交分配字母名称。 这是您的图形绘图 - 请注意,我假设这是修剪或手动编辑git log --graph --oneline
输出:
F <- 'master'
| E <- 'topic'
| D
|/|
C |
| B <- 'topic' created
|/
A
我只是简单地用一个字母替换了每个*
,以便我们可以计算每个提交。
只能从master
访问提交F
。 它有一个单亲父母,C
. 提交E
只能从topic
访问,并且具有单个父D
。 提交D
只能从主题访问,但是是与父C
和B
的合并提交,C
是第一个父级。1提交C
本身是一个普通的单父提交,具有父A
;提交B
是具有父A
的普通单父提交;提交A
是根本没有父级的根提交。
该图可能具有误导性,因为名称topic
很可能是在master
标识提交A
时创建的,当时topic
也命名为提交A
。 所以"topic
创建"应该指向A
,尽管A
显然是从master
尖直接击落的:我们从提交F
开始,去提交C
,然后去提交A
。
选择提交E
、D
和B
很容易:这只是topic ^master
,你可以拼写为master..topic
。 按名称master
选择的提交集是{F, C, A}
。 按名称topic
选择的提交集{E, D, C, B, A}
。 从第二个集合中减去(或排除)第一个集合会产生集合{E, D, B}
。
要选择提交E
和D
,请考虑,例如:
git rev-list topic ^topic^^@
也就是说,我们希望修订可以从topic
访问 - 正如我们已经看到的{E, D, C, B, A}
- 但不包括合并提交D
的所有父级。 语法rev^@
的意思正是给定修订版的所有父级,因此^rev^@
表示排除给定修订版的所有父级。 在这种情况下,rev
部分是topic^
,所以我们最终得到^topic^^@
. 这些帽子或插入^
符号中的每一个都在做不同的事情:
- 领先的
^
意味着不是; - 紧跟在主题之后的
^
,在topic^
中,表示第一个父项;和 - 最后的
^@
序列表示所有父项。
请注意,您也可以拼写此^topic~1^@
或^topic~^@
。
要选择提交E
和B
但完全排除D
,您可以使用以下事实:当git rev-list
遍历图形时,它允许您根据某些条件从其输出中排除提交。 因为我们知道master..topic
走E
、D
和B
,我们可以使用该语法,但添加--no-merges
。 并非每个命令都支持此语法,但git rev-list
支持,您可以使用git rev-list
本身生成原始哈希 ID 列表,然后可以将其提供给大多数 Git 命令。
最后,考虑简单地按名称或相对说明符列出所需的每个提交,并添加--no-walk
:
git rev-list --no-walk topic topic~2
例如,表示提交E
和C
。topic
本身意味着提交E
。 波浪号和数字后缀向后计数一定数量的第一个父步骤。E
的第一个也是唯一的父母是D
,D
有两个父母。D
的第一个父级是C
,D
的第二个父级是B
,所以topic^^
或topic~2
表示提交C
。
要按相对名称选择B
,我们需要E
的第一个父级的第二个父级,所以topic^^2
也可以解决问题。 也就是说,topic^
——或者如果我们愿意,topic^1
或topic~
或topic~1
——最初选择提交D
,但添加后缀^2
会立即移动到D
的第二个父级,即B
。
(如果父项是正常的顺序——这样D
的第一个父级是B
的,第二个父级是C
的——我们将使用不同的相对名称。
在所有这些情况下,--no-walk
意味着我们的每个选择器都不应该选择该提交及其祖先,而应该只选择该提交。
1这是不寻常的:通常C
会是第二个父母。git log --graph --oneline
将这种第二父母性描绘为:
F <- 'master'
| E <- 'topic'
| D
| |
| |/
|/|
C |
| B <- 'topic' created
|/
A
也就是说,git log --graph
总是将第一个父项放在左边,其他父项放在右边,即使这意味着它必须在随后的行中立即向左重新转移。