如何临时锁定Git存储库?

时间:2017-07-02 15:06:35

标签: git locking export git-checkout

首先,我知道我的问题已被提出并被驳回为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那里,只有pushpull。除了您创建索引文件之外,回购显然没有受到干扰。

但是,如果脚本是针对本地存储库(具有关联的工作目录)运行的,则在其生存期内存在较小的风险。 checkout虽然快速不是瞬间的。索引将更改,直到reset完成。如果在此时间范围内尝试进行任何提交,则会因错误的修补程序而损坏存储库,因为索引不是用户期望的。

因此,我再次询问@ schuess的问题(见上面的链接):

有没有办法锁定Git存储库以阻止任何访问?

锁将是短暂的。它应该防止存储库中的任何状态更改。

现在我的生活没有,但有一天或以后我会被抓住;因此,我更愿意防范这种竞争状况。

提醒:我完全清楚我试图在Git上玩弄技巧,我不应该这样做。一个更好的解决方案肯定是实现一个不依赖于export的真实checkout脚本。另请参阅上文为什么我不使用clone

1 个答案:

答案 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 checkoutgit 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存储库删除对象(这是硬链接的位置)是优越的,因为他们不需要这样的假设。)