doc: update repo
diff --git a/docs/developer/repos.md b/docs/developer/repos.md
index 840935a..b60849e 100644
--- a/docs/developer/repos.md
+++ b/docs/developer/repos.md
@@ -24,23 +24,15 @@
 > `internal/pkg/image_repositories/build_workflow.go` file to include the newly
 > forked project.
 
-## OpenStack
-
-Atmosphere has a few forks of the OpenStack repositories.  These are used to
-apply patches to the upstream code that contain fixes which have not yet been
-merged upstream.  The list of forked repositories is as follows:
-
-* [openstack/horizon](https://github.com/vexxhost/horizon)
-
-### Applying patches
+## Applying patches
 
 The only time that it is necessary to apply patches to the forked repositories
 is when there is a fix that has not yet been merged upstream.  In order to
 apply a patch, you can use the following command which includes the project
-name and the Gerrit patch number:
+name and either a Gerrit URL or a GitHub pull request URL:
 
 ```bash
-./hack/repos/openstack/patch horizon 874351
+./hack/repos/patch horizon https://review.opendev.org/c/openstack/horizon/+/874351/
 ```
 
 This command will take care of automatically cloning the project, downloading
@@ -52,3 +44,11 @@
 >
 > If the process fails because of a merge conflict, you'll need to resolve the
 > conflict and then run the command again.
+
+## OpenStack
+
+Atmosphere has a few forks of the OpenStack repositories.  These are used to
+apply patches to the upstream code that contain fixes which have not yet been
+merged upstream.  The list of forked repositories is as follows:
+
+* [openstack/horizon](https://github.com/vexxhost/horizon)
diff --git a/hack/repos/openstack/cherry-pick b/hack/repos/cherry-pick
similarity index 83%
rename from hack/repos/openstack/cherry-pick
rename to hack/repos/cherry-pick
index af1508a..4dfdd39 100755
--- a/hack/repos/openstack/cherry-pick
+++ b/hack/repos/cherry-pick
@@ -1,12 +1,12 @@
 #!/bin/bash -xe
 
 # Clone the repository in a temporary directory if it doesn't exist
-if [ ! -d "/tmp/openstack-${1}" ]; then
-  gh repo clone vexxhost/${1} /tmp/openstack-${1}
+if [ ! -d "/tmp/vexxhost-${1}" ]; then
+  gh repo clone vexxhost/${1} /tmp/vexxhost-${1}
 fi
 
 # Switch to the repository
-cd /tmp/openstack-${1}
+cd /tmp/vexxhost-${1}
 
 # Update the repository
 git fetch origin
diff --git a/hack/repos/openstack/patch b/hack/repos/openstack/patch
deleted file mode 100755
index c3445b7..0000000
--- a/hack/repos/openstack/patch
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-# Clone the repository in a temporary directory
-mkdir -p /tmp/openstack-${1}-${2}
-gh repo clone vexxhost/${1} /tmp/openstack-${1}-${2}
-
-# Switch to the repository
-cd /tmp/openstack-${1}-${2}
-
-# Create a new branch
-git checkout -b opendev/${2}
-
-# Detect the most recent revision of the change
-LATEST_REV=$(git ls-remote https://opendev.org/openstack/${1} | grep -E "refs/changes/[[:digit:]]+/${2}/" | sort -t / -k 5 -g | tail -n1 | awk '{print $2}')
-
-# Cherry-pick the change
-git fetch https://review.opendev.org/openstack/${1} ${LATEST_REV} && git cherry-pick FETCH_HEAD
-
-# Push this branch to the remote
-git push -u origin opendev/${2}
-
-# Create a PR for this change
-gh repo set-default vexxhost/${1}
-gh pr create \
-  --title "$(git show -s --format=%s)" \
-  --body "$(git show -s --format=%B)" \
-  --base master \
-  --head opendev/${2}
diff --git a/hack/repos/patch b/hack/repos/patch
new file mode 100755
index 0000000..295e981
--- /dev/null
+++ b/hack/repos/patch
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+PROJECT=${1}
+PATCH=${2}
+BRANCH=${3:-master}
+
+if [[ ${PATCH} =~ ^https://review.opendev.org ]]; then
+  FORMAT=gerrit
+  PATCH_ID=$(echo ${PATCH} | awk -F/ '{print $NF}')
+elif [[ ${PATCH} =~ ^https://github.com ]]; then
+  FORMAT=github
+  PATCH_ID=$(echo ${PATCH} | awk -F/ '{print $NF}')
+else
+  # Exit if we don't know how to handle this patch
+  echo "Unknown patch format: ${PATCH}"
+  exit 1
+fi
+
+# Clone the repository in a temporary directory if it doesn't exist
+if [ ! -d "/tmp/vexxhost-${PROJECT}" ]; then
+  gh repo clone vexxhost/${PROJECT} /tmp/vexxhost-${PROJECT}
+fi
+
+# Switch to the repository
+cd /tmp/vexxhost-${PROJECT}
+
+# Update the repository
+git fetch origin
+
+# Switch to the branch that we're cherry-picking into
+git checkout -B patch/${BRANCH}/${PATCH_ID} origin/${BRANCH}
+
+# Cherry-pick the change
+if [[ ${FORMAT} == "gerrit" ]]; then
+  LATEST_REV=$(git ls-remote https://opendev.org/openstack/${PROJECT} | grep -E "refs/changes/[[:digit:]]+/${PATCH_ID}/" | sort -t / -k 5 -g | tail -n1 | awk '{print $2}')
+  git fetch https://review.opendev.org/openstack/${PROJECT} ${LATEST_REV} && git cherry-pick FETCH_HEAD
+elif [[ ${FORMAT} == "github" ]]; then
+  gh pr checkout --branch patch/${BRANCH}/${PATCH_ID} -f ${PATCH}
+fi
+
+# Push this branch to the remote
+git push -u origin patch/${BRANCH}/${PATCH_ID}
+
+# Create a PR for this change
+gh repo set-default vexxhost/${1}
+gh pr create \
+  --title "$(git show -s --format=%s)" \
+  --body "$(git show -s --format=%B)" \
+  --base ${BRANCH} \
+  --head patch/${BRANCH}/${PATCH_ID}