Skip to content

Instantly share code, notes, and snippets.

@pvspain
Last active January 16, 2024 01:33
Show Gist options
  • Save pvspain/0438b9b6733650d3e0f52f0d82ec993f to your computer and use it in GitHub Desktop.
Save pvspain/0438b9b6733650d3e0f52f0d82ec993f to your computer and use it in GitHub Desktop.
git-triangular-workflow

Git "triangular" workflow

For hacking on open source projects (with a canonical upstream repository).

Triangular workflow diagram

Index

Setting up your local repository

  1. 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.

  2. 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
  3. 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 be origin and the default push behaviour to current. Together this means that if you just type git push, the current branch is pushed to the origin remote.

  4. 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

Hacking

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

Awoogah! Always work on a feature branch!

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!

Working on a new feature

  1. 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
  2. Create a branch $newbranch from upstream main 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 upstream main branch.

  3. if more commits are added to main upstream, you can incorporate those changes locally by:

    • effectively rebasing your local main on the updated upstream main, or fail if there are local changes: merge --ff-only
    • rebasing your $newbranch branch on the updated upstream main 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}'
  4. 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 instructions

    If you’re unsure of which branch would be pushed to, you can type:

    git push --dry-run

Submitting a pull-request (PR)

  1. 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment