Merging branches in Git is typically straightforward when they share a common ancestor. But what happens when you want to merge two branches that have entirely different histories? This situation can arise when combining code from independent projects, migrating changes from a downstream repository, or simply bringing together two repositories that began separately. In this article, we’ll go over how to merge branches with no shared history, creating a pull request in GitHub as the final step.
Let’s walk through this step-by-step using a real-world scenario: merging a branch from a downstream
repository into the main
branch of an origin
repository.
Why This Method?
When two branches have no shared history, Git doesn’t automatically know how to combine them. Merging requires an "unrelated histories" approach, allowing you to integrate them while keeping both histories intact. This method ensures that all commits from the separate branch will be included in the final merge, but it will result in a single merge commit to tie them together.
Step 1: Set Up Your Repository and Check Out the main
Branch
Start by ensuring you have a local copy of the main
branch from the origin
repository. Fetch the latest changes to make sure you’re working with the current version of main
:
Now create a new branch off main
to use as a temporary merge branch:
This main-with-downstream
branch will handle the merge and any conflicts that may arise, leaving your original branches untouched.
Step 2: Merge the from-downstream
Branch Using the --allow-unrelated-histories
Flag
With main-with-downstream
checked out, you’re ready to merge the changes from the from-downstream
branch. Because the branches have different histories, you need to use the --allow-unrelated-histories
flag to bypass Git’s assumption that branches should share a common ancestry.
Fetch the from-downstream
branch to ensure it’s up to date:
Then, initiate the merge:
This command tells Git to merge the two branches despite the lack of shared history.
Step 3: Resolve Any Merge Conflicts
When merging unrelated histories, conflicts are common, as files with similar names or structures may exist in both branches but with different content. Git will stop at each conflict, allowing you to manually decide how to resolve it.
To view all files with conflicts, use:
Open each file listed as "unmerged" and decide which version to keep or how to combine changes. After editing each file, mark it as resolved:
Once you’ve resolved all conflicts, complete the merge:
Step 4: Push the Merged Branch to origin
With all conflicts resolved and the merge complete, it’s time to push main-with-downstream
to the origin
remote.
This step publishes the new branch with its merge commit, making it available for review and a pull request.
Step 5: Create a Pull Request on GitHub
Head over to your GitHub repository and navigate to the Pull Requests tab. Select New Pull Request and choose main-with-downstream
as the source branch and main
as the target branch.
Fill in the title and description with a summary of the changes, mentioning that you’ve merged unrelated histories. GitHub will display the diff for the pull request, which should include all commits from both branches along with the single merge commit.
Once ready, click Create Pull Request. This pull request is now ready for review or direct merging into the main
branch.
Why Use a Merge Commit?
Creating a single merge commit in the main-with-downstream
branch has a few advantages:
- Preservation of History: Both commit histories remain intact, allowing for complete traceability of the code from both branches.
- Conflict Resolution: Handling conflicts in a separate merge branch ensures that
main
stays unaffected until the merge is ready to be completed. - Future Merging: The new branch structure ensures that any future merges between these branches won’t require the
--allow-unrelated-histories
flag, as Git will recognize them as part of the same repository.
Conclusion
Merging branches with different histories in Git may sound daunting, but it’s manageable by creating a new branch, merging with the --allow-unrelated-histories
flag, and resolving conflicts. By pushing the merge commit to origin
and creating a pull request, you can seamlessly integrate changes from one branch into another, even if they started in completely different repositories. This approach maintains transparency and provides a clean history of both branches, preserving all work and enabling future collaboration.