git - Git以错误的顺序提交日志信息
问题描述
我是 Git 领域的新手。我试图用git commit
不同的版本来记录我的软件。但是,我得到以下结果。
60cf510 (HEAD -> master) HEAD@{0}: commit: Automatically detect whether use the fix effect to make the final prediction
791df2d HEAD@{1}: commit: release version 1.0
f9a3697 HEAD@{2}: commit: Add colmun selection in covariate and phenotype
889b11b HEAD@{3}: commit: Add preprocess (overlap, snp order, flip allele)
8c7688f HEAD@{4}: commit (initial): Fix bug in estimating delta and add flip minor allel
带有哈希码的日志60cf510
是我最新提交的。我认为这个日志信息应该遵循8c7688f
. 我不确定问题是什么。更何况,我不知道为什么commit (initial)
存在。是因为我重新初始化了 git 吗?谢谢你。
以下消息来自命令git log
。
commit 60cf510c9b549b6a1f89fc7b3ba2f88faca7a8fa (HEAD -> master)
Author: shunkang <shunkang1997@gmail.com>
Date: Tue Feb 18 22:57:45 2020 +0800
Automatically detect whether use the fix effect to make the final prediction
If there is no prediction covariate file provided, the software will only use the random effect to make the prediction. The final output result will show two columns with the same value.
commit 791df2d446ed8db87751620c48d15beac04074ce
Author: shunkang <shunkang1997@gmail.com>
Date: Thu Nov 21 11:43:11 2019 +0800
release version 1.0
commit f9a3697960f27648e7fbe86ad1e64072ea34888a
Author: shunkang <shunkang1997@gmail.com>
Date: Thu Nov 21 11:10:57 2019 +0800
Add colmun selection in covariate and phenotype
commit 889b11b7aa4c9db9a3feb3b2f6691cd64559b46b
:
解决方案
这里的一切看起来都很正常。
我们可以从这些观察开始:
在大多数情况下,Git 存储提交。即commit是Git存储的基本单位。(可以将提交分成几个部分,Git 有时会这样做,但大多数情况下我们一次处理整个提交。)
在创建每个提交时,它都会获得一个唯一的哈希 ID。这个哈希 ID 永远为这次提交保留,不仅在这个Git 存储库中,而且在任何地方的每个Git 存储库中。从某种意义上说,它甚至在你提交之前就被保留了,除了提交哈希 ID 取决于你提交时的时间,直到第二个。
(这些哈希 ID 非常大且笨拙。它们必须是,像这样独一无二。没有人能正确地理解它们,但没关系:毕竟我们有一台计算机。)
每个提交都包含所有文件的快照。这是提交中的主要数据,但每个提交还包含一些元数据:关于提交本身的一些信息。元数据包括提交者的姓名和电子邮件地址 - 作为两个条目,作者和提交者- 以及一些日期和时间戳,以及您或任何人记录提交原因的日志消息。
但是,此元数据中的一个关键项是每个提交都存储其直接前一个提交或多个提交的实际哈希 ID。也就是说,每个提交都有一定数量的父提交——通常只有一个——并且子提交存储其父或父的原始哈希 ID。
每当我们在某处存储了提交的哈希 ID 时,我们就说持有该哈希 ID 的任何东西都指向该提交。因此,如果您在某处写了一些哈希 ID H——例如在纸上或白板上——我们可能会说 this指向commit H
。由于每个提交都存储其父级的哈希 ID,因此每个提交都指向其父级。我们可以这样画:
... <-F <-G <-H
where H
is some commit with some hash ID H,它指向它的 parent G
,它又指向它的 parent F
,依此类推。
如果我们将某个长链提交的最后一个哈希 ID 记录在一个分支名称中,例如master
,这足以让 Git 找到所有这些提交。该名称指向最后一次提交:
...--F--G--H <-- master
从那里,Git 可以向后工作:从 开始H
,它找到G
,然后F
,依此类推。这一直重复,直到 Git 找到第一个提交,这不会进一步指向,因为它不能。
要进行新的提交,我们首先将提交提取H
到工作区。(所有提交都是 100% 只读的,所以我们无法更改H
,但我们可以更改我们复制到工作区的内容。)然后我们像往常一样编辑文件,使用git add
将它们复制到索引- 另一个关键项目,但我们赢了此处不详述——并用于git commit
进行新的提交。Git将我们所有的文件打包到一个新的快照中,添加元数据——例如我们的姓名和电子邮件地址以及当前日期和时间——并将新提交的父级设置为 commit H
。这个新的提交获得了它的新 ID,这对我们来说太大了,我们无法管理,但我们将称之为I
。因此,新提交I
指向现有提交H
.
最后,git commit
将新提交的哈希 ID 写入当前分支名称。如果当前分支名称是master
,Git 会将I
哈希 ID 写入master
,因此master
现在指向I
. 由于I
点回到H
,这就是我们得到的:
...--F--G--H--I <-- master
该git log
命令从最后开始并向后工作
一个常规的git log
——<em>not git reflog
!——从某个结束点提交哈希 ID 开始,例如通过查看 name 内部master
。每当git log
查看分支名称时,根据定义,这就是分支中的最后一次提交。1 然后git log
向我们展示这个 commit——commit I
,在这种情况下——现在git log
简单地移动到提交的父级。所以你看到的下一个提交是上一个提交。
换句话说,日志会自动从头到尾反向工作。这是 Git 的一个主题:它所有的内部箭头都指向后方。Git总是必须从头开始并向后工作。所以git log
默认显示最新的提交,因为默认情况下,它从您当前的分支名称开始,这是该分支上的最新提交。
请注意,如果您使用git checkout
— 或新的 Git 2.23+ git switch
— 切换到不同的分支名称,git log
将从该其他分支名称开始,而不是从master
. 或者,如果您使用git checkout
或git switch
切换到分离 HEAD模式,其中特殊名称HEAD
直接指向提交,git log
将默认从该历史提交开始。
1分支名称的定义是它保存了最后一次提交的哈希 ID。这就是git branch -f
,git reset
等可以做的:通过将不同的哈希 ID 强制到分支名称中,这会更改哪个提交是最后一次提交。这也是为什么git commit
将新提交的哈希 ID 写入分支名称的原因:根据定义,这个新提交是最后一次提交,并且根据定义,分支名称必须包含最后一次提交的哈希 ID ,因此git commit
使两个定义一起工作.
什么时候git log
更复杂
通过绘制每个提交和从它到其父级的箭头来绘制提交图通常很重要:
I--J <-- branch1
/
...--G--H
\
K--L <-- branch2
这里我们有两个不同的分支名称,每个都指向一个提交——<code>J for和branch1
for——它们的一个提交像往常一样向后指向,但是在某些时候,两个分支在历史上合并:提交并且都指向提交。L
branch2
I
K
H
该git log
命令通常从当前分支提示开始并向后工作。例如,如果我们选择branch1
当前分支,我们将J
首先看到 commit,然后I
是 ,然后H
是 ,然后G
是 ,依此类推。如果我们选择branch2
当前分支,我们将看到L
, then K
, then H
, 以此类推。请注意,无论哪种方式,我们都看不到其中两个提交。
然而,我们可以告诉git log
从和 branch1
开始 branch2
。但git log
一次只能显示一个提交。它会首先向我们展示J
,还是L
首先向我们展示?
这个问题的答案很复杂。有时 Git 会J
先显示我们,有时它会L
先显示。要选择两者之一,请将两个提交放入git log
优先级队列。默认优先级是提交者的 date-and-time ,所以无论是哪个或后来的都是我们首先看到的。您可以提供不同的排序选项,从而改变优先级;在这种情况下,您可能会首先看到另一个提交。J
L
git log
从队列中取出两个提交之一并显示它,git log
现在将该提交的父级放入优先级队列。然后它将显示最高优先级的提交——无论是哪一个——下一个。然后它将提交的父级放入优先级队列。这个队列中还有两个提交,所以再一次,你在前两个之后看到的哪个提交是由优先级队列决定的。
最终,很可能——或者,取决于你给出的标志git log
,必要的——在显示 commit之前git log
会显示J
, I
, L
, 。此时只有提交本身将在优先级队列中,因此现在将显示并将提交放入队列中。Now将是队列中唯一的提交,因此将显示,并将的父级放入队列中,依此类推。K
H
H
git log
H
G
G
git log
G
G
换句话说,git log
有时 对提交进行排序。它仅在其优先级队列中包含多个条目时才执行此操作,如果您为其提供多个起点提交,则会自动发生这种情况,例如J
和L
此处。但是看看我们合并一些提交后会发生什么:
I--J
/ \
...--G--H M--N <-- master
\ /
K--L
现在,如果我们开始master
并返回,git log
必须先显示N
——这是队列中唯一的提交——然后是M
. 但是 commitM
有两个父母,所以git log
现在将两者都J
放入L
队列中。现在它有两个提交要显示,所以它会根据优先级选择一个。换句话说,它现在根据我们给它的选项对提交进行排序。当我们有两个分支名称时,我们又回到了同样的情况,指向提交J
和L
,并被告知git log
显示两个提交/分支。
git log
一次向我们展示一个提交,即使历史更复杂
我们从中看到的历史git log
可能会产生误导。它可能会按顺序向我们显示N
, then M
, thenL
和K, then
I and
J`。如果我们不知道存在分支合并的事实,我们可能会认为提交是这样线性进行的。
出于这个原因,您可以git log
绘制一个粗略的基于文本的图表。该图并不总是很漂亮,但它会显示提交L
并且K
与提交平行J
并且I
:它们在历史记录中形成分支和合并结构,如提交中记录的那样。
历史就是提交;提交是历史
请注意,在所有这些过程中,没有提交更改。git log --sort=...
我们可以使用或以不同的顺序一次查看一个提交git log --topo-order
,和/或让 Git 使用 绘制图表git log --graph
。或者,我们可以在白板、纸上或使用各种绘图程序绘制我们的图表。但无论我们做什么,提交本身都不会改变。这些提交是您存储库中的历史记录。从您进行提交的那一刻起,他们的联系就存在:子提交指向他们的父母。合并提交是具有两个(或更多)父级的提交。当父母有两个或更多孩子时分支“分叉”。
您始终可以向图表添加更多提交。Git通过使用分支名称来查找提交,根据定义,分支名称是该分支中的最后一个提交。您始终可以添加新的分支名称,也可以删除分支名称。如果你删除了唯一允许你找到某个提交的名称——例如,如果你有:
...--o--o--o--o--...--o <-- master
\
H <-- branch
然后你删除了这个名字branch
——在这种情况下H
,一个特定的提交变得难以找到,或者可能是不可能的。但是,Git 有其他方法来查找提交。例如,标签名称可以指向提交。Git 还会记录特定分支和其他名称的先前值。此日志称为reflog,可以让您找到 commit H
。
某些操作,例如git rebase
,通过将现有的一系列提交复制到新的和改进的提交,然后移动分支名称来工作。由于 name 包含最后一次提交的哈希 ID,如果我们复制提交然后移动name,看起来我们以某种方式更改了提交:
...--o--o--o--o--...--o <-- master
\
H--I--J <-- branch
变成:
...--o--o--o--o--...--o <-- master
\ \
H--I--J H'-I'-J' <-- branch
H'
的副本在哪里,是 的副本H
,是 的副本。不过,我们实际上并没有更改提交。原件仍然存在,在存储库中。您只是无法轻易找到它们,因为我们从名称开始现在查找提交,然后从那里向后工作。I'
I
J'
J
branch
I'
(名称的 reflogbranch
保存了 commit 的哈希 ID J
。如果我们决定要“撤消”变基操作,我们可以强制再次branch
记住该名称J
,而不是J'
。然后 reflog forbranch
将保存 commit 的哈希 ID J'
。由于 reflogs 包含多个条目,我们最终将有多个 reflog 条目保存J
和/或J'
。尽管 reflog 条目最终会过期,所以最终我们会J
完全忘记提交,只要名称branch
仅指向J'
. 分支名称只能指向一个提交,事实上,必须始终指向一个提交。)
推荐阅读
- rasa-nlu - 客户操作未执行
- mysql - MySQL如何在服务器未运行时进行备份
- java - 映射注释有什么用,我需要它吗?(Spring Data ElasticSearch)
- sql-server - 由于 'log_backup' / (Log)LDF 文件比 (Data)MDF 大 4 倍,数据库的事务日志已满
- spring - Thymeleaf + Spring:表单中的 2 个对象覆盖 ID
- r - 有没有办法计算执行指令的数量?
- python-3.x - 在“for line”循环中跳过第一行
- c# - Check count of a specific element inside a list in C#
- sql - 从帐号计算用户公式
- python - 我在数据框(csv 文件)中有 6 列 value1、value2、value3、value4、value5、value6