Git的几个技巧

作业,4个问题,记录一下。

一、你在一个分支工作,突然遇到紧急问题,要切换到另一个分支,但是当前的工作还没做完,没有ready-to-commit,如何暂时保存当前的工作内容?

Git建议,checkout分支时永远保持工作区的干净。首先,git commit是可以达到目的的,但是你可能还没有ready to commit,这样会弄乱commit log。网上有人说,可以add但不commit,工作完了再回来,内容还在。我试了一下,发现切换到新的分支,旧分支暂存的内容还存在。这样就算切换到了新的分区,工作也会受干扰。

addbutnocommit

这里,推荐的方法是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

之后变成:

这样的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。

unmerge1

第一种方法是,可以跳到C8,合并jk/post-checkout和db/push-cleanup。然后就变成了这样子:

unmerge2

这种做法的优点是,就和没有这次意外一样,所有的分支都能继续正常使用。缺点是:所有人都要执行这样的操作,而且如果已经发布merge,这么做就有困难。我讨厌这种做法,因为这是违背Git设计哲学的,所有的操作都应该向前,不能去修改历史。

另外,如果我们在不小心合并之后,进行了很多操作,“压住了”不小心的merge,如下图。如果使用第一种方法,就会丢掉后面的更新。

unmerge3

这里第二种方法,使用revert命令:

其中,参数1是parent的哪一条主线,一般是1,有可能是2.如果不确定,可以使用git show --format="%P" <SHA>查看。

就变成了这样:

unmerge4-1

这个做法,就好像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,新的工作内容会补到上一次提交中。

注意,如果已经发布,就不能用这个命令了。



Leave a comment

您的电子邮箱地址不会被公开。 必填项已用*标注