Two Ways Git Handles Pulling Code
Imagine you are halfway through editing 3 files for a sprint task when a teammate notifies you that they just pushed a hotfix to main. You need to pull that patch immediately. The standard command is git pull. Behind the scenes, however, Git handles code integration using two fundamentally different strategies.
1. Default Git Pull (Merge Strategy)
By default, if you have new local commits, git pull creates an extra intermediate commit: a merge commit. It looks something like: Merge branch 'main' of github.com:....
In a team of 6–8 developers pushing code continuously, git log --graph turns into a tangled spiderweb after just a single week. Commit history becomes heavily fragmented. When you need to use git bisect to track down a bug, you will spend twice as long navigating through dozens of unnecessary branch divergences.
2. Git Pull with the Rebase Flag
git pull --rebase approaches this differently: it rewrites and replays your timeline.
Git temporarily sets your local commits aside. Next, it pulls all the new commits from the remote branch first. Finally, Git applies each of your local commits on top of that updated branch. The project history remains a clean, linear timeline. Anyone looking at the log can clearly see the chronological progression of features.
The Bottleneck: In-Progress Code (Dirty Working Tree)
The problem is that we rarely commit every change before pulling. Usually, your local working tree still contains unfinished test lines or WIP edits.
When encountering uncommitted changes, git pull --rebase halts immediately with an error: “error: cannot rebase: You have unstaged changes”. This usually forces an annoying manual workflow:
- Run
git stashto temporarily shelf your changes. - Run
git pull --rebaseto pull incoming changes. - Run
git stash popto restore your uncommitted work.
If you simply forget step 3, you might panic thinking your code was wiped out.
Side-by-Side Solution Comparison
Here is how the three common approaches stack up against each other:
- Keeping the default pull: Easy to use and beginner-friendly because it never rewrites commit hashes. The downside is that it creates dozens of noisy merge commits (averaging 15–30 redundant commits per sprint), cluttering repository history.
- Running pull –rebase manually: Produces a clean, linear commit graph. However, repeatedly typing the three-step sequence of stash > pull > pop makes it very easy to skip a step when you are in a rush.
- Enabling pull.rebase with rebase.autoStash: 100% automated. All you have to do is run a single
git pull. Git automatically shelves your dirty working tree, rebases your branch, and restores your changes seamlessly.
Real-World Production Experience
In a 10-developer fintech project I previously worked on, our team once burned nearly three hours right before release simply resolving conflicts caused by cross-merging branches. In one instance, outdated code inadvertently overwrote freshly reviewed code.
After standardizing our workflow by having the entire team enable rebase with autoStash, those headaches vanished. Conflict frequency dropped significantly. The Git log graph remained straight and clean, making PR reviews and cherry-picking commits into release branches effortless for tech leads.
This configuration is especially ideal if you:
- Work in an Agile/Scrum environment where you regularly rebase feature branches onto
develop. - Want clean commit logs so CI/CD pipelines can automatically generate changelogs using Conventional Commits.
- Prefer speed and do not want the hassle of manually stashing code every single day.
Detailed Configuration Steps
Simply open your terminal and run the two commands below. You only need to set this up once.
Global Configuration (Recommended)
# 1. Set rebase as the default strategy for git pull
git config --global pull.rebase true
# 2. Automatically stash before rebasing and restore changes right after
git config --global rebase.autoStash true
Project-Specific Configuration (Local)
If your company’s repository requires keeping merge commits intact, apply this locally only to your personal projects:
cd /path/to/my-project
git config pull.rebase true
git config rebase.autoStash true
Verifying the Configuration
To verify that Git has applied your settings properly, run:
git config --global --get-regexp "pull|rebase"
If the output matches the following, you are all set:
pull.rebase true
rebase.autostash true
Hands-On Terminal Experience
Once configured, imagine you are editing services/auth.go without committing your changes yet. When new updates arrive on remote, simply run:
git pull
Git handles the entire underlying pipeline automatically:
Created autostash: 8f2c1b4
First, rewinding head to replay your work on top of it...
Fast-forwarded main to origin/main.
Applying autostash: 8f2c1b4
Applied autostash.
Your auth.go file retains its exact uncommitted state. All incoming commits from the server are pulled smoothly. Your commit history stays linear, clear, and completely free of cluttering merge commits.

