Stuck repo using stash after crlf normalization?

2019-01-25 10:25发布

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)

3条回答
叛逆
2楼-- · 2019-01-25 11:05

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.

查看更多
看我几分像从前
3楼-- · 2019-01-25 11:14

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

查看更多
混吃等死
4楼-- · 2019-01-25 11:24

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.

查看更多
登录 后发表回答