3 ms·
Of course. Someone explained it to me, after all. In git, a branch is NOT like a wooden branch on the trunk of a tree, although it ends up being at the top of
by BiteCode_dev 7y ago
Of course. Someone explained it to me, after all.
In git, a branch is NOT like a wooden branch on the trunk of a tree, although it ends up being at the top of one, which makes the analogy ok.
A git branch is the same thing as a git tag, except it moves automatically when you commit from it.
You can see it as a lightweight label attached to a commit. If your HEAD is itself attached to a branch (HEAD is also a lightweight label, but this one is like a red sticker on a map saying "you are here"), when you do "git commit", the branch label is moved to the newly created commit.
Hence, you can have several branches on a single commit, and you can move branches around: they are just labels. You can also have branches with different names locally and in a remote, or have a branch with the same name, but on different commits locally and in a remote.
A branch is like a reference, it's useful to tell git what place in the history you are talking about, without referring to a commit in particular. It is a moving reference because the place in history you talk about is always changing: it's the top of a chain of commits, the ever changing last thing you worked on for this particular part of the history.
We want branches because they are a convenient way to say "I'm going to do something on the latest commit of this part of the history":
- "git checkout branch_name" => I'm now working on this part of the history, gimme all the latest stuff you got and consider everything I do is now related to it.
- "git checkout branch_name /file/path" => Get the latest version of the file from this part of the history and bring it on my hard drive
Of course, you can put a branch at a commit that is not yet the top of a chain of commits. But soon this commit will become the top of a new chain of commits because when you'll commit from this branch, a new commit will be attached to the previous one, diverging from the original chain, and the branch label will be moved to it. You now have a fork of two chains of commits, both of them having a different branch label at their top:
"git checkout commit_hash && git checkout -b new_branch_name" => I'm going to consider this commit as a new starting point and work from that.
In fact you can move a branch pretty much anywhere, create one or delete one at anytime, including "master", which is not a special case, just one created automatically on the very first commit.
This is also why if you "git checkout commit_hash" instead of "git checkout branch_name", git warns you you are in a "detached HEAD" (the "you are here" label is attached to a commit directly, not a branch label). Indeed, a chain of commits (the stuff that looks like a wooden branch on a trunk in graphics) can exist without a branch label. But it won't be convenient to reference: looking for the hash of the newest, latest commit, every time you want to mention it is tedious. Besides, git will run "git gc" automatically once in a while, deleting diverging parts of the history with no branch or tag, so you may lose this work.
This makes it clear that tags are labels like branches, only they don't move. They serve the purpose of having a static reference to a fixed point in time: both allowing you to easily talk about it, and let git know you want to keep this around.
All that stuff is way clearer with a visual explanation. For my Git training, I bought a fantastic toy for 10yo with magnets that let me build a 3D history tree and use post-its to represent branches and tags. It's instantly obvious. It's really fun, you can move stuff around and show what each command does to the tree. After that, git seems much more accessible, and you just grunt at the terrible UI ergonomics.
- thaumasiotes 7y ago> In git, a branch is NOT like a wooden branch on the trunk of a tree, although it ends up being at the top of one, which makes the analogy ok. So, there's an isomorphism between (1) a commit node; and (2) the chain(s) of commits ending in that node. Why then is it important to think of "branch" as referring to one rather than the other? As evidenced by the isomorphism, they're the same thing.
- BiteCode_dev 7y agoIt helps to NOT think of a branch as a commit node, nor a chain of commits ending in that node. A branch is a separate concept, it's not even stored in the history DB but in a different dir. See it as a label attached to a commit, since a commit can have several branches attached to it, or none. A branch will be moved across the history, while a commit will keep his place in the history. A branch is designed to be easily created, deleted, and moved around, freely, from anywhere to anywhere. A commit is designed to feel immutable, and unmovable, and although this is not strictly true, this is how you will mostly use it. A chain of commits is like a rail track, it goes in one direction, each commit composing it never changing (again, conceptually), and never moving. You stack commits, you grow the track, piece by piece. The branch is more like a flag you put somewhere on the rail track (most often at the end), to let the workers know where to put the next piece. Picturing it that way let you best use its properties: - branches cost nothing. They are very lightweight, unlike in SVN, you should create as many as you want. - moving to a branch is cheap. Apart from moving the files to the working copy, it's just a matter of changing point of view on the history. Switch to branches often, it's fast. - you can put a branch anywhere you want. You like an old commit and wanna try something new from it? Plant your flag here and start working. - deleted a branch by mistake ? No worry, it's just a label. You can recreate it in a blink. - this branch is so good it should be master? Sure you can. Just swap the labels. But let everyone knows :) Etc.
- thaumasiotes 7y ago> branches cost nothing. They are very lightweight, unlike in SVN, you should create as many as you want. Ahhhh. So the distinction matters if you bring in a bad assumption from SVN. It had never occurred to me that a labeled branch would be noticeably more expensive than the weight of the commits making up the branch. > you can put a branch anywhere you want. You like an old commit and wanna try something new from it? Plant your flag here and start working. Well... yeah. That's how you create branches. You go to the commit you want to branch from, and you run `git branch`. The fact that you can do this is immediately implied by the way you have to do it. I don't understand how someone could believe something different. > deleted a branch by mistake ? No worry, it's just a label. You can recreate it in a blink. This one's a little weirder; if you delete a branch, you _can_ recreate it, but it's only blink-of-an-eye easy to do if there's another branch containing the head of the old branch. Otherwise you're mucking around in the internal data. > this branch is so good it should be master? Sure you can. Just swap the labels. This is another one where I don't see how you would believe something different. Even if branches were huge, heavyweight objects, they have names, and changing the name of something is generally not so hard to do. There's a command solely for the purpose of renaming branches. (`git branch -m`) > moving to a branch is cheap. Apart from moving the files to the working copy, it's just a matter of changing point of view on the history. Switch to branches often, it's fast. And in my mental model, a checkout is indeed a (potentially mass) update to file contents (and, if applicable, file existence). Saying "apart from moving the files to the working copy" sounds -- to my ears -- kind of like the chestnut that "controlled for height, taller men earn no more than short men do". Setting up the working copy is the thing I'm looking to accomplish in a checkout. I can imagine two types of people who want git training: - Never used version control. - Used subversion heavily; trying to update to the new new thing. In your opinion, how many of these points are "git gotchas" that the first group need to be trained in, and how many are "subversion gotchas" that only really come up for the second group?