Reputation: 633
If I have a local git repo with unstaged changes in branch1, then do the following:
git reset --hard
from branch2How can I do this without losing changes in branch1? Do I have to run git stash
from within branch1 or branch2 or commit those files first? Or can I still recover my uncommitted changes from before using git?
Upvotes: 0
Views: 53
Reputation: 488243
The fundamental error you're making here is thinking that "changes" (staged or unstaged) are "in a branch". They're not! This is true no matter which meaning we use, of the many meanings of the word branch that Git has. In fact, in a very important sense, as tkausl commented, the work you're doing, as you're doing work, isn't really in the repository at all.
Too many Git introductory tutorials begin by implying, or maybe even outright claiming, that Git is about files and branches. It isn't: it's really all about commits. The commits are what go in the repository, or most of what goes in. Once something is committed, it's safely preserved forever—well, almost forever and almost safe (you can always completely destroy the repository entirely for instance). So we should focus first on the commits.
Unfortunately, commits themselves seem all abstract and vague. If you ask Git to show you a commit—using, e.g., git show
—you get this sort of output:
$ git show
commit e4a4b31577c7419497ac30cebe30d755b97752c5 (tag: v2.37.0, ...)
Author: Junio C Hamano <[email protected]>
Date: Mon Jun 27 09:17:55 2022 -0700
Git 2.37
Signed-off-by: Junio C Hamano <[email protected]>
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 120af376c1..b210b306b7 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.37.0-rc2
+DEF_VER=v2.37.0
LF='
'
Is that a commit? Well, it's a representation of a commit, just as the image below is a representation of a woman. It's not actually the woman, it's a painting. But it's not actually a painting either: it's a JPG of a painting. Note how we may have to go around and around before we can even agree on what something really is. That's one of the problems we have, defining what a commit is.
Still, once we've used Git for a bit, we have at least a pretty good vague idea of what a commit is: it's a numbered (by hash ID) entity, like commit e4a4b31577c7419497ac30cebe30d755b97752c5
above. We can use Git for a long time without knowing much more than this, but we shouldn't.
There is, unfortunately, a lot that we need to know, at least eventually. Git is tricky! There's a lot to learn about it. But there's a bare minimum to know so that you won't get into trouble, and it goes like this:
A repository stores commits. That's not necessarily all it stores, but that's the main thing.
A commit is a numbered (by hash ID) thingy that stores files and metadata.
Each commit stores a full snapshot of every file, plus that metadata. The snapshot is just that—a snapshot—and the metadata remembers "stuff about this commit itself", such as the name and email address of the person who made it.
All parts of every commit are frozen for all time. Nothing in a commit can ever be changed! If a commit is terrible, we can stop using it, by making a new and improved version that we use instead. But that won't make the old commit stop existing. Then again, as in the old riddle, if a tree falls in the forest and there's no one around to hear it, does it make a "noise" (where "noise" means "offends all the people who heard it")? If you can't find a commit, does it matter if it exists?
Git finds commits by those big ugly hash IDs. Humans are bad at those, so Git gives us things like branch names too. The names we use—branch names, tag names, and all other kinds of names—store the hash IDs for us. Each name actually stores just one hash ID, but that's good enough.
Because commit snapshots are all frozen (the files in the commits are magically de-duplicated too—that becomes important soon, but you don't have to know it right away), you literally can't work on the committed files. So you don't. The act of checking out a commit, with git checkout
or git switch
, tells Git to extract the saved files. These become ordinary files that you can use and work on / with.
These ordinary files are not in the repository! (Well, to some extent this depends on exactly how we define repository, but to keep this list short, let's not get into this.) They are, instead, in your working tree or work-tree.
Last, Git makes new commits from a thing it calls by several names: the index, or the staging area, or—rarely these days—the cache. The existence of this thing is why Git makes you run git add
so much, and it explains a whole lot of other Git weirdness.
When you're just getting started, you can remain kind of fuzzy on this index / staging-area thing. Just remember that it exists and it's important—it holds your proposed next commit—and get around to learning more about it soon.
Once you really know these eight minimum things, you can get some work done in Git. You can refer back to its manual pages and some of them might even start to make a little bit of sense. 😀
The git reset
command is, unfortunately, a very large and complicated command that does a lot of things. But you'll see that—as SebDieBin answered—--hard
erases working tree files, replacing them with files that come out of some commit. Since you've memorized the above points by now—well, maybe you have—you will know that the working tree files aren't actually in the repository. They may have come out of some commit, but if you've changed them since then, the updated files are only there in the working tree. Erasing those files—removing them and replacing them with committed versions instead—therefore erases your changes, and since those changes were never in Git, Git can't help you get them back.
You can take this to mean git reset --hard
is scary, be careful with it, which is good advice. But this doesn't really go far enough: there are a lot of other Git operations that can remove, forever, Git's ability to help you get back unsaved changes. What you really need to know is what makes you safer. Once you've committed something—made a full snapshot of every file from Git's index or staging-area—the committed files are safely stored for as long as you can find that commit's hash ID. Well, and, as long as your laptop doesn't catch fire, for instance.
Upvotes: 0
Reputation: 3469
You can either leave out --hard
when running git reset
because that is what reverts your unstaged changes. If that is not feasable for some reason you have to use git stash
.
Upvotes: 1