第 2 篇 · Git 常用命令 FAQ

218 阅读7分钟

git图解

在开始前,让我们先来讲几个概念,这将更好的让我们理解接下来的内容:

工作区

我们正在编辑的内容就是在工作区,上图中的 workspace。

暂存区

我们将工作区的内容通过git add命令就提交到了暂存区。 上图中的 index

本地仓库

我们将暂存区的内容通过git commit就提交到了本地仓库。内容的修改从工作区 ==> 暂存区 ==> 本地仓库是顺序执行的。上图中的 repository

远程仓库

Git 是一个分布式管理工具,所以当我们将修改的内容提交到本地仓库后,就可以通过git push命令推送到远程仓库与他人协作完成项目。

分支

分支可以理解为像树枝一样来管理我们的代码,分支很好的解决了多人协作的问题。当我们需要开发一个新的功能时,从稳定分支(通常是 master 或者 release)新建分支开发,当开发完成并测试通过后,再通过git merge合并入稳定分支发布。

FAQ

工作区

怎样将工作区中的内容提交到暂存区?

$ git add [./filename]

我在工作区修改了一些文件用于调试,完成后想丢弃所有修改

$ git checkout .

我想丢弃某个文件的修改

$ git checkout --[filename]

我想暂存这些调试的代码

$ git stash

我想看看有哪些暂存的内容

$ git stash list

我想将某个暂存的内容复制到工作区

$ git stash apply stash@{n}

我想将某个暂存的内容剪切到工作区

$ git stash pop stash@{n}

我想删除某个暂存

$ git stash drop stash@{n}

我想删除所有暂存内容

$ git stash clear

我想将 git 中的某个文件取消跟踪,并保留本地文件

$ git rm --cached [filename]

已跟踪的文件也要每次 add 后 commit 吗?

不需要,可以使用 git commit -am 'msg' 合并两个命令

我回退到了某个提交,如何再重新回到最新的提交?

git reflog命令记录了你的操作记录,在这里你可以找到最新的提交,使用git reset [commit-id]即可回到未来。

暂存区

我想将暂存区的文件还原到工作区

$ git reset ./filename

git reset中,有--mixed(默认), --soft--hard三个可选参数,它们间有什么区别呢?其实是他们的修改作用域不同,具体可看下表。需要注意的是,请谨慎使用--hard,这会使你工作区的内容被覆盖!

工作区 暂存区 本地仓库
--soft
--mixed
--hard

我想对比工作区域暂存区的某个文件差异

$ git diff [filename]

我想对比暂存区与仓库某个文件的差异

$ git diff --cached [filename]

我想比较工作区与本地仓库的差异

$ git diff HEAD

我想比较当前提价与某个历史提交的差异

$ git diff [commit-id]

本地仓库

怎么将远程仓库克隆到本地,并命名为proj?

$ git clone [repo_url] [proj]

怎么更新本地仓库?

$ git fetch && git merge
$ git pull

变基

变基的命令:git rebase -i [要修改 commit 的上一个 commit]

请注意!变基是一把利剑,合理的使用会让你的分支更加简洁和灵活,滥用则会导致分支的混乱。请谨慎使用 rebase,尤其是团队合作项目,因为它会修改历史信息,导致信息冲突 在危险操作前可以先在副本分支进行操作,确认结果是预期后再行操作。

变基的概念可能难以理解,你可以到这里学习一下。

当我们使用git rebase -i 5f2452b2 8f33126c调出了变基窗口时,会看到以下内容,请注意其中的 Commands 部分,每个命令后都有说明,我们只需要按照说明操作即可。如果不明白其实际动作和结果,请创建一个测试仓库演练一下。

pick cacc52da add: qrcode
pick f072ef48 update: indexeddb hack
pick 4e84901a feat: add indexedDB floder
pick 8f33126c feat: add test2.js

# Rebase 5f2452b2..8f33126c onto 5f2452b2 (4 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

我想修改某次提交信息

r

我想将多个提交合并

s

我想删除某次提交

d

我想将 A 分支变基到 B 分支上(移花接木)

$ git rebase -i A B

我更换了邮箱,想修改历史提交的邮箱

$ git filter-branch --commit-filter '
        if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
        then
                GIT_AUTHOR_NAME="Scott Chacon";
                GIT_AUTHOR_EMAIL="schacon@example.com";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

我想在所有分支删除某个文件,如 password.txt

git filter-branch --all --tree-filter 'rm -f passwords.txt' HEAD

变基冲突解决后我该做什么?

$ git rebase --continue

变基过程中我想放弃变基

$ git rebase --abort

分支

怎么切换分支?

$ git checkout [branch name]

怎么切换到上一个分支?

$ git checkout -

我当前在test分支,并想将ver1.0合并到test分支

$ git mrege ver1.0

我想取消合并

$ git merge --abort

怎么查看已经合并的分支?

$ git branch --merged

怎么查看还未合并的分支?

$ git branch --no-merged

我想新建一个分支

$ git branch [branch name]

我想新建并切换到新分支

$ git branch -b [branch name]

我想删除已合并的分支

$ git branch -d [branch name]

我想强制删除未合并的分支

$ git branch -D [brnach name]

我想将另一个分支的某次提交应用到当前分支

$ git cherry-pick [commit-id]

怎么修改分支名?

$ git branch -m [old name] [new name]

怎么将本地分支与远程分支建立跟踪关系?

$ git branch -t [branch name] [remote-branch]

怎么查看远程分支?

$ git branch -r

我本地没有别人新推送的远程分支

请使用git fetch命令更新一下

远程仓库名为origin,怎么将本地的 A 分支推送到远程并建立同名分支?

$ git push -u origin A:B

远程仓库名为origin,我想删除origin的分支B

$ git push -u origin :B

我将 5 个提交推送到了远程仓库,但发现第3个提交需要撤回,我该如何操作?

此时,你应该使用git revert [commit-id],无论这个提交在log的哪个位置,都不会影响上下的提交,而且它会将撤销的作为一个新的提交,因此revert命令主要用于推送到远程仓库的修改。

如果你使用了git reset会有什么不同呢?

如果一个提交在log的中间位置,那么reset这个提交 之后的提交有可能都会消失掉!尤其在多人协作中,你将后两个提交删除,并推送到远程,而别人本地还是 5 个提交,这将导致分支的混乱,请清楚你的每一步操作与后果,谨慎使用每个命令。

远程仓库

怎么查看所有关联的远程仓库名称

$ git remote

我想查看远程仓库的地址

$ git remote -v

我想将本地已有仓库与远程仓库关联

$ git remote add 本地远程仓库名 url|path

我想取消远程仓库的关联

$ git remote rm 本地远程仓库名

我想重命名远程仓库

$ git remote rename [old name] [new name]

检索

我想在项目中查找某个关键词,并输出所在行号

$ git grep [-n] [keyword]

我想查看搜索结果所属方法或函数

$ git grep -p [keyword]

日志

git log中有很多参数能够帮助我们增强筛选,常用的选项如下表

选项 说明
-p 按补丁格式显示每个更新之间的差异。
--stat 显示每次更新的文件修改统计信息。
--shortstat 只显示 --stat 中最后的行数修改添加移除统计。
--name-only 仅在提交信息后显示已修改的文件清单。
--name-status 显示新增、修改、删除的文件清单。
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
--graph 显示 ASCII 图形表示的分支合并历史。
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。

git log --pretty=format 常用的选项如下表:

选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 --date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明

限制 git log 输出的选项

选项 说明
-(n) 仅显示最近的 n 条提交
--since, --after 仅显示指定时间之后的提交。
--until, --before 仅显示指定时间之前的提交。
--author 仅显示指定作者相关的提交。
--committer 仅显示指定提交者相关的提交。
--grep 仅显示含指定关键字的提交
-S 仅显示添加或移除了某个关键字的提交

我想查看某次提交信息

$ git show [commit-id]

我想查看某次提交修改的文件列表

$ git show --pretty="" --name-only [commit-id]

查看某次提交的变更内容

$ git show --pretty="" [commit-id]

我想查看某个文件的所有提交信息

$ git log -p [filename]

我想查看最近两次的提交信息

$ git log -p -2

我想查看某个文件的所有变动及统计信息

$ git whatchanged --stat [filename]

我想修改最近一次提交信息

$ git commit --amend

某行代码有问题,我想查看谁最后修改了这里

$ git blame [-L start-line, end-line] filename

我想查看某个用户在某个时间段内的所有提交,并仅输出简短hash与提交说明

$ git log --pretty="%h - %s" --author=Rock --since="2008-10-01" --before="2008-11-01"

我想用图形的方式查看分支的变化

$ git log --oneline --graph

.gitignore

  • **/*.go 忽略所有目录中的扩展名为go的文件
  • */*/temp*忽略二级目录下以temp开头的所有文件
  • temp?忽略以temp开头的文件名,如tempatempb
  • !README.md感叹号(!)表示不忽略该文件

版本控制最佳实践

鼓励频繁提交

频繁提交,而不要等到代码没有问题了再一次性提交。对于可能损坏主干原则的代码,不要直接提交到主干,而是创建一个分支,在分支中频繁提交。

定义主干原则,并且坚守它

“主干的代码必须是可以发布并且不会产生bug的”,如果不能保证新增或修改的代码符合这一原则,就在分支提交代码。

不要把逻辑的修改和代码格式化操作混在一起

如果你做了一些代码格式化的操作,就单独提交这次修改,然后再做一些逻辑的修改后提交,这样可以在出现问题时容易追溯。

不相干的代码分开提交

也就是说不要在一次提交里修复两个bug


说明

  1. 本文受启发于项目git-flight-rules
  2. 推荐 Git 学习资料 Pro Git