How to rebase branch and sync forked repository with upstream using Git
Estimated Reading Time: 7 MinutesIntroduction
When contributing to open source projects like Mautic, it's standard practice to have a personal fork of the repository.
Maintainers merge pull requests (PRs) over time, so your fork might fall behind the original repository.
This article explains how to:
- Keep your fork current,
- Rebase your feature branches, and
- Fix synchronization issues before opening a PR.
Whether you are a newcomer to Git or have been working with it for many years, this guide keeps you up to date on the best practices of open source collaboration.
What is upstream, origin, and local repository
If you're not yet familiar with open source repository terms, take a look at the table below.
| Term | Meaning | URL |
| Upstream | The original repository | https://github.com/mautic/mautic |
| Origin | The forked repository | https://github.com/YOUR-GITHUB-USERNAME/mautic |
| Local | The copy of the remote (upstream or origin) repository on the local machine |
When you fork Mautic’s repository, you’re essentially making a copy of the upstream under your GitHub account. Then, you should always clone your forked repository on your local machine rather than the upstream repository, because most open source projects don't allow you to push changes directly to the upstream.
Keeping your local and origin repositories up to date with upstream ensures that your PRs merge smoothly without conflicts.
Prerequisites
Make sure you:
- Installed a code editor, such as VS Code
- Installed Git
- Cloned your forked repository on your local machine
The next step is to verify your remote repositories by running the following command:
git remote -v
Expected output (before setting up upstream):
origin https://github.com/yourusername/mautic.git (fetch) origin https://github.com/yourusername/mautic.git (push)
Setting up remote upstream
To connect your fork to the original repository, add upstream to your remote repository:
git remote add upstream https://github.com/mautic/mautic.git
Then, run the command below to confirm if it’s added correctly:
git remote -v
You should now see:
origin https://github.com/yourusername/mautic.git (fetch) origin https://github.com/yourusername/mautic.git (push) upstream https://github.com/mautic/mautic.git (fetch) upstream https://github.com/mautic/mautic.git (push)
Syncing the forked repository with the upstream
When the upstream repository has new changes, you need to update your local default branch and push it to your forked repository.
Note: for the tutorials across in this article, it's assumed that the default branch name is 7.x. If the default branch name differs, change it to the correct one.
Step 1: Fetch all branches from upstream
git fetch upstream
Step 2: Switch to the local default branch
git checkout origin/7.x
Step 3: Rebase the local default branch with upstream
Rebasing your branch with upstream means merging the new changes from upstream into your local branch, creating a new commit for each commit in the original branch:
git rebase upstream/7.x
Step 4: Push changes to the forked repository
git push origin 7.x
Now your local and forked repository’s 7.x branch is up to date with the upstream.
Rebasing PR
When working on a feature branch, you need to rebase it on top of the latest state of the default branch.
The default branch in a repository is where new changes are merged. In many open source projects, the default branch is typically called main. However, Mautic uses versioned names such as 6.0, 7.x, and so on, depending on the current development cycle.
Screenshot: The default branch indicates branch 7.x on Mautic’s GitHub repository.
Now that you know how to identify the default branch, let’s go through the steps to properly rebase your work. This ensures your feature branch contains the latest updates from upstream before you push your changes or open a PR.
Step 1: Fetch branches from upstream
git fetch upstream
Step 2: Switch to the feature branch
git checkout feature/improve-login
Change the feature/improve-login to your branch name.
Step 3: Rebase the feature branch with upstream
git rebase upstream/7.x
During rebasing, Git pauses when merge conflicts occur, and you must resolve them before continuing.
If you're not familiar with resolving merge conflicts, please read the "Dealing with merge conflicts" section. Once all conflicts are resolved, you can continue to rebase by running these commands:
git add . git rebase --continue
If you want to abort the rebasing process, run the following command:
git rebase --abort
Step 4: Push the rebased branch to the forked repository
Since rebasing changes the history, you want to use the --force flag carefully as below:
git push origin feature/improve-login --force
Resetting local and forked repositories to match the upstream
If your local repository gets messy or too far behind, you can completely reset it to match the upstream repository.
Warning: Running commands below overwrites local changes. So, please do it with caution.
git fetch upstream git checkout 7.x git reset --hard upstream/7.x git push origin 7.x --force
This command sequence perfectly syncs your local and forked default branches with upstream, ensuring no extra commits or drift.
Rebase: common mistakes and fixes
|
Problem |
Cause |
Solution |
|
fatal: No upstream configured |
You haven’t added the upstream remote |
Run: git remote add upstream https://github.com/mautic/mautic.git |
|
force push rejected |
Branch is protected, or you lack permission |
Check PR branch permissions |
|
Conflicts during rebase |
Code differences between upstream and your branch |
Resolve conflicts and continue |
|
Rebase fails completely |
Rebase was aborted |
Try again or reset with: git reset --hard upstream/main |
Dealing with merge conflicts
Sometimes, when rebasing or merging, Git may report a conflict. This means the same part of a file was changed in both your branch and the upstream branch. Git can’t automatically decide which version to keep, so it asks you to make that decision manually.
Example output:
Auto-merging src/User/Login.php CONFLICT (content): Merge conflict in src/User/Login.php
How to resolve merge conflicts
1. Open the conflicting file listed in the message.
2. Look for conflict markers like these:
<<<<<<< HEAD Your version of the code ======= The version from upstream (or the default branch) >>>>>>> upstream/<default-branch>
3. Compare both sections carefully:
- The part between
<<<<<<< HEADand=======is your local change. - The part between
=======and>>>>>>> upstream/<default-branch>is the change from upstream.
4. Decide which version to keep, or combine both if that makes the most sense:
- Keep your version if it still applies correctly to the new upstream code.
- Keep the upstream version if it contains improvements, bug fixes, or refactors that your branch should now follow.
- Sometimes you may need to manually merge the two versions into a single, clean, consistent block of code.
5. Remove the conflict markers (<<<<<<<, =======, >>>>>>>) after editing.
6. Stage the resolved file and continue the rebase:
git add src/User/Login.php git rebase --continue
Note: when resolving merge conflicts, it’s a good practice to document what you changed in your PR description or comments. This helps reviewers understand what you decided and why. For example, you might include something like this in your PR comment:
Merge conflict resolution notes:
- Resolved conflict in
src/User/Login.phpline 120–140. - Kept upstream changes for improved logging.
- Reapplied my fix for user token validation after the refactor.
This level of transparency allows reviewers to more easily check the affected lines and confirm that the resolution aligns with project standards.
Need help?
If you get stuck while rebasing or syncing your fork, you can reach out to the Mautic Product Team on Slack at the #t-product channel.
Conclusion
Rebasing and syncing might appear intimidating at first, but they are, in fact, among the most useful Git skills when contributing to open source projects such as Mautic. Having your fork synced with upstream simplifies maintainers' lives and keeps your contributions merge-ready at all times.