How to checkout an old commit and make it a new commit

I wanted to “follow-up” with another question about this matter:
Checkout old commit and make it a new commit

But they say “Don’t Do That!” so it seems I must ask a new question. (Even though it is the same question where the answer I think is best for me didn’t work as expected…

  • Sharing rerere cache
  • Git: “Not currently on any branch.” Is there an easy way to get back on a branch, while keeping the changes?
  • Trying to setup git-http-backend on apache 2.4
  • Checkout an older commit and create a new master branch?
  • Why git difftool does not open vimdiff in case of conflicts?
  • git clone vs git pull
  • If I have commits
    A-B-C-D-E-F (imagine these are all SHA’s).
    I want to make the entire repository exactly as C and then commit that to create 'G' which is exactly like C. So that when I am done the log is A-B-C-D-E-F-G even though C & G are identical.

    One answer indicated cherry-pick, which seemed perfect, except it made me resolve every conflict between C and F. I looked at the documentation and I tried --force anyway, and then the recommendation for --patch. --patch was closest but it wasn’t absolute. So is there a way to make cherry-pick just choose the C version of the conflict?

    The other closest answer would be to checkout C, but I couldn’t find the magic word that would keep it on the same branch. The recent training I completed said use the “magic dash dash” at the end to tell git you want this on the current branch, but no matter what I do it creates a “(no branch)” branch.

    As I am sure you can tell, I am pretty new to git (and command line in general) but I tried to figure it out on my own. If you could use the verbose versions of what you recommend then it sticks in my head better and would be greatly appreciated. (-a = --all or -a = --annotate or -a = --albuquerque?)

    It seems so simple, and exactly what you might want to do with git — go back a previous commit without losing the intermediary commits in case you change your mind.

  • Is it possible to LS for files on a remote branch?
  • How do I fix GIT non-fast-forward updates?
  • Why is my git file history lost after performing a move refactor in eclipse?
  • Android Studio Backup Source to Repository
  • Can't pull from one bare git repo to another
  • New commits to github aren't getting accepted.
  • 7 Solutions collect form web for “How to checkout an old commit and make it a new commit”

    Do you mind generating: A-B-C-D-E-F-F'-E'-D' where the state of the code at D' is exactly as it was at C (so G == D')? In that case, just revert F, E, and D. If you do not want the intermediate steps, revert but do not apply, and then commit. That is:

    $ git revert -n HEAD
    $ git revert -n HEAD~
    $ git revert -n HEAD~2
    $ git commit -m 'Revert D,E,and F'
    

    After this, the current HEAD is G, and the two commits G and C should contain the same code tree. You can verify by checking the output of git cat-file -p HEAD | grep ^tree and git cat-file -p C | grep ^tree. Both of those commands should give the same output.

    But it’s not really clear why you want to keep the intermediate commits. If you want them for posterity, then do something like: git branch old-stuff, git reset C That will set your current branch back to C, but D, E, and F can still be viewed in the branch named old-stuff.

    git cherry-pick --strategy=recursive -X ours C
    

    git-merge(1):

    The recursive strategy can take the following options:

    ours

    This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. […]

    The “ours” and “theirs” refer to the two commits being merged. However, I’m not sure which way around git cherry-pick treats the commits, so you might need -X theirs instead. You could make a new branch, to try it and see.

    If you want to end up with:
    -G-D-E-F
    (not sure, I’m confused by “Where D, E and F are right there.”)
    Then the best way to get there is rebase -i, and squash A-B-C together.

    Could you describe what you want as: “make your working tree the same as C, then commit that”? If so, here’s a way to do that:

    git checkout C     # working tree same as C. But also moves HEAD to C...
    git reset F        # ...so move HEAD back to F, leaving working tree alone
    git commit -a      # commit working tree
    

    EDIT this might produce a bunch of merge conflicts, so it doesn’t address that part of your question.

    EDIT3 Again, the selected answer to your previous question solves this: by deleting everything first, there is no conflict.


    BTW: it would be nice to make the working tree equal to commit C without changing HEAD, but I don’t think there’s a (porcelain) to do that. Both git checkout and git reset change the current branch if you want the whole commit. git checkout can extract individual files to the working tree without moving the current branch, but then you have to extract each file individually, not the whole commit…

    EDIT2 oh I see from the selected answer to your previous question, you can do this. I had tried git checkout C -- "*", but you need git checkout C -- . So it would just be:

    git checkout C -- .    # working tree same as C, without moving branch (NB ".")
    git commit -a
    

    Judging from your comment to my other answer (which I am not deleting, since that solution is more correct than this, but this seems to be what you want), you can just use the plumbing command commit-tree as follows:

    git reset $( git commit-tree $tree -p F -m 'Revert D,E, and F' )
    

    where $tree is the hash of the tree object underlying commit C. (The output of git cat-file -p C | grep ^tree ). This will create a new commit in which the underlying tree is identical to that of commit C, but the parent of the new commit is commit F. It also sets the current branch to point to that new commit, making it the new HEAD.

    Looks like you want C to be the final state of your git repository.

    Take “A-B-C-D-E-F-G” as an example,

    You can just revert G,F,E,D in order using

    git revert [commitID]

    Then use
    git commit

    After G,F,E,D are all reverted, your repository will be staying in the state same as C.

    An alternative way for local branch only is:

    git resert --hard HEAD~4

    This will reset your local branch to commit C and drop D,E,F,G.

    Git Baby is a git and github fan, let's start git clone.