コンフリクト解消をしそこねて>>>>>>みたいなマーカーがそのまま上がってしまってる場合がある。以下に紹介されているようにhookを書いてがマーカーが含まれていればcommitをキャンセルすることで回避できる。
ただ、git lfs管理下のファイルがあった場合には上記だけだとうまくいかない。 git lfsのファイルはgit上ではポインタファイルと呼ばれるメタデータとして存在している。実体は.git/lfs/objects以下に保持されていて、ポインタファイルではそのhash値やファイルサイズなどを記録している。 詳しくはこちら
git-lfs/spec.md at master · git-lfs/git-lfs · GitHub
実体がworkspace内に存在しないファイルについては、git checkoutをした際にgit lfsのサーバからdownloadされて.git/lfs/objects以下に置かれる。
git lfs管理下のファイルがコンフリクトした際は以下のような差分が出ている。(適当なimageファイルでコンフリクトさせた)
-oid sha256:71fbb9a95fe26f41d33d50766a01b68204e73970bac5922b2a6f31617d96106f -size 21890 +oid sha256:c1a8f9c529bbb8b049397593c869be1a4f9d1518948297f6386be315984c7196 +size 148
これが表しているのは、.git/lfs/objects以下にある実体ファイルがsize 148のファイルになっているということ。そこで実体を見てみるとこうなっている。
<<<<<<< HEAD oid sha256:71fbb9a95fe26f41d33d50766a01b68204e73970bac5922b2a6f31617d96106f size 21890 ======= oid sha256:c1a8f9c529bbb8b049397593c869be1a4f9d1518948297f6386be315984c7196 size 148 >>>>>>> test
ポインタファイルのフォーマットがコンフリクトマーカーによって崩れたため、ポインタファイルとして認識されなくなり、実体ファイルとして.git以下に置かれたと考えられる。
ちなみに実体ファイルのpathはこんなルールで決まっている
- .git/lfs/objects/<sha256の上2桁>/<sha256の3,4桁目>/<sha256そのもの>
- 今回の例なら
- git/lfs/objects/71/fb/71fbb9a95fe26f41d33d50766a01b68204e73970bac5922b2a6f31617d96106f
そのため、これをhookから検出するためには実体ファイルを取得してそこに含まれる文字列を見ればOK。そしてgit lfsにはそのためのコマンドとしてgit lfs sumdge
が用意されている(git checkout時の処理では内部でこれを使っている)
ポインタファイルから実体を取ってくるためには以下
$ cat <ポインタファイル> | git lfs sumdge --skip
これにgrepなどでコンフリクトマーカーを検出するようにすればhookで検知することが可能