internal fragmentation

a personal journal of hacking, science, and technology

How to find rename data in Mercurial

Wed, 24 Aug 2011 11:27 by mpm in Uncategorized (link)

A fairly common question from new Mercurial users is “how do I figure out where/when a file got renamed?”

As an example, let’s look at the history of a file in the main Mercurial source that got renamed in the distant past. Start with something like this:

$ hg status --rev 10 --copies mercurial/localrepo.py
A mercurial/localrepo.py
  mercurial/hg.py

This says localrepo.py was copied from hg.py some time between the checkout and rev 10. We can even figure out where that happened:

$ hg log -v -r 'limit(follow("mercurial/localrepo.py") and file("mercurial/localrepo.py"), 1)'
changeset:   1089:142b5d5ec9cc
user:        mpm@selenic.com
date:        Sat Aug 27 14:21:25 2005 -0700
files:       mercurial/changelog.py mercurial/dirstate.py
mercurial/filelog.py mercurial/hg.py mercurial/httprepo.py
mercurial/localrepo.py mercurial/manifest.py mercurial/node.py
mercurial/remoterepo.py mercurial/repo.py mercurial/revlog.py
mercurial/sshrepo.py
description:
Break apart hg.py

- move the various parts of hg.py into their own files
- create node.py to store node manipulation functions

The magical -r argument can be read as:

“Find all revisions in the history of localrepo.py where it still has that name and show just the first one”

See ‘hg help revsets‘ for more info.

But we usually don’t need anything nearly that complicated. This simple command works where this file hasn’t existed multiple times:

$ hg log -l 1 -r 0: mercurial/localrepo.py
changeset:   1089:142b5d5ec9cc
user:        mpm@selenic.com
date:        Sat Aug 27 14:21:25 2005 -0700
summary:     Break apart hg.py

In other words “starting at rev 0, list one commit mentioning localrepo.py”

Here we can see exactly what happened in that crazy commit: lots of files copied from hg.py. These are all ‘copies’ and not ‘renames’ because hg.py continues to exist.

$ hg status --change 1089 -C
M mercurial/hg.py
M mercurial/revlog.py
A mercurial/changelog.py
  mercurial/hg.py
A mercurial/dirstate.py
  mercurial/hg.py
A mercurial/filelog.py
  mercurial/hg.py
A mercurial/httprepo.py
  mercurial/hg.py
A mercurial/localrepo.py
  mercurial/hg.py
A mercurial/manifest.py
  mercurial/hg.py
A mercurial/node.py
A mercurial/remoterepo.py
  mercurial/hg.py
A mercurial/repo.py
A mercurial/sshrepo.py
  mercurial/hg.py

And lastly, we can do:

$ hg diff --git -r 10 mercurial/localrepo.py
diff --git a/mercurial/hg.py b/mercurial/localrepo.py
copy from mercurial/hg.py
copy to mercurial/localrepo.py
--- a/mercurial/hg.py
+++ b/mercurial/localrepo.py
@@ -1,575 +1,2058 @@
-# hg.py - repository classes for mercurial
+# localrepo.py - read/write repository class for mercurial
 #
-# Copyright 2005 Matt Mackall
...

The  ‘–git’ flag asks Mercurial to use git’s non-standard diff format to show copy/rename info, and Mercurial thus shows a diff against hg.py from revision 10 rather starting with an empty file.

We obviously can’t do all of this in the web interface, but we can still easily track down file origins:

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.