Checkpoint 2.2.1. Hero and Heroine on Branches.
Make sure your practice repository has at least three files in it, with one typographic mistake. So go ahead and create a new file and a new commit if you need to. We will wait.
We are going to pretend that we are writing a novel and we want to design two possible endings. In one, the hero dies, and in the other, the heroine dies.
Make sure your working directory is clean and type
git branch heroine
. Not much will appear to have just happened. So here is a new diagnostic command you will want to use all the time. Type git show-branch
. This shows all of your possible branches, with an asterisk (“*
”) indicating the branch you are “on” and an exclamation mark indicating other branches (“!
”). It is not very informative yes, since your repository is just beginning to take shape and you have only just created a branch. Be sure to keep this output visible in your terminal for an upcoming comparison.Now we are going to move to you new branch. Ready? Type
git checkout heroine
. Now run git show-branch
again and compare to the previous output. The big change is that the asterisk has moved to indicate the heroine
branch. We say you are now on the heroine
branch. If you have experience with other revision control systems, the word “checkout” is fraught with other meanings that are not accurate. Sorry, just get over it. In git
the checkout
command will change the files in your working directory to some possibly different state, based on a different sequence of changes in a sequence of commits constituting a different branch. (Remember, commits are collections of changes.)Choose one of your two files without a typo and edit it to include some words about the heroine dying, and also remove some existing words at the same time. Use
git diff
, git add
, git commit
to form a new commit that is the changes you just made, and with a commit message about creating an ending where the heroine dies. You should have a clean working directory after the commit.Now
show-branch
will show something interesting:rob@lava:~/books/ppw$ git show-branch
* [heroine] Create an ending where the heroine dies
! [master] <message about last commit on master>
--
* [heroine] Create an ending where the heroine dies
*+ [master] <message about last commit on master>
The top half lists all your branches, with color-coding and identifying symbols. The bottom half tries to describe to you how those branches relate. We will make it even more interesting shortly.
Close any files you have open in your editor, type
git checkout master
, and open the files again. Don’t panic. You have restored your working directory to the state of all the accumulated changes up to the tip of the master
branch, so you do not see your most recent change to your novel. The changes that constitute the brilliant ending about the death of the heroine is saved by git
in a place that it is hard for you to find but easy for you to manage. Would you like your ending back? Close your files, type git checkout heroine
, and open your files. git
has manipulated your files and applied the changes with the ending, so now your novel should contain the new ending.Perhaps you now see why
git
can feel a bit foreign and why at some point you will have that “Oh, &\#*!” feeling. Don’t panic. git
manipulates the state of the files in your working directory, so in a way those files are ethereal. git
stores your commits (collections of changes) safely and can rewind and replay them in ways consistent with your writing while on various branches, using your working directory as a sort of sandbox or laboratory.Switch back and forth several times between the
master
and heroine
branches with git checkout
. Close and open your files in your editor as you let git
manipulate your working directory. Run git show-branch
liberally. When you are ready, leave a file open when you know a checkout
is going to change it. How does your editor react? We don’t know, so can’t help. But a good editor might say something like “File on disk changed, do you want to reload it?” We use an editor that just silently reloads the file, unless there are unsaved edits in it by mistake. If a git
checkout
results in a file not even being present, our editor leaves it in a state we find very confusing. Sometimes this sort of behavior can be configured in a editor. Experiment until this is not confusing and in the meantime as you are learning, close and reopen files as you instruct git
to manipulate the state of your working directory.Ready for another branch? Make sure you are on
master
(by running git checkout master
). Then make a new branch with git branch hero
, and switch to it with git checkout hero
. Run git show-branch
as you go, studying carefully how the output is changing.Open the file that is different from the one you edited before, and that is not the one with the typo. Remove some words, and author an ending where the hero dies. Create a commit with these changes, using a commit message about the hero dying. (We might now use “commit” as a verb, and say commit your changes.) Now
show-branch
will produce something like:rob@lava:~/books/ppw$ git show-branch
* [hero] Made an ending where the hero is dead
! [heroine] Create an ending where the heroine dies
! [master] <message about last commit on master>
---
* [hero] Made an ending where the hero is dead
+ [heroine] Create an ending where the heroine dies
*++ [master] <message about last commit on master>
Now this is interesting. You have three branches, you are on the
hero
branch, and the heroine
and hero
branches contain divergent storylines based on a common beginning. (Everything up to master
is common and not reported in this output.) Experiment checking out different branches, run show-branch
liberally, and do not forget that you can do things like git show hero
even if you are not presently on the hero
branch. Get comfortable with the current state of your repository. Notice that each of our two new branches could each be a sequence of many commits, but we just need one commit each for the purposes of this exercise.As you looked around, did you notice that typographical error you made in the third file when you first start writing? (If not, play along.) Checkout the
master
branch, open the file with the typo and and edit to correct the mistake. Commit those changes. You should now see:rob@lava:~/books/ppw$ git show-branch
! [hero] Made an ending where the hero is dead
! [heroine] Create an ending where the heroine dies
* [master] Correct a misspelling
---
* [master] Correct a misspelling
+ [hero] Made an ending where the hero is dead
+ [heroine] Create an ending where the heroine dies
++* [master^] <message about last commit on master>
Notice that the new commit has resulted in the tip of the
master
branch moving to be the commit with the typo fix. Every commit we have made so far has also moved the branch pointer to a new tip, but this is the first time it was really interesting and significant. Notice that through all these pointer movements we no longer have a pointer to the commit where all the branches originated. Notice too that this report still shows the last of our pre-exercise commits, since that is where our three branches diverged from common material.The good news is that we have two versions of our story and only fixed the typo once, while the bad news is that the
master
branch has advanced and left the hero
and heroine
branches behind. Do you see that in the output above? As you checkout the three branches, you will see the effect of the three editing sessions, but they are all disjoint. Said differently, switching to the hero
branch results in git
manipulating your working directory by applying a sequence of commits that do not contain the commit with the typo fix. And similarly for the heroine
branch. But not all is lost.Here is where you begin to learn how to leverage
git
. We are going to rewind the hero
branch back to the commit where the branch began, and then we are going to replay our changes at the new tip of the master
branch. And git
knows just how far to rewind. (This would be slightly more interesting if our hero
branch had multiple commits beyond the old branch point.)Ready? Make sure your files are closed, and checkout the
hero
branch, since this is the branch we are changing. Run git log
now and save the output some place, because we want to see how the commit hashes behave. Now run git rebase master
. This tells git
to rewind the current branch (hero
), checkout master
, branch off master
, and replay the commits that were just rewound (in the opposite order), leaving the hero
branch pointer at the tip of the branch. Remember, git
manipulates the files in your working directory by applying (replaying) commits in sequence.You might be aware that in replaying the commits,
git
might get confused by intermediate changes that had not been present when the commits were based on the original branch point. These situations are known as conflicts. git
can be pretty smart about these, but sometimes they require intervention by the author. If you have followed our instructions and used three files, then this will not happen in this exercise. We address conflicts in Chapter 3 and Chapter 4.Open your files and you should see the hero dying, and you should also see the typo fixed. When I need to run this command, I say to myself “
rebase
the current branch onto master
” to make sure I get it right and do the right thing. Examine the result with git show-branch
.Repeat this procedure to move the
heroine
branch up to the tip of master
. This is an exercise, so we will not hold your hand on this one. Think carefully about each step while reviewing how we rebased the hero
branch. When you are done, you should see:rob@lava:~/books/ppw$ git show-branch
! [hero] Made an ending where the hero is dead
* [heroine] Create an ending where the heroine dies
! [master] Correct a misspelling
---
+ [hero] Made an ending where the hero is dead
* [heroine] Create an ending where the heroine dies
+*+ [master] Correct a misspelling
Notice that all of the commits for the beginning of the story, prior to our typo fix are not shown in this output because they are now common to all the branches.
Before you experiment too much, checkout the
hero
branch, and as beforehand, run git log
. Compare with the output you save a few steps back. You should see that the first commit (hero dies) now has a totally different commit hash, the second commit is the typo fix (which was not evident beforehand), and the present third commit is the previous second commit, with the identical commit hash. We will discuss this outside of the exercise. Now, explore your repository thoroughly with the various commands and diagnostics you have learned.That is it, we are done. Notice that you are maintaining two versions of your novel, can easily switch between working on one or the other, and you can edit common material just once in a way that is reflected in each version. If you made a mess of this (which might be a good thing), just start over with a new repository and have a do-over. Or maybe repeat the exercise with extra commits on each branch for a fuller experience and to solidify your new skills.