1. 17

    I agree with the author, git concepts are non-orthogonal and subtle. When I think of quality UI software, I don’t think of git.

    That being said, I would not get rid of the index. The index is the primary reason I use git. I think git add -p is an invaluable tool. If you don’t use it, you’re missing out.

    1. 13

      I agree that git is awful to learn, but removing staging seems unnecessary. Even worse, they use funky flags where git uses commands, and they did away with push/pull in favor of publish/???.

      I’m not impressed. I’ll stick with git and will continue to teach people how to use git instead of some seemingly better shell.

      1. 3

        Yeah, it didn’t really feel to me like they changed much fundamentally. They just added some superficial aliases so you don’t have to run as many commands. I’ll write my own aliases when I need them.

      2. 8

        I’m perfectly happy using mercurial, which doesn’t have a staging area. Whenever I use git, I get annoyed because it has this extra useless concept. Mercurial has “hg commit -i”, which is analogous to “git add -p”, to commit only a subset of the changes to the working directory.

        1. 5

          I’ve always found a lot of utility in being able to stage certain things at once. Sometimes I make large changes without thinking about actual commits until I get to the end of a workstream, and having that all as one commit just seems generally not great, especially when there are atomic components that were tangentially related to the main work at best (like cleaning up a configuration file, or refactoring a particularly hairy section of code).

          Mainly breaking things up like that seems like the courteous thing to do for your fellow developers, because that way if you’re ripping out a large component and want to do it quickly with reverts, you don’t pull out the secondary changes by accident too. And you can also generally write better, more relevant commit messages too.

          1. 5

            You can do that workflow in mercurial as well using “hg histedit” and “hg commit –amend”.

            Having a staging area isn’t related to the workflow and just adds another concept to learn when learning or teaching the tool.

            1. 7

              You can also do git commit --amend if you want to amend a commit, however you don’t have a tool for implementing a commit queue in hg.

              If I have four things I’ve touched and I want to commit them separately, I want to verify that each of these things are in fact separate commits. I do not want to commit four things, and then try to uncommit them, and re-commit them once I’ve figured out what they should look like.

              In git, I can add -p the first one, then stash the rest, run my program and verify it works as I expect, then commit just that staged bit (or change it some more). Then I can pop the stash and move on to the next commit.

              This concept is useful to me. I can emulate it by creating four separate branches, or by copying my files around, but I find it actually useful to think in terms of the git concept of a stage so that this kind of committing is obvious to me. Tools that generate new intuition to the programmer are like candy to me.

              1. 2

                Given that I very much use hg with a commit queue, I can’t really agree, though I haven’t tried it much with the base command set (I use evolve).

                Still, the way I do something like that is to make my commits, then update to the first commit and test, then update to the next commit (by hash or using the children(.) revset) and test, etc. Then I can land any or all of them with one push. None of that requires evolve, btw, but in practice I will usually find that I’ve mixed up the changes a bit and have to move pieces between them, and that’s much easier to do with evolve and ©histedit.

                You’re using the stage+stash as your queue / working area. I’m using the actual dag. When doing so, it’s easy to get mixed up with what is “current work” vs stuff I’m basing the current work on, but hg has phases, which make it easy to distinguish work in progress vs base. (I uses aliases for it, but hg log -r 'not public() and only(.)' gives you a basic patch queue listing.)

                1. 1

                  In git, I can add -p the first one, then stash the rest, run my program and verify it works as I expect, then commit just that staged bit (or change it some more). Then I can pop the stash and move on to the next commit.

                  I find this the most confusing part of git, fwiw. I can never remember whether stash is going to stash changes that have been added or just changes that have not. Worse, stashing and unstashing seems to change which things have been added, which breaks my mental model of what stash is supposed to do.

                  1. 4

                    which breaks my mental model of what stash is supposed to do.

                    This is a variation on the “X isn’t intuitive”, and it doesn’t really offer any option to me in having a discussion about it.

                    Can I agree that the user-interface is bad without also agreeing that we need to hide/get-rid-of the index?

                    I can never remember whether stash is going to stash changes that have been added or just changes that have not. Worse, stashing and unstashing seems to change which things have been added

                    Read the manual page carefully. The first sentence begins: Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory and that’s exactly what it does, but you need to understand what the index is.

                    The thing that I’m referring to is mentioned: If the --keep-index option is used, all changes already added to the index are left intact and that -p implies this.

                    1. 1

                      This is a variation on the “X isn’t intuitive”, and it doesn’t really offer any option to me in having a discussion about it.

                      Ok, I’ll be specific. The man page says: “Remove a single stashed state from the stash list and apply it on top of the current working tree state, i.e., do the inverse operation of git stash save. The working directory must match the index.”

                      $ git status
                      # On branch master
                      # Changes to be committed:
                      #   (use "git reset HEAD <file>..." to unstage)
                      #
                      #       modified:   foo
                      #
                      # Changes not staged for commit:
                      #   (use "git add <file>..." to update what will be committed)
                      #   (use "git checkout -- <file>..." to discard changes in working directory)
                      #
                      #       modified:   bar
                      #
                      $ git stash
                      Saved working directory and index state WIP on master: b12ed82 test
                      HEAD is now at b12ed82 test
                      $ git stash apply
                      # On branch master
                      # Changes not staged for commit:
                      #   (use "git add <file>..." to update what will be committed)
                      #   (use "git checkout -- <file>..." to discard changes in working directory)
                      #
                      #       modified:   bar
                      #       modified:   foo
                      #
                      no changes added to commit (use "git add" and/or "git commit -a")
                      

                      This is not what the word “inverse” conventionally means; it is extremely confusing to have an operation described as an “inverse” that doesn’t actually invert the thing it is supposedly the inverse of.

                      Can I agree that the user-interface is bad without also agreeing that we need to hide/get-rid-of the index?

                      I don’t think so, unless you have a better proposal for how to improve it.

                      1. 3

                        it is extremely confusing to have an operation described as an “inverse” that doesn’t actually invert the thing it is supposedly the inverse of.

                        I don’t see why that means I have to agree that the index is bad.

                        Can I agree that the user-interface is bad without also agreeing that we need to hide/get-rid-of the index?

                        I don’t think so, unless you have a better proposal for how to improve it.

                        “People understand things I don’t, so we need to get rid of them”.

                        I find that attitude really off-putting.

                        1. 1

                          I don’t see why that means I have to agree that the index is bad.

                          Well, the part that it doesn’t invert is the index. As far as I can see the index causes this problem and removing it would solve the problem.

                          “People understand things I don’t, so we need to get rid of them”.

                          That’s not what I’m saying (and I’ll thank you not to put words in my mouth). To agree the user-interface is bad, you must believe a better user-interface is possible (otherwise the idea of “bad” is meaningless). To believe that a better user-interface is possible you must believe that a specific possible alternative user-interface is better. If you don’t believe gitless is better, which possible alternative user-interface do you believe is better?

                          1. 1

                            This is where git stash –keep-index comes in handy. Stash then only would apply to changes to bar.

                            1. 1

                              Sure, and apparently there’s also a flag to the load to restore changes to the index. But neither of these is the default; fundamentally, stash is clearly confused about whether it’s operating on the index or the working copy or both. If even git’s own commands can’t get staged vs unstaged straight, what hope do us poor users have?

                              1. 1

                                I won’t argue that git is the most intuitive tool by any means, but it does have the ability to address the needs at the least.

                                That said, the git log man page to this day, after 9 years of use still contains things I don’t understand after having read through it numerous times.

                  2. 1

                    Both the mq and the shelve extension implement commit queues for hg and they come with hg’s default installation. Commit queues are a power user so it’s fine if this isn’t front and center for a new user yet but they are definitely there.

              2. 4

                Tools give us power and allow us to be individually more efficient, but they require we learn new skills which can take time and make us struggle which is not something many intermediate programmers are used to.

                To paraphrase:

                I’m perfectly happy using basic which doesn’t have lambdas or macros. Whenever I use lisp, I get annoyed because it has this extra useless concept. Basic has goto and gosub which is analogous to the use of lambadas and functions that I want to use.

                The real issues are whether, having this tool of thought you are more efficient (I am; others say they are) enough to make it worth learning (Others are more convinced than me on this point) or worth fighting inertia (i.e. Git is popular, so it is useful to think in git so that I’m better able to work in git).

                As a specific example, I never want to hg commit -i in git – I’ve checked my history and I’ve never typed git commit -p (which works the same way), and I noticed whenever I use git add -p it’s followed by a git stash so I’m pretty certain my goal is to make sure that my single staged commit works in isolation (i.e. if someone just cherry picks this commit, will it work?) This is important because we don’t really have patches in git (which actually solve this problem).

                1. 5

                  I wonder how we can better talk about this conflict. Is the investment of learning worth the trouble in later efficiency? We talk about usability often without putting it into context. Git is worth learning for a developer, because you use it everyday. The banking website that you use once a month should be much more aligned with the concepts that you can be expected to know, even if that makes you ineffective.

                  1. 1

                    This is something I often wonder about.

                    Too many people respond to things they do not understand with an opinion about them: How much they don’t like them. When I see someone do something I cannot do, I want to learn how they do it; If someone can program faster, and their programs are shorter or more correct than mine, I want to know how.

                    If they say “I use the git index”, then I know I need to learn it. Whatever opinion I might have had goes right out the window at that point.

                  2. 2

                    The need is not to have a stage or stash or whatever. As the paper says, there are highlevel goals that developers want to accomplish. The stage and stash are tools that can be used to accomplish those goals, but there are a number of other ways. And you can design systems with more or fewer separate concepts. I prefer systems with fewer concepts that can be used in flexible ways. For that reason, I prefer using the straight dag as much as possible, and figuring out the minimum necessary extensions needed to make the dag handle my goals. The stage feels like a big separate concept to me – not wrong, really, but big and different and I’d rather eliminate it if possible. Similarly, the stash feels like it explodes out the set of possible states unnecessarily. You need some extra states, but I’d rather express them in terms of dag nodes than some completely different thing.

                    Honestly, I’d like to think of my working directory state as just another node in the dag, one whose hash and exact contents are only determined when necessary. I should be able to use it the same way as any other node in the graph. True, if you go whole hog on immutability, then you need to record a hash for every single keystroke that modifies a file, but I like to think of not having those nodes as an optimization on top of the conceptual dag containing them. And it turns out that you kind of want the same optimization for other nodes – for example, if you rebase a patch stack on top of upstream changes a dozen different times, then all those intermediate nodes (almost length of patch stack x number of rebases of them) are similarly uninteresting, and I would happily discard them even if it means edges in the dag sometimes represent more than one intermediate (garbage collected) node.

                    1. 1

                      The need is not to have a stage or stash or whatever.

                      I certainly don’t have this need, to “not have a stage or stash or whatever” and so I reject the theory that this need exists.

                      there are highlevel goals that developers want to accomplish

                      I think this kind of thinking leads to mistakes.

                      I don’t want to accomplish any of them: I want to show my code to someone, or I want my feature to be on the production system. Everything else is a means to that end, and so I look at how I can do the things that I want. Tools enable that.

                      I prefer systems with fewer concepts that can be used in flexible ways.

                      If we say we should prefer hg because it is simpler than git, we are making a mistake. neither “git” nor “hg” are a calculus for version control, but both a set of very messy methods. If you want something mathematically satisfying – the scheme of version control, you should look at patch theory because it may fill that need.

                      However I have things to do now, and that means I’m looking at the common lisps of the world, not the schemes: I want a robust vocabulary, so I can say what I mean, and get what I want; succinct enough to avoid errors, but I do not want to do version control in brainfuck either.

                      Both git and hg are robust, but git is more robust. That’s important to me. Can you tell a computer what to do without an index? Sure, but there was a time when programmers used punch cards and paper tape. I certainly don’t want to return to that.

                      I’d like to think of my working directory state as just another node in the dag,

                      I’m not interested in this at all.

                      1. 1

                        I am not making most of the arguments you are disagreeing with. In fact, we are saying the same thing in your first two quotes. But never mind that.

                        While to me, hg feels conceptually simpler yet equally powerful to git, that was not my point. (Nor did I say it – where did I mention hg?)

                        I am saying that a small number of concepts, flexibly applied, results in a better tool than one built from a larger set of nonorthogonal concepts that cover the same space (ie, the space of tasks you actually need to accomplish.)

                        It is also the case that once you use a tool successfully for long enough, it gets harder to distinguish what you’re doing from how you’re doing it, and alternative ways of accomplishing the same thing appear to be pointless and overcomplicated, because you are evaluating them according to how well they mimic your current tools rather than how well they accomplish the task at hand. Perhaps you are doing that here. Perhaps I am too unfamiliar with the git toolkit to see some large advantages it has.

                        1. 1

                          hg feels conceptually simpler yet equally powerful to git, that was not my point. (Nor did I say it – where did I mention hg?)

                          Given that I very much use hg with a commit queue, I can’t really agree, though I haven’t tried it much with the base command set (I use evolve [a disabled-by-default extension that emulates something that has been in git since the beginning]).

                          I am saying that a small number of concepts, flexibly applied, results in a better tool than one built from a larger set of nonorthogonal concepts that cover the same space (ie, the space of tasks you actually need to accomplish.)

                          I’m not going to disagree with that theory, but it’s clearly not sufficient:

                          Git has a smaller number of concepts than hg: You can tell because things that are evocations of the alien things like the index require extensions in hg to be implemented.

                          Patch theory represents what might be the smallest possible number of concepts. It is worth some study and makes hg feel quite pointless because where patch theory also highlights something fundamentally wrong with git, hg has the exact same thing wrong.

                          It is also the case that once you use a tool successfully for long enough, it gets harder to distinguish what you’re doing from how you’re doing it, and alternative ways of accomplishing the same thing appear to be pointless and overcomplicated, because you are evaluating them according to how well they mimic your current tools rather than how well they accomplish the task at hand.

                          I think this is a silly way to think about things, but history is littered with people who cannot tell the difference between their opinions and reality.

                  3. 3

                    I often stage changes at a time, make some more changes, stage those, etc., before finally having something I want to commit. (i.e. I don’t immediately follow git add -p with git commit) Sometimes this process itself is enough to make me change the direction of what I’m doing or decide I don’t want to make a commit at all.

                    1. 3

                      I use “hg commit –amend” for that. If I end up deciding not to commit anything at all, “he strip” will delete the WIP commit.

                      The evolve extension also provides “hg uncommit”, to remove files from a commit.

                      1. 1

                        Sounds like we both have something that works for us then!

                  4. 4

                    git gui is my prefered way to use git. Gitg/gitk/cola are also invaluable. Github client was good originally, but thry simplified whioe also some how maing it harder for me to use.

                    1. 2

                      I think git add -p is an invaluable tool.

                      And it gets even better with Magit, if you’re an Emacs user