Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function history with Mercurial

I'd like to be able to get the complete history of a function or a particular text block inside my code.

I know i can have the diffs of all my commits on a particular file, but I only want to follow the life of a particular small block of text inside my files (a C++ function for instance).

I want to see it change though past revisions, no matter if is moved inside the file or to another file or even renamed (the rest of the function remaining more or less the same when renaming)

I heard Mercurial could do this easily thanks to its proper recording of history, but I don't remember where I heard that (in my dreams ?) and I can't find any tool or way to do that except the traditional history and diff tools. Maybe I don't search with the right keywords... Anyone can help ?

Thanks

PS: I still use SVN for other projects, and if someone knows a way to accomplish the same thing with SVN, I take it too :-)

like image 808
user338759 Avatar asked Jul 18 '11 22:07

user338759


1 Answers

This is actually quite doable with hg grep. An example speaks for itself:

$ hg grep 'def revrange' --all
mercurial/cmdutil.py:14319:-:def revrange(repo, revs):
mercurial/scmutil.py:14319:+:def revrange(repo, revs):
mercurial/cmdutil.py:3707:-:def revrange(ui, repo, revs):
mercurial/cmdutil.py:3707:+:def revrange(repo, revs):
mercurial/cmdutil.py:3090:+:def revrange(ui, repo, revs):
mercurial/commands.py:3090:-:def revrange(ui, repo, revs):
mercurial/commands.py:2331:-:def revrange(ui, repo, revs, revlog=None):
mercurial/commands.py:2331:+:def revrange(ui, repo, revs):
mercurial/commands.py:705:-:def revrange(ui, repo, revs = [], revlog = None):
mercurial/commands.py:705:+:def revrange(ui, repo, revs, revlog=None):
mercurial/commands.py:697:-:def revrange(ui, repo, revs = [], revlog = None):
mercurial/commands.py:697:+:def revrange(ui, repo, revs, revlog=None):
mercurial/commands.py:580:+:def revrange(ui, repo, revs = [], revlog = None):

I asked hg to find def revrange (a function definition). In combination with the --all flag to grep, this prints every revision that contains a change in match status.

So we can easily see the evolution of this function:

  • it was first introduced in revision 580, in commands.py
  • 697 removed the default to the revs argument
  • 705 seems to be a merge
  • 2331 removed the revlog argument
  • 3090 moved the function to cmdutil.py
  • 3707 removed the ui argument
  • and finally, 14319 moved the function to scmutil.py

Of course, this isn't perfect, since if the function was renamed, the chain would end after the rename. But depending on your particular use case, this might be enough.

To be more sophisticated, you could write a relatively simple script that can even follow renames.

like image 63
Idan K Avatar answered Sep 20 '22 16:09

Idan K