Git Rebasing: An Elfin Workshop Workflow

This year Santa’s helpers have been tasked with making a garland. It’s a pretty simple task: string beads onto yarn in a specific order. When the garland reaches a specific length, add it to the main workshop garland. Each elf has a specific sequence they’re supposed to chain, which is given to them via a work order. (This is starting to sound like one of those horrible calculus problems. I promise it isn’t. It’s worse; it’s about Git.)

For the most part, the system works really well. The elves are able to quickly build up a shared chain because each elf specialises on their own bit of garland, and then links the garland together. Because of this they’re able to work independently, but towards the common goal of making a beautiful garland.

At first the elves are really careful with each bead they put onto the garland. They check with one another before merging their work, and review each new link carefully. As time crunches on, the elves pour a little more cheer into the eggnog cooler, and the quality of work starts to degrade. Tensions rise as mistakes are made and unkind words are said. The elves quickly realise they’re going to need a system to change the beads out when mistakes are made in the chain.

The first common mistake is not looking to see what the latest chain is that’s been added to the main garland. The garland is huge, and it sits on a roll in one of the corners of the workshop. It’s a big workshop, so it is incredibly impractical to walk all the way to the roll to check what the last link is on the chain. The elves, being magical, have set up a monitoring system that allows them to keep a local copy of the main garland at their workstation. It’s an imperfect system though, so the elves have to request a manual refresh to see the latest copy. They can request a new copy by running the command

git pull --rebase=preserve

(They found that if they ran git pull on its own, they ended up with weird loops of extra beads off the main garland, so they’ve opted to use this method.) This keeps the shared garland up to date, which makes things a lot easier. A visualisation of the rebase process is available.

The next thing the elves noticed is that if they worked on the main workshop garland, they were always running into problems when they tried to share their work back with the rest of the workshop. It was fine if they were working late at night by themselves, but in the middle of the day, it was horrible. (I’ve been asked not to talk about that time the fight broke out.) Instead of trying to share everything on their local copy of the main garland, the elves have realised it’s a lot easier to work on a new string and then knot this onto the main garland when their pattern repeat is finished. They generate a new string by issuing the following commands:

git checkout master
git checkout -b 1234_pattern-name

1234 represents the work order number and pattern-name describes the pattern they’re adding. Each bead is then added to the new link (git add bead.txt) and locked into place (git commit). Each elf repeats this process until the sequence of beads described in the work order has been added to their mini garland.

To combine their work with the main garland, the elves need to make a few decisions. If they’re making a single strand, they issue the following commands:

git checkout master
git merge --ff-only 1234_pattern-name

To share their work they publish the new version of the main garland to the workshop spool with the command git push origin master.

Sometimes this fails. Sharing work fails because the workshop spool has gotten new links added since the elf last updated their copy of the main workshop spool. This makes the elves both happy and sad. It makes them happy because it means the other elves have been working too, but it makes them sad because they now need to do a bit of extra work to close their work order.

To update the local copy of the workshop spool, the elf first unlinks the chain they just linked by running the command:

git reset --merge ORIG_HEAD

This works because the garland magic notices when the elves are doing a particularly dangerous thing and places a temporary, invisible bookmark to the last safe bead in the chain before the dangerous thing happened. The garland no longer has the elf’s work, and can be updated safely. The elf runs the command git pull --rebase=preserve and the changes all the other elves have made are applied locally.

With these new beads in place, the elf now has to restring their own chain so that it starts at the right place. To do this, the elf turns back to their own chain (git checkout 1234_pattern-name) and runs the command git rebase master. Assuming their bead pattern is completely unique, the process will run and the elf’s beads will be restrung on the tip of the main workshop garland.

Sometimes the magic fails and the elf has to deal with merge conflicts. These are kind of annoying, so the elf uses a special inspector tool to figure things out. The elf opens the inspector by running the command git mergetool to work through places where their beads have been added at the same points as another elf’s beads. Once all the conflicts are resolved, the elf saves their work, and quits the inspector. They might need to do this a few times if there are a lot of new beads, so the elf has learned to follow this update process regularly instead of just waiting until they’re ready to close out their work order.

Once their link is up to date, the elf can now reapply their chain as before, publish their work to the main workshop garland, and close their work order:

git checkout master
git merge --ff-only 1234_pattern-name
git push origin master

Generally this process works well for the elves. Sometimes, though, when they’re tired or bored or a little drunk on festive cheer, they realise there’s a mistake in their chain of beads. Fortunately they can fix the beads without anyone else knowing. These tools can be applied to the whole workshop chain as well, but it causes problems because the magic assumes that elves are only ever adding to the main chain, not removing or reordering beads on the fly. Depending on where the mistake is, the elf has a few different options.

Let’s pretend the elf has a sequence of five beads she’s been working on. The work order says the pattern should be red-blue-red-blue-red.

Bead garland: red, blue, red, blue, red

If the sequence of beads is wrong (for example, blue-blue-red-red-red), the elf can remove the beads from the chain, but keep the beads in her workstation using the command git reset --soft HEAD~5.

Bead garland: blue, blue, red, red, red

If she’s been using the wrong colours and the wrong pattern (for example, green-green-yellow-yellow-green), she can remove the beads from her chain and discard them from her workstation using the command git reset --hard HEAD~5.

Bead garland: green, yellow, green, yellow, green

If one of the beads is missing (for example, red-blue-blue-red), she can restring the beads using the first method, or she can use a bit of magic to add the missing bead into the sequence.

Bead garland: red, blue, blue, red

Using a tool that’s a bit like orthoscopic surgery, she first selects a sequence of beads which contains the problem. A visualisation of this process is available.

Start the garland surgery process with the command:

git rebase --interactive HEAD~4

A new screen comes up with the following information (the oldest bead is on top):

pick c2e4877 Red bead
pick 9b5555e Blue bead
pick 7afd66b Blue bead
pick e1f2537 Red bead

The elf adjusts the list, changing “pick” to “edit” next to the first blue bead:

pick c2e4877 Red bead
edit 9b5555e Blue bead
pick 7afd66b Blue bead
pick e1f2537 Red bead

She then saves her work and quits the editor. The garland magic has placed her back in time at the moment just after she added the first blue bead.

Bead garland: red, blue. Off the string: blue, red

She needs to manually fix up her garland to add the new red bead. If the beads were files, she might run commands like vim beads.txt and edit the file to make the necessary changes.

Once she’s finished her changes, she needs to add her new bead to the garland (git add --all) and lock it into place (git commit). This time she assigns the commit message “Red bead – added” so she can easily find it.

Bead garland: red, blue, red. Off the string: blue, red

The garland magic has replaced the bead, but she still needs to verify the remaining beads on the garland. This is a mostly automatic process which is started by running the command git rebase --continue.

The new red bead has been assigned a position formerly held by the blue bead, and so the elf must deal with a merge conflict. She opens up a new program to help resolve the conflict by running git mergetool.

Left column shows the current file with the red bead; middle column shows the file with neither change applied; right column shows the change that is about to be applied (incorrect blue bead)

She knows she wants both of these beads in place, so the elf edits the file to include both the red and blue beads.

Middle column now shows two new lines which incorporate changes from both the left and right columns

With the conflict resolved, the elf saves her changes and quits the mergetool.

Back at the command line, the elf checks the status of her work using the command git status.

rebase in progress; onto 4a9cb9d
You are currently rebasing branch '2_RBRBR' on '4a9cb9d'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   beads.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    beads.txt.orig

She removes the file added by the mergetool with the command rm beads.txt.orig and commits the edits she just made to the bead file using the commands:

git add beads.txt
git commit --message "Blue bead -- resolved conflict"
Bead garland: red, blue, red, blue. New beads have a different outline. Off the string: red.

With the conflict resolved, the elf is able to continue with the rebasing process using the command git rebase --continue. There is one final conflict the elf needs to resolve. Once again, she opens up the visualisation tool and takes a look at the two conflicting files.

Two conflicts to resolve: use left column to resolve merge conflicts, and add a final red bead to the last line of the middle column. The red bead is available in the right-most column, but it's easier to just type it in.

She incorporates the changes from the left and right column to ensure her bead sequence is correct.

Middle column now shows two new lines which incorporate changes from both the left and right columns

Once the merge conflict is resolved, the elf saves the file and quits the mergetool. Once again, she cleans out the backup file added by the mergetool (rm beads.txt.orig) and commits her changes to the garland:

git add beads.txt
git commit --message "Red bead -- resolved conflict"

and then runs the final verification steps in the rebase process (git rebase --continue).

Bead garland: red, blue, red, blue, red. Final three beads (red, blue, red) have a different outline as they are new commit objects.

The verification process runs through to the end, and the elf checks her work using the command git log --oneline.

9269914 Red bead -- resolved conflict
4916353 Blue bead -- resolved conflict
aef0d5c Red bead -- added
9b5555e Blue bead
c2e4877 Red bead

She knows she needs to read the sequence from bottom to top (the oldest bead is on the bottom). Reviewing the list she sees that the sequence is now correct.

Sometimes, late at night, the elf makes new copies of the workshop garland so she can play around with the bead sequencer just to see what happens. It’s made her more confident at restringing beads when she’s found real mistakes. And she doesn’t mind helping her fellow elves when they run into trouble with their beads. The sugar cookies they leave her as thanks don’t hurt either. If you would also like to play with the bead sequencer, you can get a copy of the branches the elf worked.


Our lessons from the workshop:

  • By using rebase to update your branches, you avoid merge commits and keep a clean commit history.
  • If you make a mistake on one of your local branches, you can use reset to take commits off your branch. If you want to save the work, but uncommit it, add the parameter --soft. If you want to completely discard the work, use the parameter, --hard.
  • If you have merged working branch changes to the local copy of your master branch and it is preventing you from pushing your work to a remote repository, remove these changes using the command reset with the parameter --merge ORIG_HEAD before updating your local copy of the remote master branch.
  • If you want to make a change to work that was committed a little while ago, you can use the command rebase with the parameter --interactive. You will need to include how many commits back in time you want to review.

About the author

Emma Jane Westby is an author, an educator, and a part-time beekeeper. Her latest book, Git for Teams, is now available from O’Reilly. You can follow her adventures on Twitter at @emmajanehw.

More articles by Emma Jane

Comments