What happens to tags of squashed commits?
Asked Answered
P

3

29

If I have commit A tagged with tag e.g. tag-A, and then the next commit B tagged with tag-B; if I squash these 2 commits what happens to the tags? Will both be assigned to the squashed commit?

Prelusive answered 20/1, 2019 at 21:54 Comment(0)
L
22

The tags won't move because a rebase rewrites history. The original commits will have the tags since tags don't move. Here's a picture:

Before:

(HEAD) B - tag-B
       |
       A - tag-A
       |
       X

After:

         B - tag-B
         |
(HEAD) C A - tag-A
       |/
       X

Here C is the squash of A and B. It starts a completely new history, in which A and B will not participate. The branch head will move over to C and will proceed from there.

Lydgate answered 20/1, 2019 at 22:13 Comment(6)
Ah so commits A and B remain as an “anonymous” branch out?Prelusive
@Jim. Basically. Commits are immutable. Once you make a commit the only thing you can do is delete it. Tags are static labels. They don't move and associate a name and possibly some metadata with a commit. Branches are similar, but they move when they're checked out and you commit. So the branch label moves during a rebase, but tags and prior history do not. You can manually move tags somewhere into the new history, but it's entirely up to you to decide how to do that in a meaningful manner.Lydgate
What is the best practices for migrating tags? We have go projects that frequently squash branch commits. Go modules uses tags to pull in specific package version (even if they are off the main branch). My fear is during removal of old branches any tags will be orphaned (as their commits disappear) and break subsequent builds.Knick
@colm.anseo. I have no idea what the best practice is. Whatever is sensible should work. Git commits are immutabe and don't magically disappear. I'm pretty sure that if you have a tag on the graph, that part is safe. I don't think tags can magically age away.Lydgate
If I have the following: master build which refers to a tag T on branch B; merge branch B; (build will still work as tag T is still valid); delete branch B (since it's been merged with master); Tag T will now be orphaned (as commit is gone)? Future builds will now fail. I'm going create a test go project to confirm if my final assumption is correct.Knick
@colm.anseo. The commit is not gone. Deleting a branch is like deleting a variable in python: you just deleted one of the possible names for an object. The commit itself is very much still there.Lydgate
P
7

Will both be assigned to the squashed commit?

No.

Each tag points to a specific commit, and it never moves away from that commit on its own. The commits that each tag was pointing to is still alive, just not in any of your branches.

Squashing two commits creates a separate new commit, only with the contents of the original commits. This new commit will not have any tag pointing to it.


You can manually move those two tags to point to your new commit:

git tag -f tag-A
git tag -f tag-B
Pentheam answered 20/1, 2019 at 22:13 Comment(0)
B
3

I think Mad Physicist's answer is great, but my curiosity made me want to reproduce this myself to look at the history. Here's an example that you can recreate locally to poke around the history.

First we need to create a blank repository:

cd ~
mkdir test_repo
cd test_repo
git init
touch file.txt
git add .
git commit -m "Create initial file"

Then we need to create a branch with multiple commits that will be squashed:

git checkout -b new_feature
echo "A" > file.txt
git add .
git commit -m "Added A"
git tag tag-A

echo "B" > file.txt
git add .
git commit -m "Added B"
git tag tag-B

This leaves me with the following history:

$ git log

commit 203a767647c3ebfc85b983dd573419013388b5aa (HEAD -> new_feature, tag: tag-B)
Author: Joshua Correia
Date:   Thu Jun 16 12:06:20 2022 -0700

    Added B

commit f16a24ae7b43110c98ee9a818db2a9f2ad5c8f3a (tag: tag-A)
Author: Joshua Correia
Date:   Thu Jun 16 12:06:09 2022 -0700

    Added A

commit a601965cd293c91820af6d9bc9bd9aa8965854a1 (master)
Author: Joshua Correia
Date:   Thu Jun 16 12:05:57 2022 -0700

    Create initial file

Now we can squash the commits and analyze what happens:

git rebase -i a601965cd293c91820af6d9bc9bd9aa8965854a1

Change "pick" to "squash" on the second line containing the commit "Added B" then save the file.

When we look at the history again, we see that the tags no longer exist in this branch's history. This is because tags are associated with individual commits, and these commits have been replaced by our rebase. Notice how the hash of HEAD has now changed since a new commit has been created to replace the two previous commits:

$ git log

commit 414d3cf4a12a3df293047de5271080d030cce119 (HEAD -> new_feature)
Author: Joshua Correia
Date:   Thu Jun 16 12:06:09 2022 -0700

    Added A

    Added B

commit a601965cd293c91820af6d9bc9bd9aa8965854a1 (master)
Author: Joshua Correia
Date:   Thu Jun 16 12:05:57 2022 -0700

    Create initial file

These commits, however, have not been completely removed. If you run git tag you can see that tag-A and tag-B still exist. You can git checkout tag-B and see the history that existed when that tag was originally created, but this will put you in a detached HEAD state.

Buster answered 16/6, 2022 at 19:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.