Skip to content

Instantly share code, notes, and snippets.

@keturn
Last active March 8, 2026 04:11
Show Gist options
  • Select an option

  • Save keturn/9ea3aa7e005cb7cfa5b0bb236c5526e8 to your computer and use it in GitHub Desktop.

Select an option

Save keturn/9ea3aa7e005cb7cfa5b0bb236c5526e8 to your computer and use it in GitHub Desktop.
Document git fork as "Pull-Request Only"
#!/bin/bash
# Replace the repo's default branch with a README explaining this fork is only for its submitted pull requests.
set -e -x -o pipefail
REMOTE=origin
GH_USERNAME="${GH_USERNAME:-$USER}"
TRUNK="$(git symbolic-ref --short refs/remotes/$REMOTE/HEAD | sed "s:${REMOTE}/::")"
REMOTE_URL="$(git remote get-url $REMOTE)"
UPSTREAM_REPO="${REMOTE_URL%%.git}"
GIT_ROOT=$( git rev-parse --show-toplevel )
PROJECT_NAME="${GIT_ROOT##*/}"
# Move old trunk out of the way.
git branch -m "$TRUNK" upstream-"$TRUNK"
# Make a new orphan branch with that name.
git checkout --orphan "$TRUNK"
# checkout --orphan left everything staged in the index; remove it
git reset
# Remove most files, except for those that might cause a lot of editor thrashing
# or things the host needs for repo metadata (e.g. LICENSE)
git clean --force -d --exclude=.gitignore --exclude=.editorconfig --exclude=LICENSE
cat > README.md << EOF
# Pull-Request Only Fork
This fork exists only for making pull requests against upstream.
See
* [branches here](https://github.com/${GH_USERNAME}/${PROJECT_NAME}/branches)
* [upstream repository](${UPSTREAM_REPO})
* [pull requests to upstream](${UPSTREAM_REPO}/pulls/${GH_USERNAME})
EOF
#!/bin/zsh
# Replace the repo's default branch with a README explaining this fork is only for its submitted pull requests.
#
# This version depends on gh so it can be smarter about constructing URLs.
set -e -o pipefail
# The goal is to set what someone sees when they land on your fork's page on GitHub.
# We can either replace the main branch, or change the default branch of the fork.
typeset SET_NEW_DEFAULT_BRANCH=1
typeset NEW_DEFAULT_BRANCH="PR-ONLY-FORK"
typeset GH_HOST
typeset GH_USERNAME
gh auth status --json hosts --jq '.hosts[][] | "\(.host)\t\(.login)"' \
| read -r GH_HOST GH_USERNAME
typeset PROJECT_NAME
gh repo view --json name --jq '"\(.name)"' \
| read -r PROJECT_NAME
# `gh repo view` defaults to "the repository for the current directory," but if a remote is defined
# for upstream, it may use that instead of the fork. So explicitly use the username here. There are
# edge cases where this may not reflect how you've forked things, but it should work for the common
# case.
typeset TRUNK
typeset UPSTREAM_REPO
gh repo view \
--json defaultBranchRef,parent \
--jq '"\(.defaultBranchRef.name)\t\(.parent.owner.login)/\(.parent.name)"' \
${GH_USERNAME}/${PROJECT_NAME} \
| read -r TRUNK UPSTREAM_REPO
typeset WEB_UPSTREAM_REPO="https://${GH_HOST}/${UPSTREAM_REPO}"
function branch_with_old_name () {
# Move old trunk out of the way.
git branch -m "$TRUNK" upstream-"$TRUNK"
# Make a new orphan branch with that name.
git checkout --orphan "$TRUNK"
}
function branch_with_new_name () {
git checkout --orphan "$NEW_DEFAULT_BRANCH"
}
if (( SET_NEW_DEFAULT_BRANCH > 0 )); then
branch_with_new_name
else
branch_with_old_name
fi
# checkout --orphan left everything staged in the index; remove it
git reset
# Remove most files, except for those that might cause a lot of editor thrashing
# or things the host needs for repo metadata (e.g. LICENSE)
git clean --force -d --exclude=.gitignore --exclude=.editorconfig --exclude=LICENSE
cat > README.md << EOF
# Pull-Request Only Fork
This fork exists only for making pull requests against upstream.
See
* [branches here](https://${GH_HOST}/${GH_USERNAME}/${PROJECT_NAME}/branches)
* [upstream repository](${WEB_UPSTREAM_REPO})
* [pull requests to upstream](${WEB_UPSTREAM_REPO}/pulls/${GH_USERNAME})
EOF
git add -A
git commit -m '! Document GitHub repo as a pull-request only fork'
typeset REMOTE_FORK=$( git remote -v | grep $GH_USERNAME/${PROJECT_NAME} | head -n1 | cut -f1 )
read -q "?Push this branch to your fork ($REMOTE_FORK)? [y/N] " || exit 1
if (( SET_NEW_DEFAULT_BRANCH > 0 )); then
git push $REMOTE_FORK $NEW_DEFAULT_BRANCH
else
git push --force $REMOTE_FORK $TRUNK
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment