git的show-diff命令执行入口函数main(show-diff.c):

50 int main(int argc, char **argv)
51 {
52         int entries = read_cache();
53         int i;
54
55         if (entries < 0) {
56                 perror("read_cache");
57                 exit(1);
58         }
59         for (i = 0; i < entries; i++) {
60                 struct stat st;
61                 struct cache_entry *ce = active_cache[i];
62                 int n, changed;
63                 unsigned int mode;
64                 unsigned long size;
65                 char type[20];
66                 void *new;
67
68                 if (stat(ce->name, &st) < 0) {
69                         printf("%s: %s\n", ce->name, strerror(errno));
70                         continue;
71                 }
72                 changed = match_stat(ce, &st);
73                 if (!changed) {
74                         printf("%s: ok\n", ce->name);
75                         continue;
76                 }
77                 printf("%.*s:  ", ce->namelen, ce->name);
78                 for (n = 0; n < 20; n++)
79                         printf("%02x", ce->sha1[n]);
80                 printf("\n");
81                 new = read_sha1_file(ce->sha1, type, &size);
82                 show_differences(ce, &st, new, size);
83                 free(new);
84         }
85         return 0;
86 }

git的show-diff命令比较的是同一文件在工作目录区(Working Directory)相对暂存区(cache)的变化.Line52:58获得cache信息,如果cache为空,视为错误,直接返回.Line59:84遍历cache区中的每个cache_entry对象,进行比较的逻辑.Line68通过系统调用stat获得工作目录区该文件的状态.Line72调用函数match_stat比较该文件在工作目录区和cache区中的文件元数据信息是否发生改变.该函数的实现为(show-diff.c):

 8 #define MTIME_CHANGED   0x00019 #define CTIME_CHANGED   0x0002
10 #define OWNER_CHANGED   0x0004
11 #define MODE_CHANGED    0x0008
12 #define INODE_CHANGED   0x0010
13 #define DATA_CHANGED    0x0020
14
15 static int match_stat(struct cache_entry *ce, struct stat *st)
16 {
17         unsigned int changed = 0;
18
19         if (ce->mtime.sec  != (unsigned int)st->st_mtim.tv_sec ||
20             ce->mtime.nsec != (unsigned int)st->st_mtim.tv_nsec)
21                 changed |= MTIME_CHANGED;
22         if (ce->ctime.sec  != (unsigned int)st->st_ctim.tv_sec ||
23             ce->ctime.nsec != (unsigned int)st->st_ctim.tv_nsec)
24                 changed |= CTIME_CHANGED;
25         if (ce->st_uid != (unsigned int)st->st_uid ||
26             ce->st_gid != (unsigned int)st->st_gid)
27                 changed |= OWNER_CHANGED;
28         if (ce->st_mode != (unsigned int)st->st_mode)
29                 changed |= MODE_CHANGED;
30         if (ce->st_dev != (unsigned int)st->st_dev ||
31             ce->st_ino != (unsigned int)st->st_ino)
32                 changed |= INODE_CHANGED;
33         if (ce->st_size != (unsigned int)st->st_size)
34                 changed |= DATA_CHANGED;
35         return changed;
36 }

如果文件发生改变,返回非0,如果未改变,返回0.
回到函数main, Line73:76如果未发生改变,则遍历下一个cache_entry对象,进行比较.如果发生改变,Line81调用函数read_sha1_file获得该文件在cache中的文件内容和长度.该函数的实现为(read-cache.c):

 87 void * read_sha1_file(unsigned char *sha1, char *type, unsigned long *size)88 {89         z_stream stream;90         char buffer[8192];91         struct stat st;92         int i, fd, ret, bytes;93         void *map, *buf;94         char *filename = sha1_file_name(sha1);95 96         fd = open(filename, O_RDONLY);97         if (fd < 0) {98                 perror(filename);99                 return NULL;
100         }
101         if (fstat(fd, &st) < 0) {
102                 close(fd);
103                 return NULL;
104         }
105         map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
106         close(fd);
107         if (-1 == (int)(long)map)
108                 return NULL;
109
110         /* Get the data stream */
111         memset(&stream, 0, sizeof(stream));
112         stream.next_in = map;
113         stream.avail_in = st.st_size;
114         stream.next_out = buffer;
115         stream.avail_out = sizeof(buffer);
116
117         inflateInit(&stream);
118         ret = inflate(&stream, 0);
119         if (sscanf(buffer, "%10s %lu", type, size) != 2)
120                 return NULL;
121         bytes = strlen(buffer) + 1;
122         buf = malloc(*size);
123         if (!buf)
124                 return NULL;
125
126         memcpy(buf, buffer + bytes, stream.total_out - bytes);
127         bytes = stream.total_out - bytes;
128         if (bytes < *size && ret == Z_OK) {
129                 stream.next_out = buf + bytes;
130                 stream.avail_out = *size - bytes;
131                 while (inflate(&stream, Z_FINISH) == Z_OK)
132                         /* nothing */;
133         }
134         inflateEnd(&stream);
135         return buf;
136 }

Line94根据sha1获得对应的文件名,Line96:108打开文件,通过系统调用fstat获得文件长度,并通过系统调用mmap将文件内容映射到内存,然后关闭文件.cache中的文件对象都是经过压缩的,所以Line110:118解压缩8192个字节,这样先把文件头部的元数据读取出来.Line119:124通过库函数sscanf从解压缩后的文件头中解析中类型字符串(这里为blob)和文件长度信息.分配文件长度大小的动态内存buf.Line126把已经解压缩的数据拷贝到buf.Line127:133如果还没有解压缩完毕,继续解压缩剩余的文件内容到buf,最后返回解压缩后的文件内容.

回到函数main,Line82调用函数show_differences比较工作区和暂存区该文件的差异,比较完毕后释放为解压缩cache文件动态分配的内存空间.函数show_differences的实现为(show-diff.c):

38 static void show_differences(struct cache_entry *ce, struct stat *cur,
39         void *old_contents, unsigned long long old_size)
40 {
41         static char cmd[1000];
42         FILE *f;
43
44         snprintf(cmd, sizeof(cmd), "diff -u - %s", ce->name);
45         f = popen(cmd, "w");
46         fwrite(old_contents, old_size, 1, f);
47         pclose(f);
48 }

库函数popen将启用一个shell子进程,来执行diff命令比较文件的差异.

git的show-diff命令处理逻辑相关推荐

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

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

  2. git diff命令详解

    git diff命令详解 diff里面a表示前面那个变量,b表示第二个变量 HEAD     commit版本 Index     staged版本 a.查看尚未暂存的文件更新了哪些部分,不加参数直接 ...

  3. git diff 命令获取变更的文件列表

    git diff 一般用法 git diff commit id1 commit id2 > xxxx.diff git apply xxxx.diff 获取文件列表,加- -stat参数.或者 ...

  4. git的一些常用命令讲解和开发规范总结

    一.git基本配置介绍 1. config的三个作用域 local:区域为本仓库 global: 当前用户的所有仓库 system: 本系统的所有用户 2. 添加最小配置 $ git config - ...

  5. git修改服务器的命令行,Git版本控制工具安装及命令行操作

    很多小伙伴不知道如何来安装Git版本控制工具,对于命令操作比较陌生.本文做了一个详细的文档,希望对大家有所帮助. 1.git 是什么一个分布式版本控制系统,和SVN类似,但远比SVN强大的一个版本控制 ...

  6. Git结合GitHub常用命令

    简介 GIT 学习手册简介 这是 Git 学习参考手册.目的是为学习与记忆 Git 使用中最重要.最普遍的命令提供快速翻阅. 这些命令以你可能需要的操作类型划分,并且将提供日常使用中需要的一些常用的命 ...

  7. linux下比较文件并输出,Linux使用diff命令比较文件找出文件之间相同的部分

    如果你需要比较系统文件的内容,那么你就会是使用到diff命令,可找出文件之间相同的部分,下面小编就给大家详细介绍下Linux diff命令的用法. diff 命令是 linux上非常重要的工具,用于比 ...

  8. Linux diff命令

    一.简介 diff 命令用于比较文件的内容,是svn.cvs.git等版本控制工具不可或缺的一部分. 二.语法 -a或--text diff预设只会逐行比较文本文件. -b或--ignore-spac ...

  9. Git log、diff、config 进阶

    前一段时间分享了一篇<更好的 git log>简要介绍怎么美化 git log 命令,其中提到了 alias命令,今天再继续谈谈 git相关, 看看如何通过配置自己的 git config ...

最新文章

  1. PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to fi
  2. python序列类型-python序列类型有哪些
  3. ADO学习(四)ADO扩展IADORecordBinding
  4. python入门指南阅读答案_【python】入门指南1
  5. Android 11 系统字体加载流程
  6. edius隐藏快捷键_超级实用的edius常用快捷键
  7. 手机水星路由器服务器无响应,水星路由器无线wifi连接成功但上不了网的解决方法...
  8. boost | 线程与并发(一)atomic
  9. R语言-岭回归的代码与案例解读
  10. Excle 取前几位数、中间几位数、后几位数的方法
  11. 苹果设备尺寸和控件尺寸
  12. 抖音电商的带货情况究竟如何,抖音电商带货前景如何
  13. 学数据结构 是不是一定要先学离散数学
  14. 小米蓝牙温度计2接入home assistant
  15. CList POSITION
  16. L298N模块的连接与使用(stm32驱动与51驱动)
  17. 【OpenCV】图像缩放
  18. Centos7x Oracle 11G的rac部署(无图形化安装)
  19. MIMIC-IV v2.0数据库
  20. html插入swf自动播放,如何在HTML页面中嵌入SWF文件?

热门文章

  1. linux 根目录磁盘占满,linux磁盘空间满,解决方法
  2. DBeaver 转存数据库或执行脚本报错(全方位解析)
  3. SpringCloud Bus 动态刷新遇见的500错误
  4. iOS Core Image 复杂的滤镜
  5. 【无标题】数仓实战之亚马逊全球跨境电商分析平台
  6. 乐动圈圈显示无法连接服务器,win8系统安装乐动圈圈失败导致仙剑6无法安装如何解决...
  7. 如何实现六轴机械臂的逆解计算?
  8. 【转载】osgeo和pyproj:经纬度坐标和高斯坐标互相转换
  9. Lab05-循环1(2019.10.21)
  10. blink解决的一个flink分析痛点