Git和GitHub的学习记录
本篇博客记录关于Git和GitHub的知识以及在Linux(Manjaro)的使用
GitHub
参考资料 参考资料
起步:创建新仓库->创建新分支->修改新分支的内容并commit->open and merge pull request
基本概念
repository版本库/仓库:仓库是一个存储各种文件的地方,比如你可以用来存储一个python项目
branch分支:一个仓库默认会有一个main分支,创建一个新分支会复制main分支的所有内容,之后我们可以在这个分支上自由的修改、提交,甚至最后整合如main分支中
commit提交:保存分支的修改操作成为commit
open a pull request打开拉取请求:当你修改了分支内容(与主分支的内容发生了差异)时,可以打开拉取请求,让别人审核是否能够代替主分支的内容
merge the pull request:审核人可以审核你的拉取请求,并且可以与申请人交流,如果审核人通过请求,那么main分支会被申请人申请的分支覆盖。
Git
Git的简介
定义:Git是分布式版本控制系统。那什么是分布式?版本控制系统又是什么?
分布式:
集中式版本控制系统有服务器和客户端之分,服务器上才有完整的版本库;这意味着一名开发者需要先从服务器下载最新的版本,然后在自己的客户端上修改,修改完毕后在推送到服务器中
集中式版本控制系统受网络影响很大,如果网络很慢甚至没网,下载和上传会花太长的时间甚至无法进行。
而git时分布式的,这意味着没有服务器和客户端之分(或者说每个开发者同时扮演着服务器和客户端的角色),每个开发者都可以在本地建立完整的版本库;因为每个人都有完整的版本库,就不要联网才能进行版本控制了。那么不同的开发者要如何合作呢?只需要互相推送修改信息即可。当需要和别人合作时,往往我们会建立一个中央服务器,来方便大家的交换大家的修改,而不是把修改直接推送别人的电脑上(因为他可能没开机呀)。
下面通过一个比喻来区别集中式和分布式版本控制系统的区别。假如10同学一起修改作文,却只有一张作文纸和版本记录表放在讲台上,每个人要修改作文都必须先从讲台抄写下文章的内容,修改完毕后在提交上去整合;而分布式每个人都有属于自己的作文纸和版本记录表,各种修改,最后在汇集在一起交流修改信息进行合并。
版本控制系统:
举个例子,假如目前你有一篇放在word文档里面的作文,你想对他进行修改,因为你害怕修改不成功或者出什么意外,所以你想保存着原来的文件,并复制一份新的文件在上面修改,最后保存,后面你可能又想接着修改,又是复制一份新文件并修改保存,以此类推,就会有一个又一个的修改文件。有一天,你想还原某一除修改的部分,就需要一个个地去查找原先的文件,查看修改的轨迹,非常麻烦;
同样是你有一篇存放在word中的作文,你和你的好朋友一起对它修改,当你们修改完毕后,还需要相互交流具体修改了哪里,以便把两个的修改合并在一起,这也是不方便的。
上面不方便的原因就是需要人去管理一个又一个的版本(一个又一个的修改文件),如果能开发一个软件,让机器帮我们管理就好了,软件使用起来应该是下面这个样子,
这就是版本控制软件
Git的使用
Git之创建标识
因为Git是分布式版本控制系统,所以每个机器都需要自报家门,即用户名和电子邮件
git config --global user.name "your name"
git config --global user.email "your email"
建议用户名和邮件于自己github帐号一致
Git之创建版本库
首先让我们来建立一个空的版本库
midir ~/git/Hello
cd ~/git/Hello
git init
我们先新建了一个空目录~/git/Hello,然后进入该目录,接着执行初始化命令,把该目录变成版本库,这时候我们会发现该目录下出现了./git目录,里面的内容就是来管理版本库的。
接着在这个仓库中新建readme.txt文件,然后依次输入命名
git add readme.txt
git commit -m "Create readme.txt"
我们就进行了一次版本更新。
我们还可以上述命令下git状态的变化
git status可以查看git状态,该命令会显示那些文件被修改了,那些文件放在暂存区等信息
git diff <文件名> 可以具体查看文件修改的情况
版本改变
git是版本控制软件,记录了版本的变化情况,就像单机游戏会记录没一个关卡的存档一样,我们可以根据版本号进行版本的改变
版本回退
输入命令:
git log
会显示当前版权前的历史信息,如图所示:
commit后面的是版本号,用来唯一表示版本;还有作者信息,时间,具体修改的文件信息。其中HEAD用来指代当前的版本号,HEAD、HEAD...用来指代上一个上上个...版本号,如果不想写太多,可以HEAD~n指代上n个版本号
如果我们觉得上面的输出太繁琐,可以输入下面的命令
git log --pretty=oneline
输出结果明显精简多了
根据git log提供的版本信息,我们可以通过版本号来返回之前的版本,命令如下:
git reset --hard <版本号>
<版本号>可填具体的版本号,也可以是HEAD指代
版本前进
如果你对版本回退后悔了,想回到之前那个更新的版本该怎么办呢?
输入git log命令你会发现,该命令只会显示当前版本之前的版本,最新的版本号已经没有了。我们可以通过输入以下的命令来解决
git reflog
这个命令记录了在不同版本下的操作,其中就能找到你需要的版本号,在通过git reset --hard <版本号>命令即可前进到新的版本
撤销修改
(1)如果你乱改了某一个文件,想还原,输入命令git checkout filename
即可
(2)如果你乱改了某一个文件,并且已经输入了命令git add filename
,就需要输入命令git reset --hard HEAD
(3)如果你乱改了某一个文件,同时输入了添加和提交命令,就需要利用版本回退的知识来还原,例如,git reset --hard HEAD^
删除命令
我们往往删除一个文件,在把修改添加到暂存区都会输入以下命令
rm filename
git add filename
上面的命令等效于
git rm filename
远程仓库
首先我们先在github上创建一个远程仓库Hello
远程仓库的地址如图可以获取:
http:push时需要输入用户名和密码,clone则不用
ssh:使用前要为了自己的电脑配置好ssh密钥,然后在添加到你的github中(添加ssh教程)
关联远程仓库
git remote add origin 远程仓库地址
本质上就是变量赋值,让origin存储这远程仓库的具体地址,方便我们后面的使用(在使用远程仓库地址时输入变量名origin就可以了)
本地仓库推送到远程仓库
输入
git push [-u] origin main
将本地仓库的main推送到远程仓库origin的main中
我们可以看到远程仓库的内容和本地仓库一样了
远程仓库克隆到本地仓库
git clone 远程仓库地址
你会发现当前目录下新出现一个目录,即是对远程仓库克隆。
分支
每次提交,都会生成一个提交点,git将一个个的提交点根据时间,串成一条时间线,一条时间线就是一条分支。
一开始,只有master一个分支,从物理结构上我们可以看到master指针指向最新的提交点,HEAD指针指向master。
这时候我们创建了一个新的分支dev,并让HEAD指向它(表示当前分支为dev)
从现在开始,提交针对dev分支,其实就是master指针固定不动
我们最后把dev合并到main中,其中就是master指向dev指向的提交点
最后删除dev分支,其中就是删除dev指针
分支的常用命令
查看分支:git branch
创建分支:git branch 新分支名
删除分支:git branch -d 分支名
切换分支:git switch 分支名
或git checkout 分支名
创建并切换分支:git switch -c 分支名
或git checkout -b 新分支名
合并某分支到当前分支:git merge 分支名
解决合并冲突
一般情况下,在新建分支下提交,最后在main分支下通过git merge 新建分支名
命令,即可将新建分支合并与main分支上
但是加入,在新建分支后,新建分支和main分支都进行了提交,使用git merge 新建分支名
命令就会发生冲突,这时我们需要解决冲突
举个例子:
(1)创建并切换分支git switch -c feature1
(2)修改README.md文件并提交(将"feature"添加到最后一行)
(3)接着通过git switch main
切换为main分支,修改README.md文件并提交(将"main"添加到最后一行)
(4)执行命令git merge feature1
,你会发现出现了冲突信息
(5)解决冲突:打开冲突文件README.md,我们能看到具体的冲突写进了文件中
"<<<<<<<HEAD"到"="之间的内容 与 "="到">>>>>>>feature1"之间的内容 分别为main分支和feature分支冲突的具体内容,其他的内容一致。接着我们手动修改文件为
再提交即可。整个流程用下图表示:
分支管理策略
main分支:作为发布新版本的地方
dev分支:用来工作
bug分支:用来修改bug
feature分支:有来增加新功能
Git之管理下的目录结构(逻辑结构)
Git管理的目录分为工作区和版本库,工作区就是我们能看到的文件,版本库就是隐藏文件.git;版本库可以进一步分为暂存区(stage/index)和分支(默认有一个main/master分支)。
上图工作流程的类比:假如你出生在电脑发明前的年代,正在写一本教材,你会怎么做呢?你会有一个工作台,上面是你写书的地方,写好了书,就把复印件放在书架上,觉得是时候发表了,就在把书架上的书复印一份,寄到出版社发表,于是你有了书籍1.0。但是,知识是不断更新变化的,你肯定需要对他进行修改,于是你在工具区修改了书籍一部分后,就会把修改的部分copy到书架上的复印件上,等到书架上的复印件修改成熟后,你就接着把书架上的书复印一份发至出版社,就有了书籍2.0......
在上面的概念下,重新理解之前学到的命令。
(1)git init
:该命令的作用是将当前目录变成git能够管理的目录,即添加了.git文件这个版本库
(2)git add filename
该命令的作用是将工作区的文件的修改添加到暂存区中,为最后提交到分支做准备
(3)git diff filename
该命令的作用是查看工作区的某个文件相较于暂存区的差异
(4)git checkout -- filename
该命令的作用是通过暂存区存储的文件撤销工作区的修改,具体就是用暂存取的内容覆盖工具区的内容。是git add filename
命令的反向操作
(5)git commit -m <message>
该命令的作用是将暂存区的内容添加到分支中
(6)git diff --cached filename
该命令的作用是比较暂存区和分支HEAD版本某个文件的差异
(7)git reset 版本号 filename
该命令的作用是将分支的某个版本的文件覆盖暂存取
(8)git reset --hard 版本号
该命令的作用是将分支的某个版本覆盖暂存区和工作区
Git内部原理(物理结构)
参考资料
.................................TO DO.................................................................