Git 如何撤回已 Push 的代码

一、Git 常用命令说明

1. 仓库初始化与克隆

命令说明
git init在当前目录初始化一个新的 Git 仓库
git clone <url>克隆远程仓库到本地

2. 暂存与提交

命令说明
git add <file>将指定文件添加到暂存区
git add .添加所有更改(新文件、修改、删除)到暂存区
git commit -m "message"提交暂存区内容并附上提交信息
git commit -am "message"跳过 git add,直接提交所有已跟踪文件的修改(不包含新文件)

3. 状态与差异查看

命令说明
git status查看工作区和暂存区的状态
git diff查看工作区与暂存区的差异
git diff --staged查看暂存区与上次提交的差异
git log --oneline简洁查看提交历史

4. 分支管理

命令说明
git branch列出本地分支(当前分支标 *
git branch <name>创建新分支
git checkout <name>切换到指定分支
git switch <name>Git 2.23+ 推荐的分支切换命令
git merge <branch>将指定分支合并到当前分支
git branch -d <name>删除已合并的分支
git branch -D <name>强制删除未合并的分支

5. 远程操作

命令说明
git remote -v查看远程仓库地址
git push origin <branch>推送本地分支到远程
git pull origin <branch>拉取远程分支并合并到当前分支
git fetch origin仅拉取远程更新,不自动合并
git push --force origin <branch>强制推送本地分支覆盖远程分支(⚠️ 高危)
git push --force-with-lease origin <branch>仅当远程分支未被他人更新时才强制推送(更安全)
git push --force --delete origin <branch>强制删除远程分支(即使未合并)
git pull --rebase -X theirs origin <branch>强制变基拉取,冲突时自动使用远程版本(⚠️ 高危)
git fetch --force origin强制覆盖本地已存在的远程跟踪引用
git fetch --prune --force origin强制获取并删除远程已不存在的本地远程跟踪分支

6. 撤销与回退

命令说明
git restore <file>丢弃工作区的修改(恢复成上次提交的状态)
git restore --staged <file>将文件从暂存区移出(撤销 git add
git reset --soft HEAD~1撤销上一次提交,但保留修改在暂存区
git reset --hard HEAD~1彻底撤销上一次提交,丢弃所有修改(⚠️ 危险)
git revert <commit>生成一个新提交来撤销指定提交的修改(安全)

7. 贮藏与清理

命令说明
git stash暂存当前未提交的修改
git stash pop恢复最近的贮藏并删除该贮藏
git stash list查看所有贮藏
git clean -fd删除未跟踪的文件和目录

二、Git Commit Message 常用类型前缀

前缀英文含义中文含义示例
featFeature新功能feat: 添加用户登录功能
fixBug Fix修复缺陷fix: 修复登录失败时错误提示未显示的问题
docsDocumentation文档更新docs: 更新README安装说明
styleCode Style代码格式(不影响逻辑,如空格、缩进、分号)style: 格式化UserService类的缩进
refactorCode Refactoring代码重构(不改变功能)refactor: 将订单处理逻辑抽取为独立方法
perfPerformance性能优化perf: 优化图片加载策略,减少首屏时间
testTesting添加或修改测试test: 增加支付模块单元测试
choreChores构建、工具、依赖等杂项更新chore: 升级Spring Boot版本至2.7.0
ciContinuous IntegrationCI/CD 配置或脚本修改ci: 修改GitHub Actions发布流程
buildBuild System构建系统或外部依赖变更(如webpack、gradle)build: 配置webpack支持CSS模块
revertRevert回滚之前的提交revert: 回滚feat: 添加用户登录功能

三、使用示例(含场景说明)

以下示例覆盖日常开发典型场景,帮助你快速上手。

示例1:从零开始将本地代码推送到远程仓库

# 1. 进入项目目录,初始化仓库
cd my-project
git init

# 2. 添加所有文件并首次提交
git add .
git commit -m "feat: 初始化项目,添加基础结构"

# 3. 在 GitHub/GitLab 上创建空仓库,然后关联远程
git remote add origin https://github.com/yourname/my-project.git

# 4. 推送本地主分支到远程(首次需设置上游)
git push -u origin main

示例2:开发新功能并合并到主分支

# 1. 基于主分支创建功能分支
git checkout main
git pull origin main   # 确保主分支最新
git checkout -b feat-add-login

# 2. 开发代码,多次提交
echo "login code" > login.py
git add login.py
git commit -m "feat: 实现用户名密码登录接口"

# 3. 推送到远程功能分支(用于备份或协作)
git push origin feat-add-login

# 4. 切换回主分支,合并功能分支
git checkout main
git merge feat-add-login --no-ff   # --no-ff 保留分支历史

# 5. 删除已合并的本地分支和远程分支
git branch -d feat-add-login
git push origin --delete feat-add-login

示例3:紧急修复线上 Bug

# 1. 从主分支创建 hotfix 分支
git checkout main
git checkout -b hotfix-login-error

# 2. 修复问题并提交
echo "fixed" >> login.py
git commit -am "fix: 修复用户名密码校验为空时的空指针异常"

# 3. 合并回主分支并打标签
git checkout main
git merge hotfix-login-error
git tag -a v1.0.1 -m "紧急修复登录空指针问题"
git push origin main --tags

# 4. 删除 hotfix 分支
git branch -d hotfix-login-error

示例4:撤销错误提交(未推送)

# 场景:提交了两次,发现最后一次提交有问题
git log --oneline
# a1b2c3d (HEAD) fix: 修改配置文件
# e4f5g6h feat: 添加缓存功能

# 方法1:撤销最后一次提交,但保留修改(推荐)
git reset --soft HEAD~1
git status   # 修改仍保留在暂存区

# 方法2:彻底丢弃最后一次提交的修改(慎用)
git reset --hard HEAD~1

示例5:暂存当前未完成的工作,切换分支

# 正在开发新功能,突然需要紧急修 bug
git status   # 有未提交的修改
git stash save "未完成的新功能代码"
git checkout main
git checkout -b hotfix-critical

# 修复 bug 并提交、合并后...
git checkout feat-new-function
git stash pop   # 恢复之前未完成的工作

示例6:同步远程主分支的最新代码到功能分支

# 当前在 feat-dashboard 分支
git status   # 确保工作区干净

# 方法1:使用 merge(保留合并提交)
git fetch origin
git merge origin/main

# 方法2:使用 rebase(历史更线性,推荐)
git fetch origin
git rebase origin/main
# 如果有冲突,解决后执行 git rebase --continue

示例7:查看某次提交的详细修改内容

# 查看简洁日志,找到目标提交的哈希
git log --oneline

# 查看该提交的完整改动
git show a1b2c3d

# 只查看该提交修改了哪些文件
git show --name-only a1b2c3d

四、远程操作强制场景示例

针对远程仓库操作的强制/危险场景补充,包含具体命令和风险说明。

示例8:强制推送覆盖远程分支(--force / --force-with-lease

场景:你执行了 git commit --amend 修改了最近一次提交的历史,或者用 git rebase 重写了本地分支历史,导致本地和远程分支分叉,普通 git push 被拒绝。

# 1. 查看远程仓库地址
git remote -v
# origin  https://github.com/yourname/project.git (fetch)
# origin  https://github.com/yourname/project.git (push)

# 2. 尝试普通推送(会被拒绝)
git push origin feat-dashboard
# error: failed to push some refs to '...'

# 3. 【不推荐】强制推送(直接覆盖,不管远程是否有新提交)
git push --force origin feat-dashboard

# 4. 【推荐】更安全的强制推送(如果远程分支被他人更新过,会拒绝推送)
git push --force-with-lease origin feat-dashboard

示例9:强制删除远程分支(push --force --delete

场景:普通 git push origin --delete <branch> 要求分支已合并,但你想强制删除一个未合并的远程分支。

# 普通删除(要求分支已合并)
git push origin --delete feat-obsolete
# error: remote branch 'feat-obsolete' is not fully merged

# 强制删除(忽略未合并警告)
git push --force --delete origin feat-obsolete
# 或使用更直接的命令
git push origin :feat-obsolete --force

示例10:强制覆盖本地工作区(丢弃所有未提交修改)

场景:本地工作区有未提交的修改,但你确定这些修改无用,想直接用远程最新代码覆盖本地。

# 1. 先查看状态(确认本地修改确实可丢弃)
git status
# Changes not staged for commit: modified: config.yaml

# 2. 强制覆盖本地(⚠️ 不可恢复)
git fetch origin main
git reset --hard origin/main
git clean -fd   # 删除未跟踪的文件和目录

示例11:强制变基拉取(冲突时自动使用远程版本)

场景:本地有提交,远程也有新提交,你想用变基方式拉取,但遇到冲突时强制丢弃本地提交。

# 普通变基拉取(遇冲突会暂停)
git pull --rebase origin main

# 【危险】强制变基拉取:遇到冲突时自动使用远程版本
git pull --rebase -X theirs origin main
# -X theirs 表示冲突时选择远程版本

示例12:强制获取远程引用(fetch --force

场景:远程仓库执行了 git reset --hard 回退了历史,本地 git fetch 不会自动更新已存在的远程跟踪分支,需要强制覆盖。

# 远程分支 main 从 commit B 回退到了 commit A
# 本地执行普通 fetch:
git fetch origin
git log origin/main   # 仍然显示 commit B(旧的引用)

# 强制 fetch 覆盖本地远程跟踪分支:
git fetch --force origin main
# 或等价写法
git fetch origin +refs/heads/main:refs/remotes/origin/main

# 验证
git log origin/main   # 现在显示 commit A(正确的)

示例13:清理远程已不存在的分支(fetch --prune --force

场景:同事在远程删除了一个分支,但本地 git branch -r 仍然能看到,需要强制同步。

# 普通 prune fetch
git fetch --prune origin

# 强制版本(更彻底)
git fetch --prune --force origin

# 查看效果
git branch -r   # 远程已删除的分支不再显示

五、强制操作安全对照表

操作推荐替代方案何时可用强制
git push --forcegit push --force-with-lease个人独立分支
git push --force --delete先合并再普通删除分支彻底废弃
git pull + reset --hardgit stash + git pull + stash pop确定本地修改无用
git fetch --force普通 git fetch远程仓库历史被重写

六、强制操作速查表

# 强制推送(覆盖远程)
git push --force-with-lease origin <branch>   # 推荐
git push --force origin <branch>              # 不推荐

# 强制删除远程分支
git push --force --delete origin <branch>

# 强制覆盖本地工作区(丢弃所有未提交修改)
git fetch origin <branch>
git reset --hard origin/<branch>
git clean -fd

# 强制清理远程引用
git fetch --prune --force origin

# 强制变基拉取(冲突时使用远程版本)
git pull --rebase -X theirs origin <branch>

⚠️ 重要提醒:强制操作会丢失历史或他人工作,在执行前务必确认:

  1. 使用 git loggit status 检查当前状态
  2. 与团队成员沟通,确保没有其他人依赖你覆盖的分支
  3. 考虑使用 git revert 替代 push --force(如果只是撤销提交)

七、最佳实践建议

  1. 提交粒度:每次提交只做一件事,便于回滚和代码审查。
  2. Commit Message 格式<type>: <简短描述>,描述首字母小写,不加句号。
  3. 分支命名feat/xxxfix/xxxhotfix/xxxchore/xxx
  4. 推送前先拉取git pull --rebase origin main 可避免多余的合并提交。
  5. 不要轻易强制推送:除非你确定没有其他人在协作分支上工作(git push --force 慎用)。