Git’s been a bear for our dev team to use, mostly because its got lots of little caveats, confusing vocabulary, and its not really visual at all.
So I created this little walkthrough. Lets build a house, and use the git workflow to do it.
Lets call this gray box the foundation of our house. This is all the basic infrastructure of our codebase, the bare essentials of what we need to start building features. This is the master branch, and it took us a couple of commits to get here.
We want to add a new feature, which is a door. So we’re on master, we make some changes, and we commit those changes. Now we’ve got a door!
We now want to add a new feature, a tree. We brought on a new developer, and they’re going to add another new feature at the same time, windows. We really shouldn’t work within the same branch because we might create problems if we make changes to the same files, so we create a new branch for our feature, and the other developer creates a feature for his.
We each make our changes, commit them, and we merge into master when we’re ready.
Lets pause to talk about merging for a second.
Merging is smushing two codebases together. Git will compare the two, and if there’s anything different, it will make those changes, as long as the lines we edited in the branch that we’re merging into look the same as they did when we started building.
So in our metaphor, our other developer built new windows, and then added them onto the house by merging it into master. Nothing changed about that spot since he started, so the new windows go on smoothly.
And we built a new tree, and then added it to the house by merging it to master. Sure the windows were added since we started, but that doesn’t change anything about the yard, so the tree fits in as expected. It merged in smoothly.
More than the Basics
But what if we both accidentally change the color of the house at the same time?
We’re going to run into a problem if we created a new feature branch, we built the new color, and then when we go to merge in the new color, there’s already another new color there. The place that we were going to put the new color looks different than when we started developing, so git is now going to ask you via merge conflict: which new color should git take?
We must manually go down the conflicting changes and choose what we want to keep, and what we want to toss. You can keep all of it, toss all of it, or keep bits of both.
Once all of these conflicts are resolved, git creates another commit with the results of what you chose.
We said that merging is smushing changes into the new codebase. But what if we want to add a second floor, AND a roof? We know that the top of the second floor should look about the same as the top of the first floor, so we can start building the roof with that in mind, while someone else builds the second floor.
The second floor is complete, and since nothing has changed about the first floor, they add it to the house by merging it into master.
The roof is complete, but something changed. There’s a new floor totally occupying where the roof should be, and if we try to merge the new roof in, we’re going to have a merge conflict that’s going to be really annoying to deal with.
This is where rebasing comes in handy. Rebasing will take all of your changes, look at the branch you’re rebasing from, and put your changes on top of the current state of that branch. So if we rebase from master once we’re done with our roof, it will look at master, see the new floor was created, and then add the changes that built the new roof on top of the changes that built the new floor.
HEAD: git checkout Around Your Git Tree
Warning: This part can get confusing, so follow closely.
Sometimes you want to check out another branch, or check some changes that you made a while ago in a past commit. Often your git tree will look like this:
That HEAD is where you are in the repository’s git tree. Think of it like the ping on your GPS, the HEAD shows exactly where you are located in the tree. And every time you check out either a branch or a commit, the HEAD will attach directly to what you are checking out. If you checkout a branchname, it will attach to the tip of that branch. If you checkout the SHA of where the tip of that branch currently is, you’ll stay on that SHA, not on the branch — it is important to note that if you make changes at that point, they’re NOT on that branch.
This means that if we had a branch called updates, and the tip of that branch currently has a (not typical) SHA of …111xyz, the behavior would be like so while running these commands:
git checkout updates // (Attached HEAD) at tip of <updates> branch
git checkout 333abc // (DETACHED HEAD), at some commit with
SHA 333abcl detached because its not
referencing a branch
git checkout 111xyz // (DETACHED HEAD), at the commit which is
the tip of <updates>, but since its not
referencing <updates>, its detached.
git checkout master // (Attached HEAD) since it attaches to a
git checkout updates // (Attached HEAD), since it attaches to a
If the HEAD isn’t attached to the reference of a branch (and that literally means the branch name, not the SHA), this is described as a DETACHED HEAD.
That was a lot, really quickly, but if you’d like to keep diving in, check out this fantastic git video, this other great video on git collaboration, and tons of the (really simple) resources at this site.