Rebase Workflow Workshop

Learning Goals

By the end of this lesson, you will:

  • Have a better understanding of the differences between merge and rebase workflows
  • Be able to speak on the ups and downs of using one git workflow over the other
  • Practice one way of following a rebase workflow and experiment with interactive rebasing

Prework

Hopefully you’ve had some time to process the Rebase workflow in the prework, but you might still have some questions on the flow and the differences between a Rebase and Merge workflow. Before the lesson, please take 30 minutes to watch this video led by one of our instructors, Ian Douglas. He diagrams out the differences between the two focusing on the differences with the commit timeline between Rebase and Merge and offers some thoughts on when you might use one workflow over the other. The second half of the video is a bit of a Q&A with past students and covers a couple different ways you can achieve a Rebase workflow. Later in this lesson, you will get the opportunity to practice this.

Checks For Understanding

  • Draw out your own diagram comparing the differences between a merge & rebase workflow.
  • What are the benefits of using a rebase workflow over a merge workflow? Are there downsides?

Getting Started

Today we are going to be diving into some Git commands that you may or may not be familiar with using specifically with a rebase workflow. While some of the text editors have nice visuals and may assist you with your current Git workflow, our goal for today is to gain familiarity with commands that are ran from the terminal that can help improve your Git workflow. Follow the steps below:

  1. Go to https://github.com/turingschool-examples/be-m4-git-lesson
  2. Fork the repo and then clone
  3. Make sure you change directories to be within be-m4-git-lesson

Note that spacing is important, so if you don’t see what you expect the first time you run a command make sure there isn’t a typo and that your spacing is correct.

Exercises

Exercise 1

The rebase workflow has a lot of similarities to the merge workflow, especially around resolving conflicts that arise when multiple contributors are working on the same codebase. While there are a few different ways of doing this, we’ll cover one way you can approach it.

  1. Checkout a new branch (branch1) off of master and make some edits by adding or removing methods from files or creating new files with some content.
  2. Create 3 new commits on this branch (branch1). Run git log and note the three new commits that you have added.
  3. Checkout another branch (branch2) off of master and make some edits here as well. You only need to create 1 new commit on this branch.
  4. Next, go back to your previous branch (branch1), and push up your branch to GitHub with git push origin <branch_name>. Then go to your GH repo and click Compare & pull request.
  5. When you open the pull request, change the base repository to be your repository. (NOT Turing!). Then click Create pull request.

Exercise 2

Let’s say we’re looking at those three commits, and they all appear to be tied together and likely could be one larger commit. Now is a perfect time for interactive rebase! Interactive rebase allows us to manipulate our commit history by editing our commits. Here are some tips to working through the interactive rebase flow!

  • To enter an interactive rebase you must first determine at which commit you want to begin viewing the commit history. You can either use the commit hash that is before the commit at which you want to begin editing or you can use HEAD~3 where the ~3 is the number or generations you want to go back.

  • When you begin the interactive rebase it will list out the commits you will be working with and notice the most recent commit will actually be listed last. You should also see a section of comments. These comments are there to help you remember the options you have when doing an interactive rebase.

Today we are going to practice using this command to squash commits.

When running git log --oneline, you’ll notice the 3 new commit messages you just created. Here is what my terminal shows:

ba066c8 (HEAD -> remove-factory-methods, origin/remove-factory-methods) Remove address from factory
2bea68a Remove email from factory
3485281 Remove order functionality from factory
4c94701 (origin/master, origin/HEAD, master) Update gem versions in Gemfile.lock

For me, I noticed that all three commits relate to removing some kind of functionality from the factory. Let’s clean this up a little and squash this into one commit.

  • Because I want to squash all three of these, I can either run git rebase -i 4c94701 or git rebase -i HEAD~3. Note: 4c94701 is the hash for the commit just before my first new commit to remove functionality.

In the terminal you should see something like this:

pick 3485281 Remove order functionality from factory
pick 2bea68a Remove email from factory
pick ba066c8 Remove address from factory

# Rebase 4c94701..ba066c8 onto 4c94701 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
#       However, if you remove everything, the rebase will be aborted.
#
#
# Note that empty commits are commented out

Note: If you are in the terminal, in order to edit anything first type i for insert. Once you are done editing, hit esc. Then type :wq (this will save our changes).

After typing i, replace the word pick with squash in front of two of the commit hashes (shouldn’t matter which ones since you will effectively be combing all three into one). In my case, I am going to squash 2bea68a and ba066c8 so that it looks something like this:

pick 3485281 Remove order functionality from factory
squash 2bea68a Remove email from factory
squash ba066c8 Remove address from factory

Then, press esc and type :wq.

In the terminal you should now see a message like this:

# This is a combination of 3 commits.
# This is the 1st commit message:

Remove order functionality from factory

# This is the commit message #1:

Remove email from factory

# This is the commit message #2:

Remove address from factory

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Tue May 5 15:06:38 2020 -0600
#
# interactive rebase in progress; onto 4c94701
# Last commands done (3 commands done):
#    squash 2bea68a Remove email from factory
#    squash ba066c8 Remove address from factory
# No commands remaining.
# You are currently rebasing branch 'remove-factory-methods' on '4c94701'.
#
# Changes to be committed:
#       modified:   spec/factories/order_factory.rb
#       modified:   spec/factories/user_factory.rb

Here is the opportunity to edit/write the commit message we want to use. If we did not edit any of the messages it will keep them all. So, let’s edit our message in the terminal and now it should look something similar to this:

# This is a combination of 3 commits.
# This is the 1st commit message:

Remove order, email, and address functionality from factory

# This is the commit message #1:
# This is the commit message #2:

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Tue May 5 15:06:38 2020 -0600
#
# interactive rebase in progress; onto 4c94701
# Last commands done (3 commands done):
#    squash 2bea68a Remove email from factory
#    squash ba066c8 Remove address from factory
# No commands remaining.
# You are currently rebasing branch 'remove-factory-methods' on '4c94701'.
#
# Changes to be committed:
#       modified:   spec/factories/order_factory.rb
#       modified:   spec/factories/user_factory.rb

Save the changes once you are done editing, just as you did before.

In the terminal you should now see: Successfully rebased and updated refs/heads/<branch_name>.

Now when you run git log --oneline there should no longer be 3 new commits, but instead one commit with the new message you wrote. (mine being Remove order, email, and address functionality from factory).

Exercise 3

Now that we’ve done that, take a look at your PR. Note that there are still three commits there. It’s not up to date with our local repo.

Your Turn

Try pushing up your branch again and note what it says.

To https://github.com/Kalikoze/be-m4-git-lesson.git
 ! [rejected]        remove-factory-methods -> remove-factory-methods (non-fast-forward)
error: failed to push some refs to 'https://github.com/Kalikoze/be-m4-git-lesson.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Because we are rewriting the commit timeline, it’s not allowing us to push up to our remote respository (it acts as a safety measure). To fix this and rewrite the timeline, you can run git push -f origin <branch_name>. The -f means to forcefully push up and rewrite the timeline which is necessary for this rebase because we want to combine these commits. In this scenario, it is totally okay to use this flag! (but be careful of using it in other places) Then check your Pull Request and check if it now only displays one commit.

Finally, we can click on Merge pull request to merge the branch into Master.

From there, we can locally checkout our master branch, and run git pull origin master to pull down our latest changes.

Next Steps

Remember that we had created two branches? What if we wanted to pull in our latest changes from master into our second branch (branch2)? Checkout your second branch and run git rebase master to bring in the latest changes. Depending on whether or not you made changes in a similar file, you might have to deal with merge conflicts. Work through them if so and then run git log to check your commit timeline.

Extra Resources

Lesson Search Results

Showing top 10 results