Git实用技巧

464 阅读6分钟

Git是非常强大的版本控制系统,但很多时候我们只是简单使用add commit。好多强大的功能都没有了解。这篇文章就是利用git的强大功能解决日常开发中遇到的场景。

常用开发模式

使用Git管理项目常见的做法是使用:

  • master分支用作发布版本的分支,并给每个release版本打上tag。
  • dev分支作为主开发分支,完成日常的开发工作。
  • 新功能的开发应单独拉一个分支进行开发,完成开发后再合并到dev分支。

例如,你领到一个需求(或bug修复),首先从dev分支checkout出一个分支用于完成需求或者修复bug,完成之后提测,测试通过之后再合并到dev分支,并删除开发用的分支。

习惯

使用git一定要养成一些好习惯,这些习惯可以极大地方便遇到突发状况时,使用git来解决问题。

  • 尽可能的拆分commit,一个commit应该只包含一个功能点或者bug的修改。开发新功能时经常会来回改动,拆分的commit有助于找回误修改的代码。这个习惯还可以有效应对需求临时变更。
  • 每个新功能都启用一个分支进行开发,并在开发测试都完成之后才合并到dev主干。
  • 每次提交的注释应详细说明该次提交修改的内容,方便之后快速了解每次提交都做了什么。版本回退的时候就知道了!

选取分支中的某几次提交:cherry-pick

有这样一种场景,需要把一个分支的某几次提交合并到另一个分支上,例如下面这个例子,master和dev分支同时开发并做了修改,假设现在我们需要把dev分支的“dev 1”提交合并到master分支上,但是并不需要“dev 2”的提交:

这种情况可以使用cherry-pick来完成这样的操作,我们先要获取到“dev 1”提交的commit id:

> git checkout dev
> git log 
commit 5a559a07ead0f8e6c64006ed2a46c310334ceea7
Author: saber <654360340@qq.com>
Date:   Thu Apr 19 16:44:38 2018 +0800

    dev 2

commit 68e7826fd4f5b72f4947d77e939273211edf7785
Author: saber <654360340@qq.com>
Date:   Thu Apr 19 16:44:08 2018 +0800

    dev 1

commit 490de7683fa3331c2cb115e397bc63429dfb3911
Author: saber <654360340@qq.com>
Date:   Thu Apr 19 16:41:20 2018 +0800

    create

只有在切回master分支,使用cherry-pick 选取该次commit:

> git checkout master
Switched to branch 'master'
> git cherry-pick 68e7826fd4f5b72f4947d77e939273211edf7785

这个时候可能会发生冲突:

error: could not apply 68e7826... dev 1
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

解决冲突之后,add,commit:

> git add .
> git commit -m "cherry-pick dev 1"
[master a173504] cherry-pick dev 1
 Date: Thu Apr 19 16:44:08 2018 +0800
 1 file changed, 1 insertion(+), 3 deletions(-)

删除commit

这也是经常会出现一种情况,我们需要删除历史的某次或者某几次提交。

删除最近的一次提交

这里要分情况,如果是删除最近的一次提交,比较方便。例如下面这个例子,我们需要删除(撤销)“dev something”的提交。

直接使用

> git revert HEAD
[master a45ac9f] Revert "dev something"
 1 file changed, 4 deletions(-)

注意这里是revert,不是reset。revert是放弃指定提交的修改,但是会生成一次新的提交,需要填写提交注释,以前的历史记录都在。

也可以使用reset,reset是指将HEAD指针指到指定提交,历史记录中不会出现放弃的提交记录。

> git reset --hard HEAD^

可以看到使用reset是没有记录的:

两种方式的区别就是有没有记录,推荐还是用revert。

删除历史提交

很多情况是删除之前的提交,例如,我们需要接着删除“maser change 1”的提交,该次提交并不是最近一次提交。
这种情况需要先用git log命令在历史记录中查找到想要删除的某次提交的commit id。(由此可见提交的注释很重要,一定要认真写)

> git log
commit a1735049d5eab665adcbdfa26668b99ed24390e9
Author: saber <654360340@qq.com>
Date:   Thu Apr 19 16:44:08 2018 +0800

    cherry-pick dev 1

commit bc3c7f7d117bdeb111d7f9aea51c3aaa6d272e6d
Author: saber <654360340@qq.com>
Date:   Thu Apr 19 16:46:08 2018 +0800

    master change 1

commit 490de7683fa3331c2cb115e397bc63429dfb3911
Author: saber <654360340@qq.com>
Date:   Thu Apr 19 16:41:20 2018 +0800

    create

然后执行以下命令(”commit id”替换为想要删除的提交的”commit id”,需要注意最后的^号,意思是commit id的前一次提交):

git rebase -i "commit id"^

执行该条命令之后会打开一个编辑框,内容如下,列出了包含该次提交在内之后的所有提交。

pick bc3c7f7 master change 1
pick a173504 cherry-pick dev 1

# Rebase 490de76..a173504 onto 490de76 (2 commands)

然后在编辑框中删除你想要删除的提交所在行,这里我们删除pick bc3c7f7 master change 1这行。 然后保存退出就好啦,如果有冲突的需要解决冲突。
我遇到了冲突:

error: could not apply a173504... cherry-pick dev 1

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
Could not apply a1735049d5eab665adcbdfa26668b99ed24390e9... cherry-pick dev 1

解决完冲突后执行continue,但是提示:

> git rebase --continue
a.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

其实这时候修改冲突之后需要add一下,才能continue,编辑commit(也可以保持原样)完成修改:

> git add .
> git rebase --continue
[detached HEAD e9ef87e] cherry-pick dev 1
 1 file changed, 2 insertions(+)
Successfully rebased and updated refs/heads/master.

这种修改方式实际上是把从选中commit之后的所有提交撤销,再选择需要的commit(删除不需要的),重新添加。

储藏未完成的修改:stash

经常会有这种情况:你开发一个新任务到一半,接到一个紧急bug修复需求。你不得不切换到bug分支进行修改,但是你并不想提交开发到一半的内容。这时候可以使用git stash命令。
.3 Git 工具 - 储藏(Stashing)