git fetch
origin/main
),不会改变你当前的工作状态。举例:
git fetch origin
这个命令会从远程仓库 origin
拉取所有更新,但不会改变你当前分支的代码。
远程 origin/main:
A --- B --- C --- R1 --- R2
本地 main:
A --- B --- C --- L1
远程追踪分支 origin/main: 指向 R2
git pull
git fetch
,再执行
git merge
,会把远程仓库最新的代码拉取并合并到你当前分支。举例:
git pull origin main
从远程 origin
的 main
分支拉取代码并合并到当前分支。
L1
|
A --- B --- C --- R1 --- R2
\ /
--- M (合并提交)
本地 main HEAD -> M
git rebase
举例:
git fetch origin
git rebase origin/main
先抓取远程最新代码,然后把当前分支的修改,放到
origin/main
最新提交之后,相当于“更新基础”了。
远程 origin/main:
A --- B --- C --- R1 --- R2
本地 main:
A --- B --- C --- R1 --- R2 --- L1'
但是你本地的提交可能与远程提交的R1 R2有冲突,但一般只有在极少数冲突情况下需要手动解决
如果你的提交和远程提交修改了同一个地方,rebase 会提示冲突,需要你手动解决冲突。
解决完冲突后,继续执行 git rebase –continue,完成变基。
总结对比:
命令 | 作用 | 是否合并到当前分支 | 是否产生合并提交 | 适用场景 |
---|---|---|---|---|
git fetch |
拉取远程最新代码,不改变本地代码 | 否 | 否 | 查看远程更新,准备后续操作 |
git pull |
拉取并合并远程代码到当前分支 | 是 | 可能 | 快速同步远程最新代码 |
git rebase |
变基,把当前分支基于另一个分支更新 | 是 | 否 | 保持提交历史整洁,线性化代码历史 |
好的!我用一个具体的模拟例子,用命令行交互的形式,演示
git fetch
、git pull
和 git rebase
的典型流程和效果。方便你更直观理解。
场景假设
origin/main
有新提交。main
有自己的提交(本地改动)。# 本地仓库
git log --oneline
# 输出:
C (HEAD -> main) 本地提交L1
B
A
# 远程仓库 origin/main 最新提交比本地多两个
# 远程代码比本地多了 R1 和 R2 两个提交
# 远程分支状态(假设你本地未同步):
origin/main:
E (R2)
D (R1)
B
A
git fetch
git fetch origin
# fetch 只是更新远程追踪分支,不影响本地 main
git log origin/main --oneline
# 输出:
E (origin/main)
D
B
A
git log main --oneline
# 输出:
C (main)
B
A
说明:origin/main
更新了远程最新提交,main
还是原来的状态。
git pull
git pull origin main
# 实际等于 fetch + merge,合并远程 main 到本地 main
# 可能会生成一个新的合并提交 M
git log --oneline
# 输出:
M (HEAD -> main) 合并提交
C (本地提交)
E (origin/main)
D
B
A
说明:main
分支包含了远程最新提交和本地提交,并生成了一个合并提交
M
。
git fetch
+ git rebase
先 fetch:
git fetch origin
然后 rebase:
git rebase origin/main
# git 会把本地提交 C(L1)暂存起来,把 main 基底切换到 origin/main 最新提交 E
# 然后把 C 重新应用到 E 之后
git log --oneline
# 输出:
C' (HEAD -> main) 变基后的本地提交(内容同C)
E (origin/main)
D
B
A
说明:
git rebase origin/main
# 途中如果出现冲突,Git 会提示:
CONFLICT (content): Merge conflict in file.txt
# 需要手动解决冲突,编辑冲突文件
# 解决完后:
git add file.txt
git rebase --continue
# 继续变基直到完成
如果本地没有commit 然后 git fetch新内容后,执行git rebase会提示
root@ser745692301841:/dev_dir/note# git rebase
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.
这个错误的意思是:
你当前工作区有 未暂存(unstaged)的修改,Git
为了防止这些改动丢失或冲突,不允许你直接执行
git rebase
。
解决方法有两个:
git add .
git commit -m "保存当前修改,准备rebase"
git rebase ...
git stash save "临时保存修改,准备rebase"
git rebase ...
git stash pop # rebase完成后恢复修改
为什么要这样?
git rebase
会移动你的提交,如果工作区有未保存的修改,会导致代码冲突或丢失。root@ser745692301841:/dev_dir/note# git rebase
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.
root@ser745692301841:/dev_dir/note# git stash save "临时保存修改,准备rebase"
Saved working directory and index state On main: 临时保存修改,准备rebase
root@ser745692301841:/dev_dir/note# git rebase origin/main
Successfully rebased and updated refs/heads/main.
root@ser745692301841:/dev_dir/note# git stash pop
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: convert_md_to_html.sh
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (f869fb6c69bad5bec7aa96ed8401bb9c3a297c7d)
root@ser745692301841:/dev_dir/note# git log --oneline
04a4909 (HEAD -> main, origin/main, origin/HEAD) feat: version control tool
f8cb14e update: 目录整理
4b9fccb feat: 必知必会 整理目录
给你详细解释一下 git stash save
和
git stash pop
在 Git 背后做了什么。
git stash save "说明信息"
这个命令的作用是:
具体背后发生的事:
Git 会创建两个临时提交对象:
git add
的部分)把这两个提交压入一个栈(stash列表),栈顶就是最新的 stash。
工作目录和暂存区会被恢复成最近一次提交(HEAD)的状态,相当于“干净工作区”。
这个 stash 会带有你提供的说明信息,方便以后查看。
git stash pop
这个命令的作用是:
背后发生的事:
git apply
或 git merge
的方式)。命令 | 背后原理 | 作用 |
---|---|---|
git stash save |
创建临时提交,把修改存到 stash 栈顶 | 保存当前改动,恢复干净工作区 |
git stash pop |
取出 stash 栈顶提交,应用到工作区 | 恢复之前保存的修改,并从 stash 中删除 |
git stash list
查看当前所有的 stash。git stash apply
也能恢复 stash,但不会删除
stash。