Git 基础

本文涵盖了使用 Git 完成各种工作时将会用到的各种基本命令。

git status

1
2
3
git status -s
# or
git status --short
1
2
3
4
5
6
?? README.md   # 未被追踪的文件
A README.md # 新添加到暂存区的文件
M train.py # 已修改但未被暂存的文件
M train.py # 已修改且已被暂存的文件
MM train.py # 已修改,部分修改被暂存。(暂存区和工作区都有 M,说明修改了一部分之后被暂存,但又修改了,这部分还没被暂存)
D oldFile.txt # 已删除(已被暂存)

Git 会使用不同的颜色对不同的状态进行区分。

git ignore

  • 所有空行或者以 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
  • 匹配模式可以以 / 开头防止递归。
  • 匹配模式可以以 / 结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号 ! 取反。

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。* 匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符;? 只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 09 的数字)。使用两个星号 ** 表示匹配任意中间目录,比如 a/**/z 可以匹配 a/za/b/za/b/c/z 等。

GitHub 提供的数十种项目及语言的 .gitignore 文件列表:https://github.com/github/gitignore

子目录下也可以有额外的 .gitignore 文件。子目录中的 .gitignore 文件中的规则只作用于它所在的目录中。

git diff

git diff 用来回答这两个问题:当前做的哪些更新尚未暂存? 有哪些更新已暂存并准备好下次提交?

1
git diff

此命令直接查看工作区尚未暂存的文件更新了哪些部分。比较的是工作目录中当前文件和暂存区域快照之间的差异。

1
2
3
git diff --staged
# or
git diff --cached

--staged/--cached 参数查看已暂存的将要添加到下次提交里的内容。比对已暂存文件与最后一次提交的文件差异。

git commit

打开编辑器书写提交信息:

1
2
3
git commit
# or
git commit -v

-v 参数将所作的更改的 diff 输出呈现在编辑器中。

直接在提交命令中书写:

1
git commit -m "some comments"

直接提交所有追踪的文件:

1
git commit -a -m "some comments"

-a 参数使得在提交之前不再需要 git add 将文件添加到暂存区的操作了。

重新提交:

1
2
3
git commit --amend
# or
git commit --amend -m "some comments"

--amend 参数会用这次提交覆盖掉上一次的提交。在修改提交 comments 或者一些小错误时非常有用。

git rm

删除仓库中(已提交)某个文件:

1
git rm oldFile.txt

执行之后,git 在工作区删除了该文件,并将该动作添加到暂存区,在下一次提交后,该文件就在三个区都被删除了,不再纳入版本管理了。

如果某个文件已经在工作区被修改、或者被修改后已经添加到暂存区,则需要强制删除:

1
git rm -f oldFile.txt

如果我们只想在暂存区和仓库中删除该文件,而保留工作区的(即停止 git 对该文件的追踪):

1
git rm --cached oldFile.txt

再使用 git status 命令即可看到暂存区的删除操作,以及该文件已经不被追踪。

git mv

重命名某个文件:

1
git mv oldName.txt newName.txt

执行之后,git 在工作区重命名了该文件,并且重命名工作已经被添加到暂存区等待提交。

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 合用的简写。

限制 git log 输出的选项

选项 说明
-<n> 仅显示最近的 n 条提交。
--since, --after 仅显示指定时间之后的提交。
--until, --before 仅显示指定时间之前的提交。
--author 仅显示作者匹配指定字符串的提交。
--committer 仅显示提交者匹配指定字符串的提交。
--grep 仅显示提交说明中包含指定字符串的提交。
-S 仅显示添加或删除内容匹配指定字符串的提交。

撤销

取消暂存的文件:

1
2
3
git reset HEAD <file>
# or
git restore --staged <file>

撤销对文件的修改:

1
2
3
git checkout -- <file>
# or
git restore <file>

此操作很危险,Git 会用最近提交的版本覆盖掉它

远程仓库

查看远程仓库

1
git remote -v

如果只设置了一个远程仓库,会输出类似于如下的信息:

1
2
origin	https://github.com/romkatv/powerlevel10k.git (fetch)
origin https://github.com/romkatv/powerlevel10k.git (push)

添加远程仓库

1
git remote add <shortname> <url>

以上命令添加一个新的远程 Git 仓库,同时指定一个方便使用的简写。在之后就可以在命令行中使用字符串 <shortname> 来代替整个 url。

从远程仓库获取数据

1
git fetch [<remote>]

该命令会从远程仓库中拉取所有本地还没有的数据。执行完成后,本地将会拥有那个远程仓库中所有分支的引用,可以随时查看或合并。
注意:git fetch 命令只能将远程数据拉下来,并不会自动合并、修改本地的数据。

1
git pull [<remote>]

该命令会从远程服务器上抓取数据并自动尝试合并到当前所在的分支。

推送到远程仓库

1
git push <remote> <branch>

此命令将本地的仓库推送到远程仓库。例如推送本地 master 分支到 origin 远程仓库的 master 分支:

1
git push origin master

只有当你有该远程服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。

查看某个远程仓库

1
git remote show <remote>

该命令可以查看远程仓库的更多信息。它会列出远程仓库的 URL 与跟踪分支信息、特定分支 push 的对应关系、哪些分支不在本地、哪些分支已经被删除等等。

远程仓库的重命名与移除

修改一个远程仓库的简写名:

1
git remote rename <old> <new>

这同样也会修改所有远程跟踪的分支名字。
移除某个远程仓库:

1
git remote remove <remote>

所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除。

git tag

列出标签

列出所有标签:

1
git tag

列出符合条件的标签:

1
git tag -l v1.*

创建标签

Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated)。

轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。而附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。

附注标签

1
git tag -a -m <msg> <tagname> [<commit>]

其中,<msg> 为存储在标签中的信息,可以通过 git show <tagname> 来查看。<tagname> 为欲设定的标签名称。[<commit>] 为该标签指向的对象,可以是哈希值,默认为 HEAD

轻量标签

轻量标签本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。

1
git tag <tagname> [<commit>]

轻量标签运行 git show <taname> 时没有额外的标签信息,只会显示出提交信息。

共享标签

git push 命令不会推送标签到远程仓库,必须手动显式地推送:

1
2
3
git push <remote> <tagname>
# or 一次性推送所有标签
git push <remote> --tags

删除标签

本地删除:

1
git tag -d <tagname>

同样的,远程仓库的标签必须手动显式地删除:

1
git push <remote> --delete <tagname>

检出标签

1
2
3
git checkout <tagname>
# or
git checkout -b <newbranchname> <tagname>