Git 核心概念与操作总结
1. 本地 Commit 本质
- IDEA 代码自动保存:仅保存文件内容到本地文件夹,无版本记录、无法回退、无修改历史。
- Git Commit:对当前代码状态拍摄版本快照,存入本地 .git 文件夹;仅本地可见,不上传远程仓库。
- Commit 作用:生成版本记录、可查看历史、支持回退,是 Push 的前置步骤。
2. Commit 与 Push 区别
- Commit:提交到本地 Git 仓库,仅自己可见。
- Push:将本地已 Commit 的版本上传到远程仓库(GitHub/Gitee 等),他人可拉取。
3. 查看历史更改操作
- 全局提交记录:IDEA 按 Alt+9 打开 Git 面板 → Log 标签,查看所有 Commit、修改文件及差异。
- 单个文件历史:右键文件 → Git → Show History,仅查看当前文件修改记录。
4. 代码回退操作
- 未 Commit 撤销:右键文件 → Git → Revert,放弃未提交修改。
- 版本重置 Reset:右键历史记录 → Reset Current Branch to Here
- Soft:回退到旧版本,保留未提交代码。
- Hard:彻底回退,清空未提交改动(谨慎使用)。
5. 签出修订(Checkout)
- 含义:选中历史 Commit,将项目代码切换到该时间点的旧版本。
- 特点:临时切换查看/排查 Bug,不修改分支历史;处于游离状态,可随时切回原分支。
- 与 Reset 区别:签出仅临时查看;重置抹除后续提交,回退版本。
6. 分支核心概念
- 分支类比:main/master 为主干,分支为独立树枝。
- 特性:从某分支新建分支,初始代码与原分支一致;分支可无限嵌套,可在已有分支上建子分支。
- 用途:独立开发新功能/修复 Bug,不影响主分支;完成后合并回主分支。
7. 多人分支开发冲突规则
- 冲突触发:两人从 main 建分支,修改同一文件同一行;一人先合并到 main,另一人合并时触发冲突。
- 冲突机制:Git 不自动覆盖,暂停合并,等待手动处理。
- 处理方式:保留自身代码、保留他人代码、手动合并兼容双方代码。
- 无冲突场景:功能类似但修改不同文件/行,Git 自动合并,两份代码均保留。
- 规避方式:提前划分功能、定期拉取 main 最新代码、避免多人改同一核心文件。
GitHub分支的签出,合并与变基
一、签出(Checkout)
签出 = 切换分支,是 Git 中最基础的操作。
作用:让你的本地工作区切换到指定分支,切换后可以正常查看、修改、提交代码,并非 “只读状态”。
关键:切换后,你的所有修改都会保存在当前分支上,和其他分支互不影响。
二、合并(Merge)
合并 = 将一个分支的代码,完整合并到另一个分支,是最常用的分支整合方式。
适用场景:将功能分支的开发成果合并到主分支,或合并两个独立的分支历史。
示例(合并 master 到 main,处理无关历史):
特点:
- 会保留两个分支的提交历史,提交线会出现分叉,形成清晰的 “合并节点”。
- 遇到文件冲突时,需要手动解决冲突后再提交。
三、变基
变基(Rebase)= 把你当前分支的提交,“搬家”到目标分支的最新位置。
不是把两个分支变成一样,而是把你的提交线接在别人的尾巴上,让历史变成一条直线。
假设:
- main 是主干(别人/远程最新代码)
- master 是你写的功能分支(你的提交)
不变基(直接合并)
历史会变成:
main ---A---B
\
master ------C---D两条线,有分叉。
变基之后
你的 C、D 提交会被复制、搬家,接到 main 最后面:
main ---A---B---C---D变成一条干净直线!
那变基的作用
变基 = 重新摆放你的提交,让分支历史变成一条直线,更干净。
它不会把两个分支变成一样,而是:
保留你写的代码
保留你的提交记录
只是把提交线接得更整齐记忆口诀
总结
- 签出 = 切换分支
- 合并 = 把代码合进来
- 变基 = 把提交排成一条直线
Merge与Rebase的区别
所以变基是让合并历史保持直线,merge是出现分叉的合并,但是两者不是都要解决冲突问题吗,所以使用哪个都差不多把,我都要对冲突的地方进行选择,是保留我自己的还是保留其他人的
无论是变基(rebase)还是合并(merge),当两个分支修改了同一个文件的同一区域时,都必须手动解决冲突。从“解决冲突”这个动作来说,两者确实都要做选择(保留自己的还是对方的,或者混合)。
但它们在冲突出现的次数、解决流程、最终历史形态上有明显区别,并不是完全“差不多”。下面帮你对比一下,方便你根据实际情况选择。
1. 冲突解决的“次数”不同
merge:只在最后合并的那一刻解决一次冲突。
你执行git merge recover-route,如果两个分支有冲突,Git 会直接停下来,让你一次性处理好所有冲突文件,然后提交一个合并提交。一个冲突只处理一次。rebase:会将 recover-route 上的每个提交依次重放到 main 上。
如果第一个提交有冲突,你解决 → 继续;第二个提交可能又出现冲突(因为上下文变了),再解决 → 继续……如果有 N 个提交都涉及冲突区域,你就要解决 N 次冲突。这很烦人,尤其当你不熟悉每个提交的具体改动时。
举例:你在 recover-route 上有 5 个提交,每个都修改了 MqConstants.java 的不同行。rebase 时会逐个应用这 5 个提交,每个都可能冲突,你要重复解决 5 次。merge 只会在最终合并时比较两边的最终版本,冲突可能只出现一次(或者更少)。
2. 解决冲突时的“基准”不同
merge:你看到的是“当前 main 的最终内容” 与 “recover-route 的最终内容” 之间的差异。解决时只需要关心最终代码应该长什么样。
rebase:你看到的是“当前 main 的最新内容” 与 “recover-route 上某一个历史提交” 之间的差异。你可能需要回忆或理解那个历史提交的意图,解决起来更烧脑。
3. 历史形状不同(这是你关心的)
merge:产生一个分叉点 + 一个合并提交(
Merge branch 'recover-route' into main),历史呈分叉状(非直线)。
优点:真实保留了分支的开发过程,明确知道合并点。
缺点:历史看起来有点“乱”。rebase:将 recover-route 的提交“剪下来贴到 main 的末尾”,得到一条直线。
优点:历史干净,像串行开发。
缺点:改变了提交的哈希值,如果已经推送到远程,需要强制推送,可能影响他人。
4. 所以到底用哪个?
对于你的具体目标:把 recover-route 的所有提交历史并入 main,然后删除 recover-route。
推荐用 merge:
- 一次解决冲突,简单直接。
- 即使历史有分叉,对你个人项目来说完全没问题。
- 不会重写提交,安全省心。
不推荐用 rebase(除非你特别偏爱直线历史):
- 可能需要反复解决冲突,浪费时间。
- 既然你已经在 rebase 过程中遇到冲突且感到困惑,说明对 rebase 流程还不够熟悉,贸然继续容易出错(比如误解决导致代码丢失)。
一个折中做法(既直线又不反复冲突):
如果你想获得直线历史,但不想多次解冲突,可以这样做:
# 1. 切换到 main
git checkout main
# 2. 使用 squash merge(把整个分支压成一个提交再合并)
git merge --squash recover-route
# 此时所有改动都在暂存区,但不会自动提交,也没有分支历史
# 3. 手动解决一次冲突(如果有的话)
# 4. 提交成一个新的提交
git commit -m "Add recover-route features"这样 main 上只多了一个提交,包含了 recover-route 的所有改动,历史是直线的。但缺点是你丢失了 recover-route 上的多个小提交记录(它们被压成一个了)。如果你不介意,这也很干净。
总结
两者都要解决冲突,但 merge 通常更简单(一次冲突),rebase 可能更麻烦(多次冲突)。
除非你非常想要一条直线历史并且愿意接受多次解决冲突的代价,否则对于“合并分支然后删除”的场景,直接用 merge 就好。
你目前已经在 rebase 冲突中,可以用 git rebase --abort 退出,然后改用 git merge recover-route。
如果 merge 时也遇到冲突,解决一次,完成合并,然后删除分支。这样最符合你的需求。
这里不应该是只能选择接受我的还是其他人的更改吗,为什么还能选择合并,不是不能合并吗

你观察得很细致!这里的“合并(M)”选项并不是说 Git 会自动帮你合并两边的冲突(那是不可能的),而是指允许你手动编辑冲突区域,灵活地保留双方的部分修改,而不是只能“全要你的”或“全要他的”。
具体解释一下:
1. “合并”选项的真实含义
在冲突界面中:
- “接受您的更改(Y)”:完全使用
recover-route分支上的代码(你的)。 - “接受他们的(T)”:完全使用
main分支上的代码(他人的)。 - “合并(M)”:手动编辑冲突文件,你可以逐行、逐块地选择保留哪些内容。比如保留你新增的几行,同时也保留对方修改的几行,最终生成一个混合版本。
所以不是不能合并,而是你可以“自定义合并”。对于简单的冲突(比如两边改了同一行),你只能二选一;但对于复杂的冲突(比如两边在不同位置新增了代码,或功能互补),你完全可以把两边的有用部分都留下来。
2. 为什么你感觉“不能合并”?
你可能从 Git 命令行学习时,通常解决冲突就是打开文件,删除 <<<<<<<, =======, >>>>>>> 标记,然后手动编辑成想要的代码。这个手动编辑的过程,本质上就是**“合并”**。图形界面里的“合并(M)”按钮,就是帮你自动打开编辑器(或内置合并工具),让你去做这个手动操作。
3. 什么时候该用“合并”?
- 两边的修改并不直接冲突的行,而是互补的(比如你在 A 方法加了代码,对方在 B 方法加了代码),你需要同时保留。
- 两边的修改逻辑上都需要,但需要手动调整顺序或语法。
- 你只想从对方那里取一小部分代码,而不是整个文件。
例如:
<<<<<<< HEAD
// 你的代码:增加了优惠券有效期校验
if (coupon.getExpireTime().before(now)) { ... }
=======
// 对方的代码:增加了用户黑名单检查
if (user.isBlacklisted()) { ... }
>>>>>>> main此时你既需要有效期校验,又需要黑名单检查,那么“合并”就能让你把两段代码都保留下来(适当调整顺序)。
4. 总结
- “接受您的/他们的”:简单粗暴,全盘采用一方。
- “合并”:精细控制,手动混合双方代码(或者甚至都删掉重写)。
你现在看到这个界面,说明冲突文件较多(12个文件)。如果每个文件的冲突都不大且明确该用谁的,直接选“接受您的”或“接受他们的”更快。如果有些文件需要两边都保留一部分,那就选“合并”手动处理。
关键: 无论你选哪个选项,最终目标都是生成一个可编译、逻辑正确的代码版本。如果你不确定,先选“合并”,查看冲突区域,再做出合理选择。
还原提交(Revert Commit)
- 作用:创建一个新的提交,该提交的内容刚好是选中提交的反向修改(即撤销那个提交的所有改动)。
- 用途:安全地“撤销”一个已经推送到远程的提交,因为不重写历史,不影响其他人。常用于线上修复
这里撤销了提交那就没有修改的代码了,如果已经推送到远程仓库,其他人也已经基于这个代码进行开发了,这时候还原不是就会报错吗
你提出的这个问题非常好,它触及了 Git 协作中的一个关键区别:“撤销历史” vs “反向提交”。
1. 还原(Revert)不会删除历史,而是新增一个“反向”提交
假设远程仓库有一条提交历史:A → B → C(其中 C 是你想撤销的提交)
执行 git revert C 后,Git 会自动计算 C 相对于 B 的所有改动,然后生成一个完全相反的改动,并作为一个新的提交 C' 附加在历史末尾。
结果:A → B → C → C'
C'的内容刚好是撤销C的改动。所以从最终代码看,C'让代码回到了B的状态。- 但
C这个提交依然存在,历史没有被重写。
2. 其他人基于包含 C 的代码开发,会发生什么?
假设你的同事小张在推送 C 之后,克隆了仓库(或拉取了 C),然后基于 C 继续开发了新的提交 D。
他的本地历史:A → B → C → D
现在你执行了 git revert C 并推送到远程,远程历史变成:A → B → C → C'
小张执行 git pull 时,Git 会尝试合并两边的历史:
- 本地:
A-B-C-D - 远程:
A-B-C-C'
合并时会创建一个合并提交 M,包含 D 和 C' 的改动。
如果 D 和 C' 修改了相同的文件/代码行,就会产生冲突,需要小张手动解决。
这不是“报错”,而是正常的合并冲突,就像你把两个分支合并时一样。冲突解决后,小张的代码就能正常推送到远程。
3. 为什么还说 revert 是“安全”的?
- 不破坏历史:已经推送的
C仍然存在,其他人的本地提交(如D)不需要变基或强制推送,可以直接pull并解决冲突。 - 可追溯:所有人都能看到“有人撤销了
C”这个操作记录(C')。 - 可恢复:如果将来又想恢复
C,可以revert C'(撤销撤销),非常灵活。
相比之下,如果用 git reset 删除 C 然后强制推送,其他人再拉取就会遇到“历史被重写”的错误(git pull 会提示分叉或拒绝),必须用 --force 覆盖本地历史,容易导致他人丢失工作——那才是真正的“报错”和危险。
4. 什么时候适合用 revert?
- 已经推送到公共分支(如
main、develop),且可能有其他人基于该分支开发。 - 需要保留完整的操作审计记录(企业/开源项目)。
- 你只是觉得某次提交的功能不再需要,但不想完全抹掉它的存在。
总结
git revert不会导致其他人报错,只会可能引入合并冲突(如果他人修改了相同代码)。- 冲突是 Git 日常协作的一部分,解决即可。
- revert 的最大价值:在不伤害协作流程的前提下,安全地撤销已推送的提交。
如果你希望彻底删除某个提交(且确信没有其他人依赖它),可以用 git reset + push --force,但那只适用于未推送的本地分支或你个人独占的分支。
Git图形界面中对于提交的分支操作菜单

这个菜单是在 Git 图形界面(如 IntelliJ IDEA、GitKraken、SourceTree 等)中,右键点击某个提交(commit)时弹出的操作菜单。下面逐项解释每个功能的作用和典型使用场景。
1. 复制修订号
- 快捷键:
Ctrl+Alt+Shift+C - 作用:将该提交的哈希值(40 位十六进制字符串,或短哈希)复制到剪贴板。
- 用途:方便在终端、聊天工具或文档中引用这个提交,比如执行
git show <hash>或git cherry-pick <hash>。
2. 创建补丁...
- 作用:基于选中的提交生成一个补丁文件(
.patch)。 - 用途:把这次提交的改动打包成一个文件,可以通过邮件或其他方式发送给别人,对方用
git apply或git am就能应用你的修改。常用于不共享仓库的协作或代码审查。
3. 优选(Cherry-pick)
- 作用:将选中的提交复制到当前分支上,生成一个新的提交(内容相同,但哈希值不同)。
- 用途:只想从其他分支引入某一个或某几个提交(而不是整个分支)。例如,你发现
feature分支上的一个 bug 修复很有用,但不想合并整个分支,就用 cherry-pick 把它拿过来。
4. 签出修订(Checkout revision)
- 作用:让当前工作目录切换到该提交的状态,进入 detached HEAD(分离头指针)状态。
- 用途:临时查看项目在某个历史提交时刻的样子,用来调试或回顾。注意:此时不能直接提交新代码(除非新建分支)。
5. 在修订版中显示仓库
- 作用:在版本库浏览器(或文件树)中以该提交为根节点展示文件结构。
- 用途:浏览当时的代码快照,看看哪些文件存在、内容如何。
6. 与本地比较
- 作用:将选中的提交与当前工作目录(或当前分支最新代码)进行差异对比。
- 用途:查看自那次提交以来,代码发生了哪些变化。
7. 将当前分支重置到此处...
- 作用:把当前分支的指针移动到这个提交,并选择重置模式(soft / mixed / hard)。
- 用途:
- 撤销多个提交:想回到过去某个干净的状态。
- 丢弃之后的提交:用
--hard会永久删除该提交之后的所有改动。 - 保留改动为未提交:用
--soft或--mixed可以重新整理提交。
8. 还原提交(Revert Commit)
- 作用:创建一个新的提交,该提交的内容刚好是选中提交的反向修改(即撤销那个提交的所有改动)。
- 用途:安全地“撤销”一个已经推送到远程的提交,因为不重写历史,不影响其他人。常用于线上修复。
9. 撤消提交...
- 作用:相当于
git reset的快捷方式,将当前分支回退到该提交之前,并丢弃或暂存后续改动。 - 用途:后悔最近几个提交,想重新修改后再提交。注意:如果已经推送过,不要使用(除非是个人分支)。
10. 编辑提交消息...
- 作用:修改选中提交的提交说明文字。
- 用途:发现自己写错了提交消息(比如错别字),需要纠正。这通常会改变提交的哈希值,因此只适用于尚未推送的本地提交。
11. Fixup...
- 作用:将当前选中的提交与前一个提交合并,并丢弃这个提交的消息(只保留前一个的消息)。这是交互式变基(rebase -i)的
fixup命令的图形化版本。 - 用途:把一个小修小补的提交“吸收”到它前面的主要提交中,保持历史干净。例如:你提交了“添加登录功能”,然后又提交了“修复登录功能的拼写错误”,就可以用 Fixup 把后者合并到前者里。
12. 压缩到...(Squash into...)
- 作用:将当前选中的提交与前一个提交合并,并合并两者的提交消息(让你编辑新的消息)。对应交互式变基的
squash。 - 用途:把多个相关的提交压缩成一个有意义的提交。比如开发一个功能时做了 5 个小提交,最终想合并为 1 个清晰的提交。
13. 删除提交
- 作用:完全移除选中的提交(及其改动)。一般只能删除最新的几个提交,或者通过变基删除更早的提交。
- 警告:会丢失代码,且会改变历史。只用于本地未推送的分支。
14. 从这里进行交互式变更...(Interactive Rebase from Here...)
- 作用:从选中的提交开始,弹出交互式变基的编辑器,让你可以对后续一系列提交执行重排、压缩、编辑、删除等操作。
- 用途:整理本地分支的历史,比如把多个小提交合并、修改提交顺序、拆分提交等。
15. 推送此前所有提交...
- 作用:把从该提交及之前的所有提交(即该提交到当前分支顶端的所有提交)推送到远程仓库。
- 用途:当你想推送某个提交及其之后的工作,但不想推送更早的(很少用),或者配合
git push --force修改历史后推送。
16. 新建分支...
- 作用:基于选中的提交创建一个新的分支。
- 用途:从历史中的某个时间点分支出一个新的开发线,例如发现一个 bug 需要从旧版本开始修复。
17. 新建标记...(New Tag...)
- 作用:为选中的提交打上一个标签(轻量标签或附注标签)。
- 用途:标记重要的版本(如
v1.0.0、release-2026),便于日后快速引用。
18. 转到子提交 / 向左箭头 / 转到父提交 / 向右箭头
- 解释:这些是导航功能,用于在提交图中移动。
- 转到子提交:跳到当前提交的孩子提交(即更晚的提交,如果当前分支是线性的,通常只有一个子节点)。
- 转到父提交:跳到当前提交的父提交(即更早的提交)。
- 箭头方向:左箭头可能对应“父提交”,右箭头对应“子提交”(具体依赖界面布局)。有的工具用
<和>表示。
- 用途:快速在提交历史中浏览,不用手动滚动列表。
19. 在浏览器中查看
- 作用:如果该提交关联了一个远程仓库(如 GitHub、GitLab),会在默认浏览器中打开该提交的页面。
- 用途:查看完整的 diff、评论、CI 状态等在线信息。
总结:常用操作速查表
| 操作 | 典型场景 |
|---|---|
| 复制修订号 | 需要手动输入哈希时 |
| 优选 | 从其他分支单独拿一个提交 |
| 签出修订 | 临时查看旧版本代码 |
| 重置到此处 | 撤销本地的多个提交(回到过去) |
| 还原提交 | 安全地撤销已推送的提交 |
| 编辑提交消息 / Fixup / 压缩 | 整理本地提交历史(保持干净) |
| 交互式变基 | 复杂的提交历史重写(合并、删除、编辑) |
| 新建分支 / 新建标记 | 从某个历史点开始新工作,或标记版本 |
理解这些功能后,你就能更灵活地管理 Git 历史了。如果你在使用中遇到不确定的,建议先在测试仓库中尝试,避免丢失代码。

这些选项是 Git 图形界面中针对分支 main 的常见操作。下面分别解释:
1. 从 'main' 新建分支...
- 作用:基于当前
main分支的最新提交,创建一个新的本地分支(例如feature-xxx)。新分支与main指向同一个提交,之后你可以在新分支上开发,不影响main。 - 典型场景:开始开发一个新功能或修复 bug,需要从稳定的主分支分叉出去。
2. 显示与工作树的差异
- “工作树” 是指你当前尚未提交的文件改动(包括已修改、已暂存或新增但未 add 的文件)。
- 作用:对比
main分支最新提交的内容 与 当前工作目录中未提交的内容 之间的差异。
注意: 这不是与“主分支”的差异(主分支就是main自己),而是与你本地未提交的改动的差异。 - 通俗理解:看看你在
main分支上改了哪些东西但还没提交。
3. 更新
- 作用:从远程仓库(这里远程仓库是
SmartCourse-Al-Platform)拉取main分支的最新提交,并合并到你的本地main分支。
本质上相当于依次执行:bashgit fetch SmartCourse-Al-Platform main # 下载远程最新提交到本地远程跟踪分支 git merge SmartCourse-Al-Platform/main # 合并到当前本地 main - 如果本地有未推送的提交,更新可能会产生合并提交或冲突。如果只想下载而不合并,应该用
fetch,但这里的“更新”通常是pull(fetch + merge)。
4. 推送...
- 作用:将你本地
main分支上的所有本地提交上传到远程仓库SmartCourse-Al-Platform的main分支。 - 注意:如果远程分支有本地没有的新提交(即远程领先于本地),推送会被拒绝,需要先执行“更新”拉取并合并/解决冲突。
5. 跟踪分支 'SmartCourse-Al-Platform/main'
作用:设置本地
main分支跟踪远程分支SmartCourse-Al-Platform/main。
跟踪关系意味着:- 当你在
main分支上执行git pull(无参数)时,会自动从该远程分支拉取并合并。 - 执行
git push(无参数)时,会自动推送到该远程分支。
- 当你在
什么时候需要手动设置:如果你用
git branch创建了一个新分支,但没有指定--track,或者本地分支名称与远程分支名称不同,就需要手动建立跟踪。通常git clone时,本地的main会自动跟踪远程的main。跟踪分支(tracking branch)并不会让本地分支自动拉取远程的变动。它只是建立了关联关系,让你在执行某些 Git 命令时可以省略参数。
具体来说:
当你设置了跟踪关系后(例如本地
main跟踪远程origin/main):- 直接执行
git pull(不带参数):Git 就知道要从origin/main拉取并合并到当前分支。 - 直接执行
git push(不带参数):Git 就知道要推送到origin/main。 - 执行
git status时,会提示你本地分支领先或落后远程多少提交。
- 直接执行
但远程发生变动时,本地并不会自动拉取。 你仍然需要手动执行
git fetch或git pull来获取远程的新提交。Git 没有内置的“自动同步”功能(除非使用额外的钩子或工具)。
所以“跟踪”是一种便捷配置,不是自动化同步。
6. 重命名...
- 作用:将当前本地分支
main重命名为另一个名字(例如master或trunk)。 - 注意:重命名后,如果已经推送过原来的
main到远程,远程分支不会自动改名,你需要删除旧的远程分支并推送新的分支,或者重新设置跟踪关系。
总结对照表
| 菜单项 | 核心操作 | 改变历史? | 影响远程? |
|---|---|---|---|
| 从 'main' 新建分支... | git branch <new> | 否 | 否 |
| 显示与工作树的差异 | git diff HEAD | 否 | 否 |
| 更新 | git pull(fetch+merge) | 可能产生合并提交 | 只拉取 |
| 推送... | git push | 否 | 上传本地提交 |
| 跟踪分支 '...' | git branch --set-upstream-to | 否 | 仅设置关联 |
| 重命名... | git branch -m <new> | 是(本地分支名) | 不影响远程内容 |
希望这能帮你理解这些选项的作用。如果还有疑问,欢迎继续追问。