0

If I run git replace --graft SHA on a simple test repo, it seems to correctly truncate the repo (with respect to the provided SHA) when viewed via git log.

However on a more complicated repo when I try the same thing, it instead seems to 'replace' the original commit with another - and it keeps all the previous commits surprisingly. The only difference seems to be that the commit has a gpg signature:

git replace --graft af3b4b8a5f98db343b7fc05789aa9656e786d080
warning: the original commit 'af3b4b8a5f98db343b7fc05789aa9656e786d080' has a gpg signature
warning: the signature will be removed in the replacement commit!

Why is this happening? And how can I correctly make it truncate the commit log?

Surprisingly it correctly seems to show that the commit has no parent (if I try reference af3b4b8a5f98db343b7fc05789aa9656e786d080~1) yet git log still shows commits before it.

git log af3b4b8a5f98db343b7fc05789aa9656e786d080~1
fatal: ambiguous argument 'af3b4b8a5f98db343b7fc05789aa9656e786d080~1': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

The repo in question is https://github.com/eugenp/tutorials and the commit I'm grafting is af3b4b8a5f98db343b7fc05789aa9656e786d080.

So I'm basically doing:

git clone https://github.com/eugenp/tutorials
cd tutorials
git replace --graft af3b4b8a5f98db343b7fc05789aa9656e786d080
git log | tail -n 10 # this shows commits before af3b4b8a5f98db343b7fc05789aa9656e786d080 hence it's not truncating
4
  • There's probably other ancestry paths to those other commits, paths you didn't truncate. git log --graph --decorate --oneline. Commented Nov 6, 2023 at 23:44
  • I'm not sure I understand? Why would they show up in git log though - if I'm on the master branch - git log should only show commits in the master branch? I see the same result if I do git log master. I'm not sure what significance the graph log would show? Commented Nov 6, 2023 at 23:59
  • Git doesn't work that way. Ancestry matters. Branch names do not. I wrote this reddit reply to help someone whose confusion yours reminds me of, maybe it'll help here. Do the command I suggested, then try it again with --first-parent, then try them both it again with git --no-replace-objects instead of just git. The commit whose ancestry you're (locally) rewiring was merged in from a side branch. Only its unmerged ancestry is no longer reachable from the master tip. Commented Nov 7, 2023 at 0:15
  • I'm still not sure what significance the git log would show me even running it with --first-parent or --no-replace-objects. I don't understand what you mean by the commit ancestry being from a side branch either. Reading your reddit reply is only slightly helping me understand the underlying git structure of what I'm trying to achieve. This graft commit could surely have references to the appropriate blobs/trees without previous commits being referenced as well. Commented Nov 7, 2023 at 13:09

1 Answer 1

1

git log af3b4b8a5f98db343b7fc05789aa9656e786d080 shows only a single commit. Your repository has multiple root commits after replacing with the graft commit; this happens if you do not graft/truncate all sides of a merge.

The following graphs should help explaining this behavior.

Original history:

R--A--B--C---M--N--...   (HEAD -> master)
 \          /
  `--D--E--F

D has one parent R, which has 2 children (A and D)

After replacing E with E' (the grafted commit):

R--A--B--C---M--N--...   (HEAD -> master)
            /
        E'-F

As you can see, the "truncated" history now has two root commits (the new E' commit and the original R root commit). The old root commit is still reachable via the parent of the merge commit M.

Running git log (which is identical to running git log HEAD) will show commits R, A..C, M, and E' (the grafted commit) and F.

R is still reachable through one of its children that haven't been replaced with a graft.

Everything is working as expected. If you want to fully truncate your history, you have to replace a non-merged commit or graft both sides of the merge (or all sides of the merge in case of octopus merges).

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks this has been really helpful to understand what the actual issue is. According to the graph log there are like 20 other branches that merge in later so it's likely not very feasible to graft all the branches (as it'll talk a lot of time and probably quite error prone to do by hand manually).
@ChrisStryczynski if you want to truncate your history, you have to truncate all possible paths through your history.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.