Skip to content

git 命令

git 包含一大堆的命令,因为历史原因还包含一系列的废弃命令。当然随着更新目前的命令已经优化的很多了。

Tips

所有的命令可以参看git command Reference

配置

git 的配置分为几个范围:

范围 配置文件 选项
system(系统) /etc/gitconfig --system
global(全局) ~/.gitconfig --global
local(本地) $GIT_DIR/config --local
worktree(目录树) $GIT_DIR/config.worktree --worktree
command(命令) - -c

其中下一级范围覆盖上一级范围的配置。

配置文件

git 配置文件以类似 ini 文件:

INI
# 以 ; 或 # 开头的为注释行
# 方括号定义节 section,section 不区分大小写且仅能为数字、字母和 - .
# 节下面可以包括子节 "subsection",子节与前面的节使用空格分开并且包含在双引号中,子节区分大小写且可以包含除了换行符外的任意字符
[section "subsection"]
    ; 属性的格式如下,他们必须位于一个节中
    ; 变量名不区分大小写且仅允许字母、数字和 -,并且必须以字母开头
    ; 值周围的双引号是可选的,如果包含前后空白符则必须使用双引号包括,如果使用 "" 包括值其中的双引号必须转移 \"
    name = value

[core]
    filemode = false
[branch "devel"]
    remote = origin
    merge = refs/heads/devel
# 特殊的 include.path 属性允许引入外部源
[include]
    path = /path/to/foo.inc ; include by absolute path
    path = foo.inc ; find "foo.inc" relative to the current file
    path = ~/foo.inc ; find "foo.inc" in your `$HOME` directory

config

git config 命令用于设置 git 选项,它实际上就是通过对配置文件的增删改查来实现的:

Bash
# 列出配置文件中的所有配置项和值
git config --list
# 获取指定配置项的值
git config --get <name>
# 设置指定配置项
git config <name> <value>
# 取消指定配置项的值(恢复默认)
git config --unset <name>
# 打开编辑器修改指定的配置文件
git config --edit

所有这些命令都可以通过指定 --system--global--local(默认)、--worktree 甚至 --file <filename> 来指定要修改的配置文件。其中 name 通常是 section.name 这样的形式。

Tips

最新的 git 中上面的 --list 等推荐以子命令的形式出现,例如 git config list|get|set|unset|edit 而不是以选项的形式提供

可用配置项

配置项 默认或者建议值 说明
core.editor vim 指定默认的文本编辑器
init.defaultBranch master 设置默认的分支
user.name 用户名 指定提交用户名
user.email 用户邮箱 在提交时会体现,由于他唯一是非常重要的属性

创建或获取版本库

init

git init创建一个空的 git 仓库或者重新初始化现有的仓库。

Bash
git init
    --initial-branch=<branch-name> # 指定初始的分支

该命令会创建一个空的 git 仓库,基本上就是创建一个 .git 目录其中包含了一些必须的文件和文件夹。他还会创建一个没有任何提交的初始分支(可以通过 --initial-branch 指定其他分支,如果没有指定使用 master 可通过 init.defaultBranch 配置其他默认值).

clone

git clone将存储库克隆到一个新的目录:

Bash
git clone <url>
    --branch <name> # 将 HEAD 指向指定分支而不是克隆库 HEAD 所指向的分支
    [target_dir] # 要 clone 到的目标目录,默认会在当前目录下创建一个与远程仓库同名的文件夹

clone 的核心是 url,它代表一个远程仓库的地址。git 支持很多协议主流的有 http 和 git 协议:

  • http[s]://<host>[:post]/<path-to-git-repo>
  • git://<host>[:port]/<path-to-git-repo>

由于 github 非常流行,目前常用的远程仓库都遵循:

  • https://github.com/<username>/<reponame>.git
  • git@github.com:<username>/<reponame>.git

快照管理

add

git add使工作目录的文件更新 暂存区(index) 中的内容。暂存区(index) 保存了工作目录内容的快照,该快照被作为下一次提交的内容:

Bash
git add <files>

status

git status用于显示暂存区和当前 HEAD(仓库)之间的差异、工作目录和暂存区之间的差异以及工作目录中未跟踪的文件。

commit

git commit记录对 Git 仓库的更改,即将 暂存区(index) 指向的快照提交到 Git 仓库中,并且添加描述性信息:

Bash
git commit
    --amend     # 修改最后一次提交
    -m <msg>    # 提交信息

diff

git diff显示各个地方的对文件修改的差异:

Bash
git diff        # 默认比较工作目录和暂存区之间的差异
    --staged    # 比较暂存区和 HEAD 之间的差异
    HEAD        # 比较工作目录和 HEAD 之间的差异
    <commit1> <commit2> # 比较两次提交之间的差异
    <branch1> <branch2> # 比较两个分支之间的差异
    <file>

git diff 会打开一个编辑器其中会显示如下内容:

Bash
diff --combined describe.c
index fabadb8,cc95eb0..4866510
--- a/describe.c
+++ b/describe.c
@@@ -98,20 -98,12 +98,20 @@@
    return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
  }

- static void describe(char *arg)
 -static void describe(struct commit *cmit, int last_one)
++static void describe(char *arg, int last_one)
  {
 +  unsigned char sha1[20];
 +  struct commit *cmit;
    struct commit_list *list;
    static int initialized = 0;
    struct commit_name *n;

 +  if (get_sha1(arg, sha1) < 0)
 +      usage(describe_usage);
 +  cmit = lookup_commit_reference(sha1);
 +  if (!cmit)
 +      usage(describe_usage);
 +
    if (!initialized) {
        initialized = 1;
        for_each_ref(get_name);

restore

git restore用于恢复工作目录或暂存区中的文件:

Bash
git restore
    --staged    # 从 HEAD 恢复暂存区的内容(表现就是取消文件的暂存)
    --worktree  # 使用暂存区回复工作目录的文件内容,默认行为
    --source=<commit> # 从指定的提交中恢复工作目录的内容
    <file>

注意 --staged 是安全的,因为它并不会修改工作目录中的文件内容,而 --worktree/--source 是危险的,他们会使用暂存区或者 git 仓库的指定提交覆盖工作目录中文件的内容

Tips

暂存区的存在是允许用户精心准备要提交的细节

reset

git reset用于重置当前 HEAD 到指定的其他提交:

Bash
git reset
    --soft      # 仅修改 HEAD,而并不修改暂存区(index)和工作目录中的内容,这意味着此时 git status 会显示 `Changes to be committed`
    --mixed     # 修改 HEAD 和暂存区,但是并不修改文件书,这意味着 git status 会显示未暂存
    --hard      # 修改暂存区和工作目录
    <commit>

它们各有各的用处,其中官方呈现的三个场景包括:

  1. 撤销一个提交并重做
Bash
$ git commit ...
# --soft 即重置 HEAD 到上一次提交,暂存区和工作目录并不更改
$ git reset --soft HEAD^      (1)
# 细微修改
$ edit                        (2)
# 重新提交
$ git commit -a -c ORIG_HEAD  (3)

实际上还有一个就是修改后直接 git commit --amend 来修改最后一个提交。

  1. 撤销一个提交,使其成为一个新的分支
Bash
# 你完成了一个提交,但是是在 master 分支上提交的
# 此时你觉得他直接合并到 master 并不成熟,想要在一个新的分支上开发,于是首先创建了一个新的分支
# 新的分支指向最新的提交
$ git branch topic/wip          (1)
# 此时还在 master 分支上,我们回溯到前三个提交
# 即此时 master 分支回溯到前三次提交之前
$ git reset --hard HEAD~3       (2)
# 切换到新的分支来继续进行开发
$ git switch topic/wip          (3)

这个也是 reset 最核心的使用场景。

  1. 永久撤销提交
Bash
$ git commit ...
# 最后三个提交废弃了,不想看到他们
$ git reset --hard HEAD~3 (1)

这是一个非常差的行为,我们应该仔细维护自己的提交。注意如果已经将该提交共享给他人就永远不要试图撤销提交

log

git log输出所有提交历史信息。

分支管理

branch

git branch用于列出、创建或删除分支:

Bash
git branch              # 默认列出所有分支
    -a/--all            # 列出本地和远程分支
    -r/--remotes        # 列出远程分支
    -m/--move <oldbranch> <newbranch>  # 修改分支名称
    -d/--delete <branchname> # 删除指定分支
    <branchname>        # 无指定创建分支

该命令更多的时候是列出分支以及删除分支使用的,对于创建分支通常使用 git switch -c <branchname>

switch

git switch顾名思义就是切换分支的:

Bash
git switch
    -c <branch>     # 创建新分支并切换
    <branch>        # 切换到指定分支

merge

rebase

stash

git stash将工作目录和暂存区的状态存储到栈中,他的结果会让当前仓库处于干净(clean)状态而无需将所有的更改提交。这在需要临时切换分支时很有用。

Bash
git stash
    list                # 列出当前所有 stash 的条目
    show <stash_id>     # 查看对应 stash 具体的内容
    pop <stash_id>      # 恢复指定的 stash 并删除他,如果不跟 stash_id 会恢复最后一条
    apply <stash_id>    # 恢复指定的 stash 但不删除,如果不跟 stash_id 会恢复最后一条
    drop <stash_id>     # 删除指定 stash,如果不跟 stash_id 会删除最后一条
    -u/--include-untracked     # 默认值保存已跟踪的修改和暂存区中的内容,-u 允许保存未跟踪的文件
    -m <msg> # stash 信息

checkout

git checkout用于切换分支以及恢复工作目录使用的,他集成了太多命令,在 Git2.23 版本中将它们拆分为 git switchgit restore 命令了:

功能 git checkout 对应替换命令
切换分支 git checkout <branch> git switch <branch>
创建并切换到新分支 git checkout -b <branch> git switch -c <branch>
恢复文件(从暂存区) git checkout -- <file> git restore <file>
恢复文件(从指定提交) git checkout <commit> -- <file> git restore --source=<commit> <file>

Tips

应当逐步迁移到新的命令上去,尤其像 git checkout 这种集成了太多功能的命令