Force LF eol en git repo y copia de trabajo

170

Tengo un repositorio git alojado en github. Muchos de los archivos se desarrollaron inicialmente en Windows, y no tuve demasiado cuidado con los finales de línea. Cuando realicé la confirmación inicial, tampoco tenía ninguna configuración de git para aplicar las terminaciones de línea correctas. El resultado es que tengo varios archivos con terminaciones de línea CRLF en mi repositorio github.

Ahora estoy desarrollando parcialmente en Linux, y me gustaría limpiar las terminaciones de línea. ¿Cómo puedo asegurarme de que los archivos se almacenan correctamente con LF en github y tener LF en mi copia de trabajo?

He configurado un .gitattributesarchivo que contiene text eol=LF; ¿Es eso correcto? Con eso comprometido y presionado, ¿puedo simplemente rmmi repositorio local y volver a clonar desde github para obtener el efecto deseado?

Chowlett
fuente
1
posible duplicado de git reemplazando LF con CRLF
Lazy Badger
Ninguno de esos es exactamente lo que estoy preguntando. Soy el único desarrollador y estoy dispuesto a configurar todas mis máquinas de la misma manera. Tengo un repositorio existente con algunos archivos CRLF ya comprometidos y un par de clones en diferentes máquinas. ¿Cómo puedo actualizar el repositorio y cada copia de trabajo para que haya LF en todas partes?
Chowlett
¿Has mirado esta guía de Github?
Andy

Respuestas:

237

Sin un poco de información sobre qué archivos hay en su repositorio (código fuente puro, imágenes, ejecutables, ...), es un poco difícil responder la pregunta :)

Además de esto, consideraré que está dispuesto a usar LF por defecto como terminaciones de línea en su directorio de trabajo porque está dispuesto a asegurarse de que los archivos de texto tengan terminaciones de línea LF en su repositorio .git si trabaja en Windows o Linux . De hecho, más vale prevenir que curar ...

Sin embargo, hay una mejor alternativa: Benefíciese de las terminaciones de línea LF en su directorio de trabajo de Linux, las terminaciones de línea CRLF en su directorio de trabajo de Windows Y las terminaciones de línea LF en su repositorio.

Como está trabajando parcialmente en Linux y Windows, asegúrese de que core.eolesté configurado nativey core.autocrlfconfigurado como true.

Luego, reemplace el contenido de su .gitattributesarchivo con lo siguiente

* text=auto

Esto le permitirá a Git manejar la conversión automática de terminaciones de línea para usted, en confirmaciones y pagos. Los archivos binarios no se modificarán, los archivos detectados como archivos de texto verán las terminaciones de línea convertidas sobre la marcha.

Sin embargo, como conoce el contenido de su repositorio, puede echarle una mano a Git y ayudarlo a detectar archivos de texto de archivos binarios.

Siempre que trabaje en un proyecto de procesamiento de imágenes basado en C, reemplace el contenido de su .gitattributesarchivo con lo siguiente

* text=auto
*.txt text
*.c text
*.h text
*.jpg binary

Esto asegurará que los archivos cuya extensión sea c, h o txt se almacenen con terminaciones de línea LF en su repositorio y tengan terminaciones de línea nativas en el directorio de trabajo. Los archivos JPEG no serán tocados. Todos los demás se beneficiarán del mismo filtrado automático como se ve arriba.

Para obtener una comprensión más profunda de los detalles internos de todo esto, te sugiero que te sumerjas en esta muy buena publicación "Cuidado con el final de tu línea" de Tim Clem, un Githubber.

Como ejemplo del mundo real, también puede echar un vistazo a esta confirmación donde .gitattributesse demuestran esos cambios en un archivo.

ACTUALIZAR la respuesta considerando el siguiente comentario

De hecho, no quiero CRLF en mis directorios de Windows, porque mi entorno Linux es en realidad un VirtualBox que comparte el directorio de Windows

Tiene sentido. Gracias por la aclaración. En este contexto específico, el .gitattributesarchivo por sí solo no será suficiente.

Ejecute los siguientes comandos en su repositorio

$ git config core.eol lf
$ git config core.autocrlf input

Como su repositorio se comparte entre su entorno Linux y Windows, esto actualizará el archivo de configuración local para ambos entornos. core.eolse asegurará de que los archivos de texto tengan terminaciones de línea LF en los pagos. core.autocrlfasegurará que el potencial CRLF en archivos de texto (resultante de una operación de copiar / pegar, por ejemplo) se convierta a LF en su repositorio.

Opcionalmente, puede ayudar a Git a distinguir qué es un archivo de texto creando un .gitattributesarchivo que contenga algo similar a lo siguiente:

# Autodetect text files
* text=auto

# ...Unless the name matches the following
# overriding patterns

# Definitively text files 
*.txt text
*.c text
*.h text

# Ensure those won't be messed up with
*.jpg binary
*.data binary

Si decidió crear un .gitattributesarchivo, confírmelo .

Por último, asegúrese de que se git statusmencione "nada que confirmar (limpieza del directorio de trabajo)" , luego realice la siguiente operación

$ git checkout-index --force --all

Esto recreará sus archivos en su directorio de trabajo, teniendo en cuenta sus cambios de configuración y el .gitattributesarchivo y reemplazando cualquier CRLF potencial pasado por alto en sus archivos de texto.

Una vez hecho esto, cada archivo de texto en su directorio de trabajo TENDRÁ terminaciones de línea LF y git statusaún debería considerar el workdir como limpio.

nulltoken
fuente
34
En realidad no quiero CRLF en mis directorios de Windows, porque mi entorno Linux es en realidad un VirtualBox que comparte el directorio de Windows; y aunque Notepad ++ etc. puede manejar solo LF en Windows, viestá menos contento con CRLF. ¿Solo quiero cambiarlo para que core.autocrlfsea false(o input)?
Chowlett el
55
Excelente respuesta Una nota rápida para cualquier otra persona que use esta configuración: la línea "* text = auto" debe ser la primera línea en su archivo .gitattributes para que las líneas subsiguientes puedan anular esa configuración.
Ari Patrick
9
@CMCDragonkai Dependiendo de su shell, git checkout-index --force --allpuede funcionar mejor. El segundo punto parece un poco fuera de tema con respecto a la pregunta original. ¿Qué tal hacer una pregunta dedicada?
nulltoken
8
No entiendo por qué .gitattributes no puede manejar el caso de compartir una copia de trabajo entre Linux y Windows. ¿No podemos establecer texty eol=lflograr el mismo resultado que se describe en su respuesta a través de core.eoly core.autocrlf?
DanielSank
10
git checkout-index --force --allno hace nada por mi Lo que funciona es la lista de comandos en las instrucciones de GitHub para tratar este problema.
Roman Starkov
127

Comenzando con git 2.10 (publicado el 03/09/2016), no es necesario enumerar cada archivo de texto por separado. Git 2.10 arregló el comportamiento de text = auto junto con eol = lf . Fuente .

.gitattributes archivo en la raíz de su repositorio git:

* text=auto eol=lf

Añadir y confirmarlo.

Luego, puede seguir los pasos y todos los archivos están normalizados ahora:

git rm --cached -r .  # Remove every file from git's index.
git reset --hard      # Rewrite git's index to pick up all the new line endings.

Fuente: Respuesta de kenorb .

koppor
fuente
77
Git 2.10 ha sido puesto en libertad el 3 de septiembre de 2016.
Stil
Ejecuté esto y bloqueó todos mis archivos que no son de texto
Anthony
Puede establecer explícitamente el modo binario en ciertos archivos. - Me pregunto por qué la detección automática está rota (¿todavía?) En algunos archivos
koppor
Esta debería ser la respuesta aceptada.
CletusW
25

Para forzar las terminaciones de línea LF para todos los archivos de texto, puede crear .gitattributesarchivos en el nivel superior de su repositorio con las siguientes líneas (cambie según lo desee):

# Ensure all C and PHP files use LF.
*.c         eol=lf
*.php       eol=lf

lo que garantiza que todos los archivos que Git considera como archivos de texto tienen LFterminaciones de línea normalizadas ( ) en el repositorio (normalmente, la core.eolconfiguración controla cuál tiene por defecto).

Según la nueva configuración de atributos, Git debería normalizar cualquier archivo de texto que contenga CRLF. Si esto no sucede automáticamente, puede actualizar un repositorio manualmente después de cambiar las terminaciones de línea, para que pueda volver a escanear y confirmar el directorio de trabajo siguiendo los siguientes pasos (dado un directorio de trabajo limpio):

$ echo "* text=auto" >> .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"

o según los documentos de GitHub :

git add . -u
git commit -m "Saving files before refreshing line endings"
git rm --cached -r . # Remove every file from Git's index.
git reset --hard # Rewrite the Git index to pick up all the new line endings.
git add . # Add all your changed files back, and prepare them for a commit.
git commit -m "Normalize all the line endings" # Commit the changes to your repository.

Ver también: publicación de @Charles Bailey .

Además, si desea excluir cualquier archivo para que no sea tratado como un texto, desarme su atributo de texto, p. Ej.

manual.pdf      -text

O márquelo explícitamente como binario:

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

Para ver un archivo de normalización git más avanzado, verifique .gitattributesen el núcleo de Drupal :

# Drupal git normalization
# @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# @see https://www.drupal.org/node/1542048

# Normally these settings would be done with macro attributes for improved
# readability and easier maintenance. However macros can only be defined at the
# repository root directory. Drupal avoids making any assumptions about where it
# is installed.

# Define text file attributes.
# - Treat them as text.
# - Ensure no CRLF line-endings, neither on checkout nor on checkin.
# - Detect whitespace errors.
#   - Exposed by default in `git diff --color` on the CLI.
#   - Validate with `git diff --check`.
#   - Deny applying with `git apply --whitespace=error-all`.
#   - Fix automatically with `git apply --whitespace=fix`.

*.config  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.css     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.dist    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.engine  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.html    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html
*.inc     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.js      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.json    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.lock    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.map     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.md      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.module  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.php     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.po      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.script  text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.sh      text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.sql     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.svg     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.theme   text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php
*.twig    text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.txt     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.xml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.yml     text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2

# Define binary file attributes.
# - Do not treat them as text.
# - Include binary diff in patches instead of "binary files differ."
*.eot     -text diff
*.exe     -text diff
*.gif     -text diff
*.gz      -text diff
*.ico     -text diff
*.jpeg    -text diff
*.jpg     -text diff
*.otf     -text diff
*.phar    -text diff
*.png     -text diff
*.svgz    -text diff
*.ttf     -text diff
*.woff    -text diff
*.woff2   -text diff

Ver también:

kenorb
fuente
2
1. text=autoes engañoso. No se puede usar text=autoy eoljuntos. La configuración eoldesactiva la detección automática de archivos de texto. Es por eso que debe especificar todos esos tipos de archivos. Si autoestaba habilitado, no necesitarías todo eso. 2. No necesitas texty eol=lf. eol=lfestablece efectivamente text.
Ben
2
Segundo, lo que dijo @Ben, esta configuración es actualmente incorrecta y peligrosa si no marca explícitamente todos los archivos binarios.
Michael R
1
He leído que * text=auto eol=lfel primero text=autoes anulado por eol=lf. ¿Dónde encontraste esta función? Aquí está mi fuente: stackoverflow.com/questions/29435156/…
CMCDragonkai
Eliminado * text=auto eol=lfdel ejemplo, ya que también se eliminó de Drupal. Considere eliminar los comentarios también.
kenorb
44
Es importante tener en cuenta que lo que dijo @Ben ya no es cierto y siempre fue un error, no un comportamiento intencionado.
Semmel