git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: How to recover a lost commit...

From
Jonathan Nieder <jrnieder@gmail.com>
Date
Nov 11, 2010, 17:58 UTC
Message-ID
<20101111175836.GD16972@burratino>
In-Reply-To
<AANLkTikqBXjAf44O0QERH39rK+7nNA8uD2CwtPKJTTyV@mail.gmail.com>
Patrick Doyle wrote:
Show 6 quoted lines
> Thank you for your reply and cogent explanation.  Yes, in fact, I did
> do a "git reset HEAD^".  Somewhere along the way, I decided that was a
> way to make my working copy look like it did prior to a commit.
> 
> I thought that git reset only affected HEAD.  I didn't realize that it
> also affected the branch pointer.

Right. In general, git operations that update HEAD also tend to take the current branch along with them. So:

	# update the current branch to include a new commit
	git commit
	# update the current branch to include a change from another branch
	git cherry-pick --ff $rev
	# update the current branch to incorporate the history of another branch
	git merge $rev
	# reset the current branch head to match _that_ commit
	git reset --keep $rev
	# only reset the current branch head; index and worktree will be untouched
	git reset --soft $rev

If you want to use such an operation without updating a certain branch, then switch to a different branch.

	# switch branches: we are following 'topic' now
	git checkout topic
	# detach from all branches: we are building unanchored history now
	git checkout HEAD^0
See the section DETACHED HEAD from the "git checkout" manual for details.
> Your "great power, great responsibility" comment will make me treat
> "git reset" with a lot more fear and respect.

Once you're used to it, it is not so scary. If you pass paths to "git reset", it will not change HEAD; instead, it changes the content registered in the index:

	git reset some-crazy-old-commit -- foo.c bar.c baz.c
	git diff --cached

If you do not pass paths, it will update HEAD to point to the specified commit.

	# the last commit was bad; discard it
	git reset --keep HEAD^
	# I'm totally lost.  Let's just start over, based on the version
	# that worked from yesterday.
	git reset --hard @{yesterday}
	# specialized operation: the tracked content of all files should
	# be used as a single commit on top of some other revision
	git reset --soft $new_parent
	git commit
	# less strange way to do about the same thing
	git reset $new_parent
	git diff;	# looks good?
	git add -u
	git commit

If you do not pass paths and do not pass a revision arg, this means you wanted to update HEAD to point to the commit it is already at. In other words, with --soft or --keep this is basically a noop, with --hard it discards any changes in working-tree files you haven't committed, with no operation mode arg it makes the index match the HEAD commit.

> $ git merge --no-commit
> $ git reset
> 
> Why is that "git reset" benign, when the "git reset HEAD^" wasn't benign before?
There should be a revision argument after "git merge --no-commit".

This "git reset" is equivalent to "git reset HEAD": it resets the index to match the current commit, so the changes applied by the merge appear as local changes.

Regards, Jonathan

Previous: Patrick DoyleNext: Patrick Doyle
Message 4 of 8 in “How to recover a lost commit...”
  1. Patrick DoyleNov 11, 2010
  2. Seth RobertsonNov 11, 2010
  3. Patrick DoyleNov 11, 2010
  4. Jonathan NiederNov 11, 2010
  5. Patrick DoyleNov 11, 2010
  6. Junio C HamanoNov 11, 2010
  7. Jonathan NiederNov 11, 2010
  8. Patrick DoyleNov 11, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.