【问题标题】:Get commit where merged branch forked from (with intermediate merge)获取从合并分支分支的提交(使用中间合并)
【发布时间】:2018-08-24 21:28:37
【问题描述】:

让我们使用最新可用的 git 2.16.2 和 tig 2.3.3。

cd /tmp && mkdir fit && cd fit

git init
touch m1 && git add m1 && git commit -m "master 1"
touch m2 && git add m2 && git commit -m "master 2"
git checkout -b develop
touch d1 && git add d1 && git commit -m "develop 1"
git checkout master
touch m3 && git add m3 && git commit -m "master 3"
git checkout develop
git merge master --no-edit
touch d2 && git add d2 && git commit -m "develop 2"
touch d3 && git add d3 && git commit -m "develop 3"
git checkout master
git merge develop --no-edit
touch m4 && git add m4 && git commit -m "master 4"

git reflog expire --expire=now --all && git gc --prune=now --aggressive

develop 分支中检索最后一次提交非常容易:

git --no-pager show -s --format=%B $(git rev-parse develop)

开发 3

但我无法在 develop 分支中检索 第一次提交。所以我找不到分支分支的提交。

git merge-base --fork-point develop
git rev-list develop..master
git rev-list develop master
git rev-list master develop
git rev-list ^develop master

结果没有用。

我找到了问题How to get commit where merged branch forked from的解决方案

git oldest-ancestor master develop
git oldest-ancestor develop master

结果也没有用。

但是tiggit log --graph 仍然能够看到develop 1develop 分支的第一个提交,并且这个分支是从master 2 中的master 提交分叉出来的。

是否可以使用当前的 git 控制台工具检索 master 2

【问题讨论】:

  • "结果没有用。" . . .请具体说明:你打算用什么?

标签: git git-branch git-log tig


【解决方案1】:
git --no-pager show -s --format=%B $(git rev-parse develop)

更简单:

git --no-pager show -s --format=%B develop

或:

git --no-pager log --no-walk --format=%B develop

show -slog --no-walk 几乎是一回事;这里的关键是删除不必要的git rev-parse)。

但我无法在develop 分支中检索第一次提交

该分支中的第一个提交是master 1,或您的图像中的27ee6b8(哈希 ID 会随着提交的时间而变化)。这也是分支master 中的第一次提交。

这里的问题是分支没有“起点”。分支,在某种意义上,结构——图形片段——通过从终点开始并回到起点而达到。这意味着一些提交在许多分支上;通常,root 提交,即您在存储库中所做的第一次提交,位于 every 分支上(尽管在具有多个根的存储库中,某些根可能不在某些分支上)。

分支name 通常——也有一些例外——与该分支上的提示提交同义,这就是您不需要显式git rev-parse 的原因。然而,分支名称的关键特征是它移动随着时间的推移,因此它总是命名分支的尖端提交。

另见What exactly do we mean by "branch"?

如果您希望标记某个特定的提交,以便以后记住它,通常的工具是 Git 标记。标签与分支名称非常相似,因为它标识了一个特定的提交。然而,与分支名称不同的是,标签永远不会移动,Git 也不会自动移动它。

git reflog expire --expire=now --all

Reflogs 专门用于观察引用的移动(随着时间的推移)。 develop 之类的分支名称的引用日志默认保留 30 或 90 天,1develop 用于标识的哈希 ID。通过使它们过期,您已经失去了回到过去查看develop@1develop@2 等的能力。如果您保留了它们,您可以查找存在的最旧的develop。那可能是它诞生的时候,你经常可以看出:

05d0c47 master@{37}: clone: from ...

(表示master此时诞生)。

不幸的是,reflogs 确实过期了,所以这并不完全可靠。标签是可靠的,但可能很烦人,因为git log 会用他们的标签装饰提交。如果有一个 procedure 可以找到有趣的提交,你可以使用它。在这种情况下,存在这样一个过程:您想要曾经或曾经是合并的合并基础的提交。

要找到合并基,先找到合并本身,然后找到它的父项:

m=11c63bc  # this is the merge
p1=$(git rev-parse ${m}^1)
p2=$(git rev-parse ${m}^2)

现在$p1$p2 是此合并的两个父级。 (合并可以有两个以上的父级,但大多数合并只有两个。)这两个分支最后合并的共同点是两个父级的合并基础:

git merge-base --all $p1 $p2

由于只有一个合并基础,因此只打印一个提交哈希。如果有多个,它将​​打印所有这些,因为我们使用了--all。忽略--all,我们会(显然)随机选择一个(实际选择的一个取决于用于查找合并基的算法)。

和以前一样,不需要很多临时变量——我们可以这样做:

mbases=$(git merge-base --all ${m}^1 ${m}^2)

因为git merge-base 采用与git rev-parse 相同的提交说明符语法:^1^2 后缀在那里的工作方式相同(实际上在大多数 Git 命令中工作方式相同)。


1过期时间是可配置的。较短的时间(默认为 30 天)适用于从引用的当前值无法访问的哈希 ID;较长的 90 天默认值适用于可从引用的当前值访问的哈希 ID。

【讨论】:

  • 所以 master into develop 的中间合并将使我的分支匿名,我无法遍历 develop 提交,因为只有 reflog 知道如何拆分 developmaster在此合并之前提交。
  • 差不多,是的。请注意,合并 do 具有严格的父级排序:合并的第一个父级是合并时 HEAD 的提交。真正的问题是快进操作,它不是合并,而是更新分支名称提交哈希值,以及任何git reset 命令,这会使任意(用户指定)更改为分支名称哈希值。
猜你喜欢
  • 2018-05-10
  • 2015-08-14
  • 1970-01-01
  • 2020-10-18
  • 1970-01-01
  • 1970-01-01
  • 2017-01-24
  • 1970-01-01
  • 2016-03-01
相关资源
最近更新 更多