Hacker News new | ask | show | jobs
by Rusky 5630 days ago
The difference is not fundamental, no. It is a difference in philosophy and interface that discourages modifying history.

The question is: Why would you commit (to a stable branch) when your code doesn't build or pass tests? Why would you want to eliminate a state where you made something that worked? I don't see the appeal in modifying history.

If you just need to save some partially working state, etc. you can use patch queues- They make much more sense here.

2 comments

> The question is: Why would you commit (to a stable branch) when your code doesn't build or pass tests?

Because:

a) It's not a stable branch. It's my dev branch on my local box that nobody else can see.

b) I feel like it and there's no penalty. I can go back if something is wrong.

c) The next thing I'm going to do is risky. I should save where I am just in case I'm wrong.

> Why would you want to eliminate a state where you made something that worked?

Because it may not be meaningful and it may not work. In the above case, what value do you gain from the three revisions of that change that were incorrect? When it hit code review, there were problems with it. We fixed them. Why would you publish code that is known to be incorrect (since we figured that out during code review)?

> I don't see the appeal in modifying history.

I don't see the appeal in a history full of "Oops, I forgot to add this file to the last commit," and "build fix" and "The author wrote this on Solaris, but I need a small change in the Makefile for Linux."

If there's one logical change, having several commits where you just didn't get it right only adds confusion.

> If you just need to save some partially working state, etc. you can use patch queues- They make much more sense here.

Are you saying that because that's the tool you were offered or because you actually believe it's the best way to do things?

I used mercurial very extensively before I started using git (which I have also used very extensively). Most of my time was spent in mq capturing state of work in progress. That really sucked.

Now, I just commit whenever I feel like it, and then before I publish code, I update the commit messages, squash distinct changes that represent a single logical change that shouldn't be broken up, break up commits that represent more than one logical change that shouldn't be lumped together and just generally tidy things up so the reviewers and future developers tracking back bugs can make sense of things.

Then I test it: http://dustin.github.com/2010/03/28/git-test-sequence.html

> c) The next thing I'm going to do is risky. I should save where I am just in case I'm wrong.

a and b are not really reasons /to/ commit a broken state. On c: If the next thing you're going to do is dangerous, I'd say it's a separate "thing" and either 1) commit the stuff you have in a working state or 2) shelve/stash/qimport it if it's not done and you need to do the dangerous work first, which is why I mentioned patch queues.

Thus, purposeful broken commits are eliminated.

> I don't see the appeal in a history full of "Oops, I forgot to add this file to the last commit," and "build fix" and "The author wrote this on Solaris, but I need a small change in the Makefile for Linux."

hg rollback/backout are intended for "oops, I forgot to add this file to the last commit." There's no need to leave those commits in, unless the problem isn't discovered for a while, which is when modifying history makes sense.

Patch queues are most definitely not just "the tool I was offered." They are a rather powerful way to deal with commits as a stack, and I've never been bogged down "capturing state of work in progress."

---

There's nothing really wrong with git's workflow, but there's nothing wrong with mercurial's either. That's all I'm saying - "it is a difference in philosophy and interface that discourages modifying history" that I happen to prefer.

I haven't used mercurial in anger, and mostly use subversion instead (because that's what my workplace uses at the moment), but:

1) sometimes you commit by accident. This happens to me a few times a year, from hitting the up arrow the wrong number of times and pressing enter.

2) sometimes you say something in a commit message that turns out not to be true, or is just a typo, and especially if you're using commit messages to tie commits to tickets in your bug tracker, this can make code show up on the wrong ticket, or not at all, which is quite confusing for a later maintainer.

It is trivial in Mercurial to back out the last commit: hg rollback

I use it all the time to fix typos, add a file I forgot to add, or whatever. Once you push, it is more difficult, but I try not to push my code until it works. I also commit only tested chunks of code, so that is the "unit of work" I aim for.

The equivalent in git is something stupid, I have to look it up every time: git reset --soft HEAD^

That's intuitive!

git reset HEAD^ (soft is the default option) is actually pretty intuitive once you're used to git. You're reseting the index to the state it was one commit ago (which is what HEAD^ means. That comes up a lot.)

And if you really forget it often, add this to your ~/.gitconfig:

    [alias]
      rollback = reset HEAD^
Now you can run `git rollback`
I know what HEAD^ (and HEAD^^^^^ or whatever) mean.

The fact that I have to make aliases for commonly used tasks is not a point in git's favor to me.

Do you really uncommit that frequently? I just either amend my commits or keep adding new commits and squash them later.

The point is that you can make just about any workflow with git. The ones that git users less commonly use may not be have easy toplevel commands. People already complain about how many toplevel commands there are with git.

It sounds as though the equivalent mistake would be an accidental push. Good to know that git and mercurial allow you to fix things, in any case.
git push is reversible, too: http://news.ycombinator.com/item?id=2079967 (and note my correction below that simplifies things)
git commit --amend