git - 从提交 ID 创建 git 分支后,一些 git 提交丢失
问题描述
我正在从提交 id 创建一个 git 分支,我的期望是它应该在创建新分支时在指定的提交 id 之后显示提交 id。但不知何故,新创建的 git 分支中缺少一些 git 提交。
我有一个有多个提交 id 的主分支:
我使用git checkout -b testBranch 3331a4b
命令从主分支创建了一个新分支
但是当在这个分支上触发git log --oneline
命令时,我可以看到一些提交 id 丢失了。请点击以下链接查看提交 ID
testBranch 提交 ID:
缺少主分支的提交 ID:
解决方案
这里的问题是,虽然git log --oneline
显示提交的线性列表,但提交实际上并不是线性的。考虑到一些明显线性的提交序列,您期望这一点:
010 final
009 earlier
008 earlier-still
007 ...
...
001 first
从 010 开始倒数会给你 10 次提交,而从 009 开始倒数会给你 9 次提交。
如果提交是线性的,那将是正确的,但事实并非如此。
当然,实际的数字不是连续的,也不是十进制的——它们是哈希 ID,例如(对于简单地以 开头3331a4b
的更长的东西来说,它已经很短了)。所以你已经知道你不能只使用数字作为一个简单的索引。让我们用单个大写字母...替换序列号(001 到 010)或哈希 ID(等等) ,并实际绘制在一个包含十次提交的小型存储库中进行的提交,最后一次提交是合并提交: 3331a4b
3331a4b
A
B
H
A <-B <-C <-D <-----H
\ /
E <-F <-G
这些箭头——来自E
指向C
和来自H
指向G
的箭头没有箭头提示(因为在文本中绘制太难了),但这些连接器也是箭头——允许 Git 从最后一次提交向后工作到第一的。
事实上,每个 Git 提交都包含一组父提交哈希 ID。我们说提交指向它的父节点(如上图所示)。大多数提交只有一个父级,这些提交形成一个简单的、向后的、线性链,就像从C
back 到A
. 在这里,一切都表现得很好:当您从 开始时C
,只有一条路径可以返回A
.
至少有一个提交,第一个提交,没有父哈希,因为它是第一个提交,并且没有更早的提交指向它。这是动作停止的地方。请注意,该操作从末尾开始并向后进行。
一些提交,如H
上面示例中的提交,有两个父级。在这里,事情变得很棘手,因为 Git 可以从H
到或 G
到D
. (您可能已经看到了它的发展方向。)该git log
命令使用一种特定的方法来线性化它的向后行走,我们稍后会谈到。
一个类似于或实际上指向一个提交的分支名称——<em>一个特定的提交——例如 commit ,所以我们可以更简单地绘制这些东西,像这样,然后在右边添加分支名称,最后:master
develop
H
A--B--C--D------H <-- master
\ /
E--F--G <-- develop
知道提交之间的内部链接是向后的箭头。(为了不需要更改提交,箭头本身嵌入到子级中,指向它们的父级提交——提交中的任何内容都不能移动或更改;所有提交的内容都是永久固定的。子级孩子出生的时候就知道自己的父母是谁,但是直到孩子出生,父母才知道自己的孩子会是谁,所以父母不能指点孩子。)
这里棘手的部分是名称,如master
or develop
,确实会移动:名称通过命令master
到达这里,可能通过 运行,或者可能由某人直接运行,或者通过 GitHub“合并拉取请求”按钮,或类似的。在早些时候的某个时候,绘图看起来像这样:git merge
git pull
A--B--C--D <-- master
\
E--F--G <-- develop
CommitH
尚不存在,并且从开始master
并向后工作,git log
将枚举 commits D
, then C
, then B
, then A
; 从开始develop
并向后工作,git log
将枚举提交G
,然后F
,然后E
,然后C
,然后B
,然后A
。
此时,有人跑了git checkout master; git merge develop
,或者做了类似的事情。这创建了新的 commit H
,指向G
and D
,并为我们提供了最新的绘图。
现在,假设您将一个新的分支名称附加到 commitF
或E
. 如果您一直在查看git log
基于 的输出master
,并且一直假设提交D
在提交之前E
,您可能希望看到从F
or开始的提交E
,向后工作并包括D
. 但是,一旦我们绘制了提交图,并在F
or上附加了一个标签E
,您就会发现我们不应该期望提交D
出现:
A--B--C--D------H <-- master
\ /
E--F--G <-- develop
.
.....<-- testBranch
D
可以从H
( , 目前) 到达的事实master
并不意味着D
可以从 到达testBranch
。
在更复杂的图表中,从某个分支尖端开始并向后工作的提交集可能更难看到:图表变得复杂,难以查看或可视化。尽管如此,使用git log --graph
(有或没有--oneline
)在这里可以有所帮助。
如何git log
线性化非线性图
由于git log
必须一次显示一个提交 - 每行一个--oneline
,或者使用多个输出行而不使用它 - 它需要一个待处理提交队列。这个队列通常从你命名的一个提交开始:
$ git log <hash>
或者:
$ git log <branchname>
或者没有参数,当前的 ( HEAD
) 提交。Git 会将提交从队列中取出,显示出来,然后将其父项放入队列中。如果刚刚显示的提交是合并提交,具有两个(或更多)父级,则队列现在变得更深。
然后,Git 获取队列前面的任何提交并显示该提交。该提交有一些父母;如果父级尚未显示且不在队列中,Git 会将它们放入队列中。
因此,提交的显示顺序取决于它们在队列中的位置。当队列为空(通常是这样)并且只有一个父节点时,该父节点将成为队列中的单个条目,并立即显示,将其从队列中删除,从而使队列再次为空。这就是一个简单的线性链如何显示为一个简单的线性链:我们可能将提交G
放入队列,然后将其取出并显示并放入F
队列,然后将其取出并显示并放入E
队列, 等等。
如果您从git log
多个提交开始:
$ git log master develop
(假设名称master
和develop
指向两个不同的提交——可能有两个分支名称指向同一个提交),队列开始时会有多个提交,所以再一次,队列中的提交顺序将事情。Git 将首先显示队列前提交,无论是master
命名的还是develop
命名的。显示该提交后,Git 将在适当的情况下将其父级插入队列中,然后才有机会(取决于另一个提交现在在队列中的位置)显示您在命令行中指定的另一个提交。
队列插入顺序的默认值是提交时间戳,较新的(较晚的时间戳)提交进入队列的前面。--date-order
您可以使用、--author-date-order
、--topo-order
和来在一定程度上控制此顺序--reverse
。使用--graph
武力--topo-order
。有关详细信息,请参阅git log
文档。
推荐阅读
- javascript - 在反应本机导航中调用导航道具方法时获取“未定义不是对象”
- javascript - iframe 正在破坏浏览器的后退按钮
- php - 如何遍历 PHP 上的产品和类别列表
- amazon-web-services - 通过架构更改在 S3 和 Redshift 之间卸载和重新加载数据
- matlab - 用底函数定义周期函数
- google-cloud-platform - Firebase 动态链接在 Twitter 和 LinkedIn 中被标记为可疑
- accessibility - 屏幕阅读器和浏览器事件
- c++ - 将函数作为可变参数模板参数传递,并调用它们
- python - 自动礼物的循环问题
- c# - 从 VS 构建中的 Release/Debug 文件夹中删除 DLL