【前端学习笔记】Git 原理及面试题
Git
- 1.Git概念
- 2.基本使用
- 3.如果提交了错误代码,如何撤销或回滚?
- 4.如果 git push 之后发现有错误,如何回滚远程仓库的提交?
- 5.Git merge 和 rebase 有什么区别?什么时候使用 rebase?
- 6.Git 合并时遇到冲突怎么办?
- 7.Git 的三种状态是什么?
- 8. Git rebase 和 Git merge 的区别?
- 9.如何还原已经 `git push` 的提交
- 10.git pull 和 git fetch 有什么区别
- 11.git reset 原理详解
- 12.git stash 详解
1.Git概念
Git 是分布式版本控制系统(DVCS)。它可以跟踪文件的更改,并允许你恢复到任何特定版本的更改。
Git 主要由以下几个区域组成:
- 工作区(Working Directory):本地目录中实际存放的文件,即你正在编辑的代码。
- 暂存区(Staging Area / Index):使用
git add
命令后,变更会进入暂存区,准备提交。 - 本地仓库(Local Repository):使用
git commit
提交代码后,变更会存入本地仓库。 - 远程仓库(Remote Repository):远程服务器上存储的 Git 仓库,如 GitHub、GitLab、Bitbucket。
下图展示了 Git 的基本数据流:
工作区 -> 暂存区 -> 本地仓库 -> 远程仓库
编辑 -> git add -> git commit -> git push
概念 | 解释 |
---|---|
仓库(Repository) | 存储项目的所有版本历史,可以是本地仓库或远程仓库(GitHub, GitLab, Gitee 等)。 |
分支(Branch) | 并行开发的方式,主分支(main 或 master)通常代表稳定版本,开发人员可创建新分支进行开发。 |
提交(Commit) | 代码变更的快照,每次提交都会生成一个唯一的 SHA-1 哈希值。 |
工作区(Working Directory) | 本地文件夹,开发者在其中进行修改。 |
暂存区(Staging Area) | git add 后的变更存储区域,提交前的准备状态。 |
本地仓库(Local Repository) | 本机上的 Git 仓库,存储提交的所有历史记录。 |
远程仓库(Remote Repository) | 远程服务器上的 Git 仓库(如 GitHub/GitLab),用于团队协作。 |
2.基本使用
- 初始化仓库
git init
- 用于在本地目录创建一个新的 Git 仓库,生成
.git
目录存放 Git 的所有版本控制信息。
- 克隆远程仓库
git clone <仓库地址>
- 查看当前 Git 状态
git status
- 作用:显示工作区的文件变更情况,如新增文件、修改文件、未提交的更改等。
- 添加文件到暂存区
git add <文件名>
- 例如:
git add index.html
- 添加所有修改的文件:
git add .
- 提交代码从暂存区到本地仓库
git commit -m "提交信息"
git commit --amend -m "修改后的提交信息"
- 查看提交记录
git log
- 作用:查看提交历史,包含提交哈希值、作者、日期、提交信息。
- 以简洁方式显示:
git log --oneline --graph --all
- 推送代码从本地仓库到远程仓库
git push origin <分支名>
- 拉取远程仓库代码
git pull origin <分支名>
git pull
=git fetch
+git merge
,即拉取代码并合并。
- 分支管理
创建新分支
git branch <分支名>
切换到某个分支
git checkout/switch <分支名>
创建并切换到新分支
git checkout/switch -b <分支名>
合并分支
git merge <分支名>
删除本地分支
git branch -d <分支名>
删除远程分支
git push origin --delete <分支名>
3.如果提交了错误代码,如何撤销或回滚?
- 仅仅修改了文件,还未 add
git checkout -- file.txt # 撤销未 add 之前的修改
- 已经 add,但还未 commit
git reset HEAD file.txt # 取消暂存
git checkout -- file.txt # 恢复到上次提交状态
- 已经 commit,但还未 push
git reset --soft HEAD~1 # 撤销 commit,保留代码
git reset --hard HEAD~1 # 彻底删除 commit 和修改
4.如果 git push 之后发现有错误,如何回滚远程仓库的提交?
- 使用 git revert(推荐,保留历史)
git revert <commit-hash> # 生成一个新的 commit,撤销错误提交
git push origin main # 推送到远程仓库]
- 使用 git reset + 强制推送(⚠️ 不推荐,历史丢失)
git reset --hard HEAD~1 # 本地回退到上一个提交
git push --force origin main # 强制覆盖远程仓库
5.Git merge 和 rebase 有什么区别?什么时候使用 rebase?
merge(合并):
- 创建一个新的合并提交
- 有合并点(merge commit)
- 推荐使用共享分支
- 可以保留分支历史
rebase(变基):
- 将新分支的提交 重新应用 到目标分支
- 提交历史更直线化
- 不推荐用于共享分支
6.Git 合并时遇到冲突怎么办?
- 拉取最新代码:
git pull origin main
- 尝试合并:
git merge feature-branch
- 使用
git status
查看冲突文件。 - 编辑冲突文件,手动修改
- 标记冲突解决:
git add file.txt
git commit -m "解决冲突"
- 推送代码:
git push origin main
7.Git 的三种状态是什么?
- 已修改(Modified):文件内容被修改,但未添加到暂存区。
- 已暂存(Staged):使用
git add
将修改放入暂存区,准备提交。使用git add
实现,git reset HEAD <文件名>
撤回 - 已提交(Committed):提交到本地仓库,版本被记录。使用
git commit
实现,使用git reset --soft HEAD^
撤回。
8. Git rebase 和 Git merge 的区别?
git merge
会创建一个新的合并提交(merge commit),历史记录有分叉。git rebase
会把当前分支的提交放到目标分支的最新提交之后,历史记录更直线化。
Git cherry-pick 是什么?
git cherry-pick <提交哈希>
- 作用:从另一个分支中挑选特定提交合并到当前分支,而不是合并整个分支。
9.如何还原已经 git push
的提交
-
git revert
用于撤销某个提交,但不会修改提交历史,而是创建一个新的提交来抵消之前的更改。git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。git log --oneline (找到要车型的commit ID git revert ID git push origin main (推送
-
git reset --hard
会直接回滚到指定的 commit,并丢弃所有之后的提交,但是需要git push --force
,如果有别人在这个提交之后,那会丢失。
git log --oneline
git reset --hard ID
git push origin main --force
-
git reset --soft
:仅撤销 commit,但保留文件变更,也就是修改commit信息或合并commit。git reset --soft HEAD~1 回退一个提交 git commit -m "修改后的提交信息" git push origin main --force
- 如果其他人已经拉取了你的提交,这样可能会导致他们的本地分支混乱,需要谨慎使用!
-
git reflog
+git reset
(找回误删的提交)
如果你误用了git reset --hard
丢失了提交,可以用git reflog
找回它。git reflog 查看所有历史操作 git reset --hard id 恢复误删的提交 git push origin main --force
-
git cherry-pick
(恢复某个被删除的 commit)**
如果你已经reset --hard
丢失了某个提交,但git reflog
还能找到它,你可以使用git cherry-pick
恢复它。git reflog git cherry-pick <commit-id> git push origin main
目标 | 推荐方式 |
---|---|
撤销一个错误的提交,但保留历史 | git revert <commit-id> ✅ |
彻底删除某个提交,不保留历史(慎用) | git reset --hard <commit-id> && git push --force ❌ |
撤销最近的提交,但保留代码 | git reset --soft HEAD~1 ✅ |
误删 commit 后恢复 | git reflog + git reset --hard <commit-id> ✅ |
恢复单个误删的 commit | git cherry-pick <commit-id> ✅ |
10.git pull 和 git fetch 有什么区别
git fetch:仅下载远程仓库的最新更新,不会自动合并到当前分支。只是下载远程的 commit 信息,不会影响你的工作区(Working Directory)或暂存区(Staging Area)。
git pull:相当于 git fetch + git merge,拉取并自动合并远程更新到当前分支。git pull 会执行 merge,可能会生成额外的 merge commit,使用git pull --rebase origin main
可以避免。
11.git reset 原理详解
git reset
的作用是在不同的 Git 版本之间移动分支指针,并可以选择是否修改暂存区(Staging Area)和工作区(Working Directory)。
- HEAD:指向当前分支的最新提交(commit)。
- 分支指针(Branch Pointer):HEAD 实际上指向的是某个分支,而分支指针指向某个 commit。
- 索引(Index 或 Staging Area):暂存区,用于存放
git add
之后但未commit
的变更。 - 工作区(Working Directory):本地文件系统中的代码,即开发者正在编辑的文件。
Git 的 reset
主要影响 HEAD 指针、索引(暂存区)和工作区,其不同模式决定了这些区域的变化。
Git reset
主要有三种模式:
模式 | 作用 | 影响 |
---|---|---|
git reset --soft | 仅移动 HEAD,不影响暂存区和工作区 | 提交记录被撤销,但变更仍然在暂存区 |
git reset --mixed (默认) | 移动 HEAD,同时清空暂存区,但不修改工作区 | 代码仍在工作区,但需要重新 git add |
git reset --hard | 移动 HEAD,并强制修改暂存区和工作区 | 代码被还原,未提交的变更会丢失 |
Git 的 reset
主要做了三件事:
- 移动 HEAD 指针 到指定的 commit。
- 更新暂存区(Index),使其与新的 HEAD 匹配。
- 更新工作区(Working Directory),可选(仅
--hard
执行)。
git reset --soft
(仅移动 HEAD,不影响暂存区和工作区):仅回退提交,代码仍在暂存区。适用于想撤销git commit
但不影响代码,准备重新提交。
git reset --soft HEAD~1
原理:
- HEAD 移动到前一个 commit(HEAD~1)
- 暂存区(index)保持不变
- 工作区(Working Directory)保持不变
git reset --mixed
(HEAD 移动,并清空暂存区,但代码保留):回退提交,并清空暂存区,代码仍在工作区。想撤销commit
,并重新git add
选择要提交的文件。
git reset --mixed HEAD~1
原理:
- HEAD 移动到前一个 commit
- 暂存区(Index)清空
- 工作区(Working Directory)不变
git reset --hard
(彻底回退 HEAD,并还原工作区):回退提交,并清空暂存区和工作区(代码被删除)。完全恢复到上一个 commit,丢弃所有未提交的代码。
git reset --hard HEAD~1
原理:
- HEAD 移动到前一个 commit
- 暂存区(Index)同步为 HEAD
- 工作区(Working Directory)同步为 HEAD
git reset
和 git checkout
的区别
对比项 | git reset | git checkout |
---|---|---|
作用 | 移动 HEAD,影响提交历史 | 切换分支或恢复文件 |
是否改变历史 | ✅ 可能改变 | ❌ 不改变 |
是否影响工作区 | --soft ❌ --hard ✅ | 可能影响 |
git reset
vs git revert
操作 | git reset | git revert |
---|---|---|
影响历史 | ✅ 可能删除提交 | ❌ 保留历史 |
是否影响远程 | ✅ 需要 push --force | ❌ 不影响远程 |
适合多人协作 | ❌ 不适合 | ✅ 推荐 |
12.git stash 详解
git stash
是 Git 提供的一个临时存储功能,它允许你保存当前的未提交更改,然后清空工作区,让你可以切换分支或执行其他操作,而不丢失当前的工作内容。
- 作用:临时存储未提交的修改,并在需要时恢复。
- 使用场景:
- 你正在修改代码,但需要切换到其他分支,而不想提交当前更改。
- 你想暂时保存工作,然后拉取最新代码再继续开发。
- 你正在修复 bug,需要临时存储当前开发进度。
- 保存当前更改**
git stash
- git stash :存储暂存区和未暂存的修改
- git stash -u:存储暂存区和未暂存和新增文件的修改。
- git stash --keep-index 仅保存未暂存且不是新增的文件的修改。
- 恢复
stash
中的更改
git stash pop
- 作用:从 stash 取出最近存储的更改,并应用到当前分支,同时删除该 stash 记录。
如果不想删除 stash
记录,而只是恢复修改:
git stash apply
- 作用:恢复
stash
存储的更改,但不删除 stash 记录。
- 查看所有
stash
记录
git stash list
- 作用:查看所有 stash 记录。
- 恢复指定
stash
记录
git stash apply stash@{1}
- 作用:恢复
stash@{1}
里的内容,但不会删除该 stash 记录。
- 删除
stash
记录
git stash drop stash@{0}
- 作用:删除
stash@{0}
记录,不影响其他 stash 记录。
删除所有 stash
记录:
git stash clear
- 作用:彻底清空所有 stash。
git stash
使用场景
场景 | 使用命令 |
---|---|
保存当前更改 | git stash |
恢复最新的 stash | git stash pop |
查看所有 stash 记录 | git stash list |
恢复指定的 stash | git stash apply stash@{1} |
删除指定 stash | git stash drop stash@{0} |
清除所有 stash | git stash clear |
保存未跟踪文件 | git stash -u |
仅 stash 暂存区的更改 | git stash --keep-index |
带描述的 stash | git stash save "修复登录 Bug" |
git stash
vs. git reset
vs. git checkout
操作 | 作用 | 是否影响提交历史 | 是否保留修改 |
---|---|---|---|
git stash | 临时存储未提交的修改 | ❌ 不影响 | ✅ 保留(可恢复) |
git reset | 撤销 commit 或暂存区修改 | ✅ 影响(会回滚 commit) | 🚫 不一定(--hard 会删除) |
git checkout | 切换分支,可能丢失未提交修改 | ❌ 不影响 | 🚫 可能丢失 |