5

I seem to have lost my afternoon's work in a new repo. Here's what I did:

  1. Created a new project locally and did some work.
  2. Created a repo on github
  3. git init
  4. git add src
  5. git remote add origin git@github.com:Synesso/memx.git
  6. git pull origin master
  7. git add .gitignore
  8. git commit -m 'updated ignore'
  9. git push origin master

Both my local repo and the github repo have only two commits. The initial commit (made by github on project creation) and a second one that includes only the file .gitignore.

The files added in step 4 (git add src) are not present. Nor do they appear to be staged.

Do you lose staged files when you do a git pull? Can I retrieve them somehow?

Current state:

$ git status
# On branch master
nothing to commit (working directory clean)

My inital add is not in the reflog.

$ git reflog
c80135d HEAD@{0}: checkout: moving from 999d128ea4e6969f9eacbceebb5f857f2aa5abb0 to master
999d128 HEAD@{1}: checkout: moving from master to HEAD~1
c80135d HEAD@{2}: checkout: moving from 999d128ea4e6969f9eacbceebb5f857f2aa5abb0 to master
999d128 HEAD@{3}: checkout: moving from master to 999d128ea4e6969f9eacbceebb5f857f2aa5abb0
c80135d HEAD@{4}: commit (amend): updated ignore
28b4f90 HEAD@{5}: commit: updated ignore
999d128 HEAD@{6}: initial pull

history shows that I added the src folder, but did not commit it:

223  git init
225  git add src
229  git add project/Build.scala
234  git remote add origin git@github.com:Synesso/memx.git
250  git pull origin master

I know git will complain if you try to pull with dirty files present. But it's OK with doing a pull that will obliterate staged files? That seems wrong.


I've just tested this process again and yes, it destroys staged files.

jem@jem-usb:~/projects$ mkdir x
jem@jem-usb:~/projects$ cd x
jem@jem-usb:~/projects/x$ git init
Initialized empty Git repository in /home/jem/projects/x/.git/
jem@jem-usb:~/projects/x$ echo "hi" > hello.world
jem@jem-usb:~/projects/x$ git add hello.world
jem@jem-usb:~/projects/x$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   hello.world
#
jem@jem-usb:~/projects/x$ ls -asl
total 24
 4 drwxrwxr-x 3 jem jem 4096 Apr 28 20:56 .
 4 drwxr-xr-x 8 jem jem 4096 Apr 28 20:56 ..
 4 drwxrwxr-x 7 jem jem 4096 Apr 28 20:56 .git
12 -rw-rw-r-- 1 jem jem    3 Apr 28 20:56 hello.world
jem@jem-usb:~/projects/x$ git remote add origin git@github.com:Synesso/memx.git
jem@jem-usb:~/projects/x$ git reflog
fatal: bad default revision 'HEAD'
jem@jem-usb:~/projects/x$ git pull origin master
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 7 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (7/7), done.
From github.com:Synesso/memx
 * branch            master     -> FETCH_HEAD
jem@jem-usb:~/projects/x$ ls -asl
total 36
 4 drwxrwxr-x 3 jem jem 4096 Apr 28 20:53 .
 4 drwxr-xr-x 8 jem jem 4096 Apr 28 20:52 ..
 4 drwxrwxr-x 8 jem jem 4096 Apr 28 20:53 .git
12 -rw-rw-r-- 1 jem jem   59 Apr 28 20:53 .gitignore
12 -rw-rw-r-- 1 jem jem    9 Apr 28 20:53 README.md
jem@jem-usb:~/projects/x$ git reflog
c80135d HEAD@{0}: initial pull

The file hello.world was deleted without warning.

Synesso
  • 37,610
  • 35
  • 136
  • 207

5 Answers5

7

I was able to reproduce this without using github, using two hosts (renamed here as hostB, which is the "remote", and hostA, which is the "local"):

hostB$ cd /tmp; mkdir repo; cd repo; git init
Initialized empty Git repository in /tmp/repo/.git/
hostB$ : > .gitignore; echo this is a readme > README.md
hostB$ git add .; git commit -m initial
[master (root-commit) 58d43bd] initial
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 README.md

hostA$ cd /tmp; mkdir repo; cd repo; git init
Initialized empty Git repository in /tmp/repo/.git/
hostA$ echo hi > hello.world
hostA$ git add hello.world
hostA$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   hello.world
#
hostA$ git remote add origin ssh://hostB.dom.ain/tmp/repo
hostA$ git pull origin master
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
From ssh://hostB.dom.ain/tmp/repo
 * branch            master     -> FETCH_HEAD
hostA$ ls
README.md

Important: you can use git fsck --lost-found to recover your staged files:

hostA$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling blob 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
hostA$ 

and sure enough, if you examine the blob(s) (which are now restored in .git/lost-found/other), those will have your lost stuff. (Any directory structure will be gone though, and you'll have to figure out which file is which and re-put them where you want them.)

Interestingly, if you git fetch origin followed by git merge origin/master, it grabs the origin's initial revision(s) (with the .gitignore and README.md files from hostB, in this case) and retains your "changes to be committed". Another reason to favor git fetch followed by git merge? :-)

torek
  • 448,244
  • 59
  • 642
  • 775
  • I am so appreciative - wish I could Flattr this answer! – Treffynnon Jan 23 '14 at 17:36
  • @Treffynnon: this was fixed in "official" git with commit `b4dc085a8dc2ec2fb5f6366fa672222b807ed655`, in Jun 2013, and included in git v1.8.4. – torek Jan 23 '14 at 17:51
  • 1
    I have the same problem but my file changed not deleted, how can I retrieve the version of my file before pull ?? – Mahmoud Hanafy Sep 06 '14 at 12:04
  • @MahmoudHanafy: If you `git add`-ed your earlier (now-overwritten) version, use `git fsck --lost-found` as shown above. If not, your earlier version is probably gone forever (unless you have backups, e.g., Time Machine on MacOS, etc). – torek Sep 06 '14 at 14:00
4

I received the following reply on the git mailing list from Junio Hamano:


It is an unanticipated corner case interfering our attempt to be too nice that backfired.

For a long time, having no history and asking to pull was forbidden, because "git pull" is is about combining two (or more) histories together and pulling when you have no history is a nonsense --- you only have one history (the history from the other side) and there is nothing to combine.

Later we tried to be nicer, as some new users triggered an error when doing "git init" in an empty directory followed by "git pull", by redefining "merge" into no history to mean resetting to the other history.

This solved "git init && git pull", but we did not anticipate anybody would do a "git init && git add && git pull" sequence, to which there is no sane outcome other than just erroring out.

A patch to give that only sane outcome may look like this.

 git-pull.sh |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/git-pull.sh b/git-pull.sh
index 2a10047..da102d0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -261,6 +261,9 @@ esac

 if test -z "$orig_head"
 then
+       test $(git ls-files | wc -l) = 0 ||
+       die "$(gettext "Uncommitted changes in the index")"
+
       git update-ref -m "initial pull" HEAD $merge_head "$curr_head" &&
       git read-tree -m -u HEAD || exit 1
       exit
Synesso
  • 37,610
  • 35
  • 136
  • 207
1

I believe that this is an unfortunately side effect of having a new repository w/o a single commit. If you try your test again but instead perform locally:

git init; echo "Readme" > Readme; git add Readme; git commit -m 'Initial commit'

then when you 'pull' into a working directory with 'src' files, GIT will warn and, more importantly, will not remove stuff.

GoZoner
  • 67,920
  • 20
  • 95
  • 145
0

Your repo on github does not contain any valueable files. Didn't you forget to commit them?

Even if they aren't staged, where is your src folder locally? If you did only what specified in question, git couldn't eat your files anyway.

vissi2
  • 83
  • 6
0

I think you should commit your local change after add before remote add and pull

  1. git init
  2. git add src
  3. git add .gitignore
  4. git commit -m 'updated ignore'
  5. git remote add origin git@github.com:Synesso/memx.git
  6. git pull origin master
  7. git push origin master
Ethan Zhang
  • 4,189
  • 3
  • 22
  • 17