如何解决在git分支中创建的“物理文件”在哪里?
首先,我创建了App1文件夹,初始化了本地存储库,添加了远程存储库并将其推送到其中:
mkdir App1
git init
git remote add <remote_repo_url>
git push origin master
然后,我创建了一个分支,签出到该分支,在那里创建了一个文件,然后提交:
git branch "firstbranch"
git checkout firstbranch
touch file1.js
git add file1.js
git commit -m "added file1.js"
现在,我想是因为尽管我在第一分支,但我仍在同一本地工作区中工作,所以:
1。)file1.js应该出现在App1文件夹中
2。)如果我结帐回master并检查git status,则应该将file1.js视为未跟踪的文件。
但是实际上发生的是file1.js不在App1文件夹中,当我签出回到master分支并检查git状态时,根本没有关于file1.js的评论。但是,如果我结帐至firstbranch和ls,则会列出file1.js!另外,当我转到.git / branches时,它为空,尽管我希望应该有关于firstbranch的数据。有人可以告诉我这是怎么回事吗? file1.js和有关第一个分支的数据实际上在哪里?
解决方法
没有任何文件。 等待,什么?当然有文件。
嗯,有点。这里的窍门是Git存储 commits 。那是您的基本存储单位:要么提交(通过哈希ID编号),要么根本没有提交。
每个提交存储两件事:
-
提交中的数据是Git知道的每个文件的完整快照。
-
提交中的元数据会记住提交人的姓名和电子邮件地址,依此类推。
从某种意义上说,提交包含文件。但是,它们并没有完全存储为文件。它们存储为Git 对象,特别是 blob对象,它们保存文件的内容,但特别是 not 的名称。这些Blob对象具有哈希ID(与提交具有哈希ID的方式相同)。所有Git对象实际上都存储在.git/objects/
中,但是也有两种存储格式:
-
松散对象存储在单个文件中。这里的松散与打包相反。
-
打包的对象与许多对象一起存储在单个 pack文件中。
(文件的名称分别存储在 tree 对象中,这些对象链接到提交,这些提交保存在 commit 对象中。还有第四种对象,即带注释的标签对象,用于带注释的标签,这四个对象组成了整个对象数据库:所有已提交的内容。
现在,我想是因为尽管我处于第一分支,但我仍在同一本地工作区中工作...
这是查看存储库的错误方法:它将误导您。
查看存储库的正确方法是:
-
这里有一个内部Git对象的集合,您实际上并不需要非常关心它们的格式,但是值得知道的是,每个对象都是完全只读的,并存储在压缩的Git中仅限格式。松散的对象在许多语言中都非常容易阅读,因为它们只是通过标头进行zlib压缩,但是打包后的对象则更加棘手。尽管如此,Git保留将来更改内部存储系统的权利,所以最好让Git为您阅读它们。
-
Git调用了一种东西,它们分别是 index 或 staging区域,或者(最近很少是) cache 。我们不会在这里详细介绍每一个细节,特别是我们将忽略合并,但是在进行新的提交时,了解这对您的工作至关重要。
-
最后,在大多数存储库中(至少您将在其中使用的存储库中)有一个工作树或工作树。 (Git大多称其为工作树,但我更喜欢短期术语。)
鉴于提交中的文件采用压缩,冻结和去重复的纯Git格式,因此对此工作树的需求已十分清楚:您需要以普通权限访问文件文件,您可以阅读和书写。因此,Git将从提交中将文件提取到您的工作树中。
索引本身有点复杂-例如,在发生冲突的合并中,它扮演着更大的角色-但它是方式 Git知道您的文件,以及有关Git索引的很好的单行摘要是这样的:索引包含将要提交到 next 提交中的所有文件。
当您检查一些提交时,Git:
- 使用冻结和重复数据消除的格式进行复制,因此这里没有实际的副本-每个 in 中的文件都会提交到Git的索引中;
- 将该文件扩展到您的工作树中。
通过这种方式,Git的索引现在与您已签出的提交匹配,和使您的文件对您可见,并且采用普通的读/写格式。您的工作树现在是您的,您可以根据需要进行处理。您可以创建,删除,读取和写入文件。您可以使用这些工作树文件执行计算机可以执行的任何操作,因为它们是您的 。
不过,Git 知道的文件仍然以冻结格式存在于Git的索引中,准备进行新的提交:
-
如果您以某种方式更改您的工作树中的文件,则必须告诉Git:将此更新的文件复制回索引中。 ,Git会知道更新的文件。
-
如果删除文件,则应将其从工作树和Git的索引中删除。 (例如,
git rm
命令将执行此操作。)由于它不在Git的索引中,因此不会在下一次提交中。 -
如果创建一个全新文件,并希望将其放入 next 提交中,则应让Git添加它。
git add
命令实际上可以处理所有这三种情况,因为它告诉Git:使索引副本与工作树副本匹配。如果您删除了工作树,复制,git add
删除要匹配的索引副本。如果您已经更新了工作树副本,或者该文件的工作树副本(以该名称命名)根本不在索引中,则git add
实际上会将文件转换为特殊的冻结文件,然后-压缩格式,并根据需要更新或创建索引副本。
换句话说,无论您在工作树中执行什么操作,git add
都会通过使Git的索引与您的工作树匹配来使Git的索引反映此更改或这些更改。因此,索引现在将可以进行 next 提交。
请记住,索引开始时与当前提交匹配。您使用git checkout
或git switch
选择的当前提交具有冻结,压缩和重复数据删除格式的文件快照。 Git的索引最初以相同的格式保存所有相同的文件:它与提交匹配。您的工作树最初也保存了相同的文件,但是格式可用。
通过修改工作树,您进行了一些更改,以使提交副本和索引副本仍然匹配,但是您的工作树却不匹配。通过更新索引(该文件以冻结的格式保存文件,但让您替换这些提交不能执行的索引),您已经更改了内容,以便提交可以复制不再再匹配索引副本,但是现在索引和工作树副本匹配。
如果您运行git commit
now ,则 new 提交将与Git的索引匹配,该索引与您的工作树匹配,然后您将返回快乐状态,其中所有工作树文件都永久保存在当前提交中。请注意,git commit
成功后,新的提交将变为。
现在,假设您处于这种快乐状态(每个文件的所有三个副本都匹配),并且您使用git checkout
或git switch
来切换到其他其他提交。 Git将:
- 删除所有与 this 提交一起使用的索引副本,将它们替换为与您要使用的新提交一起使用的索引副本;和
- 同时删除所有与此 this 提交一起工作的工作树副本,将它们替换为与新提交一起进行的未冻结,扩展,去Git化的纯文件。您要使用。
新的提交成为您当前的提交,并且您再次处于这种幸福的状态,每个文件的所有三个副本都匹配。
但是:如果您选择将切换为的提交与您的提交具有不同的文件名和/或文件内容从切换到,现在,Git已用与您刚刚将切换到的提交匹配的工作树替换了。 >
请注意,Git不在乎您使用的是哪个分支名称。相反,Git会在乎您使用的是 commit 。分支名称很有用,特别是对人类而言,因为我们很想记住那些看起来很随意的哈希ID,但它确实有用作为查找提交的编号的一种方式。分支名称保存分支中 last 提交的哈希ID。
当您进行新的提交时,Git将打包索引中的所有文件,然后 ,添加适当的元数据,并将其写为新的提交。此新提交将获得一个新的唯一编号:一个新的哈希ID。然后,Git将此哈希ID放入当前分支名称,这就是分支现在在其中具有新提交的方式。这意味着名称本身现在具有与之前不同的哈希ID。
为使所有这些变得有意义,如果您绘制您的提交可能会有所帮助。使用诸如大写字母之类的东西来代表真实的哈希ID。像这样绘制提交:
... <-F <-G <-H <-- master
分支名称 master
包含我们称为H
的提交的真实哈希ID。提交H
本身在其元数据中具有先前提交G
的真实哈希ID。提交G
在F
的元数据中具有G
的哈希ID。因此,通过使用 name master
,我们可以让Git查找提交H
,Git可以从中查找提交G
,然后找到F
,等等。
换句话说,Git向后向后工作。分支名称仅保存 last 提交的哈希ID。现在,可以更轻松地查看新提交的工作方式。让我们创建一个新的分支名称feature
,该分支名称还包含H
的哈希ID ,如下所示:
...--F--G--H <-- feature,master
让我们在(HEAD)
之后添加feature
一词,以表明我们做了git checkout feature
或git switch feature
以选择提交H
:
...--F--G--H <-- feature (HEAD),master
提交H
现在是我们当前的提交,并且在Git的索引和我们的工作树中。我们更改了一些文件,甚至可能添加和/或删除了一些文件,并使用git add
更新Git的索引以进行匹配。然后我们运行git commit
。
Git将索引紧接着中的内容打包,这就是我们的工作树中的内容,因为我们正确使用了git add
。 Git为提交I
添加了适当的元数据:我们的名称,当前日期和时间,给Git的日志消息,以及-为了使后向工作正常-现有提交H
的哈希ID,因此新的提交I
向后指向H
:
...--F--G--H <-- feature (HEAD),master
\
I
现在,提交I
存在(并且具有新的哈希ID),Git将该哈希ID写入附加了HEAD
的 name 中,因此{{ 1}}指向新的提交feature
:
I
如果我们...--F--G--H <-- master
\
I <-- feature (HEAD)
,Git将切换为提交git checkout master
,并将H
附加到名称HEAD
:
master
我们当前的提交现在是...--F--G--H <-- master (HEAD)
\
I <-- feature
,而不是H
,并且我们的工作树将匹配提交I
,而不是提交H
。如果我们再次 now 重新提交,则名称I
将被更新:
master
这是分支的工作方式。 Git与 commits有关。分支名称用于让我们(和Git)查找提交哈希ID。我们在工作树中看到并使用的文件根本不是Git中的文件。 Git以特殊的仅Git格式存储所有提交(每个文件的完整快照,它们在我们运行...--F--G--H--J <-- master (HEAD)
\
I <-- feature
时出现在Git的索引中)。我们选择要使用的提交,然后Git将提交提取到我们的工作树中。
文件file1.js将保留在firstbranch
分支中,直到您对master
分支进行PR并将其合并为止,您可以看看此link,我希望它可以帮助你。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。