Git 仓库下如何通过 diff 功能进行差异比对
大纲
1. 背景
2. 方案
2.1 SourceTree 查看差异
2.2 git difftool 查看差异
2.3 git diff 输出差异文件
2.4 git format-patch 生成补丁
2.5 Android Studio 差异比对
3. 总结
1. 背景
Git 作为一种分布式版本管理工具,已经越来越普及了,绝大部分公司都使用 Git 进行代码的版本管理,甚至是文档的版本管理。包括一些 wiki 平台,底层也使用了 Git 进行版本管理,提供了查看文档修改记录、多版本比对、甚至版本回退等一系列功能。
在使用 Git 的日常中,有这么一种场景,相信很多开发者都遇到过,就是差异比对。如果是还未提交的代码与已提交代码的差异,那么在工作区或者暂存区我们就可以看到修改的内容。如果是比对两个分支、两个 tag、甚至两个不同的 commit 之间的代码差异呢,除了拷贝一份代码出来,使用比对工具进行比对之外,还有没有其他的办法呢,所幸 Git 已经为我们提供了这么一个差异比对功能:diff。
什么是 diff:diff 就是目标文本和源文本之间的区别,或者说是将目标文本变成源文本所需要的一系列操作。Git diff 使用的算法默认是 Myers,一个好的算法可以为我们产生最简短最直观的差异,对 Myers 算法感兴趣的同学可以通过这篇文章了解下: Git 是怎样生成 diff 的:Myers 算法 ,本文主要讲的是如何查看 diff。
2. 方案
2.1 SourceTree 查看差异
SourceTree 作为业界有名的 Git 版本管理 GUI 工具,它不仅提供了版本管理功能,还为用户提供了非常友好的界面,使用 SourceTree 不仅可以查看代码提交的历史记录,分支路径,还可以直观快捷的查看两个不同版本之间的差异。
作为例子,首先在本地创建一个文件夹,在该文件夹路径下,创建一个 Git 仓库。操作如下:
$ cd /{path}/DiffTest
$ git init
这样一来,文件夹 DiffTest 下的所有文件的增删改重命名等各种变更操作都会被纳入版本管理中。接下来我在路径下陆续新增文本文件 readme.md、main.c,二进制文件 heart.png、dove.png,并分多次提交。然后对该路径下的文件进行移动、删除、重命名、内容修改等操作,也分多次提交。提交记录如以下 SourceTree 截图所示:
每一行代表了一个提交记录,“描述”一栏是提交时写的 commit message,“提交”那一栏的十六进制数字代表了这个 commit 的 hash 值,你可以把它当成 commit 的 ID。
如果我们想比对两个 commit 之间的差异,可以同时选中两个 commit,这时在提交图表的下方就可以看到两个 commit 的差异比对了,如上图所示。上图的区域 2 给出了摘要信息,告诉用户展示的内容是“xxxx与xxxx之间的所有差异”(xxxx分别表示两个 commit 的 hash 值),区域 1 展示了被改动的文件列表,区域 3 则展示了左边选中的文件的改动内容。上图区域 1 每一行前面有个 icon,第一个紫色的 icon 表示“移动/重命名”,第二个红色的 icon 表示“删除”,第三个黄色的表示“修改”,第四个绿色的表示“新增”,这四种代表了 Git 中最常出现的四种操作。后缀为 .png 的文件为二进制文件,.c 跟 .md 的文件为文本文件,文本文件的修改可以在右侧区域 3 看到具体的修改内容,标红的内容表示该行从 a 版本删除(此处 a 版本指 commit 27d76d0),标绿的表示在 b 版本(此处 b 版本指commit 417dc0c)新增的内容。注意,此时的差异不包括 a 版本那个 commit 所进行的修改。
2.2 git difftool 查看差异
除了 SourceTree,还有很多比对工具可以给我们提供类似的服务,如 DiffMerge、Kaleidoscope、Beyond Compare。DiffMerge 虽然好用,但是不支持中文显示,Kaleidoscope 苹果商店的售价又太贵,所以本文选择了 Beyond Compare 为例做个展示。
首先去 官网 下载对应电脑系统的版本并安装,接着启动 Beyond Compare,在菜单中选择 “Install Command Line Tools”,然后在终端使用以下命令对 Git 进行全局配置(该命令目前适用于 Git 版本为 2.3 以上,Beyond Compare 版本为 3.0 以上的情况,详细内容可参考官网的 技术支持 ):
$ git config --global diff.tool bc
这样我们就可以在终端通过 Git 命令使用 Beyond Compare 进行差异比对了。命令格式如下:
$ git difftool <commitA> <commitB>
还是以刚刚两个 commit 为例:
$ cd /{path}/DiffTest
$ git difftool 27d76d0 417dc0c
$ Viewing (1/4): 'dove.png'
$ Launch 'bc3' [Y/n]? n
$ Viewing (2/4): 'heart.png'
$ Launch 'bc3' [Y/n]? n