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
仓库均没有追踪任何文件,因此仓库是空的。
现在,我们借“完成第一笔提交”这一目的,逐步介绍各个阶段下,不同区域的情况,以加深大家对这三个区域的理解:
-
首先,我们在
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
-
然后,我们通过
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);
-
接下来,我们要想将
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
的创建”);
-
工作区非空(有
-
最后,我们要将“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的创建”);
-
为了进一步了解这三个区域的关系,现在我们尝试将
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
的删除”);
-
工作区空(
-
然后照例,要向提交这一改动,我们需要先将“
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
-
工作区空(
-
最后,我们使用
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
最后来张图: