其实上一篇写的内容仅仅是 Git 的冰山一角,如果你认为 Git 就是简简单单的几行命令,那只能说明你还没有真正了解 Git 这个强大的内容寻址文件系统。这篇文章,还是接着介绍一些实用但是很少有人知晓的一些命令,好比说具有魔性的 Git 变基 (git rebase) 以及常用的 GUI。
我之前询问过一些人,讨论到 Git 这块,他们当中有的直接使用 GUI,说简单省事。其实,每一个 GUI 都有它的侧重点,并不是所有的 GUI 都适合用。我倒是建议大家使用命令行。何况有些功能 GUI 不一定支持,而且有时候一行命令的事,还要点来点去,也不省事。之前看到过一篇文章,是关于如何使用 Vim 编辑器的,对,大家平时开发习惯了 IDE,爱上了 IDE。但是好的程序员怎么会因为简单省事而放弃学习呢。这样说可能更好提现,学习任意一款 IDE,你都需要耗时很久,但是如果你平时习惯了使用 Vim 编辑器,爱上用 Vim 编辑器写代码,那么任意一款集成 Vim 编辑器的 IDE,一上来就会非常顺手。同样的道理,如果你了解了 Git 内部原理,平时习惯使用命令处理,那么给你任意一款 GitGUI,相信你一看就会用,而且很快就上手。所以,学习顺序有时候很重要,基础扎实了,才不会被问题难倒,地基决定高度。
默认使用 Vim 编辑器,当然可以使用 core.editor 修改
- git config--global core.editor emacs
默认使用 less,可以使用 core.pager 来设置为 more 或则其他,也可以使用空字符串,关闭分页,一次性加载所有内容
- git config--global core.pager ''
使用到 color.ui,默认 auto,如果你不喜欢可以使用 false 关闭。
- git config--global color.ui false
其实如果想具体到某些特定命令,都是有 true、false 或 always 可以设置的,比如以下
- color.branch
- color.diff
- color.interactive
- color.status
以上每个配置项都有子选项,它们可以被用来覆盖其父设置,以达到为输出的各个部分着色的目的。例如,为了让 diff 的输出信息以蓝色前景、黑色背景和粗体显示,你可以运行
- git config--global color.diff.meta "blue black bold"
你能设置的颜色有: normal、black、red、green、yellow、blue、magenta、cyan 或 white。正如以 上例子设置的粗体属性,想要设置字体属性的话,可以选择包括: bold、dim、ul(下划线)、blink 、reverse(交换前景色和背景色)。
git branch -v 该命令显示本地分支最后一次提交说明
- * dev cdc7241a fixbug
- master f586f6b5 ****
如果需要显示本地和远程,加上 - a 即 git branch -v -a
- * dev cdc7241a fixbug
- master f586f6b5 ****
- remotes/origin/HEAD -> origin/master
- remotes/origin/dev cdc7241a fixbug
- remotes/origin/master f586f6b5 ****
- remotes/origin/oldIm 97d131bb 2.5.1 封版
git branch -vv 除了具有 git branch -v 命令的作用,还可以显示出每一个分支正在跟踪哪个远程分支,以及本地分支与远程分支是否是领先、落后。同样,如果想看远程加上 - a,也就是 all(所有),反正我就是这么记忆的
- * dev 6512ef90 [origin/dev: ahead 1] test
- master 78b4b30a [origin/master] 171227122 2.12.2 封版
其实在 Git 当中整合两个分支的方式除了 merge,还有一种方式,那就是 rebase。如上图,现在要合并 C3 和 C4,如果使用 merge 合并是这样子的。它会把两个分支的最新快照 (C3 和 C4) 以及二者最近的共同祖先 (C2) 进行三方合并,合并的结果是生成一个新的快照(并提交)。
但是如果使用 rebase: 你可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上再应用一次。在 Git 中,这种操作就叫做变基。你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像 "重新播放" 一样。
执行步骤就是,首先切换的 experiment 分支
,然后运行 git rebase master,此时准备 "重演",接下来就是看你要在哪个分支重演,就切换到哪个分支,这边在主分支重演,切换到主分支 git checkout master,然后整合即可
- git checkout experiment
。其实此时的 merge 和之前的 merge 不一样,这边的 merge 只需要进行一次 fast-forward,就是快速合并,head 快速前进到 C4'。
- git merge experiment
它的原理是首先找到这两个分支 (即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖 先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。
- git checkout experiment
- git rebase master
- First, rewinding head to replay your work on top of it...
- Applying: added staged command
- git checkout master
- git merge experiment
此时,C4' 指向的快照就和上面使用 merge 命令的例子中 C5 指向的快照一模一样了。这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的,但它们看上去就像是先后串行的一样,提交历史是一条直线没有分叉。
直接看下图,现在我有这样的需求,就是将 C8,C9 提交到主分支,但是不要 C3,你如何做?
其实办法总是有的,在 前篇文章 中,有讲到 git stash 命令,其实,我们可以在 client 分支找到 C3 的哈希值直接执行
然后把 C8,C9 的修改直接 git stash 贮存起来,切换到 master 分支,来个 git stash pop 搞定。现在我们使用变基来操作,感受下变基的魔性。
- git reset哈希值 (C3)
- git rebase--onto master server client
以上命令含义:取出 client 分支,找出处于 client 分支和 server 分支的共同祖先之后的修改,然后把它们在 master 分支上重演一遍。
现在可以快进合并 master 分支了。
- git checkout master
- git merge client
再举一个例子,也是关于 git rebase --onto 的使用
- H---I---J topicB
- /
- E---F---G topicA
- /
- A---B---C---D master
- git rebase --onto master topicA topicB
- H'--I'--J' topicB
- /
- | E---F---G topicA
- |/
- A---B---C---D master
- This is useful when topicB does not depend on topicA.
这样的例子好多,感兴趣可以使用 git rebase --help 查看。
注意事项这点一定要看,不要对在你的仓库外还有副本的分支执行变基。也就是说,一个人开发随便搞,多人开发有原则的搞。如果你不遵循这个原则,多人开发出现问题别来找我。
为什么呢?假如有个人在本地使用了 merge 合并分支后,push 到了远程服务器,后来他感觉不爽,想通过变基处理,恰是这个时候你 pull 了服务器的代码,那就会出现问题。问题就是,以后看记录会出现相同的提交,本来张三想丢弃的东西被你保留了。如果想看详细举例,推荐查看 Pro Git 这本书中关于 Git 变基一节。
总之,只要是你的代码和你建立的分支,还没有执行 push 之前,随意搞,push 后就不要再想着使用变基了,避免出问题。如果你更喜欢 merge,喜欢看 Git 实际发生的事,那就使用 merge 吧。反之,你更喜欢流水线一样的记录,从前到后,没有一堆堆复杂的合并,那就用 rebase。
十几款 GUI ,点开查看即可。
SourceTree GitHub Desktop TortoiseGit GitUp......
我比较喜欢 GitUp,简洁些。但是我仍旧在使用命令行,就当为了给电脑省空间吧。
来源: http://www.jianshu.com/p/a0e5d89ec900