Is it possible to manually change/reorder the revision numbers (provided topology remains the same)?

旧城冷巷雨未停 提交于 2019-11-26 21:50:28

问题


In Mercurial , revision numbers are local-clone specific, and they are provided as a facility to point to a specific changeset in a more user-friendly way than a changeset id.

However when displaying the timeline graph, TortoiseHG will order by revision number. If some guy pushes commits not that often, you'll get all his commits at once with adjacent revision numbers, and it will mess up the whole point of the graph.

This graph would be more insightful: there are two lines of development, with two authors, one merging the work of the other one:

Therefore, is it possible to manually reorder the revision numbers (as long as the topological order of changesets is still compatible with the new numbers?

Thanks.


回答1:


It is possible to reorder your repository (that's what contrib/shrink-revlog.py does). But in this case it seems overkill and complicated.

Since this is mostly a display issue, you should instead ask THG to implement the reordering you would like to have. I admittedly have no idea what you find messed up in the graph above.




回答2:


I have a similar use case: I came to this question because I pushed a bunch of changesets from different branches at once, and they did not arrive sorted by date. I now have some merges with low-numbered parents that are not in fact that old; scrolling up and down the log to see them is a pain. I followed the approach suggested in @Ry4an's answer-- it's really quite simple, if you can predict (i.e., compute) the changeset order you want.

If your workflow only merges branch heads, you can get the desired revision order by sorting revsets by date. This you can do with the following command:

hg log -r 'sort(0:tip, date)' --template '{rev}\n'

You can then clone the repository and use a loop in your favorite scripting language to pull the revisions one by one in chronological order. Rather than init a repository from scratch, I ended up doing it like this:

hg clone -r 0 messy-repo sorted-repo
cd sorted-repo
for REV in `hg log -R ../messy-repo -r 'sort(1:tip, date)' --template '{rev}\n'`
do 
    hg pull ../messy-repo -r $REV
done

I should note (before somebody else does :-)) that this will increase the storage size of the repository, because of the way deltas are computed. I don't mind.




回答3:


As others are saying, it's possible, but probably not worth the work, since it would be local to your clone (and any clones of your clone). It's not something you could push to a remote repository w/o deleting everything there first, and even if you did that the people who had clones from that remote repository locally would see "no changes" when they pulled.

That said, if you want to try you just need to use a series of hg pull -r REV commands into a new clone. Something like this:

hg init my_reordered_clone
cd my_reordered_clone
hg pull -r d84b1 ../un_reordered_clone
hg pull -r 6d269 ../un_reordered_clone
hg pull -r bb9e4 ../un_reordered_clone

Clearly that's too much work to be worth it for aesthetic purposes, but the concept there is that when you pull with -r you get that changeset and all of its ancestors, so if you do your pulls at the points where anonymous branches merged one at a time, you'll be pulling only the additional changesets from that line of development.




回答4:


Below is an implementation to narrow the graph width using a csscript

The command to copy your repo with the history reordered is

cs-script\cscs.exe HgSortMergeChangesets.cs fromRepo toNewRepo

The file "HgSortMergeChangesets.cs" has the following contents:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

class Program
{
    static int Main(string[] args)
    {
        if (args.Length != 2)
        {
            Console.WriteLine("usage: SortHgRepo <fromRepo> <toRepo>");
            return -1;
        }

        var fromRepo = new DirectoryInfo(args[0]);
        var toRepo = new DirectoryInfo(args[1]);


        int errorCode = VerifyParameters(toRepo, fromRepo);
        if (errorCode != 0)
        {
            return errorCode;
        }

        var revsOutput = ExecCmdReturnStdOut("hg.exe", "log -r \"sort(merge(),date)\" -T \"{rev} {date|date}\\n\"", fromRepo.FullName, Console.WriteLine);

        var mergeChangesets = ParseChangesetLog(revsOutput) 
            .ToList();

        ExecCmdReturnStdOut("hg.exe", string.Format("clone -U -r 0 . \"{0}\"", toRepo.FullName), fromRepo.FullName, Console.WriteLine);

        foreach (var changeset in mergeChangesets)
        {
            ExecCmdReturnStdOut("hg.exe", string.Format("pull \"{1}\" -r {0}", changeset.ChangesetId, fromRepo.FullName), toRepo.FullName, Console.WriteLine);
        }

        ExecCmdReturnStdOut("hg.exe", string.Format("pull \"{0}\"", fromRepo.FullName), toRepo.FullName, Console.WriteLine);

        return 0;

    }

    private static int VerifyParameters(DirectoryInfo toRepo, DirectoryInfo fromRepo)
    {
        if (toRepo.Exists)
        {
            Console.WriteLine("The destination repo already exists: {0}", toRepo);
            {
                return -2;
            }
        }


        if (!fromRepo.Exists)
        {
            Console.WriteLine("The source repo does not exists: {0}", fromRepo);
            {
                return -3;
            }
        }

        // make sure the source dir is a repo
        try
        {
            var identity = ExecCmdReturnStdOut("hg.exe", "identify", fromRepo.FullName, Console.WriteLine);
            Console.WriteLine(identity);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            Console.WriteLine("The source directory, {0}, does not look like an Hg repo.", fromRepo);
            return -4;
        }
        return 0;
    }


    private static IEnumerable<Changeset> ParseChangesetLog(string revsOutput)
    {
        using (var r = new StringReader(revsOutput))
        {
            string line;
            while ((line = r.ReadLine()) != null)
            {
                var spacePos = line.IndexOf(' ');
                yield return new Changeset
                {
                    ChangesetId = int.Parse(line.Substring(0, spacePos)),
                    DateStr = line.Substring(spacePos + 1)
                };
            }
        }
    }

    class Changeset
    {
        public int ChangesetId;
        public string DateStr;
        public DateTime Date { get { return DateTime.ParseExact(DateStr, "ddd MMM dd H:mm:ss yyyy zzz", null); } }
    }



    public static string ExecCmdReturnStdOut(string program, string args, string workingDir, Action<string> writeline)
    {

        writeline(String.Format("Executing: \"{0}\" {1} in {2}", program, args, workingDir));

        using (var proc = new Process())
        {

            proc.StartInfo.Arguments = args;
            proc.StartInfo.CreateNoWindow = false;
            proc.StartInfo.FileName = program;
            proc.StartInfo.WorkingDirectory = workingDir;
            proc.StartInfo.RedirectStandardError = false;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.UseShellExecute = false;

            proc.Start();

            var output = proc.StandardOutput.ReadToEnd();

            proc.WaitForExit();

            if (proc.ExitCode != 0)
            {
                throw new Exception(string.Format("error code {0} returned when running command {1} in dir {2}", proc.ExitCode, "\"" + program + "\" " + args, workingDir));
            }

            return output;
        }
    }


}



回答5:


due credit to @alexis and @Ry4an

I know this workaround of making a new clone ordered by date, and it works, although it might be slow for large repositories. It depends on whether you consider it worth the trouble.

Today, I was pulling to a Windows PC and this caught me, so I wanted to quickly automate it. So here is a rewrite for Windows command prompt:

hg clone -r 0 messy-repo sorted-repo
cd sorted-repo
for /f "usebackq tokens=*" %r in (`hg log -R ../messy-repo -r "sort(1:tip, date)" --template "{rev}\n"`) do @echo %r && @hg pull ../messy-repo -r %r

Notice: percent signs should be doubled if this goes within a batch script file, otherwise single percent for directly input it at the command prompt.

PD: also due credit to Michael Burr for the backquote for Windows prompt: windows subcommand evaluation



来源:https://stackoverflow.com/questions/12455201/is-it-possible-to-manually-change-reorder-the-revision-numbers-provided-topolog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!