Dev KnowledgeV2.0
输入关键词开始搜索

    Git 命令与易忘知识点

    按使用场景整理 Git 命令、参数和容易混淆的边界。

    类型
    速记知识
    适合读者
    希望快速复习 Git 行为和命令的开发者
    最近核验

    这是一份持续增长的 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。