这是一份持续增长的 Git 速记页。内容按本地状态、合并同步、钩子环境和身份配置分组;需要完整机制时,再进入对应专题文章。
本地历史、快照与跟踪状态
把独立 Git 仓库移入项目子目录
普通独立克隆的 .git/ 与工作区一起移动后,仓库的提交历史、分支、远端和暂存状态仍留在这个仓库里;外层目录不会因此自动进入该仓库的提交范围。
- 核对:移动前后分别在仓库中运行
git rev-parse --show-toplevel、git status --short --branch、git diff --cached --name-status和git remote -v,确认根目录变化符合预期,其他状态一致。 - 边界:先用
git worktree list确认检出类型;如果是 linked worktree,应使用git worktree move,不能套用普通目录移动。搬迁后还要检查依赖旧绝对路径的脚本、配置和运行进程。 - 来源:git-worktree 的
move说明及本机独立克隆的移动前后 Git 状态回读(2026-10-28)。
下载源码 ZIP 不等于 git clone
仓库的源码归档可以包含某个提交的文件内容,却通常不包含 .git 元数据、分支引用、索引和远端配置。即使文件字节与基线提交一致,在解压目录里开发也不是“已从该分支创建 Git 工作区”。
- 核对:在目标目录运行
git rev-parse --is-inside-work-tree、git rev-parse HEAD和git status --porcelain=v2 --branch;再确认目标分支与上游。归档目录里这些命令不能证明分支状态。 - 迁入:先取得干净的真实 clone,核对 HEAD 与归档基线一致,再用
git apply --check检查补丁。普通git apply只改工作区;不带--index或--cached时不会把新改动暂存。迁入前后都应检查现有 staged/unstaged 边界,避免覆盖他人改动。 - 只有原始发布包时建立审阅基线:在获得初始化和基线提交授权后,先备份已改文件,再以经过校验的原始包创建本地仓库,只提交原始文件;随后把自己的修改覆盖回工作区并保持未暂存。这样
git diff和编辑器的源代码管理可以直接展示“原版 → 当前修改”。如果首次提交就包含已改代码,比较基线也会包含这些修改,无法据此区分原版和新增实现。 - 本地基线的含义:自行创建的初始提交只记录发布包的文件快照,不等于找回上游提交历史。用原包哈希、
git ls-tree和git show HEAD:<文件>核对内容,再用git diff --cached --name-only确认自己的改动没有暂存;该流程已于 2026-11-03 通过原包逐文件核对及工作区状态回读验证。 - 来源与验证:git-clone、git-archive、git-apply。2026-10-26 对同一提交的源码归档和真实克隆核对 HEAD/工作区状态,并在干净克隆中以补丁检查、应用和状态回读验证边界。
git clone --single-branch --branch 与浅克隆
git clone --single-branch --branch main <repository> <directory> 只取得通向指定分支 tip 的历史,并将默认 fetch 范围限制到该远端分支;它仍是正常 Git 仓库,已有上游提交可以直接作为工作区修改的比较基线。
- 边界:
--branch单独使用只选择检出的分支,不等于仅获取该分支。--single-branch不等于只保留一个提交;需要限制历史深度时才额外使用--depth。 - 标签:默认仍可能获取标签;若也不需要标签,明确使用
--no-tags。这些选项不是远端访问权限控制。 - 核对:查看
git branch --remotes、git config --get-all remote.origin.fetch和git rev-parse --is-shallow-repository,分别确认远端分支、后续抓取范围和是否浅克隆。 - 来源:Git 官方 clone 文档,2026-11-03 核对选项说明并验证单分支克隆的引用与 fetch 配置。
撤销尚未推送的最新 commit,并保留文件修改
git reset 的模式决定撤销 commit 后,修改留在索引还是工作区:
# 只移动 HEAD:修改仍在 Staged Changes
git reset --soft HEAD~1
# 移动 HEAD 并重置索引:修改回到未暂存的 Changes
git reset --mixed HEAD~1
# --mixed 是默认值,也可简写为:git reset HEAD~1
- 适合场景:最新 commit 尚未推送,希望重新整理或修改后再提交。
- 记忆点:
--soft只重置 HEAD;--mixed重置 HEAD 和 index,但保留 working tree;想回到 GUI 的未暂存Changes应使用--mixed。操作后用git status核对。 - 边界:不要为了保留修改使用
--hard,它会同时重置 HEAD、索引和工作区。已经推送到共享分支的提交通常不应直接 reset 改写历史,应根据协作情况考虑git revert。 - 把多个本地提交恢复为相对基线的 Changes:先确认目标基线与当前提交的关系,在当前 HEAD 创建本地备份分支,再执行
git reset --mixed <已核实的基线提交>。备份分支继续保留原提交链;工作区保留最新文件,修改和删除成为未暂存差异,基线中没有的新文件成为未跟踪文件。编辑器的 Changes 因而能直接显示全部定制,而不仅是最后一次提交后的差异。 - 审阅与恢复:mixed reset 会改动当前分支和索引,不能保留原有 staged/unstaged 分组,执行前须明确授权并核对状态。保留备份分支无需重新提交或推送;恢复历史时先保存当前工作区中的后续修改。2026-11-03 以三个未推送提交验证,恢复基线后旧差异全部出现在
git status --porcelain --untracked-files=all,文件哈希保持一致、暂存区为空,备份引用仍指向原顶端。 - 来源:git-reset;结论也由本机
git reset -h的模式说明复核。
将未评审 Changes 备份到远端,同时保持本地未暂存
远端 Git 只能保存 commit;可以创建一次 WIP commit,将它通过显式 refspec 推到独立备份分支,再把本地 HEAD mixed reset 回去:
git status --short
git add -A
git commit -m "wip: backup unreviewed changes"
git push origin HEAD:refs/heads/chore/wip-backup-YYYYMMDD
git reset --mixed HEAD~1
git status
- 结果:远端
chore/wip-backup-YYYYMMDD保留 WIP commit;当前本地分支回到原 HEAD,文件内容仍在 working tree,并统一显示为未暂存 Changes。 - 边界:
git add -A不包含 ignored 文件,也不会保留原有 staged/unstaged 分组;提交钩子若会自动修改文件,也可能改变最终快照。推送前至少检查文件列表和敏感信息,备份分支不要直接作为正式合并分支。 - 不要混淆:普通
git stash默认只保存在本地仓库,电脑和本地仓库一起丢失时不能充当远端备份。 - 恢复:可从任意新 clone 中查看备份分支,或基于该分支恢复文件;不需要改写正式远端分支历史。
- 保持本地状态完全不变:自动化场景可以改用
GIT_INDEX_FILE、read-tree、write-tree和commit-tree构造快照,详见用临时索引创建不改变工作区的 Git 快照。 - 来源:git-push 的 refspec、git-reset。命令模式也由本机 Git 帮助复核。
.gitignore 不会自动取消已经跟踪的文件
.gitignore 只决定未跟踪文件是否应被 Git 忽略。一个文件只要已经进入索引,即使后来匹配 ignore 规则,修改后仍会出现在 git status 中。
# 确认文件是否已被跟踪
git ls-files --stage path/to/generated-file
# 即使文件已跟踪,也检查它本应匹配哪条 ignore 规则
git check-ignore -v --no-index path/to/generated-file
# 确认团队确实不再提交该文件后,只从索引移除并保留本地文件
git rm --cached -- path/to/generated-file
- 记忆点:添加 ignore 规则和取消跟踪是两个独立动作。
git rm --cached会把“从仓库删除该路径”加入下一次提交,但不会删除工作区文件;之后匹配的 ignore 规则才会阻止它再次被普通git add加入。 - 边界:有些仓库会默认忽略整个生成目录,但用
git add -f按需跟踪少数生成物。看到“tracked + ignored”不能仅凭目录名判断是错误,应同时检查项目文档、生成/构建流程和同目录历史文件。 - 交付包边界:
.gitignore不自动控制手工压缩或自定义ZIP遍历。打包必须显式采用忽略规则或目标文件选择,并核对归档条目;不能从Git状态推断ZIP没有缓存。2026-10-28用合成文件验证,直接调用ZIP写入仍会收录被忽略规则命中的名称;另对按Git规则选择的源码包核验排除结果。更多边界见发布目标与文件集合。 - 来源:gitignore 明确说明已跟踪文件不受影响;git-rm 说明
--cached只从索引移除路径。
合并状态
删除冲突标记不等于 Git 已标记冲突解决
手工编辑冲突文件只会改变工作区;只要索引中仍保留冲突的 stage 1/2/3 条目,git status --short 就仍会显示 UU 等未合并状态。
# 检查索引中仍未解决的路径和各阶段条目
git status --short
git ls-files -u
# 审核最终文件后,把当前内容写入索引并标记该路径已解决
git add -- path/to/file
- 适合场景:文件内已经看不到
<<<<<<<、=======、>>>>>>>,但 Git 仍报告unmerged paths。 - 记忆点:冲突标记属于工作区文本,
unmerged属于索引状态;删除标记不会自动更新索引。git add不只是“消除提示”,还会把当前文件内容写入索引,因此应先审查合并结果。 - 辅助检查:
git diff --check可以发现常见空白错误和残留冲突标记;git ls-files -u能直接确认索引是否仍有未合并条目。 - 来源:Git User Manual:Resolving a merge、git-status 的 unmerged entries、git-ls-files。结论也在 Git 2.39.5 的实际合并状态中复核。
钩子与运行环境
pre-commit 中 ESLint 因 Node 堆内存不足退出
提交输出包含 Reached heap limit、JavaScript heap out of memory 和 SIGABRT 时,直接失败原因是 Node/V8 堆上限,而不是 ESLint 已经报告了某条代码规则错误。大量 staged 文件被 lint-staged 一次性交给 ESLint 时尤其容易触发。
# 先确认本次提交和 Node 默认堆规模
git diff --cached --name-only | wc -l
node -e "const v8=require('v8'); console.log(v8.getHeapStatistics().heap_size_limit / 1024 / 1024)"
# 机器内存充足时,只为这一次终端提交提高堆上限
NODE_OPTIONS=--max-old-space-size=8192 git commit
- 记忆点:
--max-old-space-size调整 V8 old space 上限;通过NODE_OPTIONS设置后会传给提交钩子启动的 Node 子进程。GUI 提交是否继承该变量取决于 GUI 进程的启动环境,因此一次性重试优先从设置变量的同一终端执行。 - 不要混淆:提高堆上限只是资源层缓解。若钩子经常处理数百文件,应继续评估按 workspace 或文件批次运行 ESLint;不要默认用
--no-verify绕过质量门禁。 - 失败恢复:
lint-staged默认会备份原状态,并在任务失败时回滚任务产生的修改;仍应复查git status、staged/unstaged diff 和 stash,不能只根据日志假设恢复完整。 - 清理提示:
Cleaning up temporary files...表示在任务完成或原状态恢复后,删除隐藏的 unstaged patch 并丢弃本轮自动备份 stash。它作用于当前 working tree/index 的临时恢复材料,不会切换、重置或改写其他分支引用;stash 虽然在仓库内跨分支可见,但只有显式 apply/pop 才会作用到工作区。 - 来源:Node.js CLI:
--max-old-space-size与NODE_OPTIONS、lint-staged:任务参数与失败回滚。结论也通过 Node 24 的默认堆统计和一次大规模 staged ESLint OOM 日志复核。
合并与远端同步
Merge commit 打开提交信息编辑器不代表已经提交
解决冲突后运行 git commit,Git 通常会打开预填的 merge commit message。第一行是待提交信息,# Conflicts:、状态摘要和所有以 # 开头的行都是编辑提示,会被忽略。
- 完成提交:保留或修改非注释提交信息,保存并正常关闭编辑器;Git 返回终端并输出新 commit 后才算成功。
- 不要重复提交:编辑器仍打开时,原来的
git commit进程仍在等待,不应另开终端再次运行git commit。 - 验证结果:运行
git status,成功后不再显示All conflicts fixed but you are still merging;也可用git log -1 --oneline查看最新 commit。 - 记忆点:
It looks like you may be committing a merge是根据MERGE_HEAD给出的说明,不是错误。确认本来就在合并时,不要删除MERGE_HEAD。 - 来源:git-commit、githooks。
Merge commit 之后执行 git pull 突然出现大量文件
先检查 git status 和 git config --show-origin --get pull.rebase。当 pull.rebase=true 时,git pull 会先 fetch,再把本地提交重新播放到最新 upstream;普通 rebase 默认不会保留本地 merge commit 的拓扑,可能把合并进来的整组提交重新应用一次。
git status
git config --show-origin --get pull.rebase
git diff --name-only --diff-filter=U
- 不要被数量误导:rebase 状态里的大量
A/M通常是当前正在重放的提交内容,真正需要人工处理的是git status的Unmerged paths或git diff --diff-filter=U。 - 继续或退出:确认要改写本地提交时,解决冲突、
git add后运行git rebase --continue;不希望改写历史或需要保留既有 merge commit 时,使用git rebase --abort回到 rebase 前的分支状态,再明确选择 merge 工作流。 - 共享分支边界:已经发布或需要保留合并关系的集成分支,不应无意中使用普通 rebase。一次性拉取可显式选择
git pull --no-rebase;长期配置是否修改应按团队工作流决定。 - 完整流程:远程分支领先导致 push 被拒时如何处理。
- 来源:git-pull 说明
--rebase与--no-rebase的集成方式;git-rebase 说明 detached replay、冲突继续和--abort恢复原分支。
配置、身份与认证
查看某项配置的实际来源
git config --show-origin --get user.email
- 适合场景:全局和仓库配置同时存在,不确定当前值为什么与预期不同。
- 记忆点:
--show-origin显示 Git 配置层最终读取到的值及其配置文件来源;仓库本地配置通常会覆盖全局配置。它不会显示GIT_AUTHOR_*、GIT_COMMITTER_*等环境变量造成的提交身份覆盖。 - 延伸阅读:Git 提交身份、远端认证与仓库权限。
- 来源:git-config。
同时查看 author 与 committer
git log -1 --format=fuller
- 适合场景:确认最近一次提交真正记录的作者、提交者以及两组时间。
- 记忆点:
fuller格式会分别显示Author、AuthorDate、Commit和CommitDate,适合排查代提交、变基或身份配置问题。 - 来源:git-log 的 pretty formats。
确认 GitHub SSH 密钥对应哪个账号
ssh -T [email protected]
- 适合场景:一台电脑配置了多个 GitHub 账号或多把 SSH Key,需要确认当前连接被识别成谁。
- 记忆点:认证成功的消息会包含用户名,但 GitHub 不提供 shell,因此该命令成功认证后仍会以状态码
1退出;应判断消息内容,不能只判断退出码。 - 来源:GitHub:Testing your SSH connection。
远端地址
GitHub 仓库改名后,旧 remote 为什么还能使用
GitHub 会把指向仓库旧位置的 git clone、git fetch 和 git push 请求重定向到新位置;本地仓库的 .git/config 不会因此自动改写,所以 git remote -v 仍可能显示旧 URL。
- 排查:用
git remote -v查看当前保存的 fetch/push URL,用git config --show-origin --get remote.origin.url确认配置来源。 - 更新:确认新地址后运行
git remote set-url origin https://github.com/OWNER/NEW_REPOSITORY.git,再用git remote -v验证。 - 记忆点:旧地址能工作只是托管平台提供的兼容重定向,不等于本地配置已更新。GitHub 建议仍然改成新地址;若旧仓库名以后被重新使用,重定向会失效,而且作为 GitHub Action 使用的已改名仓库不会被重定向。
- 来源:GitHub:Renaming a repository。