gitgitignorerebasesquash

Files added to .gitignore lost after attempting to squash a series of commits through interactive rebasing


I've been adding some files to .gitignore over a few commits, that I do not want pushed to remote. This includes files such as .Rprofile, which may contain information I do not want shared, and *.code-workspace, which I did not see as necessary to track. After committing everything was working as intended, but then I decided to squash the .gitignore changes into one commit using git rebase -i. I did this in terminal in VS Code, which caused to program to crash. Long story short, after that all files listed in .gitignore are gone! Not just the files recently added to gitignore, but also previous files that has been in gitignore since I initiated git. This includes .Renviron.

I therefore have three questions:

  1. What happened? Why did git tamper with files in the ignore list? Isn't that the whole point of an ignore list: so that git will not tamper with them?
  2. Are the ignored files lost, or is there a way they can be retrieved? At this point I consider it best if there a way to restore the working directory to its state prior to attempting the rebase.
  3. How do I prevent this from happening again? These were files that was deliberately ignored because I need them in my working directory, but do not want Git to push them to the remote repository. However, I certainly do not want git to delete them!

Full history:

1. Initial git log output:
% git log

commit 7df4f... (HEAD -> master, origin/master)
Author: 
Date:   Tue Aug 22 10:42:52 2023 +0200

    New commit.

commit 43c8c...
Author: 
Date:   Tue Aug 22 10:32:39 2023 +0200

    Ignoring code testing notebook.

commit 7a4be...
Author: 
Date:   Fri Aug 18 15:46:28 2023 +0200

    Ignoring VS Code workspace

commit 0866e...
Author: 
Date:   Fri Aug 18 15:39:46 2023 +0200

    Ignoring .Rprofile

commit c3b51...
Author: 
Date:   Fri Aug 18 15:38:27 2023 +0200

    .gitignore ignoring .Rprofile

commit 299bd
Author: 
Date:   Fri Aug 18 13:36:33 2023 +0200

    `bugs()` output directory ignored

commit 36699
Author: 
Date:   Fri Aug 18 13:34:35 2023 +0200

    Old commit.

commit ...
2. Attempting interactive rebasing:
% git rebase -i HEAD~7

pick 36699 Old commit.
pick 299bd `bugs()` output directory ignored
s c3b51 .gitignore ignoring .Rprofile
s 0866e Ignoring .Rprofile
s 7a4be Ignoring VS Code workspace
s 43c8c Ignoring code testing notebook.
pick 7df4f New commit.

Essentially I wanted to squash commits 299bd - 43c8c together. When trying to save the rebase file, VS Code crashed and at this point all files listed in .gitignore were gone.

3. git log output in Console:
% git log

commit 3cbe9... (HEAD)
Author: 
Date:   Fri Aug 18 13:36:33 2023 +0200

    # This is a combination of 4 commits.
    # This is the 1st commit message:
    
    `bugs()` output directory ignored
    
    # This is the commit message #2:
    
    .gitignore ignoring .Rprofile
    
    # This is the commit message #3:
    
    Ignoring .Rpofile
    
    # This is the commit message #4:
    
    Ignoring VS Code workspace

commit 36699...
Author: 
Date:   Fri Aug 18 13:34:35 2023 +0200

    Old commit.

Apparently, the latest commit is "lost". Not unexpected, git branch showed that I'm in the middle of a commit.

% git branch
* (no branch, rebasing master)
  master
4. Attempting to continue rebase:
git rebase --continue 
fatal: could not read log file '.git/rebase-merge/message': No such file or directory
error: could not commit staged changes.
5. Switched to master branch:
% git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  3cbe9 # This is a combination of 4 commits. # This is the 1st commit message:

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 3cbe9

Listing the files in the directory ls -a showed that the ignored files are still absent.

git statusprovided the following output:

% git status

On branch master
Your branch is up to date with 'origin/master'.

Last commands done (6 commands done):
   squash 7a4be Ignoring VS Code workspace
   squash 43c8c Ignoring code testing notebook.
  (see more in file .git/rebase-merge/done)
Next command to do (1 remaining command):
   pick 7df4f New commit.
  (use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on '499cb'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working tree clean
6. Moved commit "3cbe9" to a new branch:

..given the warning message when checking out master.

% git branch apprentice 3cbe9
7. I then attempted to continue the rebase:
% git rebase --continue
The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:

    git commit --allow-empty

Otherwise, please use 'git rebase --skip'
On branch master
Your branch is up to date with 'origin/master'.

Last commands done (7 commands done):
   squash 43c8c Ignoring code testing notebook.
   pick 7df4f New commit.
  (see more in file .git/rebase-merge/done)
No commands remaining.
You are currently rebasing branch 'master' on '499cba5'.
  (all conflicts fixed: run "git rebase --continue")

nothing to commit, working tree clean
Could not apply 7df4f... New commit.

git log output:

% git log
commit 7df4f (HEAD -> master, origin/master)
Author: 
Date:   Tue Aug 22 10:42:52 2023 +0200

    New commit.

commit 43c8c
Author: 
Date:   Tue Aug 22 10:32:39 2023 +0200

    Ignoring code testing notebook.

commit 7a4be
Author: 
Date:   Fri Aug 18 15:46:28 2023 +0200

    Ignoring VS Code workspace

commit 0866e
Author: 
Date:   Fri Aug 18 15:39:46 2023 +0200

    Ignoring .Rpofile

commit c3b51
Author: 
Date:   Fri Aug 18 15:38:27 2023 +0200

    .gitignore ignoring .Rprofile

commit 299bd
Author: 
Date:   Fri Aug 18 13:36:33 2023 +0200

    `bugs()` output directory ignored

commit 7df4f (HEAD -> master, origin/master)
Author: 
Date:   Tue Aug 22 10:42:52 2023 +0200

    New commit.

commit 43c8c
Author: 
Date:   Tue Aug 22 10:32:39 2023 +0200

    Ignoring code testing notebook.

commit 7a4be
Author: 
Date:   Fri Aug 18 15:46:28 2023 +0200

    Ignoring VS Code workspace

commit 0866e
Author: 
Date:   Fri Aug 18 15:39:46 2023 +0200

    Ignoring .Rpofile

commit c3b51c
Author: 
Date:   Fri Aug 18 15:38:27 2023 +0200

    .gitignore ignoring .Rprofile

For some reason the commit history has now been duplicated, while commit 36699 ("Old commit.") is seemingly gone. The files in the ignore list remains absent.


Solution

  • Warning: I think you are still in the 'rebase' mode and all steps you do might count towards your rebasing activity.

    I will try to collect what I understand with the suggestions of the comments. Please correct me if anything is wrong.

    May be that, as you say, ''the commit history has now been duplicated'' because log sometimes shows two histories mixed. Use git log --graph --decorate or gitk to see something that we can interpret. The other possible reason is that during your interrupted rebase, you are allowed to add any number of commits (an example of that is described in SPLITTING COMMITS section of man git-rebase) and this is what you may have unintentionally done by git checkout master followed by git rebase --continue.

    I think it is the second because I was able to do something similar (though I had to add some git add and/or git commit -- but I had no crash here.)

    Remedy:

    1. Note the original commit 7df4f, as backup. (May be git branch goodmaster 7df4f). (Actually I see you have it recorded as origin/master, too.) Also backup all files, because you may have added to .gitignore some more than you already lost.

    2. finish rebase by git rebase --abort. You will have to do it sometime in future anyway. And whatever it does to your files, it is better to suffer now. (And shorter in-rebase-history also means less damage.)

    3. You may now look at the state by gitk, or look what might be recovered by gitk --reflog. Look at git status.

    4. Now I would recover the git repo to some reasonable state -- especially if it is not. This might be git reset 7df4f or git reset --hard 7df4f where the later also changes the working tree (i.e., the files). The later hence can delete files for which you have done git rm (when playing with .gitignore). May be git checkout master works the same but maybe not.

    5. recover missing files by git checkout some-commit-id -- some-path-and-file. You can find some commit ids by gitk --reflog. Also git log -- filename can reveal the commits where you added/deleted the file. Or git reflog -- filename.

    .gitignore This file tells git setup not to list specified files. But no more than that.

    What happenend? I think you have done git rm --cached files when you were adding them to .gitignore. Even if not, you possibly have done at least git add files for them some time ago. This way, in the history there are records of this files being created/deleted. If you make git to move you through the history, they have to appear/disappear accordingly. (File .gitignore makes no influence.)

    How to avoid this situation Well. Something like that happened to me too. May be to convince the git developers to warn you before doing such a thing both 1. as an immediate result of a command 2. as a temporary action in course of something like rebase. Hmm, well. ... Sounds complicated, but there might be a chance for implementation...(?)