git - 正在创建分支而不添加
问题描述
我想为我的存储库创建一个新的分支,因为我遇到了以前的问题。
但是,我正在尝试的任何方法都不起作用。当我
(venv) C:\..\..\PycharmProjects\WebP1\DEMOPROJECT>git ls-tree --name-only hope
在创建新分支时运行时,我得到
.gitignore
DEMOAPP
DEMOPROJECT
__init__.py
__pycache__
db.sqlite3
manage.py
media
static
这不是我想要的,因为我希望 gitignore 忽略它
*.log
*.pot
*.pyc
__pycache__/
local_settings.py
db.sqlite3
media
我已经尝试过--orphan
分支,但它似乎总是让我回到我不再想要的错误提交。出于某种我不想发生的原因,DEMOPROJECT 文件夹也被制作成一个子模块。请问我该如何解决?有什么add
我需要做的吗?
解决方案
正如Gabriel 所说,您从现有提交创建一个新分支,因此它将从现有提交的内容开始。您试图git checkout --orphan
避免从现有提交开始,这是一个有效且有时是明智的做法,但这可能不是您想要的。它失败了,因为即使那样,您也是从现有索引和 work-tree开始的。
(我们可以解决这个问题:
出于某种我不想发生的原因,DEMOPROJECT 文件夹也被设为子模块。
稍后,虽然单独的问题更合适。而且,如果你已经知道接下来的几节,你可以跳到关于索引的那一节。)
对 Git 来说重要的是提交
如果你打算使用 Git,你需要习惯 Git 的小怪癖。其中之一是分支——或者更准确地说,分支名称——对 Git 来说并不是那么重要。重要的是提交。首先准确了解提交的作用和代表的内容,然后引入分支名称至关重要。
每个提交都包含一组文件的快照。那部分非常简单。快照是您的git ls-tree
输出中显示的内容——尽管从技术上讲git ls-tree
,这里已经总结了整个子树的文件;您需要git ls-tree -r
查看快照中的所有文件。
提交还包含一些元数据:例如,创建提交的人的姓名和电子邮件地址,以及日期和时间戳。(实际上,其中有两个。)它包含一个日志消息,您在提交时提供该消息:您应该输入一些东西来告诉未来 - 您为什么要提交此提交。而且——非常重要的是——每个提交都包含一定数量的父提交哈希 ID(通常只有一个)。
每一次提交,一旦做出,都有一个唯一的哈希 ID。Universe 1中的每个 Git也同意该提交获得该哈希 ID,并且没有其他提交获得该哈希 ID。一旦分配了哈希 ID,提交中的任何内容都不会改变。(原因是这个哈希 ID 实际上是提交对象内容的加密校验和。这就是宇宙中每个 Git 能够同意这个提交获得这个哈希 ID 的方式。)
您已经看到了这些哈希 ID:它们是大而丑陋的字符串,例如745f6812895b31c02b29bdfe4ae8e5498f776c26
. 它们对人类没有用,但对 Git 有用。Git 使用哈希 ID 来查找实际提交,然后从中找到文件,依此类推。
提交中存储的父哈希 ID 让 Git 可以找到在此特定提交之前的提交。也就是说,给定一系列具有随机散列 ID 的提交,我们可以用单个大写字母代表真正的散列 ID 来绘制它们,我们可以这样绘制它们:
... <-F <-G <-H
这H
是最后一次提交的哈希 ID。它存储了较早提交的哈希 ID G
,因此 Git 可以加载提交G
。如果 Git 确实加载了它,则G
存储先前提交的哈希 ID F
,依此类推。我们说H
指向 G
,G
指向F
,等等。
1实际上,这仅限于与另一个 Git交换此提交的每个 Git。如果两个 Git 存储库从未相遇,它们可以对不同的提交使用相同的哈希 ID。他们会的机会很小:目前是 2 160分之一。但是,如果两个 Git 存储库确实会面并交换提交——就像git push
你提交到 GitHub 时那样——它们不会重用哈希 ID:每个提交对于每个提交都是唯一的。
分支名称指向一个提交
这就是分支名称的用武之地。像这样的分支名称master
只包含一个哈希 ID。我们确保它拥有最新的哈希 ID,因此它master
指向H
:
... <-F <-G <-H <--master
与提交本身不同,名称 可以更改。为了进行新的提交,我们让 Git 写出提交的内容——所有文件的快照、日志消息、来自 的您的姓名git config --get user.name
等等,将新提交的父哈希设置为H
. 结果是我们将调用一些新的唯一哈希 ID I
:
...--F--G--H <-- master
\
I
既然I
存在,Git 只需将其哈希 ID 写入 name master
:
...--F--G--H
\
I <-- master
现在I
是分支中的最后一次提交。(现在我们可以把它画成一条直线,并I
指向H
。请注意,我们根本没有改变H
:我们只是添加了I
,指向现有的H
。)
这就是分支的增长方式:我们让 Git 添加一个新的提交。Git 写出快照以及元数据。新提交的父提交是当前提交——我们已经签出的那个。新的提交获得一个新的、唯一的哈希 ID。作为提交操作的最后一步,Git 将新的哈希 ID写入某个分支名称——我们已经签出的分支。
请注意,当我们进行第一次提交时,我们没有现有的提交。所以第一次提交的父级根本不存在。这个新的提交没有父母;Git 将此称为根提交。这使我们获得了存储库中的第一个提交,因此名称master
也可以存在:
A <-- master
之后,下一个提交B
将A
作为其父提交,Git 将写入B
名称master
。
这也是如何git checkout --orphan
工作的。它所做的是进行设置,以便您进行的下一次提交将像往常一样使用它将使用的任何内容,但没有父级:它将是根提交。因此,如果您有:
A--B--C--D--E--F--G--H <-- master
并做:
git checkout --orphan newbranch
git commit
你得到:
A--B--C--D--E--F--G--H <-- master
I <-- newbranch (HEAD)
(当我们有多个分支时,将特殊名称HEAD
准确地附加到一个分支上很有用,这样我们就可以看到哪一个是当前分支。)
问题是,这个新提交与现有提交I
存储相同的快照H
,除非您更改要存储的快照。
索引是每个新快照的来源
Git 当然有提交,这些提交是永远冻结的。提交中的文件以特殊的、压缩的、只读的、仅限 Git 的格式存储。我喜欢将这些文件称为“冻干文件”。这对于存档非常有用,但对于完成任何新工作完全没有用。
因此,Git 能够从提交中提取文件到工作区。这个工作区,称为您的工作树或工作树或这些名称的一些变体,具有您计算机的普通格式的普通文件和文件夹/目录。这使您可以与他们一起工作。这是你工作的地方。
您可以在工作树中包含不想放入下一次提交的文件。但是你的下一个提交在哪里?一些版本控制系统说你的工作树是你的下一个提交。这非常简单易用,所以它不是 Git 所做的。:-)
相反,在 Git 中,您的下一次提交存储在 Git 调用的不同地方,即index或staging area,或(现在很少)cache。这三个名字都涵盖一件事。索引中的内容是将进入下一次提交的所有文件。这些文件处于冻干形式,可以提交,但与提交的文件不同,您可以将它们替换为新的和不同的文件,甚至完全删除它们。
你不能直接看到索引。好吧,你可以,但它有点尴尬。如果您只有几个文件,请运行git ls-files --stage
以查看索引中的内容。如果你有很多文件,这会产生很多输出!下面是 Git 存储库中 Git 本身的一个片段:
100644 6e69877f25791632d98bf7b109a2eaebd04c96af 0 ws.c
100644 9f6c65a5809754717f8c51f809eae78f435bcd12 0 wt-status.c
100644 77dad5b92048851c622a35d8b34d802fbd0ecac6 0 wt-status.h
100644 8509f9ea223a1282a367874c3e3a3ef0c351a30f 0 xdiff-interface.c
100644 ede4246bbd3397086f90217539a2d07a35a4b986 0 xdiff-interface.h
100644 032e3a9f41a2f79eaab78ae36666b8b6218b3899 0 xdiff/xdiff.h
100644 1f1f4a3c7808435f73b0ffd1c35d5b0572516b6c 0 xdiff/xdiffi.c
请注意,此输出中没有目录/文件夹。那是因为 Git 不存储目录。它只是存储文件。如果需要保存文件,Git 只需创建一个目录/文件夹。例如,文件xdiff/xdiff.h
是Git,但对于您的计算机,该文件在名为. 因此,如果必须,Git 将首先将 Git 的文件写入您计算机的-within- 。xdiff.h
xdiff
xdiff
xdiff/xdiff.h
xdiff.h
xdiff
跟踪文件是索引中的文件
假设您的工作树中有一个名为main.pyc
. 如果该文件也在索引中,main.pyc
则被跟踪。如果此文件不在索引中,则该文件未跟踪。
当你git checkout
进行一些提交时,Git 会将提交中的所有文件复制到索引中,然后复制到你的工作树中。当您git checkout
进行其他提交时,Git 会根据需要切换所有索引和工作树文件。
您可以随时git add
在工作树文件上运行。这会将工作树文件复制到索引。如果之前有,那就换了。如果以前不存在,则已添加。
您还可以随时git rm
在任何文件名上运行。这将删除索引副本和工作树副本。
而且,当然,您可以运行git commit
. 每当您这样做时,Git 都会立即打包索引中的所有内容并使用它来进行新的提交。新提交的父提交是当前提交——您在开始时签出的提交。新提交成为当前分支(您签出的那个)中的最后一个提交。
该.gitignore
文件只能忽略未跟踪的文件
如果一个文件被跟踪——记住,这意味着它现在在索引中——列出该文件是.gitignore
没有效果的。
因此,如果您不想提交文件,但它已经在索引中,则必须将其从索引中删除:
git rm --cached file
该--cached
选项告诉 Git,即使它从索引中删除文件,它也应该单独保留工作树副本。因此,在删除之后,下一次提交将不会拥有该文件,而不会被跟踪。
但是,有一个问题:如果此提交连接回某个较早的提交,并且您曾经检查过较早的提交,则该文件会将文件写入索引和您的工作树。然后,当您切换回没有该文件的新提交时,Git 将从索引和您的工作树中删除该文件。
请注意,如果您要创建一个初始提交没有先前提交--orphan
的新分支,那会有所帮助。但是,旧分支仍然存在,并且仍然具有包含该文件的提交。
结论(在我们进入子模块之前)
您可能想要--orphan
,但如果您真的想要它,也许您只想从一个全新的 Git 存储库开始。
在任何情况下,如果您希望在以后的提交中不跟踪文件,如果它们现在在索引中,则必须将它们从索引中删除。您可以使用git rm
,将它们从索引和工作树中删除;或者您可以使用git rm --cached
,它将它们从索引中删除,而不是从您的工作树中删除。
一旦文件未被跟踪,您可以将它们列出.gitignore
以确保它们将来不会被添加到索引中,即使它们在您的工作树中。这也不再git status
抱怨未跟踪的文件。请注意,在检出期间,检出任何具有该文件的旧提交,会将其放入索引中。切换回没有该文件的较新提交将从索引和工作树中删除该文件。确保这没问题,否则在查看旧提交时要非常小心。
子模块
我只会简单地谈到这一点,因为子模块可能会变得非常复杂。
在 Git 存储库中,不是工作树的东西通常都隐藏在.git
工作树顶层命名的目录/文件夹中。
如果你的工作树的某个子目录/子文件夹有一个.git
目录,你的 Git 会假设其他一些 Git正在控制你的树的那个部分。然后你的 Git 将决定它不应该对任何这些进行源代码控制。相反,您的 Git 将添加对其他 Git 存储库中提交的引用。此引用采用索引中的gitlink的形式。如果你使用,你可以用(gitlink)git ls-files --stage
把它看成一个“文件” 。mode 160000
为了让 Git不这样做,请确保您的工作树都不是它自己的存储库:没有子文件.git
夹里面有文件夹。使用子模块时,Git 会将.git
文件夹迁移到超级项目的.git
文件夹中,替换为一个文件.git
,其内容是超级项目的路径.git
,因此如果子文件夹有.git
文件,这也可以触发子模块代码。
推荐阅读
- android - 在 Android 应用程序中查看 .PDF 文件 - 有可用的 Phonegap 插件吗?
- asp.net-core - 如何在 F# Asp Core Wep API 中序列化 F# 可区分联合类型
- c - 在宏定义中使用成员名称
- c - 循环彩色动画
- python - 尝试使用 cell.offset 在源工作表和目标工作表具有不同起始行的工作表之间进行复制
- python - 如何使用 numpy 正确计算神经网络中的梯度
- javascript - 使用评估作为结果的 Javascript 三元
- javascript - React 组件之间基于状态的实时更新
- ios - React Native 0.61 仍然需要我链接原生模块
- python - 旋转字典的值