现实并不总是尽如人意。 通常,你不能立刻就把接触到的每一个项目都切换到 Git。 有时候你被困在使用其他 VCS 的项目中,却希望使用 Git。 在本章的第一部分我们将会了解到,怎样在你的那些托管在不同系统的项目上使用 Git 客户端。在某些时候,你可能想要将已有项目转换到 Git。
我们已经阐述了大部分通过自定义 Git 客户端和服务端来适应自己工作流程和项目内容的方式。 你已经学到各种各样的设置项、基于文件的选项和事件钩子,还建立了一个示例用的强制策略服务器。 无论创造出了什么样的工作流程,你都能使 Git 与它珠联璧合。
在本节中,你将应用前面学到的知识建立这样一个 Git 工作流程:检查提交信息的格式,并且指定只能由特定用户修改项目中特定的子目录。 你将编写一个客户端脚本来提示开发人员他们的推送是否会被拒绝,以及一个服务器端脚本来实际执行这些策略。我们待会展示的脚本是用 Ruby 写的,部分是由于我习惯用它写脚本,另外也因为 Ruby 简单易懂,即便你没写过它也能看明白。
和其它版本控制系统一样,Git 能在特定的重要动作发生时触发自定义脚本。 有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。安装一个钩子钩子都被存储在 Git 目录下的 hooks 子目录中。 也即绝大部分项目中的 .git/hooks 。
你也可以针对特定的路径配置某些设置项,这样 Git 就只对特定的子目录或子文件集运用它们。 这些基于路径的设置项被称为 Git 属性,可以在你的目录下的 .gitattributes 文件内进行设置(通常是你的项目的根目录)。如果不想让这些属性文件与其它文件一同提交,你也可以在 .git/info/attributes 文件中进行设置。
到目前为止,我们已经阐述了 Git 基本的运作机制和使用方式,介绍了许多 Git 提供的工具来帮助你简单且有效地使用它。 在本章,我们将演示如何借助 Git 的一些重要的配置方法和钩子机制,来满足自定义的需求。 通过这些工具,它会和你、你的公司或你的团队配合得天衣无缝。配置 Git你在 起步 中看到,可以用 git config 配置 Git。
你已经接触了很多能够精确地操控提交和暂存区的高级工具。 当你碰到问题时,你应该可以很容易找出是哪个分支在什么时候由谁引入了它们。 如果你想在项目中使用子项目,你也已经知道如何来满足这些需求。 到此,你应该能毫无压力地在命令行中使用 Git 来完成日常中的大部分事情。
如果你使用的是 SSH 方式连接远端,并且设置了一个没有口令的密钥,这样就可以在不输入用户名和密码的情况下安全地传输数据。 然而,这对 HTTP 协议来说是不可能的 —— 每一个连接都是需要用户名和密码的。 这在使用双重认证的情况下会更麻烦,因为你需要输入一个随机生成并且毫无规律的 token 作为密码。幸运的是,Git 拥有一个凭证系统来处理这个事情。
Git 对象是不可改变的,但它提供一种有趣的方式来用其他对象假装替换数据库中的 Git 对象。replace 命令可以让你在 Git 中指定一个对象并可以声称“每次你遇到这个 Git 对象时,假装它是其他的东西”。 在你用一个不同的提交替换历史中的一个提交时,这会非常有用。
虽然我们已经了解了网络传输 Git 数据的常用方法(如 HTTP,SSH 等),但还有另外一种不太常见却又十分有用的方式。Git 可以将它的数据 “打包” 到一个文件中。 这在许多场景中都很有用。 有可能你的网络中断了,但你又希望将你的提交传给你的合作者们。 可能你不在办公网中并且出于安全考虑没有给你接入内网的权限。 可能你的无线、有线网卡坏掉了。
有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。我们举一个例子。 假设你正在开发一个网站然后创建了 Atom 订阅。 你决定使用一个库,而不是写自己的 Atom 生成代码。
Git 也提供了两个工具来辅助你调试项目中的问题。 由于 Git 被设计成适用于几乎所有类型的项目,这些工具是比较通用的,但它们可以在出现问题的时候帮助你找到 bug 或者错误。文件标注如果你在追踪代码中的一个 bug,并且想知道是什么时候以及为何会引入,文件标注通常是最好用的工具。 它展示了文件中每一行最后一次修改的提交。
git rerere 功能是一个隐藏的功能。 正如它的名字 “reuse recorded resolution” 所指,它允许你让 Git 记住解决一个块冲突的方法,这样在下一次看到相同冲突时,Git 可以为你自动地解决它。有几种情形下这个功能会非常有用。 在文档中提到的一个例子是如果你想要保证一个长期分支会干净地合并,但是又不想要一串中间的合并提交。
在 Git 中合并是相当容易的。 因为 Git 使多次合并另一个分支变得很容易,这意味着你可以有一个始终保持最新的长期分支,经常解决小的冲突,比在一系列提交后解决一个巨大的冲突要好。然而,有时也会有棘手的冲突。 不像其他的版本控制系统,Git 并不会尝试过于聪明的合并冲突解决方案。
在继续了解更专业的工具前,我们先讨论一下 reset 与 checkout。 在你初次遇到的 Git 命令中,这两个是最让人困惑的。 它们能做很多事情,所以看起来我们很难真正地理解并恰当地运用它们。 针对这一点,我们先来做一个简单的比喻。三棵树理解 reset 和 checkout 的最简方法,就是以 Git 的思维框架(将其作为内容管理器)来管理三棵不同的树。
许多时候,在使用 Git 时,可能会因为某些原因想要修正提交历史。 Git 很棒的一点是它允许你在最后时刻做决定。 你可以在将暂存区内容提交前决定哪些文件进入提交,可以通过 stash 命令来决定不与某些内容工作,也可以重写已经发生的提交就像它们以另一种方式发生的一样。
无论仓库里的代码量有多少,你经常需要查找一个函数是在哪里调用或者定义的,或者一个方法的变更历史。 Git 提供了两个有用的工具来快速地从它的数据库中浏览代码和提交。 我们来简单的看一下。Git GrepGit 提供了一个 grep 命令,你可以很方便地从提交历史或者工作目录中查找一个字符串或者正则表达式。 我们用 Git 本身源代码的查找作为例子。
Git 虽然是密码级安全的,但它不是万无一失的。 如果你从因特网上的其他人那里拿取工作,并且想要验证提交是不是真正地来自于可信来源,Git 提供了几种通过 GPG 来签署和验证工作的方式。GPG 介绍首先,在开始签名之前你需要先配置 GPG 并安装个人密钥。$ gpg --list-keys/Users/schacon/.gnupg/pubring.
有时,当你在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状态,而这时你想要切换到另一个分支做一点别的事情。 问题是,你不想仅仅因为过会儿回到这一点而为做了一半的工作创建一次提交。 针对这个问题的答案是 git stash 命令。
Git 自带的一些脚本可以使在命令行下工作更容易。 本节的几个互交命令可以帮助你将文件的特定部分组合成提交。 当你修改一组文件后,希望这些改动能放到若干提交而不是混杂在一起成为一个提交时,这几个工具会非常有用。 通过这种方式,可以确保提交是逻辑上独立的变更集,同时也会使其他开发者在与你工作时很容易地审核。
关注时代Java