threads / discuss / 65155

[git/contrib/subtree] Remote-ref unexpectedly deleted if pushing subtree commit twice

Subject: [git/contrib/subtree] Remote-ref unexpectedly deleted if pushing subtree commit twice

## tl;dr

One message between Mar 6, 2026 and Mar 6, 2026.

replies: 0people: 1as markdown or json

joerg.gambihler@gmx.de· Mar 6, 2026, 17:53 UTC · lore

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]

← back to recent threads