在Git中,提交是用来记录版本库的变更的。

当提交时,Git会记录索引的快照并将快照放进对象库,该快照不包含该索引中任何文件或记录中的副本。Git会将当前索引的状态与之前的快照做一个比较,并派生出一个受影响的文件和目录列表,并会为任何有变化的文件创建新blob对象,对有变化的目录创建新的树对象,对于未改动的文件和目录则会沿用之前的blob与树对象。

提交的快照是串联到一起的,每张新的快照指向其前驱,随着时间的推移,一系列变更就表示为一系列提交。

版本库中的变更和提交时一一对应的关系,提交则是将变更引入版本库的唯一方法,任何版本库中的变更都必须由一个提交引入。

原子变更集

每个Git提交都代表一个相对于之前状态的单个原子变更集合。即一个提交中的改动,无论包含多少文件,多少修改内容,要么全部应用,要么全部拒绝。

这点和数据库操作是一致的,不能十行修改因为某个不知名的原因只成功提价了九行,那如何定位未提交的一行很显然也是一个问题。

而在底层对象模型方面,原子性也是有意义的:一张提交快照就代表所有文件和目录的变更,其表示了一棵树的状态,而两张提交快照之间的变更集就代表一个完整的树到树的转换。

识别提交

在Git中,可以通过显式或隐式引用来指代每一个提交。如某次提交的散列值是显式提交,而始终指向最新提交的HEAD则是隐式提交。

同时Git提供了不同的命名机制来提交命名,

绝对提交名

在Git中,最严格的识别提交方式肯定是散列值,毕竟Git中的对象都是通过散列值识别的。

$ git log -1 --pretty=oneline HEAD
9f1d1da871fe53fcaa5bdaa8417b47ab7b1b740f (HEAD -> master) commit file$ git log -1 --pretty=oneline 9f1d1da871fe53fcaa5bdaa8417b47ab7b1b740f
9f1d1da871fe53fcaa5bdaa8417b47ab7b1b740f (HEAD -> master) commit file

比如上面的命令会识别出散列值对应的提交,并打印。

引用和符号引用

引用(ref)是一个散列值,指向Git对象库中的对象。虽然一个引用可以指向任何Git对象,但是其通常指向提交对象。符号引用(symbolic reference),或称为symref,间接指向Git对象。

本地特性分支名称,远程跟踪分支名称和标签名都是引用。

每一个符号引用都有一个以ref/开始的明确全称,并且都分层存储在版本库的.git/refs/目录中。目录中基本有三种不同的命名空间代表不同的引用:

  • refs/heads/ref代表本地分支
  • refs/remotes/ref代表远程跟踪分支
  • refs/tags/ref代表标签

比如当前版本库的引用目录为:

$ find .git/refs/
.git/refs/
.git/refs/heads
.git/refs/heads/master
.git/refs/tags

同时Git会自动维护几个用于特定目的的特殊符号引用,这些引用可以在使用提交的任何地方使用。

  • HEAD:HEAD始终指向当前分支的最近提交,当切换分支时,HEAD会更新为指向新分支的最近提交。
  • ORIG_HEAD:某些操作,如merge或reset,会把调整为新值之前的先前版本的HEAD记录到ORIG_HEAD中。可以使用ORIG_HEAD来恢复或回滚到之前的状态或者做一个比较。
  • FETCH_HEAD:当时用远程库时,git getch命令将所有抓取分支的头记录到.git/FETCH_HEAD中。FETCH_HEAD是最近抓取的分支的HEAD的缩写,并且仅在刚刚抓取操作之后才有效。
  • MERGE_HEAD:当一个合并操作正在进行时,其它分支的头暂时记录在MERGE_HEAD中。换言之,MERGE_HEAD是正在合并进HEAD的提交。

所有的这些符号引用都可以使用底层命令git symbolic-ref进行管理。

相对提交名

Git还提供一种机制来确定相对于另一个引用的提交,通常是分支的头。

开发中关于提交可能会出现master、master^、master~2之类的符号,这就是相对提交名。

除了第一个根提交外,所有的提交都来自至少一个比其更早的提交,即父提交。而若一个提交存在多个父提交,那么其必定是由合并操作产生的。

在同一代提交中,插入符号^是用来选择不同的父提交的。比如给定提交A,A^1表示其第一个父提交,A^2表示其第二个父提交。而波浪线~用于返回父提交之前并选择上一代提交,比如给定提交A,A~1表示其第一个父提交,A~2表示其第一个父提交的第一个父提交。

同时还存在一些特殊写法,比如A~1、A^1、A~、A^含义相同,都是A第一个父提交,A^^、A^1^1含义也相同,实际使用需要灵活运用。

这里以git的源码为例,看下其提交的历史:

$ git show-branch master --more=35 | tail -10
fatal: bad sha1 reference --more=35$ git show-branch --more=35 | tail -10
[master~9^2~3] t2107: test 'git update-index --verbose'
[master~7^2~6] Git 2.37-rc0
[master~10] Merge branch 'jk/perf-lib-test-titles'
[master~10^2] perf-lib: fix missing test titles in output
[master~10^2^] t/perf: add iteration setup mechanism to perf-lib
[master~11] builtin/rebase: remove a redundant space in l10n string
[master~12] Fixes and updates post -rc0
[master~13] Merge branch 'fs/ssh-default-key-command-doc'
[master~13^2] gpg docs: explain better use of ssh.defaultKeyCommand
[master~14] Merge branch 'po/rebase-preserve-merges'

其中的一次提交为:

$ git rev-parse master~13^2
ce18a30bb78720d90df42b9d9ee6b8b7dd33d7e6$ git cat-file -p ce18a30bb78720d90df42b9d9ee6b8b7dd33d7e6
tree ff62097391dd860007845ec05624eb1decfc740e
parent dc8c8deaa6b5847733bd7df011a4c7b7d1a64e0a
author Fabian Stelzer <fs@gigacodes.de> 1654701877 +0200
committer Junio C Hamano <gitster@pobox.com> 1654731220 -0700gpg docs: explain better use of ssh.defaultKeyCommandUsing `ssh-add -L` for gpg.ssh.defaultKeyCommand is not a good
recommendation. It might switch keys depending on the order of known
keys and it only supports ssh-* and no ecdsa or other keys.
Clarify that we expect a literal key prefixed by `key::`, give valid
example use cases and refer to `user.signingKey` as the preferred
option.Signed-off-by: Fabian Stelzer <fs@gigacodes.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

从中可以看出,该次提交对应的散列值正是对应的本次提交,这样说起来可能有点绕,但是相对提交名确实是有效的。

而Git中的git rev-parse命令会将任何形式的提交名,包括标签,相对名,简写或绝对名称都转换为对象库中的散列值。

提交历史记录

查看旧提交

显式提交历史记录的命令主要是git log,该命令还存在很多参数。

不过首先git log的形式和git log HEAD的作用一样,输出每一个可以从HEAD找到的历史记录中的提交日志信息。变更从HEAD提交开始进行回溯,并且Git是基于其内部的提交图进行回溯的,跟提交时间并不完全一致。

而如果在git log命令中显式提供了一个提交名,那么该日志将从该提交开始回溯。

$ git log
commit 5b71c59bc3b9365075e2a175aa7b6f2b0c84ce44 (HEAD -> master, tag: v2.37.0-rc1, origin/master, origin/main, origin/HEAD)
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 17 17:15:13 2022 -0700Git 2.37-rc1Signed-off-by: Junio C Hamano <gitster@pobox.com>commit 694c0cc0fb531b17750ac6e81920054f193f8eb8
Merge: b4eda05d58 6b11e3d52e
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 17 17:12:31 2022 -0700Merge branch 'cb/path-owner-check-with-sudo-plus'"sudo git foo" used to consider a repository owned by the originaluser a safe one to access; it now also considers a repository ownedby root a safe one, too (after all, if an attacker can craft amalicious repository owned by root, the box is 0wned already).* cb/path-owner-check-with-sudo-plus:git-compat-util: allow root to access both SUDO_UID and root ownedcommit 6b11e3d52e919cce91011f4f9025e6f4b61375f2
Author: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Date:   Fri Jun 17 13:23:38 2022 -0700git-compat-util: allow root to access both SUDO_UID and root ownedPrevious changes introduced a regression which will prevent root foraccessing repositories owned by thyself if using sudo because SUDO_UIDtakes precedence.Loosen that restriction by allowing root to access repositories ownedby both uid by default and without having to add a safe.directoryexception.A previous workaround that was documented in the tests is no longerneeded so it has been removed together with its specially craftedprerequisite.Helped-by: Johanness Schindelin <Johannes.Schindelin@gmx.de>Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>Signed-off-by: Junio C Hamano <gitster@pobox.com>commit b4eda05d58ca3e4808d3d86ab5826c77995a06f7
Author: Jiang Xin <zhiyou.jx@alibaba-inc.com>
Date:   Fri Jun 17 18:03:09 2022 +0800i18n: fix mismatched camelCase config variablesSome config variables are combinations of multiple words, and wetypically write them in camelCase forms in manpage and translatablestrings. It's not easy to find mismatches for these camelCase configvariables during code reviews, but occasionally they are identifiedduring localization translations.To check for mismatched config variables, I introduced a new featurein the helper program for localization[^1]. The following mismatchedconfig variables have been identified by running the helper program,such as "git-po-helper check-pot".Lowercase in manpage should use camelCase:* Documentation/config/http.txt: http.pinnedpubkeyLowercase in translable strings should use camelCase:* builtin/fast-import.c:  pack.indexversion* builtin/gc.c:           gc.logexpiry* builtin/index-pack.c:   pack.indexversion* builtin/pack-objects.c: pack.indexversion* builtin/repack.c:       pack.writebitmaps* commit.c:               i18n.commitencoding* gpg-interface.c:        user.signingkey* http.c:                 http.postbuffer* submodule-config.c:     submodule.fetchjobsMismatched camelCases, choose the former:* Documentation/config/transfer.txt: transfer.credentialsInUrlremote.c:                          transfer.credentialsInURL[^1]: https://github.com/git-l10n/git-po-helperSigned-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>Signed-off-by: Junio C Hamano <gitster@pobox.com>commit b81b98f818fdacdc472f2afed2ae67d9d0893fe2
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 17 10:33:42 2022 -0700Another batch of fixes before -rc1Signed-off-by: Junio C Hamano <gitster@pobox.com>commit aa11b94ef87050af9e4e0aab64f1ab89636c5be4
Merge: 7f5a382aa5 f8535596aa
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 17 10:33:32 2022 -0700Merge branch 'jk/bug-fl-va-list-fix'$ git log 6b11e3d52e919cce91011f4f9025e6f4b61375f2
commit 6b11e3d52e919cce91011f4f9025e6f4b61375f2
Author: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Date:   Fri Jun 17 13:23:38 2022 -0700git-compat-util: allow root to access both SUDO_UID and root ownedPrevious changes introduced a regression which will prevent root foraccessing repositories owned by thyself if using sudo because SUDO_UIDtakes precedence.Loosen that restriction by allowing root to access repositories ownedby both uid by default and without having to add a safe.directoryexception.A previous workaround that was documented in the tests is no longerneeded so it has been removed together with its specially craftedprerequisite.Helped-by: Johanness Schindelin <Johannes.Schindelin@gmx.de>Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>Signed-off-by: Junio C Hamano <gitster@pobox.com>commit b9063afda17a2aa6310423c9f7b776c41f753091
Author: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Date:   Thu May 12 18:00:19 2022 -0700t0034: add negative tests and allow git init to mostly work under sudoAdd a support library that provides one function that can be usedto run a "scriplet" of commands through sudo and that helps invokingsudo in the slightly awkward way that is required to ensure it doesn'tblock the call (if shell was allowed as tested in the prerequisite)and it doesn't run the command through a different shell than the onewe intended.Add additional negative tests as suggested by Junio and that use anew workspace that is owned by root.Document a regression that was introduced by previous commits whereroot won't be able anymore to access directories they own unlessSUDO_UID is removed from their environment.The tests document additional ways that this new restriction couldbe worked around and the documentation explains why it might be insteadconsidered a feature, but a "fix" is planned for a future change.Helped-by: Junio C Hamano <gitster@pobox.com>Helped-by: Phillip Wood <phillip.wood123@gmail.com>Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>Signed-off-by: Junio C Hamano <gitster@pobox.com>

上面的例子也说明历史记录并不是按照时间打印的,具体的要看提交图。

但这样从头开始看很难定位某个提交,此时可以使用since..until的形式指定提交的范围:

$ git log --pretty=short --abbrev-commit master~12..master~10
commit 2fec2d2895
Merge: 3b9a5a33c2 55d9d4bbd0
Author: Junio C Hamano <gitster@pobox.com>Merge branch 'jk/perf-lib-test-titles'commit 55d9d4bbd0
Author: Jeff King <peff@peff.net>perf-lib: fix missing test titles in outputcommit 3b9a5a33c2
Author: Fangyi Zhou <me@fangyi.io>builtin/rebase: remove a redundant space in l10n string

上面的代码就是打印了master~12到master~10之间的所有提交,也就是该分支上之前10次和第11次的提交。而同时--pretty=short调整打印的信息数量,--abbrev-commit则是以缩写散列值打印。

git log -p则可以输出提交引进的补丁或变更:

$ git log -1 -p master
commit 5b71c59bc3b9365075e2a175aa7b6f2b0c84ce44 (HEAD -> master, tag: v2.37.0-rc1, origin/master, origin/main, origin/HEAD)
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 17 17:15:13 2022 -0700Git 2.37-rc1Signed-off-by: Junio C Hamano <gitster@pobox.com>diff --git a/Documentation/RelNotes/2.37.0.txt b/Documentation/RelNotes/2.37.0.txt
index f1b93f3c59..99dc7e32f8 100644
--- a/Documentation/RelNotes/2.37.0.txt
+++ b/Documentation/RelNotes/2.37.0.txt
@@ -234,9 +234,8 @@ Fixes since v2.36* With a recent update to refuse access to repositories of otherpeople by default, "sudo make install" and "sudo git describe"
-   stopped working.  This series intends to loosen it while keeping
-   the safety.
-   (merge b9063afda1 cb/path-owner-check-with-sudo later to maint).
+   stopped working, which has been corrected.
+   (merge 6b11e3d52e cb/path-owner-check-with-sudo-plus later to maint).* The tests that ensured merges stop when interfering local changesare present did not make sure that local changes are preserved; now
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c0b5e722dd..22e76c2a59 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@#!/bin/sh

而上边的-1则会限制输出为一个提交。

而git log中的--stat选项将会列举出提交中所更改的文件以及每个更改的文件中有多少行存在改动。

$ git log --pretty=short --stat master~12..master~10
commit 2fec2d289588a70f8683bfe8f429d9e3d3d31ef5
Merge: 3b9a5a33c2 55d9d4bbd0
Author: Junio C Hamano <gitster@pobox.com>Merge branch 'jk/perf-lib-test-titles'commit 55d9d4bbd044afa004c6962aa50635158dc8719e
Author: Jeff King <peff@peff.net>perf-lib: fix missing test titles in outputt/perf/perf-lib.sh | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)commit 3b9a5a33c2986522736d484da497ccd99d715220
Author: Fangyi Zhou <me@fangyi.io>builtin/rebase: remove a redundant space in l10n stringbuiltin/rebase.c | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)

而另一个查看对象库中对象信息的命令是git show,可以使用其来查看某个提交:

$ git show HEAD
commit 5b71c59bc3b9365075e2a175aa7b6f2b0c84ce44 (HEAD -> master, tag: v2.37.0-rc1, origin/master, origin/main, origin/HEAD)
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 17 17:15:13 2022 -0700Git 2.37-rc1Signed-off-by: Junio C Hamano <gitster@pobox.com>diff --git a/Documentation/RelNotes/2.37.0.txt b/Documentation/RelNotes/2.37.0.txt
index f1b93f3c59..99dc7e32f8 100644
--- a/Documentation/RelNotes/2.37.0.txt
+++ b/Documentation/RelNotes/2.37.0.txt
@@ -234,9 +234,8 @@ Fixes since v2.36* With a recent update to refuse access to repositories of otherpeople by default, "sudo make install" and "sudo git describe"
-   stopped working.  This series intends to loosen it while keeping
-   the safety.
-   (merge b9063afda1 cb/path-owner-check-with-sudo later to maint).
+   stopped working, which has been corrected.
+   (merge 6b11e3d52e cb/path-owner-check-with-sudo-plus later to maint).* The tests that ensured merges stop when interfering local changesare present did not make sure that local changes are preserved; now
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c0b5e722dd..22e76c2a59 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@#!/bin/shGVF=GIT-VERSION-FILE
-DEF_VER=v2.37.0-rc1 ;# not quite
+DEF_VER=v2.37.0-rc1LF=''

上面的代码具体打印了本次提交对应提交对象的详细信息,也可以查看某个特定的对象信息:

$ git show b1a8c144e073ba9c5f5d085fa864b5bfb99892fa
#ifndef TR2_DST_H
#define TR2_DST_Hstruct strbuf;
#include "trace2/tr2_sysenv.h"struct tr2_dst {enum tr2_sysenv_variable sysenv_var;int fd;unsigned int initialized : 1;unsigned int need_close : 1;unsigned int too_many_files : 1;
};/** Disable TRACE2 on the destination.  In TRACE2 a destination (DST)* wraps a file descriptor; it is associated with a TARGET which* defines the formatting.*/
void tr2_dst_trace_disable(struct tr2_dst *dst);/** Return the file descriptor for the DST.* If 0, the dst is closed or disabled.*/
int tr2_dst_get_trace_fd(struct tr2_dst *dst);/** Return true if the DST is opened for writing.*/
int tr2_dst_trace_want(struct tr2_dst *dst);/** Write a single line/message to the trace file.*/
void tr2_dst_write_line(struct tr2_dst *dst, struct strbuf *buf_line);#endif /* TR2_DST_H */

提交图

Git中通过有向无环图来实现版本库的提交历史记录。

在提交图中,每个节点都代表一个单独的提交,所有边都从子节点指向父节点,形成祖先关系。

并且在提交图中,时间并不是提交图排序的决定因素,因为如果全球协作开发的项目,不同地点的时间加上不同用户主机实际的时间总是不一致的。

提交图具体可以使用gitk工具看一下大概是什么东西:

上图对应的就是gitk的界面,也很好理解,就不多解释了。

而对于提交图来说:

  • 一般的提交有且只有一个父提交,也就是提交历史记录中的上一次提交
  • 通常一种提交没有父提交,就是初始提交,该提交一般在图的最低端
  • 合并提交会拥有多个父提交

提交范围

通常情况下,可以使用提交范围检查分支或分支的某一部分。

之前使用master~12..master~10就是指明了提交的范围,前边的master~12不包含,master~10包含,该范围标记为start..end,就是end可达,start不可达的范围。而使用git log就是打印HEAD可达的范围。

也可以通过^A排除可达提交集中特定的提交A,git log ^A B就等同于git log A..B。

当如果上面的提交范围设计到分支就会不太容易理解。这里看几个例子:

上图的topic..master范围为W、X、Y、Z。

上图的topic..master范围为V之前的提交和V、W、X、Y、Z。

上图的topic..master范围为W、X、Y、Z。

而提交范围start..end的形式如果没有指定start或end,则缺省项均默认为HEAD。

而与start..end类似的还有start...end,就是两个点和三个点的区别。这种形式表示为对称差,也就是start或end可达但又不是start和end同时可达的提交集合。

上图的topic...master范围为D、E、F、G、H、I、X、Y、Z。

可以使用如下命令计算A和B的对称差:

$ git rev-list A B --not `(git merge-base --all B)`

而有时也会遇到很抽象的命令,如:

git log ^dev ^topic master

上述命令表示在master分支,不在dev或topic分支上的所有提交。

查找提交

git bisect

该命令一般基于任一搜索条件查找特定的错误提交。

该命令一般用于定位某个错误的提交,比如某次提交存在bug,但之后隔了好久这个bug才出现,那么如果定位该bug处于哪一次提交呢,此时就可以用到git bisect命令

该命令使用二分法来定位bad提交,而用户只需要判断本地提交是good或是bad即可。这里简单看一下该过程。

$ git bisect startxxx@xxxxxx ~/Desktop/GIT/git (master|BISECTING)
$ git bisect badxxx@xxxxxx ~/Desktop/GIT/git (master|BISECTING)
$ git bisect good 1f8496c65f963d2b75ef57dc4f09dbc2f5646bf3
Bisecting: 20 revisions left to test after this (roughly 5 steps)
[99bbf4739d927a3d8183d1fc3f1ee7871aac9fb9] Merge branch 'jc/cocci-cleanup'xxx@xxxxxx ~/Desktop/GIT/git ((99bbf4739d...)|BISECTING)
$ git bisect good
Bisecting: 9 revisions left to test after this (roughly 3 steps)
[d0d96b8280faf7c22c115374732f50972689c0d2] Merge branch 'js/ci-github-workflow-markup'xxx@xxxxxx ~/Desktop/GIT/git ((d0d96b8280...)|BISECTING)
$ git bisect good
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[aa11b94ef87050af9e4e0aab64f1ab89636c5be4] Merge branch 'jk/bug-fl-va-list-fix'xxx@xxxxxx ~/Desktop/GIT/git ((aa11b94ef8...)|BISECTING)
$ git bisect bad
Bisecting: 2 revisions left to test after this (roughly 1 step)
[7281c196b1166f1c00df33948c67b0ef81ba63a9] transfer doc: move fetch.credentialsInUrl to "transfer" config namespacexxx@xxxxxx ~/Desktop/GIT/git ((7281c196b1...)|BISECTING)
$ git bisect good
Bisecting: 1 revision left to test after this (roughly 1 step)
[f8535596aa7bd7f6862af3fe6420ac12b17c9912] bug_fl(): correctly initialize trace2 va_listxxx@xxxxxx ~/Desktop/GIT/git ((f8535596aa...)|BISECTING)
$ git bisect bad
f8535596aa7bd7f6862af3fe6420ac12b17c9912 is the first bad commit
commit f8535596aa7bd7f6862af3fe6420ac12b17c9912
Author: Jeff King <peff@peff.net>
Date:   Thu Jun 16 16:04:25 2022 -0400bug_fl(): correctly initialize trace2 va_listThe code added 0cc05b044f (usage.c: add a non-fatal bug() function to gowith BUG(), 2022-06-02) sets up two va_list variables: one to output tostderr, and one to trace2. But the order of initialization is wrong:va_list ap, cp;va_copy(cp, ap);va_start(ap, fmt);We copy the contents of "ap" into "cp" before it is initialized, meaningit is full of garbage. The two should be swapped.However, there's another bug, noticed by Johannes Schindelin: we forgetto call va_end() for the copy. So instead of just fixing the copy'sinitialization, let's do two separate start/end pairs. This is allowedby the standard, and we don't need to use copy here since we have accessto the original varargs. Matching the pairs with the calls makes it moreobvious that everything is being done correctly.Note that we do call bug_fl() in the tests, but it didn't trigger thisproblem because our format string doesn't have any placeholders. So eventhough we were passing a garbage va_list through the stack, nobody everneeded to look at it. We can easily adjust one of the trace2 tests totrigger this, both for bug() and for BUG(). The latter isn't broken, butit's nice to exercise both a bit more. Without the fix in this patch(but with the test change), the bug() case causes a segfault.Signed-off-by: Jeff King <peff@peff.net>Signed-off-by: Junio C Hamano <gitster@pobox.com>t/helper/test-trace2.c | 4 ++--usage.c                | 8 +++++---2 files changed, 7 insertions(+), 5 deletions(-)

上面的过程为:

  • 首先使用git bisect start命令启动该过程
  • 启动该过程后,Git会进入二分模式,并为自己设置一些状态信息,然后使用一个分离的HEAD来管理版本库的当前检出版本。该HEAD本质上是个匿名分支,可用于版本库中来回移动并视需要指定不同的修订版本。
  • 然后执行一个bad提交,因为此时默认在分离HEAD处,可用git bisect bad指定当前HEAD为bad
  • 然后利用git bisect good或git bisect bad对提示的提交指明其为good或为bad
  • 指明后Git会打印当前还有多少提交要确认,因为是二分搜索,每次确认数目都会减少一半
  • 当确认完毕,就会打印bad提交的具体信息

当然这过程中还有其它额外命令。

git bisect log可以打印该过程的log:

$ git bisect log
git bisect start
# bad: [5b71c59bc3b9365075e2a175aa7b6f2b0c84ce44] Git 2.37-rc1
git bisect bad 5b71c59bc3b9365075e2a175aa7b6f2b0c84ce44
# good: [1f8496c65f963d2b75ef57dc4f09dbc2f5646bf3] push: fix capitalisation of the option name autoSetupMerge
git bisect good 1f8496c65f963d2b75ef57dc4f09dbc2f5646bf3
# good: [99bbf4739d927a3d8183d1fc3f1ee7871aac9fb9] Merge branch 'jc/cocci-cleanup'
git bisect good 99bbf4739d927a3d8183d1fc3f1ee7871aac9fb9
# good: [d0d96b8280faf7c22c115374732f50972689c0d2] Merge branch 'js/ci-github-workflow-markup'
git bisect good d0d96b8280faf7c22c115374732f50972689c0d2
# bad: [aa11b94ef87050af9e4e0aab64f1ab89636c5be4] Merge branch 'jk/bug-fl-va-list-fix'
git bisect bad aa11b94ef87050af9e4e0aab64f1ab89636c5be4
# good: [7281c196b1166f1c00df33948c67b0ef81ba63a9] transfer doc: move fetch.credentialsInUrl to "transfer" config namespace
git bisect good 7281c196b1166f1c00df33948c67b0ef81ba63a9
# bad: [f8535596aa7bd7f6862af3fe6420ac12b17c9912] bug_fl(): correctly initialize trace2 va_list
git bisect bad f8535596aa7bd7f6862af3fe6420ac12b17c9912
# first bad commit: [f8535596aa7bd7f6862af3fe6420ac12b17c9912] bug_fl(): correctly initialize trace2 va_list

如果某条bad或good的判定不正确,可以结合git bisect reset和git bisect replay file使用某个文件作为输入重新执行该过程。

也可以使用git bisect visualize命令可视化地检查提交范围内的内容。

如果一切都结束了,则可以使用git bisect reset结束该过程,回到原来的分支上。

$ git bisect reset
Previous HEAD position was f8535596aa bug_fl(): correctly initialize trace2 va_list
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

git blame

该命令能够识别特定提交,通过用户一个文件的每一行最后是谁修改的和哪些提交做出了修改。

$ git blame -L 1, apply.h
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200   1) #ifndef APPLY_H
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200   2) #define APPLY_H
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200   3)
97b989ee3a9 (Denton Liu              2019-09-25 01:20:53 -0700   4) #include "hash.h"
ef3ca95475c (Elijah Newren           2018-08-15 10:54:05 -0700   5) #include "lockfile.h"
ef3ca95475c (Elijah Newren           2018-08-15 10:54:05 -0700   6) #include "string-list.h"
4e9a3252531 (René Scharfe            2022-01-07 13:16:53 +0100   7) #include "strmap.h"
ef3ca95475c (Elijah Newren           2018-08-15 10:54:05 -0700   8)
82ea77eca7a (Nguyễn Thái Ngọc Duy    2018-08-13 18:14:39 +0200   9) struct repository;
82ea77eca7a (Nguyễn Thái Ngọc Duy    2018-08-13 18:14:39 +0200  10)
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  11) enum apply_ws_error_action {
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  12)     nowarn_ws_error,
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  13)     warn_on_ws_error,
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  14)     die_on_ws_error,
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  15)     correct_ws_error
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  16) };
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  17)
71501a71d04 (Christian Couder        2016-08-08 23:02:59 +0200  18) enum apply_ws_ignore {

不过该打印结果看起来似乎太冗余了。

git log -Sstring

git log -Sstring根据给定的string沿着文件的差异历史搜索。通过搜索修订版本间的实际差异,该命令可以找到那些执行改变的提交。

$ git log -Sinclude --pretty=oneline --abbrev-commit apply.h
4e9a325253 apply: use strsets to track symlinks
97b989ee3a apply.h: include missing header
ef3ca95475 Add missing includes and forward declarations
7e1bad24e3 apply: refactor `git apply` option parsing
13b5af22f3 apply: move libified code from builtin/apply.c to apply.{c,h}
71501a71d0 apply: move 'struct apply_state' to apply.h

打印结果对应的左侧每个提交都添加或删除了包含include的行。但是如果某个提交添加和删除了相同数量的含关键词的行,它将不会显示出来。该提交必须有添加和删除数量上的变化才能计数。

Git版本控制管理——提交相关推荐

  1. 《Git版本控制管理(第2版)》——4.3 Git在工作时的概念

    本节书摘来自异步社区<Git版本控制管理(第2版)>一书中的第4章,第4.3节,作者:[美]Jon Loeliger , Matthew McCullough著,更多章节内容可以访问云栖社 ...

  2. java中git版本控制,git版本控制管理是什么?git如何实现版本控制?

    大家好,今天要跟大家讲的是关于git版本控制管理的一点小知识,git相信程序员小伙伴们都已经很熟悉了,很多项目开发都需要git,所以,git版本控制管理到底是干嘛的呢?Git又如何实现版本控制呢?下面 ...

  3. 【Git版本控制管理】Gitee(码云)和GitHub的使用

    远程仓库的使用 文章目录 远程仓库的使用 使用码云(Gitee) 使用GitHub 远程仓库是指托管在因特网或其他网络中的你的项目的版本库. 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读 ...

  4. Git版本控制管理——远程版本库

    之前提到的Git的所有操作都是在本地完成的,而实际项目开发并不是一个人就可以搞定的,通常需要团队的协作,而这些协作可能又不是在同一个地区的,这就涉及到Git的分布式特性了. Git的分布式特定会涉及到 ...

  5. 一篇文章让你全方位掌握git版本控制管理

    注:侵权请联系作者删除 目录 1.引入: 2.Git 的工作区域和流程 3.stash区域 4.git基本操作 A.git add B.git commit c.git pull D.git fetc ...

  6. Git版本控制管理——diff

    Git中的diff命令可以显示文件之间的差异,同时-r选项可以遍历两个树对象,同时显示它们的差异. 从Git中的对象类型上看,一个树对象值只代表版本库中的一个目录层级,它包含该目录下的直接文件和它的所 ...

  7. Git版本控制管理——合并

    之前提到了分支,既然有分,就一定有合. 在Git中,当一个分支中的修改与另一个分支中的修改不发生冲突的时候,Git会计算合并结果,并创建一个新提交来代表新的统一状态.但是当分支冲突时,Git并不解决冲 ...

  8. Git 版本控制管理(一)

    Git 是一个分布式版本控制工具,它的作者 Linus Torvalds 是这样给我们介绍 Git  -- The stupid content tracker(傻瓜式的内容跟踪器) 关于 Git 的 ...

  9. Git版本控制管理——简介

    说明 在大型项目开发或者多人协作开发时,都希望可以对软件代码进行管理和追踪,以便确认开发的进度和方便问题追溯.这就需要使用到版本控制系统(VCS),比如Git就是一款很优秀的版本控制工具.如今很多项目 ...

最新文章

  1. 黑马vue---14、v-model双向绑定
  2. 实现原理_Condition 实现原理
  3. Python于*args 和**kwargs使用
  4. hello,world———C++入门有感
  5. Android 获取网络错误
  6. kali升级python3.6_kali下将Python2.x切换至Python3.x
  7. 洛谷 P1890 gcd区间
  8. DB2 9 根本(730 磨练)认证指南,第 3 部门: 谋面 DB2 数据(4)
  9. pdfjs实现pdf预览
  10. 给MDK5/KEIL5安装51/ARM编译坏境
  11. Black Hat 2017:不容错过的七大主题演讲
  12. Infer的安装及基本使用
  13. 高并发场景以及应对技巧
  14. 保研之路——复旦计算机学院预推免
  15. jquery easyui下拉框多选 和原生多选下拉多选
  16. 双宾语与复合宾语,分词状语与独立主格状语
  17. 电子体温计方案温度传感器的解析
  18. 第十一课_编程语言发展史
  19. Cobalt Strike使用教程一
  20. 阿里云建立Web网站基本步骤

热门文章

  1. linux安装Oracle 11g详解
  2. error: expected declaration or statement at end of input
  3. java面试微信交流群-欢迎你的加入
  4. 每七本 你的生命有什么可能
  5. 文档编辑之markdown语法(typora)
  6. multienant oracle_甲骨文(Oracle Cloud)不愧是臭名昭著的垃圾公司
  7. Infiniband网络测速
  8. 安利给CIO的零信任安全指南
  9. TOP10! KubeCon + CloudNativeCon最受欢迎演讲视频
  10. 使用OpenCV-python实现以图搜图