Reputation: 5036
When fetching a single branch, git fetch
includes any tags that point into the branch:
When refspec stores the fetched result in remote-tracking branches, the tags that point at these branches are automatically followed. This is done by first fetching from the remote using the given s, and if the repository has objects that are pointed by remote tags that it does not yet have, then fetch those missing tags. If the other end has tags that point at branches you are not interested in, you will not get them.
Is there any way to make git push
behave the same way? The man page says how to push no tags (the default), all tags (--tags
), or ones you name on the command line. It doesn't give a way to push all the ones pointing into the branch.
Upvotes: 53
Views: 31221
Reputation: 1327064
You can try, with git1.8.3+ (May 2013):
git push --follow-tags
The new "
--follow-tags
" option tells "git push
" to push relevant annotated tags when pushing branches out.
This won't push all the tags, but only the ones accessible from the branch(es) HEAD(s) you are pushing.
As mentioned in "Push a tag to a remote repository using Git?", this concerns only annotated tags, not lightweight tags.
git tag 1.0
(lightweight) would not be pushed with --follow-tags
, it would with git push --tags
.
With Git 2.4.1+ (Q2 2015), that option can be set as default.
See commit a8bc269 by Dave Olszewski (cxreg
):
make it easier to add new configuration bits and then add
push.followTags
configuration that turns--follow-tags
option on by default.
The documentation will include:
push.followTags::
If set to true enable '
--follow-tags
' option by default. You may override this configuration at time of push by specifying '--no-follow-tags
'
Do enable this setting globally, you can run git config --global push.followTags true
. It can also be specified on a per repository-basis.
I need a solution that can also push lightweight tags.
These limitations between lightweight and annotated tags are so annoying in Git.
Pushing lightweight tags alongside annotated tags is a more complex scenario: Lightweight tags are simpler pointers to specific commits, without the additional metadata or checksum verification provided by annotated tags. Git's built-in options for pushing tags (--tags
and --follow-tags
) differentiate between these types, with --follow-tags
designed specifically to push only annotated tags that are reachable from the branches being pushed.
If you need to push both lightweight and annotated tags that are relevant to the branches being pushed, a custom approach is necessary.
First, identify the commits that are part of the branch you are about to push. That can be done using git log
or git rev-list
.
With the list of commits in hand, you can identify both annotated and lightweight tags that point to these commits. That requires filtering the tags based on whether their referenced commit SHA is in the list of branch commits. Once you have identified all relevant tags, you can push the branch and these tags in a single or consecutive Git commands.
For instance, assuming that you are pushing the current branch and identifies tags pointing to any commit in this branch:
# Get the current branch name
current_branch=$(git rev-parse --abbrev-ref HEAD)
# Get all commits on this branch
commits=$(git rev-list $current_branch)
# Initialize an empty string to hold tags to push
tags_to_push=""
# Loop through all tags
for tag in $(git tag); do
# Check if the tag points to a commit on this branch
if echo "$commits" | grep -q $(git rev-parse $tag); then
# If so, add the tag to the list of tags to push
tags_to_push="$tags_to_push $tag"
fi
done
# Push the current branch
git push origin $current_branch
# Push all identified tags
if [ -n "$tags_to_push" ]; then
git push origin $tags_to_push
fi
Or you could use that script to push only lightweight tags, since annotated tags are easy to push with normal git
commands:
# Loop through all tags, filtering for those pointing directly to commits (lightweight tags)
for tag in $(git for-each-ref --format '%(refname:short) %(objecttype)' refs/tags | grep ' commit$' | cut -d " " -f1); do
# Check if the tag points to a commit on this branch
if echo "$commits" | grep -q $(git rev-parse $tag); then
# If so, add the tag to the list of tags to push
tags_to_push="$tags_to_push $tag"
fi
done
Upvotes: 93