1.概述 linux
对于软件版本管理工具,酷讯决定摒弃CVS而转向Git了。 git
为何要选择Git? 你真正学会使用Git时, 你就会以为这个问题的回答是很是天然的。然而当真正须要用文字来回答时,却以为文字好像不是那么够用。 咳,该则么回答呢? 程序员
其实,关键的问题不在于如何回答这个问题。 问题的关键是公司已经决定使用它了。那么,咱们的程序员们! 请开动大家的浏览器,请拿出你的搜索引擎工具,去本身发掘答案吧。在这里,我只能给大家一个最朦胧的感受。 浏览器
Git和 CVS、SVN不一样,是一个分布式的源代码管理工具。Linux内核的代码就是用Git管理的。它很强,也很快。它给咱们带来的直接好处有: 服务器
1. 傻瓜都会的初始化,git init, git commit -a, 就完了。对于随便写两行代码就要放到代码管理工具里的人来讲,再合适不过。也能够拿git作备份系统,或者同步两台机器的文档,都很方便。 ssh
2. 绝大部分操做在本地完成,不用和集中的代码管理服务器交互,终于能够随时随地大胆地check in代码了。 只有最终完成的版本才须要向一个中心的集中的代码管理服务器提交。 分布式
3. 每次提交都会对全部代码建立一个惟一的commit id。不像CVS那样都是对单个文件分别进行版本的更改。因此你能够一次性将某次提交前的全部代码check出来,而不用考虑到底提交过那些文件。(其实SVN也能够作到这点) 工具
4. branch管理容易多了,不管是创建新的branch,仍是在branch之间切换都一条命令完成,不须要创建多余的目录。 学习
5. branch之间merge时,不只代码会merge在一块儿,check in历史也会保留,这点很是重要。 搜索引擎
6. … 太多了
固然,Git也会带给咱们一些困难,首先,你想要使用好git, 就要真正明白它的原理,理解它的观念,对以那些CVS的熟手来讲,改变你已经固有的纯集中式源代码管理的观念尤其重要,同时也会让你以为有些困难。在使用 git的初期,你可能会以为有些困难,但等你逐渐明白它时,你绝对会喜欢上它。这是必定的,就像我问你“喜欢一个温吞如水、毫无感受的主妇,仍是喜欢一个 奔放如火,让你爱的痴狂恨的牙痒的情人 ”同样毋庸置疑。
下面,就让咱们进入学习Git之旅…
请记住,这只是一个很是简单并且初级的教程, 想要成为git的专家,须要各位同事不断的本身深刻挖掘。
2. Git基础命令
2.1 建立Git库—git-init
大家曾经建立过CVS的库么?应该不多有人操做过吧?由于不少人 都是从CVS库里checkout代码。一样,在合做开发中,若是你不是一个代码模块的发起者,也不会使用到这个命令,更多的是使用git- clone(见2.7节)。可是,若是你想我的开发一个小模块,并暂时用代码管理工具管理起来(其实我就常这么作,至少不少我的开发过程均可以保留下来, 以便备份和恢复),建立一个 Git库是很容易和方便的。
对于酷讯来讲,当一个代码的Git库建立后,会添加代码文件到库里,并将这个库放到公司一个专门用来进行代码管理的服务器上,使你们能够在之后clone(不明白?不要紧,继续日后看就明白了)它。对于我的来讲,你能够随便将这个库放到哪里,只要你能访问的到就行。
建立一个Git库是很容易和方便的,只要用命令 git-init 就能够了。在Git1.4以前(包括git1.4)的版本,这个命令是git-init。
a) $ mkdir dir
b) $ cd dir
c) $ git-init
这样,一个空的版本库就建立好了,并在当前目录中建立一个叫 .git 的子目录。之后,因此的文件变化信息都会保存到这个目录下,而不像CVS那样,会在每一个目录和子目录下都建立一个讨厌的CVS目录。
在.git目录下有一个config文件, 须要咱们添加一下我的信息后才能使用。不然咱们不能对其中添加和修改任何文件。
原始的config文件是这样的,
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
咱们须要加入
[user]
name = xxx
emai= xxx@kuxun.cn
如今已经建立好了一个 git 版本库,可是它是空的,还不能作任何事情,下一步就是怎么向版本库中添加文件了。若是但愿忽略某些文件,须要在git库根目录下添加. gitignore文件。
2.2 一条重要的命令 -- git-update-index
在介绍如何向git库中添加文件前,不得不先介绍git- update-index命令。这条命令可能会使不少熟悉CVS的用户疑惑,通常来讲,咱们向一个源代码管理库提交代码的更改,都会抽象为如下的动做:更 改文件;向源码管理系统标识变化;提交。好比从一个CVS库里删除一个文件,须要先删除文件,而后cvs delete; 最后cvs commit。
所以, git-update-index就是向源码管理系统标识文件变化的一个抽象操做。说的简要一些,git-update-index命令就是通知git库 有文件的状态发生了变化(新添、修改、删除等待)。这条命令在早期的git版本中是很是经常使用的。在新的git版本(1.5版本及之后)已经被其它命令包装 起来,而且不推荐使用了。
git-update-index最经常使用的方式有如下两种,更多功能请man git-update-index。
方法一:git-update-index --add 文件名列表。 若是文件存在,则这条命令是向git库标识该文件发生过变化(不管是否该文件确实被修改过),若是文件不存在,则这条命令是向git库表示须要加入一个新文件。
方法二: git-update-index --force-remove 文件名列表。 这表示向git库表示哟啊从库中删除文件。不管该文件是否已经被删除,这条命令仅仅是通知git库要从库中删除这些文件。这些文件都不会受影响。
所以,git-update-index仅仅是向git库起到一个通知和标识的做用,并不会操做具体的文件。
2.3 向git库中添加或删除文件 – git-add、git-rm
其实,说使用git-add命令向git库里添加文件是不对的, 或者说至少是不全面的。git-add 命令的本质是命令"git-update-index --add” 的一个包装。所以,git-add除了能够添加文件,还能够标识文件修改。在调用了git-add后,才能够作commit操做。git-rm 也是同样, 它是git-update-index --force-remove的一个包装。
对于git-add来讲, 若是在一个目录下调用了git-add * ,则默认是递归将子目录中全部文件都add到git库中。对于git-rm来讲,也是同样。 这点和CVS有较大区别。
此外,咱们还能够经过命令git-ls-files来查看当前的git库中有那些文件。
2.4 查看版本库状态—git-status
经过该命令,咱们能够查看版本库的状态。能够得知那些文件发生了变化,那些文件尚未添加到git库中等等。 建议每次commit前都要经过该命令确认库状态。以免误操做。
其总,最多见的误操做是, 修改了一个文件, 没有调用git-add通知git库该文件已经发生了变化就直接调用commit操做,从而致使该文件并无真正的提交。若是这时若是开发者觉得已经提交 了该文件,就继续修改甚至删除这个文件,那么修改的内容就没有经过版本管理起来。若是每次在提交前,使用git-status查看一下,就能够发现这种错 误。所以,若是调用了git-status命令,必定要格外注意那些提示为 “Changed but not updated:”的文件。这些文件都是与上次commit相比发生了变化,可是却没有经过git-add标识的文件。
2.5 向版本库提交变化 – git-commit
直接调用git-commit命令,会提示填写注释。也能够经过以下方式在命令行就填写提交注释:git-commit -m "Initial commit of gittutor reposistory"。 注意,和CVS不一样,git的提交注释必须不能为空。不然就会提交失败。
git-commit还有一个 –a的参数,能够将那些没有经过git-add标识的变化一并强行提交,可是不建议使用这种方式。
每一次提交,git就会为全局代码创建一个惟一的commit标识代码,用户能够经过git-revert命令恢复到任意一次提交时的代码。 这比CVS不一样文件有不一样的版本呢号管理可方便多了。(和SVN相似)
若是提交前,想看看具体那些文件发生变化,能够经过git-diff来查看, 不过这个命令的输出并不友好。所以建议用别的工具来实现该功能。在提交后,还能够经过git-log命令来查看提交记录。
2.6 分支管理 – git-branch
咱们迎来了git最强大,也是比CVS、SVN强大的多的功能 — 分支管理。
大概每一个程序员都会常常遇到这样的状况:
1. 须要马上放下手头的工做,去修改曾经一个版本的bug并上线,而后再继续当的工做。
2. 本想向中心库commit一个重要修改,可是因为须要常常备份代码,最终不得不频繁的向中心库commit。从而致使大量无用的commit信息被保留在中心库中。
3. 将一次修改提交同事进行code review, 可是因为同事code review比较慢, 获得反馈时,本身的代码已经发生了变化,从而却是合并异常困难
这些场景,若是用CVS或者SVN来解决,虽然说不必定解决不了,但过程之繁琐,之复杂,确定另全部人都有生不如死的感受吧!究其关键,就是CVS或者SNV的branch管理太复杂,基本不具可用性。
在 git 版本库中建立分支的成本几乎为零,因此,没必要吝啬多建立几个分支。当第一次执行git-init时,系统就会建立一个名为”master”的分支。而其它分支则经过手工建立。下面列举一些常见的分支策略,这些策略相信会对你的平常开发带来很大的便利。
1.建立一个属于本身的我的工做分支,以免对主分支 master 形成太多的干扰,也方便与他人交流协做。
2.当进行高风险的工做时,建立一个试验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多。
3.合并别人的工做的时候,最好是建立一个临时的分支用来合并,合并完成后在“fatch”到本身的分支(合并和fatch后面有讲述,不明白就继续往下看好了)
2.6.1 查看分支 – git-branch
调用git-branch能够查看程序中已经存在的分支和当前分支
2.6.2 建立分支 – git-branch 分支名
要建立一个分支,可使用以下方法:
1. git-branch 分支名称
2. git-checout –b 分支名
使用第一种方法,虽然建立了分支,可是不会将当前工做分支切换到新建立的分支上,所以,还须要命令”git-checkout 分支名” 来切换, 而第二种方法不但建立了分支,还将当前工做分支切换到了该分支上。
另外,须要注意,分支名称是有可能出现重名的状况的, 好比说,我在master分支下建立了a和b两个分支,而后切换到b分支,在b分支下又建立了a和c分支。 这种操做是能够进行的。 此时的a分支和master下的a分支其实是两个不一样的分支。所以,在实际使用时,不建议这样的操做,这样会带来命名上的疑惑。
2.6.3 删除分支 – git-branch –D
git-branch –D 分支名能够删除分支,可是须要当心,删除后,发生在该分支的全部变化都没法恢复。
2.6.4 切换分支 – git-checkout 分支名
若是分支已经存在, 能够经过 git-checkout 分支名 来切换工做分支到该分支名
2.6.5 查看分支历史 –git-show-branch
调用该命令能够查看分支历史变化状况。 如:
* [dev1] d2
! [master] m2
--
* [dev1] d2
* [dev1^] d1
* [dev1~2] d1
*+ [master] m2
在上述例子中, “--”之上的两行表示有两个分支dev1和master,且dev分支上最后一次提交的日志是“d2”,master分支上最后一次提交的日志是”m2”。 “--”之下的几行表示了分支演化的历史,其中 dev1表示发生在dev分支上的最后一次提交,dev^表示发生在dev分支上的倒数第二次提交。dev1~2表示发生在dev分支上的倒数第三次提交。
2.6.6 合并分支 – git-merge
git-merge的用法为:git-merge “some memo” 合并的目标分支 合并的来源分支。如:
若是合并有冲突,git会由提示,当前,git-merge已经不多用了, 用git-pull来替代了。
用法为:git-pull 合并的目标分支 合并的来源分支。 如git-pull . dev1
2.7 远程获取一个git库 git-clone
在2.1节提到过,若是你不是一个代码模块的发起者,也不会使用到git-init命令,而是更多的是使用git-clone。经过这个命令,你能够从远端完整获取一个git库,并能够经过一些命令和远端的git交互。
基于git的代码管理的组织结构,每每造成一个树状结构,开发者 通常从某个代码模块的管理者的git库经过git-clone取得开发环境,在本地迭代开发后,再提交给该模块的管理者,该模块的管理者检查这些提交并将 代码合并到本身的库中,并向更高一级的代码管理者提交本身的模块代码。
对于酷讯来讲,公司会有一个中心的git库, 你们在开发时,都是从中心库git-clone获取最新代码。
git-clone的使用方法以下: git-clone [ssh://]username@ipaddr:path。 其中, “ssh://”可选,也有别的获取方式,如rsync。 Path是远端git的根路径,也叫repository。
经过git-clone获取远端git库后,.git/config中的开发者信息不会被一块儿clone过来。仍然须要为.git/config文件添加开发者信息。此外,开发者还须要本身添加. gitignore文件
另外,经过git-clone获取的远端git库,只包含了远端git库的当前工做分支。若是想获取其它分支信息,须要使用”git-branch –r” 来查看, 若是须要将远程的其它分支代码也获取过来,可使用命令” git checkout -b 本地分支名远程分支名”,其中,远程分支名为git-branch –r所列出的分支名, 通常是诸如“origin/分支名”的样子。若是本地分支名已经存在,则不须要“-b”参数。
2.8 从远程获取一个git分支 – git-pull
与git-clone不一样, git-pull能够从任意一个git库获取某个分支的内容。用法以下:
git-pull username@ipaddr: 远端repository名 远端分支名:本地分支名。这条命令将从远端git库的远端分支名获取到本地git库的一个本地分支中。其中,若是不写本地分支名,则默认pull到本地当前分支。
须要注意的是,git-pull也能够用来合并分支。 和git-merge的做用相同。 所以,若是你的本地分支已经有内容,则git-pull会合并这些文件,若是有冲突会报警。
2.9 将本地分支内容提交到远端分支 – git-push
git-push和git-pull正好想反,是将本地某个分支的内容提交到远端某个分支上。用法:
git-push username@ipaddr: 远端repository名 本地分支名:远端分支名。这条命令将本地git库的一个本地分支push到远端git库的远端分支名中。
须要格外注意的是,git-push好像不会自动合并文件。这点个人试验代表是这样,但我不能确认是不是我用错了。所以,若是git-push时,发生了冲突,就会被后push的文件内容强行覆盖,并且没有什么提示。 这在合做开发时是很危险的事情。
2.10 库的逆转与恢复 – git-reset
库的逆转与恢复除了用来进行一些废弃的研发代码的重置外,还有一 个重要的做用。好比咱们从远程clone了一个代码库,在本地开发后,准备提交回远程。可是本地代码库在开发时,有功能性的commit,也有出于备份目 的的commit等等。总之,commit的日志中有大量无用log,咱们并不想把这些 log在提交回远程时也提交到库中。 所以,就要用到git-reset。
Git-reset的概念比较复杂。它的命令形式:git-reset [--mixed | --soft | --hard] [<commit-ish>]
命令的选项:
--mixed
这个是默认的选项。 如git-reset [--mixed] dev1^(dev1^的定义能够参见2.6.5)。它的做用仅是重置分支状态到dev1^, 可是却不改变任何工做文件的内容。即,从dev1^到dev1的全部文件变化都保留了,可是dev1^到dev1之间的全部commit日志都被清除了, 并且,发生变化的文件内容也没有经过git-add标识,若是您要从新commit,还须要对变化的文件作一次git-add。这样,commit后,就 获得了一份很是干净的提交记录。
--soft
至关于作了git-reset –mixed,后,又对变化的文件作了git-add。若是用了该选项, 就能够直接commit了。
--hard
这个命令就会致使全部信息的回退, 包括文件内容。 通常只有在重置废弃代码时,才用它。 执行后,文件内容也没法恢复回来了。
2.11 更多的操做
以前的10节只简要介绍了git的基本命令,更多的细节能够去linux下man git的文档。
3. 基于git的合做开发
对于酷讯来讲,当咱们采用了Git,如何进行合做开发呢? 具体步骤以下:
3.1 获取最新代码
酷讯会准备一个中心git代码库。首先,咱们将整理好的代码分模块在git中心库中创建git库。并将文件add到中心库中。 接下来,开发者经过git-clone将代码从中心库clone到本地开发环境。
对于较大的项目,咱们还建议每一个组选择一个负责人,由这个负责人负责从中心库获取和更新最新的代码,其它开发者从这个负责人的git代码库中clone代码。此时,对开发者来讲,这个负责人的git库就是中心库了。
3.2 和中心库进行代码合并
使用过CVS的人都知道, 在commit以前,都要作一次cvs update,以免和中心库冲突。Git也是如此。
如今咱们已经通过了code review, 准备向中心库提交变化了, 在开发的这段时间,也许中心库发生了变化,所以,咱们须要在向中心库提交前,再次将中心库的master分支git-pull到本地的master分支 上。而且和dev分支作合并。最终,将合并的代码放入master分支。
若是开发过程提交日志过多,能够考虑参照2.10节的介绍作一次git-reset。
此外,若是发现合并过程变化很是多, 出于代码质量考虑,建议再作一次code review
3.3提交代码到中心库
此时,已经彻底准备好提交最终的代码了。 经过git-push就能够了。
3.4合做流程总结
你们能够看到,使用git进行合做开发,这一过程和CVS有不少类似性,同时,加强了如下几个环节:
1. 开发者在本地进行迭代开发,能够常常的作commit操做且不会影响他人。 并且即便不在线也能够进行开发。只须要最后向中心库提交一次便可。
2. 你们都知道,若是CVS管理代码,因为咱们会经常作commit操做。可是在commit以前cvs update时常会遇到将中心库上的其它最新代码checkout下来的状况,此时,一旦出现问题,就很难确认究竟是本身开发的bug仍是其它用户的代码带来了影响。 而使用git则避免了用户间的开发互相影响。
3. 更有利于在代码提交前作code review。以往用cvs, 都是代码提交后才作code view。若是发生问题, 也没法避免服务器上有很差的代码。 可是用git,真正向中心库commit前,都是在本地开发,能够方便的进行code review, 而后才提交到中心库。更有利于代码质量。并且,你们应该能够感到,使用git的过程当中,更容易对代码进行code review,由于影响因素更小。
4. 建立多分支,更容易在开发中进行多种工做,而使工做间不会互相影响。 好比user2对user1的代码进行code review时,就能够很是方便的保留当时的开发现场,并切换到user1的代码分支,在code review完毕后,也能够很是方便的切换会曾经被中断的工做现场。