Search code examples
gitbranchgit-branchrebase

Git copy commit without checkout or rebase?


I am currently on commit 123456 and branch foo. I'd like to add a new commit to branch bar with the exact contents of 123456 (not rebased, just created from the same snapshot, so the diff will be whatever it will be).

I can accomplish this like so:

$ git checkout bar
$ git reset foo
$ git commit -am '...'
$ git checkout foo

I have two questions:

  • Is there a way of doing this without needing to leave foo or needing to change my working tree?
  • Is there a clean way that I can copy the commit message from 123456? (I can obviously do it manually, but automatically via native git commands would be nice)

Solution

  • It's easy to do

    git checkout bar
    git restore --worktree --staged --source=foo -- .
    git commit -m "Here we make it just like 1234546 (or foo back when I created this commit)"
    

    You can use git commit -C 123456 to use that commit's information for the new commit but it would be misleading because you are creating a single commit and you are disregarding all history in foo..bar.... does it make sense to do that in a single commit? Well, perhaps it does for your use case but I wouldn't assume it will work for everybody.

    And sure, it can be done without changing your working tree.... by using a superduper second working tree. So, check git help worktree.

    Now that I think about it, there is yet another way to do it without having to move a single bit from your working tree and without needing a second working tree, but it's hackish:

    # we are on foo, right?
    git branch temp $( git commit-tree -p bar -m "Here we make it just like 1234546 (or foo back when I created this commit)" 123456^{tree}" )
    # commit-tree is a command not intended for the faint-of-heart. It
    # will create a new commit just like 123456 in contents and that has bar
    # as its parent.... and the outer command will set the branch temp
    # on it.
    # It's a hackish thing so no -C available to copy the info from
    # 123456.
    # if you like it, then move bar to that position
    git branch -f bar temp
    # and now you can delete temp
    git branch -D temp