Search code examples
gitgit-push

git push --all --tags: incompatible


When I try to push all branches and tags to a remote, git emits the following error:

# git push origin --all --tags
fatal: --all and --tags are incompatible

However, this works:

# git push origin refs/heads refs/tags
Everything up-to-date

Questions:

  1. Why git names push-all-branches --all but not --branches or --heads? git push origin --all only pushes branches, not all refs. What's the philosophy behind such naming? Does this mean tags are really 2nd-class citizens in a Git repo?

  2. Why git doesn't allow the use of both --all and --tags?


PS. I know there's a --follow-tags option. I know pushing all tags is not recommended by some people, but this thread is not about that.


man git-push:

--all

Push all branches (i.e. refs under refs/heads/); cannot be used with other <refspec>.

--tags

All refs under refs/tags are pushed, in addition to refspecs explicitly listed on the command line.


Solution

  • The message "--all and --tags are incompatible" comes from builtin/push.c#cmd_push()

    This was introduced by Marek Zawirski in commit b259f09 in August 2008 (Git v1.6.1-rc1):

    Make push more verbose about illegal combination of options

    It may be unclear that --all, --mirror, --tags and/or explicit refspecs are illegal combinations for git push.

    Git was silently failing in these cases, while we can complaint more properly about it.

    In 2008, Marek was implementing git push in JGit, and proposed that patch mentioned above, adding:

    I forgot about this one, it was reported long time ago.

    It seems that it may be really unclear what's going on with git failing on $ git push --tags --all and similar, as it is implementation related perhaps.

    While it is possible to configure a remote with:

    [remote "origin"]
      push = refs/heads/*
      push = refs/tags/*
    

    Jeff King discovered a bug (kind of deadlock) which is probably why this patch exists.

    The sender does a "tellme-more" and then waits for a line back.
    The receiver gets the tellme-more, but never says anything else, presumably because he doesn't have that commit (because master is ahead of any tags).

    In short, pushing branches and tags separately seems easier to support than pushing them together.

    See more with "Push git commits & tags simultaneously", with git push --follow-tags, or git config --global push.followTags true.