本文主要介绍Git版本控制工具的具体使用,并不介绍其安装,具体安装可自行上网搜索。
本文所有操作均在Linux环境进行,但命令本身并不区分平台,在Windows平台也可正常运行。
为了便于大家进行实操练习,本文使用的远程Git库是GitHub,可以很方便的申请一个账户。
作者: SunnyZhang
Git是一个分布式的版本控制工具,其在使用上要比SVN等版本控制工具稍显复杂。为了便于理解,本文通过图文方式详细介绍Git的使用,以便于快速掌握Git。Git涉及的主要概念和命令如图所示。理解上述概念后,基本可以使用Git完成日常开发工作。
从上图可以看出Git从概念上分为3个大的区域,分别是工作空间、本地仓库和远程仓库。另外还有一个暂存区域,也称为索引区。下面我们看一下各个区域是做什么的。体现Git是分布式版本控制的关键点是它具备一个本地仓库,其实平时的版本控制工作都是在本地库操作,如果不涉及团队协作或者备份,甚至可以只使用本地库即可。
为了保持文章的完整性,这里啰嗦一下。创建工作空间其实就是创建一个本地目录。在Linux平台执行如下命令即可。
mkdir gittest
然后切换到该目录,并在里面随便创建一个文件,可以执行如下命令。
cd gittest
echo "hello itworld123" > test.md
完成上述操作后,我们可以看一下工作空间(其实就是一个本地目录,没有什么高大上的)。
创建本地仓库其实非常简单,保持在刚才创建的文件夹内部(工作空间)。通过执行git init
命令就可以初始化一个本地仓库。
git init
完成本地仓库的创建之后,我们可以看到在目录下多出一个.git的隐藏目录,Git就是通过这个目录里面的内容实现版本控制的。
我们可以看一下这个目录里面都包含什么内容。具体文件的含义超出本文的介绍范围,本文不做过多解释。这里只是对该目录有个感性的认识。
创建完成本地仓库之后就可以查看工作区的状态了。通过git status
命令可以查看工作空间的状态(也就是文件的被管理情况)。
git status
执行该命令后,可以看到在该工作区有一个文件,且处于未管理状态。
![图5 工作区状态](http://github.itworld123.com/tools/git/add_before_status.png)
如果在没有创建本地仓库的情况下执行该命令会有相应的报错,其内容大概是这样的:fatal: Not a git repository (or any of the parent directories): .git
好吧,经过上面的操作其实我们已经有了一个本地仓库了,但是本地仓库内部并没有管理任何内容。我们这一步做的就是让他管理一个文件。我们在前面工作空间中已经创建了一个名为’test.md’的文件了,这是个普通的文本文件,内容是"hello itworld123"。我们这步先把它管理起来,具体执行如下命令。
git add test.md
此时就将该文件添加到了暂存区。然后我们在执行以下git status
命令,可以看到如下结果。此时该文件已经被管理起来了,从提示我们可以看到这个文件还没有提交。没有提交的意思就是还没有真正在本地仓库里面,只是在暂存区而已。
![图6 添加文件后状态](http://github.itworld123.com/tools/git/add_after_status.png)
提交文件其实就是将文件提交到本地库,也就是开始进行真正的版本管理了。具体可以通过执行如下命令,其后面的-m选项表示该次提交的注释内容。
git commit -m "add new file"
完成提交后,我们可以在看一下这个工作空间的状态。可以看到此时工作空间的内容已经与本地仓库完全一致。
![图8 提交后状态](http://github.itworld123.com/tools/git/local_rep_commit_status.png)
完成提交之后,在本地仓库已经有了我们刚才提交的内容。也就是说现在本地仓库已经对我们的内容进行版本控制了。那么,我们怎么知道已经做了哪些提交呢?这个时候git log
命令就派上用场了。从字面上我们也能猜出大概用途来,这个命令是用来查看提交日志的。
git log
![图9 提交日志查询](http://github.itworld123.com/tools/git/local_rep_commit_log.png)
从上图可以看到提交的基本信息,包括提交的UUID(黄色字体)、作者、日志和描述信息等内容。
如果我们想看一下提交的详细内容又该怎么办呢?通过git show
命令可以查看某一次提交的详细内容。以上次提交为例:
git show 4909da5e6097e2f50c36ad892a18fd6f2527d4c1
![图10 提交日志详情](http://github.itworld123.com/tools/git/local_rep_commit_detail.png)
由上图可以看到提交的详细内容,除了上一个命令所涉及的简要信息外,还包括具体修改的那个文件,哪一行,以及具体修改的内容等等。
我们在本地进行修改后,有的时候想了解当前工作区的内容作了哪些修改,这个时候可以使用git diff
命令进行查看。
git diff
执行该命令是查看工作空间与暂存区
的差异情况。比如我们在test.md文件中增加一行,此时执行git diff
命令,如图绿色的部分就是我们新加的内容。
![图11 工作区差异详情](http://github.itworld123.com/tools/git/local_rep_git_diff.png)
但是如果我们把这个文件加入暂存区,然后在执行相同的命令,这时我们将看不到任何差异提示。当然该命令不仅仅能够实现工作区与暂存区的对比,还能实现更复杂的对比功能。这里本文暂时不做介绍,后面再详细介绍。
在修改代码的时候经常会出现改了很多代码导致程序无法正常运行的情况,这个时候想回退到某个版本,然后把修改的代码慢慢加进去。Git提供了git reset
命令来解决代码回退的问题。比如我们对刚才添加的代码不满意,想通过Git命令回退到之前的版本。这是需要找到期望回退版本的commit id,然后执行如下命令。
git reset --hard 4909da5e6097e2f50c36ad892a18fd6f2527d4c1
执行成功后,可以看到如下提示,并且文件的内容已经被回退到该版本。
该命令同样有更为丰富的功能,不仅可以实现上述的代码回退,还可以实现本地仓库、暂存区和远程仓库的回退,本文暂时不做介绍。
首先介绍一下什么是分支,分支( branches ) 是指在开发主线中分离出来,做进一步开发(比如新特性)而不影响到原来主线。实际上在我们创建完本地仓库时,就已经有一个_分支_了,只不过这个分支是主分支,也叫主线(master)。如图所示,在实际应用中除了主分支外还会有其它分支,比如dev分支用于开发新特性。当完成新特性开发后,将代码统一合并到主分支中。
我们先了解一下我们工作空间的分支情况,通过命令git branch -l
可以看到本地分支。在我们的测试环境运行该命令可以看到当前以及存在的分支。
我们前面提交的内容都是直接提交到主线的。如果我们开发一个新的特性,直接提交到主线在人多的情况下会非常乱。因此我们可以创建一个分支,等特性开发完成后再合并到主线。执行git branch
命令可以创建一个新的分支。
git branch branch0
创建完成后,我们通过git branch -l
可以看到已经有一个新的分支,名称为branch0。
如果仔细观察就会发现,此时master分支的颜色是绿色的,而且前面有个*
,这说明当前工作空间仍然在master分支。如果想切换到新的分支怎么办呢?可以使用下面介绍的命令。
通过git checkout
命令可以将工作空间切换到新创建的分支。执行该命令进行分支切换,然后通过git branch -l
可以看到发生的变化,此时branch0分支变成了绿色。
git checkout branch0
切换分支以后,再提交的代码就位于新的分支。需要注意的是,如果在分支做了一些修改,但还没有提交,这时切换分支会丢失已经做得的修改,因此切换之前需要提交代码。
假设我们在branch0分支已经添加了一些内容,并进行了提交。此时我们想将这些内容合并到主分支中。合并的方法就是先切换到主分支,然后执行git merge
命令。
git merge branch0
如下图是整个合并分支的过程,红线上面的是branch0分支的test.md文件的内容,绿线上面是master分支中test.md文件的内容,前者比后者多3行内容(含1行空行),执行合并命令后再看master分支中test.md的内容已经与branch0中的一致了。
其实我们前面玩了半天,都是在本地玩的,压根没有涉及Git服务器的任何事情。如果要多人协同肯定要涉及到一个服务节点,这个服务节点其实类似于中转站的概念,跟SVN服务有着本质的区别。前面说了我们以github为例进行介绍。假设我们在github上已经有了一个空的远程库(假设远程库路径为https://github.com/xxx/test.git),此时远程库没有任何内容。此时我们可以通过git remote add
命令添加远程库。
git remote add origin https://github.com/xxx/test.git
添加远程库后,其实并没有对远程库做任何事情,远程库还是空的。这里只是添加了本地仓库与远程仓库的关联关系。其中origin是远程仓库的一个代名词,可以使用其它任何名称,这里只是惯用法而已。
添加完关联关系之后,我们就可以将本地仓库推送到远程服务器上,例如我们将本地的master分支推送到github上,执行如下命令,过程中需要我们输入github上注册的用户名及对应的密码。
git push origin master
完成该操作后,可以登录github看一下远程仓库的情况。可以看到在github上的远程仓库已经具备了一个master分支,且包含与本地仓库一样的内容。
除了第一次向远程仓库推送内容外,我们后面修改代码后想向远程仓库提交代码使用的也是这个命令。默认情况下,git会将代码推送到与本地分支同名的远程分支。
我们提交代码的一般流程是这样的:添加到暂存区(git add),提交到本地仓库(git commit),最后推送到远程仓库(git push),具体可以参考图1。
如果我们来了一个新同事,需要下载远程仓库的代码进行开发怎么办?这个使用就用到了克隆命令,克隆命令可以将远程仓库的内容克隆一份,生成一个一模一样的本地仓库,同时会生成工作空间的内容。需要知道的是,默认情况下工作空间的内容是master分支的内容,如果需要其他分支,则需要创建本地分支,并且进行切换。例如我们从测试用的github上克隆上文推送的代码,假如我们克隆到一个新的文件夹gittest1,执行如下命令后,可以看到克隆后gittest1下面已经具有master分支的内容。
git clone https://github.com/xxx/test.git gittest1
在多人协同的情况下,会不断的有人向远程仓库提交新内容。为了保证代码的同步,我们需要将远程代码拉到本地,git有2个命令可以将远程仓库的内容拉到本地,一个是pull,可以将远程仓库的代码拉到本地仓库,同时合并到本地工作空间;另一个是fetch命令,这个命令只将远程仓库的内容更新到本地仓库。
git fetch
执行上面命令可以将远程仓库的内容拉取到本地仓库,但并不会更新本地工作空间
。如图所示,我们将gittest中文件添加一行(a5),然后同步到远程仓库。然后切换到目录gittest1,并通过git fetch
命令拉取远程仓库的内容。可以看到gittest1中test.md文件中的内容并没有变化。然后我们再执行git merge
命令,该命令会将本地仓库相同分支的内容更新到工作空间,此时再查看文件内容,已经更新为最新的内容。
使用git pull
命令可以直接将文件内容更新到工作空间,如图我们在gittest文件夹中test.md添加一行a6,并同步到远程仓库。然后,我们切换到gittest1文件夹执行git pull
命令,可以看到文件内容已经更新。
在很大的项目中,团队成员会很多,有时候我们需要知道某一段代码的作者。这时可以使用git blame
命令。通过该命令可以获取提交的ID、作者和时间等信息。
git blame -L 5 test.md
写到这里其实已经涵盖了Git的大部分常用命令,基本上可以满足我们日常开发使用。但是,Git的功能是如此的强大,以至于我们介绍三天三夜也无法讲完。本文先介绍到这里,后面再详细介绍每条命令的用法。
出处在这里