跳到主要内容
稻草人
プロフィール

EP.02

💻Technology

Git 与 GitHub 开发常用手册

Git 命令很多,但日常开发真正高频使用的只有一部分。本文按照实际工作的顺序,整理从初始化仓库、提交代码、分支 […]

BY 稻, 草人

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 -vfetch 与 push 地址可能不同
看当前分支和跟踪git branch -vv确认推向哪个远程分支
看未暂存差异git diffadd 前检查
看已暂存差异git diff --cachedcommit 前检查
暂存指定文件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 -sshort,用简短格式看改动git status -s
git status -bbranch,显示分支与跟踪信息;通常与 -s 合用git status -sb
git remote -vverbose,列出远程名称和 URLgit remote -v
git branch -v / -vv显示分支最近提交;-vv 再显示上游分支及领先、落后情况git branch -vv
git branch -aall,列出本地分支和远程跟踪分支git branch -a
git switch -ccreate,创建分支并切换过去git switch -c feature/login
git add -Aall,不指定路径时暂存整个仓库的新增、修改和删除;指定目录后只处理该范围git add -A
git init -binitial-branch,初始化时指定第一个分支的名字git init -b main
git add -ppatch,逐块选择要暂存的改动git add -p
git commit -mmessage,直接写提交说明git commit -m "fix: 修复错误"
git stash push -m给这条暂存记录写备注git stash push -m "进行中"
git stash push -uinclude-untracked,把未跟踪的新文件也暂存;不包括被忽略的文件git stash push -u
git push -uset-upstream,为推送的本地分支设置上游跟踪分支git push -u origin main
git branch -d删除已合并的本地分支git branch -d feature/login
git branch -D强制删除本地分支,未合并的提交可能因此失去分支引用git branch -D feature/login
git show -sno-patch,只显示提交信息,不显示文件修改内容git show -s HEAD
git check-ignore -v显示是哪条忽略规则让文件被忽略git check-ignore -v -- a.log
git blame -L 20,40line-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
--stagedrestore 操作暂存区,而不是仅操作工作区git restore --staged app.js
--worktreerestore 操作工作区文件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检查前一个提交是否是后一个提交的祖先;成功返回退出码 0git 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 / --hardreset 的三种恢复方式:保留暂存/保留文件但取消暂存/丢弃相应未提交修改git reset --soft HEAD~1
--continue / --abort冲突解决后继续进行,或退出当前 rebase/merge/cherry-pickgit 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:maingit 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 登录与传输方式

方式远程地址使用要点
HTTPShttps://github.com/USERNAME/REPO.gitGitHub CLI、Git Credential Manager 或个人访问令牌(PAT)可完成验证
SSHgit@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-onlyfetch 后仅在能快进时更新当前分支会,条件不满足就报错
git pullfetch 后按当前配置整合(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

  1. 推送功能分支。
  2. 在仓库页面选择 Compare & pull request,设定 base=main、compare=feature/contact-form。
  3. 写清楚目的、主要改动、测试方式和相关 Issue;检查 Files changed。
  4. 合并 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否,工作区仍保留
已暂存且还修改过,想全部恢复到 HEADgit 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。