Git的使用以及Git协同工作流的选择
[TOC]
为什么要使用Git
- Git 是一个分布式的版本管理工具,而且可以是单机版的,所以,你在没有网络的时候同样可以提交(commit)代码。对于我们来说,这意味着在出差途中或是没有网络的环境中依然可以工作写代码。
- Git 从一个分支向另一个分支合并代码的时候,会把要合并的分支上的所有提交一个一个应用到被合并的分支上,合并后也能看得到整个代码的变更记录。而其他的版本管理工具则不能。
- Git 切换分支的时候通常很快。不像其他版本管理器,每个分支一份拷贝
- Git 有很多非常有用的命令,让你可以很方便地工作。
-
git stash
命令,可以把当前没有完成的事先暂存一下,然后去忙别的事。 -
git cherry-pick
命令可以让你有选择地合并提交。 -
git grep $regexp $(git rev-list --all)
可以用来在所有的提交中找代码。因为都是本地操作,所以你会觉得飞快。 - ... ...
- 除此之外,由 Git 衍生出来的 GitHub/GitLab 可以帮你很好地管理编程工作,比如 wiki、fork、pull request、issue……集成了与编程相关的工作。
概念
版本库 Repository
理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。 简单理解成 .git目录。
工作区 working directory
就是你在电脑里能看到的目录,比如我的test目录就是一个工作区:
暂存区 stage/index
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区。
[图片上传失败...(image-dd4519-1520338302455)]
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
[图片上传失败...(image-f3ca47-1520338302455)]
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
远程仓库 origin repository
远程服务器上的git仓库, 让其他人通过该仓库来协作。
分支 Branch
因为创建、合并和删除分支非???,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支。
标签 Tag
在branch上面打tag, 可以用来做版本管理。
HEAD指针
HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭
用Shell还是GUI
- 图形化工具 : SoureTree, 或者IDE里面的git插件
- 图形化界面更加直观, 敲命令更快, 看个人喜好。
日常场景
初次使用
- 本地安装git
- (可?。┍镜匕沧巴夹位ぞ逽ourceTree
- (可?。㊣DE中安装git插件并配置
- 在github 创建代码库
- 复制项目地址 比如:git@git.xxx.com:themis/themis.git
- git clone git@git.xxx.com:themis/themis.git。 Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。ssh需要用到公私钥,https需要用户名密码。
提交文件
git add file1.txt
git add file2.txt file3.txt --将文件添加到暂存区
git commit -m "add 3 files." --将暂存区内容提交到本地
git push origin master -- 将本地内容推送到远程
创建分支,切换分支,合并分支,删除分支
git branch dev -创建
git checkout dev -切换
git branch -查看当前分支
git merge branch-name -合并某分支到当前分支
git branch -d branch-name - 删除本地分支
git push origin branch-name - 推送到远程仓库
注意:如果此分支是需要走cd发布的,请在phoebus平台上创建,不然平台无法获取新建的分支。
合并分支中的冲突解决
git checkout -b feature1
修改readme.txt
git add readme.txt
git commit -m '11'
git checkout master
git add readme.txt
git commit -m '22'
git merge feature1 -- 这一步就冲突了,修改完再提交
版本回退
回退本地版本
git reset --hard commit-id
强制推送到远程分支
git push -f
参考附录3
多人协作
多人协作的工作模式通常是这样:
1. 首先,可以试图用git push origin branch-name推送自己的修改;
2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
3. 如果合并有冲突,则解决冲突,并在本地提交;
4. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
那么 多人多版本多环境协作怎么搞?这时候就需要有一个工作流来指导我们进行代码管理。
工作流
中心式协同工作流
Git 是可以像 SVN 这样的中心工作流一样工作的。很多程序员都是在采用这样的工作方式。
这个过程一般是下面这个样子的。
- 从服务器上做git pull origin master把代码同步下来。
- 改完后,git commit到本地仓库中。
- 然后git push origin master到远程仓库中,这样其他同学就可以得到你的代码了。
- 如果在第 3 步发现 push 失败,因为别人已经提交了,那么你需要先把服务器上的代码给 pull 下来。
功能分支协同工作流
上面的那种方式有一个问题,就是大家都在一个主干上开发程序,对于小团队或是小项目你可以这么干,但是对比较大的项目或是人比较多的团队,这么干就会有很多问题。
最大的问题就是代码可能干扰太严重。尤其是,我们想安安静静地开发一个功能时,我们想把各个功能的代码变动隔离开来,同时各个功能又会有多个开发人员在开发。
这时,我们不想让各个功能的开发人员都在 Master 分支上共享他们的代码。我们想要的协同方式是这样的:同时开发一个功能的开发人员可以分享各自的代码,但是不会把代码分享给开发其他功能的开发人员,直到整个功能开发完毕后,才会分享给其他的开发人员(也就是进入主干分支)。
因此,我们引入“功能分支”。这个协同工作流的开发过程如下。
- 首先使用 git checkout -b new-feature 创建 “new-feature”分支。
- 然后共同开发这个功能的程序员就在这个分支上工作,进行 add、commit 等操作。
- 然后通过 git push -u origin new-feature 把分支代码 push 到服务器上。
- 其他程序员可以通过git pull --rebase来拿到最新的这个分支的代码。
- 最后通过 Pull Request 的方式做完 Code Review 后合并到 Master 分支上。
就像上面这个图显示的一样,紫色的分支就是功能分支,合并后就会像上面这个样子。
GitFlow 协同工作流
在真实的生产过程中,前面的协同工作流还是不能满足工作的要求。这主要因为我们的生产过程是比较复杂的,软件生产中会有各式各样的问题,并要面对不同的环境。我们要在不停地开发新代码的同时,维护线上的代码,于是,就有了下面这些需求。
希望有一个分支是非常干净的,上面是可以发布的代码,上面的改动永远都是可以发布到生产环境中的。这个分支上不能有中间开发过程中不可以上生产线的代码提交。
希望当代码达到可以上线的状态时,也就是在 alpha/beta release 时,在测试和交付的过程中,依然可以开发下一个版本的代码。
最后,对于已经发布的代码,也会有一些 Bug-fix 的改动,不会将正在开发的代码提交到生产线上去。
面对这些需求,前面的那些协同方式就都不行了。因为我们不仅是要在整个团队中共享代码,我们要的更是管理好不同环境下的代码不互相干扰。说得技术一点儿就是,要管理好代码与环境的一致性。
为了解决这些问题,GitFlow 协同工作流就出来了。
整个代码库中一共有五种分支。
- (长期)Master 分支。也就是主干分支,用作发布环境,上面的每一次提交都是可以发布的。
- (短期) Feature 分支。也就是功能分支,用于开发功能,其对应的是开发环境。
- (长期)Developer 分支。是开发分支,一旦功能开发完成,就向 Developer 分支合并,合并完成后,删除功能分支。这个分支对应的是集成测试环境。
- (短期) Release 分支。当 Developer 分支测试达到可以发布状态时,开出一个 Release 分支来,然后做发布前的准备工作。这个分支对应的是预发环境。之所以需要这个 Release 分支,是我们的开发可以继续向前,不会因为要发布而被 block 住而不能提交。一旦 Release 分支上的代码达到可以上线的状态,那么需要把 Release 分支向 Master 分支和 Developer 分支同时合并,以保证代码的一致性。然后再把 Release 分支删除掉。
- (短期)Hotfix 分支。是用于处理生产线上代码的 Bug-fix,每个线上代码的 Bug-fix 都需要开一个 Hotfix 分支,完成后,向 Developer 分支和 Master 分支上合并。合并完成后,删除 Hotfix 分支。
Git flow的优点是清晰可控,缺点是相对复杂,需要同时维护两个长期分支。具体了解可以参考附录2。
GitHub 协同工作流
过于简单,不适合。具体了解可以参考附录2。
GitLab 协同工作流
- 引入环境分支,如下图所示,其包含了开发环境(master)、预发布(Pre-Production)和生产(Production)分支。
上游优先原则:开发分支是预发分支的"上游",预发分支又是生产分支的"上游"。代码的变化,必须由"上游"向"下游"发展。比如,生产环境出现了bug,这时就要新建一个功能分支,先把它合并到master,确认没有问题,再cherry-pick到pre-production,这一步也没有问题,才进入production。
只有紧急情况,才允许跳过上游,直接合并到下游分支。
- (不一定有这个需求)而有些时候,我们还会有不同版本的发布,所以,还需要有各种 release 的分支。如下图所示。Master 分支是一个 roadmap 分支,然后,一旦稳定了就建稳定版的分支,如 2.3.stable 分支和 2.4.stable 分支,其中可以 cherry-pick master 分支上的一些改动过去。
这样也就解决了两个问题:
- 环境和代码分支对应的问题;
- 版本和代码分支对应的问题。
我的选择
使用GitLab 协同工作流
其他操作
忽略特殊文件
- 用.gitignore文件处理
- 参考 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013758404317281e54b6f5375640abbb11e67be4cd49e0000
本地修改不提交到远程仓库
本地修改不提交到远程仓库
git update-index --assume-unchanged 文件名
取消本地忽略
git update-index --no-assume-unchanged 文件名
cherry-pick
- 选择某一个分支中的一个或几个commit(s)来进行操作
- 参考 http://08643.cn/p/8fbb12781d05