版本库间的交互是经过git push和/或git pull命令实现的,这是Git最主要的交互模式,但并非所有。使用补丁文件是另一种交互方式,适用于参与者众多的大型项目进行分布式开发。git
Git提供了将提交批量转换为补丁文件的命令:git format-patch。该命令后面的参数是一个版本范围列表,会将包含在此列表中的提交一一转换为补丁文件,每一个补丁文件包含一个序号并从提交说明中提取字符串做为文件名。app
下面演示一下在user1工做区中,如何将master分支的最近3个提交转换为补丁文件。分布式
$ cd /path/to/user1/workspace/hello-world/ $ git checkout master $ git pull
$ git format-patch -s HEAD~3..HEAD 0001-Fix-typo-help-to-help.patch 0002-Add-I18N-support.patch 0003-Translate-for-Chinese.patch
在上面的git format-patch命令中使用了-s参数,会在导出的补丁文件中添加当前用户的签名。这个签名并不是GnuPG式的数字签名,不过是将做者姓名添加到提交说明中而已,和在本书第2篇开头介绍的git commit -s命令的效果相同。虽然签名很不起眼,可是对于以补丁方式提交数据却很是重要,由于以补丁方式提交可能由于合并冲突或其余缘由使得最终提交的做者显示为管理员(提交者)的ID,在提交说明中加入原始做者的署名信息大概是做者惟一露脸的机会。若是在提交时忘了使用-s参数添加签名,能够在用git format-path命令建立补丁文件的时候补救。工具
看一下补丁文件的文件头,在下面代码中的第7行能够看到新增的签名。ui
1 From d81896e60673771ef1873b27a33f52df75f70515 Mon Sep 17 00:00:00 2001 2 From: user1 <user1@sun.ossxp.com> 3 Date: Mon, 3 Jan 2011 23:48:56 +0800 4 Subject: [PATCH 1/3] Fix typo: -help to --help. 5 6 7 Signed-off-by: user1 <user1@sun.ossxp.com> 8 --- 9 src/main.c | 2 +- 10 1 files changed, 1 insertions(+), 1 deletions(-)
补丁文件有一个相似邮件同样的文件头(第1-4行),提交日志的第一行做为邮件标题(Subject),其他提交说明做为邮件内容(若是有的话),文件补丁用三个横线和提交说明分开。this
实际上这些补丁文件能够直接拿来做为邮件发送给项目的负责人。Git提供了一个辅助邮件发送的命令git send-email。下面用该命令将这三个补丁文件以邮件形式发送出去。spa
git send-email *.patch 0001-Fix-typo-help-to-help.patch 0002-Add-I18N-support.patch 0003-Translate-for-Chinese.patch The following files are 8bit, but do not declare a Content-Transfer-Encoding. 0002-Add-I18N-support.patch 0003-Translate-for-Chinese.patch Which 8bit encoding should I declare [UTF-8]? Who should the emails appear to be from? [user1 <user1@sun.ossxp.com>] Emails will be sent from: user1 <user1@sun.ossxp.com> Who should the emails be sent to? jiangxin Message-ID to be used as In-Reply-To for the first email? ... Send this email? ([y]es|[n]o|[q]uit|[a]ll): a ...
命令git send-email提供交互式字符界面,输入正确的收件人地址,邮件就批量地发送出去了。翻译
在前面经过git send-email命令发送邮件给jiangxin用户。如今使用 Linux 上的mail命令检查一下邮件。设计
$ mail Mail version 8.1.2 01/15/2001. Type ? for help. "/var/mail/jiangxin": 3 messages 3 unread >N 1 user1@sun.ossxp.c Thu Jan 13 18:02 38/1120 [PATCH 1/3] Fix typo: -help to --help. N 2 user1@sun.ossxp.c Thu Jan 13 18:02 227/6207 =?UTF-8?q?=5BPATCH=202/3=5D=20Add=20I18N=20support=2E?= N 3 user1@sun.ossxp.c Thu Jan 13 18:02 95/2893 =?UTF-8?q?=5BPATCH=203/3=5D=20Translate=20for=20Chinese=2E?= &
若是邮件不止这三封,须要将三个包含补丁的邮件挑选出来保存到另外的文件中。 在 mail 命令的提示符(&)下输入命令。3d
& s 1-3 user1-mail-archive "user1-mail-archive" [New file] & q
上面的操做在本地建立了一个由开发者user1的补丁邮件组成的归档文件user1-mail-archive,这个文件是mbox格式的,能够用mail命令打开。
$ mail -f user1-mail-archive Mail version 8.1.2 01/15/2001. Type ? for help. "user1-mail-archive": 3 messages > 1 user1@sun.ossxp.c Thu Jan 13 18:02 38/1121 [PATCH 1/3] Fix typo: -help to --help. 2 user1@sun.ossxp.c Thu Jan 13 18:02 227/6208 =?UTF-8?q?=5BPATCH=202/3=5D=20Add=20I18N=20support=2E?= 3 user1@sun.ossxp.c Thu Jan 13 18:02 95/2894 =?UTF-8?q?=5BPATCH=203/3=5D=20Translate=20for=20Chinese=2E?= & q
保存在mbox中的邮件能够批量的应用在版本库中,使用git am命令。am是apply email的缩写。下面就演示一下如何应用补丁。
$ git checkout -b user1 HEAD~3 Switched to a new branch 'user1'
$ git am user1-mail-archive Applying: Fix typo: -help to --help. Applying: Add I18N support. Applying: Translate for Chinese.
$ git log -3 --pretty=fuller commit 2d9276af9df1a2fdb71d1e7c9ac6dff88b2920a1 Author: Jiang Xin <jiangxin@ossxp.com> AuthorDate: Thu Jan 13 18:02:03 2011 +0800 Commit: user1 <user1@sun.ossxp.com> CommitDate: Thu Jan 13 18:21:16 2011 +0800 Translate for Chinese. Signed-off-by: Jiang Xin <jiangxin@ossxp.com> Signed-off-by: user1 <user1@sun.ossxp.com> commit 41227f492ad37cdd99444a5f5cc0c27288f2bca4 Author: Jiang Xin <jiangxin@ossxp.com> AuthorDate: Thu Jan 13 18:02:02 2011 +0800 Commit: user1 <user1@sun.ossxp.com> CommitDate: Thu Jan 13 18:21:15 2011 +0800 Add I18N support. Signed-off-by: Jiang Xin <jiangxin@ossxp.com> Signed-off-by: user1 <user1@sun.ossxp.com> commit 4a3380fb7ae90039633dec84acc2aab85398efad Author: user1 <user1@sun.ossxp.com> AuthorDate: Thu Jan 13 18:02:01 2011 +0800 Commit: user1 <user1@sun.ossxp.com> CommitDate: Thu Jan 13 18:21:15 2011 +0800 Fix typo: -help to --help. Signed-off-by: user1 <user1@sun.ossxp.com>
从提交信息上能够看出:
提交的时间信息使用了邮件发送的时间。
做者(Author)的信息被保留,和补丁文件中的一致。
提交者(Commit)全都设置为user1,由于提交是在user1的工做区完成的。
提交说明中的签名信息被保留。实际上git am命令也能够提供-s参数,在提交说明中附加执行命令用户的签名。
对于不习惯在控制台用mail命令接收邮件的用户,能够经过邮件附件,U盘或其余方式获取git format-patch生成的补丁文件,将补丁文件保存在本地,经过管道符调用git am命令应用补丁。
$ ls *.patch 0001-Fix-typo-help-to-help.patch 0002-Add-I18N-support.patch 0003-Translate-for-Chinese.patch $ cat *.patch | git am Applying: Fix typo: -help to --help. Applying: Add I18N support. Applying: Translate for Chinese.
Git还提供一个命令git apply,能够应用通常格式的补丁文件,可是不能执行提交,也不能保持补丁中的做者信息。
一个复杂功能的开发必定是由多个提交来完成的,对于在以接收和应用补丁文件为开发模式的项目中,复杂的功能须要经过多个补丁文件来完成。补丁文件由于要通过审核才能被接受,所以针对一个功能的多个补丁文件必定要保证各个都是精品:补丁1用来完成一个功能点,补丁2用来完成第二个功能点,等等。必定不能出现这样的状况:补丁3用于修正补丁1的错误,补丁10改正了补丁7中的文字错误,等等。这样就带来补丁管理的难题。
实际上基于特性分支的开发又未尝不是如此?在将特性分支归并到开发主线前,要接受团队的评审,特性分支的开发者必定想将特性分支上的提交进行重整,把一些提交合并或者拆分。使用变基命令能够实现提交的重整,可是操做起来会比较困难,有什么好办法呢?
Stacked Git(http://www.procode.org/stgit/)简称StGit就是解决上述两个难题的答案。实际上StGit在设计上参考了一个著名的补丁管理工具Quilt,而且能够输出Quilt兼容的补丁列表。
StGit是一个Python项目,安装起来仍是很方便的。在Debian/Ubuntu下,能够直接经过包管理器安装:
$ sudo aptitude install stgit stgit-contrib
下面仍是用hello-world版本库,进行StGit的实践。
$ cd /path/to/my/workspace/ $ git clone file:///path/to/repos/hello-world.git stgit-demo $ cd stgit-demo
$ stg init
$ stg series
$ stg uncommit -n 3 Uncommitting 3 patches ... Now at patch "translate-for-chinese" done
第一列是补丁的状态符号。加号(+)表明该补丁已经应用在版本库中,大于号(>)用于标识当前的补丁。
$ stg ser + fix-typo-help-to-help + add-i18n-support > translate-for-chinese
$ git log -3 --oneline c4acab2 Translate for Chinese. 683448a Add I18N support. d81896e Fix typo: -help to --help.
$ stg pop Popped translate-for-chinese Now at patch "add-i18n-support" $ stg pop -a Popped add-i18n-support -- fix-typo-help-to-help No patch applied
$ git log -3 --oneline 10765a7 Bugfix: allow spaces in username. 0881ca3 Refactor: use getopt_long for arguments parsing. ebcf6d6 blank commit for GnuPG-signed tag test.
$ stg ser - fix-typo-help-to-help - add-i18n-support - translate-for-chinese
$ stg push Pushing patch "fix-typo-help-to-help" ... done (unmodified) Now at patch "fix-typo-help-to-help" $ stg goto add-i18n-support Pushing patch "add-i18n-support" ... done (unmodified) Now at patch "add-i18n-support"
$ cd src/ $ rm locale/helloworld.pot $ make po xgettext -s -k_ -o locale/helloworld.pot main.c msgmerge locale/zh_CN/LC_MESSAGES/helloworld.po locale/helloworld.pot -o locale/temp.po . 完成。 mv locale/temp.po locale/zh_CN/LC_MESSAGES/helloworld.po
$ git status -s M locale/helloworld.pot M locale/zh_CN/LC_MESSAGES/helloworld.po
$ stg refresh Now at patch "add-i18n-support"
$ git status -s
$ stg show ...
$ stg push Pushing patch "translate-for-chinese" ... done (conflict) Error: 1 merge conflict(s) CONFLICT (content): Merge conflict in src/locale/zh_CN/LC_MESSAGES/helloworld.po Now at patch "translate-for-chinese"
50 " hello -h, --help\n" 51 " 显示本帮助页。\n" ... 61 msgid "Hi," 62 msgstr "您好,"
$ git add locale/zh_CN/LC_MESSAGES/helloworld.po
$ stg refresh Now at patch "translate-for-chinese" $ git status -s
$ ./hello 世界你好。 (version: v1.0-5-g733c6ea) $ ./hello Jiang Xin 您好, Jiang Xin. (version: v1.0-5-g733c6ea) $ ./hello -h ...
$ cd /path/to/my/workspace/stgit-demo/ $ stg export -d patches Checking for changes in the working directory ... done
$ ls patches/ add-i18n-support fix-typo-help-to-help series translate-for-chinese
$ cat patches/series # This series applies on GIT commit d81896e60673771ef1873b27a33f52df75f70515 fix-typo-help-to-help add-i18n-support translate-for-chinese
经过上面的演示能够看出StGit能够很是方便的对提交进行整理,整理提交时无需使用复杂的变基命令,而是采用:提交StGit化,修改文件,执行stg refresh的工做流程便可更新补丁和提交。StGit还能够将补丁导出为补丁文件,虽然导出的补丁文件没有像git format-patch那样加上表明顺序的数字前缀,可是用文件series标注了补丁文件的前后顺序。实际上能够在执行stg export时添加-n参数为补丁文件添加数字前缀。
StGit还有一些功能,如合并补丁/提交,插入新补丁/提交等,
Quilt是一款补丁列表管理软件,用Shell语言开发,安装也很简单,在Debian/Ubuntu上直接用下面的命令便可安装:
$ sudo aptitude install quilt
Quilt约定俗成将补丁集放在项目根目录下的子目录patches中,不然须要经过环境变量QUILT_PATCHES对路径进行设置。为了减小麻烦,在上面用stg export导出补丁的时候就导出到了patches目录下。
简单说一下Quilt的使用,会发现真的和StGit很像,其实是先有的Quilt,后有的StGit。
$ git reset --hard HEAD~3 $ rm -rf src/locale/
$ quilt series 01-fix-typo-help-to-help 02-add-i18n-support 03-translate-for-chinese
$ quilt push Applying patch 01-fix-typo-help-to-help patching file src/main.c Now at patch 01-fix-typo-help-to-help
$ quilt next 02-add-i18n-support
$ quilt push -a Applying patch 02-add-i18n-support patching file src/Makefile patching file src/locale/helloworld.pot patching file src/locale/zh_CN/LC_MESSAGES/helloworld.po patching file src/main.c Applying patch 03-translate-for-chinese patching file src/locale/zh_CN/LC_MESSAGES/helloworld.po Now at patch 03-translate-for-chinese