【问题标题】:Case-insensitive diffs in MercurialMercurial 中不区分大小写的差异
【发布时间】:2010-03-05 22:38:54
【问题描述】:

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

我想在执行差异时忽略源代码中的大小写变化。最简单的方法是什么? (我缺少的一些 diff 选项,一个外部 diff 实用程序,还有什么?)

注意:我说的不是处理“不区分大小写的文件名”(是的,我说的是 Google...)

【问题讨论】:

  • 我们又见面了,我的朋友!你有没有找到一个解决方案,或者可能是一个可以进行不区分大小写差异的 VCS?
  • @RubberDuck:你激励我最终发布了我过去几年一直在使用的方法。我还没有完全解决这个问题,但我已经消除了很多痛苦。基本上,我忽略了唯一改变大小写的文件。如果文件有合法更改,我仍然无法看到案例更改,但它(很多)总比没有好。

标签: mercurial diff tortoisehg


【解决方案1】:

您可以在使用 ExtDiff Extension 区分屏幕消费时这样做。

  [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 语言的 indent,它规范化变量大小写并在一个 mercurial 提交挂钩中运行它。那么至少所有进入源代码控制的代码都是一致的,你可以准确地区分不同的版本。

【讨论】:

  • 听起来像是某种代码清理器将是我唯一的选择。感谢您的帮助。
【解决方案2】:

如果您可以将代码全部使用小写,那么您可以为此使用encode/decode hooks。它会像这样工作:

[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 扩展可以在这里为您提供帮助。

【讨论】:

  • 在这种情况下,这对我来说并不适用,但这是一个很好的提示,我会努力记住以备将来使用。感谢您的帮助。
【解决方案3】:

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

我创建了一个自动热键脚本,它执行以下操作:

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

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

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

这是我的脚本。请注意,该脚本包含另一个 Autohotkey 脚本 ConsoleApp.ahk,它提供了一个名为 ConsoleApp_RunWait() 的函数。这是一个第 3 方脚本,它不再适用于 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
}

【讨论】:

  • 感谢您确认这是一种有用的方法。我正在考虑类似的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
  • 2013-03-06
  • 2020-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多