跳至主要内容

源码控制感知查询

自 2021.08.30 起

已添加 Git 支持 🎊

自 4.9 起。

与此增强功能关联的 capability 名称是 scm-since

此功能的capability名称是scm-hg。内部架构可以轻松支持其他源代码控制系统;只需要有人实现和测试它们!

使用watchman的工具的一个常见模式是想要推理版本控制存储库中的更改。对于大多数存储库来说,简单地接收有关所有已更改文件的信息,即使在其他人进行了几天的rebase期间也是如此。

对于非常大或非常繁忙的存储库,在短时间内可能会更改大量文件,因此希望获得关于更改的最小化信息集。

例如,如果你的工具能够从某些artifact存储加载一些预构建的数据,而不是增量地处理数百个已更改的文件,你可能希望获取本地更改的合并基础,并使用它来定位预构建的数据,并仅处理该状态和存储库的当前状态之间的增量。

一个图示可能会有所帮助。在这里,我们看到用户基于符号main commit有一个两个commits的栈。在这种情况下,main正在跟踪本地存储库发布到的存储库的提示,并且用户在6b38a5 commit处check out

| @  6b38a5  wez
| | Add cats.cpp
| |
| o fa2e92 wez
|/ Add cat.jpg
|
o f12345 main

现在,用户将其存储库与远程存储库同步,获取commits但不更改其工作。这通常与以下步骤结合使用,但我们在此将其分解出来以进行说明。这相当于运行hg pullgit fetch

o  fabf87  coworker     main
. Amazing new feature
.
| @ 6b38a5 wez
| | Add cats.cpp
| |
| o fa2e92 wez
|/ Add cat.jpg
|
o

DAG的省略部分代表对wez不感兴趣的commits; 这些提交可能会更改数百个文件,但wez只关心DAG本地分支中的工作。

现在wez想要将其工作rebase到main上。这将使用类似hg rebase -d main -s fa2e92的命令完成

| @  bbbbbb  wez
| | Add cats.cpp
| |
| o aaaaaa wez
|/ Add cat.jpg
|
o fabf87 coworker main
. Amazing new feature
.

关键部分是工作副本会发生什么; 假设我们现在落在commit bbbbbb上,Watchman将观察到rebase中更改的所有数百个文件的更改,并将此信息传递给已订阅或正在查询此信息的工具。

如果你的工具能够感知源码控制,那么你可以要求watchman以一种模式运行since查询,在该模式下,它将返回你与main的合并基础以及已更改的最小文件集的信息。

要启用此模式,你可以使用新的fat clock作为查询的since参数发出查询

$ watchman -j <<-EOT
["query", "/path/to/root", {
"since": {
"scm": {
"mergebase-with": "main"
}
},
"expression": ["type", "f"],
"fields": ["name"]
}]
EOT

这个特殊的since值以未指定的clock值开头,并请求watchman以源码控制感知模式运行查询,使用符号名称main来计算commit图的合并基础。

如果我们回顾上面的插图并倒回到第一个场景,则此查询的结果将如下所示

{
"clock": {
"clock": "c:123:123",
"scm": {
"mergebase": "f12345",
"mergebase-with": "main"
}
},
"files": ["cat.jpg", "cats.cpp"]
}

此结果告知客户端与main的合并基础(恰好是main本身)以及自该合并基础以来的更改列表。

为了获得下一个增量更改,客户端将该clock值反馈到其下一个查询中。 回顾上面的第二个插图,如果我们在运行hg pull之后运行此查询(请注意,这不会更改工作副本)

$ watchman -j <<-EOT
["query", "/path/to/root", {
"since": {
"clock": "c:123:123",
"scm": {
"mergebase": "f12345",
"mergebase-with": "main"
}
},
"expression": ["type", "f"],
"fields": ["name"]
}]
EOT

我们会得到这样的结果

{
"clock": {
"clock": "c:123:124",
"scm": {
"mergebase": "f12345",
"mergebase-with": "main"
}
},
"files": []
}

请注意,files列表为空,因为我们没有更改任何文件,并且请注意,clock字符串的数字部分之一已更改。

另请注意,合并基础修订保持不变,因为我们也没有rebase commit。

这是一个小小的善意的谎言:现实是,某些文件确实在版本控制系统中更改了,并且使用我们使用的表达式,我们会看到它们,但它们不是工作副本的一部分,因此为了清晰起见,我们省略了它们。这个例子。

现在,如果我们rebase并更新到rebased修订版(将我们带到上面插图的最后一个),我们将运行此查询,将上一次查询中的clock反馈到其中,以获得正确的增量结果

$ watchman -j <<-EOT
["query", "/path/to/root", {
"since": {
"clock": "c:123:124",
"scm": {
"mergebase": "f12345",
"mergebase-with": "main"
}
},
"expression": ["type", "f"],
"fields": ["name"]
}]
EOT

我们会得到这样的结果

{
"clock": {
"clock": "c:123:125",
"scm": {
"mergebase": "fabf87",
"mergebase-with": "main"
}
},
"files": ["cat.jpg", "cats.cpp"]
}

请注意,clock中报告的合并基础已更改,并且请注意,报告的文件列表只是commit栈中的两个文件,尽管磁盘上实际更新了数百个文件。

你的客户端现在可以查找基于fabf87修订版的某些状态并下载它,然后可以在该状态之上增量地应用cat.jpgcats.cpp的计算。

如果你的客户端不知道如何执行此操作,则你不应使用此源码控制感知查询模式!

源码控制感知订阅

你还可以在订阅中使用相同的源码控制感知。这基本上与上面的进行查询的过程相同,但是有一些前提条件和需要注意的事项

  • Watchman需要源码控制系统的配合才能知道何时应该推迟事件。
  • 源码控制感知订阅隐式启用defer_vcsdefer:["hg.update"]。与上面的观点一样,这是为了确保你不会收到有关工作副本更新操作期间文件更改的通知;这将破坏使用源码控制感知的意义。

要启动源码控制感知订阅

["subscribe", "/path/to/root", "mysubscriptionname", {
"fields": ["name"],
"since": {
"scm": {
"mergebase-with": "main"
}
}
}]

然后,你将收到作为文件更改的订阅响应;这些响应将包含sinceclock字段的fat clock

{
"subscription": "mysubscriptionname",
"clock": {
"clock": "c:1234:125",
"scm": {
"mergebase": "fabf87",
"mergebase-with": "main",
}
},
"since": {
"clock": "c:1234:123",
"scm": {
"mergebase": "f12345",
"mergebase-with": "main",
}
},
"files": ["cat.jpg", "cats.cpp"],
"root": "/path/to/root"
}

clock字段保存clock的值和订阅通知时的合并基础。

since字段保存先前订阅更新中clock字段返回的fat clock。 它的存在是为了方便你;你可以比较两者之间的mergebase字段来确定此更新中合并基础已更改。 这是一个重要的细节,因为工作副本中已物理更改的文件多于files列表中反映的文件; 你的工具将需要采取适当的措施,以确保它可以计算出一致且正确的结果。

state-enter & state-leave

源码控制感知订阅始终会在其响应中包含一个fat clock,但是,只有常规clock会在state-enterstate-leave通知中提供。 这是因为计算源码控制信息是一个非平凡的操作,并且可能会增加延迟。