http://zh-tw.whygitisbetterthanx.com/
http://rogerdudler.github.com/git-guide/index.zh.html
Git and Github
http://ihower.tw/blog/archives/5391
Pro Git professional version control
http://progit.org/book/
https://github.com/
http://help.github.com/win-set-up-git/
Git Reference
http://gitref.org/
git中文教程
http://fsjoy.blog.51cto.com/318484/75365
http://roclinux.cn/?p=605
http://roclinux.cn/?p=622
http://roclinux.cn/?p=647
《看日记学git》之随笔笔记
本文章就是我复习前三十集后的一个总结,把忘了的知识点写在这重新提一下。你也看看,正好复习复习:)
1 git clone只会提取远程git仓库里已提交的信息,working tree和index file里的信息,git clone根本不会理会。如果你是经理,你让你的手下用git clone path/to/your/repo newrepo来将你的代码下载到他的本地就可以了,注意,他用此命令下载的是path/to/your/repo仓库中的当前分支的内容。当你的手下开 发完他负责的那部分代码之后,通知你。你用git fetch path/to/his/newrepo hisbranch:yourbranch 来将你手下的工作成果抓取到你本地的yourbranch分支上。待审核合格之后,你就可以用git merge来合并他的工作了。
2 想查看两个分支的区别,就用git whatchanged -p branch1..branch2。注意,-p表示以易理解的字符方式表示两者区别。如果不加-p的话,git会输出一些内部格式的区别信息,你根本看不懂:)
3 git pull的用法至少有四种,一个是在git clone之后用git pull来同步;第二个用法是用git pull .来替代git merge命令;第三个用法是git pull /path/to/repo,将运程仓库的内容直接merge到当前分支中。第四种用法是在git pull /path/to/repo后面加上<src>:<dst>来指定源的分支和本地分支。
4 git里有四种对象:commit对象、tree对象、blob对象和tag对象
5 尽量不要用git-push,因为他类似于CVS的管理模式,而git的模式特点就是分布式,所以常用git pull代替git push。
6 git fetch <仓库路径> <分支信息>,用于从远程仓库获取代码。其中<分支信息>的格式是这样的 “<src>:<dst>”,<src>表示源的分支,而<dst>表示本地分支。如 果<dst>被省略,那么就默认为本地当前分支。
7 如果在当前分支有代码修改,但未commit,那么不允许git checkout到其他分支。
8 想从index file中删除一个登记文件,用git reset — filename
9 用git checkout -- filename来将此文件代码恢复到index中的状态。
《看日记学git》系列文章汇总
1
获得帮助可以使用类似man git-****的命令格式:
想获得关于commit命令的帮助,则man git-commit
想获得关于pull命令的帮助,则man git-pull
想获得关于merge命令的帮助,则man git-merge
以此类推
2
任何人在使用git之前,都要提交简单的个人信息,以便git区分不同的提交者身份。
#git config –global user.name “your name”
#git config –global user.email yourname@example.com
3
想新开启一个项目,应该先建立一个目录,例如名为myproject,然后所有的项目开发内容都在此目录下进行。
#cd myproject
#git init
#git add .
#git commit //这个步骤会自动进入编辑状态,要求提交者输入有关本次提交的“开发信息”
至此,一个新项目就诞生了,第一个开发信息(开发日志)也随之诞生。
4
如果改进了项目源代码,并且到了开发者认为“应该再次记录开发信息”的时候,则提交“工作成果”。
#git commit -a //这是一个偷懒的命令,相当于git add .; git commit;
但是,此处有一点应该注意,那就是git commit -a无法把新增文件或文件夹加入进来,所以,如果你新增了文件或文件夹,那么就要老老实实的先git add .,再git commit喽。[此处非常感谢freeren的提醒]
5
想检查到目前为止对源码都做了哪些修改(相对于本次工作刚开始之时):
#git diff //这个命令只在git add之前使用有效。如果已经add了,那么此命令输出为空
#git diff –cached //这个命令在git add之后在git commit之前有效。
#git status //这个命令在git commit之前有效,表示都有哪些文件发生了改动
6
想查看自项目开启到现在的所有开发日志
#git log
#git log -p //会输出非常详细的日志内容,包括了每次都做了哪些源码的修改
7
开启一个试验分支(experimental),如果分支开发成功则合并到主分支(master),否则放弃该试验分支。
#git branch experimental //创建一个试验分支,名称叫experimental
#git branch //显示当前都有哪些分支,其中标注*为当前所在分支
#git checkout experimental //转移到experimental分支
(省略数小时在此分支上的开发过程)…
如果分支开发成功:
#git commit -a //在experimental分支改进完代码之后用commit在此分支中进行提交
#git checkout master //转移回master分支
#git merge experimental //经证实分支开发成功,将exerimental分支合并到主分支
#git commit -a //彻底完成此次分支合并,即提交master分支
#git branch -d experimental //因为experimental分支已提交,所以可安全删除此分支
如果分支开发失败:
#git checkout master
#git branch -D experimental //由于分支被证明失败,因此使用-D来放弃并删除该分支
8
随时查看图形化分支信息。
#gitk
9
当合作伙伴bob希望改进我(rocrocket)的工作成果,则:
bob$git clone /home/rocrocket/project myrepo //此命令用于克隆我的工作到bob的myrepo目录下。请注意,此命令有可能会因为/home/rocrocket的目录权限问题而被拒绝,解决方法 是chmod o+rx /home/rocrocket。
(省略bob数小时的开发过程)…
bob$git commit -a //bob提交自己的改进成果到自己的git仓库中,并口头告知我(rocrocket)他已经完成了工作。
我如果非常非常信任bob的开发能力:
$ cd /home/rocrocket/project
$ git pull /home/bob/myrepo //pull命令的意思是从远端git仓库中取出(git-fetch)修改的代码,然后合并(git-merge)到我(rocrocket)的项目中 去。读者要记住一个小技巧,那就是“git pull .”命令,它和git merge的功能是一样的,以后完全可以用git pull .来代替git merge哦!请注意,git-pull命令有可能会因为/home/bob的目录权限问题而被拒绝,解决方法是chmod o+rx /home/bob。
如果我不是很信任bob的开发能力:
$ cd /home/rocrocket/project
$ git fetch /home/bob/myrepo master:bobworks //此命令意思是提取出bob修改的代码内容,然后放到我(rocrocket)工作目录下的bobworks分支中。之所以要放到分支中,而不是 master中,就是要我先仔仔细细看看bob的开发成果,如果我觉得满意,我再merge到master中,如果不满意,我完全可以直接git branch -D掉。
$git whatchanged -p master..bobworks //用来查看bob都做了什么
$git checkout master //切换到master分区
$git pull . bobworks //如果我检查了bob的工作后很满意,就可以用pull来将bobworks分支合并到我的项目中了
$git branch -D bobworks //如果我检查了bob的工作后很不满意,就可以用-D来放弃这个分支就可以了
过了几天,bob如果想继续帮助我开发,他需要先同步一下我这几天的工作成果,只要在其当初clone的myrepo目录下执行git pull即可:
#git pull //不用加任何参数,因为当初clone的时候,git已经记住了我(rocrocket)的工作目录,它会直接找到我的目录来取。
本次将重点关注历史记录查询。
1
git的历史记录是由一些列相关联的”commit”所组成的。每一次“commit”都会有一个唯一的名称。如下黑体字所示:
[rocrocket@wupengchong project]$ git log
commit 5b888402aadd3cd41b3fe8c84a8658da07893b20
Author: rocrocket <wupengchong@gmail.com>
Date: Wed Sep 24 13:16:46 2008 +0800
after pull from rocrocket
Hello!!!!!
2
我们可以使用git show再加上述的commit名称来显式更详细的commit信息:
[rocrocket@wupengchong project]$ git show 5b888402aadd3cd41b3fe8c84a8658da07893b20
你完全可以用一个最短的且唯一的“名称前几个字符”来只待某次commit:
[rocrocket@wupengchong project]$ git show 5b888 //只要能区别与其他名称就足够了
使用git show加分支名称,亦可以显示分支信息:
[rocrocket@wupengchong project]$git show master
[rocrocket@wupengchong project]$git show experimental
使用HEAD字段可以代表当前分支的头(也就是最近一次commit):
[rocrocket@wupengchong project]$git show HEAD
每一次commit都会有”parent commit”,可以使用^表示parent:
[rocrocket@wupengchong project]$git show HEAD^ //查看HEAD的父母的信息
[rocrocket@wupengchong project]$git show HEAD^^ //查看HEAD的父母的父母的信息
[rocrocket@wupengchong project]$git show HEAD~4 //查看HEAD上溯4代的信息
要注意的是git-merge是会产生双父母的,这种情况这样处理:
[rocrocket@wupengchong project]$git show HEAD^1 //查看HEAD的第一个父母
[rocrocket@wupengchong project]$git show HEAD^2 //查看HEAD的第二个父母
3
你可以给复杂名称起个别名:
[rocrocket@wupengchong project]$ git tag V3 5b888 //以后可以用V3来代替复杂的名称(5b888…)
[rocrocket@wupengchong project]$ git show V3
[rocrocket@wupengchong project]$ git branch stable V3 //建立一个基于V3的分支
4
可以用git grep帮助我们搜索:
[rocrocket@wupengchong project]$ git grep “print” V3 //在V3中搜索所有的包含print的行
[rocrocket@wupengchong project]$ git grep “print” //在所有的历史记录中搜索包含print的行
5
定位具体的历史记录
[rocrocket@wupengchong project]$ git log V3..V7 //显示V3之后直至V7的所有历史记录
[rocrocket@wupengchong project]$ git log V3.. //显示所有V3之后的历史记录。注意<since>..<until>中任何一个被省略都将被默认设置为HEAD。所以如果使 用..<until>的话,git log在大部分情况下会输出空的。
[rocrocket@wupengchong project]$ git log –since=”2 weeks ago” //显示2周前到现在的所有历史记录。具体语法可查询git-ref-parse命令的帮助文件。
[rocrocket@wupengchong project]$ git log stable..experimental //将显示在experimental分支但不在stable分支的历史记录
[rocrocket@wupengchong project]$ git log experimental..stable //将显示在stable分支但不在experimental分支的历史记录
6
你最喜欢的gitk也可以定位具体的历史记录:
[rocrocket@wupengchong project]$ gitk –since=”2 weeks ago” drivers/ //将在GUI中显示自2周前到现在为止的且位于drivers目录下的分支记录信息
===
这次重点讲解索引文件(index file)的作用。
我们在提交工作时,使用最多的命令就是git commit -a了,但是这个将提交你所做的所有工作。其实,如果你了解commit的工作机制,你会知道我们可以自定义提交哪些部分到哪些工作树中,其实自由度很大的。
1
还记得之前我们建立的test-project工作目录么。我们继续在这个目录下演示讲解。
[rocrocket@wupengchong test-project]$ echo “hello world,again”>>file.txt
这次,我们不急着执行commit命令,而是先用git diff看看差别情况:
[rocrocket@wupengchong test-project]$ git diff
diff –git a/file.txt b/file.txt
index 60be00d..a559610 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
Hi,rocrocket!
+hello world,again
好了,我们可以看到git报告了我们刚才所做的修改。下面我们来add一下,然后再git diff,看看diff有什么变化呢:
[rocrocket@wupengchong test-project]$ git add file.txt
[rocrocket@wupengchong test-project]$ git diff
[rocrocket@wupengchong test-project]$
大家可以看到在add之后的git diff的输出竟然为空了,但是此时我们尚未执行commit阿。如果这个时候你执行git diff HEAD,你仍然会看到修改报告:
[rocrocket@wupengchong test-project]$ git diff HEAD
diff –git a/file.txt b/file.txt
index 60be00d..a559610 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
Hi,rocrocket!
+hello world,again
这就说明了一个问题:git diff不是在和HEAD比,而是和另外一个“神秘”内容在比,而这个“神秘”内容就是“索引文件”!
索引文件(index file)就是.git/index文件,它是二进制形式的文件。我们可以用ls-files来检查它的内容。
[rocrocket@wupengchong test-project]$ git ls-files –stage //一定要记住,此命令是用于查看index file的!!
100644 a55961026a22bdd4e938dcc90a4a83823a81f776 0 file.txt
[rocrocket@wupengchong test-project]$ git cat-file -t a5596
blob
[rocrocket@wupengchong test-project]$ git cat-file blob a5596
Hi,rocrocket!
hello world,again
很明显,我们可以看到其内容已经是改进后的代码了,怪不得git-diff会输出空呢!
我们的结论就是git add的作用就是创建一个blob文件来记录最新的修改代码,并且在index file里添加一个到此blob的链接。
2
如果在git-diff后面加上参数HEAD,则git-diff会显示当前工作目录和最近一次提交之间的代码区别。
[rocrocket@wupengchong test-project]$ echo ‘again?’>>file.txt
[rocrocket@wupengchong test-project]$ git diff HEAD
diff –git a/file.txt b/file.txt
index 60be00d..dfb67dc 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,3 @@
Hi,rocrocket!
+hello world,again
+again?
如果使用参数–cached,则会比较index file和最近一次提交之间的代码区别。
[rocrocket@wupengchong test-project]$ git diff –cached
diff –git a/file.txt b/file.txt
index 60be00d..a559610 100644
— a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
Hi,rocrocket!
+hello world,again
按我的认识,更清楚且通俗的解释就是:git维护的代码分成三部分,“当前工作目录”<->“index file”<->git仓库。git commit会将index file中的改变写到git仓库;git add会将“当前工作目录”的改变写到“index file”;“commit -a”则会直接将“当前工作目录”的改动同时写到“index file”和“git仓库”。
而git diff的使用稍微有些复杂,大家可以看看Lee.MaRS对于这个命令非常精彩的分析(蓝色字部分):(在此非常感谢Lee.MaRS)
将 Current working directory 记为 (1)
将 Index file 记为 (2)
将 Git repository 记为 (3)
他们之间的提交层次关系是 (1) -> (2) -> (3)
git add完成的是(1) -> (2)
git commit完成的是(2) -> (3)
git commit -a两者的直接结合
从时间上看,可以认为(1)是最新的代码,(2)比较旧,(3)更旧
按时间排序就是 (1) <- (2) <- (3)
git diff得到的是从(2)到(1)的变化
git diff –cached得到的是从(3)到(2)的变化
git diff HEAD得到的是从(3)到(1)的变化
3
status命令会显示当前状态的一个简单总结:
[rocrocket@wupengchong test-project]$ git status
# On branch master
# Changes to be committed:
# (use “git reset HEAD <file>…” to unstage)
#
# modified: file.txt
#
# Changed but not updated:
# (use “git add <file>…” to update what will be committed)
#
# modified: file.txt
#
上面两行黑体字中的Changes to be committed表示在index和commit的区别状况。而Changed but not updated表示当前目录和index的区别状况。