Live data from Hacker News

Git Branches: Intuition and Reality

jvns.ca

201–210 of 281 posts

Re: Git Branches: Intuition and Reality

#201

While the explanation is right in some sense, it misses a few points. Branches are pointers to a commit and that pointer is refreshed when a new commit is created. One could say they are a wandering tag (without explaining a tag for now). The actual chain of commits that represent what we see as branch comes from the commits themselves. Those commits point back to their parent commit. And then one can see why no bran…

A key point with git is that every clone is effectively its own set of branches; even if they have the same name. The mechanisms you use for synchronizing your local branches with some remote branches are exactly the same as the mechanisms you use between to your local named branches. Git was actually designed initially for email based workflows where there was no central remote at all. Basically, that works by expor…

> The branch name isn't even part of the patch.

More generally, the branch name is not stored with commits; it has to be computed by walking back from the branch tips, and commits can have multiple possible branch names based on this. In other words, git does not preserve information about which branch was actually active when you made a particular commit. (Mercurial, by contrast, stores the branch that was active when a commit was made in the commit, so that information is preserved.) The article discusses some implications of this, although it doesn't phrase it quite the way I did above.

Re: Git Branches: Intuition and Reality

#202
post #140

Earlier quoted context omitted.

git reset --hard is actually dangerous, because it throws away local modifications that were not yet committed. To undo just the commit and not the work, you should use git reset --soft (to undo just the git commit) or git reset --mixed (to undo both the git commit and the "git add"s leading up to the commit).

git checkout will also happily throw away local unstaged modifications, and I would argue that it is even more dangerous because I did not have to type "--hard" to shoot myself in the foot.

That's not what checkout does.

Re: Git Branches: Intuition and Reality

#203
post #167
post #145

Earlier quoted context omitted.

The fact that the branch tip can be moved to unrelated commits is another issue with Git’s model, and a mismatch to the intuitive “a named lineage in the DAG” conception of branches. In other VCSs, that would be a new/different branch, and you could still rename branches so that the same name will later refer to a different branch, but the branch history as such (including renames) would be preserved.

> mismatch to the intuitive “a named lineage in the DAG” conception of branches Once more, that conception may be intuitive but it is wrong . A branch is emphatically NOT a line through the DAG, it's the whole DAG. There simply is no single list of patches to apply to get from one commit to another, even if both were at some point heads of the same branch, and even if one is an ancestor of the other. And the reason i…

I don’t see what is wrong. Branches in that conception are paths through the DAG. One would like to annotate such paths with names, and have those names automatically apply by default when adding a commit to the end of such a path.

This has nothing to do with lists of patches. Nevertheless, for any given path, it is always possible to compute a list of patches that would match that path. Just compute the diffs between all adjacent pairs of commits on that path. What you maybe mean is that you can’t replay just a single path and have it result in the same commit hash. That, of course, is correct, you need to replay the complete prefix DAG. However, I don’t see why you think that causes issues for the branches-as-paths conception.

Yes, branches can merge together. That just means that different paths can share nodes and edges. Just like two hiking trails can partially overlap. Again, I see no problem here.

Re: Git Branches: Intuition and Reality

#204

I don't use git at work, but in my private hobby projects my friends usually get mad when they watch me juggle changes and branch pointers with git reset --hard and git stash... How do you undo a merge that you didn't mean to do/did wrongly? git reset --hard Have some cosmetic fixups on your local branch that really should go into main (or a separate branch) first before merging a bigger feature? git stash git checko…

Both of those sound totally reasonable to me! I don't know of any better ways to do that stuff and there's nothing risky about it.

Completely reasonable if you do on your local branch, or if you have a convention that remote branches starting with your name or something are yours only.

If you rewrite history on master… well… completely unreasonable.

Re: Git Branches: Intuition and Reality

#205
post #42
post #3

I cannot be the only one that gets away with only knowing: git pull git merge x git checkout [-b] foo git commit git push

Git is conceptually simple but has a baroque UI. I really recommend spending 15 minutes to understand it conceptually: objects: blobs, trees, commits, annotated tags refs: branches (local, remote-tracking), tags, HEAD other: working tree, index (aka cache aka staging area), remotes There's lots of good guides out there: git from the bottom up, git for computer scientists, and the git parable are some that spring to m…

> The others may have had simpler interfaces, but they were either conceptually more complex, overly rigid in their design and behavior, or both

Most of the time, I'll humbly trade "overly rigid in their design and behavior" for "simpler interfaces". Please master VCS, discipline me !

Re: Git Branches: Intuition and Reality

#206
post #200

While the explanation is right in some sense, it misses a few points. Branches are pointers to a commit and that pointer is refreshed when a new commit is created. One could say they are a wandering tag (without explaining a tag for now). The actual chain of commits that represent what we see as branch comes from the commits themselves. Those commits point back to their parent commit. And then one can see why no bran…

> Branches are pointers to a commit and that pointer is refreshed when a new commit is created. One could say they are a wandering tag (without explaining a tag for now). A good name for these "wandering tags" would be "heads", since it's what git calls them internally (for instance, when not packed, they're stored at the "refs/heads/" path in the repository). This also exposes a distinction between a "branch" and it…

Just to make this explicit: a branch in the chain of commits. The start of the chain is pointed to by a head. When you create a new commit on a branch, the head (of that branch) changes to point to the new commit.

Re: Git Branches: Intuition and Reality

#208

While the explanation is right in some sense, it misses a few points. Branches are pointers to a commit and that pointer is refreshed when a new commit is created. One could say they are a wandering tag (without explaining a tag for now). The actual chain of commits that represent what we see as branch comes from the commits themselves. Those commits point back to their parent commit. And then one can see why no bran…

A key point with git is that every clone is effectively its own set of branches; even if they have the same name. The mechanisms you use for synchronizing your local branches with some remote branches are exactly the same as the mechanisms you use between to your local named branches. Git was actually designed initially for email based workflows where there was no central remote at all. Basically, that works by expor…

> A git patch is just a textualized form of the list of commits you created locally. You can apply them to any branch you like.

Not even branch. You can combine two unrelated repositories, and in theory you could cherry-pick commits from one of the original repositories to the other.

Of course, in practice this rarely works because the files mentioned in the commit don't exist in the other repository. But there's nothing in git's mechanisms that stops this: it's just a bunch of commits, which are actually just a bunch of file contents.

The whole "diff" or "patch" concept in git is just way of doing data presentation - rather than showing you the actual commit, which is generally not helpful, it shows you the difference between the contents of the commit, and the same files in the state referenced by the previous commit.

Re: Git Branches: Intuition and Reality

#209
post #202

Earlier quoted context omitted.

git checkout will also happily throw away local unstaged modifications, and I would argue that it is even more dangerous because I did not have to type "--hard" to shoot myself in the foot.

That's not what checkout does.

In a repo with unstaged changes, running "git checkout ." will checkout files from a specific commit into the worktree and clobber your unstaged changes. By default it probably uses HEAD as the commit to checkout from.

You can checkout files and directories from completely unrelated commits and even unrelated repos!

I have used this to checkout specific useful files from other projects. It's a little nicer than just copying them in, because you can keep the repo tracking branch updated and keep checking out updates, and you can easily compare your file to theirs, and see what changes they have made to the file.

Re: Git Branches: Intuition and Reality

#210
post #71

Earlier quoted context omitted.

This was the most useful piece of information that I have ever read about Git. But what happens if you merge branch A into beanch B? A and B will both contain the commits of A, but in B there may be commits of B between the commits that were merged. Do the same commits of A then have different parents depending on which branch they are on?

Merging branch A into branch B does two things: 1. Create a new merge commit with two parents: the commit pointed to by A and the commit pointed to by B. 2. Set branch B to point at the new merge commit. This is a non-linear history; when comparing some commits there isn't a "before" or "after."

If I checkout the merge commit and then do a ‘git log -n 5’, which parent pointer is followed to show the previous commit logs? A or B or Both / all if it is more than a 2-way merge?
Post reply on HN