Git:git深入理解及常见问题

需要深入理解的内容

一、git本地仓库

下面是Git本地仓库目录结构

.git/

├── objects/ # 对象存储目录

├── refs/

│ ├── heads/ # 本地分支

│ │ ├── main

│ │ └── feature

│ ├── remotes/ # 远程跟踪分支

│ │ └── origin/

│ │ ├── main

│ │ └── dev

│ └── tags/ # 标签

└── index # 暂存区

1、 暂存区 (staging Area / Index)

对应.git/index文件(一个二进制文件),记录了文件的路径、权限、以及指向对象存储区中对应blob 对象的哈希值

记录了即将提交的文件快照的元数据,包括:

文件名

文件模式(权限)

文件内容的SHA-1哈希值(指向.git/bject/中的,blob对象)

文件时间戳等缓存信息(用于性能优化)

列出暂存区中的所有文件及其状态

git ls-files --stage

查看暂存区与工作区的差异

git status

2、对象存储目录

对应.git/objects/,存放所有 Git 对象 (blob、tree、commit、tag)。

(1) 提交对象 (commit):记录作者、时间、提交信息,以及指向树对象的指针。

(2) 树对象 (tree):记录目录结构和文件列表,每个文件对应一个数据对象。

(3) 数据对象 (blob):存储文件的具体内容。

当执行 git add 时,Git 会将文件内容压缩成一个 blob 对象,并存入 .git/objects/ 中,同时更新 .git/index 文件(暂存区)来指向这个新对象

当执行 git commit 时,Git 会创建 tree 对象和 commit 对象,也存入 .git/objects/。

查看对象存储区内容

git rev-list --objects --all

3、远程跟踪分支 (Remote-tracking branches)

存储路径:.git/refs/remotes/<远程仓库名>/<分支名>

例如,远程仓库名为 origin,分支名为 main,则存储在:

.git/refs/remotes/origin/main

作用:记录远程仓库中对应分支的最新提交哈希值,用于跟踪远程仓库的状态。

特点:

只读 (不能直接通过 git checkout 切换并修改)。

通过 git fetch 或 git pull 自动更新。

属于本地仓库的一部分,但不会影响工作区。

4、本地分支 (Local branches)

存储路径:.git/refs/heads/<分支名>

例如,当前工作分支名为 main,则存储在:

.git/refs/heads/main

作用:记录本地分支的最新提交哈希值,指向通过 git commit 创建的本地提交。简单来说,本地分支是指向对象存储中某个提交对象的指针。

当切换到某个分支时,Git 会读取该分支指向的提交对象,然后递归地找到对应的树对象和数据对象,最终将文件内容还原到工作区。

特点:

可读写(可以通过 git checkout、git merge 等操作修改)。

通过 git commit、git merge、git rebase 等命令更新。

与工作区直接关联(git checkout 切换分支时,工作区文件会同步更新)。

二、git 中 revert、 restore、 reset、 rebase 的详细用法介绍

1、revert、 restore、 reset、 rebase的主要区别

git revert

操作内容:撤销某次提交的更改,并创建一个新的提交

作用范围:工作区、暂存区、历史记录

是否危险:否(安全)

使用场景:撤销已推送到远程仓库的错误提交。

git restore

操作内容:恢复工作区或暂存区的文件到某个历史状态

作用范围:工作区、暂存区

是否危险:否(安全)

使用场景:放弃工作区的修改,或从暂存区取消暂存文件。

git reset

操作内容:将当前分支的 HEAD 指针移动到指定的提交,并可选择地重置暂存区和工作区

作用范围:历史记录、暂存区、工作区

是否危险:是(危险)

使用场景:撤销本地的、尚未推送的提交,或彻底清理工作区。

git rebase

操作内容:将一个分支的提交"移植"到另一个分支的顶端,或合并/修改历史提交

作用范围:历史记录

是否危险:是(危险)

使用场景:保持线性历史,合并分支前整理提交,或修改最近的提交信息。

2、revert、 restore、 reset、 rebase的各自用法介绍

2.1、git revert (安全撤销)

核心思想:

创建一个新的提交来抵消之前某个提交的更改。它不会删除或修改历史记录中的任何提交,因此是最安全的撤销方式,尤其适用于已经推送到远程仓库的提交。

用法:

撤销指定的单个提交

git revert <commit-hash>

撤销一系列连续的提交(会为每个提交创建一个新的 revert 提交)

git revert <oldest-commit-hash>..<newest-commit-hash>

撤销提交,但不自动创建新的提交(用于手动合并多个 revert 提交)

git revert -n <commit-hash>

示例:

假设提交历史为 A -> B -> C -> D,你想撤销提交 B。

git revert B

执行后,历史变为 A -> B -> C -> D -> E,其中 E 是一个新的提交,其内容与 B 提交的更改完全相反。

2.2、git restore (文件级恢复)

核心思想:

专注于文件级别的操作,用于恢复工作区或暂存区中的文件到某个状态。它不操作提交历史,因此非常安全。

用法:

1. 恢复工作区的文件到暂存区(或 HEAD)的状态(放弃工作区的修改)

git restore <file-name>

2. 恢复工作区的文件到指定提交的状态

git restore --source=<commit-hash> <file-name>

3. 将暂存区的文件取消暂存(恢复到工作区)

git restore --staged <file-name>

4. 同时恢复暂存区和工作区到 HEAD 的状态

git restore --source=HEAD --staged --worktree <file-name>

示例:

修改了 index.html,但想放弃修改:git restore index.html

执行了 git add index.html,但想取消暂存:git restore --staged index.html

2.3、git reset (指针移动与状态重置)

核心思想:

将当前分支的 HEAD 指针移动到指定的提交,并可选择地重置暂存区和工作区。它会重写历史,因此非常危险,通常只用于本地未推送的分支。

用法:

模式一:--soft (最温和) # 移动 HEAD 指针,暂存区和工作区保持不变

git reset --soft <commit-hash>

模式二:--mixed (默认模式) # 移动 HEAD 指针,并重置暂存区,但工作区保持不变

git reset --mixed <commit-hash>

模式三:--hard (最危险) # 移动 HEAD 指针,并重置暂存区和工作区,所有未提交的更改都将丢失

git reset --hard <commit-hash>

示例:

假设提交历史为 A -> B -> C -> D,当前 HEAD 在 D。

git reset --soft B:HEAD 指针移动,暂存区和工作区仍包含 C 和 D 的更改。你可以重新提交它们。

git reset --mixed B:HEAD 指针移动,暂存区被清空,但工作区仍包含 C 和 D 的更改(显示为未暂存的修改)。

git reset --hard B:HEAD 指针移动,暂存区和工作区都被重置为 B 的状态。C 和 D 的更改以及所有未提交的修改将永久丢失。

2.4、git rebase (变基与历史整理)

核心思想:

将一个分支上的所有提交"移植"到另一个分支的顶端,或者交互式地修改、合并、删除历史提交。

它会重写历史,因此非常危险,主要用于本地分支或团队约定好的协作流程中。

用法:

(1)将当前分支变基到目标分支的顶端

git rebase <target-branch>

(2)交互式变基,用于修改最近的 N 个提交

git rebase -i HEAD~N

交互式变基 (-i) 是最强大的功能,它允许你对提交执行以下操作:

pick: 使用该提交

reword: 修改提交信息

edit: 修改提交内容

squash: 将该提交合并到上一个提交中

fixup: 类似 squash,但丢弃该提交的提交信息

drop: 删除该提交

示例:

假设你在 feature 分支上开发,main 分支有了新的提交。你想让 feature 分支的历史看起来像是在最新的 main 上开发的。

git checkout feature

git rebase main

这会将 feature 分支上所有与 main 分支不同的提交,依次应用到 main 分支的最新提交之上。

三、git 中Cherry Pick介绍

Cherry Pick 是 git 中的一个非常有用的命令,用于将某个分支上的一个或多个特定提交(commit)复制到当前分支。它允许你只选择性地合并某些提交,而不是合并整个分支。

选择性合并

当你不想合并整个分支(例如,该分支包含未完成的或不需要的功能),但需要其中的某个特定提交(比如一个重要的 bug 修复)时,可以使用 Cherry Pick。

修复移植:在维护多个版本(如发布版和开发版)时,将一个分支上的修复补丁应用到另一个分支。

基本用法

git cherry-pick commit-hash>

<commit-hash>:你想要复制的提交的哈希值(可以通过 git log 查看)。

示例场景

假设有两个分支:main(主分支)和 feature(功能分支)。

在 feature 分支上,提交了一个重要的 bug 修复,哈希值为 a1b2c3d。

当前在 main 分支上,但不想合并整个 feature 分支(因为还有其他未完成的功能)。

执行命令:

git checkout main git cherry-pick a1b2c3d

现在,main 分支上就有了 feature 分支中那个特定的 bug 修复提交,而其他提交不会被合并。

注意事项

冲突处理:如果被复制的提交与当前分支的代码有冲突,Git 会暂停并提示手动解决冲突。解决后,使用 git cherry-pick --continue 继续,或使用 git cherry-pick --abort 取消操作。

提交信息:Cherry Pick 会保留原提交的提交信息,但会生成一个新的提交哈希值(因为提交的上下文不同)。

避免滥用:频繁使用 Cherry Pick 可能导致分支历史变得混乱,增加后续合并的复杂性。通常建议在确实需要"精准移植"时使用。

常用选项

git cherry-pick -n:只应用更改到工作区,但不自动创建新提交(方便你修改后再提交)。

git cherry-pick <start-commit>..<end-commit>:复制一个范围内的多个连续提交

(注意:范围是左开右闭,即不包含 start-commit)。

git cherry-pick -m 1 <merge-commit>:当需要 Cherry Pick 一个合并提交时,使用 -m 指定父提交编号(通常为 1 表示主分支)。

四、git 中cherry pick与merge的区别

git merge

■目的

将整个分支的完整历史记录和所有更改合并到当前分支。

■作用范围

分支级别。它关注的是两个分支之间的差异和共同祖先。

■典型场景

功能开发完成后,将 feature 分支合并回 main 分支;定期同步主分支的更新到开发分支。

git cherry-pick

■目的

将一个或多个特定的提交(commit)复制到当前分支。

■作用范围

提交级别。它只关注你指定的那一个或几个提交。

■典型场景

紧急修复一个 Bug,只想把修复提交从 dev 分支移植到 release 分支,而不想引入 dev 上的其他未完成

常见问题

一、git reset --hard origin/develop中origin/develop指的是远程develop分支吗?

origin/develop 在 Git 中指的是本地存储的远程跟踪分支(remote-tracking branch),而不是直接操作远程仓库上的 develop 分支。

git reset --hard origin/develop 的作用:

这条命令将当前本地分支的 HEAD 指针重置到 origin/develop 指向的提交,并强制更新工作目录和暂存区。

它不会对远程仓库的 develop 分支做任何修改。

二、git fetch origin develop 为什么不写成 git fetch origin/develop ? git reset --hard origin/develop为什么不写成 git fetch origin develop ?

核心原因:git fetch 的参数是"源"和"目标",而 git reset 的参数是"引用"

1、git fetch 的语法

git fetch <远程仓库名> <远程分支名>

第一个参数:远程仓库的名称(如 origin),告诉 Git 去哪个远程服务器拉取数据。

第二个参数:远程仓库上的分支名(如 develop),告诉 Git 只拉取该分支的最新数据。

结果:Git 会连接到远程服务器,下载 develop 分支的新提交,然后更新本地的远程跟踪分支 origin/develop。

2、git reset 的语法

git reset <提交引用>

参数:一个本地可访问的提交引用,可以是哈希值、分支名、标签,或者远程跟踪分支(如 origin/develop)。

结果:Git 直接读取本地存储的 origin/develop 这个引用指向的提交,然后移动当前本地分支的 HEAD。

三、本地分支和标签是什么关系?

1、分支(Branch)

动态指针:每次提交后,分支指针自动前移到最新提交。

可变性:可以 reset、rebase、merge 等操作改变其指向。

典型用途:

●开发新功能(feature-x)

●修复 bug(bugfix-y)

●实验性开发(experiment)

示例:

git switch -c feature-login # 创建并切换

git commit -m "Add login" # 分支自动前移

git commit -m "Fix login" # 继续前移

2、标签(Tag)

静态指针:创建后永远指向同一个提交,不会随新提交移动。

不可变性:默认不可修改(除非使用 -f 强制移动)。

典型用途:

●标记发布版本(v1.0.0、v2.3.1)

●标记重要里程碑(release-candidate)

●标记历史关键点(before-refactor)

示例:

git tag v1.0.0 # 创建轻量标签

git tag -a v1.0.0 -m "Release 1.0" # 创建附注标签

git checkout v1.0.0 # 切换到标签(分离头指针)

3、共同点

都指向某个提交(commit)。

都可以通过 git checkout 或 git switch 检出(但标签检出会进入分离头指针状态)。

都可以推送到远程仓库(git push origin <branch> 或 git push origin <tag>)。

4、不同点

创建

分支:git branch <name>

标签:git tag <name>

删除

分支:git branch -d <name>

标签:git tag -d <name>

推送

分支:git push origin <name>

标签:git push origin <name>

查看

分支:git branch

标签:git tag

移动

分支:自动随提交移动

标签:固定不动(除非强制)

四、在 IntelliJIDEA中,Git 的Rollback功能通常对应的是什么Git 命令

1.在 Local Changes(本地更改)视图中

场景: 修改了某个文件,但还没有git add(未暂存)

IDEA操作: 右键点击文件 -> Rollback。

对应的 Git命令:

git checkout <file>

或

(Git 2.23+推荐)

git restore <file>

效果: 撒销工作区中对该文件的修改,恢复到最近一次提交的状态

2.在commit视图中(已git add但未提交)

场景: 已经 git add了某个文件(暂存区有更改),但尚未提交

IDEA操作: 在 Commit 窗口的 changes列表中,右键点击文件 -> Rollback

对应的 Git 命令:

git reset HEAD <file>

或

(Git2.23+推荐)

git restore --staged <file>

效果: 将文件从暂存区移出,但保留工作区的修改(即文件内容不会变,只是不再处于暂存状态)。

3.在Git Log(版本历史)视图中

场景: 想撤销某次已经提交的更改(例如最近一次提交)

IDEA操作: 右键点某次提交 -> Undo Commit或Revert Commit

Undo Commit: 相当于git reset --soft HEAD~1(保留更改,但撤销提交)

Revert Commit: 相当于 git revert <commit-hash> (创建一个新的反向提交)

注意: IDEA中没有直接叫 Rollback 的按钮来撒销已提交的更改,而是用Undo Commit或Revert Comit来实现.

相关推荐
蹊黎3 小时前
Git 从入门到精通(二):创建本地仓库与三大核心区域
git
蹊黎5 小时前
Git 从入门到精通(一):初识 Git 与环境搭建
git
゛凌乱的记忆づ1 天前
好用的md文件编辑器——TyporaS与Typora
笔记·git·typora·markdown
এ慕ོ冬℘゜1 天前
Git 基础规范:小步提交、提交信息规范与常用命令
git·svn
忘了ʷºᵇₐ1 天前
Git学习笔记
笔记·git·学习
BIBI20492 天前
换 Git 托管平台怎么做?基于 TortoiseGit 的跨平台迁移教程
windows·git·tortoisegit·问题解决·版本控制·最佳实践
echome8882 天前
Git 日常救急:撤销提交、找回误删文件和解决冲突
git·版本控制
赵民勇2 天前
Git命令详解
git
不老刘3 天前
Antigravity 的 New Worktree 模式:给 AI 代理一个安全的“平行工位”
人工智能·git·ai编程·antigravity