There's no symmetry in commands. The opposite of "git commit" is "git reset --soft HEAD^", not "git uncommit". "git reset" is three commands in one. I could go on and on.
git was designed as a data model and then a series of slapdash commands that enabled manipulation of that data model. It wasn't designed from the end-user perspective backwards, and this really, really shows.
I actually use the GIT-SVN bridge to work with git locally, pushing my changes up to SVN when I've resolved a topic. I do this in part because of the staging area. I have accidentally included changes in SVN commits so many times that I try to avoid SVN altogether.
I agree though, so many of the commands are just plain painful, the reset command(s) is a perfect example.
You have it right that it was designed as a data model. Linus has said a few times that it wasn't originally intended to be the Source Control Management tool itself, but more like a kit for building an SCM. Sadly, it took off so quickly simply because Linus built it and was adopted as the end user solution.
I'm curious, as someone who actually loves it, what if there were just better tools for incrementally altering the last commit instead? I'm not sure that a more robust git commit --amend couldn't achieve the same goals as the index with less conceptual overhead.
If you make a specific case for 'git reset --hard/--soft HEAD^' then you would either be left without the more general (and more useful) 'git reset --hard/--soft <commit>', or you would have a situation where you have to use 'uncommit' to (for example) re-commit something, or you would be left with a git-uncommit command and still have git-reset for related operations. Why would any of that be better?
You could split the third invocation of git-reset off into its own command, but honestly I don't see the utility in doing that.
git reset --hard tells you absolutely nothing obvious about what it's going to do unless you understand git and its specific incantations. You have to learn git commands, rather than intuit them.
-p, --patch
Interactively choose hunks of patch between the index and the work
tree and add them to the index. This gives the user a chance to
review the difference before adding modified contents to the index.
This effectively runs add --interactive, but bypasses the initial
command menu and directly jumps to the patch subcommand. See
“Interactive mode” for details.I much prefer bzr's porcelain, it's much better designed and more sane.
git is more complex on the surface, but I really find it to be so much simpler when you end up in real nontrivial use cases, especially when something goes wrong. I would agree that the commands are sometimes too memorization-intensive, but I've never been in a situation with git, even as a beginner, that I couldn't figure out and resolve relatively easily, especially with all the online resources available. I can't say the same for svn. Maybe I was just an idiot when using svn, but if I was an idiot there, I don't see why I wouldn't be an idiot with git as well unless there was just something fundamentally more useable and flexible and understandable about git.
When I tried the same approach with mercurial I found that rewriting the history is not reasonably supported by mercurial. They use these append-only data structures that sound nice, because they assure stability (no already written data is ever in danger because files are only appended) and fit with the general concept of commit->pull->merge. But when you want to change the commit history you clash with the append-only concept. The Histedit extension which is meant to provide this feature has warnings all over the place that what I do is dangerous and might result in data loss with changeset backups written to locations in the working tree. It's horrible compared to Git.
Now don't misunderstand me, Git has a lot of problems UI wise (for example I still don't really grasp what is going on with detached heads). But I find the fundamental design choices more sound than with any other VCS that I have tried.
> Histedit extension which is meant to provide this feature has warnings all over the place
Ignore them — you do know, what are you doing, right?
> changeset backups written to locations in the working tree
That's not true. Backups are written to .hg/strip-backup directory, which isn't tracked.
No, I don't :). I heavily rely on my CVS to never loose any data and to be able to go back to a previous state whenever I need to. This works great with Git's reflog.
> That's not true. Backups are written to .hg/strip-backup directory, which isn't tracked.
I stand corrected then. Maybe I'm mixing that up with amend or revert? I last used mercurial 9 months ago, but believe to remember there was some command that left .orig files lying around and that if you applied a history rewrite command several times those backups were overwritten with the new backups and you weren't able to come back all the way.
as I've said, old commits are backed up.
> This works great with Git's reflog.
except git reflog is cleaned on git gc
Not mentioning http://mercurial.selenic.com/wiki/ChangesetEvolution feature is being in development.
> there was some command that left .orig files lying around
Only way .orig files may pop up is failure to replay rebased commit(s). No way these are backups — their purpose is to make user able to fix things and continue.
Since I failed to understand SVN after years of use I would say it is more complex.
If you're using svn you need to understand the implementation to get why copies are cheap, so that you can understand how to use branching and tagging appropriately.
Git seems to force you to dive straight into the deep-end, since everything is a branch, even your own local working folder.