赞
踩
今天遇到一个问题,本来在主分支上checkout了一条新分支出来工作,可是做一半的时候突然发现后续要做的东西依赖于另一条特性分支里面的代码。特性分支其实是已经推送到远程并且提交合并请求了,但是并没有及时合入。所以跟老大沟通了一下,先把远程的特性分支合入主分支,我本地再rebase一下最新的主分支。可是因为功能才完成一半,并不属于一个完整的commit,所以我先把代码用git stash
存了起来。本地rebase完执行git stash pop
的时候就出现了冲突。因为以前从来没有遇到过这种情况,所以一时不知道怎么处理比较好。网上查了资料,发现上面的做法不是很好,所以自己尝试着把问题处理了。
干讲命令的话估计不好理解,下面我通过一个例子来演示一下整个冲突出现和解决的过程。由于只是展示怎么解决冲突,不涉及具体生产时的工作流程,所以就直接在本地进行了。本文为了尽可能地把问题讲清楚,手动复现了冲突,所以冗余的内容较多,可能对于Git老手来说显得有点啰嗦,如果想直接看结论,请直接跳转到第六步。
第一步,我们先做好准备工作,初始化一个版本仓库,新建一个文件test并且提交,作为master分支上的根commit:
$ git init
$ touch test
$ git add test
$ git commit -m "init test"
[master (root-commit) c1f4cda] init test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
$ git log
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2 (HEAD -> master)
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第二步,切换到另一条分支上工作,新建另一个文件anothertest并提交commit,代表在新分支上的某个工作阶段的成果:
$ git checkout -b another
Switched to a new branch 'another'
$ touch anothertest
$ git add anothertest
$ git commit -m "init anothertest"
[another 66966d5] init anothertest
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 anothertest
$ git log
commit 66966d50a3128771bf70c06ab2b6bd05ef748337 (HEAD -> another)
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:14:56 2017 +0800
init anothertest
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2 (master)
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第三步,在another分支上修改test和anothertest文件的内容,使用git stash
进行暂存,代表工作一半的成果,无法作为一个完整的commit进行提交:
$ vim test
$ vim anothertest
$ git stash
Saved working directory and index state WIP on another: 66966d5 init anothertest
$ git stash list
stash@{0}: WIP on another: 66966d5 init anothertest
第四步,回到master分支,修改test文件并提交commit,模拟master分支出现了another分支需要使用的代码。这个时候分支树出现了分叉,master分支和another分支各自往前进行了一个commit:
$ git checkout master
Switched to branch 'master'
$ vim test
$ git add test
$ git commit -m "changes on branch master"
[master 9bc290f] changes on branch master
1 file changed, 1 insertion(+)
$ git log
commit 9bc290f5b6cea5757e01af64ea8c2591c9debdf9 (HEAD -> master)
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:18:11 2017 +0800
changes on branch master
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第五步,再回到another分支,使用git rebase
进行变基,模拟another分支取得master分支上的最新代码,这时分支树又变成了一条直线:
$ git checkout another
Switched to branch 'another'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: init anothertest
$ git log
commit 0687e2a2f0d243a725de6093d9f42de5ab02acfd (HEAD -> another)
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:14:56 2017 +0800
init anothertest
commit 9bc290f5b6cea5757e01af64ea8c2591c9debdf9 (master)
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:18:11 2017 +0800
changes on branch master
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2
Author: ganziqim <ganziqim@live.com>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第六步,事情进展到目前来看,都非常顺利,特性分支成功地取得了主分支上需要用到的代码。但是当我们执行git stash pop
想取出之前工作一半的成果之后,却出现了冲突,其原因是主分支上的最新代码和stash暂存的代码对同一个文件都进行了修改。
$ git stash pop
Auto-merging test
CONFLICT (content): Merge conflict in test
$ git status
On branch another
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: anothertest
Unmerged paths:
(use "git reset HEAD <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: test
用git status
查看状态的时候,可以看到Git是有标出冲突的文件的,是不是很熟悉呢?对,这个时候先按照解决普通的pull conflict的方式修改文件,然后执行git add
。如果完全接受主分支的修改,那么再次查看git status
的时候这个文件应该不会再出现在状态里了,但这里我们模拟的是冲突两边的修改我们都想保留的情况。这时候代表你个人已经接受当前的冲突解决了,Git会把修改完的结果包括其它没有出现冲突的文件放入暂存区。
$ vim test
$ git add test
$ git status
On branch another
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: anothertest
modified: test
其实事情进行到上面那一步已经算作解决了,可是有时候你并不想把这些文件中的某一个作为下个commit的内容提交到远程,所以此时再执行一次git reset HEAD
,就恢复git stash pop
后该有的状态了。
$ git reset HEAD
Unstaged changes after reset:
M anothertest
M test
$ git status
On branch another
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: anothertest
modified: test
no changes added to commit (use "git add" and/or "git commit -a")
需要注意的是,冲突解决之后,Git并不会删除之前的stash记录,可以使用git stash drop
将没用的记录删除掉。
$ git stash list
stash@{0}: WIP on another: 66966d5 init anothertest
$ git stash drop stash@{0}
Dropped stash@{0} (113018d1c2be77ffae51afc15944d8620619ef7d)
$ git stash list
Git属于越用越顺手的东西,并且有很多实用的骚操作技巧,所以建议大家平时多多练习,没事多捣鼓捣鼓,熟能生巧嘛!而且我是推荐直接使用命令行的,GUI工具虽然方便,但有时候处理问题的速度跟不上思维,而使用命令行更顺手,尤其是专注工作,脑子快速运转的时候。相信你会爱上那种感觉的!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。