(Previously: Part 1 – The Basics)

Remember that a Git repository is a sequence of commits, where each commit includes a pointer to its “parent”.

A branch in Git is just a pointer to one of those commits. There is a default branch typically called “master”. As we make commits, the master branch pointer moves forward along the sequence.

We can create a second branch pointer named, say, “secundo”:

$ git branch secundo

Now we have a new named pointer (branch), which currently also points to the same commit as “master”.

Switching branches

We can switch to this branch, and continue making commits on it:

$ git checkout secundo
$ git switch secundo

Either of these commands will change the current branch to be “secundo” instead of “master”. switch is more recent syntax and I think it is clear in intent.

As we make more commits, the “secundo” branch pointer advances to keep up. Meanwhile, “master” remains unchanged. We can switch back to it:

$ git switch master

When we do this, the source files revert to what they were at the commit point that the “master” branch is pointing to. Any commits made now will advance the “master” branch pointer independently from the “secundo” branch: they will be pointing to different commit points in the repository history tree.

Note: Git refers to the current state of the source directory as “HEAD”. It marks the current branch, and advances forward as commits are made on the current branch.

So, when we switch back to “secundo”, HEAD is moving to that branch, and (naturally) the source files are restored to reflect the latest state of “secundo”.

If you have files open in an editor, be alert for “file has changed outside the editor; reload?” warnings. And if your editor isn’t smart enough to warn you about file system changes, I recommend you find another editor.

Important: any staged files are discarded when you switch branches. Also, any edits in the working tree will be discarded as the version from the switched-to branch is placed into the working tree.

Branch management

Creating branches in Git is a very low impact operation. We can create and switch to a new brand in one step:

$ git switch -c temp_stuff

Delete it when we’re done experimenting (you can’t delete the currently checked-out branch):

$ git switch master
$ git branch -d temp_stuff

Or rename it, if it turns out our experiments are worth keeping for later:

$ git branch --move temp_stuff keep_stuff

Merging

So, I’ve made some changes in my “secundo” branch and I want to keep them and move them into the “master” branch. I could do this manually but one of the powerful features of using Git is that it can do this for us: Merging combines source file changes made in one branch with existing and possibly different changes made in another branch.

First, we need to switch to the target branch, and then perform the merge:

$ git switch master
$ git merge secundo
Updating 82c55cb..fba73e5
Fast-forward
 README.md     |  4 ++--
 cow_tipper.py | 14 +++++++++++++-
 2 files changed, 15 insertions(+), 3 deletions(-)

The source files in the directory have been updated, and contain the changes from the “secundo” branch. We end up with changes made in both branches.

I could now delete the “secundo” branch if I wanted.

Resolving conflicts

What happens if different changes are made to the same section of code in both branches? Let’s try it:

$ git merge secundo
Auto-merging cow_tipper.py
CONFLICT (content): Merge conflict in cow_tipper.py
Automatic merge failed; fix conflicts and then commit the result.

We can get some more advice from git status:

$ git status
On branch master 
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge) 

Unmerged paths: 
  (use "git add <file>..." to mark resolution) 
     both modified: cow_tipper.py 

no changes added to commit (use "git add" and/or "git commit -a")

Git is telling us that it couldn’t perform the merge automatically, and that we’ll have to correct it manually. Here’s what cow_tipper.py looks like in the “master” branch now:

<<<<<<< HEAD
output_text = "Cow Tipping For Beginners"
print( output_text )
=======
first_cut = "Cow Tipping: A Beginners Guide"
print( first_cut )
>>>>>>> secundo

I’ll have to decide which variable name is best, and which output text string is correct, and make the edits, and then commit the changes into “master”.

How do I…?

Return to the previously checked-out branch

$ git switch -

Retrieve files by tag

Probably the best way is to use a temporary branch and then checkout the tag:

$ git branch tmp_v0_0_0
$ git switch tmp_v0_0_0
$ git checkout v0.0.0

Further reading

There’s a whole chapter on this and it is worth digging into:

That’s all for this chapter. Next: Part 3: Remotes.