For hacking on open source projects (with a canonical upstream repository).
-
Go to the upstream repository on GitHub, say upstream, and press the Fork button. This creates a new fork under your account with the URL
https://github.com/your-username/upstream
. -
Create and save your config in a local file
./triangular.config
, following the commented steps 1-3 below for your situation:# 1. Replace the chevron'd text <...> in the three lines below for your situation export upstreamRepoName=<upstream-repo-name> upstreamOwner=<upstream-owner-name> myUsername=<your-github-user-name> export upstreamRepoUrl=https://github.com/$upstreamOwner/$upstreamRepoName.git # 2. Uncomment the next line if you access your repos via git+ssh protocol #export myRepoUrl=git@github.com:$myUsername/$upstreamRepoName.git # 3. Uncomment the next line if you access your repos via https protocol # export myRepoUrl=https://github.com/$myUsername/$upstreamRepoName.git
-
Create a local clone of your fork on your computer:
# Apply your config to this terminal session source ./triangular.config && # Create local repo git clone "$myRepoUrl" && cd "$upstreamRepoName" && # Set up the 'triangular' workflow magic git config remote.pushdefault origin && git config push.default current
After this step, the remote called
origin
refers to your fork of upstream. It also sets the default remote for pushes to beorigin
and the default push behaviour tocurrent
. Together this means that if you just typegit push
, the current branch is pushed to theorigin
remote. -
Create a second remote called
upstream
that points at the main upstream repository and fetch from it:git remote add upstream "$upstreamRepoUrl" && git fetch upstream
You only have to follow the above steps once. From then on, whenever you want to work on a new feature, you can more easily interact with the remote repositories
The main
branch of your repo must remain a replica of the upstream main branch. Don't commit directly to your local main
branch - always work on a feature branch!
-
First, make sure that your local repository is up-to-date with the upstream repository:
# Refresh your 'upstream' remote git fetch upstream && # Update your 'local' main to match the 'upstream' main git rebase upstream/main main
-
Create a branch
$newbranch
from upstreammain
to work on a new feature, and check out the branch:export newbranch={new-branch-name}
git checkout -b $newbranch upstream/main
This automatically sets up your local
$newbranch
branch to track the upstreammain
branch. -
if more commits are added to
main
upstream, you can incorporate those changes locally by:- effectively rebasing your local
main
on the updated upstreammain
, or fail if there are local changes:merge --ff-only
- rebasing your
$newbranch
branch on the updated upstreammain
by typing:
# Refresh the upstream remote with the new commits git fetch upstream && # Update your 'local' main to match the 'upstream' main - FAIL if there are local modifications. git checkout main && git merge --ff-only upstream/main && # Rebase your branch on the modified local main git rebase main $newbranch
If you’re ever unsure of the branch that would be pulled from, you can type:
# On the $newbranch branch git rev-parse --abbrev-ref '@{u}'
- effectively rebasing your local
-
Hack, commit, hack, commit. Push your
$newbranch
branch to your fork:git push
Because of the above configuration, and because
$newbranch
is the current branch, the above command doesn’t need any arguments.[!IMPORTANT] If you've previously pushed
$newbranch
, and your local branch has since been rebased onto upstream changes, you'll need to do a force-push:git push --force
This is only problematic if other people are working off your personal
origin
repository. If your repository is on the receiving end of a force-push, here are recovery instructionsIf you’re unsure of which branch would be pushed to, you can type:
git push --dry-run
-
Create a pull request via the GitHub page for the upstream repo, using your forked repo branch on GitHub as the PR source branch
For our example,
- the source branch would be the
$newbranch
branch on$myRepoUrl
, and - the target branch would be the
main
branch on$upstreamRepoUrl
- the source branch would be the