Git 命令很多,但日常开发真正高频使用的只有一部分。本文按照实际工作的顺序,整理从初始化仓库、提交代码、分支开发到 GitHub 多仓库同步的常用操作,并补充每个常见参数的含义。
这篇手册适合已经接触过 Git,但经常忘记命令、参数或操作顺序的开发者。遇到问题时,也可以直接通过页面搜索查找 stash、remote、restore、non-fast-forward 等关键词。
- 命令默认在 Git 仓库根目录运行。
- 示例使用
main作为主分支;如果项目使用master或其他名称,请替换成实际分支名。 USERNAME、REPO、abc1234和path/to/file.php都是占位符,需要替换成真实值。- 命令适用于 macOS、Linux,以及已经安装 Git 的 Windows PowerShell 7。
- 执行恢复、删除、强制推送等命令前,先运行
git status -sb、git branch -vv和git remote -v确认当前位置与目标。
1. 先理解 Git 与 GitHub
Git 是本地版本管理工具;GitHub 是托管 Git 仓库、查看代码和协作的平台。你的电脑断网时仍可 add、commit、切换分支;只有与 GitHub 交换数据的 fetch、pull、push 等命令需要访问远程。
一个改动通常经过以下位置:
工作区(正在编辑的文件)
└─ git add → 暂存区(准备提交的内容)
└─ git commit → 本地仓库(历史记录)
└─ git push → GitHub 仓库(远程历史)
git add 不是上传 GitHub,git commit 也不是上传 GitHub。真正发送提交的是 git push。反方向通常是 git fetch(只取回远程信息)或者 git pull(取回并整合到当前分支)。
| 名称 | 含义 | 例子 |
|---|---|---|
| 仓库(repository) | 保存代码及历史的项目 | 本地项目目录、GitHub 上的仓库 |
| 分支(branch) | 指向一条开发历史的名称 | main、feature/login |
| 提交(commit) | 一次有说明的历史快照 | fix: 修正登录验证 |
| 远程仓库别名(remote) | 本地保存的远程仓库地址别名 | origin、public |
| 上游分支(upstream branch) | 当前本地分支默认跟踪的远程分支 | main 跟踪 origin/main |
| Pull Request(PR) | 在 GitHub 提议把一个分支的变更合并到另一个分支 | feature/login → main |
容易混淆:
origin只是默认的远程别名,可以改名,也可以同时存在public、private等远程。GitHub 上的main与本地main是两个分支;origin/main是本地上次获知的远程分支状态,需要fetch更新。
2. 一页速查:最常用的命令
| 想做什么 | 命令 | 记住什么 |
|---|---|---|
| 看所在仓库与改动 | git status -sb | 操作前后都看一眼 |
| 看远程地址 | git remote -v | fetch 与 push 地址可能不同 |
| 看当前分支和跟踪 | git branch -vv | 确认推向哪个远程分支 |
| 看未暂存差异 | git diff | add 前检查 |
| 看已暂存差异 | git diff --cached | commit 前检查 |
| 暂存指定文件 | git add path/to/file.php | 推荐按文件选 |
| 暂存整个仓库的改动 | git add -A | 包括新增、修改、删除 |
| 提交 | git commit -m "fix: 修正登录错误" | 提交保存在本地 |
| 下载远程信息 | git fetch origin | 不改当前工作文件 |
| 整合远程提交 | git pull --ff-only | 仅在可以直接快进时成功 |
| 首次推送分支 | git push -u origin feature/login | 设置默认跟踪 |
| 后续推送 | git push | 先确认 upstream |
| 建立并切换分支 | git switch -c feature/login | 从当前提交新建 |
| 切换已有分支 | git switch main | 切换前检查未提交改动 |
| 看简洁历史 | git log --oneline --graph --decorate -15 | 快速确认提交 |
| 撤销暂存 | git restore --staged path/to/file.php | 工作区编辑仍在 |
| 丢弃文件工作区改动 | git restore -- path/to/file.php | 未提交改动会丢失 |
| 暂存未提交工作(含新文件) | git stash push -u -m "处理中" | -u 包含未跟踪文件 |
2.1 Git 参数应该怎么看?
Git 命令通常由“子命令、参数和操作对象”组成:
git <子命令> [参数] [分支、远程仓库或文件路径]
例如,下面两个命令都带有短参数:
git status -sb <em># -s:简短显示;-b:显示分支。-sb 是 -s -b 的合写</em>
git remote -v <em># -v:显示远程仓库的 URL(包括 fetch 和 push 地址)</em>
git status -sb 可能显示 ## main...origin/main 和 M src/app.js。第一行表示当前分支及其跟踪的远程分支;第二行表示文件有未暂存的修改。?? new.txt 表示新文件尚未纳入 Git 跟踪。
常用短参数
同一个字母要连同前面的 Git 命令一起看,不能脱离命令记忆。
| 命令中的参数 | 简单意思 | 示例 |
|---|---|---|
git status -s | short,用简短格式看改动 | git status -s |
git status -b | branch,显示分支与跟踪信息;通常与 -s 合用 | git status -sb |
git remote -v | verbose,列出远程名称和 URL | git remote -v |
git branch -v / -vv | 显示分支最近提交;-vv 再显示上游分支及领先、落后情况 | git branch -vv |
git branch -a | all,列出本地分支和远程跟踪分支 | git branch -a |
git switch -c | create,创建分支并切换过去 | git switch -c feature/login |
git add -A | all,不指定路径时暂存整个仓库的新增、修改和删除;指定目录后只处理该范围 | git add -A |
git init -b | initial-branch,初始化时指定第一个分支的名字 | git init -b main |
git add -p | patch,逐块选择要暂存的改动 | git add -p |
git commit -m | message,直接写提交说明 | git commit -m "fix: 修复错误" |
git stash push -m | 给这条暂存记录写备注 | git stash push -m "进行中" |
git stash push -u | include-untracked,把未跟踪的新文件也暂存;不包括被忽略的文件 | git stash push -u |
git push -u | set-upstream,为推送的本地分支设置上游跟踪分支 | git push -u origin main |
git branch -d | 删除已合并的本地分支 | git branch -d feature/login |
git branch -D | 强制删除本地分支,未合并的提交可能因此失去分支引用 | git branch -D feature/login |
git show -s | no-patch,只显示提交信息,不显示文件修改内容 | git show -s HEAD |
git check-ignore -v | 显示是哪条忽略规则让文件被忽略 | git check-ignore -v -- a.log |
git blame -L 20,40 | line-range,只查看第 20~40 行的修改来源 | git blame -L 20,40 -- app.js |
git log -<数量> | 限制最多显示多少条记录;本文的 -1、-10、-15、-20、-25 都属于这种写法,reflog 也可使用 | git log -15 |
特别注意:-u 在 git stash push -u 中是“包含未跟踪文件”,在 git push -u 中是“设置上游分支”;-a 在 git branch -a 中是“显示所有分支”,在 git add -A 中是“暂存所有类型的文件变化”。
常用长参数
| 参数或写法 | 简单意思 | 示例 |
|---|---|---|
--global | 配置写到当前用户的全局设置;省略时通常写到当前仓库 | git config --global user.name "名字" |
--get | 读取一个配置项的值 | git config --get user.name |
--show-origin | 显示配置来自哪个文件 | git config --show-origin --get user.email |
--cached | 根据命令表示暂存区:diff 查看已暂存差异;rm 只从 Git 跟踪中移除,保留工作区文件 | git diff --cached |
--staged | restore 操作暂存区,而不是仅操作工作区 | git restore --staged app.js |
--worktree | restore 操作工作区文件 | git restore --worktree app.js |
--source=HEAD | 以当前最新提交 HEAD 的版本作为恢复来源 | git restore --source=HEAD -- app.js |
--stat | 只看各文件变更行数摘要,不显示完整代码差异 | git diff --stat |
--check | 检查 diff 中的空白字符错误等问题 | git diff --cached --check |
--ignore-space-at-eol | 比较时忽略行尾空白差异 | git diff --ignore-space-at-eol |
--oneline | 每条提交用一行显示 | git log --oneline |
--graph | 用文本线条显示提交的分叉与合并 | git log --graph |
--decorate | 显示分支名、标签等引用位置 | git log --decorate |
--all | 对 git log:展示所有引用可到达的提交;含义依命令而变 | git log --all --oneline |
--left-right | 两个分支比较时,用 < 和 > 标识提交来自哪一边 | git log --left-right main...origin/main |
--format="..." | 自定义提交信息的显示格式;--format= 为空表示不显示提交标题 | git show -s --format="%an" HEAD |
--prune | 获取远程更新时,移除本地已失效的远程跟踪分支记录;不删除自己的本地分支 | git fetch --prune origin |
--ff-only | 只允许直接向前移动分支;需要合并提交时就停止 | git pull --ff-only |
--force | 强制更新远程分支,可能覆盖别人已推送的提交;文中只用作反例 | git push --force origin main |
--force-with-lease | 改写远程分支前先核对远程状态;仍是覆盖历史的操作 | git push --force-with-lease origin feature/login |
--mirror | 完整镜像所有引用到远程,可能删除远程独有引用;文中只用作反例 | git push --mirror public |
--name-only | 只列出改动的文件路径 | git log --name-only |
--since / --until | 将历史查询限制在指定时间范围 | git log --since="2026-08-01" |
--is-ancestor | 检查前一个提交是否是后一个提交的祖先;成功返回退出码 0 | git merge-base --is-ancestor public/main main |
--delete | 在 push 中删除指定的远程分支 | git push origin --delete feature/login |
--show-current | 只输出当前本地分支名称 | git branch --show-current |
--show-toplevel | 输出当前仓库根目录的路径 | git rev-parse --show-toplevel |
--short | 在 status 中简短显示;与 git status -s 相同 | git status --short |
--amend | 用新提交替换最近一次提交,提交 ID 会改变 | git commit --amend -m "新说明" |
--soft / --mixed / --hard | reset 的三种恢复方式:保留暂存/保留文件但取消暂存/丢弃相应未提交修改 | git reset --soft HEAD~1 |
--continue / --abort | 冲突解决后继续进行,或退出当前 rebase/merge/cherry-pick | git rebase --continue |
-- | 结束参数部分,后面作为文件路径处理;也便于区分分支名与文件名 | git diff -- src/app.js |
容易被误认为参数的特殊写法
| 写法 | 含义 |
|---|---|
HEAD / HEAD~1 | 当前检出的提交/它的第一个父提交;常用于撤销最近一次提交 |
main..feature | 对 git log:看 feature 有而 main 没有的提交 |
main...feature | 对 git diff:从共同祖先到 feature 的变化;对 git log --left-right:看两边各自独有的提交 |
main:main | git push public main:main 中,冒号左边是本地来源分支,右边是远程目标分支 |
. | 在路径位置表示当前目录,例如 git restore -- .;这里的作用不同于 git add -A 未指定路径时的整个仓库范围 |
Sort-Object -Unique | 这是 PowerShell 参数,去除重复结果;并不是 Git 的参数 |
git show -s --format="Author: %an <%ae>%nCommitter: %cn <%ce>%nDate: %ad" HEAD 中,%an/%ae 是作者名字/邮箱,%cn/%ce 是提交者名字/邮箱,%ad 是作者日期,%n 是换行;这里的 %... 是格式占位符,不是命令行参数。
短参数可以合写,例如 -sb 等于 -s -b,-vv 等于两次 -v。以 -- 开头的通常是完整参数名;如果忘记某个参数的准确作用,运行 git help status,把 status 换成要查的命令即可。
个人项目常见循环:
git status -sb
git pull --ff-only
git switch -c feature/new-page
<em># 编辑文件</em>
git diff
git add path/to/file.php
git diff --cached
git commit -m "feat: 添加新页面"
git push -u origin feature/new-page
<em># 在 GitHub 发起 PR;合并后再回到 main</em>
如果是一个人开发,也可以直接在 main 提交;功能改动较大时开分支,方便审查和回退。
3. 首次配置与建立仓库
3.1 配置提交作者
git config --global user.name "你的名字"
git config --global user.email "you@example.com"
git config --global --get user.name
git config --global --get user.email
这两项写入提交记录的作者信息,不是登录 GitHub 的账号密码。如果工作仓库需要不同的署名,请在该仓库目录运行不带 --global 的配置:
git config user.name "工作用名字"
git config user.email "work@example.com"
git config --show-origin --get user.email
--show-origin 可查出配置来自全局还是当前仓库。网页上通过 GitHub 按钮合并 PR 所生成的提交,其 author/committer 也可能与本地配置不同。
3.2 已有 GitHub 仓库:直接 clone
git clone https://github.com/USERNAME/REPO.git
cd REPO
git status -sb
git remote -v
克隆会自动设置一个名为 origin 的远程。也可使用 SSH URL:git@github.com:USERNAME/REPO.git。
3.3 本地已有项目:连接到新建的 GitHub 仓库
先在 GitHub 建一个空仓库;以下假设目录尚未初始化 Git:
cd path/to/project
git init -b main
<em># 先准备 .gitignore,再检查提交内容</em>
git status -sb
git add -A
git diff --cached --stat
git commit -m "chore: 初始化项目"
git remote add origin https://github.com/USERNAME/REPO.git
git push -u origin main
如果已有 .git,不要再初始化,先运行 git status -sb 与 git remote -v。如果 GitHub 新仓库自动创建了 README/LICENSE,而本地也有独立的初始提交,两边可能形成不相干的历史;先确认要保留哪些内容,不要直接强制推送。
3.4 .gitignore 的最小示例
node_modules/
dist/
.env
.env.*
!.env.example
.DS_Store
.gitignore 只影响尚未被 Git 跟踪的文件。一个已经提交的 .env 不会因为后来加入 .gitignore 就从历史中消失。若误提交过凭据,应尽快轮换凭据并按 GitHub 官方流程处理历史。
3.5 GitHub 登录与传输方式
| 方式 | 远程地址 | 使用要点 |
|---|---|---|
| HTTPS | https://github.com/USERNAME/REPO.git | GitHub CLI、Git Credential Manager 或个人访问令牌(PAT)可完成验证 |
| SSH | git@github.com:USERNAME/REPO.git | 把 SSH 公钥加入 GitHub;使用私钥进行身份验证 |
GitHub 的 Git 命令行操作不接受账号密码作为 Git 远程验证密码。令牌不要写在命令示例的 URL 或提交进仓库。已经设置远程时切换 URL:
git remote -v
git remote set-url origin git@github.com:USERNAME/REPO.git
git remote -v
git config user.email 控制提交署名;HTTPS/SSH 凭据决定是否有权访问仓库,二者是不同的设置。
4. 每天开发:查看、提交、同步
4.1 随时确认状态
git status -sb
git diff --stat
git diff -- path/to/file.php
git diff --cached -- path/to/file.php
git diff 默认看工作区与暂存区的差异,所以 git add 后它可能看起来“空了”。此时应看 git diff --cached。git status 中的 ?? 表示未跟踪文件。
4.2 一次提交做一件事
git add src/login.php
git add tests/login_test.php
git diff --cached --check
git diff --cached --stat
git commit -m "fix: 修正登录后重定向"
git add -p 可以逐块选择同一文件中要提交的改动;当你同时修改了两个功能时很有用。git diff --cached --check 能提醒一些空白字符问题。
4.3 理解 fetch、pull、push
git fetch origin
git log --oneline --left-right main...origin/main
git switch main
git merge --ff-only origin/main
git push origin main
| 命令 | 作用 | 会直接改当前分支吗? |
|---|---|---|
git fetch origin | 取回远程更新并刷新 origin/* | 不会 |
git pull --ff-only | fetch 后仅在能快进时更新当前分支 | 会,条件不满足就报错 |
git pull | fetch 后按当前配置整合(merge/rebase 等) | 会 |
git push origin main | 将本地 main 的提交发送到远程 main | 更新远程 |
git pull --ff-only 适合先保持操作可预期。如果本地和远程都多了提交,它会停下来,让你选择合并或变基;此时先 git fetch、git log --graph --oneline --all -20 看历史。
4.4 查看历史与定位改动
git log --oneline --graph --decorate -20
git log -- path/to/file.php
git show --stat HEAD
git show abc1234 -- path/to/file.php
git blame -L 20,40 -- path/to/file.php
git show abc1234 里 abc1234 是示例提交 ID,实际以 git log 的输出为准。git blame 可以查看某几行最近由哪个提交修改。
4.5 查看两个分支的区别
git diff main...feature/login --stat
git diff main...feature/login
git log --oneline main..feature/login
main...feature/login 在 git diff 中以双方共同祖先为起点,适合看功能分支相对于基线的变更;main..feature/login 在 git log 中表示只在功能分支出现的提交。.. 与 ... 在不同命令中有不同语义,先按上述场景记忆。
5. 分支开发与 Pull Request
5.1 创建、切换、删除分支
git switch main
git pull --ff-only
git switch -c feature/contact-form
<em># 完成开发后提交、推送</em>
git push -u origin feature/contact-form
git branch -a
git branch -vv
git branch -d feature/contact-form 删除已合并的本地分支;-D 会强制删除,即使未合并,使用前先确认提交还有其他引用。远程分支的删除命令是 git push origin --delete feature/contact-form。
5.2 在 GitHub 上提 PR
- 推送功能分支。
- 在仓库页面选择 Compare & pull request,设定 base=
main、compare=feature/contact-form。 - 写清楚目的、主要改动、测试方式和相关 Issue;检查 Files changed。
- 合并 PR 后更新本地
main。
git switch main
git pull --ff-only
git branch -d feature/contact-form
git fetch --prune origin
PR 是 GitHub 上的代码合并与审查流程,与 git pull 命令没有直接关系。Issue 可以在 PR 描述中写 Closes #123 来关联并在适用条件下自动关闭;#123 指同仓库的 Issue/PR 编号,跨仓库可写 OWNER/REPO#123。
5.3 功能分支落后于 main
方法 A:merge,保留合并记录,适合共享分支。
git switch feature/contact-form
git fetch origin
git merge origin/main
<em># 冲突时解决冲突,再 git add 并 git commit</em>
git push
方法 B:rebase,让个人分支提交接在最新 main 后。
git switch feature/contact-form
git fetch origin
git rebase origin/main
<em># 如有冲突:解决 → git add 对应文件 → git rebase --continue</em>
已经推送的分支在 rebase 后历史发生变化,可能需要 git push --force-with-lease origin feature/contact-form。只对自己掌控、确认没有其他人基于其工作的分支这么做;共享分支优先使用 merge。不要用 git push --force 处理普通的同步冲突。
5.4 Fork 与 upstream(参与别人的项目)
Fork 是 GitHub 上复制的仓库;这里的 upstream 是原项目远程别名,与本地分支的“上游跟踪分支”是两个相关但不同的概念。
<em># origin = 自己 Fork 的仓库</em>
git remote add upstream https://github.com/ORIGINAL/REPO.git
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main
改动推到自己 Fork 的功能分支,然后在 GitHub 上发往原项目的 PR。若 main 上已有个人提交,--ff-only 可能失败,应先看分支图再决定如何整合。
6. 远程仓库:一个本地项目连接多个 GitHub 仓库
6.1 一个本地仓库连接两个 GitHub 仓库
例如同一个本地项目连接一个私有仓库和一个公开仓库:
git remote -v
git remote add public https://github.com/USERNAME/project-public.git
git remote -v
假设现有的 origin 指向私有仓库,现在有 origin 和 public 两个远程。增加远程只保存地址,不会自动同步代码。
git push origin main <em># 推给私有仓库</em>
git push public main <em># 推给公开仓库</em>
每次推送都明确写远程名,可以避免推错地方。也可以把两个远程重命名为更直观的 private 与 public:
git remote rename origin private
git remote -v
git push private main
git push public main
git remote rename 只修改本地别名;不会更改 GitHub 上的仓库名称。注意:只要推送私有分支到公开仓库,该分支可到达的历史提交也可能一起公开,并不是只公开“当前文件”。
6.2 更换远程地址、移除连接
git remote set-url origin https://github.com/USERNAME/new-repo.git
git remote remove public
git remote -v
remote remove 只删本地连接设置,不会删 GitHub 上的仓库。若出现 remote origin already exists,先用 git remote -v 检查,再按需要 set-url 或另取远程名。
6.3 当前分支默认推向哪里?
git branch -vv
git status -sb
git remote -v
git push -u origin main 会为该分支设定上游跟踪关系;此后 git push、git pull 的具体目标受跟踪关系与 Git 配置影响。管理私有和公开两个远程时,建议始终显式写 git push private main / git push public main。
6.4 不同本地目录连接不同仓库
两个不同项目分别 clone 到两个目录,就是两个独立本地 Git 仓库;分别有各自的 .git、分支和 origin。如果想让同一个项目同时连接多个仓库,用上一节的多个 remote,而不是在项目内部再运行 git init。
6.5 一个远程别名同时推送到多个 URL?
Git 支持为同一个远程仓库别名配置多个推送 URL。这样执行一次 git push origin main 时,会依次推送到这些地址。不过公开仓库与私有仓库的内容边界通常不同,日常开发更适合使用 private、public 两个独立的远程别名,并明确指定推送目标。
7. 私有仓库与公开仓库的同步
这里用一个常见场景:project-private 比 project-public 多了一些提交,现在决定把私有仓库的代码及相应历史公开。先确认两个仓库的历史关系,以及所有待公开内容都允许公开。
7.1 两个仓库同源,公开仓库只是落后
以下命令均在已克隆的私有仓库目录中运行:
git status -sb
git remote -v
<em># 如果没有 public 远程,先添加</em>
git remote add public https://github.com/USERNAME/project-public.git
git fetch origin
git fetch public
git log --oneline --graph --decorate --all -25
git log --oneline public/main..main
检查 public/main..main 列出的所有即将公开的提交,包括文件、作者信息、配置、历史版本和大文件。确认公开库原有提交已包含在本地 main 历史中:
git merge-base --is-ancestor public/main main
退出码为 0 表示可直接快进;PowerShell 中可用 $LASTEXITCODE 查看,bash/zsh 中可用 echo $?。确认后再推:
git push public main:main
这表示把本地 main 推到公开仓库的 main。若远程启用分支保护或有新提交,可能被拒绝;先 git fetch public 看新状态,不要直接强推。首次 git remote add public 如果报已存在,先 git remote -v,不要重复添加。
7.2 两边都各自有新提交
假设公开仓库也新增了 README 或其他提交:
git fetch public
git log --oneline --left-right --graph main...public/main
先确认这些提交属于同一个项目。可以在本地 main 分支整合公开仓库的更新,再正常推送:
git switch main
git merge public/main
<em># 如有冲突,解决并完成 merge</em>
git push origin main
git push public main
如不希望公开仓库的提交进入私有仓库,需要重新设计公开内容的来源分支;这不再是简单的双向镜像。
7.3 两仓库历史完全无关,或私有历史不宜公开
不要照搬 git push --force / --mirror。可以创建一个干净的公开仓库工作目录,只拷贝审查后的文件并重新提交;这会产生新的公开历史,适合不公开旧提交的场景。文件拷贝时不要拷贝 .git 目录。
<em># 进入仅包含已审查文件的新目录后</em>
git init -b main
git add -A
git diff --cached --stat
git commit -m "chore: 发布公开版本"
git remote add origin https://github.com/USERNAME/new-public-repo.git
git push -u origin main
如果旧公开仓库必须保留原有历史,则在其 clone 中增加经审查的文件并做一个新提交,或规划迁移;不要用新历史强行覆盖既有提交。
7.4 公开前检查清单
- 检查将要公开的每个提交,而不只是现在的文件;历史中的密码、密钥、客户资料仍有暴露风险。
- 检查
.env、数据库备份、部署配置、私有文档、图片资源、仓库许可和第三方代码的授权。 .gitignore、git rm、git revert不能擦除已经存在于提交历史中的敏感数据;凭据如曾提交,应轮换并参考 GitHub 官方清理说明。- 推送之后公开仓库页面确认分支、提交、文件;必要时分别检查两边
git log -1与git ls-remote。
GitHub 网页没有一个适用于任意两个独立 repository 的“始终自动同步”开关。 每次手动推送两个 remote 是最清楚的做法。需要自动化时可额外设计 GitHub Actions,但应先决定同步方向、分支保护、认证和私有历史是否允许公开。
8. 撤销、恢复与临时保存
8.1 先判断改动到哪一步
| 当前情况 | 推荐命令 | 是否会丢失改动? |
|---|---|---|
| 只修改工作区,想丢弃 | git restore -- path/to/file.php | 是,丢弃该文件未暂存的编辑 |
已 add,想取消暂存 | git restore --staged path/to/file.php | 否,工作区仍保留 |
| 已暂存且还修改过,想全部恢复到 HEAD | git restore --source=HEAD --staged --worktree -- path/to/file.php | 是,全部未提交改动会丢失 |
| 本地最新提交未推,想修改说明 | git commit --amend -m "新说明" | 会改写最新提交 ID |
| 已推送提交,想抵消其效果 | git revert <提交ID> | 创建一个新的反向提交,保留历史 |
git restore -- path/to/folder/ 可恢复被跟踪且位于该目录内的工作区文件。先用 git status --short -- path/to/folder/ 检查。若终端已经在 wp-content/themes/swell 目录中,传入的路径应相对于当前目录,例如 git restore -- .,不要再写仓库根目录下的完整相对路径。git restore 不会清理未跟踪的 ?? 文件。
8.2 撤销最近一次本地提交
git reset --soft HEAD~1 <em># 撤销提交,改动仍保持暂存</em>
git reset --mixed HEAD~1 <em># 撤销提交,改动回到工作区(默认方式)</em>
上述两条是二选一示例,不要连续照抄执行。仅对未推送、自己掌控的提交使用 reset 改历史。git reset --hard HEAD~1 会丢弃相应工作区内容,务必先确认并备份;不要把它当成普通“撤销 push”命令。
8.3 已共享的提交:用 revert
git log --oneline -10
git revert abc1234
git push origin main
revert 保留旧提交并新增一个抵消变更的提交,适合共享分支。它不能从 Git 历史中抹掉误提交的密钥。
8.4 暂时离开工作:stash
git stash push -u -m "登录页做到一半"
git stash list
git stash show --stat stash@{0}
git stash apply 'stash@{0}'
<em># 确认已恢复后,再按需要删除</em>
git stash drop 'stash@{0}'
默认 git stash push 不包含未跟踪(??)文件;-u 包含未跟踪文件,但默认仍不包含被忽略文件。apply 恢复但保留 stash,pop 尝试恢复并移除记录;谨慎起见先 apply。PowerShell 中将 stash@{0} 加引号,避免语法解析问题。Stash 只保存在当前本地仓库,不会随 push 上传 GitHub。
8.5 找回误操作前的提交
git reflog -15
git show <找到的提交ID>
<em># 确认后,可用新分支先保住它</em>
git branch rescue-work <找到的提交ID>
reflog 记录本地 HEAD/引用的移动,可以帮助找回刚 reset 或切换前的提交;它不是永久备份,也不会自动同步到 GitHub。
9. 冲突、报错与排查
9.1 merge 冲突
git status
<em># 打开冲突文件,人工处理 <<<<<<< / ======= / >>>>>>> 标记</em>
git add path/to/conflicted-file.php
git commit
如果正在 rebase,解决后使用 git rebase --continue,放弃则 git rebase --abort。如果正在 merge,可用 git merge --abort 回到合并前。先看 git status,它会提示当前进行的操作。
9.2 push 被拒绝:non-fast-forward
通常是远程有本地尚未整合的提交,或你改写了已推送历史:
git fetch origin
git log --oneline --left-right --graph main...origin/main
再决定 merge origin/main 或对个人分支执行 rebase origin/main。普通情况不要用 --force 绕过拒绝;--force-with-lease 也只在明确需要改写自己分支历史时使用。
9.3 src refspec main does not match any
可能还没创建首个提交,或者本地分支名称不是 main:
git status -sb
git branch --show-current
git log -1 --oneline
核实后提交第一版,或者使用真实的分支名推送。
9.4 fatal: not a git repository
git rev-parse --show-toplevel
git status -sb
检查当前目录是否位于正确项目内;PowerShell 可运行 Get-Location,macOS/Linux 可运行 pwd。不要在不确定的目录里运行 git init 来掩盖路径问题。
9.5 pathspec ... did not match
可能路径相对于当前工作目录写错、文件未被跟踪,或路径并不存在:
git rev-parse --show-toplevel
git status --short
git ls-files -- wp-content/themes/swell/
git ls-files 没输出时,检查该目录是否被忽略、是未跟踪文件,还是你正站在它内部。
9.6 换行符变化导致大量 diff
Windows 与 macOS/Linux 混用时先查配置和属性,不要立刻把大量文件提交:
git config --show-origin --get core.autocrlf
git check-attr text eol -- path/to/file.php
git diff --check
git diff --ignore-space-at-eol -- path/to/file.php
项目可通过 .gitattributes 约定,例如 * text=auto eol=lf,但调整后可能需要一次统一的规范化提交。先确认纯换行变化与实际代码变化,避免误覆盖同事的工作。PowerShell 没有内置的 Unix uniq,可使用 Sort-Object -Unique。
10. 开发中常见的进阶用法
10.1 按时间列出修改过的文件(PowerShell 7)
git log --since="2026-08-01" --until="2026-09-01" --name-only --format= |
Where-Object { $_ } |
Sort-Object -Unique
--until 这里设为次月 1 日,若需要严格排除该日,应指定时间边界并按实际时区验证;--name-only 会包含该范围内提交所触及的路径。这是按提交历史查询,不包含尚未提交的文件。
10.2 把某个提交带到当前分支
git switch release
git cherry-pick abc1234
常见于修复已在 main,需要单独移植到维护分支的情况。冲突时看 git status,解决后 git cherry-pick --continue;放弃使用 git cherry-pick --abort。
10.3 同时打开两个分支目录:worktree
git worktree add ../project-release release
git worktree list
<em># 确认目录没有未提交工作后</em>
git worktree remove ../project-release
适合一边开发、一边查看维护分支;两个目录共用一个 Git 仓库的历史。一个分支一般不能同时在两个 worktree 中检出。
10.4 查为什么文件被忽略
git check-ignore -v -- path/to/file
如果文件已被跟踪,.gitignore 不会自动停止跟踪;想停止跟踪但保留本地文件,可执行 git rm --cached -- path/to/file 后提交。先确认它不包含不应留在已有历史中的敏感信息。
10.5 找提交作者与提交者
git show -s --format="Author: %an <%ae>%nCommitter: %cn <%ce>%nDate: %ad" HEAD
git config --show-origin --get user.name
git config --show-origin --get user.email
Author 记录原作者,Committer 记录创建当前提交对象的人或服务。GitHub 网页编辑和 PR 合并也会影响显示结果。
写在最后
日常使用 Git 时,可以先记住一条稳定的操作顺序:
git status -sb
git pull --ff-only
<em># 编辑文件</em>
git diff
git add <文件路径>
git diff --cached
git commit -m "提交说明"
git push
操作前确认状态,提交前检查差异,推送前确认分支和远程地址,可以避开大部分误操作。遇到冲突或推送失败时,先用 git status 和 git log --oneline --graph --decorate --all -20 看清当前历史,再决定使用 merge、rebase、restore 或 revert。

