10

I have my local repo in a state that forbid me to either commit, stash, checkout to another branch or even discard changes. So I'm just stuck.

I will try to describe what steps brought me to this situation, as far as I remember.

Please, take a seat.

A not so long time ago, in another computer far, far away... an other dev normalized crlf in the project according to: https://help.github.com/articles/dealing-with-line-endings

In the while (you know, speed of light...) I made some changes locally, commited, and pulled.

When I pulled Git said:

error: Your local changes to the following files would be overwritten by merge:
    wp-config.php

wp-config.php was earlier removed from the index using git update-index --assume-unchanged wp-config.php since its a template config file adapted to each local environment.

The base "template" can change. Nothing surprising. Here what I planned:

  1. reindex wp-config.php
  2. stash my own config changes
  3. pull origin master
  4. stash apply my config back

Things went wrong at step 3. git pull origin master still raised the error above, as if the stash was ineffective.

git status said wp-config.php had changes not staged for commit. That surprised me a bit after a stash.

Since I stashed my changes I ran git checkout -- wp-config.php... but without any effect! File was still not staged for commit.

Since I was becoming mad, I created a new branch my-config, added and commited wp-config.php into it, then switched back to master, deleted wp-config.php (using git rm), and merged origin/master... with success!

So now that master was up to date and clean, I planned to restore my own config without the help of Git (editing the file manually).

Since I wanted to know what happened, I switched to my-config branch, and tried here a very simple manipulation:

git stash
git stash apply

And guess what? stash apply failed saying:

error: Your local changes to the following files would be overwritten by merge:
    wordpress/license.txt
    wordpress/readme.html
    ...
    (all the files that where modified by the crlf conversion)

And now I'm stuck on my branch (and plan to saw it, Francophones will understand ;)) since:

  • git stash apply, commit and checkout master gives the error above
  • git stash produces a stash entry but doesn't change the unstaged states
  • and git checkout -- <file> neither removes the unstaged state

The only thing I can do now is to delete all these files (using the OS rm) to be able to go back to the master branch.

True story.

I would love to understand what happened on the master branch, then on my-config branch, and what brought me in such situations (I suspect using stash on crlf converted file).

Important notes:

  • I run on linux
  • git core.autocrlf is on input
  • my .gitattributes is the same as the one in "dealing-with-line-endings" article
  • I'm relatively new to Git (2nd day living with it)

When I did stash on my-config branch it outputed:

warning: CRLF will be replaced by LF in wordpress/license.txt.
The file will have its original line endings in your working directory.
... (one for each crlf converted file) ...
Saved working directory and index state WIP on my-config: dbf65ad my config -- should not be pushed
HEAD is now at dbf65ad my config -- should not be pushed

(dbf65ad is the only commit I did on my-config branch)

SQB
  • 3,926
  • 2
  • 28
  • 49
Pierre
  • 1,322
  • 11
  • 17

3 Answers3

5

After some research i guess the following happened. Your workmate changed the lineendings which caused the first pull-conflict.

That's why you stashed your work, pulled the stuff (now without problems) and started to apply the stash again.

With invoking git stash apply git starts a recursive merge in of your stashed changes.

The error-message just tells you ran into a merge-conflict. According to the developer's stash-documentation this may be resolved by a git stash drop after resolving the conflicts:

"Applying the [stash] can fail with conflicts; in this case, it is not removed from the stash list. You need to resolve the conflicts by hand and call git stash drop manually afterwards."

Conclusion: If the configuration of the line-endings must be done in a existing project it seems to be best practise to do so by using a .gitattributes in your project-folder. Since it gets distributed with your line-ending-change-commit, it will avoid the headaches switching your current work to the new normalization-standard.

Changing line endings within projects & .gitattributes

According to the developers documentation of .gitattributes you can change the line-endings for all files (in the active branch) with the following steps:

$ echo "<<filepattern>> eol=lf" >>.gitattributes
$ rm .git/index     # Remove the index to force Git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

Replace <<filepattern>> with a pattern that matches your source files - in your case *.py for python-files (a good pattern-explanation is given in this .gitignore-description).

If you have more than one filepattern to add, you may add several line-ending-definitions to the .gitattributes.

Attention: Since the second step requires to delete the .git/index (which is branch-specific) this must be done in every single branch you'd like to keep.

If you have many branches to process, you might consider writing a short script iterating through your git branches.

Community
  • 1
  • 1
Florian Neumann
  • 5,587
  • 1
  • 39
  • 48
  • 1
    It looks like when I added `*.py eol=lf` to my .gitattributes, few files got stuck, git stash etc., didn't do anything, commenting it out did unstuck the repo but I am still not sure what was the reason. – Vaibhav Mishra May 09 '14 at 06:43
  • @VaibhavMishra this is very interesting, could i ask you to try the modified receipe, i recently added to my answer? I would really like to know how to handle this kind of behaviour, since it happens often. – Florian Neumann May 09 '14 at 08:43
  • Hi, I followed your instruction, however after going to different branch, all the line endings reappear, looks like I have to do it everywhere(In every branch) for it to work – Vaibhav Mishra May 12 '14 at 07:32
  • @VaibhavMishra thanks - it seems that theese steps must be done in every single branch you'd like to keep. One key-step is deleting the [`.git/index`](http://stackoverflow.com/questions/4084921/what-does-the-git-index-exactly-contain) which is different from branch to branch. – Florian Neumann May 12 '14 at 07:38
  • 1
    agreed, thanks - can you update the answer with the comment so that I can accept the answer. – Vaibhav Mishra May 12 '14 at 11:28
  • @VaibhavMishra - you're welcome. I generalized my answer, any further suggestions for improvement are welcome. – Florian Neumann May 12 '14 at 11:50
  • @Pierre i modified my answer to show my investigations on stash apply, this may now answer your question. – Florian Neumann May 12 '14 at 14:01
1

The best way to reset your local module is to use

git clean -f -x -d

This effectively removes all untracked changes to your local module and puts it back in a 'vanilla' state.

-f clean files.
-x clean files normally ignored by .gitignore.
-d clean directories.

Now run git reset --hard origin/<BRANCH_NAME>. This will reset your branch to the state of the remote.

git status at this point should tell you:

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

If you have your actual changes stashed you should then be able to git stash apply to put them back correctly.

If git stash show stash@{0} shows more changes than you expected you can just apply the ones you want to see with git checkout stash@{0} -- <filename>.

Hope this helps

mproffitt
  • 2,409
  • 18
  • 24
  • 3
    `git clean` would remove all untracked files. I think untracked files have nothing to do with my problem. Moreover I have some personal stuff untracked I would regret to delete... anyway, a `git reset --hard` worked. But it's not a valuable solution since if I had important local modifications, I would have lost them (I know I can retrieve them with git fsck, but definitely not clean). – Pierre Jun 23 '13 at 22:05
  • This worked for me where other recipes failed. Thanks. – Toby Sharp Mar 19 '15 at 21:42
0

First, regarding the GitHub help page, I would seriously recommend setting:

git config --global core.autocrlf false

Let reserve eol modification to explicit declaration in .gitattributes files instead of a global magic rule: keep core.autocrlf to false.

Second, you can see if you observe the same eol modifications on git stash with git update-index --skip-worktree.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    With `git config --global core.autocrlf false` i'm now able to see clearly the CRLF differences in `git status`, but a `git checkout wp-config.php` does not remove the *not staged* status. (strangely, a diff, even a binary diff does not show me the CRLF diff... files are reported equal). And `git update-index --skip-worktree` have no effect, even in conjunction with `core.autocrlf false`. It seems like the CRLF handling in Git is a bit esoteric, even with `core.autocrlf` set to `false`... – Pierre Jun 23 '13 at 21:11