[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)