简介
还是先了解些概念性的东西吧!
- Git为分布式版本控制系统,与集中式版本控制系统SVN不一样。具体区别这里不做解释,因为有更好的解释—>git 分布式工作流。
- 仓库:实际开发中一般是把github当远端仓库。所以要理解实际使用存在两个仓库,一个本地,一个远端。
- 分支:这可能是Git 最重要的部分,当然了分支也是分远端分支和本地分支。比如本地分支:develop 对应远端分支:origin/develop。分支间互不干扰又能相互衍合,分支对于协同工作和代码管理简直再适合不过。
- 三个工作区域:工作目录、暂存区、git目录。每次更改都是发生在工作目录,也是我们的工作区域。暂存区解释起来有些抽象,但简单来说就是索引文件,提交前需要将文件添加进暂存区。提交之后文件将永久存储在git目录。
- 三个状态:已修改(modified)、已暂存(staged)、已提交(committed)。
- commit: 一次提交就是一个commit,每个commit 都具有唯一SHA值如:b14287b56c371542380ca0900d53fb2171a4f42e 不过一般前7位 b14287b 就具有唯一性了。Git里面的commit 与svn 不一样,Git里面的commit 仅仅是提交在本地仓库,要同步到远端仓库还要push。所以说没网的情况下也能做提交,有网了统一push就是了,这点svn做不到。
新建git库
若是建本地仓库,则在文件夹根目录下git init 即可,新增.git 文件夹既是git 仓库。
实际开发中一般是先在github 新建远端仓库,然后git clone到本地,clone 下来的文件已经有本地仓库,不需要git init。
提交
Git 上的提交流程也蛮easy,修改之后git add . 默认全部暂存,提交写个提交信息 git commit -m"..."就算完成提交了。你想推到远端那就git push。
对应的各种文件状态:
分支
前面说了分支是git 最为重要的东西,一切操作都是基于分支。什么都不做,建好git 仓库之后,默认为master分支,即主分支。
一条分支可以理解为一条工作线,推动工作线不断向前的便是commit。
-
分支的新建
新建分支同样也是基于某个分支的某个commit,新建分支之后就好比在一条工作线上的某个位置,又拉了一条工作线,两条工作线同时存在,互不影响。
- 远端分支
远端分支的最新指向由 origin/分支名 来表现。当协同开发时,有人将远端分支指针向前移动了,那你的分支上则表现为本地分支落后于远端分支。比如develop 落后于 origin/develop,可通过git pull远端分支来同步。
当然了在本地与远端同步的基础上,你进行了commit那你的分支表现为本地分支领先于远端分支,可通过git push来将commit 推向远端,使远端指针向前移动,让本地与远端同步。
- 分支与分支之间的合并
不考虑远端分支的情况下进行本地分支合并。
1、merge
merge 是一种三方合并,把两个分支的最新节点与两个分支最近的共同祖先进行合并。生成一个新的节点,a merge b,那a 分支指向最新节点,同理b merge a,b指向最新节点。
2、rebase
rebase 又称衍合,但与merge不一样,它是一种变基操作。a rebase b,会将a 的最新提交重新以b为基座运用一遍。
下面是坑:
在不考虑远端分支的情况下,merge、rebase 都没什么问题,都能完成合并工作。但考虑远端分支,特别是多人协同开发时,使用rebase 就要注意了。弄不好就把别人写好的代码给冲掉了。
具体情景:
在节点c2新建你的carson分支之后,你已经在你的分支上做了push操作,也就是说origin/carson指向的节点领先与基点c2。
这种情况是carson 落后于origin/carson,就好比多人开发,你的同事在carson 分支上提交并push了,你这边会落后于origin/carson,你本地没有拉去你同事的最新代码,此时你想用rebase把develop上的代码合过来。合完之后会发现carson 分支与origin/carson 出现了差异。那这时git 会提示你又要拉取代码,又要push代码,这样操作的后果还不算太坏,也就出现几个相同的commit,最坏的结果是,你不pull,直接强制push。那后果就比较严重了,好比c5是你同事的提交,你强制push之后,c5就没了,origin和origin/carson 都指向c4,这就是把代码给冲掉了。如果这个时候你的同事再取拉代码,那本地的c5也没了,工作全白费了。
所以rebase 的使用要分情况了,同时强制push 也不是没有好处,有时push了一个错误代码,你可以reset 本地,修改之后再强制push,冲掉远端仓库的错误代码。
pull、fetch、pull --rebase
相信这样的等式大家看到很多次了,但我还是想结合图形来直观说明下。
git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase
git fetch 只是让远端分支的指针origin/分支名指向最新,不改变本地分支,一般在联网情况下fetch 操作不用执行,感觉单独执行git fetch 无太大的实际意义。
本地与远端分叉的情况
看看git pull:
看看git pull --rebase:
这种情况下用pull 、pull --rebase 出现的分支图会有差异。用哪种看个人喜好了,一般rebase会保证一条线,也不会出合成新的commit,比较干净。
当本地与远端没分叉,在一条线上,这种情况下pull 、pull --rebase 效果都一样。
实用操作
-
别名配置
嫌git 命令长,自己也可以在.gitconfig 里面设置git 别名。
git reset
能够回滚本地分支,表现为将本地分支指针向后移动。
默认接参数 --mixed,回滚之后但最新的改动还在工作区。
加参数 --soft, 回滚之后最新改动回到暂存区。
加参数 --hard,回滚之后改动不要了。git push origin [分支名] -f
强制提交,一般配合git reset 使用,可以冲掉远端commit,用于覆盖掉远端错误代码比较好。git cherry-pick #[SHA]
假如说你在分支carson 上提交了 c1、c2、c3,但现在develop 分支要发布,但需要有c2、c3 这两个更新,所以你又不能简单的把carson 合并到develop,因为c1这个改动还不能发布上线。那这个时候cherry-pick 就发挥作用了。可以在develop 分支上cherr-pick #[c2、c3 的SHA值,前7位即可],当然cherry-pick 得保证顺序,谁先提交的,那重新运用时也要先pick 谁。git reflog
查看当前分支的所有操作记录。
总结
刚来公司CTO就说“不会用git的程序员不是好程序员”,确实,git 功能强大,设计非常优秀,对于项目开发管理再适合不过。不会用git 如何跟团队一起高效的协同工作?上面所提的只是一些入门的知识点,没介绍太多命令,因为命令随便搜搜就能查到,重要的还是想多介绍些Git 工作原理,原理弄明白了才能真正做到会用。还不会使用的朋友看完这篇希望对你有所帮助。