On Mon, Jul 18, 2022 at 07:51:48AM -0700, Maiasa Liger wrote:

> A tale born through some hot tears at work...
> 
> I had made a *temporary commit* on feature branch *A*, that I wanted to put 
> directly in the *master *(main) branch, as it was not related to the 
> feature.
> 
> However, I had a lot of unstaged changes (read: 10+ hours of work) that I 
> didn't want to stash and cause Eclipse to refresh & rebuild.
> 
> So my "incredibly smart" idea was to cherry pick that commit onto the 
> master, then *git reset --hard HEAD^* to remove the unrelated commit from 
> the feature branch. I foolishly thought that this would only remove the 
> commit and leave any local changes alone.

I think it could help if you'll try to visualize a string of commits which a
branch is: the `git reset` command can only move the tip of the branch which
is a pointer to the currently-last commit on that branch.
I mean, with this in mind, it should be clear that it's impossible to first
cherry-pick a commit - hence adding a new commit and moving the branch
forward - and then removing a single commit which is now the second - if
counted from the tip backwards. It cannot work that way; you can "revert"
a past commit by recording a new one using the `git revert` command, but this
only undoes the changes in a new commit, not removes an existing one.
IOW, you cannot remove a commit from a middle of a branch using `git reset`
as this command only manipulates the branch pointer.

[...]

> In other terms: if you run git reset --hard, any modification that was not 
> staged, stashed or committed will be IRREVERSIBLY lost. Maybe some of you 
> will now think "yeah, duh".
> Well, I did not know that.
> 
> I personally would have really wished that git had informed me of this, 
> e.g. by prompting me to confirm with a notice of the effect.
> 
> Perhaps it would be expected of me to be 100% aware of what git reset 
> --hard does, and this is simply a case of "learning it the hard way".
> I genuinely do not know.
> 
> Before submitting this as a feature idea, I was moved to post my dilemma 
> here first to see if it would find any support.

Well, it's sad you have faced this situation but unfortunately making Git ask
questions will not work either: multiple studies showed that human beings
quickly learn to mindlessly press "y" / click the "yes" button / do whatever
else _recurring_ action.

Basically, to my knowledge, there are only two working solutions to this
(except for implementing a way to not deal with the original problem in the
first place, which is almost always cannot be implemented in real-world cases):
implementing a way to do easy "full undo" for any user's action and forcing
the user to stop and think. You could see the former in programs like word
processors (it usually sucks in one way or another, but still) and the latter,
say, in Android dialog allowing a program to install software - the "OK, I
understand the consequences" button is disabled for a long enough time period
ca. 10 seconds, requiring you to pause read the dialog's text.

The second solution is sort of okay but only if the action leading to it being
used is very infrequent because a forced pause sucks big time when you _know_
what you're doing.

The second solution is next to ideal but it has practical problems: note that
you can have literally any files in the Git's work tree - with the program's
build artefacts being the most obvious examples, - and this does not plays
nicely with the idea of "let's save everything in the work tree when the user
calls `git reset --hard`". For instance, there may be stored files of
insane size, which are never intended to be "saved" somewhere. Also there's
the question of what to do when you want to restore the autosaved state but
the work tree has conflicting changes - this basically is a case of creating
another "autosave".

Another solution which seems logical at the first glance is using the "trash
bin" feature is the OS provides it but it also has practical problems: it is
never the core feature provided by the kernel, and Git is not always used by
human beings through graphical user interfaces, and also Git uses lots of
files not intended to be dealt with by the user anyway (though admittedly in
your particular case moving the files to the trash can could help).


All-in-all, to me, looks like the best approach for the user is to always err
on the safe side which is _always commit everything_ and verify afterwards
that there is no uncommitted changes (using `git status`). It's far easier to
massage the history afterwards by removing unneeded bits or picking the
necessary bits into a clean series of commits. Committing makes Git remember
the committed stuff, and losing _that_ is very hard in a normal repository as
all the commits are recorded in the so-called "reflog" which normally has a
long expiration time. Committing is very cheap, and Git provides tools for
rewriting unpushed ("private") history (you've been bitten in the neck by one
of these tools, alas).


By the way, there was recently a similar discussion in the main Git list.
For instance, see [1].

 1. http://public-inbox.org/git/ysyytoipiu29omn...@tapette.crustytoothpaste.net/

-- 
You received this message because you are subscribed to the Google Groups "Git 
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to git-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/git-users/20220718161627.5elf5szaznyi7mhy%40carbon.

Reply via email to