Git
Jackie

Git

理论

  • SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候用的是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活儿推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。

  • Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作时不需要联网了,因为版本都在自己电脑上,协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

image

image

#git init从master改成main
git config --global init.defaultBranch main
#设置提交代码时的用户信息
git config --global user.name 'jackie'
git config --global user.email **@qq.com
#如果去掉 --global 参数只对当前仓库有效,即./.git/config

自用基本操作

git clone <链接>
git add .
git status
git commit -m "消息内容"
git remote rm origin(有的话删除)
git remote add origin https://github.com/xxx.git
#5、6可以合并成下面
git remote set-url origin <链接>
#origin是给远程仓库起的别名,也可以起其他名字,但是如果用origin,git push时可以不指出名字,如果用其他名字需要指出名字,git push 名字
git push origin main

#本地和远程仓库不同时
git pull origin main
#fatal: Need to specify how to reconcile divergent branches.
#致命:需要指定如何协调不同的分支。
#虽分支名相同,但本地有commit,而新建仓库添加README&License后同样会commit,本地&仓库各自有commit↓
git pull --rebase origin main
git init
git pull <remote link>
git switch -c <new branch>
修改文件
git diff、add、commit
git push origin <new branch>
---以下存疑
#修改代码时main分支又有了更新,此时应首先更新本地分支
git checkout main
git pull origin master#同步远端的main到本地main,此时GitHub上新的更新的commit会被同步到本地
git checkout <new branch>
git rebase main#把之前的修改都扔一边,然后把main最新的修改拿过来,接着在最新修改的基础上再把该分支上的修改尝试弄回去(可能存在rebase conflict,手动选择保留哪一段代码)
git push -f origin <new branch>
~~~
Squash and merge#将多条commit扁平合并为一个新的改变,然后把该commit放到main(只是commit结构数量和名字改变了)
#此时一般情况会把远端的branch删掉(delete branch)
git checkout main
git branch -D <new branch>
git pull origin master

image

参考链接:Git 基本操作 | 菜鸟教程

  • git status

A:你本地新增的文件(服务器上没有)

C:文件的一个新拷贝

D:你本地删除的文件(服务器上还在)

M:文件的内容或者mode被修改了

R:文件名被修改了

T:文件的类型被修改了

U:文件没有被合并(你需要完成合并才能进行提交)

X:未知状态(很可能是遇到git的bug了,你可以向git提交bug report)

??:未被git进行管理,可以使用git add file1把file1添加进git能被git所进行管理

红色是工作区状态,绿色是暂存区的状态

  • git diff

git diff:尚未缓存的改动

git diff -p -2:-p显示文件改动的详情,-2表示仅显示近2次

git diff --cached:查看已缓存的改动

git diff HEAD:查看已缓存的与未缓存的所有改动

git diff --stat:显示摘要而非整个 diff

git diff origin<远程仓库名>/main<分支名>
  • git commit

git commit -a:修改文件后不需要执行 git add 命令,直接来提交

  • git rm

git rm <file>:从暂存区和工作区中删除

git rm -f <file>:若删前修改过且已放到暂存区域,则必须要用强制删除选项 -f

git rm -r ***:递归删除该目录下的所有文件和子目录

  • git mv

git mv <file> <newfile> -f:若新文件名已经存在,但还是要重命名它,可用 -f

  • git checkout

git checkout -b 分支名:创建并切换分支

.gitignore忽略文件

有些时候我们不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等

在主目录下建立".gitignore"文件,此文件有如下规则:

  1. 忽略文件中的空行或以井号(#)开始的行将会被忽略。
  2. 可以使用Linux通配符。例如:星号(*)代表任意多个字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围,大括号({string1,string2,…})代表可选的字符串等。
  3. 如果名称的最前面有一个感叹号(!),表示例外规则,将不被忽略。
  4. 如果名称的最前面是一个路径分隔符(/),表示要忽略的文件在此目录下,而子目录中的文件不忽略。
  5. 如果名称的最后面是一个路径分隔符(/),表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)。
*.txt        #忽略所有 .txt结尾的文件,这样的话上传就不会被选中!
!lib.txt #但lib.txt除外
/temp #仅忽略项目根目录下的TODO文件,不包括其它目录temp
build/ #忽略build/目录下的所有文件
doc/*.txt #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

Branch

假设当前主分支经历了两个版本,我们要为当前仓库新增文件,但该文件还不能确定是否需要,我们可在主分支的基础上创建一个新的分支,等新分支文件一切准备好了再合并过来

image

git branch <分支名>#创建分支
git checkout <分支名>#切换分支
git branch -d <分支名>#删除分支,-D可强制删除
git checkout -b <分支名1>#创建并马上切换到新分支
#等价于↓
git switch -c <分支名>
git merge <分支名1>#把别的分支合并到当前所处分支

GitHub Issues

问题+“#+数字”

commit时的-m “解决#+数字”,提交到远程仓库后会关联相应的issue

GitHub Pull Requests

若尝试新增一个Pull Request会发现创建按钮无法点击且提示需要选择不同的Branches或Forks

Issues和Pull Requests会共用"#+数字"的顺序

后面提交PR后"#+数字"会顺延前面的数字

PR后远程仓库只有一个分支,但本地仍有两个分支

若直接branch -d删除,提示出错,且提示可用-D删除

远程仓库已合并,且有n个Commits,而本地只有m个(m<n),因为本地还没做合并的操作

git pull origin main

此时git log会看到此时Commits的数量一致了,再次删除小分支,则不会出错

如果想参与别人的项目

  1. 在github.com上fork到自己仓库

  2. clone到本地

  3. 建立一个branch

    git branch work
    git checkout work
    ---
    git checkout -b work
  4. 编程工作

  5. git diff查看更改

  6. push到自己的网站

    git add path/file_name.py
    git commit -m "填写你的说明"
    git push origin work
  7. 在github上发送PR

Fork

拷贝仓库到自己账号,注意commit时按照别人仓库的规范来进行

此时进行Fork的那名用户账号里可看到横幅(源仓库拥有者那里不会显示)

Tags

#-a是annotation,意为注解
git tag -a v1.0.0 -m "v1.0.0大功告成"
#删除标签
git tag -d v1.0.0

GitHub Actions

【Github Action题目world.execute.me 出题人讲解】 https://www.bilibili.com/video/BV1jm411d7Jk/?share_source=copy_web&vd_source=15214a7977f78540f7402494fb912cda

拓展链接

Git _ 报错信息

https://www.cnblogs.com/iini/p/16300299.html

实用代码

clone指定tag的指定commit

git clone git@github.com:hankcs/HanLP.git -b v1.7.5 --depth=1
# -b 后面接 tag 名,--depth=1 指只克隆最新的版本,可以节省很多空间

Git的奇技淫巧

一台电脑绑很多ssh

https://www.cnblogs.com/jikexianfeng/p/5873698.html

撤回已 Push 的代码

IDEA中Git较为优雅的方法:Reset Current Branch 到你想要恢复的commit记录

这个时候会跳出四个选项供选择

Soft:#之前写的不会改变,之前暂存过的文件还在暂存。
Mixed:#之前写的不会改变,之前暂存过的文件不会暂存。
Hard:#文件恢复到所选提交状态,任何更改都会丢失。你已经提交了,然后你又在本地更改了,如果选hard,那么提交的内容和提交后又本地修改未提交的内容都会丢失。
keep:#任何本地更改都将丢失,文件将恢复到所选提交的状态,但本地更改将保持不变。你已经提交了,然后你又在本地更改了,如果选keep,那么提交的内容会丢失,提交后又本地修改未提交的内容不会丢失。

然后,之前错误提交的commit就在本地给干掉了。但是远程仓库中的提交还是原来的样子,你要把目前状态同步到远程仓库。也就是需要把那几个commit删除的操作push过去。

打开push界面,虽然没有commit需要提交,需要点击Force Push,强推过去。

需要注意的是对于一些被保护的分支,这个操作是不能进行的。需要自行查看配置,我这里因为不是master分支,所以没有保护。

实操

git reset --hard <所需要恢复到位置的hash值>
git push --force origin

.git

简单地说,git 只是一堆通过文件名相互链接的文本文件。

git init

$ tree .git

.git
├── config
├── HEAD
├── hooks
│ └── prepare-commit-msg.msample
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
  • config是一个 txt 文件,里面记录了当前仓库的 git 设置,如作者信息、文件模式等。

  • HEAD表示仓库的当前head。根据你设置的默认分支,它可能是refs/heads/masterrefs/heads/main或其他你设定的名字。实际上,它指向refs/heads这个文件夹,并关联了一个名为master的文件,但该文件目前还不存在。只有在你完成首次提交后,master文件才会生成。

  • hooks是一个特殊的目录,其中包含了可以在git执行任何操作前后运行的脚本。

    https://blog.meain.io/2019/making-sure-you-wont-commit-conflict-markers/

  • objects存放的是git的对象,比如关于仓库中的文件、提交等的数据。我们稍后会对此进行深入探讨。

  • refs正如我们之前提到的,是用来存放引用的目录。例如,refs/heads里存放的是分支的引用,而refs/tags则存放的是标签的引用。我们将进一步深入了解这些文件的内容。

git add file

--- init       2023-07-02 15:14:00.584674816 +0530
+++ add 2023-07-02 15:13:53.869525054 +0530
@@ -3,7 +3,10 @@
├── HEAD
├── hooks
│ └── prepare-commit-msg.msample
+├── index
├── objects
+│ ├── 4c
+│ │ └── 5b58f323d7b459664b5d3fb9587048bb0296de
│ ├── info
│ └── pack
└── refs

此操作主要引发了两个变化。首先,文件index被修改。index是记录当前暂存信息的地方,这表明名为file的文件已经被加入到索引中。

更为关键的是,新建了一个objects/4c文件夹,并在其中添加了5b58f323d7b459664b5d3fb9587048bb0296de文件。

#看看该文件具体包含了什么信息
$ file .git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de
.git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de: zlib compressed data
---
#这个用 zlib 压缩的数据中具体包含了什么呢?
$ zlib-flate -uncompress <.git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de
blob 9\0meain.io

结果可看出,该文件记录了我们之前通过git add命令添加的file文件的相关信息,包括文件的类型、大小和内容。具体地说,文件类型为blob,大小为9,内容则是meain.io

文件名其实是基于内容的sha1哈希值生成的。通过对zlib压缩的数据进行sha1sum处理,我们就可以得到这样的文件名。

$ zlib-flate -uncompress <.git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de|sha1sum
4c5b58f323d7b459664b5d3fb9587048bb0296de

git在存储内容时,会使用内容的sha1哈希值,取其前两个字符作为文件夹名(如4c),余下的部分作为文件名。这种方式是为了确保在objects文件夹中不会有过多的文件,从而使文件系统保持高效。

git cat-file

git提供了一个基础命令git cat-file,让我们可以更直观地查看它。通过-t参数,你可以查询对象的类型;使用-s参数,你可以得知对象的大小;而-p参数则能让你直观地查看对象的具体内容。

$ git cat-file -t 4c5b58f323d7b459664b5d3fb9587048bb0296de
blob

$ git cat-file -s 4c5b58f323d7b459664b5d3fb9587048bb0296de
9

$ git cat-file -p 4c5b58f323d7b459664b5d3fb9587048bb0296de
meain.io

git commit

$ git commit -m 'Initial commit'
[master (root-commit) 4c201df] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 file

以下是相关的变动:

--- init        2023-07-02 15:14:00.584674816 +0530
+++ commit 2023-07-02 15:33:28.536144046 +0530
@@ -1,11 +1,25 @@
.git
+├── COMMIT_EDITMSG
├── config
├── HEAD
├── hooks
│ └── prepare-commit-msg.msample
├── index
+├── logs
+│ ├── HEAD
+│ └── refs
+│ └── heads
+│ └── master
├── objects
+│ ├── 3c
+│ │ └── 201df6a1c4d4c87177e30e93be1df8bfe2fe19
│ ├── 4c
│ │ └── 5b58f323d7b459664b5d3fb9587048bb0296de
+│ ├── 62
+│ │ └── 901ec0eca9faceb8fe0a9870b9b6cde75a9545
│ ├── info
│ └── pack
└── refs
├── heads
+ │ └── master
└── tags

首先有一个新文件``COMMIT_EDITMSG`,保存了最新的提交信息。

若直接运行git commit未带-m参数,git会启动一个编辑器并加载COMMIT_EDITMSG文件,方便用户编辑提交信息。编辑完成后,git就采用该文件内容作为提交信息。

此外,新增了一个logs目录,git通过它来记录所有的提交变动。在此,你可以查看所有引用(refs)及HEAD的提交记录。

object文件夹也发生了些变化,但首先,我希望你关注一下refs/heads目录,里面现有一个master文件。毫无疑问,这就是master分支的引用。

$ cat refs/heads/master
3c201df6a1c4d4c87177e30e93be1df8bfe2fe19

显然,它是指向了一个新的对象。我们有方法查看这类对象,接着来试试。

$ git cat-file -t 3c201df6a1c4d4c87177e30e93be1df8bfe2fe19
commit

$ git cat-file -p 3c201df6a1c4d4c87177e30e93be1df8bfe2fe19
tree 62902ec0eca9faceb8fe0a9870b9b6cde75a9545
author Abin Simon <mail@meain.io> 1688292123 +0530
committer Abin Simon <mail@meain.io> 1688292123 +0530

Initial commit

同样可以使用git cat-file -t refs/heads/master命令来查看。

commit的内容中,我们得知它包含了一个哈希值为62902ec0eca9faceb8fe0a9870b9b6cde75a9545tree对象,这与我们在提交时新加的对象相似。commit`还显示了这次提交的作者和提交者信息,这里都是我。最后,它还展示了这次提交的信息。

接下来,让我们看一下tree对象中包含的内容。

$ git cat-file -t 62902ec0eca9faceb8fe0a9870b9b6cde75a9545
tree

$ git cat-file -p 62901ec0eca9faceb8fe0a9870b9b6cde75a9545
100644 blob 4c5b58f323d7b459664b5d3fb9587048bb0296de file

tree对象中会通过其他treeblob对象的形式呈现工作目录的状态。在这个示例中,因为我们仅有一个名为file的文件,所以你只能见到一个对象。细看的话,你会发现这个文件指向了我们在执行git add file时加入的那个初始对象。

下面展示了一个更为成熟的仓库中的tree示意。在commit对象关联的tree对象中,嵌套有更多的tree对象,用以标识不同的文件夹。

$ git cat-file -p 2e5e84c3ee1f7e4cb3f709ff5ca0ddfc259a8d04
100644 blob 3cf56579491f151d82b384c211cf1971c300fbf8 .dockerignore
100644 blob 02c348c202dd41f90e66cfeb36ebbd928677cff6 .gitattributes
040000 tree ab2ba080c4c3e4f2bc643ae29d5040f85aca2551 .github
100644 blob bdda0724b18c16e69b800e5e887ed2a8a210c936 .gitignore
100644 blob 3a592bc0200af2fd5e3e9d2790038845f3a5cf9b CHANGELOG.md
100644 blob 71a7a8c5aacbcaccf56740ce16a6c5544783d095 CODE_OF_CONDUCT.md
100644 blob f433b1a53f5b830a205fd2df78e2b34974656c7b LICENSE
100644 blob 413072d502db332006536e1af3fad0dce570e727 README.md
100644 blob 1dd7ed99019efd6d872d5f6764115a86b5121ae9 SECURITY.md
040000 tree 918756f1a4e5d648ae273801359c440c951555f9 build
040000 tree 219a6e58af53f2e53b14b710a2dd8cbe9fea15f5 design
040000 tree 5810c119dd4d9a1c033c38c12fae781aeffeafc1 docker
040000 tree f09c5708676cdca6562f10e1f36c9cfd7ee45e07 src
040000 tree e6e1595f412599d0627a9e634007fcb2e32b62e5 website

git commit -a(modify)

$ git commit -am 'Use blog link'
[master 68ed5aa] Use blog link
1 file changed, 1 insertion(+), 1 deletion(-)

更改内容如下:

--- commit      2023-07-02 15:33:28.536144046 +0530
+++ update 2023-07-02 15:47:20.841154907 +0530
@@ -17,6 +17,12 @@
│ │ └── 5b58f323d7b459664b5d3fb9587048bb0296de
│ ├── 62
│ │ └── 901ec0eca9faceb8fe0a9870b9b6cde75a9545
+│ ├── 67
+│ │ └── ed5aa2372445cf2249d85573ade1c0cbb312b1
+│ ├── 8a
+│ │ └── b377e2f9acd9eaca12e750a7d3cb345065049e
+│ ├── e5
+│ │ └── ec63cd761e6ab9d11e7dc2c4c2752d682b36e2
│ ├── info
│ └── pack
└── refs

新增了三个对象。一个是含有文件新内容的blob对象,还有一个是tree对象,以及一个commit对象。

再次从HEADrefs/heads/master开始追踪这些对象。

$ git cat-file -p refs/heads/master
tree 9ab377e2f9acd9eaca12e750a7d3cb345065049e
parent 3c201df6a1c4d4c87177e30e93be1df8bfe2fe19
author Abin Simon <mail@meain.io> 1688292975 +0530
committer Abin Simon <mail@meain.io> 1688292975 +0530

Use blog link

$ git cat-file -p 9ab377e2f9acd9eaca12e750a7d3cb345065049e
100644 blob e5ec63cd761e6ab9d11e7dc2c4c2752d682b36e2 file

$ git cat-file -p e6ec63cd761e6ab9d11e7dc2c4c2752d682b36e2
blog.meain.io

仔细观察会注意到commit对象现在有了一个额外的键名为parent,它链接到上一个提交,因为当前提交是基于上一个提交创建的。

git branch

git branch fix-url

--- update      2023-07-02 15:47:20.841154907 +0530
+++ branch 2023-07-02 15:55:25.165204941 +0530
@@ -27,5 +28,6 @@
│ └── pack
└── refs
├── heads
+ │ ├── fix-url
│ └── master
└── tags

此操作会在refs/heads目录下加入一个新的文件。该文件的名称就是我们新建的分支名,而内容则是最新的提交标识id。

$ cat .git/refs/heads/fix-url
68ed5aa2372445cf2249d85573ade1c0cbb312b1

这基本上就是创建分支的全部内容。在git中,分支是相当轻便的。另外,标签的创建也是类似的操作,但它们是被创建在refs/tags目录下。

logs目录下也新增了一个文件,该文件用于记录与master分支类似的提交历史信息。

git checkout

git中进行分支切换实际上是让git获取某个提交的tree对象,并更新工作区中的文件,使其与其中记录的状态相匹配。在此例中,由于我们是从master分支切换到fix-url分支,而这两个分支都指向同一个commit和它的tree对象,因此git在工作区的文件上并没有任何更改。

git checkout fix-url

在进行分支切换时,.git目录中唯一发生的变化是.git/HEAD文件的内容,现在它指向fix-url分支。

$ cat .git/HEAD
ref: refs/heads/fix-url

既然我们在这里,我将进行一个提交操作。这将有助于我稍后展示合并的效果。

$ echo 'https://blog.meain.io'>file
$ git commit -am 'Fix url'

git merge

有三种主要的合并方法。

  1. 最简单且直观的是快进式合并。这种方式中,你只是更新一个分支的提交,使其指向另一个分支的提交。具体操作就是把refs/heads/fix-url中的哈希值复制到refs/heads/master

  2. 第二种是变基(rebase)合并。在这种方式中,我们首先将更改依次应用到主分支当前的提交上,然后进行类似于快进式的合并。

  3. 第三种是通过创建一个独立的合并来合并两个分支。这种方法与前两者略有不同,因为它的提交对象会有两个parent条目。我们稍后会详细探讨这种方法。

首先,我们来看看合并前的graph。

git log --graph --oneline --all
* 42c6318 (fix-url) Fix url
* 67ed5aa (HEAD -> master) Use blog link
* 3c201df Initial commit

接下来进行合并:

$ git merge fix-url # updates refs/heads/master to the hash in refs/heads/fix-url

我们再来看看合并后的 graph。

$ git log --graph --oneline --all
* 42c6318 (HEAD -> master) (fix-url) Fix url
* 67ed5aa Use blog link
* 3c201df Initial commit

git remote

为了演示这个过程,我首先创建了一个新的git仓库作为这个仓库的远程连接。

$ mkdir git-talk-2
$ cd git-talk-2 && git init --bare
$ cd ../git-talk && git remote add origin ../git-talk-2

git init --bare用于在git中创建一个裸(bare)仓库,裸仓库则不包含工作目录,它只是一个.git目录,没有实际的项目文件。裸仓库通常被用作远程仓库,用于与其他开发者共享代码。它只包含Git版本控制所需的文件,因此更适合作为一个中心化的代码仓库。

当你在一个服务器上搭建Git仓库时,通常会使用裸仓库。这样其他开发者可以通过克隆(clone)这个裸仓库来获取项目代码,并将自己的更改推送(push)回去,而不会涉及到冗余的工作目录。

另外,添加新的远程仓库实际上是修改了配置文件,可以在.git/config中查看这个变更。接下来,执行推送操作。

$ git push origin master

再来检查一下本地仓库发生了哪些改变。

--- branch	2023-07-02 15:55:25.165204941 +0530
+++ remote 2023-07-02 17:41:05.170923141 +0530
@@ -22,12 +29,18 @@
│ ├── e5
│ │ └── ec63cd761e6ab9d11e7dc2c4c2752d682b36e2
│ ├── info
│ └── pack
├── ORIG_HEAD
└── refs
├── heads
│ ├── fix-url
│ └── master
+ ├── remotes
+ │ └── origin
+ │ └── master
└── tags

会发现新增了一个新的refs/remotes目录,这是用来存储不同远程仓库相关信息的。

但是,实际上传送到远程git仓库的数据是什么呢?那就是objects文件夹内的所有数据,以及你明确推送的refs下的分支和标签。仅凭这些,远程的git就能完整地构建出你的所有git历史记录。

大厂的Git代码管理规范

分支命名

  • master分支

master为主分支,也是用于部署生产环境的分支,需要确保master分支稳定性。master分支一般由release以及hotfix分支合并,任何时间都不能直接修改代码。

  • develop分支

develop为开发环境分支,始终保持最新完成以及bug修复后的代码,用于前后端联调。一般开发新功能时,feature分支都是基于develop分支创建的。

  • feature分支

开发新功能时,以develop为基础创建feature分支。

分支命名时以feature/开头,后面可以加上开发的功能模块,命名示例:feature/user_modulefeature/cart_module

  • test分支

test为测试环境分支,外部用户无法访问,专门给测试人员使用,版本相对稳定。

  • release分支

release为预上线分支(预发布分支),UAT测试阶段使用。一般由test或hotfix分支合并,不建议直接在release分支上直接修改代码。

  • hotfix分支

线上出现紧急问题时,需要及时修复,以master分支为基线,创建hotfix分支。修复完成后,需要合并到master分支和develop分支。

分支命名以hotfix/开头的为修复分支,它的命名规则与feature分支类似。

分支与环境对应关系

在系统开发过程中常用的环境:

  • DEV环境(Development environment):用于开发者调试使用。
  • FAT环境(Feature Acceptance Test environment):功能验收测试环境,用于测试环境下的软件测试者测试使用。
  • UAT环境(User Acceptance Test environment):用户验收测试环境,用于生产环境下的软件测试者测试使用。
  • PRO环境(Production environment):生产环境。

对应关系:

分支 功能 环境 可访问
master 主分支,稳定版本 PRO
develop 开发分支,最新版本 DEV
feature 开发分支,实现新特性
test 测试分支,功能测试 FAT
release 预上线分支,发布新版本 UAT
hotfix 紧急修复分支,修复线上bug

分支合并流程规范

业界常见的两大主分支(master、develop)、三个辅助分支(feature、release、hotfix)的生命周期:

image

以上生命周期仅作参考,不同开发团队可能有不同的规范,可自行灵活定义。

例如我们团队在开发时,至少需要保证以下流程:

  • develop分支和hotfix分支,必须从master分支检出。
  • 由develop分支合并到test分支。
  • 功能测试无误后,由test分支合并到release分支。
  • UAT测试通过后,由release分支合并到master分支。
  • 对于工作量小的功能开发(工时小于1天),可以直接在devolop分支进行开发,否则由develop分支检出feature分支进行开发,开发完后合并到develop分支。

Git Commit Message规范

Git Commit Message规范指提交代码时编写的规范注释,编写良好的Commit Message可以达到3个重要的目的:

  • 加快代码review的流程。
  • 帮助我们编写良好的版本发布日志。
  • 让之后的维护者了解代码里出现特定变化和feature被添加的原因。

Angular Git Commit Guidelines

业界应用的比较广泛的是Angular Git Commit Guidelines:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
  • type:提交类型。
  • scope:可选项,本次commit波及的范围。
  • subject:简明扼要地阐述下本次commit的主旨,在AngularGit Commit Guidelines中强调了三点。使用祈使句,首字母不要大写,结尾无需添加标点。
  • body:同样使用祈使句,在主体内容中我们需要把本次commit详细地描述一下,比如此次变更的动机。
  • footer:描述下与之关联的issue或break change。

简易版

项目中实际可以采用简易版规范:

<type>(<scope>):<subject>

type规范

Angular Git CommitGuidelines中推荐的type类型如下:

  • feat:新增功能。
  • fix:修复bug。
  • docs:仅文档更改。
  • style:不影响代码含义的更改(空白、格式设置、缺失分号等)。
  • refactor:既不修复bug也不添加特性的代码更改。
  • perf:改进性能的代码更改。
  • test:添加缺少的测试或更正现有测试。
  • chore:对构建过程或辅助工具和库(如文档)的更改。

除此之外,还有一些常用的类型:

  • delete:删除功能或文件。
  • modify:修改功能。
  • build:改变构建流程,新增依赖库、工具等(例如webpack、gulp、npm修改)。
  • test:测试用例的新增、修改。
  • ci:自动化流程配置修改。
  • revert:回滚到上一个版本。

单次提交注意事项

  • 提交问题必须为同一类别。
  • 提交问题不要超过3个。
  • 提交的commit发现不符合规范,git commit --amend -m "新的提交信息"git reset --hard HEAD重新提交一次。

配置.gitignore文件

.gitignore是一份用于忽略不必提交的文件的列表,项目中可以根据实际需求统一.gitignore文件,减少不必要的文件提交和冲突,净化代码库环境。

通用文件示例:

HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

# Log file
*.log
/logs*

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
*.cmd

其他

此外,还有一些其他建议:

  • master分支的每一次更新,都建议打tag添加标签,通常为对应版本号,便于管理。
  • feature分支、hotfix分支在合并后可以删除,避免分支过多,管理混乱。
  • 每次pull代码前,提交本地代码到本地库中,否则可能会出现合并代码出错,导致代码丢失。
 评论
评论插件加载失败
正在加载评论插件