Question

I'm writing an example application for a book.

Every important commit is tagged (e.g. Ch01_Ex04, Ch03_Ex01) so that readers can get straight to the state of the application that they're interested in.

Every now and then I change my mind about something I did in the exxample and 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.

Say I have:

 Tag1    Tag2    Tag3
  |       |       |
- A - B - C - D - E
                  |
                 HEAD

Now I want to make a change between B and C, so I branch from B and make the change, and I have:

 Tag1    Tag2    Tag3
  |       |       |
- A - B - C - D - E
       \          |
        F        HEAD

What I want to get to is:

 Tag1        Tag2    Tag3
  |           |       |
- A - B - F - C - D - E
                      |
                     HEAD

I can't get my head around how to do this. Is there a way?

Was it helpful?

Solution

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===.

OTHER TIPS

To modify a commit that is farther back in your history, you must move to more complex tools. Git doesn’t have a modify-history tool, but you can use the rebase tool to rebase a series of commits onto the HEAD they were originally based on instead of moving them to another one. With the interactive rebase tool, you can then stop after each commit you want to modify and change the message, add files, or do whatever you wish. You can run rebase interactively by adding the -i option to git rebase. You must indicate how far back you want to rewrite commits by telling the command which commit to rebase onto.

For example, if you want to change the last three commit messages, or any of the commit messages in that group, you supply as an argument to git rebase -i the parent of the last commit you want to edit, which is HEAD~2^ or HEAD~3. It may be easier to remember the ~3 because you’re trying to edit the last three commits; but keep in mind that you’re actually designating four commits ago, the parent of the last commit you want to edit:

$ git rebase -i HEAD~3

Source git documentation for rewriting history

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top