85217
Git for Windows 2.34.1.windows.1 を Git Bash 上で利用していますが、後述のリポジトリの特定の範囲のコミットを
checkout すると、バージョン管理下にある特定のファイルが modified 状態になってしまいます。  
(追記: Ubuntu 上の Git version 2.29.2 でも再現しました)

この理由を知りたいです。

#### 再現手順

```

    git clone https://github.com/ScoopInstaller/Main.git
    cd Main
    git reset --hard 7eeb0aed86a0979feb0fa40a72ac5ffb2f574cb2
    
```

上記操作を行うと、 `bucket/prowiz.json` が modified 状態になります。

```

    $ git status
    On branch master
    Your branch is behind 'origin/master' by 137 commits, and can be fast-forwarded.
      (use "git pull" to update your local branch)
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
            modified:   bucket/prowiz.json
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
```

#### 試してみたことなど

`git diff --word-diff-regex=.` 実行結果を見たところ、行末から `CR`
が無くなっているため差分があるとみなされているようでした

```

    index 7e8d59138..2233ac3cf 100644
    --- a/bucket/prowiz.json
    +++ b/bucket/prowiz.json
    @@ -1,28 +1,28 @@
    {[-^M-]
        "version": "1.70",[-^M-]
    ...
    
```

ので、バイナリエディタで開いて `0D 0A` を `0D 0D 0A` に置き換えてみたところ確かに差分は無くなりました。  
しかし、なぜこのような状況になるのかがわかりません。

自分で新しく Git リポジトリを作成して行末が `0D 0D 0A` となるようなファイルを commit, checkout
してみましたが前述のリポジトリのような挙動にはなりませんでした。  
(差分は表れず、 commit したものがそのまま checkout されました。)

#### 実行環境

  * Windows 10
  * Git for Windows 2.34.1.windows.1

Git の config 設定は次の通りです(長いので折りたたみます):  

```

    $ git config -l --show-origin
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        core.symlinks=false
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        core.autocrlf=true
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        core.fscache=true
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        color.diff=auto
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        color.status=auto
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        color.branch=auto
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        color.interactive=true
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        help.format=html
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        diff.astextplain.textconv=astextplain
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        rebase.autosquash=true
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        filter.lfs.clean=git-lfs clean -- %f
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        filter.lfs.smudge=git-lfs smudge -- %f
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        filter.lfs.process=git-lfs filter-process
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        filter.lfs.required=true
    file:C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/etc/gitconfig        credential.helper=!"C:/Users/yuki/scoop/apps/git/2.34.1.windows.1/mingw64/libexec/git-core/git-credential-manager-core.exe"
    file:C:/Users/yuki/.gitconfig   credential.helper=manager-core
    file:C:/Users/yuki/.gitconfig   user.email=*****@example.com
    file:C:/Users/yuki/.gitconfig   user.name=*****
    file:C:/Users/yuki/.gitconfig   filesystem.AdoptOpenJDK|11.0.5|-628477916.timestampresolution=2001 microseconds
    file:C:/Users/yuki/.gitconfig   filesystem.AdoptOpenJDK|11.0.5|-628477916.minracythreshold=0 nanoseconds
    file:C:/Users/yuki/.gitconfig   core.quotepath=false
    file:C:/Users/yuki/.gitconfig   core.autocrlf=false
    file:C:/Users/yuki/.gitconfig   pull.ff=only
    file:C:/Users/yuki/.gitconfig   credential.helperselector.selected=manager-core
    file:C:/Users/yuki/.gitconfig   gui.encoding=utf-8
    file:C:/Users/yuki/.gitconfig   branch.sort=authordate
    file:C:/Users/yuki/.gitconfig   submodule.recurse=true
    file:C:/Users/yuki/.gitconfig   alias.logshort=log --pretty=format:"%h %an %ai %s"
    file:.git/config        core.repositoryformatversion=0
    file:.git/config        core.filemode=false
    file:.git/config        core.bare=false
    file:.git/config        core.logallrefupdates=true
    file:.git/config        core.symlinks=false
    file:.git/config        core.ignorecase=true
    file:.git/config        remote.origin.url=https://github.com/ScoopInstaller/Main.git
    file:.git/config        remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
    file:.git/config        branch.master.remote=origin
    file:.git/config        branch.master.merge=refs/heads/master
```
CC BY-SA 4.0
2021-12-14T05:07:04.063
84126
2021-12-18T16:58:10.117
2021-12-18T16:58:10.117
2808
2808
question
git
git reset --hard でファイルが modified になる
`.gitattributes` の設定によって改行コード `LF` でコミットされているはずのファイルが、実際には `CRLF`
でコミットされているため発生しています。  
`git add --renormalize` を実行することで解消できます。

* * *

質問文にあるような状態のリポジトリは次の手順で作成できます:

```

    #!/bin/bash
    
    set -eux
    
    mkdir workrepo
    cd workrepo
    git init -b main
    git commit --allow-empty -m init
    echo '* text eol=crlf' > .gitattributes
    git add .gitattributes && git commit -m 'add .gitattributes'
    git checkout -b feature
    git rm .gitattributes && git commit -m 'remove .gitattributes'
    echo $'hello\r\nworld' > hello.txt
    git add hello.txt && git commit -m 'add hello.txt with CRLF'
    GIT_SEQUENCE_EDITOR="sed -i '1d'" git rebase -i main
    git checkout -f main
    git merge --no-ff --no-edit feature
    
```

この事象について、[`gittattribubes(5)` の `eol` 節](https://git-
scm.com/docs/gitattributes/2.34.1#_eol) に次の記述があります:

> Note that setting this attribute on paths which are in the index with CRLF
> line endings may make the paths to be considered dirty.

また、この文章が追加された[当時のやりとり](https://lore.kernel.org/git/20170822191318.GA22118@tor.lan/)の中では次のように説明されています:

> This is by design.
>
> When you set the text attribute (in your case "eol=crlf" implies text)  
>  then the file(s) -must- be nomalized and commited so that they have LF  
>  in the repo (technically speaking the index)

このあたりの説明をまとめると、次のような動作になっているようです:

  * `.gitattrubutes` に `text` や `eol=*` を設定すると、 Git は対象となるファイルを行末正規化して管理する 
    * 行末正規化とは、改行コードを `LF` に統一すること
  * また、コミット済みのファイルは、 行末正規化されている前提で扱う
  * そのため、 `CRLF` のファイルがコミットされ(てい)ると今回のような不整合が発生する
  * これを修正するには再正規化操作を行えば良い 
    * (現在のバージョンでは([参考](https://lore.kernel.org/git/CAHd499B5hM9ixnsnwWwB2uyDT10dRQpN473m5QjxH9raHtFXiw@mail.gmail.com/))) `git add --renormalize` で修正できる
CC BY-SA 4.0
2021-12-18T16:56:15.440
85217
2021-12-18T16:56:15.440
2808
84126
answer