Git基本操作
Git仓库创建
Git仓库的基本认知
Git仓库就是一个用来跟踪和管理项目文件变化的地方,其记录了所有的修改历史,可以回退到之前的任何一个历史版本
- 工作区:正在进行实际操作的文件夹
- 暂存区:临时保存想要提交修改的区域
- 版本库:保存所有的提交历史记录
初始化本地的仓库
- 首先创建一个文件夹,然后git init 即可
远程克隆仓库
git clone (项目地址)
Git配置
设置与删除用户名和邮箱
//配置创建命令
git config [--global] user.name " name "
git config [--global] user.email " email"
//配置删除命令
git config [--global] --unset user.name
git config [--global] --unset user.email
查看配置命令
git config --list
配置文件的用途
- 全局配置文件:
~/.gitconfig
- 仓库级配置文件:
your_project/.git/config
配置默认的文本编辑器
// 默认vscode
git config --global core.editor "code --wait"
// 默认vim
git config --global core.editor "vim"
工作区-暂存区-版本库
查看文件状态
git status
git status比较工作区、暂存区与版本库中的文件,显示哪些文件被修改、哪些文件已经暂时存储、哪些文件未跟踪
文件添加到暂存区
git add filename
//添加所有修改
git add .
- 该命令会将工作区中的修改记录到索引中,为下一次提交做准备。Git会计算文件的内容,并将其存储为Blob对象,然后更新索引中的指针
提交暂存区的文件到版本库
git commit -m "提交信息"
- 创建提交对象:git commit会将索引中的内容创建一个新的提交对象(Commit Object),其中包含指向树对象(Tree Object)的指针、提交信息、作者信息等
- 链式结构:每个提交对象包含指向其父提交的引用,形成一个链式的提交记录
- 快照存储:每次提交的时候都会记录项目的当前状态,也就是快照。Git使用高效的压缩和存储机制来避免重复存储未修改的文件
完整尝试(提交README.md文件)
注意文件的提交是必须通过add commit来提交的,不可以直接将文件拖拽到.git文件夹中
打印所有提交记录
git log
.git文件夹查询
文件夹内容以及原理理解
.git文件夹是Git仓库的核心,其中包含所有的版本控制数据,其中有版本控制的核心数据,以及分布式存储系统
- 核心数据存储:文件夹中包含有Git运行所需要的所有数据,包含对象数据库(Object)、引用(refs)、配置文件(config)等
- 分布式存储:因为Git是分布式,.git文件夹使得每个本地仓库都可以独立的管理和存储项目的完整历史,无需依赖于远程服务器
.git文件夹中的主要内容
- HEAD:指向当前分支的引用
- 本质是一个指针,指向当前检出的分支,其决定了当前工作区的内容和后续提交的基准
- config:仓库的配置信息
- objects:存储所有的数据对象
- Blob:存储文件的内容
- Tree:表示目录结构,包含文件和子目录的引用
- Commit:记录一次提交的元数据,包含指向树对象的指针、作者信息、提交信息以及父提交引用
- refs:用于管理分支和标签,指向具体的提交对象
修改文件
添加和提交修改
git add filename
git commit -m "描述你的修改"
实现分析
- git add会将修改记录到索引上,然后git commit将索引中的内容创建为一个新的提交对象
- 每次提交都会创建一个的新的Blob和Tree对象,Git会通过这些管理文件的内容和目录结构的变化
修改实践
查看暂存区中是否发生了变化
git diff --cached
版本回退
查看提交历史
git log 会显示提交历史,按照时间顺序列出每个提交的哈希值、作者、日志和提交信息,每个提交信息对象又会指向其父提交的引用,从而形成一个链式结构
Git底层通过遍历提交对象的父引用,从而逐步展示整个提交情况
回退到上一个版本
- 使用git reset命令,移动当前分支的HEAD指针到指定的位置,从而达到回退版本的目的
- --hard选项:使用该选项不仅会HEAD指针,还会重置暂存区和工作区,从而使得目标提交一致,这也就以为着所有未提交的修改就会被丢弃
- HEAD~1,即表示当前的前一个提交
回退到特定的提交
git reset --hard <commit-hash>
通过特定的提交哈希值,git reset可以将HEAD指针移动到该提交;注意--hard选项会强制更新工作区和暂存区,是得其目标提交一致,所有未提交的更改将被覆盖
注意--hard选项要谨慎使用,因为该选项会丢失工作区的修改
撤销修改
撤销工作区的修改
git checkout -- filename
使用该命令后,会将工作区中的文件恢复到HEAD一致状态,丢失所有未提交的修改;Git通过将文件从最新Blob对象复制到工作区,实现文件的恢复
撤销暂存区的修改
git reset HEAD filename
该命令会将暂存区中的文件恢复到与HEAD一致的状态,但是保留的工作区中的修改,这也就意味着修改不会被丢弃,只是从暂存区中移除
先将文件添加到暂存区,然后将文件移动会工作区
撤销提交
git revert <commit-hash>
该提交命令会创建一个新的提交,用于撤销指定提交,但是不会改变提交的历史,该撤销的提交是可以修改的
撤销情况1:代码未提交,工作区中书写的代码撤销
git checkout -- ReadMe
撤销情况2:工作区与暂存区都有代码情况下的撤销操作
git reset [<mode>] <commit>
<commit>
:可以是完整的提交哈希值、提交哈希的前几位、分支名、HEAD(代表当前提交),或者相对的引用(如HEAD~1
表示上一个提交,HEAD~2
表示上两个提交)。<mode>
:有三种模式:--soft
:仅回退 HEAD 指针,不改变暂存区和工作区。--mixed
(默认模式):回退 HEAD 并重置暂存区,但保留工作区的更改。--hard
:回退 HEAD,清空暂存区,并将工作区恢复到指定提交的状态,删除所有未提交的更改。
情况三:工作区、暂存区、版本库中都含有提交代码时的撤销方法
该方法实现前提是不进行Push操作
指定版本进行回退
使用HEAD
HEAD
:当前的提交点。HEAD~1
:当前提交的上一个提交(倒数第二个)。HEAD~2
:上上个提交,以此类推
删除文件
Git中删除文件并提交
git rm filename
git commit -m "删除了 filename"
Git文件移除不仅仅是从工作区中删除文件,还会将删除操作记录到暂存区中,为下一次提交做准备
删除文件的时候会导致Tree对象变化,git commit会创建一个新的提交对象,从而反映出文件删除
仅在Git中删除文件,仍然保留本地文件
git rm --cached filename
该命令会将文件从版本控制中移除,但保留在本地文件系统中;--cached选项会将文件从索引中移除,不会删除工作区中的文件,这样就实现了仅仅删除Git中该文件,但是本地任然保留该文件
分支管理
分支含义
验证master本质是一个主分支
链表连接验证
分支实现流程实践
HEAD指针指向的是当前所使用的分支
新分支是基于当前最新版本创建
切换分支
不同分支下提交内容
合并master和test两个分支
创建分支
创建分支
git branch <branch-name>
该命令只会创建新分支,并不会切换到新分支上,当前仍然停留在原来的分支
创建并切换到新分支
git checkout -b <branch-name>
从特定的提交或者分支上创建新分支
git branch <new-branch-name> <commit-hash-or-existing-branch>
切换分支
git checkout切换分支
git switch 分支名
合并分支
合并冲突问题
冲突演示
在dv1分支上修改文件内容,然后在master分支也进行修改,最后两者合并
解决冲突方法:进入文件保留自己想要的文件,然后删除自己不需要内容,最后重新提交
git log 常用参数
--graph
使用ASCII字符图形化地显示提交历史及其分支、合并关系、直观查看提交树结构
--abbrev-commit
将提交的哈希值缩短为较短的形式(下面即是与前面命令结合使用)
--reverse
以相反的顺序显示提交历史,默认git log是从最新的提交开始
合并模式
Fast forwark merge模式
快速合并就是在合并的时候,如果目标分支没有新的提交,Git不需要创建的新的合并提交,只需要将分支指针“快进”到源分支的最新提交即可。这种方法不会产生额外合并提交,保持提交历史的线性结构。
- Git 直接将当前分支的 HEAD 移动到要合并的分支的最新提交,没有产生额外的合并记录。
- 适合没有并行开发的情况。
创建dv2分支,然后修改文件内容,在master分支下合并默认的就是Fast forward提交
--no-ff合并
强制创建合并提交的方式,即使Git可以通过快速合并来完成合并,其也会强制生成一个合并提交,从而使合并后的提交历史包含一个明确的分支合并点。
- 保留合并历史:每次合并时都会生成一个新的合并提交,保留了分支的开发历史。通过合并提交,可以清楚地看到功能分支是在何时、以何种方式合并到主分支中的,便于日后追溯。
- 有助于代码审查:在大型团队协作中,生成合并提交可以让开发人员轻松追踪每个功能或修复的合并点,便于后期排查问题或审计代码历史。
- 功能分支的完整性:即使分支很小或者只有一两个提交,使用
--no-ff
合并也能保留分支的完整性,避免功能分支的历史被压平到主分支的提交历史中。
总结Git中的两个合并模式
no-ff模式
分支策略
master分支与dev分支的稳定和不稳定
- master分支:即高度稳定的分支,只有经过测试和验证的代码才会合并到这个分支,一般是当前发布版本
- dev分支:不稳定的开发分支,其中包含正在开发和测试的功能,这个分支代表了即将合并到master分支的候选代码
分支流动的基本流程
- 功能开发:开发人员从 dev 分支拉取新功能分支(
feature-branch
),在功能分支上进行开发。 - 合并到 dev:开发完成后,功能分支通过 Pull Request 合并到 dev 分支,通常经过初步测试。
- 测试和稳定:在 dev 分支中,所有新功能集成在一起,进行更大范围的集成测试和 Bug 修复。确保新功能可以稳定运行。
- 合并到 master:在所有测试通过且功能稳定的前提下,dev 分支的代码通过 Pull Request 合并到 master 分支,通常是在版本发布前完成。
合并冲突
场景复现:在dv2中修改的内容,不想影响master分支下的内容
使用stach命令,将工作区中的修改放入改文件夹里面
创建新分支,修复dv2提交的错误分支
切换到dv2分支,就爱那个stash中存储的内容进行恢复
情况一:master分支下合并dv2会发生冲突,此时在master下还需要解决冲突
解决方法:在dv2分支下合并master,然后将合并的版本在在master下合并,从而避免master的冲突
删除分支
方法总结--删除本地分支
使用场景:开发完某个功能后,你将其合并到主分支,然后可以删除这个本地的功能分支以保持分支结构的简洁
git branch -d <branch-name>
该命令的-d选项只可以删除已经合并到当前分支或者其他分支的分支。如果分支还没有合并,该命令就会发出警告,拒绝删除。
git branch -D <branch-name>
-D则是忽略分支是否合并,强制删除(下文场景演示中即是),谨慎使用该情况,因为该情况通常在分支的工作内容已经不需要或者错误创建的时候使用。
删除步骤总结
- 切换到其他分支,不可以在当前分支上删除当前分支
- 删除分支(如果强制删除则用-D)
删除远程分支
典型场景: 当你开发完某个功能,并且将其合并到主分支或其他分支后,远程的开发分支已不再需要,可以通过该命令删除远程分支,确保远程仓库的整洁
git push origin --delete <branch-name>
其中origin表示的是远程仓库的名称,使用该命令可以直接在远程仓库中删除指定分支
实现步骤
// 先删除本地分支(推荐先删除本地分支,避免不必要的冲突)
git branch -d <branch-name>
// 删除远程分支
git push origin --delete <branch-name>
直接使用git branch -d "分支名"即可删除分支,需要注意的是,不可以在当前分支下删除该分支
删除本地和远程分支后的同步
删除本地分支后(远程分支也是该方法)
如果删除本地分支后,远程仓库中该分支仍然存在,那么执行git fetch 或者git pull的时候,仍然可以看到远程的分支信息
// 清理本地远程分支引用,使其与远程仓库的实际状态保持一致
git fetch --prune
场景:master下dev3分支开发内容删除