Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145841
  • 博文数量: 33
  • 博客积分: 667
  • 博客等级: 中士
  • 技术积分: 277
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-27 11:18
文章分类

全部博文(33)

文章存档

2014年(1)

2013年(2)

2012年(11)

2011年(19)

分类: 嵌入式

2011-07-27 11:49:30

工欲善其事,必先利其器。在学习Android之前,我们必须掌握Git的使用。

什么是Git?Git是一个免费、开放源码的分布式版本控制系统。目前,包括Git自身、Linux kernel、Perl、Eclipse、Gnome、KDE、QT、Ruby on Rails、Android、PostgreSQL、Debian,X.org等很多项目都在使用Git进行版本管理。(摘自Git官网)

如何学习Git?Git文档以man pages的方式提供给用户。对于Ubuntu用户,命令行运行sudo apt-get install git-man即可安装Git相关文档。

本文是gittutorial的翻译版本,可以通过man gittutorial查看原文。

概述

本文讲述了如何导入新项目到Git,如何修改项目以及如何将修改通知给其他开发者。

如果主要是想了解如何使用Git来取得一个项目,例如测试项目的最新版本,可以参考的前两章。

这里首先介绍下如何查阅Git文档,下面以命令git log --graph为例:

  1. $ man git-log

或者:

  1. $ git help log

利用后者,可以查阅manual pages式的帮助,详情请参见。

在开始使用Git之前,最好设置使用者的名字和电子邮件以方便Git记录日志。设置方法如下:

  1. $ git config --global user.name "Your Name Comes Here"
  2. $ git config --global user.email you@yourdomain.example.com

导入新项目

假如项目文件为project.tar.gz,可以通过如下方法将其导入到Git。

  1. $ tar xzf project.tar.gz
  2. $ cd project
  3. $ git init

Git会做出以下回应

  1. Initialized empty Git repository in .git/

至此,工作目录已经初始化完成,并且在当前位置创建了一个新目录.git。

接着,利用git add命令将当前目录下所有文件的快照通知Git:

  1. $ git add .

当前目录所有文件的快照被存储在索引文件中。可以利用git commit命令把索引文件的内容永远存储到Git中:

  1. $ git commit

这条命令会提示用户输入注释。至此,项目的第一个版本已经存储到Git中了。


修改项目

修改一些文件,然后将修改添加到索引文件中:

  1. $ git add file1 file2 file3

现在可以提交了。在提交以前,可以通过如下命令检查即将提交的内容与原始内容的差异:

  1. $ git diff --cached

(如果不添加--cached选项, git diff将会显示所有没有添加到索引文件的修改)

也可以通过命令git status来获取当前Git状态:

  1. $ git status
  2. # On branch master
  3. # Changes to be committed:
  4. #     (use "git reset HEAD ..." to unstage)
  5. #
  6. #         modified: file1
  7. #         modified: file2
  8. #         modified: file3
  9. #

如果还需要修改其他内容,那赶紧改吧。然后,就可以把所有的修改加到索引文件,并用下面的命令提交:

  1. $ git commit

执行上面的命令,系统会提示输入注释,然后记录一个新版本到版本库。

如果不想在提交之前执行git add命令,可以使用:

  1. $ git commit -a

这条命令可以自动检查所有修改(不包括新加文件),然后添加到索引文件中并提交。

注意:在提交修改时,最好在注释的开始写上一行简短的修改摘要(少于50个字符),接着一个空行,最后是关于修改的详细描述。Git会把修改注释转换成电子邮件,例如,把注释的第一行作为邮件的标题,其余部分作为邮件的内容。


Git跟踪的是文件的内容,而不是文件本身

很多版本控制系统都提供add命令,用于通知版本控制系统跟踪新添加文件的修改。Git的add命令用法更简单,功能更强:git add 不仅用于跟踪新添加文件,还可以用于跟踪最近修改内容的文件。在这两种情况下,Git都会记录修改,并修改索引文件,再下次提交的时候将修改写入版本库。


查看项目的修改历史日志

在任何时候,可以利用如下的命令查看修改历史日志

  1. $ git log

如果希望查看每一步的完整比较,使用:

  1. $ git log -p

更为常用的用法是利用下面的命令查看每一次修改的总结

  1. $ git log --stat --summary

管理分支

一个简单的Git版本库可以支持多个分支的开发。使用如下命令创建名为“experimental”的分支:

  1. $ git branch experimental

如果现在执行下面的命令

  1. $ git branch

系统将会列出目前所有的分支:

  1.   experimental
  2. * master

"experimental"是刚刚创建的分支,"master"是系统自动创建的默认分支。星号代表当前用户正在工作的分支。输入如下命令:

  1. $ git checkout experimental

切换为“experimental“分支。然后编辑文件,提交,并返回“master”分支:

  1. (edit file)
  2. $ git commit -a
  3. $ git checkout master

检查刚刚的修改在当前分支上并不存在,这是因为刚刚在“experimental”分支上修改,修改后切换回“master”分支。

针对同一文件,在"master"分支做不同的修改:

  1. (edit file)
  2. $ git commit -a

此时,两个分支出现不一致,不同的分支上有着不同的修改。为了把“experimental”分支上的修改合并到“master”分支,需要执行

  1. $ git merge experimental

如果修改没有冲突,那么合并就做完了。否则,用于表明冲突的标记会被添加到冲突的文件中。

  1. $ git diff

git diff可以用来查看冲突。一旦你修改了文件,解决了冲突

  1. $ git commit -a

将会提交合并的结果到版本库。最后

  1. $ gitk

将会显示一个友好的图形界面来展示修改历史。

这时,可以执行下面的命令删除“experimental”分支

  1. $ git branch -d experimental

这个命令可以确保“experimental”分支的全部修改已经合并到当前的分支,否则删除将失败。

如果不想在“crazy-idea”分支上继续开发,可以执行如下命令删除分支

  1. $ git branch -D crazy-idea

Git的分支操作如此的简单高效,所以,这是我们做试验的好方法。


利用Git进行团队协作

假设Alice已经开始了一个新项目,项目的Git版本库位于/home/alice/project。Bob想要参与到项目中来,并且,Bob在同一台机器上也有home目录。

Bob开始执行如下命令:

  1. bob$ git clone /home/alice/project myrepo

这条命令创建了一个新目录"myrepo",它是Alice的Git版本库的克隆。这个克隆的版本库和原始的项目处于同等地位,一切在克隆版本库上的操作,都会记录在属于克隆版本库自己的项目日志文件中。

然后,Bob做了一些修改并提交到Git版本库

  1. (edit files)
  2. bob$ git commit -a
  3. (repeat as necessary)

当修改完成后,Bob通知Alice把他的修改从位于同台机器/home/bob/myrepo目录下的Git版本库中合并到本地。Alice执行了下面的命令

  1. alice$ cd /home/alice/project
  2. alice$ git pull /home/bob/myrepo master

这条指令将会把Bob在"master"分支做的修改合并到Alice当前的分支上。如果同时Alice也在修改,那么她需要手动的解决冲突。

"pull"命令实际上执行两个操作:从待合并的分支获取变更,然后把它们合并到当前分支。

注意:一般情况下,Alice希望在执行“pull”命令之前把她的本地修改提交到Git版本库。如果Bob的修改与Alice的修改存在冲突,Alice将要利用她的版本树和索引文件来解决冲突。这时候现有的本地修改将会干扰冲突的解决(Git将会执行获取,但是不会执行合并……Alice将不得不删掉本地的修改,然后重新执行"pull"命令)。

Alice可以在没有合并之前利用“fetch”命令来查看一下Bob的修改;为了决定到底是否需要利用“pull”命令获取Bob的修改,Alice可以使用特殊的符号"FETCH_HEAD"来查看Bob的修改:

  1. alice$ git fetch /home/bob/myrepo master
  2. alice$ git log -p HEAD..FETCH_HEAD

即使Alice存在没有提交的本地修改,这条指令也不会影响本地的修改。范围"HEAD..FETCH_HEAD"的含义是:显示从FETCH_HEAD开始可以取得的修改,但是不包含从HEAD开始可以取得的修改。Alice已经知道使她处于当前状态的(HEAD)的所有修改,通过这个命令Alice可以查看Bob所处状态((FETCH_HEAD)的修改。

如果Alice想要以一种图形化的方式查看Bob的修改,她可以使用如下命令:

  1. $ gitk HEAD..FETCH_HEAD

这种两个点表示范围的用法和我们刚才使用git log时的用法是一致的。

Alice或许想要查看他们两个人的修改。她可以使用三个点的形式:

  1. $ gitk HEAD...FETCH_HEAD

三个点表示范围的含义是:显示从它们任意一个开始可以取得的修改,但是不包含从它们两个全都包含的修改。

注意:以三个点表示范围的用法既可以和“gitk”一起使用,也可以和"git log"一起使用。

在检查了Bob的修改以后,如果没有什么紧急的修改,Alice或许会继续本地的修改,而不会合并Bob的修改到本地。如果Bob的修改是Alice当前需要的,Alice可能会选择先备份她本地的修改,然后,取得Bob的修改到本地,最后恢复她的备份。

当你工作在一个小的工作组时,通常会不断操作同一版本库。可以通过定义远程版本库缩写使操作更简单:

  1. alice$ git remote add bob /home/bob/myrepo

定义了版本库缩写,Alice可以利用git fetch命令单独执行"pull"操作的第一部分,而不去执行合并操作:

  1. alice$ git fetch bob

和git fetch普通用法不一样的是,当Alice利用缩写来取得Bob的修改时,取得的修改是存储在远程跟踪分支(remote-tracking branch),上面的例子中存储在bob/master分支。因此,运行如下命令:

  1. alice$ git log -p master..bob/master

显示的是从Bob克隆Alice分支后所有修改的列表。

在检查过所有的修改后,Alice可能会合并所有的修改到本地的"master"分支:

  1. alice$ git merge bob/master

也可以通过从远程跟踪分支(remote-tracking branch)上获取来完成合并,像下面这样:

  1. alice$ git pull . remotes/bob/master

注意:无论在命令行上添加任何参数,git pull总是合并修改到当前的分支。

稍后,Bob可以用下面的命令更新自己版本库:

  1. bob$ git pull

注意:Bob不需要指定Alice版本库的路径。当Bob克隆Alice版本库的时候,Git将Alice版本库的位置保存在版本库的配置中,这个配置在执行git pull命令的时候使用:

  1. bob$ git config --get remote.origin.url /home/alice/project

(Git克隆所创建的全部配置可以通过命令git config -l查询,详情请参见)

Git还保存了Alice版本库master分支的原始拷贝,名字为"origin/master":

  1. bob$ git branch -r origin/master

如果以后Bob希望在另一台机器上工作,他可以利用ssh协议来执行克隆,获取:

  1. bob$ git clone alice.org:/home/alice/project myrepo

再者,Git还提供原生协议,也可以使用rsync协议或者http协议,详情参见。

Git也可以工作在一种类似于CVS的模式,在这种模式下,不同的用户推送修改到中心版本库,详情参见和。


浏览历史日志

Git历史日志被表示为一系列相关的提交。在前面的例子中,已经看到git log可以列出这些提交。值得注意的是,每条日志的第一行是提交的名字:

  1. $ git log
  2. commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
  3. Author: Junio C Hamano
  4. Date: Tue May 16 17:18:22 2006 -0700 

  5.      merge-base: Clarify the comments on post processing.

可以利用这个名字来查看每个提交的详细内容。

  1. $ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

Git还支持其他的方法查看提交的详细内容。可以使用提交名字的一部分来标识提交:

  1. $ git show c82a22c39c   # the first few characters of the name are
  2.                         # usually enough
  3. $ git show HEAD         # the tip of the current branch
  4. $ git show experimental # the tip of the "experimental" branch

每个提交一般都有一个父提交,父提交指向项目的前一个状态:

  1. $ git show HEAD^        # to see the parent of HEAD
  2. $ git show HEAD^^       # to see the grandparent of HEAD
  3. $ git show HEAD~4       # to see the great-great grandparent of HEAD

注意:合并提交可能有不止一个父提交:

  1. $ git show HEAD^1       # show the first parent of HEAD (same as HEAD^)
  2. $ git show HEAD^2       # show the second parent of HEAD

可以通过下面的命令给提交命名:

  1. $ git tag v2.5 1b2e1d63ff

可以通过自定义名字“v2.5"查看提交1b2e1d63ff。如果你希望和其他人共享这个自定义名字(例如:指定发行版本号), 你应该创建一个"tag"对象并签名,详情参见。

任何涉及提交内容的命令都可以使用自定义名字。例如:

  1. $ git diff v2.5 HEAD      # compare the current HEAD to v2.5
  2. $ git branch stable v2.5  # start a new branch named "stable" based
  3.                           # at v2.5
  4. $ git reset --hard HEAD^  # reset your current branch and working
  5.                           # directory to its state at HEAD^

请注意最后一个命令:除了丢失当前工作目录的所有修改, 当前分支之后的的提交也会被删除。如果那些提交仅仅存在于当前分支,那么它们会彻底丢失。再者,不要在公共可见的分支上使用git reset命令,因为它将强制其他开发者做没有必要的合并,从而导致其他开发者丢失修改。如果你需要回滚你的提交,可以使用git revert。

命令git grep可以用来在项目的任意版本中搜索字符串,因此

  1. $ git grep "hello" v2.5

上述命令会在v2.5这个提交中搜索"hello"。

如果不指定提交名称,git grep将会搜索当前目录的所有文件。

  1. $ git grep "hello"

上述命令是一种比较快捷的方法用来搜索所有Git跟踪的文件。

很多Git命令可以选取一组提交,而且有多种实现方法。下面以git log为例:

  1. $ git log v2.5..v2.6             # commits between v2.5 and v2.6
  2. $ git log v2.5..                 # commits since v2.5
  3. $ git log --since="2 weeks ago"  # commits from the last 2 weeks
  4. $ git log v2.5.. Makefile        # commits since v2.5 which modify
  5.                                  # Makefile

在使用git log的时候,可以指定一个范围,而且范围的起始点不必是终止点的祖先。例如,如果分支“stable"和分支"master"在一段时间以前就已经不一致了,那么

  1. $ git log stable..master

将会列出在“master”分支上的提交,而不会列出在“stable”分支上的提交,然而,

  1. $ git log master..stable

将会列出在“stable”分支上的提交,而不会列出在“master”分支上的提交。

命令git log有一个缺点:它必须把提交以列表的形式展现。当历史记录中包含一些分叉的开发,然后又被合并到一起,那么git log所展现的这些提交的顺序则失去了意义。

有很多参与者的项目(例如Linux kernel或者Git本身)都会频繁的做合并,gitk在这方面做的比较好,提供给用户以图形的界面。例如,

  1. $ gitk --since="2 weeks ago" drivers/

上述命令允许你浏览最近两个星期在“drivers”目录下的提交。(注意:可以通过按住Ctrl+或者Ctrl-来调整gitk的字体。)

最后,大多数以文件名作为参数的命令,允许你在文件名前指定版本号:

  1. $ git diff v2.5:Makefile HEAD:Makefile.in

可以利用git show查看任意文件

  1. $ git show v2.5:Makefile

下一步

本指南对于在项目中使用分布式版本管理应该是足够了。但是,如果想更全面的理解Git,你应该了解下面两个观念:

  • 对象数据库是相当优雅的系统被用来存储项目历史(文件,目录和提交)。

  • 索引文件是目录树状态的缓存,主要用在创建提交, 签出工作目录以及保持合并过程中涉及的各种文件。

本指南的第二部分介绍了对象数据库,索引文件和一些零碎的东西,这样你将了解了Git的绝大多数内容。第二部分参见.

如果你不想立刻学习第二部分,还有一些其他方面的或许你会感兴趣:

  • , : 这些将Git提交转换成电子邮件的插件,或者反向转换的插件,对于十分倚重电子邮件的项目十分有用,例如Linux kernel项目。

  • : 当项目出现退步,跟踪bug的一个方式是搜索Git历史日志找到使项目退步的提交。Git bisect可以帮助你执行二进制搜索找到指定的提交。即使针对一个包含很多合并分支,并且复杂的非线性历史记录,Git bisect也能够智能的执行接近于最优的搜索。

  • :推荐的工作流概述

  • : CVS用户迁移到Git

阅读(2187) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Ubuntu11.04使用笔记

给主人留下些什么吧!~~