作业,4个问题,记录一下。
一、你在一个分支工作,突然遇到紧急问题,要切换到另一个分支,但是当前的工作还没做完,没有ready-to-commit,如何暂时保存当前的工作内容?
Git建议,checkout分支时永远保持工作区的干净。首先,git commit
是可以达到目的的,但是你可能还没有ready to commit,这样会弄乱commit log。网上有人说,可以add但不commit,工作完了再回来,内容还在。我试了一下,发现切换到新的分支,旧分支暂存的内容还存在。这样就算切换到了新的分区,工作也会受干扰。
这里,推荐的方法是git stash。
“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。
如果遇到紧急事件需要切换分支,使用git stash
储藏当前分区,切换到别的分支工作,解决问题之后换到旧分区,使用git stash apply继续工作。
- 储藏是全局的,你不仅可以在使用
git stash
的分支使用git stash apply
,还可以在别的分区使用。(可能遇到冲突) - apply之后,储存并没有被删除(可以使用drop删除);使用pop命令可以“弹出”
- 也可以在当前分支存储之后,继续在当前分支工作。如果以后要合并存储,建议以分支形式合并
参考:git-scm
二、如何merge一个commit,而不是整个分支?
问题描述:github的一个仓库更新了一个新的feature,我想在我的环境中用这个feature,但是不想merge之前所有的commit,可以只merge这一个commit吗?
使用git cherry-pick
1 2 3 4 |
A-----B------C \ \ D |
之后变成:
1 2 3 4 |
A-----B------C \ \ D-----C' |
这样的merge,会在分支产生一个新的commit,log一样,id不一样。git把merge的这个提交当做是从HEAD过去的,也就是说,如果提交C中用到了提交B的一个函数,git并不会知道。
参考:http://stackoverflow.com/questions/880957/pull-all-commits-from-a-branch-push-specified-commits-to-another/881014#881014
三、如何撤销一次merge操作?
问题描述:现在有以下的情况,此时,C10是不小心合并的,我们不要合并tv/rebase-stat,需要re-merge这次merge。
第一种方法是,可以跳到C8,合并jk/post-checkout和db/push-cleanup。然后就变成了这样子:
这种做法的优点是,就和没有这次意外一样,所有的分支都能继续正常使用。缺点是:所有人都要执行这样的操作,而且如果已经发布merge,这么做就有困难。我讨厌这种做法,因为这是违背Git设计哲学的,所有的操作都应该向前,不能去修改历史。
另外,如果我们在不小心合并之后,进行了很多操作,“压住了”不小心的merge,如下图。如果使用第一种方法,就会丢掉后面的更新。
这里第二种方法,使用revert命令:
1 2 3 4 |
$ git revert -m 1 [sha_of_C8] Finished one revert. [master 88edd6d] Revert "Merge branch 'jk/post-checkout'" 1 files changed, 0 insertions(+), 2 deletions(-) |
其中,参数1是parent的哪一条主线,一般是1,有可能是2.如果不确定,可以使用git show --format="%P" <SHA>
查看。
就变成了这样:
这个做法,就好像git cherry-pick
所有C8中的提交一样,撤销所有提交的更新。相当于,我做了新的工作,内容就是把C8的内容改了回去,大家都pull一下就好啦。
但是这个方法存在的问题是,git认为,C5 C6已经被正确merge了,把^C8当做是新的commit对待。上文说道,我们只是“不小心”merge的,这时如果merge jk/post-checkout分支,只会mergeC6之后的。
如果^C8之后有很多更新,如何保留这些更新,再入merge之前re-merge的分支内容,我还没有找到合适的方法。
参考:
四、刚刚的提交有错误,需要修改?
如果是commit写错了,想修改一下。使用git commit --amend
,会打开编辑器,重新填写commit。关闭编辑器,新的log就覆盖掉了旧的,但是不会产生新的提交。但是id会变。
如果是有文件需要修改,直接做新的工作,将工作内容添加到暂存区,然后执行git commit --amend
,新的工作内容会补到上一次提交中。
注意,如果已经发布,就不能用这个命令了。