13个相见恨晚的Git技巧

Published On July 07, 2016

category tool | tags git


下面这些是我在使用git的过程中屡试不爽的命令,我相信有些命令一定会让大家相见恨晚。在介绍这些技巧之前,先明确几个概念

  • working tree:就是当前看到的文件,中文名叫工作区,与版本库(.git目录)对应
  • index:版本库里的暂存区,用于存放将要提交的文件
  • HEAD:指向当前分支,分支名指向对应分支的最后一次commit

1. 只add修改过的文件,忽略新增的文件

git add -u

2. 查看对某个文件的改动

当我们对很多文件做了修改后,希望看到对某个文件改动了哪些地方,如果用git diff将显示所有文件的改动,查看一下git help diff发现确实有针对某个文件的diff,命令如下:

git diff HEAD -- path/to/file
HEAD代表当前分支的最后一次提交,将HEAD替换成某个则会显示此文件基于该commit的修改。

3. 查看某个文件的修改历史

我们常常要看某个文件的commit历史纪录,比如找到某行代码是谁修改的,可以使用如下命令:

git log -p <filename>
它显示了指定文件的所有改动,按commit倒序排,通过搜索即可知道某行代码是谁改的

4. 查看某个人的提交

下面这条命令会显示出author行里包含yanxr的所有commit记录

git log --author=yanxr
--author选项的值可以是一个正则表达式,如果要查看多个人的提交则指定多个--author

5. 克隆某个指定的分支

使用git checkout 默认会克隆master分支,github上很多项目的master分支都不是稳定的分支,使用clone命令的-b选项可以克隆指定的分支

git clone -b <branch name> <repo-url>

6. 比较两个分支有哪些不同

当我们在dev分支上开发的时候常常需要和master分支做比较,看多了哪些commit,可以执行

git log master..dev // 或git log master..HEAD
上面这条命令查看dev分支有而master分支没有的commit,同样的道理可以查看master有而dev没有的commit 如果要查看某个分支和另一个分支的差别,可以使用下面的命令:
git diff master...dev

7. 切换到远程的某个分支

在协作开发中,如果要在别人的某个分支上开发,需要先使用fetch拉下该分支,然后checkout到该分支,其实可以用一条命令就搞定:

git checkout -b dev origin/dev
作用是checkout远程的dev分支,在本地起名为dev分支,并切换到本地的dev分支 查看本地分支对应的远程分支
git branch -vv

8. 回到过去的某次commit的状态?

自从我接触git以来我就一直有这个问题,相当长的时间里我都不知道,我还一度以为git做不到,其实很容易啦

git checkout <commit-hash-id>
第一条语句将当前的index,working tree和HEAD切到指定的commit的状态,而且命令行中提示得很清楚了
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>
按照提示,我们执行下面的命令就可以新建一个分支
git branch -b <new-branch-name>

9. 回退某个文件到以前的某次commit

(可选)使用如下命令查看该文件与指定commit的差别

git diff <commit hash> <filename>
回退该文件
git checkout <commit-hash-id> <filename>
参见Reset or revert a specific file to a specific revision using Git?

10. 修改上一次的commit

使用add命令将需要的修改添加到index,然后执行

git commit --amend
执行上述命令后会弹出vim编辑框,可以修改commit message,然后退出。 这个命令不会创建新的commit,而是将新的修改添加到上一次commit中,在实际应用中经常使用。 如果需要推送到远端,执行:
git push -f origin master
这个命令是github starter的良药,使用该命令的时候请提供分支名(这里用的master),否则其他分支中的commit也会被删除会修改。

11. 撤销最近的1次或n次commit

如果我们要彻底abondon上次的commit,可以执行:

git reset --hard HEAD~1
这样上次commit、stage、working directory中的所有修改都删除了,同理把1改成n就可以删除最近n次的提交 上面使用的是hard选项,默认是mixed,表示只重置HEAD和index,删除的commit做的改动都在working tree中,如果使用soft选项则是只重置HEAD,会将删除的commit的改动保留到index中。

12. 修改最后一次commit以前的某次commit

这个也勉强可以办到,但下面的做法不适用于涉及到merge的commit。

  • step 1 git rebase -i <commit-hash-id>^ 注意不要漏掉^ 运行这个命令会将你带入到一个文本编辑器中,开始的n行正序列出了从commit-hash-id开始的所有commit
  • step 2 将想要修改的commit(第一行)的前面的pick改成edit,可以同时修改多行,保存退出。git会回退到列表中的第一个commit
  • step 3 修改内容后,使用git commit --amend更新commit(要修改的commit位于当前最后一个commit)
  • step 4 执行git rebase --continue 这个命令会自动应用后续的提交,你就完成任务了。如果你将多行的 pick 改为 edit ,你就能对你想修改的提交重复这些步骤。Git每次都会停下,让你修正提交,完成后继续运行。 <commit-hash-id>..HEAD范围内的每一次提交都会被重写,无论你是否修改。不要覆盖你已经推送到远端的提交,否则会使其他开发者产生混乱,因为你提供了同样变更的不同版本。
  • step 5 运行git status可以看到当前处于detached状态,新建一个分支 git branch new

13. 移除以前的某次commit(不是最后一次commit)?

在实际应用中我们经常有这个需求,比如临近上线发现主分支中的某个commit暂时不能上线,怎么移除呢?有很多种方法,但没有哪种方法可以保证100%顺利的完成这个任务。我使用的是revert命令:

git revert <commit-hash-id>
revert会将指定的commit移除并添加一个新的commit记录这次commit,但如果要移除的commit影响的行后来被修改过了,就需要手动解决冲突

git是一个由linux之父最先开始用来管理linux源码的工具,它的功能强大无比,没有办不到的,只有我们不知道的。 但是git的使用并非那么简单,有很多技巧是需要不断积累的。在我写下这篇博客时stack overflow上按vote数排名前10的问题有4个都是关于git,由此可见一斑。


qq email facebook github
© 2018 - Xurui Yan. All rights reserved
Built using pelican