Hacker News new | past | comments | ask | show | jobs | submit login

One personal anecdote:

In a decade of using Mercurial, I've managed to get a repository in such a confused state that I had to blow it up and start from scratch just once. In the same time, I've had to do the same for git repositories at least 5 or 6 times--and I never really used git all that much. Even nowadays, where I'm more or less forcing myself to use git [1], I'm incredibly hesitant to try any sort of complex git operation because of the risk that I might lose my in-progress commits.

While the problems of git's UI is well-known, I don't think it's as appreciated that git's complexity generally discourages people from trying things out. I'm never really sure what could cause me to lose unpushed commits or uncommitted working files, especially with git's predilection for reusing the same verb to do slightly different operations for different concepts. In stark contrast, it's more difficult to get Mercurial to chew up your work without telling you [2], and it's easier to explore the command lists to see if there's something that can do what you want it to do.

[1] The repositories I'm working on involve submodules, which hg-git is exceptionally poor at supporting well. Even so, the list of git alias commands on the whiteboard is entitled "Forcing myself to use git before I rage-quit and switch to Mercurial."

[2] I have done it, though. Worst offender was discovering that hg qrefresh <list of files> causes only those file changes to be committed, and files not mentioned are decommited to working-directory-only changes... which hg qpop happily deleted without warning me, causing me to lose a large patch. That was when I put the patch queue directory in version control.




> I don't think it's as appreciated that git's complexity generally discourages people from trying things out.

For me, at least, the underlying model actually makes it easier to try things out. As long as my work is in commits and I have refs that point to those commits, I can be pretty sure that I'm not going to lose anything. I also take a fair amount of comfort in the fact that (unlike, say, SVN), any remote actions can be deferred until I know things are correct locally.

This sort of robustness in the data model makes it a bunch easier for me to forgive the (very real) usability issues in the command line UI. (And, after years of work, the command line is getting more familiar, aside from some of the more complex rebase operations.)


> I don't think it's as appreciated that git's complexity generally discourages people from trying things out.

Personally, I'm not shy about recursively copying the entire repository on disk to run potentially destructive experiments in a duplicated environment.

Also, once you understand how to pull things out of the reflog, it's usually not hard to restore to a sane state.


> I'm not shy about recursively copying the entire repository on disk

Agreed.

> Also, once you understand how to pull things out of the reflog,

That, and I'll also dump a git log of the last couple dozen commits into an editor buffer so that I can hang onto the commit ids. Until a GC cycle occurs, you don't lose the commits even if they aren't reachable through normal paths.


`git reflog` gives you the historical list of SHAs that you've pointed HEAD at; even if you destroy your branch with a rebase, you can still see what commit your branch pointed to before you started the operation.


Yeah... I just find the printed log output a bit easier to read (at least for the few times I need to do this sort of thing). '@' syntax falls into that same basic category - powerful, the better solution, but nothing I use enough to bother mastering.


I agree.

I want a VCS that does NOT try to hide how it works from me.

I love that git gives me a) a bag of commits forming one or more rooted trees, b) symbolic names for commits/branches that resolve to individual commits in that bag.

That's such a simple model.

Remotes. Commits. Branches/tags. That's it.

Merging and rebasing merely create new anonymous branches in the bag of commits, then move a branch name (if applicable) to point to the new HEAD. Done. Trivial.

The reflog is just a local log of actions taken, and can be used to quickly recover from missteps: just find a HEAD you want as your branch's head, and then git branch -f branch <commit>.

The index/staging area are very, very useful, mostly because of git add -e, which is extremely powerful. This lets me split up my commits usefully.

Just about everything else is stuff you can figure out as you go.

The only thing you can ever lose in git (short of doing rm -rf .git) is workspace content that you have not added to the index or committed. Stay away from git reset unless you know what you're doing with it, and all is good.

Being able to think of the state of the repo as a tree of anonymous commits, with a name resolution table for resolving branches/tags to commits, makes doing complex tasks trivial for me. I often rebase in detached head mode and nothing goes wrong; when I'm done I manually move/create a branch to the new HEAD -- I can do this because the tree-of-anon-commits model is so darned simple.


Now, can that be explained to a git newbie in under half an hour, to get them up and running?

IMO, the scary UI/UX of git is holding back the use of version control for a lot of digital documents beyond just source code. It needn't be this complicated.


I've tried to get noobies to use SourceTree on OS/X, with Mercurial or git, and it never goes well. Version control is just hard the moment you want to do anything other than linear commits. The moment you want to undo something partially, it gets ETOOHARD on most non-developers, and especially people like my mom.

On the other hand, when explaining the git model to sysadmins and developers, not sugar-coating it has worked best for me. I explain the bag-of-commits+nametable design. I explain the workspace and staging area. I show how one does things. This works for me.

Maybe git's UI "needn't be this complicated", but I do find that Mercurial's heavy-duty branches lead to hell very quickly and it's always difficult to recover -- and Mercurial is supposed to be simple! The lesson is that simplifying isn't easy, and not every simplification works well generally.

With git I can simplify in that I show users a small amount of abstract concepts (bag-of-commits, nametable) and a small set of common usages and then let them learn by experience and osmosis as they reach out for help when they stray past those usages. I can't do this with other VCSes. At some point it just becomes painful.

One of the nice things about git is that I can push users to make very linear history. This is nice because diving into the history of a tangled mess of merged branches is not easy, and it's actually very confusing to non-professionals. But even for professionals, linear history is far superior to a tangled mess of merged branches, and only git really gives us that power today.


> I'm never really sure what could cause me to lose unpushed commits...

Effectively nothing. By default, old, unreferenced data is only garbage collected after a month. If you screw up a rebase, the old commits are still there with the same hash they always had. You just need to point the branch at them again.

> ...or uncommitted working files

That's fair. If I'm unsure, I just stash or commit first. Anything that's in git can be retrieved.


Sometimes I find myself doing "git stash; git stash apply" just so I have a checkpoint of what I'm working on. That plus "git stash list -p" lets me go back through tons of non-checked in junk to find (say) that one line of debugging code that turned out to be pretty useful…


You can do small temporary commits on a branch, and once you want to do an actual commit which will then be pushed, you go onto the master branch and `git merge --squash <work-branch>`.


This.

Git makes using branches very easy and it is fairly quick with most operations. Once you understand what the commands are doing, you'll see that unless you do something specifically (like reset --hard with uncommitted changes, checkout a modified file etc.), you'll never lose work which has been committed in some branch or the other.

I tend to just do "in-between" commits very often and rebase to reorganise the commits (reorder, squash, reword) when I hit a (micro)milestone.

If your work has been committed and the repo was not just garbage collected, it is going to be easy to retrieve it from reflog even if you did something nasty with the branch and it appears that your commit has disappeared.

Git is the piece of software which I find very good in terms of what it does but it does it behind the worst user-interface I have ever encountered.

EDIT: minor clarifications and punctuation


Microtutorial for git:

`git clone https://repository.url` (download repository)

`git checkout -b issue_XXX` (create new branch with the name 'issue_XXX')

`vim README.MD` (edit a file)

`git add README.MD` (mark the file to be committed, `git reset README.MD` to unmark)

`git status` (see list of changed/marked files)

`git commit -m "Add Readme"` (create commit based on marked files)

`vim README.MD`

`git add README.MD`

`git commit -m "Fix Typo"`

`git checkout master` (switch to branch with name 'master')

`git merge --squash issue_XXX` (merge branch with name 'issue_XXX' into current branch (master), but stop before committing)

`git commit -m "Add Readme.MD"` (create a new commit)

`git push` (upload changes)


yeah, I do this too.

psa: `git reflog show stash` shows the stash list along w/ with their shorthashes for easy reference


> If you screw up a rebase, the old commits are still there with the same hash they always had.

Disclaimer, if you're compelled for none other than neurotic reasons to run `git gc` periodically like me, these old commits will get thrown out. I found this out the hard way :(


Yeah, don't do that


> I don't think it's as appreciated that git's complexity generally discourages people from trying things out.

The irony here is that the model that git internals use aren't really complex at all; it's the poor porcelain and poor naming that makes it seem complicated.


> In a decade of using Mercurial, I've managed to get a repository in such a confused state that I had to blow it up and start from scratch just once. In the same time, I've had to do the same for git repositories at least 5 or 6 times--and I never really used git all that much.

I have used git for a long time, but never arrived at such a state, apart from when I was converting existing SVN repo to git (where starting the process anew after 10 minutes of experimenting was faster than restoring refs). How did you manage to do it?


How did you manage to do it

Same way everyone else manages it, including myself: abject ignorance. You and I (as a now more experienced git user) know that it is extremely unlikely to actually be in a state where blowing away the repository is necessary. Like you, I can’t think of how one would pull that off. That’s why I tell less experienced users “if you’ve committed, even just locally, you can’t lose your work without really trying. If you get in trouble, don’t use the ‘-f’ switch, and come get me, we’ll get it sorted out.

But that was not me nine years ago as I blew away the repository again because I got in a confused state (me, not git). And be honest, that was you nine years ago, too, before you wrapped your head around git.


I'd like to think I know git pretty well... I understand the internals, i've written cli tools that utilise all the plumbing commands, I understand the different types of objects merkel trees, and various form of references.

Yet, once when I had a power failure by chance the second I fired the commit trigger... I was pretty hopeless at trying to clear up the mess of objects it exploded everywhere, I couldn't be bothered and just re-cloned the blasted thing, hope it never happens to me again.


I very much doubt that this is a Git issue, but suspect that it is instead a file system/OS/hardware issue. The problem is that operating systems generally offer only very limited guarantees about the atomicity of the bits actually being physically stored on a device (at least guarantees that can be used with reasonable efficiency).

It should not normally be a problem, but a power failure just at the wrong time seems the prime suspect to me; there's nothing in Git's logic that should normally allow for such a problem.

See, for example, the "Failure to sync" section of SQLite's page on "How to Corrupt an SQLite Database".

[1] https://www.sqlite.org/howtocorrupt.html#_failure_to_sync


It is a git issue... File system atomicity is not the issue: Creating a commit is a process of creating a whole collection of blobs and trees and ultimately a commit tree object, this is fundamentally the way git works. There are many external reasons it could fail half way through creating that tree of objects (objects are files) and that has nothing to do with atomicity of those external factors.

This type of incident is not irrecoverable, but it will hella-waste-your-fucking-time (FYI I really like git, but it's far from infallible)... Try it out and you will have a fun time following the trail of dangling objects.

My point is not that git is fundamentally flawed (fundamentally it's extremely resilient and elegant), but merely that "commit" being a porcelain command should provide a simple way to recover from arbitrary failure without having to dive deeply into the internals and plumbing commands (it's another CLI UI failure)... I knew what was wrong but it was such a pain to reconcile that I resorted to re-cloning, imagine what a confusing mess it would appear to a regular user.


Um..a mission critical data store shouldn't be affected by a "power failure at just the wrong time".


Sure, but the same things could happen to (say) a relational database under the same circumstances. There's nothing that you can do if (say) the hardware lies to you about having written bits to disk or reorders writes. I was citing the SQLite page for a reason. You can only work with the tools that the OS gives you.


Git is not a mission critical data store. Corruption should cause a bad day, not a disaster.


> In a decade of using Mercurial

> I never really used git all that much

Does not sound like a fair comparison ;)


It's a valid comparison for his point that Mercurial is much more reliable for his workflows than git.


I have used git a lot, and rarely, if ever, get it into a confused state. I have used Mercurial less, and I have found it easy to get things tangled up without a clear way out.

It kinda sounds like the system you know best, is the one you can handle better regardless of whether it's git or Mercurial.


> It's a valid comparison for his point that Mercurial is much more reliable for his workflows than git

To me it reads as a warning that Mercurial repos are prone to being screwed up even if the user has over a decade of experience avoiding Mercurial's traps while with Git only bold inexperienced users can screw up repos in a similar matter.


A decade's worth of experience vs beginner-level experience could explain the issue. Not saying it does, just that it could.


In response to [2], these days MQ is deprecated and there's a big push to get people to use evolve, which avoids this mess and is much safer.


Just keep a copy of the `.git` dir before you try the complex operation. If you screw it up, restore it back and voila!


No. This does not safeguard any uncommitted files.


Leaving any files uncommitted before a complex operation in git is a really bad idea (make a temporary commit if necessary). It's almost impossible to completely lose committed data, but pretty easy to destroy uncommitted data.


This. I also do a `git diff > save.patch` if there is something uncommmited that i don't want to commit at the moment. A patch file feels more comfortable to me than git stash, as i can easily view the patch files, and reapply them with `patch -p1 < save.patch`


You can show the diff with `git stash show` or also apply your patch with `git apply save.patch`


No. Commit your changes and mark it. For instance by creating a branch.

git commit -a git checkout -b before-complex-operation ...

To get back to where you were, git checkout before-complex-operation


wow.

> I'm incredibly hesitant to try any sort of complex git operation because of the risk that I might lose my in-progress commits.

correct way of learning git is every time you want to use a "complex"/dangerous commands in git, you `cd /tmp` and create a git repository there. then create some commits, branches and experiment. you will NOT lose anything, but you will learn a lot.

I did and do this every time I have doubts. and with time you will understand how non-dangerous git commands are.

"dangerous" part comes from the user, not the software, and it is okay. when you accidentally kick a corner of a furniture, that does not make that furniture "dangerous".


If this is the "correct" way to learn, the problems are not with the user.

A well designed ui should be learnable while being used - creating a fresh learning repo for dedicated learning for fear of losing data while using the tool in your "real" repo is the ultimate red flag in terms of usability.


> A well designed ui should be learnable while being used

Strongly disagree with that one. A UI that lets you work in the most efficient way (e.g. vi) can also be well designed, even if it's incredibly difficult to learn.

> creating a fresh learning repo for dedicated learning for fear of losing data while using the tool in your "real" repo is the ultimate red flag in terms of usability.

Again, strongly disagree. Git is a powertool. You don't let loose a powertool if you don't understand how it works. Creating a fresh learning repo is merely acknowledging that you don't know the tool well enough yet. There's nothing wrong with that.

There's a big difference between being noob-friendly and being user-friendly. Personally, I hate noob-friendly tools, because they tend to just get in the way.


> Strongly disagree with that one. A UI that lets you work in the most efficient way (e.g. vi) can also be well designed, even if it's incredibly difficult to learn.

See, I don't think you do disagree. I said a UI should be learnable while being used - vi is. I said nothing about it that learning needing to happen quickly.

I use vim every day; it's not my primary editor, but I'm incredibly comfortable with it, which I wasn't for years after I started using it. But during those years of learning, I never got stuck with an unusable dev environment, I never lost data, I never had to Google how to proceed in order to get my work done. If I ran into a problem, I had the option of opening an alternative editor and continuing with my nice non-corrupted dev env, or I could choose to spend some time figuring out the vim way (and learn something).

vi/vim have no foot guns.

Perhaps this comparison is slightly unfair to git - vi is much simpler insofar as a modal interface is a simpler concept to grok than directed acyclic graphs. So they're not directly comparable, since vi's main barrier to learning is memorising commands and git's is conceptual. However - as has been mentioned elsehwere - hg makes a fine candidate in that regard.


> If this is the "correct" way to learn, the problems are not with the user.

OP's advice was essentially to first learn how to use a tool in a sandbox before screwing up mission-critical services. I really don't understand why you perceived the need to learn how to use a tool in a sandbox as problem that lies somewhere else other than the clueless newbie who's taking his first steps.

Letting toddlers learn how to ride a bike by installing training wheels doesn't mean that bicycles are flawed or poorly designed.


a still, while people cry about UI (which is irrelevant part), other people just take time and learn git. by whatever measures.

PS. throwing out things you test on. isn't that how every programming tutorial works? write code NOT in your main repository, test things out, throw it away (or keep it, whatever)?


> UI (which is irrelevant part)

UI usability is irrelevant... ?!??

> isn't that how every programming tutorial works

Firstly, learning programming and learning to use a tool that is a component of your workflow are two independent things. The latter should generally (ideally) have a much lower (aiming towards zero) learning curve. Yes, this is possible, with good UI design.

Secondly, even programming language designers strive towards lowering this learning curve. There is, imo, a necessary complexity, or "table stakes" for any reasonably useful language, but its still very evident to any language designer that this is a trade-off. Usability is desirable.

For a tool as popular and essential as Git, usability should be a much more central goal than it seems to have been in the past.


Is writing programs and building them a part of your workflow? Do you even spend time on setting up your build? On acquiring an actual understanding of how it works?

Other tools are no different. If it's an important tool, it pays to actually study it. Do not expect tools to do what you mean before you know well what you mean.


I think you're misinterpreting my post. I completely agree, you're absolutely right, but there's a huge different between what you're saying and what the gp was: that usability should not be a consideration for these tools.

I do understand, in quite a bit of depth (which I'm sure is still far from complete), how Git works. I still prefer to use Mercurial because it doesn't require me to be continuously aware of the dangers of those internals on a day-to-day basis - it doesn't supply me with a loaded foot gun. Sadly, I use Git every day, and rarely Mercurial, because that's what the masses have chosen and I've found using in-between compat tools not to be worth the extra hassle for me.


OK, I can agree: git is not as safe, mistake-proof, or consistent as it could be.

What I like about git is that it gives a simple algebra of patches (diffs), and allows almost any sensible operation over them.

It would be great to build a different CLI on top of the same data structures (and maybe the same plumbing) that would expose a more consistent and usable interface, while allowing for [most of] the same capabilities, and preserving interoperability. I suppose git-hg tries to achieve something similar, too.

For me, much of the pain of git CLI was alleviated first by a set of aliases, and then by using magit from within emacs.


With a programming language, if you open a new file A in the same repo and try out some stuff, and it doesn't turn out well, you can just delete the file and be reasonably sure that it doesn't fuck up files B, C and D in the same directory.


No but if occasionally the furniture kicks you, then it could be improved on, pointing out flaws in the best of the best is very worthwhile, it's in that pain space that the biggest usability gains are to be had.


> when you accidentally kick a corner of a furniture, that does not make that furniture "dangerous".

When the piece of furniture has a serrated corner that cuts deep into your toe, you'll probably reevaluate the appropriateness of your metaphor.


oh, so if you are careless, that's furniture's fault. okay. your comment is not the best counter to my point either.

PS: i have a lot of furniture with rought edges. I've learned my lesson, and furniture is not a problem anymore.


> correct way of learning git is every time you want to use a "complex"/dangerous commands in git, you `cd /tmp` and create a git repository there. then create some commits, branches and experiment. you will NOT lose anything, but you will learn a lot.

What if your repo with full history is about 30gb?


Why are you learning how to use hit by testing commands on a 30gb repo?




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

Search: