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.