1. 基本概念
仓库
说明:
workspace:工作区
staging area:暂存区/缓存区
local repository:版本库或本地仓库
remote repository:远程仓库
2. 基本操作
2.1 一个简单的操作步骤:
$ git init
$ git add .
$ git commit
------------
$ git clone
2.2 常用查看命令
$ git status
$ git diff
$ git log
$ git blame
2.3 远程操作
$ git remote
$ git fetch
$ git pull
$ git push
3. 进阶操作
$ git reset
$ git rm
$ git mv
$ git tag
4. 高级操作
git rebase
git branch
5. 子模块
git submodule
操作示例
1. 新建git工程
git clone [email protected]:yh_cv/git_test.git
cd git_test
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
注:使用gitlab新建空白工程之后,会有相关提示操作
1.1 暂存
git stash
2. 分支操作
2.1. 新建devel分支
git branch devel
2.2 切换到新分支
git checkout devel
2.3 在新分支进行开发操作
touch fileB.txt
git add
git commit
2.3 将devel分支修改合并到master分支
git checkout master
git merge devel
假如两个分支都做了修改
3. 高级操作 rebase
3.1 作为更灵活的merge
比如:在devel分支做开发,提交了几次bugfix之后,需要将master分支上的新提交合并,此时可直接在devel分支上运行:
git rebase master
git会默认 寻找当前分支和目标分支共同点【根】,然后基于此合并两个分支的内容,如果两个分支同时修改了某一个文件,则会出现合并冲突,处理冲突的方法有三种:
-
- 手动修改冲突文件,可以借助IDE实现 ,然后使用
git add/rm
git rebase --continue
Q1:rebase 的过程是怎样的?
A1:我们知道rebase 的过程首先会产生 rebase 分支(master)的备份,放到(no branch )临时分支中。再将支线分支(branch)的每一次提交修改,以补丁的形式,一个个的重新应用到主干分支上。这个过程是一个循环应用补丁的过程,期间只要补丁产生冲突,就会停止循环,等待手动解决冲突。这个冲突指的是上一个合并后版本与补丁之间的冲突。
-
- 跳过这次提交
git rebase --skip 命令,可以跳过某一次补丁(存在上一轮冲突的解决方案中,已经包含了这一轮的补丁内容,这样会使补丁无效,需要跳过)
git rebase --skip
慎用,不推荐
- 跳过这次提交
-
- 终止合并
git rebase --abort
- 终止合并
3.2 合并多次提交
在日常开发中,代码变更比较频繁,有时候想让前几次提交的合并为一次提交,这里可以使用git rebase -i 命令来完成。
格式:git rebase -i [startpoint] [endpoint]
其中-i的意思是–interactive,即弹出交互式的界面让用户编辑完成合并操作,[startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。
- 先使用
git log --oneline
查看 commit id - 使用
git rebase -i
或者 git rebase -i HEAD~2 - 在弹出的编辑器里进行合并操作
里面的提示有:
pick:保留该commit(缩写:p)
reword:保留该commit,但我需要修改该commit的注释(缩写:r)
edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)
squash:将该commit和前一个commit合并(缩写:s)
fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)
exec:执行shell命令(缩写:x)
drop:我要丢弃该commit(缩写:d)
一般的操作是
然后在新弹出的编辑页面修改commit message 信息,注意:使用[#]注释掉的内容都不会保留在最终的commit message中
保存即可
4. 高级操作之 reset / revert
- git reset 命令用于回退版本,可以指定退回某一次提交的版本。
- git revert 表示回退到历史版本,但是作为新的一次提交保留
区别:
- git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit
- git revert 回滚指定的commit, git reset 将当前HEAD指向指定commit
注:如果回滚指定commit时,与当前HEAD有共同修改的文件,则会CONFILICT,可进行冲突合并
5. 高级操作之 submodule
5.1 添加子仓库
$ git submodule add <仓库地址> <本地路径>
添加成功后,在父仓库根目录增加了.gitmodule文件。
[submodule "sub"]
path = lib
url = xxxxx.git
并且在父仓库的git 配置文件中加入了submodule段。
$ cat .git/config
// 加了submodule段
[submodule "sub"]
url = xxxxx.git
5.2 检出(checkout)
克隆一个包含子仓库的仓库目录,并不会clone下子仓库的文件,只是会克隆下.gitmodule描述文件,需要进一步克隆子仓库文件。
// 初始化本地配置文件
$ git submodule init
// 检出父仓库列出的commit
$ git submodule update
或者使用组合指令
$ git submodule update --init --recursive
5.3删除子仓库
删除.gitsubmodule里相关部分
删除.git/config 文件里相关字段
删除子仓库目录。
$ git rm --cached <本地路径>
如果未按照上述步骤删除,可能残留在.git/modudles文件夹内。
5.4 Git 之 revert
revert 可以取消指定的某次提交内容。
当讨论 revert 时,需要分两种情况,因为 commit 分为两种:一种是常规的 commit,也就是使用 git commit
提交的 commit;另一种是 merge commit,在使用 git merge
合并两个分支之后,你将会得到一个新的 merge commit。
merge commit 和普通 commit 的不同之处在于 merge commit 包含两个 parent commit,代表该 merge commit 是从哪两个 commit 合并过来的。
在上图所示的红框中有一个 merge commit,使用 git show
命令可以查看 commit 的详细信息
➜ git show bd86846
commit bd868465569400a6b9408050643e5949e8f2b8f5
Merge: ba25a9d 1c7036f
这代表该 merge commit 是从 ba25a9d 和 1c7036f 两个 commit 合并过来的。
而常规的 commit 则没有 Merge 行
➜ git show 3e853bd
commit 3e853bdcb2d8ce45be87d4f902c0ff6ad00f240a
(1) revert 常规 commit
使用 git revert
即可,git 会生成一个新的 commit,将指定的 commit 内容从当前分支上撤除。
(2) revert merge commit
revert merge commit 有一些不同,这时需要添加 -m
选项以代表这次 revert 的是一个 merge commit
但如果直接使用 git revert
,git 也不知道到底要撤除哪一条分支上的内容,这时需要指定一个 parent number 标识出"主线",主线的内容将会保留,而另一条分支的内容将被 revert。
如上面的例子中,从 git show
命令的结果中可以看到,merge commit 的 parent 分别为 ba25a9d 和 1c7036f,其中 ba25a9d 代表 master 分支(从图中可以看出),1c7036f 代表 will-be-revert 分支。需要注意的是 -m 选项接收的参数是一个数字,数字取值为 1 和 2,也就是 Merge 行里面列出来的第一个还是第二个。
我们要 revert will-be-revert 分支上的内容,即 保留主分支,应该设置主分支为主线,操作如下:
➜ git revert -m 1 bd86846
一些其他概念表示:
- HEAD 表示当前仓库空间所指向的commit提交
- ^ 表示基于指定提交的上一次,可以使用多个,比如HEAD^^
- ~
直接使用数字表示基于指定提交的向上几次,比如HEAD~2
GIT commit message 常用规范
每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。
():
// 空一行
// 空一行
type
type:用于说明 commit 的类别,比如使用下面7个标识。
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
scope
scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
subject
subject是 commit 目的的简短描述,不超过50个字符。
以动词开头,使用第一人称现在时,比如change,而不是changed或changes
第一个字母小写
结尾不加句号(.)
Body
Body 部分是对本次 commit 的详细描述,可以分成多行
Footer
Footer 部分只用于两种情况。
(1)不兼容变动
如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。
BREAKING CHANGE: isolate scope bindings definition has changed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
}
After:
scope: {
myAttr: '@',
}
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
(2)关闭 Issue
如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。
Closes #234
也可以一次关闭多个 issue 。
Closes #123, #245, #992
Revert
还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。
revert: feat(pencil): add 'graphiteWidth' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
Body部分的格式是固定的,必须写成This reverts commit hash.,其中的hash是被撤销 commit 的 SHA 标识符。
Git 命令图谱
Git常用命令速查表
Git 修改已提交 commit 的信息
# 修改最近提交的 commit 信息
$ git commit --amend --message="modify message by xxx" --author="xxx "
# 仅修改 message 信息
$ git commit --amend --message="modify message by xxx"
# 仅修改 author 信息
$ git commit --amend --author="xxx "
参考资料
- 官方参考文档
- 可视化教程
- branch 可视化
- 子模块
子模块操作