Git 是分布式版本控制系统,那么它就根本没有“中央服务器”,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
前言:
关于命令行窗口,用Windows的cmd或者用Git Bash Here都行,我用的后者,个人习惯。
Tab键可以自动补全命令,上下键可以选择之前输入过的命令。
常用的几个命令及其作用,请见下图:
Workspace:工作区
Index:暂存区
Repository:版本库
Remote:远程库
add:把内容提交到暂存区
commit:把暂存区的所有内容提交到当前分支
checkout:用版本库的内容来覆盖工作区
push:推送
fetch/clone:从远程拉取最新版本到版本库,不自动合并(推荐用pull)
pull:从远程拉取最新版本到本地,并自动合并
reset :版本跳转
更好理解的一张图:
一、创建并修改一个版本库
1.创建一个空目录
//先用cd选择一个合适的地方(省略此步)
$ mkdir learngit//再创建一个空文件(又叫空目录)
$ cd learngit//进入这个文件
2.把这个目录变成Git可以管理的仓库$ git init
会产生一个.git
文件,这个目录下包含了所有 Git 正常工作所需要的信息。说白了,如果你想从你的项目中删除 Git 但是又要保留项目文件,只需要删除 .git 文件夹就可以了。
要创建一个.gitignore
文件,比如Unity,通常会忽略掉根目录的Library、Temp和解决方案相关的文件.sln等,因为这些文件要么是临时的、运行时生成的,要么就是像.meta文件这类,我们不需要版本控制的。
Git只能跟踪文本文件的改动,比如TXT文件、网页、所有的程序代码等等; 图片、视频、Word这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化。
3.编写一个readme.txt
文件,一定要放到learngit目录下(子目录也行)
4.第一步,用命令git add告诉Git,把提交的文件修改放到暂存区:$ git add readme.txt
。$ git add .
则添加全部文件。
执行上面的命令,没有任何显示,说明添加成功。可以多次add不同的文件。
5.第二步,用命令git commit告诉Git,把暂存区中的内容提交到当前分支,-m后面输入的是本次提交的说明。commit可以一次提交很多文件。$ git commit -m "wrote a readme file"
。会显示:1个文件被改动(我们新添加的readme.txt文件),插入了两行内容(readme.txt有两行内容)
6.要随时掌握工作区的状态,使用git status命令。
7.如果git status告诉你有文件被修改过,用git diff可以查看修改内容。
知道了对readme.txt作了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件是一样的两步。
二、远程仓库
GitHub网站就是提供Git仓库托管服务,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。
添加远程库(从本地库克隆到远程库)
现在,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。
1.登陆GitHub,创建一个新的仓库
2.然后,把本地仓库的内容推送到GitHub仓库:
$ git remote add origin git@github.com:(github名)/(Repository name).git
3.下一步,就可以先add,再commit,最后再把本地库的所有内容push推送到远程库上:$ git push -u origin master
4.从现在起,只要本地作了提交,就可以通过命令:$ git push origin master
就把本地master分支的最新修改推送至GitHub。
从远程库克隆到本地库
用命令git clone克隆一个本地库:
$ git clone git@github.com:michaelliao/gitskills.git
小结:要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。
Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。
三、版本回退或前进
如果已经提交了不合适的修改到版本库时,想要撤销本次提交,就可以用版本跳转。
Git允许我们在版本的历史之间穿梭,穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
git log(查看提交的历史)
git log - -pretty=oneline(查看简版提交历史)
git reset - -hard HEAD^(回退到上个版本)
git reset - -hard HEAD^^(回退到上上个版本),git reset - -hard HEAD~10(回退到上10个版本)
git reset - -hard “commit id”(版本号(就写版本号前面几个字符就行),跳转到制定版本)
如果看不到“commit id”:Git提供了一个命令git reflog用来记录你的每一次版本切换的“commit id”
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD改变指向而已,然后顺便把文件更新了。
四、分支管理
分支的意义:
• 假设你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
• 现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到写完代码后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
创建和合并分支
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支大保健:git checkout -b <name>
在分支上修改、提交到暂存区、提交到本地版本库
Dev分支完事,切换回master分支
合并某分支到当前分支(一定要合并后才有效果):git merge <name>
删除分支:git branch -d <name>
解决冲突
vi txt.name 是修改txt中的内容的指令,修改完后按Esc,再输入:wq保存退出
两个分支上都对同一个地方做了修改,Git无法执行“快速合并”,要解决冲突。
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并。用git log --graph
命令可以看到分支合并图。
分支管理策略
分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
小结:
Git分支十分强大,在团队开发中应该充分应用。
Bug分支
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交。并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作
小结:
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
Feature分支
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature(新功能)分支,在上面开发,完成后,合并,最后,删除该feature分支。
小结:
开发一个新feature,最好新建一个分支,正常合并;
如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>
强行删除。
多人协作—推送Push和拉取Pull分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
推送到master主分支:$ git push origin master
如果要推送其他分支,比如dev,就改成:$ git push origin dev
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
• master分支是主分支,因此要时刻与远程同步;
• dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
• bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
• feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
抓取分支,多人协作时,大家都会往master和dev分支上推送各自的修改。
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub,也就是要在github上邀请你的伙伴加入这个项目的开发)或者同一台电脑的另一个目录下克隆:$ git clone git@github.com:michaelliao/learngit.git
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用如下方式创建本地dev分支:
确认你本地的 learngit 中的 dev分支推送到远程了没,如果没有就git push origin dev
在小伙伴的目录下(我是在本机不同目录实验)
git pull//抓取远程提交
git checkout -b dev origin/dev//在新的本地创建和远程分支对应的分支
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:先add再commit最后$ git push origin dev
如果抓取分支失败,怎么办?
你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送->推送失败
推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送
如果git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
再pull:$ git pull
这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push。
小结:
多人协作的工作模式通常是这样:
- 在本地创建和远程分支对应的分支,使用
git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致; - 可以试图用
git push origin branch-name
推送自己的修改; - 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name
。 - 若git pull 成功,如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再用
git push origin branch-name
推送就能成功!
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
标签管理
Git有commit,为什么还要引入tag?
• “请把上周一的那个版本打包发布,commit号是6a5819e…”
• “一串乱七八糟的数字不好找!”
如果换一个办法:
• “请把上周一的那个版本打包发布,版本号是v1.2”
• “好的,按照tag v1.2查找commit就行!”
所以,tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
标签:
git tag v1.0 #给当前分支最新的commit打标签
git tag v0.9 36df530 #给历史提交的commit打标签
git tag -a v0.1 -m 'version 0.1 released' 3628164 #-a指定标签名,-m指定说明文字
git tag -s <tagname> -m 'blabla' #可以用PGP签名标签
git tag #查看所有标签
git show v1.0 #查看标签信息
git tag -d v0.1 #删除标签
git push origin <tagname> #推送某个标签到远程
git push origin --tags #推送所有尚未推送的本地标签
git tag -d v0.2 #先删除本地标签
git push origin :refs/tags/v0.2 #删除远程标签
自定义git
• 忽略某些文件时,需要编写.gitignore;
• .gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
总结
经过几天的学习,相信你对git已经有了初步掌握。一开始,可能觉得git上手比较困难,没关系,多操练几次,就会越用越顺手。
git虽然极其强大,命令繁多,但常用的就那么十来个,掌握好这十几个常用命令,你已经可以得心应手地使用git了。