Hacker News new | past | comments | ask | show | jobs | submit login
Five Features from Mercurial That Would Make Git Suck Less (nubyonrails.com)
37 points by ionfish on July 23, 2009 | hide | past | favorite | 14 comments



Commits happen Subversion-style. Yes, this is a feature! No need to add files before every commit or use a flag.

Please, Git maintainers, don't listen to this guy and don't ever change the current behavior. I've come to rely on staging my commits incrementally.

I really care about keeping a pristine history with isolated and understandable commits. Being able to commit pieces without including temporary code or debugging comments is invaluable to my workflow. I want to be able to modify source code without worrying about any piece of it getting committed accidentally. I also want all edits I made, including uncommitted ones, to stick around until I explicitly remove them.

Maybe Mercurial can do this also, but Git has been almost completely do-what-I-mean with regard to making sure I don't lose any changes or confuse myself about where they went.


With Mercurial, you can either use queues and the "qref" command to continually prep a commit in progress, or use the "record" extension (like an interactive Git commit) to pick and choose parts of the working tree to commit.

I suppose it's a matter of what the common case is. For me, the majority of my commits are either one or two files, or the whole working tree -- so Mercurial's defaults make sense with that usage pattern. Of course, other usage patterns would dictate more of a "massage the commit" style.


Git's incremental commits may be a great idea in theory, but in practice, it allows you--even forces you, if you run in any mode except "git add ."--to make commits you've never actually tested. I'd rather have a cluttered history that built at any given point than a clean one that didn't.


I feel the opposite way. I often see hunks like:

     sub foo {
    +    warn "made it here";
         actual code;
     }
This stuff, I never want to commit. Sure, I haven't tested the code without it, but I'm sure it works.

Subversion-style committing sucks hard; worst idea ever. (And besides, svn still lets you do this; svn commit one-file. Untested tree committed, with no possibility of ever backing out the change. Not good.)


It's not so bad as long as you don't push any untested changes. If I do something freaky with the index, I usually stash the leftovers and test the last commit. Like this:

  git add -i
  git commit
  git stash
  ./some_tests  # ...shoot, forgot something
  git add .     # whatever I forgot
  git commit --amend
  ./some_tests  # now we're good
  git stash apply
  git stash clear
  git push
On the hg side, you can use mq and record to get yourself in and out of the same kind of trouble, as someone else mentioned. I think these are essential but dangerous features that any good DVCS should have.

A better safety mechanism (than deleting the feature) is a pre-push hook that runs the test suite on every commit since the remote head. Not everyone needs that level of strictness, though.


It's the other way around. Partial commits terrify me in theory; in practice it's really easy to work out which lines you want to commit and which lines you don't, and having a clean history is really really nice.

And since you've got both "git commit --amend" and "git rebase -i" to hand, it's trivial to later on fix up any mistakes you do make.

Honestly, having a clean history is an enormous win - it far outweighs the minor cost of making the odd wrong but easily-correctable-after-the-fact commit.


You can have both, you know: you use git stash/Mercurial attic to shelve the parts of the change you don't want, test the result, commit, then reapply what you stashed. You get a clean history, and you can easily verify your source code works. This solution notably does not involve explicitly exposing the dirstate to the user.


I agree with the superficial things for the most part, though it should be pointed out that 'hg revert .' and 'git checkout .' do basically the same thing - the 'git reset --hard ORIG_HEAD' example is way more complex than it needs to be and is a bit more harsh than he's asking for.

The one big issue is the branching comments. Creating named branches like he's doing here is very problematic, especially if you're at all used to Git branches. Running '--close-branch' doesn't really remove the branch, it adds another commit that has some metadata saying it's closed - but older versions of hg won't recognize that (the feature is very, very new - it was introduced in 1.2) and even if you have a version of hg that supports it, the last I tried it won't hide the closed branches by default, you have to provide a switch to 'hg branch' to hide them ('hg branch --active'), which is pretty annoying. If I created named branches for all the topic branches I've made in my various Git projects, I'd have hundreds or thousands of named branches littering up many of them.

There are tons of other serious problems with Hg's concepts of lightweight branching - for instance, you can't NOT push all of your branches to a repo when you push, meaning you can't have any branches that are just for you to test stuff out in - if you create what Git users think of as a 'topic branch', it's basically there forever - no way to ever really remove it or not share it. If you use the Bookmarks extension, which is meant to more closely mimic Git branching, you have the opposite problem - you can't push the bookmarks up to a shared server, you have to SCP them separately. I believe the heads will be there, but that's even more confusing because now you just have a bunch of unnamed heads...

Speaking of namespace issues, named branches are way worse for that - if you create a named branch locally and someone else creates the same named branch locally and then you clone from them, you'll have two heads with the same branch name, which could have totally different lines of work on them and Hg doesn't complain - that could get ridiculously confusing.

Most Hg users I know only very rarely use named branches - the online book recommends doing a local clone instead of a named branch for branching. Many serious Hg users instead use the 'mq' extension, which provides a patch queue toolset for Hg and allows you to do some revlog editing - allowing you to do development much more similarly to how Git devs do, but the toolset and paradigm are _much_ more convoluted and confusing than the problems he states about Git branches, IMHO.

There are certainly a number of UI improvements that Git could make (and Hg, too) but I really don't think Hg's branching model is something to emulate.


The Mercurial equivalent of "git reset --hard ORIG_HEAD" is "hg update --clean" (or "hg up -C" for short), which is still clearer to understand than the git equivalent, in my opinion.

To correct another common misconception, you can absolutely push only certain heads of a repository. The command is "hg push -r <head of relevant branch>". If you have bookmarks installed, that can be as easy as "hg push -r <bookmark name>".


For feature branches, I've seen meaningful uses of named branches, but as a devout Mercurial user, I actually agree that git's "lightweight tag" model of branching feels a little more useful. Hopefully soon hg's bookmarks will be push/pull'able.

Also, you totally can push all of your branches to a repo - that's just not the behavior that is allowed by default because often that isn't what the user meant. It's also confusing because bookmarks aren't push-pull capable (yet).


The only feature I would really like to see is 'hg serve'. I would like to be able to host Git easily on my website and gitweb just isn't there today. GitHub is nice and everything but it isn't appropriate in all cases


Amen to that. Lack of easy serving is the only disadvantage I see to current version of git over Hg.

Been a Merucial enangelist some time ago, since about 0.9. Once switched to git, I had never looked back but for the ease of `hg serve'. Anyway, git's branch handling is a killer advantage, matches the workflows I use (small team, and single developer on multiple machines) much better than the branches with one global namespace in Hg.

About that reset/update/revert, you may want to define an alias in your ~/.gitconfig; simple as that.


Honestly, I think this numeric sequence of commits is terribly confusing.

In theory, a small happy number is easy to deal with. In practice, a team of two developers doing pushes and pulls with auto-merging will have sequences that don't line up so they can't use them to talk about revisions anyway.

git's "describe" output is the best of all worlds.


Use bazaar.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: