Git索引如何创建与提交

75次阅读
没有评论

共计 5522 个字符,预计需要花费 14 分钟才能阅读完成。

这篇“Git 索引如何创建与提交”文章的知识点大部分人都不太理解,所以丸趣 TV 小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Git 索引如何创建与提交”文章吧。

  不一样的索引

Git 索引是一个在你的工作目录 (working tree) 和项目仓库间的暂存区域(staging area)。有了它,   你可以把许多内容的修改一起提交(commit)。如果你创建了一个提交(commit),那么提交的一般是暂存区里的内容, 而不是工作目录中的内容。

一个 Git 项目中文件的状态大概分成下面的两大类,而第二大类又分为三小类:

1、未被跟踪的文件(untracked file)

2、已被跟踪的文件(tracked file)

          1、被修改但未被暂存的文件(changed but not updated 或 modified)

          2、已暂存可以被提交的文件(changes to be committed 或 staged)

          3、自上次提交以来,未修改的文件(clean 或 unmodified)

看到上面的这么多的规则,大家早就头大了吧。老办法,我们建一个 Git 测试项目来试验一下:

我们先来建一个空的项目:

$rm -rf stage_proj
$mkdir stage_proj
$cd stage_proj
$git init
Initialized empty Git repository in /home/test/work/test_stage_proj/.git/

我们还创建一个内容是“hello, world”的文件:

$echo  hello,world    readme.txt

现在来看一下当前工作目录的状态,大家可以看到“readme.txt”处于未被跟踪的状态(untracked file):

$git status
# On branch master
# Initial commit
# Untracked files:
# (use  git add ...  to include in what will be committed)
# readme.txt
nothing added to commit but untracked files present (use  git add  to track)

把“readme.txt 加到暂存区:$git add readme.txt

现在再看一下当前工作目录的状态:

$git status
# On branch master
# Initial commit
# Changes to be committed:
# (use  git rm --cached ...  to unstage)
# new file: readme.txt
#

可以看到现在 readme.txt 的状态变成了已暂存可以被提交(changes to be committed),这意味着我们下一步可以直接执行“git  commit“把这个文件提交到本地的仓库里去了。

暂存区 (staging  area) 一般存放在“git 目录“下的 index 文件 (.git/index) 中,所以我们把暂存区有时也叫作索引(index)。索引是一个二进制格式的文件,里面存放了与当前暂存内容相关的信息,包括暂存的文件名、文件内容的 SHA1 哈希串值和文件访问权限,整个索引文件的内容以暂存的文件名进行排   序保存的。

但是我不想马上就把文件提交,我想看一下暂存区 (staging area) 里的内容,我们执行 git ls-files 命令看一下:

$git ls-files --stage
100644 2d832d9044c698081e59c322d5a2a459da546469 0 readme.txt

我们如果有看过上一篇文章里 的 庖丁解牛 ,   你会发现“git 目录“里多出了”.git/objects/2d/832d9044c698081e59c322d5a2a459da546469”这么一个文件,再执行“git  cat-file -p 2d832d”  的话,就可以看到里面的内容正是“hello,world。Git 在把一个文件添加暂存区时,不但把它在索引文件 (.git/index) 里挂了号,而且把它的内容先保存到了“git 目录“里面去了。

如果我们执行”git add“命令时不小心把不需要的文件也加入到暂存区中话,可以执行“git rm –cached filename   来把误添加的文件从暂存区中移除。

现在我们先在 readme.txt 文件上做一些修改后:

$echo  hello,world2    readme.txt

再来看一下暂存区的变化:

$git status
# On branch master
# Initial commit
# Changes to be committed:
# (use  git rm --cached ...  to unstage)
# new file: readme.txt
# Changed but not updated:
# (use  git add ...  to update what will be committed)
# (use  git checkout -- ...  to discard changes in working directory)
# modified: readme.txt
#

大家可以看到命令输出里多了一块内容:“changed but not updated …… modified:  readme.txt”。大家可能会觉得很奇怪,我前面不是把 readme.txt 这个文件给添加到暂存区里去了吗,这里怎么又提示我未添加到暂存区  (changed but not updated)呢,是不是 Git 搞错了呀。

Git 没有错,每次执行“git  add”添加文件到暂存区时,它都会把文件内容进行 SHA1 哈希运算,在索引文件中新加一项,再把文件内容存放到本地的“git 目录“里。如果在上次执行“git  add”之后再对文件的内容进行了修改,那么在执行“git  status”命令时,Git 会对文件内容进行 SHA1 哈希运算就会发现文件又被修改了,这时“readme.txt“就同时呈现了两个状态:被修改但未被暂存的文件(changed  but not updated),已暂存可以被提交的文件(changes to be committed)。如果我们这时提交的话,就是只会提交 *** 次“git  add 所以暂存的文件内容。

我现在对于“hello,world2 的这个修改不是很满意,想要撤消这个修改,可以执行 git checkout 这个命令:

$git checkout -- readme.txt

现在再来看一下仓库里工作目录的状态:

$git status
# On branch master
# Initial commit
# Changes to be committed:
# (use  git rm --cached ...  to unstage)
# new file: readme.txt
#

好的,现在项目恢复到我想要的状态了,下面我就用 git commit 命令把这个修改提交了吧:

$git commit -m  project init 
[master (root-commit) 6cdae57] project init 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 readme.txt

现在我们再来看一下工作目录的状态:

$git status
# On branch master
nothing to commit (working directory clean)

大家可以看到“nothing to commit (working directory clean)”; 如果一个工作树 (working  tree) 中所有的修改都已提交到了当前分支里(current head),那么就说它是干净的(clean),反之它就是脏的(dirty)。

SHA1 值内容寻址

正如 Git is the next Unix 一文中所说的一样,Git 是一种全新的使用数据的方式(Git is a totally new way to  operate on  data)。Git 把它所管理的所有对象(blob,tree,commit,tag hellip; hellip;),全部根据它们的内容生成 SHA1 哈希串值作为对象名; 根据目前的数学知识,如果两块数据的 SHA1 哈希串值相等,那么我们就可以认为这两块数据是相同   的。这样会带来的几个好处:

Git 只要比较对象名,就可以很快的判断两个对象的内容是否相同。

因为在每个仓库 (repository) 的“对象名”的计算方法都完全一样,如果同样的内容存在两个不同的仓库中,就会存在相同的“对象名”。

Git 还可以通过检查对象内容的 SHA1 的哈希值和“对象名”是否匹配,来判断对象内容是否正确。

我们通过下面的例子,来验证上面所说的是否属实。现在创建一个和“readme.txt“内容完全相同的文件”readme2.txt“,然后再把它提交到本地仓库中:

$echo  hello,world    readme2.txt
$git add readme2.txt
$git commit -m  add new file: readme2.txt 
[master 6200c2c] add new file: readme2.txt
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 readme2.txt

下面的这条很复杂的命令是查看当前的提交 (HEAD) 所包含的 blob 对象:

$git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme2.txt

我们再来看看上一次提交 (HEAD^) 所包含的 blob 对象:

$git cat-file -p HEAD^ | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme.txt

很明显大家看到尽管当前的提交比前一次多了一个文件,但是它们之间却是在共用同一个 blob 对象:“2d832d9”。

No delta, just snapshot

Git 与大部分你熟悉的版本控制系统,如 Subversion、CVS、Perforce 之间的差别是很大的。传统系统使用的是:“增量文件系统” (Delta Storage  systems),它们存储是每次提交之间的差异。而 Git 正好与之相反,它是保存的是每次提交的完整内容(snapshot); 它会在提交前根据要提交   的内容求 SHA1 哈希串值作为对象名,看仓库内是否有相同的对象,如果没有就将在“.git/objects 目录创建对应的对象,如果有就会重用已有的   对象,以节约空间。

下面我们来试验一下 Git 是否真的是以“snapshot”方式保存提交的内容。

先修改一下 readme.txt,给里面加点内容,再把它暂存,*** 提交到本地仓库中:

$echo  hello,world2    readme.txt
$git add readme.txt
$git commit -m  add new content for readme.txt 
[master c26c2e7] add new content for readme.txt 1 files changed, 1 insertions(+), 0 deletions(-)

我们现在看看当前版本所包含的 blob 对象有哪些:

$git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2e4e85a61968db0c9ac294f76de70575a62822e1 readme.txt
100644 blob 2d832d9044c698081e59c322d5a2a459da546469 readme2.txt

从上面的命令输出,我们可以看到 readme.txt 已经对应了一个新的 blob 对象:“2e4e85a”,而之前版本的 readme.txt“对应的 blob 对象是:“2d832d9”。下面我们再来看一看这两个”blob“里面的内容和我们的预期是否相同:

$git cat-file -p 2e4e85a
hello,world
hello,world2
$git cat-file -p 2d832d9
hello,world

大家可以看到,每一次提交的文件内容还是全部保存的(snapshot)。

以上就是关于“Git 索引如何创建与提交”这篇文章的内容,相信大家都有了一定的了解,希望丸趣 TV 小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-04发表,共计5522字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)