Skip to content

get-ivim.sh --uninstall can rm -rf unpushed commits on a branch with no upstream #3

@chiro-hiro

Description

@chiro-hiro

Severity: medium · Category: robustness
Location: get-ivim.sh — uninstall(), lines 232-247 (the unpushed-commits branch at line 238)

What's wrong

The uninstall path tries to protect a user's local work before deleting ~/.ivim. The committed-but-unpushed check is git -C "$IVIM_DIR" log '@{u}..HEAD' --oneline 2>/dev/null. When the checked-out branch has no configured upstream (e.g. the user did git checkout -b mytweaks to keep local edits, or HEAD is detached), @{u} does not resolve: git exits 128 with fatal: no upstream configured, and 2>/dev/null swallows it so the command substitution yields an empty string. dirty therefore stays empty, the guard is skipped, and rm -rf "$IVIM_DIR" (line 247) destroys the unpushed commits the guard was written to protect. The git status --porcelain check does not catch this because the work is committed, not in the working tree. The plain-clone default branch (master) does get upstream tracking so the common case is safe, but any user who forked their config onto a local branch loses it with no warning, directly contradicting the inline intent comment 'Guard against losing uncommitted/unpushed local work.'

Evidence

Line 238: elif [ -n "$(git -C "$IVIM_DIR" log '@{u}..HEAD' --oneline 2>/dev/null)" ]; then

Reproduced: on a local branch with no upstream and a fresh commit, git log '@{u}..HEAD' --oneline prints fatal: no upstream configured for branch 'master' to stderr and rc=128 with empty stdout. With 2>/dev/null the substitution is empty, so dirty="", the if [ -n "$dirty" ] block is skipped, and execution falls through to rm -rf "$IVIM_DIR" at line 247.

Suggested fix

Treat a non-zero exit from the @{u}..HEAD check as 'cannot prove it is safe' rather than 'no unpushed work'. For example, capture status explicitly and also detect the no-upstream / detached-HEAD cases as dirty: if git -C "$IVIM_DIR" rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1 fails while HEAD has commits, set dirty="local commits with no upstream". Alternatively compare against the matching remote-tracking ref for the current branch, and on any ambiguity refuse to delete (require the user to remove ~/.ivim manually).


Filed from an automated multi-agent source review (2026-05-29); finding adversarially verified at high confidence. Line numbers reflect the audit-fixes-2026-05 working tree.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions