是否可以在git存储库之外添加和提交文件?

是否可以在git存储库之外添加和提交文件?,git,Git,我们在系统的各个角落都有文本文件,我们计划将这些文件中的所有修改添加到git存储库中 每次对这些文件进行修改时,都是由脚本进行的。因此,我们计划向该脚本添加新命令,以将文件添加到git存储库。但是,这些修改是并行的 我们可以根据每个文件的原始路径为其构建一个代表原始位置的路径 是否可以同时将这些文件添加到git存储库 就像一个加入add+commit并同时指向外部文件路径和存储库对应路径的原子操作一样。比如: git--user=“Script1”--git dir=/home/repo/fil

我们在系统的各个角落都有文本文件,我们计划将这些文件中的所有修改添加到git存储库中

每次对这些文件进行修改时,都是由脚本进行的。因此,我们计划向该脚本添加新命令,以将文件添加到git存储库。但是,这些修改是并行的

我们可以根据每个文件的原始路径为其构建一个代表原始位置的路径

是否可以同时将这些文件添加到git存储库

就像一个加入add+commit并同时指向外部文件路径和存储库对应路径的原子操作一样。比如:


git--user=“Script1”--git dir=/home/repo/filescolection.git/.git add--external path=/home/user1/file.txt--repo path=home\u user1\u files.txt

不可能。您可以考虑创建一个巨大的Git存储库,多个Git存储库,重新考虑您的文件结构,以将其全部包含在一个目录中(如果可能的话),或者使用像DOCKER之类的东西来创建整个计算机的图像。

< P>答案是“否”和“是”。1</P> 如果您计划只使用Git“ceral”命令,那么很明显是“no”,因为这些命令使用一个(单个)工作树的概念,该工作树包含所有正常格式的文件,加上一个索引(保存该工作树的当前状态并构建下一个提交)。有一个
HEAD
文件包含当前分支名称的概念。按照以下顺序,至少需要两个单独的命令:

git add <path>
git commit <arguments>
现在,我们可以使用
git update index
替换该索引中的任何给定文件(或者事实上,更熟悉、更舒适的
git add
:环境变量也在那里工作)。因为这是我们自己的私有索引,所以它与可能修改任何其他索引的所有其他进程都是隔离的

现在我们可以执行
git commit
执行的步骤:

tree_id=$(git write-tree)
这将索引(现在是我们的临时索引)转换为一个新的顶级树,其中包含任何子目录的子树,所有这些都基于我们先前读取到索引中的内容(使用
git read tree
)并进行更新(使用
git update index
git add
)。此顶级树以及存储库中尚未包含的任何必要子树现在都存储在存储库中。新对象在配置的过期时间(默认为14天)内不受自动
git gc
的影响,因此这就是我们必须完成提交的时间。该命令将新树的ID打印到其标准输出,我们在
$tree\u ID
变量中捕获该输出

接下来,我们需要编写一个提交对象,引用我们刚刚创建的树,并使用适当的父散列。正确的父散列显然是
$commit\u id
。我们必须构造提交消息,然后运行:

new=$(git commit-tree -p $commit_id $tree_id < message_file)
如果此参考有reflog,则可选的
-m
部分存储在reflog中。(此步骤还使用
user.name
user.email
,因此如果需要,请在此处提供它们。)refname部分是引用的全名,例如分支
refs/heads/branch
。newvalue部分是我们想要存储的哈希ID,而oldvalue部分是我们希望分支名称立即存储的值,我们将提供它来检查竞争

现在,假设我们正在进行其他过程,有两种可能的情况:

  • 我们赢得了这场比赛:回到起点,我们读到的树就是当前位于分支顶端的提交树。因此,我们的commit可以以一种简单的线性方式添加到分支中
或:

  • 我们输掉了比赛:我们在开始时读取的树是有效的,但是分支名称现在指向一个新的提交。因此,我们的承诺是毫无价值的,或者需要放在一个分支上,或者其他什么东西上。如果我们的承诺真的毫无价值的话,我们可以重新开始,把整个事情重新做一遍:也许这次我们会赢得比赛
如何处理“输掉比赛”的案子取决于你。但现在我们看到了“魔力”的来源:当我们开始整个过程时,我们想要的提交ID是与引用关联的当前提交哈希。所以“魔法”就是:

它读取引用的当前值(如果它是一个分支名称,我们可以假设基础对象的类型是
commit

由于
updateref
步骤有它自己的原子性(通过锁定强制),这就是我们获得原子性的地方。然而,如何应对失败的问题是最困难的。还记得在每一个中间步骤中考虑和处理故障,例如,如果<代码> git Rev解析< /代码>失败,或者任何<代码> git读树或<代码> Git写树< /代码>或<代码> git提交树< /代码>失败,


一,

new=$(git commit-tree -p $commit_id $tree_id < message_file)
git update-ref [-m <reason>] <refname> <newvalue> <oldvalue>
commit_id=$(git rev-parse $refname)