[HN Gopher] Confusing Git Terminology
       ___________________________________________________________________
        
       Confusing Git Terminology
        
       Author : soheilpro
       Score  : 367 points
       Date   : 2023-11-02 13:05 UTC (9 hours ago)
        
 (HTM) web link (jvns.ca)
 (TXT) w3m dump (jvns.ca)
        
       | asicsp wrote:
       | See also: Why Git Is Hard
       | (https://roadrunnertwice.dreamwidth.org/596185.html)
       | 
       | Discussion: https://news.ycombinator.com/item?id=37799082
        
         | happytoexplain wrote:
         | Regarding "Why Git is Hard",
         | 
         | I love Git, but with the huge caveat that it is relative love -
         | relative to the universe of garbage software trying to perform
         | complex tasks. I think it has a few glaring issues (the reset
         | command and the overloaded pages of the official docs come to
         | mind), but I also think 80% of the criticism aimed at the
         | design or CLI of Git is undeserved or misapplied. E.g., here's
         | my quick critique of some of the points under the "alien mental
         | model" part:
         | 
         |  _> A commit is its entire worldline_
         | 
         |  _> Commit content is both a snapshot and a patch_
         | 
         |  _> Branches aren 't quite branches, they're more like little
         | bookmark go-karts_
         | 
         | These are three versions of the same fallacy - technically
         | correct, but only in the same sense that a text file is "both
         | text and ones-and-zeroes", or "not text, but actually ones-and-
         | zeroes". The author is pointing at different abstraction
         | layers, some of which aren't even necessary parts of the user
         | mental model. If you don't yet understand concepts like
         | "abstraction layers" or "implementation details" (e.g. the
         | difference between "a branch is a series of commits" and "a
         | branch is represented by a pointer to a commit, which, by the
         | definition of a tree, resolves deterministically to a series of
         | commits"), then you will have this problem with any software
         | that gives you power to work on a complex problem like version
         | control.
         | 
         |  _> Merge conflicts are actually just difficult_
         | 
         | If your version control system makes merge conflicts easy/rare
         | in the absolute sense, then it is doing dangerous/cute "idiot-
         | proofing" that will bite you at some point.
         | 
         | In summary, I think a good chunk of complaints about Git are
         | actually just complaints about version control (i.e. Git is
         | hard because version control is hard), or unnecessary
         | combinations of different abstraction layers (which, to be
         | fair, most software/documentation hides better from the user,
         | but IMHO that is a bad thing). Git is an amazing piece of
         | software ( _relatively speaking_ ).
        
       | jcranmer wrote:
       | Don't worry, git manpages have a builtin glossary, just type in
       | `git help glossary`, and you can get helpful definitions for
       | confusing terms:
       | 
       | > index
       | 
       | > A collection of files with stat information, whose contents are
       | stored as objects. The index is a stored version of your working
       | tree. Truth be told, it can also contain a second, and even a
       | third version of a working tree, which are used when merging.
       | 
       | Correction: you can get _unhelpful_ definitions of all the
       | confusing terminology.
        
         | otikik wrote:
         | You have described my experience with man pages, and in general
         | with developer-written documentation. I think part of it is
         | simply that a lot of devs struggle to communicate what they
         | know to people who don't already know what they know. I also
         | suspect lack of interest is a big reason (writing the code is
         | fun, writing the docs is boring).
        
           | jgalar wrote:
           | In my experience, having to explain a software's design in
           | plain English often reveals that some aspects were poorly
           | thought-out in the first place.
        
             | hinkley wrote:
             | ...which in turn triggers defensiveness in some people,
             | making a bad situation worse.
        
           | sodapopcan wrote:
           | A lot of the time the language in man pages fine, but it
           | could be easily clarified for first-time readers with simple
           | examples. What is it with that? It seems to be an unwritten
           | rule that Man Pages Shalt Not Provide Examples. Is there a
           | good reason for this is or is it a "secret club"-type thing
           | or something else?
           | 
           | EDIT: I "let me google that for you"'d myself and found this
           | [0] right away which explains it, I guess.
           | 
           | [0] https://unix.stackexchange.com/questions/306189/why-dont-
           | man...
        
           | psunavy03 wrote:
           | https://www.mountaingoatsoftware.com/blog/the-difference-
           | bet...
        
           | dspillett wrote:
           | The trouble with a lot of technical documentation,
           | particularly man-pages and in-tool command-line help, is that
           | it usually seems written as a reference/reminder for people
           | who know more-or-less what they are doing already. You can
           | often work things out from a more standing start, but that
           | sort of documentation isn't optimised for this so you have to
           | work for your illucidation.
        
             | vbezhenar wrote:
             | For popular technologies there are often books, tutorials
             | and other introductory articles. Git certainly has enough
             | information to start out without reading every manpage.
        
           | hiAndrewQuinn wrote:
           | I think this is why `tldr` is so helpful as a starting point:
           | It's crowdsourced from other people than the dev who need to
           | just _get things done_.
        
             | shadowgovt wrote:
             | The single biggest contribution StackOverflow made to
             | documentation as a whole was to flip the script.
             | 
             | Instead of the original developer of the material trying to
             | prognosticate what questions people would have, people
             | asked questions and either other users or the developer
             | could answer them.
        
             | jaynetics wrote:
             | As this might not be obvious to all, tldr is a crowdsourced
             | man-page replacement, and also really useful when working
             | with git.                   $ tldr git cherry-pick
             | Apply the changes introduced by existing commits to the
             | current branch.         To apply changes to another branch,
             | first use `git checkout` to switch to the desired branch.
             | More information: <https://git-scm.com/docs/git-cherry-
             | pick>.                  - Apply a commit to the current
             | branch:             git cherry-pick commit
             | - Apply a range of commits to the current branch (see also
             | `git rebase --onto`):             git cherry-pick
             | start_commit~..end_commit                  - Apply multiple
             | (non-sequential) commits to the current branch:
             | git cherry-pick commit_1 commit_2                  - Add
             | the changes of a commit to the working directory, without
             | creating a commit:             git cherry-pick -n commit
        
           | maw wrote:
           | Believe it or not, I enjoy writing documentation.
           | 
           | I imagine it as a competition between myself and an adversary
           | with an uncooperative attitude, one who's prepared to act
           | smarter, dumber, better informed and more ignorant than I am
           | in order to to find gaps, inaccuracies, or ambiguities in the
           | docs I write.
           | 
           | It doesn't hurt that it improves my understanding of whatever
           | it is that I'm documenting -- and where it could be improved.
        
             | mbork_pl wrote:
             | This. I also like writing, but I _love_ your description of
             | technical writing as a (sort of) competition. Thanks!
        
             | Tao3300 wrote:
             | I write docs with my most terrifyingly dangerous adversary
             | in mind: Future Me. His forgetfulness and capacity for
             | ignorant destruction are unparalleled, at least that's what
             | Past Me says.
        
           | kagakuninja wrote:
           | In the '80s, all we had on UNIX were man pages, and I was
           | able to glean useful info from them.
           | 
           | Now they make my eyes glaze over, probably because every
           | command now has 57 options. I just google how to do the
           | thing.
        
             | dboreham wrote:
             | There have never been "just man pages" in Unix. E.g. V7 had
             | a number of papers (in troff format which could be rendered
             | to the terminal or sent to the printer in finite time) that
             | helped with understanding how to use the system (assuming
             | you had more than the bare minimum disk space on your
             | machine).
        
           | nvy wrote:
           | I basically never read man pages. In the overwhelming
           | majority of cases you spend 20+ minutes reading the manual
           | and it ends up not answering your question (or at least this
           | is my experience) so you end up just doing a web search
           | anyway.
        
           | bjornasm wrote:
           | Same here. I feel like a majority of documentation and
           | eapecially man pages are helpfull if you already know it, but
           | just need a reminder.
        
           | PH95VuimJjqBqy wrote:
           | That hasn't been my experience at all, I find man and info
           | pages hugely helpful.
        
           | masto wrote:
           | A lot of documentation is atrocious, particularly for newer
           | stuff. But I kind of disagree on man pages. At least, when I
           | first encountered Unix, it was on old SunOS machines, and I
           | remember being impressed first that everything _was_
           | documented, and second, that the documentation was
           | comprehensive and useful.
           | 
           | The things that make me most frustrated are when docs are
           | missing, incomplete, or useless ("--foo: enables the foo
           | option"). When it comes to man pages, at least in the good
           | old days, I felt like I could always rely on them to cover
           | all of the possible inputs, outputs, and errors, and to
           | describe them, if not in the plainest language, in a way I
           | could understand without being the author of the program.
           | 
           | For example, I don't have much bad to say about
           | https://shrubbery.net/solaris9ab/SUNWaman/hman1/ls.1.html
        
         | hinkley wrote:
         | "I understood every one of those words."
        
         | jakub_g wrote:
         | The upside of this is, when I have a bad humour, I go to git-
         | man-page-generator, and one minute later I'm laughing my arse
         | off.
         | 
         | https://git-man-page-generator.lokaltog.net/
        
       | esoterae wrote:
       | The way in which the author structured the language used to
       | describe things may be the most confusing thing of all. For
       | example:
       | 
       | "HEAD^ and HEAD~ are the same thing (1 commit ago)"
       | 
       | Followed by:
       | 
       | "But I guess they also wanted a way to refer to "3 commits ago",
       | so HEAD^3 is the third parent of the current commit, and HEAD~3
       | is the parent's parent's parent."
       | 
       | The author's language implies a contradiction they immediately
       | prior said doesn't exist. If these two distinct constructs were
       | indeed different ways to define the same relationship, the second
       | paragraph would say "^3 and ~3 are both ways of saying the third
       | parent of the current commit, or the parent's parent's parent."
       | Instead, they've defined the constructs as different once again.
        
         | jcranmer wrote:
         | > If these two distinct constructs were indeed different ways
         | to define the same relationship, the second paragraph would say
         | "^3 and ~3 are both ways of saying the third parent of the
         | current commit, or the parent's parent's parent."
         | 
         | They're not the same thing. Merge commits can have multiple
         | parents, and HEAD^3 refers to the third parent. If HEAD is not
         | a merge commit, then HEAD^3 doesn't refer to anything. HEAD~3,
         | by contrast, refers to following the parent's parent's parent,
         | independent of how many parents any of the commits in question
         | had.
        
           | dicytea wrote:
           | > HEAD~3, by contrast, refers to following the parent's
           | parent's parent,
           | 
           | More specifically, following _the first_ parent only. _man
           | git-rev-parse_ (surprisingly) has a nice explanation:
           | 
           | > A suffix ~<n> to a revision parameter means the commit
           | object that is the <n>th generation ancestor of the named
           | commit object, following only the first parents. I.e. <rev>~3
           | is equivalent to <rev>^^^ which is equivalent to <rev>^1^1^1.
        
           | ahmedfromtunis wrote:
           | To make it even clearer, "^3" is when a team of, say, 4
           | commits contributed to the current commit. "^3" is then the
           | team member number 3.
           | 
           | "~3" however refres to grand-grand-parent to the current
           | commit.
           | 
           | It's confusing because ^ looks like an up-arrow, so we think
           | of it as a pointer to look n levels up. That's not the case.
        
       | j16sdiz wrote:
       | I think the author got "heads" wrong and failed to explain how
       | heads and branches are different concept with the same
       | identifier.
        
         | wavemode wrote:
         | Care to explain?
        
       | pickledish wrote:
       | I guess I've never really found the "ours" and "theirs"
       | terminology too confusing -- it's called "ours" because that
       | refers to the branch I have checked out right now (i.e. that's
       | "my" branch), and "theirs" because that's the other branch, the
       | foreign one which isn't currently "mine".
       | 
       | But maybe that's because I almost never use rebase, where it
       | apparently is switched?
        
         | sakisv wrote:
         | Ah, but it's not switched! Remember that rebase essentially
         | replays commits against a different branch/base commit:
         | 
         | e.g. if you have your branch `feature-1` and want to rebase it
         | on `main`, then you would do `git checkout feature-1; git
         | rebase -i main`
         | 
         | Git will then switch to main (that's "ours" now) and then it
         | will replay the changes from `feature-1` on top of it (that's
         | "theirs" now) - like cherry-picking all your commits, but in
         | sequence (and not actually merging them in `main`)
        
           | saghm wrote:
           | > Remember that rebase essentially replays commits against a
           | different branch/base commit
           | 
           | This is exactly the reason that git is hard. Its abstractions
           | are so leaky that you'd think it's interface is designed to
           | be a sieve. I really like the underlying model git uses, but
           | the actual CLI does a terrible job of providing mechanisms to
           | use it to the point where you have to pay far too much
           | attention to the internal model to be able to avoid footguns.
           | It's an indictment of a poor API when the best way to figure
           | out how to do something isn't to search the docs but to
           | figure out how to express the thing you want to do as an
           | operation on the underlying model and then Google that to
           | find the invocation that happens to map to that operation
           | (and half the time, it's not even it's own subcommand; it's
           | just some obscure flag to a grossly overloaded subcommand
           | like `checkout`).
        
             | porridgeraisin wrote:
             | I can't quite find it, but there's a video on git
             | internals, and how you can make commits without using the
             | git cli, by directly manipulating .git folder. That really
             | helped me deal with certain idiosyncracies of the git cli
             | (either I guess a hacked-together sequence of git cli
             | commands, or i know what to nuke)
        
         | technojamin wrote:
         | That's exactly why the author included it. Your definition
         | seems appropriate at first and is probably what most people
         | assume: "ours" refers to "my current branch" (HEAD), and
         | "theirs" refers to "the other branch".
         | 
         | This breaks down during rebase, where the terminology gets
         | reversed. The definitions are more accurately:
         | 
         | - "Ours" refers to "the branch whose HEAD will be the 1st
         | parent of the merge commit" (during merge) or "the branch who
         | will get commits applied on top of its HEAD" (during rebase)
         | 
         | - "Theirs" refers to "the branch whose HEAD will be the 2nd
         | parent of the merge commit" (during merge) or "the branch whose
         | commits will be applied on top of the other branch" (during
         | rebase)
         | 
         | This gets a little more complicated during "octopus merges",
         | where there are multiple "theirs" branches.
        
         | hotnfresh wrote:
         | I'm constantly having to double-check directionality for pretty
         | much everything in Git. I find none of the terminology or
         | ordering intuitive, and never trust myself to have remembered
         | it correctly. Ditto whether various commands that take or imply
         | ranges are inclusive or exclusive.
        
       | petepete wrote:
       | git has had `switch` and `restore` for years now, they provide a
       | more sensible interface than having `checkout` do so much.
        
         | chungy wrote:
         | I honestly never wrapped my head around the `git branch` and
         | `git switch` commands and continue to use checkout for
         | everything branch-related because it's what I've been doing
         | since 2007. I haven't given them a fair shake, granted, but to
         | me it's kind of like complaining that Unix's mv is confusing
         | because it also renames files.
         | 
         | `git restore` though is slightly nicer than using checkout.
         | I've incorporated its use into my workflow, even though I've
         | previously used checkout for the same operation.
        
           | petepete wrote:
           | I've also been using git since around that time but had no
           | problem _switching_ in 2019 because I'd also spent many years
           | using svn. Choice is good, switch just fits my brain better.
        
       | civopsec wrote:
       | See also:
       | 
       | - The git staging area, the term literally everyone agrees with
       | 
       | - https://news.ycombinator.com/item?id=28143078
       | 
       | > "Your branch is up to date with 'origin/main'"
       | 
       | > ... But it's actually a little misleading. You might think that
       | this means that your main branch is up to date. It doesn't.
       | 
       | No need to well-actually this one. Isn't the Two Generals problem
       | applicable here? If you are being really pedantic, it is
       | impossible to tell whether you are "up to date" right this split
       | second. Even if you do a fetch before `status`. So what's the
       | reasonable expectation? That the ref in your object database--on
       | your own computer--is up-to-date with some other way-over-there
       | ref in an object database last time you checked.
       | 
       | A simple `status` invocation can't (1) do a network fetch
       | (annoying) and (2) remind you about the fundamentals of the tool
       | that you are working with. In my opinion. But amazingly there are
       | a ton of [votes on] comments on a StackOverflow answer[1] that
       | suggest that those two are exactly what is needed.
       | 
       | > I think git could theoretically give you a more accurate
       | message like "is up to date with the origin's main as of your
       | last fetch 5 days ago"
       | 
       | But this is more reasonable since it just reminds you how long
       | ago it was that you fetched.
       | 
       | [1] https://stackoverflow.com/questions/27828404/why-does-git-
       | st...
       | 
       | ...
       | 
       | Another thing: I thought that `ORIG_HEAD` was related to
       | `FETCH_HEAD`, i.e. something to do with "head of origin". But no.
       | That "pseudoref" has something to do with being a save-point
       | before you do a more involved rewrite like a rebase. Which was
       | implemented before we got the reflog. I guess it means "original
       | head"?
        
         | dooglius wrote:
         | The expectation is that the information you get is up-to-date
         | as of the time you started the status command, yes there can be
         | a race in the time it takes to present information to your
         | terminal but that's a small time window. This more or less
         | means you want to fetch, yes. Two Generals problem is only
         | applicable on the remote side, which may keep sending
         | retransmits for a while, if it doesn't get acks that you
         | received its data (which isn't the client's problem). If the
         | client doesn't get data from the server presumably the right
         | behavior (which I'd expect happens now with fetch) is to hang
         | and print an error after a timeout.
        
           | civopsec wrote:
           | > The expectation is that the information you get is up-to-
           | date as of the time you started the status command,
           | 
           | Why is that the expectation of a "distributed VCS"?
        
             | happytoexplain wrote:
             | It is not - it is the expectation of the phrase "up to
             | date". You don't have to alter reality, you can just alter
             | the description of reality to be a little more
             | conversationally precise.
        
           | fragmede wrote:
           | That's _your_ expectation, but how does that work without
           | Internet access? You 're holding it wrong...
        
             | happytoexplain wrote:
             | It's pretty presumptuous to just tell somebody what they
             | think about English is wrong. We can change the wording
             | without changing the system (Though technically we could
             | even alter the system to update the remote ref as part of
             | the status command, and the wording would be much better to
             | a human! Though we shouldn't, since, as you imply, we don't
             | want the status command to be dependent on a network call.)
             | 
             | Edit: Removed accusation of "Conflating the implementation
             | of the system with the wording of its output".
        
         | happytoexplain wrote:
         | I'm pretty pro-Git, but I agree with the author on the wording
         | of that message (though I disagree with their suggested
         | alternative). "Your branch is up to date with 'origin/main'" is
         | technically correct, but the usage of the phrase "up to date"
         | implies on a casual reading _two_ things: That main matches
         | origin /main, and that origin/main is up to date (i.e. that it
         | was updated as part of the command, or is being kept up to date
         | automatically and the last successful sync was arbitrarily
         | recently). We're talking about a user-facing status message,
         | not a machine-readable signal that must be true during this CPU
         | cycle. This is a reasonable interpretation without having to
         | get into networking theory.
         | 
         | "Up to date" means caught up in time, as opposed to space.
         | Local branch positions are more like space ("where is this
         | branch pointing?") and remote ref state is more like time
         | ("when did I last update the remote ref?"). I know, that's very
         | subjective. Either can mean either.
         | 
         | Anyway, I think a better wording might be "Your branch matches
         | origin/main" or "Your branch's head is the same as origin/main"
         | or "Your branch is pointing to the same commit as origin/main"
         | or some other tradeoff between verbosity and clarity. Maybe
         | with the author's suggestion as a parenthetical: "Your branch
         | ... origin/main (remote ref last updated 5 days ago)."
        
           | civopsec wrote:
           | > Anyway, I think a better wording might be "Your branch
           | matches origin/main"
           | 
           | That's fine. And also less partial to the implicit view that
           | the remote ref is the thing you are supposed to be "up to
           | date" with.
        
           | Lutger wrote:
           | I like the last one and would shorter it to:
           | 
           | "Your branch ... origin/main, updated 5 days ago."
        
         | fernandotakai wrote:
         | >A simple `status` invocation can't (1) do a network fetch
         | (annoying)
         | 
         | i don't think that's annoying. i want network operations to be
         | explicit, not implicit. when i do git status, i wanna know the
         | status of my repository as is in my file system.
         | 
         | if i want to know what's going on in another remote, i will
         | fetch that and then compare.
        
       | javier_e06 wrote:
       | Not to pile on but also the idiots at Bitbucket cooking the "pull
       | request" term. A "pull" is the action of merging remote changes
       | into a local repo. What the user is actually requesting is for
       | the server to merge her/his remote changes into a branch. Gitlab
       | calls it a "merge request" which is right. I saw someone doing a
       | fetch and their commits disappeared! They where hidden because
       | the repo went backwards in time. Git hides all those tidbits of
       | information in the status but if you don't use git-prompt or
       | powerline-shell ...you are working in the dark.
        
         | civopsec wrote:
         | Github popularized "pull request" and I think it's a fine term.
         | Whether you are "actually" pulling from a different repository
         | instead of just doing a "merge request" (idiosyncratic GitLab
         | term) within the same repository doesn't feel like an
         | interesting distinction.
        
           | fragmede wrote:
           | If you're treating git as a centralized VCS, that is, there
           | is only a singular upstream, perhaps, say, GitHub.com, then
           | that makes sense. That, however, is not the only way to use
           | the tool (though GitHub.com obviously has their own opinions
           | on whether that should be the case or not), but the upstream
           | repository that you're pulling from certainly it's an
           | important distinction if you're using the tool beyond how
           | GitHub.com wants you to.
        
             | civopsec wrote:
             | So you should change your terminology depending on some
             | "how X" your workflow is? If you are working with two
             | repositories between yourself and a teammate then it
             | becomes "pull request", but then if you move back to the
             | centralized company upstream then you're doing "merge
             | requests"? The distinction is not interesting enough to,
             | well, make a distinction over.
             | 
             | > That, however, is not the only way to use the tool
             | 
             | And "pull request" somehow is exclusionary? No, because you
             | can use it to talk about both inter- and intra-repository
             | changes.
        
               | lemoncucumber wrote:
               | Yeah, `git pull` is just shorthand for `git fetch`
               | followed by `git merge`, so it's technically a superset
               | of a "merge request".
               | 
               | And it also handles the cross-repo case, which is a
               | common case in the Github model of "make your own
               | personal fork of the upstream repo and send PRs from
               | there," which has advantages -- it allows random people
               | to send PRs without needing to give them permission to
               | e.g. pollute the upstream repo's branch namespace.
        
           | bjornasm wrote:
           | Disagree. Why are you both pulling when you want code from
           | the repo and when you want to put your code up to someone
           | elses repo?
        
             | Ajedi32 wrote:
             | You pull when you want code from their repo, they pull when
             | they want code from your repo. You don't have permission to
             | push to their repo, so instead you _request_ that they
             | _pull_ from yours.
        
         | thomastjeffery wrote:
         | From the server's perspective, you are the remote and it is
         | local. You are requesting that the server pulls from you.
         | 
         | ...at least, that's how I always read it.
        
           | dboreham wrote:
           | I thought it originated in a decentralized git use case where
           | developer A asks developer B to pull their proposed new code
           | into their (local) repo. So predating server hosted git.
           | Perhaps I made that up though.
        
             | thomastjeffery wrote:
             | That's generally my point: despite the server _presenting
             | itself as_ a centralized  "hub", it is really just another
             | decentralized user of a decentralized git repo.
             | 
             | From a git perspective, there is no meaningful difference
             | between server and client.
        
         | jordigh wrote:
         | The original idea, as enshrined in git-request-pull(1), was
         | that we would all have our own git repos somewhere,
         | kernel.org/git or redhat.com/git, and then we would request to
         | pull from each other by sending emails to each other to pull
         | from each other repos across different servers, even different
         | organisations and different domains.
         | 
         | Github took inspiration from git's request-pull command but
         | instead reinterpreted it as merging from one github repo to
         | another.
        
         | bjornasm wrote:
         | This is the one that allwaays was impossible for me to wrap my
         | head around. Surely it is a push or merge request not a pull
         | request.
        
           | PH95VuimJjqBqy wrote:
           | It's a request for the other person to pull, it's only a push
           | if the requestor is doing the action (and they're not).
        
           | ajross wrote:
           | So... technically no. It really is a "pull" request from
           | Github's perspective. A PR is (1) a bunch of
           | review/comment/history/hook tracking in the web/cloud
           | backends and (2) a single git branch name somewhere else on
           | github, writable by the author, which contains the changes.
           | 
           | The underlying action of merging a "pull request" is to pull
           | from the submitted branch to the target branch. It's no
           | different than Linus doing it from a maintainer branch.
        
         | ptx wrote:
         | The Git book [0] explains where this term comes from and how it
         | makes sense.
         | 
         | In short, it's not a request to a server but to another person.
         | You're requesting that they pull your branch to take a look at
         | the changes you want to contribute to the project.
         | 
         | [0] https://git-scm.com/book/en/v2/Distributed-Git-
         | Contributing-...
        
       | MzHN wrote:
       | One of my favorites:
       | 
       | You want to permanently destroy all work you've done since last
       | commit (maybe it was a bad start and you want a fresh one).
       | 
       | The (new-ish) command you run is                 git restore .
        
         | drewolbrich wrote:
         | This makes sense though, because in Swedish, the words for
         | restore and destroy are homonyms.
        
       | hyperhopper wrote:
       | See also: Git Koans
       | 
       | https://stevelosh.com/blog/2013/04/git-koans/
        
       | sakisv wrote:
       | I was having a similar hard time to remember most of these (the
       | remaining ones I just don't use often, so I still haven't quite
       | grasped).
       | 
       | The single thing that made everything "click" together is that
       | most things are just pointers to commits: branch names, HEAD,
       | tags, all of them are pointers.
       | 
       | HEAD is pointing to the commit you're currently looking at
       | 
       | The name of each branch (e.g. `my-feature` points to the latest
       | commit of that branch)
       | 
       | When you're on main and you `git checkout -b my-feature` then you
       | have at least 3 pointers to the latest commit on main: `main`,
       | `my-feature` and `HEAD`.
       | 
       | Every time that you make a commit on `my-branch`, then both the
       | `HEAD` and `my-branch` move to point to the new commit.
       | 
       | "detached HEAD" means that the the `HEAD` (the commit you're
       | looking at) is not pointed at by a branch.
       | 
       | The difference between tags and branches is that the tags point
       | to a specific commit and do not move.
       | 
       | ----
       | 
       | The other thing caught me out multiple times is that most
       | commands seem inconsistent because git assumes default arguments:
       | 
       | `git checkout file.txt` is the same as `git checkout HEAD --
       | file.txt`
       | 
       | When you're on `my-branch`, `git rebase main` is the same as `git
       | rebase main my-branch`
       | 
       | The difference is that the latter you can run it from other
       | branches too.
       | 
       | ----
       | 
       | Last but not least, when everything goes wrong, the single
       | command that can take you out of any weird situation is `git
       | reflog` which shows you all the commits that HEAD has pointed to.
       | 
       | Having said all that, I'm glad that git is acknowledging all this
       | confusion and are implementing commands with fewer surprises and
       | simpler interface as that will make it easier for newcomers to
       | pick it up.
        
         | bingemaker wrote:
         | One thing that has really helped me understand git better is
         | DAG (https://en.wikipedia.org/wiki/Directed_acyclic_graph).
         | Whenever I do `git add <file/folder>`, it is somewhat easier to
         | imagine how new blobs are created and how they are linked.
         | 
         | For beginners it is a fun exercise to understand why empty
         | folders can't be added to git.
        
           | bonzini wrote:
           | Not that there is any reason why git _has_ to forbid the
           | existence of empty tree objects.
           | 
           | (Fun fact, all such empty trees would be deduplicated to a
           | single object).
        
         | strifey wrote:
         | I love this explanation. One unfortunately confusing extra
         | piece that some people might occasionally run into is that
         | there are two types of tag. Most tags are what you describe:
         | pointers (git ref) to a commit (git object) and nothing more.
         | These are usually referred to as lightweight tags.
         | 
         | There are also annotated tags that can contain a message, have
         | a timestamp, and sha, etc. These are proper git objects that
         | behave a lot like commit objects, except they're still
         | typically only referring to another git object (commit).
        
           | recursive wrote:
           | I thought I understood tags...
           | 
           | But now what's a "proper git object"? Is there an improper
           | git object? Is there a proper git non-object?
        
             | oasisaimlessly wrote:
             | "proper git object" = anything that has its own unique
             | hash.
        
             | derefr wrote:
             | Underneath the SCM plumbing, the "true core" of git is a
             | content-addressable object store. (See https://git-
             | scm.com/book/en/v2/Git-Internals-Git-Objects)
             | 
             | When you `git fetch`, git is asking the remote to walk a
             | tree of objects -- starting at the commit object that the
             | ref points to -- and deliver them to you, to unpack into
             | your own object store.
             | 
             | Git _could in theory_ do a lot with just objects -- with
             | the whole  "data state" of the repo (config, reflog, etc)
             | just being objects, and then one toplevel journal file to
             | track the hash of the newest versions of these state
             | objects. (Sort of like how many DBMSes keep much of the
             | config inside the database.)
             | 
             | But git mostly isn't designed to do this. Instead, git's
             | higher SCM layers manage their state directly, outside of
             | the object store, as files in well-known locations under
             | .git/. This means that this higher-level state isn't part
             | of the object-store synchronization step, and there must
             | instead be a domain-specific synchronization step for each
             | kind of SCM state metadata where applicable.
             | 
             | Tags are an interesting exception, though, in that while
             | the default "lightweight" tags _are_ "high-level SCM
             | metadata" of the kind that isn't held in the object store;
             | "annotated" tags _become_ objects held in the object store.
             | 
             | (To be honest, I'm not sure what the benefit is of having
             | "lightweight" tags that live outside the object store. To
             | me, it looks like tags could just _always_ be objects, and
             | "lightweight" vs "annotated" should just determine the
             | required fields of the data in the object. Maybe it's a
             | legacy thing? Maybe third-party tooling parses lightweight
             | tags out of the .git/ directory directly, and can't "see"
             | annotated tags?)
        
               | bonzini wrote:
               | Lightweight tags are simply references to commits that
               | lie in refs/tags instead of refs/heads. Annotated tags
               | are references to tag objects rather than commit objects.
               | In both cases, the purpose of the reference is to give
               | the object (tag or commit) a name.
               | 
               | I think no one uses lightweight tags anymore, except if
               | you push by mistake a commit to refs/tags/something.
        
         | nvy wrote:
         | >the single command that can take you out of any weird
         | situation is `git reflog` which shows you all the commits that
         | HEAD has pointed to.
         | 
         | Can you elaborate on why that's helpful? I rarely get into a
         | weird state with git but when I do it's almost always
         | faster/easier to just delete the repository, re-clone, and re-
         | apply my changes manually.
        
           | CorrectHorseBat wrote:
           | When you accidentally delete a local branch or mess up a
           | rebase you can use the reflog to retrieve your lost commits
        
           | olddustytrail wrote:
           | If you accidentally symlink the wrong file, would you find it
           | easier to delete the whole directory and restore from backup,
           | or just learn how to change a symlink?
        
           | sakisv wrote:
           | A recent scenario had to do with me rebasing something to
           | squash out some intermediate commits, and then I opened a PR,
           | only to realise that some of the things I squashed I actually
           | needed them.
           | 
           | With reflog I was able to go back before my rebase and redo
           | it again, more carefully this time. (Unfortunately I couldn't
           | just cherry-pick the thing I wanted)
           | 
           | In general it saves you from having to do what you described
           | with delete/re-clone/re-apply things.
        
         | afiori wrote:
         | I believe that detached HEAD means that there is not a current
         | branch, that is no branch will be updated the next time you
         | commit.
         | 
         | You can get to detached HEAD even if the commit is pointed to
         | by a branch
        
         | derefr wrote:
         | > pointers to commits
         | 
         | Or to use the name git gives to that concept, "refs." Thus
         | _reflog_ :)
         | 
         | Also, one thing that I've found hasn't occurred to most people
         | using git, is that all the branch/tag/etc refs of your fetched
         | remotes, are _also_ refs, able to be referenced anywhere you
         | can name a ref.
         | 
         | For example, if you ever want to say "I don't care what's on
         | this branch, don't fast-forward _or_ merge _or_ rebase, just
         | overwrite my local branch with what 's on the remote!" then
         | that'd be:                   git checkout foo         git reset
         | --hard origin/foo
        
           | sakisv wrote:
           | Ah yes, the fact that git brings the remote stuff locally
           | when you `git pull` and all the `origin/<whatever>` are just
           | branch names is something that I realised only too late.
           | 
           | As for the refs, yes, good point ;)
        
             | xorcist wrote:
             | When you do 'git fetch'. The 'pull' is just an alias for
             | fetch + merge (or rebase, depending on local settings).
        
           | mjochim wrote:
           | > Or to use the name git gives to that concept, "refs." Thus
           | reflog :)
           | 
           | A command name that I read as re-flog for the longest time
           | :D. I really wondered about the strange, strange name for
           | quite a while before I bothered to look up what it does and
           | found out that I should read it as ref-log and that it is,
           | indeed, a very useful thing.
        
         | virtue3 wrote:
         | Really great point and also really illustrates the tree
         | structure underneath the hood for git and how it rules
         | everything.
         | 
         | The joke that isn't a joke is that you really need a CS degree
         | to use git. It's not wrong.
         | 
         | The git default arguments makes for a very inconsistent
         | experience, agreed.
         | 
         | And then `git checkout .` vs `git reset --hard/soft` vs `git
         | cleanup` are all super similar but very different.
         | 
         | Still love it more than perforce/svn (I did like mercurial a
         | little better back in the day but I doubt that might still be
         | the case).
         | 
         | ----- `git reflog` is king and shows you the truth.
        
           | sleepybrett wrote:
           | Yeah anyone I run into that 'doesn't get git' and only has
           | like the four commands they ever run... I point them at
           | https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
           | 
           | Once you internalize that git unlocks.
        
           | cloudwalk9 wrote:
           | I use Stable Diffusion (A1111 webui) and sometimes run into
           | config issues, sometimes untracked by git. Nothing more
           | catastrophic than doing `git clean -dfx` by habit from
           | tinkering with Debian packages and knowing that command
           | actually resets everything that `git reset --hard` doesn't...
           | 
           | And then accidentally wiping out all of your checkpoints and
           | generated images :')
        
         | sampo wrote:
         | > HEAD is pointing to the commit you're currently looking at
         | 
         | HEAD pointer is pointing to the branch pointer (e.g. my-branch)
         | which is pointing to the commit. (Except in a detached HEAD
         | state.)
         | 
         | > Every time that you make a commit on `my-branch`, then both
         | the `HEAD` and `my-branch` move to point to the new commit.
         | 
         | HEAD pointer keeps pointing at the my-branch pointer, and only
         | the my-branch pointer moves to point to the new commit. But of
         | course, when you now follow HEAD to my-branch to the commit,
         | now you end up to the new commit.
         | 
         | > "detached HEAD" means that the the `HEAD` (the commit you're
         | looking at) is not pointed at by a branch.
         | 
         | "Detached HEAD" means that HEAD is pointing directly to a
         | commit, instead of pointing to a branch pointer.
         | 
         | You can have a detached head state, where both HEAD and the
         | branch pointer point to the latest commit. If you use `git log
         | --decorate`, for the latest commit it will show (HEAD, my-
         | branch) instead of the normal (HEAD -> my-branch).
        
           | sakisv wrote:
           | > "Detached HEAD" means that HEAD is pointing directly to a
           | commit, instead of pointing to a branch pointer.
           | 
           | Ah, thanks for pointing it out, always good to learn the
           | finer distinctions
        
           | iamcreasy wrote:
           | > HEAD pointer is pointing to the branch pointer (e.g. my-
           | branch) which is pointing to the commit. (Except in a
           | detached HEAD state.)
           | 
           | Yes! Here[1] is a nice picture about from Git Reset
           | Demystified article.
           | 
           | [1] https://git-scm.com/book/en/v2/Git-Tools-Reset-
           | Demystified
        
         | jacobegold wrote:
         | I think that this video should be considered mandatory viewing
         | if you're a developer using Git -- the whole lecture starts
         | from the basic data structures involved and builds from there,
         | as opposed to the way that it seems many people approach Git:
         | "What command do I run?"
         | 
         | https://www.youtube.com/watch?v=2sjqTHE0zok
        
           | SAI_Peregrinus wrote:
           | That's great evidence that git's UI is such a leaky
           | abstraction that it's actually terrible.
        
         | Terr_ wrote:
         | > Last but not least, when everything goes wrong, the single
         | command that can take you out of any weird situation is `git
         | reflog` which shows you all the commits that HEAD has pointed
         | to.
         | 
         | And if you're feeling extra-paranoid like me, a `git rev-parse
         | HEAD` and copying that string down somewhere safe _before_
         | embarking on a tricky process with lots of merge-conflicts or
         | other shuffling.
         | 
         | It's nice to have confidence that I've accurately identified
         | _which_ state is the last-known-good one--not one a few steps
         | too far into the chaos-zone--and that I can usually get back to
         | if everything goes to hell. (Barring unwise use of stuff like
         | `git gc` or `git filter-branch`.)
        
       | andrewla wrote:
       | > "can be fast-forwarded"
       | 
       | I find this one annoying because I generally don't want to run
       | `git pull` -- I almost never `git pull`, I usually just `git
       | fetch` and update my branches as necessary. I do wish there was a
       | built-in shortcut for "try to fast-forward this branch"; I often
       | just do a rebase or a merge, which will do the right thing for a
       | fast-forward, but won't fail if a fast-forward is impossible. I
       | can do `git merge --ff-only`, but I would like it if `git
       | fastforward` or `git ff` was available instead because for me it
       | is such a common operation.
       | 
       | To forestall the obvious -- I don't like to make custom aliases
       | or commands (though I've done it in the past) because it makes it
       | harder to migrate between environments.
        
         | ericyd wrote:
         | I don't mean any criticism but I'm genuinely curious: how often
         | are you migrating between fresh git environments?
        
           | ksenzee wrote:
           | I'm not convinced this matters. It's very important that some
           | things be kept easy and accessible even if you don't do them
           | very often. I don't call emergency services very often, but
           | when I do, it had better be trivially easy. I don't spin up a
           | new server very often, but when I do, I need to be able to
           | function there without immediately installing a bunch of
           | config. I don't help colleagues who need git assistance very
           | often, but when I do, the last thing I need is to mess
           | something up for them because all my aliases and defaults are
           | missing.
        
         | Am4TIfIsER0ppos wrote:
         | git ff
         | 
         | Very useful to make a git alias for that. When git bitches at
         | my about the unknown command on the work servers I know I can
         | just use the full merge command.
        
           | mckn1ght wrote:
           | I have a shell alias for this: gff='git fetch && git pull
           | --ff-only'
        
         | ZeroGravitas wrote:
         | I believe you can set the default to be --ff-only then you only
         | need to specify if you want to merge.
         | 
         | Despite knowing this is an option it's still hard for me to
         | find decent documentation, but I think this is probably the
         | best I found:
         | 
         | https://salferrarello.com/git-warning-pulling-without-specif...
        
           | andrewla wrote:
           | That's even worse because it will just do the wrong thing
           | when I'm on a different setup. At least with an alias the
           | system can say "yeah, I ain't never heard of 'ff'" so I can
           | fall back on a default.
        
       | Tomis02 wrote:
       | It's been about a decade since git "won" the version control war
       | due to the (yet another) unjustified tech hype wave, and we're
       | still having difficulties with what should be trivial tasks. I
       | remember reading a comment by Linus Torvalds being surprised that
       | people started using git directly rather than putting a
       | friendlier layer on top. If it was capable of introspection, the
       | industry would admit it made a mistake by going with git and
       | switch to another VCS instead, rather than wasting huge amounts
       | of time on a tool whose only job is to save text.
        
         | Lutger wrote:
         | > whose only job is to save text
         | 
         | I don't see git as a tool to save text, its for coordinating
         | changes on the same 'text' by multiple people, and doing so
         | quite precisely and reliably, _without_ blocking anyone 's path
         | forward. Try that with word.
         | 
         | It could be better, yes. But I'm always surprised by the hate
         | git gets. Its an amazing tool and miles ahead of the tools we
         | created for non-developers (word, google docs, etc).
         | 
         | Maybe its because I'm old enough to remember when subversion
         | was king.
        
           | tharkun__ wrote:
           | This. Git is miles ahead of anything else.
           | 
           | Is is entirely intuitive to everyone? No.
           | 
           | Did developers always have trouble with version control and
           | merging? Yes.
           | 
           | In my experience most devs don't grok version control,
           | period. It does not matter if it's SVN, CVS, RCS, Visual
           | Source Safe, Clearcase, Perforce, you name it. Or now git.
        
             | rebolek wrote:
             | If you think Git is miles ahead of anything else, you
             | probably haven't really used anything else.
             | 
             | I don't think that Git sucks, it's usable. But there are
             | better alternatives.
        
           | Tomis02 wrote:
           | > whose only job is to save text
           | 
           | It's a hyperbole, a figure of speech used to make a point.
           | I'm pretty sure everyone on HN knows what git is used for.
           | 
           | > Maybe its because I'm old enough to remember when
           | subversion was king.
           | 
           | I used SVN for more than a year. Why would you compare git
           | with SVN rather than other DVCS like Mercurial?
        
             | Lutger wrote:
             | > It's a hyperbole, a figure of speech used to make a
             | point. I'm pretty sure everyone on HN knows what git is
             | used for.
             | 
             | I know. The hyperbole makes it sound as if gits job is
             | actually quite simple and we could easily have a better
             | system. But I disagree with that, I don't believe it is
             | simple. Most other tools have and are failing still at
             | this.
             | 
             | > Why would you compare it with SVN rather than other DVCS
             | like Mercurial?
             | 
             | Because SVN ruled the world back then and that is what I
             | and many other devs used. Many of us went from SVN to Git
             | without even knowing what Mercurial was. That explains why
             | I was (eventually) so in awe of git, had I gone from
             | Mercurial to Git I might have lamented the loss of a more
             | friendly system. I do actually remember doing the odd thing
             | with mercurial and it being much smoother to work with, but
             | then git was already becoming the dominant player.
        
               | Tomis02 wrote:
               | > Many of us went from SVN to Git without even knowing
               | what Mercurial was.
               | 
               | Yeah I know, that's the problem. In other words, many of
               | us decided git is the best because many of us didn't know
               | any better.
               | 
               | But it's been more than a decade, surely that's enough
               | time to reevaluate one's position.
        
           | scottlamb wrote:
           | > Maybe its because I'm old enough to remember when
           | subversion was king.
           | 
           | Heh. I'm old enough to remember when CVS was king. Subversion
           | was a huge improvement. Git was too. I have every reason to
           | believe further huge improvements are possible. They might
           | have to be gargantuan though to overcome inertia by now.
        
         | jordigh wrote:
         | In 2013, it was far from clear that git would win. There was
         | still a sizable amount of users of darcs, Mercurial, svn, and
         | even cvs. Many of the tools of that era would have plugins to
         | support all of them.
         | 
         | I wish we still had that, because git monoculture also means
         | that anything that replaces git first has to reimplement git.
         | This means that just like ASCII or scroll lock buttons, we're
         | stuck with git mostly forever.
        
         | PH95VuimJjqBqy wrote:
         | > unjustified tech hype wave
         | 
         | git won for good reasons, it's clearly better than what came
         | before it. It may be popular to shit on it now (similarly for
         | jquery), but when it arrived on the scene it was clearly an
         | improvement.
        
         | regularjack wrote:
         | Git won because it's better than Subversion, and because of
         | GitHub.
        
         | failingslowly wrote:
         | Hard agree.
         | 
         | Weekly, I witness co-workers confused about git, I see posts
         | online asking for help, I see articles like the one here once
         | again trying in vain to explain something that should be
         | simple.
         | 
         | In all my time coding, I don't remember anyone wasting hours
         | trying to undo some mess they'd made in SVN, TFVC, Perforce,
         | etc.
         | 
         | Tools exist to make our lives easier. If they can't do that,
         | they don't deserve our time.
        
         | retpoline__ wrote:
         | >It's been about a decade since git "won" the version control
         | war due to the (yet another) unjustified tech hype wave
         | 
         | Hah, I've recently wrote a post about similar issue - why we
         | may be locked with git.
         | 
         | >So what's the issue here? I'm worried that just because GitHub
         | is so good, then unless they decouple from git as letters
         | management engine and allow any/other, then we will be locked
         | with git.
         | 
         | https://trolololo.xyz/github
         | 
         | https://news.ycombinator.com/item?id=38098109
        
       | dgan wrote:
       | "Your branch is up to date with origin/master" is the biggest lie
       | i am being told on daily basis. I just "pull" every time
        
         | abledon wrote:
         | should be "Your branch is up to date with the local copy of
         | origin/master, last updated on XXXX-XX-XX:XX:XX:XX" haha
        
           | pests wrote:
           | That sounds like the origin/master branch last got an update
           | on XXXXXXXXXX, not that you checked out your local copy on
           | that. I would fetch and then be wondering why nothing
           | charged.
           | 
           | Further it does nothing - it tells you nothing about the
           | remote. It could be 1 second or 100 years and you would still
           | need to fetch to determine if anything is different. Then
           | what is the information for?
        
             | SAI_Peregrinus wrote:
             | By the last line's logic there would need to be an atomic
             | fetch & compare. `git fetch && git status` still has the
             | same race condition!
        
         | jlarcombe wrote:
         | that's the most common confusion yes! along with 'stage' vs
         | 'cache' vs 'index'.
        
         | Lutger wrote:
         | Nice. But technically its true. origin/master is not master on
         | origin. It just refers to the last known commit pointed to by
         | origin/master, which gets updated when you fetch (pull
         | automatically fetches).
         | 
         | ls -l .git/refs/remotes/origin/master
         | 
         | origin/master is just a file on your system, you can see when
         | it has been changed. It doesn't magically get updated. Do `git
         | fetch origin` and if there are any changes, you'll see the
         | timestamp change, and the contents:
         | 
         | cat .git/refs/remotes/origin/master
         | 
         | The basics of git are so simple, you can implement the core
         | data structures and some operations in a day. It is really
         | worth it to get to know these.
         | 
         | Somehow git has managed to create a very complex user interface
         | on top of quite a simple core.
        
           | cush wrote:
           | > It just refers to the last known commit pointed to by
           | origin/master
           | 
           | The confusion lies in that origin refers to different things
           | depending on if it's `origin master` or `origin/master`. Eg
           | `git pull origin master` does the thing we expect
        
           | Y-bar wrote:
           | > But technically its true.
           | 
           | Is it though?
           | 
           | Consider a bank telling a store I am buying things at "This
           | person has has EUR450 in their bank account", when at that
           | moment I have EUR310. The store would be rightfully pissed at
           | the bank for effectively lying when it is made clear later on
           | that the transaction could not be completed and the bank
           | answers "well, the person had EUR450 a few days prior to you
           | asking us".
           | 
           | Without an explicit temporal information it is explicitly
           | now.
           | 
           | Without an explicit status on sync status it is implicitly
           | saying sync is up-to-date.
           | 
           | It's a lie of omission.
        
             | fernandotakai wrote:
             | >It's a lie of omission.
             | 
             | but it's not?
             | 
             | if you have an old bank receipt that says you have $450 in
             | your account, but you actually have $310, you need to "get"
             | a new receipt that has the newest value.
             | 
             | you do that by issuing git fetch origin. then you can git
             | merge origin/master to make everything up-to-date.
        
               | Y-bar wrote:
               | Bank receipts always have a date and time, that's
               | _exactly_ the point I am making, the omission is part of
               | the lie.
        
               | fernandotakai wrote:
               | you are getting confused here.
               | 
               | what you have is a "paper receipt" (your checked out
               | version) from your bank. something that, if you need an
               | up-to-date version (from another remote), you need to
               | request a new one (by issuing git fetch).
               | 
               | git is, by default, distributed, so whenever you need to
               | see the world outside, you need to be explicit. linus
               | made it this way because back in the day (not sure right
               | now tbf) tons of kernel developers do work without any
               | internet connection, and would only connect to pull/send
               | patches.
               | 
               | this talk[0] by linus from 2007 (i remember watching it
               | on google videos lol) explains really well where the git
               | mentality came from. i really recommend it to you, since
               | it feels like you are not really getting how git works.
               | 
               | [0]https://www.youtube.com/watch?v=4XpnKHJAok8
        
               | SAI_Peregrinus wrote:
               | If you have a paper recipt (git status) it tells you when
               | it was up to date, so you can determine whether you need
               | a new one. Git doesn't provide that info. That's the
               | problem, not that it can be outdated, but that it omits
               | the date/time!
        
               | ksenzee wrote:
               | Very good point. "Up to date with origin/master as of 4
               | hours ago" would be an improvement.
        
               | pests wrote:
               | That is a lie though. Who knows if the remote has been
               | updated? You wouldn't find out about that 4 hours until
               | you did a fetch.
               | 
               | You can't go to the hotel desk clerk and ask if you have
               | any messages. Then for the next four hours keep telling
               | people "the front desk has no messages for me" despite
               | you not asking them in the last 4 hours. Things could
               | change!
        
               | ksenzee wrote:
               | No, this is exactly like a receipt from the ATM. "Your
               | bank balance is $300.00 as of 10/10/23 10:10." That was
               | weeks ago, so I know to ignore it. The wording can likely
               | be improved. Maybe "You are up to date with origin/master
               | as last fetched 4 hours ago".
        
               | pests wrote:
               | > That was weeks ago, so I know to ignore it.
               | 
               | But you haven't talked to your bank, used an ATM, or been
               | on the app in weeks! Your balance could be totally
               | different - bills have came out, you got paid, interest,
               | etc.
               | 
               | You are making my point! You know to ignore it because
               | its old, outdated information.
               | 
               | Then why are you telling me this? How is it useful to me?
               | 
               | Of course youre up to date with what you last fetched -
               | that is _always_ the case.
               | 
               | Why mention being up to date even? Just tell the user
               | when they last synced with their remote(s).
        
               | SAI_Peregrinus wrote:
               | You're making their point! `git status`tells you the
               | status as of whenever you last fetched, and omits that
               | timestamp. You can't tell if it's outdated, because it
               | doesn't tell you when the last update was!
        
               | mjochim wrote:
               | > Of course youre up to date with what you last fetched -
               | that is _always_ the case.
               | 
               | But that is not what this message is about. It's
               | confusingly worded, as many people agree, but what it
               | says is that your local ref "main" points to the same
               | commit as your local ref "origin/main." It says nothing
               | about "main" on the other computer/server.
               | 
               | And it is not the case (i.e. you are not up to date with
               | origin/main), for example, when you have committed to
               | main but haven't pushed. It is also not the case when you
               | have fetched but not merged.
        
               | ksenzee wrote:
               | > Of course youre up to date with what you last fetched -
               | that is _always_ the case.
               | 
               | This might be where the misunderstanding is. You are
               | _not_ always up to date with what you last fetched. Say
               | you have develop checked out, and you run a git pull. As
               | part of that process, git checks the status of all
               | upstream branches, and updates your local reference copy
               | of them (that's what origin /develop, origin/production,
               | origin/feature-branch-1 are: your local reference copies
               | of upstream). Then you check out production, which you
               | last touched two weeks ago. Git will let you know that
               | your two-week-old local copy is behind origin/production,
               | which is your local reference copy of what it just saw
               | when it fetched from upstream.
        
             | globular-toast wrote:
             | Git is a distributed system by design.
             | 
             | A problem it has is there is now a generation of developers
             | who don't know _why_ we don 't use centralised VC any more.
        
               | Y-bar wrote:
               | Yes. Which is why temporal data and status is so
               | important and makes things worse when left out.
        
               | yCombLinks wrote:
               | Everyone uses git as a centralized vcs. You could remove
               | the distributed part and 99% of people wouldn't notice.
               | The killer feature was branches, which are orthogonal
        
               | globular-toast wrote:
               | Case in point. I take it you don't remember (or don't
               | know) that truly centralised systems like Subversion
               | required a network connection just to make a _commit_?
               | The commit happened in the repository. There was no local
               | clone. You could check stuff out. That was it.
        
               | yCombLinks wrote:
               | Yeah, I've used subversion a bit. The DAG aspect and
               | commits do not require a distributed system. I'm talking
               | about the idea that git users would pull commits directly
               | from other users and "build consensus" across the
               | network, rather than push and pull from a central repo
        
               | toast0 wrote:
               | I mean, we use whatever the boss tells us to, because
               | that's how a job works?
               | 
               | git has a better experience than cvs or svn if you're far
               | away from the VCS server, but that was solvable by having
               | dev machines near the VCS server. I've gotten used to the
               | git workflow, but it still doesn't strike me as uniformly
               | better, other than if you're using git, you don't have to
               | deal with everybody always ask why aren't you using git.
        
             | capableweb wrote:
             | > Is it though?
             | 
             | Yes, yes it is.
             | 
             | origin/master is not saying that the remote has/hasn't
             | changed. It's comparing your local copy of origin/master,
             | not giving you the status about if remote has/hasn't
             | changed. You need to explicitly ask if remote/origin/master
             | has changed or not if you want to know.
             | 
             | Which in your analogy would be like if the store forgot to
             | actually ask the bank if the customer had the money or not,
             | and instead relying on whatever information they have
             | "cached" in the store. Instead, the store has to first ask
             | the bank (remote) if there is any changes.
             | 
             | I do agree that it could be worded better to actually help
             | the user understand, as it seems to be a common
             | misconception.
             | 
             | Sidenote: I'd be driven to absolute insanity if `git
             | status` started doing remote requests to check the remote
             | origin/master status each time I invoked it.
        
           | cesarb wrote:
           | > origin/master is just a file on your system
           | 
           | Unless it's a packed ref (https://git-scm.com/docs/git-pack-
           | refs), in which case it's just a line in the packed-refs
           | file.
        
         | e40 wrote:
         | > I just "pull" every time
         | 
         | I hope you "git pull -r" every time. Merges are almost always
         | unwanted.
        
         | flostk wrote:
         | That's just saying git doesn't connect to the internet (or
         | whereever the remote is) to check for updates without you
         | explicitly telling it to. I think that's a desirable property,
         | though the message could be clearer.
        
         | leni536 wrote:
         | What I do is I delete the local master branch. I typically
         | can't push to master, or I don't want to work on master
         | directly anyway, so why have a local mutable master branch? So
         | I only need to update origin/master, which I can do with fetch.
        
       | kbknapp wrote:
       | Git terminology is a clinical example where many (most?
       | definitely not all) terms make perfect sense _once you already
       | understand how it works_ , but make almost no sense in concert
       | with other terminology or when you don't know the implementation
       | details.
       | 
       | Leaky terminology.
        
         | jordigh wrote:
         | In part, but also, it's because different people worked on
         | different parts of git and came up with different names. Linus
         | originally called it the cache, the most computer sciency term,
         | and then I think Junio renamed it to index, a more DVCS-
         | specific term, but most users called it the staging area, and
         | now the evolution of this term is fossilised into the git UI as
         | well as its internals.
        
         | tester756 wrote:
         | So basically poor API design
         | 
         | Imagine if you had to know OS/IDE/compiler internals for basic
         | usage
        
       | KingMob wrote:
       | As always, here's a link to the helpful https://ohshitgit.com
        
       | michaelkaufman wrote:
       | Dear AI, it would be nice to just use an English prompt, like:
       | 'put the work I just did onto the Develop branch, even though I
       | forgot to make a separate branch for it first'. Somebody must be
       | making a Git-AI, right?
        
       | mparnisari wrote:
       | I always get 'git restore' and 'git reset' mixed up. I just want
       | to undo my changes dammnit
        
       | tornato7 wrote:
       | The GitHub Desktop app changes some terminology to make it more
       | usable, for example "Undo" instead of "reset HEAD~". I typically
       | make aliases for this sort of thing in my terminal, but it would
       | be great if some of those made it to the Git CLI.
        
       | tombert wrote:
       | I think I have a case of "Git Stockholm Syndrome"; I don't find
       | any of these terms terribly confusing, but I think that's in no
       | small part because I haven't really learned any other systems,
       | and have been entrenched in Git since like 2011.
       | 
       | Looking back, I suspect that I was extremely confused when
       | starting out, but was pretending I wasn't to try and seem cool.
        
         | raincole wrote:
         | The only other version control that I used is Plastic SCM, and
         | honestly Stockholm Syndrome or not, I like git much more.
        
           | tombert wrote:
           | Someone told me that I really need to check out Mercurial for
           | its binary diffing stuff, and as I've gotten more into 3d
           | modeling in the last year then that might actually buy me
           | something.
           | 
           | However, now that bitbucket has dropped Mercurial support,
           | I'm not entirely sure where I can easily push a mercurial
           | repo for backup. For better or worse, I am extremely
           | dependent on Gitlab to backup my code so I'm not risking my
           | work on a potentially failing hard disk/ssd.
        
             | raincole wrote:
             | > 3D modeling
             | 
             | I don't know. For large binary files I still use Google
             | Drive as backup (I know 3D models are not necessarily
             | "large" by today's standard)
             | 
             | One can use git LFS, but there isn't an easy way to free up
             | the storage them occupy from the history. And GitHub LFS is
             | about 5 times more expensive than Google Drive per GB.
        
               | tombert wrote:
               | These are just CAD-style models for functional robotic
               | parts, not game assets or anything, so they're not
               | actually very large as they're pretty utilitarian, but
               | they do change a lot. As of right now, I'm just pushing
               | the binary files to Gitlab with vanilla git, and at least
               | thus far Gitlab hasn't complained to me.
               | 
               | I figure that the moment Gitlab sends me a nastygram
               | about it, I'll move to S3 or Google Storage or something.
        
             | pseudalopex wrote:
             | https://wiki.mercurial-scm.org/MercurialHosting
        
         | jeltz wrote:
         | I had used cvs and svn before I used git, and compared to svn
         | git was much easier to understand.
        
         | bad_username wrote:
         | I knew that I had Stockholm syndrome when I took a look at the
         | CLI of the Fossil VCS. It is so... straightforward.
        
           | tombert wrote:
           | Fossil looks neat, but it didn't look "sufficiently better"
           | than Git for me to bother changing, especially due to all the
           | services that support Git out of the box.
           | 
           | What does Fossil buy you over Git?
        
             | PH95VuimJjqBqy wrote:
             | in terms of Fossil as an SCM, it's very similar outside of
             | the author's views of rebase (which I happen to agree
             | with).
             | 
             | https://fossil-scm.org/home/doc/trunk/www/rebaseharm.md
             | 
             | In terms of Fossil as a technology, it's an SCM with built-
             | in project management tools (wiki, forums, bug tracker,
             | etc) so it does much more than git does.
             | 
             | The front page has more info:
             | 
             | https://fossil-scm.org/home/doc/trunk/www/index.wiki
        
       | globular-toast wrote:
       | I'm usually the "git guy" so having something like this to refer
       | to when people ask me about such things will be really useful.
       | Thanks!
       | 
       | One of the problems I have is figuring out how people get
       | themselves into such situations. Like if someone submits a merge
       | request and their branch looks like it's been merged into itself
       | with one side rebased or something. When I ask them what they did
       | they have invariably forgotten. If someone cooked a dish that was
       | too salty I'd be able to tell them "try putting less salt in less
       | time". I wish I could do the same with git.
       | 
       | Although upon typing this I'm thinking perhaps I could figure it
       | out by looking at their reflog? But that involves accessing their
       | computer or walking them through it which would probably confuse
       | them even more.
        
       | jkingsman wrote:
       | > When you configure a git remote in .git/config, there's this
       | 
       | > +refs/heads/main:refs/remotes/origin/main thing.
       | 
       | >
       | 
       | > [remote "origin"]
       | 
       | > url = git@github.com:jvns/pandas-cookbook
       | 
       | > fetch = +refs/heads/main:refs/remotes/origin/main
       | 
       | >
       | 
       | > I don't really know what this means, I've always just used
       | 
       | > whatever the default is when you do a git clone or git remote
       | 
       | > add, and I've never felt any motivation to learn about it or
       | 
       | > change it from the default.
       | 
       | This is a refspec[0], and it tells Git the relationship between
       | local references and remote references, defined in the pattern
       | [+]<src>:<dest>. So, in this case, it defines the local head of
       | main to refer to the remote branch main on origin. You could, for
       | example, define all branches on local as linked to all branches
       | on the remote with +refs/heads/*:refs/remotes/origin/*.
       | 
       | An example of a real world usage of this was when we were
       | migrating our repo between providers -- configuring the fetch
       | field to link a different remote for different branch names kept
       | things simple for our developers as we quietly moved branches to
       | the new remote.
       | 
       | It also configures the scope of a git fetch command, iirc, so you
       | can restrict your fetches to only scopes that you care about
       | (maybe your team has a branch name prefix/namespace that you can
       | specify, so when you git fetch you only get things that are
       | relevant and not some other teams' branches you don't need).
       | 
       | [0]: https://git-scm.com/book/en/v2/Git-Internals-The-Refspec
        
       | adhesive_wombat wrote:
       | As with all these posts, use the git lola alias regularly and all
       | becomes clear as you can see where all the branches locally and
       | remote are and how they change when you do things.
       | 
       | http://blog.kfish.org/2010/04/git-lola.html
        
       | mc10 wrote:
       | In this section:
       | 
       | > I think in the context of the merge commit ours/theirs
       | discussion earlier, HEAD^ is "ours" and HEAD^^ is "theirs".
       | 
       | Should HEAD^^ be HEAD^2 instead?
        
         | jvns wrote:
         | fixed, thanks!
        
       | ketzo wrote:
       | I so appreciate Julia's authorial voice. She does such a great
       | job writing content that's super valuable for even veteran devs,
       | while maintaining a tone that's friendly to the newest people in
       | the field and actively includes them rather than gatekeeping.
        
       | kazinator wrote:
       | Regarding "rebase --onto"
       | 
       | > _Imagine that for some reason I just want to move commits F and
       | G to be rebased on top of main. I think there's probably some git
       | workflow where this comes up a lot._
       | 
       | This comes up for me in a branch where I have some necessarly
       | local changes which are permanently there and have to be
       | maintained, and that branch experiences non-fast-forward changes
       | from upstream.
       | 
       | Say we are up-to-date in this branch, plus our two local commits
       | that are not in upstream.
       | 
       | We do a fetch. Upstream has rewritten 17 commits. So now we have
       | 19 diverging local commits. We only care about two of them. We
       | just want to accept the diverged upstream commits, and then
       | rebase the two on top of that.
       | 
       | We do not want to rebase all 19 commits!
       | 
       | We can do:                 git rebase HEAD^^ --onto origin/master
       | 
       | So HEAD^^ is the "upstream" here that we have explicitly
       | specified. So following the documentation:
       | 
       | - All changes made by commits in the current branch but that are
       | not in <upstream> are saved to a temporary area.
       | 
       | [That's precisely our two local commits; those are the ones not
       | in HEAD^^]
       | 
       | - The current branch is reset to <upstream>, or <newbase> if the
       | --onto option was supplied.
       | 
       | [We did specify --onto, so the current branch goes weeee... to
       | origin/master, the abruptly updated, non-fast-forward upstream
       | that we want to catch up with.]
       | 
       | - The commits that were previously saved into the temporary area
       | are then reapplied to the current branch, one by one, in order.
       | 
       | [That's the cherry-picking that we want: our two local commits.]
       | 
       | So end result is that our branch is now the same as origin/master
       | (up-to-date) plus has the two needed local commits.
       | 
       | Further, I have a situation in which there are two git repos on
       | the same machine which have a different version of a local
       | commit. One of the repos (A) is an upstream for the other (B).
       | 
       | When B does a fetch, it gets the master branch from A with A's
       | local commit, which is unwanted in B. B has its own flavor of
       | that commit:                 git rebase HEAD^ --onto
       | origin/master^
       | 
       | takes care of it. We catch up with origin/master, but ignoring
       | one commit, and on top of that we cherry pick ours.
        
       | chrisbrandow wrote:
       | This is really great!
       | 
       | I'd suggest one edit in the first entry:
       | 
       | "heads" are "branches" --> a "head" is the end of any given
       | "branch"
       | 
       | This makes it a little clearer when talking about detached head
       | state, since switching to a commit on a _branch_ can still leave
       | you detached.
       | 
       | I was confused by that when I got to your detached head
       | description, so I double-checked.
        
         | e40 wrote:
         | > "heads" are "branches" --> a "head" is the end of any given
         | "branch"
         | 
         | and throw "tip" in there, as in "HEAD is the tip of the current
         | branch".
        
         | ryeights wrote:
         | That's not quite right is it? HEAD is simply a pointer to
         | whatever commit is currently on disk.
         | 
         | HEAD _can_ point to a commit that is the end of a branch
         | (typical state, HEAD is "attached"), but it can also point to
         | one that isn't (HEAD is "detached").
        
       | Zigurd wrote:
       | Git has proven to be impervious to designing a discoverable
       | visual UI. All the ones I have used are fine if you understand
       | git. But put a naive user in front of a git GUI and they are
       | almost as confused, just differently. It would be wild if git
       | turned out to be something that just can't be made visual. But I
       | suspect the task of making git n00b friendly was never taken
       | seriously.
        
       | tobyjsullivan wrote:
       | The most valuable step in learning git is having the right mental
       | model: it's all graphs.
       | 
       | This tool gets shared a lot and it feels appropriate here. It
       | visualizes the underlying git model and the effects of various
       | commands.
       | 
       | https://learngitbranching.js.org/
       | 
       | I learned more from 10 minutes with this tool than the preceding
       | ~10 years of git experience. Can't recommend it enough.
        
       | japhyr wrote:
       | I've been using Git pretty much since it came out, and I just
       | learned about "porcelain" this week. I have a project that
       | involves parsing the output of `git status`, and adding the
       | `--porcelain` flag is really helpful. It generates a more concise
       | output that's easier to parse programmatically.
       | 
       | I wondered how many commands have a more machine-readable output,
       | and that led me to the git-scm page "Git Internals - Plumbing and
       | Porcelain". In summary, Git was originally written as a toolkit
       | for dealing with version control, rather than a polished version
       | control system. Many of us who used Git from the early days
       | learned to do VCS work with these lower-level commands, and we've
       | passed those workflows on to many other people as well. This is
       | the "plumbing" layer. Git later developed a more polished layer,
       | referred to as the "porcelain".
       | 
       | I'm not entirely clear yet on which commands are part of which
       | layer, but this helped me make sense of the newer workflows I've
       | seen recommended in recent years. It also gives me a better way
       | of reasoning about possible changes to my own workflows.
       | 
       | https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...
        
         | taocoyote wrote:
         | Literally potty humor.
        
       | ulizzle wrote:
       | This is why I gave up a long time ago and learned to love the
       | GUIs.
        
       | phendrenad2 wrote:
       | Git is so integral to software development, I find it hard to
       | imagine anything else. But I firmly believe that there must be a
       | better way. Whatever people used before git (perforce?) was
       | working fine, let's use that.
        
       | FranklinMaillot wrote:
       | The "Missing Semester" is a collection of video lectures from MIT
       | that covers the fundamentals of command line, git, vim, and other
       | tools often overlooked in computer science courses. As a self-
       | taught developer, I found it to be an ideal introduction to git.
       | 
       | The series made me also pick up vim, and I have not looked back
       | since.
       | 
       | https://youtu.be/2sjqTHE0zok
        
       | sleepybrett wrote:
       | My constant git commandline annoyance is that some commands take
       | remote branches as `origin mybranch` and some take
       | `origin/mybranch` .. maybe there is an arcane reason for this,
       | but I've never seen it.
        
         | qsantos wrote:
         | Because they are referring to different things. `mybranch` is a
         | reference in your local repository. `origin/mybranch` is a
         | reference on a remote repository that you call `origin`,
         | `origin/mybranch` is just a representation of this remote
         | reference for convenience.
         | 
         | So, if we take the example from derefr [1], `git chekcout foo`
         | lets you go to your own local branch `foo`. Then, `git reset
         | --hard origin/foo` modifies the current local ref (`foo`) to be
         | the same as `origin/foo`, and change the working directory
         | accordingly.
         | 
         | [1] https://news.ycombinator.com/item?id=38118475
        
           | permo-w wrote:
           | perhaps I'm misunderstanding, but this doesn't read so much
           | as why as it does a rephrasing of the problem with an example
        
         | zufallsheld wrote:
         | I _think_ origin /mybranch is a ref to a commit that was the
         | current one when you last did a git fetch. `origin mybranch`
         | fetches the latest commit from the origin.
        
         | skeaker wrote:
         | This one gets me constantly even after using Git for nearly a
         | decade. My workflow where I try it one way and then the other
         | is uncannily similar to how most people have to flip a USB at
         | least once to get it plugged in. No idea why it's like this.
        
       | infogulch wrote:
       | I'm watching Jujutsu / https://github.com/martinvonz/jj as a git-
       | compatible wrapper/porcelain that adds some important features
       | and fix a bunch of what is confusing about git:
       | 
       | It explicitly models conflicts, so you can e.g. send your
       | conflicts around and aren't forced to deal with them immediately.
       | 
       | It tracks and logs all repo state including repo operations
       | (checkout, rebase, merge, etc) and those state changes can be
       | manipulated and reverted individually just like commits.
       | 
       | The working copy is automatically committed, and operations
       | typically amend that latest commit. This alone like halves the
       | number of unintuitive concepts new users need to learn. Combined
       | with robust history rewriting tools this makes for a much better
       | workflow.
        
       | tomcam wrote:
       | Come to think of it, "Detached head state" sounds like a line
       | from a 1980s action movie
        
         | Cthulhu_ wrote:
         | Or a Meshuggah or Fear Factory track
        
       | jroseattle wrote:
       | I'd prefer to hear everyone's home-cooked list of aliases to
       | encapsulate all the git command-line funkiness. I'll start:
       | - last: `git log -1 HEAD --stat`       - past: `git log
       | --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]"
       | --decorate --numstat`       - save: `!git add -A && git commit -m
       | 'save'`
       | 
       | (Hat tip to those who helped me with these. I stand on the
       | shoulders of giants.)
        
         | Cthulhu_ wrote:
         | The save command can be rewritten to 'git commit -am "save"'
         | for brevity (caveat: I don't know if -A is different from -a
         | for the two commands).
        
           | xorcist wrote:
           | Not really. It's in the manpage:                 commit -a
           | Tell the command to automatically stage files that have been
           | modified and deleted, but new files you have not told Git
           | about are not affected.            add -A         Update the
           | index[...] This adds, modifies, and removes index entries to
           | match the working tree.
           | 
           | So commit -a won't track new files, but add -A will.
        
       | jheriko wrote:
       | HEAD - something you only need to know about when easily fixed
       | usability bugs in git make your life a misery
        
       ___________________________________________________________________
       (page generated 2023-11-02 23:00 UTC)