Suppose I have a linear git
history
A-B-C-...-X (HEAD)
↑
master
Now I noticed, that I deleted some lines in C
that were present in B
and that I want to restore. It is possible to just copy everything manually or apply a patch. But I want the tree to look something like
-------
/ \
A-B-C-...-X-Y (HEAD)
↑
master
to make the changes more apparent. I tried to merge using
git checkout master
git merge --no-commit --no-ff B
but git
only tells me that everything is "already up to date".
There's no user-oriented command to do what you'd like. You can do exactly that, somewhat manually. For instance:
git diff <hash-of-A> <hash-of-B> | git apply
# make sure it looks right
git add <files> # as desired
tree=$(git write-tree)
vim /tmp/message # or other editor of choice
commit=$(git commit-tree -p HEAD -p <hash-of-B> -F /tmp/message $tree)
git log --graph --decorate --oneline $commit # make sure you like it
git merge --ff-only $commit
# then clean up etc
You can shrink this down to just a few commands using nested $(...)
sequences.
Most people, however, just prefer to use git cherry-pick
, perhaps with -x
. Note that git cherry-pick -n
lets you do the equivalent of the diff-and-apply sequence and may make the above more convenient: I chose the diff-and-apply sequence more for illustration.
The git write-tree; git commit-tree; git merge --ff-only
sequence is roughly how git commit
itself actually works, except that git commit
is much fancier, and doesn't let you specify the individual parents.
Another approach is to use git checkout <hash-of-A>; git cherry-pick <hash-of-B>
to make a new commit B'
, then use git merge
to merge this new B'
commit. (Save its hash for your git merge
, or do this on a temporary branch that you delete after the merge, so that you don't need to fuss with raw hash IDs.) The result looks like this instead of what you've drawn:
------B'------
/ \
A--B--C--...--X--Y <-- master (HEAD)
This may be clearer to some future viewer than the weird manually-constructed merge.