¿Puede git ignorar una línea específica?

114

Estoy usando git para sincronizar con phonegap mientras pruebo en el navegador nativo del teléfono. Como tal, tengo la siguiente línea:

var isPhoneGap = false;

Obviamente, cambio esto al compilar, pero ¿hay alguna forma de configurar git para ignorar esta línea o tengo que ir y ponerlo en su propio archivo e ignorarlo de esa manera?

Estoy usando Gitx y el terminal en OSX 10.6.

Iolo
fuente
@ user494461: Los filtros de Git son la forma de hacerlo: stackoverflow.com/a/16244970/520162
eckes
1
¿No puede detectar el entorno y utilizar un archivo de configuración de entorno?
exussum
En resumen: No. Pero he escrito un script de preprocesador que busca cierto código comentado y lo elimina antes de publicarlo en git. Échale un vistazo aquí: github.com/franklinchou/ahk_config/blob/master/preprocess.sh
franklin

Respuestas:

103

Si su archivo es de un tipo específico, puede declarar un controlador de filtro de contenido , que puede declarar en un .gitattributesarchivo (como se presenta en la "Expansión de palabras clave" de " Atributos de Git "):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(incluso puede configurar ese filtro para un archivo específico , si lo desea)

Implementar:

  • yourFilterName.smudge(activado git checkout) y

    git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(activado git add)

    git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

Su archivo aparecería sin cambios git status, pero su versión extraída tendría el valor correcto para isPhoneGap.

VonC
fuente
1
Gracias por esto. lo tengo funcionando. ¿Sabes cómo hacer git diff or git status`, pero ignoras los filtros? ¿Entonces todavía puedo ver qué es diferente? Mi caso de uso es para los registros de depuración ... que eventualmente quiero eliminar ... @jthill @VonC
timh
1
@timh si el filtro está funcionando, git status o git diff no deberían mostrar nada.
VonC
1
Es una pena que no haya una forma más sencilla en GIT. git ignore <filename> <linenumber> ¡sería muy útil!
kiedysktos
22
@kiedysktos linenumber? ¿Qué pasa si cambia el número de línea?
VonC
Esto funcionó muy bien, pero los usuarios de Windows tengan cuidado, el gitconfig es muy exigente con los caracteres que quiere contener, por lo que al probar algunas expresiones regulares semi-exóticas, puede tener problemas. Terminé poniendo mis llamadas sed en un archivo helper.sh separado que llamé desde mi gitconfig sh ".git/helper.sh"asegurándome de pasar cualquier parámetro a sed con "$@"(supongo que solo se pasa la ruta del archivo).
ohaal
43

Puedes usar

git update-index --assume-unchanged [file]

para ignorar los cambios de un archivo del que no desea realizar un seguimiento. Utilizo esta solución cuando necesito tener un archivo en el repositorio, pero este archivo tiene algunas partes que cambian que no necesito rastrear siempre.

Cuando el archivo tiene cambios que son importantes, debe hacer esto:

git update-index --no-assume-unchanged [file]

También, ver el Git Doc actualización de índice de --[no-]assume-unchangedparámetro.

Cuando se especifican estos indicadores, los nombres de objeto registrados para las rutas no se actualizan. En cambio, estas opciones activan y desactivan el bit "asumir sin cambios" para las rutas. Cuando el bit "asumir sin cambios" está activado, git deja de comprobar los archivos del árbol de trabajo en busca de posibles modificaciones, por lo que debe desarmar manualmente el bit para decirle a git cuando cambie el archivo del árbol de trabajo.

Carlos
fuente
2
¿Hacer esto todavía traerá la nueva versión cuando haga git pull?
Saad Rehman Shah
1
@Caffeine cuando haces git pull, obtienes la última versión que se comprometió, esta será la última antes de cambiar a '--assume-sin cambios' el archivo.
Carlos
1
Creo que --skip-worktreees una mejor opción para la mayoría de los propósitos. stackoverflow.com/a/39583010/4233593
Jeff Puckett
3
esto ignora las actualizaciones de todo el archivo, no de una línea específica
Nikoss
6

Gitx debería permitirte cometer o ignorar líneas individuales (es posible que ya lo sepas), pero tendrías que hacerlo cada vez que confirmes. Creo que sería mejor tener un archivo de configuración por destino de implementación (puede versionarlos) y algún parámetro de tiempo de ejecución para la forma en que esté iniciando el servidor (como ./myserver --config=whatever.js).

Andy Ray
fuente
5

Continuando con https://stackoverflow.com/a/20574486/4935114 , @Mike propuso crear un pre-commitgancho que se incluirá grepen los archivos organizados para las líneas que uno podría querer ignorar. El gancho comprueba si esas líneas se organizaron. Si es así, echoes una advertencia y exitestá con código, 1por lo que el proceso de confirmación no continuará.

Inspirado por la respuesta de @ Mike , me encontré usando quizás una versión mejorada de su gancho que automáticamente reset envía (con la -pbandera) la línea específica que queremos ignorar.

No estoy seguro de que este gancho funcione para una situación en la que tiene muchos archivos con esta línea para ignorar, pero este pre-commitgancho busca un cambio en esta línea en un archivo específico buildVars.java. El script de gancho se veía así cuando lo probé en mi máquina.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Explicación

Lo que hice fue repetir una secuencia de control que busca la expresión regular isPhoneGapdurante un resetproceso interactivo . Así emulando a un usuario que presiona /para buscar isPhoneGap, presiona ycuando se le pregunta si quiere descartar este parche y finalmente presiona qpara salir del interactivo reset.

El proceso de parche inverso interactivo se documenta aquí: https://git-scm.com/docs/git-add#git-add-patch


NOTA: El script anterior asumiendo que la variable interactive.singleKeyes false. Si configuró el suyo para true, elimine cualquiera $'\n'del echocomando justo después de la advertencia.

Doron Behar
fuente
3

Así es como puedes hacerlo con filtros git :

  1. Crear / Abrir archivo gitattributes:
    • <raíz del proyecto> /. gitattributes (se confirmará en el repositorio)
      O
    • <proyecto raíz> /. git / info / atributos (no se confirmará en el repositorio)
  2. Agregue una línea que defina los archivos que se filtrarán:
    • *.rb filter=gitignore, es decir, ejecutar el filtro nombrado gitignoreen todos los *.rbarchivos
  3. Defina el gitignorefiltro en su gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d", es decir, elimine estas líneas
    • $ git config --global filter.gitignore.smudge cat, es decir, no hacer nada al extraer el archivo del repositorio

Notas:
Por supuesto, esto es para archivos ruby, aplicado cuando una línea termina con #gitignore, aplicado globalmente en ~/.gitconfig. Modifique esto como necesite para sus propósitos.

¡¡Advertencia!!
Esto deja su archivo de trabajo diferente del repositorio (por supuesto). ¡Cualquier comprobación o rebase significará que estas líneas se perderán! Este truco puede parecer inútil ya que estas líneas se pierden repetidamente en el check out, rebase o pull, pero tengo un caso de uso específico para hacer uso de él.

Solo git stash save "proj1-debug" mientras el filtro está inactivo (simplemente desactívelo temporalmente gitconfigo algo así). De esta manera, mi código de depuración siempre se puede git stash applyagregar a mi código en cualquier momento sin temor a que estas líneas se confirmen accidentalmente.

Tengo una posible idea para solucionar estos problemas, pero intentaré implementarla en otro momento.

Gracias a Rudi y jw013 por mencionar filtros git y gitattributes.

Kache
fuente
2

Un controlador de filtro de contenido no es una buena solución. Es posible que pueda ocultar esta línea de git status/ etc, pero en realidad no se ignora. Tan pronto como cambie el valor, su directorio de trabajo se marcará como sucio aunque el cambio no sea visible.

Si realmente desea que esta línea esté fuera del control de versiones, cambiarla a un argumento de línea de comando o colocarla en un archivo de inclusión o compilación ignorado puede ser el único medio práctico.

patricktokeeffe
fuente
"Tan pronto como cambie el valor, su directorio de trabajo se marcará como sucio aunque el cambio no sea visible": no debería hacerlo, si el script limpio aún restaura el archivo en su contenido original.
VonC
Eso es lo que había pensado. Estoy usando GitExtensions y mostrará el archivo como modificado incluso aunque el panel de diferencias esté en blanco. Posiblemente porque el filtro limpio no se ejecuta hasta el registro del archivo. Posiblemente porque es msysgit, no git-git. IDK, YMMV
patricktokeeffe
1

Supongo que esto podría ser algo que aparezca en más de una línea de su fuente.

Creo que sería más limpio tener un archivo .userbuildconfig de algún tipo que solo incluya y tenga los valores predeterminados registrados. Entonces puede usar la sugerencia de Carlos de marcar ese archivo solo como asumir sin cambios. De esta manera, no se perderán otros cambios en el archivo donde necesita verificar la configuración.

Esto puede permitirle ajustar las macros del preprocesador localmente (o para java algo como esto https://stackoverflow.com/a/1813873/1270965 ).

johnb003
fuente
-1

No Solo puede ignorar archivos individuales (y más) ya que las líneas en .gitignore coinciden con los nombres de los archivos y no con el contenido del archivo. Ya ha mencionado la solución a esto, es decir, ignore un solo archivo que contiene ese contenido que desea ignorar.

ralphtheninja
fuente
Estoy de acuerdo, en mi caso fue suficiente y posible simplemente incluir ese contenido de un archivo ignorado. Así que moviendo todos los ajustes ignorables. ahí. Además, creé una copia de ese archivo ignorado y lo agregué al índice como referencia, por lo que la información sobre lo que habrá en ese archivo no se perderá.
Urs