{"thread":{"id":"66333","subject":"Bug!?: Refspec '+' should be same as '--force' but is not","startedAt":"2026-09-15T15:22:05Z","lastAt":"2026-09-15T19:35:01Z","messageCount":3,"participants":["André Kießling","Ben Knoble","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"552757","messageId":"1bcb043e-e744-4e01-8569-4da5669d25fc@carneios.de","threadId":"66333","inReplyTo":null,"subject":"Bug!?: Refspec '+' should be same as '--force' but is not","fromName":"André Kießling","fromEmail":"akiessling@carneios.de","sentAt":"2026-09-15T15:06:38Z","receivedAt":"2026-09-15T15:22:05Z","isPatch":false,"body":"Hi there, think I found a bug...\n\nIn https://git-scm.com/docs/git-push I find:\n > The + is optional and does the same thing as --force.\n\nThe fetch documentation refers to push for the details of <refspec> so I \nassume, the statement also holds for fetch refspecs.\nHowever, this is not true:\nWhen I run `git fetch origin --tags --force` it will force update tags \nthat changed on remote (as expected) but will NOT delete local tags.\nWhen I run `git fetch origin` with config set to `remote.origin.fetch = \n+refs/tags/*:refs/tags/*` it will delete my local tags as if prune was set.\n\nI'm using Git 2.54.0.windows.1\n\n\n\n\n\nCarneios GmbH\n\nAm Borsigturm 64\n13507 Berlin\n\nTel. +49 30 2332035-0\nFax +49 30 2332035-99\n\nhttps://www.carneios.de\ninfo@carneios.de\n\nGeschäftsführer: Michael Giersch\nHandelsregister: Charlottenburg HRB 138285\nUSt.-ID: DE 280 745 293\n\n\n"},{"id":"552762","messageId":"DF50C11C-44E1-4BEC-A446-8C27F165478F@gmail.com","threadId":"66333","inReplyTo":"1bcb043e-e744-4e01-8569-4da5669d25fc@carneios.de","subject":"Re: Bug!?: Refspec '+' should be same as '--force' but is not","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-15T16:41:17Z","receivedAt":"2026-09-15T16:41:30Z","isPatch":false,"body":"\n> Le 15 sept. 2026 à 11:33, André Kießling <akiessling@carneios.de> a écrit :\n> \n> ﻿Hi there, think I found a bug...\n> \n> In https://git-scm.com/docs/git-push I find:\n> > The + is optional and does the same thing as --force.\n> \n> The fetch documentation refers to push for the details of <refspec> so I assume, the statement also holds for fetch refspecs.\n> However, this is not true:\n> When I run `git fetch origin --tags --force` it will force update tags that changed on remote (as expected) but will NOT delete local tags.\n> When I run `git fetch origin` with config set to `remote.origin.fetch = +refs/tags/*:refs/tags/*` it will delete my local tags as if prune was set.\n> \n> I'm using Git 2.54.0.windows.1\n\nI think this behavior is described in git-fetch(1) in the PRUNING\nsection. It’s a bit opaque to me :) Still, you might take a look\nthere and see what you find. "},{"id":"552766","messageId":"xmqqld92z4t9.fsf@gitster.g","threadId":"66333","inReplyTo":"1bcb043e-e744-4e01-8569-4da5669d25fc@carneios.de","subject":"Re: Bug!?: Refspec '+' should be same as '--force' but is not","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-15T19:34:58Z","receivedAt":"2026-09-15T19:35:01Z","isPatch":false,"body":"André Kießling <akiessling@carneios.de> writes:\n\n> Hi there, think I found a bug...\n>\n> In https://git-scm.com/docs/git-push I find:\n>  > The + is optional and does the same thing as --force.\n>\n> The fetch documentation refers to push for the details of <refspec> so I \n> assume, the statement also holds for fetch refspecs.\n\nA fresh clone typically creates\n\n    [remote \"origin\"]\n\turl = ...\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n\nAnd indeed \"+\" there *is* optional.  If you remove \"+\" from there,\nthen your \"git fetch\" from origin will notice every time \"origin\"\nrewinds its branches because it fails to update your remote-tracking\nbranches without forcing.  So it is like giving \"--force\" to allow\nthe origin rewind its branch tips hence your remote-tracking branches.\n\nIOW, the statement holds for both push and fetch and the\ndocumentation is correct.  But forcing vs not forcing should not\naffect pruning.  They are totally separate concepts.  So quoting the\nabove documentation and then suddenly discussing if pruning takes\nplace or not is a bit jarring.\n\n> When I run `git fetch origin --tags --force` it will force update tags \n> that changed on remote (as expected) but will NOT delete local tags.\n> When I run `git fetch origin` with config set to `remote.origin.fetch = \n> +refs/tags/*:refs/tags/*` it will delete my local tags as if prune was set.\n>\n> I'm using Git 2.54.0.windows.1\n\nEven though I do not do Windows, this is so basic a thing that I do\nnot think there would be platform-dependent behaviour differences.\n\nUnfortunately, the above does not reproduce for me.  Here is my\nfailed reproduction attempt.\n\nFirst the set-up.\n\n    $ rm -fr /var/tmp/x && mkdir /var/tmp/x && cd /var/tmp/x\n    $ git init src\n    $ cd src\n    $ git commit --allow-empty -m initial\n    [master (root-commit) 9edb8aa] initial\n    $ git tag -m initial v0.0 master\n    $ git for-each-ref\n    9edb8aaed37552991a2c7578da7862ffecae1e30 commit refs/heads/master\n    26fb2b9f313528b70566594e621d3873e9815415 tag    refs/tags/v0.0\n    $ cd ..\n    $ git clone --no-local src dst\n    Cloning into 'dst'...\n    remote: Enumerating objects: 3, done.\n    remote: Counting objects: 100% (3/3), done.\n    remote: Compressing objects: 100% (2/2), done.\n    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)\n    Receiving objects: 100% (3/3), done.\n    $ cd dst\n    $ git tag -m ours -f w0.0 master\n    $ git commit --allow-empty -m second\n    [master 4b48c71] second\n    $ git tag -m 'our second' w0.1 master\n    $ git for-each-ref\n    4b48c71f0f2d3ca58eeed0d3afa71f23681dd98e commit refs/heads/master\n    9edb8aaed37552991a2c7578da7862ffecae1e30 commit refs/remotes/origin/HEAD\n    9edb8aaed37552991a2c7578da7862ffecae1e30 commit refs/remotes/origin/master\n    26fb2b9f313528b70566594e621d3873e9815415 tag    refs/tags/v0.0\n    cc47a66dac78d2838e767436a44b24aaca521ef7 tag    refs/tags/w0.0\n    9f49b658425485deff4cc1c4ea52583bfecd294a tag    refs/tags/w0.1\n\nThe origin (src) has a commit and a tag that points at it, the clone\n(dst) builds a commit on top of that, has two tags of its own.\n\nNow the reproduction attempt comes.\n\n    $ git config set remote.origin.fetch --append '+refs/tags/*:refs/tags/*'\n    $ git fetch origin\n    $ git for-each-ref\n    4b48c71f0f2d3ca58eeed0d3afa71f23681dd98e commit refs/heads/master\n    9edb8aaed37552991a2c7578da7862ffecae1e30 commit refs/remotes/origin/HEAD\n    9edb8aaed37552991a2c7578da7862ffecae1e30 commit refs/remotes/origin/master\n    26fb2b9f313528b70566594e621d3873e9815415 tag    refs/tags/v0.0\n    cc47a66dac78d2838e767436a44b24aaca521ef7 tag    refs/tags/w0.0\n    9f49b658425485deff4cc1c4ea52583bfecd294a tag    refs/tags/w0.1\n    $ git config list --local\n    core.repositoryformatversion=0\n    core.filemode=true\n    core.bare=false\n    core.logallrefupdates=true\n    remote.origin.url=/var/tmp/x/src\n    remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*\n    remote.origin.fetch=+refs/tags/*:refs/tags/*\n    branch.master.remote=origin\n    branch.master.merge=refs/heads/master\n\nUnless this is Windows specific, which I highly doubt, there must be\nsomething that is missing from your report.  Perhaps you have some\nconfiguration settings?\n"}]}