Yíu Yíu - 1 month ago 11
Git Question

Is it possible to change a file from a tagged commit?

I am doing an assignment for a course and there is an automated test system. It will test files in my Git repository which have a certain tag. For example, I make a commit with the files:

main.cpp
header1.h
header2.h
source1.cpp
source2.cpp


and I tag them with the tag
A1
.

Now as far as I know tags are bound to commits and not to the files and if I add a tag it goes to the last commit I made. So if I fail an automated test case and I want to change something in a file, I have to delete all files and the tag and then readd and recommit them and delete the old tag and make a new one. This takes quite some time given there are a lot of different test cases. I was wondering if there was a way that I can change a file in my last commit so that I don't have to delete all files and reupload them.

Like if I made the commit above and see that I failed a testcase, I would delete all files, and delete the tag and after that recommit all the files again and give them a new tag
A1
so that the test system finds the updated version. So is there an option to change a file under an existing tag?

Answer

In Git, commits are immutable, so they can't be changed. And since a tag points to a commit, the only way to fix this situation is to move the tag.

First of all, no need to delete all the files; just make any changes you need and commit again:

# edit files
git add .
git commit

This will create a new commit on your current branch (likely master).

Next, as described in How can I move a tag on a git branch to a different commit?, move the tag:

git push origin :refs/tags/A1
git tag -f A1
git push origin --tags

You can force-update a tag like this, but tags are designed to never move, unlike branches. Because of this, you may want to ask your teacher/professor if the test system can be set up to build a given branch, rather than a tag. Then you could do this instead:

git checkout master
# do work, commit, push
# when ready to test:
git checkout A1 # now a branch
git merge --ff-only master
git push origin A1