Git06-提交

  • 在Git中,提交(commit)是用来记录版本库的变更的。
  • 当提交时,Git会记录索引的快照并把快照放进对象库。这个快照不包含该索引中任何文件或目录的副本,因为这样的策略会需要巨大的存储空间。Git会将当前索引的状态与之前的快照做一个比较,并派生出一个受影响的文件和目录列表。Git会为有变化的文件创建新blob对象,对有变化的目录创建新的树对象,对于未改动的文件和目录则会沿用之前的blob与树对象。
  • 将整个索引与之前某个状态的索引进行比较,看起来开销是比较大的,但整个过程是非常快的,因为每个Git对象都有一个SHA1散列值。如果两个对象甚至两个子树拥有相同的SHA1散列值,那么它们就是相同的。Git可以通过修剪有相同内容的子树来避免大量的递归比较
  • 提交的快照是串联在一起的,每个新的快照都指向它的先驱。随着时间的推移,一系列变更就表示为一系列提交。
  • 版本厍中的变更和提交之间是一一对应的关系:提交是将变更引入版本库的唯一方法,版本库中的任何变更都必须由一个提交引入。此项授权提供了问责制。任何情况下都不会出现版本库有数据变动而没有记录!试想一下,如果主版本库中的内容不知何故发生了变化,又没有任何记录记载这一切是如何发生的、谁干的,甚至是什么原因,那将是多么混乱啊。
  • 虽然最常见的提交情况是由开发人员引入的,但是Git自身也会引入提交。除了用户在合并之前做的提交外,合并操作自身会导致在版本库中多出一个提交。
  • Git非常适合频繁的提交,并且它还提供了丰富的命令集来操作这些提交。
  • 创建一个新的版本库
//(1)创建一个新的版本库
]# mkdir test_commit
]# cd test_commit/
]# git init

//(2)创建第一个提交
]# echo "hello world" > hello.txt
]# git add hello.txt
]# git commit -m "Commit a file that says hello"

//(2)创建第二个提交
]# echo "hello world 2" > hello2.txt
]# git add hello2.txt
]# git commit -m "Commit a file that says hello2"

//(2)创建第三个提交
]# echo "hello world 3" > hello3.txt
]# git add hello3.txt
]# git commit -m "Commit a file that says hello3"

1、原子变更集

  • 每个Git提交都代表一个相对于之前状态的单个原子变更集。对于一个提交中所有做过的改动,无论多少目录、文件、行、字节的改变,要么全部应用,要么全部拒绝。
  • 在底层对象模型方面,原子性是有意义的:一个提交的快照代表所有文件和目录的变更,它代表一个树的状态,而两个提交快照之间的变更集就代表一个完整的树到树的转换(后面会讲,有关提交之间的衍生差异来了解更多细节)。
  • 考虑把一个函数从一个文件移动到另一个文件的流程。
    • 假设你在第一次提交中删除了某函数,第二次提交中把该函数加回来。那么在函数被删除期间版本库的这段历史记录中,就会出现一个小小的语义鸿沟(semantic gap),调换这两次提交的顺序也是有问题的。在这种情况下,第一次提交之前和第二次提交之后,代码在语义上都是一致的,而在第一次提交过后的代码则是错误的。
    • 然而,使用原子提交同时添加和删除该函数,就不会有语义鸿沟出现在历史记录中。
  • Git不关心文件为什么变化,即变更的内容并不重要。作为开发人员,可以将一个函数从这里移动到那里,并期望这算一次移动。但是也可以先提交删除再提交添加。Git对此并不关心,因为它丝毫不在乎文件的语义。
  • 但这揭示了Git实现原子性操作的关键原因之一:它允许你根据一些最佳实践来设计你的提交
  • 最后,你可以放心Git没有把你的版本库置于两次提交之间的过渡状态。

2、识别提交

  • 无论你是独自编码还是在团队中工作,识别提交都是一个很重要的任务。
    • 当创建新分支时,必须要选择某个提交来作为分支的起点。
    • 当比较代码差异时,必须要指定两个提交。
    • 当编辑提交历史记录时,必须提供一个提交集。
  • 在Git中,可以通过显示或隐式引用来指定每一个提交
    • 显式引用:是直接使用提交ID,即提交对象的40位十六进制SHA1值。
    • 隐式引用:是始终指向最新提交的HEAD。
  • 尽管有时这两种引用都不方便,但是幸运的是,Git提供了多种机制来为提交命名,这些机制有各自的优势,需要根据上下文来选择。例如,在分布式环境中,当你要与同事讨论相同数据的提交时,最好使用两个版本库中相同的提交名。另一方面,如果你在自己的版本库上工作,当你需要查找一个分支几次提交之前的状态时,有一个简单相关的名字足矣。

2.1、绝对提交名

  • 每一个提交都有一个唯一的SHA1值,即提交ID。无论提交处于版本库历史中的任何位置,SHA1值都对应相同的提交。
  • 每一个提交的SHA1值都是全局唯一的,不仅仅是对某个版本库,而且是对任意版本库都是唯一的。例如,如果一个开发人员在他的版本库有一个特定的提交ID,并且你在自己的版本库中发现了相同的提交ID,那么你就可以确定你们有包含相同内容的相同提交。此外,因为导致相同提交ID的数据包含整个版本库树的状态和之前提交的状态,所以通过归纳论证,可以得出一个更强的推论:你可以确定你们讨论的是之前完全相同的开发线,包括提交也是相同的。
  • 由于输入一个40位十六进制的SHA1数字是一项繁琐且容易出错的工作,因此Git允许你使用版本库的对象库中唯一的前缀来缩短这个数字。
//通过HEAD获取当前提交的SHA1值,
]# git log -1 --pretty=oneline HEAD
970af6200f7b27153a0cc0397db2f432b126faa4 (HEAD -> master) Commit a file that says hello

//使用对象的唯一前缀来查看提交ID
]# git log -1 --pretty=oneline 970a
970af6200f7b27153a0cc0397db2f432b126faa4 (HEAD -> master) Commit a file that says hello
  • 虽然标签名并不是全局唯一的,但它会明确的指向一个的提交,这种指向是不会随着时间而改变的(当然,除非你明确地修改它)。

2.2、引用和符号引用

  • 引用(ref)是一个SHA1散列值,指向Git对象库中的对象。虽然一个引用可以指向任何Git对象,但是它通常指向提交对象。
  • 符号引用(symbolic reference),或称为symref,间接指向Git对象,但它仍是一个引用。
  • 本地分支名称远程跟踪分支名称标签名都是引用。
  • 每一个符号引用都有一个以ref开始的明确全称,并且都分层存储在版本库的.git/refs/目录中。目录中有三种不同的命名空间代表不同的引用:
    • refs/heads/ref代表本地分支。
    • refs/remotes/ref代表远程跟踪分支。
    • refs/tags/ref代表标签。
  • 例如,一个叫做dev的本地特性分支就是refs/heads/dev的缩写。因为远程追踪分支在refs/remotes/命名空间中,所以origin/master实际上是refs/remotes/origin/master。最后,标签v2.6.23就是refs/tags/v2.6.23的缩写。
  • 可以使用引用全称或其缩写,但是如果你有一个分支和一个标签使用相同的名字,Git会应用消除二义性的启发式算法,根据gitrev-parse手册上的列表选取第一个匹配项。
  • Git自动维护几个用于特定目的的特殊符号引用。这些引用可以在使用提交的任何地方使用。
    • HEAD:始终指向当前分支的最近提交。当切换分支时,HEAD会更新为指向新分支的最近提交。
    • ORIG_HEAD:某些操作,例如合并(merge)和复位(reset),会把调整为新值之前的先前版本的HEAD记录到ORIG_HEAD中。可以使用ORIG_HEAD来恢复或回滚到之前的状态或者做一个比较。
    • FETCH_HEAD:当使用远程库时,git fetch命令将所有抓取分支的头记录到.git/FETCH_HEAD中。FETCH_HEAD是最近抓取(fetch)的分支HEAD的简写,并且仅在刚刚抓取操作之后才有效。使用这个符号引用,哪怕是一个对没有指定分支名的匿名抓取操作,都可以也在gitfetch时找到提交的HEAD。
    • MERGE_HEAD:当一个合并操作正在进行时,其他分支的头暂时记录在MERGE_HEAD中。换言之,MERGE_HEAD是正在合并进HEAD的提交。
  • 所有符号引用都可以用底层命令git symbolic-ref进行管理。
  • Git中有一个特殊符号集来指代引用名。两个最常见的符号“^”和符号“~”。
    • 在转向另一个引用时,冒号“:”可以用来指向一个产生合并冲突的文件的替代版本。

2.3、相对提交名

  • Git还提供一种机制来确定相对于另一个引用的提交,通常是分支的头。
    • 例如,master和master^,其中master^始终指的是在master分支中的倒数第二个提交。还有一些其他的方法,例如master^^、master~2,甚至像master~10^2~2^2这样复杂的名字。
  • 除了第一个根提交之外,每一个提交都来自至少一个比它更早的提交,这其中的直接祖先称作该提交的父提交。若某个提交存在多个父提交,那么它必定是由合并操作产生的。其结果是,每个分支都有一个父提交贡献给合并提交。
  • 在同一代提交中,插入符号^是用来选择不同的父提交的。给定一个提交C,C^1是其第一个父提交,C^2是其第二个父提交,C^3是其第三个父提交等等,如图6-1所示。

  • 波浪线~用于返回父提交之前并选择上一代提交。同样,给定一个提交C,C~1是其第一个父提交,C~2是其第一个祖父提交,C~3是第一个曾祖父提交。当在同一代中存在多个父提交时,紧跟其后的是第一个父提交的第一个父提交。你可能会注意到,C^1和C~1都指的是C的第一个父提交,两个都是对的,如图6-2所示。

  • Git也支持其他形式的简写和组合。如C^和C~两种简写形式分别等同于C^1和C~1。另外,C^^与C^1^1相同,因为这代表提交C的第一父提交的第一父提交,它也可以写做C~2。
  • 通过把引用与“^”和“~”组合,就可以从提交历史图中引用任意提交。不过要注意,这些名字都相对于引用的当前值。如果当前引用指向一个新提交,那么提交历史图将变为“新版本”,所有父提交“辈分”都会上升一层。
//查看master分支的SHA1值
]# git rev-parse master
f0cd009b8980e0845e271c568b44bace460c2aa2

//列出当前分支的历史提交
]# git show-branch --more=10
[master] Commit a file that says hello3
[master^] Commit a file that says hello2
[master~2] Commit a file that says hello
  • git rev-parse命令会把任何形式的提交名(包含标签、相对名、简写或绝对名称)转换成对象库中实际的提交ID。

3、提交历史记录

3.1、查看提交历史记录

  • git log可以列出每一个从HEAD中找到的历史记录的提交日志消息。从HEAD提交开始显示,并从提交图中回溯。它们大致按照时间逆序显示,但是要注意当回溯历史记录的时候,Git是依附于提交图的,而不是时间。
  • 如果你提供一个提交名(如git log commit),那么将从该提交开始回溯。对于查看某个分支的历史记当是非常有用的。
//显示最近10次的提交历史记录(仅有三个提交)
]# git log -n 10 --pretty=oneline HEAD
f0cd009b8980e0845e271c568b44bace460c2aa2 (HEAD -> master) Commit a file that says hello3
f7eb66f834c9f3e3cd3c2504413cccd408f39ac6 Commit a file that says hello2
970af6200f7b27153a0cc0397db2f432b126faa4 Commit a file that says hello

//查看master分支的最近10次的提交记录
]# git log -n 10 master
commit f0cd009b8980e0845e271c568b44bace460c2aa2 (HEAD -> master)
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 20:42:24 2023 +0800

    Commit a file that says hello3

commit f7eb66f834c9f3e3cd3c2504413cccd408f39ac6
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 20:42:00 2023 +0800

    Commit a file that says hello2

commit 970af6200f7b27153a0cc0397db2f432b126faa4
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 19:21:54 2023 +0800

    Commit a file that says hello
  • 给定一个范围,git log将会把在since到until之间的所有提交显示出来。
    • --pretty=short:调整每个提交的信息数量,可选值有oneline、short、ull。
    • --abbrev-commit:缩写提交ID。
//列出在master~2到master之间的提交记录
]# git log --pretty=short --abbrev-commit master~2..master
commit f0cd009 (HEAD -> master)
Author: heng ha <hengha@123.com>

    Commit a file that says hello3

commit f7eb66f
Author: heng ha <hengha@123.com>

    Commit a file that says hello2
  • --stat:会列出提交中更改的文件以及文件中的改动
    • 也可以使用git log -n 2 --stat

    • 提示,比较git log --stat和git diff --stat的输出,其根本区别在于两者的现实。前者为指定范围中每个单独提交产生一个摘要,而后者输出命令行中指定的两个版本库状态差异的汇总。
]# git log --pretty=short --stat master~2..master
commit f0cd009b8980e0845e271c568b44bace460c2aa2 (HEAD -> master)
Author: heng ha <hengha@123.com>

    Commit a file that says hello3

 hello3.txt | 1 +
 1 file changed, 1 insertion(+)

commit f7eb66f834c9f3e3cd3c2504413cccd408f39ac6
Author: heng ha <hengha@123.com>

    Commit a file that says hello2

 hello2.txt | 1 +
 1 file changed, 1 insertion(+)
  • 使用-p选项来列出提交引进的补丁或变更。
//从该提交开始回溯
]# git log -p f7eb66f834c9f3e3cd3c2504413cccd408f39ac6
commit f7eb66f834c9f3e3cd3c2504413cccd408f39ac6
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 20:42:00 2023 +0800

    Commit a file that says hello2

diff --git a/hello2.txt b/hello2.txt
new file mode 100644
index 0000000..d0e1e95
--- /dev/null
+++ b/hello2.txt
@@ -0,0 +1 @@
+hello world 2

commit 970af6200f7b27153a0cc0397db2f432b126faa4
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 19:21:54 2023 +0800

    Commit a file that says hello

diff --git a/hello.txt b/hello.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/hello.txt
@@ -0,0 +1 @@
+hello world
  • 查看对象库中对象信息。
//可以使用它来查看某个提交。
]# git show HEAD~2
commit 970af6200f7b27153a0cc0397db2f432b126faa4
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 19:21:54 2023 +0800

    Commit a file that says hello

diff --git a/hello.txt b/hello.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/hello.txt
@@ -0,0 +1 @@
+hello world

//查看某个特定的blob对象信息。
]# git show heads/master
commit f0cd009b8980e0845e271c568b44bace460c2aa2 (HEAD -> master)
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 20:42:24 2023 +0800

    Commit a file that says hello3

diff --git a/hello3.txt b/hello3.txt
new file mode 100644
index 0000000..ee87853
--- /dev/null
+++ b/hello3.txt
@@ -0,0 +1 @@
+hello world 3

3.2、提交图

  • gitk命令:查看提交图。(在windows上使用)

1、完整的提交图

  • 对一个仅仅拥有几个提交、合并和补丁的小版本库来说,需要展示细节的图像也是非常难以实现的。例如,图6-3显示了一幅更完整但仍稍显简单的提交图。

2、简化的提交图

  • 每个提交都使用一个树对象来表示整个版本库。图6-4与图6-3展示了同样的一幅提交图,但是略去了树对象和blob对象。为了便于讨论或引用,通常在提交图中还会显示分支名。

3、标记的提交图

  • 在计算机科学领域,图(graph)表示的是一组节点之间的关系的工具。根据不同的属性将图分为几种类型。Git使用其中的一种--有向无环图(DAG)。
  • DAG具有两个重要的属性。首先,图中的每条边都从一个节点指向另一个节点(称为有向)。其次,从图中的任意一节点开始,沿着有向边走,不存在可以回起始点的路径(称为无环)。
  • Git通过DAG来实现版本库的提交历史记录。在提交图中,每个节点代表一个单独的提交,所有边都从子节点指向父节点,形成祖先关系。图6-3和图6-4都属于DAG。
  • 当谈及提交历史和讨论提交图中提交的关系时,单独的提交节点通常被标记,如图6-5所示。

  • 在图中,时间轴是从左到右。A是初始提交,因为它没有父提交,B发生在A之后。E和C发生在B之后,但是对于C和E之间的相对时间关系则没有明确声明,谁都有可能发生在另一个之前。事实上,Git并不关心提交的时间(无论是绝对时间还是相对时间)。
  • E和C拥有共同的父提交B。因此,B是一个分支的源头。
    • 主分支是从提交A、B、C开始。
    • pr-17的分支是由A、B、E、F和G提交形成的。
    • 提交H是一个合并提交(mergecommit),在此处pr-17分支合并到了master分支。因为它是合并操作,所以H有多个父提交,即G和D。这次提交后,master将指向新提交H,而pr-17仍继续指向提交G。

4、无箭头的提交图

  • 在现实中,插入提交的支根末节是不重要的。此外,提交指向它的父提交的实现细节也经常被忽略,如图6-6所示。

  • 这种提交图经常用来讨论一些Git命令的操作和每个操作是如何修改提交历史的。
  • 要理解提交的DAG所必须知道的,首先每个提交都会有零到多个父提交:
    • 通常只有一种提交没有父提交--初始提交(initial commit),它一般出现在图的底部。
    • 一般的提交有且只有一个父提交,也就是提交历史记录中的上一次提交。当进行修改时,修改就是新提交和其父提交之间的差异。
    • 合并提交拥有多个父提交。
  • 有多个子提交的提交,就是版本历史记录出现分支的地方。该提交就是分支点
  • 提示,分支的起点并没有永久记录,但Git可以通过git merge-base命令来在算法上确定它们。

3.3、提交范围

  • 许多Git命令都允许指定提交范围。在最简单的实例中,一个提交范围就是一系列提交的简写。更复杂的形式允许过滤提交。
  • 双句点(..)形式就表示一个范围,如“开始..结束”(不包含头,包含尾)。通常情况下,提交范围用来检查某个分支或分支的一部分。
    • 如果省略start或end,就默认用HEAD替代。因此,“..end”等价于“HEAD..end”,“start..”等价于“start..HEAD”。

1、线性提交图

  • 例如master~12..master~10来指定主分支上倒数第11次和倒数第10次之间的提交,如图6-8所示。

2、非线性提交图

  • 当版本库的提交历史记录是线性的时,范围的定义很容易理解。但在图中加入分支或合并之后,事情开始变得棘手了,因此理解严格的范围定义很重要。
  • 在图6-11中,master分支上的提交V合并到topic分支上的提交B。

  • 范围topic..master表示在master分支而不在topic分支的提交。master分支上提交V和之前的所有提交(即集合{…, T, U, V})都加入到topic分支中了,这些提交就排除了,只有W、X、Y和Z在该范围中。

3、对称差

  • 三个句点(如A...B)则表示A和B之间的对称差(symmetric difference),也就是在A和B的并集中,且不在在A和B的交集中。
    • 可以这样理解A和B分支间的对称差——显示分支A或分支B的一切,但只回到两个分支的分离点。
//获取A和B之间的对称差
git rev-list A B --not $(git merge-base --all A B)
  • 如图6-14所示。
    • 两个分支的并集是:(A, ..., I, U, ..., Z)
    • 两个分支的交集是:(A, B, C, U, V, W)
    • 对称差(并集-交集)是:(D, E, F, G, H, I, X, Y, Z)

4、交集操作

  • 注意,Git实际上并不支持真正的范围操作符。引入这些纯粹只为了概念上的便利,比如A..B就代表底层的^A B形式。
  • 实际上,Git在它的命令行上允许功能更强大的提交集操作。接受范围参数的命令实际上接受任意序列的包含和排除提交作为参数。
//选择在master分支但不在dev、topic或bugfix分支上的所有提交
git log ^dev ^topic ^bugfix master
  • 该命令的作用是,如果某个分支来自另一个版本库的提交,那么可以快速地发现那些在你自己版本库而不在别人版本库中的提交了!

4、查找提交

4.1、使用git bisect

  • git bisect命令是一个功能强大的工具,它一般基于任意搜索条件查找特定的错误提交。
  • git bisect命令通常为了找出某个导致版本库产生倒退或bug的特殊提交。例如,当你从事Linux内核开发工作时,git bisect命令可以帮助你找到问题和bug,比如编译失败、无法启动、启动后无法执行某些任务或者不再拥有所需的性能特性等。在上述的这些情况下,git bisect可以帮助你分离并定位导致该问题的提交。(当发行代码有问题时,git bisect命令可以从版本库中找到是哪个提交引起的。)
  • 只需要在开始的时候提供一个初始的“好”提交和“坏”提交,然后重复回答“这个版本是否可以正常工作”这个问题。
    • 在实际中,“坏”提交往往是当前的HEAD,因为那是你在工作时突然注意到出现问题的地方或是你被分配了一个bug修复工作。
    • 寻找一个初始的“好”提交可能会有点儿困难,因为它通常埋藏在历史记录中的某个地方。你可以自己选择或猜测在版本库中你知道的某个“好”提交作为开始。这可以是v.2.6.25这样的标签,或者是100个修订之前的某个提交(在你的主分支上就是master~100)。理想情况下,好提交会靠近你的“坏”提交(master~25会比master~100更好),并且不会埋得太久远。在任何情况下,你需要知道或能验证它事实上是否是一个好提交。
  • 至关重要的是你要从一个干净的工作目录中启动git bisect。此过程会调整你的工作目录来包含版本库的不同版本。从脏的工作目录开始是在自寻烦恼。

1、启动查找

  • 启动二分搜索后,Git将进入二分模式,并为自己设置一些状态信息。Git使用一个分离的(detached)HEAD来管理版本库的当前检出版本。这个分离的HEAD本质上是一个匿名分支,它可用于在版本库中来回移动并视需要指定不同的修订版本。
]# git bisect start

2、告诉Git一个“坏”提交”

  • 一旦启动,就要告诉Git哪个提交是“坏”的。一般将当前的HEAD作为“坏”提交”。
//告诉Git一个“坏”提交”(默认使用当前HEAD)
]# git bisect bad

3、告诉Git一个“好”提交”

//告诉Git一个“好”提交”
]# git bisect good 970af6200f7b27153a0cc0397db2f432b126faa4
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[f7eb66f834c9f3e3cd3c2504413cccd408f39ac6] Commit a file that says hello2
  • 识别“好”的和“坏”的版本,界定了从“好”到“坏”转变的提交范围。在查找的每一步中,Git都会告诉你在范围中有多少个修订版本。Git也会通过检出那些介于“好”与“坏”之间中点的修订版本来修改你的工作目录。现在你要回答以下问题了:“现在这个版本是好是坏?”,你每次回答这个问题时,Git都会缩小一半的搜索空间,并定位新的修订版本,检出后继续问你“是好是坏”的问题。

4、告诉Git二分法都到的提交是好的,还是坏的

//如果回答good
]# git bisect good
f0cd009b8980e0845e271c568b44bace460c2aa2 is the first bad commit
commit f0cd009b8980e0845e271c568b44bace460c2aa2
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 20:42:24 2023 +0800

    Commit a file that says hello3

 hello3.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 hello3.txt

//如果回答bad
]# git bisect bad
f7eb66f834c9f3e3cd3c2504413cccd408f39ac6 is the first bad commit
commit f7eb66f834c9f3e3cd3c2504413cccd408f39ac6
Author: heng ha <hengha@123.com>
Date:   Sat Mar 18 20:42:00 2023 +0800

    Commit a file that says hello2

 hello2.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 hello2.txt

5、bisect日志

  • 在整个二分搜索过程中,Git维护一个日志来记录你的回答及其提交ID。
  • 如果你在此过程中迷失了,或者想重新开始,那么输入git bisect replay 命令使用日志文件作为输入。如果需要,这是一种很好的机制来在此过程中回退一步并选用其他的路径。
]# git bisect log
git bisect start
# bad: [f0cd009b8980e0845e271c568b44bace460c2aa2] Commit a file that says hello3
git bisect bad f0cd009b8980e0845e271c568b44bace460c2aa2
# good: [970af6200f7b27153a0cc0397db2f432b126faa4] Commit a file that says hello
git bisect good 970af6200f7b27153a0cc0397db2f432b126faa4
# bad: [f7eb66f834c9f3e3cd3c2504413cccd408f39ac6] Commit a file that says hello2
git bisect bad f7eb66f834c9f3e3cd3c2504413cccd408f39ac6
# first bad commit: [f7eb66f834c9f3e3cd3c2504413cccd408f39ac6] Commit a file that says hello2

6、告诉Git完成了查找

  • 最后,当你完成二分查找、完成二分记录并保存了状态时,非常重要的一点是要告诉Git你已经完成了。你可能还记得,整个二分过程在一个分离的HEAD上执行。
//列出分支
]# git branch

//切回到原来的分支上
]# git bisect reset

4.2、使用git blame

  • git blame命令显示一个文件中的每一行是谁修改的(最后一次修改),是哪次提交做出的修改。
]# git blame hello.txt 
^970af62 (heng ha 2023-03-18 19:21:54 +0800 1) hello world

4.3、使用Pickaxe

  • git blame命令告诉你文件的当前状态,git log -Sstring则根据给定的string沿着文件的差异历史搜索。通过搜索修订版本间的实际差异,这条命令可以找到那些执行改变(增加或删除)的提交。
]# git log -Shello --pretty=oneline --abbrev-commit hello.txt
970af62 Commit a file that says hello
  • 注意,如果某个提交添加和删除了相同数量的含关键词的行,它将不会显示出来。该提交必须有添加和删除数量上的变化才能计数。
  • 带有-S选项的git log命令称为pickaxe,对你来说这是一种暴力考古。

1

#                                                                                                                        #
posted @ 2023-03-19 20:37  麦恒  阅读(36)  评论(0编辑  收藏  举报