在未使用 Mercurial 检出编辑时将文件设置为只读

Make files read-only when not checked out for editing with Mercurial

有没有办法让 Mercurial 将存储库的工作副本设为只读,并要求我在开始编辑文件之前明确告诉 Mercurial 我想编辑文件?

不是询问有关锁定以防止并发编辑的问题,也不是有关防止意外更改进入存储库的问题。 这是为了防止工作副本本身发生意外的未提交更改。

我已经尝试创建一个批处理文件 checkout.bat 来删除只读文件属性和另一个 checkin.bat 提交更改并再次使文件只读,但是当您执行 hg 更新时,Hg 期望文件是可写的。

我知道这不是使用 Mercurial 的正常方式(让我们避免争论是否最好避免检出-编辑-检入模型)。但是切换到另一个版本控制系统不是一种选择。 (我在大多数项目中使用 TFS,但这个项目需要 Mercurial。)

每当对 Mercurial 存储库或工作副本执行某些操作时,都会调用许多 hooks。您需要的是一个 update 挂钩,理论上您可以在其中更改属性。

请注意,默认情况下挂钩是 "local",这意味着它们不会传播到存储库的克隆。要解决这个问题,有一个 ProjRc 扩展,您可以使用它来 "distribute" 挂钩设置。

您可能最好使用一对 preupdateupdate 挂钩,其中第一个使存储库中的所有文件都可写,第二个使它们只读。

例如:

[hooks]
preupdate = hg files -0 | xargs -0 chmod u+w 2>/dev/null || true
update = hg files -0 | xargs -0 chmod u-w 2>/dev/null || true

因为您似乎在使用 Windows,Unix shell 脚本可能不是最佳解决方案,您可能必须恢复到 Python(使用 Python也将消除调用 hg 两次的开销)。这将是以下几行:

[hooks]
preupdate = python:.hg/pyhooks.py:make_writable
update = python:.hg/pyhooks.py:make_readonly

这需要 .hg 中的 pyhooks.py 文件,其中包含以下内容:

import os, stat
from mercurial import scmutil

def make_writable(ui, repo, hooktype, node=None, source=None, **kwargs):
  ctx = scmutil.revsingle(repo, ".")
  for f in ctx:
    try:
      perm = os.stat(f)[0]
      os.chmod(f, perm | stat.S_IWUSR)
    except:
      pass

def make_readonly(ui, repo, hooktype, node=None, source=None, **kwargs):
  ctx = scmutil.revsingle(repo, ".")
  wflags = stat.S_IWUSR or stat.S_IWGRP or stat.S_IWOTH
  for f in ctx:
    try:
      perm = os.stat(f)[0]
      os.chmod(f, perm & ~wflags)
    except:
      pass

上面的代码仍然是为 Unix 编写的,但也应该适用于 Windows(至少根据文档,S_IWRITE == S_IWUSR 是唯一为 os.stat() 查看的标志os.chmod() Windows).

您显然也可以通过调整挂钩中的路径将文件放在不同的位置。挂钩也不是存储库本身的一部分,如果您在其他地方克隆存储库,则必须将它们再次添加到您的 .hg/hgrc 文件中。

最后,请注意这里存在潜在的性能影响:这些挂钩每次更新都会更改存储库中 所有 文件的权限两次,这在大型存储库中可能代价高昂。