Git-Mastery: Lessons

T10L2. Forking Workflow (with Branching)


A branch-based forking workflow is common in open-source projects and other large projects.

This lesson covers that part.

In a branch-based forking workflow, the official code lives in a designated 'main' repo, while each developer works in their own fork (hence, the name) and submits pull requests from separate branches (either long-lived branches or short term branches) back to the main repo. That is, it is a combination of the forking model and the feature-branch strategy. Not only this workflow is common for OSS projects and other large-team projects, it provides a good foundation for learning Git workflows (because other workflows are simpler than this, once you learn this workflow, it is easy to move to other workflows).

To illustrate how the workflow goes, let’s assume Jean wants to fix a bug in the code. Here are the steps:

  1. Jean creates a separate branch in her local repo and fixes the bug in that branch.
    Common mistake: Doing the proposed changes in the main branch -- if Jean does that, she will not be able to have more than one PR open at any time because any changes to the main branch will be reflected in all open PRs.
  2. Jean pushes the branch to her fork.
  3. Jean creates a pull request from that branch in her fork to the main repo.
  4. Other members review Jean’s pull request.
  5. If reviewers suggested any changes, Jean updates the PR accordingly.
  6. When reviewers are satisfied with the PR, one of the members (usually the team lead or a designated 'maintainer' of the main repo) merges the PR, which brings Jean’s code to the main repo.
  7. Other members (and Jean), realizing there is new code in the upstream repo, sync their forks with the new upstream repo (i.e., the main repo). This is done by pulling the new code to their own local repo and pushing the updated code to their own fork. If there are unmerged branches in the local repo, they can be updated too e.g., by merging the new main branch to each of them.
    Potential mistake: Creating another 'reverse' PR from the team repo to the team member's fork to sync the member's fork with the merged code. PRs are meant to go from downstream repos to upstream repos, not in the other direction.

One main benefit of this workflow is that it does not require most contributors to have write permissions to the main repository. Only those who are merging PRs need write permissions. The main drawback of this workflow is the extra overhead of sending everything through forks.

HANDS-ON: Practice the forking workflow

This practical is best done as a team.

Preparation One member: set up the team org and the team repo.

1 Each team member: create PRs via own fork.

  • Fork that repo from your team org to your own GitHub account.

  • Create a branch named add-{your name}-info (e.g. add-johnTan-info) in the local repo.

  • Add a file yourName.md into the members directory (e.g., members/johnTan.md) containing some info about you into that branch.

  • Push that branch to your fork.

  • Create a PR from that branch to the main branch of the team repo.

2 For each PR: review, update, and merge.

  • [A team member (not the PR author)] Review the PR by adding comments (can be just dummy comments).

  • [PR author] Update the PR by pushing more commits to it, to simulate updating the PR based on review comments.

  • [Another team member] Approve and merge the PR using the GitHub interface.

  • [All members] Sync your local repo (and your fork) with upstream repo. In this case, your upstream repo is the repo in your team org.

    • The basic mechanism for this has two steps (which you can do using Git CLI or any Git GUI):
      (1) First, pull from the upstream repo -- this will update your clone with the latest code from the upstream repo.
      If there are any unmerged branches in your local repo, you can update them too e.g., you can merge the new main branch to each of them.
      (2) Then, push the updated branches to your fork. This will also update any PRs from your fork to the upstream repo.
    • Some alternatives mechanisms to achieve the same can be found in this GitHub help page.
      If you are new to Git, we recommend that you use the above two-step mechanism instead, so that you get a better view of what's actually happening behind the scene.

3 Create conflicting PRs.

  • [One member]: Update README: In the main branch, remove John Doe and Jane Doe from the README.md, commit, and push to the main repo.

  • [Each team member] Create a PR to add yourself under the Team Members section in the README.md. Use a new branch for the PR e.g., add-johnTan-name.

4 Merge conflicting PRs one at a time. Before merging a PR, you’ll have to resolve conflicts.

  • [Optional] A member can inform the PR author (by posting a comment) that there is a conflict in the PR.

  • [PR author] Resolve the conflict locally:

    1. Pull the main branch from the repo in your team org.
    2. Merge the pulled main branch to your PR branch.
    3. Resolve the merge conflict that crops up during the merge.
    4. Push the updated PR branch to your fork.
  • [Another member or the PR author]: Merge the de-conflicted PR: When GitHub does not indicate a conflict anymore, you can go ahead and merge the PR.

done!