
Guard a Public Remote Against Accidental Direct Push
Source:R/clean_publish.R
guard_public_remote.RdRecords the URL(s) of the public remote in git config (cleanpublish.publicurl) and
makes sure the pre-push hook is installed. The hook refuses a git push whose
push URL is one of them, after git has applied its own rewriting
(url.<base>.insteadOf, pushInsteadOf) and the URLs have been normalised: case,
a trailing .git or slash, a scheme, a user name, host:path and backslash
notation do not matter, and a local directory counts by its physical path as well. Nothing
else is resolved (a symbolic link on a remote host, a changed DNS name), and a URL of
another spelling is not the same URL.
Arguments
- public_url
The name of a configured remote (its fetch and push URLs, as
git remote get-url --alland--push --allreport them, are stored), or a URL. A URL must match the push URL of at least one configured remote after normalising, so that a fence that guards nothing is an error, unlessallow_unmatched = TRUE. It must not contain whitespace, which the hook cannot compare word by word.- repo_root
Path to the git repository root. Defaults to the git toplevel of the working directory (an error when that is not in a repository).
- allow_unmatched
Logical (default
FALSE). SetTRUEto fence a URL that no configured remote has yet, for a remote that will be added later.
Details
The one push that goes through is the one clean_publish() makes: it sets the
environment variable TEMPLECBE_PUBLISHING=1, and with that variable the hook lets
through the clean commits clean_publish() recorded, and nothing else. The variable
bypasses the fence only: any other ref, the private branch for one, is still refused.
After writing, the function checks the result. It runs the hook by hand, as git does, for
every configured remote and for every fenced URL, with TEMPLECBE_PUBLISHING unset,
and stops with an error when the hook is missing, is not executable, or does not refuse
a push to a remote the fence matches: a fence that is not confirmed is not left to guard
nothing in silence.
What the guard does not stop. It is a hook of command-line git. It does
not stop git push --no-verify, a push made by a client that does not run hooks (the
gert package, which usethis uses, is one), a push after core.hooksPath
has been pointed elsewhere or the hook has been deleted or made non-executable, and a push
to the URL in a spelling that is not one of the fenced ones, for example an explicit URL
that names the same repository through another host name. It checks pushes, not reads. The
safest procedure is to publish from a throwaway clone and to keep no pushable public remote
in the clone you work in.
Examples
if (FALSE) { # \dontrun{
# the remote of the public repository, by name ...
guard_public_remote("public")
# ... or by URL, which must be the push URL of a configured remote
guard_public_remote("https://github.com/OWNER/NEW-PUBLIC-REPO.git")
# a URL for a remote that is added after this call
guard_public_remote("https://github.com/OWNER/NEW-PUBLIC-REPO.git", allow_unmatched = TRUE)
} # }