Git developers utilize multiple local branches to isolate work before integrating code with the team‘s shared repository. By pulling upstream changes from the central master branch into a developer‘s local feature branches, teams can surface conflicts early and prevent tricky merges down the road.
This guide will take a comprehensive look at what happens in the background when you execute git pull origin master
from within a local develop branch. Well-versed in Git fundamentals, we will go beyond the basics and dive deep into real-world use cases and best practices.
Laying the Groundwork
Before running the pivotal git pull origin master
command, let‘s examine what needs to be in place:
Local and Remote Repositories
There must be both a local Git repository on your file system as well as a remote repository hosted somewhere like GitHub or GitLab. The remote serves as the "source of truth" for the team, while local repositories allow for isolated development and experimentation.
Tracking Branches
Your local branches must be linked to remote branches, this is called tracking. Tracking branches allow you to reference the remote branch name directly instead of the full URL path. For our example, we will have:
- Local master branch tracking origin/master
- Local develop branch tracking origin/develop
You can confirm tracking with:
git branch -vv
Recent Commits on Remote Master
There must be new commits that exist on the remote master branch that don‘t yet exist locally. Typically commanded by another developer on the team pushing to the central repository.
With these fundamentals established, we arrive at the scenario of being on local develop but needing to pull down upstream changes from remote master before continuing our work.
What Happens When git pull origin master
Now, while on our local develop branch, we execute the infamous command:
git pull origin master
Under the hood, this triggers the following sequence of Git operations:
1. Fetch Latest Snapshot from Remote Master
Git begins by establishing a network connection to the remote repository using the saved URL under the alias "origin".
Once connected, Git retrieves the current commit snapshot of the master branch on origin. This effectively downloads all commits that exist on remote master that don‘t yet exist locally.
2. Attempt to Merge Remote Master into Local Develop
Next, Git will integrate those downloaded commits from remote master into the tip of your local develop branch.
This kicks off a merge operation to preserve all new commits along with retaining the existing change history on develop.
3. Handle Merge Conflicts if Any
During the merge process, Git will auto-combine any non-conflicting changes from remote master with your local develop. However, if both branches touched the same parts of code, Git will pause and flag the conflicting file.
Developers must manually resolve merge conflicts before Git can continue with the merge commit. Thankfully, modern dev tools provide interfaces to streamline conflict resolution.
4. Complete Merge with New Commit
Once all files are conflict-free, Git will commit a merge commit onto the tip of develop, containing all changes from remote master while retaining your unique change history.
With the technical "behind the scenes" understood, let‘s shift to explore some compelling reasons to actually pull upstream master into local develop…
Why Pull Remote Master into Local Develop
While keeping your local branches up-to-date may sound obvious, the actual practice can be forgotten or avoided by developers. However, making frequent pulls from central master the norm within your team can pay major dividends down the road.
Surfacing Merge Conflicts Early
The biggest value is finding and addressing merge conflicts immediately rather than allowing branches to diverge for prolonged periods. Detecting conflicts early is exponentially easier than unraveling months of tangled changes down the road.
By regularly pulling upstream master into local branches, developers will reveal team conflicts in real-time when they are still simple to resolve.
Incorporating Bug Fixes and Hotfixes
Another incentive to pull master is to incorporate any hotfixes or bug patches completed by other team members. It‘s typical to commit urgent patches directly to the master/main branch for fastest production deployment.
By syncing those commits back into develop, you avoid stumbling over defects that are already fixed upstream. This allows you to focus on new features knowing master is stable.
Adhering to Git Team Workflow Standards
Many teams standardize on frameworks like Gitflow or GitHub Flow which prescribe merging or pulling upstream branches often. Habitually pulling master reinforces adherance to the team standards and overall DevOps culture.
Consistently keeping local branches in sync encapsulates the spirit of collaborative development – leveraging the work of others while contributing back your own enhancements.
Facilitating Continuous Integration and Testing
For teams practicing continuous integration, frequent pulls from master assist downstream automation like build validation, automated testing, code analysis, etc.
Keeping local branches updated enables developer workstations to simulate the CI environments and uncover issues before attempting to merge with master. Developing this reflex benefits the entire team.
Recovering from an Errant Merge with git revert
Despite best efforts to stay in sync, sometimes a pull and merge from master can introduce breaking changes. Thankfully, Git provides a safety net to easily undo a conflicting merge.
The git revert
command will effectively undo a problematic merge:
git revert -m 1 <merge_commit_id>
This will:
- Create a new "revert commit" that undoes all changes introduced by the target merge commit
- Append this revert commit as a new entry in current branch history
Visually, the before and after commit history would look as follows:
Before faulty merge:
A - B - C - D [develop]
\
E - F [master]
Errant result after merging master into develop at D:
A - B - C - D - G [develop]
\
E - F [master]
After git revert of merge G:
A - B - C - D - G - H [develop]
\
E - F [master]
By reverting the unwanted merge G via new commit H, we encapsulated the fix as just another commit on develop.
Compare git revert vs. git reset vs. git checkout
The git revert
method shown above preserves original history by adding new commit(s) that undo previous changes. This is safe for shared team branches.
However both git reset
and git checkout
are more dangerous as they literally delete commits from branch history.
git resetUndoes commits by deleting them from current branch
git checkoutDiscards changes by overwriting files with another branch or commit
Reverting is typically safest approach when collaborating on shared repositories.
Advanced Git Pull Techniques
Up to this point we have focused on the most common usage of git pull which fetches remote changes and performs a merge commit.
However, Git pull provides advanced options that deviate from the standard behavior. Let‘s take look at utilizing --rebase
instead.
git pull –rebase
The --rebase
flag tells Git to replay local commits on top of fetched branch commits instead of the default merge operation.
Conceptually this results in a linear commit history by removing evolutionary dead-ends as branches diverged and converged. For small short-lived branches rebase prunes needless merge bubbles.
Standard git pull:
A - B - C - D [develop]
\
E - F [master]
$ git pull origin master
A - B - C - D - M [develop]
\
E - F [master]
git pull --rebase:
A - B - C - D [develop]
\
E - F [master]
$ git pull --rebase origin master
A - B - C - D - E - F [develop]
\
E - F [master]
However, rebasing has risks when used on highly shared branches:
- Re-writing public commit history can disrupt other developers
- Dropped merges undermine branch topology and review trails
The linear history does provide local clarity. Overall there is no definitively superior approach – teams should assess use case tradeoffs and standardize usage.
Wrap Up
Regularly pulling upstream branches into local repositories enables developers to coordinate seamlessly while crafting software collectively. Frequent merging propagates the most recent contributions across the team allowing everyone to build upon each other‘s work.
Specifically, pulling remote master into local develop branches surfaces conflicts rapidly, fosters sharing of urgent fixes, adheres to team coding standards, and ultimately leads to higher quality software.
While this guide went deep on the technical dynamics behind git pull
, the foundational takeaway is simply about cultivating a development culture rooted in communication, transparency, and shared understanding of the codebase at large.