├── README.md └── illustrations ├── areas.png ├── git-flow.png └── lifecycle.png /README.md: -------------------------------------------------------------------------------- 1 | # git 2 | 关于git的方方面面。包括基本概念,git flow,git提交规范,git插件以及常见问题解决 3 | ## 概念 4 | 5 | > 不要死记命令,而要知道命令背后的原理,即命令背后究竟做了什么事情。 6 | 7 | ### git是一个分布式版本控制系统 8 | 9 | 说它是分布式,其实是相对于传统的集中式版本控制系统如SVN来说的。 10 | git有本地仓库和远程仓库的概念。因此就涉及到了本地仓库和远程仓库的同步问题。 11 | 12 | 通过以下命令可以查看远程分支的地址信息: 13 | 14 | ```bash 15 | git:(daily/0.1.0) git remote -v 16 | origin http://gitlab.test.com/f/test.git (fetch) 17 | origin http://gitlab.test.com/f/test.git (push) 18 | ``` 19 | 20 | 本地分支拥有完整的内容,多人协作的时候,可以通过clone远程分支,通过fetch同步远程仓库,然后在本地仓库做修改,push 到远程达到多人协作的目的。 21 | 22 | ### git是面向对象,本质上是内容寻址系统 23 | 24 | .git目录的下有一个文件夹objects。存储了git库中的对象,对象是git中非常重要的概念。 25 | 26 | ```bash 27 | 28 | git会对所有内容做hash-obejct生成40位的校验和,然后前两位作为文件夹的名字。如下: 29 | 30 | git:(daily/0.1.0) ✗ ls -1 .git/objects 31 | 00 32 | 01 33 | 02 34 | 03 35 | 04 36 | 05 37 | 06 38 | 39 | 后38位作为文件名: 40 | 41 | git:(daily/0.1.0) ✗ ls -1 .git/objects/00 42 | 04a9fe24ed3e25e7a9d0cd87178bc4aed32891 43 | 1ab1dbd031b06b88acf247c2734a6ce5f2c2f2 44 | 384c5dbd2a126e09f27aa3f818516830b38933 45 | 604011e29363914659a5e436564f0c20b95ff4 46 | 80c38f950f9199744b82328f29ceb8ba5e7745 47 | 98a6385296048f8b3e5bf923374266f5df3d36 48 | b876a0e0adfa03a51862b0cbc7e04015628257 49 | bf64fbe6d61edbcc43484cd1feebf48ffbc668 50 | ff7645be03614527ec8c15f943e6d77ed56749 51 | 52 | 可以通过如下命名查看具体的文件内容,下图是显示tree的内容,如果显示blob内容,则会直接显示文件内容本身。 53 | 54 | 可以通过 git cat-file -t hash 查看对象类型 55 | 56 | git:(daily/0.1.0) ✗ git cat-file -p 001ab1dbd031b06b88acf247c2734a6ce5f2c2f1 57 | 100644 blob 4b02ba48a1dc2be18735b763d7e17c8aa9640ac5 index.js 58 | 100644 blob 7c49e625833ea4009c035ac8a568b53b0b68a3da a.less 59 | 100644 blob b1c19145a728e038bfb9b94525d48f6df70fb82f b.vue 60 | 61 | ``` 62 | 63 | git就是根据object建立一种树形结构。将文件和通过hash的方式关联起来。 64 | 65 | 当你推送远程分支的时候会看到类似下面的信息: 66 | 67 | ```bash 68 | git:(daily/0.1.0) ✗ git gc 69 | Counting objects: 843, done. 70 | Delta compression using up to 4 threads. 71 | Compressing objects: 100% (764/764), done. 72 | Writing objects: 100% (843/843), done. 73 | Total 843 (delta 453), reused 0 (delta 0) 74 | ``` 75 | 你也可以像我一样用git gc手动触发。 76 | 77 | ### 暂存区, 工作区,远程仓库的概念和区别 78 | 79 | 比如add,commit,checkout [file], reset究竟是在三者中怎么变化的。 80 | 81 | 暂存区,工作区,远程仓库的关系可以用一张图来表示。为了方便,直接拿廖雪峰的图: 82 | 83 | ![workspace-stage](https://cdn.liaoxuefeng.com/cdn/files/attachments/001384907702917346729e9afbf4127b6dfbae9207af016000/0) 84 | 85 | git add 会添加文件到暂存区,commit是将暂存区的文件提交到版本库。 然后push才最终将代码推送到远程对应的分支。 86 | 87 | 另外git还有一个文件状态生命周期的概念,同样也可以用一张图来表示。我直接从git-scm拿的图: 88 | 89 | ![life-cycle](https://github.com/azl397985856/git/blob/master/illustrations/lifecycle.png) 90 | ### HEAD,指针 91 | 92 | 当你新建一个git项目的时候,git会在根目录新建一个git目录. 93 | 94 | git 目录的文件内容: 95 | 96 | ```bash 97 | ➜ .git git:(master) ls -F1 98 | COMMIT_EDITMSG 99 | HEAD 100 | ORIG_HEAD 101 | config 102 | description 103 | hooks/ 104 | index 105 | info/ 106 | logs/ 107 | objects/ 108 | packed-refs 109 | refs/ 110 | ``` 111 | 其中比较重要的是HEAD hooks index objects refs这五个,理解上面五个概念对理解git非常重要。 112 | 113 | HEAD是一个特殊的指针,它是指针的指针。它用来标记当前的提交。当你使用git checkout branch, 114 | HEAD指针就会发生移动。 当你新建一个分支的时候其实仅仅是改变了HEAD的指向,这也是git分支比较轻量的原因。 115 | 通过如下命令可以查看当前HEAD位置: 116 | 117 | ```bash 118 | git:(develop) cat HEAD 119 | ref: refs/heads/develop 120 | ``` 121 | 122 | hooks是钩子。用来在git操作前后进行一些操作。 比如下面讲的husky插件就是基于这个原理实现的。 123 | 124 | index是本地的暂存区 125 | 126 | objects就是上面讲的内容 127 | 128 | refs其实是分支的引用。 129 | 130 | ```bash 131 | git:(daily/0.1.0) ✗ ls .git/refs 132 | heads remotes tags 133 | 134 | git:(master) ✗ cat .git/refs/remotes/origin/HEAD 135 | ref: refs/remotes/origin/master 136 | ``` 137 | ## git flow 138 | git flow其实就是分支管理模型。对于大型项目遵循一定的规则是很有必要的, 139 | 你可以定义一个完全适合你自己项目的工作流程,或者使用一个别人定义好的。 140 | 141 | 典型的git flow流程大概是这样的: 142 | 143 | git-flow 144 | 145 | 目前比较流行的git flow包含如下几种分支类型。 146 | ### hotfix 147 | 工作分支,用于修复线上bug 148 | ### feature 149 | 工作分支,用于开发新的功能 150 | ### develop 151 | 合并分支,用于合并hotfix和feature。 develop分支恐怕是我们用的最多的分支。 152 | develop汇总了所有的功能分支代码。当develop代码达到稳定状态(测试完成),将其合并到release分支。 153 | 154 | > develop其实包含了所有的功能分支,包括未被测试的分支。 155 | 当分支被测试完毕才可以将其合并到release。所有的分支只有master和develop是长期分支。 156 | ### release 157 | 合并分支,用于发布某一个版本,通常采用semver。 158 | release分支通常不做任何代码修改的,仅仅修改版本号,构建信息等元数据。但是其提供了发布生产最后修改代码的机会,也就是 159 | 说你可以正在这里进行`小范围`的代码修改。 160 | 161 | ### master 162 | 应该是随时可以发布的代码(这点非常重要),不可对其进行任何提交,只可以从hotfix或者release合并。 163 | 164 | git flow是被应用广泛的一种分支管理模型,受到很多开发者的追捧。 165 | 但是其复杂性确并不被所有开发者买单,google就没有采用git flow的开发模式。 166 | 这有一篇文章,讲的就是git flow的反模式。[anti git-flow](http://endoflineblog.com/gitflow-considered-harmful) 167 | 168 | 如果合并到develop中的一个分支没有通过测试,无法发布,其他分支需要发布怎么办? 169 | 170 | 这就需要checkout develop,然后revert指定feature分支合并的commit id。这也就是为什么 171 | git flow 合并分支需要非快速合并的原因(--no-ff) 172 | 173 | 更详细的git flow的使用方法见文末的参考文献。 174 | ## git commit msg 175 | 好的提交不仅方便查看,由于其一致的数据格式,还可以用于其他处理的数据源。 176 | 如根据commit msg,生成changelog。 177 | 178 | 下面介绍一种被广泛使用的提交规范 179 | ### angular commit message conventions 180 | 181 | 由必选的几个部分和可选的部分组成的简短的git提交信息规范。 182 | 183 | 形如: 184 | 185 | ``` 186 | feat: 增加一个新特性 187 | fix(module-a): 修复一个bug #89123 188 | doc: 增加文档 189 | chore: 增加注释 190 | 191 | ``` 192 | 详细介绍可以参考文末的参考资料。 193 | ## 插件 194 | 好的工具不仅可以提高效率,减少失误,配合起来使用更能达到意想不到的效果。 195 | 下面我推荐下我个人正在使用的一些git插件。 196 | 197 | - [git](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugin:git) 198 | - [git-flow](https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/git-flow) 199 | - [commitzen](https://github.com/commitizen/cz-cli) 200 | - [coventional-changelog](https://github.com/commitizen/cz-conventional-changelog) 201 | - [husky](https://github.com/typicode/husky) 202 | - [git blame](https://github.com/Sertion/vscode-gitblame) or [git lens](https://github.com/eamodio/vscode-gitlens) 203 | 204 | ## 常见场景及解决方案 205 | 206 | > 前提是需要理解上面的基本概念 207 | 208 | 1. 如何回退某个提交的内容? 209 | 210 | 如果需要回滚某个提交,可以提交一个新的提交,将那次提交的内容给反向抵消掉。 211 | 这正是git revert commit-id 所做的。 212 | 213 | 2. 如何回退到某次提交? 214 | 215 | 理论上我们可以通过git revert HEAD , git revert HEAD^1 ... 216 | 但是这样比较麻烦,你可以通过git reset commit-id完成。 217 | 218 | 这样操作和git revert是有区别的。 它直接将指针指向commit-id,强制改变了提交历史。 219 | 而不是创建新的提交,这样做会有风险,因此推送到远程的时候需要强制操作。 git push --force 220 | 221 | > 如果git reset 之后想要回到reset之前的版本。可以通过git reflog查看,然后再次通过git reset commit-id回滚。 222 | 如果把git commit 看成是游戏存档的话, 那么git reflog就是存档记录 223 | 224 | 3. 我在开发一个功能,此时线上有个bug。但是功能写了一半,不能提交,怎么办? 225 | 226 | 可以通过git stash将工作区的内容存储起来。然后切换新分支完成bug修复,再次切换到未完成的分支,执行 227 | git stash pop 将未完成的工作还原到工作区。 228 | 229 | 4. 如何解决冲突以及减少冲突? 230 | 231 | 参考 [git 实践之冲突管理](https://my.oschina.net/wanjubang/blog/1502709) 232 | 233 | 更多场景及解决方案可以[issue](https://github.com/azl397985856/git/issues) 或者 [pr](https://github.com/azl397985856/git/pulls) 给我。 234 | 235 | ## 参考资料 236 | [git-flow](https://www.git-tower.com/learn/git/ebook/en/command-line/advanced-topics/git-flow) 237 | 238 | [a-successful-git-branching-model](http://nvie.com/posts/a-successful-git-branching-model/) 239 | 240 | [Git-Internals-Git-Objects](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects) 241 | 242 | [Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 243 | 244 | [git-recipes](https://github.com/geeeeeeeeek/git-recipes) 245 | 246 | [git奇淫技巧](https://github.com/521xueweihan/git-tips) 247 | 248 | > 上述参考资料中git-flow 和 Git-Internals-Git-Objects 有对应中文版,可以直接修改url中的en为cn查看中文内容。 249 | -------------------------------------------------------------------------------- /illustrations/areas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azl397985856/git/eeb3e2626178f0b38634820e3111e3355c91fb36/illustrations/areas.png -------------------------------------------------------------------------------- /illustrations/git-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azl397985856/git/eeb3e2626178f0b38634820e3111e3355c91fb36/illustrations/git-flow.png -------------------------------------------------------------------------------- /illustrations/lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azl397985856/git/eeb3e2626178f0b38634820e3111e3355c91fb36/illustrations/lifecycle.png --------------------------------------------------------------------------------