Good morning, my name is张轩铭, You can call me Louis if you like.It is really a great honor to have this for the English race ,I like many sth .For example:I like play football, basketball ,I like ride bicycle. I am 10 years old, reside in Jing’fan district. I am clever, energetic and confident. I feel that my strongest asset is I like learn.I feel happy when I Finished my homework . I have some interest, singing drawing。 I think I am able to under great pressure singing and drawing.
That’s me. It is my great pleasure to have a chance to present myself to you.Thank you!
1. 概述
对于软件版本管理工具,酷讯决定摒弃CVS而转向Git了。
为什么要选择Git? 你真正学会使用Git时, 你就会觉得这个问题的回答是非常自然的。然而当真正需要用文字来回答时,却觉得文字好像不是那么够用。 咳,该则么回答呢?
其实,关键的问题不在于如何回答这个问题。 问题的关键是公司已经决定使用它了。那么,我们的程序员们! 请开动你们的浏览器,请拿出你的搜索引擎工具,去自己发掘答案吧。在这里,我只能给你们一个最朦胧的感觉。
Git和 CVS、SVN不同,是一个分布式的源代码管理工具。Linux内核的代码就是用Git管理的。它很强,也很快。它给我们带来的直接好处有:
1. 傻瓜都会的初始化,git init, git commit -a, 就完了。对于随便写两行代码就要放到代码管理工具里的人来说,再合适不过。也可以拿git做备份系统,或者同步两台机器的文档,都很方便。
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= [email protected]
现在已经创建好了一个 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-merge master dev1~2
如果合并有冲突,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] []
命令的选项:
--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的文档。此外
介绍
Git --- The stupid content tracker, 傻瓜内容跟踪器。Linus 是这样给我们介绍 Git 的。
Git 是用于 Linux 内核开发的版本控制工具。与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。 Git 的速度很快,这对于诸如 Linux kernel 这样的大项目来说自然很重要。 Git 最为出色的是它的合并跟踪(merge tracing)能力。
实际上内核开发团队决定开始开发和使用 Git 来作为内核开发的版本控制系统的时候,世界开源社群的反对声音不少,最大的理由是 Git 太艰涩难懂,从 Git 的内部工作机制来说,的确是这样。但是随着开发的深入,Git 的正常使用都由一些友好的脚本命令来执行,使 Git 变得非常好用,即使是用来管理我们自己的开发项目,Git 都是一个友好,有力的工具。现在,越来越多的著名项目采用 Git 来管理项目开发,例如:wine, U-boot 等,详情看 http://www.kernel.org/git
作为开源自由原教旨主义项目,Git 没有对版本库的浏览和修改做任何的权限限制。它只适用于 Linux / Unix 平台,没有 Windows 版本,目前也没有这样的开发计划。
本文将以 Git 官方文档 Tutorial, core-tutorial 和 Everyday GIT 作为蓝本翻译整理,但是暂时去掉了对 Git 内部工作机制的阐述,力求简明扼要,并加入了作者使用 Git 的过程中的一些心得体会,注意事项,以及更多的例子。建议你最好通过你所使用的 Unix / Linux 发行版的安装包来安装 Git, 你可以在线浏览本文 ,也可以通过下面的命令来得到本文最新的版本库,并且通过后面的学习用 Git 作为工具参加到本文的创作中来。
$ git-clone http://www.bitsun.com/git/gittutorcn.git
创建一个版本库:git-init-db
创建一个 Git 版本库是很容易的,只要用命令 git-init-db 就可以了。现在我们来为本文的写作创建一个版本库:
$ mkdir gittutorcn$ cd gittutorcn$ git-init-db
git 将会作出以下的回应
defaulting to local storage area
这样,一个空的版本库就创建好了,并在当前目录中创建一个叫 .git 的子目录。你可以用 ls -a 查看一下,并请注意其中的三项内容:
-
一个叫 HEAD 的文件,我们现在来查看一下它的内容:
现在 HEAD 的内容应该是这样:
我们可以看到,HEAD 文件中的内容其实只是包含了一个索引信息,并且,这个索引将总是指向你的项目中的当前开发分支。
-
一个叫 objects 的子目录,它包含了你的项目中的所有对象,我们不必直接地了解到这些对象内容,我们应该关心是存放在这些对象中的项目的数据。
Note
|
关于 git 对象的分类,以及 git 对象数据库的说明,请参看 [Discussion] |
-
一个叫 refs 的子目录,它用来保存指向对象的索引。
具体地说,子目录 refs 包含着两个子目录叫 heads 和 tags,就像他们的名字所表达的意味一样:他们存放了不同的开发分支的头的索引, 或者是你用来标定版本的标签的索引。
请注意:master 是默认的分支,这也是为什么 .git/HEAD 创建的时候就指向 master 的原因,尽管目前它其实并不存在。 git 将假设你会在 master 上开始并展开你以后的工作,除非你自己创建你自己的分支。
另外,这只是一个约定俗成的习惯而已,实际上你可以将你的工作分支叫任何名字,而不必在版本库中一定要有一个叫 master 的分支,尽管很多 git 工具都认为 master 分支是存在的。
现在已经创建好了一个 git 版本库,但是它是空的,还不能做任何事情,下一步就是怎么向版本库植入数据了。
植入内容跟踪信息:git-add
为了简明起见,我们创建两个文件作为练习:
$ echo "Hello world" > hello$ echo "Silly example" > example
我们再用 git-add 命令将这两个文件加入到版本库文件索引当中:
git-add 实际上是个脚本命令,它是对 git 内核命令 git-update-index 的调用。因此上面的命令和下面的命令其实是等价的:
$ git-update-index --add hello example
如果你要将某个文件从 git 的目录跟踪系统中清除出去,同样可以用 git-update-index 命令。例如:
$ git-update-index --force-remove foo.c
Note
|
git-add 可以将某个目录下的所有内容全都纳入内容跟踪之下,例如: git-add ./path/to/your/wanted 。但是在这样做之前,应该注意先将一些我们不希望跟踪的文件清理掉,例如,gcc 编译出来的 *.o 文件,vim 的交换文件 .*.swp 之类。 |
应该建立一个清晰的概念就是,git-add 和 git-update-index 只是刷新了 git 的跟踪信息,hello 和 example 这两个文件中的内容并没有提交到 git 的内容跟踪范畴之内。
提交内容到版本库:git-commit
既然我们刷新了 Git 的跟踪信息,现在我们看看版本库的状态:
我们能看到 git 的状态提示:
## Initial commit### Updated but not checked in:# (will commit)## new file: example# new file: hello#
提示信息告诉我们版本库中加入了两个新的文件,并且 git 提示我们提交这些文件,我们可以通过 git-commit 命令来提交:
$ git-commit -m "Initial commit of gittutor reposistory"
查看当前的工作:git-diff
git-diff 命令将比较当前的工作目录和版本库数据库中的差异。现在我们编辑一些文件来体验一下 git 的跟踪功能。
$ echo "It's a new day for git" >> hello
我们再来比较一下,当前的工作目录和版本库中的数据的差别。
差异将以典型的 patch 方式表示出来:
diff --git a/hello b/helloindex a5c1966..bd9212c 100644--- a/hello+++ b/hello@@ -1 +1,2 @@ Hello, world+It's a new day for git
此时,我们可以再次使用组合命令 git-update-index 和 git-commit 将我们的工作提交到版本库中。
$ git-update-index hello$ git-commit -m "new day for git"
实际上,如果要提交的文件都是已经纳入 git 版本库的文件,那么不必为这些文件都应用 git-update-index 命令之后再进行提交,下面的命令更简捷并且和上面的命令是等价的。
$ git-commit -a -m "new day for git"
管理分支:git-branch
直至现在为止,我们的项目版本库一直都是只有一个分支 master。在 git 版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。下面列举一些常见的分支策略,仅供大家参考:
-
创建一个属于自己的个人工作分支,以避免对主分支 master 造成太多的干扰,也方便与他人交流协作。
-
当进行高风险的工作时,创建一个试验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多。
-
合并别人的工作的时候,最好是创建一个临时的分支,关于如何用临时分支合并别人的工作的技巧,将会在后面讲述。
创建分支
下面的命令将创建我自己的工作分支,名叫 robin,并且将以后的工作转移到这个分支上开展。
$ git-branch robin$ git-checkout robin
删除分支
要删除版本库中的某个分支,使用 git-branch -D 命令就可以了,例如:
$ git-branch -D branch-name
查看项目的发展变化和比较差异
这一节介绍几个查看项目的版本库的发展变化以及比较差异的很有用的命令:
git-show-branch
git-diff
git-whatchanged
我们现在为 robin, master 两个分支都增加一些内容。
$ git-checkout robin$ echo "Work, work, workd" >> hello$ git-commit -m "Some workd" -i hello
$ git-checkout master$ echo "Play, play, play" >> hello$ echo "Lots of fun" >> example$ git-commit -m "Some fun" -i hello example
git-show-branch 命令可以使我们看到版本库中每个分支的世系发展状态,并且可以看到每次提交的内容是否已进入每个分支。
这个命令让我们看到版本库的发展记录。
* [master] Some fun ! [robin] some work--* [master] Some fun + [robin] some work*+ [master^] a new day for git
譬如我们要查看世系标号为 master^ 和 robin 的版本的差异情况,我们可以使用这样的命令:
我们可以看到这两个版本的差异:
diff --git a/hello b/helloindex 263414f..cc44c73 100644--- a/hello+++ b/hello@@ -1,2 +1,3 @@ Hello World It's a new day for git+Work, work, work
Note
|
关于 GIT 版本世系编号的定义,请参看 git-rev-parse 。 |
我们现在再用 git-whatchanged 命令来看看 master 分支是怎么发展的。
$ git-checkout master$ git-whatchanged
diff-tree 1d2fa05... (from 3ecebc0...)Author: Vortune.Robin Date: Tue Mar 21 02:24:31 2006 +0800 Some fun:100644 100644 f24c74a... 7f8b141... M example:100644 100644 263414f... 06fa6a2... M hellodiff-tree 3ecebc0... (from 895f09a...)Author: Vortune.Robin Date: Tue Mar 21 02:17:23 2006 +0800 a new day for git:100644 100644 557db03... 263414f... M hello
从上面的内容中我们可以看到,在 robin 分支中的日志为 "Some work" 的内容, 并没有在 master 分支中出现。
合并两个分支:git-merge
既然我们为项目创建了不同的分支,那么我们就要经常地将自己或者是别人在一个分支上的工作合并到其他的分支上去。现在我们看看怎么将 robin 分支上的工作合并到 master 分支中。现在转移我们当前的工作分支到 master,并且将 robin 分支上的工作合并进来。
$ git-checkout master$ git-merge "Merge work in robin" HEAD robin
合并两个分支,还有一个更简便的方式,下面的命令和上面的命令是等价的。
$ git-checkout master$ git-pull . robin
但是,此时 git 会出现合并冲突提示:
Trying really trivial in-index merge...fatal: Merge requires file-level mergingNope.Merging HEAD with d2659fcf690ec693c04c82b03202fc5530d50960Merging:1d2fa05b13b63e39f621d8ee911817df0662d9b7 Some fund2659fcf690ec693c04c82b03202fc5530d50960 some workfound 1 common ancestor(s):3ecebc0cb4894a33208dfa7c7c6fc8b5f9da0eda a new day for gitAuto-merging helloCONFLICT (content): Merge conflict in helloAutomatic merge failed; fix up by hand
git 的提示指出,在合并作用于文件 hello 的 'Some fun' 和 'some work' 这两个对象时有冲突,具体通俗点说,就是在 master, robin 这两个分支中的 hello 文件的某些相同的行中的内容不一样。我们需要手动解决这些冲突,现在先让我们看看现在的 hello 文件中的内容。
此时的 hello 文件应是这样的,用过其他的版本控制系统的朋友应该很容易看出这个典型的冲突表示格式:
Hello WorldIt's a new day for git<<<<<<< HEAD/helloPlay, play, play=======Work, work, work>>>>>>> d2659fcf690ec693c04c82b03202fc5530d50960/hello
我们用编辑器将 hello 文件改为:
Hello WorldIt's a new day for gitPlay, play, playWork, work, work
现在可以将手动解决了冲突的文件提交了。
以上是典型的两路合并(2-way merge)算法,绝大多数情况下已经够用。但是还有更复杂的三路合并和多内容树合并的情况。详情可参看: git-read-tree, git-merge 等文档。
逆转与恢复:git-reset
项目跟踪工具的一个重要任务之一,就是使我们能够随时逆转(Undo)和恢复(Redo)某一阶段的工作。
git-reset 命令就是为这样的任务准备的。它将当前的工作分支的 头 定位到以前提交的任何版本中,它有三个重置的算法选项。
命令形式:
git-reset [--mixed | --soft | --hard] []
命令的选项:
-
--mixed
-
仅是重置索引的位置,而不改变你的工作树中的任何东西(即,文件中的所有变化都会被保留,也不标记他们为待提交状态),并且提示什么内容还没有被更新了。这个是默认的选项。
-
--soft
-
既不触动索引的位置,也不改变工作树中的任何内容,我们只是要求这些内容成为一份好的内容(之后才成为真正的提交内容)。这个选项使你可以将已经提交的东西重新逆转至“已更新但未提交(Updated but not Check in)”的状态。就像已经执行过
git-update-index 命令,但是还没有执行
git-commit 命令一样。
-
--hard
-
将工作树中的内容和头索引都切换至指定的版本位置中,也就是说自 之后的所有的跟踪内容和工作树中的内容都会全部丢失。因此,这个选项要慎用,除非你已经非常确定你的确不想再看到那些东西了。
一个重要技巧--逆转提交与恢复
可能有人会问,--soft 选项既不重置头索引的位置,也不改变工作树中的内容,那么它有什么用呢?现在我们介绍一个 --soft 选项的使用技巧。下面我们用例子来说明:
$ git-checkout master$ git-checkout -b softreset$ git-show-branch
这里我们创建了一个 master 的拷贝分支 softreset,现在我们可以看到两个分支是在同一起跑线上的。
! [master] Merge branch 'robin' ! [robin] some work * [softreset] Merge branch 'robin'---- - [master] Merge branch 'robin'+ * [master^] Some fun++* [robin] some work
我们为 文件增加一些内容并提交。
$ echo "Botch, botch, botch" >> hello$ git-commit -a -m "some botch"$ git-show-branch
我们可以看到此时 softreset 比 master 推进了一个版本 "some botch" 。
! [master] Merge branch 'robin' ! [robin] some work * [softreset] some botch--- * [softreset] some botch- - [master] Merge branch 'robin'+ * [master^] Some fun++* [robin] some work
现在让我们来考虑这样的一种情况,假如我们现在对刚刚提交的内容不满意,那么我们再编辑项目的内容,再提交的话,那么 "some botch" 的内容就会留在版本库中了。我们当然不希望将有明显问题的内容留在版本库中,这个时候 --soft 选项就很有用了。为了深入了解 --soft 的机制,我们看看现在 softreset 分支的头和 ORIG_HEAD 保存的索引。
$ cat .git/refs/heads/softreset .git/ORIG_HEAD
结果如下:
5e7cf906233e052bdca8c598cad2cb5478f9540a7bbd1370e2c667d955b6f6652bf8274efdc1fbd3
现在用 --soft 选项逆转刚才提交的内容:
现在让我们再看看 .git/ORIG_HEAD 的中保存了什么?
结果如下:
5e7cf906233e052bdca8c598cad2cb5478f9540a
看!现在的 .git/ORIG_HEAD 等于逆转前的 .git/refs/heads/softreset 。也就是说,git-reset --soft HEAD^ 命令逆转了刚才提交的版本进度,但是它将那次提交的对象的索引拷贝到了 .git/ORIG_HEAD 中。
我们再编辑 hello 文件成为下面的内容:
Hello WorldIt's a new day for gitPlay, play, playWork, work, workNice, nice, nice
我们甚至可以比较一下现在的工作树中的内容和被取消了的那次提交的内容有什么差异:
结果如下:
diff --git a/hello b/helloindex f978676..dd02c32 100644--- a/hello+++ b/hello@@ -2,4 +2,4 @@ Hello World It's a new day for git Play, play, play Work, work, work-Botch, botch, botch+Nice, nice, nice
接着,我们可以恢复刚才被取消了的那次提交了。
$ git-commit -a -c ORIG_HEAD
注意,这个命令会打开默认的文本编辑器以编辑原来提交的版本日志信息,我们改为 "nice work" 。大家可以自行用 git-show-branch 命令来查看一下现在的分支状态。并且我们还可以不断地重复上述的步骤,一直修改到你对这个版本进度满意为止。
git-reset 命令还有很多的用途和技巧,请参考 git-reset ,以及 Everyday GIT with 20 commands or So 。
提取版本库中的数据
这是个很有用的小技巧,如果你对你现在的工作目录下的东西已经不耐烦了,随时可以取出你提交过的东西覆盖掉当前的文件,譬如:
标定版本
在 git 中,有两种类型的标签,“轻标签”和“署名标签”。
技术上说,一个“轻标签”和一个分支没有任何区别,只不过我们将它放在了 .git/refs/tags/ 目录,而不是 heads 目录。因此,打一个“轻标签”再简单不过了。
“署名标签”是一个真正的 git 对象,它不但包含指向你想标记的状态的指针,还有一个标记名和信息,可选的 PGP 签名。你可以通过 -a 或者是 -s 选项来创建“署名标签”。
合并外部工作
通常的情况下,合并其他的人的工作的情况会比合并自己的分支的情况要多,这在 git 中是非常容易的事情,和你运行 git-merge 命令没有什么区别。事实上,远程合并的无非就是“抓取(fetch)一个远程的版本库中的工作到一个临时的标签中”,然后再使用 git-merge 命令。
可以通过下面的命令来抓取远程版本库:
根据不同的远程版本库所使用的通讯协议的路径来替代上面的 remoted-repository 就可以了。
-
Rsync
-
rsync://remote.machine/patch/to/repo.git/
-
SSH
-
remote.machine:/path/to/repo.git
or
ssh://remote.machine/patch/to/repo.git/
这是可以上传和下载的双向传输协议,当然,你要有通过 ssh 协议登录远程机器的权限。它可以找出两端的机器提交过的对象集之中相互缺少了那些对象,从而得到需要传输的最小对象集。这是最高效地交换两个版本库之间的对象的方式(在 git 兼容的所有传输协议当中)。
下面是个取得 SSH 远程版本库的命令例子:
$ git-fetch [email protected]:/path/to/gittutorcn.git (1)(1) 这里 robin 是登录的用户名,192.168.1.168 是保存着主版本库的机器的 IP 地址。
-
Local directory
-
/path/to/repo.git/
本地目录的情况和 SSH 情况是一样的。
-
git Native
-
git://remote.machine/path/to/repo.git/
git 自然协议是设计来用于匿名下载的,它的工作方式类似于 SSH 协议的交换方式。
-
HTTP(S)
-
http://remote.machine/path/to/repo.git/
到这里可能有些朋友已经想到,实际上,我们可以通过 Rsync, SSH 之类的双向传输方式来建立类似 CVS,SVN 这样的中心版本库模式的开发组织形式。
通过电子邮件交换工作
读过上一节之后,有的朋友可能要问,如果版本库是通过单向的下载协议发布的,如 HTTP,我们就无法将工作上传到公共的版本库中。别人也不能访问我的机器来抓取我的工作,那怎么办呢?
不必担心,我们还有 email !别忘了 git 本来就是为了管理 Linux 的内核开发而设计的。所以,它非常适合像 Linux Kernel 这样的开发组织形式高度分散,严重依赖 email 来进行交流的项目。
下面模拟你参加到《Git 中文教程》的编写工作中来,看看我们可以怎么通过 email 进行工作交流。你可以通过下面的命令下载这个项目的版本库。
$ git-clone http://www.bitsun.com/git/gittutorcn.git
之后,你会在当前目录下得到一个叫
gittutorcn 的目录,这就是你的项目的工作目录了。默认地,它会有两个分支:
master 和
origin,你可以直接在
master 下展开工作,也可以创建你自己的工作分支,但是千万不要修改
origin 分支,切记!因为它是公共版本库的镜像,如果你修改了它,那么就不能生成正确的对公共版本库的
patch 文件了。
Note
|
如果你的确修改过 origin 分支的内容,那么在生成 patch 文件之前,请用 git-reset --hard 命令将它逆转到最原始的,没经过任何修改的状态。 |
你可以直接在 master 下开展工作,也可以创建你自己的工作分支。当你对项目做了一定的工作,并提交到库中。我们用 git-show-branch 命令先看下库的状态。
* [master] your buddy's contribution ! [origin] degining of git-format-patch example--* [master] your buddy's contribution*+ [origin] degining of git-format-patch example
上面就假设你已经提交了一个叫 "your buddy's contribution" 的工作。现在我们来看看怎么通过 email 来交流工作了。
$ git-fetch origin (1)$ git-rebase origin (2)$ git-format-patch origin (3)(1)更新 origin 分支,防止 origin 分支不是最新的公共版本,产生错误的补丁文件;(2)将你在 master 上提交的工作迁移到新的源版本库的状态的基础上;(3)生成补丁文件;
上面的几个命令,会在当前目录下生成一个大概名为 0001-your-buddy-s-contribution.txt 补丁文件, 建议你用文本工具查看一下这个文件的具体形式,然后将这个文件以附件的形式发送到项目维护者的邮箱: [email protected]
当项目的维护者收到你的邮件后,只需要用 git-am 命令,就可以将你的工作合并到项目中来。
$ git-checkout -b buddy-incomming$ git-am /path/to/0001-your-buddy-s-contribution.txt
用 Git 协同工作
假设 Alice 在一部机器上自己的个人目录中创建了一个项目 /home/alice/project, Bob 想在同一部机器自己的个人目录中为这个项目做点什么。
Bob 首先这样开始:
$ git-clone /home/alice/project myrepo
这样就创建了一个保存着 Alice 的版本库的镜像的新目录 "myrepo"。这个镜像保存着原始项目的起点和它的发展历程。
接着 Bob 对项目做了些更改并提交了这些更改:
(编辑一些文件)$ git-commit -a (如果需要的话再重复这个步骤)
当他搞定之后,他告诉 Alice 将他的东西从 /home/bob/myrepo 中引入,她只需要这样:
$ cd /home/alice/project$ git pull /home/bob/myrepo
这样就将 Bob 的版本库中的 "master" 分支的变化引入了。 Alice 也可以通过在 pull 命令的后面加入参数的方式来引入其他的分支。
在导入了 Bob 的工作之后,用 "git-whatchanged" 命令可以查看有什么信的提交对象。如果这段时间里以来,Alice 也对项目做过自己的修改,当 Bob 的修改被合并进来的时候,那么她需要手动修复所有的合并冲突。
谨慎的 Alice 在导入 Bob 的工作之前,希望先检查一下。那么她可以先将 Bob 的工作导入到一个新创建的临时分支中,以方便研究 Bob 的工作:
$ git fetch /home/bob/myrepo master:bob-incoming
这个命令将 Bob 的 master 分支的导入到名为 bob-incoming 的分支中(不同于 git-pull 命令,git-fetch 命令只是取得 Bob 的开发工作的拷贝,而不是合并经来)。接着:
$ git whatchanged -p master..bob-incoming
这会列出 Bob 自取得 Alice 的 master 分支之后开始工作的所有变化。检查过这些工作,并做过必须的调整之后, Alice 就可以将变化导入到她的 master 分支中:
$ git-checkout master$git-pull . bob-incoming
最后的命令就是将 "bob-incoming" 分支的东西导入到 Alice 自己的版本库中的,稍后,Bob 就可以通过下面的命令同步 Alice 的最新变化。
注意不需为这个命令加入 Alice 的版本库的路径,因为当 Bob 克隆 Alice 的版本库的时候, git 已经将这个路径保存到 .git/remote/origin 文件中,它将会是所以的导入操作的默认路径。
Bob 可能已经注意到他并没有在他的版本库中创建过分支(但是分支已经存在了):
$ git branch* master origin
"origin" 分支,它是运行 "git-clone" 的时候自动创建的,他是 Alice 的 master 分支的原始镜像, Bob 应该永远不要向这个分支提交任何东西。
如果 Bob 以后决定在另外一部主机上开展工作,那么他仍然需要通过 SSH 协议从新克隆和导入( Alice 的版本库):
$ git-clone alice.org:/home/alice/project/ myrepo
我们可以使用 git 自然协议,或者是 rsync, http 等协议的任何一种,详情请参考 git-pull。
Git 同样可以建立类似 CVS 那样的开发模式,也就是所有开发者都向中心版本库提交工作的方式,详情参考 git_push 和 git for CVS users 。
为版本库打包
在前面,我们已经看到在 .git/objects/??/ 目录中保存着我们创建的每一个 git 对象。这样的方式对于自动和安全地创建对象很有效,但是对于网络传输则不方便。 git 对象一旦创建了,就不能被改变,但有一个方法可以优化对象的存储,就是将他们“打包到一起”。
上面的命令让你做到这点,如果你一直是做着我们的例子过来的,你现在大约会在 .git/objects/??/ 目录下积累了17个对象。 git-repack 会告诉你有几个对象被打包了,并且将他们保存在 .git/objects/pack 目录当中。
Note
|
你将会看到两个文件,pack-*.pack and pack-*.idx 在 .git/objects/pack 目录。他们的关系是很密切的,如果你手动将他们拷贝到别的版本库中的话,你要决定将他们一起拷贝。前者是保存着所有被打包的数据的文件,后者是随机访问的索引。 |
如果你是个偏执狂,就运行一下 git-verity-pack 命令来检查一下有缺陷的包吧,不过,其实你无须太多担心,我们的程序非常出色 ;-).
一旦你已经对那些对象打包了,那么那些已经被打过包的原始的对象,就没有必要保留了。
会帮你清楚他们。
如果你好奇的话,你可以在执行 git-prune-repacked 命令之前和之后,都运行一下 find .git/objects -type f,这样你就能看到有多少没有打包的对象,以及节省了多少磁盘空间。
Note
|
git pull git-pull 对于 HTTP 传输来说,一个打包过的版本库会将一定数量的相关联的对象放进一个有关联性的打包中。如果你设想多次从 HTTP 公共版本库中导入数据,你也许要频繁地 reapck & prune,要么就干脆从不这样做。 |
如果你此时再次运行 git-repack,它就会说 "Nothing to pack"。要是你继续开发,并且积累了一定数量的变迁,再运行 git-repack 将会创建一个新的包,它会包含你自上次对库打包以来创建的对象。我们建议你尽快在初始化提交之后打包一下你的版本库(除非你现在的项目是个涂鸦式的草稿项目),并且在项目经历过一段很活跃的时期时,再运行 git-repack 一下。
当一个版本库通过 git-push 和 git-pull 命令来同步源版本库中打包过的对像的时候,通常保存到目标版本库中的是解包了的对象,除非你使用的是 rsync(远程同步协议)协议的传输方式。正是这种容许你在两头的版本库中有不同的打包策略的方式,他意味着你也许在过一段时间之后,需要在两头的版本库中都重新打包一下。
将工作捆绑到一起
通过 git 的分支功能,你可以非常容易地做到好像在同一时间进行许多“相关-或-无关”的工作一样。
我们已经通过前面的 "fun and work" 使用两个分支的例子,看到分支是怎么工作的。这样的思想在多于两个的分支的时候也是一样的,比方说,你现在在 master 的头,并有些新的代码在 master 中,另外还有两个互不相关的补丁分别在 "commit-fix" 和 "diff-fix" 两个分支中。
$ git show-branch! [commit-fix] Fix commit message normalization. ! [diff-fix] Fix rename detection. * [master] Release candidate #1--- + [diff-fix] Fix rename detection. + [diff-fix~1] Better common substring algorithm.+ [commit-fix] Fix commit message normalization. * [master] Release candidate #1++* [diff-fix~2] Pretty-print messages.
两个补丁我们都测试好了,到这里,你想将他们俩合并起来,于是你可以先合并 diff-fix ,然后再合并 commit-fix,像这样:
$ git merge 'Merge fix in diff-fix' master diff-fix$ git merge 'Merge fix in commit-fix' master commit-fix
结果如下:
$ git show-branch! [commit-fix] Fix commit message normalization. ! [diff-fix] Fix rename detection. * [master] Merge fix in commit-fix--- - [master] Merge fix in commit-fix+ * [commit-fix] Fix commit message normalization. - [master~1] Merge fix in diff-fix +* [diff-fix] Fix rename detection. +* [diff-fix~1] Better common substring algorithm. * [master~2] Release candidate #1++* [master~3] Pretty-print messages.
然而,当你确信你手头上的确是一堆互不相关的项目变化时,就没有任何理由将这堆东西一个个地合并(假如他们的先后顺序很重要,那么他们就不应该被定以为无关的变化),你可以一次性将那两个分支合并到当前的分支中,首先我们将我们刚刚做过的事情逆转一下,我们需要通过将 master 分支重置到 master~2 位置的方法来将它逆转到合并那两个分支之前的状态。
$ git reset --hard master~2
你可以用 git-show-branch 来确认一下的确是回到了两次 git-merge 的状态了。现在你可以用一行命令将那两个分支导入的方式来替代两次运行(也就是所谓的 炮制章鱼 -- making an Octopus)git-merge :
$ git pull . commit-fix diff-fix$ git show-branch! [commit-fix] Fix commit message normalization. ! [diff-fix] Fix rename detection. * [master] Octopus merge of branches 'diff-fix' and 'commit-fix'--- - [master] Octopus merge of branches 'diff-fix' and 'commit-fix'+ * [commit-fix] Fix commit message normalization. +* [diff-fix] Fix rename detection. +* [diff-fix~1] Better common substring algorithm. * [master~1] Release candidate #1++* [master~2] Pretty-print messages.
注意那些不适合制作章鱼的场合,尽管你可以那样做。一只“章鱼”往往可以使项目的提交历史更具可读性,前提是你在同一时间导入的两份以上的变更是互不关联的。然而,如果你在合并任何分支的过程中出现合并冲突,并且需要手工解决的话,那意味着这些分支当中有相互干涉的开发工作在进行,那么你就应该将这个两个冲突先合并,并且记录下你是如何解决这个冲突,以及你首先处理他们的理由。(译者按:处理完冲突之后,你就可以放心制作“章鱼”了)否则的话将会造成项目的发展历史很难跟踪。
管理版本库
版本库的管理员可以用下面的工具来建立和维护版本库。
update hook howto 一个很好的管理中心版本库的例子。
例子
-
在 /pub/scm 上运行 git 守护进程
-
$ grep git /etc/inet.confgit stream tcp nowait nobody \ /usr/bin/git-daemon git-daemon --inetd --syslog --export-all /pub/scm
这个配置行应该在配置文件中用一行来写完。
-
仅给开发者 push/pull 的访问权限。
-
$ grep git /etc/passwd (1)alice:x:1000:1000::/home/alice:/usr/bin/git-shellbob:x:1001:1001::/home/bob:/usr/bin/git-shellcindy:x:1002:1002::/home/cindy:/usr/bin/git-shelldavid:x:1003:1003::/home/david:/usr/bin/git-shell$ grep git /etc/shells (2)/usr/bin/git-shell (1) 将用户的登录 shell 设定为 /usr/bin/git-shell,它除了运行 "git-push" 和 "git-pull" 不能做任何事。这样用户就可以通过 ssh 来访问机器。(2) 许多的发行版需要在 /etc/shells 配置文件中列明要用什么 shell 来作为登录 shell。
-
CVS - 模式的公共库。
-
$ grep git /etc/group (1)git:x:9418:alice,bob,cindy,david$ cd /home/devo.git$ ls -l (2) lrwxrwxrwx 1 david git 17 Dec 4 22:40 HEAD -> refs/heads/master drwxrwsr-x 2 david git 4096 Dec 4 22:40 branches -rw-rw-r-- 1 david git 84 Dec 4 22:40 config -rw-rw-r-- 1 david git 58 Dec 4 22:40 description drwxrwsr-x 2 david git 4096 Dec 4 22:40 hooks -rw-rw-r-- 1 david git 37504 Dec 4 22:40 index drwxrwsr-x 2 david git 4096 Dec 4 22:40 info drwxrwsr-x 4 david git 4096 Dec 4 22:40 objects drwxrwsr-x 4 david git 4096 Nov 7 14:58 refs drwxrwsr-x 2 david git 4096 Dec 4 22:40 remotes$ ls -l hooks/update (3) -r-xr-xr-x 1 david git 3536 Dec 4 22:40 update$ cat info/allowed-users (4)refs/heads/master alice\|cindyrefs/heads/doc-update bobrefs/tags/v[0-9]* david(1) 将所有的开发人员都作为 git 组的成员。(2) 并且给予他们公共版本库的写权限。(3) 用一个在 Documentation/howto/ 中的 Carl 写的例子来实现版本库的分支控制策略。(4) Alice 和 Cindy 可以提交入 master 分支,只有 Bob 能提交入 doc-update 分支,David 则是发行经理只有他能创建并且 push 版本标签。
-
支持默协议传输的 HTTP 服务器。
-
dev$ git update-server-info (1)dev$ ftp [email protected] (2)ftp> cp -r .git /home/user/myproject.git(1) 保证 info/refs 和 object/info/packs 是最新的。(2) 上传到你的 HTTP 服务器主机。
项目开发的模式推介
尽管 git 是一个正式项目发布系统,它却可以方便地将你的项目建立在松散的开发人员组织形式上。 Linux 内核的开发,就是按这样的模式进行的。在 Randy Dunlap 的著作中("Merge to Mainline" 第17页)就有很好的介绍(http://tinyurl.com/a2jdg)。
需要强调的是正真的非常规的开发组织形式, git 这种组织形式,意味着对于工作流程的约束,没有任何强迫性的原则。你不必从唯一一个远程版本库中导入(工作目录)。
项目领导人(project lead)的工作推介
-
在你自己的本地机器上准备好主版本库。你的所有工作都在这里完成。
-
准备一个能让大家访问的公共版本库。
如果其他人是通过默协议的方式(http)来导入版本库的,那么你有必要保持这个 默协议的友好性。 git-init-db 之后,复制自标准模板库的 $GIT_DIR/hooks/post-update 将包含一个对 git-update-server-info 的调用,但是 post-update 默认是不能唤起它自身的。通过 chmod +x post-update 命令使能它。这样让 git-update-server-info 保证那些必要的文件是最新的。
-
将你的主版本库推入公共版本库。
-
git-repack 公共版本库。这将建立一个包含初始化提交对象集的打包作为项目的起始线,可能的话,执行一下 git-prune,要是你的公共库是通过 pull 操作来从你打包过的版本库中导入的。
-
在你的主版本库中开展工作,这些工作可能是你自己的最项目的编辑,可能是你由 email 收到的一个补丁,也可能是你从这个项目的“子系统负责人” 的公共库中导入的工作等等。
你可以在任何你喜欢的时候重新打包你的这个私人的版本库。
-
将项目的进度推入公共库中,并给大家公布一下。
-
尽管一段时间以后,"git-repack" 公共库。并回到第5步继续工作。
项目的子系统负责人(subsystem maintainer)也有自己的公共库,工作流程大致如下:
-
准被一个你自己的工作目录,它通过 git-clone 克隆自项目领导人的公共库。原始的克隆地址(URL)将被保存在 .git/remotes/origin 中。
-
准备一个可以给大家访问的公共库,就像项目领导人所做的那样。
-
复制项目领导人的公共库中的打包文件到你的公共库中,除非你的公共库和项目领导人的公共库是在同一部主机上。以后你就可以通过 objects/info/alternates 文件的指向来浏览它所指向的版本库了。
- 将你的主版本库推入你的公共版本库,并运行 git-repack,如果你的公共库是通过的公共库是通过 pull 来导入的数据的话,再执行一下 git-prune 。
-
在你的主版本库中开展工作。这些工作可能包括你自己的编辑,来自 email 的补丁,从项目领导人,“下一级子项目负责人”的公共库哪里导入的工作等等。
你可以在任何时候重新打包你的私人版本库。
-
将你的变更推入公共库中,并且请“项目领导人”和“下级子系统负责人”导入这些变更。
-
每隔一段时间之后,git-repack 公共库。回到第 5 步继续工作。
“一般开发人员”无须自己的公共库,大致的工作方式是:
-
准备你的工作库,它应该用 git-clone 克隆自“项目领导人”的公共库(如果你只是开发子项目,那么就克隆“子项目负责人”的)。克隆的源地址(URL)会被保存到 .git/remotes/origin 中。
-
在你的个人版本库中的 master 分支中开展工作。
-
每隔一段时间,向上游的版本库运行一下 git-fetch origin 。这样只会做 git-pull 一半的操作,即只克隆不合并。公共版本库的新的头就会被保存到 .git/refs/heads/origins 。
-
用 git-cherry origin 命令,看一下你有什么补丁被接纳了。并用 git-rebase origin 命令将你以往的变更迁移到最新的上游版本库的状态中。(关于 git-rebase 命令,请参考 git-rebase)
- 用 git-format-patch origin 生成 email 形式的补丁并发给上游的维护者。回到第二步接着工作
GIT和SVN之间的五个基本区别
本文是从 5 Fundamental differences between GIT & SVN 这篇文章翻译而来。
如果你在读这篇文章,说明你跟大多数开发者一样对GIT感兴趣,如果你还没有机会来试一试GIT,我想现在你就要了解它了。
GIT不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等。如果你是一个具有使用SVN背景的人,你需要做一定的思想转换,来适应GIT提供的一些概念和特征。所以,这篇文章的主要目的就是通过介绍GIT能做什么、它和SVN在深层次上究竟有什么不同来帮助你认识它。
那好,这就开始吧…
-
GIT是分布式的,SVN不是:
这是GIT和其它非分布式的版本控制系统,例如SVN,CVS等,最核心的区别。如果你能理解这个概念,那么你就已经上手一半了。需要做一点声明,GIT并不是目前第一个或唯一的分布式版本控制系统。还有一些系统,例如Bitkeeper, Mercurial等,也是运行在分布式模式上的。但GIT在这方面做的更好,而且有更多强大的功能特征。
GIT跟SVN一样有自己的集中式版本库或服务器。但,GIT更倾向于被使用于分布式模式,也就是每个开发人员从中心版本库/服务器上chect out代码后会在自己的机器上克隆一个自己的版本库。可以这样说,如果你被困在一个不能连接网络的地方时,就像在飞机上,地下室,电梯里等,你仍然能够提交文件,查看历史版本记录,创建项目分支,等。对一些人来说,这好像没多大用处,但当你突然遇到没有网络的环境时,这个将解决你的大麻烦。
同样,这种分布式的操作模式对于开源软件社区的开发来说也是个巨大的恩赐,你不必再像以前那样做出补丁包,通过email方式发送出去,你只需要创建一个分支,向项目团队发送一个推请求。这能让你的代码保持最新,而且不会在传输过程中丢失。GitHub.com就是一个这样的优秀案例。
有些谣言传出来说subversion将来的版本也会基于分布式模式。但至少目前还看不出来。
-
GIT把内容按元数据方式存储,而SVN是按文件:
所有的资源控制系统都是把文件的元信息隐藏在一个类似.svn,.cvs等的文件夹里。如果你把.git目录的体积大小跟.svn比较,你会发现它们差距很大。因为,.git目录是处于你的机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签,分支,版本记录等。
-
GIT分支和SVN的分支不同:
分支在SVN中一点不特别,就是版本库中的另外的一个目录。如果你想知道是否合并了一个分支,你需要手工运行像这样的命令svn propget svn:mergeinfo,来确认代码是否被合并。感谢Ben同学指出这个特征。所以,经常会发生有些分支被遗漏的情况。
然而,处理GIT的分支却是相当的简单和有趣。你可以从同一个工作目录下快速的在几个分支间切换。你很容易发现未被合并的分支,你能简单而快捷的合并这些文件。
-
GIT没有一个全局的版本号,而SVN有:
目前为止这是跟SVN相比GIT缺少的最大的一个特征。你也知道,SVN的版本号实际是任何一个相应时间的源代码快照。我认为它是从CVS进化到SVN的最大的一个突破。因为GIT和SVN从概念上就不同,我不知道GIT里是什么特征与之对应。如果你有任何的线索,请在评论里奉献出来与大家共享。
更新:有些读者指出,我们可以使用GIT的SHA-1来唯一的标识一个代码快照。这个并不能完全的代替SVN里容易阅读的数字版本号。但,用途应该是相同的。
-
GIT的内容完整性要优于SVN:
GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。这里有一个很好的关于GIT内容完整性的讨论 – http://stackoverflow.com/questions/964331/git-file-integrity
GIT和SVN之间只有这五处不同吗?当然不是。我想这5个只是“最基本的”和“最吸引人”的,我只想到这5点。如果你发现有比这5点更有趣的,请共享出来,欢迎
My name is ________. I am graduatefrom ________ seniorhigh school and major in ________. There are ________ people in my family. My father works in a computer company. And my mother is a housewife. I am the youngest one in my family.
In my spare time, I like to read novels. I think reading could enlargemy knowledge. As for novels, I could imagine whatever I like such as a well-known scientist or a kung-fu master. In addition to reading, I also like to play PC games. A lot of grownups think playing PC games hinders the students from learning. But I think PC games could motivate me to learn something such as English or Japanese.My favorite course is English because I think it is interesting to say one thing via different sounds. I wish my English could be improved in the next four years and be able to speak fluent English in the future.
Sample1:
I am . I was born in . I graduate from senior high school and major in English. I started learning English since I was 12 years old. My parents have a lot of American friends. That’s why I have no problem communicating with Americans or others by speaking English.
In my spare time, I like to do anything relating to English such as listening to English songs, watching English movies or TV programs, or even attending the activities held by some English clubs or institutes. I used to go abroad for a short- term English study. During that time, I learned a lot of daily life English and saw a lot of different things.
I think language is very interesting. I could express one substanceby using different sounds. So I wish I could study and read more English literatures and enlarge my knowledge.
Sample3:
My name is . There are 4 people in my family. My father is a Chemistryteacher. He teaches chemistry in senior high school. My mother is an English teacher. She teaches English in the university. I have a younger brother, he is a junior high school student and is preparing for the entrance exam.
I like to read English story books in my free time. Sometimes I surf the Internet and download the E- books to read. Reading E- books is fun. In addition, it also enlarges my vocabulary words because of the advanced technology and the vivid animations.
I hope to study both English and computer technology because I am interested in both of the subjects. Maybe one day I could combine both of them and apply to my research in the future.
Sample4:
My name is . I am from . There are people in my family. My father works in a computer company. He is a computer engineer. My mother works in a international trade company. She is also a busy woman. I have a older sister and a younger brother. My sister is a junior in National Taiwan University. She majors in English. My brother is an elementary school student. He is 8 years old.
Because of my father, I love surfing the Internet very much. I play the on-line game for about 2 hours every day. I wish I could be a computer program designer in the future. And that is why I am applying for the electronics program in your school.
Sample5:
From a middle class family, I was born in Hsin Ying, Tainan on October 10th, 1965. My father is a civil official at Tainan City Government. My mother is a house wife good at cooking. Although I am the only child of my parents, I am by no mans a spoiled one. On the contrary, I have been expected to be a successful man with advanced education. I study hard at school. Besides texts knowledge, journalism is my favorite; whenever reading, my heart is filled with great joy and interesting.
“Being good is must; successful, however, is plus.” Father adopts the idea of his father. Especially in military service, I realized it more precisely. People said: Military service makes a boy to man, I agree that.
I realized the importance of English and began to study diligently when I was eighteen. I did not start in my early age, but I hope that I could pass the test of General English Proficiency Test. And this is my best wish at the moment.
Sample6:
After completing my military service, I have been looking for a challenging goal for me to achieve. And I found that the Intermediate of General English Proficiency Test fits my new achievement properly.
I graduated from Taipei Commercial Junior College, majored in business administration. Instead of spending much time in playing, I devoted myself to my studies and paid attention to all meaningful things happened in daily life. By the way, I learned a lot from Mr. Wang, the professor of my business class. He is my good friend till now an often gives some appropriate suggestions toward my problem confusion.
My father is, in the same way, a good consultant to me. As he said: I am in poor education, little for you; to clarify, what he have given is far beyond his words, I do think so. I was born in a country of Ping Tung Country, farming is our career of generations. There are four people in my family, Mother is housewife and my brother is a student of an Agriculture College.
I am optimistic and active, and I am confident that I can pass the test. Thank you for your precious to read my autobiography.
、Good morning/afternoon/evening, my name is . It is really a great honor to have this opportunity/chance to introduce myself. I would like to answer whatever you may raise, and I hope I can make a good performance today.
上午好/下午好/晚上好!我的名字叫……。今天有机会进行自我介绍深感荣幸。我乐意回答你们所提出来的任何问题。我希望我今天能表现的非常出色。
2、I am years old, born in province/Beijing, northeast/southeast/southwest…… of china, and I am currently a freshman(大一新生)/sophomore(大二学生)/junior(大三学生)/senior(大四学生) student at Capital Institute of Physical Education.
我今年……岁,出生在……省/北京,它位于中国的东北/东南/西南……等部。我目前是首都体育学院大一/大二/大三/大四的学生。
3、 My major is sports training of basketball/voellyball/football/badminton/pingbang/tennis/
我主修篮球/排球/足球/羽毛球/乒乓球/网球/田径/游泳/跆拳道等运动训练专业。在我毕业以后,我将会获得学士学位。
4、In the past 1/2/3 years, I spend most of my time on study. I have passed CET3/4/6 and I have acquired basic knowledge of sports training both in theory and in practice.
在过去的1/2/3年中,我把大量的时间用在学习上。我已经通过了大学英语2/3/4/6级。而且,我已经从理论和实践二方面对运动训练专业的基础知识有了一个大致的了解。
5、Besides, I have attended several sports meetings held in Beijing. I am also the volunteers of China Tennis Open, Chinese Badminton Masters…… . Through these I have a deeply understanding of my major—sports training.
除此以外,我还参加了在北京举行的许多运动会。我还是中国网球公开赛,羽毛球大师赛……的志愿者。通过这些,我对运动训练专业有了一个更深刻的了解。
6、I have lots of interest, such as singing, dancing, drawing and so on.
我有很多兴趣爱好,如唱歌、跳舞、画画等。
7、Thank you!
谢谢大家!
Sample :简介版自我介绍
Hello, everyone!My name is Winnie. I'm a 15 years old girl. I live in the beautiful city of Rizhao.
I'm an active, lovely, and clever girl. In the school my favorite subject is math. Perhaps someone thinks it's difficult to study well. But I like it. I believe that if you try your best, everything can be done well.
I also like sports very much. Such as, running, volleyball and so on. I'm kind-hearted. If you need help, please come to me.I hope we can be good friends!
OK. This is me .A sunny girl.
General Introduction
I am a third year master major in automation at Shanghai Jiao Tong University, P. R. China. With tremendous interest in Industrial Engineering, I am writing to apply for acceptance into your Ph.D. graduate program.
Education background
In 1995, I entered the Nanjing University of Science & Technology (NUST) -- widely considered one of the China’s best engineering schools. During the following undergraduate study, my academic records kept distinguished among the whole department. I was granted First Class Prize every semester,In 1999, I got the privilege to enter the graduate program waived of the admission test.
At the period of my graduate study, my overall GPA(3.77/4.0) ranked top 5% in the department. In the second semester, I became teacher assistant that is given to talented and matured students only. This year, I won the Acer Scholarship as the one and only candidate in my department, which is the ultimate accolade for distinguished students endowed by my university. Presently, I am preparing my graduation thesis and trying for the honor of Excellent Graduation Thesis.
Research experience and academic activity
When a sophomore, I joined the Association of AI Enthusiast and began to narrow down my interest for my future research. With the tool of OpenGL and Matlab, I designed a simulation program for transportation scheduling system. It is now widely used by different research groups in NUST. I assumed and fulfilled a sewage analysis & dispose project for Nanjing sewage treatment plant. This was my first practice to convert a laboratory idea to a commercial product.
In retrospect, I find myself standing on a solid basis in both theory and experience, which has prepared me for the Ph.D. program. My future research interests include: Network Scheduling Problem, Heuristic Algorithm research (especially in GA and Neural network), Supply chain network research, Hybrid system performance analysis with Petri nets and Data Mining.
Mr. gao
good morning, my name XX, it is really a great honor to have this opportunity for a interview, i would like to answer whatever you may raise,
and i hope i can make a good performance today, eventually enroll in this prestigious university in september. now i will introduce myself briefly,
i am XX years old,born in XX province ,and i am curruently a senior student at beijing XX university.my major isXX.and i will receive my bachelor
degree after my graduation in june.in the past 4 years,i spend most of my time on study,i have passed CET4/6 with a ease. and i have acquired basic
knowledge of packaging and publishing both in theory and in practice. besides, i have attend several packaging exhibition hold in Beijing, this is our advantage study here, i have taken a tour to some big factory and company.
through these i have a deeply understanding of domestic packaging industry. compared to developed countries such as us, unfortunately,
although we have made extraordinary progress since 1978,our packaging industry are still underdeveloped, mess, unstable, the situation
of employees in this field are awkard. but i have full confidence in a bright future if only our economy can keep the growth pace still.
i guess you maybe interested in the reason itch to law, and what is my plan during graduate study life, i would like to tell you that pursue
law is one of my lifelong goal,i like my major packaging and i wont give up,if i can pursue my master degree here i will combine law with my
former education. i will work hard in thesefields ,patent ,trademark, copyright, on the base of my years study in department of p&p, my character?
i cannot describe it well, but i know i am optimistic and confident. sometimes i prefer to stay alone, reading, listening to music, but i am not lonely,
i like to chat with my classmates, almost talk everything ,my favorite pastime is valleyball,playing cards or surf online. through college life,
i learn how to balance between study and entertainment. by the way, i was a actor of our amazing drama club. i had a few glorious memory on stage.
that is my pride.
Good morning, my dear professors. I am very glad to be here for your interview. My name is XXX(姓名), and i am 22 years old .I come from XX(城市), a beautiful and charming city. My major is biology engineering, and my undergratuade period will be accomplished in XX(大学名) university in July ,2011(应该是那个时候毕业吧?);and now, I am trying my best for obtaining a key to XX(要申请的大学名) university。
Generally speaking ,I am a hard working student especially when doing what I am interested in. I will try my best to finish it no matter how difficult it is. ((When I was sophomore, I found web design very interesting, so I learned it very hard. To weaver a homepage for myself, I stayed with my personal computer for half a month, and I am the first one in my class who own his homepage. )) Forther more,I am a person with great perserverence. During the days preparing for the first examination, I insist on running every day, no matter what the weather was like. And just owning to this, I could concentrate on my study and succeeded in the end。
Well ,in my spare time ,I like (( basketball, tennis and chinese chess.)) Also english is my favorate. I often go to English corner to practise my oral English on every thursday, and write compositions to improve my witten ability .But I know my english is not good enough , I will continue studying.
Ok, that is all, thank you for your listening.