Giulio Vian
Giulio Vian

Reputation: 8353

How to rebuild the packed-refs file

Context

I am writing a script to mirror and periodically refresh some repositories from GitHub. GitHub repos have reference to Pull request branches that have no meaning outside, so I am filtering them out as suggested in Howto: Mirror a GitHub Repo Without Pull Refs. So far the steps are

git clone --mirror SourceGitHubRepoUrl
git remote add --mirror=push alice MyMirrorUrl
git config --local --replace-all remote.origin.fetch "+refs/heads/*:refs/heads/*" 
git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

at this point the local mirror has the correct fetch rules and

git remote update origin

works nicely, but

git push --mirror alice

gives errors like ! [remote rejected] refs/pull/22/head -> refs/pull/22/head because the packed-refs still lists the refs/pull/* branches.

Question

How can I fix the content of packed-refs? Can I simply remove all lines matching "refs/pull"?

This latter seems to work, but one is never sure that there are no lurking gremlins.

Upvotes: 4

Views: 6559

Answers (2)

VonC
VonC

Reputation: 1328142

so I am filtering them out

Speaking of filtering, Git 2.42 (Q3 2023), "git pack-refs"(man) learns --include and --exclude to tweak the ref hierarchy to be packed using pattern matching.

See commit 4fe42f3, commit 826ae79, commit 283174b (12 May 2023) by John Cai (john-cai).
(Merged by Junio C Hamano -- gitster -- in commit cbc882e, 13 Jun 2023)

pack-refs: teach --exclude option to exclude refs from being packed

Signed-off-by: John Cai

At GitLab, we have a system that creates ephemeral internal refs that don't live long before getting deleted.
Having an option to exclude certain refs from a packed-refs file allows these internal references to be deleted much more efficiently.

Add an --exclude option to the pack-refs builtin, and use the ref exclusions API to exclude certain refs from being packed into the final packed-refs file

git pack-refs now includes in its man page:

'git pack-refs' [--all] [--no-prune] [--exclude ]

git pack-refs now includes in its man page:

--exclude <pattern>

Do not pack refs matching the given glob(7) pattern. Repetitions of this option accumulate exclusion patterns. Use --no-exclude to clear and reset the list of patterns. If a ref is already packed, including it with --exclude will not unpack it.

When used with --all, pack only loose refs which do not match any of the provided --exclude patterns.

And:

pack-refs: teach pack-refs --include option

Signed-off-by: John Cai

Allow users to be more selective over which refs to pack by adding an --include option to git-pack-refs.

The existing options allow some measure of selectivity.
By default git-pack-refs(man) packs all tags.
--all can be used to include all refs, and the previous commit added the ability to exclude certain refs with --exclude.

While these knobs give the user some selection over which refs to pack, it could be useful to give more control.
For instance, a repository may have a set of branches that are rarely updated and would benefit from being packed.
--include would allow the user to easily include a set of branches to be packed while leaving everything else unpacked.

git pack-refs now includes in its man page:

'git pack-refs' [--all] [--no-prune] [--include ] [--exclude ]

git pack-refs now includes in its man page:

--include <pattern>

Pack refs based on a glob(7) pattern. Repetitions of this option accumulate inclusion patterns. If a ref is both included in --include and --exclude, --exclude takes precedence. Using --include will preclude all tags from being included by default. Symbolic refs and broken refs will never be packed. When used with --all, it will be a noop. Use --no-include to clear and reset the list of patterns.

git pack-refs now includes in its man page:

When used with --include, refs provided to --include, minus refs that are provided to --exclude will be packed.

With that, you can control what you want in your pack-refs.

Upvotes: 1

Phssthpok
Phssthpok

Reputation: 1659

In a similar situation, I was able to incrementally update the remote origin to the mirrored remote backup through a bare repo by using git-update-ref and git-pack-refs:

git fetch --all --prune
BRANCHES="$(git branch --remotes | grep origin/ )"
for BRANCH in $BRANCHES; do
    echo "--> setting local branch ${BRANCH#origin/} to remote branch ${BRANCH}"
    git update-ref "refs/heads/${BRANCH#origin/}" $(git rev-parse $BRANCH)
    git pack-refs --all
done
echo "--> pushing to backup"
git push --mirror backup

Upvotes: 1

Related Questions