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

5

8

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.

enter image description here

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

enter image description here

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.

Trioxide answered 17/9, 2012 at 7:59 Comment(6)
Must admit, I don't see the issue. The graph shows topology. The real world timing of commits is secondary.Wingfield
@Paul S: When you have many transversal lines in your graph, they can be hard to follow. Moving commits 404–405 between commits 370—371 and 406 right after 371, 407 right after 380, 408 and 409 right after 399, would produce a graph of lesser width (two columns actually).Trioxide
@Paul S: see edit. Can't you see that one is really more clear, and has the exact same topology?Trioxide
Ah yes, I see what you mean. I think that graphlog seem to be quite good at this, but tortoise isn't, which is a little odd.Wingfield
Ok, so I'm 3 years late here, but can't you just ask your co-worker to use hg rebase instead of hg merge?Janejanean
I had the same question. It came as an unpleasant surprise to realise that TortoiseHg wasn't actually doing it in chronological order; it just looks like that if you're pulling and pushing frequently, or working by yourself.Habitforming
A
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.

Ascending answered 17/9, 2012 at 10:7 Comment(1)
It is already down as a proposal on the THG issue tracker here, but it was raised in April 2011 so I guess that the THG team don't have it as a high priority either.Polygamous
E
6

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.

Excommunicatory answered 15/4, 2013 at 10:11 Comment(1)
This is almost perfect, except that it always puts revision 0 at the start of the new repository, so if even that is out of order then that won't be fixed. To solve that, use hg init instead of hg clone ..., then change ...sort(1:tip, date)... to ...sort(:, date)....Gouveia
G
4

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.

Gagliardi answered 17/9, 2012 at 13:6 Comment(1)
I wouldn't say it's too much work: If you know the order you want, it's just a simple loop in your favorite scripting language. I've a similar use case (see my answer).Excommunicatory
A
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.

Ascending answered 17/9, 2012 at 10:7 Comment(1)
It is already down as a proposal on the THG issue tracker here, but it was raised in April 2011 so I guess that the THG team don't have it as a high priority either.Polygamous
L
1

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;
        }
    }


}
Lashawnda answered 28/2, 2015 at 23:37 Comment(0)
L
0

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

Langland answered 9/6, 2016 at 19:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.