The Complete Guide to git pull: From Your First Fetch-and-Merge to Mastering Rebase Strategies and…
Everything you need to know about the command that brings the outside world into your local repository, explained in plain English with…
The Complete Guide to git pull: From Your First Fetch-and-Merge to Mastering Rebase Strategies and Advanced Configuration (The human-readable manual: git pull)

Everything you need to know about the command that brings the outside world into your local repository, explained in plain English with real-world scenarios, visual diagrams, and an honest look at the traps that catch developers at every skill level.
A deep-dive tutorial covering Beginner, Intermediate, and Advanced usage, all options from the official Git manual, plus real-world team workflows, rebase vs merge decision-making, conflict resolution, shallow clone management, and practical configuration tips for every team size.
**inter-git.com teaches git fundamentals visually: [inter-git.com](https://inter-git.com)** is an interactive Git tutorial where each command is shown visually so you can see exactly how it works in real time. It runs entirely in your browser, so there is nothing to install. Before moving on to the intermediate level, it is a great place to practice what you have just learned.
Table of Contents
- Introduction: What git pull actually does and why you need to understand it properly
- Level 1: Beginner 2.1 The two steps hidden inside every git pull 2.2 Remotes and tracking branches explained 2.3 git pull: fetching and merging from your tracked remote 2.4 git pull origin branch: explicit remote and branch 2.5 Reading the pull output for the first time 2.6 Understanding merge commits created by pull 2.7 Handling conflicts after a pull 2.8 git pull — verbose and — quiet 2.9 Beginner pitfalls
- Level 2: Intermediate 3.1 git pull — rebase: the cleaner alternative to merge 3.2 git pull — ff-only: only fast-forward, never create a merge commit 3.3 git pull — no-ff: always create a merge commit 3.4 git pull — no-commit: merge but let me review before committing 3.5 git pull — squash: flatten remote work into one commit 3.6 git pull — stat and — no-stat 3.7 git pull — tags and — no-tags 3.8 git pull — autostash: pull even with dirty working tree 3.9 git pull — recurse-submodules 3.10 git pull — allow-unrelated-histories 3.11 Intermediate pitfalls
- Level 3: Advanced 4.1 Merge strategies: ort, recursive, octopus, ours, subtree 4.2 Strategy options: -X ours, -X theirs, -X patience, and more 4.3 Rebase modes: interactive, merges, and preserve 4.4 Shallow clones: — depth, — update-shallow, — unshallow 4.5 git pull — jobs: parallel submodule fetching 4.6 git pull — atomic: safe atomic updates 4.7 git pull — negotiate-only 4.8 Setting upstream tracking with -u 4.9 Configuration variables: pull.rebase, pull.ff, pull.autostash, branch settings 4.10 Real-world advanced workflows 4.11 Advanced pitfalls
- Quick Reference Card
- Complete Flags Reference Table
- Conclusion
Introduction: What git pull Actually Does and Why You Need to Understand It Properly
Let us be honest about something. Most developers type git pull at the start of every morning, watch some output scroll by, and then get on with their work without really knowing what happened. That works fine, right up until it does not. And when it stops working, the confusion is spectacular: diverged branches, accidental merge commits cluttering history, conflicts that seem to come from nowhere, and that terrifying message about how your branch and the remote have diverged and you need to specify how to reconcile them.
All of that confusion comes from the same root cause: people use git pull as a magic "sync" button without understanding the two separate operations it combines. This tutorial is going to fix that. By the time you finish the beginner section, you will understand exactly what git pull does in every situation. By the time you finish the intermediate section, you will be able to choose the right pull behavior for any workflow. By the time you finish the advanced section, you will understand the merge strategies, configuration variables, and edge cases that even senior engineers look up.
Every section includes at least one diagram, because these Git concepts are genuinely easier to understand visually than in text alone. Every option from the official Git 2.54 manual is covered. And every pitfall section is based on the exact kind of mistakes real developers make in real codebases. Let us start at the very beginning.
Level 1 Beginner: Understanding git pull From the Ground Up
Before you touch a single flag or option, you need to understand the mental model behind git pull. Skipping this is the number one reason developers end up confused later. The mental model is simple, but it is not the one most people carry around.
The Two Steps Hidden Inside Every git pull
Here is the core truth about git pull: it is not one command. It is two commands run back to back. When you type git pull, Git runs git fetch first, and then immediately runs git merge (or git rebase if you configure it that way). Understanding what each of those does is the key to understanding everything else in this tutorial.
Step 1: git fetch goes out to the remote server (for example, GitHub), downloads any new commits and branches it does not have yet, and stores them in your local repository as remote-tracking branches. These are the branches with names like origin/main or origin/feature-login. Crucially, git fetch does not touch your working files at all. It just updates Git's internal knowledge of what is on the remote. Your files are unchanged after a fetch.
Step 2: git merge takes the remote-tracking branch that was just updated and merges it into your current local branch. This is the step that actually changes your files. If the remote had new commits that you do not have, they get integrated into your branch right here.

Figure 1: git pull is a convenience wrapper around two separate commands. Step 1 (git fetch) downloads new remote work into your remote-tracking branch, origin/main. Step 2 (git merge) integrates that work into your local branch and updates your files. Your files on disk do not change until Step 2.
Why does this matter? Because if you run just git fetch, you can see what changed on the remote without touching your working files. You can inspect those changes with git log origin/main or git diff main origin/main. Only when you are ready do you run git merge origin/main to bring those changes in. git pull just does both steps at once for convenience.
Remotes and Tracking Branches Explained
When you clone a repository, Git automatically sets up a remote called origin. A remote is just a short name for a URL. origin is almost always the URL of the GitHub (or GitLab, or Bitbucket) repository you cloned from. You can have multiple remotes if you need to, but most projects start with just one.
For every branch that exists on the remote, Git also creates a corresponding remote-tracking branch in your local repo. These live in the refs/remotes/ namespace and have names like origin/main, origin/develop, or origin/feature-login. They are read-only snapshots. Git updates them when you run git fetch (or git pull). You cannot directly commit to origin/main. It is just a reference that records what main looked like on the remote the last time you fetched.

Figure 2: Remotes, remote-tracking branches, and local branches. git fetch updates the gray remote-tracking branches (origin/main, origin/develop) from the remote server. git merge then integrates those tracking branches into your local green branches. Remote-tracking branches are local copies of remote state, not live connections.
Your local main branch has a concept called a tracking relationship. It knows that it "tracks" origin/main. This is what makes it possible to run git pull with no arguments and have Git know which remote branch to pull from. When you clone a repo, Git sets up this tracking relationship automatically. You can see it by running git branch -vv, which shows all local branches and what remote branch each one tracks.
git pull: Fetching and Merging From Your Tracked Remote
The simplest form of git pull has no arguments at all:
git pull
When you run this, Git looks at your current branch (say, main), finds its configured tracking branch (say, origin/main), fetches any new commits from origin, and then merges origin/main into your local main. It is equivalent to running these two commands separately:
git fetch origin
git merge origin/main
For this to work with no arguments, your branch must have a tracking relationship configured. If it does not, Git will tell you that it does not know which remote and branch to pull from, and it will ask you to be more explicit. That error message is common and it is not a bug, it is Git asking for information it does not have.
Real World Usage
You arrive at your desk in the morning. Your teammates have been committing to the main branch overnight. You are already on main, which tracks origin/main. You type git pull, watch the output, and your local branch is now up to date with everyone's work. This is the scenario where plain git pull is exactly right: you are on a branch with a tracking relationship, you want everything from that remote branch, and you are ready to integrate it now.
git pull origin branch: Explicit Remote and Branch
Sometimes you want to be explicit about which remote and which branch to pull from. The full form of the command lets you specify both:
git pull origin main
This tells Git: go to the remote named origin, get the main branch, and merge it into my current local branch. You can use any remote name and any branch name here. For example:
# Pull from the develop branch of origin into your current branch
git pull origin develop
# Pull from a completely different remote called upstream
git pull upstream main
# Pull a specific branch from a colleague's fork
git pull teammate feature-login
The explicit form is useful in a few situations. If your current branch does not have a tracking relationship set up, the explicit form gives Git all the information it needs. It is also useful when you want to merge a different remote branch into your current branch, for example pulling the latest main into your feature branch to stay up to date with the main line of development.
Important Distinction
When you run git pull origin main, Git merges the remote main into whatever your current branch is. If you are currently on feature-login, it merges origin/main into feature-login. This is sometimes exactly what you want (updating your feature branch with the latest main line changes), but it can be surprising if you expected it to switch your branch first. Always check which branch you are on before pulling.
Reading the Pull Output for the First Time
When a pull succeeds, the output can look a little cryptic. Here is a real example of what you might see:
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 6 (delta 3), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From https://github.com/you/myrepo
a1b2c3d..e4f5g6h main -> origin/main
Updating a1b2c3d..e4f5g6h
Fast-forward
src/auth.js | 42 +++++++++++++++++++++++++
src/login.css | 8 +++++
2 files changed, 50 insertions(+)

Figure 3: Every section of a typical git pull output explained. The “remote:” lines are the fetch step. The “From” and hash lines confirm what was downloaded and where it went. “Fast-forward” means your history was linear and no merge commit was needed.
The two most important pieces of information in that output are the hash range (a1b2c3d..e4f5g6h), which tells you which commits were integrated, and the word "Fast-forward," which tells you how the integration happened. That word is so important that it gets its own section next.
Understanding Merge Commits Created by Pull
When you and your teammates are both committing to the same branch, a situation arises where you have commits the remote does not have, and the remote has commits you do not have. Git calls this a diverged history. When git pull runs its merge step in this situation, it cannot do a fast-forward. Instead, it has to create a special commit called a merge commit.
A fast-forward happens when your local branch has no commits that are not also on the remote. In that case, Git can simply move your branch pointer forward to the remote’s latest commit without creating any new commit. No merge commit is needed. This is the cleanest possible outcome.
A merge commit happens when both sides have unique commits. Git creates a new commit that has two parents: the tip of your local branch and the tip of the remote branch. Your history then has a visible “branch and rejoin” shape in the commit graph.

Figure 4: Fast-forward vs merge commit. A fast-forward (left) simply moves your branch pointer forward, keeping history linear. A merge commit (right) is created when both you and the remote have unique commits. The merge commit has two parents and creates a visible branch-and-rejoin shape in history.
Neither outcome is wrong, but they have different effects on your project’s history. Fast-forwards are clean and linear. Merge commits are honest: they show that collaboration happened and two parallel lines of work were combined. Some teams prefer always having merge commits (for visibility), while others prefer always using rebase to avoid them (for cleanliness). Both approaches are covered later in this tutorial.
Handling Conflicts After a Pull
When the merge step of git pull finds that both you and the remote changed the same part of the same file, it cannot automatically decide which version is correct. This is called a merge conflict, and it stops the pull midway. You will see output like this:
Auto-merging src/config.js
CONFLICT (content): Merge conflict in src/config.js
Automatic merge failed; fix conflicts and then commit the result.
At this point, your working directory contains conflict markers inside the affected files. The file looks like this:
<<<<<<< HEAD
const timeout = 5000;
=======
const timeout = 3000;
>>>>>>> origin/main
The section between <<<<<<< HEAD and ======= is your local version. The section between ======= and >>>>>>> origin/main is the remote version. You need to edit the file, remove the conflict markers, and keep whatever the correct code should be. Then you stage the resolved file and create the merge commit:
# Edit the file to resolve conflicts, then:
git add src/config.js
git commit # or git merge --continue
# If you want to abort the merge entirely and go back to before the pull:
git merge --abort
Tip: Use a Merge Tool
Resolving conflicts in raw text with conflict markers is tedious. Most editors (VS Code, IntelliJ, Vim with plugins) have built-in conflict resolution UI that shows the three versions (yours, theirs, and the common ancestor) side by side. You can also use git mergetool from the command line to launch a configured graphical tool. If your team deals with conflicts regularly, setting up a merge tool is well worth the few minutes of configuration.
git pull — verbose and — quiet
These two flags control how much output git pull produces. They are opposites of each other.
git pull --verbose, also written as git pull -v
Makes the output more detailed. You will see additional information about the objects being transferred during the fetch step, which remote refs are being updated, and what compression ratios were achieved. Useful when you are troubleshooting a slow or failing pull and want to see exactly what is happening over the network connection.
git pull --quiet, also written as git pull -q
Suppresses most of the output. The pull happens silently and you only see error messages if something goes wrong. Useful in scripts, CI/CD pipelines, or situations where you are running pulls in a loop and the output would be noise. Note that this does not suppress conflict messages, since those require your attention.
# Verbose: see every detail of what is being transferred
git pull --verbose
# Quiet: run silently, only show errors
git pull --quiet
# You can combine with other flags too
git pull --quiet origin main
Beginner Pitfalls
Pitfall 1: Pulling With Uncommitted Changes and Getting an Error
If you have uncommitted changes in your working directory that conflict with changes on the remote, git pull will refuse to proceed with a message like "Your local changes to the following files would be overwritten by merge." Git is protecting your work. You have two options: commit your changes first, then pull, or stash them with git stash before pulling and git stash pop afterward. Starting in newer versions of Git, the --autostash flag can do the stash and pop automatically for you, which is covered in the intermediate section.
Pitfall 2: The “Diverged Branch” Error and Not Knowing What to Do
When you see the message “Your branch and origin/main have diverged, and have N and M different commits each, respectively,” it means both you and the remote have unique commits. Git is asking how you want to reconcile them. Since Git 2.27, it will also warn you that you have not specified how to handle diverged branches (the pull.rebase setting). The fix is to decide: do you want to create a merge commit (the default), rebase your commits on top of the remote's commits (cleaner history), or force a fast-forward only (which fails if there is divergence)? These are covered in the intermediate section.
Pitfall 3: Pulling on the Wrong Branch
It is very easy to forget which branch you are on and run git pull origin main while you are on a feature branch. This merges the remote main into your feature branch, which may not be what you wanted at all. Always run git status or git branch to confirm your current branch before pulling, especially if you are about to pull from a different branch than the one you are on.
Pitfall 4: Force-Pushing After Someone Else Has Pulled
If you run git push --force to rewrite history on a shared branch, and then someone else runs git pull on that branch, Git will try to merge the old history with the new history, creating a confused mess. Force-pushing is sometimes necessary, but only on branches that are not shared with other people. If you need to force-push on a shared branch, coordinate with your team and make sure everyone re-clones or resets their local copies.
Pitfall 5: Not Understanding That git pull Can Create Merge Commits
Many beginners are surprised to find merge commits in their project’s history that say something like “Merge branch ‘main’ of github.com/you/myrepo.” These come from running git pull when the history had diverged. If your team wants a clean linear history, you need to use git pull --rebase instead, or configure pull.rebase = true globally. This is one of the most common policy decisions teams make about their Git workflow.
**inter-git.com teaches git fundamentals visually: [inter-git.com](https://inter-git.com)** is an interactive Git tutorial where each command is shown visually so you can see exactly how it works in real time. It runs entirely in your browser, so there is nothing to install. Before moving on to the intermediate level, it is a great place to practice what you have just learned.
Level 2 Intermediate: Controlling How git pull Integrates Remote Work
At the intermediate level, the big question is: how should the remote work be integrated into your local branch? The default answer is “create a merge commit if needed,” but that is not always the right answer for every team or workflow. This section covers all the flags that let you control that integration strategy, plus several other useful options you will reach for regularly.
git pull — rebase: The Cleaner Alternative to Merge
This is arguably the most important flag in the entire git pull command set, and understanding it deeply will change how you work with Git on a team. When you pass --rebase, the second step of git pull changes from a merge to a rebase. Instead of creating a merge commit, Git replays your local commits on top of the remote's latest commits, as if you had written them after the remote work was already there.
git pull --rebase
git pull --rebase origin main

Figure 5: The core difference between git pull (merge mode) and git pull — rebase. With merge mode, your local commit X and the remote commits D and E are combined into a merge commit M with two parents. With rebase mode, your commit X is “replayed” on top of E as X-prime, creating a perfectly linear history with no merge commit.
The important thing to understand about rebase is that it rewrites your local commits. Your commit X gets a new hash (X-prime) because its parent changed. The changes inside X are identical, but its position in history is different. This is why you should never rebase commits that you have already pushed to a shared branch. If you only have local commits that others have not seen yet, rebasing is perfectly safe.
Real World Usage
Your team uses a trunk-based development model where main is always deployable and everyone commits to it directly (or via very short-lived feature branches). Because dozens of commits land on main every day, you quickly accumulate merge commits if you use the default pull behavior. Most teams in this situation configure git pull --rebase as the default (using git config --global pull.rebase true) so that every developer's work slots cleanly into the linear history. Code review tools like GitHub and GitLab also display linear histories more cleanly than histories full of merge commits.
Rebase and the New Warning From Git 2.27+
Since Git 2.27, if you run git pull in a diverged state without having configured pull.rebase, Git shows a warning asking you to specify how you want to handle diverged branches. It shows three options: git config pull.rebase false (merge, the old default), git config pull.rebase true (rebase), and git config pull.ff only (fast-forward only). This warning was added because many developers were accidentally creating merge commits they did not want. The fix is to pick one of those three and set it globally so the warning never appears again.
git pull — ff-only: Only Fast-Forward, Never Create a Merge Commit
This flag tells git pull to refuse to do anything unless the merge can be done as a fast-forward. If the history has diverged (you have local commits the remote does not have), the pull will fail with an error rather than creating a merge commit or rebasing.
git pull --ff-only
git pull --ff-only origin main
The error message you will see when a fast-forward is not possible looks like this:
fatal: Not possible to fast-forward, aborting.
This is useful when you want a strong guarantee: “only update my branch if it is safe to do so without any integration work.” If the command fails, it is telling you that you have local work that needs to be dealt with first, either by rebasing or by explicitly deciding to merge.
Real World Usage
You are maintaining a long-running release branch and you only want to pull upstream bug fixes into it when those fixes apply cleanly. If someone has also committed directly to the release branch and created a divergence, you do not want a merge commit created automatically. You use git pull --ff-only so that any divergence triggers an error instead of silently creating a complicated merge that could introduce unexpected changes. It forces you to make an explicit decision about how to handle the divergence.
git pull — no-ff: Always Create a Merge Commit
The opposite of --ff-only, this flag forces a merge commit to be created even when a fast-forward would have been possible. Even if the remote's history is a direct ancestor of yours, Git will create a new commit with two parents.
git pull --no-ff
git pull --no-ff origin develop
This is useful when you want every pull to be clearly visible in the project’s history, even when the merge was trivially easy. Some teams prefer this because it makes it clear exactly when work from the remote was integrated, and by whom. The merge commit acts as a documented record of synchronization. However, it does create more commits and makes the history less linear.
git pull — no-commit: Merge But Let Me Review Before Committing
With this flag, git pull performs the fetch and the merge, but stops just before creating the final merge commit. The merged changes are in your working directory and staging area, ready to commit, but the commit itself has not happened yet. You get a chance to review, modify, or add more changes before finalizing the merge.
git pull --no-commit
git pull --no-commit origin main
After the merge is staged but not committed, you can inspect the state with git status and git diff --staged. If everything looks good, you commit with git commit. If you want to abandon the merge, you run git merge --abort.
Real World Usage
Your team maintains a changelog file (CHANGELOG.md) that is updated by different people. When you pull someone else's work in, the merge might put the changelog entries in a slightly awkward order or you want to add a note about the integration. Using --no-commit lets you pull in all the code changes automatically, then manually tidy up the changelog before committing. This way, the merge commit in the history reflects exactly what you intended, including any manual adjustments.
Note: — no-commit Does Not Apply to Fast-Forwards
If the pull can be done as a fast-forward, --no-commit has no effect. A fast-forward does not create a commit, it just moves the branch pointer, so there is nothing to stop before. The --no-commit flag only kicks in when an actual merge commit would have been created. If you want to prevent fast-forwards so that --no-commit always applies, combine it with --no-ff.
git pull — squash: Flatten Remote Work Into One Commit
The --squash flag is for an unusual but sometimes very useful workflow: you want to bring in all the remote changes as a single new commit in your local history, regardless of how many commits are on the remote branch. This is the pull equivalent of the "squash merge" option you see in GitHub pull requests.
git pull --squash origin feature-login
git commit -m "Integrate feature-login work"
After running git pull --squash, the changes from the remote branch are in your staging area but not committed. You then run git commit yourself to create a single commit representing all the work. This is intentional: Git cannot generate a good commit message for the squashed work automatically.
Note that --squash implies --no-commit, so you always have to create the commit yourself. Also note that the resulting commit does not preserve the parent information from the remote branch's commits, so Git will not know you have already integrated this work if you try to pull the same branch again later. Use this flag carefully and only when you genuinely want to collapse many remote commits into one local one.
Real World Usage
You are integrating a long-running feature branch that has 40 commits full of work-in-progress messages like “WIP,” “fix typo,” and “trying something.” You do not want all those messy intermediate commits in your main branch history. Using git pull --squash origin feature-login pulls all the changes as a single staged diff, and then you write one clean, comprehensive commit message that describes the entire feature. This is exactly what GitHub's "Squash and merge" button does under the hood.
git pull — stat and — no-stat
After the merge step of a pull completes, Git can show you a summary of which files changed and by how many lines. The --stat flag ensures this summary is shown even if your global configuration has turned it off. The --no-stat flag suppresses it even if your configuration turns it on.
# Always show the file change summary after merging
git pull --stat
# Never show the file change summary
git pull --no-stat
The stat output looks like this, and it is the same format as git diff --stat:
src/auth.js | 42 ++++++++++++++
src/login.css | 8 +++
tests/auth.test.js | 18 ++++++
3 files changed, 68 insertions(+)
This is controlled globally by the merge.stat configuration option. The --stat and --no-stat flags override that setting for a single pull. Most developers find the stat output helpful because it gives a quick at-a-glance sense of what changed without having to run a separate git diff.
git pull — tags and — no-tags
When you run git pull, Git also fetches tags from the remote by default, but only tags that are reachable from the commits it just fetched. The --tags and --no-tags flags change this behavior.
git pull --tags
Fetches all tags from the remote, not just the ones reachable from the commits being fetched. This is equivalent to git fetch --tags combined with the merge step. Use this when you want to make sure you have every tag from the remote, including tags on branches you have not fetched.
git pull --no-tags
Suppresses automatic tag fetching entirely. Only the commits and their parent chains are fetched, with no tags at all. Useful if your remote has thousands of tags (common in large monorepos or projects with many releases) and fetching them all would be slow.
# Fetch all remote tags, not just reachable ones
git pull --tags
# Fetch commits but skip all tags
git pull --no-tags origin main
git pull — autostash: Pull Even With a Dirty Working Tree
This is a very practical flag that solves a common frustration. Normally, if you have uncommitted changes in your working directory that conflict with what the pull would bring in, Git refuses to proceed. You have to manually stash your work, pull, and then pop the stash. The --autostash flag automates exactly that sequence.
# Automatically stashes your uncommitted changes, pulls, then pops the stash
git pull --autostash
git pull --autostash --rebase origin main
Under the hood, Git runs git stash push before the pull, then runs git stash pop after the pull completes. If the stash pop causes a conflict (because the pulled changes and your stashed changes both modified the same part of a file), you will need to resolve that conflict just like any other merge conflict.
Real World Usage
You are in the middle of debugging a problem. You have made some temporary changes to a config file to test something. A colleague tells you they just pushed a fix that you need. Instead of committing your debugging changes (which you do not want in history) or manually stashing and popping, you run git pull --autostash. Git saves your temporary changes, pulls the fix, and restores your temporary changes. You continue debugging with both your changes and the new fix in place.
Make — autostash Permanent
You can configure autostash to always be on when rebasing by setting git config --global rebase.autoStash true. For plain merge pulls, you can configure it with git config --global pull.autostash true. Once you use this feature, it is hard to go back.
git pull — recurse-submodules: Keeping Submodules in Sync
If your project uses Git submodules (separate repositories nested inside your main repository), pulling the main project does not automatically update the submodules to the commits your updated main project expects. The --recurse-submodules flag changes that behavior.
# Pull the main project AND update all submodules to their expected commits
git pull --recurse-submodules
# With an explicit remote and branch
git pull --recurse-submodules origin main
When you use this flag, after the main project is updated, Git also updates each submodule to the commit that the newly pulled version of your main project points to. Without this flag, if someone updated the expected submodule commit in the main project, your local submodules will be out of date and you might get build errors or unexpected behavior.
Configure it Permanently
If your project uses submodules, it is almost always right to update them on every pull. Set git config --global submodule.recurse true and you will never need to type --recurse-submodules again. Every pull, fetch, and checkout will automatically update submodules.
git pull — allow-unrelated-histories
By default, Git refuses to merge two repositories that do not share a common ancestor commit. This protection was added in Git 2.9 because merging completely unrelated histories is almost always a mistake. But occasionally it is exactly what you want, and this flag removes the restriction.
git pull --allow-unrelated-histories origin main
Real World Usage
The most common scenario is combining two separately initialized repositories. You created a local repository with git init and made some commits. Then you created a new repository on GitHub (which automatically creates an initial commit with a README). When you try to pull the GitHub repository into your local one, Git refuses because they have no common history. Adding --allow-unrelated-histories lets you force the merge, combining the two unrelated histories into one. After this initial merge, everything behaves normally. This is also sometimes needed when importing an old SVN or Mercurial project into an existing Git repository.
Use With Caution If you are getting an “unrelated histories” error in any situation other than a deliberate repository combination, stop and investigate before using this flag. The error is telling you that something unusual is going on. Common causes include accidentally pulling from the wrong remote, pointing a remote at a completely different project, or a corrupted repository state. The flag is not wrong, but the situation that triggered the error usually is.
Intermediate Pitfalls
Pitfall 1: Using — rebase and Losing Your Changes to a Force Push
If you run git pull --rebase and a teammate has force-pushed to the remote branch (rewriting history), the rebase will try to replay your commits on top of the new history. This can result in your commits being applied twice or in strange conflicts. The safest approach when you know a force push happened is to reset your branch to the remote's state: git fetch origin and then git reset --hard origin/main. Only do this if you do not have local commits you want to keep.
Pitfall 2: — squash Breaking Future Pulls From the Same Branch
When you use git pull --squash origin feature-login, the resulting commit does not have the remote branch's commits as its parents. Git does not know you have integrated that work. If you try to pull from feature-login again later, Git will see all those same commits as new and try to integrate them again, causing conflicts. Always treat a squash pull as a one-time final integration, not as a way to partially pull from a branch you will continue working with.
Pitfall 3: — autostash Masking a Conflict You Should Deal With First
The --autostash flag is convenient, but it can hide a situation that deserves attention. If your stashed changes conflict with what the pull brings in, Git will pop the stash after the pull and immediately present you with a conflict. At that point, the context for why your stashed changes exist may be unclear. A better habit for complex situations: commit your changes to a temporary branch, pull, and then cherry-pick or merge your temporary branch back. That gives you a clearer record of both sets of changes.
Pitfall 4: Forgetting That — rebase Changes Commit Hashes
After git pull --rebase, your local commits have new hashes because they have been replayed with new parents. If you had already noted those hashes somewhere (in a ticket, a Slack message, or a script), those references are now stale. This is a minor issue in practice, but it is worth being aware of. It is also why you should never rebase commits that have already been pushed to a shared branch: other people's repositories still have the old hashes, and their next pull will be very confusing.
Level 3 Advanced: Merge Strategies, Rebase Modes, Shallow Clones, and Configuration
The advanced level of git pull is where you start shaping Git's behavior at a deeper level. These are the options that let you specify exactly which merge algorithm to use, how to handle histories where automatic merging fails, how to work with large repositories efficiently, and how to configure all of the above permanently so you never have to type flags manually.
Merge Strategies: ort, recursive, octopus, ours, subtree
When git pull runs its merge step, it uses an algorithm called a merge strategy to figure out how to combine the two histories. The --strategy flag (or the short form -s) lets you choose which algorithm to use.
git pull --strategy=ort origin main
git pull -s ort origin main # same thing, short form

Figure 6: The five merge strategies available in git pull. The “ort” strategy has been the default since Git 2.34 and handles the vast majority of merges correctly. The others exist for specific advanced scenarios described in detail below.
The ort strategy (which stands for "Ostensibly Recursive's Twin") is the default since Git 2.34 and is designed to be safe for concurrent use in multi-threaded environments, which matters in large repository operations. For most developers on most projects, you will never need to specify a strategy manually.
The ours strategy is the most surprising one. When you run git pull -s ours origin feature-old, Git creates a merge commit that looks like it integrated the remote branch, but actually throws away all the remote changes and keeps only your local content. The merge commit is there for history, but the files are identical to what you had before. This is used in situations like: "we tried that feature branch, decided we do not want any of it, but we want the history to show that the decision was made and the branch is closed."
Strategy Options: -X ours, -X theirs, -X patience, and More
Strategy options are sub-settings that control the behavior of the chosen merge strategy. They are specified with the -X flag (note: capital X, different from the lowercase -x which does not exist). The most useful strategy options are for the default ort and recursive strategies.
# When a conflict occurs, automatically take our version
git pull -X ours origin main
# When a conflict occurs, automatically take their version (remote)
git pull -X theirs origin main
# Use patience diff algorithm for merge (better at detecting moved blocks)
git pull -X patience origin main
# Ignore whitespace changes when merging
git pull -X ignore-space-change origin main
git pull -X ignore-all-space origin main
# Tune how rename detection works
git pull -X find-renames=50 origin main
# Subtree prefix: when using subtree strategy
git pull -s subtree -X subtree=lib/vendor origin main
The most commonly used strategy options are -X ours and -X theirs. These are different from the ours strategy. While the -s ours strategy discards all remote changes, -X ours only kicks in when there is a conflict. Uncontested changes from the remote are still merged normally. Only the conflicting sections are automatically resolved by taking your version. This is a subtle but important difference.
Real World Usage
Your team maintains a GENERATED_FILE.json that is rebuilt from source by your build system on every branch. When merging branches, this file almost always has conflicts because both branches regenerated it. You know that your current branch's version of this file is always the one you want to keep, so you use git pull -X ours origin main to automatically resolve this one recurring conflict without having to manually resolve it every single time. The legitimate code conflicts still require your attention; only the generated file conflicts are resolved automatically.
Rebase Modes: interactive, merges, and preserve
The --rebase flag is not just on or off. You can pass specific values to it to control exactly how the rebase works.
# Standard rebase: replay commits linearly on top of remote
git pull --rebase=true
git pull --rebase # same as =true
# Interactive rebase: opens editor to let you edit, squash, reorder commits
git pull --rebase=interactive
# Preserve merge commits: replays commits but keeps merge commit structure
git pull --rebase=merges
# Deprecated: preserve was the old name for merges mode
git pull --rebase=preserve # avoid this, use =merges instead
The --rebase=interactive mode is particularly powerful. Instead of automatically replaying your commits, Git opens your configured editor (usually nano or vim, or whatever you set as core.editor) with a todo list of your commits and the actions to perform on each one. You can reorder commits, squash several into one, edit commit messages, drop commits entirely, or split commits by marking them for editing.

Figure 7: The interactive rebase todo file opened by git pull — rebase=interactive. You edit this file before the rebase runs to control exactly which commits are kept, combined, reordered, or deleted. This is how you clean up a messy local commit history before integrating with remote work.
The --rebase=merges mode is for when your local work itself contains merge commits (for example, you merged a sub-feature branch into your feature branch locally). In standard rebase mode, those merge commits are flattened out and the commits are replayed as if they were all sequential. The merges mode preserves the structure of your merge commits during the rebase, which gives a more accurate representation of your local development history.
Shallow Clones: — depth, — update-shallow, and — unshallow
A shallow clone is a repository where the history has been intentionally truncated to a certain depth. Instead of downloading every commit since the project began, you only download the most recent N commits. This dramatically reduces clone time and disk space usage, which is why CI/CD systems almost always use shallow clones.
# Pull and fetch only the most recent 10 commits of history
git pull --depth=10 origin main
# Pull and update an existing shallow clone's depth
git pull --update-shallow origin main
# Convert a shallow clone to a full clone (fetch all history)
git pull --unshallow origin main

Figure 8: Full clone vs shallow clone. A shallow clone downloads only the most recent N commits, making it much faster and smaller. This is ideal for CI/CD systems. You can convert back to a full clone at any time with git pull — unshallow, which fetches the rest of the history from the remote.
The --update-shallow flag is for a subtler case. When you pull new commits into a shallow clone, those new commits might reference parents that are beyond your shallow boundary. The --update-shallow flag allows Git to update the shallow boundary as needed to accommodate the new commits, keeping the clone valid and functional. Without it, pulling into a shallow clone could fail or produce an inconsistent state.
Real World Usage
Your CI/CD pipeline runs on every pull request. The full repository history is 5GB because the project has been running for ten years and the database schema migrations alone have thousands of commits. Your CI only needs the latest code to run tests, not ten years of history. You configure your CI to use git clone --depth=1 for the initial clone and git pull --depth=1 origin main for subsequent updates. This reduces your CI clone time from 4 minutes to 12 seconds and cuts disk usage dramatically. If a build tool needs more history (for example, to generate a changelog), you can run git pull --unshallow in a specific step that needs it.
git pull — jobs: Parallel Submodule Fetching
When a repository has many submodules and you use --recurse-submodules, fetching all of them sequentially can be slow. The --jobs flag specifies how many submodule fetches can run in parallel.
# Fetch up to 4 submodules simultaneously instead of one at a time
git pull --recurse-submodules --jobs=4 origin main
git pull --recurse-submodules -j 4 origin main # short form
The number of jobs you should use depends on your machine’s available CPU and network bandwidth. For most development machines, a value between 4 and 8 is reasonable. Setting it too high will not help and may actually slow things down if the network becomes the bottleneck. You can also set this permanently with git config submodule.fetchJobs 4.
git pull — atomic: Safe Atomic Updates
This flag ensures that the remote-tracking references update either all at once or not at all. Without it, if you are fetching multiple refs and the operation fails partway through, some refs will have been updated while others have not, leaving your repository in a partially updated state.
git pull --atomic origin main
The --atomic flag also ensures that if fetching a ref would cause a non-fast-forward update that you have not explicitly allowed, the entire fetch is aborted rather than being partially applied. This is most relevant in environments where Git is being used as part of an automation pipeline where consistency is critical.
git pull — negotiate-only
This flag is a specialized option for protocol negotiation. It runs the negotiation phase with the remote (where client and server exchange information about what objects they each have) but does not actually download any objects. It is used by higher-level tooling that needs to understand what would be fetched without actually fetching it.
git pull --negotiate-only origin main
This is not something you would use in day-to-day development. It appears in tools that implement custom Git protocols or in debugging scenarios where you want to inspect the negotiation phase without committing to a full fetch.
Setting Upstream Tracking With -u
While not strictly a git pull flag, the tracking relationship that makes git pull work with no arguments is set up using git push -u or git branch --set-upstream-to. Understanding this is essential for using git pull effectively.
# Create and push a new branch, setting up tracking in one step
git push -u origin feature-login
# After this, git pull on feature-login with no arguments works
git pull # Git knows to pull from origin/feature-login
# Manually set tracking for a branch that already exists
git branch --set-upstream-to=origin/main main
# See all tracking relationships at a glance
git branch -vv
The output of git branch -vv looks something like this:
* feature-login a1b2c3d [origin/feature-login: ahead 2, behind 1] Add login form
main e4f5g6h [origin/main] Update dependencies
hotfix-auth b2c3d4e [No tracking branch configured]
The text in brackets tells you the tracking branch, and the “ahead N, behind M” counts tell you exactly how diverged you are from the remote. This is the single most useful command for understanding the state of your repository before pulling.
Configuration Variables: pull.rebase, pull.ff, pull.autostash, and Branch Settings
All of the behavior covered in this tutorial can be made permanent through Git configuration. Configuration can be set at three levels: local (just this repository), global (all your repositories on this machine), and system (all users on this machine).
Config Variable: pull.rebase
What It Controls: Whether pull uses merge or rebase as the integration step
Common Values and Effects: false: merge (old default), true: rebase, ff-only: refuse if not fast-forward
Config Variable: pull.ff
What It Controls: Fast-forward behavior when no rebase is configured
Common Values and Effects: true: fast-forward when possible (default), false: always merge commit, only: refuse non-fast-forward
Config Variable: pull.autostash
What It Controls: Whether to autostash before every pull
Common Values and Effects: true: always autostash and pop, false: default behavior (refuse with dirty tree)
Config Variable: submodule.recurse
What It Controls: Whether to recurse into submodules on every pull, fetch, checkout
Common Values and Effects: true: always recurse, false: never (default)
Config Variable: submodule.fetchJobs
What It Controls: How many submodules to fetch in parallel
Common Values and Effects: Integer, e.g. 4 or 8. Default is 1 (sequential)
Config Variable: branch.autosetuprebase
What It Controls: Whether new branches automatically use rebase when pulling
Common Values and Effects: always: new branches default to rebase, never: use merge (default)
Config Variable: branch.<name>.remote
What It Controls: Which remote a specific branch tracks
Common Values and Effects: e.g. origin or upstream. Set automatically by git push -u
Config Variable: branch.<name>.merge
What It Controls: Which remote branch a specific local branch tracks
Common Values and Effects: e.g. refs/heads/main. Set automatically by git push -u
Here are the most useful configurations to set globally and why:
# OPTION A: Rebase-based workflow (clean linear history)
git config --global pull.rebase true
# OPTION B: Merge-based workflow with fast-forward when possible
git config --global pull.rebase false
git config --global pull.ff true
# OPTION C: Strict fast-forward only (fail loudly on divergence)
git config --global pull.ff only
# Always autostash when pulling
git config --global pull.autostash true
# New branches automatically set up to rebase when pulling
git config --global branch.autosetuprebase always
# Always recurse into submodules
git config --global submodule.recurse true
# Parallel submodule fetching
git config --global submodule.fetchJobs 4
# See your current global configuration
git config --global --list | grep pull
The most important choice to make and stick with is whether you want a rebase-based or merge-based workflow. Setting this once globally means you never see the Git 2.27+ warning again, and every pull on every repository behaves consistently.
Real-World Advanced Workflows
Workflow 1: The Trunk-Based Rebase Workflow
Many high-velocity engineering teams use a workflow where everyone works from main directly or merges feature branches quickly. In this environment, the goal is to keep history as linear as possible so that git log is readable and git bisect works well.
# Global config: always rebase, always autostash
git config --global pull.rebase true
git config --global pull.autostash true
# Morning routine: update main cleanly
git checkout main
git pull # fetches and rebases automatically
# Start work on a feature
git checkout -b feature-payment
# Stay in sync with main daily
git pull --rebase origin main # replay your feature commits on latest main
# Before merging your feature, do a final rebase and clean up commits
git pull --rebase=interactive origin main
Workflow 2: The Long-Running Feature Branch Workflow
When features take weeks to develop, you need a strategy for keeping the feature branch in sync with the main line without accumulating hundreds of merge commits.
# On your feature branch, stay in sync with main using rebase
git checkout feature-large-redesign
git pull --rebase origin main
# If you encounter conflicts during the rebase:
# 1. Git pauses and shows the conflict
# 2. You resolve the conflict in your editor
git add src/affected-file.js
git rebase --continue
# If the rebase goes wrong and you want to abandon it:
git rebase --abort
# When ready to merge back to main (as a merge commit for visibility):
git checkout main
git pull
git merge --no-ff feature-large-redesign
git push origin main
Workflow 3: Open Source Fork Workflow (Multiple Remotes)
When contributing to open source projects, you typically have two remotes: origin (your fork) and upstream (the original project). Keeping your fork in sync requires pulling from upstream and pushing to origin.
# One-time setup: add the upstream remote
git remote add upstream https://github.com/original-project/repo.git
# Check what remotes you have
git remote -v
# Update your local main from the upstream project
git checkout main
git pull --ff-only upstream main # should always fast-forward if you never commit to main
# Push the updated main to your fork
git push origin main
# Create a feature branch for your contribution
git checkout -b fix-issue-123
# ... do your work ...
git push -u origin fix-issue-123 # -u sets up tracking
# Before submitting a pull request, rebase on upstream main
git pull --rebase upstream main
Workflow 4: CI/CD Pipeline Pull
In CI/CD environments, pulls need to be fast, deterministic, and quiet. Here is how to configure a pull for automation:
# Shallow pull for speed: only last 1 commit needed for most CI tasks
git pull --depth=1 --quiet --ff-only origin main
# If your CI needs tags (for version detection):
git pull --depth=1 --tags --quiet origin main
# For a repository with submodules:
git pull --depth=1 --recurse-submodules --jobs=4 --quiet origin main
# If the CI might be running on a previously shallow clone and
# a build step needs full history (e.g., for changelog generation):
git pull --unshallow --quiet origin main
Advanced Pitfalls
Pitfall 1: Using -s ours Instead of -X ours (Very Different Results)
This is one of the most dangerous confusions in Git. git pull -s ours (strategy "ours") silently discards ALL remote changes and keeps your local version of every file. git pull -X ours (strategy option "ours") only applies to conflicting sections and still merges everything else normally. If you want to automatically resolve conflicts in favor of your version while still merging non-conflicting remote changes, use -X ours. If you intend to discard all remote changes entirely, use -s ours, but make sure that is really what you want.
Pitfall 2: Shallow Clones Breaking Certain Git Operations
Shallow clones work great for CI but can break commands that need full history. git blame only shows blame back to the shallow boundary. git log --follow to track file renames may not work correctly. git bisect cannot search commits before the shallow boundary. git merge-base may return incorrect results. If you are seeing strange behavior with history-based commands, check whether you are in a shallow clone with git rev-parse --is-shallow-repository. If the answer is "true," run git pull --unshallow to fix it.
Pitfall 3: pull.rebase = true Causing Trouble on Shared Branches
Configuring pull.rebase = true globally is great for your own feature branches, but it can be dangerous if you occasionally work on a shared branch where other people have already seen your commits. Rebasing in that situation rewrites history, which causes problems for your teammates. The safest approach is to use pull.rebase = true globally but explicitly override it with git pull --no-rebase on the specific occasions where you are pulling a shared branch that others have already pulled from.
Pitfall 4: The “Cannot Fast-Forward” Error After Setting pull.ff = only
If you configure pull.ff = only and then find yourself in a diverged state, every pull will fail with "Not possible to fast-forward, aborting." The fix is not to change the configuration but to deal with the divergence first. Either rebase your local commits on top of the remote (git fetch origin followed by git rebase origin/main), or explicitly create a merge commit by running git merge origin/main directly. The pull.ff = only setting is intentionally strict: it forces you to make a deliberate choice rather than accidentally creating a merge commit.
Pitfall 5: Interactive Rebase During Pull Overwriting Your Commit Messages
When you use git pull --rebase=interactive, the todo file opens in your terminal editor, which for many people is set to vim by default. If you are not familiar with vim, you might accidentally save the file without making any changes (which is fine) or you might exit in a way that signals failure (which aborts the rebase). To set a more comfortable editor, run git config --global core.editor "nano" or git config --global core.editor "code --wait" for VS Code.
Pitfall 6: — allow-unrelated-histories on the Wrong Repository
If you ever get the “refusing to merge unrelated histories” error and you were NOT intentionally combining two separate repositories, do not immediately reach for --allow-unrelated-histories. First ask: did I accidentally initialize a new repository in the wrong directory? Did I point the wrong remote at this repository? Is the remote pointing at a completely different project? The error message is protecting you from a mistake. Fix the root cause before forcing the merge.
Quick Reference Card
# git pull: Essential Commands at a Glance
git pull # fetch + merge from tracked remote
git pull origin main # explicit remote and branch
git pull --rebase # fetch + rebase instead of merge
git pull --rebase=interactive # rebase with interactive commit editing
git pull --rebase=merges # rebase preserving local merge commits
git pull --ff-only # only fast-forward, fail on divergence
git pull --no-ff # always create merge commit
git pull --no-commit # merge but stop before committing
git pull --squash # flatten remote commits into one staged diff
git pull --autostash # auto stash/pop around the pull
git pull --recurse-submodules # also update submodules
git pull --recurse-submodules -j 4 # fetch submodules in parallel
git pull --depth=1 # shallow pull (only latest commit)
git pull --unshallow # convert shallow to full clone
git pull --tags # fetch all tags from remote
git pull --no-tags # fetch commits but skip all tags
git pull --stat # show file change summary after merge
git pull --no-stat # suppress file change summary
git pull --verbose # more output detail
git pull --quiet # suppress output (good for scripts)
git pull --allow-unrelated-histories # merge repos with no common ancestor
git pull -s ort # use ort merge strategy (default)
git pull -s ours # discard all remote changes
git pull -X ours # auto-resolve conflicts with our version
git pull -X theirs # auto-resolve conflicts with remote version
git pull --atomic # all-or-nothing ref updates
Complete Flags Reference Table
Flag or Option: git pull
Short Form: None
Level: Beginner
Plain-English Description: Fetch and merge from the tracked remote of the current branch.
Flag or Option: git pull origin main
Short Form: None
Level: Beginner
Plain-English Description: Explicitly specify the remote and branch to pull from.
Flag or Option: --verbose
Short Form: -v
Level: Beginner
Plain-English Description: Show more detail about what is being transferred and updated.
Flag or Option: --quiet
Short Form: -q
Level: Beginner
Plain-English Description: Suppress output except for errors. Useful in scripts.
Flag or Option: --rebase
Short Form: None
Level: Intermediate
Plain-English Description: Rebase local commits on top of remote commits instead of creating a merge commit.
Flag or Option: --rebase=interactive
Short Form: None
Level: Advanced
Plain-English Description: Like --rebase but opens an editor to let you edit, squash, or reorder commits.
Flag or Option: --rebase=merges
Short Form: None
Level: Advanced
Plain-English Description: Rebase while preserving any local merge commit structure.
Flag or Option: --no-rebase
Short Form: None
Level: Intermediate
Plain-English Description: Override pull.rebase config and use merge for this pull only.
Flag or Option: --ff-only
Short Form: None
Level: Intermediate
Plain-English Description: Only fast-forward the branch pointer. Fail with an error if branches have diverged.
Flag or Option: --no-ff
Short Form: None
Level: Intermediate
Plain-English Description: Always create a merge commit, even when fast-forward is possible.
Flag or Option: --ff
Short Form: None
Level: Intermediate
Plain-English Description: Explicitly allow fast-forward when possible (overrides config).
Flag or Option: --no-commit
Short Form: None
Level: Intermediate
Plain-English Description: Perform the merge but stop before creating the merge commit.
Flag or Option: --squash
Short Form: None
Level: Intermediate
Plain-English Description: Stage all remote changes as a single diff. You create the commit yourself.
Flag or Option: --stat
Short Form: None
Level: Intermediate
Plain-English Description: Show a summary of which files changed and by how many lines after merging.
Flag or Option: --no-stat
Short Form: -n
Level: Intermediate
Plain-English Description: Suppress the file change summary even if configured to show it.
Flag or Option: --tags
Short Form: None
Level: Intermediate
Plain-English Description: Fetch all tags from the remote, not just reachable ones.
Flag or Option: --no-tags
Short Form: None
Level: Intermediate
Plain-English Description: Suppress automatic tag fetching entirely.
Flag or Option: --autostash
Short Form: None
Level: Intermediate
Plain-English Description: Automatically stash a dirty working tree before pull and restore it afterward.
Flag or Option: --no-autostash
Short Form: None
Level: Intermediate
Plain-English Description: Override pull.autostash config for this pull only.
Flag or Option: --recurse-submodules
Short Form: None
Level: Intermediate
Plain-English Description: After updating the main repository, also update submodules to their expected commits.
Flag or Option: --no-recurse-submodules
Short Form: None
Level: Intermediate
Plain-English Description: Do not recurse into submodules for this pull.
Flag or Option: --allow-unrelated-histories
Short Form: None
Level: Intermediate
Plain-English Description: Allow merging two repositories that share no common ancestor commit.
Flag or Option: --strategy=<name>
Short Form: -s
Level: Advanced
Plain-English Description: Choose a merge strategy such as ort (default), recursive, octopus, ours, or subtree.
Flag or Option: --strategy-option=<opt>
Short Form: -X
Level: Advanced
Plain-English Description: Pass a sub-option to the merge strategy, such as -X ours, -X theirs, or -X patience.
Flag or Option: --depth=<n>
Short Form: None
Level: Advanced
Plain-English Description: Fetch only the most recent N commits. Creates or deepens a shallow clone.
Flag or Option: --unshallow
Short Form: None
Level: Advanced
Plain-English Description: Convert a shallow clone into a full clone by fetching all missing history.
Flag or Option: --update-shallow
Short Form: None
Level: Advanced
Plain-English Description: Update the shallow boundary when pulling into an existing shallow clone.
Flag or Option: --jobs=<n>
Short Form: -j
Level: Advanced
Plain-English Description: Fetch this many submodules in parallel when --recurse-submodules is used.
Flag or Option: --atomic
Short Form: None
Level: Advanced
Plain-English Description: Update remote-tracking references atomically so that all updates succeed or all fail.
Flag or Option: --negotiate-only
Short Form: None
Level: Advanced
Plain-English Description: Run negotiation with the remote but do not actually download objects. Mainly used for tooling.
Flag or Option: --prune
Short Form: None
Level: Intermediate
Plain-English Description: Remove local remote-tracking references that no longer exist on the remote.
Flag or Option: --append
Short Form: -a
Level: Advanced
Plain-English Description: Append fetched references to FETCH_HEAD instead of overwriting it.
Flag or Option: --upload-pack=<path>
Short Form: None
Level: Advanced
Plain-English Description: Specify a custom path to git-upload-pack on the remote host.
Flag or Option: --force
Short Form: -f
Level: Advanced
Plain-English Description: Allow updating local references even when the update is not a fast-forward.
Flag or Option: --keep
Short Form: -k
Level: Advanced
Plain-English Description: Keep the downloaded pack even if it is not used (primarily for debugging).
Flag or Option: --deepen=<n>
Short Form: None
Level: Advanced
Plain-English Description: Deepen an existing shallow clone by N more commits from its current depth.
Flag or Option: --shallow-since=<date>
Short Form: None
Level: Advanced
Plain-English Description: Shallow clone with history reaching back to a specific date instead of a fixed depth.
Flag or Option: --shallow-exclude=<ref>
Short Form: None
Level: Advanced
Plain-English Description: Exclude commits reachable from the specified reference when deepening a shallow clone.
Flag or Option: --ipv4
Short Form: -4
Level: Advanced
Plain-English Description: Use IPv4 addresses only when connecting to the remote.
Flag or Option: --ipv6
Short Form: -6
Level: Advanced
Plain-English Description: Use IPv6 addresses only when connecting to the remote.
Flag or Option: --no-verify
Short Form: None
Level: Advanced
Plain-English Description: Bypass pre-merge and commit-message hooks that would otherwise run.
Flag or Option: --signoff
Short Form: None
Level: Advanced
Plain-English Description: Add a Signed-off-by trailer to the merge commit.
Flag or Option: --gpg-sign=<keyid>
Short Form: -S
Level: Advanced
Plain-English Description: GPG-sign the resulting merge commit with the specified key.
Conclusion
If you started this tutorial thinking git pull was just a "sync button," you now know it is considerably more nuanced than that. It is two commands (fetch and merge) combined into one convenience wrapper, and the merge step has a dozen different modes of operation depending on what kind of history you want, how strict you want to be about fast-forwards, and how you want to handle the edge cases.
The most important decisions to make and lock into your global configuration are:
- Do you want a rebase-based workflow (
pull.rebase = true) or a merge-based one? Rebase gives cleaner linear history. Merge is more transparent about when integration happened. - Do you want
pull.ff = onlyto fail loudly on divergence, or do you want Git to handle it automatically? - Do you want
pull.autostash = trueto handle dirty working directories gracefully?
Once you have answered those three questions and set your configuration, you will almost never need to type a flag with your daily git pull. The flags are there for the times when you need to override your defaults for a specific situation: pulling with a specific strategy for a tricky merge, using --depth in CI/CD for speed, or using --no-commit when you want to review before finalizing.
The visual mental model that matters most: git fetch downloads new information from the remote into your remote-tracking branches without touching your files. git merge integrates those changes into your current branch and updates your files. git pull runs both in sequence. Every flag you learned in this tutorial is modifying one of those two steps or the relationship between them.
Keep this tutorial bookmarked. The flags table alone is worth coming back to whenever you find yourself in a situation that plain git pull cannot handle. And if you are still building your Git fundamentals, go visit inter-git.com to see these concepts demonstrated visually and interactively.
메타데이터
- post_id
- c4f54890fe2a
- slug
- the-complete-guide-to-git-pull-from-your-first-fetch-and-merge-to-mastering-rebase-strategies-and-c4f54890fe2a
- url
- https://medium.com/@eloquentcoder/the-complete-guide-to-git-pull-from-your-first-fetch-and-merge-to-mastering-rebase-strategies-and-c4f54890fe2a
- canonical_url
- https://medium.com/@eloquentcoder/the-complete-guide-to-git-pull-from-your-first-fetch-and-merge-to-mastering-rebase-strategies-and-c4f54890fe2a
- author_url
- https://medium.com/@eloquentcoder
- status
- ok
- fetched_at
- 2026-06-09 15:37:30