Git分支从哪里开始,它的长度是多少?
每隔一段时间我都会问,关于在git上启动某个分支的提议,或者是否在特定分支上创建了某个提交。 分支的终点非常明确:这就是分支标签所在的位置。 但是 - 它从哪里开始? 微不足道的答案是:在我们创建该分支的那个提交上。 但据我所知,这些信息就是我所知道的,这就是为什么我问这个问题,在第一次提交后就失败了。
只要我们知道我们分支的地方,我们就可以绘制图表来清楚地说明:
A - B - C - - - - J [master]
D - E - F - G [branch-A]
H - - I [branch-B]
我在提交E
创建了分支B,这就是“开始”。 我知道,因为我做到了。 但其他人能否以同样的方式认出它? 我们可以像这样绘制相同的图表:
A - B - C - - - - J [master]
F - G [branch-A]
/
D - E
H - I [branch-B]
那么,现在看图,哪个分支在E
开始,哪个分支在B
? 提交D
是两个分支的成员还是可以明确地决定它是属于分支-A还是分支-B?
这听起来有些哲学性,但实际上并非如此。 主管有时想知道,分支何时开始(通常标志着任务的开始)以及某些更改属于哪个分支(为了达到某种更改的目的 - 是否需要这项工作),而且我会想知道git是否提供了信息(工具,命令)或定义来正确回答这些问题。
在Git中,你可以说每个分支都是从根提交开始的,而这完全是真的。 但我想这对你不是很有帮助。 你可以做的是定义“分支的开始”与其他分支的关系。 一种可以做到这一点的方法是使用
git show-branch branch1 branch2 ... branchN
并且会向您显示输出底部的所有指定分支之间的常见提交(如果实际上存在常见提交)。
以下是适用于show-branch
的Linux Kernel Git文档的一个示例
$ git show-branch master fixes mhf
* [master] Add 'git show-branch'.
! [fixes] Introduce "reset type" flag to "git reset"
! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
---
+ [mhf] Allow "+remote:local" refspec to cause --force when fetching.
+ [mhf~1] Use git-octopus when pulling more than one heads.
+ [fixes] Introduce "reset type" flag to "git reset"
+ [mhf~2] "git fetch --force".
+ [mhf~3] Use .git/remote/origin, not .git/branches/origin.
+ [mhf~4] Make "git pull" and "git fetch" default to origin
+ [mhf~5] Infamous 'octopus merge'
+ [mhf~6] Retire git-parse-remote.
+ [mhf~7] Multi-head fetch.
+ [mhf~8] Start adding the $GIT_DIR/remotes/ support.
*++ [master] Add 'git show-branch'.
在这个例子中, master
正在与fixes
和mhf
分支进行比较。 把这个输出看作一个表格,每个分支由它自己的列表示,每个提交都有自己的行。 包含提交的分支将在其提交的行的列中显示+
或-
。
在输出的最底部,你会看到所有3个分支共享一个共同的祖先提交,并且它实际上是master
的head
提交:
*++ [master] Add 'git show-branch'.
这意味着fixes
和mhf
都是从master
中提交的。
替代方案
当然,这只是一种可能的方式来确定Git中的通用基础提交。 其他方法包括git merge-base
来寻找共同的祖先,并且git log --all --decorate --graph --oneline
或者gitk --all
- 所有可视化分支并且看他们在哪里分歧(尽管如果有很多提交这很快就变得困难)。
来自原始海报的其他问题
至于这些问题你有:
提交D
是两个分支的成员还是可以明确地决定它是属于branch-A
还是branch-B
?
D
是两个分支的成员,这是他们两个的祖先承诺。
主管有时想知道, 当一个分支已经启动(它通常标志着任务的开始) ......
在Git中,你可以重写整个提交树和它们的分支的历史,所以当一个分支“启动”不像TFS或SVN那样固定。 您可以rebase
在一个Git树枝到任意时间点,甚至把它的根在提交前! 因此,您可以使用它在您想要的树中的任何时间点“开始”任务。
对于git rebase
,这是一个常见的用例,它将同步分支与来自上游分支的最新更改一起推动它们沿着提交图形“及时向前”,就好像您刚刚开始在分支上工作一样,甚至尽管你实际上一直在研究它。 如果你愿意的话,你甚至可以按照提交图推回分支(尽管你可能需要解决很多冲突,具体取决于分支内容......或者你可能不会)。 你甚至可以在开发历史中插入或删除一个分支(尽管这样做可能会改变很多提交的提交)。 重写历史记录是Git的主要功能之一,它使它非常强大和灵活。
这就是提交创建日期(提交最初创建时)和提交日期(提交最后提交到提交树时)的原因。 您可以将它们想象为创建时间日期和上次修改的时间日期。
主管有时想知道...... 某些变更属于哪个分支 (为了达到某种变化的目的 - 是否需要这项工作)。
同样,因为Git允许你重写历史,所以你可以(重新)在你想要的提交图中的任何分支/提交上进行一系列更改。 从字面上看, git rebase
允许你自由地移动你的整个分支(尽管你可能需要根据你移动分支的位置以及它包含的内容来解决冲突)。
这就是说,您可以在Git中使用的工具之一来确定哪些分支或标记包含一组更改是--contains
:
# Which branches contains commit X?
git branch --all --contains X
# Which tags contains commit X?
git tag --contains X
关于这个问题的赏金通知要求,
我有兴趣知道是否考虑将Git分支作为除root提交之外的定义“开始”提交甚至是有意义的?
它的种类除外:
gh-pages
) 我更喜欢将分支的开始考虑为从其创建分支的另一分支的提交(tobib的回答没有~1
),或者(更简单) 共同的祖先 。
(即使OP提到对共同祖先不感兴趣,也在“使用Git查找分支点”中):
git merge-base A master
这意味着:
filter-branch
外,它可能永远不会改变) 第二个对git更有意义,这是关于分支之间的合并和重新分配。
主管有时想知道,分支何时开始(通常标志着任务的开始)以及某些变更属于哪个分支(为了达到某种变化的目的 - 是否需要这项工作)
分支仅仅是错误的标记:由于分支的瞬时特性(可以重新命名/移动/重新设置/删除/ ...),您无法模仿分支的“更改集”或“活动”代表一项“任务”。
这是一个XY问题:OP要求尝试解决方案(分支开始的地方)而不是实际问题(可能被认为是Git中的一项任务)。
要做到这一点(代表任务),您可以使用:
git notes
记住“工作项目”表示提交已经创建(与标签相反,如果提交被修改或重新发布,便可以重写注释)。 也许你在问错误的问题。 海事组织,它没有任何意义了问一个分支开始,因为这个分支包括有史以来的所有文件(即从最初的承诺)的所有更改。
另一方面,问两个分支在哪里分歧绝对是一个有效的问题。 事实上,这似乎正是你想知道的。 换句话说,你并不想知道关于单个分支的信息。 相反,你想知道关于比较两个分支的一些信息。
有一点研究发现了gitrevisions手册页,它描述了提及特定提交和提交范围的细节。 尤其是,
要排除提交可达的提交,使用前缀^符号。 例如^ r1 r2表示提交从r2可达的提交,但不包括从r1可到达的提交。
这套操作经常出现,以至于有一个简写。 如果您有两个提交r1和r2(根据上述指定版本中所述的语法命名),则可以要求可从r2访问的提交,但不包括可通过^ r1 r2从r1访问的提交并可将其写为r1。 .r2。
因此,使用您问题中的示例,您可以获取branch-A
与master
分离的提交
git log master..branch-A
链接地址: http://www.djcxy.com/p/23609.html