本文肯定不是Git的最佳的教程,它只是本人的Git操作手册,我将从一些实际问题出发,让熟悉SVN用户顺利过度到Git来(当然包括我自己了),其中会加入一些个人感受或看法,相信会对大家有些启发。另外,全部把这些操作写在一个网页里的好处是哪天忘记了怎么做,只需要到这里来<Ctrl/Command>+<F>即可,无需再点来点去找了。这里讲的功能是我自己最常用的功能,其实估计只占Git全部功能的1/10不到,太复杂的东西也记不住,不明白就google或者stackoverflow去吧。内容如有必要,后面再补充。
估计很少人知道Git这个名称是怎么来的,其实这个名字是Git的作者最初定的,Git在英文中是“饭桶”的意思,有趣的是,跟中文很相似,它同时有“没用的家伙”,“讨厌的人”等意思,Git的作者说他是个自大的王八蛋,所以他的项目也要起个很王八蛋的名字。这可不是我瞎编的,不信可以自己去维基百科找找资料看。高人的品味,岂是我等凡人所能理解。
果断选择安装TortoiseGit,因为我发现用cygwin去使用Git在遇到中文时总是会有些问题,调来调去很心烦,MinGW也好不去哪里,感觉Git本身就不是为Windows设计的。(不奇怪啊,其原作者就是大名鼎鼎的Linux之父Torvalds Linus)虽然TortoiseGit是图形化界面,但最好还是自己用命令行来演练一下,以便加深理解。TortoiseGit的用法不在本文讲述范围中,因为TortoiseGit太好用了,为啥不做个Mac版的呢?
SVN没有暂存区,暂存区是让Git变得复杂的重要因素,但也让Git变得更加灵活。
SVN有个提交流水号,从1开始,一直递增下去,Git则没有,原因是Git是分布式的,没有一个集中管理的容器,简单流水号累加必然出现冲突,所以Git使用SHA-1摘要的方式来记录“流水号”,SHA-1摘要是160位的,表示成HEX码一共有40个字符,如:6c1a24e6593678f074a2f6ee37ec42606a2545ed。这实在太长了,不太方便我们指定这么一个提交号,通常我们只需要指定前面七个字符即可,如“6c1a24e”,在同一个项目中,前七个字符是不太可能出现重复的。
有些文件不想被加入到版本控制中去,和SVN一样,Git也支持这么一个“忽略文件列表”的设置,这样执行git add filename的时候就会提示错误,git add *的时候也默认不会把这些文件放进去。
git config --global core.excludesfile=~/.gitignore
其中~/.gitignore的内容大致如此:
*.swp
*.tmp
.DS_Store
据说还支持正则表达式,我没去研究。如果实在需要把个别被忽略文件加入到版本控制中去的话可以git add -f filename这样,强制加入。
如果仅仅是想让某个工程忽略掉某些文件,而不是让全部工程去忽略的话,可以在.git同级的目录下创建.gitignore文件。
Git使用远程托管服务是需要身份验证的,跟SVN使用简单的用户名/密码验证机制不太一样,Git通常需要你造一对公私钥,让后把公钥交给服务器,这样服务器才能识别你的身份(不需要再通过额外的用户名密码),具体怎么弄,得看你使用的是那个远程库,如果是github.com,那就到github.com去看看上面的说明,别的也大同小异。比如我使用的是开源中国的免费托管服务:
git clone git@git.oschina.net:guogangj/GitTest.git
clone其实和SVN的checkout最像,而git checkout和svn的checkout一点都不像。
git pull能把远程的库“拉”回来,其实它是git fetch和git merge两个命令的结合;git push能把本地的库“推”到远程的库去。
跟SVN不太像,在commit之前,得指定要commit哪些东西,用git add命令来指定,add命令其实作用就是把修改内容从工作区搬到暂存区。放入暂存区之后,再从暂存区提交到本地容器。
git add filename1 filename2
git commit -m "The comment…”
这个也和SVN不太一样:
rm
filename1
#默认情况下,add命令会带上“—ignore-removal”参数来忽略被删文件,所以现在需要额外带上-A参数
git
add -A filename1
git commit -m "filename1 is deleted."
你也许有点奇怪,为什么明明是删除,却用add命令?其实Git管理的是“修改”,删除本身也是一种修改,所以需要把这个修改add到暂存区去。
到底哪些文件没变,哪些变了,变了的文件有没放入暂存区,有没有文件被删除或新增?怎么看?用git status。它会明明白白,清清楚楚地告诉你究竟现在是怎么一种情况。但直接用git status命令的话有些凌乱,我们需要更加简洁的信息:git status -sb
由于这条命令很常用,所以我们可以在~/.gitconfig中配置一下:
[alias]
check = status -sb
以后直接打“git check”即可,或者你写得更简单点“git ck”,这个命令使用相当频繁。
当然是“git log”,但显示结果有些乱,不太友好,我们在~/.gitconfig中配置一下:
[alias]
tree = log --graph --pretty=format:‘%h %cd %C(yellow)%cn
%C(green)%s %C(cyan)%d‘ --date=short
这样只要git tree就行了,显示结果还是蛮好看的。(参考下面的一张图)
查看某个文件的修改履历:
git tree filename1
比较工作区中的某个文件跟以前版本的差别:
git diff b5624a7 filename1
比较某个文件历史提交之间的差别:
git diff b5624a7 1433ae5 filename1
有时候可能需要用“--”隔开:
git diff b5624a7 1433ae5 -- filename1 filename2 filename3
如果要比较两次提交之间的差别(非单个文件),那我个人觉得直接用diff在命令行界面上显示比较凌乱,最好得借助一些图形界面的工具了。最方便的图形化工具,无疑是gitk,这是Git包自带的,敲如gitk就启动了。它很方便地指定任意两次提交之间的比较,这点SourceTree(一个充满好评的Git图形化工具)貌似还没有这个功能,我还试用过一个收费的软件,叫Tower,号称最强大,但也不知道怎么弄,实在郁闷,说实在的,TortoiseGit能弄个Mac版本就好了。在gitk中要比较两次提交,可以先选中一次提交,再右击另一处提交,选择“Diff selected -> this”或者“Diff this -> selected”,选哪个,我的原则是旧的在前,新的在后,否则会出现一些理解上的障碍,如下图:
上图中,我选中的提交是比我右击的提交要旧的,所以selected放在this前。即使有了gitk,我还是觉得很不爽,因为它比命令行方式好不了多少,甚至说没什么差别,仅仅是好看了点,我最想要的一个分栏比较功能它都没有,所谓分栏比较就是一个文件放左边,一个文件放右边,而不是把两个文件的内容混在一起显示,很显然,分栏比较需要图形界面,TortoiseSVN就做得很好,Windows下还有如ExamDiff等工具,都是我很喜欢的工具,咋Mac下想找一个就那么难呢?
不过,我真找到了一个:DiffMerge,一看名称就知道它是干啥用的,我下载的是Mac版的DMG文件。
我们可以将它设置为gitk的External diff tool,在gitk的Preferences中,如下图:
然后就可以右击要比较的文件,选择External Diff,如图:
看起来不错,但还是有些不方便,因为这样的话我得先启动gitk,然后再选比较的文件,再右击……能不能在命令行方式下直接启动DiffMerge?答案是肯定的。一步步来:
1,首先确保DiffMerge的命令行脚本已经正确安装(DMG版本的得自己手动装装)
ls /usr/bin/diffmerge
如果找不到这个脚本的话,那么将DMG镜像中的Extra中一些内容这样弄过去:
#以root身份执行下面命令
cp Extras/diffmerge.sh
/usr/bin/diffmerge
chmod 755
/usr/bin/diffmerge
#增加diffmerge的帮助信息
cp Extras/diffmerge.1
/usr/share/man/man1/diffmerge.1
chmod 644 /usr/share/man/man1/diffmerge.1
2,退出root,执行下面的命令,其实就是改变一下~/.gitconfig中的配置内容。
git config --global diff.tool diffmerge
git config --global
difftool.diffmerge.cmd "/usr/bin/diffmerge \"\$LOCAL\" \"\$REMOTE\""
git
config --global merge.tool diffmerge
git config --global
mergetool.diffmerge.trustExitCode true
git config --global
mergetool.diffmerge.cmd "/usr/bin/diffmerge --merge --result=\"\$MERGED\"
\"\$LOCAL\" \"\$BASE\" \"\$REMOTE\""
3,这样就搞定了,现在比较下当前的版本跟3fc7ea2这个版本:
git difftool 3fc7ea2
你会发觉,git会一个个提示你是否执比较,如果选“Y”(默认就是“Y”,若命令带“-y”参数,那就不提示,直接全部“Y”),那么就会自动打开diffmerge执行比较,这是我们想看到的效果。另外difftool跟diff的语法是一样的,随你高兴,想咋用就咋用吧。
要还原成先前的某个版本,当然要show一下它的内容,然后再还原。
git tree filename1
#显示filename1在1433ae5这次提交的内容
git show 1433ae5 filename1
git
checkout 1433ae5 filename1
这样并不会改变当前的工作分支,仅仅是修改了filename1的文件内容而已,checkout这里的用法跟SVN的revert比较像。
和SVN不同,大多数时候,Git是在分支上干活,而不是在主干上,分支上的活干好了之后,再将其合并入主干中。
#从当前工作分支(master这个主干也可以看作一个分支哦)中分出一个叫newjob的新分支(-b参数表示新建分支,否则是切换分支)
git
checkout -b newjob
#接着干了一些修改
#回到主干
git checkout master
#在主干上做一些修改
#把newjob的修改合并到主干中
git merge newjob
另外,查看所有分支的方法是:git branch -vva
想要切换到别的分支去干活也很简单,不要带-b参数即可:
#切换到comment4分支
git branch comment4
分支是临时的,这个与SVN所提倡的使用是一致的,当你这个分支开发完成了之后,要尽快将它合并回主干,然后你可以考虑删除掉分支了。
git branch -d newjob
SVN中有个很有用的命令,blame,可以用来追踪出了问题的某行代码是谁在什么时候改的,Git中也有同样的命令,也叫blame。
git blame filename1
最接近SVN的还原(reverse)应该是:
git reset —hard
这样一来工作区和暂存区中的修改皆被抛弃掉。
如果仅仅要抛弃掉暂存区的修改,那么:
git reset
对SVN来说,如果你做了一个错误的提交,那只能用后面的修改来将它改正过来,而不能把历史的提交动作删除,正所谓历史不可改变,这个特性其实对于大多数项目来说是个不错的特性。而在Git中,历史是可以改变的!这是Git和SVN的一大不同。最最常见的需要改变历史的情况应该是这样:我刚刚commit了一下,但发现comment写错了,我想倒退回来,再重新commit一次:
#做了一些改动
git add .
git commit -m "the wrong message"
#发现注释写错了
#工作区和暂存区都不变,将容器指针指向前一个版本
git reset —soft HEAD^
git commit -m "the
correct message"
还可以放弃最近几轮的提交,比如:
git reset —hard HEAD^^^
将还原至前三个版本,放弃最近的三次提交,如果你不记住最后的一次提交的摘要码的话就可能再找不回最近的这几次提交了,如果你还记得住的话,可以这样恢复回最近的提交去:
git reset —hard 1749d74
你猜对了,其实reset最大的作用在于改变容器的HEAD指向,一般情况下不要乱用啊,否则真可能导致辛辛苦苦改动的东西彻底找不回了。
原文:http://www.cnblogs.com/guogangj/p/3602321.html