confusing git terminology https://jvns.ca/blog/2023/11/01/confusing-git-terminology/
89 comments
@b0rk I manage to remember the order of commits vs files because sometimes you have to put the files after -- to indicate you're done with options and things that aren't files, so I tend to always include -- when doing branch and file stuff to help me remember the files must always go at the end. (I feel like I've used other commands that did this thing with -- as well.) @b0rk the dots thing is worse than what you described: it's inconsistent between log and diff https://matthew-brett.github.io/pydagogue/pain_in_dots.html @b0rk A "head" isn't a branch; it's the tip of the branch. Branches are like Hydras, with a head at the end of every branch. HEAD is like a cursor in database operations or in an editor, or your current directory. It's where you are and your operations take effect. Usually it's the commit at the head of the current branch, but if you move it to a non-tip commit, it's no longer at a head - HEAD has detached from the head of the branch. @peternerlich @jannem thanks but I know all of this, I chose to explain it a different way intentionally @b0rk oh yes. Most confusing to me is the "ours" and "theirs" terminology when resolving merge conflicts. @lea @b0rk The trick with "ours" and "theirs" is to remember that git was written by Linus, whose workflow involves rebasing other people's patches onto his `main` branch. So, despite the fact that you had some feature branch checked out when you started, "ours" is main (because you're Linus) and "theirs" is the feature branch (written by the person about to get cussed out on the LKML). @b0rk Nice work! For a tool that I used almost every day, it's odd how much I have to search for answers on how to use git... @stormsweeper that's the right way to do it. Pre-emptive forking is only a thing because GitHub want to exploit the same network effect that social media companies were milking, so they decided to force every prospective contributor not just to create a superfluous fork, but insist that it be hosted on GitHub, too, and use their proprietary PR system. @stormsweeper in a more perfect world, you'd clone the original, make your changes, and just submit that (a patch). But GitHub refuses. Can't grow the garden that way. @arclight @b0rk You're probably not looking for answers here, but you kind of *did* give a single sentence description of rebase 😂 it's exactly what you said about reapplying the changes you want, except without making a new clean repo, and it's using the original commits. Of course there's all kinds of bells and whistles and finger traps, but that's the gist. @arclight @b0rk Rebase recreates all the commits in a branch as though the branch had been created from the commit to which it is being rebased. (While leaving the originals in existence!) Last night, I rebased to pick up a couple sprints worth of changes from other people because my particular task took way too long for Reasons. No manual conflict resolution seems like a win. Whole thing took seconds, and doesn't assume I know where the critical stuff is in other people's work. @graydon @b0rk And that's a big challenge for my projects; I don't have the same problems as the Linux kernel developers have so the tool really isn't suitable for my use. It's incredibly difficult to identify and isolate the relevant parts of git. You're faced with full complexity at the outset whether you need it or not. Fine for kernel devs, a nightmare for everyone else. Project scale should also be a warning sign https://www.amazon.com/Limits-Software-People-Projects-Perspectives/dp/0201433230 @arclight @b0rk Don't agree with the "nightmare for everyone else", not anymore than the shell is a nightmare. Some instruction is required. It's one of those cases where the more you know going in the more instruction is required, even; git is rough on autodidacts who want to be able to infer function. I had a lot less trouble when I started using the git-scm documentation and any workplace ought to have a "this is how we use git" explainer in wide currency. @arclight Something that is free and sufficient tends to win, and git's selling point is that your source control problem is not as challenging as the problems it was created to solve. The terminology mostly comes in because it isn't doing commit, branch, and merge, it's using a distinct abstraction, and the words for the abstraction weren't there so people just grabbed whatever didn't run away quickly enough. I agree that the result is horrid confusing. (git-scm docs make a heroic effort.) @b0rk Currently reading… It seems to me like "fast forward" would be easier to understand if not "duplicating" de commits between the branches (main and origin/main). ``` @b0rk I should have thought of this *before* you published (sorry) but the .. vs ... section reminds me of one: log and diff kind of disagree on which is which. "git log foo..bar" shows changes on bar that aren't on foo, whereas "git log foo...bar" shows changes on _both_ sides. But "git diff foo..bar" asks for a diff that shows foo stuff *and* bar stuff (one being removed, one added), whereas "git diff foo...bar" diffs against the merge-base, showing only the changes on the bar side. @b0rk I was thinking, "this could be turned into a zine ppl pay money for..." and oh hey, https://store.wizardzines.com/products/oh-shit-git . Maybe Volume 2? Great work on this post and thanks for listening to the crowd & doing that research. @b0rk my understanding of "git pickaxe" is it's the same as "git's meat cleavers" in Travis Swicegood's old talk from more than a decade ago. In other words, various flavors of interactive rebase (`git rebase -i`) @b0rk my mistake, he also covers bisect, normal rebase, and amending commits https://speakerdeck.com/tswicegood/gits-meat-cleavers ... and a quick google search shows I'm completely wrong 🤦🏻♂️ Apologies. It's a way to search the commit log for when a specific term was added/removed/modified http://www.philandstuff.com/2014/02/09/git-pickaxe.html @brianfenton oh it's `git log -S`? I love that flag, no idea it was called a pickaxe (???) @b0rk apparently? no idea how that came to be, but I think it's one of those plumbing (non-porcelain) that escaped into the wild https://git-scm.com/docs/gitdiffcore#_diffcore_pickaxe_for_detecting_additiondeletion_of_specified_string Git can't be explained because it is an incredibly badly designed program that routinely fails in real world use. I've been a programmer for 4 decades and I hate projects that make me use that horrible pile of junk @b0rk This is great! I finally internalized the two uses of `git checkout` when I realized the `--` before the file list ("pathspec") was optional but more clear. That is, `git checkout main -- file1 file2` is checking out main, but only for those two files. I will probably never remember `switch` and `restore` at this point. - the **dots thing** working for diff is, I think, to be able to copy and paste line from `git fetch` output to git - **refspec** for fetch tells Git how to map references in remote repository (usually branches or branch, like refs/heads/main) into references in your repository (usually remote-tracking branches or branch, like refs/remotes/origin/main); compare how they look like when you clone the repository vs when you clone repository in the _mirror mode_. @jnareb yeah i understand what the refspec does in theory but what I don't understand is -- does ANYONE understand the syntax for the refspec and change it from the default? why? is it worth my time to try to understand more deeply than "yea it's some nonsense just ignore it”? @b0rk I use it to push **all** my local feature branches to remote with `git push origin :` - here `:` is a special kind of refspec Before `git push` got `--delete` option it could be used to delete branch in remote repository with `git push origin :branch-to-delete` (push empty into branch). If GitHub/GitLab/... is configured so that 'main' branch is protected and you cannot push there, you can use `git push origin main:other-name` and then create pull request/merge request. Not usual cases. @b0rk Also, I think if you want to share git-notes (for example to add information to existing commits, such as that it was the cause of the bug, and was fixed later), or git-replace (which can be used to connect current history with historical repo converted from some other SCM), you need to hand-craft refspec - as they both use references which are not branches. https://git-scm.com/docs/git-notes @b0rk “remote-tracking branch” vs “branch that tracks a remote”: one tracks branches in remote repository, one tracks the remote-tracking branch ;-) @b0rk great post, thanks! one note: i'd be careful around saying that "`git reset --hard` and `git restore .` do basically the same thing": it's true if you read this literally, but the second you add an argument to `git reset --hard`, that goes out the window and you're moving the branch pointer! very dangerous, as you can lose commits! @b0rk very nice! I don't use git a lot, but while reading your explanations, a question popped up that might be good to answer if it fits: In a merge commit, is the first parent ours or theirs? I just read the explanation of "ours", then HEAD^2 was introduced, that seems pike it should be expressible in these terms? @b0rk If it helps any, Git calls things like `HEAD^^^` "revisions": https://git-scm.com/docs/revisions It's a little weird though, because it's usually a "revision argument" or "revision parameter", and they can name Git objects that aren't commits (like blobs, trees, or tags). i'm always a bit frustrated when people look at all this confusing terminology and respond "oh yeah but all you need to understand is that everything in git is a reference". Like -- sure! That's a useful thing to understand! But there are a bunch of different kinds of references (branches, tags, remotes, the stash) and git's commands affect them in different ways. You actually do need to understand how they all work and git’s terminology doesn't do a lot to help you do that. @b0rk "all you need to understand is everything is a reference" My reply would be "so all I need to do is read all the source code to understand how to use this ?" Alas far too common in the foss world these days :( @b0rk "You have to understand everything is a reference" as if references haven't been biting C programmers in the face for nigh forty years. @b0rk right, tags for example act very differently to other kinds of git references, and they have special metadata you can attach to them. @b0rk Yes! And that there are always at least 3 copies of all references in play at once (yours, the remote's, and your most recently-made copy of the remote's). The mental model is quite a lot to internalize, as powerful as the resulting tool may be. @graydon @b0rk As someone who honestly has stopped contributing anything that can’t be done via GH web interface in part because I find git monumentally confusing, I wonder if jj (which looked very promising to me, a no-longer-active-dev) actually does what it promises to remedy some of these mental model challenges? Or is it off on the wrong track? @luis_in_brief @graydon i haven't figured out how to get jj to compile yet but I want to try it out! definitely curious about it @b0rk The thing that gets me about git terminology isn't any one specific term (though I have problems with plenty), it's the lack of a consistent metaphor. Are we operating on tree that have trunks and branches and pick cherries? Are we on a river where we go upstream and downstream? Are we adventurers that need to reset our basecamp and merge with other groups? All of the above!? @b0rk everything seems easy when you know how it works. I’ve used got for a loooong time and I’m not ashamed of admitting I don’t really know what I’m doing. @b0rk Understanding everything is a reference does not explain the at least 4 different metaphors going on in their UX! @b0rk Upstream/downstream, head, branch, fast-forward, checkout, base...Ok, at least 6. @b0rk in a way, a head is a tag floating at a top of a branch while an actual tag have sunk in the ground (truth?). The stash are also tag to free/lost bit of code but to me, stash being long lived feel more like an implementation mistake or a quick fix to a practical problem than a real feature @b0rk 100% Also the way the CLI refers to references can be confusing as heck. I didn’t reply because I saw someone else already mentioned it, but ^ and ~ always trip me up. Like I know ^2 is something about the second parent branch, but I can never remember which way round the branches are. @b0rk hey thanks so much for posting this, and I'm going to assume you are OK with sharing it :-) This is a fantastic resource for developers like me that have years of deep git experience and a solid mental model - and struggle with explaining git new newer developers, or developers that are just now moving from svn or that have never used git. It is so awesome to have a clearly written explanation for the most confusing parts of git - will be my go to resource! @b0rk Great idea! Personally, I found this ebook very helpful to understand the concepts from git: https://jwiegley.github.io/git-from-the-bottom-up/ @b0rk Oh and before I forget, some #git #humor https://www.tartley.com/posts/a-guide-to-git-using-spatial-analogies/ @b0rk Another great article, thanks for writing and sharing. With checkout the '--' can be used between a branch and a file on that branch and it will copy that file from that branch to the current one. Kind of like cherry-picking files rather than whole commits. git checkout -b new_feature # Create and checkout a new branch @b0rk This is very helpful for git newcomers. The one that always terrifies me is getting "yours/theirs" wrong. |
@b0rk oh this is great!
Some of the confusion I think comes from git adding less confusing subcommands but not removing the old ones. So like, "git switch" can switch which branch you're on, a simpler checkout, but checkout still exists. I am guessing "git restore" is similar, because that didn't exist in the past I think, and the things you mention for it, I have done painfully with "git reset".
So now there is two ways to do things, an easier one, and one more people know...