Git 规范

为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件。

commit

分支:master分支,每个任务一个分支(注意.gitignore)

  • fix:修复了bug
  • docs:只修改了文档
  • style:调整代码格式,未修改代码逻辑(比如修改空格、格式化、缺少分号等)
  • refactor:代码重构,既没修复bug也没有添加新功能
  • perf:性能优化,提高性能的代码更改
  • test:添加或修改代码测试
  • chore:对构建流程或辅助工具和依赖库(如文档生成等)的更改
1
2
3
# --pretty=oneline: commit 信息展示为行
# --abbrev-commit: 仅显示 commit id 的前几个标识符
git log --pretty=oneline --abbrev-commit

add

git add的反向命令git checkout,撤销工作区修改,即把暂存区最新版本转移到工作区。

例如,如果修改了某个文件,但是想回到特定版本,就可以使用如下命令。

1
2
3

git log file.java
git checkout hash file.java

git commit的反向命令git reset HEAD,就是把仓库最新版本转移到暂存区。

rm

手动删除文件,然后使用git add <file>git rm <file>效果是一样的。

有时候,发现有不该提交的文件已经提交后,仅仅在.gitignore中加入忽略是不行的。这个时候需要执行:

1
git rm -r --cached [被回收的文件]

去掉已经托管的文件,然后重新提交:

1
2
git add .
git commit -m ''

注意!git rm -r --cached 文件/文件夹名字 是高危操作,一定要指定文件名不能不写,否则 git rm -r --cached 会删除所有缓存,包括本地未提交的文件。

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
25
26
27
# 切换到旧分支
git checkout oldBranch

# 创建并切换至新分支
git checkout -b luorong

# 最新版本的Git提供了新的git switch命令来切换分支:
git switch -c 新的分支名
git switch 已有的分支名

# 更新分支代码并提交
git add *
git commit -m "init newBranch"
git push origin newBranch

# 查看所有分支
git branch -a

# 查看当前使用分支(结果列表前面*号,代表当前使用的分支)
git branch

# 合并分支
git merge 分支名

# 删除分支
git branch -d 分支名
git branch -D 分支名 # 强行删除

merge

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

1
2
# 因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
git merge --no-ff -m "merge with no-ff" dev

合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

restore

执行 ADD 后

1
2
3
4
git restore --staged [file] : 表示从暂存区将文件的状态修改成 unstage 状态。当然,也可以不指定确切的文件 ,例如:
git restore --staged *.java 表示将所有暂存区的java文件恢复状态
git restore --staged . 表示将当前目录所有暂存区文件恢复状态
--staged 参数就是表示仅仅恢复暂存区的

diff

虽然Git告诉我们readme.txt被修改了,但如果能看看具体修改了什么内容,自然是很好的。比如你休假两周从国外回来,第一天上班时,已经记不清上次怎么修改的readme.txt,所以,需要用git diff这个命令看看:

1
git diff 文件名

git diff 时是分为两种情况的:暂存区为空和暂存区不为空。

首先我们明确知道git diff是比较工作区和暂存区的文件的,如果此时暂存区为空,那么稍微有点不同,即:

1 暂存区为空使用git diff:因为此时暂存区为空,此时使用git diff同样也是比较工作区和仓库,即和使用git diff HEAD结果相同

2 暂存区不为空使用git diff:因为此时暂存区不为空,此时使用git diff比较的就是工作区和暂存区

reset: 回退到某个版本

首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1094adb…(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

现在,我们要把当前版本append GPL回退到上一个版本,就可以使用git reset命令:

1
git reset --hard HEAD^

Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL

git reflog用来记录你的每一次命令。

现在总结一下:

  • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset —hard commit_id。

  • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。

  • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本

注意:这里不会保存 add 后的文件。所以要用 stash。

更新 commit 的信息

经常 commit 错误信息。如何修改?分为如下三种情况:

  1. 刚刚 commit,还没有 push,使用 git commit —amend;
  2. 刚刚 push,要修改最近一个 push 的commit信息,使用 git commit —amend;
  3. 修改历史 push 的 commit 信息,使用 git rebase -i HEAD~n【其中的n为记录数】,配合2中的命令

stash: 把当前工作现场“储藏”起来,等以后恢复现场后继续工作

出现一个 bug,但是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?

Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 保存当前分支 dev 的内容
git stash
# 回到主分支,新建 bug 修复分支,修复 bug,回到主分支,merge 后回到 dev 分支
git switch master
git checkout -b issue-101
git add fixbug.txt
git commit -m "fix bug 101"
git switch master
git merge --no-ff -m "merge bug fix 101" issue-101
git switch dev
# 查看工作现场
git stash list
git stash apply stash@{0} # 第一种恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删
git stash pop # 第二种恢复,恢复的同时把stash内容也删了

在master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。

那怎么在dev分支上修复同样的bug?Git专门提供了一个cherry-pick命令,让我们能复制一个特定的提交到当前分支

tag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 打标签:git tag 标签名 commitId
git tag v0.9 f52c633
# -a指定标签名,-m指定说明文字
git tag -a v0.1 -m "version 0.1 released" 1094adb
# 查看标签,标签不是按时间顺序列出,而是按字母排序的
git tag
# 查看标签的详细信息
git show 标签名
# 删除标签:
git tag -d v0.1
# 推送某个标签到远程
git push origin <tagname>
# 一次性推送全部尚未推送到远程的本地标签
git push origin --tags

参考

  • 廖雪峰的 Git 教程
  • 阿里巴巴 Git commit 规范