Git agrega líneas específicas no interactivamente

7 minutos de lectura

avatar de usuario
irbanana

Yo quiero git add solo un rango específico de líneas de un archivo con un solo comando de shell. Estoy imaginando algo como:

git add -c [email protected]

yo no quiero usar git add -i, git add -po git -e (herramientas git interactivas) porque mi archivo es grande y tiene muchos cambios, y ya sé exactamente qué líneas quiero. Por el bien del argumento (¿entiendes?), digamos que quiero escenificar líneas inclusivamente 123-204 de un archivo de 2000 líneas myfile.go.

yo tampoco quiero para usar una GUI. O mi computadora es demasiado vieja para los nuevos programas, demasiado lenta para ejecutarlos, la pantalla es demasiado pequeña… lo que sea. Todo lo anterior. interfaz gráfica de usuario de Github, Árbol fuenteun (Atom|IntelliJ|VSC|.* complemento, KDiff, Kaleidescope… están todos fuera.

Se puede hacer?

Puntos extra: ¿se puede hacer para varios archivos a la vez?

Para referencia:

dos relacionados, pero no duplicado, preguntas. Tampoco se ajusta a mis necesidades:

  • Enviar líneas específicas de un archivo a git
  • Confirmar solo una parte de un archivo en Git
    • Este comentario me hace pensar que se puede hacer… Confirmar solo una parte de un archivo en Git

Documentación de Git que está cerca, pero no cigarro:

  • Creo que tienes que aceptar eso: el parche es lo más cercano que estás recibiendo jajaja

    – L_Iglesia

    31 de mayo de 2018 a las 14:53

  • Entonces, las herramientas como Sourcetree en realidad tienen que pasar por al menos 4 pasos diferentes de git y/o manipulación de archivos para solo organizar un mísero trozo.

    – irbanana

    31 de mayo de 2018 a las 14:54

  • Pero mi fiel TI-86 me ha llevado tan lejos… No puedo dejarlo ahora.

    – irbanana

    31 de mayo de 2018 a las 14:59

  • Lo más probable es que necesite buscar un comando de “plomería” (manipulación de estructura de datos de bajo nivel) en lugar de un comando de “porcelana” (control de versión de alto nivel).

    – IMSoP

    31 de mayo de 2018 a las 16:33

  • Si puede construir un archivo de parche con las líneas requeridas, git apply --cached organizará esos cambios sin tocar el árbol de trabajo. los implementación de git add --interactive parece estar escrito en Perl, y funciona de esa manera bajo el capó. Por lo que puedo ver, el enfoque que toma es tomar secciones de un parche (git diff salida, esencialmente), luego reconstruya las partes requeridas en un nuevo archivo de parche manipulando las líneas de encabezado/contexto.

    – IMSoP

    31 de mayo de 2018 a las 16:51

A partir de los comentarios, no está claro si le preocupa la eficiencia de ejecutar la operación de agregar, la escritura que se debe hacer para indicar a las herramientas qué hacer, o ambas cosas.

No me preocuparía por lo primero; y si tu son preocupado por eso, no hay mucho que puedas hacer de todos modos. Hay más pasos de los que podría pensar que son razonables, e implican procesar todo el archivo; pero en realidad, no importa, ya que nunca he visto que una operación de preparación de un solo archivo tome el tiempo suficiente para preocuparme por eso.

En cuanto a la cantidad de tipeo involucrado, el add las opciones que enumeró son el soporte integrado más cercano git ofertas Así que puedes hacer un poco de secuencias de comandos para aumentarlos. Pero no será fácil asegurarse de que siempre “haga las cosas bien”.

En particular, es más complicado de lo que te imaginas definir “los cambios en este rango de líneas”. El problema aparentemente obvio es que las adiciones y eliminaciones de líneas cambian los números de línea de las líneas que ocurren después de ellas; pero probablemente pueda resolverlo definiendo su rango de números de línea en términos de trabajo actual versión del archivo (ya que eso es lo que uno probablemente estaría viendo más recientemente al determinar el rango de números de línea)…

Pero el mayor problema es detectar el caso en el que se editaron todas las líneas de un rango, y ese rango se superpone al final del rango de líneas para las que está organizando cambios. Por ejemplo, suponga que tiene el archivo

1
2
3
4
5

en el índice, y su copia de trabajo dice

1
2
3 THREE
4 FOUR
5 FIVE

Ahora especifica que desea organizar los cambios de las líneas 2-4.

El parche se verá como

@@ -1,5 +1,5 @@
 1
 2
-3
-4
-5
+3 THREE
+4 FOUR
+5 FIVE

Y está bastante claro que en este caso el resultado intuitivo es

1
2
3 THREE
4 FOUR
5

Pero escribir código que haga esto “correcto” sin que otros casos sean “incorrectos” (en relación con una interpretación igualmente intuitiva) no es tan fácil. A veces realmente está abierto a la interpretación. “¿Fue esta una operación que cambió tres líneas? ¿O una operación que eliminó tres líneas, seguida de tres operaciones en las que cada una agregó una línea? O…”

Las herramientas automatizadas en git evitan tomar esas decisiones interpretativas, primero mirando el código en trozos de cambio (en lugar de rangos de líneas arbitrarios) y haciéndote intervenir manualmente si quieres algo diferente (es decir, usando el modo de edición de parches); y luego insertando marcadores de conflicto (y nuevamente requiriendo intervención manual) cuando todavía parece que se requiere interpretación.

Básicamente, debe hacer suposiciones simplificadas para crear una herramienta y asegurarse de que esas suposiciones sean válidas al usar la herramienta.

Entonces, la idea sería crear un script que lea el parche del archivo nombrado por su primer argumento y edite el parche en su lugar; y configure ese script como el editor (es decir, configurando el GIT_EDITOR variable de entorno) cuando se ejecuta git add -e. Usarías líneas de la forma @@ -#,# +#,# @@ para averiguar los números de línea afectados por un cambio, use esa información (y sus suposiciones) para decidir si desea mantener o descartar una línea de cambio determinada, y si desea descartarla

  • si la línea comienza con -cambiar el - a un
  • si la línea comienza con +elimine la línea

  • El parche en su ejemplo sería la diferencia y no el parche para la línea de etapa 2-4 a menos que esté malinterpretando algo.

    – CervEd

    13 de marzo de 2021 a las 19:57

avatar de usuario
CervEd

He investigado esto pero no extensamente. Mi entendimiento es que la manera git add -p funciona generando parches, proporcionando una interfaz intuitiva para editarlos y luego aplicarlos.

Podrías hacer este proceso tú mismo.

Los cambios en su árbol de trabajo son proporcionados por git diff. Estos son cambios que se pueden aplicar a su índice como un parche usando git apply

Entonces, en lugar de git add . podrías correr

git diff . | git apply - --cached

Es decir. obtenga todas las diferencias en su árbol de trabajo en el directorio actual y aplíquelas todas al índice.

Entonces, lo que podría hacer es modificar la salida del diff usted mismo y producir un parche diferente antes de aplicarlo, usando secuencias de comandos o cualquier método.

Puede ser que el proceso de modificar esto usando secuencias de comandos sea más complicado que optar por un git add -e o git add -p solución pero por lo que entiendo, esta es la forma de abordar el problema si desea resolverlo de manera diferente.

Apéndice:

Esto es básicamente exactamente lo que hacen los comandos git interactivos, usando scripts perl. Crea archivos diff fragmentados, luego los abre en $EDITOR. Es importante destacar que corrige automáticamente el formato de diferencia después de que haya realizado la modificación (muy molesto para hacerlo usted mismo), porque el resumen de línea se encuentra en la parte superior de una diferencia. ++ XYZ / -- zyx debe ser correcto para que se aplique el parche.

No recuerdo qué comando ejecuta el script perl para fragmentar la diferencia, pero está en alguna parte.

Si tuviera que resolver este problema hoy, probablemente generaría las diferencias fragmentadas. Eliminar los que están fuera de la línea. Después git appy foo.diff --cached && git restore --staged foo.diff && git add -p.

¿Ha sido útil esta solución?