0%

代码规范_04_Git协同

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。Git是协同开发的最常用工具。

理论部分主要是狂神git视频的笔记

第5节主要记录实习过程遇到的诸多git问题

最常用的命令 没有之一

1
2
3
git checkout -b feature/wuzhikang #新建分支并切换到该分支
git status
git log --oneline

1 什么是版本控制

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。

  • 实现跨区域多人协同开发
  • 追踪和记载一个或者多个文件的历史记录
  • 组织和保护你的源代码和文档
  • 统计工作量
  • 并行开发、提高开发效率
  • 跟踪记录整个软件的开发过程
  • 减轻开发人员的负担,节省时间,同时降低人为错误

简单说就是用于管理多人协同开发项目的技术。Git是最优秀的分布式版本控制系统,最初Linus Benedic Torvalds开发的目的是为了Linux内核系统的版本控制。

2 Git的安装和基本命令

Git安装

  • 下载地址淘宝镜像网站http://npm.taobao.org/mirrors/git-for-windows/
  • 我这里下载了一个Git-2.33.0-64-bit.exe的安装包。选择开发软件安装路径,然后无脑安装(查看器可以选择notepad++)。会自动帮你配置环境变量
  • 配置账号名和邮箱,任意路径下点开git bush
1
2
3
git config --global user.name "wukang"
git config --global user.email "67363085@qq.com"
git config --global --list #查看配置

实际上git的配置都保存在本地

  • Git\etc\gitconfig # Git 安装目录下的 gitconfig –system 系统级
  • C:\Users\Administrator\ .gitconfig #只适用于当前登录用户的配置 –global 全局

常用的Linux命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cd #切换目录
cd [绝对路径] #切换至该绝对路径下
cd / #表示切换到根目录下
cd .. #表示返回上一级目录

ls #查看当前下的目录、可能时最常用的命令
ls -a #查看当前目录下的所有目录,包括隐藏
ls -l #列出当前下目录的包含文件的属性与权限等等数据;(常用)
ls -al #列出当前下目录的包含文件的属性与权限等等数据,包括隐藏
ls / #查看根目录/下的目录

pwd #显示目前所在的目录
pwd -P # 如果是链接,要显示真实地址

mkdir -p test2/test3/test4 # 用-p递归创建层级目录
rmdir -p test2/test3/test4 #递归删除文件

cp /root/install.sh /home #将install.sh 复制到home文件夹中

clear #清屏
exit #退出

3 Git基本理论(重要)

1 Git的工作区域

Git本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。远处有一个远程git仓库(Remote Directory)。状态变化最主要的几个操作分别是add、commit、push和pull、fetch

img
  • Remote:远程仓库,就是git上面的所有已经上传过的代码,所有协同开发人员都可以随时获取(即pull或fetch)
  • Repository:资源库(我更喜欢叫本地库),就是你本地这个主机修改过的代码经过提交后的版本(未提交的不算)。也就是idea右下角点开分支目录,这些分支都是你本地的版本
  • Working Directory:工作目录,就是本地这个主机的未提交的代码的版本(就是我们工作的地方!!正在码代码的这个版本)
  • Index:暂存区,新修改或者新建的代码通过add后放入暂存区。但不重要(但在我都是add&commit一起执行)

2 文件的几种状态

git管理的文件有几种状态:未跟踪(Untracked),已修改(modified),已暂存(staged),已提交(committed)

image-20220114092338934
  • Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.

  • Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件

  • Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改 !

  • Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified

查看文件的状态:

1
2
3
4
5
6
7
#查看指定文件状态
git status [filename]
#查看所有文件状态
git status
# 修改文件状态
git add . #添加所有文件到暂存区
git commit -m "消息内容bababa" #提交暂存区中的内容到本地仓库 -m 提交信息

忽略文件:有些时候我们不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等。需要在主目录下建立”.gitignore”文件。此文件夹内适用如下规则

1
2
3
4
5
6
#为注释
*.txt #忽略所有 .txt结尾的文件,这样的话上传就不会被选中!
!lib.txt #但lib.txt除外
/temp #仅忽略项目根目录下的TODO文件,不包括其它目录temp
build/ #忽略build/目录下的所有文件
doc/*.txt #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

4 Git的使用

1 Git的基本使用

  • 1 先登录码云,然后为本地机器添加一个SSH公钥。码云上创建一个空项目作为远程仓库。
image-20220114112613923
  • 2 将该项目克隆到本地,比如C:\IdeaProjects文件夹下。记得选择SSH链接的形式克隆
  • 3 idea新建spring项目比如hello-01,将克隆gitstudy下所有文件复制进hello-01项目目录
  • 4 观察学习idea中git的命令和按钮。
    • 右上角有update、commit和push
    • 左下角有git图标,可以查看版本信息
    • Terminal标签窗口可以执行git命令
    • 任意文件右键,有git命令选择
1
2
3
4
# 命令行常见操作
git add . #添加所有文件到暂存区
git commit -m "本次提交了****" #提交暂存区中的内容到本地仓库 -m 提交信息
git push #提交

2 Git常用命令

image-20220114120159076

git命令之branch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 列出所有本地分支
git branch

# 列出所有远程分支
git branch -r

# 新建一个分支,但依然停留在当前分支
git branch [branch-name]

# 新建一个分支,并切换到该分支
git checkout -b [branch]

# 合并指定分支到当前分支
git merge [branch]

#切换至某分支
git checkout [branch]

# 删除分支
git branch -d [branch-name]

# 删除远程分支
git push origin --delete [branch-name]
git branch -dr [remote/branch]

git命令之add、commit、restore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 添加指定文件到暂存区 
git add [file1] [file2] ...

# 添加指定目录到暂存区,包括子目录
git add [dir]

# 添加当前目录的所有文件到暂存区
git add .

# 提交暂存区到仓库区
$ git commit -m [message]

# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]

# 提交工作区自上次commit之后的变化,直接到仓库区
$ git commit -a

# 提交时显示所有diff信息
$ git commit -v

# 使用一次新的commit,替代上一次提交 # 如果代码没有任何新变化,则用来改写上一次commit的提交信息
$ git commit --amend -m [message]

# 重做上一次commit,并包括指定文件的新变化
$ git commit --amend [file1] [file2] ...

# 将在工作空间但是不在暂存区的文件撤销更改,文件的修改将消失(丢失)
$ git restore <file>

# 作用是将暂存区的文件从暂存区撤出,但不会更改文件
$ git restore --staged <file>

git命令之checkout、reset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 恢复暂存区的指定文件到工作区 
$ git checkout [file]

# 恢复某个commit的指定文件到暂存区和工作区
$ git checkout [commit] [file]

# 恢复暂存区的所有文件到工作区
$ git checkout .

# 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
$ git reset [file]

# 重置暂存区与工作区,与上一次commit保持一致
$ git reset --hard

# 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
$ git reset [commit]

# 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致
$ git reset --hard [commit]

# 重置当前HEAD为指定commit,但保持暂存区和工作区不变
$ git reset --keep [commit]

# 新建一个commit,用来撤销指定commit # 后者的所有变化都将被前者抵消,并且应用到当前分支
$ git revert [commit]

# 暂时将未提交的变化移除,稍后再移入
$ git stash
$ git stash pop

# 生成一个可供发布的压缩包
$ git archive

git命令之查看信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 显示有变更的文件 
$ git status

# 显示当前分支的版本历史
$ git log

# 显示commit历史,以及每次commit发生变更的文件
$ git log --stat

# 搜索提交历史,根据关键词
$ git log -S [keyword]

# 显示某个commit之后的所有变动,每个commit占据一行
$ git log [tag] HEAD --pretty=format:%s

# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
$ git log [tag] HEAD --grep feature

# 显示某个文件的版本历史,包括文件改名
$ git log --follow [file]
$ git whatchanged [file]

# 显示指定文件相关的每一次diff
$ git log -p [file]

# 显示过去5次提交
$ git log -5 --pretty --oneline

# 显示所有提交过的用户,按提交次数排序
$ git shortlog -sn

# 显示指定文件是什么人在什么时间修改过
$ git blame [file]

# 显示暂存区和工作区的差异
$ git diff

# 显示暂存区和上一个commit的差异
$ git diff --cached [file]

# 显示工作区与当前分支最新commit之间的差异
$ git diff HEAD

# 显示两次提交之间的差异
$ git diff [first-branch]...[second-branch]

# 显示今天你写了多少行代码
$ git diff --shortstat "@{0 day ago}"

# 显示某次提交的元数据和内容变化
$ git show [commit]

# 显示某次提交发生变化的文件
$ git show --name-only [commit]

# 显示某次提交时,某个文件的内容
$ git show [commit]:[filename]

# 显示当前分支的最近几次提交
$ git reflog

3 Commit message格式

Git的核心是commit,所以写好commit信息极其重要。

方式一:提交信息只能有一行

git commit [fileName] -m “commit message”

方式二:使用vim编辑方式,提交现信息可以多行(推荐这种,可以按规范来)

git commit [fileName]

Commit message规范如下:Header 第一行是必需的,Body 和 Footer 可以省略。不管是哪一个部分,任何一行都不得超过72个字符(或100个字符)。这是为了避免自动换行影响美观。

1
2
3
4
5
<type>(<scope>): <subject>

<body>

<footer>

(1)type

type用于说明 commit 的类别,只允许使用下面7个标识。

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

如果typefeatfix,则该 commit 将肯定出现在 Change log 之中。其他情况(docschorestylerefactortest)由你决定,要不要放入 Change log,建议是不要。

(2)scope

scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。

(3)subject

subject是 commit 目的的简短描述,不超过50个字符。

  • 以动词开头,使用第一人称现在时
  • 第一个字母小写,结尾不加句号(.

(4)body

Body 部分是对本次 commit 的详细描述,可以分成多行。

有两个注意点。

  • 使用第一人称现在时

  • 应该说明代码变动的动机,以及与以前行为的对比。

(5)Footer

Footer 部分只用于两种情况:不兼容变动关闭 Issue

  • 如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。
  • 如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。

Revert撤销commit

还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。

1
2
3
revert: feat(pencil): add 'graphiteWidth' option

This reverts commit 667ecc1654a317a13331b17617d973392f415f02.

Body部分的格式是固定的,必须写成This reverts commit <hash>.,其中的hash是被撤销 commit 的 SHA 标识符。

5 Git开发流程

5.1 Git Flow

参考了博文,关于分支的介绍和主要的工作流程都介绍的很好

Git官方给的流程:

img

由上图可知,GitFlow的常用分支有:master、develop、feature、release、hotfix。分支介绍如下:

master

  • 主分支 , 产品的功能全部实现后 , 最终在master分支对外发布
  • 该分支为只读唯一分支 , 只能从其他分支(release/hotfix)合并 , 不能在此分支修改
  • 另外所有在master分支的推送应该打标签做记录,方便追溯
  • 例如release合并到master , 或hotfix合并到master

develop

  • 主开发分支 , 基于master分支克隆
  • 包含所有要发布到下一个release的代码
  • 该分支为只读唯一分支 , 只能从其他分支合并
  • feature功能分支完成 , 合并到develop(不推送)
  • develop拉取release分支 , 提测
  • release/hotfix 分支上线完毕 , 合并到develop并推送

feature

  • 功能开发分支 , 基于develop分支克隆 , 主要用于新需求新功能的开发
  • 功能开发完毕后合到develop分支(未正式上线之前不推送到远程中央仓库!!!)
  • feature分支可同时存在多个 , 用于团队中多个功能同时开发 , 属于临时分支 , 功能完成后可选删除

release

  • 测试分支 , 基于feature分支合并到develop之后 , 从develop分支克隆
  • 主要用于提交给测试人员进行功能测试 , 测试过程中发现的BUG在本分支进行修复 , 修复完成上线后合并到develop/master分支并推送(完成功能) , 打Tag
  • 属于临时分支 , 功能上线后可选删除

hotfix

  • 补丁分支 , 基于master分支克隆 , 主要用于对线上的版本进行BUG修复
  • 修复完毕后合并到develop/master分支并推送 , 打Tag
  • 属于临时分支 , 补丁修复上线后可选删除
  • 所有hotfix分支的修改会进入到下一个release

公司的项目流程:

image-20220217174754792

作为开发人员,我们公司的大致流程就是:

  • 1 master分支poll更新拉取最新的代码,新建分支fix或feature
  • 2 本地开发并调试,完成后commit、pull、push,push完成后请求合并test分支,更新测试环境并进行测试
  • 3 将分支代码merge合并到master分支,并上线

5.2 场景最佳实践

此部分参考博客

先介绍一下最常用的3个Git指令!!

1
git status # 充分、及时了解当前的 git 状态可以避免一些误操作

我通常在 写完代码后、做任何git操作前、做复杂的git操作的途中(比如 rebase、merge遇到冲突时)和 做完任何git操作后,都会使用 git status去查看当前的状态 —— 哪些文件还在工作区(还没 git add)、哪些文件还在暂存区(还没 git commit)或者 rebase、merge 的进展等。

1
git log --oneline # 打印出最近的commit messages,每条message只占一行,使界面更干净、美观。

我通常会在 切换分支的前后,拉取线上分支的前后 使用git log –oneline,它能帮我根据 commit message 确认我当前的分支以及当前分支是否是最新的 (前提是每次 commit 时一定要认真填写 commit message)

1
git commit  # commit 是git 设计中的核心

在日常开发工作中,我通常会在 写完一部分代码后,准备暂时休息前或确认某个功能/bug处理完成后 使用 git addgit commit 来保存代码到本地仓库。

记住:只要正确地 commit了,代码就几乎永远不会丢失。

场景一:新任务(开发新特性 / 修bug)

一般的业务需求都是这个场景

  • 1 git status 查看当前项目的状态,如果有未保存的修改,就保存和提交修改

    1
    2
    3
    git status
    git add .
    git commit [fileName] #使用vim方式提交message
  • 2 切换到开发主分支develop,并确认主分支是最新的版本

    1
    2
    git checkout develop
    git pull origin develop
  • 3 创建新的开发分支feature/newFunctionWK,并在该分支上进行开发

    1
    git checkout -b feature/newFunctionWK
  • 4 开发过程如果当前任务比较复杂,代码量比较多,通常会多次使用 git add .git commit

    1
    2
    3
    4
    git status
    git add .
    git commit [fileName] #使用vim方式提交message
    #message需要按照规范写清楚,第一行为标题,空格行后写详细的备注
  • 5 代码开发结束,整理合并 commit message,代码步骤如下:

    前面说过多次 commit 是为了防止意外丢失代码,但是在推到远端之前,最好把一次开发的 commit 合并成一个,避免污染远端的 git commit message,

    • 首先git status确保所有代码都提交了
    • 然后git logl查看当前分支下最近所有的commit,比如最近我有两个关于fix:规范代码的提交
    • 执行git rebase -i HEAD命令
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    git status
    git log --oneline #oneline可加可不加
    git rebase -i HEAD~2 #合并本地最近两次的commit
    # git rebase -i [startpoint] [endpoint] #也可以指定两个commit的点如下
    # git rebase -i 23cc2cabb387f4ba43b7b0daa4d0aa40847a7cc6 22e4245da8330644f865c5eb582fc857ed109685
    # 正常应该是在控制台vim编辑修改,但我这个会弹窗Nodepad++,如下图,要更新的代码如下
    git rebase --continue #再执行这个
    # 然后继续编辑合并两条message,原图如下,要修改部分如下代码

    git log #查看日志,发现两条commit已经合并为1条

    image-20220218151826942

    image-20220218165247203
    1
    2
    pick 22e4245 fix:代码规范
    squash 23cc2ca fix:代码规范

    image-20220218165622637

    1
    2
    3
    4
    fix:代码规范&更新时可以指定初稿状态

    更优雅的判断新建文章和更新文章的判断
    添加更新文章时指定初稿状态仍然可以作为初稿的逻辑判断

    img

  • 6 push本分支到远端仓库,然后上git上请求合并

    • 这里为了避免冲突,一般还有其他的实施方案:
    • 1 先切换到develop分支,poll拉最新的代码
    • 2 然后在本地将feature/newFunctionWK分支合并到本地的develop分支,如果出现冲突就解决冲突
    • 3 将本地的develop分支push到远端仓库(此时远端develop就是最新的已经合并的代码了)
    1
    git push origin develop

场景二:开发进行一半,需要远端主分支的最新代码

背景:有些时候,你在本地开发某个功能,代码写到一半,某个同事将某些重要代码合进了**远端的主分支(如 develop 分支)**里。这些重要代码可能是可以极大提升本地开发效率,可能是加入了某些规范检查或者是跟你当前开发相关的代码 —— 总之需要你将那部分代码融入你当前的本地开发环境里。

三个步骤如下:

  • git status 查看当前项目的状态,如果有未保存的修改,就git add .git commit 保存下来
  • git pull –rebase origin develop 使用这个指令将远端的主分支develop以 rebase 的形式 “合进”当前分支
    • 执行这条命令之前,需要保证没有文件处于modified状态
    • 如果有文件处于modified而这个修改又不应该commit,比如application.yml,就先移除这个修改:git restore
  • git log –oneline 查看当前分支下的 commit message 是否符合预期

为什么用 –rebase 呢?

因为这么做,可以让git历史最干净、整洁 —— 所有本地开发的 commit 都会出现在远端主分支里的 commit 之后;并且可以避免额外引入一次 merge 的 commit(避免本地多执行一次merge)

场景三:希望把某个分支中的 commit 对应的代码复制到当前分支

有时我会创建一些实验性的分支,写一些实验性的代码,如果代码不可行,我可以直接废弃掉这个分支,返回原本的开发分支中;如果这些实验性代码可行,我会返回开发分支中,然后把实验性分支的那部分代码“复制”过来

具体操作如下:

  • git status 查看当前项目的状态,如果有未保存的修改,就git add .git commit 保存下来

  • 假设我们需要的是 feature/newFunctionWK 这个分支的某个 commit ,使用 git log –oneline feature/newFunctionWK 查看最近这个分支的所有 commit 记录

    img

  • 使用 git cherry-pick 50dd556 将这个 commit 对应的代码复制到当前分支

1
2
3
4
5
6
7
git status
git add .
git commit [fileName] #使用vim方式提交message

git log --oneline feature/newFunctionWK #查询commit日志

git cherry-pick 50dd556 #复制50dd556这个commit到当前分支

5.3 使用git的原则和可能的问题

1 check分支之前需要先下拉代码

2 如何解决merge代码冲突的问题

3 为什么出现merge代码不完整的问题

使用git的原则(习惯)

  1. 永远记得 git st 和 git logl 来确认当前分支的状态
  2. 宁愿临时制造一些无用的 commit 来保证代码不会丢失,也不要轻信自己的记忆力
  3. 谨慎(最好能避免)使用 git stash ,极易造成代码丢失
  4. 认真对待、编写每次的 commit message —— 它们能在关键时刻救你一命
  5. 必要的时候可以创建一些临时的分支写实验性的代码,而不是依赖 git reset 撤销 commit —— 大多数人在 git reset 的时候容易犯错误

出现冲突如何解决(git merge conflict)

参考博文https://blog.csdn.net/u012150179/article/details/14047183

一个解决的方法就是push之前先poll

-------------感谢阅读没事常来-------------