Skip to content

Instantly share code, notes, and snippets.

@mtilson
Last active February 8, 2024 17:51
Show Gist options
  • Save mtilson/be5e01de1182180b720adc3393a5cba1 to your computer and use it in GitHub Desktop.
Save mtilson/be5e01de1182180b720adc3393a5cba1 to your computer and use it in GitHub Desktop.
what are GitHub 'refs/pull/*' refspecs and how to get full copy of GitHub repo [git] [github]
#!/usr/bin/env bash
# we are going to fetch all refs (including 'refs/pull/*') from Git remote
# 'repo-to-fetch', which points to public GitHub repo defined by URL
# '${repoURL}' where the GitHub user account '${userName}' has write access
# for more details on GitHub 'refs/pull/*' refspecs see [1]
userName=mxxxxxx
userEmail=mxxxxxx@xxxxx.xxx
repoURL=https://github.com/txxxx-xx/gxx-xxxx.git
# create, init, and configure git repo
mkdir bare-repo
cd bare-repo
git init --bare
git config user.email ${userEmail}
git config user.name ${userName}
git config credential.username ${userName}
# set up 'repo-to-fetch' remote, you NEED TO CREATE new GitHub repo
# preliminarily
git remote add --mirror=fetch repo-to-fetch ${repoURL}
# see default set of 'refspec' for the created remote (for 'git fetch'
# command)
git config --get-all remote.repo-to-fetch.fetch # output: '+refs/*:refs/*'
# see existing branches and tags before fetch
git branch -avv | wc -l # output: 0
git tag -l | wc -l # output: 0
find refs -type f | wc -l # output: 0
tree refs # output:
#> refs
#> ├── heads
#> └── tags
#>
#> 2 directories, 0 files
# fetch updates from 'repo-to-fetch' remote
git remote update 2>&1 | grep "^ \*" > log
# examine log
cat log | wc -l # output: ' 20'
cat log | grep "new branch" | wc -l # output: ' 3'
cat log | grep "new ref" | wc -l # output: ' 11'
cat log | grep "new tag" | wc -l # output: ' 6'
# see existing branches and tags after fetch (with help of git command)
git branch -avv | wc -l # output: ' 3'
git tag -l | wc -l # output: ' 6'
# see stored refs
find refs -type f | wc -l # output: ' 20'
find refs/heads -type f | wc -l # output: ' 3'
find refs/pull -type f | wc -l # output: ' 11'
find refs/tags -type f | wc -l # output: ' 6'
# see all remote refs
git ls-remote repo-to-fetch | wc -l # output: ' 24'
git ls-remote repo-to-fetch | grep HEAD | wc -l # output: ' 1'
git ls-remote repo-to-fetch | grep "refs/heads" | wc -l # output: ' 3'
git ls-remote repo-to-fetch | grep "refs/pull" | wc -l # output: ' 11'
git ls-remote repo-to-fetch | grep "refs/pull/[0-9]\+/head" | wc -l # output: ' 10'
git ls-remote repo-to-fetch | grep "refs/pull/[0-9]\+/merge" | wc -l # output: ' 1'
git ls-remote repo-to-fetch | grep "refs/tags" | wc -l # output: ' 9'
git ls-remote repo-to-fetch | grep "refs/tags" | grep -v "\^{}$" | wc -l # output: ' 6'
# let's see how 'refs/pull/*' refspecs look like; let's assume we have
# open pull request which have number ${prOpen}
# change N to the number of existing open pull request
prOpen=N
# the GitHub 'refs/pull/*/head' refspecs correspond to all created (open
# and closed) pull requests; new 'refs/pull/<N>/head' is created every
# time new pull request <N> is created (e.g. via GitHub webUI, 'gh', 'hub')
find refs/pull -type f | grep "refs/pull/[0-9]\+/head" | wc -l # output: ' 10'
# see how 'refs/pull/<N>/head' refspecs look like
cat refs/pull/${prOpen}/head # output: 'ce46a4519061e27250e1284523d8b3275f07248b'
git show $(cat refs/pull/${prOpen}/head) # output:
#> commit ce46a4519061e27250e1284523d8b3275f07248b (refs/pull/N/head, user/featureN)
#> Author: user <user@email.io>
#> Date: Mon Apr 6 16:04:48 2020 +0300
#>
#> featureN
#>
#> diff --git a/featureN b/featureN
#> new file mode 100644
#> index 0000000..e69de29
# the GitHub 'refs/pull/*/merge' refspecs correspond to open pull requests
# only; new 'refs/pull/<N>/merge' is created every time new pull request
# <N> is created (e.g. via GitHub webUI, 'gh', 'hub'); the
# 'refs/pull/<N>/merge' is deleted every time pull request <N> is
# merged (e.g. via GitHub webUI, 'gh', 'hub')
find refs/pull -type f | grep "refs/pull/[0-9]\+/merge" | wc -l # output: ' 1'
# see how 'refs/pull/<N>/merge' refspecs look like
cat refs/pull/${prOpen}/merge # output: '4ab972401e31c379d012e0c76bef97df8ec8e886'
git show $(cat refs/pull/${prOpen}/merge) # output:
#> commit 4ab972401e31c379d012e0c76bef97df8ec8e886 (refs/pull/N/merge)
#> Merge: 6937f49 ce46a45
#> Author: user <user@email.io>
#> Date: Mon Apr 6 13:05:50 2020 +0000
#>
#> Merge ce46a4519061e27250e1284523d8b3275f07248b into 6937f49a3f85b94c1caaa46245a0b9e02ffc23ff
#>
# let's see how 'refs/pull/*' are created/deleted as pull requests are
# created/merged (e.g. via GitHub webUI, 'gh', 'hub'); let's assume the
# next created pull request will have the number ${prNext}
# change M to the number of the next pull request (the number of
# the last one plus one)
prNext=M
# look at the pull request locally and remotely
find refs/pull -type f -path "refs/pull/${prNext}/*" # no output
git ls-remote repo-to-fetch | grep "refs/pull/${prNext}" # no output
# create and checkout to new branch 'user/featureM'
git branch user/feature${prNext}
mkdir ../work-tree
git --work-tree=../work-tree checkout user/feature${prNext}
# make, stage, and commit changes
touch ../work-tree/feature${prNext}
git --work-tree=../work-tree add feature${prNext}
git --work-tree=../work-tree commit -m "feature${prNext}"
# push the created branch to remote
git --work-tree=../work-tree push repo-to-fetch user/feature${prNext}
echo "here you NEED TO CREATE new branch pull request (e.g. via GitHub webUI)"
echo "the script will continue in 60 seconds"
sleep 60
# the GitHub Action refspecs (github.ref) for the created pull request
# is 'refs/pull/M/merge'
# look at the pull request locally and remotely
find refs/pull -type f -path "refs/pull/${prNext}/*" # no output
git ls-remote repo-to-fetch | grep "refs/pull/${prNext}" # output:
#> 71940958cc9ebf3904119ae16c549cc23cbe6652 refs/pull/M/head
#> 3c68ecbc55105bd7f9ecf67fb1692880fd7ae4a5 refs/pull/M/merge
# fetch and look at changes locally
git fetch repo-to-fetch
find refs/pull -type f -path "refs/pull/${prNext}/*" # output:
#> refs/pull/M/merge
#> refs/pull/M/head
find refs/pull -type f -path "refs/pull/${prNext}/*" | xargs cat # output:
#> 3c68ecbc55105bd7f9ecf67fb1692880fd7ae4a5
#> 71940958cc9ebf3904119ae16c549cc23cbe6652
echo "here you NEED TO MERGE the pull request (e.g. via GitHub webUI)"
echo "the script will continue in 60 seconds"
sleep 60
# the GitHub Action refspecs (github.ref) for the merge is 'refs/heads/master'
# look at the pull request locally and remotely
find refs/pull -type f -path "refs/pull/${prNext}/*" # output:
#> refs/pull/M/merge
#> refs/pull/M/head
git ls-remote repo-to-fetch | grep "refs/pull/${prNext}" # output:
#> 71940958cc9ebf3904119ae16c549cc23cbe6652 refs/pull/M/head
# fetch and look at changes locally
git fetch repo-to-fetch
find refs/pull -type f -path "refs/pull/${prNext}/*" # output:
#> refs/pull/M/merge
#> refs/pull/M/head
# remove any remote-tracking references (that no longer exist on the remote),
# fetch and look at changes locally
git fetch repo-to-fetch -p
find refs/pull -type f -path "refs/pull/${prNext}/*" # output:
#> refs/pull/M/head
# PS: clean up local and remote repos
# remote feature branch is deleted after pull request merge
# see remote feature branch before it is deleted
git ls-remote repo-to-fetch | grep "feature${prNext}" # output:
#> 71940958cc9ebf3904119ae16c549cc23cbe6652 refs/heads/user/featureM
echo "here you NEED TO DELETE feature branch remotely (e.g. via GitHub webUI)"
echo "the script will continue in 60 seconds"
sleep 60
# no more remote feature branch after it is deleted
git ls-remote repo-to-fetch | grep "feature${prNext}" # no output
# local feature branch is also can be deleted after pull request merge
# see local feature branch before it is deleted
git br -a | grep "feature${prNext}" # output: '* user/featureM'
# delete feature branch locally
git br -d user/feature${prNext}
# no local feature branch after it is deleted
git br -a | grep "feature${prNext}" # no output
# [1] https://gist.github.com/piscisaureus/3342247
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment