楔子
本文的有些 Git 命令是基于我本地的 Git alias, 如下做下解释:
- [alias]
- co = checkout
- st = status
- ci = commit
- br = branch
项目背景
开发项目特别是团队协作的项目, 每个项目组的人都会在本地建自己的项目分支, 同时远端会有自己的 repository, 功能需求代码完成后会先把代码 push 到远端自己的相应的分支下, 然后手动提交 PR 合到项目主线上来.
正常的代码提交流程
1. 基于 zaihui/dev 在本地新建一个 branch, 假如分支名叫做 my_branch:
- Git fetch zaihui
- Git co -b my_branch zaihui/dev
2. 本地分支 my_branch 开发, 开发完成后提交代码:
- Git st
- Git diff
- Git add .
- Git ci -m <commit_desc>/ Git ci -amend
- Git fetch zaihui
- Git rebase zaihui/dev
- Git push origin my_branch [-f]
3. 手动提交 PR, 将 origin/my_branch 合进 zaihui/dev
其中, Git add . 和 Git ci -m <cm_desc > 可以合并成 Git ci -am <cm_desc>
分支管理
- Git br
- Git br -v
- Git br -merged
- Git br -d/D <branch_name>
- Git br -M <old_branch_name> <new_branch_name>
拉取代码
尽量用 Git fetch + Git merge
少用 Git pull --- 相当于先 fetch 再 merge
变基 vs 合并
- Git rebase
- Git merge
变基使得提交历史更加整洁. 你在查看一个经过变基的分支的历史记录时会发现, 尽管实际的开发工作是并行的, 但它们看上去就像是串行的一样, 提交历史是一条直线没有分叉.
无论是通过变基, 还是通过三方合并, 整合的最终结果所指向的快照始终是一样的, 只不过提交历史不同罢了. 变基是将一系列提交按照原有次序依次应用到另一分支上, 而合并是把最终结果合在一起.
总的原则是, 只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作
Git stash/Git stash apply stash@{index}
Git stash / Git stash apply stash@{index} 这组命令可以使我们暂时保存当前的修改, 并在之后的某个时间将代码恢复. 它的用途非常广泛, 而且对于提高我们的工作效率非常有帮助. 它常常用于这样一种场景, 当我们在一个分支上工作时修改了很多代码, 但是任务还没完成, 还没有到能够提交代码的程度, 这时测试人员发现了一个非常严重的 bug, 需要我们紧急修复, 这时我们怎么做呢? 首先要做的就是先运行 Git stash 命令将这些修改暂存, 然后我们切换到 master 命令上去创建一个新的针对这个 bug 修复的分支, 并在这个新的分支上工作. 当我们完成修复工作后, 我们切换回到之前的分支上, 通过命令 Git stash stash@{index} 将之前暂存的改动提取出来, 继续我们的工作.
Git cherry-pick <commit_id>
Git cherry-pick <commit ID > 这条命令非常有意思, 它使我们可以在工作树上随意摘取一个或者一组 commit 到当前的分支. 这些 commit 可以是不同的 branch 上的. 这条命令的好处在于, 当我们在一个分支上面进行了代码修改并提交后, 有其他的分支也同样需要这些代码的时候, 可以通过 Git cherry-pick <commit ID > 命令将想要的 commit 摘取到当前的分支上, 并自动提交到本地仓库. 它常常用于这样的一种场景: 我们新创建了一个分支用于新的版本 1.0 的 release, 同时我们也维护着 master 分支的代. 当我们在 master 上面发现了 bug 并将其修复后, 我们同样也需要在 1.0 的分支上将这些修改拿过来, 此时 Git cherry-pick <commit ID > 就可以派上用场了, 它将这些修改的 commit 从 master 分支上摘取过来, 并自动提交到当前的分支.
Git pull -rebase/Git rebase -continue
这组命令主要用于从远程代码库拉取代码到本地, 主要针对在一个相同分支上的代码操作 (比如 master 分支). 试想一下, 当我们有多个人都在同一个分区上面进行代码操作时, 这时候我们拉取代码时会有多少冲突, 场面会有多么混乱. 如果我们使用 Git pull 或者 Git fetch 从远程拉取代码, 那么我们在提交自己新的代码时就会使得整个工作树变得非常凌乱. Git pull --rebase / Git rebase --continue 可以很好的解决这些问题. 首先我们将我们改动的代码提交到本地仓库, 然后利用 Git pull --rebase 命令将远程仓库的代码拉取到本地, 它将其获取的所有的 commit 放在我们新提交的 commit 的底部, 这步完成后可能会有冲突, 等我们将冲突解决完成后, 再利用 Git rebase --continue 命令将解决冲突后的代码提交到之前提交的代码中去. 通过这两步之后, 我们整个的工作树始终会保持在一条直线上, 而不会出现代码的 merge 分支的情况.
Git rebase -i/Git rebase -continue
与多人同时工作在一个相同的分支上相比, 我们一般真对每个 task 都会新建一个对应的 branch, 每个人仅仅工作在自己的分支上, 没有人会工作在 master 上, 当工作完成后才会将代码提交到 master 上去. 这样做的好处显而易见, 它使得我们无须同时操作相同的分支, 尤其是 master 的分支, 从而保证了 master 分支的整洁与安全. 那么这样做的一个关键在于我们在自己的分支上如何与 master 分支保持一致性. 实践中, 我们不应在工作切底完成之后, 再与 master 分支同步代码, 实践证明, 这样会导致大量的冲突, 我们应该做的是工作的每天都应该与 master 同步一次代码, 这里仅仅是从 master 同步新的代码, 而不应将自己的代码提交到 master 分支. Git rebase -i master 这条命令就是我们最好的工具. 它不仅可以让我们当前的分支从 master 同步最新的代码, 而且还可以将我们分支上的多个 commit 合并成为一个, 可以让 branch 更简洁, 毕竟 branch 上的代码都是为了实现一个功能. 如果同步时有冲突, 我们解决完冲突后, 使用 Git rebase --continue 将代码提交到先前的 commit 中去. 有了这两条命令, 我们在不同分支上的工作就会变得简单轻松.
来源: http://www.jianshu.com/p/dbf2661e4752