Reputation: 57
Ok, so the context is that im working on my own branch, creating a feature for a certain project.
My branch is called Exif (capital E) and today i accidentally did
git push origin exif (lowercase e)
so it created a new branch for me called exif
After I realized this , I did
$ git push origin --delete exif
$ git branch -d exif
effectively deleting the branch again.
I have to add that I executed these 2 lines while I was checked out inside Exif (capital E), But that shouldn't matter right?
Now, when I execute
git status
I get a huge list saying that every file inside the whole project is a new file
When I try
git log
It says , you're current branch doesn't have any commits yet
when I do
git branch -a
all branches are there, except Exif, its also not in the remote branch list
but on our gitlab server it shows the branch just fine like nothing happened.
Does anyone have any idea what happened here?
EDIT:
In eclipse it shows an asterix next to every file, meaning that every file is staged.
In eclipse it also shows next to the root project folder that the project has [NO-HEAD]
Upvotes: 0
Views: 2571
Reputation: 487755
The other answer here is not quite right, although this:
but on our gitlab server it shows the branch just fine like nothing happened.
is promising and hence you may have an easy way to fix things.
I'll show an example where I destroy my own master
branch (in a clone of course). Since this particular system is case-sensitive I just hand-removed the master
branch (behind Git's back, as it were).
This is a bug in Git: it managed to delete the branch you were standing on.
The problem occurs because Git is case-sensitive: the branch exif
is, as far as Git is concerned, entirely separate from the branch Exif
. When you asked Git to delete exif
it, in essence, checked:
exif
? exif
.So Git checked, and it saw that your current branch was Exif
, not exif
. Well, to Git, those are clearly different, it must be safe to delete! Only ... they're not, and it's not. The truth is complicated, but on Windows and MacOS systems, Git either needs some implementation changes—so that branch names really can be case-sensitive, all the time—or Git needs to stop believing that they are case-sensitive because they sometimes (usually, on these systems) aren't.
In the meantime, the tricky part is recovering your branch. This requires a bit of delving into Git internals.
Within Git, there are two key components to the current branch. One is the file .git/HEAD
. This file contains a simple string:
$ cat .git/HEAD
ref: refs/heads/master
$
That is, this file contains (as plain text: not "rich text", not Unicode, not Windows UCS-2 format, just simple ASCII text) the literal string ref: refs/heads/
, with one space before refs/heads/
, followed by the name of the branch, followed by a newline. This file is unharmed!
The other half is more complicated. The good news is most of the complication goes away, because if it hadn't, the branch name would be case sensitive "the rest of the way" and you might (or might not) still be OK. But this:
$ git log
fatal: your current branch 'Exif' does not have any commits yet
proves the branch value was stored only in the file .git/refs/heads/branchname
.
That is, you used to have a file named:
.git/refs/heads/Exif
which had some hash value in it, something like this one (but with a different hash):
$ cat .git/refs/heads/master
3ab228137f980ff72dbdf5064a877d07bec76df9
What we need to do is to put that file back, with that same value.
If you can see the value—or even just part of it—somewhere, e.g., in an existing window, that is sufficient to get the whole value back. For instance, if I have 3ab228
showing somewhere I can do this:
$ git rev-parse 3ab228
3ab228137f980ff72dbdf5064a877d07bec76df9
which lets me do this to fix things:
$ git rev-parse 3ab228 > .git/refs/heads/master
and we're done. (See the last item below about reflogs.)
If you have successfully pushed the branch earlier, you may have the value as a remote-tracking branch:
$ git rev-parse origin/master
3ab228137f980ff72dbdf5064a877d07bec76df9
In this case you can put that back in place:
$ git rev-parse origin/master > .git/refs/heads/master
and you're done. (See the last item below about reflogs.)
In your case it sounds like the remote named origin
has the right hash ID under the name exif
(all lower-case), i.e., for some reason it ignored the git push --delete
command. In this case, you can ask the remote for the value. Note that anyone else might have updated it since then:
$ git ls-remote origin master
454cb6bd52a4de614a3633e4f547af03d5c3b640 refs/heads/master
(clearly my remote has moved on, so I would not be able to use this, but if you're lucky yours has not). Make sure the value is good:
$ git rev-parse 454cb6bd
454cb6bd
fatal: ambiguous argument '454cb6bd': unknown revision or path
not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
(so this doesn't work for me, because they have indeed moved on).
As a last resort, you can run:
$ git fsck --unreachable
which is likely to spit out a whole lot of unreachable
messages:
unreachable commit fcfbe9a1165e38467b4d24d41b3166a20c1dfb80
unreachable commit c8056a11ef8eee1bfaaaa2e32a9cc92a02eae2e0
unreachable blob 010a1a22a90b2bd78e6b87a3922c3324c44a8a9b
unreachable commit c1163ad1eeff0c86f030483907ea8cedcdd431e3
unreachable commit f35fc21adeb21e1a4800ccebd5719317efb968dc
Ignore everything but the "commit"s: one of those is the right one. To find out which one, run git show
on each one, perhaps with something to help shorten them a bit, e.g.:
$ git show --pretty=oneline --no-patch fcfbe9a1165e38467b4d24d41b3166a20c1dfb80
fcfbe9a1165e38467b4d24d41b3166a20c1dfb80 WIP on precious: e59f6c2 The last
minute bits of fixes
(this shows that this particular item was actually a git stash
commit).
When you find the right one, you can put it into .git/refs/heads/Exif
to restore the value, and your repository will be mostly back in shape. The git rev-parse
method works here too, although since you have the full raw hash, you don't really have to rev-parse
it.
Restoring the branch file fixes up the branch and makes everything ready again, e.g.:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
However, the reflog for the branch is now gone:
$ git reflog master
$
The reflog for HEAD
still works, and once you do a few more things on your branch, the reflog for the branch will be re-created.
If your file system gets backed up—e.g., via MacOS Time Machine, or by doing snapshots on a Windows network drive, or some such—you can look at your system backups. If you are lucky, you may find both the branch file and the reflog in these backups.
In this case, you can simply restore them in place. This has the same effect as finding the correct hash, but by restoring the reflog, you get your reflog back.
Upvotes: 0
Reputation: 14149
When deleting a branch, git is not case sensitive, meaning your branch "Exif" would be deleted if you executed
git branch -d exif
You didn't even create a branch "Exif" in the first place, because by pushing to a different branch, you don't create that branch in your local repository automatically.
To go back to your original branch, I would create a new local branch by checking out the remote branch again like so:
git checkout origin/exif
Upvotes: 1