一、本文介绍git rebase两种常用使用场景
-
本地分支合并多个commit为1个
-
多人合作开发时保持master或develop等公共分支的线性增长(不分叉)
二、准备工作
- 启动gitlab
首次启动:
docker run --name gitlab -d -p 5443:443 -p 5080:5080 -p 5022:22 -v /Users/sw/gitlab/config:/etc/gitlab -v /Users/sw/gitlab/logs:/var/log/gitlab -v /Users//sw/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce
非首次:
docker start gitlab
-
确保已经上传个人公钥到gitlab
-
确保宿主机用户目录下已经添加.ssh/config文件,其中有这么一段:
host mygitlab
user liuliangbin
hostname 127.0.0.1
port 5022
identityfile ~/.ssh/liuliangbin
-
登录gitlab,创建group:test,创建project:test
-
clone代码
git clone git@mygitlab:test/test.git
- 添加文件,创建develop分支
cd test
git checkout -b develop origin/develop
echo "a" > a.txt
git add a.txt
git commit -m "add a.txt"
git push
- 目前test项目develop分支只有一个commit:“add a.txt”
三、场景1: 个人分支合并commit
- 为了开发某个特性,用户创建个人分支feature1
git checkout -b feature1
- 第1天开发结束了,虽然代码不完整,而且还没跑通,但作为一个好的实践,保持每天commit代码
echo "b" >b.txt
git add b.txt
git commit -m "add b.txt"
- 第2天开发结束了,虽然代码不完整,而且还没跑通,但作为一个好的实践,保持每天commit代码
echo "c" >c.txt
git add c.txt
git commit -m "add c.txt"
- 第3天开发完成,代码完整
echo "d" >d.txt
git add d.txt
git commit -m "add d.txt"
-
合入develop之前,分支的commit情况
-
合入develop之前,最好把上图中3个commit变成1个,原因是:
这3个commit是为了开发一个特性所做的工作
每个commit都不是完整的,每个单独commit没有意义(如果checkout出来可能甚至无法构建) -
git rebase合并本地分支最近3个commit
git rebase -i HEAD~3
-i 表示弹出交互式界面,让用户编辑控制合并操作,弹出界面如下:
编辑后:
上图表示在cb0e82e这个commit的基础上合并其它commit,保存并退出编辑器后会弹出另一个编辑器:
p
s
s
在这里可以编辑3个commit合并后的提交信息,只有非注释部分有效,保存退出后:
p
s
s
查看本地commit:
发现已经把3个commit合为1个新的commit,这时候可以往develop上合入:
git checkout develop
git merge feature1
git push
四、场景2:保持分支线性
在多人协作场景中,随着每个人代码合入变多,commit历史将变成复杂的树形结构,为了保持简洁,可以强制团队成员:
git pull --rebase
具体描述如下:
- 作为对比先来看下不用git pull --rebase的情况, 用普通的git pull
(1)两个用户基于同一个master的commit开发不同功能
//用户1, 在git_test目录下操作
git clone git@mygitlab:test/test.git test
cd test
git checkout -b user1
echo "u1" > u1.txt
git add u1.txt
git commit -m "add u1.txt"
//用户2,在git_test目录下操作
git clone git@mygitlab:test/test.git test2
cd test2
git checkout -b user2
echo "u2" > u2.txt
git add u2.txt
git commit -m "add u2.txt"
(2)用户1从user1分支把代码合入master分支并推送到远程master
//在git_test/test目录下
git checkout master
git merge user1
git pull
git push
(3)用户2从user2分支把代码合入本地master并推送到远程master
//在git_test/test2目录下
git checkout master
git merge user2
git pull
//git pull执行后,会弹出编辑框产生额外一个合并commit
git push
(4)master的commit历史将呈现分支和合并结构
- 用git pull --rebase
(1)两个用户继续分别开发
//用户1:
git checkout master
git pull
//上面命令确保本地master分支是最新的
git checkout -b f1
echo "f1" > f1.txt
git add f1.txt
git commit -m "f1"
//用户2:
git checkout master
git pull
git checkout -b f2
echo "f2" > f2.txt
git add f2.txt
git commit -m "add f2.txt"
(2)用户1合入代码
git checkout master
git merge f1
git pull --rebase
git push
(3)用户2合入代码
git checkout master
git merge f2
git pull --rebase
git push
(4)master的commit历史将呈现结构:
可以观察到:
master分支的commit没有分支结构,也没有合并commit的情况,非常清爽。其中后合入的f2分支产生的commit就好像是基于f1分支的最新commit开发的,这就是git pull --rebase的效果
当然,如果git pull --rebase时有冲突,还是需要解决冲突,并用git rebase --continue继续rebase操作,或者用git rebase --abort中断rebase操作,回到rebase之前状态
有冲突时,如果冲突还没解决,执行git rebase --continue将不被允许,会报冲突未解决的错误
- 如果我们一开始就强制团队成员每次pull都要执行:git pull --rebase,master分支就不会分叉,保持非常清爽的线性结构
五、场景3:保持分支线性:在没有权限合入分支的场景
- 用户继续开发
//用户1:
git checkout master
git pull
//上面命令确保本地master分支是最新的
git checkout -b f1 origin/f1
echo "f1" > test.txt
git add test.txt
git commit -m "f1"
//用户2:
git checkout master
git pull
git checkout -b f2 origin/f2
echo "f2" > test.txt
git add test.txt
git commit -m "f2"
- 用户1合入代码
git checkout master
git pull --rebase
git checkout f1
git rebase -i master
git push f1 origin/f1
//申请把origin/f1合入origin/master分支
- 用户2合入代码
git checkout master
git pull --rebase
git checkout f2
git rebase -i master
//选择commit,解决冲突
git add test.txt
git rebase --continue
git push f2 origin/f2
//申请把origin/f2合入origin/master
- 管理员执行merge操作后,分支结构如下图
六、总结
git的rebase功能有两个常用场景:
合并本地分支(如feature分支)中多个commit为一个: git rebase -i HEAD~3
多人合作开发时保持分支线性无分支状态:
在有权限操作目标分支的情况下,可以在对应分支上(如master或develop上)执行:git pull --rebase
在无权限操作目标分支的情况下,可以在个人分支上(如feature分支)执行: git rebase -i develop
确保你的团队成员已经理解rebase概念,在实际开发中鼓励团队用起来!
内部资料 学习记录