Home > database >  Git: Restore uncomitted changes from new branch
Git: Restore uncomitted changes from new branch

Time:07-03

If I have a local git repo with unstaged changes in branch1, then do the following:

  1. Checkout to a new branch: branch2
  2. Commit some (not all) files
  3. Run git reset --hardfrom branch2
  4. Checkout back to branch1

How 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?

CodePudding user response:

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.

CodePudding user response:

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.

Mona Lisa

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.

The absolute minimum you need to know when using Git

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.

  •  Tags:  
  • git
  • Related