Attic Extension
This extension is not distributed with Mercurial.
Author: Bill Barry (BillBarry)
Repository: https://bitbucket.org/Bill_Barry/hgattic
Mailing list: http://groups.google.com/group/hgattic
Overview
This module deals with a set of patches in the folder .hg/attic. At any time you can shelve your current working copy changes there or unshelve a patch from the folder.
Configuration
Enable the extension by adding following lines to your configuration file (hgrc):
[extensions] hgattic=/path/to/attic.py
Usage
The extension adds a couple of commands, all starting with attic- so that they are grouped together in hg help, but all have shorter aliases:
hg attic-shelve
Shelve will take the current changes to the working copy and create a patch in the attic:
hg shelve [name]
You need to supply a name for the patch when you first shelve it, but you can forget it if you are already working on a patch as, in that case, changes are added to the current patch.
This command comes with a lot of options, some are:
-m or --message |
Use <text> as the commit message |
-e or --edit |
Bring up an editor to supply the commit message |
-r or --refresh |
Refresh the current patch without stowing it away |
-i or --interactive |
Use the 'record' extension to interactively select hunks for a shelf |
as well as some for setting the user and the date. See the command help for more details.
hg attic-unshelve
Unshelve is the mirrored partner to shelve
hg unshelve [name]
(if any HUNK gets rejected because, for example, somebody else made changes to your files, you can consider using mpatch http://oss.oracle.com/~mason/mpatch/ to handle rejected files)
You need to supply a name if it isn't the same as the last patch you were working on. Ex:
... do some work hg shelve patch1 ... fix a bug hg ci -m "fixed bug" hg unshelve ... name is not needed here because it is assumed to be patch1
vs.
... do some work hg shelve patch1 ... work on something else hg shelve patch2 ... switch back to patch1 hg unshelve patch1 ... name is needed here because it is assumed to be patch2
hg attic-display
The attic command displays the list of patches in the attic:
hg attic
There are some options to change what it displays:
-c or --current |
Show information about the current shelf being worked on |
-d or --header |
Show information about a given patch by name |
Comparison with similar functionality
Attic is much like several other extensions, but still is different enough that you have a reason to choose one above the other.
Mq
Attic and mq are alike in that: 1. They both deal with patches and you can use patches from one wherever you can use patches from the other. 2. Both are designed to enable sharing patches.
Yet, these two extensions are very different. Mq is designed to work with a series of patches and attic is designed to work with a set of patches. If for example you have 3 patches that have nothing to do with each other in your series file in mq:
feature1 feature2 feature3
and you find that you are working on feature1 and suddenly realize there is a bug in feature2, you would:
hg qpush ... working on feature1 and realize bug hg qrefresh hg qpop ... reorder feature2 and feature1 (put feature2 first) hg qpush ... fix feature2 hg qrefresh hg qpop ... reorder feature2 and feature1 (put feature1 first) hg qpush ... continue working on feature1
whereas with attic:
hg unshelve feature1 ... working on feature1 and realize bug hg shelve hg unshelve feature2 ... fix feature2 hg shelve hg unshelve feature1 ... go back to feature1
While this process is workable in mq with only 3 patches, it grows unwieldly as your patch count increases.
In addition to providing different usecases to mq, attic works well alongside mq, for example: splitting a patch in mq (one way of many):
hg qgoto patchtosplit hg qpop ... move patchtosplit from .hg\patches to .hg\attic and remove it from series hg unshelve patchtosplit hg shelve -f --interactive patch1 hg shelve --interactive patch2 hg shelve therest hg unshelve --delete patchtosplit hg up -C qtip hg qimport .hg\attic\patch1 hg qimport .hg\attic\patch2 hg qimport .hg\attic\therest
working on feature1 and realize a fix for feature3, but you aren't ready to switch to it yet:
hg qpush ... work on feature1, realize fix for feature3 hg qrefresh ... make fix for feature3 hg shelve feature3-fix ... continue on feature1, eventually doing hg qrefresh hg qgoto feature3 hg unshelve --delete feature3-fix ... now test the changes and qrefresh
see also MqExtension
Pbranch
Though I (BillBarry) do not know enough about pbranch yet to provide an in depth discussion on it, I do know enough to say that pbranch can do just about everything that attic can do (perhaps interactive shelving is the only thing attic can do that pbranch cannot) and can also be used to provide long term support for patches (attic is designed for mostly quick and dirty stuff). Pbranch is more powerful than attic in multiple ways (one quick example: pbranch can deal with a full patch graph whereas attic only deals with one patch at a time). However, with the power of pbranch comes the complexity of pbranch.
see also PatchBranchExtension
Shelve
Shelve (the interactive shelving extension) is almost entirely a subset of attic. In fact attic's hg shelve --interactive is calling 3 methods directly pulled from the hgshelve extension source code.
see also ShelveExtension
Potential usecases
temporarily shelving something away to fix something else:
... working on something, bug comes in hg shelve mywork ... make fix hg ci -m "fixed bug" hg unshelve ... continue
splitting patches:
... put bigpatch into .hg/attic hg unshelve bigpatch hg shelve -f --interactive patch1 hg shelve --interactive patch2 hg shelve finalpatch
cherry picking:
all devs have attic under version control and 1 dev can pull from them: dev1 finishes feature: hg shelve -m "the message I want for the commit" -u featurea cd .hg/attic hg addrem hg ci -m "featurea ready" hg push (or whatever to make the patch public, example with shared repo assumed) dev2 finishes feature: hg shelve -m "the message I want for the commit" -u featureb cd .hg/attic hg addrem hg ci -m "featureb ready" hg push picker: cd .hg/attic hg pull cd ../.. hg unshelve featurea ... checks, it is ok hg ci (or move to mq, etc) hg unshelve featureb ... not ok hg shelve cd .hg/attic hg rm featurea hg ci -m "brought featurea into mainline" hg push
folding patches:
... patch1, patch2 and patch3 in attic hg unshelve --delete patch1 hg unshelve --delete -f patch2 hg unshelve --delete -f patch3 hg shelve foldedpatch
considering multiple implementations:
... do implementation 1 hg shelve impl1 ... do implementation 2 hg shelve impl2 ... do implementation 3 hg shelve impl3 ... converse with people about which patch is best hg unshelve impl2 hg ci -m "impl2 was best" cd .hg/attic rm impl1 rm impl3
Technical details
Restrictions on patches
Don't create a patch with a name that starts with a period. It will not be shown with the attic-display command (and it could conflict with special files in the attic). Any special file in the attic is expected to start with a period (this is reserved for future usage as well).
Versioning the attic directory
You can put the attic under revision control, just ignore files that start with a period. This is particularly useful for sharing patches with a group of people.
Special files
Currently there are two special files:
.applied |
contains the name of the current applied patch |
.current |
contains the name of the assumed default patch |
See also
ShelveExtension, PatchBranchExtension, MqExtension