Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mercurial - How do I create a .zip of files changed between two revisions?

I have a personal Mercurial repository tracking some changes I am working on. I'd like to share these changes with a collaborator, however they don't have/can't get Mercurial, so I need to send the entire file set and the collaborator will merge on their end. I am looking for a way to extract the "tip" version of the subset of files that were modified between two revision numbers. Is there a way to easily do this in Mercurial?

Adding a bounty - This is still a pain for us. We often work with internal "customers" who take our source code releases as a .zip, and testing a small fix is easier to distribute as a .zip overlay than as a patch (since we often don't know the state of their files).

like image 562
Joe Schneider Avatar asked Dec 09 '09 04:12

Joe Schneider


People also ask

How to remove files in Mercurial?

Once you decide that a file no longer belongs in your repository, use the hg remove command. This deletes the file, and tells Mercurial to stop tracking it (which will occur at the next commit). A removed file is represented in the output of hg status with a “ R ”.

What does HG update do?

Use the command hg update to switch to an existing branch. Use hg commit --close-branch to mark this branch head as closed.


2 Answers

The best case scenario is to put the proper pressure on these folks to get Mercurial, but barring that, a patch is probably better than a zipped set of files, since the patch will track deletes and renames. If you still want a zip file, I've written a short script that makes a zip file:

import os, subprocess, sys
from zipfile import ZipFile, ZIP_DEFLATED

def main(revfrom, revto, destination, *args):
    root, err = getoutput("hg root")
    if "no Merurial repository" in err:
        print "This script must be run from within an Hg repository"
        return
    root = root.strip()

    filelist, _ = getoutput("hg status --rev %s:%s" % (revfrom, revto))
    paths = []

    for line in filelist.split('\n'):
        try:
            (status, path) = line.split(' ', 1)
        except ValueError:
            continue
        if status != 'D':
            paths.append(path)

    if len(paths) < 1:
        print "No changed files could be found."
        return

    z = ZipFile(destination, "w", ZIP_DEFLATED)
    os.chdir(root)
    for path in paths:
        z.write(path)
    z.close()

    print "Done."


def getoutput(cmd):
    p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return p.communicate()


if __name__ == '__main__':
    main(*sys.argv[1:])

The usage would be nameofscript.py fromrevision torevision destination. E.g., nameofscript.py 45 51 c:\updates.zip

Sorry about the poor command line interface, but hey the script only took 25 minutes to write.

Note: this should be run from a working directory within a repository.

like image 58
Dan Avatar answered Oct 22 '22 00:10

Dan


Well. hg export $base:tip > patch.diff will produce a standard patch file, readable by most tools around.

In particular, the GNU patch command can apply the whole patch against the previous files. Isn't it enough? I dont see why you would need the set of files: to me, applying a patch seems easier than extracting files from a zip and copying them to the right place. Plus, if your collaborator has local changes, you will overwrite them. You're not using a Version Control tool to bluntly force the other person to merge manually the changes, right? Let patch deal with that, honestly :)

like image 25
Nicolas Dumazet Avatar answered Oct 22 '22 02:10

Nicolas Dumazet