Git 常用命令
Git 常用的一些命令汇总,及相关用法。
什么是Git
Git 是一个分布式版本控制系统,常用于软件代码的版本控制,在这个系统的控制下,所有提交过的操作都是可追溯的。
Git 处理数据特点
Git 把数据看作是对小型文件系统的一系列快照。在 Git 中,每当你提交更新或保存项目状态时,它基本上就会对当前的全部文件创建一个快照并保存这个快照的索引。如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。Git 对待数据更像是一个快照流。
Git 中所有发数据在存储前都计算检验和,然后以校验和来引用。Git 用以计算检验和的机制叫做 SHA-1 散列(hash,哈希)。这是一个由 40 个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来。SHA-1 哈希看起来是这样:
24b9da6552252987aa493b52f8696cd6d3b00373
Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
Git 文件工作状态
Git 项目拥有三个阶段:工作区、暂存区以及 Git 目录。
工作区是对项目的某个版本独立提取出来的内容。这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
暂存区是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。按照 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。
Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据,一般为
.git
目录。
Git 项目下文件大的方面分两个状态:未跟踪和已跟踪。
未跟踪指未纳入 Git 管理的文件,Git 下没有该文件的记录,不识别该文件
已跟踪指已在 Git 管理下的文件,又区分为:已修改、已暂存和已提交状态。
已修改,指文件被修改,但修改之后还没有暂存
已暂存,指被操作后的文件已被标记,放入暂存区,将纳入下次提交
已提交(也称为未修改状态),指该文件已被提交到 Git 仓库,仓库中目前的快照为当前状态。第一次 clone 下来的文件就处于这个状态
配置及帮助
初次运行 Git 前的配置
1 | $ git config --system // 系统配置文件,包含系统上每一个用户及他们仓库的通用配置 |
获取帮助
有三种等价的方法可以找到 Git 命令的综合手册:
1
2
3$ git help <verb> // 如 git help config
$ git <verb> --help // 如 git add -h
$ man git-<verb>查看网页指导,本编基于 git 教程
Git 基础
获取 Git 仓库
本地初始化一个仓库,开始使用 Git 管理。
$ git init
克隆远程仓库。
$ git clone https://github.com/libgit2/libgit2
这会在当前目录下创建一个名为 “libgit2” 的目录,并在这个目录下初始化一个 .git 文件夹, 从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。如果你进入到这个新建的 libgit2 文件夹,你会发现所有的项目文件已经在里面了,准备就绪等待后续的开发和使用。
如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以通过额外的参数指定新的目录名:
$ git clone https://github.com/libgit2/libgit2 mygitfloder
查看当前项目文件状态
可以用 git status
命令查看哪些文件处于什么状态。可能的输出如下:
1 | $ git status |
如果觉得输出内容比较繁琐,可以带上 -s 或 –short 参数打印精简信息,输出中有两栏,左栏指明了暂存区的状态,右栏指明了工作区的状态。
1 | $ git status -s |
暂存文件
可以使用 git add
精确地将内容添加到下一次提交中。如:
1 | $ git add CONTRIBUTING.md |
Tips: git add
只暂存了运行该命令时的版本,之后又作了修订的文件,需要重新运行 git add
把最新版本重新暂存起来。
.gitignore 忽略文件
一些文件通常我们不想 Git 来管理,也不想每次 git status
时出现提示未跟踪该文件,譬如说一些 log 文件,或者代码编译过程中的中间文件,没必要通过版本控制来管控。Git 提供 .gitignore 文件来忽略这些文件,该文件的格式规范如下:
- 所有空行或者以 # 开关的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
- 匹配模式可以以(/)开头防止递归。
- 匹配模式可以以(/)结尾指定目录。
- 要忽略批定模式以外的文件或目录,可以在模式前加上(!)取反。
1 | # 忽略所有的 .a 文件 |
Tips: 在最简单的情况下,一个仓库可能只根目录下有一个 .gitignore 文件,它递归地应用到整个仓库中。然而,子目录下也可以有额外的 .gitignore 文件。子目录中的 .gitignore 文件中的规则只作用于它所在的目录中。
查看已暂存和未暂存的修改
git diff
命令可以通过显示文件补丁的方式告诉我们,哪些更新尚未暂存(当前工作区与暂存区对比),哪些更新已暂存并准备好下次提交(当前暂存区与上一次提交对比)。
要查看尚未暂存的文件更新了哪些部分,不加参数直接输入 git diff
,此命令比较的是工作目录中当前文件和暂存区域快照之间的差异。也就是修改之后还没有暂存起来的变化内容。
1 | $ git diff |
若要查看已暂存的将要添加到下次提交里的内容,可以用 git diff --staged
或 git diff --cached
命令。此命令将比对已暂存文件与最后一次提交的文件差异:
1 | $ git diff --staged |
提交更新
1 | $ git commit // 将打开通过 git config --global -core.editor 设置的编辑器,输入提交信息即可完成提交 |
Tips: 打开编辑器输入提交信息,退出编辑器时,Git 会丢弃注释行。
移除文件
git rm
命令
1 | $ git rm <file> // 从工作目录和跟踪清单中删除文件,提交后该文件将不存在于工作目录和 Git 管理中,当要删除之前修改过或存放到暂存区的文件,则要加上强制删除选项 -f,以防止误删尚未添加到快照的数据 |
git rm
命令后面可以列出文件或者目录的名字,也可以使用 glob
模式。
1 | $ git rm log/\*.log // 删除 log/ 目录下扩展名为 .log 的所有文件 |
Tips: 注意使用 git rm <file>
命令时,不管后续是否进行提交,该文件已经在工作区间被删除,如果此时想恢复,只能从 Git 仓库中 checkout 该文件。
移动文件
git mv
命令
1 | $ git mv file_from file_to |
如:
1 | $ git mv README.md README |
其实,相当于如下命令集合:
1 | $ mv README.md README |
查看提交历史
git log
会按时间先后顺序列出所有的提交,最近的更新排在最上面。这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。
1 | $ git log |
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 (用来定义自己的格式) |
–oneline | –pretty=oneline –abbrev-commit 合并的简写 |
- |
仅显示最近的 n 条提交 |
–since, –after | 仅显示指定时间之后的提交 |
–until, –before | 仅显示指定时间之前的提交 |
–author | 仅显示作者匹配指定字符串的提交 |
–committer | 仅显示提交者匹配指定字符串的提交 |
–grep | 仅显示提交说明中包含指定字符串的提交 |
-S | 仅显示添加或删除内容匹配指定字符串的提交 |
撤消操作
撤消提交 - 修补提交
有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。这时候可以使用简单的修补提交操作,用一个 新的提交 替换旧的提交,从效果上来说,就像旧的提交从未存在过一样,它并不会出现在仓库的历史中。
1 | $ git commit --amend |
撤消暂存的文件
如何取消已暂存的文件,git status
命令中已经给了提示:
1 | $ git status |
提示使用 git restore --staged <file>...
来取消暂存。所以,我们可以使用此命令来取消暂存,但取消时并没有任何提示,再次查看状态时可以看到已经取消成功:
1 | $ git restore --staged mytest.txt # 无任何输出提示 |
Tips: git reset HEAD <file>...
命令也能达到目的,但是使用 reset 命令比较危险,新版本中推荐使用 git restore
撤消对文件的修改
如果你想放弃对文件的修改,还原成上次提交时的样子,或仓库中某一个版本的样子,同样,git status
也告诉了你应该如何做,就是使用 git restore <file>...
命令。
1 | $ git status |
可以看到使用该命令后无任何提示,但修改已经被撤消。
使用 git checkout -- <file>
也可以达到同样的效果。
远程仓库的使用
远程仓库是指托管在因特网或其他网络中的项目版本库,用于项目多人协作。一个项目可以关联多个远程仓库,而这些远程仓库的权限对你可能都是不同的。远程仓库也可以在你的本地主机上,可以像其它远程仓库上一样进行标准摄像头、拉取和抓取操作。
查看远程仓库
git remote
会列出指定的每一个远程服务器的简写,可以指定选项 -v
显示需要读写的远程仓库使用的 Git 保存的简写与其对应的 URL。
1 | $ git remote -v |
添加远程仓库
如果使用
git clone
拉取一个远程仓库到本地,那么本地该项目会自动添加并关联远程仓库,且默认以 “origin” 为简写。手动使用
git remote add <shortname> <url>
添加一个新的远程仓库,同时指定一个方便使用的简写:1
2
3
4
5
6
7
8$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)现在你可以在命令行中使用字符串
pb
来代替整个 URL。例如如果你想拉取 Paul 的仓库中有但你没有的信息,可以运行git fetch pb
:1
2
3
4
5
6
7
8$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
* [new branch] master -> pb/master
* [new branch] ticgit -> pb/ticgit
从远程仓库中抓取与拉取
从远程仓库中获取数据,可以执行:
1 | $ git fetch <remote> |
git fetch <remote>
会抓取克隆(或上一次抓取)后新推送的所有工作,将远程数据下载到你的本地仓库。执行完成后,你将会拥有那个远程仓库中所有分支的引用,但它不会自动合并或修改你当前的工作,当准备好时你必须手动将其合并入你的工作中。
如果你想抓取之后自动合并到当前工作中,你可能想执行以下命令:
1 | $ git pull <remote> # 会从跟踪分支中拉取数据并尝试合并到当前所在分支 |
推送到远程仓库
当你想分享你的项目时,必须将其推送到上游。这个命令很简单:git push <remote> <branch>
。当你想要将 master 分支推送到 origin 服务器时,那么运行这个命令就可以将你所做的备份到服务器:
1 | $ git push origin master |
只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。当你和其他人在同一时间克隆,他们先推送到上游然后你再摄像头到上游,你的推送就会毫无疑问地被拒绝。你必须先抓取他们的工作并将其合并进你的工作后才能推送。
查看某个远程仓库
如果想要查看某个远程仓库的更多信息,可以使用 git remote show <remote>
命令。如果想以一个特定的缩写名运行这个命令,例如 origin
,会得到像下面类似的信息:
1 | $ git remote show origin |
它同样会列出远程仓库的 URL 与跟踪分支的信息。这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull
,就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支。它也会列出拉取到的所有远程引用。
远程仓库的重命名与移除
你可以运行 git remote rename <old_name> <new_name>
来修改一个远程仓库的简写名。
1 | $ git remote rename pb paul # 将远程仓库 pb 重命名为 paul,那些过去引用 pb/master 的现在会引用 paul/master |
可以使用 git remote remove
或 git remote rm
来移除一个远程仓库,一旦删除了一个远程仓库,那么所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除。
1 | $ git remote rm paul |
标签
Git 可以给仓库历史中的某一个提交打上标签,以示重要。Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated)。
列出标签
使用 git tag
列出标签,可带上可选的 -l 选项 –list:
1 | $ git tag # 列出所有标签,-l 或 --list 可选 |
创建标签
轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。
而附注标签是存储在 Git 数据库中的一个完整对象,它们是可以被检验的,其中包含打标签者的名字、电子邮件地址、日期时间,此外还有一个标签信息,并且可以使用 GNU Privacy Guard(GPG)签名并验证。通常会建议创建附注标签。
附注标签
在 Git 中创建附注标签十分简单。最简单的方式是当你在运行 tag
命令时指定 -a
选项:
1 | $ git tag -a v1.4 -m "my version 1.4" |
-m
选项指定了一条将会存储在标签中的信息。如果没有为附注标签指定一条信息,Git 会启动编辑器要求你输入信息。
通过使用 git show
命令可以看到标签信息和与之对应的提交信息:
1 | $ git show v1.4 |
输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。
轻量标签
另一种给提交打标签的方式是使用轻量标签。轻量标签本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。创建轻量标签,不需要使用 -a
、-s
或 -m
选项,只需要提供标签名字:
1 | $ git tag v1.4-lw |
这时,如果在标签上运行 git show
,你不会看到额外的标签信息。命令只会显示出提交信息:
1 | $ git show v1.4-lw |
后期打标签
你也可以对过去的提交打标签。假设提交历史是这样的:
1 | $ git log --pretty=oneline |
现在,假设在 v1.2 时你忘记给项目打标签,也就是在 “updated rakefile” 提交。 你可以在之后补上标签。 要
在那个提交上打标签,你需要在命令的末尾指定提交的校验和(或部分校验和):
1 | $ git tag -a v1.2 9fceb02 |
可以看到你已经在那次提交上打上标签了:
1 | $ git tag |
共享标签
默认情况下,git push
命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到
共享服务器上。 这个过程就像共享远程分支一样——你可以运行 git push origin <tagname>
。
1 | $ git push origin v1.5 |
如果想要一次性推送很多标签,也可以使用带有 –tags 选项的 git push 命令。 这将会把所有不在远程仓库
服务器上的标签全部传送到那里。
1 | $ git push origin --tags |
现在,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。
删除标签
要删除掉你本地仓库上的标签,可以使用命令 git tag -d <tagname>
。 例如,可以使用以下命令删除一个
轻量标签:
1 | $ git tag -d v1.4-lw |
注意上述命令并不会从任何远程仓库中移除这个标签,你必须用 git push
注意上述命令并不会从任何远程仓库中移除这个标签,你必须用 git push
:refs/tags/
1 | $ git push origin :refs/tags/v1.4-lw |
上面这种操作的含义是,将冒号前面的空值推送到远程标签名,从而高效地删除它。
第二种更直观的删除远程标签的方式是:
1 | $ git push origin --delete <tagname> |
Git 别名
为方便一些长命令的记忆,可使用 Git 别名。Git 只是简单地将别名替换为对应的命令。
1 | $ git config --global alias.last `log -1 HEAD` |
如上,可以轻松地看到最后一次的提交。
然而,你可能想要执行外部命令,而不是一个 Git 子命令。如果是那样的话,可以在命令前面加入 ! 符号。如果你自己要写一些与 Git 仓库协作的工具的话,那会很有用。我们现在演示将 git visual
定义为 gitk
的别名
1 | $ git config --global alias.visual `!gitk` |