盘点那些不知名却经常使用的 Git 操做

Git 很是复杂。我即便几乎天天都在用,也不敢保证对 Git 的每个角落都了如指掌。
本文试图盘点一些不知名,但在我看来较经常使用的操做。若是没有你预期的操做,说明要么在我看来它很知名,要么在我看来它不太经常使用。git

  • git log --graph --abbrev-commit --decorate --all --onelinegithub

  • git cherryshell

  • git show ref:pathvim

  • git reset [--hard|--soft|--keep]缓存

  • git update-index --assume-unchangedless

git log --graph --abbrev-commit --decorate --all --oneline

若是要看项目中的分支状况,一般的作法是打开一个 Git GUI 软件,经过 GUI 界面来查看全景。
对于有些人来讲,这是装 GUI 的惟一需求。
其实这个需求能够砍掉,由于 Git 提供了在终端中输出提交记录全景的操做:编辑器

git log --graph --abbrev-commit --decorate --all --oneline

输出结果至关惊艳,你能够像看 GUI 界面同样,在终端中查看不一样分支的提交信息。
git-log.png
(这里采用了一个开源项目的提交历史来示例,若是是公司的商业项目,输出会更炫目)lua

这个输出跟 man xxx 同样,会经过 $PAGER(一般是 less) 显示在终端上。这意味着你能够在输出中搜索特定的提交或 tag。
许多 GUI 界面并不提供这一功能,致使用户只能瞪大眼睛,一点点地挪动,才能揪出特定的提交。
就这一点上,终端版的功能要比 GUI 版本胜出许多。
终端版的另外一个优势是,提供了自由组合各类选项的能力。你能够自定义输出信息和显示的提交范围。
若是嫌命令太长,能够给它一个 alias(经过 git alias 或 shell 的 alias 功能)。spa

git cherry

有一个经常使用的 Git 操做是 git cherry-pickgit 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 ref:path

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 [--hard|--soft|--keep]

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,不能不提误操做时的补救办法。

  1. 被抹掉的内容已经提交了。这种状况好办。经过 git reflog,咱们能够找到被抹掉的提交,而后 cherry-pick回来,抑或 reset --hard HEAD{x} 到对应的提交上去。

  2. 被抹掉的内容原来在暂存区里。这个比较蛋疼。你须要 git fsck | grep blob 拣出每个 dangling blob,逐个 git show xxx 看看,应该能找回被抹掉的内容。这种感受,就像在垃圾桶里翻出丢失的手稿同样。

  3. 被抹掉的内容不在暂存区里。靠 Git 已经救不回来了。要不找下编辑器的备份文件,要不尝试能不能从文件系统缓存里把文件抠出来。若是不行,试试磁盘数据恢复程序……

说这么多,关键记住一点:reset 有风险,用时需谨慎。

git update-index --assume-unchanged

假设代码仓库里存在这么一个配置文件:每一个人在开发时,会根据本地状况修改里面的值。好比某些 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
相关文章
相关标签/搜索