学会 Git, 看这篇就够了(2)

Learn Git the hard way 2

Posted by Chinsyo on April 20, 2019

在前文中,我们掌握了 Git 基础的知识和操作,可以通过下述链接进行回顾。

学会 Git,看这篇就够了(1)

本篇将在掌握基础知识和操作的基础上,介绍 Git 的诞生、Git 的安全机制、关联和克隆远程仓库、推送本地提交记录、拉取远程提交记录、解决合并冲突以及如何获得帮助。

(1)Git 的诞生

Git 的诞生是一个充满争议的传奇故事,故事要从 Git 的缔造者说起,Linux 之父 —— Linus Torvalds。

在 1991 年到 2002 年之间 Linus 通过手动合并补丁的方式管理 Linux 内核这个庞然大物的更新,随着参与贡献代码的规模渐渐变大,这种方式显得愈发力不从心。2002 起一家叫作 BitMover 的商业公司将旗下版本控制系统 BitKeeper 授权 Linux 核心团队免费使用,随着 Linux 核心团队和 BitMover 关系的恶化,该公司在 2005 年收回了 Linux 核心团队的 BitKeeper 免费使用权。

倘若换做他人,故事的走向通常是 Linus 负荆请罪,双方冰释前嫌。偏偏传奇故事往往超越了凡人的假设,Linus 花了两周(也有记载两个周末)完成了 Git 第一版的开发。

感兴趣的朋友可以访问 https://www.amazon.cn/dp/B00MB51SAI 购买 Linus 自传《Just for fun》(中文译名:只是为了好玩)进一步了解关于 Linus 的故事。

(2)Git 的安全机制

还记得前文中的查看提交日志吗?日志中除了作者、日期、描述之外还有摘要字段。安全是Git 最初的设计目标之一,所有数据在存储前都计算出来 40 位摘要,使用摘要校验文件正确性。Git 数据库中保存的信息都是以文件内容的摘要来索引,这个功能建构在 Git 底层,是 Git 哲学不可或缺的部分。

执行 Git 操作时几乎只向 Git 数据库增加记录,版本记录一旦提交即使发生版本回退也难以发生丢失数据。值得一提的是,定期向远程仓库推送同步本地记录,数据将更加安全。

下面就以前文介绍过的 GitHub 网站创建远程仓库并关联,进而展示如何向远程仓库推送同步本地记录。

(3)关联远程仓库

前文中完成了 GitHub 账号的注册和 ssh 连接的配置,创建 Git 仓库并提交,假设随着项目的进展,有新的同事要加入项目和你进行协作,那么你就需要创建远程仓库并将本地仓库与之关联以便进行版本控制。

首先需要在 GitHub 网站创建远程仓库,点击网页上方导航栏的加号展开菜单,选中 New Repository 选项。

接着网页会跳转到创建仓库的表单页面,表单信息包括仓库名称、访问权限(公开或私有),以及非必填项描述、是否创建项目帮助文档(README)、忽略文件(.gitignore)和开源协议(license)。

设置仓库名称为 learning-git ,并勾选 Public 选项,点击 Create repository 完成创建。

接着我们可以选择将远程仓库克隆到本地,或者将本地已有的项目和远程进行关联。对于目前的情况而言,项目已经开始并且有了提交记录,这时有新的同事加入,将本地代码仓库关联到远程仓库即可。

打开本地 Git 仓库所在的根目录,执行以下命令关联远程仓库。

1
git remote add origin git@github.com:chinsyo/learning-git.git

输入命令后如果没有出现错误信息即表示关联成功,通过 git remote get-url origin 命令查看关联的远程仓库。

1
git remote get-url origin

(4)推送本地提交记录

作为项目已有的团队成员,需要将本地仓库推送到远程仓库,以便新同事加入时可以获得最新的仓库状态。

在首次推送时需要在 git push 命令后面添加 -u origin master 以设置本地仓库的 upstream,表明以后本地与 origin 仓库的 master 分支同步。其中 origin 是远程仓库的默认名称,master 是主分支的默认名称。

1
2
3
4
5
6
# 没有设置 upstream 时, push 命令需要显式指定远程仓库
git push origin master
# 通过 -u 或 --set-upstream 设置 upstream
git push -u origin master
# 完成设置后, 再次向 master 分支推送记录无需指定 upstream
git push

(5)克隆远程仓库

如果你作为团队协作的一员加入项目后,需要克隆远程仓库到本地进行开发。克隆这个叫法很有趣,在 svn 系统中相同作用的命令叫作 checkout,Git 中也有一个 checkout 命令但是作用截然不同。从名字上看,克隆即复制一份完全一样的仓库,这也侧面印证了 Git 是分布式的 VCS,远程仓库和本地仓库具有同样的效力,只是为了出于备份和协作的需要而创建。

在 GitHub 的项目页面可以找到克隆仓库和下载仓库的方式,两者的不同在于下载仓库并不包含修改历史。

点击 Clone or download 按钮,展开选项,可以通过点击 Use HTTPS 按钮切换到 https 的连接方式,如果你还不清楚这个按钮的影响,出于安全的考虑建议你不要这么做。

点击 Download ZIP 下载仓库,或者使用文本框内的 Git 地址进行克隆。

1
git clone git@github.com:chinsyo/learning-git.git

有时,我们仅需仓库最新的状态进行查阅或是试用,可以通过 git clone 实现和下载仓库一样的效果(即只克隆最新仓库而不包含历史记录),达到减小体积加速下载的目的。

1
git clone git@github.com:chinsyo/learning-git.git --depth 1

(6)拉取远程提交记录

通过以上两步,团队成员都有了和远程仓库关联的本地仓库,接下来可以使用 git pull 拉去远程提交记录,学习过程中可以通过在 GitHub 网页端对文件进行修改模拟同事的提交,也欢迎 fork 我的项目 https://github.com/chinsyo/learning-git 让我充当你的同事。

(7)解决合并冲突

岁月静好,现世安稳。你和同事躬耕在各自的一亩三分地,直到某一天你提交本地记录时出现了错误。

错误信息显示你本地记录不是最新,需要先拉取远程变更,it’s easy,执行 git pull 命令。

如提示所言,greeting.txt 文件发生了冲突,cat greeting.txt 查看冲突的内容。

冲突的内容如上所示,文件中出现了连续的大于号(»>),小于号(«<)和等号(===)。这是 Linux 系统 diff 的格式,diff 即差异(diffrence)的缩写,具体的格式可以 man diff 查阅文档。简单的说,«< 表示本地提交的文件内容,»> 表示远程提交的文件内容,=== 表示分隔符。

在上图中,你和同事共同修改了 # Create by origin,你在句末添加了句号而同事添加了感叹号。经过一番杨风拂柳般的暴打之后,同事屈服和你达成一致,认为这个注释使用句号更合适。

那么,我们只需要删除 »>,«< 和 === 开头的 diff 内容,并删除 === 和 »> 之间的内容(远程提交的文件内容,经过协商不需要保留),修改后的文件内容如下图。

这时使用 git status 查看本地仓库的最新状态。

如提示所言,经过一番友好的暴揍,你和同事已经就解决方案达成共识并由你修改了冲突,这时只需要将冲突解决完毕的文件添加到暂存区。

再次查看本地仓库的最新状态。

对于我们冲突已解决,因此按照提示 git commit 提交,由于没有指定提交信息,自动跳转到输入提交信息的页面。

使用默认提交信息,在 vi 界面输入 :wq 保存并退出,回到 Shell 主界面会在 git commit 下方显示我们这次解决冲突的提交信息。

这时再次使用 git push 推送我们已经解决了冲突的本地改动。

查看 Git 提交日志,能看到自己的提交、同事的提交以及对两者文件冲突进行合并的提交。其中 chinsyo@sina.cn 是本地提交的用户,chinsyo@users.noreply.github.com 是通过 GitHub 网页模拟的同事。

(8)获得帮助

和命令行类似,git 提供了繁复的命令来应对各种使用场景和解决各种使用问题,我们可以通过以下三个命令获得 Git 子命令的帮助信息。

1
2
3
git help <verb>
git <verb> --help
man git-<verb>
1
2
3
4
# 例如,要想获得 config 命令的手册,执行 
git help config
git config --help
man git-config

经过上述的步骤我们学习了Git 的诞生、Git 的安全机制、关联和克隆远程仓库、推送本地提交记录、拉取远程提交记录、解决合并冲突以及如何获得帮助

在多人协作中,Git 提供了强大的分支管理来帮助我们进行版本控制,减少产生冲突,下一篇文章我们将讨论如何利用好分支管理,还会花时间讨论冲突产生时 diff 格式中出现的 HEAD 是什么含义以及如何使用 。