Git 从入门到进阶:一篇吃透版本管理的实战指南

Git 是现代软件工程里最重要的基础工具之一。它不仅是"保存代码版本"的工具,更是团队协作、代码评审、发布回滚、问题追踪和知识沉淀的基础设施。 很多人学 Git 时会陷入两个误区:一是把命令背成孤立清单,遇到真实问题仍然不知道该用哪个;二是把 GitHub、GitLab、Gitee 这类平台等同于 Git 本身。前者会让操作变得机械,后者会让概念混乱。

一、先分清:Git、远程仓库和托管平台

Git 是一个分布式版本控制系统。它运行在你的本机,负责记录文件快照、提交历史、分支指针和标签。即使没有网络,Git 仍然可以提交、查看历史、创建分支、回滚本地改动。

远程仓库是另一份 Git 仓库副本,通常放在服务器上,用来和团队共享提交。origin 只是远程仓库的默认别名,不是固定概念,也可以叫 upstreamcompany 或其他名字。

GitHub、GitLab、Gitee、Gitcode等平台是 Git 仓库托管服务。它们在 Git 之上提供 Pull Request、Merge Request、代码评审、CI、权限管理、Issue、Release 等协作能力。

名称 本质 主要作用
Git 本地版本控制工具 记录历史、分支、合并、回滚
远程仓库 另一份 Git 仓库副本 多人同步提交
GitHub 等平台 Git 托管与协作平台 评审、CI、权限、发布管理

二、Git 的四个核心区域

学习 Git 最重要的不是先背命令,而是理解改动在不同区域之间如何流动。

Git 日常操作围绕四个区域展开:

区域 英文常见说法 你需要知道什么
工作区 Working Tree 你正在编辑的真实文件
暂存区 Staging Area / Index 下一次提交要包含的改动清单
本地仓库 Local Repository 已提交的历史、分支、标签都在这里
远程仓库 Remote Repository 团队共享的仓库副本

最基本的流动关系如下:

bash 复制代码
工作区 --git add--> 暂存区 --git commit--> 本地仓库 --git push--> 远程仓库

从远程获取别人改动时,通常是:

bash 复制代码
远程仓库 --git fetch / git pull--> 本地仓库和工作区

你只要记住一句话:每次不知道下一步怎么做,先执行 git status。它会告诉你改动在哪个区域、哪些文件已暂存、当前分支是否落后或领先远程分支。

三、第一次使用 Git:配置与初始化

3.1. 配置身份

Git 的每次提交都会记录作者信息。首次使用建议设置全局用户名和邮箱:

bash 复制代码
git config --global user.name "你的名字"
git config --global user.email "you@example.com"

查看配置:

bash 复制代码
git config --global --list

3.2. 设置默认分支名

现在很多项目默认主分支叫 main。你可以设置新仓库的默认分支名:

bash 复制代码
git config --global init.defaultBranch main

已经创建过的仓库如果主分支不是 main,可以在仓库内改名:

bash 复制代码
git branch -M main

3.3. 新建一个仓库

在已有项目目录中启用 Git:

bash 复制代码
git init
git status
git add README.md
git commit -m "docs: 初始化项目说明"

如果要关联远程仓库:

bash 复制代码
git remote add origin <仓库地址>
git push -u origin main

-u 的意思是建立当前本地分支和远程分支的跟踪关系。设置之后,后续在这个分支上可以直接使用 git pushgit pull

3.4. 克隆已有仓库

参与已有项目时,一般从克隆开始:

bash 复制代码
git clone <仓库地址>
cd <项目目录>
git status

克隆完成后,你本地会得到完整历史,以及默认远程名 origin

四、最常用的一套日常流程

真实项目里,Git 不应该随手乱用。建议把日常流程固定下来:同步主线、创建分支、修改代码、检查变化、提交、同步、推送、发起评审。

一个标准功能开发流程可以这样做:

bash 复制代码
# 1. 切回主线
git switch main

# 2. 获取远程最新提交,并要求只能快进合并
git pull --ff-only

# 3. 创建功能分支
git switch -c feat/login

# 4. 修改代码后查看状态
git status
git diff

# 5. 挑选要提交的改动
git add -p

# 6. 提交
git commit -m "feat: 增加短信登录入口"

# 7. 推送当前分支,并建立上游跟踪
git push -u origin feat/login

这里有几个细节值得养成习惯。

第一,尽量不要直接在 main 上开发。主线分支应该保持稳定,功能、修复、实验都放在独立分支。

第二,提交前先看 git diff。很多糟糕提交不是因为 Git 难,而是因为作者没有检查自己到底提交了什么。

第三,优先使用 git add -p。它可以按代码块挑选改动,适合把无关变化拆开提交。

第四,推送前先同步主线。如果团队约定使用线性历史,可以在个人分支上执行:

bash 复制代码
git fetch origin
git rebase origin/main

如果团队不使用 rebase,就按团队约定 merge。关键不是某个命令绝对正确,而是团队策略一致。

五、看懂分支:分支不是文件夹

很多初学者会把分支理解成"复制了一份文件夹"。这个理解不够准确。Git 分支本质上只是一个指针,指向某个提交。你每次提交,当前分支指针就向前移动。

常用分支命令:

bash 复制代码
# 查看本地分支
git branch

# 查看本地和远程分支
git branch -a

# 查看分支跟踪关系
git branch -vv

# 切换分支
git switch main

# 创建并切换到新分支
git switch -c feat/login

# 删除已合并分支
git branch -d feat/login

# 强制删除未合并分支,谨慎使用
git branch -D feat/login

分支命名建议

分支名不需要复杂,但要能表达目的。常见规范如下:

类型 示例 含义
feat/ feat/login 新功能
fix/ fix/payment-timeout 缺陷修复
hotfix/ hotfix/order-crash 紧急线上修复
chore/ chore/update-deps 构建、依赖、工程事务
docs/ docs/git-guide 文档

一个好分支名应该让评审者不用点开代码,也能大致知道这个分支要解决什么问题。

六、提交不是保存按钮:写好 Commit

git commit 不是"我怕代码丢了,所以先保存一下"。提交应该代表一个完整、可理解、可验证的变更单元。

6.1. 好提交的三个标准

第一,单一目的。一次提交只解决一个问题。不要把功能开发、格式化、重构、依赖升级混在一起。

第二,可验证。提交后项目应该尽量保持可构建、可测试。至少不要把明显无法运行的中间状态提交到共享分支。

第三,可回滚。如果这个提交上线后出问题,团队能独立撤销它,而不会误伤一堆无关改动。

6.2. 提交信息怎么写

推荐使用"类型 + 简短说明"的格式:

bash 复制代码
git commit -m "feat: 增加短信登录入口"
git commit -m "fix: 修复订单金额精度问题"
git commit -m "refactor: 提取用户权限判断逻辑"
git commit -m "docs: 更新部署说明"
git commit -m "test: 补充支付超时用例"

常见类型:

类型 适用场景
feat 新功能
fix 缺陷修复
refactor 不改变外部行为的重构
docs 文档
test 测试
chore 工程配置、依赖、脚本等事务
perf 性能优化
style 格式、空白、样式,不影响逻辑

当变更复杂时,不要只写一行标题。可以打开编辑器写多行提交信息:

bash 复制代码
git commit

推荐结构:

text 复制代码
feat: 增加短信登录入口

当前账号体系只支持密码登录,移动端注册转化率较低。
本次增加短信验证码登录入口,并复用现有验证码发送限流逻辑。

验证方式:
- npm test
- 手动验证验证码过期提示

关联:#123

6.3. 修改最近一次提交

如果刚提交完发现漏了一个文件,且还没有推送,可以使用:

bash 复制代码
git add <文件>
git commit --amend

如果只是改提交信息:

bash 复制代码
git commit --amend -m "fix: 修正验证码过期提示"

注意:--amend 会产生新的提交哈希。如果提交已经推送到多人共享分支,不要随意 amend。

七、Merge 与 Rebase:两种整合历史的方式

分支开发完成后,需要把改动整合回主线。常见方式是 merge 和 rebase。

7.1. Merge:保留真实分叉历史

bash 复制代码
git switch main
git merge feat/login

merge 的特点是不会改写已有提交。它会把两条历史线合并起来,必要时生成一个合并提交。优点是历史真实、审计友好;缺点是分支多时提交图可能比较复杂。

适合场景:

  • 主线集成功能分支。
  • 多人共同维护同一个长期分支。
  • 团队希望保留完整分叉与合并记录。

7.2. Rebase:把提交重放到新基底上

bash 复制代码
git fetch origin
git rebase origin/main

rebase 的特点是会改写提交哈希。它把当前分支上的提交拿出来,放到新的基底后面重新应用。优点是历史线性、评审清晰;风险是如果别人已经基于你的旧提交继续开发,改写历史会影响他们。

适合场景:

  • 整理自己的本地功能分支。
  • 提交 PR 前让分支跟上最新主线。
  • 团队明确约定使用线性历史。

重要原则:

text 复制代码
可以 rebase 自己尚未共享的分支。
不要随意 rebase 已经被他人基于开发的共享分支。

7.3. Pull 到底做了什么

git pull 本质上相当于:

bash 复制代码
git fetch
git merge

如果使用:

bash 复制代码
git pull --rebase

则相当于:

bash 复制代码
git fetch
git rebase

很多团队会要求使用 git pull --ff-only,它只允许快进合并。如果本地和远程出现分叉,命令会失败,提示你先明确选择 merge 或 rebase。这种方式能避免不小心生成意外的合并提交。

八、冲突处理:不要害怕,但要认真

冲突不是 Git 出错,而是 Git 无法自动判断最终应该保留哪段内容。比如你和同事都修改了同一行,Git 不知道哪一边代表正确业务语义。

冲突处理流程:

bash 复制代码
# 1. 查看冲突文件
git status

# 2. 打开文件,找到冲突标记
<<<<<<< HEAD
当前分支中的内容
=======
对方分支中的内容
>>>>>>> origin/main

# 3. 手动编辑为最终正确结果,并删除冲突标记

# 4. 标记已解决
git add <文件>

# 5. 如果是 merge
git commit

# 6. 如果是 rebase
git rebase --continue

如果 rebase 过程中发现方向错了,可以中止:

bash 复制代码
git rebase --abort

如果 merge 过程中想回到合并前状态:

bash 复制代码
git merge --abort

处理冲突时最危险的做法,是为了"让冲突消失"而直接选择某一边。正确做法是理解双方改动目的,必要时找相关同事确认,再保留真正正确的最终代码。

九、撤销与回滚:先判断改动在哪个阶段

Git 撤销命令很多,真正难点不是命令本身,而是判断当前改动处于哪个阶段,以及是否已经推送到共享分支。

9.1. 丢弃工作区改动

适用于文件已经修改,但还没有暂存:

bash 复制代码
git restore <文件>

丢弃当前目录下已跟踪文件的工作区改动要非常谨慎:

bash 复制代码
git restore .

执行前建议先看:

bash 复制代码
git diff

9.2. 从暂存区撤出

适用于已经 git add,但不想让某些文件进入下一次提交:

bash 复制代码
git restore --staged <文件>

这不会丢弃文件内容,只是把改动从暂存区拿回工作区。

9.3. 撤销本地未推送提交

如果最近一次提交还没有推送,可以根据目的选择:

bash 复制代码
# 撤销提交,但保留改动在暂存区
git reset --soft HEAD~1

# 撤销提交,保留改动在工作区
git reset --mixed HEAD~1

# 撤销提交,并丢弃对应工作区改动,危险
git reset --hard HEAD~1

git reset --hard 是高风险命令。它会移动分支指针,并让工作区回到目标提交状态。执行前必须确认没有未保存的重要改动。

9.4. 回滚已经推送的提交

如果提交已经进入共享分支,优先使用 revert

bash 复制代码
git revert <提交哈希>

revert 会生成一个新的反向提交,用来抵消指定提交的影响。它不会改写公共历史,因此更适合团队协作和审计。

9.5. 找回误删提交

如果你误删分支、reset 错了,先别慌。Git 可能还能通过 reflog 找到旧位置:

bash 复制代码
git reflog
git switch -c rescue <提交哈希>

reflog 是本地引用日志,记录 HEAD 和分支指针曾经指向哪里。它不是永久备份,过期清理后可能消失,所以越早处理越好。

十、进阶命令:提升效率与排障能力

当你掌握基础流程后,这些命令会显著提升真实项目效率。

10.1. Stash:临时保存现场

当你正在开发一半,但需要马上切换分支修一个线上问题,可以先 stash:

bash 复制代码
git stash push -u -m "登录页开发到一半"

说明:

  • -u 会包含未跟踪文件。
  • 默认不会包含被 .gitignore 忽略的文件。
  • -m 给这次 stash 加说明,方便以后识别。

查看 stash:

bash 复制代码
git stash list

恢复并删除最近一次 stash:

bash 复制代码
git stash pop

恢复但保留 stash 记录:

bash 复制代码
git stash apply

10.2. Cherry-pick:拣选某个提交

当你只想把另一个分支上的某个提交拿过来:

bash 复制代码
git cherry-pick <提交哈希>

它会把该提交的补丁应用到当前分支,并生成一个新的提交,因此新提交哈希和原提交通常不同。

适合场景:

  • 把修复提交同步到 release 分支。
  • 从实验分支挑一个稳定改动。
  • 临时补齐某个环境缺失的提交。

10.3. Tag:标记发布版本

标签常用于标记发布点:

bash 复制代码
git tag -a v1.2.0 -m "发布 v1.2.0"
git push origin v1.2.0

查看标签:

bash 复制代码
git tag

查看某个标签信息:

bash 复制代码
git show v1.2.0

建议生产发布使用带说明的注解标签,即 git tag -a

10.4. Bisect:二分定位问题提交

当你知道"某个旧版本是好的,现在坏了",但不知道哪个提交引入问题,可以用 bisect:

bash 复制代码
git bisect start
git bisect bad
git bisect good <旧提交哈希>

Git 会切到中间提交,你运行测试或手动验证后告诉它:

bash 复制代码
git bisect good
# 或
git bisect bad

重复几轮后,Git 会定位到最可能引入问题的提交。结束后:

bash 复制代码
git bisect reset

10.5. Worktree:同时检出多个分支

如果你经常需要在功能开发和线上修复之间切换,git worktree 比频繁 stash 更舒服:

bash 复制代码
git worktree add ../project-hotfix hotfix/payment

这样你可以在另一个目录同时打开 hotfix 分支,而原目录继续保留当前开发现场。

查看 worktree:

bash 复制代码
git worktree list

删除不再使用的 worktree:

bash 复制代码
git worktree remove ../project-hotfix

十一、远程协作:PR / MR 是质量闸门

团队项目中,远程仓库不是简单备份。它连接了代码评审、自动化测试、权限控制、版本发布和回滚审计。

一个成熟 PR 应该包含:

  • 背景:为什么要改。
  • 变更:改了哪些核心内容。
  • 验证:跑了哪些测试,手动验证了哪些路径。
  • 风险:是否涉及兼容性、数据迁移、性能或安全。
  • 截图:前端或可视化改动应提供前后对比。

示例 PR 描述:

markdown 复制代码
## 背景
登录页目前只支持密码登录,移动端转化率低。

## 变更
- 增加短信验证码登录入口
- 复用已有验证码限流逻辑
- 增加验证码过期提示

## 验证
- npm test
- 手动验证验证码发送、过期、重试路径

## 风险
- 依赖短信服务可用性
- 需要观察发送失败率

常见远程命令

查看远程仓库:

bash 复制代码
git remote -v

获取远程最新状态,但不自动合并:

bash 复制代码
git fetch origin

删除本地已经失效的远程跟踪分支:

bash 复制代码
git fetch --prune

推送当前分支并建立跟踪关系:

bash 复制代码
git push -u origin <分支名>

删除远程分支:

bash 复制代码
git push origin --delete <分支名>

十二、.gitignore、LFS 与仓库治理

仓库治理影响长期可维护性。忽略规则、大文件策略和密钥管理如果做得不好,仓库会越来越慢,甚至引发安全事故。

12.1. .gitignore 只影响未跟踪文件

常见 .gitignore

gitignore 复制代码
# 依赖
node_modules/

# 构建产物
dist/
build/

# 日志
*.log

# 本地环境
.env
.env.local

# 系统文件
.DS_Store
Thumbs.db

一个常见误区是:把文件写进 .gitignore 后,Git 就不再跟踪它。实际上,如果文件已经被提交过,.gitignore 不会让它自动消失。

停止跟踪但保留本地文件:

bash 复制代码
git rm --cached <文件>
git commit -m "chore: 停止跟踪本地配置文件"

12.2. 用 .gitattributes 管理换行和二进制文件

跨平台团队容易遇到 CRLF 和 LF 换行差异。更稳妥的做法是在仓库中使用 .gitattributes 明确规则,而不是依赖每个人的全局配置。

示例:

gitattributes 复制代码
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary

个人的 core.autocrlf 应遵循团队约定。项目内有 .gitattributes 时,优先以项目规则为准。

12.3. 大文件使用 Git LFS

Git 擅长管理源码文本,不擅长频繁变化的大型二进制文件。图片源文件、模型、设计稿、压缩包等大文件可以考虑 Git LFS:

bash 复制代码
git lfs install
git lfs track "*.psd"
git add .gitattributes
git add design.psd
git commit -m "chore: 使用 LFS 管理设计源文件"

注意:LFS 对后续新增文件有效。已经进入历史的大文件,需要专门做历史迁移,不能简单认为 git lfs track 会自动瘦身旧历史。

12.4. 密钥泄露必须轮换

如果 .env、私钥、Token 被提交过,正确处理不是只删掉文件。只要进入过 Git 历史,就可能被别人拉取过。

严谨处理步骤:

  1. 立即撤销或轮换泄露的密钥。
  2. 从当前代码中删除密钥。
  3. 必要时用 git filter-repo 或 BFG 等工具清理历史。
  4. 通知团队重新拉取或按迁移方案处理。
  5. 增加扫描工具,避免再次提交。

安全原则很简单:提交过的密钥视为已经泄露。

十三、故障排查:不要先复制命令

Git 出问题时,最重要的是先定位问题范围。盲目复制 reset --hardforce push 之类命令,往往会把小问题变成团队事故。

排查三件套:

bash 复制代码
git status
git diff
git log --oneline --graph --decorate -n 12

如果涉及远程:

bash 复制代码
git branch -vv
git remote -v
git fetch origin

如果怀疑提交丢失:

bash 复制代码
git reflog

常见场景处理

场景 1:我改乱了一个文件,想恢复到上次提交

bash 复制代码
git restore <文件>

场景 2:我 add 错了文件

bash 复制代码
git restore --staged <文件>

场景 3:刚提交完发现漏了文件

bash 复制代码
git add <文件>
git commit --amend

前提是还没有推送到共享分支。

场景 4:提交已经推送,想撤销它

bash 复制代码
git revert <提交哈希>

这是公共历史中更稳妥的做法。

场景 5:本地分支和远程主线分叉了

先获取远程状态:

bash 复制代码
git fetch origin

如果是个人功能分支,团队也允许线性历史:

bash 复制代码
git rebase origin/main

如果团队保留合并记录:

bash 复制代码
git merge origin/main

场景 6:我把分支删了

先查 reflog:

bash 复制代码
git reflog

找到旧提交后创建救援分支:

bash 复制代码
git switch -c rescue <提交哈希>

场景 7:远程分支已经删了,本地还看得到

bash 复制代码
git fetch --prune

这会清理失效的远程跟踪分支。

十四、常用命令速查

下面这张图适合收藏,也适合放到团队 Wiki。

补充一个更完整的命令表:

目的 命令 说明
查看状态 git status 查看当前分支、工作区、暂存区
查看未暂存差异 git diff 对比工作区和暂存区
查看已暂存差异 git diff --staged 对比暂存区和最近提交
暂存文件 git add <文件> 加入下一次提交
分块暂存 git add -p 按块选择改动
提交 git commit -m "说明" 生成提交
修改最近提交 git commit --amend 改写最近一次提交
查看历史 git log --oneline --graph 图形化简洁历史
查看提交详情 git show <提交哈希> 查看某次提交内容
查看文件归属 git blame <文件> 查看每行最后修改者
创建分支 git switch -c <分支> 创建并切换
切换分支 git switch <分支> 切到已有分支
合并分支 git merge <分支> 合并指定分支
变基 git rebase <基底> 把当前提交重放到新基底
获取远程 git fetch origin 只获取,不合并
拉取并快进 git pull --ff-only 只允许快进
推送 git push 推送当前分支
推送并跟踪 git push -u origin <分支> 建立上游关系
撤出暂存 git restore --staged <文件> 暂存区回到工作区
丢弃工作区改动 git restore <文件> 恢复为最近提交状态
公共回滚 git revert <提交哈希> 新增反向提交
本地重置 git reset --soft HEAD~1 撤销提交,保留暂存
临时保存 git stash push -u -m "说明" 保存当前现场
找回历史位置 git reflog 查看本地引用移动记录

十五、团队 Git 规范建议

个人会用 Git 只是第一步,团队要靠规范降低协作成本。下面是一套可落地的建议。

15.1. 主线保护

主线分支建议开启保护:

  • 禁止直接 push。
  • 必须通过 PR / MR。
  • 必须通过自动化测试。
  • 至少一名评审者批准。
  • 对高风险仓库启用 CODEOWNERS 或类似机制。

15.2. 分支生命周期要短

功能分支存在越久,越容易和主线偏离,冲突风险越高。建议:

  • 小需求 1 到 3 天内合入。
  • 大需求拆成多个可评审 PR。
  • 长期分支定期同步主线。
  • 合并后及时删除远程分支。

15.3. 提交历史保持可读

推荐:

  • 一次提交一个意图。
  • 提交信息说明"为什么"。
  • 无关格式化单独提交。
  • 不提交临时代码、调试日志、个人配置。
  • 推送前用 git log --oneline --graph -n 12 看一眼历史。

15.4. 危险命令建立团队约束

以下命令不是不能用,而是要清楚后果:

命令 风险
git reset --hard 丢弃工作区和暂存区改动
git push --force 改写远程历史,可能影响他人
git clean -fd 删除未跟踪文件
git rebase 改写提交哈希,不适合随意用于共享分支

如果确实需要强推,优先使用带保护的方式:

bash 复制代码
git push --force-with-lease

它会在远程分支没有被别人更新时才允许强推,比 --force 更稳妥,但仍然需要遵守团队约定。

15.5. 让自动化替你守门

Git 工作流最好和自动化检查结合:

  • 提交前运行格式化和测试。
  • PR 自动运行 CI。
  • 合并前检查测试、Lint、类型检查、构建。
  • 对密钥、许可证、大文件进行扫描。
  • 发布时用 tag 和 release note 记录版本。

十六、一套推荐的新手练习路径

如果你刚开始学 Git,不建议只看教程。最好拿一个临时目录练习下面这些场景:

  1. git init 创建仓库,提交 README。
  2. 修改同一个文件,分别练习 git diffgit addgit commit
  3. 创建两个分支,分别提交,再 merge。
  4. 人为制造冲突,练习解决冲突。
  5. 使用 git restore 丢弃工作区改动。
  6. 使用 git restore --staged 撤出暂存。
  7. 使用 git reset --soft 撤销未推送提交。
  8. 使用 git revert 回滚一个提交。
  9. 使用 git stash 临时保存现场。
  10. 使用 git reflog 找回一个旧提交。

练习时不要怕把仓库弄坏。真正的能力来自你知道弄坏后如何恢复。

十七、最终心法

Git 的难点不是命令数量,而是历史意识。你要始终知道三件事:

第一,当前改动在哪个区域:工作区、暂存区、本地仓库,还是远程仓库。

第二,当前操作是否会改写历史:commit --amendresetrebase 都会产生新的提交关系。

第三,这段历史是否已经共享给别人:只要进入共享分支,就优先选择保留审计痕迹的修复方式,例如 revert

最后记住这条原则:

text 复制代码
本地私有历史可以整理,远程共享历史要谨慎。
先看 status,再做决定。

如果你能真正理解这两句话,Git 就不再是一堆吓人的命令,而会变成一套帮助你管理变化、协作和风险的工程系统。

相关推荐
开发者联盟league2 小时前
git commit报错No .pre-commit-config.yaml file was found
git
猫老板的豆7 小时前
git实战
git
风曦Kisaki8 小时前
# Linux实战笔记-HIS项目实战Day01:版本控制与Git基础
linux·笔记·git
鲸~屿11 小时前
Git上传本地文件到GitHub教学指南
git·github
减瓦1 天前
Windows 环境使用 Git Bash 最佳实践
windows·git
史呆芬1 天前
CodeX多仓库提交Skill搭建
git·后端·openai
城东1 天前
Git使用[原意要新建分支提交但是误提交到原来分支恢复办法]
git·原意要新建分支提交·但是误提交到原来分支
开发者联盟league1 天前
git 压缩本地最近多个commit
git