git 我怎样才能看到另一个分支是从哪个分支分叉出来的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4803492/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I see what branch another branch was forked from?
提问by Frerich Raabe
My git repository has three branches, devel
, stable
and customers/acme_patches
. A long time ago, stable
was forked from devel
, and all the bugfixing takes place in stable
. Every now and then, stable
is merged back into devel
. customers/acme_patches
is a branch with a few customer-specific patches. The branch wasn't merged into either of devel
and stable
.
我的 git 存储库有三个分支devel
,stable
和customers/acme_patches
。很久以前,stable
是从 分叉出来的devel
,所有的错误修复都发生在stable
. 时不时地,stable
被合并回devel
. customers/acme_patches
是一个分支,有一些客户特定的补丁。分支没有合并到devel
和 中的任何一个stable
。
A bit of ASCII art to illustrate the scenario:
一些 ASCII 艺术来说明这个场景:
o---o---o customers/acme_patches? / o---o---1---o---o---o stable / \ \ o---o---o---2---o---o---o---o devel \ o---o---o customers/acme_patches?
Now I wonder:
现在我想知道:
What branch was customers/acme_patches
forked from - devel
or stable
? I only know that it was forked off one of them in the past, but I don't know which. E.g. it might have been commit 1
or 2
in the above diagram.
哪个分支是customers/acme_patches
从 -devel
或分叉出来的stable
?我只知道它过去是从其中一个分叉出来的,但我不知道是哪个。例如,它可能已提交1
或2
在上图中。
I've been playing around with git log --oneline --graph
and gitk
but since customers/acme_patches
was forked a few hundred commits ago, it's hard to follow the lines being drawn.
我一直在玩git log --oneline --graph
,gitk
但是自从customers/acme_patches
几百个提交前分叉以来,很难遵循所绘制的线条。
Is there maybe a quick command (a little script is fine, too) which can somehow follow the commits in customers/acme_patches
backwards to find the first commit with two children (the fork point) and then determines whether that commit was done in stable
or in devel
?
是否可能有一个快速命令(一个小脚本也可以),它可以以某种方式customers/acme_patches
向后跟踪提交以找到具有两个孩子的第一个提交(分叉点),然后确定该提交是在 中stable
还是在中完成的devel
?
In the best case, I could just execute something like (excuse the prompt, I'm on Windows):
在最好的情况下,我可以执行类似的操作(请原谅提示,我在 Windows 上):
C:\src> git fork-origin customers/acme_patches
stable
采纳答案by Antoine Pelisse
Well, there is probably no perfect solution to this answer. I mean there is no fork-origin
equivalent in git (to my knowledge).
Because the stable
branch is merged into devel
, your acme_patches
(from 1) is on both devel
and stable
branch.
好吧,这个答案可能没有完美的解决方案。我的意思是fork-origin
git 中没有等价物(据我所知)。由于stable
分支已合并到 中devel
,因此您的acme_patches
(来自 1)在devel
和stable
分支上。
What you could possibly do is:
你可能会做的是:
git branch --contains $(git merge-base customers/acme_patches devel stable)
If you have stable and not devel, or devel and not stable, then you know where it comes from.
如果你有稳定而不是发展,或者发展和不稳定,那么你就知道它来自哪里。
For example, in the case 2, you would have
例如,在情况 2 中,您将有
$ git branch --contains $(git merge-base customers/acme_patches devel stable)
customers/acme_patches
devel
while in case 1 you would have
而在情况 1 你会有
$ git branch --contains $(git merge-base customers/acme_patches devel stable)
customers/acme_patches
devel
stable
As it's now on both branches (because of the merge from stable to dev)
因为它现在在两个分支上(因为从 stable 到 dev 的合并)
回答by VonC
With git 1.9/2.0 (Q1 2014), you can use git merge-base --fork-point
to ask for the best common ancestor according to Git.
使用 git 1.9/2.0(2014 年第一季度),您可以git merge-base --fork-point
根据 Git使用请求最佳公共祖先。
You can see that new option:
你可以看到这个新选项:
- detailed in "How do I recover/resynchronise after someone pushes a rebase or a reset to a published branch?".
- used in "How do you deal with a public repository that has already been rebased?".
- 在“有人将 rebase 或重置推送到已发布的分支后,我如何恢复/重新同步?”中有详细说明。
- 用在“你如何处理已经重新定位的公共存储库?”。
And since commit ad8261dfrom John Keeping (johnkeeping
), git rebase
can use that same new --fork-point
option, which can come in handy should you need to rebase a branch like customers/acme_patches
onto devel
.
(I am not saying this would make sense in your specific scenario)
而且,由于提交ad8261d从约翰饲养(johnkeeping
),git rebase
可以使用相同的新--fork-point
选项,它可以派上用场,如果您需要衍合分支像customers/acme_patches
到devel
。
(我并不是说这在您的特定情况下有意义)
Note: Git 2.16 (Q1 2018) does clarify and enhance documentation for "merge-base --fork-point
", as it was clear what it computed but not why/what for.
注意:Git 2.16(2018 年第一季度)确实澄清并增强了“ merge-base --fork-point
”的文档,因为很清楚它计算了什么,但不清楚为什么/为什么。
See commit 6d1700b(09 Nov 2017) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
--in commit 022dd4a, 27 Nov 2017)
请参阅Junio C Hamano() 的commit 6d1700b(2017 年 11 月 9 日)。(由Junio C Hamano合并-- --在commit 022dd4a,2017 年 11 月 27 日)gitster
gitster
merge-base --fork-point
doc: clarify the example and failure modesThe illustrated history used to explain the
--fork-point
mode named three keypoint commits B3, B2 and B1 from the oldest to the newest, which was hard to read.
Relabel them to B0, B1, B2.
Also illustrate the history after the rebase using the--fork-point
facility was made.The text already mentions use of reflog, but the description is not clear what benefit we are trying to gain by using reflog.
Clarify that it is to find the commits that were known to be at the tip of the remote-tracking branch.
This in turn necessitates users to know the ramifications of the underlying assumptions, namely, expiry of reflog entries will make it impossible to determine which commits were at the tip of the remote-tracking branches and we fail when in doubt (instead of giving a random and incorrect result without even warning).
Another limitation is that it won't be useful if you did not fork from the tip of a remote-tracking branch but from in the middle.
Describe them.
merge-base --fork-point
doc:阐明示例和故障模式图解历史用于解释
--fork-point
从最旧到最新的三个关键点提交 B3、B2 和 B1的模式,这很难阅读。
将它们重新标记为 B0、B1、B2。
还说明使用该--fork-point
设施进行变基后的历史。文中已经提到了 reflog 的使用,但描述并不清楚我们试图通过使用 reflog 获得什么好处。
澄清它是找到已知位于远程跟踪分支尖端的提交。
这反过来又要求用户知道潜在假设的后果,即,reflog 条目的到期将无法确定哪些提交位于远程跟踪分支的尖端,并且我们在有疑问时失败(而不是给出随机的和错误的结果甚至没有警告)。
另一个限制是,如果您不是从远程跟踪分支的尖端分叉而是从中间分叉,它将没有用。
描述他们。
So the documentationnow reads:
所以文档现在是这样的:
After working on the
topic
branch created withgit checkout -b topic origin/master
, the history of remote-tracking branchorigin/master
may have been rewound and rebuilt, leading to a history of this shape:
在使用
topic
创建的分支上工作后git checkout -b topic origin/master
,远程跟踪分支的历史origin/master
可能已经被倒带和重建,导致这种形状的历史:
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\
B0
\
D0---D1---D (topic)
where
origin/master
used to point at commits B0, B1, B2 and now it points at B, and yourtopic
branch was started on top of it back whenorigin/master
was at B0, and you built three commits, D0, D1, and D, on top of it.
Imagine that you now want to rebase the work you did on thetopic
on top of the updatedorigin/master
.In such a case,
git merge-base origin/master topic
would return the parent of B0 in the above picture, butB0^..D
is notthe range of commits you would want to replay on top of B (it includes B0, which is not what you wrote; it is a commit the other side discarded when it moved its tip from B0 to B1).
git merge-base --fork-point origin/master topic
is designed to help in such a case.
It takes not only B but also B0, B1, and B2 (i.e. old tips of the remote-tracking branches your repository's reflog knows about) into account to see on which commit your topic branch was built and finds B0, allowing you to replay only the commits on your topic, excluding the commits the other side later discarded.Hence
其中,
origin/master
在提交B0,B1,B2用于地步,现在它在乙组分,和你的topic
分支开始在它的上面回来时,origin/master
在B0,和你建立三个提交,D0,D1和d,在它的上面.
想象一下,您现在想要topic
在更新的origin/master
.在这种情况下,
git merge-base origin/master topic
将返回B0的家长在上面的图片,但是B0^..D
是不是你想重播对B的顶部提交的范围(它包括B0,这是不是你写的东西,它是一个提交其他将其尖端从 B0 移至 B1 时丢弃的一侧)。
git merge-base --fork-point origin/master topic
旨在帮助这种情况。
它不仅需要 B 还需要 B0、B1 和 B2(即您的存储库的引用日志知道的远程跟踪分支的旧提示)来查看您的主题分支是在哪个提交上构建并找到 B0,允许您只重播关于您主题的提交,不包括另一方后来丢弃的提交。因此
$ fork_point=$(git merge-base --fork-point origin/master topic)
will find B0, and
会找到 B0,并且
$ git rebase --onto origin/master $fork_point topic
will replay D0, D1 and D on top of B to create a new history of this shape:
将在 B 之上重放 D0、D1 和 D,以创建此形状的新历史:
o---B2
/
---o---o---B1--o---o---o---B (origin/master)
\ \
B0 D0'--D1'--D' (topic - updated)
\
D0---D1---D (topic - old)
A caveat is that older reflog entries in your repository may be expired by
git gc
.
If B0 no longer appears in the reflog of the remote-tracking branchorigin/master
, the--fork-point
mode obviously cannot find it and fails, avoiding to give a random and useless result (such as the parent of B0, like the same command without the--fork-point
option gives).Also, the remote-tracking branch you use the
--fork-point
mode with must be the one your topic forked from its tip.
If you forked from an older commit than the tip, this mode would not find the fork point (imagine in the above sample history B0 did not exist,origin/master
started at B1, moved to B2 and then B, and you forked your topic atorigin/master^
whenorigin/master
was B1; the shape of the history would be the same as above, without B0, and the parent of B1 is whatgit merge-base origin/master topic
correctly finds, but the--fork-point
mode will not, because it is not one of the commits that used to be at the tip oforigin/master
).
需要注意的是,存储库中较旧的 reflog 条目可能会过期
git gc
。
如果 B0 不再出现在远程跟踪分支的 reflog 中origin/master
,--fork-point
模式显然找不到它并失败,避免给出随机和无用的结果(例如 B0 的父级,就像没有--fork-point
选项的相同命令给出)。此外,您使用该
--fork-point
模式的远程跟踪分支必须是您的主题从其尖端分叉出来的分支。
如果你从旧犯比前端分叉,这种模式不会找到叉点(想象一下在上面的示例历史B0是不存在的,origin/master
在B1开始,转移到B2,然后B,你在分叉您的主题origin/master^
时,origin/master
是B1;历史的形状将与上面相同,没有 B0,并且 B1 的父项是git merge-base origin/master topic
正确找到的,但--fork-point
模式不会,因为它不是曾经位于origin/master
)尖端的提交之一.
回答by araqnid
well, git merge-base customers/acme_patches stable
should show the common ancestor of those two branches.
好吧,git merge-base customers/acme_patches stable
应该显示这两个分支的共同祖先。
You could try, for instance, gitk --left-right customers/acme_patches...stable
(note three dots!). This will show all the commits that are in those branches and not in the merge base. Using --left-right
will mark each commit with a left or right arrow according to which branch they are in- a left arrow if they are in customers/acme_patches and a right arrow if they are in stable.
例如,您可以尝试gitk --left-right customers/acme_patches...stable
(注意三个点!)。这将显示在这些分支中而不是在合并基础中的所有提交。Using--left-right
将根据每个提交所在的分支用左箭头或右箭头标记每个提交 - 如果它们在 customer/acme_patches 中,则为左箭头,如果它们处于稳定状态,则为右箭头。
Possibly also add --date-order
which I've found sometimes helps make sense of the output.
可能还添加--date-order
我发现有时有助于理解输出的内容。
(You can use this syntax with git log --graph
rather than gitk
but imho this is a case where the visual graph display is a big improvement).
(您可以使用这种语法git log --graph
而不是gitk
但恕我直言,这是可视化图形显示有很大改进的情况)。
回答by x-yuri
Not sure if it covers all cases, but here's the functions that I came up with:
不确定它是否涵盖所有情况,但这是我想出的功能:
git_branch_contains() {
local b=
local c=
IFS_=$IFS
IFS=$'\n'
local branches=($(git branch --contains "$c" | sed -E 's/^(\*| ) //'))
IFS=$IFS_
for b2 in "${branches[@]:+${branches[@]}}"; do
if [ "$b2" = "$b" ]; then
return 0
fi
done
return 1
}
git_upstream_branch() {
local b=
local c1=$(git merge-base --fork-point master "$b") || local c1=
local c2=$(git merge-base --fork-point dev "$b") || local c2=
if ! [ "$c1" ]; then
echo dev
return
fi
if ! [ "$c2" ]; then
echo master
return
fi
local fp
if git merge-base --is-ancestor "$c1" "$c2"; then
fp=$c2
else
fp=$c1
fi
if git_branch_contains master "$fp" && ! git_branch_contains dev "$fp"; then
echo master
else
echo dev
fi
}
And here's the script to test them (git-upstream-branch-test.sh
):
这是测试它们的脚本 ( git-upstream-branch-test.sh
):
#!/usr/bin/env bash
set -eu
. git-upstream-branch.sh
git_commit() {
if ! [ "${commit_i:-}" ]; then
commit_i=0
fi
(( commit_i++ )) || true
echo "$commit_i" > "$commit_i"
git add "$commit_i"
git commit -qm "c$commit_i"
}
git_merge() {
if ! [ "${merge_i:-}" ]; then
merge_i=0
fi
(( merge_i++ )) || true
git merge -m "$merge_i"
}
A_TOPOLOGY=${1:-}
mkdir git-upstream-branch-test-repo
cd git-upstream-branch-test-repo
git init -q
if [ "$A_TOPOLOGY" = 10 ]; then
git_commit
git_commit
git checkout -qb dev
git_commit
git_commit
git checkout -q master
git_commit
git_commit
c=$(git rev-parse HEAD)
git_commit
git_commit
git checkout -q dev
git checkout -qb t1
git_commit
git_commit
git checkout -q dev
git_commit
git_commit
git rebase --onto "$c" dev t1
elif [ "$A_TOPOLOGY" = 11 ]; then
git_commit
git_commit
git checkout -qb dev
git_commit
git_commit
git checkout -q master
git_commit
git_commit
git checkout -q dev
c=$(git rev-parse HEAD)
git_commit
git_commit
git checkout -q master
git checkout -qb t1
git_commit
git_commit
git checkout -q master
git_commit
git_commit
git rebase --onto "$c" master t1
else
git_commit
git_commit
git checkout -qb dev
git_commit
git_commit
git checkout -q master
git_commit
git_commit
if [ "$A_TOPOLOGY" = 4 ] || [ "$A_TOPOLOGY" = 5 ] || [ "$A_TOPOLOGY" = 6 ]; then
git_merge dev
git_commit
git_commit
git checkout -q dev
git_commit
git_commit
git checkout -q master
elif [ "$A_TOPOLOGY" = 7 ] || [ "$A_TOPOLOGY" = 8 ] || [ "$A_TOPOLOGY" = 9 ]; then
git checkout -q dev
git_merge master
git_commit
git_commit
git checkout -q master
git_commit
git_commit
fi
git checkout -qb t1
git_commit
git_commit
git checkout -q master
git_commit
git_commit
if [ "$A_TOPOLOGY" = 2 ] || [ "$A_TOPOLOGY" = 5 ] || [ "$A_TOPOLOGY" = 8 ]; then
git_merge dev
elif [ "$A_TOPOLOGY" = 3 ] || [ "$A_TOPOLOGY" = 6 ] || [ "$A_TOPOLOGY" = 9 ]; then
git checkout -q dev
git_merge master
fi
fi
git --no-pager log --oneline --graph --decorate --all
git_upstream_branch t1
Use it like so,
像这样使用它,
$ rm -rf git-upstream-branch-test-repo && ./git-upstream-branch-test.sh NUMBER
Where NUMBER is a number from 1 to 11 to specify which case (topology) to test.
其中 NUMBER 是一个从 1 到 11 的数字,用于指定要测试的情况(拓扑)。