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 文件:
# 以 ; 或 # 开头的为注释行
# 方括号定义节 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 选项,它实际上就是通过对配置文件的增删改查来实现的:
# 列出配置文件中的所有配置项和值
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 仓库或者重新初始化现有的仓库。
该命令会创建一个空的 git 仓库,基本上就是创建一个 .git
目录其中包含了一些必须的文件和文件夹。他还会创建一个没有任何提交的初始分支(可以通过 --initial-branch
指定其他分支,如果没有指定使用 master 可通过 init.defaultBranch
配置其他默认值).
clone
git clone将存储库克隆到一个新的目录:
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)
保存了工作目录内容的快照,该快照被作为下一次提交的内容:
status
git status用于显示暂存区和当前 HEAD(仓库)之间的差异、工作目录和暂存区之间的差异以及工作目录中未跟踪的文件。
commit
git commit记录对 Git 仓库的更改,即将 暂存区(index)
指向的快照提交到 Git 仓库中,并且添加描述性信息:
diff
git diff显示各个地方的对文件修改的差异:
git diff # 默认比较工作目录和暂存区之间的差异
--staged # 比较暂存区和 HEAD 之间的差异
HEAD # 比较工作目录和 HEAD 之间的差异
<commit1> <commit2> # 比较两次提交之间的差异
<branch1> <branch2> # 比较两个分支之间的差异
<file>
git diff
会打开一个编辑器其中会显示如下内容:
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用于恢复工作目录或暂存区中的文件:
git restore
--staged # 从 HEAD 恢复暂存区的内容(表现就是取消文件的暂存)
--worktree # 使用暂存区回复工作目录的文件内容,默认行为
--source=<commit> # 从指定的提交中恢复工作目录的内容
<file>
注意 --staged
是安全的,因为它并不会修改工作目录中的文件内容,而 --worktree/--source
是危险的,他们会使用暂存区或者 git 仓库的指定提交覆盖工作目录中文件的内容
Tips
暂存区的存在是允许用户精心准备要提交的细节
reset
git reset用于重置当前 HEAD 到指定的其他提交:
git reset
--soft # 仅修改 HEAD,而并不修改暂存区(index)和工作目录中的内容,这意味着此时 git status 会显示 `Changes to be committed`
--mixed # 修改 HEAD 和暂存区,但是并不修改文件书,这意味着 git status 会显示未暂存
--hard # 修改暂存区和工作目录
<commit>
它们各有各的用处,其中官方呈现的三个场景包括:
- 撤销一个提交并重做
$ git commit ...
# --soft 即重置 HEAD 到上一次提交,暂存区和工作目录并不更改
$ git reset --soft HEAD^ (1)
# 细微修改
$ edit (2)
# 重新提交
$ git commit -a -c ORIG_HEAD (3)
实际上还有一个就是修改后直接 git commit --amend
来修改最后一个提交。
- 撤销一个提交,使其成为一个新的分支
# 你完成了一个提交,但是是在 master 分支上提交的
# 此时你觉得他直接合并到 master 并不成熟,想要在一个新的分支上开发,于是首先创建了一个新的分支
# 新的分支指向最新的提交
$ git branch topic/wip (1)
# 此时还在 master 分支上,我们回溯到前三个提交
# 即此时 master 分支回溯到前三次提交之前
$ git reset --hard HEAD~3 (2)
# 切换到新的分支来继续进行开发
$ git switch topic/wip (3)
这个也是 reset 最核心的使用场景。
- 永久撤销提交
这是一个非常差的行为,我们应该仔细维护自己的提交。注意如果已经将该提交共享给他人就永远不要试图撤销提交。
log
git log输出所有提交历史信息。
分支管理
branch
git branch用于列出、创建或删除分支:
git branch # 默认列出所有分支
-a/--all # 列出本地和远程分支
-r/--remotes # 列出远程分支
-m/--move <oldbranch> <newbranch> # 修改分支名称
-d/--delete <branchname> # 删除指定分支
<branchname> # 无指定创建分支
该命令更多的时候是列出分支以及删除分支使用的,对于创建分支通常使用 git switch -c <branchname>
。
switch
git switch顾名思义就是切换分支的:
merge
rebase
stash
git stash将工作目录和暂存区的状态存储到栈中,他的结果会让当前仓库处于干净(clean)状态而无需将所有的更改提交。这在需要临时切换分支时很有用。
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 switch
和 git 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
这种集成了太多功能的命令