* Git版本控制、分支策略与代码评审
<https://blog.csdn.net/nklinsirui/article/details/80303605#git版本控制分支策略与代码评审>
* Git介绍 <https://blog.csdn.net/nklinsirui/article/details/80303605#git介绍>
* Git工具与代码托管网站
<https://blog.csdn.net/nklinsirui/article/details/80303605#git工具与代码托管网站>
* 在Windows上安装使用Git
<https://blog.csdn.net/nklinsirui/article/details/80303605#在windows上安装使用git>
* IDE支持Git
<https://blog.csdn.net/nklinsirui/article/details/80303605#ide支持git>
* 代码托管网站 <https://blog.csdn.net/nklinsirui/article/details/80303605#代码托管网站>
* Git原理 <https://blog.csdn.net/nklinsirui/article/details/80303605#git原理>
* Git工作流 <https://blog.csdn.net/nklinsirui/article/details/80303605#git工作流>
* Git 分支 <https://blog.csdn.net/nklinsirui/article/details/80303605#git-分支>
* 概述 <https://blog.csdn.net/nklinsirui/article/details/80303605#概述>
* 理解如何使用Git分支
<https://blog.csdn.net/nklinsirui/article/details/80303605#理解如何使用git分支>
* Git常用命令 <https://blog.csdn.net/nklinsirui/article/details/80303605#git常用命令>
* 参考文档 <https://blog.csdn.net/nklinsirui/article/details/80303605#参考文档>
* Git使用场景 <https://blog.csdn.net/nklinsirui/article/details/80303605#git使用场景>
* 场景1: 在GitLab上新建一个repository
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景1-在gitlab上新建一个repository>
* 场景2:将GitLab上一个repository clone到本地
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景2将gitlab上一个repository-clone到本地>
* 场景3:创建一个本地分支
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景3创建一个本地分支>
* 场景4:将本地分支的改动push到GitLab
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景4将本地分支的改动push到gitlab>
* 场景5:用户A/B同时修改同一个文件,A先提交,B后提交,解决冲突后push到GitLab
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景5用户ab同时修改同一个文件a先提交b后提交解决冲突后push到gitlab>
* 场景6:在本地改动后,在git add 前回退
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景6在本地改动后在git-add-前回退>
* 场景7:在本地改动后,在git push 前回退
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景7在本地改动后在git-push-前回退>
* 场景8:在本地改动后,在git push后回退
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景8在本地改动后在git-push后回退>
* 场景9:查看文件修改历史
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景9查看文件修改历史>
* 场景10:在GitLab上设置分支保护,要求只有通过merge request才能合并代码
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景10在gitlab上设置分支保护要求只有通过merge-request才能合并代码>
* 场景11:本地改动后,push到本地分支,然后在GitLab上发起merge request
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景11本地改动后push到本地分支然后在gitlab上发起merge-request>
* 场景12:代码审查,通过merge request
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景12代码审查通过merge-request>
* 场景13:代码审查,拒绝merge request
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景13代码审查拒绝merge-request>
* 场景14:将本地的一个新项目放在GitLab上
<https://blog.csdn.net/nklinsirui/article/details/80303605#场景14将本地的一个新项目放在gitlab上>
* 使用GitHub来学习提升
<https://blog.csdn.net/nklinsirui/article/details/80303605#使用github来学习提升>
* 分支策略 <https://blog.csdn.net/nklinsirui/article/details/80303605#分支策略>
* 主流分支策略比较
<https://blog.csdn.net/nklinsirui/article/details/80303605#主流分支策略比较>
* 如何选择分支策略
<https://blog.csdn.net/nklinsirui/article/details/80303605#如何选择分支策略>
* 代码评审 <https://blog.csdn.net/nklinsirui/article/details/80303605#代码评审>
* 思考: 什么文件不应该放在Git上?
<https://blog.csdn.net/nklinsirui/article/details/80303605#思考-什么文件不应该放在git上>


Git版本控制、分支策略与代码评审

Git介绍

* Git是一种免费的、开源的分布式版本控制系统(DVCS)
* Git是目前使用最为广泛的版本控制系统
* Git是由Linus Torvalds开发的 (这位IT界的大神同时也是Linux的作者)
* Git的第一个版本(v0.99)在2005年7月发布,最新版本是v2.17(截止2018年4月)
* Git支持Windows, Linux/Unix, Mac
* 和商业版本控制系统相比,Git免费、开源且更强大、稳定、快速
* 和传统版本控制系统(比如CVS, SVN)相比,Git具有支持轻量级分支、分布式开发、高性能等优点。
* Git支持命令行操作,可以非常方便地集成到CI/CD pipeline中
参考文档:

*
https://en.wikipedia.org/wiki/Git <https://en.wikipedia.org/wiki/Git>

*
Git官网: https://git-scm.com <https://git-scm.com>

Git工具与代码托管网站

在Windows上安装使用Git

登录Git官网: https://git-scm.com/ <https://git-scm.com/> 下载Git for
Windows,安装后有3个程序:

* Git Bash (模拟Linux终端)
* Git CMD (Windows终端)
* Git GUI (Windows界面)
推荐使用Git Bash,Git CMD和Git GUI可以忽略。

在Linux/Unix和Mac上使用Git和在Windows上使用Git Bash一样,不再赘述。

IDE支持Git

现在主流的IDE(比如Intellij Idea和Eclipse) 都对Git有非常好的支持。

推荐通过IDE + Git Bash 方法来使用Git。

代码托管网站

* 全世界最大的代码托管(同性交友)网站: https://github.com/ <https://github.com/>
* 可以免费搭建自己的代码托管网站的GitLab: https://gitlab.com/ <https://gitlab.com/>
* Atlassian公司全家桶的过气网红: https://bitbucket.org/ <https://bitbucket.org/>
如何选择?

* 土豪自己搭建GitHub Enterprise
* Atlassian铁粉用BitBucket
* 中产用GitLab Enterprise
* 屌丝自己搭建GitLab CE (我是屌丝我自豪)
* 最屌丝用国内的代码托管网站…
Git原理

Git工作流

下图列出了一个简明的Git工作流:



Git 分支

概述

* 分支(branch)可以理解为是仓库(repository)的一种隔离视图。
*
分支的目的为了支持多人、多版本开发。

*
Git支持多分支开发,并鼓励使用本地多分支,这些分支之间是彼此完全独立的。

* 和传统的版本控制工具(比如CSV, SVN)相比,Git对分支的隔离是逻辑隔离而不是物理隔离,这意味着创建分支非常快速、存储分支不会占用过多磁盘空间
* 常见的分支操作包括:创建分支、切换分支、合并分支、删除分支。
参考文档:

* https://git-scm.com/about/branching-and-merging
<https://git-scm.com/about/branching-and-merging>
理解如何使用Git分支

这里以GitHub Flow为例 来演示常见的分支操作。

打开GitHub Flow <https://guides.github.com/introduction/flow/>
,点击动画上的不同区域来理解常见的分支操作:

*
创建分支

* 给分支名取一个简短且有意义的名字
*
提交改动

*
填写有意义的commit message: what & why

*
推荐的commit message格式为 <Item Id>: <Description> ,比如:

512: 增加了对NFS的支持

*
发起合并请求

* 同时发起code review和讨论
* 不经过review的代码不允许合并进public branch
*
代码评审和讨论

* 审查代码是否满足功能、规范、测试结果、测试覆盖等要求
* 审查合格才允许合并合进public branch,不合格的代码退回重新修改
* 鼓励使用同行评审(Peer Review)而不是上下级评审,鼓励积极反馈、互动
* 评审对事不对人,多建议,不批评,不指责
* 评审过程对reviewer和代码提交者双方都是一个学习提升的过程
*
部署

* 使用经过完整测试的分支来部署到生产环境
* 部署后发生问题需要回退时,用上一个版本进行回退
*
合并回master分支

* 部署成功,没有问题后才合并到master分支
GitHub Flow是一种非常好的Git分支策略,但不是唯一的Git分支策略。

在后面的分支策略中会对Git分支策略作深入探讨。

Git常用命令

参考文档

* git no deep shit: http://rogerdudler.github.io/git-guide/
<http://rogerdudler.github.io/git-guide/>
* 常用Git命令清单(阮一峰): http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html
<http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html>
* git操作规范(Miss_Ye): https://segmentfault.com/a/1190000014461898
<https://segmentfault.com/a/1190000014461898>
除了查看网上的参考文档之外,还可以在Git Bash中执行git --help 或 git <command> --help 来查看Git帮助文档。

Git使用场景

下面列出常用的Git使用场景。

场景1: 在GitLab上新建一个repository

如果不想让公众都能看到你的代码,需要将repository设置为private,并将相应权限授给团队成员。

强烈推荐为每个repository创建README.md和.gitignore文件。

强烈推荐对repository的public branch进行保护,只有通过merge request才能合并代码进public branch。

场景2:将GitLab上一个repository clone到本地

GitLab支持SSH和HTTP(S)两种方式。

* SSH方式需要将本地的SSH public key添加到GitLab账号的setting中
* HTTP(S)方式第一次push到GitLab时需要提供用户名和密码登陆
设置git config的user.name 和 user.email :
# 查看git config git config --list # 设置Global的user.name和user.email git config
--global user.name <user_name> git config --global user.email <user_email>#
查看git config确认 git config --list
从GitLab上clone一个repository到本地:
# SSH 方式 git clone <repo_git_url> # HTTP 方式 git clone <repo_http_url>
克隆后的缺省分支是GitLab repository上的缺省分支,一般是master分支。

场景3:创建一个本地分支

Git创建分支时,缺省从当前分支(base branch)来创建,如果当前分支不是想要的base branch,需要先切换分支。
# 切换当前分支(base branch) git checkout <base_branch> # 创建一个新分支,并切换到该分支 git
checkout -b <new_branch>
场景4:将本地分支的改动push到GitLab
# 更新working directory git pull # 改动代码...此处省略2048个字 # 查看working tree状态 git
status# 比较改动前后,查看改动了什么 (用IDE来比较更加直观) git diff <file> # 添加新建的文件到Git Stage中 git
add <file># 或添加全部新建的文件到Git Stage中 git add . # 提交改动到local repository git commit
-m"<commit_message>" # 推送到remote repository,创建remote new branch,并设置upstream
reference git push -u origin <new_branch>
如果第一次push时不通过-u 来push新的branch,在git pull时会提示要先设置upstream reference。
# 设置upstream reference git branch --set-upstream-to=origin/<branch> <branch>
之后的push可以不需要再加-u参数:
git push origin <branch>
场景5:用户A/B同时修改同一个文件,A先提交,B后提交,解决冲突后push到GitLab

此时B在git push 时会遇到错误,错误信息为:

error: failed to push some refs to …
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., ‘git pull …’) before pushing again.
hint: See the ‘Note about fast-forwards’ in ‘git push –help’ for details.

B执行git pull 试图自动合并A先前提交的改动,自动合并失败的情况下需要手工合并:

Auto-merging …
CONFLICT (content): Merge conflict in …
Automatic merge failed; fix conflicts and then commit the result.

B打开并编辑发生冲突的文件,手工修改后,保存文件。

参照场景4,重新提交完成合并冲突(合并冲突也是一种改动)的文件到GitLab。

场景6:在本地改动后,在git add 前回退

撤销本地改动:
git checkout -- <file>
推荐使用IDE的revert功能,更加简单直观。

Intellij Idea: Version Control -> Local Changes -> Right click the file ->
Revert

场景7:在本地改动后,在git push 前回退

用远程repository强制替换本地文件:
git fetch origin git reset --hard origin/<branch>
推荐使用IDE的Reset功能,更加简单直观。

Intellij Idea: Version Control -> Log -> Right click the last commit marked
with remote branch (origin/) -> Reset current branch to here -> Select “Hard”

场景8:在本地改动后,在git push后回退

方法一:

手工回退后,重新提交改动去覆盖remote branch。

方法二:

使用IDE的revert功能。

Intellij Idea: Version Control -> Log -> Right click the commit -> Revert, and
then commit and push a “revert commit” to override both remote and local
branches.

方法三:
# 查看git commit log,复制要回退的版本commit id git log --graph --oneline --decorate --all
# 将本地回退到指定版本 git reset --hard <commit_id> # 查看working tree状态,此时本地落后于远程1个commit
git status# 强制用本地覆盖远程(危险操作!!) git push -f origin <branch> # 再次查看working
tree状态,此时本地和远程应该同步 git status
推荐使用方法二

方法三比较危险,不推荐使用;强烈建议通过protect branch来防止强制用本地覆盖远程分支。

场景9:查看文件修改历史
# 按树形结构显示 git log --graph --oneline --decorate --all [file] # 按列表显示 git log
--pretty=oneline [file]# 简单粗暴显示 git log [file]
推荐使用IDE的查看历史功能。

Intellij Idea:

* 查看全部文件修改历史:Version Control -> Log
* 查看单个文件修改历史:Right click the file -> Git -> Show history
场景10:在GitLab上设置分支保护,要求只有通过merge request才能合并代码

用Admin或Owner或Master账号登录,打开指定project -> Settings -> Repository -> Protected
Branches

选择要protect的branch (支持wildcard):

* 要求每个人都要通过merge request才能合并代码进入public branch:选择”Allowed to
merge”为”Developers + Masters”,选择”Allow to push” 为”No one“
* 对public branch都要设置protect branch
参考文档:

https://docs.gitlab.com/ee/user/project/protected_branches.html
<https://docs.gitlab.com/ee/user/project/protected_branches.html>

在我使用的GitLab CE 10.6.4 貌似有一个bug,当选择”Allowed to
push”为”Masters“时,Developer角色的用户仍然可以push。
这个问题的原因可能是在向gitlab作git push时,读取的是在Windows上Manage
WindowsCredentials中的另一个较高权限的username,所以gitlab才允许作git push。

场景11:本地改动后,push到本地分支,然后在GitLab上发起merge request

参照场景4,创建一个新的本地分支,改动后push到远程的该分支。

然后在GitLab上发起merge request:

* 打开项目,点击左边的Merge Requests,选择New merge request
* 选择Source branch和Target branch
* 点击”Compare branches and continue“
* 选择Assignee (不要选择Assign to me)
* 如果是临时branch,勾选“Remove source branch when merge request is accepted”
* 检查无误后,点击“Submit merge request”按钮
GitLab CE貌似不能做到防止自己来merge自己的merge request,这一点和GitHub Enterprise还是有差距的。

所以只能流程上要求大家不要merge自己的merge request。

如果发起merge request后,在该merge request关闭之前,继续往source
branch分支push代码,这些commit也会被自动包含在该merge request里。

场景12:代码审查,通过merge request

*
打开项目,点击左边的Merge Request,选择Open查看Open状态的merge request

*
点击Commit查看详细信息

*
点击Changes查看具体的改动

*
写comment,并和代码提交者讨论。

*
审查通过后,点击”Merge”按钮

场景13:代码审查,拒绝merge request

如果审查不通过,写清楚comment,并在和代码提交者讨论后,要求其进行修改。

场景14:将本地的一个新项目放在GitLab上

在GitLab上创建一个同名的空project (不包含任何文件),设置好用户权限。

用Owner/Master角色账号将本地项目push到GitLab:
# 设置Global的user.name和user.email (如果需要) git config --global user.name
<user_name> git config --global user.email <user_email># 将本地项目转成Git项目 git init
# 检查对应的remote repository git remote -v # 添加远程的remote repository git remote add
origin <repo_git_url># 确认remote repository git remote -v # 推送到remote branch git
status git add . git commit -m"Inital commit" git push -u origin <branch>
在我使用的GitLab CE 10.6.4 有一个bug,当创建好一个空的项目后,用Owner账号将本地项目作git push,会遇到”You are
not allowed to push code to this project“的错。

这个问题的原因是在向gitlab作git push时,读取的是在Windows上Manage Windows
Credentials中的另一个错误的username,所以被gitlab拒绝了。

解决的方法是,在Manage Windows Credentials中删除原来的credentials,作git push
时会提示输入用户名和密码,输入owner的用户名和密码后,就可以git push成功了。

这应该是GitLab的一个设计缺陷,也就是GitLab假设在一个GitLab上,你总是只用一个账号来登陆。

参考文档:https://gitlab.com/gitlab-com/support-forum/issues/207
<https://gitlab.com/gitlab-com/support-forum/issues/207>

使用GitHub来学习提升

打开GitHub Explore <https://github.com/explore>
来查看GitHub上最流行的项目,也可以通过搜索来查看比如最流行的Java项目、最流行的JavaScript项目等等。

国内有一些走歪道的程序员上淘宝买GitHub加star服务(鄙视),所以看到一些流行的中文项目时,要持保留态度。


大部分开源软件都把代码托管在GitHub上,可以通过GitHub来clone开源软件的代码到本地作源代码研读,是提升编程的内功的有效方法。如果想加快clone速度可以在
git clone后加上--depth=1 的参数来只clone最新版本。

你也可以把你的点子变成一个项目放到GitHub上,分享给开源社区。

分支策略

分支策略就是在哪个分支上开发、在哪个分支上部署、分支同步和分支合并的原则。

项目团队应该遵循统一的分支策略。

现代主流的分支策略包括:

* Git Flow <http://nvie.com/posts/a-successful-git-branching-model/>
* GitHub Flow <https://guides.github.com/introduction/flow/>
* Trunk based development <https://trunkbaseddevelopment.com/>
注意:这里讲的分支不包括个人的private branch,不管哪种分支策略都要求先在private branch开发测试后再发起merge
request/pull request, 通过代码评审后才能合并进入public branch。

主流分支策略比较

下表对上面的三种现代主流的分支策略进行了比较:



Trunk based development官网将Trunk based development和一些现代主流的分支策略进行了比较:

https://trunkbaseddevelopment.com/alternative-branching-models/
<https://trunkbaseddevelopment.com/alternative-branching-models/>

下面这篇文章也详细地论述了比较了不同的分支策略:

https://www.continuousdeliveryconsulting.com/blog/version-control-strategies/
<https://www.continuousdeliveryconsulting.com/blog/version-control-strategies/>

如何选择分支策略

分支策略没有好坏,适合自己的才最重要。

通常的建议是,项目团队选择一种比较符合自己团队的主流分支策略,在实际工作中加以调整,最终发展成符合团队开发节奏的分支策略。

分支越多,复杂度越大,分支同步与分支合并的成本越大,团队内部的沟通成本也越大。

选择分支策略的原则:

* 始终保持master处在可发布状态
* 始终保持构建处在成功状态
* 降低代码合并的复杂度和风险
* 降低团队沟通成本
* 符合团队的现状
代码评审

前面章节也已经描述了如何作代码评审,这里再对代码评审的一些原则作小结:

* Four eyes check
*
不要既当运动员,又当裁判员

*
审查代码是否满足功能、规范、测试结果、测试覆盖等等

* 借助工具来提升代码审查的效率
* 审查合格才允许合进public branch,不合格的代码退回重新修改
* 不怕犯错,但是不要犯重复的错
* 提交审查前,自己先检查一遍
* 鼓励使用同行评审(Peer Review)而不是上下级评审,鼓励积极反馈、互动
* 评审对事不对人,多建议,不批评
* 己所不欲,勿施于人
* 评审过程对reviewer和代码提交者双方都是一个学习提升的过程
* 保持开放的心态,相互学习,共同成长
思考: 什么文件不应该放在Git上?

你应该把几乎一切文件都作版本控制,除了:

* 敏感信息,比如用户名、密码、Token等
* 编译后产生的二进制文件,比如jar/war包、class文件
* 测试结果
* 日志
* 临时文件
*
IDE自动生成的配置文件

*
空文件夹(如果一定要加入Git,在该目录下添加一个.gitkeep
<http://www.ryanwright.me/cookbook/git/gitkeep> 文件)

使用.gitignore来让Git忽略上述的文件和文件夹。

参考文档:

* GitHub gitignore: https://github.com/github/gitignore
<https://github.com/github/gitignore>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信