[HN Gopher] Git branches are named sequences of commits
       ___________________________________________________________________
        
       Git branches are named sequences of commits
        
       Author : EamonnMR
       Score  : 90 points
       Date   : 2023-02-28 04:18 UTC (18 hours ago)
        
 (HTM) web link (blog.plover.com)
 (TXT) w3m dump (blog.plover.com)
        
       | vhab wrote:
       | The comments in this thread are very interestingly making the
       | Author's point.
       | 
       | Yes, you can be "technically correct" saying branches are just
       | refs, but it's not a useful statement for most users.
       | 
       | I believe the author makes a very valid point, and we could do
       | with a bit less "technically correct" and more with language
       | targeting the usage rather than technical implementation.
       | 
       | Git is confusing enough for many people, and we don't have to
       | make it more confusing for them.
        
         | MrJohz wrote:
         | I wonder if this has more to do with how people visualise
         | commits than branches per se. I think the git UI by default
         | often encourages users to think of commits as diffs. A branch
         | then is a bundle of diffs that, when stacked together, produces
         | the current state of the repository. Internally, git uses some
         | sort of optimisation to make calculating that current state
         | quicker. In this mental model, it doesn't really make sense to
         | talk about a pointer to a specific commit, because a commit
         | without the rest of the information that makes up its branch is
         | useless.
         | 
         | The problem is that this mental model isn't that useful in the
         | first place, and often leads to confusion. Instead, it's
         | usually easier to think of each commit as a complete snapshot
         | of the entire codebase, that includes a link to the previous
         | complete commit that it was made from (which in turn contains a
         | link to the previous commit, and so on). In this scenario, a
         | branch _is_ just a pointer to a given commit - that 's pretty
         | much the easiest way to think about it - and the commit itself
         | is a stack of history. Internally, git optimises for
         | compression by removing redundant information between different
         | snapshots.
         | 
         | In this mental model, thinking about branches as just a
         | different type of tag is easier than thinking about it as a
         | stack of commits, because each commit is already a stack of
         | commits. Moreover, I think the snapshot model often ends up
         | being clearer and easier to use overall. All you need is the
         | basic concepts of snapshots, a linked list, and pointers, and
         | the whole thing kind of just falls into place.
        
           | jameshart wrote:
           | A 'series of snapshots' vs a 'series of diffs' are just duals
           | of one another.
           | 
           | Since you can go back and forth between them at will, it
           | seems odd to claim that one perspective is inherently
           | superior. Like insisting that a chess board is _actually_ a
           | white board with 32 black squares on it.
        
         | metafunctor wrote:
         | I'd argue git is confusing for many people _because_ they don
         | 't understand the data model. The solution is to learn the
         | basic data model instead of pretending that "a branch is a ref"
         | is not true. Because it is true.
        
           | coldpie wrote:
           | For anyone reading this who would like to learn about the
           | data model, I highly recommend following along the "gitcore-
           | tutorial" manpage. Like actually type the commands and play
           | around with the results. Once you understand what's going on
           | under the hood, the UI commands all make intuitive sense.
        
           | jameshart wrote:
           | A branch is not a ref.
           | 
           | A head ref is a ref that _names_ a branch. But branches can
           | exist in git without refs. Branches are artifacts that exist
           | in the commit DAG - they are dangling chains of commits that
           | end without being merged in to some other commit. They
           | _exist_ , as pure platonic branches, even if they are un-
           | referenced.
           | 
           | But then you can make a head ref and _name_ one and now all
           | of a sudden you have a named branch. As you make more commits
           | that extend the branch while 'attached' to that head, the
           | head ref follows the tip of the branch (that is in particular
           | a thing a head ref does that a tag ref does not).
           | 
           | But you can add commits and extend a branch in a detached
           | state of you like - no head refs following the branch tip.
           | Yet the branch definitely exists. And then if you tag it, you
           | name it.
           | 
           | So no, I don't think "a branch is a ref" tells the whole
           | story.
        
         | seba_dos1 wrote:
         | Targeting the usage is exactly what makes git confusing to
         | people. You can start using git just by learning when to type
         | "git add", "git commit", "git push" and "git pull" and you'll
         | manage to collaborate somehow, but it will all fall apart the
         | first time you stumble upon an unfamiliar situation. And
         | because Git's UX isn't great, it's pretty hard to create a
         | right mental model just by using it and inferring from the
         | interface.
         | 
         | If you start by creating a mental model, the confusion goes
         | away. Reminding people that "branch is just a ref" is just a
         | way to push them towards less confusion.
        
           | delecti wrote:
           | This, so much this. Lots of times where I've seemed like a
           | git whiz, it's really just that I've got a _marginally_
           | better understanding of how git really works. Git is much
           | easier to use when you wrap your head around how commits and
           | branches are internally represented.
        
           | Oxidation wrote:
           | Honestly, I think that if "git lol" was the default log
           | command it would do the most to make things much more obvious
           | to newcomers.                 git log --oneline --graph
           | 
           | And git lola for a gestalt of the repo's recent state:
           | git log --oneline --graph --all
        
             | Am4TIfIsER0ppos wrote:
             | If you do that ^ a lot then look at the `tig` tool which is
             | that with an ncurses ui (and some more features)
        
             | seba_dos1 wrote:
             | Just think about how useless and confusing the GitHub's
             | history view is as soon as a merge is involved. Countless
             | times I pulled something from there just to browse the
             | graph because of how unhelpful the web UI is.
        
         | adityaathalye wrote:
         | Yes, I think it's a common case of getting the fact right, viz.
         | branch == just a ref (true), but the understanding wrong, viz.
         | ref == commit (false).
         | 
         |  _A commit_ is an immutable object. Whereas _a ref_ is a
         | pointer, literally a place on disk (a regular file) that holds
         | an address (plaintext SHA) to the latest point in a logical
         | chain of commits.
         | 
         | Meta remark:
         | 
         | This is also what makes it ok to delete a branch after it is
         | "done", and why it is ok to merge a standard working branch
         | (like "develop") repeatedly into a target branch (like
         | release/master/main/trunk).
         | 
         | The semantic / meaning of a branch is transient. It is mutable
         | conceptually and literally.
         | 
         | edit: formatting
        
           | evandale wrote:
           | Sort of an aside, I find it funny that the reflog is named
           | that and not commitlog. With this mental model when you look
           | at the reflog you usually want to get back an immutable
           | commit because you've lost the ref. I know it displays the
           | commits and the refs, but does anyone actually look at the
           | reflog and checkout HEAD@{6} or do they use the commit sha?
        
         | umanwizard wrote:
         | > Git is confusing enough for many people, and we don't have to
         | make it more confusing for them.
         | 
         | Using terms with the wrong definition, and not precisely
         | defining concepts, makes things more confusing, not less.
        
       | satisfice wrote:
       | Some people are really into Git.
        
       | aequitas wrote:
       | When teaching Git I often use a whiteboard with a permanent
       | marker and Post-its for branches. It really brings home the point
       | of the commits themselves being rigid and branches flexible.
        
         | 0cf8612b2e1e wrote:
         | That's a great visual. I am on deck to give a mini git
         | tutorial, and I am stealing this.
        
       | abstrakraft wrote:
       | OP argues that branches aren't "just refs", they're a sequence of
       | commits. I'd argue that a ref _is_ a sequence of commits. (Or, to
       | be pedantic, it uniquely identifies a sequence of commits.)
        
         | [deleted]
        
       | mschaef wrote:
       | I tend to think of branches in git the same way I think about
       | strings in C or lists in (Common) Lisp.
       | 
       | In each of these cases, there's a simpler underlying data
       | structure that's directly overlaid with a set of conventions.
       | It's the conventions on the use of the simpler structure that
       | gives the illusion of some higher order data type.
       | 
       | (The distinction I'm making between these and abstraction in
       | general is that here the abstraction is almost intentionally
       | somewhat leaky - presenting both strengths and weaknesses.)
        
       | comfypotato wrote:
       | This article begs for git manual awareness. I'm fairly certain
       | the author doesn't know the manual exists. It's a short manual.
       | The chapters through branching should be required 1.5 hour
       | reading. It's stupidly simple when it's broken down correctly.
       | (The plumbing chapters are admittedly over my head.)
        
       | davidw wrote:
       | git branches are just a monoid in the category of endofunctors.
       | Did I get that right?
        
       | cybrexalpha wrote:
       | > It's true that Git implements branches as refs, plus also a
       | nebulous implicit part that varies from command to command. But
       | that's an unfortunate implementation detail, not something we
       | should be committed to.
       | 
       | I actually find git way easier to understand if I don't think
       | about branches in the way the author suggests. My mental model
       | for git really is commits and refs, and it helps me use it
       | fluently. When I wave my hands around and say "a branch is
       | nothing but a ref" what I actually mean is "...and so you should
       | understand how it _actually_ works, so what I 'm about to do
       | doesn't look like magic".
        
         | Gunax wrote:
         | I think you and the author are right, but addressing different
         | audiences.
         | 
         | I think most people come to git with their own mental model of
         | what a branch is, what a merge is, etc.
         | 
         | Learning git is often mostly undoing their preconceptions (ie
         | by saying 'a branch is just a ref').
         | 
         | But ultimately, we humans tend to think of a branch as a
         | branch, not a ref. For instance, the previous sentence probably
         | made perfect sense to you.
        
           | topaz0 wrote:
           | I agree, and would add that this is exactly what the OP is
           | saying when it talks about this being a communication issue.
           | Saying "a branch is just a ref" is the right attitude for
           | talking to git and making it do what you want it to do, but
           | it's the wrong attitude when you are writing or talking about
           | code, in which case branches are the reification of the
           | processes by which your code evolves.
        
           | edflsafoiewq wrote:
           | Do they? I certainly had no intuitive notion of how version
           | control would work before I learned git for the first time.
        
       | totorovirus wrote:
       | I thought git branch is an alias to specific commit...
        
       | expazl wrote:
       | It reads a bit like the author has a misconception of what
       | commmits are. A commit is not a diff, it's a snapshot. All of the
       | talk about branches containing changes etc, make sense in the
       | context of it being a reference to the latest snapshot. And yes
       | it might not make sense if you think of a branch as a reference
       | to the latest difference, but this is a misconception.
        
         | tantalor wrote:
         | Came here to say this. Commits on a branch should be as easy as
         | "save file". You shouldn't put commit messages on them other
         | than something like "snapshot 3". Nobody cares about the
         | commits on the branch.
        
           | justinclift wrote:
           | That sounds weird to me, as commit messages in a (side?)
           | branch are just as useful as commits on the main development
           | branch. eg very, as they describe what that change did
           | 
           | Maybe the only time I'd scenario I'd agree with you though,
           | is when I'm just creating a commit to capture a temporary
           | development state (eg WIP) on the way to some development
           | objective. That's not very often though.
        
           | slaymaker1907 wrote:
           | For certain changes, a clean branch history can be very
           | valuable during review. For example, if you had some feature
           | which was rolled back due to bugs, a new branch with the
           | feature plus the fixes should have the original (buggy)
           | feature as the first commit(s) with no other modifications so
           | that people can clearly see what was done to fix the original
           | bugs and what was in the original code.
           | 
           | However, you can fix things up when ready for review by just
           | rebasing things into a coherent sequence of commits. I really
           | wish there was a good autocommit/push feature in Git that
           | would help back things up but continuously rebase and compact
           | old autocommits.
        
         | comfypotato wrote:
         | The author has written more about git (see the link at the
         | bottom) than there is in the git manual. Do they... do they
         | know there's a manual?
        
       | brianpan wrote:
       | I'd argue that there's a difference between a git branch (an
       | implementation detail) and a development branch (a process
       | feature) and that's the difference the author is running up
       | against.
       | 
       | Are you teaching someone about development? Or teaching about
       | git? Because a git branch IS a ref. And a git branch is useful
       | because it points at a commit in a series of commits. Branches
       | and commits are slightly different concepts depending on your VCS
       | and it can be worth understanding the details.
        
       | dataflow wrote:
       | I feel like I have a bigger problem with "a sequence of commits"
       | as a phrase than I do with whatever he wishes to call a branch. A
       | commit _itself_ is a sequence (it includes its own history!), so
       | a sequence of a sequence is a confusing thing to talk about
       | without any sort of qualification, since they 're heavily
       | constrained by being linked together. Moreover, what he's calling
       | a sequence is really a DAG; it's not linear. Hearing "a sequence
       | of commits" is so jarring that it conveys more confusion about
       | git than anything else... perhaps that's why he gets corrected so
       | often?
       | 
       | But in terms of what a branch is, if you don't want to call it a
       | "ref", then I'd just say it's a commit symlink?
        
         | LegionMammal978 wrote:
         | Hmm, I think you'd be going a bit far by calling each commit a
         | sequence. A commit does not contain its parent commits: it only
         | contains pointers to its parent commits. By that logic, a
         | linked list isn't a sequence of nodes, since each node is
         | itself the head of a sublist.
        
           | dataflow wrote:
           | The pointer isn't really relevant to what I'm sharing. I'm
           | talking about what it is logically, not how it might be
           | represented physically. You could certainly make each commit
           | contain the other one physically if you wanted to represent
           | it that way in some programming language. Of course there's
           | not much of a reason to, and it'd be annoying since they'd be
           | different sizes, but it's not like your have infinite
           | recursion or something preventing you from doing that.
           | 
           | What I meant is something else though. A linked list is a
           | _linked_ sequence of nodes (or a chain of nodes, if you wish
           | to call it that). A branch is a _linked_ DAG of nodes, if you
           | wish to call it that. Calling a branch a sequence of commits
           | feels like calling your extended family (or I guess your
           | genealogy)  "a sequence of people" - it misses some crucial
           | aspects of the structure and just sounds very confused.
        
       | _ZeD_ wrote:
       | [insert obligatory mercurial comment here]
        
       | [deleted]
        
       | berjin wrote:
       | It's a shame Mercurial became a betamax since it's much more user
       | friendly.
        
         | sinistersnare wrote:
         | How does Mercurial differ in this way? I always figured
         | mercurial was just a 'better UI', but using similar internals.
        
       | beej71 wrote:
       | A "branch" is two things. In git, it's the ref. To humans, it's
       | the ref or the chain of commits under it.
       | 
       | Both of these have their place, I feel.
       | 
       | When thinking about commits to a branch, humans (I speculate)
       | tend to imagine the branch as a sequence of commits.
       | 
       | But when operating on the branch ref itself, like when you delete
       | it, you should be very clear that you're not deleting commits.
        
         | [deleted]
        
         | mirekrusin wrote:
         | Branch is ref. Chain of commits is distance between two
         | commits/refs/their first common commit (branch point). If
         | people working on the repo branch off main branch 99% of time,
         | its meaning is quite straight forward. If they branch of a
         | branch, it's also obvious what it is. As branching point is
         | always defined so is equivalence between those two.
         | 
         | What's the point in arguing about it? It's a bit like arguing
         | if `Line = { a: Point, b: Point }` is a line or two points.
        
           | voxic11 wrote:
           | There is no need for a "branch point" you can create multiple
           | "branches" that are just references to different points on
           | the same linear sequence of commits.
        
             | yamtaddle wrote:
             | You can have branches that are and have always been
             | entirely disconnected from one another, for that matter.
             | With completely different content, but still in the same
             | repository.
        
               | jononor wrote:
               | Quite rare in practice though. Only case I have had that
               | is gh-pages branch in a GitHub project repository, which
               | contained only generated artifacts (generated by code in
               | master). Which I believe there are better ways to do now.
               | At least with Gitlab one instead uses a "pages" CI job,
               | triggered from master, and the artifact it produces is
               | the contents that will be hosted.
        
         | chrisjc wrote:
         | > A "branch" is two things. In git, it's the ref. To humans,
         | it's the ref or the chain of commits under it.
         | 
         | Isn't that true of a git tag too?
        
           | jameshart wrote:
           | A head ref is a kind of ref that, when you 'attach' to one as
           | the current HEAD, has useful semantics for managing branches.
           | 
           | A tag is another kind of ref that.. doesn't have those
           | semantics.
           | 
           | When you fetch a remote and it disagrees about a head ref,
           | you need to do some sort of merge.
           | 
           | When you fetch a remote and it disagrees about a tag ref? The
           | remote wins.
           | 
           | Because one of the things git is trying to do is help you
           | _manage source code_. Which means that it has to help you
           | manage branching sequences of changes in a commit DAG.
           | 
           | Git doesn't just have an arbitrary set of ref semantics
           | chosen at random - it has head refs which behave in a very
           | particular way to help with branching, and it has tag refs
           | which behave in a way that is useful for versioning.
           | 
           | So that's why I think 'a branch is just a ref' is a reductive
           | take.
           | 
           | Git has a thing called refs that it uses for various
           | purposes. Git provides tools for naming and working with
           | named branches based on creating head refs. As far as many
           | parts of git (that deal with arbitrary refs, whether they be
           | heads or tags or remotes or whatever) go, sure: they can work
           | with (the heads of) branches because branches are named using
           | head refs.
           | 
           | But as far as humans wanting to do things with branches are
           | concerned, 'branches are just refs' isn't helpful they don't
           | want to do a thing to a ref, they want to do a thing to a
           | branch _of the commit DAG_ , so they need to know 'how do I
           | get git to do this thing with the commits that are part of
           | this branch?', and saying 'a branch is just a ref' doesn't
           | answer that question.
        
       | p-e-w wrote:
       | I wish we had a version control system that can be used without
       | worrying, or even knowing, about its technicalities and
       | implementation details.
       | 
       | Working with Git for version control is as if your photo
       | management tool required you to learn about inodes and b-tree
       | superblocks in order to save a JPEG file. I just want to keep
       | source code history, and allow multiple people to collaborate on
       | the same project. I don't want to know anything about "refs" or
       | whatever else is happening behind the scenes, yet it appears Git
       | can't be used unless you are (at least occasionally) willing to
       | look at the plumbing layer.
        
         | ozim wrote:
         | My view on it is that unfortunately there is no way to do that.
         | Some things are going to be hard and that is it, you cannot
         | make it easier. We see that in never ending stream of
         | frameworks or "new/better/easier" ways which in the end become
         | bloated in the same ways as most other stuff because problems
         | don't go away if you don't know about them.
         | 
         | In the end data model of git is its killer feature because it
         | gives me tools to deal with hard problems and do it
         | efficiently.
        
           | comfypotato wrote:
           | I always feel that complaints like the one you're replying to
           | aren't thought through. The simple follow up is: how would
           | you do it better? There's no better way. You only need to
           | look at the complicated part of git for very complicated
           | things. If you think about it, commits and branches are
           | incredibly simple relative to what's actually happening (when
           | it comes to working with them, that is). Listening to old
           | folks talk about pre-git version control gives me
           | appreciation for just how good it is.
        
             | OkayPhysicist wrote:
             | There are a few fixes I would make, but only a handful
             | would be significant to everyday usage, none would involve
             | fundamentally changing the underlying data model. The
             | biggest would probably be to make all commits required to
             | be made onto branches and either embed the data of what
             | branch created a commit into the commit itself, or have a
             | separate data store of branch-to-commit info, which would
             | allow for "branches as a series of commits" to be a first
             | class citizen besides "branches as references to a commit".
             | Maybe add git notes-esque support for editable metadata on
             | the branch, where you could put information that currently
             | would be stored in some pull request management system.
        
         | somat wrote:
         | I use the heck out of fossil and have little idea how it works
         | underneath. I consider fossil the gold standard for a good
         | versioning system ui. I don't think git has any excuse for
         | being as weird as it is.
         | 
         | fossil init repo; make a new fossil repository
         | 
         | fossil open repo; open a fossil repository somewhere
         | 
         | fossil add file; note: very different than git add. in fact I
         | was very confused by git add, in fossil the repository knows
         | what files are managed by it and there is no staging area. so
         | you only use "fossil add" when adding a new file. If you move a
         | file use "fossil mv" to let fossil know what you did. Along
         | with "rm" when you remove a file. The staging area still feels
         | like an unnecessary added bit of friction.
         | 
         | fossil commit
         | 
         | There are others I use often "merge", "sync", "revert" but they
         | tend do what the command appears to do. Speaking of revert, the
         | git equivalent is really strange , even among the rest of the
         | strange git ui. Shit! I messed something up and want to revert
         | back to the last committed change, easy, just run the command
         | "git reset --hard HEAD"
        
           | seba_dos1 wrote:
           | How do you choose which changes go into a commit and which
           | don't without an equivalent of a staging area?
        
             | somat wrote:
             | I don't use git a lot, so I am not all that familiar with
             | it's work flow. But I think fossil assumes a change will go
             | into the commit so you use the stash command to hide items
             | you don't want in. while git assumes a change does not go
             | in a commit so you use add on files that you want in.
             | 
             | A bigger question is what to do when you only want specific
             | chunks from the diff in your commit. I tend to faff around
             | with stash, interactive sdiff and hand editing the patch
             | when I need to dissect a chunk, a situation I feel could be
             | better.
        
           | KRAKRISMOTT wrote:
           | The bad thing is that fossil allows the upstream to make
           | destructive changes to client's copy of code. That's a big no
           | no.
        
             | somat wrote:
             | So does git, in fact, without a better explanation of what
             | exactly you mean, I would say upstream making changes to
             | the the clients code is the core useful property of a
             | version control system.
        
             | owyn wrote:
             | Until you need it. :)
        
           | osigurdson wrote:
           | git init .
           | 
           | git add file
           | 
           | git commit -am "my message"
           | 
           | Pretty simple really. You don't need to think about staging
           | if you don't want to.
        
             | dataflow wrote:
             | Is that a typo or intentional? If you did git add, you
             | don't want commit -a, right?
        
               | osigurdson wrote:
               | "git add" is used in this context to add an untracked
               | file (like the fossil example).
               | 
               | git init .
               | 
               | vi file (initial content)
               | 
               | git add file
               | 
               | git commit -am "first commit"
               | 
               | vi file (make changes)
               | 
               | git commit -am "second commit"
               | 
               | Basically if you use commit -am, you never have to worry
               | about staging - which is most of the time imo. In the
               | rare case where you want to avoid committing something
               | that has changed use git add to stage individual files.
        
               | seba_dos1 wrote:
               | I believe these were supposed to map to what its parent
               | comment has listed.
        
         | graypegg wrote:
         | Version control feels like it does require some complexity
         | though. I think we all like to imagine that all it does is
         | stores changes per file, wrapped in commits.
         | 
         | But when you add requirements like merging other people's work
         | with yours, movable "tags" to mark named versions, and the sort
         | of cut/splice/move around operations you will always need
         | because you accidentally did something you shouldn't have... I
         | think you end up rebuilding most of Git's plumbing.
        
           | p-e-w wrote:
           | Video codecs are also complex (actually, they are almost
           | unimaginably complex). But I've never seen a smart TV telling
           | the user something about "lapped transforms" or "chroma
           | subsampling".
           | 
           | I'm a _user_ of Git. Why do I have to learn about
           | implementation complexities in order to fix problems that
           | arise from normal version control operations?
           | 
           | I can't think of any other software that forces me to do
           | this. Even compilers (at least those for mainstream
           | programming languages) don't require me to understand their
           | AST representation or other details of how they work
           | internally.
        
             | taeric wrote:
             | Televisions absolutely do this for power users. Or give
             | them terrible image quality for regular users.
        
             | buck4roo wrote:
             | When it comes to tools you use every day, everyone _should_
             | be critical. Does this tool decrease my workload? or do I
             | need to expend extra work just to operate it?
             | 
             | I'm a _user_ of mercurial. I 've learned enough git to know
             | it's an inferior tool. git's CLI complexity (and mental
             | model) is patent overkill for 99.9% of all users.
             | 
             | Mercurial gets out of my way.
             | 
             | I'm able to clone and push git repos with it just fine
             | (thanks hg-git!)
             | 
             | This is because both (git,hg) are tools that manipulate the
             | same simple data structure: the DAG.
             | 
             | hg CLI's verbs match my mental model from decades of use of
             | other VCS's _. I 'm able to perform my daily tasks with
             | simplicity (including n-way merge/cherry-pick tasks that
             | git "expert" colleagues often struggle with).
             | 
             | My 2C/.
             | 
             | _ I've used local (SCCS, RCS), client-server (CVS,
             | subversion, perforce) and distributed (bazaar, git, hg)
        
             | graypegg wrote:
             | WildBit had a really cool project a while ago called
             | Conveyor. [0] It's a shame it never took off.
             | 
             | It was built on git, but hid the complexity of branching +
             | other git things behind "tasks". You'd start a task, and
             | silently push that branch out to everyone. It'd silently
             | merge things in the background and handle a lot of the
             | chores you have to do with git rebasing and such to keep
             | branches mergeable.
             | 
             | It failed miserably with us because it perpetually created
             | impossible to solve git issues. Someone accidentally
             | removes a gitignore file and commits a config file with a
             | password? Your SOL. It will keep coming back because it
             | will exist on at least one other person's device which will
             | get force pushed back to the repo.
             | 
             | The weird plumbing exists because version control is hard,
             | and prone to humans throwing wrenches into its nominally
             | perfect system.
             | 
             | The real reason you don't remember every magic git
             | incantation is because you normally only need a specific
             | one, once a year. But it has to be there!
             | 
             | [0] https://web.archive.org/web/20190226201600/https://conv
             | eyor....
        
             | theamk wrote:
             | TVs are consuming devices. If you are only wishing to
             | consume git, you need to know "git clone" and "git
             | checkout", and that's it, no need for internals. Or manybe
             | not even that, you need to know where "download" link on
             | Github interface is.
             | 
             | If you are encoding video, you often need to know about
             | chroma subsampling, and colorspaces, and fractional
             | framerate and all the other absurd technical details. It is
             | actually much worse than git.
             | 
             | You can avoid those technical details if you use high-level
             | software, only stay on happy path, and avoid any complex
             | operations. You'll take longer and produce worse quality
             | output than if you had fully mastered the software -- but
             | often this is OK.
             | 
             | This is true both for video encoding and for git.
        
             | danaris wrote:
             | Git is a fundamentally different kind of tool than a video
             | codec, and I don't think comparing them is particularly
             | helpful.
             | 
             | I agree that Git could be a bit more internally consistent,
             | and have a few more convenience shortcuts for very basic
             | usage. But I can also see a strong argument that, as part
             | of the Linux ecosystem, that's a perfectly good opportunity
             | for someone who wants to build a wrapper around Git (and I
             | believe many have).
             | 
             | It seems to me that unless you really only want to use Git
             | in the _most basic way possible_ (add all your changes
             | every commit, never roll anything back, single branch, no
             | stashes), understanding something of Git 's internal model
             | is less like understanding how the compiler's internals
             | work, and more like understanding the fact that a C program
             | needs to be compiled into object code and potentially
             | linked into an executable before it can be run.
        
         | kaba0 wrote:
         | People mention previous gen version control systems in sibling
         | comments, but git quite clearly "won" against them. A more
         | useful outlook would be looking for what the next gen VSC might
         | be, which would be Pijul and alia (where diffs/patches are
         | applicable in any order, so merges will be trivial, no more
         | merge strategies), and if they do get production ready they
         | might really provide a better UX/more intuitive mental model
         | for the programmer.
        
         | rjbwork wrote:
         | We do, at least to my mind. It's called Mercurial. It's great,
         | extremely close to git, but is much easier to use IMO. It's
         | really a damn shame that git won - primarily, I think, due to
         | the cachet of its author.
        
           | shanev wrote:
           | Close. It won because of Github. Git was gaining over SVN
           | slowly but it was Github that really propelled it into
           | widespread use.
        
           | dilyevsky wrote:
           | The way I remember it git one for two reasons: 1. hg was
           | (maybe still is?) much slower 2. "No technology can ever be
           | too arcane or complicated for the black t-shirt crowd" (fake
           | Linus's words not mine)
        
             | gregjor wrote:
             | I think you're quoting me. Thanks!
             | 
             | https://typicalprogrammer.com/linus-torvalds-goes-off-on-
             | lin...
        
           | bigDinosaur wrote:
           | Either way, is Git actually that hard to use? You can learn
           | about 10 commands and develop any software just with those. I
           | have no illusions about it's gnarly aspects but also just
           | don't find it particularly difficult. Contrast a programming
           | language that might have footguns in just printing strings.
        
             | photonbeam wrote:
             | Git is a pain to provide support for if you're an internal
             | tools team, lots of users with incorrect mental models
        
         | Agentlien wrote:
         | Why do you feel you need to know these details?
         | 
         | I used git actively without issues for years before I took the
         | time to learn how it works under the hood. While understanding
         | the details was fun and helpful, I can't say it really changed
         | much about how I use the tool.
        
         | OkayPhysicist wrote:
         | It's version control for software developers, who
         | simultaneously need all the power it provides, and ought to
         | have the educational background to understand directed acyclic
         | graphs. Complaining that git is too complicated because it
         | requires basic knowledge of DAGs is like complaining that your
         | word processor is too complicated because it assumes a
         | proficiency in written language.
        
         | bad_username wrote:
         | Linus built an incredibly elegant and simple underlying model
         | for git. For what it successfully does - distributed version
         | control - it is remarkably simple and easy to grasp if you want
         | to.
         | 
         | However, this model was not mapped well to the high level
         | concepts that the typical user of a VCS operates in. This is
         | the biggest issue of git: it's hard to make sense of it by its
         | UI if you do not understand how it works under the hood. I
         | struggled until I read the pro git book.
         | 
         | I wouldn't go as far as to compare this to knowing about
         | filesystem data structures for saving a jpeg file. It's more
         | like using an old school file dialog where you just see the
         | bare file system and you need to know your way around your
         | drive.
        
           | josephg wrote:
           | Git's other (compounding) problem is how the CLI is an
           | inconsistent mess.
           | 
           | Why do you create a branch via the "git checkout" command?
           | Why do you delete tags using "git tag -d" but delete stashes
           | using "git stash drop"? If you want to blow away local
           | uncommitted changes, you can use "git reset", "git reset
           | --hard" or "git checkout (file)" - which (I think) all do
           | totally different things.
           | 
           | Git's data model may be elegant, but its hard to appreciate
           | it through the tangled mess of git command line options.
        
             | foresto wrote:
             | One of my favorite examples of this is the cache. I mean
             | index. I mean staging area.
             | 
             | Sigh.
        
               | OkayPhysicist wrote:
               | How else would you support breaking up a change into
               | multiple commits?
        
             | Nadya wrote:
             | I use Git daily and literally couldn't tell you how to use
             | it because I've aliased every single command it has. I
             | basically have a wrapper over it and to teach anyone how to
             | use Git I have to peel my layer away and check what I have
             | things aliased to.
             | 
             | It feels like terrible ad hoc user design built over an
             | otherwise extremely elegant and clean data model.
        
               | freetonik wrote:
               | Would you mind sharing your aliases? Curious to see a
               | different mental model.
        
             | amadvance wrote:
             | They tried to fix that mess, like with the recent git
             | switch/restore. But it looks like it was too late.
        
             | sampo wrote:
             | > Why do you create a branch via the "git checkout"
             | command?
             | 
             | Now there is also `git switch --create` / `git switch -c`
             | for this.
             | 
             | Perhaps in time, there will appear different front end
             | dialects for git. Like the statistics programming language
             | R has the base R language, data.table dialect, and the
             | tidyverse dialect.
        
             | jolmg wrote:
             | > Why do you create a branch via the "git checkout"
             | command?                 git checkout -b foo
             | 
             | is just a shortcut for                 git branch foo
             | git checkout foo
             | 
             | > Why do you delete tags using "git tag -d" but delete
             | stashes using "git stash drop"?
             | 
             | That _is_ inconsistent. One has an interface of `git
             | <thing> <options-to-manage-thing>` and the other `git
             | <thing> <subcommand-actions-for-thing>`. I imagine what
             | happened is the former was the original and was probably
             | thought to be sufficient, but then it wasn't for `stash`
             | and the latter was introduced for more flexibility. The
             | inconsistency is probably from backwards compatibility.
             | 
             | It might be worth noting that, at least as far as I know,
             | git was like the first to use or at least popularize
             | subcommands. It'd be understandable if they didn't include
             | support for sub-sub-commands from the get-go.
             | 
             | > If you want to blow away local uncommitted changes, you
             | can use "git reset", "git reset --hard" or "git checkout
             | (file)" - which (I think) all do totally different things.
             | 
             | git-reset is mainly about resetting the branch, index,
             | and/or working tree to a given ref. git-checkout is mainly
             | about checking out a ref, setting HEAD and syncing the
             | working tree to it. They're different things with an
             | overlap. I would say that's not really inconsistent. It
             | would only appear so when one only learns specific patterns
             | of commands for subsets of their function, like "blow away
             | local uncommitted changes", which in this case fits in
             | their overlap.
        
               | josephg wrote:
               | That can all be true, but it doesn't make git any less of
               | a nightmare to learn. Even very experienced git users
               | make mistakes and need to google things all the time. Its
               | become almost a trope at multiple places I've worked that
               | even once in awhile someone makes a mess of their git
               | repository, and needs to call for help from one of the 2
               | people in the entire office who understand git enough to
               | unbreak it.
               | 
               | Another annoying inconsistency: git tag prints a list of
               | tags. Git branch prints a list of branches. Git commit
               | prints ... modified files? And git stash _modifies the
               | stash_. You need git stash list to see the stash. What!?
               | 
               | I get it; its a complex tool. Its managing 4 different
               | storage areas for your code (the repository, the staging
               | area, the index and the stash). It also manages tags,
               | branches, remotes and configuration. And it has multiple
               | networking interfaces.
               | 
               | But I can't escape the conclusion that its just not a
               | very good user interface. A good interface wouldn't be so
               | hard to use. Redis is more complex, but I don't make so
               | many mistakes using the redis cli. Awk is more powerful -
               | but its much more intuitive. And cargo probably has more
               | subcommands than git does, but I don't get lost in them.
               | Git? Git is a mess.
        
             | Oxidation wrote:
             | I know what you mean (deleting a branch in a remote is a
             | very unintuitive syntax to me at first glance, especially),
             | but these are perhaps not the best examples:
             | 
             | > Why do you create a branch via the "git checkout"
             | command?
             | 
             | That's a shortcut for "git branch (name)", then "git
             | checkout (name)". Or the newer "switch" which is more
             | obvious.
             | 
             | > Why do you delete tags using "git tag -d" but delete
             | stashes using "git stash drop"?
             | 
             | Because the stash is more like a stack, and tags are not,
             | so "drop" without a parameter is a valid and very usual
             | command. Yes, it feels inconsistent, but allowing "git
             | stash -d" without a parameter would probably not be better.
             | 
             | > If you want to blow away local uncommitted changes, you
             | can use "git reset", "git reset --hard" or "git checkout
             | (file)" - which (I think) all do totally different things.
             | 
             | These do all do different things, so that's why they all
             | exist. "git restore (file)" was introduced a few years ago
             | (with "switch", mentioned earlier) to make the last one
             | more obvious, since that's indeed always been an
             | uncomfortable syntax for a core operation.
             | 
             | Git's a very powerful tool, originally aimed at a very
             | complex code base run by experts, and was written very
             | quickly as an emergency replacement for BitWarden. This
             | rushed development and target audience does show through
             | even today, but it's being annealed over time.
             | Nevertheless, it's so good at what it does that it's taken
             | out nearly every other VCS by just existing (ok, and the
             | network effects of GitHub, but they choose it for a reason
             | too).
        
               | martijnvds wrote:
               | BitKeeper was the version control system.
               | 
               | Bitwarden is the password manager.
        
           | lmm wrote:
           | So what's the underlying model that makes the staging area
           | make sense? Why does stash followed by unstash leave my
           | checkout in a different state from what it was before?
        
             | kevin_thibedeau wrote:
             | Staging is useful for gradually queuing up multi-file
             | commits rather than listing them all in one command. It
             | becomes even more useful with partial file commits.
        
               | lmm wrote:
               | I know, but that's not what I was asking.
        
             | JonathonW wrote:
             | The staging area is where you construct your next commit--
             | giving you a middle ground between your changes in your
             | local working copy and the last actual commit so that, if
             | you don't want to commit _everything_ that you've changed
             | in a single commit, you can do that.
             | 
             | (If you always want to commit everything you've changed,
             | you can do that too-- always commit with 'git commit -a'
             | and only use 'git add' when dealing with new files that you
             | want to add to version control.)
        
               | iggldiggl wrote:
               | Hmm. With Mercurial I just use "commit --interactive" if
               | I only want to commit part of my changes, and I always
               | found that more intuitive and less confusing than having
               | to mentally keep track of Git's staging area as well.
        
               | OrderlyTiamat wrote:
               | The git analogue to that would be `git commit
               | --interactive`, or using `git status` to check the
               | staging area while using `git add`. Keeping mental check
               | of it is the worst solution imho.
               | 
               | You can also have your git porcelain handle it. Magit for
               | example has a great interactive overview of unstaged and
               | staged changes. When I need to do something more picky
               | than just commiting every change, I'll usually grab magit
               | to stash individual chunks: I don't necessarily want to
               | commit all changes in a file, sometimes I want individual
               | lines.
               | 
               | You can do that with staging using the commands above,
               | magit, or some other porcelain (I've heard good things
               | about git kraken). If you really want to forget staging
               | even exists, you could just commit straight up and amend
               | the commit afterwards to get a comparable experience I
               | guess. I've found staging to be helpful in keeping track
               | of what I've achieved for my next "version" of the
               | software to be added to the history, which is why I'm
               | still using it.
        
               | graywh wrote:
               | or `git add -p` to interactively stage changes
        
               | lmm wrote:
               | I know. None of that answers my question.
        
         | taeric wrote:
         | You've clearly never tried to save raw image files from a mid
         | level camera. :) heaven help you if you try a newer camera than
         | your os.
         | 
         | I will make no major defense of git, but I am intrigued at the
         | level of difficulty reported about it, compared to the
         | obviously higher level of use that it gets.
        
           | ansgri wrote:
           | What kind of cameras and difficulties are you talking about?
           | It's almost always just a DCIM folder on the sd card.
           | 
           | Videos, OTOH, are stored rather arcanely, at least on my
           | Sony, with separate directory structure for each format.
        
             | taeric wrote:
             | Newer cameras have had raw formats that were not supported
             | right away. Cr3 being the one that bit me recently.
             | 
             | I think most software has caught up. But it did catch me
             | off guard that my machine needed updating to support this.
             | I also think flatpak had some trouble with it. Can't
             | remember details.
        
               | ansgri wrote:
               | Ah, you're talking about actually using them, not just
               | saving :)
        
               | taeric wrote:
               | Little of both. Took me a few tries to get them
               | recognized as pictures. Rather frustrating experience,
               | all told.
        
         | seba_dos1 wrote:
         | "refs" are not behind-the-scenes things, they're the things you
         | want to operate on. It wouldn't be like having to learn JPEG
         | superblocks, it's more like learning what a pixel is.
         | 
         | You need to understand Git's data model, _not_ its plumbing. No
         | VCS will be useful for anything that isn 't trivial if you
         | don't understand its data model.
        
           | Gunax wrote:
           | I disagree. We shouldn't have to know _how_ a branch or
           | commit is stored. Whether git interally makes a new ref,
           | copies everything to a new directory, or does some hashing
           | magic doesn 't matter to the user.
           | 
           | I agree that we end up needing to know about refs because of
           | git's user interface, but I consider that a flaw or
           | limitation.
        
             | seba_dos1 wrote:
             | It's not about "how a branch is stored". We're not talking
             | about objects, packs, blobs or any other stuff I never
             | actually had to learn about while using git. We're talking
             | about refs - the primary way for users to reference commits
             | and other things in git. Just about every command you use
             | takes refs as arguments. It's essential to even just
             | imagine the state of the repository in your head. It's what
             | the first tutorial you read about git should explain to
             | you.
        
         | aaronbrethorst wrote:
         | There's something funny to me about the idea that the user-
         | level Git commands are called the "porcelain," as if they were
         | a toilet. https://stackoverflow.com/a/6976506
         | 
         | unrelated: I wish people would stop insisting on using full-
         | width columns to display their blog content because it is
         | nearly impossible to read on a 27" monitor.
         | 
         | Wrap that blog content with a                   <div
         | style='max-width: 65ch'>
        
           | thiht wrote:
           | > I wish people would stop insisting on using full-width
           | columns to display their blog content because it is nearly
           | impossible to read on a 27" monitor.
           | 
           | There's a noticeable portion of tech people who seem to
           | believe that unused screen space is somehow wasted. No
           | margins + no line breaks is the gold standard to them.
           | 
           | I don't get it, it's unreadable to me.
        
         | xorcist wrote:
         | All abstractions leak.
         | 
         | You cannot work your jpeg photo collection but opening,
         | editing, saving, editing, saving, editing, saving and then
         | blame your tools when your jpegs are blocky and ugly.
         | 
         | First you have to know some basics about lossy compressing and
         | destructive editing. Then, you can understand what steps you
         | really want to take.
         | 
         | It's the same with version control systems. With git, first you
         | have to understand what a commit and a branch is. Then, you can
         | work.
        
         | cratermoon wrote:
         | If there's a UI, or even a CLI, that properly matches the
         | conceptual model of development with git, I'm not aware of it.
         | I'm sure there's a much clearer user-centric model of work
         | struggling to get out from underneath the implementation
         | details. Over the years of working with git I've gradually
         | learned bits of the plumbing underneath the porcelain, but
         | reluctantly.
        
         | thunderbong wrote:
         | That's why we use fossil [0]. It just gets out of the way. It
         | has its own server, wiki, ticket system and now, even chat!
         | 
         | The main complaint I see here is that it doesn't have rebase,
         | and my point is the goal of the code is for the product to
         | work, not to have a beautiful commit graph.
         | 
         | I've used CVS, SVN, Git. But nothing comes close to the
         | usability that fossil provides.
         | 
         | [0]: https://www.fossil-scm.org/
        
           | vbezhenar wrote:
           | Beatiful commit graph allows to actually understand commit
           | history. I dread opening history with merges. It's always
           | incomprehensible mess for me.
        
       | OJFord wrote:
       | I think you can be technically accurate ('branch is a named ref')
       | and still have the same mental model of branches described.
       | 
       | A commit, specifically _its_ ref, is already encoding the
       | 'sequence of commits' that led to it - viz. it knows its
       | parent(s).
       | 
       | A branch is a named pointer to one of those then, and 'nothing
       | more', but that is already a sequence a commits.
        
         | Oxidation wrote:
         | > and 'nothing more'
         | 
         | Also it "follows along" when you commit to the branch. Named
         | pointers that stay put are tags.
        
         | bigiain wrote:
         | It seems to me that "a branch is just a ref" is important
         | knowledge to anyone developing git software or any other
         | software that interacts directly with the files in a git repo.
         | 
         | For pretty much every other developer who's just using git for
         | source control, "a branch is a named sequence of commits" is a
         | much more useful way to understand them. I don't want to think
         | about the implementation details of how git internally
         | represents a branch any more than I want to think about
         | whatever's going on inside a word .doc when I add a table into
         | my document. The important thing is my branch (or table) works
         | the way I and everybody else expects it to work.
         | 
         | (It's good to have at least one person on your team who
         | understands both those concepts deeply, as the obligatory xkcd
         | explained...)
        
       | draw_down wrote:
       | It's not helpful to say branches are only refs as a way of
       | arguing branches don't exist. But it is helpful in understanding
       | how they work, what it means to pass a branch argument to git for
       | some operation.
       | 
       | When I understood the reflog and how nothing I do is really gone
       | (just gotta find it!), that was when I realized how much I like
       | git.
        
         | littlestymaar wrote:
         | > When I understood the reflog and how nothing I do is really
         | gone (just gotta find it!), that was when I realized how much I
         | like git.
         | 
         | The reflog won't help you recover things in the staging area
         | that where accidentally `reset --hard` though ... (you can
         | still get the ones you added to the index with `git add` but
         | not committed[1], but changes that weren't added are lost for
         | good)
         | 
         | I love git, but the UX is still terrible ...
         | 
         | [1]: https://stackoverflow.com/questions/7374069/undo-git-
         | reset-h...
        
           | seba_dos1 wrote:
           | The reflog also won't help you recover things you manually
           | delete before you `git add` them. Or that were outside of the
           | git repo. Or that you written on a piece of paper that you
           | threw away.
           | 
           | To someone who has a right mental model of git, all of these
           | should be just as obvious. If you didn't stage your things,
           | they were never in your repo.
        
             | littlestymaar wrote:
             | > Or that were outside of the git repo. Or that you written
             | on a piece of paper that you threw away.
             | 
             | Those aren't useful analogies as git cannot remove them in
             | the first place. It's normal for a user to expect a tool to
             | have an "undo" mechanism for its commands (with a prompt
             | "this action is irreversible, do you want to proceed" for
             | the rare actions where the action _have_ to be destructive,
             | like when running the git garbage collector manually)
             | 
             | I know exactly _why_ git behaves like it does, but that
             | doesn 't make its footgun less of a nuisance. And it's all
             | about the UX, there's zero technical reason that would
             | prevent git from saving your work as a temporary commit
             | before deleting it, in a way that would make it
             | recoverable, just a lack of user empathy.
        
           | draw_down wrote:
           | [dead]
        
           | buck4roo wrote:
           | Why do you love it?
           | 
           | It looks like you've described a tool with 1) a terrible UI,
           | and 2) trains users to use commands that will eventually
           | cause them to lose unsaved work.
        
             | littlestymaar wrote:
             | 1. git has a terrible UX (not UI), including destructive
             | actions without warning and much more really cumbersome
             | things for newbies to learn about
             | 
             | 2. once you know it enough, git is a powerful tool that I
             | really appreciate.
             | 
             | 1. and 2. aren't contradictory. And I would love git even
             | more if the UX wasn't the dumpster fire it is, but I happen
             | to know enough of its bad UX to be able to do what I want
             | with it.
             | 
             | Also, unlike the average git expert on HN, I still
             | recognize that the UX is shit, and that you should need to
             | spent as much time as I did in order to be able to use it
             | at all. I'm really annoyed when people argue that a bad UX
             | is in fact good because of some elitist reasoning.
        
             | draw_down wrote:
             | [dead]
        
       | roboben wrote:
       | I am not saying a branch is nothing than a ref, I am saying there
       | are only refs in git and this is the powerful part of it because
       | being so arcane and simple makes it so flexible
        
       | PeterWhittaker wrote:
       | Yes and no. Especially once one considers how a remote branch is
       | not a branch in the local sense.
       | 
       | If that struck as odd, consider reading this, which I wrote
       | sometime ago when a number of pennies dropped: https://peter-
       | whittaker.com/
        
       | xvilka wrote:
       | This is why there is a hope to build a new VCS that isn't that
       | state-dependent and based on isolated patches - Pijul[1].
       | 
       | [1] https://pijul.org
        
       | chclt wrote:
       | I think this highlights a deeper issue with how we as programmers
       | tend to think about abstractions. It is easy to pretend, that you
       | can conjure any interface/any abstraction from thin air as long
       | as you define what you want well enough. But the reality is, that
       | a good abstraction needs to be build using elegant constituent
       | parts. It needs to be built in a way, which looks at the problem
       | in an angle which simplifies it.
       | 
       | Building named sequences of source changes via commits which
       | chain together, with the only thing that defines the identity of
       | the chain being a ref to the end is such an elegant abstraction,
       | which is not bad to expose; It allows for easy reasoning about
       | source changes. Saying git branches are a seperate sequence of
       | commits and keeping it at that would be not a good abstraction,
       | even if you hid the implementation really well.
        
       | seba_dos1 wrote:
       | > None of these can be understood if you think that a branch is
       | nothing but a ref.
       | 
       | To the contrary - all of these can have "branch" changed to "ref"
       | and they still make perfect sense. "ref" is just as much a
       | sequence of commits as "branch" is. Every commit is.
        
       | paweladamczuk wrote:
       | I'm pretty sure every person who says "branches are nothing but
       | refs" understands why they are called branches.
       | 
       | They just want you (and others) to learn. This is an important
       | piece of puzzle that many people miss.
       | 
       | Would you sacrifice all those (other people's) learning
       | opportunities just so that you don't get annoyed?
        
         | [deleted]
        
       | hedora wrote:
       | A ref is a pointer to a node in an directed acyclic graph, and a
       | branch is a pointer to a ref. Not all subgraphs of directed
       | acyclic graphs are sequences.
       | 
       | So, not all branches are sequences.
        
       | drewcoo wrote:
       | Subversion still exists. So does Perforce. There may be others.
       | 
       | This mental model fits those models in the code. It also fits
       | Git-Flow. Those are all authoritarian.
       | 
       | So is everything Linus produces.
       | 
       | But, the secret genius of Linus is that he creates things with
       | branchier futures than most creations and then he lets them
       | wander around, becoming even more aggressively future-branching.
       | No, actually . . . the secret is what allows him to do that. It
       | is at least two derivatives of "creates branchy things . . . go!"
       | 
       | Thus git. Thus Linux.
        
       | manmal wrote:
       | I think the author put it well. Branches are an abstraction
       | (albeit a leaky one) over refs, and abstractions are useful. Tags
       | are also just refs, but we (and the git client) assign them a
       | different semantic meaning and functionality than branches. Using
       | those names for different ref types creates shared meaning
       | between people around the world. They allow further abstractions
       | like git flow, which in turn allow (in a way) CI/CD or analysis
       | software to build on those conventions.
        
       | quadhome wrote:
       | A commit is also a sequence of commits.
        
       ___________________________________________________________________
       (page generated 2023-02-28 23:01 UTC)