Git 很是复杂。我即便几乎天天都在用,也不敢保证对 Git 的每个角落都了如指掌。
本文试图盘点一些不知名,但在我看来较经常使用的操做。若是没有你预期的操做,说明要么在我看来它很知名,要么在我看来它不太经常使用。git
git log --graph --abbrev-commit --decorate --all --oneline
github
git cherry
shell
git show ref:path
vim
git reset [--hard|--soft|--keep]
缓存
git update-index --assume-unchanged
less
若是要看项目中的分支状况,一般的作法是打开一个 Git GUI 软件,经过 GUI 界面来查看全景。
对于有些人来讲,这是装 GUI 的惟一需求。
其实这个需求能够砍掉,由于 Git 提供了在终端中输出提交记录全景的操做:编辑器
git log --graph --abbrev-commit --decorate --all --oneline
输出结果至关惊艳,你能够像看 GUI 界面同样,在终端中查看不一样分支的提交信息。
(这里采用了一个开源项目的提交历史来示例,若是是公司的商业项目,输出会更炫目)lua
这个输出跟 man xxx
同样,会经过 $PAGER(一般是 less) 显示在终端上。这意味着你能够在输出中搜索特定的提交或 tag。
许多 GUI 界面并不提供这一功能,致使用户只能瞪大眼睛,一点点地挪动,才能揪出特定的提交。
就这一点上,终端版的功能要比 GUI 版本胜出许多。
终端版的另外一个优势是,提供了自由组合各类选项的能力。你能够自定义输出信息和显示的提交范围。
若是嫌命令太长,能够给它一个 alias(经过 git alias 或 shell 的 alias 功能)。spa
有一个经常使用的 Git 操做是 git cherry-pick
。git cherry
顾名思义,天然跟 cherry-pick
有关。git cherry
能够比较两个分支,筛选出存在于甲分支却不存在于乙分支的提交。显而易见,这是在为后面的 cherry-pick
作准备。插件
¥ git cherry 4.2.0 | tail + bb5f4b02340b3c269d7a8e11842d4a16b2b8eba1 + 2451c0c202dd48bc610ef9731c503ea54f19af83 + 64b4a599e8af4b31444f2a86559d4860401925f4 + c80b4e773f746ffe11aca9010b4433f6b6ba13ad + b2c7de9a5a5c8ea0254001a07ae24ffc27118dbb + 719dd2c3af9ba801114101ccdec1cd9e2f1bbc5d + 518db6e648aaf646db4be3067a583bdcc37ee2a8 + b01359efc5761a17cd3b893fd51219a005009641 + 422c9a8e69acc5cf013340715f8d2fa7d7cabf75 + cc0dff2f49cfbd786eca498fe2532de0455e1759
美中不足的是,git cherry
的输出是 sha1,对机器来讲友好,对人来讲就是天书。若是要看具体的提交信息,须要借其余命令之力。好比 git show
:
git show --no-patch --format='%s' cc0dff2f49cfbd786eca498fe2532de0455e1759
git show
是我最喜欢的命令之一。输出提交的内容,是 git show
的拿手好戏之一。举个例子,git show @
能够显示当前分支上最新提交。(@
是 HEAD
的别名,能少敲三个字符呢)
不过这不算 git show
的杀手锏。git show
的绝活,是能在不检出特定提交的前提下,显示特定提交的某个文件的内容。
假设咱们想看看 xxx 提交上的 db.lua
,纯粹只想看一看,不涉及调试或其余复杂的操做。咱们固然能够 git checkout xxx
,而后想看啥就看啥。然而用 git show
的话,就能保持当前分支不变,直接显示 xxx 提交上的 db.lua
了:
git show xxx:path/to/db.lua
编辑器的 Git 插件通常支持在编辑器内直接打开 git show
的输出。若是你用的是 Vim,又装了 fugitive,
经过敲 :Gedit revision:%
,能够打开当前文件的特定版本。
若是想找到哪几个提交修改了特定文件,能够先用 git log --format='%s' -- /path/to/your/file
获取涉及的提交。
git reset
可不能算是“不知名”操做。任何 Git 入门教程,都会提到怎么用 git reset
把文件移出暂存区。但在本人的平常开发流程中,移出暂存区实际上是最少用上的git reset
操做。因此我以为能够打个擦边球,讲讲 git reset
其余的打开方式。
移出暂存区的 git reset
操做,至关于 git reset --mixed
。除了 --mixed
,经常使用的选项还有下面三个:
--soft
--hard
--keep
开发中常有的状况:劈劈啪啪写了一堆代码,连续好几个提交。而后脑子里灵机一动,顿悟了更好的作法。这个作法是如此地好,以至于以前的提交记录都成了你的黑历史。你巴不得
把这些提交记录一笔勾销,但该怎么办呢?这时候就轮到 reset --soft
上场了。reset --soft
俗称 squash
,能够在保留修改的同时,把最近的几个提交历史给抹掉。好比 git reset --soft @~3
就能重置到倒数第四个提交,但保留被抹掉的三个提交的更改。
这么操做以后再提交一次,而后选一个夜深人静的时刻,push -f
到远程仓库,你的黑历史就烟消云散了。固然仍是会留下些痕迹什么的,但至少别人通常发现不了……
跟 --soft
对应的是 --hard
。--hard
也会抹掉最近的几个提交,但不保留修改。若是感到本身的代码实在无法看,能够直接 reset --hard
试试。不过 reset --hard
倒不失清理环境的好方法。
--keep
正好在 --soft
和 --hard
之间。--keep
会保留未提交的更改,这一点跟 --soft
同样;同时会抹掉已经提交的更改,这一点跟 --hard
相同。
有些时候,这一特性会派上用场。
若是你在开发的时候,忽然发现本身忘记切分支了,能够这么作:
git branch feature/you_need git reset --keep comit_your_hack_starts_from git checkout feature/you_need
这样作既消除了错误分支上的提交,又保留了工做区里未提交的内容。
提到 reset
,不能不提误操做时的补救办法。
被抹掉的内容已经提交了。这种状况好办。经过 git reflog
,咱们能够找到被抹掉的提交,而后 cherry-pick
回来,抑或 reset --hard HEAD{x}
到对应的提交上去。
被抹掉的内容原来在暂存区里。这个比较蛋疼。你须要 git fsck | grep blob
拣出每个 dangling blob,逐个 git show xxx
看看,应该能找回被抹掉的内容。这种感受,就像在垃圾桶里翻出丢失的手稿同样。
被抹掉的内容不在暂存区里。靠 Git 已经救不回来了。要不找下编辑器的备份文件,要不尝试能不能从文件系统缓存里把文件抠出来。若是不行,试试磁盘数据恢复程序……
说这么多,关键记住一点:reset 有风险,用时需谨慎。
假设代码仓库里存在这么一个配置文件:每一个人在开发时,会根据本地状况修改里面的值。好比某些 IDE 的项目描述文件,里面可能夹杂着项目的路径。
有什么办法,能够避免本地的修改不会提交到仓库里去呢?
我的认为 git update-index --assume-unchanged
是众多解决方法中最好的。git update-index
能够修改 Git 对特定路径下的文件的处理方式。其中 --assume-unchanged
选项告诉 Git,指定路径下的文件不会有修改。
即便在本地修改了那些文件,也不会被 Git 记录在案。
若是我有一天须要修改这个配置文件并入库,能够用 --no-assume-unchanged
选项解开封印,让 Git 从新追踪修改。
¥ gs On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: check_integrity.sh no changes added to commit (use "git add" and/or "git commit -a") ¥ git update-index --assume-unchanged check_integrity.sh ¥ gs On branch master nothing to commit, working tree clean ¥ git update-index --no-assume-unchanged check_integrity.sh ¥ gs On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: check_integrity.sh