TortoiseSVN 提交前钩子 (Pre-commit Hook) in C# - 避免麻烦!
你是否曾经提交过本应保留在自己机器上的代码?我们都会添加临时的hack来让开发或调试更轻松... 而且很容易忘记它们!
几乎每个创建或调试程序的人都会对代码进行临时更改,使当前任务更容易,但永远不应该进入存储库。而且几乎每个人都曾意外地将这样的代码放入下一个修订版中。如果幸运的话,错误会很快被发现,结果只会有一点羞愧,如果不是...
如果有一种方法可以标记“不可提交”的代码就好了...
你可以做到,而且很简单!
TortoiseSVN 允许你设置所谓的提交前钩子 (pre-commit hook)。它是一个在用户点击“SVN提交”窗口中的“确定”按钮时运行的程序(或脚本)。例如,钩子可以检查已修改文件的内容,并在认为合适时阻止提交。Tortoise 钩子与 Subversion 钩子的区别在于它们是在本地执行的,而不是在托管存储库的服务器上执行。因此,你不必担心你的钩子是否会被管理员接受,或者它是否在服务器上运行(例如,服务器可能没有安装 .NET),你也不会影响存储库其他用户的体验。客户端钩子也更快。
关于钩子的详细描述可以在 Tortoise 的帮助文件的“4.30.8. 客户端钩子脚本”一章中找到。
Tortoise 支持 7 种钩子:start-commit, pre-commit, post-commit, start-update, pre-update, post-update 和 pre-connect。我们关注的是pre-commit动作。钩子的本质是检查添加或修改的文件中是否包含临时代码标记。我们的标记可以是放置在临时代码上方的注释中的“NOT_FOR_REPO
”文本。
这是整个钩子的代码 – 一个简单的控制台应用程序,可以拯救你。
using System;
using System.IO;
using System.Text.RegularExpressions;
namespace NotForRepoPreCommitHook
{
class Program
{
const string NotForRepoMarker = "NOT_FOR_REPO";
static void Main(string[] args)
{
string[] affectedPaths = File.ReadAllLines(args[0]);
Regex fileExtensionPattern = new Regex(@"^.*\.(cs|js|xml|config)$", RegexOptions.IgnoreCase);
foreach (string path in affectedPaths)
{
if (fileExtensionPattern.IsMatch(path) && File.Exists(path))
{
if (ContainsNotForRepoMarker(path))
{
string errorMessage = string.Format("{0} marker found in {1}",
NotForRepoMarker, path);
Console.Error.WriteLine(errorMessage);
Environment.Exit(1);
}
}
}
}
static bool ContainsNotForRepoMarker(string path)
{
StreamReader reader = File.OpenText(path);
try
{
string line = reader.ReadLine();
while (line != null)
{
if (line.Contains(NotForRepoMarker))
{
return true;
}
line = reader.ReadLine();
}
}
finally
{
reader.Close();
}
return false;
}
}
}
TSVN 使用四个参数调用 pre-commit 钩子。我们只对第一个感兴趣。它包含到 *.tmp 文件的路径。在此文件中,有一个当前提交影响的文件的列表。每一行是一个路径。加载列表后,文件按扩展名过滤(如果你不想处理所有类型的文件,则很有用)。检查文件是否存在也很重要 – 来自 *.tmp 文件的列表也包含已删除文件的路径!由 NotForRepoMarker
常量表示的标记的检测是通过 ContainsNotForRepoMarker
方法实现的。尽管它很简单,但它提供了良好的性能。在我的(中端)笔记本电脑上,处理 100 MB 的文件需要不到一秒钟。如果找到标记,程序将以错误代码(不同于 0 的值)退出。在退出之前,有关包含标记的文件的信息将发送到标准错误输出(通过 Console.Error
)。此消息将显示在 Tortoise 窗口中。
代码很简单,不是吗?此外,钩子的安装也很简单!
要附加钩子,请从 Tortoise 的上下文菜单中选择“设置”项。然后选择“钩子脚本”元素并单击“添加…”按钮。将出现如下窗口
将“钩子类型”设置为“提交前钩子 (Pre-Commit Hook)”。在“工作副本路径”字段中填写包含存储库本地副本的目录的路径(不同的文件夹可以有不同的钩子)。在“要执行的命令行”字段中,设置实现钩子的应用程序的路径。选中“等待脚本完成”(这很重要!)和“在运行时隐藏脚本”选项(后者将防止显示控制台窗口)。按下“确定”按钮,就完成了,钩子就安装好了!
现在用“NOT_FOR_REPO
”注释标记一些代码,并尝试执行提交。你应该看到类似这样的内容
请注意“无钩子重试”按钮 – 它允许通过忽略钩子来完成提交。
我们现在有一个钩子,可以防止临时代码的提交。人们可能还想创建一个钩子来强制填写日志消息,阻止提交 *.log 文件等。你的私人钩子 – 你来决定!如果其中一些钩子对整个团队有用,你随时可以将它们改造成 Subversion 钩子。
在 TortoiseSVN 1.7.8/Subversion 1.7.6 上测试。
更新 2014 年 3 月 24 日:强调了检查“等待脚本完成”选项 - 如果没有它,钩子将不会阻止提交!
更新 2013 年 9 月 17 日(附加信息):你可以在包含多个存储库检出的父文件夹上设置钩子。如果你愿意牺牲一点性能来获得额外的保护,你可以在检查 NotForRepoMarker
标记之前放弃过滤文件。