GIT & REPO & GERRIT (二)

来源:互联网 发布:文言文虚词乎 编辑:程序博客网 时间:2024/05/01 04:30
GIT
想了很久,也不知道该如何下笔,那就从基本的概念说起吧。(下面如果没有特别说明,那么都是指在Unix下面使用GIT。)

Snapshot
GIT所设想的一个工作场景是这样的:
  • 在写代码的过程中,我们会不断对我们正在做的项目进行完整的备份,这样,就算改错了什么东西,我们可以很容易的从某个备份点重新开始。
  • 然后,我们还需要能比较我们当前开发的内容和备份内容的差别(diff),这样,我们就可以方便把代码差异打包(patch)发给别人进行审核(review)。
于是GIT就是这么一个工具,让这个流程自动化,并且提供了其他相关的强大功能。当然GIT实际上并不是每次对项目进行完整的备份,它有自己的另外一套更好机制来达到相同效果,而在GIT中每一次保存一个改动(commit)的时候,它的理念就是保存一个项目的当前的状态,称为快照(snapshot)。而我们可以通过任何一个snapshot很方便的取回(或部分取回,比如只是某个文件)项目当时的状态。

这是GIT的核心概念,要想运用好GIT,理解这个概念是非常重要的。

Repository
要使用GIT管理一个项目的时候,就需要一个仓库(repository)用于存放GIT对项目管理所必须要保存的各种文件,使用 git init 命令创建一个新的仓库。GIT会在当前目录下创建一个.git文件夹,用作仓库。然后,当你使用GIT记录每一次代码改动的时候,GIT就会把需要的信息都放到这个文件夹下面。

在使用GIT的时候,一般是还要配置一个用户名和邮件地址,这不是注册GIT账户,而是在你commit a change的时候,要有个作者的信息。通常来说,加一个全局的信息就可以了:
git config --global --add user.name Edward
git config --global --add user.email edward@somedomain.com
或者你可以选择直接编辑~/.gitconfig,这个文件看起来是这样的:
[user]
    email = edward@somedomain.com
    name = Edward

Commit
每当你完成一个改动(change)的时候,就可以commit一下,记录当前项目的情况(snapshot)。每一个commit包含如下信息:
  • commit-id(sha-id):这是一个通过sha-1算法算出来的一个id,它不只作为每个commit的唯一识别码,也可以用来验证保存的代码是否损坏。所以在GIT在管理代码的时候,如果发生代码损坏,可以很有效的检测到。
  • author:作者
  • date: 日期时间
  • log messge:一段作者对代码改动的文字描述。
  • change-id:如果是和repo、gerrit一起使用的话,repo会加上这个信息,以便在整个代码系统中识别同一个改动的多个版本。
用代码管理软件管理代码的时候,有个理念就是:每次改动提交以后,整个项目都应该是可以工作的。所以,每次commit最好都能是这样的的改动,虽然这不是必须的,但是这样对项目整体质量的提高很有好处。

在GIT使用中,一个change开发的常见工作流程大概是这样的:
  1. 新建一个工作分支(topic branch)
  2. 作一些代码改动
  3. 查看当前状态(很常用!):git status 查看当前branch以及那些文件有改动;git diff 查看目前为止的详细的改动情况。
  4. git add xxx 将这些改动暂时归档。在很多时候,一个change包含的东西并不少,我们在做到一半的时候通常也需要暂时保存一些东西。使用git add会将指定的文件的现有改动暂时保存下来(这个暂时归档的地方,GIT称它为staging area,可以认为是一个临时的snapshot。顺便说一下HEAD,在GIT中,HEAD总是指向项目当前状态最近的一次正式的snapshot。)。git add . 会将所有改动暂时归档。
  5. git reset xxx 将某个文件从staging area中移出来。git reset 不带参数的时候,就是将staging area中所有的文件移出。
  6. 查看staging area中的详细改动:git diff --cached
  7. 继续写代码,git add xxx 将新的改动归档。
  8. 当你发现你的改动非常不合理,想要取消这些改动的时候:git checkout xxx 将某个文件恢复到修改之前(最后一次snapshot)。git checkout . 会恢复所有的文件到修改之前的状态,很方便的功能,但使用的时候一定注意,不要让自己的心血付诸流水。
  9. 重复上面的步骤,直到你认为你的改动已经可以作为一个有效的change,那你就可以执行 git commit 来将当前的改动真正的保存下来。记得在commit message里面写上适当的描述信息,这样在查看代码历史的时候,就能方便的知道每个change都干了些什么。
  10. 有时候,你commit以后,你还发现还有需要修改的地方(特别是让别人review的话,commit之后需要多次改动也是很常见的事情),那么你就重复上面的步骤,不过在最后commit的时候加上 --amend 参数,这样,它就会将目前的修改内容添加到最近的一次commit。如果忘记/误用了 --amend 参数的时候怎么办呢?只要在编辑commit message的时候把内容全部清空,保存退出,GIT就会放弃这次commit。
  11. 根据情况,将这个改动合并(merge)回原来的主分支
经过上面的流程(某些步骤会不断的重复),那么一个有效且高质量的change就完成了。通过上面的这些步骤我们可以看出,在使用GIT来管理代码的时候,我们可以很容易的在任何时候保存我们想要保存的项目状态,并且可以很容易的取消某些文件的改动。这样,我们修改代码的时候,可以更随心所欲的进行修改,只要我们采取了适当的行动,我们就不怕半途丢失了我们的成果。当然,你必须要对上面每一个步骤都很熟悉,才能有随心所欲的感觉。

Tag
在git中,每一个commit都是一个项目当时的snapshot,tag的作用就是给commit打上标签。比如你当项目进行到某一点,你觉得可以发布(release)一下,那你就可以在这个位置做一个标记,打一个tag,一个发布点就被明确的标示出来了,这样可以方便的对项目的情况进行管理。我通常把它理解为某个commit的别名。GIT对项目的版本管理通常就是在这里体现的。由于tag通常是用于项目发布管理的,所以通常是项目管理人员来使用它。

查看tag情况:git tag
新建一个tag:git tag <tagname> <commitid>
删除一个tag:git tag -d <tagname>
查看帮助:git tag -h

Branch
GIT最方便的莫过于本地分支(branch)的使用了。就开发来讲,你需要尝试你的各种想法,就发布项目来说,不同的branch可以让你有效的管理各个版本软件的发布以及维护。这里只说说开发。

查看branch
git branch命令就可以查看本地当前的所有branch。常用的参数有:
-r 查看远程(remote)的branch
-a 查看(本地+远程)所有branch
-v 查看branch的时候显示每个branch的最后一个commit信息

跳转到一个branch
你任何时候只能在某一个branch上面,或者某一个特定的snapshot。
git checkout branchname 跳转到某一个branch
git checkout sha1/tag 跳转到某个指定的snapshot,这是你不在任何一个branch上面。

新建一个branch
git branch newbranch 从项目当前所在的commit创建一个branch
git checkout sha1/tag -b newbranch 从某一个指定的snapshot创建一个新的branch,并跳转到新建的branch
git checkout remote_branch -b newbranch 以某个远程branch最新的一个snapshot为基础创建一个新的branch,注意这不会影响远程branch,因为他的实质和上面其实是一样的。

那么我们该如何使用branch呢?首先,你要知道GIT是个分布式的代码管理工具,在你没有和远程代码仓库交流的时候,你的任何改动都是本地的,不用担心影响到远程代码仓库。而你只要不刻意去破坏你本地的仓库,那么,就大胆的使用branch吧,做各种尝试。任何时候你有一个新的想法,在本地建一个branch尽情的去尝试,很快你就会喜欢上这东西的。

如果是个多人协作项目的话,通常你的工作并不只是改动一个地方,那么当你完成了某一个change正在等待review的时候,你就可以新起一个branch,接着就开始你的另一个change了。

Merge
有了分支你就可以尽情的做各种尝试,随心所欲的写代码。但我们通常是有一个主干分支,然后我们把每个成熟的改动的合并(merge)到我们的主干,这样,项目才真正有效的在前进。这个工作流程就完美的解决了多人协作开发项目的问题:因为每个人都是在自己的本地工作区进行修改,互不影响,在完成后将自己的成果放进主仓库(某个remote repository)就可以了,最坏的情况就是可能会有些代码冲突,但代码冲突通常并不是什么很难解决的问题:毕竟在分配任务的时候就会有大致进行安排,所以一般是不会有什么无法解决的冲突。

说到merge的话,很多时候有人就会和rebase搞混。虽然两个命令的功能都是把两个branch合并起来,但是还是有很大差别的。

rebase主要用于如下情形:在多人协作的项目中,当你完成了一个改动以后,你发现别人已经在远端主代码仓库添加了很多改动了,这时候很可能会有代码冲突,或者已经有代码冲突,那这时候,你就需要把你当前的工作branch更新到最新的状态,然后解决代码冲突,然后再提交你的change。这时候,你就:
  1. 从远端获取最新的代码
  2. git rebase xxx 更新你当前的branch到最新状态,然后把你的代码改动放在最上面
  3. 向远端提交代码
而merge的话,就只是简单的将两个branch合并,如果出现GIT无法处理的冲突的时候,那么就先采取上面的步骤,然后在merge。在Android的工作环境中,我们通常是不需要使用merge这个操作的,这个操作是在gerrit里面完成review以后,点merge按钮来完成的。

查看历史
最常用的查看项目历史(实际上是某个分支的历史)的命令就是git log,常见用法如下:
  • git log 查看项目从当前位置(最近一个snapshot)之前的历史记录。可以这么来理解:当你在某个branch上面的时候,这个snapshot就是当前分支的最新的一个comit,当你不在一个branch上面的时候,就是当前情况下最新的那个commit。
  • git log shaid/tag 同上,不过指定了snapshot的位置
  • git log file_name 同上上,不过查看的是特定文件相关的改动记录
  • git log branch 查看特定branch的历史记录
  • git log branch file_name 同上,不过查看的是特定文件相关的改动记录
  • git log --no-merges 由于GIT在进行merge的时候,会自动生成一个merge的commit,但其实这个commit本身是没有内容的,--no-merges这个参数的作用就是在查看log的时候忽略这种commit。
这个命令可以满足大部分需要查询历史记录的情况,但有时候,你需要一个更强大的工具,那就是GITK。在当前branch下面,使用gitk命令,就可以使用gitk查看当前项目状态之前的历史记录。它是一个有界面的工具,基本上是一目了然的,所以我也不过多的介绍,花几分钟去试试它吧。

Remote
GIT既然是分布式代码管理工具,那么就必然涉及到远程的交互了。GIT和远端的交互可以通过常见的HTTP、HTTPS,在比较正式的项目中,通常是基于SSH的GIT协议。

以github.com为例,上面支持3种方式:
  • HTTP:只是从服务器上下载代码
  • HTTPS:需要登录,可以下载和上传代码,但上传代码的时候需要每次登录
  • SSH:配置好以后,GIT会自动采取SSH验证关于SSH的配置,这是github上面关于如何配置SSH的帮助:https://help.github.com/categories/56/articles
在Android系统的管理中,由于和服务器的交互都是封装在repo这个工具里面,所以,通常是不需要用到remote操作的。所以只简单说一下:
git remote 查看当前已添加的远程服务器
git remote -v 同上,不过显示更详细的信息
git remote -h 查看帮助

其他
.gitignore
在开发一个项目的时候,有时候总会有些项目无关的文件,比如bin文件夹下面的内容,一般是不需要用GIT管理起来的。这时候,你就把这些文件的信息写到.gitignore里面,然后,把.gitignore的改动使用GIT管理起来,这样,GIT在查询状态的时候,就会忽略在.gitignore里面提到的文件。
color & alias
GIT可以给各个命令的输出结果加上适当的颜色以提高视觉识别度,只需要简单的配置即可。如果你嫌有些GIT命令太长,每次打完太麻烦,没关系,有办法,添加别名。
因此我通常会在我的/etc/gitconfig文件中加入如下的内容:
[color]
    ui = auto
[alias]
    st = status
    cm = commit
    cma = commit --amend
    br = branch -v
    cp = cherry-pick
    co = checkout
    df = diff
    dfc = diff --cached
如何使用alias:以第一个为例,当我想用git status的时候,我打git st就可以了。

小结
GIT的功能很丰富,上面说的这些不过是一些常用的功能而已,要想把每个细节都说清楚的话,还远远不够。想要用好GIT,还需要在实际运用中进行实践和进一步学习。
原创粉丝点击