Is there a risk to using git commit-tree

Viewed 187

If I have a commit history (that was cloned from a remote repository for example) that looks like the following:

A ---> B ---> C ---> D (master)

and I want to create a branch that looks like the following:

A ---> B ---> C ---> D (master)
   \-> N ---> B' ---> C' ---> D' (branch)

That is, insert a commit called 'N' on the branch right after commit A then copy to this branch the commits B, C, and D. Let's say I use the following steps to create the branch 'branch':

create 'branch' -> make commit N -> find the hash of the tree blob of commit B using git cat-file -p <hash of commit B> -> run the command: git commit-tree <hash of tree blob of B> -p <hash of commit N> -> move 'branch' to point to B' -> repeat the last two steps for commits C and D

After adding commit N, is there a risk of using the git commit-tree command as is done above to copy commits B, C, D to the branch? Will I loose any files, changes, etc from B, C, or D from doing so (especially if there were conflicts between B and N for example)? As you can see this is different from using cherry-pick in the sense that cherry-pick checks for conflicts between B and B', C and C', D and D' before cherry-picking while this approach does not check for any conflicts.

1 Answers

It depends on your purpose. Why do you want N in the first place? After you create B', all of the changes introduced by N (the ones between A and N) are just gone, because now the files are exactly the same with those of B. At last, the files of D' are completely the same with D.

If you want there to be a snapshot of N in the history so that you can check it out later, it's okay to do so.

If you want the changes introduced by N to exist on the new branch, you need git cherry-pick or git rebase. If so, the only harmless case I can think of is that the changes between A and N is a subset of the changes between A and B. In other words, you want to split B's changes into N and B'. As @torek pointed out in the comments, the changes are not really gone, they just have no effect on the subsequent commit snapshots, as if the changes have been reverted in B'.

In practice, I've used git commit-tree in 2 cases. We had a messed-up branch whose history was long. It was quite hard to make it clean by git revert or git rebase, so we decided to reset the branch to a previous good commit. But we are not allowed to delete&recreate or force-push any existing branches. So we used git commit-tree -p HEAD -m xxx ${good_commit}^{tree} to reset the code to the status of the good commit, while we kept the whole messed-up history.

The other case is we once wanted branch foo to have the same code with branch bar. foo and bar had been diverged and developed since quite long ago. So we used git commit-tree -p foo -m xxx bar^{tree} to reset the code while keeping the history.

Related