I'd like to go back in time and change, for example, a class name. I want that change to be applied from a given commit, without me needing to reset all the tags.
Tag1 Tag2 Tag3
| | |
- A - B - C - D - E
|
HEAD
What I want to get to is:
Tag1 Tag2 Tag3
| | |
- A - B - F - C - D - E
|
HEAD
Git's strongest guarantee is that nobody can do that.
It's simply not possible ("because math", specifically the math behind cryptographic hash functions) to insert commits into or make any other alteration to a history without everybody getting the modified history instantly detecting it.
The closest you can get is
Tag1 Tag2 Tag3
| | |
- A - B - F - C*- D*- E*
|
HEAD
where C*
, D*
, and E*
are new commits that look almost exactly like C
, D
, E
-- same commit message, author, date, what not, except for their hash codes. That means the tags have to get reset. git does not go out of its way to make rewrites at this scale easy.
The answer @Joe linked will show you how to move any orphaned tags after filter-branch is done rewriting history, assuming you go that route.
But I'd suggest you consider a different solution to your problem.
As I understand it, you want people to be able to find the current version of e.g. "Ch01_Ex04" easily, but those can change as the writing proceeds. Perfectly reasonable stuff. Thing is, tags aren't the right solution for that. They exist to identify a specific, fixed, historical content distribution.
What you want, identifying the current commit of content playing a particular role, might be best achieved by putting the status directly in the commit message itself and rather than referring to a commit by its tag name, instead identify it by that content: e.g. git show
':/^===Ch01_Ex04==='
will show the most recent commit on the current branch whose message starts ===Ch01_Ex04===
.