首页 > 其他分享 >Learn Git in 30 days——第 09 天:比对文件与版本差异

Learn Git in 30 days——第 09 天:比对文件与版本差异

时间:2023-08-31 10:33:05浏览次数:39  
标签:HEAD git 30 days 物件 09 版本 commit diff

写的非常好的一个Git系列文章,强烈推荐

原文链接:https://github.com/doggy8088/Learn-Git-in-30-days/tree/master/zh-cn

使用任何版本控制软件的过程中,经常会需要查看历史记录与比对版本之间的差异。而在使用 Git 的时候要如何进行比对,将是本文重点。

准备工作目录

我们通过以下指令快速建立一个拥有两个文件与两个版本变更记录的 Git 仓库与工作目录:

mkdir git-demo
cd git-demo
git init

echo 1 > a.txt
echo 2 > b.txt
git add .
git commit -m "Initial commit"

echo 3 > a.txt
echo 4 > b.txt
git add .
git commit -m "Update a.txt and b.txt to 3 and 4"
 

关于 git diff 的基本观念

在 Git 中比对两个版本之间的差异,通常会用 git diff 命令,我们先执行一个简单的命令,比对两个版本之间的差异:

  1. 先执行 git log 取得版本信息,并取得最近两个 commit 物件的 id
  2. 我们在执行 git diff commit1 commit2 指令,比对两个版本间的差异,其中 commit1 请用较旧的版本,而 commit2 则用较新的版本。

如下图示:

image

我们从 git diff 执行的输出结果,将可得到一个执行的结果。由于我们这两个版本库中有两个文件,而且在这两个版本之间也都有异动,所以他会列出两段「差异比对」的结果。

各位可以从上图看到每一段都是以 diff --git 开头,代表 git 对哪两个文件进行比对。

第二行的 index 37bcc8b..d855592 100644 则是代表 git 在做这次比对时的「标头信息」(Header Line),这里可能会有好几行,信息不一定只有这些。这里会标示许多关于此次差异比对的额外信息。例如 index 这行,后面的两个 hash id (37bcc8b..d855592) 就代表在 Git 物件仓库(object storage)中的两个 blob 物件 id,用来比较这两个 blob 物件。在后面的 100644 则是 git 属性,有点类似 Linux 环境下的文件属性,例如宣告这是个文件、目录、可读、可写、可执行之类的。以下是几个常见的 git 属性范例:

0100000000000000 (040000): Directory
1000000110100100 (100644): Regular non-executable file
1000000110110100 (100664): Regular non-executable group-writeable file
1000000111101101 (100755): Regular executable file
1010000000000000 (120000): Symbolic link
1110000000000000 (160000): Gitlink
 

相关连结可参考以下讨论串:

接下来第三行的 --- a/a.txt 则代表两个比对的版本中「比较旧的」那个版本。

接下来第四行的 +++ b/a.txt 则代表两个比对的版本中「比较新的」那个版本。

接下来第五行的 @@ -1 +1 @@ 则代表这个文件在旧版的总行数与新版的总行数,-1 代表旧版只有 1 行,+1 代表新版也只有 1 行。

最后则是列出所有变更的内容,这里有三种可能的表示法:

  • 以減号 - 号开头,代表从旧版到新版的过程中,此行被删除了。
  • 以加号 + 号开头,代表从旧版到新版的过程中,此行是被新增上去的。
  • 以空白字元开头,则代表这一行在两个版本中都有出现,没有任何变更。

如此一来就完成了这两个版本中第一个 blob 物件的差异比对,接着会显示该版本中第二个 blob 物件的差异比对,以此类推。

在 Git 中使用 git diff 的时候,事实上是以 tree 物件为比较的单位,我们从【第 06 天:解析 Git 资料结构 - 物件结构】文章图解与影片中有学到,其实每一个 commit 物件都会包括一个根目录的 tree 物件。所以我们刚刚利用 git diff 比对两个 commit 物件时,其实比对的是 commit 物件下的那个 tree 物件,而比对的过程又会递归的一直比下去。由此你应该可以感受到,Git 的 diff 比对机制十分强大,你可以很快速的比对出任意两个版本之间的异动比较。

在使用 git diff 命令时,主要有三种 tree 物件的来源,分別是:

  • 在所有的 commit graph 中存在的 tree object,也就是任意版本中任意一个 tree 物件的意思。
  • 索引 (index),代表你已经将文件状态送进「索引资料库」的那些信息,此时通过 git add 命令时,其实 tree 物件已经被建立。
  • 你目前的工作目录 (working directory),虽然工作目录的改变还没有变成 tree 物件,但通过 git diff 是可以这样用的。

四种基本的比较方式

要通过 git diff 命令比对任意两个版本,通常会有以下四种指令的用法:

  1. git diff

    在什么参数都不加的使用情況,比对的是「工作目录」与「索引」之间的差异。这是个很常用的指令,因为当你执行 git add . 指令之前,先通过 git diff 查看你自己到底改了哪些东西。

    注:事实上,在使用 Git 版本控制的过程中,在执行 git commit 之前,的确有可能会执行 git add 指令好几次,用以确认到底哪些文件要加入到索引之中,最后才会 commit 进版本。

  2. git diff commit

    如果你只在 git diff 之后加上一个 commit id,比对的是「工作目录」与「指定 commit 物件里的那个 tree 物件」。

    最常用的指令是 git diff HEAD,因为这代表你要拿「工作目录」与「当前分支的最新版」进行比对。这种比对方法,不会去比对「索引」的状态,所以各位必须区分清楚,你到底比对的是什么 tree 物件的来源。

  3. git diff --cached commit

    在执行 git commit 之前,索引状态应该已经都准备好了。所以如果你要比对「当前的索引状态」与「指定 commit 物件里的那个 tree 物件」,就可以用这个指令完成比对任务。

    最常用的指令一样是 git diff --cached HEAD,这个语法代表的是「当前的索引状态」与「当前分支的最新版」进行比对。这种比对方法,不会去比对「工作目录」的文件内容,而是直接去比对「索引」与「目前最新版」之间的差异,这有助于你在执行 git commit 之前找出那些变更的内容,也就是你将会有哪些变更被建立版本的意思。

    注1: git diff --cached 与 git diff --staged 是完全一样的结果,--staged 只是 --cached 的別名,让你比较好记而已!

    注2: git diff --cached 与 git diff --cached HEAD 执行时也是完全一样的结果,最后的 HEAD 可以省略。

  4. git diff commit1 commit2

    最后一种则是通过两个不同的版本 ( commit id ) 来比对其差异,这个命令可以跳过「索引」与「工作目录」的任何变更,而是直接比对特定两个版本。事实上 Git 是比对特定两个版本 commit 物件内的那个 tree 物件。

    最常用的指令则是 git diff HEAD^ HEAD 命令,这代表你要比较【最新版的前一版】与【最新版】之间的差异。这里的 HEAD 与 ^ 的意义,我们会在日后的文章中说明。

今日小结

今天介绍的 git diff 是个很常用的指令,各位应该熟练地使用它。我们最后来复习一下其常用指令的差异:

git diff                 => 工作目录 vs 索引
git diff HEAD            => 工作目录 vs HEAD
git diff --cached HEAD   => 索引     vs HEAD
git diff --cached        => 索引     vs HEAD
git diff HEAD^ HEAD	     => HEAD^   vs HEAD
 

我重新整理一下本日学到的 Git 指令与参数:

  • git log
  • git diff
  • git diff HEAD
  • git diff --cached
  • git diff --staged
  • git diff HEAD^ HEAD

标签:HEAD,git,30,days,物件,09,版本,commit,diff
From: https://www.cnblogs.com/songzhenhua/p/17668919.html

相关文章

  • 二分查找(两种模板)/高精度 (加 减) 计算模板(2023/8/30)
    //二分查找(两种模板)#include<iostream>usingnamespacestd;#defineN100001inta[N];intmain(){intn,m;cin>>n>>m;for(inti=0;i<n;i++)scanf("%d",&a[i]);while(m--){intx;scanf("%d"......
  • 闲话8.30
    今天好像终于没摆了。上午姬芈让vp一张CF,div3的C切不出来我是不是该退役了啊......
  • 8.30日遇到的问题及其解决
    问题1问题描述:在piplist显示没有opencv包,但是可以运行opencv的代码。原因:opencv被编译成了cv2.so文件供python调用解释:参考IndexOut的手动编译opencv生成cv2.so文件供python调用(http://t.csdn.cn/9ujLu)问题2问题描述:安装boost库总是下载失败原因:用的是官方镜像解决:换国......
  • node18 vue2启动报错 error:0308010C:digital envelope routines::unsupported
    出现原因貌似是因为是因为node17版本开始发布的OpenSSL3.0,而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响。解决方法第一种方法降低node版本降低到17以下即可,如项目不能降低版本看后面的解决方式第二种方法设置NODE_OPTIONS环境变量......
  • 30s无痛进入状态
    来源:让状态切换和喝水一样简单,30s停止胡思乱想学习进入状态从听开始。接收内容比思考和输出内容更加容易,人本能会从轻松愉快的事情做起,从只听不做开始,听一个会儿,就会进入状态。提示一来,进入状态。给大脑一个固定提示,只在专注时适合的提示,如古典音乐,学习视频。打开你要看的视频......
  • P7809 [JRKSJ R2] 01 序列 题解
    对于第二种操作,很容易想到只有\(1\)或\(2\)两种答案,若该区间内存在\(01\)这个子序列,那么答案为\(2\)反之为\(1\).可以通过对该\(01\)串做一个前缀和,若出现\(01\)这个子序列就累加,最后判断左右端点是否相等即可,时间复杂度\(O(n)\).对于第一种操作,\(\text{Subtest1}......
  • 20230802模拟赛
    20230802模拟赛T1数学题题意令\(A,B,C\)为三个质数(\(A\leqB\leqC\)),\(N=A\timesB\timesC\)。给出\(N(1\leqN\leq10^{14})\),求\(B\)。题解由\(A\leqB\leqC\)可证复杂度直接枚举\(1e7\)个质数,求\(B\)。T2子序列题意给定一个长度为\(n(\leq35)\)的序列:......
  • 【230829-8】▲ABC中,tanC=12/5,a=b=13开方,BC边上的中点为D。则Sin∠BAC=?,AD=?
    ......
  • 20230627 java.net.URL
    介绍java.net.URLpublicfinalclassURLimplementsjava.io.SerializableURI是个纯粹的语法结构,包含用来指定Web资源的字符串的各种组成部分URL是URI的一个特例,它包含了用于定位Web资源的足够信息URL语法authority部分具有以下形式:[user-info@]host[:port]......
  • 20230627 java.net.URI
    介绍java.net.URIpublicfinalclassURIimplementsComparable,SerializableURI是个纯粹的语法结构,包含用来指定Web资源的字符串的各种组成部分URL是URI的一个特例,它包含了用于定位Web资源的足够信息URI语法URI具有以下句法:[scheme:]schemeSpecficPart[#fra......