首先,我知道我的问题已被提出并被驳回为Git滥用(例如参见this question)。我将尝试解释我的用例。
我需要定期(cron job)对存储库中的源版本进行特殊冗长的处理。为了不打扰回购,我提取了所需的版本。不幸的是,在Git中没有像export
这样的东西。文档建议使用archive
。由于我想要一个源树的精确副本(因为它出现在工作目录中),我必须在某个目标位置解压缩归档。
事实上,这实际上看起来像checkout
,但checkout
也会更改索引,然后会因意外更改而对用户造成混乱。
在这种情况下,许多答案都会向clone
推荐回购,然后在克隆上无关紧要。我也不想继续这样做,因为我必须同时提取许多版本,而且我不想为每个副本浪费回购存储(想想像Linux内核那样的怪物回购)。
我不想要使用worktree
,因为我的副本会被严重调整,而且我不想冒这些花哨的副本重新进入回购的风险。 Git一旦被制作,就必须忘记这些副本。
我最终实现了一个export
等效的短脚本:
ref=$(git rev-parse --symbolic-full-name HEAD)
git --work-tree=<somewhere> checkout -f -q <branch_or_tag> -- '*'
git reset ${ref}
第一行在repo中保存当前位置(commit id)。第二行检查所需版本而不更改HEAD
,但同时将索引设置为签出提交。第三行恢复初始位置。
这对裸存储库工作正常,因为你不应该commit
那里,只有push
或pull
。除了您创建索引文件之外,回购显然没有受到干扰。
但是,如果脚本是针对本地存储库(具有关联的工作目录)运行的,则在其生存期内存在较小的风险。 checkout
虽然快速不是瞬间的。索引将更改,直到reset
完成。如果在此时间范围内尝试进行任何提交,则会因错误的修补程序而损坏存储库,因为索引不是用户期望的。
因此,我再次询问@ schuess的问题(见上面的链接):
有没有办法锁定Git存储库以阻止任何访问?
锁将是短暂的。它应该防止存储库中的任何状态更改。
现在我的生活没有,但有一天或以后我会被抓住;因此,我更愿意防范这种竞争状况。
提醒:我完全清楚我试图在Git上玩弄技巧,我不应该这样做。一个更好的解决方案肯定是实现一个不依赖于export
的真实checkout
脚本。另请参阅上文为什么我不使用clone
。
答案 0 :(得分:2)
这个答案分为两部分。
[使用]
git --work-tree=<somewhere> checkout -f -q <branch_or_tag>
...对裸存储库工作正常......
是。有一两个警告:
除了创建索引文件这一事实外,回购显然没有受到干扰。
实际上,这不一定是创建它。 可能已经是一个索引。如果是索引,它会使用现有索引来优化结帐。这可能是好事还是坏事。
具体来说,这是一些人在部署脚本中使用的技术:推送到裸存储库会触发使用git checkout
更新已部署部署分支的Git挂钩。工作树使用--work-tree
作为常量字符串提供。该索引跟踪 工作树的内容,而不跟踪其他工作树。
有一种很好的方法可以处理这个问题,它与git worktree
使用的方法相同:为每个工作树分配一个索引。然后,该特定索引仅跟踪 那个特定的工作树。与任何索引一样,您可以完全擦除它,让Git稍后重建它(如果有的话),只要您可以丢失到目前为止存储在其中的任何更改。
您可以通过创建唯一路径(例如mktemp
)并将该路径设置到环境GIT_INDEX_FILE
中来创建自己的索引,如the git
front end documentation, section ENVIRONMENT VARIABLES中所述。
[编辑:我已删除了第二个警告,因为我发现您使用的是非HEAD
更新形式的git checkout
:git checkout <tree-ish> -- <paths>
。
你提到:
由于我想要源树的精确副本(因为它出现在工作目录中),我必须在某个目标位置解压缩存档。
与直接执行git checkout
相比,这个成本非常低,至少在任何现代系统上都是如此:git archive ... | tar -C path -xf -
可能会使用比git checkout
更多的CPU,但是花费全部费用无论如何,等待磁盘I / O的时间。 (管道使用内存和#34; I / O&#34;因此以内存速度而不是I / O设备速度运行。)git archive
除了增加一些开销之外唯一的做法是服从任何特殊的归档规则。这些特殊规则是使用git archive
的优势,当然这些特殊规则对于使用git archive
是不利的。
许多答案建议在这种情况下克隆回购,然后在克隆上无害地玩。我也不想继续这样做,因为我必须同时提取许多版本,而且我不想为每个副本浪费回购存储(想想像Linux内核那样的怪物回购)。
本地克隆(使用路径名或使用--local
)使用硬链接,因此不会增加额外空间。这确实假设硬链接是可能的(即,您没有跨文件系统移动)。
您也可以使用--shared
代替复制对象数据库。您甚至可以使用--reference
在网络上获取和共享一个副本:即&#34; main&#34;存储库可以存在于机器上 M (对于主机),并且您可以保留一个&#34;参考副本&#34;在您的计算机上重复<em> L (对于本地)。然后使用git clone --reference
使临时克隆使用引用克隆的对象数据库。这两种技术都假设您在借用对象存储库的克隆期间不会从--shared
或--reference
存储库删除对象(这是硬链接的位置)是优越的,因为他们不需要这样的假设。)