git 命令详解与参数实测(Ubuntu 22.04)
以 Ubuntu 22.04(git 2.34.1)实测逐用法讲解 git:init/status/add 工作流、commit -m/--allow-empty/--amend(含空提交 amend 被拒)、log 参数组、diff 与 show、branch/switch/checkout、merge 与冲突解决、remote/clone/push/fetch/pull、tag、blame/shortlog/describe/rev-parse/reflog、reset 三模式与 ORIG_HEAD、stash、clean/worktree、rm/mv/cherry-pick/revert、cat-file/count-objects/gc/fsck/archive、config 别名与 help,附实战与注意事项。
git 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 git 的核心用法——init/status/add 基础工作流、commit 的 -m/--allow-empty/--amend(含 amend 空提交被拒绝的边界行为)、log 参数组(-n/--skip/--grep/--路径/-p/--stat/--format/--reverse)、diff 与 show、branch/switch/checkout 分支三件套、merge 快进与 --no-ff 及冲突解决(CONFLICT 标记与 --ours 取舍)、remote/clone/push/fetch/pull 远程协作、tag 轻量与附注标签、blame/shortlog/describe/rev-parse/reflog 历史检索、reset 三种模式与 ORIG_HEAD 找回提交、stash、clean/worktree、rm/mv/cherry-pick/revert、cat-file/count-objects/gc/fsck/archive 仓库维护、config 与别名、help 系列,全部命令与回显已在 Ubuntu 22.04(git 2.34.1)实测通过。
一、环境信息
本文所有命令均在以下环境实测,回显逐字照抄:
- 操作系统:Ubuntu 22.04.5 LTS(
PRETTY_NAME="Ubuntu 22.04.5 LTS") - git 版本:git version 2.34.1(Ubuntu 软件源 git 软件包自带版本)
- Shell:GNU bash 5.1.16(1)-release
- 执行身份:root
- 测试目录:
/tmp/gitdemo、/tmp/gitbranch、/tmp/gitremote、/tmp/githist、/tmp/gitmaint(由测试脚本动态创建,每个小节可独立复现) - 全局身份配置:
git config --global user.name "testuser"、user.email "test@example.com"、init.defaultBranch main
二、命令概览
2.1 语法形态
git 是分布式版本控制系统,命令形态为「git 子命令 + 子命令参数」:
git <command> [<options>] [<arguments>]
本文按工作流分组逐项实测:仓库与暂存(init/add/status/diff)、提交(commit/log/show)、分支(branch/switch/checkout/merge)、远程(remote/clone/push/fetch/pull/tag)、检索(log/blame/shortlog/describe/rev-parse/reflog)、撤销(reset/stash/clean/revert/cherry-pick/rm/mv)、维护(cat-file/ls-files/count-objects/gc/fsck/archive/worktree)、配置(config/help)。
2.2 git help -a 子命令清单(节选)
$ git help -a
See 'git help <command>' to read about a specific subcommand
Main Porcelain Commands
add Add file contents to the index
am Apply a series of patches from a mailbox
archive Create an archive of files from a named tree
bisect Use binary search to find the commit that introduced a bug
branch List, create, or delete branches
bundle Move objects and refs by archive
checkout Switch branches or restore working tree files
cherry-pick Apply the changes introduced by some existing commits
citool Graphical alternative to git-commit
2.3 子命令速查:git add -h(全量)
$ git add -h
usage: git add [<options>] [--] <pathspec>...
-n, --dry-run dry run
-v, --verbose be verbose
-i, --interactive interactive picking
-p, --patch select hunks interactively
-e, --edit edit current diff and apply
-f, --force allow adding otherwise ignored files
-u, --update update tracked files
--renormalize renormalize EOL of tracked files (implies -u)
-N, --intent-to-add record only the fact that the path will be added later
-A, --all add changes from all tracked and untracked files
--ignore-removal ignore paths removed in the working tree (same as --no-all)
--refresh don't add, only refresh the index
--ignore-errors just skip files which cannot be added because of errors
--ignore-missing check if - even missing - files are ignored in dry run
--sparse allow updating entries outside of the sparse-checkout cone
--chmod (+|-)x override the executable bit of the listed files
--pathspec-from-file <file>
read pathspec from file
--pathspec-file-nul with --pathspec-from-file, pathspec elements are separated with NUL character
退出码=129
⚠️ 注意:-h 是速查用途,git 以 129 退出(usage 类错误码),不是执行失败。
2.4 版本信息
$ git --version
git version 2.34.1
退出码=0
三、参数逐项实测
3.1 init / status / add:基础工作流
git init demo-repo # 初始化仓库
git -C demo-repo status # -C 在仓库外执行子命令
echo "hello" > README.md # 产生未跟踪文件
git add README.md # 暂存
echo "world" >> README.md # 暂存后继续修改
git add -A # 全部改动入暂存区
git diff --cached --stat # 暂存区 vs HEAD 统计
实测回显:
$ git init demo-repo
Initialized empty Git repository in /tmp/gitdemo/demo-repo/.git/
退出码=0
$ git -C demo-repo status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
退出码=0
$ git status -s
?? README.md
退出码=0
$ git status -sb
## No commits yet on main
?? README.md
退出码=0
$ git status -s
A README.md
退出码=0
$ echo "world" >> README.md
$ git status -s
AM README.md
退出码=0
$ git diff --cached --stat
README.md | 2 ++
1 file changed, 2 insertions(+)
退出码=0
关键点:短格式 git status -s 用两列状态码——?? 未跟踪、A 新增暂存、AM 暂存后又修改(第一列暂存区状态、第二列工作区状态)。
3.2 commit:-m / --allow-empty / --amend
$ git commit -m "init: add README"
[main (root-commit) b66ca1c] init: add README
1 file changed, 2 insertions(+)
create mode 100644 README.md
退出码=0
$ git commit --amend -m "init: add README (amended)"
[main 41fab93] init: add README (amended)
Date: Sat Oct 17 02:49:51 2026 +0000
1 file changed, 2 insertions(+)
create mode 100644 README.md
退出码=0
$ git log --oneline
41fab93 init: add README (amended)
退出码=0
$ git commit --allow-empty -m "chore: empty commit"
[main 0eabac9] chore: empty commit
退出码=0
$ git commit --amend -m "try amend empty"
On branch main
No changes
You asked to amend the most recent commit, but doing so would make
it empty. You can repeat your command with --allow-empty, or you can
remove the commit entirely with "git reset HEAD^".
退出码=1
$ git commit --amend --allow-empty -m "chore: empty commit (amended)"
[main 638c99d] chore: empty commit (amended)
Date: Sat Oct 17 02:49:51 2026 +0000
退出码=0
两个关键结论:
--amend修正最近提交时会生成新哈希(41fab93 取代 b66ca1c)——已推送的提交被 amend 后需要强推,务必只 amend 未共享的提交;- amend 一个空提交且不引入新改动时,git 拒绝执行(退出码 1),必须显式加
--allow-empty。这是 2.34 实测出的真实边界,不是文档臆造。
3.3 log 参数组
$ git log --oneline
638c99d chore: empty commit (amended)
41fab93 init: add README (amended)
退出码=0
$ git log -1 --format="%h %an %ad %s" --date=short
638c99d testuser 2026-10-17 chore: empty commit (amended)
退出码=0
在 6 个提交的测试仓库上继续实测过滤与展示参数:
$ git log --oneline -3
30145bd initial add other
4d746d4 commit 5
511a933 commit 4
退出码=0
$ git log --oneline --skip=2 -2
511a933 commit 4
a09b398 commit 3
退出码=0
$ git log --oneline --grep="commit 3"
a09b398 commit 3
退出码=0
$ git log --oneline -- log.txt
4d746d4 commit 5
511a933 commit 4
a09b398 commit 3
8b92c70 commit 2
a696815 commit 1
退出码=0
$ git log --stat -1
commit 30145bd75ec0e994b573121c94a375e6bf8aa4b1
Author: testuser <test@example.com>
Date: Sat Oct 17 02:52:09 2026 +0000
initial add other
other.txt | 1 +
1 file changed, 1 insertion(+)
退出码=0
$ git log --format="%h|%s" --reverse
a696815|commit 1
8b92c70|commit 2
a09b398|commit 3
511a933|commit 4
4d746d4|commit 5
30145bd|initial add other
退出码=0
$ git log -p -1
commit 30145bd75ec0e994b573121c94a375e6bf8aa4b1
Author: testuser <test@example.com>
Date: Sat Oct 17 02:52:09 2026 +0000
initial add other
diff --git a/other.txt b/other.txt
new file mode 100644
index 0000000..e45c9c2
--- /dev/null
@@ -0,0 +1 @@
退出码=0
| 参数 | 作用 |
|---|---|
-n | 只显示最近 n 条 |
--skip=N | 跳过最近 N 条(配合 -n 做分页) |
--grep="关键词" | 按提交信息正则过滤 |
-- <路径> | 只看触及该路径的提交 |
-p | 附带完整补丁 |
--stat | 附带文件级增删统计 |
--format="..." | 自定义占位符格式(%h 短哈希、%an 作者、%ad 日期、%s 标题) |
--reverse | 逆序输出(旧→新) |
3.4 diff 与 show
$ git diff --cached --stat
README.md | 2 ++
1 file changed, 2 insertions(+)
退出码=0
$ git show HEAD --stat
commit 638c99dbfbd789d1fd6dbcd0b42fba05764ad190
Author: testuser <test@example.com>
Date: Sat Oct 17 02:49:51 2026 +0000
chore: empty commit (amended)
退出码=0
$ git diff HEAD~1 HEAD --name-only
退出码=0
三个 diff 视角的分工:git diff 看工作区 vs 暂存区;git diff --cached(或 --staged)看暂存区 vs HEAD;git diff A B 看两个提交之间。--name-only 只列文件名,最后一例两个提交间无差异所以无输出。
3.5 branch / switch / checkout:分支三件套
$ git branch
* main
退出码=0
$ git branch feature-a
退出码=0
$ git branch -v
feature-a 0e9c7fc base commit
* main 0e9c7fc base commit
退出码=0
$ git switch feature-a
Switched to branch 'feature-a'
退出码=0
$ git switch -c feature-b
Switched to a new branch 'feature-b'
退出码=0
$ git checkout feature-a
Switched to branch 'feature-a'
退出码=0
实测结论:git switch 是 2.23+ 推荐的分支切换命令,-c 创建并切换;git checkout 是老命令,仍可用。创建分支后立即切换,工作区文件随分支变化(切回 main 后 ls 只剩 file.txt,fa.txt 消失)。
3.6 merge:快进、--no-ff 与冲突解决
$ git merge feature-b -m "merge feature-b"
Already up to date.
退出码=0
$ git switch main && git merge --no-ff feature-a -m "merge feature-a"
Switched to branch 'main'
Merge made by the 'ort' strategy.
fa.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 fa.txt
退出码=0
$ git log --oneline --graph
* 1992676 merge feature-a
|\
| * 90efb31 add fa.txt
|/
* 0e9c7fc base commit
退出码=0
两个分支从同一基点修改同一文件时产生冲突:
$ git merge side-edit
Auto-merging conflict.txt
CONFLICT (content): Merge conflict in conflict.txt
Automatic merge failed; fix conflicts and then commit the result.
退出码=1
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: conflict.txt
no changes added to commit (use "git add" and/or "git commit -a")
退出码=0
$ cat conflict.txt
<<<<<<< HEAD
main version
=======
side version
>>>>>>> side-edit
退出码=0
$ git checkout --ours conflict.txt && git add conflict.txt && git commit -m "resolve keep main"
Updated 1 path from the index
[main 06a40e4] resolve keep main
退出码=0
要点:merge 冲突时退出码为 1;<<<<<<< 与 >>>>>>> 之间是需要人工裁决的区域;git checkout --ours <file> 保留当前分支版本(--theirs 取对方版本),裁决后 git add 标记已解决并 git commit 收尾;放弃合并用 git merge --abort。
3.7 remote / clone / push / fetch / pull:远程协作
以本地裸仓库模拟远端(无需网络即可复现):
$ git init --bare server.git
Initialized empty Git repository in /tmp/gitremote/server.git/
退出码=0
$ git clone /tmp/gitremote/server.git work
Cloning into 'work'...
warning: You appear to have cloned an empty repository.
done.
退出码=0
$ git remote -v
origin /tmp/gitremote/server.git (fetch)
origin /tmp/gitremote/server.git (push)
退出码=0
$ git remote show origin
* remote origin
Fetch URL: /tmp/gitremote/server.git
Push URL: /tmp/gitremote/server.git
HEAD branch: (unknown)
Local branch configured for 'git pull':
main merges with remote main
退出码=0
$ git push origin main
To /tmp/gitremote/server.git
* [new branch] main -> main
退出码=0
第二份工作副本推送新提交后,回到第一份副本观察 fetch 与 pull 的差别:
$ git fetch origin
From /tmp/gitremote/server
7748ade..ead509f main -> origin/main
* [new tag] v1.0 -> v1.0
退出码=0
$ git log --oneline main..origin/main
ead509f v2
退出码=0
$ git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
退出码=0
$ git pull origin main
From /tmp/gitremote/server
* branch main -> FETCH_HEAD
Updating 7748ade..ead509f
Fast-forward
app.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
退出码=0
$ git ls-remote origin
ead509f0ac53ae021ecc982b9e5f285ad16e933e HEAD
ead509f0ac53ae021ecc982b9e5f285ad16e933e refs/heads/main
7748ade8dfef045a4a34d2be635cb7b2901e3e14 refs/tags/v1.0
95786ae12a5d0cbcf3bb67c40cb402065e64cb20 refs/tags/v1.1
7748ade8dfef045a4a34d2be635cb7b2901e3e14 refs/tags/v1.1^{}
退出码=0
要点:fetch 只更新远程跟踪分支(origin/main),不碰工作区;pull = fetch + merge。main..origin/main 列出「远端有、本地没有」的提交。远程管理:git remote rename origin upstream、git remote remove upstream(删除后 git remote -v 无输出)。
3.8 tag:轻量与附注标签
$ git tag v1.0
退出码=0
$ git tag -a v1.1 -m "release 1.1"
退出码=0
$ git tag -l
v1.0
v1.1
退出码=0
$ git show v1.1
tag v1.1
Tagger: testuser <test@example.com>
Date: Sat Oct 17 02:51:22 2026 +0000
release 1.1
commit 7748ade8dfef045a4a34d2be635cb7b2901e3e14
Author: testuser <test@example.com>
Date: Sat Oct 17 02:51:22 2026 +0000
v1
退出码=0
$ git push origin v1.1
To /tmp/gitremote/server.git
* [new tag] v1.1 -> v1.1
退出码=0
$ git push origin --tags
To /tmp/gitremote/server.git
* [new tag] v1.0 -> v1.0
退出码=0
$ git tag -d v1.0
Deleted tag 'v1.0' (was 7748ade)
退出码=0
要点:无参数 git tag 是轻量标签(仅一个指针);-a 创建附注标签(独立对象,含作者/日期/说明,git show 可见)。推送时标签不会随 git push origin main 自动上远端,需 git push origin <tag> 或 --tags。
3.9 blame / shortlog / describe / rev-parse / reflog:历史检索五件套
$ git blame log.txt
^a696815 (testuser 2026-10-17 02:52:09 +0000 1) line-1
8b92c70e (testuser 2026-10-17 02:52:09 +0000 2) line-2
a09b3982 (testuser 2026-10-17 02:52:09 +0000 3) line-3
511a9331 (testuser 2026-10-17 02:52:09 +0000 4) line-4
4d746d44 (testuser 2026-10-17 02:52:09 +0000 5) line-5
退出码=0
$ git blame -L 2,3 log.txt
8b92c70e (testuser 2026-10-17 02:52:09 +0000 2) line-2
a09b3982 (testuser 2026-10-17 02:52:09 +0000 3) line-3
退出码=0
$ git shortlog HEAD
testuser (6):
commit 1
commit 2
commit 3
commit 4
commit 5
initial add other
退出码=0
$ git describe --tags
fatal: No names found, cannot describe anything.
退出码=128
$ git tag v0.1 HEAD~2 && git describe --tags
v0.1-2-g30145bd
退出码=0
$ git rev-parse HEAD
30145bd75ec0e994b573121c94a375e6bf8aa4b1
退出码=0
$ git rev-parse --short HEAD
30145bd
退出码=0
$ git rev-parse HEAD~1
4d746d44b07a6e3211d249609f8a2e53fc9fe3d6
退出码=0
$ git reflog
30145bd HEAD@{0}: commit: initial add other
4d746d4 HEAD@{1}: commit: commit 5
511a933 HEAD@{2}: commit: commit 4
a09b398 HEAD@{3}: commit: commit 3
8b92c70 HEAD@{4}: commit: commit 2
a696815 HEAD@{5}: commit (initial): commit 1
退出码=0
⚠️ 两个实测陷阱:
git shortlog不带参数时从 stdin 读提交清单——在脚本管道里执行会挂起或吞掉上游数据;在仓库内请显式写git shortlog HEAD(本篇实测即因此改写命令)。git describe --tags在仓库无任何标签时 fatal(退出码 128);v0.1-2-g30145bd的含义是「v0.1 之后第 2 个提交,其短哈希 30145bd」。
3.10 reset 三种模式与 ORIG_HEAD 找回
$ git reset --soft HEAD~1
退出码=0
$ git status -s
M src/main.c
退出码=0
$ git reset --mixed HEAD
Unstaged changes after reset:
M src/main.c
退出码=0
$ git reset --hard HEAD~1
HEAD is now at 4d746d4 commit 5
退出码=0
$ git log --oneline -1
4d746d4 commit 5
退出码=0
$ git reset --hard ORIG_HEAD
HEAD is now at 30145bd initial add other
退出码=0
$ git log --oneline -1
30145bd initial add other
退出码=0
| 模式 | HEAD 移动 | 暂存区 | 工作区 |
|---|---|---|---|
--soft | 移动 | 保留 | 保留(改动停在暂存区,第一列 M) |
--mixed(默认) | 移动 | 重置 | 保留(改动退回工作区,第二列 M) |
--hard | 移动 | 重置 | 重置(未提交改动全部丢弃,慎用) |
实测确认:--hard 丢掉的提交并未消失——git 自动把重置前的 HEAD 记在 ORIG_HEAD,git reset --hard ORIG_HEAD 一步找回;更早的历史用 git reflog 定位。
3.11 stash:临时暂存
$ git stash
Saved working directory and index state WIP on main: 30145bd initial add other
退出码=0
$ git stash list
stash@{0}: WIP on main: 30145bd initial add other
退出码=0
$ git stash show -p
diff --git a/log.txt b/log.txt
index 22a7868..3db3aa1 100644
--- a/log.txt
@@ -3,3 +3,4 @@ line-2
line-3
line-4
line-5
退出码=0
$ git stash pop
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: log.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (a6564785d786d44a7b1af5db698673c6a8995408)
退出码=0
$ git stash list
退出码=0
$ git stash drop
Dropped refs/stash@{0} (a6564785d786d44a7b1af5db698673c6a8995408)
退出码=0
要点:pop = 恢复 + 删除栈顶暂存;想保留暂存条目用 apply;drop 主动丢弃。栈式管理:stash@{0} 最新。
3.12 clean 与 worktree
$ git clean -n
Would remove untracked1.txt
Would remove untracked2.txt
退出码=0
$ git clean -fd
Removing untracked1.txt
Removing untracked2.txt
Removing untrackeddir/
退出码=0
$ git status -s
退出码=0(无输出为干净)
$ git worktree add ../wt-feature -b wt-feature
Preparing worktree (new branch 'wt-feature')
HEAD is now at 30145bd initial add other
退出码=0
$ git worktree list
/tmp/githist/repo 30145bd [main]
/tmp/githist/wt-feature 30145bd [wt-feature]
退出码=0
$ git worktree remove ../wt-feature
退出码=0
$ git worktree list
/tmp/githist/repo 30145bd [main]
退出码=0
⚠️ 安全铁律:clean 先 -n(dry-run)预览再真删;-f 允许删除、-d 连未跟踪目录一起删、-x 连被 ignore 的文件一起删。worktree 允许同一仓库在多个目录同时检出不同分支,list 查看全部工作树。
3.13 rm / mv / cherry-pick / revert
$ git rm --cached b.txt
rm 'b.txt'
退出码=0
$ ls
a.txt
b.txt
src
退出码=0
$ git status -s
D b.txt
?? b.txt
退出码=0
$ git mv a.txt renamed.txt
退出码=0
$ git status -s
R a.txt -> renamed.txt
退出码=0
$ git cherry-pick 08476f4bf905c45bac76ec35422bc6f05590c40d
[main 48d71d8] patch main.c
Date: Sat Oct 17 02:52:38 2026 +0000
1 file changed, 1 insertion(+)
退出码=0
$ git revert --no-edit HEAD
[main dfb7287] Revert "patch main.c"
Date: Sat Oct 17 02:52:38 2026 +0000
1 file changed, 1 deletion(-)
退出码=0
$ git log --oneline -3
dfb7287 Revert "patch main.c"
48d71d8 patch main.c
433d85f rename a
退出码=0
$ cat src/main.c
code
退出码=0
对比:rm --cached 只把文件从索引摘除(磁盘保留、变回未跟踪,D+?? 双状态);rm 连磁盘一起删。cherry-pick <sha> 把指定提交的改动复制到当前分支(生成新哈希);revert 生成一个反向提交撤销历史中某次改动——不重写历史,适合已共享分支。
3.14 cat-file / ls-files / count-objects / gc / fsck / archive:仓库维护
$ git cat-file -t HEAD
commit
退出码=0
$ git cat-file -p HEAD
tree ae13618210093684f556161d35964b62a19e8fd4
parent 433d85f5425246ef193f4c476ca8b5fd2677c3fc
author testuser <test@example.com> 1792205558 +0000
committer testuser <test@example.com> 1792205558 +0000
patch main.c
退出码=0
$ git cat-file -s HEAD
215
退出码=0
$ git ls-files
renamed.txt
src/main.c
退出码=0
$ git count-objects
20 objects, 80 kilobytes
退出码=0
$ git gc --quiet
退出码=0
$ git count-objects -v
count: 0
size: 0
in-pack: 20
packs: 1
size-pack: 3
prune-packable: 0
garbage: 0
size-garbage: 0
退出码=0
$ git fsck
退出码=0
$ git archive -o /tmp/snapshot.tar HEAD
退出码=0
$ tar -tf /tmp/snapshot.tar
renamed.txt
src/
src/main.c
退出码=0
要点:git 对象四类型 commit/tree/blob/tag,cat-file -t/-p/-s 看类型/内容/字节数;gc 后松散对象(count: 20, size: 80KB)打包为 1 个包(size-pack: 3KB),体积骤降;fsck 校验对象库完整性;archive 从任意提交导出干净源码快照(不含 .git)。
3.15 config 与 alias
$ git config user.name
testuser
退出码=0
$ git config --local core.quotepath false
退出码=0
$ git config --get core.quotepath
false
退出码=0
$ git config --list --local
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.quotepath=false
退出码=0
$ git config --unset core.quotepath
退出码=0
$ git config alias.lg "log --oneline --graph"
退出码=0
$ git lg
* 48d71d8 patch main.c
* 433d85f rename a
* c9ab1ba remove b
* 23accab update a
* 6121b73 initial
退出码=0
$ git config --get alias.lg
log --oneline --graph
退出码=0
配置三级作用域 --system(全机)> --global(当前用户)> --local(当前仓库,默认),近者优先。alias.<名> 定义命令别名,别名可组合任意子命令与参数。
四、实战示例
4.1 场景一:功能分支开发合并全流程
git switch -c feature-login # 从 main 开出功能分支
# ...编码、自测...
git add -A # 暂存全部改动
git commit -m "feat: add login" # 提交
git switch main # 回主线
git merge --no-ff feature-login -m "merge feature-login" # 禁快进保留分支轨迹
git branch -d feature-login # 删除已合并分支
git log --oneline --graph -5 # 复核历史
全程对应 3.5/3.6 实测回显;若合并冲突,按 3.6 的「--ours/--theirs 裁决 → add → commit」或 git merge --abort 退出。
4.2 场景二:误操作找回(reset --hard 反悔)
git reset --hard HEAD~1 # 手滑丢弃最近提交
git log --oneline -1 # 确认提交"消失"
git reset --hard ORIG_HEAD # git 已记下重置前位置,一步找回
# 更早之前的提交:
git reflog # 找到目标提交短哈希,如 30145bd
git reset --hard 30145bd # 恢复到任意 reflog 记录点
对应 3.10 实测:reset --hard 后 ORIG_HEAD 恢复成功。reflog 默认保留 90 天,是「提交从未丢失」的兜底证据。
五、注意事项与常见问题
- amend 空提交被拒:
git commit --amend在最近提交为空且无新改动时退出码 1,需--amend --allow-empty(3.2 实测)。 - amend 改写哈希:amend 生成新提交对象,已推送的提交 amend 后强推会殃及协作者——只 amend 本地未共享提交。
- shortlog 的 stdin 陷阱:非交互环境下裸
git shortlog会等待/读取 stdin,应写git shortlog HEAD(3.9 实测踩坑)。 - describe 依赖标签:仓库无标签时
git describe --tags直接 fatal(128)。 - 标签不随分支推送:
git push origin main不带标签,发布版本记得git push origin <tag>或--tags(3.8 实测)。 - reset --hard 不可逆假象:工作区未提交改动会被永久丢弃;已提交内容靠 ORIG_HEAD/reflog 找回。软重置选
--soft,默认--mixed只动暂存区(3.10 表格)。 - clean 先干跑:
git clean -fd直接删文件,先git clean -n预览(3.12 实测)。 - merge 冲突退出码是 1:脚本里判断
git merge返回值即可捕获冲突,不要只看报错文本(3.6 实测)。 - --cached 与 --staged 等价:2.34 两者均可,老脚本兼容用
--cached。 - gc 是安全操作:只打包/清理可达对象,正常仓库无需担心丢数据;
fsck用于怀疑损坏时体检(3.14 实测)。
六、参考链接
- 官方文档:https://git-scm.com/docs
- Pro Git 中文版(第 2 版):https://git-scm.com/book/zh/v2
- git 2.34 发布说明:https://github.com/git/git/blob/master/Documentation/RelNotes/2.34.0.txt
- Ubuntu 22.04 软件源 git 包页:https://packages.ubuntu.com/jammy/git
站内相关:ssh-keygen 篇(SSH 远程仓库免密配置)