文章目录
有自己思想,拒绝纯复制黏贴!!!
有自己思想,拒绝纯复制黏贴!!!
有自己思想,拒绝纯复制黏贴!!!
这里说个题外话,现在网上有一种现象让我深恶痛绝,就是很多网友对别人所发的博文不加验证,便进行纯复制转发,我很想知道,转发了之后意义在哪?自己都没有去验证所转发的内容是否有效便进行纯复制转发,你们这是在污染网络环境,每次我遇到问题,网上一搜,搜索引擎前面几页一模一样的答案,而且还不是有效的博文,看着这些千篇一律的东西,真的是让我抓狂!!!小小吐槽一下
----------------------------------------------------------------------------------以下是正文-----------------------------------------------------------------------------------
一、背景
本篇博文放在【IDEA Git系列(共x篇)】的最前面,主要是想先说一下本菜鸟在学习Git过程中所得出的总结,内容主要包含“名词解释”、“深入释疑”和“命令作用”三块。
为啥出这个总结篇呢?主要是因为本菜鸟也看了不少网友的博文和视频教程,但总感觉他们讲的有些东西还是不够细不够清楚,还有就是概念也解释得不够明白,有点交叉,让人看了误解,看了很迷糊,所以便出了这篇总结篇,至于为啥放在最前面,也是有原因的,请看下面。
看本篇博文之前本菜鸟有点小建议,就是,对于刚接触Git的小白,可以对本篇博文先稍微过下眼,不需要深入,然后直接进入下一篇学习,在学习后面篇章过程中,如果学着学着疑惑了,便可以回来这里找答案,本菜鸟会尽量完善本篇,但也许有可能还是没有你想要的答案,不要慌,可在下方评论,本菜鸟看到了,一定是知无不言、言无不尽的;而对于已接触过并对Git有一定了解的小伙伴,那就可以深入学习本篇博文。
希望可以帮到你们,如果有不妥之处,请指出,能力有限,海涵海涵!
二、总结
【名词解释】
工作区:在个人电脑上可以看到的文件夹(里边会有一个.git隐藏文件夹,但这个.git隐藏文件夹不属于工作区);
版本库:就是.git隐藏文件夹;
暂存区:就是.git隐藏文件夹下的index文件,暂存区也可以理解为一个虚拟工作区,不过这个index文件只是个简单的索引文件而已,里边包含的是文件的目录树,记录了文件名、文件的最后修改时间、文件长度、文件类型以及最重要的SHA-1值,而文件的内容并没有记录在这个index索引文件中,文件的具体内容是在.git/objects目录下;
本地仓库:(个人理解)应该是工作区+.git隐藏文件夹;
(大伙可能会有点疑惑,大伙应该看过或听过这句话“先提交到本地仓库,最后再push到远程仓库上”,我们创建的文件不就是在本地仓库里了吗?为啥还要先提交到本地仓库?这好像很矛盾,以我个人的理解是,提交到本地仓库的真正意思应该是在.git隐藏文件夹里做好本次版本的记录,以便之后我们可以回退到这个历史版本)
本地分支:本地仓库下的分支,会在我们第一次提交的时候自动帮我们新建一条master主分支,其他的副分支则需要手动新建,存在的作用和意义请看附录一1,准确来说,我们提交的文件其实是放在了仓库的分支下;
远程仓库:基于Git实现的在线代码仓库,比如下一篇博文演示的Gitea下的仓库;
远程分支:远程仓库下的分支,会在我们第一次推送的时候自动帮我们新建一条origin/master主分支,其他的副分支则需要手动新建;
——延伸说明:我们在工作区所存在的文件,Git它是不知道这些文件的存在的,只有当我们用git add命令将工作区的文件添加到暂存区,这个时候Git才知道这些文件的存在,但此时还没有历史版本控制,想要有历史版本控制,需要我们使用git commit命令将暂存区的文件提交到本地仓库,这个时候才会有版本树。
【深入释疑】
1、git文件有四种状态:Untracked(未跟踪状态)、Unmodify(未修改状态)、Modified(已修改状态)和Staged(暂存状态)。可将这四种状态分成两类,一类是Untracked,里边有Untracked;另一类是Tracked,里边有Unmodify、Modified和Staged。Tracked这一类状态的文件才是加入了Git版本控制的,而实际可以使用git commit命令提交到本地仓库的文件状态仅仅只有Tracked这一类里的Staged。那么Tracked这一类里的三个状态是怎样的关系呢?记住,现在只说这三个状态!开始文件状态是Staged,当这个文件被修改了,文件状态便变成Modified,这个时候使用git add命令将这个文件添加到暂存区,文件状态便变成Staged,紧接着再使用git commit命令将这个文件提交到本地仓库,文件状态便变成Unmodify。也就是说Tracked这一类里的Modified状态的文件不可以直接使用git commit命令进行提交,需要先使用git add命令将它的文件状态转变为Staged,才可以使用git commit命令。到了这里,给我的感觉就是,git add命令作用其实有两个,第一个是我们熟知的,也就是将文件加入版本控制,文件状态由Untracked变成Staged;第二个是将文件状态为Modified的文件的状态变成Staged,以便接下来可以使用git commit将文件提交到本地仓库。
(这条总结并未进行测试,是我结合网上博文和视频教程得出的总结,道友可自行斟酌)
2、使用git commit命令将暂存区的文件提交到本地仓库,提交成功后,暂存区里对应的文件是会被清掉的。(该结论是网友得出,在我编写到第四篇博文(第3篇:如何回退版本)的时候经过测试发现,提交后,暂存区里对应文件并不会被清掉,不知道网友如何得出这结论的,搞不懂,大伙如果想看测试过程,可到本系列第四篇(第3篇:如何回退版本)中查看)
3、git branch [branchname]这个命令是用来新建本地分支的,那么想新建远程分支应该如何新建呢?用这个命令git push [远程主机名] [本地分支名]:[远程分支名],例子如下,
注:如果本地分支名与远程分支名相同,则可以省略冒号:和[远程分支名]。
说明:有些命令的执行跟你当前处于哪个分支下是有关系的,比如git commit,但这个新建远程分支命令跟你处在哪个本地分支下执行没有关系。
4、借用一下网友的图,如下,然后我一直在疑惑版本提交记录树这样画貌似看着还是不够清晰,这个版本提交记录树是描述的本地仓库的,还是远程仓库的,还是本地仓库和远程仓库共用的?你们单纯考虑本地仓库,这个图看着是很清晰,但我们使用Git也是为了能多人协同,那么就避免不了还得考虑远程仓库那边,那么应该也得把远程仓库的远程分支也画进去,感觉会合理点,不会导致迷糊。
看了很多视频和教程,他们在讲解分支的时候,就一直说的是分支,分支,分支,而不是说本地分支,远程分支,毕竟新建本地分支和新建远程分支还是不同的命令呢,所以感觉讲解分支得指明是在说本地分支还是远程分支,我这里也不是评判他们,只是提出我看了之后的疑惑点,绝无恶意的。
那么下面我讲一下我的理解吧!
先说一下这三个颜色标签的含义,黄色标签叫做头指针HEAD,它停在哪一条记录上,你工作区里文件的内容就是那条记录里文件的内容,可以人为移动这个头指针HEAD;绿色标签叫做本地分支master指针,它永远都是指向当前分支(即master)的最新commit,不可以人为移动这个本地分支master指针;紫色标签叫做远程分支origin/master指针,它永远都是指向当前分支(即origin/master)的最新commit,不可以人为移动这个远程分支origin/master指针。
说明:我们这里演示的本地分支和远程分支各取一条,你说本地分支你想用两条,那也可以,那就新建多一条dev本地分支,那么相对应的它的指针就是本地分支dev指针,同时这个指针永远都是指向当前分支(即dev)的最新commit,远程分支你想用两条,那么新建的那一条也是跟远程分支origin/master一个道理。
大伙可以看一下这篇文章Git-你好, HEAD 同学,一位大佬写的,我这里总结一下要点,1)头指针HEAD指向本地分支,本地分支再指向commit;2)为什么头指针HEAD不跳过本地分支直接指向commit?因为你在本地分支master的基础上再新建一个本地分支dev的时候,两条分支是重叠的,直接指向commit的话,这样根本不知道指向的到底是本地分支master的commit,还是本地分支dev的commit,下面用图演示给你们看;3)也有头指针HEAD直接指向commit的情况,不过指针会进入游离状态(detached state),这状态下可以进行提交,但切换到分支上后,游离状态下提交的记录会被垃圾回收掉,所以是看不到的,这个游离状态的好处是你可以在上面进行各种各样的操作,如果你不想保留这些操作记录,只要直接从游离状态切换到分支上便可以了,但如果你想保留这些操作记录,那就需要额外的操作,即直接新建一个分支,这样就脱离游离状态了,那些操作记录也就保留下来了;4)本地分支指针永远都是指向当前本地分支的最新commit,你如果想回到当前分支前面的版本,你可以移动头指针HEAD,移动之后头指针HEAD会进入游离状态,此时的本地分支指针并没有跟着移动,依旧指向当前分支的最新commit
前面的都是铺垫,现在我们来真正讲一下版本提交记录树的真实情况!
首先,我们先看一下起初的状态,此时的b319765提交记录上有(HEAD -> master, origin/master)
接着,我们修改这个test.txt文件的内容,并进行添加提交,此时再查看一下提交记录,(HEAD -> master)移动到了最新的14c845a提交记录上了,而(origin/master)还在原来的b319765提交记录上,这是为什么呢?因为我们只对test.txt文件进行了第二次提交,并没有进行第二次推送,所以此时本地仓库里的test.txt文件的内容是第二次提交的内容(内容为000000000011111),而远程仓库里的test.txt文件的内容依旧是第一次推送的内容(内容为0000000000),
此时,我们只要将第二次提交的内容(内容为000000000011111)推送到远程仓库的origin/master远程分支上,(origin/master)就会移动到最新的14c845a提交记录上了
那么我们来看一下,要是有多条本地分支和多条远程分支,版本提交记录树的情况又会是怎样的呢?
我们现在新建多一条dev本地分支和origin/dev远程分支,
此时的版本提交记录树如下图,
接下来再进行提交和推送,你们也能推测出图是怎样的了吧,就这样吧,我不想画了,不是画图的那块料,有点累。
结论:
1、本地仓库和远程仓库的版本提交记录树是同一个;
2、只要一提交到本地仓库,就会在版本提交记录树上有一条记录,并有对应的commitId,可以用git log命令查看,推送到远程仓库就仅仅只是移动远程分支指针了。
【命令作用】
1、git remote add [shortname] [url] —— 用于给远程仓库取别名
2、git checkout [branchname] —— 用于切换分支(分支应该是本地分支,不知道远程分支可不可以?),讲明白点,就是这个命令是用来移动HEAD头指针的
深入剖析:checkout本意是检出的意思,也就是将某次提交的内容检出到工作区。过程是先将HEAD头指针指向某次提交,然后从这个提交恢复index,最后从index恢复工作区。(结论由网友得出,我觉得在理,但我并没有进行验证,理由很简单,没时间)
git checkout [commitID] —— 用于指向某个提交
深入剖析:使用这个命令有可能会让HEAD头指针处于游离状态,我们先了解一下两位大佬的这两篇文章《HEAD detached at —》、《Git HEAD detached from XXX 解决》是如何解释这个游离状态的?我这里整理一下这两篇文章的一些要点吧,1)正常情况下,HEAD头指针是指向一个branch,而branch又指向一个commit。HEAD头指针处于游离状态的意思是HEAD头指针没有指向任何branch,而是直接指向了一个commit;2)HEAD头指针处于游离状态下可以进行提交,但一旦HEAD头指针离开回到branch上,处于游离状态下提交的记录会被当做垃圾回收掉,也就是看不到提交记录;3)HEAD头指针不能指向远程分支,只能指向本地分支或者本地分支的某个commit。
3、git branch [branchname] —— 用来新建本地分支
4、git push [远程主机名] [本地分支名]:[远程分支名] —— 用于新建远程分支
5、git branch -d [本地分支名] —— 用于删除本地分支
6、git push [远程主机名] --delete [远程分支名] —— 用于删除远程分支
7、git log —— 用于查看所有提交过的版本信息
8、git reflog —— 用于查看所有操作记录(包括已经被删除的commit记录和reset的操作)
git log和git reflog的区别:假如此时有三个提交版本,我们使用git reset回退到版本二,此时使用git log命令是无法查看到版本三的记录的,但使用git reflog却可以看到版本三的记录。
|=============================================================================|
【IDEA Git系列(共x篇)】文章清单
总结篇:Git使用总结(此时在这里)
第1篇:Git和Gitea介绍、建立远程仓库以及推送和下拉代码
第2篇:提交代码时提示冲突如何处理
第3篇:如何回退版本
|=============================================================================|
附录一:
提问:Git本地分支有什么用?
为什么Git要有本地分支和远程分支?
难道不能始终保持本地和远程分支一样么?
我如果在本地创建了一个分支branch1,这个分支可以和远程的master分支关联吗?
回答:我觉得你对远程分支和本地分支的理解没什么问题,只是对Git或者版本控制工具有一些误解。
版本控制工具的诞生,并不单单是为了备份而诞生的,它更多是为了方便多人协作。
从这个角度上来看的话,你可以这么理解:
远程主分支(比如origin/master):是为了与多人协作存在的,同时也是一个项目的公共代码仓库;
本地主分支(比如master):是为了与远端公共分支保持同步而存在的,这和你的理解一致,就是理想情况下,它应该和
远端保持一致;
远程副分支(比如origin/develop或者origin/feature-xxx):是为了像公共分支合并代码存在的,同时也兼顾一定的协作职
能;
本地副分支(比如develop或者feature-xxx):单纯是为了个人开发方便,因为你可能会同时开发多项功能,而多项功能的代
码基础却是相同的。 ↩︎