先用一幅图,从整体上描述主要git命令的工做流程css
workspace: 本地的工做目录。(记做A)
index/stage:暂存区域,临时保存本地改动。 (记做B)
local repository: 本地仓库,只想最后一次提交HEAD。(记做C)
remote repository:远程仓库。(记做D)git
如下全部的命令的功能说明,都采用上述的标记的A、B、C、D的方式来阐述。github
初始化数据库
git init //建立 git clone /path/to/repository //检出 git config --global user.email "you@example.com" //配置email git config --global user.name "Name" //配置用户名
操做segmentfault
git add <file> // 文件添加,A → B git add . // 全部文件添加,A → B git commit -m "代码提交信息" //文件提交,B → C git commit --amend //与上次commit合并, *B → C git push origin master //推送至master分支, C → D git pull //更新本地仓库至最新改动, D → A git fetch //抓取远程仓库更新, D → C git log //查看提交记录 git status //查看修改状态 git diff//查看详细修改内容 git show//显示某次提交的内容
撤销操做安全
git reset <file>//某个文件索引会回滚到最后一次提交, C → B git reset//索引会回滚到最后一次提交, C → B git reset --hard // 索引会回滚到最后一次提交, C → B → A git checkout // 从index复制到workspace, B → A git checkout -- files // 文件从index复制到workspace, B → A git checkout HEAD -- files // 文件从local repository复制到workspace, C → A
分支相关网络
git checkout -b branch_name //建立名叫“branch_name”的分支,并切换过去 git checkout master //切换回主分支 git branch -d branch_name // 删除名叫“branch_name”的分支 git push origin branch_name //推送分支到远端仓库 git merge branch_name // 合并分支branch_name到当前分支(如master) git rebase //衍合,线性化的自动, D → A
冲突处理ssh
git diff //对比workspace与index git diff HEAD //对于workspace与最后一次commit git diff <source_branch> <target_branch> //对比差别 git add <filename> //修改完冲突,须要add以标记合并成功
其余分布式
gitk //开灯图形化git git config color.ui true //彩色的 git 输出 git config format.pretty oneline //显示历史记录时,每一个提交的信息只显示一行 git add -i //交互式添加文件到暂存区
① 建立版本库
经过git init
命令把这个目录变成Git能够管理的仓库
第一步,用命令git add告诉Git,把文件添加到仓库:
$ git add readme.txt
执行上面的命令,没有任何显示,这就对了,ide
Unix的哲学是“没有消息就是好消息”
说明添加成功。
第二步,用命令git commit -m "xxx"
告诉Git,把文件提交到仓库,-m后面输入的是本次提交的说明,能从历史记录里方便地找到改动记录。
② 添加远程库
git remote add origin git@github.com:tcyfree/test.git(或https://github.com/tcyfree/test.git,用git@比https快)
添加后,远程库的名字就是origin,这是Git默认的叫法,也能够改为别的,可是origin这个名字一看就知道是远程库。
下一步,就能够把本地库的全部内容推送到远程库上:
$ git push -u origin master
把本地库的内容推送到远程,用git push
命令,其实是把当前分支master推送到远程。
因为远程库是空的,咱们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在之后的推送或者拉取时就能够简化命令。
总结:从如今起,只要本地做了提交,就能够经过命令:git push origin master
把本地master分支的最新修改推送至GitHub,如今,你就拥有了真正的分布式版本库!
要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git;
关联后,使用命令git push -u origin master第一次推送master分支的全部内容;
此后,每次本地提交后,只要有必要,就可使用命令git push origin master推送最新修改;
分布式版本系统的最大好处之一是在本地工做彻底不须要考虑远程库的存在,也就是有没有联网均可以正常工做,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!
③ 从远程库克隆
上次咱们讲了先有本地库,后有远程库的时候,如何关联远程库。
如今,假设咱们从零开发,那么最好的方式是先建立远程库,而后,从远程库克隆。
要克隆一个仓库,首先必须知道仓库的地址,而后使用git clone命令克隆。
Git支持多种协议,包括https,但经过ssh支持的原生git协议速度最快。
时光机穿梭
1.要随时掌握工做区的状态,使用git status
命令。
2.若是git status告诉你有文件被修改过,用git diff
能够查看修改内容。
版本回退
1.HEAD指向的版本就是当前版本,所以,Git容许咱们在版本的历史之间穿梭,使用命令git reset --hard commit_id
。
2.穿梭前,用git log
能够查看提交历史,以便肯定要回退到哪一个版本。
3.要重返将来,用git reflog
查看命令历史,以便肯定要回到将来的哪一个版本。
git diff HEAD -- readme.txt命令能够查看工做区和版本库里面最新版本的区别
撤销修改
场景1:当你改乱了工做区某个文件的内容,想直接丢弃工做区的修改时,用命令git checkout -- file
。
场景2:当你不但改乱了工做区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file
,就回到了场景1,第二步按场景1操做。
(git reset
命令既能够回退版本,也能够把暂存区的修改回退到工做区。当咱们用HEAD时,表示最新的版本。)
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
删除文件
1.命令git rm
用于删除一个文件。
2.确实要从版本库中删除该文件,那就用命令git rm删掉,而且git commit:
$ git rm test.txt rm 'test.txt' $ git commit -m "remove test.txt" [master d17efd8] remove test.txt 1 file changed, 1 deletion(-) delete mode 100644 test.txt
如今,文件就从版本库中被删除了
git checkout实际上是用版本库里的版本替换工做区的版本,不管工做区是修改仍是删除,均可以“一键还原”。
git pull:至关因而从远程获取最新版本并merge到本地
git pull origin master
上述命令其实至关于git fetch 和 git merge
在实际使用中,git fetch更安全一些
由于在merge前,咱们能够查看更新状况,而后再决定是否合并
建立与合并分支
截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来讲不是指向提交,而是指向master,master才是指向提交的,因此,HEAD指向的就是当前分支。
git checkout
命令加上-b
参数表示建立并切换,至关于如下两条命令:
$ git branch dev $ git checkout dev Switched to branch 'dev'
而后,用git branch
命令查看当前分支:
$ git branch * dev master
git branch命令会列出全部分支,当前分支前面会标一个*
号。
假如咱们在dev上的工做完成了,就能够把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
因此Git合并分支也很快!就改改指针,工做区内容也不变!
合并完分支后,甚至能够删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,咱们就剩下了一条master分支:
git merge
命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就能够看到,和dev分支的最新提交是彻底同样的。
注意到上面的Fast-forward信息,Git告诉咱们,此次合并是“快进模式”,也就是直接把master指向dev的当前提交,因此合并速度很是快。
小结
Git鼓励大量使用分支:
查看分支:git branch
建立分支:git branch <name>
切换分支:git checkout <name>
建立+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
解决冲突
Git用<<<<<<<,=======,>>>>>>>标记出不一样分支的内容
修改master后提交:
如今,master分支和feature1分支变成了下图所示:
最后,删除feature1分支:
git branch -d feature1
总结:
当Git没法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
用git log --graph
命令能够看到分支合并图。
分支管理策略
一般,合并分支时,若是可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
分支策略
在实际开发中,咱们应该按照几个基本原则进行分支管理:
首先,master分支应该是很是稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,好比1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每一个人都在dev分支上干活,每一个人都有本身的分支,时不时地往dev分支上合并就能够了。
因此,团队合做的分支看起来就像这样:
准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
由于本次合并要建立一个新的commit,因此加上-m参数,把commit描述写进去。
合并后,咱们用git log看看分支历史:
$ git log --graph --pretty=oneline --abbrev-commit
7825a50 merge with no-ff
|\
| * 6224937 add merge
|/
59bc1cb conflict fixed
...
能够看到,不使用Fast forward模式,merge后就像这样:
小结
Git分支十分强大,在团队开发中应该充分应用。
合并分支时,加上--no-ff参数就能够用普通模式合并,合并后的历史有分支,能看出来曾经作过合并,而fast forward合并就看不出来曾经作过合并。
Bug分支
修复bug时,咱们会经过建立新的bug分支进行修复,而后合并,最后删除;
当手头工做没有完成时,先把工做现场git stash
一下,而后去修复bug,修复后,再git stash pop
,回到工做现场。
Feature分支
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,你确定不但愿由于一些实验性质的代码,把主分支搞乱了,因此,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
若是要丢弃一个没有被合并过的分支,能够经过git branch -D <name>
强行删除。
多人协做
当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,而且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote
或者,用git remote -v
显示更详细的信息。
并非必定要把本地分支往远程推送,那么,哪些分支须要推送,哪些不须要呢?
master分支是主分支,所以要时刻与远程同步;
dev分支是开发分支,团队全部成员都须要在上面工做,因此也须要与远程同步;
bug分支只用于在本地修复bug,就不必推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合做在上面开发。
总之,就是在Git中,分支彻底能够在本地本身藏着玩,是否推送,视你的心情而定!
多人协做的工做模式一般是这样:
首先,能够试图用git push origin branch-name推送本身的修改;
若是推送失败,则由于远程分支比你的本地更新,须要先用git pull试图合并;
若是合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
若是git pull
提示“no tracking information”
,则说明本地分支和远程分支的连接关系没有建立,用命令git branch --set-upstream branch-name origin/branch-name
。
小结
查看远程库信息,使用git remote -v
;
本地新建的分支若是不推送到远程,对其余人就是不可见的;
从本地推送分支,使用git push origin branch-name
,若是推送失败,先用git pull
抓取远程的新提交;
在本地建立和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致;
创建本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
;
从远程抓取分支,使用git pull,若是有冲突,要先处理冲突。
这就是多人协做的工做模式,一旦熟悉了,就很是简单。
忽略特殊文件
有些时候,你必须把某些文件放到Git工做目录中,但又不能提交它们,好比保存了数据库密码的配置文件啦,等等,每次git status
都会显示Untracked files ...
,有强迫症的童鞋内心确定不爽。
在Git工做区的根目录下建立一个特殊的.gitignore
文件,而后把要忽略的文件名填进去,Git就会自动忽略这些文件。
忽略文件的原则是:
忽略操做系统自动生成的文件,好比缩略图等;
忽略编译生成的中间文件、可执行文件等,也就是若是一个文件是经过另外一个文件自动生成的,那自动生成的文件就不必放进版本库,好比Java编译产生的.class文件;
忽略你本身的带有敏感信息的配置文件,好比存放口令的配置文件。
加上你本身定义的文件,最终获得一个完整的.gitignore文件,内容以下:
# Windows: Thumbs.db ehthumbs.db Desktop.ini # Python: *.py[cod] *.so *.egg *.egg-info dist build # My configurations: db.ini deploy_key_rsa
最后一步就是把.gitignore也提交到Git,就完成了!
小结
忽略某些文件时,须要编写.gitignore
;
.gitignore
文件自己要放到版本库里,而且能够对.gitignore
作版本管理!
安装Git
参考文档:Git经常使用命令
推荐文档:Git经常使用命令和Git团队使用规范指南
git - 简易指南
经常使用Git命令清单