Look: http://imgur.com/xY8dKWD no verbosity here and this is 99% of my git workflow. Working in a team is more tricky, but you should use and IDE with built in git support.
If you want to see a bad command line tool, try FFMPEG.
Look: http://imgur.com/xY8dKWD no verbosity here and this is 99% of my git workflow. Working in a team is more tricky, but you should use and IDE with built in git support.
If you want to see a bad command line tool, try FFMPEG.
As a professional trainer, here are the most commong problems:
- git checkout does so many different things. Git check file, git checkout branch, git checkout commit all do different stuff, and don't get me started on the option flags.
- git is context dependant. If you don't know the context, espcially the state your repo is in, you will struggle. And nothing in the tool gives you enough context if you don't explicitly ask for it, which supposes you need to know you need it, and what "it" is.
- branch switching is a hard. see article.
- stashing is dangerous. I've seen many students loosing work with a stash pop requiring a merge which ended badly.
- the whole syntax is impossible to discover, even for very common tasks: git checkout HEAD^ /file/path, git rm --cached, etc.
- git assumes you know what you are doing. Which means it let you destroy history with rebase, loose stuff with stash pop, create detached head, make force push, and all it all put yourself in many situations a beginer won't understand, and above all won't need.
Now I don't blame git designers for those. They made the tool they wanted to use.
What we need is a good UI on top of that. It can solve 99% of those problems.
The github one is not so bad compared to all the ones I tried (yes I tried yours), but it's still not it. What you need is someone that look at the most done tasks and questions, and provide safe, fast buttons for that.
The index is by far one of the best features git has in comparison to other VCS, and trying to hide it because it can be confusing to users is doing them a disservice.
EDIT: editing this to expand on why I think the index is essential:
Being able to use the VCS tool to fashion a commit separately from what is in the worktree allows you to create changesets that make sense, instead of them being "this is what happened". Exact history is not interesting, it is the logical progression of the codebase (via changes applied to it) which really matters.
Furthermore, when resolving conflicts, the index is extremely useful because you can work through a conflict (which often can span multiple files) piece-by-piece and easily tell whether you've already fixed everything, run diffs on what's resolved and what isn't, etc. I find myself missing the index whenever I need to do anything nontrivial with other VCS (which is most often Subversion)
I've seen some people argue that they don't want to commit something that has not been tested, but I don't understand this argument. Why would you test something that isn't committed? Committing (or even pushing) something does not mean the code is instantly in production, but it means you have an unambiguous way to refer to what is being tested, instead of whatever state your worktree and system happened to be in. How could you be sure you're really testing what you will be committing?
Certainly, creating separate commits after-the-fact can cause commits where the tests don't pass, but it's up to you to decide whether the merge points are what should be tested, or each individual changeset.
Let's go through that list
- git checkout does one thing: it updates your worktree to match whatever you want to check out, be that a commit, a branch (which actually is just a named commit) or a file in a branch. Why is this difficult for beginners, and how would you refactor/name the operations so that they make sense?
- I'm not sure what you mean with context-dependency. Obviously it's context-dependent in that your worktree and repository may be in a state where certain commands do different things eg. because they have the current checked out branch as an implicit parameter. I don't think it's at all different from most other VCS
- I'm not sure I'm convinced by the article's argument that branch switching is hard, but I guess I'll grant that.
- Huh. I don't use stash that often, so this is a maybe. Teach people to use stash apply instead?
- git rm --cached is weird, but mostly because git can't choose just one thing to call the index.
- You can never accidentally destroy history with a rebase. Nothing short of manually wiping files destroys history in git once something has been committed. I don't really see why detached heads would be a problem (just create a branch?) and if you force push, you're basically telling git "I know what I'm doing, shut up" in which case the tool doesn't assume you're an idiot and will do what you want. You can't call it bad UI when you explicitly have to use a --force flag to do potentially destructive things. Not being able to do it at all is worse.
Really though, other than minor gripes with terminology and maybe sometimes confusing command line switches, what is a good (hypothetical) UI for git that doesn't just ignore all the good things?
I can't disagree more. The index is entirely unnecessary, as umpty thousands of happy Mercurial users can testify.
> Being able to use the VCS tool to fashion a commit separately from what is in the worktree allows you to
... record states which never existed, and haven't been tested. It's an antipattern. If you are doing this a lot, you are doing development wrong. In the rare occasions where you do want to do it, Gitless and Mercurial, like every other source control tool, give you a way to fine-tune the set of files which go into the commit. They don't need an index to do it.
> Furthermore, when resolving conflicts, the index is extremely useful because you can work through a conflict (which often can span multiple files) piece-by-piece and easily tell whether you've already fixed everything, run diffs on what's resolved and what isn't, etc.
Again, you don't need the index for this, you need to track conflict state. As Mercurial does:
https://www.mercurial-scm.org/wiki/TutorialConflict
> I've seen some people argue that they don't want to commit something that has not been tested, but I don't understand this argument. Why would you test something that isn't committed?
This is a very interesting perspective! It doesn't immediately sound immensely practical, though. Say i want to test a fraction of the current working tree's state; i commit, and then ... what? Create a fresh clone of that state somewhere so that i can run tests on it?
I personally don't feel comfortable with mercurial, but that may be because I don't understand it. It's been a long time since I last touched it, but I remember thinking that the way it does branches was just needlessly complicated and cumbersome. Why does closing a branch even need to be a thing?
> you don't need the index for this, you need to track conflict state
This is what the index does. You don't need the index in mercurial, because you have something that is like the index, but not called the index.
Maybe the UI is better because "add" is called resolve, but that is really just an alias away.
> and then ... what?
Then you push it to remote somewhere and a CI system runs tests for you. Maybe you can do something productive in the meantime.
If you're just testing locally, then there's little difference, but I would still prefer testing a committed state, knowing it's safe in the repository and I can't clobber it afterwards.
I'm curious what you mean by this. What are good & bad habits wrt the index?
It makes sense the index is there for conflict resolution, and it seems really convenient for interactive adds & rebases. But I could imagine implementing those things without having an explicit staging area. Are there other more important requirements for the index? It mostly seems like a convenience that it's exposed, but not something that provides either more safety or better practice.
Many VCSs that predate git don't have an index because they don't need one, and having one wouldn't encourage better habits. Git has an index and rebasing almost entirely as a result of it's strict enforcement of lineage, which older VCSs didn't have. In Perforce you can create and manage multiple changes before you push, and you can push them in any order. Because git enforces order, it basically needs rebase and an index to make using git sane. In that sense, these things can be seen as a UI disadvantage over other VCSs. Of course we know there are much bigger advantages that come with strict lineage, so we learn to stage, rebase, etc.
What other benefits does the index provide that I'm missing?
> git is context dependant
In particular, git violates the universal *nix convention that you can operate on a file using a full or relative path regardless of your current directory.But many people don't use it very deeply most of the time, and only occasionally have need to do something out of the ordinary, at which point it can be a pain to discover the Right Way to do what they need, and easy to shoot themselves in the foot.
Yes!! Stash has a problem that it's attractive to beginners, and its easier than other commands to hose yourself. It's a separate system for managing changes outside of commits, I don't get it. They could have made shortcuts to branch & commit. Mystifying.
> What we need is a good UI on top of that.
Srsly. But, wouldn't having a consistent & clean command line interface enable that? I haven't seen a good git GUI yet, they are all crippled because they stick to git's terminology. None of the UIs have been able to escape the foundation of the git command line, and I'm starting to think it's not possible.
It isn't a separate system "outside of commits". Stashes are literal commits. If you were to write a script that made little WIP commits it would probably end up looking a lot like git-stash (which is literally just a shell script wrapper around other git commands).
`pop` will no longer drop the stash if there is an error applying it; it did in the past.
There is a point where it is worth having at least one person on a team study the internals of Git vs. struggling with it constantly and possibly losing work---it will save time, energy, and work in the long run.
In the stash case, `git reflog` would immediately allow you to recover the lost stash. If you're in deep shit, `git fsck` is valuable until the commits are GC'd. Even if you don't remember the commands, you'll know where to look for them, or what to search for to find it. Or even understand that it's _possible_.
> nothing in the tool gives you enough context if you don't explicitly ask for it, which supposes you need to know you need it, and what "it" is.
There are numerous PS1-augmenting scripts available; git even comes with one. But I agree that it otherwise would be incredibly frustrating for beginners.
> branch switching is a hard
I've heard many criticisms when watching others learn Git and teaching others, but this is one of the only things that never comes up once they've done it a couple times. Stash and switch. Or commit WIP and switch.
> the whole syntax is impossible to discover, even for very common tasks: git checkout HEAD^ /file/path, git rm --cached, etc.
I learned pretty much everything I know about Git from experimentation and, most importantly, the manpages. If someone is unaware of manpages, the documentation is online. Failing to read is failing to discover, yes.
> git assumes you know what you are doing. Which means it let you destroy history with rebase, loose stuff with stash pop, create detached head, make force push, and all it all put yourself in many situations a beginner won't understand, and above all won't need.
Yes, this is fair. But also essential. I have recovered from more fucked situations that I could have imagined, and have helped others do the same---situations where I would have otherwise lost work.
But it's a matter of teaching someone fallbacks. If you accidentally screw up everything with a rebase on <branch>, `git reset --hard origin/<branch>`. If you can't remember that, open tig / gitk / a web interface / etc, find the hash, and reset to it. If you are on a detached head, check out a branch. You shouldn't be force pushing, but that's nothing the manpage can't help with.
It all comes back to the basic understand that nothing is ever deleted in Git until garbage collection. There is always a hash to recover. Sometimes I just lazily scroll up in my terminal and grab it.
But your first point:
> git checkout does so many different things. Git check file, git checkout branch, git checkout commit all do different stuff, and don't get me started on the option flags
Yes, this is unfortunate.
tl;dr: Research your tools! Poke around the manpages or online. Know what you don't know so that you know where to look later. And there is always e.g. gitk to fall back on for certain things---I see others on my team do that as well.
> In the stash case, `git reflog` would immediately allow you to recover the lost stash.
Stashes don't go in the reflog, you cannot recover them with git reflog, so you're automatically in the 'deep shit' category if you lose them. Hence the statement that stashes are dangerous.
You do still have the safety net of fsck, and knowing that it's possible matters, as you point out. But, my experience with people who mess up stashes has been that fsck is so intimidating they'd rather re-create their changes. Silly, but true.
You can see them with `git reflog --all`.
It's called magit.
I've seen this assertion before, I don't understand it. If `stash pop` has conflicts and it gets confusing, you can always just `git reset --hard` and `git stash pop` again. The stash does not disappear if there are conflicts.
The only time you can lose data is if you explicitly `git stash drop`. So don't do that. And even then, the data is sitting in the git repo and can be recovered with `git fsck`. It's really hard to lose data with git.
In my case, I temporarily changed a number of tracked "build" files that are custom my system and that I do not intend to check in for others to use. I was then asked to test a branch that someone else had checked in. My desire was to stash my local changes, check out their branch, and reapply my local changes to build it. But after "git stash pop" failed I had trouble figuring out the state of the system. I couldn't make any sense out of the messages that appeared, and fell back on Googling for answers.
My expectation was that the stash would have been popped, that I would open the build files, find some lines about merge conflicts, that I would manually fix them in an editor, and then I would rebuild. Instead, it does "something else", and hard part was figuring out what that "something else" was. There are probably excellent reasons for the exact behavior, but I'd ask: where is it made clear to the user what happens when "git stash pop" experiences conflicts? Where does it say to do what you suggest?
Separately, if you happen to know, how should I best deal with this personally frequent situation that I have a small "patch set" that I want to be able to apply to arbitrary branches, but that I have no intention of ever making visible to other users? I'm sometimes tempted to fall back on "git diff > patch.local" and manage it manually, but there must be a better way.
I'm curious, how would you redesign git checkout to handle each of those different types of inputs? For me, while it appears cumbersome, understanding that a file is different from a branch and commit head seems to alleviate this problem.
The ffmpeg command line program is basically a demo that exposes every one of those features directly. Having it "do less" would defeat the point.
It's coffeescript vs javascript all over again and we saw how that played out.
Don't like how git works? contribute. Don't make some stupid command line utility that just adds another entire layer of abstraction on top because people don't want to take an hour to read about git internals.
Git is fine the way it is, but it targets power users. Most people don't need that power.
In that sense, gitless has a proper approach even if I don't like the result.
You need a really compelling reason to layer another level of abstraction on top of git and from what I can tell, having branches be full sets of working files isn't really a good enough reason to make that switch.
Where are the improvements in Gitless exactly? Pretty telling they don't even list them in anywhere.