Thank you for filling out a Git bug report! Please answer the following questions to help us understand your issue.
What did you do before the bug happened? (Steps to reproduce your issue)
# setup main and subtree repo $ git init main && git init subtree $ cd main && git remote add subtr ../subtree/.git
# populate main repo $ mkdir dir && echo hello > dir/hello.txt $ git add . && git commit -m "Commit dir"
# split/push subtree 'dir'... $ git subtree push --prefix=dir --rejoin --squash subtr subtrbranch # ...and again $ git subtree push --prefix=dir --rejoin --squash subtr subtrbranch
What did you expect to happen? (Expected behavior)
- No change on 2nd git subtree push
What happened instead? (Actual behavior)
- Remote-ref unexpectedly deleted on 2nd git subtree push: > git push using: subtr subtrbranch > Subtree is already at commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. > To ../subtree/.git > - [deleted] subtrbranch
What's different between what you expected and what actually happened?
- No change vs deleted remote-ref on 2nd git subtree push.
Anything else you want to add:
- Root cause in contrib/subtree/git-subtree.sh (branch next, 3824d2c): In the scenario above: cmd_push calls cmd_split in a subshell: localrev=$(cmd_split "$localrev_presplit" "$repository") || die cmd_split calls cmd_merge. cmd_merge exits 0 without writing to stdout if test "$sub" = "$rev" then say >&2 "Subtree is already at commit $rev." exit 0 fi With exit 0 only the subshell is exited. Instead of dying this assignement localrev=$(cmd_split "$localrev_presplit" "$repository") || die becomes localrev= yielding a refspec :refs/heads/$remoteref pushed to the remote repository: git push "$repository" "$localrev":"refs/heads/$remoteref"
- Proposed fix (I can try to submit a patch if desired):
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 791fd8260c..0951a5aadd 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -1102,7 +1102,11 @@ cmd_push () { echo "git push using: " "$repository" "$refspec" localrev=$(cmd_split "$localrev_presplit" "$repository") || die - git push "$repository" "$localrev":"refs/heads/$remoteref" + # Validate localrev. It maybe empty if cmd_split exits with 0. + if test -n "$localrev" + then + git push "$repository" "$localrev":"refs/heads/$remoteref" + fi else die "fatal: '$dir' must already exist. Try 'git subtree add'." fi Please review the rest of the bug report below. You can delete any lines you don't wish to share. [System Info] git version: git version 2.53.0.windows.1 cpu: x86_64 built from commit: a5512bdee37ed7142c233d21e2d347ffc4860ff3 sizeof-long: 4 sizeof-size_t: 8 shell-path: D:/git-sdk-64-build-installers/usr/bin/sh rust: disabled feature: fsmonitor--daemon gettext: enabled libcurl: 8.18.0 OpenSSL: OpenSSL 3.5.5 27 Jan 2026 zlib: 1.3.1 SHA-1: SHA1_DC SHA-256: SHA256_BLK default-ref-format: files default-hash: sha1 uname: Windows 10.0 26100 compiler info: gnuc: 15.2 libc info: no libc information available $SHELL (typically, interactive shell): C:\Program Files\Git\usr\bin\bash.exe [Enabled Hooks]