Git的使用以及Git协同工作流的选择

Git的使用以及Git协同工作流的选择

[TOC]

为什么要使用Git

  • Git 是一个分布式的版本管理工具,而且可以是单机版的,所以,你在没有网络的时候同样可以提交(commit)代码。对于我们来说,这意味着在出差途中或是没有网络的环境中依然可以工作写代码。
  • Git 从一个分支向另一个分支合并代码的时候,会把要合并的分支上的所有提交一个一个应用到被合并的分支上,合并后也能看得到整个代码的变更记录。而其他的版本管理工具则不能。
  • Git 切换分支的时候通常很快。不像其他版本管理器,每个分支一份拷贝
  • Git 有很多非常有用的命令,让你可以很方便地工作。
  1. git stash命令,可以把当前没有完成的事先暂存一下,然后去忙别的事。
  2. git cherry-pick命令可以让你有选择地合并提交。
  3. git grep $regexp $(git rev-list --all)可以用来在所有的提交中找代码。因为都是本地操作,所以你会觉得飞快。
  4. ... ...
  • 除此之外,由 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
  • (可选)本地安装图形化工具SourceTree
  • (可选)IDE中安装git插件并配置
  • 在github 创建代码库
  • 复制项目地址 比如:[email protected]:themis/themis.git
  • git clone [email protected]: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 这样的中心工作流一样工作的。很多程序员都是在采用这样的工作方式。

这个过程一般是下面这个样子的。

  1. 从服务器上做git pull origin master把代码同步下来。
  2. 改完后,git commit到本地仓库中。
  3. 然后git push origin master到远程仓库中,这样其他同学就可以得到你的代码了。
  4. 如果在第 3 步发现 push 失败,因为别人已经提交了,那么你需要先把服务器上的代码给 pull 下来。

功能分支协同工作流

上面的那种方式有一个问题,就是大家都在一个主干上开发程序,对于小团队或是小项目你可以这么干,但是对比较大的项目或是人比较多的团队,这么干就会有很多问题。

最大的问题就是代码可能干扰太严重。尤其是,我们想安安静静地开发一个功能时,我们想把各个功能的代码变动隔离开来,同时各个功能又会有多个开发人员在开发。

这时,我们不想让各个功能的开发人员都在 Master 分支上共享他们的代码。我们想要的协同方式是这样的:同时开发一个功能的开发人员可以分享各自的代码,但是不会把代码分享给开发其他功能的开发人员,直到整个功能开发完毕后,才会分享给其他的开发人员(也就是进入主干分支)。

因此,我们引入“功能分支”。这个协同工作流的开发过程如下。

  1. 首先使用 git checkout -b new-feature 创建 “new-feature”分支。
  2. 然后共同开发这个功能的程序员就在这个分支上工作,进行 add、commit 等操作。
  3. 然后通过 git push -u origin new-feature 把分支代码 push 到服务器上。
  4. 其他程序员可以通过git pull --rebase来拿到最新的这个分支的代码。
  5. 最后通过 Pull Request 的方式做完 Code Review 后合并到 Master 分支上。

就像上面这个图显示的一样,紫色的分支就是功能分支,合并后就会像上面这个样子。

GitFlow 协同工作流

在真实的生产过程中,前面的协同工作流还是不能满足工作的要求。这主要因为我们的生产过程是比较复杂的,软件生产中会有各式各样的问题,并要面对不同的环境。我们要在不停地开发新代码的同时,维护线上的代码,于是,就有了下面这些需求。

  1. 希望有一个分支是非常干净的,上面是可以发布的代码,上面的改动永远都是可以发布到生产环境中的。这个分支上不能有中间开发过程中不可以上生产线的代码提交。

  2. 希望当代码达到可以上线的状态时,也就是在 alpha/beta release 时,在测试和交付的过程中,依然可以开发下一个版本的代码。

  3. 最后,对于已经发布的代码,也会有一些 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 协同工作流

  1. 引入环境分支,如下图所示,其包含了开发环境(master)、预发布(Pre-Production)和生产(Production)分支。

上游优先原则:开发分支是预发分支的"上游",预发分支又是生产分支的"上游"。代码的变化,必须由"上游"向"下游"发展。比如,生产环境出现了bug,这时就要新建一个功能分支,先把它合并到master,确认没有问题,再cherry-pick到pre-production,这一步也没有问题,才进入production。

只有紧急情况,才允许跳过上游,直接合并到下游分支。

  1. (不一定有这个需求)而有些时候,我们还会有不同版本的发布,所以,还需要有各种 release 的分支。如下图所示。Master 分支是一个 roadmap 分支,然后,一旦稳定了就建稳定版的分支,如 2.3.stable 分支和 2.4.stable 分支,其中可以 cherry-pick master 分支上的一些改动过去。

这样也就解决了两个问题:

  1. 环境和代码分支对应的问题;
  2. 版本和代码分支对应的问题。

我的选择

使用GitLab 协同工作流

其他操作

忽略特殊文件

  • 用.gitignore文件处理
  • 参考 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013758404317281e54b6f5375640abbb11e67be4cd49e0000

本地修改不提交到远程仓库

本地修改不提交到远程仓库

git update-index --assume-unchanged 文件名

取消本地忽略

git update-index --no-assume-unchanged 文件名

cherry-pick

  • 选择某一个分支中的一个或几个commit(s)来进行操作
  • 参考 https://www.jianshu.com/p/8fbb12781d05

参考附录

  1. 廖雪峰的git教程 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
  2. Git工作流
    http://www.ruanyifeng.com/blog/2015/12/git-workflow.html
  3. 远程仓库版本回退方法
    http://blog.csdn.net/fuchaosz/article/details/52170105

你可能感兴趣的:(Git的使用以及Git协同工作流的选择)