从中间合并获取合并分支分支的提交 [英] Get commit where merged branch forked from (with intermediate merge)

查看:116
本文介绍了从中间合并获取合并分支分支的提交的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  cd / tmp&& amp;& mkdir fit&& cd fit 

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

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


  git最老的祖先master开发
git最老的祖先开发master

$ b

结果也是无用的。



但是 tig git log --graph 仍然能够看到开发1 开发分支,并且此分支从 master 2 >在 master 中提交。 p>

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

解决方案


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


更简单:

  git --no-pager显示-s --format =%B develop 

或者:

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

show -s log --no-walk 是几乎相同的东西;这里的关键项目是删除不必要的 git rev-parse )。


但是我无法在开发分支中检索第一次提交

该图像中的第一个提交是 master 1 27ee6b8 将随着提交的时间而变化)。这也是第一次提交分支 master



这里的问题是分支没有起点。在某种意义上,分支结构 - 图片片段 - 通过从结束点开始并回溯到开始到达。这意味着一些提交在许多分支上;通常, root 提交,您在存储库中进行的第一次提交,位于每个分支上(尽管在具有多个根的存储库中,某些根可能不在某些分支上)。
$ b

一个分支 name 一般来说有一些例外,就是该分支上的提示提交的同义词,这就是为什么你不需要明确的 git rev-parse 。然而,分支名称的关键特征是它随着时间的推移移动,因此它总是命名分支的提示提交。



另请参阅我们的意思是分支?



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


  git reflog expire --expire = now --all 




Reflogs的存在是为了能够观察参考文献的移动(随着时间的推移)。像开发这样的分支名称的reflog默认保留30或90天, 1 <开发的哈希ID 用于识别。通过使他们失效,你已经消除了及时回顾并查看 develop @ 1 develop @ 2 等等。如果您保留了它们,您可以查找存在的最旧的 develop 可能是它出生的时候,你可以经常说:

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

(表示 master 出生在这一点)。

不幸的是,reflogs do 过期了,所以这不是完全可靠的。该标签是可靠的,但可能很烦人,因为 git log 会修饰其标签提交。如果有一个过程用于查找有趣的提交,那么可以使用它。在这种情况下,就是这样一个过程:你想要提交已经或者已经是合并的基础



要找到合并基础,找到合并本身,然后找到它的父母:

  m = 11c63bc#这是合并
p1 = $(git rev-parse $ {m} ^ 1)
p2 = $(git rev-parse $ {m} ^ 2)

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

  git merge-base --all $ p1 $ p2 

由于只有一个合并基础,因此只打印一个提交哈希。如果有几个,它会打印所有的,因为我们使用 - 所有。如果省略 - all ,我们会得到一个在(显然)随机选择的实体(实际选择取决于用于查找合并基的算法)。



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

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

> git merge-base 采用与 git rev-parse 相同的提交说明符语法: ^ 1 ^ 2 后缀的工作方式与此相同(并且在大多数Git命令中的确如此) p>




1 到期时间是可配置的。缺省情况下,30天的更短时间用于无法从引用的当前值到达的散列ID;更长的90天默认值是针对可从当前参考值获得的哈希ID。


Lets use the latest available git 2.16.2 and 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

It is so easy to retrieve the last commit in develop branch:

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

develop 3

But I couldn't retrieve the first commit in develop branch. So I couldn't find the commit where branch forked from.

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

Results are useless.

I've found a solution for question How to get commit where merged branch forked from

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

Results are useless too.

But tig and git log --graph are still able to see that develop 1 was the first commit of the develop branch and this branch were forked from master 2 commit in master.

Is it possible to retrieve master 2 with current git console tools?

解决方案

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

Even simpler:

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

or:

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

(show -s and log --no-walk are nearly the same thing; the key item here is to drop the unnecessary git rev-parse).

But I couldn't retrieve the first commit in develop branch

The first commit in that branch is master 1, or 27ee6b8 in your image (the hash ID will vary with the time that the commit is made). This is also the first commit in branch master.

The problem here is that branches do not have "starting points". Branches are, in one sense, the structure—the graph fragment—that one reaches by starting at the ending point and working back to the beginning. This means that some commits are on many branches; typically, the root commit, the first commit you make in a repository, is on every branch (though in a repository with multiple roots, some roots may not be on some branches).

A branch name is, in general—there are some exceptions—synonymous with the tip commit on that branch, which is why you don't need an explicit git rev-parse. The key feature of a branch name, however, is that it moves over time, so that it always names the tip commit of the branch.

See also What exactly do we mean by "branch"?

If you wish to mark some particular commit, in order to remember it later, the usual tool for this is a Git tag. A tag is very much like a branch name, in that it identifies one specific commit. Unlike a branch name, however, a tag is never supposed to move, and Git won't move it automatically.

git reflog expire --expire=now --all

Reflogs exist specifically to be able to observe the movement (over time) of references. The reflog for a branch name like develop retains, for 30 or 90 days by default,1 the hash IDs that develop used to identify. By expiring them, you've removed your ability to go back in time and look at develop@1, develop@2, and so on. If you had retained them, you could look for the oldest develop that exists. That might be when it was born, and you can often tell:

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

(indicating that master was born at this point).

Unfortunately, reflogs do expire, so this is not completely reliable. The tag is reliable, but may be annoying since git log will decorate commits with their tags. If there's a procedure for finding the interesting commit, you can use that. In this case, there is such a procedure: you want the commit(s) that was or were the merge base(s) of the merge.

To find the merge base, find the merge itself, then find its parents:

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

Now $p1 and $p2 are the two parents of this merge. (A merge can have more than two parents, but most merges have only two.) The common point where these two branches were last merged is the merge base of the two parents:

git merge-base --all $p1 $p2

Since there is only one merge base, this prints just the one commit hash. If there were several, it would print all of them because we used --all. Leaving out --all, we would get one chosen at (apparently) random (the actual one chosen depends on the algorithm used to find the merge bases).

As before, one does not need a lot of temporary variables—we could do:

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

since git merge-base takes the same commit-specifier syntax as git rev-parse: the ^1 and ^2 suffixes work the same there (and indeed work the same in most Git commands).


1The expiration times are configurable. The shorter time, 30 days by default, is for hash IDs that are not reachable from the current value of the reference; the longer 90-day default is for hash IDs that are reachable from the current value of the reference.

这篇关于从中间合并获取合并分支分支的提交的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆