Lite Git (III) - First Commit

Lite Git (III) - First Commit

前言

本专栏名为Lite Git。主要想与Pro Git对应,后者为Git官方指南,有兴趣,或者想了解更多细节的同学,请移步官网下载PDF版

本专栏主要为了让初出茅庐的同学更快、更合理地掌握Git的基本运用;

同时,本专栏也会介绍一下作为Android开发人员关心的:repo的运用;

本篇是该专栏的第三篇,主要介绍Git仓库的的结构划分,属于比较重要的一节,刚开始了解Git的同学强烈建议了解一下;

在了解了本章节以后,后续的git命令学习就是手到擒来的事情。

此后会完成第一笔提交,并在此过程中进一步加深对Git仓库结构的理解;

结构划分

在介绍使用步骤之前,我认为如下概念需要先介绍一下,这有助于后面命令的记忆与理解;

前面已经提到了工作区(Working Directory)以及git仓库(Repository)的的概念。事实上,在常规Git仓库(即:非裸仓库)下,还有一个暂存区(Staging Area)。那么这三个概念的简介依次如下:

  • working directory 工作区,即git仓库托管的文件内容检出后的工作区域,可以由用户*查看、编辑、更改。大部分情况下等效于除去.git目录以外的内容,git裸仓库下没有工作区
  • git repository 仓库本身,大部分情况下等效于.git目录(非裸仓库,后者仓库根目录即为仓库本身),其内部是有一套管理、压缩、索引机制,这个对于初学者来说无需过多关注(如果后面有时间会提一提);
  • staging area 我习惯于称之为暂存区(后面将维持此称呼)。在git内部通过一个名为index的文件进行管理(因此部分地方提到index也是指代这个),主要用于一些版本控制过程的中间态的记录,通常是一些待提交的内容的记录。这部分比较难理解,但是对玩转git有很大的帮助。后面会详细讲解;

为了加深记忆,这里使用上一节的demo_client仓库来讲解:

# demo_client 为常规仓库(非裸仓库)
ryan ~/git_demo/demo_client (master) $ ll
total 12
drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:36 ./
drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:36 ../
drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:36 .git/
ryan ~/git_demo/demo_client (master) $

此时:

  • 工作区为空(但不是不存在,git裸仓库下工作区不存在);
  • 仓库非空(结构存在,但内容为空);
  • 暂存区为空(没有index);

提交修改

由于目前demo_client与远端的demo_bare仓库均没有追踪任何文件,因此仓库是空的。

现在,我们借“完成第一笔提交”这一目的,逐步介绍各个阶段下,不同区域的情况,以加深大家对这三个区域的理解:

  1. 首先,我们在demo_client目录下创建一个文件FileA(Linux环境):

    ryan ~/git_demo/demo_client (master) $ touch FileA
    ryan ~/git_demo/demo_client (master) $ ll
    total 12
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:44 ./
    drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:36 ../
    drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:36 .git/
    -rw-r--r-- 1 ryan ryan    0 Oct 27 13:44 FileA
    
  2. 然后,我们通过git status查看git的情况:

    #查看.git仓库,依旧没有index文件
    ryan ~/git_demo/demo_client (master) $ ll .git/
    total 40
    drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:45 ./
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:44 ../
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:36 HEAD
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 branches/
    -rw-r--r-- 1 ryan ryan  254 Oct 27 13:36 config
    -rw-r--r-- 1 ryan ryan   73 Oct 27 13:36 description
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 hooks/
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 info/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 objects/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 refs/
    
    #git status可以查看当前仓库的文件情况
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    
    No commits yet
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
            FileA
    
    nothing added to commit but untracked files present (use "git add" to track)
    

    可见,git发现了FileA,但是表示自己并未追踪该文件(Untracked

    所以此时:

    • 工作区非空(有FileA);
    • 仓库非空(结构存在,但内容为空);
    • 暂存区为空(没有index);
  3. 接下来,我们要想将FileA提交到git仓库中,则先需要使用git add命令将其添加进暂存区

    #将FileA添加进暂存区
    ryan ~/git_demo/demo_client (master) $ git add FileA
    #查看.git目录情况,发现有了index文件
    ryan ~/git_demo/demo_client (master) $ ll .git/
    total 44
    drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:52 ./
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:44 ../
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:36 HEAD
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 branches/
    -rw-r--r-- 1 ryan ryan  254 Oct 27 13:36 config
    -rw-r--r-- 1 ryan ryan   73 Oct 27 13:36 description
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 hooks/
    -rw-r--r-- 1 ryan ryan  104 Oct 27 13:52 index
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 info/
    drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:52 objects/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 refs/
    #再次使用git status查看情况
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
            new file:   FileA
    
    

    可以看到FileA已经不再是Untracked状态,而是to be committed状态了,说明“新建FileA的行为已经被暂存区记录下来了”;

    所以此时:

    • 工作区非空(有FileA);
    • 仓库非空(结构存在,但内容为空);
    • 暂存区非空(有index,记录了“FileA的创建”);
  4. 最后,我们要将“FileA的创建”这一修改提交进git仓库,这里需要使用git commit命令:

    # git commit -m 可以直接将后面的字符串作为提交信息直接提交,如果不带-m参数,则会弹出默认的文本编辑器(之前我配置的是nano)供用户输入提交信息;
    ryan ~/git_demo/demo_client (master) $ git commit -m "[demo_client]add FileA"
    [master (root-commit) 0dbaef0] [demo_client]add FileA
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 FileA
    # 查看仓库根目录情况
    ryan ~/git_demo/demo_client (master) $ ll
    total 12
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:44 ./
    drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:36 ../
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 13:59 .git/
    -rw-r--r-- 1 ryan ryan    0 Oct 27 13:44 FileA
    # 查看.git仓库情况
    ryan ~/git_demo/demo_client (master) $ ll .git/
    total 52
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 13:58 ./
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:44 ../
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:58 COMMIT_EDITMSG
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:36 HEAD
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 branches/
    -rw-r--r-- 1 ryan ryan  254 Oct 27 13:36 config
    -rw-r--r-- 1 ryan ryan   73 Oct 27 13:36 description
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 hooks/
    -rw-r--r-- 1 ryan ryan  137 Oct 27 13:58 index
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 info/
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:58 logs/
    drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:58 objects/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 refs/
    # 使用git status查看git管理情况
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    nothing to commit, working tree clean
    # 使用git log查看提交信息
    ryan ~/git_demo/demo_client (master) $ git log
    commit 0dbaef0a8d45b36725fe6df20e1f1484709cea1f (HEAD -> master)
    Author: Ryan_ZHENG <***>
    Date:   Wed Oct 27 13:58:48 2021 +0800
    
        [demo_client]add FileA
    

    所以此时:

    • 工作区非空(有FileA);
    • 仓库非空(有“[demo_client]add FileA”的提交记录);
    • 暂存区非空(有index,记录了“FileA的创建”);
  5. 为了进一步了解这三个区域的关系,现在我们尝试将FileA删除:

    # 直接操作工作区,删除文件FileA
    ryan ~/git_demo/demo_client (master) $ rm FileA
    # 查看仓库根目录,FileA已不存在
    ryan ~/git_demo/demo_client (master) $ ll
    total 12
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 14:07 ./
    drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:36 ../
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 13:59 .git/
    
    # 查看.git目录情况
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 14:07 ./
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 14:07 ../
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:58 COMMIT_EDITMSG
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:36 HEAD
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 branches/
    -rw-r--r-- 1 ryan ryan  254 Oct 27 13:36 config
    -rw-r--r-- 1 ryan ryan   73 Oct 27 13:36 description
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 hooks/
    -rw-r--r-- 1 ryan ryan  137 Oct 27 13:58 index
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 info/
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:58 logs/
    drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:58 objects/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 refs/
    
    # 使用git status查看git管理情况
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            deleted:    FileA
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    可以看到,此时git发现FileA已经被删除,但是由于暂存区还是有FileA的,因此认定“删除FileA”的操作not stagged for commit
    所以此时:

    • 工作区空(FileA已被删除);
    • 仓库非空(有“[demo_client]add FileA”的提交记录);
    • 暂存区非空(有index,记录了“FileA的创建”,但没有记录“FileA的删除”);
  6. 然后照例,要向提交这一改动,我们需要先将“FileA的删除”这一行为添加进暂存区。需要注意的是,由于FileA已不在工作区中了,因此此时git add命令需要带上-A参数:

    # 将“删除FileA”添加进暂存区
    ryan ~/git_demo/demo_client (master) $ git add -A FileA
    # 查看仓库根目录的情况
    ryan ~/git_demo/demo_client (master) $ ll
    total 12
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 14:07 ./
    drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:36 ../
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 14:13 .git/
    # 查看.git目录情况
    ryan ~/git_demo/demo_client (master) $ ll .git/
    total 52
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 14:13 ./
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 14:07 ../
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:58 COMMIT_EDITMSG
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:36 HEAD
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 branches/
    -rw-r--r-- 1 ryan ryan  254 Oct 27 13:36 config
    -rw-r--r-- 1 ryan ryan   73 Oct 27 13:36 description
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 hooks/
    -rw-r--r-- 1 ryan ryan   46 Oct 27 14:13 index
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 info/
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:58 logs/
    drwxr-xr-x 7 ryan ryan 4096 Oct 27 13:58 objects/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 refs/
    # git status查看git管理情况
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            deleted:    FileA
    

    可以看到,此时.git/index文件已更新,且git status显示“FileA的删除”已经从not stagged for commit变为to be committed
    所以此时:

    • 工作区空(FileA已被删除);
    • 仓库非空(有“[demo_client]add FileA”的提交记录);
    • 暂存区非空(有index,记录了“FileA的创建”,也记录了“FileA的删除”);

    注意,此时虽然暂存区非空,而工作区为空,但是两者记录的现象是一致的——没有FileA

  7. 最后,我们使用git commit将“FileA的删除”也提交:

    ryan ~/git_demo/demo_client (master) $ git commit -m "[demo_client]delete FileA"
    [master 0b64004] [demo_client]delete FileA
     1 file changed, 0 insertions(+), 0 deletions(-)
     delete mode 100644 FileA
     
    ryan ~/git_demo/demo_client (master) $ ll
    total 12
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 14:07 ./
    drwxr-xr-x 5 ryan ryan 4096 Oct 27 13:36 ../
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 14:19 .git/
    
    ryan ~/git_demo/demo_client (master) $ ll .git
    total 52
    drwxr-xr-x 8 ryan ryan 4096 Oct 27 14:19 ./
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 14:07 ../
    -rw-r--r-- 1 ryan ryan   26 Oct 27 14:19 COMMIT_EDITMSG
    -rw-r--r-- 1 ryan ryan   23 Oct 27 13:36 HEAD
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 branches/
    -rw-r--r-- 1 ryan ryan  254 Oct 27 13:36 config
    -rw-r--r-- 1 ryan ryan   73 Oct 27 13:36 description
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 hooks/
    -rw-r--r-- 1 ryan ryan   65 Oct 27 14:19 index
    drwxr-xr-x 2 ryan ryan 4096 Oct 27 13:36 info/
    drwxr-xr-x 3 ryan ryan 4096 Oct 27 13:58 logs/
    drwxr-xr-x 9 ryan ryan 4096 Oct 27 14:19 objects/
    drwxr-xr-x 4 ryan ryan 4096 Oct 27 13:36 refs/
    
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    nothing to commit, working tree clean
    
    ryan ~/git_demo/demo_client (master) $ git log
    commit 0b64004ae55297fee8ba6453f065a43a9135e5d7 (HEAD -> master)
    Author: Ryan_ZHENG <easter_walk@hotmail.com>
    Date:   Wed Oct 27 14:19:08 2021 +0800
    
        [demo_client]delete FileA
    
    commit 0dbaef0a8d45b36725fe6df20e1f1484709cea1f
    Author: Ryan_ZHENG <easter_walk@hotmail.com>
    Date:   Wed Oct 27 13:58:48 2021 +0800
    
        [demo_client]add FileA
    

    可以看到,此时git status显示工作区又回到了clean的状态,即工作区仓库暂存区三者记录的情况一致;
    此时:

    • 工作区空(FileA已被删除);
    • 仓库非空(有“[demo_client]add FileA”的提交记录);
    • 暂存区非空(有index,记录了“FileA的创建”,也记录了“FileA的删除”);

    跟上面一样,这里需要注意,此时虽然三者的状态不一样,但是现象是一致的——没有FileA,不同的是,对于仓库而言,记录了FileA的创建于删除两个节点;对于暂存区而言,记录了当前目录存在,但没有任何文件在内;而对于工作区,则只知道没有任何文件;

总结

三个区域状态的不同,就可以判断出当前工作区文件对于git仓库的状态,并通过git status中不同类别显示:

细心的同学应该已经发现了如下规律:

  • 工作区存在,暂存区不存在,表现为Untracked
  • 工作区不存在,暂存区存在(或者工作区与暂存区内容不一致),表现为Changes not staged for commit:
  • 暂存区存在,仓库不存在(或者暂存区与仓库内容不一致),表现为Changes to be committed:
  • 三者完全一致,则提示nothing to commit, working tree clean,且没有Untracked

事实上,上面的前三种情况是可以任意排列组合的,甚至可以组合出如下两种情况:

  • 三者完全不一致;
  • 暂存区不存在,仓库存在;

这两种属于比较进阶的使用场景下才会出现的,这里仅简单“造”一下环境,后面在讲解git reset的时候会有更多示例;

  • 三者完全不一致

    # 创建一个FileB文件,内容为bbb
    ryan ~/git_demo/demo_client (master) $ echo "bbb" > FileB
    
    # 查看内容无误
    ryan ~/git_demo/demo_client (master) $ cat FileB
    bbb
    
    # git status查看FileB状态为Untracked
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
            FileB
    
    nothing added to commit but untracked files present (use "git add" to track)
    
    # 将FileB添加进暂存区
    ryan ~/git_demo/demo_client (master) $ git add FileB
    
    # 再次使用git status查看,此时工作区与暂存区进度一致,与仓库不一致
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            new file:   FileB
    
    
    # 修改FileB内容为bbbbbb
    ryan ~/git_demo/demo_client (master) $ echo "bbbbbb" > FileB
    
    # 查看内容无误
    ryan ~/git_demo/demo_client (master) $ cat FileB
    bbbbbb
    
    # 再次使用git status查看,此时工作区与暂存区进度不一致,与仓库也不一致
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            new file:   FileB
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            modified:   FileB
    
    
  • 暂存区不存在,仓库存在;

    #接着上方的环境继续
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            new file:   FileB
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            modified:   FileB
    # 删除FileB,使仓库与工作区都不存在FileB
    ryan ~/git_demo/demo_client (master) $ rm FileB
    # git status查看
    ryan ~/git_demo/demo_client (master) $ git status
    On branch master
    Your branch is based on 'origin/master', but the upstream is gone.
      (use "git branch --unset-upstream" to fixup)
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            new file:   FileB
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            deleted:    FileB
    

最后来张图:
Lite Git (III) - First Commit

上一篇:Linux 笔记 - 第十七章 Linux LVM 逻辑卷管理器


下一篇:使用Bootstrap设置一个div容器为响应式的