~edwargix/git.sr.ht

4966a6604e2f2eac9686d19616404750d27b6c20 — наб 4 years ago 6d7c9eb
Set receive.denyDeleteCurrent=ignore for old and newly created repositories

By default, git disallows removing the current default branch, with a
large error notice like this:
-- >8 --
remote: error: By default, deleting the current branch is denied, because the next
remote: 'git clone' won't result in any file checked out, causing confusion.
remote:
remote: You can set 'receive.denyDeleteCurrent' configuration variable to
remote: 'warn' or 'ignore' in the remote repository to allow deleting the
remote: current branch, with or without a warning message.
remote:
remote: To squelch this message, you can set it to 'refuse'.
-- >8 --

However, we handle this ourselves in the post-update hook, and will only
let the default branch dangle if there are no branches (the repository
is empty), which is equivalent to the "fresh repository" state.

This also means that *all current repositories need to be migrated*
to the new config to be able to take advantage of the new semantics.
M gitsrht-shell/main.go => gitsrht-shell/main.go +5 -0
@@ 299,6 299,11 @@ func main() {

					notFound("git init", err)
				}
				if err = exec.Command("git", "-C", path, "config",
					"receive.denyDeleteCurrent", "ignore").Run(); err != nil {

					notFound("git config", err)
				}
				if err = exec.Command("ln", "-s", postUpdate,
					gopath.Join(path, "hooks", "update")).Run(); err != nil {


A gitsrht/alembic/versions/3c1285bb23e2_allow_deleting_default_branch.py => gitsrht/alembic/versions/3c1285bb23e2_allow_deleting_default_branch.py +42 -0
@@ 0,0 1,42 @@
"""Allow deleting default branch

Revision ID: 3c1285bb23e2
Revises: 163fc2d2a2ea
Create Date: 2020-07-28 12:04:39.751225

"""

# revision identifiers, used by Alembic.
revision = '3c1285bb23e2'
down_revision = '163fc2d2a2ea'

import subprocess
from alembic import op
from sqlalchemy.orm import sessionmaker
from gitsrht.types import Repository
try:
    from tqdm import tqdm
except ImportError:
    def tqdm(iterable):
        yield from iterable

Session = sessionmaker()


def upgrade():
    bind = op.get_bind()
    session = Session(bind=bind)
    print("Setting receive.denyDeleteCurrent=ignore")
    for repo in tqdm(session.query(Repository).all()):
        subprocess.run(["git", "config", "receive.denyDeleteCurrent", "ignore"],
            check=True, cwd=repo.path,
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)


def downgrade():
    bind = op.get_bind()
    session = Session(bind=bind)
    for repo in tqdm(session.query(Repository).all()):
        subprocess.run(["git", "config", "--unset", "receive.denyDeleteCurrent"],
            check=True, cwd=repo.path,
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

M gitsrht/repos.py => gitsrht/repos.py +5 -0
@@ 90,6 90,11 @@ class GitRepoApi(SimpleRepoApi):
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        subprocess.run(["git", "config", "srht.repo-id", str(repo.id)], check=True,
            cwd=repo.path, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        # We handle this ourselves in the post-update hook, and git's
        # default behaviour is to print a large notice and reject the push entirely
        subprocess.run(["git", "config", "receive.denyDeleteCurrent", "ignore"],
            check=True, cwd=repo.path,
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        subprocess.run(["ln", "-s",
                post_update,
                os.path.join(repo.path, "hooks", "pre-receive")