Git config: pull.rebase and rebase.autoStash

— 20 minute read

Photo by USGS on Unsplash

Table of contents

These git config settings provide a smoother developer experience when working with the git pull command to combine local and remote changes in your local branch:

git config --global pull.rebase true
git config --global rebase.autoStash true

The --global parameter means that the config will be applied at the global scope (my preference), but you can omit this parameter if you prefer to configure git on a project-by-project basis.

Git pull: rebase vs merge

Setting pull.rebase to true tells git to always use the rebase option with git pull instead of the (default) merge option.

In my experience this approach results in fewer issues than the default merge option used by git pull.

How does pull.rebase work?

Assuming the following scenario:

  • You have committed some changes in your local branch.
  • Other developers (or automated processes) have committed and pushed some changes to the remote branch.
  • You need to retrieve those remote changes and combine them with your local changes.

Using git pull with pull.rebase will rewrite your local branch history so that commits from the remote branch are applied first, with your local commits applied on top of those changes, as if they occurred after the remote changes.

Once the git pull is complete (and you have resolved any conflicts between the remote/local branches), you can git push the combined changes to the remote branch.

Why is this useful?

First, it eliminates the unnecessary merge commits required by git merge.

Second, rebasing also results in a perfectly linear project history—you can follow the tip of feature all the way to the beginning of the project without any forks.

This makes it easier to navigate your project with commands like git log, git bisect, and gitk.

Merging vs. Rebasing | Atlassian Git Tutorial

Merge conflicts

I use Visual Studio Code for most common Git tasks (add, commit, pull, push) and usually you can resolve any merge conflicts that arise from the Source Control panel - these should be shown underneath the Merge Changes heading.

You can click on individual files to view a diff of local vs. remote changes, choose which changes to keep, then add and commit the merge changes once you’re done.

Occasionally I’ll switch over to Fork for more complex Git tasks or if I can’t seem to do what I need to do with Visual Studio Code’s Git functionality. Fork provides a great user experience for working with Git, especially when dealing with merge conflicts.

Useful Git commands

Although I’ll usually use Fork if I need to check the status or history of my local branch, these Git commands can be useful:

  • git status: Tells you the status of your working directory.
  • git log: An interactive terminal view of the checked out branch’s commit history. Use up/down arrows to scroll, press Q to exit.
  • git reflog: An interactive terminal view of your local repository’s history. Use up/down arrows to scroll, press Q to exit.

Git pull: rebase.autoStash

By default, Git will prevent you from using git pull to fetch and apply commits from a remote branch to your local branch if you have uncommitted changes in your working directory. To me this feels clumsy.

With autoStash enabled, executing git pull will automatically git stash any changes in your working directory, fetch and apply commits from the remote branch to your local branch, then re-apply the stashed changes to your working directory, so you can continue working on whatever you were working on before executing git pull, with minimum fuss.

What is git stash?

So git stash can be used as part of the git pull action as described above, but it’s also a command you can choose to execute manually. Here’s what it does:

Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.

Git Stash Documentation

Using git stash will stash away your uncommitted changes and revert your working directory to match the HEAD commit. You can restore those changes into your working directory later, if desired.

⚠ A warning about git stash: stashed changes are only saved locally on your machine!

For this reason git stash is best used only for storing a small set of changes temporarily, as those changes could be lost if something happened to the machine they were stashed on.

The feature branch workflow

The feature branch workflow is a more appropriate and tidier approach for working on a new feature or experimental changes than using git stash to save and restore work-in-progress.

To summarise, the feature branch workflow involves the following steps:

  1. Create a local ‘feature’ branch.
  2. Push (publish) the local feature branch to your remote repository.
  3. While you are working on the feature, commit and push to the remote branch regularly.
  4. Merge your feature branch into your ‘development’ or ‘main’ branch when appropriate (e.g. once the feature is complete / ready for testing) OR create a pull request if that’s the preferred approach in your team/project.

This approach reduces the risk of losing work should anything go drastically wrong with your computer.

Pull requests and squash merge

Both GitHub and Azure DevOps make it easy to squash merge when completing a Pull Request. This combines all commits in your feature branch into one commit in the branch you are merging into, reducing noise in that branch’s commit history.

This may or may not be desirable, depending on the size of the Pull Request and the preferences of your team.

Using Git stash

If for some reason you need to use git stash (rather than committing work-in-progress to a feature branch), here are the main commands you need to know:

Stash uncommitted / untracked changes

git stash push -u -m <stash message>

This command will stash away any uncommitted changes in your working directory, including untracked files, with the <stash message> that you provide.

This is equivalent to using the Git: Stash (Include Untracked) command in Visual Studio Code.

See all stashes

git stash list

This command will list any stashes you have created. The list of stashes is ordered from newest to oldest.

Each stash is displayed in the following format:

stash@{0}: On <branch-name>: <stash-message>

stash@{0} is the auto-assigned ID of the stash. This isn’t tied to a particular stash, but denotes the index of that item, which changes as additional stashes are created.

If you had several stashes, this might look something like the following:

stash@{0}: On development: most recent changes
stash@{1}: On development: some changes I made earlier
stash@{2}: On development: these changes are old news

Apply latest stash

git stash apply

This command will ‘apply’ the latest (most recent) stash, restoring the stashed changes to your working directory.

Apply specific stash

If you want to apply an older stash you can specify the name of that stash as follows:

git stash apply <stash-name>

For example:

git stash apply stash@{1}

Remove a stash

git stash drop <stash-name>

This will remove <stash-name>.

For example, this will remove the most recently created stash:

git stash drop stash@{0}