Git元数据 - 是否有一种方法可以添加与每个分支无关的Git元数据?

4

最终目标:我想要使用Git跟踪文件,但是希望这些文件的版本在所有分支中都是相同的。如果使用gitignore将文件忽略掉,那么在所有分支中这些文件都是相同的,但是很不幸它们并没有被跟踪。当我执行git push等命令时,我需要这些文件被传递到其他仓库中。

例如,在.git文件夹中通常会忽略掉一些数据。我想要添加一些数据到我的仓库中,并使其独立于所有分支,但是数据仍然出现在所有分支中,当你克隆仓库时,这些数据也会呈现出来。

这个可能吗?例如,如果.git目录看起来像:

.git/
  branches/
  hooks/
  objects/
  config
  HEAD
  index

我在考虑添加一个文件夹:
.git/
  .oresoftware/

我希望在其中放置数据,而这些数据独立于所有分支。

我认为这不起作用,因为.git仓库中的数据并没有真正被跟踪。我正在寻找一些被Git跟踪但在所有分支中相同的东西...

更新:阅读了答案并思考了一段时间后,我想也许如果我用新文件修改初始提交,那么它可能会奇妙地工作,但是当然这不是Git的工作方式,每个提交都是完整的快照,所以在事后更改历史提交不会改变较新的提交。


1
作为初始提交,放一些代码? - evolutionxbox
@evolutionxbox 嗯?抱歉,我没听清楚。 - Alexander Mills
为了在所有分支中都有可跟踪的代码,它必须位于所有分支的父提交中。就像初始提交一样。 - evolutionxbox
好的,这是个好主意,但如果数据是在初始提交之后很长时间才添加的,我必须处理数据不在初始提交中的情况。有很多原因,其中包括数据需要稍后进行修改的原因。 - Alexander Mills
如果您希望数据在所有分支中都可用,那么为什么要将其添加到.git\文件夹中,而您知道它不会被跟踪? - vsr
好的。要么将内容添加到每个分支中,要么将其放在每个分支的祖先提交中。 - evolutionxbox
2个回答

3

好的,我现在理解您的问题了。基本上,您需要将数据添加到可见文件夹中,以便git跟踪它,即在其中一个分支中使用git add <data>,然后将此分支合并master,随后将其他两个分支与master同步(git fetch origin master && git merge origin master)。 在这种情况下,由于您在git中添加了新文件/文件夹,因此您将不会面临合并冲突。最后,您的数据将在所有分支中都可用。 编辑(基于另一个用户的评论):git cherry-pick <commit-hash> 是另一种应用特定提交到分支的方法。


1
为什么要合并呢?你可以挑选提交,这样只有新内容会被添加。 - evolutionxbox
@evolutionxbox 好的,我更新了答案。我选择了一种比较简单的方式,因为我认为提问者对git不是很熟悉。感谢你的建议。 - vsr

1

通常 .git 文件夹中的数据会被 Git 忽略。

这不仅是典型情况,对于 Git 的安全模型来说也是必要的。

(过去,Git 存在一些 bug,你可以创建名为 .GIT/whatever 的文件并将它们放入仓库中,然后在 Windows 和 MacOS 上检出时它们会存在于 .git/whatever 中,因为这些系统默认忽略大小写:一个名为 .GIT/foo 的文件实际上会被创建为 .git/foo,因为此时 .git 已经存在。这个 bug 在现代的 Git 中已经得到了修复。)

我想添加一些数据到我的仓库,使这些数据独立于所有分支,但仍然出现在所有分支中,而且当你克隆仓库时,这些数据也会显示出来。

这种情况可能吗?

不可能,但有其他方法可以实现你的需求。

克隆一个仓库相当于以下步骤:

  • 创建一个空目录(或使用现有的目录):mkdir path
  • 在此处创建一个新的、空的 Git 存储库:cd path && git init
  • 为 URL 添加一个名为 origin远程git remote add origin url
  • 从该远程获取所有内容:git fetch origin
  • 通过 git checkout 创建一个分支:git checkout branch,其中 branch 通常是从前面的 git fetch 步骤中创建的远程跟踪名称。

有一些历史特殊性,以及如果出现问题的话可能会存在问题,因此上述方法并不完美。它还省略了一个可选的git config步骤。最后创建的分支是您-b参数指定的分支。如果您的-b参数命名为标签而不是分支,则Git只会检出一个分离的HEAD,而不创建任何分支。如果您没有提供-b参数,则Git使用来自远程的指令来确定要创建哪个分支。默认情况下,也就是通常情况下,会创建一个指向与origin/master相同提交的master分支。

一旦在存储库中有一个分支或多个分支,这些分支——更准确地说,那些名称,如“master”和“develop”等——都归属于拥有存储库的人。他们可以为所欲为;你作为克隆它们的存储库的所有者,无法阻止他们。你不能让他们在他们的分支中显示某个文件。当然,我们也可以这样说整个存储库,这样的论点有点荒谬:你确实无法控制他们;整个存储库都是他们自己想怎么处理就怎么处理。
因此,你想要的是使他们能够轻松地将某些内容安装到某个文件中。做到这一点的方法是使内容可以通过一些简单的名称访问。但是Git提供了哪些名称呢?
在底层,Git 存储的是提交(commits),这些提交又存储了树(trees)(路径名),这些树又存储了 blob(文件内容)。任何给定的提交、树或 blob 的实际名称都是原始哈希 ID,哈希 ID 是不可预测的,并且通常对人类不太有用或无法访问。因此,你可以告诉人们提取哈希 ID 为 1bdc91e282c5393c527b3902a208227c19971b84 的内容到 .oresoftware/foo 中,但是(1)哈希 ID 是难以理解的,(2)谁想要输入那么多?如果你有多个文件,你需要一个 blob 哈希 ID 对应一个文件。很烦人!但有更好的方法。你可以创建一个包含名为 .oresoftware/foo、.oresoftware/bar 等文件的提交对象。这是一个普通的提交,可以随时提取到普通的工作树中。

现在假设您将此提交放在名为ORESOFTWARE的分支上。然后您可以告诉其他人应该运行:

git checkout origin/ORESOFTWARE -- .oresoftware && git reset .oresoftware

这样做可能并不更短,但至少没有充满难以理解的哈希ID。

只要他们有远程跟踪名称(来自git clonegit fetch),git checkout就会在他们的工作树中创建.oresoftwaregit reset .oresoftware将从索引中删除git checkout在其中创建的.oresoftware条目。 如果/.oresoftware/.gitignore中列出,则工作树文件将被忽略。 这意味着您必须在每个分支的每个提示提交中都有一个.gitignore,以便该目录将方便地自动忽略,但这很容易做到。

最后,您可以说,而不是指导其他人运行两个看似神奇的Git命令:

运行 ./setup.sh

这意味着你可以把这两个Git命令放进一个shell脚本setup.sh中,然后在每个分支的末端提供这个脚本,就像你在每个分支末端提供.gitignore文件一样。此外,你甚至可以让你的软件构建过程自动运行./setup.sh,这样你就不需要他们采取任何特殊的行动。

如果你决定更改.oresoftware中的文件,你只需要在自己的ORESOFTWARE分支上进行新的提交。这可以(并且可能应该)只包含.oresoftware目录。因为构建过程会在每次构建时重新提取目录,所以git fetch将获取你的用户更新的origin/ORESOFTWARE远程跟踪名称,然后会得到更新的文件。


这可能可行,但对于我的用例来说并不是很方便。从长远来看,维护额外的分支的开销最多也是令人烦恼的。我并不是在责怪你,我想这是 Git 模型的限制。 - Alexander Mills
我希望有一种方法可以在Git中忽略某些内容,但仍将其保留在版本控制中。这就像分支忽略某些内容,但不是仓库忽略它。因此,当您将本地分支与远程分支合并时,就需要进行合并。 - Alexander Mills
或者,不如使用git-stash,它和你的解决方案很相似。 - Alexander Mills
git notes 使提交成为特殊的,因为提交中文件的名称是哈希 ID,所以当 git log 查看一个提交并且有哈希 ID,Git 可以查找到 refs/notes/commits 指向的提交。假设问题提交是 a1b2c3...,如果备注提交包含名为 a1b2c3... 的文件,则 git log 显示该备注文件的内容。 - torek
同时,git stash 会创建一个临时的提交。你可能会感觉到这里正在形成一个主题。 :-) - torek
嗯,我明白主题了 :) 嗯,这不容易,老实说,忽略该文件似乎是最好的选择。 - Alexander Mills

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接