Advanced Git

This is a guide for Git operations such as amending, squashing, rebasing, and other helpful things.

Table of Contents

Editing/Adding Changes to Last Commit

Use Case: Need to change your last commit message or add/remove/modify files without making a new commit

To add changes to the previous commit, first stage the changed files (skip this step if you just want to edit the commit message)

git add [files]

To combine these changes to the last commit or to change the last commit’s message

git commit --amend

A text editor will then pop up and you can edit the commit message or do nothing to keep it the same. A new commit with your changes and/or new commit message will now have overwritten the previous commit locally.

If you pushed your previous commit (the commit that was overwritten) onto GitHub already

git push -f

This will overwrite the commit on GitHub with your local commit

Squashing Multiple Commits

Use Case:

  • Avoid meaningless commits

  • Avoid commits like “Fix typo”

  • Reduces number of commits

On the branch with the commits that you want to combine

git rebase -i HEAD~N

where N is the number of previous commits that we want to edit.

For example, if you wanted to combine your commits “Another change”, “Edit README again” and “Add message to README”, N would be 3 since you want to edit the past three commits from HEAD.

So after running git rebase -i HEAD~3 an interactive prompt will pop up like this:

In this prompt it gives the following commands that you can use to edit the commits,

Commands:
p, pick = use commit
r, reword = use commit, but edit the commit message
e, edit = use commit, but stop for amending
s, squash = use commit, but meld into previous commit
f, fixup = like "squash", but discard this commit's log message
x, exec = run command (the rest of the line) using shell
d, drop = remove commit

On the first three lines above, we can see that each line starts with a command followed by the commit hash.

We can see that the commits are in order from oldest to newest. In this example, we want to combine the 2nd commit and 3rd commit with the 1st one.

The definition of the squash command is “use commit, but meld into previous commit”. Since we want to combine our 2nd and 3rd commit with the 1st one, squash seems like the command we want to use on the 2nd and 3rd commit.

In our text editor, we can change the command pick for the 2nd and 3rd commit to squash (or s) to combine those commits with the one above. The 3rd commit will get melded into the 2nd commit but since the 2nd commit is being melded into the 1st commit, the 2nd and 3rd commit will be combined with the 1st one.

After saving those changes, another prompt should pop up with the commit messages of the commits you’re combining.

If you want to keep all messages, you can just save and exit. Or you can edit the commit messages here. Generally, we just want to keep one message so in this example you would delete the 2nd and 3rd commit message, and you can also edit the 1st commit message if you wanted to.

Note: If you already know that you want to discard the commit messages of the commits you’re squashing, you can use the “fixup” command (or f) instead of “squash”.

After you save and quit, you would get a message like this saying rebasing was successful.

Now, running git log would just show the one commit that you combined everything with.

If you pushed any of the edited commits onto GitHub already, use the following command to push your changes to GitHub

git push -f

This will overwrite those commits on GitHub with your local commit history/new edited commits.

Rebasing Your Branch

Use Case:

  • You need new commits from another branch on your branch

  • Cleaner merge commits

  • Address merge conflicts earlier

    What is rebasing?

For example (see image above), I created a feature branch off of the master branch at commit B. Then, I made commits E and F on feature. At the same time, commits C and D were made on master. I realize that I need commits C and D on my feature branch since those commits include some code I need. I could do the following to include those commits on my feature branch.

git checkout master
git pull // make sure my local master is up to date

git checkout feature
git rebase master
// Address merge conflicts if any
git push -f  // If you previously pushed your branch

Note: You should only rebase on your branches (never shared branches)

Renaming Files in Git

Use Case: You are renaming files in your repo

git mv original_file_name new_file_name

Why?

  • Git will recognize that you renamed the file vs deleted a file and created a new one

  • Track changes made with renamed file

  • On Mac, if you change the case of a file name Git will not automatically recognize this change

    • Example: Api.jsAPI.js

Stashing

Use Case: You want to switch branches or are trying to pull from GitHub and get a message like below, but you don’t want to make a commit

To save your changes without making a commit

git stash

To list all of the changes stashed

git stash list

To apply a specific stashed change

git stash apply [index]

where index is the index of the specific change in the output of git stash list.

To reapply the latest stashed change

git stash pop

Last updated