Mercurial 中不区分大小写的差异

发布于 2024-08-24 10:36:57 字数 295 浏览 10 评论 0原文

我正在使用 Mercurial(特别是 Windows 上的 TortoiseHg)对 VBA 代码进行版本控制。任何尝试过此操作的人都知道,每当项目中任何位置(无论范围如何)更改该变量的任何声明时,VBA 都会更改整个项目中每个变量的大小写。它使版本控制成为一场噩梦。

我想在执行差异时忽略源代码中的大小写更改。做到这一点最简单的方法是什么? (我缺少的 diff 的一些选项,外部 diff 实用程序,还是其他东西?)

注意:我不是在谈论处理“不区分大小写的文件名”(是的,我正在与你交谈谷歌......)

I'm using Mercurial (specifically TortoiseHg on Windows) to do version control of VBA code. Anybody who's tried this knows that VBA changes the case of every variable throughout a project whenever any declaration of that variable is changed anywhere in the project (regardless of scope). It makes version control a nightmare.

I would like to ignore case changes in my source code when performing diffs. What is the easiest way to do this? (some option for diff that I'm missing, an external diff utility, something else?)

NOTE: I am not talking about dealing with 'case-insensitive filenames' (yes, I'm talking to you Google...)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

匿名的好友 2024-08-31 10:36:58

您可以在使用 ExtDiff 扩展 比较屏幕上的消耗时执行此操作。

  [extensions]
  hgext.extdiff =

  [extdiff]
  # add new command that runs GNU diff(1) in case-insensitive mode
  cmd.mydiff = diff
  opts.mydiff = -i

然后,您可以从命令行运行 hg mydiff 。当然,这需要您安装一个 diff 二进制文件,无论是 gnu 的还是其他的。

然而,这不会像您希望的那样有用,因为在内部,Mercurial 当然不能忽略大小写——它采用文件内容的加密哈希,而这些不允许有回旋余地。因此,如果您进行了此设置,您将执行 hg mydiff,并不会看到任何更改,然后执行 hg commit 并看到整个地方的更改。

所以你可以在屏幕上实现这一点,但不是从根本上实现。

一种选择是找到一个 Visual Basic 代码清理器,类似于类 C 语言的缩进,它可以标准化变量大小写并在 Mercurial 提交钩子中运行它。那么至少进入源代码管理的所有代码都将是一致的,并且您可以准确地跨版本进行比较。

You can do that when diffing for your on-screen consumption using the ExtDiff Extension.

  [extensions]
  hgext.extdiff =

  [extdiff]
  # add new command that runs GNU diff(1) in case-insensitive mode
  cmd.mydiff = diff
  opts.mydiff = -i

Then you'd run hg mydiff from the command line. That, of course, requires you have a diff binary installed be it gnu's or other.

However, that's not going to be as helpful as you might like because internally, of course, Mercurial can't ignore case -- it's taking the cryptographic hash of the file contents, and those don't allow for wiggle room. So if you get this set up you'll do hg mydiff, and see no changes, and then do hg commit and see changes all over the place.

So you can make this work on-screen, but not fundamentally.

One option would be to find a visual basic code-cleaner, similar to indent for C-like languages, that normalizes variable case and run that in a mercurial commit hook. Then at least all the code going into source control will be consistent and you can diff across revisions accurately.

猫烠⑼条掵仅有一顆心 2024-08-31 10:36:58

如果您同意将代码全部采用小写,那么您可以使用 为此编码/解码挂钩。它的工作原理如下:

[encode]
*.vba = tr A-Z a-z

每当您进行提交时,这都会以小写形式对文件内容进行编码。差异也是根据文件的编码(存储库)版本计算的。

考虑一个文件,其中包含

hello

将其在工作副本中更改为

Hello World

将给出差异请

% hg diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,1 +1,1 @@
-hello
+hello world

注意大写“H”和“W”是如何被忽略的。

我对 VBA 代码一无所知,所以我不能 100% 确定这个解决方案适合您。但我希望这可以成为一个起点。

一个缺点是您需要为所有存储库设置此编码规则。 reposettings 扩展程序可以在这里为您提供帮助。

If you are okay with having your code in all lower-case, say, then you could employ the encode/decode hooks for this. It would work like this:

[encode]
*.vba = tr A-Z a-z

This will encode the file content in lower-case whenever you do a commit. The diffs are also computed based on the encoded (repository) version of the files.

Consider a file that contains

hello

Changing it in your working copy to

Hello World

will give a diff of

% hg diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,1 +1,1 @@
-hello
+hello world

Notice how the capital "H" and "W" has been ignored.

I don't really know anything about VBA code, so I'm not 100% sure this solution works for you. But I hope it can be a starting point.

One drawback is that you'll need to set this encode rule for all your repositories. The reposettings extension can help you here.

白芷 2024-08-31 10:36:58

这是我已经确定的解决方案。它远非理想,但比我考虑过的其他替代方案要好。

我创建了一个 Autohotkey 脚本,它执行以下操作:

  • 恢复存储库中检测到更改的 MS Access 文件(到 .orig 文件)
  • 读取 .orig 文件(有更改的文件)
  • 读取现有文件(已存在于 .orig 文件中)存储库)
  • 将两个文件的文本转换为小写,
  • 比较文件的小写内容,
  • 则可以将其提交到存储库
  • 如果文件仍然不同,则恢复 .orig 文件,以便如果文件相同(即它们不同), 仅在以防万一,.orig 文件被删除,因为我们不关心这些更改)

对于具有我们关心的实际更改的文件,我仍然会看到所做的大小写更改。如果这会导致大量噪音,我会在允许不区分大小写比较的比较工具(例如 kdiff)中打开文件。

这不是一个完美的解决方案,但它消除了我大约 90% 的挫败感。

这是我的脚本。请注意,该脚本包含另一个 Autohotkey 脚本 ConsoleApp.ahk,它提供了一个名为 ConsoleApp_RunWait() 的函数。这是一个 3rd 方脚本,不再适用于 64 位 AHK,因此我不会将其包含在我的答案中。任何执行命令行并将输出作为字符串返回的 AHK 函数就足够了。

; This script checks an MS Access source directory and reverts all files whose only modifications are to the 
; case of the characters within the file.

#Include %A_ScriptDir%\ConsoleApp.ahk
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Allow for custom path to hg (support for moving to TortoiseHg 2.0)
IniRead hg, %A_ScriptDir%\LocalSettings\Settings.cfg, TortoiseHg, hg_path, hg

if 0 < 1  ; The left side of a non-expression if-statement is always the name of a variable.
{
    MsgBox Usage:`n`HgIgnoreCase DirectoryWithFilesToScrub
    ExitApp
}

SrcDir = %1%
StringReplace SrcDir, SrcDir, ", , All

StringRight test, SrcDir, 1 ; add trailing slash if necessary
ifnotequal test, \
    SrcDir = %SrcDir%\

RestoreOriginals(SrcDir)
RevertCaseChangeModifiedFiles(SrcDir)

RevertCaseChangeModifiedFiles(SrcDir) {
global hg
    includes =  -I "*.form" -I "*.bas" -I "*.report" -I "*.table"
    cmdline = %hg% revert --all %includes%

    ;Don't revert items that have been removed completely
    Loop 3
    {
        Result := ConsoleApp_RunWait(hg . " status -nrd " . includes, SrcDir)
        If (Result)
            Break
    }
    Loop parse, Result, `n, `r
    {
        if (A_LoopField)
            cmdline = %cmdline% -X "%A_LoopField%"
    }
    Result =
    ;msgbox %cmdline%
    ;revert all modified forms, reports, and code modules
    Loop 3
    {

        Result := ConsoleApp_RunWait(cmdline, SrcDir)
        If (Result)
            Break
    }
    ;MsgBox %Result%

    Loop parse, Result, `n, `r
    {
        StringLeft FileStatus, A_LoopField, 9
        If (FileStatus = "reverting")
        {
            StringMid FName, A_LoopField, 11
            FullPath = %SrcDir%%FName%
            ToolTip Checking %FullPath%
            RestoreIfNotEqual(FullPath, FullPath . ".orig")
        }
    }
    ToolTip
}

RestoreIfNotEqual(FName, FNameOrig) {
    FileRead File1, %FName%
    FileRead File2, %FNameOrig%

    StringLower File1, File1
    StringLower File2, File2
    ;MsgBox %FName%`n%FNameOrig%
    If (File1 = File2)
        FileDelete %FNameOrig%
    Else
        FileMove %FNameOrig%, %FName%, 1
}

RestoreOriginals(SrcDir) {
    Loop %SrcDir%*.orig
    {
        ;MsgBox %A_LoopFileLongPath%`n%NewName%
        NewName := SubStr(A_LoopFileLongPath, 1, -5)
        FileMove %A_LoopFileLongPath%, %NewName%, 1
    }
    while FileExist(SrcDir . "*.orig")
        Sleep 10
}

Here's the solution I have settled on. It is far from ideal, but better than the other alternatives I've considered.

I created an Autohotkey script that does the following:

  • reverts MS Access files in a repository with detected changes (to .orig files)
  • reads in the .orig file (the one with the changes)
  • reads in the existing file (the one already in the repository)
  • converts the text of both files to lower case
  • compares the lower case contents of the files
  • if the files still differ, the .orig file is restored so it may be committed to the repository
  • if the files are the same (i.e., they differ only in case, the .orig file is deleted because we don't care about those changes)

For files that have actual changes that we care about, I still see the case changes that were made as well. If that results in a lot of noise, I open the file in a comparison tool that allows case-insensitive compares (e.g., kdiff).

It's not a perfect solution, but it removes about 90% of the frustration for me.

Here's my script. Note that the script includes another Autohotkey script, ConsoleApp.ahk, which provides a function named, ConsoleApp_RunWait(). This is a 3rd party script that no longer works very well with 64-bit AHK, so I'm not including it as part of my answer. Any AHK function that executes a command line and returns the output as a string will suffice.

; This script checks an MS Access source directory and reverts all files whose only modifications are to the 
; case of the characters within the file.

#Include %A_ScriptDir%\ConsoleApp.ahk
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Allow for custom path to hg (support for moving to TortoiseHg 2.0)
IniRead hg, %A_ScriptDir%\LocalSettings\Settings.cfg, TortoiseHg, hg_path, hg

if 0 < 1  ; The left side of a non-expression if-statement is always the name of a variable.
{
    MsgBox Usage:`n`HgIgnoreCase DirectoryWithFilesToScrub
    ExitApp
}

SrcDir = %1%
StringReplace SrcDir, SrcDir, ", , All

StringRight test, SrcDir, 1 ; add trailing slash if necessary
ifnotequal test, \
    SrcDir = %SrcDir%\

RestoreOriginals(SrcDir)
RevertCaseChangeModifiedFiles(SrcDir)

RevertCaseChangeModifiedFiles(SrcDir) {
global hg
    includes =  -I "*.form" -I "*.bas" -I "*.report" -I "*.table"
    cmdline = %hg% revert --all %includes%

    ;Don't revert items that have been removed completely
    Loop 3
    {
        Result := ConsoleApp_RunWait(hg . " status -nrd " . includes, SrcDir)
        If (Result)
            Break
    }
    Loop parse, Result, `n, `r
    {
        if (A_LoopField)
            cmdline = %cmdline% -X "%A_LoopField%"
    }
    Result =
    ;msgbox %cmdline%
    ;revert all modified forms, reports, and code modules
    Loop 3
    {

        Result := ConsoleApp_RunWait(cmdline, SrcDir)
        If (Result)
            Break
    }
    ;MsgBox %Result%

    Loop parse, Result, `n, `r
    {
        StringLeft FileStatus, A_LoopField, 9
        If (FileStatus = "reverting")
        {
            StringMid FName, A_LoopField, 11
            FullPath = %SrcDir%%FName%
            ToolTip Checking %FullPath%
            RestoreIfNotEqual(FullPath, FullPath . ".orig")
        }
    }
    ToolTip
}

RestoreIfNotEqual(FName, FNameOrig) {
    FileRead File1, %FName%
    FileRead File2, %FNameOrig%

    StringLower File1, File1
    StringLower File2, File2
    ;MsgBox %FName%`n%FNameOrig%
    If (File1 = File2)
        FileDelete %FNameOrig%
    Else
        FileMove %FNameOrig%, %FName%, 1
}

RestoreOriginals(SrcDir) {
    Loop %SrcDir%*.orig
    {
        ;MsgBox %A_LoopFileLongPath%`n%NewName%
        NewName := SubStr(A_LoopFileLongPath, 1, -5)
        FileMove %A_LoopFileLongPath%, %NewName%, 1
    }
    while FileExist(SrcDir . "*.orig")
        Sleep 10
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文