快速定位版本
快速定位版本是通过git bisect命令完成的,git bisect提供了二分查找方法让我们快速地定位出首次发生指定内容变更的版本。使用git bisect的一般思路是先给出查找的版本范围(一个版本存在着我们要查找的内容,另一个版则没有)并命名,git bisect会自动切换到这个范围中的一个版本,让用户(或通过脚本)判断该版本是否存在要查找的内容,直到找出第一次出现查找内容的版本。
默认可对版本范围命名的词对有:good/bad,new/old。也可以在开始二分查找时指定:
git bisect start --term-old <term-old> --term-new <term-new>
git bisect一般操作流程(如要找出bug是由谁产生,bad用于标记存在该bug的版本,good用于标记不存在该bug的版本):
- 开始二分查找
git bisect start - 标记当前版本为bad
git bisect bad
- 标记v2.1.3版本为good
git bisect good v2.1.3
- 此时
git bisect会自动切换到一个版本。标记这个版本是bad还是good,让二分查找算法继续下去。
git bisect good
- 查找到分支后,退出二分查找
git bisect reset
上面使用git bisect的一般过程示例,但如果我们可以提供一些预知条件,让二分查找更快结束。
如已知bug是由于修改了某个(或某些)文件导致的,可以让二分查找只查找修改了指定文件的版本号:
git bisect start -- <the files caused bug>
也可以在开始二分查找命令中指定good/bad版本的范围:
git bisect start <bad version> <good version> -- <the files caused bug>
也可以将good/old,bad/new的判断工作交给脚本,脚本返回0意味着是good/old,返回1~124即是bad/new,返回125就是skip了。如:
$ git bisect start HEAD origin -- # HEAD is bad, origin is good
$ git bisect run make test # "make test" builds and tests
$ git bisect reset # quit the bisect session
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
$ git bisect reset # quit the bisect session
提交整理
我们在日常工作中可能要移除某些提交,又或者需要把某些提交嫁接到其他提交之上,git提供了git rebase功能实现这个功能。先看看git rebase的基本使用方式:
git rebase --onto <newbase> <upstream> [<branch>]
以上命令的执行步骤可以描述如下:
- 如果有提供branch,则执行`git checkout branch
- 临时保存upstream..HEAD之间的提交列表,这些提交不包含upstream的所有提交。
- 如果有提供
--onto newbase,则执行git reset --hard newbase,否则执行git reset --hard upstream - 把临时保存的提交列表按顺序逐个应用到HEAD中。
- 提交都成功添加到HEAD之后,将HEAD恢复到branch(如果有提供的话)或恢复到执行
git reset前所在的分支
使用示例(当前所在分支是topic):

git rebase另一个更强大的用法是在上面命令的基础上添加 -i| --interactive选项:
git rebase [-i| --interactive] --onto <newbase> <upstream> [<branch>]
这个选项的作用是让用户可以编辑upstream..HEAD之间的提交列表,可编辑选项在执行命令时有详细的提示:
pick f67772d third commit
pick f0e0f29 modified forth commit
# Rebase 878ce51..f0e0f29 onto d6f0d63 (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
从上面可以看到,这个提交列表实际上是一个待执行的命令列表,用户可以使用注释中提及的命令来修改这个列表。
上面的示例忽略了在使用git rebase时出现冲突的处理。当在rebase过程中出现冲突,可以修复完冲突后执行git add filename,再执行git rebase –continue继续执行命令列表。另外,也可以执行git rebase –abort中断rebase过程,恢复到执行rebase之前的状态。
注意git rebase –quit也会中断rebase过程,但不会恢复到rebase之前的状态(不会恢复到执行rebase之前的分支,而且已经执行的命令也不会回滚)
强制推送分支
git push -f origin dev