神奇的像个猴子(猴子都懂的git)

548 阅读7分钟

git版本控制

💯✔️ 懒惰粗使人进步,勤奋使人变得不愿意上进, 哈哈哈哈,至理名言。

大概就是一个什么事情呢,昨天不是写实验吗?今天刚把实验报告写完,就想哎,不是要全面输出咩,那万一没有东西输出咋搞,于是,课程实验来了啊,他就来了嘛不是💯✔️✔️

被git玩了一早上

大早上兴致勃勃地想到了可以给自己的仓库增加点内容,还是挺开心的,于是我就开始老一套,创建一个仓库,然后在本地已有的文件中进行上传.

# 进入本地目录并初始化版本链
$ git init
# 追踪当前文件夹下的所有文件
$ git add .
# 提交暂存与修改
$ git commit -m "first commit"
# 添加远程仓库作为提交链接
$ git remote add origin {URL}
# 算了,我来贴一个我的仓库吧
$ git remote add origin https://github.com/tc6-01/network_and_information.git
# 推送到远程仓库的master分支中
$ git push -u origin master

emm,非常的不错,这小伙,非常的熟练啊,一看就是经常用我们这个github,总裁来了都得夸夸。

上传之后,我忽然猛地想起来一个事情,之前宿舍里讨论说为啥有的老师不发课件,我就忽然想起来不能将课件和实验报告上传到网上,直接删除咩,emmm,也不是不行。可是那个课件我还要复习啊。所以,我就去在GitHub上删除了那一个report和slides文件夹

💨可是下次如果更新仓库,那个文件不是还得被上传吗?然后聪明的我就想起来用.gitignore万能得防止上传,哈哈哈。于是我兴致勃勃的去搜了一下子,还找到了一个不错的模板

git@github.com:github/gitignore.git

添加完成后,我去上传了,结果就出现了当前版本与远程版本不一致,不能进行上传,需要先拉取远程代码(后话是,原来我在远程仓库中进行修改,可是本地的那个Head还在上一个版本,没有办法直接进行上传)。

然后,那咱就git pull一下呗,拉取之后,我就傻了,我的实验报告和课件呢,我还没复习呢。呜呜呜呜。于是就开始各种百度,用了checkout 、 merge、 switch、 revert各种我以前从来没有接触过的命令。

tips

过程中发现了几个问题。

  • git版本控制的本质就是远程和本地分别管理不同的版本,然后远程和本地都可以有多个分支,本地和远程同步的契机在于本地要保证修改的是远程分支,然后才能进行修改提交
  • git的merge指令,比如说用一个本地分支合并远程分支,如果我的本地分支上有report和slides文件夹,而master上没有,那最后的结果就是合并之后本地分支和master都指向master分支,然后文件还是和master中的一致,也就是说,如果是合并的话,只会修改相同文件中的不同内容,不会增加和删除原有的文件。
  • git的revert指令可以进行版本回退,但是它的前提是只能回退那些修改部分,也就是说,比如第一次我添加了Readme文件,然后第二次上传了所有文件,第三次删除了report和slides,那么他回退之后就只是恢复report和slides,不会把原有的所有文件都恢复。(后面把孩子整委屈了,都不知道说啥,呜呜呜)
  • git的checkout是切换分支,但是也可以用来切换到某个commit上面,这样的结果就是可以获得这个提交上的所有文件,注意是所有。但是缺点就是没有办法进行远程更新,因为现在处于一种游离分支(匿名分支)。所以好的做法是,先回到想要去的commit然后新建一个分支(其实就是切换一个分支,没有就会自动进行创建),这样这个分支上就是最新的文件(当时我还不太懂,切换完分支,就去Github上把这个分支修改为master,然后变成默认✔️)。

具体可以参考这篇文章: Git HEAD detached from XXX (git HEAD 游离) 解决办法_detached from git_拭心的博客-CSDN博客

猴子都懂得git

在被折腾一上午之后,中午我想了想,还是要把这个搞清楚,于是我就找到了一本神书(图书馆的书是真的多哈哈哈),另外加上官网的文档,没错就是下面这个

git-scm.com/book/zh/

image.png

正文开始:

引入git的目的,就是为了更方便的管理文件的修改。有这么一个场景,你正在写你的毕业论文,经过呕心沥血写完第一版之后给老师发了过去。老师说你这不行,要大修,然后你开始在第一版的基础上进行修改,没日没夜的修改,终于修改好了,老师说你这还要修改,然后你就又开始修修补补,这就有了三个版本,这个时候交完毕业论文,老师说你太菜了,让你的师兄帮你修改(期待遇到这样的老师😍)然后你就把三个版本的论文都给了师兄,然后师兄将你的最后一个版本修改之后又发给了你。你说,师兄真的是牛。

这个场景里,师兄只需要修改最后一个版本,但是却要发送多个版本给他,不方便;另外,不管是师兄还是我自己,对于这个毕业论文不同版本需要有不同的命名(比如:最终版,再改就是狗版,最终终终终版)也不太方便。

于是我们的git出现了,不仅是命名(对于同一个文件进行修改,但是不需要修改文件名,只是会产生不同版本号),而且是多方协作(不同的人都可以从远程获取,然后本地进行修改,修改之后进行同步),还可以是多版本切换(通过版本切换来获取历史版本,可以更方便的进行文件修改)。

下面就分享一些关于git的高级(常见)知识

其实比较常见的就是

$ git add .
$ git commit -m "commit message"
$ git push 

大概就是保存修改,然后提交修改,推送远程仓库。这是在自己的本地创建仓库,然后使用仓库的做法。还没有牵涉到任何合作相关(其实合作相关也就是用一个git pull 拉取别人修改的代码,然后一个git merge合并自己的分支到别人的上面)。

那下面就结合前面的我被玩坏的过程场景来理解一遍原理。

创建仓库,跟踪文件、提交文件,并推送

首先是git init初始化仓库。该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。 但是,在这个时候,仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。

如果在一个已存在文件的文件夹(而非空文件夹)中进行版本控制,你应该开始追踪这些文件并进行初始提交。 可以通过 git add 命令来指定所需的文件来进行追踪,然后执行 git commit :

然后呢,这个add命令就是非常的好玩儿,他可以用文件匹配,比如

# 匹配当前目录下的所有文件
$ git add . 
# 匹配以file命名的所有类型文件
$ git add file.*

然后就是remote操作了,我们用的命令是git remote add origin url,这个url就是远程仓库的地址,也就是说远程仓库也是一个文件夹,然后他相当于是一个管理员,把文件放在他那里,然后remote就是操作远程的指令,add是给他添加一个链接,执行远程仓库,然后进行pull和push。我们可以用git remote -v 查看当前的远程仓库。 应该是下面这样 image.png 然后呢,连接之后就可以进行修改和提交了。关于修改和提交我就不多说了,应该都明白,这里提供一个官网的流程。

image.png

版本回退与更新

上面的是一种基础操作,下面的就涉及到一些稍稍复杂的东西了,比如说查看已提交的版本,然后进行版本回退巴拉巴拉。

上午的我就想知道我自己提交了哪些,然后有什么修改,找到那个删除文件之前的版本。(emmm,大家别听我在这瞎哔哔,可以直接用VScode的git graph插件,贼香,直接图形化解决)使用的就是git log命令

image.png

然后呢,比如我这里修改一个文件,我把lab1下面的excel删掉了,然后用add,commit生成了一个快照。然后我们的这个Graph里面就多了一条记录,而且是先于origin(远程仓库)的。

image.png 那个test吗,大家可以猜一猜是怎么来的。

其实就是在未提交修改之前创建了一个分支git branch test,然后进行提交,因为这个时候我们本地的Head指向的还是master,所以test并不会移动,就像这个一样

image.png

但是我们可以用git checkout test将Head指向新的test分支,这样就会让文件变成原来没有修改的部分(test并未提交修改,master提交了修改

image.png

不过我发现了一个新的比较便捷的方式。在原分支上进行修改,然后修改完之后呢,先add,commit,然后直接进行git checkout -b newBranch会自动创建一个分支(跟当前分支一模一样,然后直接切换为新的分支,原分支不变),它是两条命令的简写

$ git branch iss53
$ git checkout iss53

然后就是merge操作,为什么会有这个呢,除了我自己瞎捣鼓之外,还有一个原因,比如当前线上环境需要优化,那不可能直接去修改线上的代码吧,肯定要对复制版进行修改的啊,也就是刚刚提到的分支,可以通过git checkout -b hotfix创建一个紧急分支,然后进行测试,最后优化完成后,进行合并

image.png

image.png

再来看看我的修改

$ git checkout master
$ git merge test

image.png

搞定,轻轻松松,其实就是在合并的时候使用的是master分支,然后合并就是保证默认的分支保证是发布版本。另外分支也可以进行修改,比如删除,查看等等

远程仓库更新与同步

刚刚说的都是本地进行修改的版本控制,如果涉及到远程的呢,比如我想让我的远程仓库展现出我最后更改的结果。

从远程clone下来一个仓库,就会得到这样的一个结果

image.png 有远程的master,也有本地的master,做的本地修改就是本地master的移动

image.png

还记得最开始的时候修改完远程的仓库,本地的仓库没有办法直接push吗?终于找到问题了!!

假如说有两个协作者,一个用户在自己的分支进行修改,然后就将自己的分支提交到了远程仓库,这个时候我们的远程仓库Head已经更新了,但是另外一个用户的本地仓库的远程Head指针并未改变。

就像下面这样,上面的是第一个提交修改的用户的版本指针,下面的是未修改的用户的本地版本指针(远程HEAD并没有发生变化image.png

这样就真相大白了,因为在远程进行了修改,所以本地和远程的远程仓库指针并不一致,emm似乎有点绕,就是像这样,远程的Head指针已经更新,但是本地的还未更新。

image.png

所以需要进行同步,使用git pull同步最新的远程仓库,然后再次进行git push同步本地的修改到远程仓库。

然后,再来细细想一下,为什么report/和slides/文件夹会丢失呢,git pull之后发生了什么呢,其实这个命令是两个命令的合并

git fetch拉取远程的master,git merge将远程的Head和本地的Head进行合并

而拉取之后的远程仓库中是没有reports和slides的,然后合并之后就变成了完全消失了。唔,终于整完了。大概就是了解了所有过程了,就先到这里吧。关于revert的命令,还有一些分布式的命令,就等下次吧