Git版本控制与工作流
idjs6295
8年前
<p style="text-align:center"><img src="https://simg.open-open.com/show/63d0ca0caa834f2ddf19ceb206200cd8.gif"></p> <h2><strong>基本概念</strong></h2> <h3><strong>Git是什么?</strong></h3> <p>Git 是 <strong>分布式</strong> 版本控制系统,与SVN类似的 <strong>集中化</strong> 版本控制系统相比,集中化版本控制系统虽然能够令多个团队成员一起协作开发,但有时如果中央服务器宕机的话,谁也无法在宕机期间提交更新和协同开发。甚至有时,中央服务器磁盘故障,恰巧又没有做备份或备份没及时,那就可能有丢失数据的风险。</p> <p>但Git是分布式的版本控制系统,客户端不只是提取最新版本的快照,而且将整个代码仓库镜像复制下来。如果任何协同工作用的服务器发生故障了,也可以用任何一个代码仓库来恢复。而且在协作服务器宕机期间,你也可以提交代码到本地仓库,当协作服务器正常工作后,你再将本地仓库同步到远程仓库。</p> <h3><strong>为什么要使用Git</strong></h3> <ul> <li> <p>能够对文件 <strong>版本控制</strong> 和 <strong>多人协作开发</strong></p> </li> <li> <p>拥有强大的 <strong>分支特性</strong> ,所以能够灵活地以 <strong>不同的工作流</strong> 协同开发</p> </li> <li> <p>分布式版本控制系统,即使协作服务器宕机,也能继续提交代码或文件到本地仓库,当协作服务器恢复正常工作时,再将本地仓库同步到远程仓库。</p> </li> <li> <p>当团队中某个成员完成某个功能时,通过 <strong>pull request</strong> 操作来通知其他团队成员,其他团队成员能够review code后再合并代码。</p> </li> </ul> <h3><strong>Git有哪些特性</strong></h3> <ul> <li> <p>文件三种状态(modified, staged, committed)</p> </li> <li> <p>直接记录快照,而非差异比较</p> </li> <li> <p>多数操作仅添加操作</p> </li> <li> <p>近乎所有操作都是本地执行</p> </li> <li> <p>时刻保持数据完整性</p> </li> </ul> <p>有关以上特性的详细解释,请查看Pro git的 git基础章节</p> <h3><strong>Git基本工作流程</strong></h3> <ol> <li> <p>在git版本控制的目录下修改某个文件</p> </li> <li> <p>使用 git add 命令对修改后的文件快照,保存到暂存区域</p> </li> <li> <p>使用 git commit 命令提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中</p> </li> </ol> <h3><strong>Git基本技巧</strong></h3> <ul> <li> <p>自动补全</p> </li> <li> <p>Git 命令别名</p> </li> </ul> <p>关于具体如何使用自动补全和命名别名技巧,请查看Pro git的 技巧和窍门</p> <h2><strong>Git版本控制</strong></h2> <h3><strong>创建仓库</strong></h3> <ul> <li> <p>git init</p> </li> <li> <p>git clone</p> </li> <li> <p>git config</p> </li> </ul> <h3><strong>保存修改</strong></h3> <ul> <li> <p>git add</p> </li> <li> <p>git commit</p> </li> </ul> <h3><strong>查看仓库</strong></h3> <ul> <li> <p>git status</p> </li> <li> <p>git log --oneline</p> </li> </ul> <h3><strong>撤销修改</strong></h3> <p>查看之前的commit</p> <ul> <li> <p>git checkout</p> </li> <li> <p>git checkout</p> </li> <li> <p>git checkout</p> </li> </ul> <p>撤销公共修改</p> <ul> <li> <p>git revert</p> </li> </ul> <p>撤销本地修改</p> <ul> <li> <p>git reset</p> </li> <li> <p>git clean</p> </li> </ul> <h3><strong>重写Git历史记录</strong></h3> <ul> <li> <p>git commit --amend</p> </li> <li> <p>git rebase</p> </li> <li> <p>git reflog</p> </li> </ul> <h2><strong>Git协作开发</strong></h2> <h3><strong>分支</strong></h3> <ul> <li> <p>git branch</p> </li> <li> <p>git checkout</p> </li> <li> <p>git merge</p> </li> </ul> <h3><strong>仓库同步</strong></h3> <ul> <li> <p>git remote</p> </li> <li> <p>git fetch</p> </li> <li> <p>git pull</p> </li> <li> <p>git push</p> </li> </ul> <h2><strong>Git工作流</strong></h2> <p>由于git拥有强大的 <strong>分支特性</strong> ,它的工作流比较灵活而缺乏约束,于是参考 Atlassian Git Tutorial 的 Comparing Workflows 章节提供 <strong>四种Git工作流</strong> :</p> <ul> <li> <p>Centralized Workflow</p> </li> <li> <p>Feature Branch Workflow</p> </li> <li> <p>Gitflow Workflow</p> </li> <li> <p>Forking Workflow</p> </li> </ul> <p>以上工作流只是 <strong>参考指南</strong> ,而不是具体规则。你可以根据自己实际情况来选择适合自己的工作流或微调来满足自己的需要。</p> <h2><strong>Centralized Workflow</strong></h2> <p>过渡到分布式版本控制系统看起来像一个艰巨的任务,但如果你充分利用好git的话,你不必改变你既有的工作流,你的团队可以采用与之前使用SVN一样的方式来开发项目。</p> <p>如何工作</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/d3c499ee649d416caa50e013e9f055dc.png"></p> <ol> <li> <p>从远程仓库(central repository)克隆工程到本地仓库(local repository) --- git clone</p> </li> <li> <p>在本地仓库编辑文件和提交更新 --- git add 和 git commit</p> </li> <li> <p>fetch远程仓库已更新的commit到本地仓库和rebase到已更新的commit的上面 --- git fetch 和 git rebase 或 git pull --rebase</p> </li> <li> <p>push本地主分支(master branch)到远程仓库 --- git push</p> </li> </ol> <p><strong>管理冲突</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/b7fd64a769628272a1ce6752fc7b23a2.png"></p> <ul> <li> <p>何时发生冲突:在开发者发布它们功能之前,他们需要fetch远程仓库已更新的commit到本地仓库和rebase到已更新的commit的上面。有时,本地提交与远程提交会发生冲突,git会暂停rebase过程来让你手动解决冲突。</p> </li> <li> <p>如何解决冲突:你可以使用 git status 和 git add 来手动解决合并时冲突。</p> </li> </ul> <h2><strong>Feature Branch Workflow</strong></h2> <p>Feature Branch Workflow的主要思想就是在开发每个功能时都应该创建 <strong>一个独立的分支</strong> 而不只是使用主分支。由于每个分支是独立且互不影响,这就意味着主分支不会包含broken code,对持续集成环境是很有帮助的。</p> <p><strong>如何工作</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/4792d8e1bac48f8b9922193e9a429602.png"></p> <ol> <li> <p>仍然使用远程仓库(central repository)和主分支(master branch)仍记录官方工程的历史</p> </li> <li> <p>开发者每次开发新功能时都创建一个新分支 --- git checkout -b</p> </li> <li> <p>Feature branches应该推送到远程仓库(central repository) --- git push</p> </li> <li> <p>发送pull request来请求管理员能否合并到主分支(master branch)</p> </li> <li> <p>发布新功能到远程仓库(central repository)</p> </li> </ol> <p>Pull Request</p> <p>Pull request是一种当开发者完成一个新功能后向其他团队成员发送通知的机制。它的使用过程如下:</p> <ul> <li> <p>开发者可以通过Github或Bitbucket发送pull request</p> </li> </ul> <p style="text-align:center"><img src="https://simg.open-open.com/show/99c3a22ea7b1f1c6621fe99677df1de0.png"></p> <ul> <li> <p>其他的团队成员审查、讨论和修改代码</p> </li> <li> <p>项目维护者合并新增功能分支到主分支(master branch),然后关闭pull request</p> </li> </ul> <h2><strong>Gitflow Workflow</strong></h2> <p>Feature Branch Workflow是一种非常灵活的开发方式。对于一些规模比较大的团队,最好就是给特定的分支赋予不同的角色。除了 <strong>功能分支(feature branch)</strong> ,Gitflow Workflow还使用独立的分支来 <strong>准备发布(preparing)</strong> , <strong>维护(maintaining)</strong> , 和 <strong>记录版本(recording releases)</strong> 。下面我会逐个介绍这个几个分支:Historical Branches、Feature Branches、Release Branches和Maintenance Branches。</p> <p><strong>Historical Branches</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c57903e5f0886f79d63698346c7cfb3d.png"></p> <ul> <li> <p>master分支保存官方发布历史</p> </li> <li> <p>develop分支衍生出各个feature分支</p> </li> </ul> <p><strong>Feature Branches</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/e1de50dcfc400327a7e209c099ed677a.png"></p> <ul> <li> <p>feature分支使用develop分支作为它们的父类分支</p> </li> <li> <p>当其中一个feature分支完成后,它会合并会develop分支</p> </li> <li> <p>feature分支应该从不与master分支直接交互</p> </li> </ul> <p><strong>Release Branches</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/8417e3b64b6146ff515ae0a854756bc5.png"></p> <ul> <li> <p>release分支主要用来清理释放、测试和更新文档</p> </li> <li> <p>一旦develop分支获得足够的功能来发布时,你可以从develop衍生出一个release分支</p> </li> <li> <p>一旦准备好上架,release合并到master分支并且标记一个版本号</p> </li> <li> <p>另外,还需要合并回develop分支</p> </li> </ul> <p><strong>Maintenance Branches</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/2df12fdeeac4eb4bb2ed32a854e2702e.png"></p> <ul> <li> <p>maintenance分支用来快速给已发布产品修复bug或微调功能</p> </li> <li> <p>它从master分支直接衍生出来</p> </li> <li> <p>一旦完成修复bug,它应该合并回master分支和develop分支</p> </li> <li> <p>master应该被标记一个新的版本号</p> </li> </ul> <p><strong>标记Tags</strong></p> <p>使用两个命令来给master分支标记版本号:</p> <ul> <li> <p>git tag -a 0.1 -m "Initial public release" master</p> </li> <li> <p>git push origin master --tags</p> </li> </ul> <h2><strong>Forking Workflow</strong></h2> <p>Forking Workflow与以上讨论的工作流很不同,一个很重要的 <strong>区别</strong> 就是它不只是多个开发共享一个远程仓库(central repository),而是每个开发者都拥有一个独立的服务端仓库。也就是说每个contributor都有两个仓库:本地私有的仓库和远程共享的仓库。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/6490a81a6697757923ade595a45f117a.png"></p> <p>Forking Workflow这种工作流主要好处就是每个开发者都拥有自己的远程仓库,可以将提交的commits推送到自己的远程仓库,但只有工程维护者才有权限push提交的commits到官方的仓库,其他开发者在没有授权的情况下不能push。Github很多 <strong>开源项目</strong> 都是采用Forking Workflow工作流。</p> <p><strong>如何工作</strong></p> <ol> <li> <p>在服务器上有一个官方公共的仓库</p> <p>开发者fork官方仓库来创建它的拷贝,然后存放在服务器上</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/8ba625ba192cf966c0592c2ec0af01c4.png"></p> </li> <li> <p>当开发者准备好发布本地的commit时,他们push commit到他们自己的公共仓库</p> </li> <li> <p>在自己的公共仓库发送一个pull request到官方仓库</p> </li> <li> <p>维护者pull贡献者的commit到他自己的本地仓库</p> </li> <li> <p>审查代码确保它不会破坏工程,合并它到本地仓库的master分支</p> </li> <li> <p>push master分支到服务器上的官方仓库</p> </li> <li> <p>其他开发者应该同步官方仓库。</p> </li> </ol> <p> </p> <p> </p> <p>来自:http://www.cocoachina.com/ios/20161102/17925.html</p> <p> </p>