As
discussed previously, I'm working on enhancing Hg-Git by adding support for deleting remote Git branches in the same way you would normally use Hg to delete remote bookmarks. The main pain-point this addresses is that there isn't currently any way to perform this operation using Hg-Git (you need to instead use Git or some other tool). This approach was preferred over a new command ('hg remove-git-branch', for example), since I believe the current thinking is that, as much as possible, Hg-Git should match Hg's normal behavior. In this case, that means that using Hg with Hg-Git to push/pull remote Git branches should exhibit similar behavior to using Hg to push/pull remote Hg bookmarks.
"To delete a bookmark from a server, delete it locally first, then use push -B on the deleted name."
The main implementation of this in Mercurial is in mercurial/command.py in the push method. It first converts any specified bookmark options into revisions to include in the push, then calls push on the repo, then goes through the specified bookmarks again to use listkeys and pushkeys to synchronize bookmarks. From this, it looks to me like there are three main ways we should hook in to implement support for this feature:
- Wrap commands.push. If the remote is a git repository, call special logic to delete remote branches if appropriate.
- Add logic into the push method in our existing repo subclass. We'd need to somehow gain access to opts['bookmark'], which isn't passed in... which might really mean that this is a false option, and is a subset of option #1.
- Add logic into the listkeys and pushkeys methods in our existing gitrepo peerrepository subclass. We'd need access to the GitHandler instance to do anything meaningful.
I started down the road of #3 first, and got it to the point where it appears to be accomplishing the desired change (deleting remote git branches) as appropriate. Currently, in my implementation, it is doing an additional send_pack() for each branch that needs to be deleted. I don't think that this is likely to be a big deal in practice (since deleting remote branches hopefully isn't a frequently-used operation), but it seems inelegant, as it would have been possible to delete them all at once during the send_pack in push() if we had the appropriate information (a la option #1 above).
Putting performance concerns aside for the moment, option #3 has a side-effect I hadn't realized up-front. By having listkeys() return the accurate list of remote bookmarks, Mercurial now is able to recognize divergent bookmarks (as documented in
Transferring bookmarks on the wiki). This feature was only added in Mercurial 2.1. Thus, when in a divergent bookmark use case, previously, Hg-Git would leave the local bookmark alone silently (but fail on push, I believe). Now, in Mercurial 2.1+, a message "divergent bookmark master stored as master@default" is printed and an incoming bookmark is created with a suffix. In previous versions of Mercurial, a different message "not updating divergent bookmark master" is printed and no incoming bookmark is created.
As an Hg-Git user that uses a recent versions of Mercurial, I'd prefer being able to use a workflow based completely around bookmarks (including divergent bookmarks, when appropriate). When this support is available, I don't think there's a need for creating local tags for remotes any more; from a user perspective, it's a redundant way of storing and displaying the same information.
Our current policy is to support the version of Mercurial shipped with the latest Ubuntu LTS build and subsequent Mercurial releases. Currently, that means Hg 2.0.2 (shipped with Ubuntu 12.04 LTS). From the
Ubuntu wiki LTS page, I don't expect there will be a new LTS release until 2014. That means that, unless we change our support policy, we need to support a workflow without divergent bookmark support until the next LTS release.
There are a few ways we could handle this:
- Don't pursue a deeper integration with bookmark workflow yet. Use option #1 from above to support deleting remote branches, and don't pursue divergent bookmarks.
- Add support for divergent bookmarks, but keep local tag support as well. Add a configuration option to allow users to disable local tag support. This option increases the complexity of the codebase and test corpus, but allows progress on the new features immediately.
- Create a new branch for a bookmark-based workflow, and in that branch, require Hg 2.1 or later. Remove support for local tags in that branch. Either hold off on publishing any release versions of this branch until the next LTS release, or maintain both this branch and a stable branch, and perform releases from both.
- Fork the project, and tune the fork to a clean bookmark-based workflow (maybe similar to the hgit repo?). This allows for users to choose between Hg-Git and the fork based on their needs. However, it splits the development.
I'm not sure which direction is best. Thoughts on that, or anything else?