Use ‘git’ with 3rd-party upstream repo

4 minute read  

There are cases when you want to base your project off of a 3rd-party/open-source repo (e.g. seed projects). It’s easy to clone the repo and start your project from there. However, when that 3rd-party repo has updates and you want to get those updates into your project, what’s the best way to do so without messing up your working branch and the main git repo?

The process of working in harmony with a 3rd-party git repo is to maintain an upstream remote pointing to that repo, along with a main origin remote for your code. Once in a while, checkout the new upstream code in a local branch, and rebase/merge it to your working branch which is then pushed independently to your main code repo.

Simplified version:

# Get upstream updates
$ git fetch upstream --tags
$ git checkout tags/v1.1
$ git checkout -b upstream/v1.1

# Rebase to working branch
$ git checkout dev
$ git rebase upstream/v1.1
$ git push origin dev

However, there are a few quirks that you may run into with regards to rebase and pushing to the main repo. Let’s walk through those issues in detail.

SET UP ‘UPSTREAM’ REMOTE

upstream refers to the 3rd-party/open-source git repo. origin refers to our main repo. upstream and origin are names by convention. You can name them anything you’d like.

Add the ‘upstream’ repo

# Estashlish our empty git locally
$ mkdir project
$ cd project
$ git init .

# Add the 3rd-party repo
$ git remote add upstream git@3rdPartyRepo

Fetch ‘upstream’ for the first time

Option 1: if ‘upstream’ has tags and we want to use it

# Fetch its content
$ git fetch upstream --tags

# Get the specific tag that we want to use, this will put us on a detached state
$ git checkout tags/v1.0

Option 2: if ‘upstream’ doesn’t have tags or we want to use master branch on ‘upstream’

# Fetch its content
$  git fetch upstream

# Create a local 'master' branch that tracks upstream's 'master'
# Note that we'll treat our local 'master' as a read-only branch from now on
$ git checkout master

WORK ON OUR ‘ORIGIN’ REMOTE

First time adaption from 3rd-party ‘upstream’

# Create a new 'dev' branch from 'tags/v1.0' or 'master' and switch to 'dev'
$ git checkout -b dev
... edit code

Add the ‘origin’ repo and push working code to it

$ git remote add origin git@ourMainRepo
$ git push origin dev

We can continue working on our working branch and push to our origin remote until we want to get updates from the upstream 3rd-party repo.

Get updated code from ‘upstream’

Option 1: if ‘upstream’ has tags and we want to use it

# Fetch 'upstream' updates
$ git fetch upstream --tags

# Get the specific tag that we want to use, this will put us on a detached state
# We cannot merge/rebase this until we've created a local branch for this
$ git checkout tags/v1.1

# Create a local branch from the tag, so we can merge/rebase this code
# We name the local branch 'upstream/v1.1'
$ git checkout -b upstream/v1.1

# Double check the branches and verify we're on the local branch 'upstream/v1.1'
$ git branch -a

Option 2: if ‘upstream’ doesn’t have tags or we want to use master branch on ‘upstream’

# Fetch 'upstream' updates
$ git fetch upstream

# Get updated 'master' branch
$ git checkout master
$ git pull upstream

‘rebase/merge’ to our working branch

If you plan on contributing back to the upstream repo, you can merge the updates with your code. In our case, we want to keep our modifications independently in the origin repo. Then it’s better to use rebase so our changes always stay on top of whatever is the newest code from upstream.

# Let's get back to our working branch
$ git checkout dev

# Rebase 'dev' on top of 'upstream/v1.1' or 'master'
$ git rebase upstream/v1.1
or
$ git rebase master

And we’re done. If everything went smoothly with the rebase, we can then push this rebased code to our main repo:

# Double check our log
$ git log

# Push to main repo with '--force',
# because we've rewritten previously pushed commits with new ones when rebasing,
# without --force our main 'origin' remote won't allow us to push to it
$ git push origin dev --force

Potential conflicts

However, if you have modified a file that was also modified in the upstream repo, you will run into a conflict. Your console will report something like this:

CONFLICT (content): Merge conflict in ... <some file>
error: Failed to merge in the changes.
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

Go ahead and resolve the conflict:

  • Edit to resolve the conflicted files
  • Add those resolved files with git add to make them ready to continue rebase
  • Continue rebase
# Continue git rebase
$ git rebase --continue

TIPS

  • If at some point during the git rebase you got panic (due to the CONFLICT error), just do git rebase --abort and you’re back to normal. You can then calm down and gather your breath to see what you want to do next.
  • When resolving a conflict, the conflicted files may seem to miss some of your latest changes. This is normal because the files is at a specific commit where the conflict first occured. You may need to resolve different conflicts in the same file multiple times.

Tags: ,

Published:

Leave a Comment