分支基础
- 在不同的分支可以同时进行不同的任务,互相不干扰,任务完成后再合并
- 分支本质上只是一个指向commit object的一个指针
- 分支指针一定是指向当前分支最新的commit object
- 当前处于哪一个分支是由HEAD指针指向哪一个分支指针决定的
新建分支
git branch <branch>
创建名为branch的分支
新建testing分支后示意图(未示意HEAD指针和tag)
切换分支
- 切换分支后,工作区和暂存区的状态会转换为该分支的最后提交的代码状态
git switch <branch>
或git checkout <branch>
切换到名为branch的分支git switch -c <branch>
或git checkout -b <branch>
创建并切换分支
查看分支
git branch
查看分支git branch -v
分支信息加上该分支最后一次提交的信息git branch --merged
查看已经合并到当前分支的分支信息git branch --no-merged
查看未合并到当前分支的分支信息git diff <first-branch> <second-branch>
查看两个分支的差异
删除分支
git branch -d <branch>
删除名为branch的分支git branch -D <branch>
强制删除未被合并的branch分支
合并分支
基础合并
git merge <branch>
当前所在的分支合并名为branch的分支git merge -m "<comment>" <branch>
非快进合并加上合并的提交注释
快进合并
-
快进(fast forward)合并,要合并的分支在当前分支的直接下游,即可使用快进合并,直接移动分支指针完成合并
合并后
-
git merge --no-ff <branch>
强制禁止快进合并,则生成一次合并的提交
三方合并
- 要合并的分支不在当前分支的直接下游,不可使用快进合并的情况下,则使用三方合并
- 三方合并前后对比示意图,三方合并将生成一次合并提交
git merge --no-commit <branch>
可以延迟合并的生成,让你可以在合并之后提交之前再作改动
解决合并冲突
- 合并发生冲突后,使用
git status
可以查看当前未解决冲突的文件 - 未解决冲突的文件,Git将自动在冲突的部分加上不同版本的修改信息
git checkout --conflict=diff3 <file>
冲突三方比较git checkout --ours <file>
git checkout --theirs <file>
使用单方面代码快速解决冲突git merge -Xours <branch>
git merge -Xtheirs <branch>
单方面代码快速解决冲突合并git log --oneline --left-right --merge
冲突相关提交日志- 解决好冲突后,加入暂存区并提交即可完成合并
git merge --abort
中断合并,尝试恢复到你运行合并前的状态
但当运行命令前,在工作目录中有未储藏、未提交的修改时它不能完美处理,除此之外它都工作地很好。
git reset --hard HEAD
另一种中断合并的方式git reset --hard HEAD^
撤销合并git revert -m <n> <commit-id>
增加一个提交用于撤销合并,n=1保留合并前的HEAD,n=2保留另一分支撤销合并后又要再合并,先撤销之前的撤销合并提交
假合并
git merge -s ours <branch-name>
不管有没有冲突,代码全用当前分支的,并没有真正合并,只是标记合并
squash
git merge --squash <branch>
将branch的所有提交压缩成一个变更集,应用到当前分支,不会自动生成提交,合并后的提交只会有一个父提交
变基
常见变基
git rebase <base-branch>
当前分支以base-branch为基础变基 变基前变基后,可快进合并分支(当前分支experiment 执行
git rebase master
)git rebase --onto <base-branch> <excluded-branch> <included-branch>
执行
git rebase --onto master server client
后git rebase <base-branch> <rebase-branch>
无需先把rebase-branch切换到当前分支的变基
变基原则
-
不要对在你的仓库外有副本的分支执行变基
-
变基解决变基
git fetch <remote>
后git rebase <remote-branch>
git pull --rebase
变基 vs. 合并
至此,你已在实战中学习了变基和合并的用法,你一定会想问,到底哪种方式更好。在回答这个问题之前,让我们退后一步,想讨论一下提交历史到底意味着什么。 有一种观点认为,仓库的提交历史即是记录实际发生过什么。它是针对历史的文档,本身就有价值,不能乱改。从这个角度看来,改变提交历史是一种亵渎,你使用谎言掩盖了实际发生过的事情。如果由合并产生的提交历史是一团糟怎么办?既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。 另一种观点则正好相反,他们认为提交历史是项目过程中发生的事。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。持这一观点的人会使用rebase及filter-branch 等工具来编写故事,怎么方便后来的读者就怎么写。 现在,让我们回到之前的问题上来,到底合并还是变基好?希望你能明白,这并没有一个简单的答案。Git是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。 总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。
cherry-pick
git cherry-pick <commit-id>
把commit id这次提交提取出来,提交到当前分支
变基冲突
- 变基过程中出现冲突,则需要手动修改冲突,处理完后执行
git rebase --continue
- 若发生冲突后不希望继续进行变基,则执行
git rebase --abort