Hacker News new | past | comments | ask | show | jobs | submit login

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.




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.


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.


Yes, it's basically labeled commit. But when you talk about what it means, you do it in relation to some other labeled commit which will always have common branching point. Edge cases may mean it's empty content (disconnected branches) or commit itself is branching point (you're not behind, just purely ahead) or your branching point is your immediate parent (commit delta itself).

It's a DAG with optionally labelled vertices (content is cyclic of course, commit history is acyclic).

It's all potato potato.


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.


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.


pristine-tar branches used for Debian packaging are another common example.


Yes, their branching point is initial empty content.


> 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?


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.


This post is confusing a few things. Branches and tags are nothing more than prescribed semantics for certain refs by default. You could treat a tag as a branch and vice versa if you really wanted. They're just refs. The tool has semantics around managing refs that map to branches and tags, but there's no hard rules here.

You're welcome to create your own configuration of refs and define how remotes handle refs. You don't need to use branches or tags, you can treat every ref as a tag if you like.

Branches and tags really are just refs. Any ref can be a branch or a tag. The refs don't behave in any way. They're just refs. The semantics are not frozen.

Take a look at git notes, or gerrit review refs, or GitHub pull request refs, or... any number of tools which build on the ref system.

git is surprisingly flexible, but ships with sane defaults. They're not gospel.


Thanks for taking the time to explain this. The idea that a lot of these names are just "prescribed semantics" really makes understanding git easier. I think it also drives home the point of how powerful, "simple" and thought out git is.


‘A branch is just a ref with some sane defaults’ is saying a strictly different thing than ‘a branch is just a ref’.

Yes, you can do anything you can do to a branch tag to any other tag (or directly to any commit hash).

Which means you can do things like ‘merge’ any of those things. Not just refs. So things that are not refs can act like branches.

And you can’t just treat any ref as a branch. Is a remote a branch? No - so things that are refs can also not act like branches.

X is Y can’t be true if there are instances of X that are not Y and instances of Y that are not X.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: