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,附实战与注意事项。

Linux命令gitLinux系统UbuntuUbuntu 22.04命令行2026/10/17

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

两个关键结论:

  1. --amend 修正最近提交时会生成新哈希(41fab93 取代 b66ca1c)——已推送的提交被 amend 后需要强推,务必只 amend 未共享的提交;
  2. 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

⚠️ 两个实测陷阱:

  1. git shortlog 不带参数时从 stdin 读提交清单——在脚本管道里执行会挂起或吞掉上游数据;在仓库内请显式写 git shortlog HEAD(本篇实测即因此改写命令)。
  2. 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 天,是「提交从未丢失」的兜底证据。

五、注意事项与常见问题

  1. amend 空提交被拒:git commit --amend 在最近提交为空且无新改动时退出码 1,需 --amend --allow-empty(3.2 实测)。
  2. amend 改写哈希:amend 生成新提交对象,已推送的提交 amend 后强推会殃及协作者——只 amend 本地未共享提交。
  3. shortlog 的 stdin 陷阱:非交互环境下裸 git shortlog 会等待/读取 stdin,应写 git shortlog HEAD(3.9 实测踩坑)。
  4. describe 依赖标签:仓库无标签时 git describe --tags 直接 fatal(128)。
  5. 标签不随分支推送:git push origin main 不带标签,发布版本记得 git push origin <tag> 或 --tags(3.8 实测)。
  6. reset --hard 不可逆假象:工作区未提交改动会被永久丢弃;已提交内容靠 ORIG_HEAD/reflog 找回。软重置选 --soft,默认 --mixed 只动暂存区(3.10 表格)。
  7. clean 先干跑:git clean -fd 直接删文件,先 git clean -n 预览(3.12 实测)。
  8. merge 冲突退出码是 1:脚本里判断 git merge 返回值即可捕获冲突,不要只看报错文本(3.6 实测)。
  9. --cached 与 --staged 等价:2.34 两者均可,老脚本兼容用 --cached。
  10. gc 是安全操作:只打包/清理可达对象,正常仓库无需担心丢数据;fsck 用于怀疑损坏时体检(3.14 实测)。

六、参考链接

站内相关:ssh-keygen 篇(SSH 远程仓库免密配置)