# We need to fetch the remote state to list its files.
# Fetch all heads to ensure we see files on any branch (e.g. main vs master).
# We map them to a temporary namespace refs/gcrypt/list-files/*
+
+ # Clean up any stale refs/gcrypt/list-files (could be a file from old version)
+ # to avoid D/F conflicts with the directory we are about to use.
+ git update-ref -d "refs/gcrypt/list-files" 2>/dev/null || :
+
if git fetch --quiet "$URL" "refs/heads/*:refs/gcrypt/list-files/*" 2>/dev/null; then
# List files from ALL fetched branches
# We iterate refs manually to detect which one has files
echo_info "Removing files..."
# If we are forcing clean on uninitialized repo, Gref might be missing.
+ # If we found dirty refs, pick the first one as our base to insure Gref is valid.
+ if [ "$Did_find_repo" != "yes" ] && isnonnull "$Global_Dirty_Refs"; then
+ # shellcheck disable=SC2086
+ set -- $Global_Dirty_Refs
+ if isnonnull "$1"; then
+ echo_info "Using $1 as base for cleaning."
+ Gref_rbranch="$1"
+ fi
+ fi
+
# Fetch it so gitception_remove has a base.
if [ "$Did_find_repo" != "yes" ] && isnonnull "$Gref_rbranch"; then
git fetch -q -f "$URL" "$Gref_rbranch:$Gref" 2>/dev/null || :
+++ /dev/null
-#!/bin/bash
-# Test: clean command should wipe all branches with files
-set -e
-
-# Colors
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-CYAN='\033[0;36m'
-NC='\033[0m'
-
-print_info() { echo -e "${CYAN}$*${NC}"; }
-print_success() { echo -e "${GREEN}✓ $*${NC}"; }
-print_err() { echo -e "${RED}✗ $*${NC}"; }
-
-# Setup path
-SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
-export PATH="$SCRIPT_DIR:$PATH"
-
-# Setup temp dir
-tempdir=$(mktemp -d)
-trap 'rm -rf "$tempdir"' EXIT
-
-export GNUPGHOME="${tempdir}/gpg"
-mkdir -p "${GNUPGHOME}"
-chmod 700 "${GNUPGHOME}"
-
-# GPG Wrapper
-cat <<'EOF' >"${GNUPGHOME}/gpg"
-#!/usr/bin/env bash
-exec /usr/bin/gpg --no-tty "$@"
-EOF
-chmod +x "${GNUPGHOME}/gpg"
-
-# Helper for git
-GIT="git -c advice.defaultBranchName=false -c commit.gpgSign=false"
-
-# Generate key
-gpg --batch --passphrase "" --quick-generate-key "Test <test@test.com>"
-
-# 1. Init bare repo (the "remote")
-print_info "Initializing 'remote'..."
-mkdir "$tempdir/remote" && cd "$tempdir/remote"
-$GIT init --bare
-
-# 2. Populate 'main' branch with a file
-print_info "Populating remote 'main' with a file..."
-mkdir "$tempdir/seeder" && cd "$tempdir/seeder"
-$GIT init -b main
-$GIT remote add origin "$tempdir/remote"
-echo "KEY DATA" >key.txt
-$GIT add key.txt
-$GIT config user.email "test@test.com"
-$GIT config user.name "Test"
-$GIT commit -m "Add key"
-$GIT push origin main
-
-# 3. Populate 'master' branch with a file
-print_info "Populating remote 'master' with a file..."
-$GIT checkout -b master
-echo "CONFIG DATA" >config.txt
-$GIT add config.txt
-$GIT commit -m "Add config"
-$GIT push origin master
-
-# Now remote has master (config.txt) and main (key.txt + config.txt? No, branched off main).
-# Both have unencrypted files.
-# `clean` should remove files from both.
-
-# 4. Attempt clean
-print_info "Attempting clean..."
-cd "$tempdir"
-git init
-# Explicitly target the remote
-if "$SCRIPT_DIR/git-remote-gcrypt" clean --init --force "gcrypt::$tempdir/remote"; then
- print_info "Clean command finished."
-else
- print_err "Clean command failed."
- exit 1
-fi
-
-# 5. Check if files still exist
-cd "$tempdir/remote"
-FAIL=0
-if $GIT -c core.quotePath=false ls-tree -r main | grep -q "key.txt"; then
- print_err "FAILURE: key.txt still exists on main!"
- FAIL=1
-else
- print_success "SUCCESS: key.txt was removed from main."
-fi
-
-if $GIT -c core.quotePath=false ls-tree -r master | grep -q "config.txt"; then
- print_err "FAILURE: config.txt still exists on master!"
- FAIL=1
-else
- print_success "SUCCESS: config.txt was removed from master."
-fi
-
-if [ $FAIL -eq 1 ]; then
- exit 1
-fi
+++ /dev/null
-#!/bin/bash
-# Test: clean command fails if master exists but is empty, and files are on main
-set -e
-
-# Colors
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-CYAN='\033[0;36m'
-NC='\033[0m'
-
-print_info() { echo -e "${CYAN}$*${NC}"; }
-print_success() { echo -e "${GREEN}✓ $*${NC}"; }
-print_err() { echo -e "${RED}✗ $*${NC}"; }
-
-# Setup path
-SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
-export PATH="$SCRIPT_DIR:$PATH"
-
-# Setup temp dir
-tempdir=$(mktemp -d)
-trap 'rm -rf "$tempdir"' EXIT
-
-export GNUPGHOME="${tempdir}/gpg"
-mkdir -p "${GNUPGHOME}"
-chmod 700 "${GNUPGHOME}"
-
-# GPG Wrapper
-cat <<'EOF' >"${GNUPGHOME}/gpg"
-#!/usr/bin/env bash
-exec /usr/bin/gpg --no-tty "$@"
-EOF
-chmod +x "${GNUPGHOME}/gpg"
-
-# Helper for git
-GIT="git -c advice.defaultBranchName=false -c commit.gpgSign=false"
-
-# Generate key
-gpg --batch --passphrase "" --quick-generate-key "Test <test@test.com>"
-
-# 1. Init bare repo (the "remote")
-print_info "Initializing 'remote'..."
-mkdir "$tempdir/remote" && cd "$tempdir/remote"
-$GIT init --bare
-
-# 2. Populate 'main' branch with a file
-print_info "Populating remote 'main' with a file..."
-mkdir "$tempdir/seeder_main" && cd "$tempdir/seeder_main"
-$GIT init -b main
-$GIT remote add origin "$tempdir/remote"
-echo "SECRET DATA" >secret.txt
-$GIT add secret.txt
-$GIT config user.email "test@test.com"
-$GIT config user.name "Test"
-$GIT commit -m "Add secret"
-$GIT push origin main
-
-# 3. Create an empty 'master' branch on the remote using a second seeder
-# We do this by pushing an unrelated history or just a new branch
-print_info "Creating empty 'master' on remote..."
-mkdir "$tempdir/seeder_master" && cd "$tempdir/seeder_master"
-$GIT init -b master
-$GIT remote add origin "$tempdir/remote"
-touch empty.txt
-$GIT add empty.txt
-$GIT config user.email "test@test.com"
-$GIT config user.name "Test"
-$GIT commit -m "Add empty"
-$GIT push origin master
-
-# Now remote has both master (with empty.txt) and main (with secret.txt)
-# But wait, if master has empty.txt, `clean` should at least find empty.txt.
-# We want to simulate a case where `master` is "empty" or irrelevant, but `main` is the real one.
-# If `master` has files, `clean` will report them.
-# The user said: "Remote is empty. Nothing to clean."
-# This implies `master` has NO files?
-# How can a branch exist but have no files?
-# Maybe `git ls-tree -r master` returns nothing if the branch is truly empty (e.g. only contains a .gitignore that was filtered out, or maybe just literally empty tree - possible in git but hard to maximize).
-# Or maybe the user has `master` that is just NOT the one with the data.
-# The user's output "Remote is empty" suggests `clean` found NOTHING.
-# If `master` had `empty.txt`, `clean` would list `empty.txt`.
-
-# Let's clean up `master` to be truly empty?
-# GIT allows empty commits but they still have a tree.
-# If we delete all files from master?
-cd "$tempdir/seeder_master"
-$GIT rm empty.txt
-$GIT commit -m "Remove all"
-$GIT push origin master
-
-# Now master exists but has NO files. "secret.txt" is on main.
-# `clean` should ideally check `main` (or all branches) and find `secret.txt`.
-# If `clean` only checks `master`, it will see empty tree and say "Remote is clean".
-
-# 4. Attempt clean
-print_info "Attempting clean..."
-cd "$tempdir"
-git init
-# Explicitly target the remote
-if "$SCRIPT_DIR/git-remote-gcrypt" clean --init --force "gcrypt::$tempdir/remote"; then
- print_info "Clean command finished."
-else
- print_err "Clean command failed."
- exit 1
-fi
-
-# 5. Check if secret.txt is still there
-cd "$tempdir/remote"
-if $GIT -c core.quotePath=false ls-tree -r main | grep -q "secret.txt"; then
- print_err "FAILURE: secret.txt still exists on main!"
- exit 1
-else
- print_success "SUCCESS: secret.txt was removed (or wasn't there)."
- # If it wasn't there, we need to know if we actually cleaned it.
- # The clean output should have mentioned it.
-fi
--- /dev/null
+#!/bin/bash
+# Test: clean command fails if refs/gcrypt/list-files exists as a file (D/F conflict)
+set -e
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+NC='\033[0m'
+print_info() { echo -e "${GREEN}$*${NC}"; }
+print_err() { echo -e "${RED}✗ $*${NC}"; }
+
+SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
+export PATH="$SCRIPT_DIR:$PATH"
+tempdir=$(mktemp -d)
+trap 'rm -rf "$tempdir"' EXIT
+
+export GNUPGHOME="${tempdir}/gpg"
+mkdir -p "${GNUPGHOME}"
+chmod 700 "${GNUPGHOME}"
+cat <<'EOF' >"${GNUPGHOME}/gpg"
+#!/usr/bin/env bash
+exec /usr/bin/gpg --no-tty "$@"
+EOF
+chmod +x "${GNUPGHOME}/gpg"
+
+GIT="git -c advice.defaultBranchName=false -c commit.gpgSign=false"
+gpg --batch --passphrase "" --quick-generate-key "Test <test@test.com>"
+
+mkdir "$tempdir/remote" && cd "$tempdir/remote"
+$GIT init --bare
+
+mkdir "$tempdir/seeder" && cd "$tempdir/seeder"
+$GIT init -b main
+$GIT remote add origin "$tempdir/remote"
+echo "DATA" >file.txt
+$GIT add file.txt
+$GIT commit -m "init"
+$GIT push origin main
+
+print_info "Attempting clean with poisoned environment..."
+cd "$tempdir"
+git init
+# Create a commit so we have something to point the ref to
+touch foo
+git add foo
+git commit -m "init"
+
+# POISON: Create a ref that conflicts with the directory we want to use
+# The old code used refs/gcrypt/list-files as a file.
+# The new code uses refs/gcrypt/list-files/BRANCH.
+# If we have the old ref, git fetch might fail.
+git update-ref refs/gcrypt/list-files HEAD
+
+if "$SCRIPT_DIR/git-remote-gcrypt" clean --init --force "gcrypt::$tempdir/remote"; then
+ print_info "Clean command finished."
+else
+ print_err "Clean command returned error code."
+fi
+
+# Check if file still exists (it should be gone if clean worked)
+cd "$tempdir/remote"
+files=$($GIT ls-tree -r main | grep "file.txt" || :)
+if [ -n "$files" ]; then
+ print_err "FAILURE: file.txt still exists on main! (Clean likely failed silently)"
+ exit 1
+else
+ print_info "SUCCESS: file.txt was removed."
+fi