Re: How to revert to a specific commit?
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Dec 3, 2024, 00:57 UTC
- Message-ID
- <xmqqser5h9c6.fsf@gitster.g>
- In-Reply-To
- <CAPx1Gve_dCRux9_cF7NTspomS4K=Hp_y74d94S-Hm0amuovUqQ@mail.gmail.com>
Chris Torek <chris.torek@gmail.com> writes:
Show 23 quoted lines
> On Mon, Dec 2, 2024 at 4:15 AM tao lv <thebookofunknowable@gmail.com> wrote: >> I want to revert the code to a specific commit. ... > > OK, first some background: > > * A commit _is_ a full snapshot of every file, as of the state > it had at the time you (or whoever) made that particular > commit. Hence, if you want the particular files from a > particular commit, you simply check out that (historical) > commit. > > Now: > >> I don't want to revert each individual commit; I just want to restore >> the code to this specific commit while retaining all the current >> history commits. >> >> How can I achieve this? Is there a better way than using the revert function? > > git checkout [--detach] <hash> # or git switch --detach <hash> > git reset --soft <branch-name> > > git restore --no-overlay -S -W <hash>
While that would _work_ in the sense that you can revert the effect of what the discarded commits did, I would not recommend any of the above since it does not leave any record of what you discarded.
Imagine that I regret doing everything since we tagged, say, v2.47.0 release and want to discard everythig on 'master' newer than that commit. If I want to "keep" the history of failed commits that I regret having made since v2.47.0, here is a way to do it:
$ git checkout master
$ git reset --hard v2.47.0
$ git merge -s ours --no-ff -m 'Discard everything since v2.47.0' master@{1}The first two steps just discard the unwanted commits. The third step is a trick to
- Keep the tree contents of the current commit (i.e. -s ours) as the result,
- Make sure the result is recorded as a merge commit (i.e. --no-ff), not "fast-forward" to the tip of the history I am discarding, and
- Record the discarded history (i.e. master@{1}) as the side branch
of the resulting history.The last part would help if I later need to merge changes that were based on 'master' I am discarding. The presense of the side branch makes sure that only the effects from the new work done on the discarded history, and not from the commits such a new work was based on (which are the commits I regret having made and I am discarding), are taken into account when computing further merges.