问题描述
如果我做了一个
git checkout -b bar foo
或
git checkout foo
git branch bar
都应该在分支foo
的基础上创建分支bar
.但是让我们说第二天,如果我想验证bar
确实是基于foo
创建的,那么在git中没有简单的方法可以做到这一点,或者存在吗?
both should have created a branch bar
base on the branch foo
. But let's say the next day, if I want to verify that bar
really was created based on foo
, there is no easy way to do that in git, or is there?
使用应用程序SourceTree,似乎有可能并且很容易看出,如果bar
和foo
显示在同一行上,则表示在该阶段它们是相同的,并且如果我在bar
,它将在树图中显示bar
是从foo
扩展的,因此我可以很容易地看出bar
是基于foo
的.我在SO中发现的其他一些问题似乎暗示着没有简单的方法可以说出来,但是我不明白为什么.至少在有可能告诉的情况下,不应该有一个告诉它的命令,例如git branch --show-base-on
之类的东西,并且在不可能指示时,显示不能告诉,因为[由于某种原因]" ?
Using the app SourceTree, it seems it is possible and easy to tell, that if bar
and foo
are displayed on the same row, that means they are the same at that stage, and if I commit anything in bar
, it will show that bar
is "extended" from foo
in the tree graph, so I can easily tell bar
was based on foo
. Some other questions I found in SO seem to suggest there is no easy way to tell, but I don't understand why. At least when it is possible to tell, shouldn't there be a command that tells it, such as something like git branch --show-base-on
or something like that, and when not possible to tell, then display "cannot tell because [some reason]"?
推荐答案
git checkout -b bar foo
的最后一个参数实际上只是一个提交ID.您使用了分支名称foo
,但是git将其解析为提交ID.结果是git用相同的提交ID创建了新的分支标签bar
.
The last argument to git checkout -b bar foo
is really just a commit-ID. You used the branch name foo
, but git resolves this to a commit-ID. The effect is that git creates the new branch label bar
with that same commit-ID.
假设您有以下提交图:
A <- B <- C <- D
\
E
(ASCII没有合适的上下箭头,因此可以想象\
的箭头指向C
,即,提交E
的父提交是C
).每个字母代表一个与提交对应的唯一SHA-1 ID.提交D
具有其(单个)父作为提交C
,提交E
也是如此,因此分支在提交C
处分叉.
(ASCII does not have a proper up-and-left arrow so imagine the \
as having an arrow-head pointing to C
, i.e., the parent commit of commit E
is C
). Each letter represents one unique SHA-1 ID corresponding to a commit. Commit D
has its (single) parent as commit C
, and so does commit E
, so the branches fork at commit C
.
现在,让我们也粘贴一些分支标签.名为bra
的分支包含提交A
的提交ID,因此它指向A
.名为brb
的分支包含提交B
的提交ID,因此它指向B
.分支brc
指向C
,依此类推. (我不能真正用ASCII正确地绘制所有这些图像,因此我们必须简单地想象它们.)
Now let's paste on some branch labels as well. The branch named bra
contains the commit ID of commit A
, so it points to A
. The branch named brb
contains the commit ID of commit B
, so it points to B
. Branch brc
points to C
, and so on. (I can't really draw all of these properly in ASCII so we must simply imagine them.)
让我们再创建一个分支,例如master
,它也指向提交D
.
Let's make one more branch, say, master
, that also points at commit D
.
对于超混凝土而言,假设D
的SHA-1是5f95c9f850b19b368c43ae399cc831b17a26a5ac
.
For super-concreteness, let's say the SHA-1 for D
is 5f95c9f850b19b368c43ae399cc831b17a26a5ac
.
现在,如果我这样做:
git checkout -b new 5f95c9f850b19b368c43ae399cc831b17a26a5ac
您说分支new
是基于哪个分支的?新的分支标签new
指向提交D
,就像现有的分支标签brd
和master
一样.那么new
是否起源于brd
或master
或...?
which branch would you say branch new
is based on? The new branch label new
points to commit D
, just like the existing branch labels brd
and master
. So does new
originate from brd
, or master
, or ...?
您可能对此有一个答案,但是git没有. git中的分支标签是短暂的:它们可以随时被清除和/或重新创建或重命名. (如果删除标签master
,以便仅brd
指向D
,则可以说分支new
基于分支brd
.但是如果我随后将brd
重命名为bird
?)
You may have an answer to this, but git doesn't. Branch labels in git are ephemeral: they can be swept away and/or re-created or renamed at any time. (If I delete the label master
, so that only brd
points to D
, you could then say that branch new
is based on branch brd
. But what if I then rename brd
to bird
?)
git中唯一真正永久的是SHA-1值,它完全取决于基础对象的内容.创建完全相同的对象内容,您将获得完全相同的SHA-1哈希.在任何对象中的任何地方更改一点,您将获得一个新的不同的SHA-1.
The only things really permanent in git are the SHA-1 values, which depend entirely on the contents of the underlying object. Create the exact same object contents and you get the exact same SHA-1 hash. Alter a single bit anywhere in any object, and you get a new, different SHA-1.
由于提交记录了其父提交(在合并的情况下为多个父提交),所以通过从某个引用开始并向后工作至无父提交(根提交)而构造的图是永久性的(前提是起点仍保留在资源库中(即,永远不会被垃圾收集),但标签则不会. (只有在没有外部引用(分支,标签等)指向它们并且没有其他已经保留的存储库对象指向它们的情况下,才对垃圾进行垃圾回收.像E
这样的图形提示的单个引用足以保留整个提交链.但是,如果删除该引用,该链将变得脆弱.)
Since commits record their parent commit(s) (multiple parents in the case of a merge), the graph constructed by starting at some reference and working backwards to a parent-less commit (a root commit) are permanent (provided that the starting-point remains in the repository, i.e., is never garbage-collected), but the labels are not. (Commits are garbage collected only when no no external reference—branch, tag, etc.—points to them and no other already-retained repository object points to them, so a single reference to a graph-tip like E
suffices to retain the entire chain of commits. But if you delete that reference, the chain becomes vulnerable.)
这些其他存储库对象"必然是其他提交或带注释的标记对象,因为它们是仅有的两个应包含提交的SHA-1的对象.带注释的标签对象本身应该由相应的轻量级标签或其他可能带注释的标签指向(引用).
These "other repository objects" are necessarily either other commits, or annotated tag objects, as those are the only two that are supposed to contain the SHA-1 of a commit. Annotated tag objects themselves should be pointed-to—referenced—by a corresponding lightweight tag, or possibly another annotated tag.
顺便说一句,git branch
可以帮助您解决其他问题.假设您有一个提交图,看起来像这样:
Incidentally, git branch
can help you out if you want to ask a different question instead. Let's say you have a commit graph that looks more like this:
...-o-o-o-o-o-A <-- master
\ /
o-o-B <-- feature1
\
C <-- feature2
其中每个o
节点代表一个无趣的"(且未标记)的提交.此处标记的分支提示提交(A
,B
和C
)是master
,feature1
和feature2
的分支提示. (很可能feature2
是通过feature1
的分支创建的,而feature1
是通过master
的分支创建的,但这通常也不是特别有趣.)
where each o
node represents an "uninteresting" (and un-labeled) commit. The labeled branch-tip commits here (A
, B
, and C
) are the branch-tips of master
, feature1
, and feature2
. (It's likely that feature2
was created by branching off of feature1
, and feature1
was created by branching off master
, but usually this is not particularly interesting either.)
如果您现在要在分支master
上工作,您经常想知道的是:合并了哪些分支,而没有合并哪些分支?" git branch
命令可以回答此问题:
What you often want to know, if you are to work on branch master
now, is: "what branches are merged in, and what branches are not merged?" The git branch
command can answer this:
git branch --merged master
和:
git branch --no-merged master
这两个命令都要求git branch
从master
标识的提交(即,提交A
)开始,并沿着提交图向后工作".
Both commands ask git branch
to start at the commit identified by master
(i.e., commit A
) and "work backwards" along the commit graph.
对于--merged
,它应该打印分支的名称,当从master
向后进行工作时,将到达由这些分支标识的提交.因此,我们从A
开始,然后回到最右边的o
.这是一个合并提交(有两个父级),因此我们沿两个父级退后一步,找到下一个o
提交,然后提交B
.提交B
由分支名称feature1
指向.它是从master
到达的 ,因此git branch
打印feature1
.这是合并到"分支master
的分支.
With --merged
, it should print the names of branches that, when working backwards from master
, the commit identified by those branches is reached. So we start at A
and step back to the right-most o
. This is a merge commit (with two parents), so we then step back along both parents, finding the next o
commit and commit B
. Commit B
is pointed-to by branch name feature1
. It is reached from master
, so git branch
prints feature1
. This is a branch that "is merged into" branch master
.
对于--no-merged
,git branch
命令应打印那些未达到 提交的分支.和以前一样,我们从A
开始并向后工作,找到最右边的o
是合并.我们沿着父母双方向后工作,找到另一个o
和B
;继续往回走,我们发现了另外两个o
,另外两个o
,然后重新加入最左侧的o
,并通过...
部分进行了重新操作.我们什么时候都没有到达提交C
,因此git branch
打印feature2
:这是一个 not 合并到"分支master
的分支.
With --no-merged
, the git branch
command should print those branches whose commits are not reached. As before, we start at A
and work backwards, finding the right-most o
that is a merge. We work backwards along both parents, finding another o
and B
; continuing back we found two more o
s, another two o
s, and then rejoin the left-most o
and work back through the ...
section. At no point do we reach commit C
—so git branch
prints feature2
: this is a branch that is not "merged into" branch master
.
git branch
的袖子还有另一个窍门(如果它有头袖的话,:-)).我们可以要求git branch --contains
并为其指定特定的提交ID,或者提供任何可以解析为提交ID的内容.假设我们为它提供了提交B
的ID.
There's one more trick up git branch
's sleeve (if it has any sleeves in the first place :-) ). We can ask for git branch --contains
and give it a particular commit-ID, or anything that resolves to a commit-ID. Let's say we give it the ID of commit B
.
这次,使用--contains
,git branch
命令从每个分支尖端开始,然后开始向后工作.如果它可以达到我们给它的提交ID,它将打印分支名称.和以前一样,当我们从提交A
(master
)开始时,我们到达了提交B
.当我们从提交B
(feature1
)开始时,我们当然会立即到达提交B
.当我们从提交C
(feature2
)开始时,我们到达了提交B
.因此git branch --contains feature1
打印所有三个分支名称.
This time, with --contains
, the git branch
command starts at every branch-tip and begins working backwards. If it can reach the commit ID we gave it, it prints the branch-name. As before, when we start from commit A
(master
), we reach commit B
. When we start from commit B
(feature1
), we of course reach commit B
immediately; and when we start from commit C
(feature2
), we reach commit B
. So git branch --contains feature1
prints all three branch-names.
(如果我们要问git branch
哪个分支包含最右边的o
提交,则只有master
会包含它.对于大多数顶行o
提交,这都是正确的最左边的一个;分支feature1
和feature2
也包含该提交,以及...
部分中的所有较早提交.)
(If we were to ask git branch
which branches contain the right-most o
commit, only master
would contain it. The same would be true of most of the top-line o
commits, except for the left-most one; branches feature1
and feature2
also contain that commit, and any earlier ones in the ...
section.)
这篇关于使用Git时,如何判断新分支是基于哪个分支创建的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!