You are currently viewing Install git-upstream and Fork a Repository

Install git-upstream and Fork a Repository

Version 1.2

In a previous blog post I described a strategy for tracking an open-source project using the rebase & weld git operation that combines the advantages of rebase and merge operations. In this article I’m going to cover how to install and set up the git-upstream tool, which implements that strategy. Examples are going refer to GitHub.

Installation

To get to the latest version of git-upstream, I recommend installing from source. As of this writing, git-upstream requires Python 3.9, not newer, so install it on your workstation using the method appropriate for your operating system (if you are not sure how, google for “install old version of Python on <your system>”). Then run the following commands:

git clone https://opendev.org/x/git-upstream.git
cd git-upstream
python3.9 -m pip install -r requirements.txt
python3.9 -m pip install .

Goal

Let’s assume you want to develop a patch to the following project: https://github.com/argoproj/argo-rollouts. You then want to deploy the patched software to your environment. After some time, you also want to import any future changes to the upstream project, taking advantage of the git upstream import approach.

Repo Creation

GitHub has built-in buttons to fork a repository and to sync with upstream, but we’re not going to use them, because GitHub uses an ordinary merge or rebase, not the rebase & weld strategy. In addition, GitHub doesn’t allow to make a fork private or internal, even if you’re a user of GitHub Enterprise. So we’re going to use the command line to fork the repo.

I recommend that you use the same name for the repository as the original, but put it under a different organization. For example:
https://github.com/argoproj/argo-rollouts
becomes
https://github.com/akorzynski/argo-rollouts.

Create the repository using the standard GUI, for example:

Don’t create a README file or a license for this repository. All the files will be cloned from the original open-source repo. We want a completely empty repository for our purposes, as in the screenshot below:

Define the Environment

Define the following environment variables to correspond to your situation. With those variables defined, you will be able to copy/paste the commands from the upcoming sections, without having to modify them.

UPSTREAM_ORG=argoproj # source organization 
MY_ORG=akorzynski     # destination organization
REPO=argo-rollouts    # name of repository

Copy Repository Contents

Run the following commands:

# Clone the repository
git clone "https://github.com/$MY_ORG/$REPO"
cd "$REPO"

# Add the upstream repository as a new remote, 
# so that you can fetch the data from it
git remote add upstream "https://github.com/$UPSTREAM_ORG/$REPO"

# Fetch the data
git fetch --all

# Retrieve the head branch name
HEAD_BRANCH="$(git remote show upstream | \
               grep '^ *HEAD branch:' | \
               grep --only-matching '[^ ]*$' )"
              
# Push the head branch to your internal repository
git push origin --set-upstream \
  "upstream/$HEAD_BRANCH:refs/heads/$HEAD_BRANCH"

# Push the data to your internal repository, 
# prefixing branches with 'upstream/'
# (command based on git-upstream's documentation)
git for-each-ref refs/remotes/upstream --format "%(refname:short)" | \
  sed -e 's@\(upstream/\(.*\)\)$@\1:refs/heads/upstream/\2@' | \
  xargs git push --tags origin

# Checkout the head branch
git checkout --track "origin/$HEAD_BRANCH"

Commit your change

Develop your change using your favorite editor. Then commit:

git commit -a -m "My change"

Import Upstream

When upstream changes, find the ref you want to import (usually the latest tag or the tip of the default branch). Then, assuming you want to import v1.2.3, you can do so using the following command:

git upstream import v1.2.3

Import Upstream – Advanced

If you wish to change the patch queue before welding it to main, run the following:

# Define a variable with the Git ref to import
GIT_REF="v1.2.3"

# Create an import branch without the last "welding merge"
git upstream import --no-merge --force --import-branch "import/$GIT_REF" "$GIT_REF"

# Switch to the import branch
git checkout "import/$GIT_REF"

# Use the interactive rebase to change the patch queue as required
git rebase --interactive "import/$GIT_REF-base"

# Return to main
git checkout main

# Create the final "welding merge"
git upstream import --finish --import-branch "import/$GIT_REF" "$GIT_REF"

Conclusion

We are done! You’re now tracking the repository using git-upstream.

This Post Has One Comment

Leave a Reply