Formally: How to merge changes from a 'forked' Git repository
- Edit your PR config
- Load the PR config
- Add a remote for the pull request repository
- Load the pull request
- QA the changes
- Merge the changes
- QA the merged changes
- Proceed or abort!
- Clean up
Create a config file, pull-request-config.sh
, substituting the values for the pull request where indicated in chevrons (<>
) below, for example: <some-value>
#! /usr/bin/env bash
# How to process a pull request (forked repository) locally
# Instructions: https://gist.github.com/pvspain/92ead8ecd4552bedd643922877d62500
# Fill in the details for the pull request variables - trim all whitespace!
export forkRepoOwner=<fork-repo-owner>
# For example: export forkRepoOwner=bobthecoder
export forkRepoUrl=<fork-repo-url>
# For example: export forkRepoUrl=https://github.com/bobthecoder/forkedrepo.git
# The forker's branch name for the pull request
# Often main/master
export prBranch=<fork-repo-pull-request-branch>
# For example: export prBranch=bobspr
# The local destination branch for an accepted pull request
# Typically main/master
export localTargetBranch=<local-target-branch>
# For example: export localTargetBranch=main
# The GitHub Pull Request number
export prNumber=<pull-request-number>
# For example: export prNumber=47
# The tag to identify the head of $localTargetBranch prior to merging
# Default: pre-PR${prNumber}
export prePrTag=pre-PR${prNumber}
# Using our example: pre-PR47
# A (temporary) local branch to inspect the pull request code
# Default: $forkRepoOwner-$prBranch
export localPrBranch=$forkRepoOwner-$prBranch
# Using our example: bobthecoder-bobspr
Source the config file into a (bash) terminal session...
source ./pull-request-config.sh
A one-time operation per contributor
# Add a new remote - using fork repo owner's name - as remote name will be unique per repository hub
git remote add "$forkRepoOwner" "$forkRepoUrl"
# Get their changes
git fetch "$forkRepoOwner" "$prBranch"
# Checkout their changes locally
git checkout -b "$localPrBranch" "$forkRepoOwner/$prBranch"
- Run any tests and review the code
- If you wish to proceed with the pull request...
-
Checkout the intended target branch for the pull request
git checkout "$localTargetBranch" # Identify the current head of the branch - used as a rollback point if we abort the merge later. git tag "$prePrTag"
Both Option A and Option B below will apply the changes to your repository. We allow fast-forward commits to simplify the branch history where possible, and stage other changes. Neither option will proceed to commit any other changes.
-
Option A: Use the pull-request version wherever there are merge conflicts.
git merge --no-commit --strategy=ort --strategy-option=theirs "$localPrBranch"
Note: Conflicts may still occur if a file is deleted in one branch but modified in the other. In this case, you can decide to:
- Stage the file deletion:
git rm <file-spec>
, or - Revert the file deletion:
git add <file-spec>
.
Run
git status
to review the staged changes - Stage the file deletion:
-
Option B: Manually reconcile all conflicts
git merge --no-commit "$localPrBranch" # Stage reconciled conflicts with "git add <file-path>"
-
- Run any tests and review the merged code
-
If you wish to abort the merge...
# This will rollback non-fast-forward commits git merge --abort # This will roll back ff commits, and reset to the previous head git reset --hard "$prePrTag"
-
If you wish to accept the merged code, commit the merged changes locally
git merge --continue
-
Follow your normal process for pushing changes to the upstream repository (GitHub , Bitbucket, GitLab, whatever!) when you're ready.
- Delete the local PR branch
git branch --delete "$localPrBranch" # Remove the tag for the previous head of $localTargetBranch git tag --delete "$prePrTag"
- Optionally, remove the Git remote for the pull request
git remote rm "$forkRepoOwner"