Git Notes

Git常用命令及GitLab CI/CD介绍


经典git工作流

简化git工作流(基于环境)

功能开发/修复完成后合并到develop,测试通过后基于master创建发布分支release,release合并开发/修复分支后,部署上线, 验收通过并封版后合到master,看需要来打tag

  • 开发/缺陷分支只能合并稳定分支例如可以合并master分支,不可merge develop分支,作用是防止环境 污染
  • develop分支只能用于测试环境发布,不可直接合并到release分支,正确流程是在release分支合并开 发/缺陷分支

常用命令

 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
# 初始化git配置
git config --global user.name xxx
git config --global user.email xxx

# 查看git配置
git config -l

# 查看git用户名 邮箱
git config user.name
git config user.email

# 修改用户名
git config --global user.name {用户名}

git remote -v   显示所有远程仓库
git remote prune origin      删除本地有但在远程库已经不存在的分支
git clone -b   克隆分支名 地址
git remote add origin git@github.com:XXXXX/demo.git   新增远程仓库
git remote set-url origin git@github.com:XXXXX/demo.git  修改远程仓库
git remote set-url --add origin git@github.com:XXXXX/demo.git  添加多个远程仓库

git stash    不提交工作区内容
git stash pop 恢复工作区
git fetch   拉取远程分支
git checkout -b develop origin/develop 
git reset --hard <commit ID号> 回滚

git push -f origin master 推送到远程分支 
git diff    查看工作区和暂存区的区别 
git diff –cached    查看暂存区和版本库之间的区别 
git diff HEAD   查看工作区和版本库之间的区别 
git status   查看当前的工作状态

git branch -a 查看本地所有分支
git branch -r 查看远程所有分支
git branch -r --contains v0.10.2	查看远程tag属于哪一个分支
git push --set-upstream origin online_help_20191024   推分支
git push origin --delete dev20181018    删除远程分支
git branch -d dev20181018   删除本地分支
git cherry-pick 285c9477a759abdee94099e25e75e39e8c77d46b 合并指定版本


git tag -d tag-name		#删除本地tag
git push origin --delete tag-name		#删除远程tag

分支操作

创建一个新分支

1
2
git branch <new_branch_name>
git checkout <new_branch_name>

基于当前分支创建新分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 从main分支创建develop分支并切换到develop
git pull origin main (可选)
git checkout -b develop main
# 发布develop分支,使本地分支与远程develop关联
git push -u origin develop


# 发布到main分支
git checkout main  					# 切换到main分支
git merge --no-ff develop			# 对develop分支进行合并

--no-ff 
禁止使用快速合并模式,会生成一个新的提交,可以回退到main的上一次提交状态,
如果不加此参数的话,只能回到develop的上一次提交

从develop分支拉出一个新功能分支

1
2
3
4
5
6
7
8
9
git pull origin develop (可选)
git checkout -b feature_v1.0 develop
git push -u origin feature_v1.0

# 完成后,合并到develop分支
git pull origin develop
git checkout develop
git merge --no-ff feature_v1.0			# 从feature分支合并到develop分支
git branch -d feature_v1.0					# 删除feature分支,可选

从develop拉出一个release分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
git pull origin develop								#可选,获取最新版本
git checkout -b release_v1.0 develop

# 完成release,合并到main分支和develop分支,在main打上tag标记
git checkout main
git merge --no-ff release_v1.0
git tag release1.0 master
git push origin v0.10.3	推送v0.10.3分支
git push --tags	推送本地所有tags

#合并到develop
git checkout develop
git merge --no-ff release_v1.0

拉取dev分支到当前本地分支

1
2
3
先切换到本地分支v1.0

git pull origin dev:v1.0

本地项目和远程仓库关联

1
2
3
4
5
6
7
8
9
git init
git remote add origin <remote url>
git fetch origin main				
git branch --set-upstream-to=origin/main main
git add .
git commit -m "xxx"
git push

若远程分支不存在,git fetch origin main命令替换为git push -u origin main   

回退

  • git revert

revert仅仅是撤销指定commit的修改,并不影响后续的commit,但所撤销的commit被后续的commit修改了同一地方则会产生冲突;

  • git reset 彻底回退到指定的commit版本,其后的commit会被删除

git log找到commit id,然后git reset <commit_id>,然后git push -f

删除某次提交

 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
# 1. 找到要删除的那个 commit 的**前一个** commit hash(比如 B)
git log --oneline

# 2. 启动交互式 rebase
git rebase -i <commit-B-hash>

# 或者用相对位置,比如删除倒数第 3 个
git rebase -i HEAD~3



#把要删除的那行改成 drop 或直接删掉这一行:
drop c123456 commit C
pick d234567 commit D
pick e345678 commit E
# 保存退出,Git 会自动应用。


# 然后可能会出现:CONFLICT (content): Merge conflict in README.md error: could not apply 6cbbb27... feat:
# 需要解决冲突 1. 查看冲突文件
git status

# 2. 手动编辑冲突文件(删掉 <<< === >>> 标记)
vim README.md

# 3. 标记为已解决
git add README.md

# 4. 继续 rebase
git rebase --continue

# 5. 如果又遇到冲突,重复 2-4



#3. 强制推送到远程
git push origin -f

开发流程

  1. 项目负责人从master的基线check out,初始化dev分支
  2. 开发者从dev分支check out,建立本地个人开发分支feature*</font>
  3. 开发者完成功能开发后,commit个人feature分支,并push至远程个人feature分支
  4. 开发者在gitlab上提交个人的代码和并请求至dev分支
  5. 代码审查人负责代码审查,合并合理代码
  6. 代码提测时,开发负责人提交dev分支到test的合并请求
  7. 项目负责人合并dev分支至test分支
  8. 版本测试完成后,开发负责人提交test分支至master分支的合并请求
  9. 项目负责人合并代码至master
  10. 项目负责人以当前代码为基线,在master分支上tag当前版本号
1
2
3
git tag -a v1.0.0 -m "Release v1.0.0" # 或 git tag v1.0.0

git push origin v1.0.0

紧急修复工作流

1
2
3
4
5
6
7
8
git checkout master
git checkout -b hotfix/1.2.1
# gerrit切出hotfix/1.2.1分支
# 修复完成
# 合并到master
git push origin HEAD:refs/for/master
# 合并到develop
git push origin HEAD:refs/for/develop

版本发布工作流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 获取预先规划的版本号,并根据实际更新内容修改版本号
# 确保规划的问题修复和功能开发均已合并到develop
# gerrit上创建release/1.2.0分支
# 全量测试并生成固件
# 软件
# 修 bug、验证
git push origin HEAD:refs/for/master
git tag -a v1.0.0 -m "Release v1.0.0"
git checkout develop
git merge release/1.2.0
git push origin HEAD:refs/for/develop
# 删除release/1.2.0分支

主分支同步到功能分支

如果是仅个人的功能分支,推荐用rebase保持干净历史,多人开发的功能分支用merge

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 更新development
git checkout development
git pull origin development


# 切回功能分支
git checkout feature-branch
git rebase development


# 如果有冲突
# 解决冲突后
git add .
git rebase --continue


# 强制推送
git push --force-with-lease

分支类型

开发分支: feat/xxx(功能)_20200804(创建日期)开发分支基于master创建,开发完成合并到测试develop分支 测试分支:develop 只用来发布测试环境 发布分支:release/vx.x.x(版本号)_20200804(创建日期),基于master创建,验收完成,进行封版后合并回master 缺陷分支:hotfix/xxx(功能)_20200804(创建日期)合并流程和开发分支一致,区别在于,hotfix在测试环境测试通过后直接合到最新的release分支验收

提交规范

 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
commit 规范:

feat: ⼀个新特性

fix: 修了⼀个 Bug

docs: 更新了⽂档(⽐如改了 Readme)

style: 代码的样式美化,不涉及到功能修改(⽐如改了缩进,css修改不算)

refactor: ⼀些代码结构上优化,既不是新特性也不是修 Bug(⽐如函数改个名字)

perf: 优化了性能的代码改动

test: 新增或者修改已有的测试代码

chore: 跟仓库主要业务⽆关的构建/⼯程依赖/⼯具等功能改动(⽐如新增⼀个⽂档⽣成⼯具)

操作规范(技巧):

在代码push 前先 pull
遇到代码冲突时,最先考虑取最近commit的版本,若想撤销本次拉取 执行git revert --abort
正在开发发现分支错了,执行 git stash,切换分支后,执行git stash pop
只想合并其他分支的某条commit 记录 执行 git cherry-pick commitId
开发分支新建必须基于干净版本,合并到稳定版本前必须是验收通过的版本
开发分支不能合并其他正在开发或者非干净分支
提交类型含义
feat新功能(feature)
fix修复 bug
perf性能优化
refactor重构代码
docs文档相关
style样式相关
test测试相关
chore构建过程或辅助工具的变动

生成密钥对

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
ssh-keygen -t ed25519 -C "your_email@example.com"

# 拷贝
## mac
pbcopy < ~/.ssh/id_ed25519.pub

## linux

## win
 cat ~/.ssh/id_ed25519.pub | clip

GitLab CI/CD

项目根目录下新建.gitlab-ci.yml文件

 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
variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

# 缓存配置,加快项目的构建速度,减少重复下载
cache:
  key: $CI_JOB_NAME-$CI_COMMIT_REF_SLUG	# job名称-提交的分支名称
  paths:
    - ${PIP_CACHE_DIR}		# 需要被缓存的文件或文件夹的路径

# 定义pipeline
stages:
  - lint
  - test

# 定义了2个job
lint_job:
  stage: lint				# 属于哪个stage
  image: python:3.7	# 需要的docker镜像
  before_script:		# job开始之前执行的脚本
    - pip install flake8 -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
  script:						# 执行脚本
    - flake8 app

test_job:
  stage: test
  image: python:3.7
  services:	# 启动名为 postgres 的服务
    - postgres
  variables:
    POSTGRES_HOST: postgres
    POSTGRES_PORT: 5432
    POSTGRES_USER: postgres
    POSTGRES_PASS: postgres
    POSTGRES_DB: oa_performance_test
    POSTGRES_PASSWORD: postgres
  before_script:
    - pip install -r requirements-test.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
  script:
    - echo "Test started."
    # - coverage run --source app -m pytest tests
    # - coverage report
    - echo "Test finished."

常见问题

  1. fatal: refusing to merge unrelated histories git merge main –allow-unrelated-histories

  2. pull时提示:your local changes will be overwritten by merge… 先git stash changes,然后pull更新,然后git stash pop

  3. 忽略已跟踪的某个文件或目录 git rm –cached /path/file 或 git rm -r –cached logs/