Re: What actually is a branch?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Martin wrote:
> On 08/07/2021 22:37, Felipe Contreras wrote:
> > Technically a branch is a file with an object id in it. That doesn't
> > give the user any useful information.
> > 
> > What is important is the *meaning* of that file.
> > 
> >> People indeed tend to thing, I branched at X, so anything before is not
> >> part of the branch.
> >> "--contains" says otherwise.
> > 
> > Yes, that is the status quo, but the fact that X is the case doesn't
> > mean it *should* be the case.
> 
> Well yes. So lets start over.
> 
> A branch is a container for commits. Those commits have a start (root or 
> base / not sure), and an end (head).
> The commits are continuous, in that they have no gaps.
> 
> The big question is the start point of the branch.
> 
> And there is a further consequence:
> If a branch "starts" at "base" then
>   --contains  needs to be changed
>   --reachable needs to be added (for what contains does now)

Indeed, but as of this moment @{base} is not being considered, it's just
a mental model tool.

> This also complicates it, because now there are 3 types of relation 
> between commits and a branch
> - unrelated (outside / not reachable)
> - inside (base..head)
> - reachable (base and all its parents) // better word needed

I think that has always been the case. The fact that the git
documentation doesn't talk about that doesn't mean the concept doesn't
exist.

> The last is important:
> 
> A => B => C master
>       \ => D  foo
> 
> If I delete master, without the concept of reachable, I would expect 
> commit A to be dropped. Technically B should drop too, but it takes some 
> insight to expect that.
> So then with only the branch foo left, I would also have only the commit 
> D (well maybe B too, if the system is lenient)

Commits don't need a branch to exist. B could have a tag 0.3.7 and no
branch pointing to it. There could be other refs pointing to that
commit.

> One might even go an say if master is deleted, then the base of foo is 
> deleted. since foo must have a base, and it no longer has, foo can not 
> exist any longer.

Of course it can. The base of a branch doesn't necessarily need to be
part of any other branch.

Or another way to think of it is that B is part of an unnamed branch.

> > A branch that you hold, or point to, is a concete concept easy to
> > underand. When I say: "me, my sister, and my father are one tiny branch
> > of the Contreras family", people understand what that means inuitively.
> > 
> > On the other hand saying "Felipe contains his great-great-grandfather"
> > would stop anyone on their tracks.
> 
> The Chicago branch of your family contains Al Capone.
> That works.

Sure, if you start from a certain grandparent, not if you start from my
grandfather.

Most humans have issue with more than 7 items. A branch containing
millions of members reaching as far back as a fish is a notion an
evolutionary biologist might not have any problem with, but most people
would struggle.

For most people a branch must start from somewhere.

> > But if you do `git reset --hard origin/master`, you are saying: drop
> > everything about this branch, and make it the same 'origin/master'.
> > *Now* we have a reason to distinguish `git merge --ff-only` from `git
> > reset --hard`.
> 
> No you don't. IMHO not.
> "reset --hard" resets the branch to a commit. You can specify that 
> commit by giving a branch-name (that then will be resolved). But it 
> could be any commit, even a detached one.

OK. Sure. It could be repurposed to say what I explained, but we might
be overloading that command in that case.

How about `gt branch --reset <otherbranch>`?

> So "reset --hard" has to set the base and the head to the same commit. 
> Effectively creating an empty branch based at that commit.

Maybe. Or maybe the base remains the same. Fortunately that's not
something we need concern ourselves with at this moment.

> But local tracking branches still are counter intuitive.
> 
> IMHO local tracking branches should follow one of the following 
> scenarios. (And ideally that should be the same for all local tracking 
> branches, for any user.)
> 
> 1) Always have the same base as their remote branch.
> Therefore always have the same content as the remote branch, up to where 
> they diverge, if they diverge.
> 
> 2) Not include the remote branches content. Just hold my local commits, 
> until they will be pushed to the remote.
> 
> But neither works:
> 
> Say I have a local commit, and you pushed new changes to the remote.
>     git pull --rebase
> My branch is rebased.
> So my local tracking branch has its base at the head of the remote. It 
> has only local commits => case 1.
> 
> Say I have no local commits, and you pushed new changes to the remote.
>     git pull --ff-only
> If I understand correct the --ff-only move the head of my local branch, 
> but leaves the base where it is.
> Now I have some shared commits with the remote branch.
> => either case 2, or worse none of the 2 cases.

There's no need for --ff-only, do `git pull --rebase` on both cases, and
the base will constantly be reset to the remote head.

However, at least I never do this. My 'master' branch doesn't contain
any commits and I always do the equivalent of `git pull --ff-only`, so
the base would never change.

> > If you send a pull request for your 'master' branch, which then gets
> > merged to 'origin/master', then you can do `git merge --ff-only` to
> > advance the head pointer of the 'master' branch to the remote branch so
> > both are in sync... Except the base won't be the same.
> 
> There may be something I missed. ff should not touch the base?
> So the 2 base will still be the same or not the same, depending on if 
> they were equal before the ff?

That's right. Before the fast-forward the base was different (because of
the rebase), so after the fast-forward the base remains different.

> >> So yes, what is a branch? More exactly what does it contain.
> >> Two examples, that to me suggest two answers.
> > 
> > Not necessarily. See above.
> 
> I feel we must have some understandingly on the part how base and local 
> branches would interact.
> 
> You agree: rebase changes the base (it creates a new branch on to --onto)
> 
> You pointed out there also is fast-forward. But see my above example.
> I am not even doing a pull request. I simply go for you and I both can 
> push to the same remote. So we both commit to master and pull/push it.

It doesn't matter who does the merge:

  git merge origin/master
  git push

It would be the same as a pull request followed by a fast-forward
(except with the parents reversed).

The base remains unmoved.

> >> Also if branch@{base}..branch  then there is a problem.
> >> - branch@{base} is then correctly not part of the branch
> >> - So immediately after "git switch -c branch" the branch is empty => ok
> >> But if so, then what is the branch head at that time?
> >> The Pointer would point the @{base}, but @base is outside the branch. So
> >> the pointer of the branch points outside the branch?
> > 
> > Yes, the base pointer doesn't include the branch. When you do
> > `branch@{base}..branch` that's the same as `^branch@{base} branch` so that
> > excludes all the commits rechable from branch@{base} *including* that
> > commit iself.
> 
> My question is, where you see the branch head pointing to?
> If the branch is empty, i.e. if it has no commit at all, then to what 
> commit does the branch head point?

To the same commit as the base: master..master contains zero commits.

> >> The only problem is:
> >> branch is too often used for "the commits contained in the branch". That
> >> is way to common to even try to stop it.
> > 
> > We don't need to stop it, we can sidestep it.
> > 
> > Instead of talking about the branch, talk about the branch head:
> > "the brach head is moved to X".
> 
> Yes well, we need to be very concise, if we speak about anything that is 
> not the "commits in the branch".
> 
> 
> >>> When you change the branch head you are effectively changing the branch.
> >> Well if branch is the pointer, then you change the branch, and head is
> >> being changed.
> >> If branch is the content, then you change the head, and yes the content
> >> changes.
> > 
> > Exactly, so regardless of which semantics you choose, everyone
> > understands that the branch is not the same anymore.
> > 
> 
> Your original text was
> > When you change the branch head you are effectively changing the branch.
> > If @{base} existed, then changing the base would also change the branch
> > (although that would be a much less dangerous operation).
> > 
> > Does that make sense?
> 
> And yes, if either boundary changes, the branch changed.

But our immediate concern is to improve the documentation of
`git switch -C`, and perhaps improve the interface while we are at it.

I believe we have all the semantic tools needed to write something that
is understandable by most people regardless of their conception of what a
branch is.

No?

-- 
Felipe Contreras



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux