GIT——一个我一直也没有仔细学过的软件
笔记基于Git - Book,只记录原理,不会事无巨细的记录每一个命令的语法格式。
基础#
版本控制#
版本控制所做的就是记录代码随时间推移的每个版本,然后,我们可以在需要的时候退回到某个版本(比如新版本中的某些修改导致了安全风险),对比版本间的差异等等。
构建代码仓库#
❯ mkdir gitlearn && cd gitlearn
❯ git init
Initialized empty Git repository in /home/yudoge/tmp/gitlearn/.git/
untrackted 未跟踪文件#
Git会记录文件是否被改变,不过前提是你得指定该文件被GIT所跟踪,当你在一个Git项目下创建一个文件时,Git并不会记录该文件的任何信息,比如它是否被修改等。git status
会列除这些未被跟踪的文件,并告诉你git add
命令可以开始跟踪它们。
再运行status
,这个文件已经不是未跟踪的状态了
to be comiited 待提交文件#
当你使用git add
跟踪一个文件,代表这个文件将被git纳入版本控制的范畴。实际上,它存在于一个暂存区中。为什么要有一个暂存区?
想象我们正在写一个发送邮件的功能,我们会为实现这一功能创建很多个文件,并且为了将它们纳入GIT的控制范围以获得一些GIT独有的能力(比如代码写乱了可以复原成开始跟踪它之初的样子),我们会使用git add
将这些文件放入暂存区(也就是开始跟踪)。但我们并不希望GIT将我们的每一次add
都记录成为一个代码版本,而是这个功能开发完成才记录一个版本。所以暂存区就出现了。
git add
会将我们的文件放到暂存区中,当我们觉得暂存区中累计的开发进度已经可以使得代码推进到下一个版本了,那么才将它们通过git commit
提交成一个版本。
暂存区文件操作#
暂存区可以看作是距离上次提交的版本之间所做的累计修改,并且它们会被提交到下个版本中。那么使用暂存区可以获得GIT的哪方面加持呢?
修改已经添加到暂存区的文件,添加一个新行:
❯ vim hello.py
print("Hello, GIT project!")
print("NEW LINE!")
查看仓库状态,我们可以看到,hello.py
同时存在于改动待提交(Changes to be commited)和改动未暂存的(Changes not staged for commit)两个栏目中。因为暂存区里有之前的hello.py
,它可以被提交,而现在GIT又跟踪到暂存区外的hello.py
被改动了,和暂存区不一样,如果你现在执行git commit
那么新的改动不会被提交,所以它在两个栏目中。
使用git diff
还可以查看改动的位置
如果你希望提交的版本包含NEW LINE
那行修改,那么可以再次git add hello.py
,将这次改动存储到暂存区中。这里使用了git status -s
查看精简的状态信息,A
代表暂存区中有该文件,M
代表当前文件和暂存区内的有差异。
可以通过git reset HEAD <file>
来取消暂存的文件(将文件从暂存区移除)。
可以通过git checkout -- <file>
取消该文件上次暂存到现在所做的修改,即还原到暂存区中的样子。实际上这个命令有些hack,它是通过切换分支会丢失未提交文件的原理实现的。后面会说到工作区。
提交#
使用git commit
命令提交暂存区中的修改,该命令会推进代码库的版本。-m
是此次提交的说明,用于说明该版本主要做了什么工作,比如修复了上个版本的哪些bug,添加了什么功能。
使用git log
命令可以看到当前代码库的版本。
分支#
分支是版本控制工具的精髓。
我们日常的代码仓库中至少应该有两条分支,第一条是master
主分支,它是项目能够稳定运行的版本,不应该轻易改动,而再有一个就是development
分支,添加新功能在这个分支中添加,当新功能测试通过准备上线时,将development
分支合并到master
分支,可以理解为让进度被甩在后面的master
分支追上development
。
下图中的testing
你可以理解为development
,它在master
的前面开发新功能,等到它完毕,master
会请求与它合并并追上它的进度。
分支基础——Git如何管理文件#
GIT会将每一个暂存的待提交文件存储为一个blob
对象,该对象除了存储文件本身外,还存储了该文件的校验和(SHA1)。下图是一个README文件的blob对象。
暂存区中只存储文件的校验和。
当GIT进行提交时,先会计算每个子目录和子文件的校验和,然后保存为一个树对象。如下是包含三个文件的一个树对象。
提交时会产生一个代码库的版本,这个版本被记录在一个提交对象中,这个提交对象指向了上面所创建的树对象,它具有自己的校验和和提交详情。
最后,整个提交过程产生了这样的结构:
所以,提交对象指向提交时创建的树对象,树对象指向暂存时创建的blob对象。
由于GIT需要记录代码库的提交历史,所以每一次提交(除了首次提交)都有一个父提交对象,父提交对象就是该次提交的上一次提交,如果你没有其它分支,那么所有提交对象会连成一个链表。
可以清楚的知道版本之间的演进记录。
那分支是啥啊#
上面我们了解了提交历史在GIT中怎么记录,那分支怎么记录??假设现在我们已经提交了两次,有了两个版本,当你使用git log
时,你就会发现第二个版本上有(HEAD -> master)
这个标记
先来解释master
,这是创建git仓库的默认分支,分支指向所有版本中的一个,代表当前该分支所处的开发进度,从上面的讲解中大家也知道了分支就是为了在一个项目中提供几个不同的开发进度的能力(比如稳定版和开发版)。
HEAD
则是一个指针,它的作用很简单,指向你现在处于哪个分支中。
当你使用git branch testing
创建了一个名为testing
的分支后,GIT中具有这样的结构:
master
和testing
在一个版本上,但当前还在master
分支,并没自动切换到testing
。
推进testing分支!#
使用git checkout
切换分支,可以看到现在HEAD
已经指向testing
了,我们再做的任何提交操作都是testing
在提交,master
不会向前推进。
❯ git checkout testing
Switched to branch 'testing'
❯ git log
commit e3d35b798297c91991caed4c9873702d30fe1d74 (HEAD -> testing, master)
Author: yhn <1355265122@qq.com>
Date: Fri Apr 29 11:11:32 2022 +0800
SECOND COMMIT
commit 11579eabf1a5e34d33ba6b6258c0889d314474af
Author: yhn <1355265122@qq.com>
Date: Fri Apr 29 11:11:10 2022 +0800
FIRST COMMIT
~
git checkout -b <branchname>
可以切换到一个分支,如果分支不存在就创建。
使用testing
分支提交一个新版本,可以看到testing
分支的进度已经超过了master
分支:
让master追上进度#
假设testing
中在做一些新功能,这次提交后,它做完了这个功能并且测试显示一切都很稳定,那么是时侯让master
追上testing
的进度了。git merge
命令可以合并分支,将testing
中的修改合并到master
现在,master
已经跟上了testing
的进度
多分支操作#
假设你依旧在testing
上做一些新功能,使用git log --oneline --decorate --graph
查看当前的分支情况。
这时来了个突发状况,你必须去处理当前稳定版本中紧急发生的BUG。你需要先切换到稳定版本,并从稳定版本的代码位置切出一个新的分支hotfix
来处理这个BUG。
从testing
分支的角度来看,现在仓库中的分支情况如下,testing
做了新的改动,但还没与master
合并,hotfix
和master
在同等位置,并且一会儿它要修改之前的bug。
hotfix
修改了之前的BUG并提交了一个自己的版本,现在版本库中不是一个简单的链表了,已经产生了两路分叉。master
较为靠后,testing
和hotfix
较为靠前并且它们都是从master
衍生的,但它们的新增或修改的代码之间并没有什么联系。如下图,假设最下面的C3是testing
分支。
现在,master
可以轻易的与两个分支中的任何一个合并,因为这只需要将master
指针移动即可,因为这两个分支都是由master
衍生出来的。这种合并叫快进(fastforward)。
现在我们决定先将master
快进到hotfix
来解决燃眉之急,你也可以反着来。
现在通过向git log
中添加--all
选项,能看到整个版本链的情况,否则你看不到分支之间的情况。可以看到master
被快进到了hotfix
分支,但目前的testing
分支已经不是由现在的master
直接衍生的了,显然它们之间的合并要麻烦点。
由于hotfix
已经没用,先删除。
我们尝试运行一下git merge testing
,看看会出现什么情况。第一次是发生了冲突,这是因为之前的hotfix
和我们的testing
都改动了hello.py
的同一行,GIT不知道应该留哪个。
但在正常情况下,hotfix
和testing
所改动的不太可能一样。
当你打开hello.py
时,你会看到git帮你标注了哪里冲突了
这里我们决定将Add in testing branch
这句删除,然后git add hello.py
,git commit
已经成功,这次的合并不是简单的快进,而是一种三方合并,GIT会尝试将两个分支的内容进行整合,如果遇到冲突就提示你修复冲突。
现在我们可以把testing
分支删除了
git branch -d testing
作者:Yudoge
出处:https://www.cnblogs.com/lilpig/p/16206107.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
欢迎按协议规定转载,方便的话,发个站内信给我嗷~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)