如何在mercurial的历史记录中检测哪些文件是手动合并的?

时间:2011-02-18 19:24:51

标签: version-control mercurial merge

我是新使用mercurial的团队的一员,我们已经确定,当合并发生时,手动合并的文件中会有更多错误。是否有可能从mercurial日志(即在某人完成合并并将合并变更集推送到中央存储库之后)来检测哪些文件是手动合并的?

2 个答案:

答案 0 :(得分:3)

注意,我不知道这是否万无一失。此外,它需要我的尚未完成的Mercurial库for .NET的副本,可能只在Windows上运行,并且有点粗糙。

注意:我假设“手动合并”,你的意思是“文件Mercurial没有为我们自动合并”

这样的文件仍然可以通过外部工具进行一些或完全自动合并,但如果上述假设足够好,请继续阅读。

但是,我所做的是有效地运行测试存储库中的所有合并,重新进行合并并要求Mercurial仅使用其内部合并工具,如果文件无法由Mercurial自动合并,则会使文件无法解析,然后报告所有未解析的文件,清理合并,然后转到下一个合并变更集。

您需要的库(目前仅以源代码形式提供,我告诉您它尚未完成):

我在底部附加了一个zip文件,其中包含所有内容,测试存储库,脚本和库的二进制副本。

脚本(我使用LINQPad编写并测试它,测试库的输出如下):

void Main()
{
    var repo = new Repository(@"c:\temp\repo");
    var mergeChangesets = repo.Log(new LogCommand()
        .WithAdditionalArgument("-r")
        .WithAdditionalArgument("merge()")).Reverse().ToArray();

    foreach (var merge in mergeChangesets)
    {
        Debug.WriteLine("analyzing merge #" + merge.RevisionNumber +
            " between revisions #" + merge.LeftParentRevision +
            " and #" + merge.RightParentRevision);
        // update to left parent
        repo.Update(merge.LeftParentHash);
        try
        {
            // perform merge with right parent
            var mergeCmd = new MergeCommand();
            mergeCmd.WithRevision = merge.RightParentHash;
            repo.Execute(mergeCmd);

            // get list of unresolved files
            var resolveCmd = new ResolveCommand();
            repo.Execute(resolveCmd);
            var unresolvedFiles = new List<string>();
            using (var reader = new StringReader(resolveCmd.RawStandardOutput))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                    if (line.StartsWith("U "))
                        unresolvedFiles.Add(line.Substring(2));
            }

            // report
            if (unresolvedFiles.Count > 0)
            {
                Debug.WriteLine("merge changeset #" + merge.RevisionNumber +
                    " between revisions #" + merge.LeftParentRevision +
                    " and #" + merge.RightParentRevision + " had " +
                    unresolvedFiles.Count + " unresolved file(s)");
                foreach (string filename in unresolvedFiles)
                {
                    Debug.WriteLine("  " + filename);
                }
            }
        }
        finally
        {
            // get repository back to proper state
            repo.Update(merge.LeftParentHash, new UpdateCommand().WithClean());
        }
    }
}

public class MergeCommand : MercurialCommandBase<MergeCommand>
{
    public MergeCommand()
        : base("merge")
    {
    }

    [NullableArgumentAttribute(NonNullOption = "--rev")]
    public RevSpec WithRevision
    {
        get;
        set;
    }

    public override IEnumerable<string> Arguments
    {
        get
        {
            foreach (var arg in base.Arguments)
                yield return arg;
            yield return "--config";
            yield return "ui.merge=internal:merge";
        }
    }

    protected override void ThrowOnUnsuccessfulExecution(int exitCode,
        string standardOutput, string standardErrorOutput)
    {
        if (exitCode != 0 && exitCode != 1)
            base.ThrowOnUnsuccessfulExecution(exitCode, standardOutput,
                standardErrorOutput);
    }
}

public class ResolveCommand : MercurialCommandBase<MergeCommand>
{
    public ResolveCommand()
        : base("resolve")
    {
    }

    public override IEnumerable<string> Arguments
    {
        get
        {
            foreach (var arg in base.Arguments)
                yield return arg;
            yield return "--list";
        }
    }
}

示例输出:

analyzing merge #7 between revisions #5 and #6
analyzing merge #10 between revisions #9 and #8
merge changeset #10 between revisions #9 and #8 had 1 unresolved file(s)
  test1.txt

包含所有内容的Zip文件(LINQPad脚本,Mercurial.Net程序集,如果您不信任我就编译它,以及我在上面执行它的测试存储库):

BIG CAVEAT :仅在您的存储库的克隆中运行它!如果这会破坏您的存储库,我将不会承担任何责任,但我认为这不太可能。

答案 1 :(得分:2)

Tis是Lasses回答的shell脚本变体:

#!/bin/bash

test "$1" = "--destroy-my-working-copy" || exit

hg log -r 'merge()' --template '{parents} {rev}\n' | sed -e 's/[0-9]*://g' | while read p1 p2 commit
do
        echo "-------------------------"
        echo examine $commit
        LC_ALL=C hg up -C -r $p1 >/dev/null
        LC_ALL=C hg merge -r 26 --config ui.merge=internal:merge 2>&1 | grep failed
done

hg up -C -r tip > /dev/null

示例输出:

> mergetest.sh --destroy-my-working-copy
-------------------------
examine 7
-------------------------
examine 11
-------------------------
examine 23
-------------------------
examine 31
-------------------------
examine 37
merging test.py failed!