• Git轻松入门1:本地仓库篇


    什么是Git

    版本控制系统

    首先我们要明白,什么是版本控制系统(version control systems)?

    版本控制系统,顾名思义,就是能控制文件处于哪个版本的系统。

    e.g. 你在博客园里编辑的文章,你可以控制文章是处于某个时间点的版本。

    而Git就是一款版本控制系统,而且是分布式的。

    与分布式相对应的是集中式版本控制系统,它的版本库是存储在中央服务器的。工作的时候你需要先从中央服务器取得最新的版本,等工作完了,再把自己的工作推送回中央服务器。但这有个问题:万一哪天中央服务器崩溃了甚至数据丢失了,那所有人不就都无法工作了?

    于是分布式版本控制系统(Distributed Version Control System,简称 DVCS)就应运而生了。它没有“中央服务器”,每个人的电脑上都有一份完整的版本库,如果某个人的电脑坏了导致版本库丢失了,直接从别人那复制一个版本库过来即可。

    Git的基本工作原理

    有一类版本控制系统是基于差异(delta-based)来进行版本控制的。

    这类版本控制系统存储的是新文件和旧文件间的区别(delta)。这里的delta和高中物理里的delta一样,(Δv = v_2 - v_1),都指的是变化量。

    而Git和上述这类版本控制系统的工作原理不同:每当你对提交新项目或者对项目进行修改,它会把项目的所有文件都压缩保存起来,这个压缩文件在Git中被称为快照(snapshot)。每次有更新就会每次把所有文件都压缩起来存储一遍,形成一系列快照。

    当我们需要处于某个时间点版本的文件时,直接根据索引,找到那个时间点的快照即可。

    操作指令

    在开始介绍Git相关的指令前,我们先创建三个文件。

    创建版本库

    所谓“版本库(repository)”就是一个用来存储文件历史版本的仓库。所以要想对文件进行版本控制,我们需要先初始化一个版本库来存储文件的各个历史版本。

    $ git init 命令能把当前所在目录变为由Git管理的仓库(或是对该位置已有仓库进行初始化),使得该目录下的文件可被Git进行版本控制。

    当执行完该命令后,可以看到该目录下生成了一个 .git 的文件夹。

    把文件添加到版本库

    创建完版本库后,我们还需要把文件放进去才能对其进行版本控制。

    而把文件添加到版本库需要两个步骤:

    第一步,用 $ git add 命令把需要跟踪版本的文件添加到暂存区。

    第二步,用 $ git commit 命令告诉仓库:我确定要对暂存区里的文件进行版本控制,请把暂存区里的文件正式放入仓库管理。

    -m "xxx" 是对本次提交的备注说明;2 files changed 指有两个文件变动:即我们新添加的 README.mddemo1.txt1 insertion 指插入1行内容:即我们在 README.md 文件中插入的“Git is a version control system.”。

    在每次提交变动(commit)后,都会产生对应的快照。快照,我们在Git的工作原理那章提到过,它就是被放入版本库中的所有文件的压缩版本。我们可以把快照理解成是游戏的存档。在玩游戏时,我们每通过一关就会保存游戏。如果进行到某一关死了,那就可以通过读取存档来回到前面的某一关。Git也一样,每次commit就是在给文件存档,要是哪一天文件误删了或出错了,那我们就可以读取存档,让文件恢复到存档时的状态。

    通过 $ git log 命令,可以查看当前共有几个存档。

    同步修改到版本库

    当我们在工作区(工作区就是当你打开“我的电脑”看到的目录就叫工作区)里对文件进行修改后,如何把更新同步到版本库中,让版本库也拥有文件最新的版本呢?

    我们先添加一行话到 README.md 文件中,使其内容变为如下:

    Git is a version control system.
    Git is distributed. 
    

    现在,运行 $ git status 命令查看版本库当前状态:

    从状态中我们可以得到2个信息:

    1. README.md 文件进行了修改,并且这次修改还没有被添加到暂存区。
    2. learn_git 目录下,demo2.txt 文件没被添加到仓库中以进行版本追踪。

    如果我们想要进一步得知对 README.md 文件进行了哪些修改,可以用 $ git diff 命令(这步并不是必须的)。

    可以看到,新增加的改动是“Git is distributed”这行话。

    确定了作出哪些修改后,再把它提交到仓库自然就放心多了。提交修改和之前提交新文件需要同样的两个步骤:$ git add$ git commit

    我们先运行 $ git add,然后看看版本库状态。

    可以看到,当我们用 $ git add 命令把文件添加到暂存区后,版本库状态就不会再提示我们“尚未暂存已备提交的变更”,而是提示“要提交的变更”,即提示我们要用 $ git commit 命令提交这次变更。

    那我们就再运行一下 $ git commit 命令,再来看看版本库状态。

    再用git log查看一下当前共有几个存档(快照)。

    从以上两张截图可以看出现在已经没有需要提交的修改了,只剩下未跟踪的文件 demo2.txt 了,刚才的那次变动已经被版本库存档了。

    把文件从版本库中删除

    删除文件也算是对文件的一种修改。同样也需要两步:

    1. $ git rm <file> 把该文件从工作区删除。
    2. commit这次变动,把删除同步到版本库。

    注:在执行 $ git rm <file> 指令时,Git会默认执行 $ git add 命令来把这次修改提交到暂存区。

    回退到某个版本

    我们已知目前共有2个存档:第一个存档的ID是b1a6863...,存档备注是“added README and demo1”;第二个存档的ID是245fcc1...,存档备注是“modified README”。

    在Git中,HEAD 是一个指针,它会指向当前所在分支的最新存档,分支的概念我们后边在介绍,但反正目前我们没有创建别的分支。你让 HEAD 指向哪个版本号,Git就把当前版本定位在哪。所以此时 HEAD 代表的就是ID为245fcc...的存档,那么在它前一个的存档就是 HEAD^,前N个的存档就是 HEAD~N

    有一天你可能会觉得第二个版本很糟糕,不如第一个版本,于是想坐时光机回到过去,让一切复原到第一个版本时的样子。这时我们可以用 $ git reset 命令来帮助我们穿越时空。

    我们再来看一下 README.md 里的内容,后面新添加的那行就不见了,内容回到了最初的时候:

    Git is a version control system.
    

    再运行一下 $ git log

    一切真的都回到了过去!连存档都变成和当时一样,只有b1a6863...这一个了!

    为什么回退的速度这么快呢?

    因为我们每个版本的文件都被保存在了快照里,Git仅仅只需要把 HEAD 指针从一个快照指向到另一个快照,再把目录里的文件替换成那个快照里的文件即可。

    所以建议:无论是大的变动还是小的变动,都存一下档(即commit)。只有把这个版本存档了,保存进快照里了,日后才能通过读档来返回到该版本。

    可万一你又后悔了,觉得一切还是像第二个版本时的那样好,怎么办?通过 $ git log 命令已经找不到第二个版本的存档了,是不是回不去了?

    并不是的。在Git中,你的每次操作就会留下记录,我们可以用 $ git reflog 来查看所有的操作。

    从中我们可以看到,备注为“modified README”的那次commit的ID是245fcc1。有了commit ID后,我们就又能通过 $ git reset 命令回到未来了!

    再运行一下 $ git log 和打开 README.md 文件,可以确认真的回到了未来!

    撤销修改

    撤销修改有三种情况:

    1. 修改还没添加到暂存区。
    2. 修改已经添加到暂存区,但还没commit。
    3. 修改已经commit。

    修改还没添加到暂存区

    我们先谈第一种情况。

    假设你往 README.md 文件里添加了一行“My boss is stupid. ”,而这最新修改还没有被你添加到暂存区。所以当你运行$ git status 命令时,你看到Git提示你有尚未暂存已备提交的修改。

    你觉得这句话可能会让你被炒鱿鱼,尽管你说的是事实。于是你最终还是决定把这句话删掉。

    有两种删除方式:

    1. 手动打开 README.md 文件,然后把这句话删掉,让文件回到添加这行话前的样子。
    2. 按照Git提示的,用 $ git restore <file> 命令,来直接撤销改文件在工作区的变动。

    你觉得第二种方式看起来显得逼格更高点,于是你输入如下命令。

    $ git restore README.md
    

    然后当你再打开README.md文件,发现那句话果然消失了;再运行 $ git status 命令,发现Git也没有任何提示了。

    修改已经添加到暂存区但还没commit

    再来谈谈第二种情况:你不仅写了那句话,还提交到了暂存区!所以当你运行 $ git status 命令时,你看到Git提示你有要提交的变更。

    有了上次撤销的经验,你就放心地按照Git的提示输入如下命令:

    $ git restore --staged README.md
    

    再运行 $ git status,你发现现在它提示的和第一种情况一样了,而打开工作区里 README.md 文件,那句话还在。原来这个命令只是帮你撤销一小步,仅仅是从暂存区移除,而不是帮你一夜回到解放前。

    当然了,如果你很不幸的已经commit这次提交了,那就只能用 $ git reset 来版本回退了。

    总结

    Git中文件的所有状态以及状态间的转换可以被概括为下面这张图。

    最后,总结一下今天出现过的几个Git命令:

    # 创建版本库
    $ git init
    
    # 把文件添加到暂存区
    $ git add <file>
    
    # 把暂存区里的变动提交到版本库
    $ git commit
    
    # 查看当前所有快照
    $ git log
    
    # 查看版本库当前状态
    $ git status
    
    # 查看某文件的变动
    $ git diff
    
    # 删除文件,并把这次变动提交到暂存区
    $ git rm <file>
    
    # 版本间的前进和回退
    $ git reset
    
    # 撤销修改
    $ git restore
    

    参考

    1. https://sp18.datastructur.es/materials/guides/using-git.html
    2. https://www.liaoxuefeng.com/wiki/896043488029600
    3. http://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F
    4. https://stackoverflow.com/questions/4964099/what-is-a-git-snapshot

     
    有问题欢迎大家在评论区留言,转载请注明出处。

  • 相关阅读:
    iptables防火墙--------基本操作
    iptables防火墙--------基本概念
    常用运维工具小结
    ELK6.6.0+filebeat6.6.0部署
    Yum安装时出现 The program yum-complete-transaction is found in the yum-utils package
    重温面向对象核心 下 : 你一定能看懂的委托和事件
    重温面向对象核心 上
    程序员创业第一步:如何获取第一笔风险投资
    MVC + EFCore 完整教程19-- 最简方法读取json配置:自定义configuration读取配置文件
    MVC+EFCore 完整教程18 -- 升级分布视图至 View Component
  • 原文地址:https://www.cnblogs.com/linj7/p/14361459.html
Copyright © 2020-2023  润新知