main branches locally
main branches locally
Posted Oct 23, 2025 15:27 UTC (Thu) by josh (subscriber, #17465)In reply to: main branches locally by Wol
Parent article: Git considers SHA-256, Rust, LLMs, and more
The fork would be a repository that has the metadata pointing to the upstream repo, and holds feature branches used for filing PRs, just as it is now; the only difference would be that it'd stop having a `main` branch that serves no function. main is not the metadata that points to the upstream repo.
> (b) you have no record that it IS a fork, and hence no way to update your fork from the original project.
My fork doesn't get "updated from the original project", it gets new feature branches pushed to it and used to submit PRs to the original project. Those feature branches are pushed from my local repository, which in turn has a remote for both the upstream origin and my fork. The workflow is "update origin, create new feature branch from origin/main, make commits, push feature branch to fork, create PR for fork, delete branch when PR is merged". At no point in that process is my fork's main branch useful in any way.
Posted Oct 23, 2025 17:59 UTC (Thu)
by Wol (subscriber, #4433)
[Link] (12 responses)
So you basically want to save about 20 bytes of on-disk space? And get rid of one line from the display of git branches?
> The workflow is "update origin, create new feature branch from origin/main, make commits, push feature branch to fork, create PR for fork, delete branch when PR is merged". At no point in that process is my fork's main branch useful in any way.
For which you need the main branch to exist. Otherwise, when upstream actions the pull request, how does it know what exactly to pull?
Bear in mind your repository is (unless you did a shallow clone) a copy of the *complete* repository with everything including everybody else's feature branches and everything (until they are pruned). So the cost of that tiny file saying "this is where remote origin/master/HEAD was when local origin was updated" is tiny. The cost of deleting the master branch depends on what you mean by "master branch". If you mean that file, your branch suddenly becomes the entire repository because you know longer have any way of knowing what exactly exists on your system and what exists upstream. If however you mean the entire master branch itself, you've just deleted most of your project, and it will no longer build because all of upstream code has disappeared ...
What problem do you *actually* have with the master branch, other than you think it's visual clutter? Whatever you call it, from the PoV of the project as a whole, a master branch is an absolute necessity.
Cheers,
Posted Oct 23, 2025 19:00 UTC (Thu)
by mathstuf (subscriber, #69389)
[Link] (9 responses)
*My* pet peeve is using the upstream repository for any feature branches at all. Forges have finally gotten a clue and offered the "only copy the `HEAD` ref" trick, but I'd really rather *everyone* use their own fork for development (at least for projects with any kind of velocity…I have far more leeway for personal projects where cleanup was a feature branch or two a week). But fetching from GitLab's `origin` repository and having 100s of refs to update, prune, and manage is insane.
Posted Oct 23, 2025 19:06 UTC (Thu)
by josh (subscriber, #17465)
[Link] (4 responses)
But it *isn't* a baseline. Assuming I don't screw up and push to main by accident, all it does is provide a stale years-old snapshot of the upstream project's main branch (including its README), unrelated to any actual development going on in the repository.
> but having it not-exist introduces questions of what it means when your last feature branch is merged and you delete it. Is the `HEAD` ref resynced to keep the repository alive?
There's no fundamental reason a repository *couldn't* be kept alive with a virtual/fake/nonexistent HEAD. And to the extent forges don't support that, I'm frankly tempted sometimes to push a main branch containing a single empty commit, and make that HEAD. That's all independent of the metadata forges have showing what repository it was forked from.
Posted Oct 24, 2025 1:38 UTC (Fri)
by mathstuf (subscriber, #69389)
[Link] (3 responses)
> Forges could have an option to sync it automatically (a button, automatic, or scheduled),
I agree that it is annoying that it is not (often) synchronized. I typically only do so to make it easier to batch-delete already-merged branches on the remote (`git branch -a --merged` exists, but it is useful to have the "how far ahead/behind" view).
> There's no fundamental reason a repository *couldn't* be kept alive with a virtual/fake/nonexistent HEAD.
I guess my question is: what happens when you fetch from your fork in this state?
Forges do store repositories in a single object space and namespaced refs. I wonder if a symref can point between namespaces so that your fork's main is just a symref to the origin's main.
Posted Oct 24, 2025 23:26 UTC (Fri)
by intgr (subscriber, #39733)
[Link] (2 responses)
But why spend the compute resources updating the branch if users don't need or use it? Even if it were periodically updated, that would just create the illusion of an up to date branch. When I rebase, I want the latest origin/main, not "a few hours out of sync" one.
I might only use the fork for one pull request and never thereafter. Why even waste the disk space if there are no remaining feature branches?
As for "baseline state" of the fork: that's just the common ancestor of upstream repo and any particular feature branch.
I had never thought about these things but everything that gioele and Josh here said is a revelation about why git and the forges based on it feel so clunky to interact with.
Posted Oct 25, 2025 2:01 UTC (Sat)
by mathstuf (subscriber, #69389)
[Link] (1 responses)
That's fine; why is your local `main` tracking your fork's `main` if you're not keep it up-to-date?
> I might only use the fork for one pull request and never thereafter. Why even waste the disk space if there are no remaining feature branches?
Forks live in the same repository as the main one. They are segregated using git namespaces (see `gitnamespaces(7)`) so that each access uses a different ref namespace and cannot "see" each other. This is the root cause of that issue where one could push a commit to a fork and then rewrite the URL to be that of the main repository and it would render your content under upstream's URL. I believe there is now a banner when this is done to show that the content is not actually "in" the repository being viewed when the object/tree/commit is not actually reachable from the project's ref namespace.
There was slight reference to this in it being "20 bytes on disk" elsewhere in this thread, but even that might be wrong (besides ref files being 40 bytes due to their ASCII representation) because I believe forges now use `reftable` to store refs in a single file (sqlite db?) rather than a file-per-ref due to filesystem overhead with that mechanism. The vast majority of the cost of a fork is in the database presence it takes up, not the git repository itself.
The shared-repository-with-namespaced-refs is also why I think some namespace-hopping symref to just make a fork's `main` *be* upstream's `main` would be an ideal solution here.
Posted Oct 25, 2025 3:03 UTC (Sat)
by josh (subscriber, #17465)
[Link]
14 years ago, a friend and I wrote the first version of the git namespaces support. :)
This is very much what I had in mind when saying that there's no fundamental reason a fork "needs" a main branch, or a distinct main branch, in order to be tied to the original repository.
> I had never thought about these things but everything that gioele and Josh here said is a revelation about why git and the forges based on it feel so clunky to interact with.
❤️
Posted Oct 23, 2025 21:00 UTC (Thu)
by gioele (subscriber, #61675)
[Link] (3 responses)
Some forges even have an "update fork" button/API as well as ways to periodically fetch updates the the HEAD-pointed branch.
I'd love if git-the-command-line-tool could also finally get a clue about this paradigm.
I'd like to be able to do something like `git clone $MYFORK-REPO-ON-A-FORGE --real-upstream $UPSTREAM-REPO` and have git taking care of:
1) correctly setting the remote from which branches should be pushed and pulled (`main` should be merged ff-only from $UPSTREAM-REPO, but pushed to $MYFORK-REPO-ON-A-FORGE),
I know that there are plenty of situations in which this kind of arrangement would not work, but it would cover the vast majority (95%+) of the projects and repos I deal with.
Posted Oct 24, 2025 1:44 UTC (Fri)
by mathstuf (subscriber, #69389)
[Link] (2 responses)
If upstream ever rewrites history, the `ff-only` can leave you stranded. I prefer to just always trust what the remote repo is. Granted, actual rewriting should be for *extreme* cases (e.g., legal in nature or catastrophic like "oops, committed my VM disk"), but I see no reason to force ff-only here.
> 2) ignore all branches of $UPSTREAM-REPO not pointed by HEAD (so, only fetch `main`),
Some projects have support branches (`release` or the like). I also like to have these. It's the main reason I prefer upstream repos to only publish their maintained branches.
> 3) prevent direct pushes to $UPSTREAM-REPO (I may have admin access to that repo, but our workflow is PR-based),
Branch protection rules (i.e., server-side git hooks) should handle these situations. There's nothing to be done on the developer's side for these as I want the server to enforce them.
> I know that there are plenty of situations in which this kind of arrangement would not work, but it would cover the vast majority (95%+) of the projects and repos I deal with.
Yes, but when you bake in policy, all those corner cases become much sharper. Personally, I have a `git gh-add-fork` command that adds a fork on github to a repo I have with a structured name (`gh/$handle`) and, if it is my handle, sets it as the `remote.pushdefault` as well.
Posted Oct 24, 2025 10:00 UTC (Fri)
by gioele (subscriber, #61675)
[Link] (1 responses)
Agreed. What I meant was "ff-only" by default. If a pull cannot be fast-forwarded then I definitely want to know about it. I will mostly likely pass some option that says "it's OK, overwrite the branch instead of merging it", but I want to be in control of that.
> > 3) prevent direct pushes to $UPSTREAM-REPO (I may have admin access to that repo, but our workflow is PR-based),
As an admin I should have the ability to push whatever I want (or need) to any branch. But that's a big gun pointing at my foot, so I'd like my local tools to not allowing me to do that by default and then shout loudly when I ask them to do it nevertheless. Server-side hooks can be used to implements something similar, but IMO they should be used to solve problems like enforcing policy and access control, rather than as preventive measures for common mistakes.
Posted Oct 24, 2025 13:33 UTC (Fri)
by mathstuf (subscriber, #69389)
[Link]
Sure, the *ability* makes sense, but I'd rather have to go back to the forge, open the gate, do the action, then close the gate again. Having admin privileges just "laying around" is not a good idea (as you need to keep this in mind when onboarding new co-admins) and as an additional layer of defense in case your machine/key becomes compromised (not limited to rogue LLM-based agents "trying to help" or trying to cover their own mistakes).
I also can't say I've seen "common" mistakes which require rights to rewrite history (e.g., any token leak is not a reason as once it is leaked, it needs rotated anyways, so there's no reason to scrub it from history either). I acknowledge they can exist…but I'd also rather continue doing the "gate" thing to help try and train those making the mistakes to, maybe, not do that?
Posted Oct 23, 2025 19:16 UTC (Thu)
by josh (subscriber, #17465)
[Link] (1 responses)
I want to get rid of a years-out-of-date useless snapshot of the upstream repo, complete with rendered ancient README.
(That's leaving aside occasional annoying UI issues with local git when it starts thinking the local `main` branch should follow fork/main rather than origin/main.)
> For which you need the main branch to exist. Otherwise, when upstream actions the pull request, how does it know what exactly to pull?
That isn't how forges like github typically work. A pull request is sent from a feature branch to the upstream main branch, and the relevant thing is what changes are in that feature branch that aren't in *upstream's* main. The main branch of the fork plays no part in that whatsoever.
> Bear in mind your repository is [snip explanation of how git repositories and parent commits work]
I'm aware, and I'm certainly not suggesting all the parent commits should go away; that would not be compatible with how git works. I'm saying a fork that exists to host feature branches has no reason to have a main branch.
> If you mean that file, your branch suddenly becomes the entire repository because you know longer have any way of knowing what exactly exists on your system and what exists upstream.
The difference between my feature branch and upstream is represented via the changes present in `fork/myfeaturebranch` that aren't present in `origin/main`; that's what the PR will show as the commits it contains, and that's what upstream will end up reviewing. `fork/main` plays no part in that comparison, and is *always* useless noise (and useless noise that has a rendered stale README, etc).
Posted Oct 24, 2025 17:22 UTC (Fri)
by rfunk (subscriber, #4054)
[Link]
main branches locally
Wol
main branches locally
main branches locally
main branches locally
main branches locally
main branches locally
main branches locally
main branches locally
2) ignore all branches of $UPSTREAM-REPO not pointed by HEAD (so, only fetch `main`),
3) prevent direct pushes to $UPSTREAM-REPO (I may have admin access to that repo, but our workflow is PR-based),
4) block commits to the `main` branch (all development should happen in feature branches).
main branches locally
> 4) block commits to the `main` branch (all development should happen in feature branches).
main branches locally
>
> If upstream ever rewrites history, the `ff-only` can leave you stranded. I prefer to just always trust what the remote repo is.
> > 4) block commits to the `main` branch (all development should happen in feature branches).
>
> Branch protection rules (i.e., server-side git hooks) should handle these situations. There's nothing to be done on the developer's side for these as I want the server to enforce them.
main branches locally
main branches locally
main branches locally
