Friday, February 7, 2020

Git 使用指南
Li Yanrui
v 0.1, 20080728
liyanrui.m2@gmail.com
Git 是什么
非常简单地说Git 是一个快速可扩展的分布式版本控制系统,它具有极为
富的集,对内统提级操完全访本控 (Version
Control System),从狭义上来说,它是软件项目开发过程中用于储存我们所写的代
码所有修订版本的软件,但事实上我们可以将任何对项目有帮助的文档交付版本控
制系统进行管理。
2005 Torvalds Git
BitKeeper,后者一直 Linux 内核开发在使版本工具当时
于自软件区中许多觉得 BitKeeper 使用许证并适合软件
的工 Linus 决定着发许更为由灵版本系统
Git 的开发是为了辅 Linux 内核开发的过程,但是现在很多其他自由软件项目
也使用了 Git 实现代码版本管譬如X.org Freedesktop.org 的项目、
Ruby 项目等。
为什么使用版本控制系统
版本控制系统是为懒人准备的,它让懒人们比那些善于备份文档的勤劳人拥有
更干净的文件系统以及更多的可以活着的时间。
本文档主要内容
1 使 Git Git
使 2 章中 Git 实现
开发
3 章讲 Git 强大
4 Git 使 FAQ,用广使
Git 过程中诸位同学所遇到的一些细节问题。
Contents
1 使用 Git 管理个人文档 1
1.1 何种文档需要保存 1
1.2 建立项目仓库 1
1.3 关于建立 Git 仓库的一些细节 2
1.4 仓库与工作树 3
1.5 在项目中工作 4
1.6 查看版本历史 5
1.7 撤销与恢复 7
1.8 如何使用 Git 帮助文档 7
1.9 总结 8
2 基于 Git 的团队协同开发 9
2.1 两个人如何协同 9
2.2 如何解决仓库合并冲突 10
2.3 三人以至更多人如何协同 12
2.4 M2GE 的协同开发 12
2.5 总结 13
3 项目分支管理 14
3.1 如何产生项目分支 14
3.2 分支的合并 15
3.3 M2GE 新的协同开发模式 15
3.4 总结 16
1 章 使用 Git 管理个人文档
本章述如使用 Git 管理我的个档,用以展示 Git 的一些本功
并且秉承以致用、用以促学的精导大家积地将 Git 应用于日常学习
作中的文档备份。仿温水煮蛙之古例,此章乃温水也。
1.1 何种文档需要保存
凡需要持续变动的文档皆可作为项目并交付于 Git 进行管理。由于 Git 可以详
细地记录对于项目的各种修改并提供了功能强大的版本控制,因此愈是修改较为频
繁的文档,愈是有必要将其纳入 Git 的管理之下。
理论上Git 可以保存任何文档但是最善于保存文本文档,为它本来就是
解决软件源代码(也是一种文本文档)版本管理问题而开发的,提供了许多有助于文
本分析的工具。对于非文本文档,Git 只是简单地为其进行备份并实施版本管理。
1.2 建立项目仓库
欲使 Git 对现有文进行本控先要于现文档立项仓库
面以本文档的版本管理为例,演示如何将其作为项目并纳于 Git 的版本控制之下。
T
E
X T
E
X $HOME/work/m2doc
下,下文为叙述方便, Bash 变量 $WORK 代替该目录。首先需初始化 Git 仓库:
$ cd $WORK
$ git init
Git 会作出以下回应:
Initialized empty Git repository in $PROJECT/.git/
果是 $WORK 目录 .git 它就
Git 仓库过现的。 $WORK 目录
今后我们将其称为工作树
Git Git
加文
2
Git Git "take a snapshot"
快照)若将工作树下所有文档(包含子目录)生成快照,可采用以下命令:
$ cd $WORK
$ git add .
Git 使
git-commit 令可将索提交至仓中,这个过称为提交一次交都意味
版本在进行一次更新。git-commit 最简单的用法如下:
$ git commit
执行 git-commit 命令时,Git 会自调用统默文本辑器
输入版本更新说明并保存。请记住,输入简约的版本更新说明是非常有必要的,它就
像剧本一样,可以帮助你快速回忆起对项目的重大改动。
对于简短的版本更新信息,可以使用 git-commit 的“-m”选项,如下:
$ git commit -m "你的版本更新信息"
上述过程即为建立 Git 仓库的一般过程,我将其总结为图1.1所示之流程:
git-init
git-add
git-commit
1.1 Git
1.3 关于建立 Git 仓库的一些细节
看过上一节内容,也许你会跃跃欲试,准备拿自己的一个文档目录下手。切莫如
此着急,为了概念的整性上一内容中,我故意省略两个细节问题面逐
道来。
3
第一个问题是在使用 Git 之前,你需要面对 Git 来一番自我介绍Git 不喜
不愿透漏姓名人,因为它要求个人在向库提交数时,当承担一的责
任。要向 Git 进行自我介绍,请使用以下命令:
$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com
第二个问是:在生成档内快照时,工作树中有一文档你不希望
Git 譬如对于
快照?
譬如对于上一节的用例,在工作树中存在以下文件(或子目录)
doc-env.tex git-tutor.tex Makefile zh
git-tutor main.tex vfonts.tex
其中的 zh 目录存放着 T
E
X 文档编译时生成的中间文件,因此该目录不应该被
Git 管理决此题,Git 提供文档机制将工中你希望
Git .gitignore
zh 目录,采用如下操作可将其排除仓库之外,然后再对 $WORK 生成快照即可。
$ cd $WORK
$ echo "zh" > .gitignore
$ git add .
有关 gitignore 文件的诸多细节知识可阅读其使用手册:
$ man gitignore
1.4 仓库与工作树
按照前文的说法,Git 库就是那个 .git 录,其中存放的是我们所提交的
索引Git
文档的版本控制。工作树是包含 .git 的目录,在前文示例中即 $WORK 目录。
为了更加明确仓库与工作树的概念,下面做一个实验:
4
$ cp -R $WORK/.git /tmp/m2doc.git
$ cd /tmp
$ git clone m2doc.git m2doc-copy
首先我们 $WORK 目录 .git 目录复 /tmp 目录下并
m2doc.git ,然后使用 git-clone 命令
1
m2doc.git m2doc-copy 目录。
进入 m2doc-copy 目录观察一下,就会发现该目录所包含的内容是等同于 $WORK
录的。
上述实验意味着只要我们拥有仓库, m2doc.git ,那么就可以很容易地生
成工而这着一 m2doc-copy/.git 。所以,我们
以这样理解: Git 中,仓库与工作树之间无需分的很清楚。
1.5 在项目中工作
Git
改,添加/删除一文件些操与采 Git 管理我们文档前没任何
Git,命
行更新,这一步骤是通过生成文档快照并将其加入到索引中来实现的。
我向 $WORK ch1.tex ,我需要通 Git
住我的这一更新:
$ cd $WORK
$ git add ch1.tex
Git ch1.tex
doc-env.tex 以及 git-tutor.tex 使
git-add 命令将它们的更新添加到索引中:
$ git add doc-env.tex git-tutor.tex
晚上,这一天的工作告以段落,我觉得有必要将今天所做的提交到仓库中,于是
执行 git-commit 操作,将索引内容添加到仓库中。
除)但是我忘记它们的名字,此时若所做的全部更添加到索引中较轻
的做法就是:
工作树克隆命令,在后文中将会对其详细讲述。
1
5
$ cd $WORK
$ git add .
$ git commit -a
... 输入日志信息 ...
git-add
git-commit -a
或者已删除的档的当前态提交倒库中住,只是修改者删除了
Git 管理的文档,是没必要使用 git-add 命令的。
本节并未述新 Git 命令,是前所讲的一命令重复绍,只是
它们出现的场景有所区别而已另外,注意的问题是,Git 会主动记录你对文档
进行的更新,除非你对它发号施令。
1.6 查看版本历史
使 git-log 使
git-commit 向仓库提交新版本时所属如的版本更新信息。
$ git log
如果你想看一下每一次版本的大致变动情况,可使用以下命令:
$ git log --stat --summary
git-log 命令Git 使用
档项目的工作树中查阅项目日志,git-log 命令给出了以下回应信息:
6
commit dfb02e6e4f2f7b573337763e5c0013802e392818
Author: Li Yanrui <LiYanrui.m2@gmail.com>
Date: Wed Jul 9 16:32:25 2008 +0800
Git 使用指南文档项目初始化
commit 9a4a9ce37561bbb42d8187d7a851e228e26e1212
Author: Li Yanrui <LiYanrui.m2@gmail.com>
Date: Wed Jul 9 16:31:07 2008 +0800
添加 .gitignore 文件
commit 459640624390eb733fb2ad45bcb8731435931e60
Author: Li Yanrui <LiYanrui.m2@gmail.com>
Date: Wed Jul 9 16:28:50 2008 +0800
M2Doc 项目初始化
lines 1-17/17 (END)
从上面的项目日志信息中可以看到我对 M2Doc 项目所做的一些阶段性工作,
每一个版本都应着一次目版本更提交项目日志息中条日志的
(就是那一串名奇妙的字)本更新提所进行的名,可以将该
理解为项目版本号。项目版本号应该是唯一的,默认由 Git 自动生成,用以标示项目
的某一次更新如果我们将项目版本号用作 git-show 命令的参数即可查看该次项
目版本的更新细节:
$ git show dfb02e6e4f2f7b573337763e5c0013802e392818
除了使用完整的版本号查看项目版本更新细节之外,也还可以使用以下方式:
$ git show dfb02 # 一般只使用版本号的前几个字符即可
$ git show HEAD # 显示当前分支的最新版本的更新细节
每一个项目版本号通常都对应存在一个父版本号,也就是项目的前一次版本状
态。可使用如下命令查看当前项目版本的父版本更新细节:
$ git show HEAD^ # 查看 HEAD 的父版本更新细节
$ git show HEAD^^ # 查看 HEAD 的祖父版本更新细节
$ git show HEAD~4 # 查看 HEAD 的祖父之祖父的版本更新细节
你可以对项目版本号进行自定义,然后就可以使用自定义的版本号查看对应的
项目版本更新细节:
7
$ git tag v0.1 dfb02
$ git show
实际命令是真进行号自是制一个 tag 对象
而已进行目版外发时比有用本文档后章节 tag 的一些细
节进行介绍。
1.7 撤销与恢复
git-reset 命令就是为这样的任务而准备的它可以将项目当前版本定位到之前提交
的任何版本中。
git-reset --mixed --soft --hard 。我使
使两个使
用。
--mixed git-reset 的默认选项它的作重置引内定位指定
的项目版本,而不改变你的工作树中的所有内容,只是提示你有哪些文件还未更新。
--soft 选项既不触动索引的位置,也不改变工作树中的任何内容,但是会要求
它们处于一个良好的次序之内。该选项会保留你在工作树中的所有更新并使之处于
待提交状态。
git-reset 命令使便
Git 仓库并更新后测 --mixed --soft 选项的
如果欲查 git-reset 令对工作树的影响,可使 git-status 令。另外这道练习
git-reset 使节) git-reset
用法,这道题就算做对了。
1.8 如何使用 Git 帮助文档
使
git-reset 命令但是际输形式
git reset。我猜测这样做的原是后者作为命形式对于用户更为好一
些,我们已经习惯在终端中入这样的令格式。但是在阅命令的明文
档时,需要使用第一种命令格式,譬如要查看 git reset 命令的用法,可:
8
$ man git-reset
1.9 总结
现在我们总算是掌握了有关 Git 的一些粗浅但非常实用的知识,已具备了使用
Git 积极使 Git 来管
需要进行版本控制的个人文档。
2 章 基于 Git 的团队协同开发
很多时候我们是多个人同时为做一件事情而努力,如何有效化解多人协同运作
过程中出现的种种矛盾是相当重要的实践证明Git 可以很好的胜任此类任务
也是我们要在实验室内部推广 Git 应用的主要原因。
2.1 两个人如何协同
Lyr Tzc 是本节的两位主角。现在假设 Lyr 开始着手开发 M2GE 并按照
1 章所讲述的 Git 基本用法将 M2GE 库纳于 Git 的管理之下。但是,很快 Lyr
个人项目 Tzc
M2GE 库,故事就这样开始了。
Lyr M2GE /work/m2ge Tzc 可通 Lyr 同样
的工作树:
$ cd work
$ git clone lyr@192.168.0.7:~/work/m2ge m2ge
git-clone 访 Git
Tzc SSH 访 Lyr 机器 lyr 账户
M2GE m2ge
git-clone Tzc Lyr
M2GE Tzc m2ge
些多余。
注意git-clone 命令只要碰到以下式的仓库址,它就认为
址是符合 SSH 协议的。
账户@IP:工作树路径
Tzc 既已获得 M2GE 工作树,他就可以开始工作了,同时,Lyr 也在位于自己的
机器 M2GE 工作二人 M2GE 仓库
的操作只需具备第 1 章所讲述的内容足矣。
一个阶段后,二人均将做的作不地提到各 Git 仓库中,
后再阶段 Lyr
10
为主要开发者二人的工作在他的机器上进合并是比较自然的当然 Tzc 机器
上合并也尝不可,因为 Git 是不分主仓库的,同一项目的不仓库都是位均
等。
为实现与 Tzc 的工作合并,Lyr 执行了以下操作:
$ cd ~/work/m2ge
$ git pull tzc@192.168.0.5:~/work/m2ge
git-pull 命令可将属于同一项目的远端仓库与同样属于同一项目的本地仓库进
行合并,它包含了两操作从远仓库中取出更版本后合并到本地库。
述命令可在 Lyr m2ge 仓库中完成对 Tzc 机器上的 myge 仓库的合并。
Lyr Tzc 了改那么
库合并。但是倘二人对一些相的文件进了改动,那么在并时必然遭遇
并冲突的问题,此时手动修改发生合并冲突的文件,然后将结果提交到本地仓库。
于处理合并冲突的问题比较复杂一些,所以下面单独拿出一个小节来讲述。
当项目合并结束后,味着 Lyr Tzc 一个协同开发周期的结束他们彼此很
欣赏对方的工作,所以又开始了下一个周期……
2.2 如何解决仓库合并冲突
现在假设 Lyr Tzc 各自的工作树对同一份文件 foo.txt 行了修改
foo.txt 原内容如下:
one
two
three
Lyr foo.txt 进行了如下改动,并将该改动提交到本地仓库。
ONE
two
three
Tzc foo.txt 进行了以下改动,也将该改动提交到本地仓库。
one
two
THREE
11
Lyr 在合并 Tzc Git 仓库时,Git 会自动合并二人对 foo.txt 的修改:
ONE
two
THREE
Lyr foo.txt Lyr Tzc
动,而且合并结果自动作为新版本提交到 Lyr 的仓库中。
观察上述合并冲突示例可以看出虽然 Lyr Tzc 是对同一份文件进行了修
改,但是他们修改未重在假二人 foo.txt 同一做出修改
在仓库合并时会发生什么,应当如何处理呢?
现在假定上述示例中,Tzc foo.txt 的修改如下:
one ONE
two
three
foo.txt 一行修改合并Git 会给出以下
反馈信息:
Auto-merged foo.txt
CONFLICT (content): Merge conflict in foo
Automatic merge failed; fix conflicts and then commit the result.
上述息之试合 foo.txt 的改发生突,自动并失
用户突然交到Lyr 看到上述就打合并
foo.txt,他看到了以下内容:
<<<<<<< HEAD:foo
ONE
=======
one ONE
>>>>>>> 1116d3270764d91a25532a753a47b8b0e1b6f1b8:foo
two
three
以一 < 开头的字串表示 Lyr 的当前项目版 foo.txt 的修改结果,而以一
> Tzc foo.txt
= 修改结果隔开Lyr
现实情况将合并冲突问题解决掉他认 Tzc 的改动是不符合项目需求的且按
12
照项目的实际需求进行了手工合并。最后Lyr 将合并处理结果提交到仓库中,
成了重叠冲突的合并问题的解决。
2.3 三人以至更多人如何协同
前文在讲述二人协同模式时强调 Lyr Tzc 主次关系这种关系似乎对
于三更多也有现在再引事主 Lxc Zhu 来说
Lxc Zhu 仿照 Tzc Lyr 那里 git-clone 了一
进行了一番卓有成效的版本更新。最后,Lyr 要一一取回其他三人的仓库,然后再
成一个协这些工作逐渐 Lyr 汗流
Lyr 希望其他三人能够分担一下项目版本合并问题的处理工作。
Git git-pull git-push。顾git-pull 命令
远端仓库取回版本更新, git-push 可将本地版本更新推送到远端仓库中。
利用 git-pull git-push 令,那么在一个协同周期之内,除了 Lyr 之外,其余
三人的项目开发流程大致如下:
$ git clone lyr@192.168.0.7:~/work/m2ge
... 项目开发 ...
$ git add 改动的文件
$ git commit
$ git pull
... 解决版本合并问题 ...
$ git push
内,Lyr M2GE 仓库的管一份他个人项
目一般,因为 M2GE 库是位于他的机器上,他是不需要 git-pull git-push 的。
这样个基 Git 较为简单的人以更多的协工作式被现了
是我们在尚未熟悉 Git 应用之时比较稳妥的协同方案。下一节将基于这一方案讲述
M2GE 库仓库的建立以及多人协同开发过程的具体实现。
2.4 M2GE 的协同开发
Lyr 过于
特殊人都 git-pull git-push,唯独不需在要夺他这一权,
有效的办法就是将 M2GE 仓库建立在实验室的服务器上。
13
首先Lyr 通过 SSH 登录务器寻找置,建立 m2ge.git 目录
/project/m2ge.git ,然后初始化一个空仓库,以此作为 M2GE 仓库:
$ mkdir -p ~/project/m2ge.git
$ cd ~/project/m2ge.git
$ git --bare init --shared
上述操作中git-init 令的 --bare 选项可以 m2ge.git 目录等价于一个
m2ge.git 本来 --bare
m2ge.git/.git 容全放置 m2ge.git 目录就好仓库完全
露在工作树中,所以称之为赤裸的仓库。
Lyr Git m2ge
m2ge.git 仓库:
$ cd ~/work/m2ge
$ git push m2@192.168.0.2:~/project/m2ge.git master
上述 git-push 命令中出现 master 参数的含义将下一章讲处可略过
不谈。在,家已经得到 M2GE 库的最初版本,并且可以使用 git-clone 命令
在本地创建工作目录:
$ git clone m2@192.168.0.2:~/project/m2ge.git
之后,我们就可以开始一个又一个协同周期,服务器上的 m2ge.git 库将会逐
次记录着每位协同开发者的版本更新提交,此基本过程可参考上一节所述内容来理
解。
2.5 总结
Git Git
令:git-clonegit-pull git-push。基于这三个命令并配合上一章所讲述 Git 基本
操作,足以实现 M2GE 初级阶段的协同开发。
3 章 项目分支管理
Git 最为世人称道的就是它那强大的项目分支管理功能,现在较为流行的版
控制系统,诸如 CVSSVN 等,虽然也提供了项目分支管理功能,但是可用性极低。
对于 Git 而言,多个目分如探囊取耳。本章主要 Git 的项目分支管
理的基本知识以及如何利用这一功能形成更有章法的项目协同开发模式。
3.1 如何产生项目分支
前两章所内容有提及项分支题,实上有一个分存在
master 分支(主分支是 Git 自动产生此之们针项目
本的各种操作都是在主分支上进行的,只是我们未察觉它的存在而已。
Git 可以轻松地产生新的项目分支,如下面操作可添加一个名曰local”的
新的项目分支:
$ git branch local
生的 local local
所进行的所有本更新工都不影响分支意味着作项目的参与者
local 中开始各种各样的更新尝试。
查看目仓中存多少支,可直接使 git-branch 命令如使该命
查看我的 M2Doc 项目分支列表:
$ git branch
local
* master
在上述操作输出结果中,若分支名之前存在 * 符号,表示此分支为当前分支。
Git 各分支不存在尊卑别,只存在个分支是前分的区别。为了某良好
的秩序,很多人默认是将 master 分支视为主分支,本文也将沿用这一潜在规则。
使 git-branch
local Git local 使 git-checkout
令实现分支切换,下面操作将当前分支切换为前文所产生的 local 分支:
$ git checkout local
15
3.2 分支的合并
我们产生了 local 分支,并在该分支下进行了诸多修改与数次的版本更新提交,
但是该如何将这一分支的最终状态提交到 master 分支中呢?
git-merge local master 分支
合并,操作如下:
$ git checkout master # 将当前分支切换为master
$ git merge local # local分支与当前分支合并
当一分支查无且与 master 分支成合并毕后那么这一支基
上就没有存在的必要性了,可以删除掉:
$ git branch -d local
注意,git-branch -d 选项只能删除已经参与了合并的分支,对于未有合并的
分支是无删除果想问青红皂地删一个支,可以使 git-branch
-D 选项。
3.3 M2GE 新的协同开发模式
Git
M2GE 库的协同开发机制。
实验室服务器上已经建立了 M2GE 仓库
1
现在以 Lyr 作为主角,看一看他围绕
M2GE 开发工作的一天中的工作过程。
首先Lyr 自己的版
信息:
$ git pull
$ git log
然后,Lyr 始建立一个新的项目分支将其命名 lyr,并将当前分支切换为
该分支:
$ git branch lyr
$ git checkout lyr
如有不解,请阅读第 2 章。
1
16
然后分时Lyr 己所
如增加了 3 个新的接口及相关测试序,对原有接做了一些修改一天工作
完成他有要将的工 M2GE 仓库 master 分支进合并然后
lyr 分支:
$ git checkout
$ git merge lyr
$ git branch -d lyr
现在,Lyr 已经将这一天的工作反映到自己机器上的 M2GE master 分支上了,
他最做的其推服务 M2GE 仓库,使目其员能享他
的工作这里要注意,推送版本更新之前,要使用 git-pull 命令将这一天中其他
成员对服务器端的 M2GE 更新拉过来合并到自己的 master 支,然后才可以将
自己的版本更新推送到服务器上的 M2GE 仓库,具体操作如下:
1. 使用 git-pull 命令更新本地工作树;
2. 若出现版本合并冲突,并且 Git 无法自动合并,需要手工合并,然后将合并结
果提交到本地 master 分支;
3. 使用 git-push 命令将本地 master 分支更新推送到服务器 M2GE 仓库中。
Git M2GE
M2GE 仓库
据。避免 git-clone 服务
M2GE 仓库来恢复本地的项目主分支。
3.4 总结
本章 Git 项目分本知并利些知 M2GE
的协同开发机制。至此为止,诸位同学已经接触了 Git 的主要功能,并且已经具备了
向专业级别的开发团队过渡的基本能力。但是,工具毕竟是工具,并不能代替人的地
使 Git,并
努力培养团队协同开发意识。