git rebase最主要的功能:通过移动某些commit,将当前分支的起始节点重置为目标分支,并且最终
实验 准备2个分支首先,初始化一个仓库:
mkdir git-rebase cd git-rebase git init # 添加一个空文件 touch a.txt git add a.txt # 初始提交 git commit -m "init" # 创建feat分支 git checkout -b feat
我们将会在这个仓库上建立两个分支:master和feat;仓库中我们建立一个a.txt文件用于测试。
master分支将会对a.txt文件进行两次修改,feat分支也会对a.txt文件进行两次修改。
最终我们会在feat分支上rebase master,看看会有什么结果。
master分支修改a.txt:
git checkout master echo -ne 'first line by masternsecond line by mastern' > a.txt git add a.txt git commit -m "master add first line and second line" echo -ne 'FIRST line by masternsecond LINE by masternTHIRD LINE by mastern' > a.txt git add a.txt git commit -m "master add thrid line, and change letter in first line and second line"
git log:
feat分支修改a.txt:
git checkout feat echo -ne 'first line by featnsecond line by featnthird line by featn' > a.txt git add a.txt git commit -m "feat add first,second and third line" echo -ne 'first line BY featnsecond line BY featnthird line BY featn' > a.txt git add a.txt git commit -m "feat change change letter in first,second and thrid line"
git log:
git checkout feat git rebase master
我们必须清楚rebase的过程,即先计算两个分支的最近起点,然后将差异的分支依次移动到目标分支上。在这个移动的过程中,目标分支是作为基准的,所以用"us",“ours”, “current"指代;差异分支是作为引入分支,所以用"theirs”,"incoming"指代。
feat的第1个commit
在这里,最近的共同提交是init。因此,差异分支是feat的两次提交,基准则是master的最后一次提交。
因为这两次提交都修改了a.txt文件,所以产生了冲突。我们合并冲突,分别保留部分:
feat的第2个commit
继续合并:
git add a.txt git rebase --continue
继续合并,feat的第二次提交与刚才的commit也产生了冲突,编辑文件内容,提交后使用git log查看:
rebase的操作就是将当前分支的差异移动到目标分支上。其结果就是差异分支全都基于目标分支。
在rebase过程中skip掉的那些commit不会影响最终形成的结果。因为,假设中间所有的commit都skip了,最后一个commit结果仍然是以最后一个差异commit来合入基准分支的,因此不会导致结果丢失。
rebase结束后,除了skip掉的commit,所有的commit都会有形成新的提交记录。
–skipskip,即跳过当前分支,最终rebase的历史记录中不会体现这次提交。
当所有的commit都被skip掉时,最终就是与目标分支相同,等价于:git reset --hard target
当除了最后一个commit被合入,其他commit都被skip掉时,其操作等价于cherry-pick。
squash可以使用git rebase -i COMMIT来“交互式”的选择需要squash的项:
前面的行列出的是所有的commit,pick表示保留,squash表示将会与其他提交被合并。
git rebase --edit-todo可以继续编辑这个文件。
使用git merge --squash可以在merge时将提交合并成一个。



