¿Por qué git no puede hacer restablecimientos duros / suaves por ruta?

138

$ git reset -- <file_path> Se puede restablecer por ruta.

Sin embargo, $ git reset (--hard|--soft) <file_path>informará un error como el siguiente:

Cannot do hard|soft reset with paths.
yao
fuente

Respuestas:

143

Porque no tiene sentido (otros comandos ya proporcionan esa funcionalidad), y reduce la posibilidad de hacer algo incorrecto por accidente.

Acaba de hacer un "restablecimiento git checkout HEAD -- <path>completo " para una ruta (verificando la versión existente del archivo).

Un restablecimiento parcial de una ruta no tiene sentido.

Un restablecimiento mixto para una ruta es lo que git reset -- <path>hace.

Ámbar
fuente
72
Personalmente, creo que git checkout -- <path>debería ser reemplazado por git reset --hard <path>. Tiene mucho más sentido ...
vergenzt
24
git checkout -- <path>no hace un restablecimiento completo; reemplaza el contenido del árbol de trabajo con el contenido en etapas. git checkout HEAD -- <path>realiza un restablecimiento completo para una ruta, reemplazando tanto el índice como el árbol de trabajo con la versión de la confirmación HEAD.
Dan Fabulich
1
@EdPlunkett Er, la segunda oración en la respuesta te dice qué otro comando proporciona la funcionalidad.
Ámbar
16
-1: La comprobación de dicha revisión no eliminará archivos de la copia de trabajo si dicha revisión contiene archivos eliminados. reset --hardcon un camino proporcionaría esta pieza que falta. Git ya es tan poderoso que la excusa "No dejamos que hagas esto por tu propia protección" no tiene agua: hay muchas maneras de hacer lo incorrecto "por accidente". Nada de eso importa de todos modos cuando lo tienes git reflog.
void.pointer
1
como lo menciona @ void.pointer checkout no eliminará archivos. Si quieres ese comportamiento, mira esta respuesta. Aún así, espero que algún día lleguemos git reset --hard -- <path>. Hay casos de uso legítimo para ello.
Mariusz Pawelski
18

Puedes lograr lo que estás tratando de hacer usando git checkout HEAD <path>.

Dicho esto, el mensaje de error proporcionado no tiene sentido para mí (ya que git resetfunciona bien en subdirectorios), y no veo ninguna razón por la git reset --hardque no deba hacer exactamente lo que le está pidiendo.

Aaron Kent
fuente
usando la etapa de pago los cambios, que no es lo mismo que un reinicio --soft
worc
11

La pregunta de cómo ya está respondida , explicaré la parte del por qué .

Entonces, ¿qué hace git reset ? Dependiendo de los parámetros especificados, puede hacer dos cosas diferentes:

  • Si especifica una ruta, reemplaza los archivos coincidentes en el índice con los archivos de una confirmación (HEAD de forma predeterminada). Esta acción no afecta en absoluto el árbol de trabajo y generalmente se usa como lo contrario de git add.

  • Si no especifica una ruta, mueve la cabeza de la rama actual a una confirmación especificada y, junto con eso , opcionalmente restablece el índice y el árbol de trabajo al estado de esa confirmación. Este comportamiento adicional está controlado por el parámetro de modo:
    --soft : no toque el índice ni el árbol de trabajo.
    --mixed (predeterminado): restablece el índice pero no el árbol de trabajo.
    --hard : restablece el índice y el árbol de trabajo.
    También hay otras opciones, consulte la documentación para ver la lista completa y algunos casos de uso.

    Cuando no especifica una confirmación, el valor predeterminado es HEAD, por git reset --softlo que no hará nada, ya que es un comando para mover la cabeza a HEAD (a su estado actual). git reset --hard, por otro lado, tiene sentido debido a sus efectos secundarios , dice mover la cabeza a HEAD y restablecer el índice y el árbol de trabajo a HEAD.

    Creo que ya debería estar claro por qué esta operación no es para archivos específicos por su naturaleza: en primer lugar, está destinada a mover un encabezado de rama, restablecer el árbol de trabajo y el índice es una funcionalidad secundaria.

usuario
fuente
está claro que reset está destinado a mover una cabeza de rama en primer lugar, pero dado que tiene la funcionalidad adicional de restablecer el árbol de trabajo y el índice para confirmaciones completas y la funcionalidad de restablecer el índice para archivos específicos, ¿por qué no lo hace? ¿Tiene la funcionalidad de restablecer el árbol de trabajo para archivos específicos? Creo que eso es lo que pide el OP.
Danilo Souza Morães
¿Tal vez porque esa funcionalidad (restablecer el árbol de trabajo para archivos específicos) ya está disponible como git checkoutcomando? Y hacer un reinicio para hacer lo mismo confundiría aún más a los usuarios. Mi respuesta fue que esa --hardopción no es aplicable a archivos específicos porque es un modo de restablecimiento de rama, no restablecimiento de índice. Y el reinicio del árbol de trabajo se denomina pago, como puede leer en otras respuestas. Todo eso es solo un mal diseño de la interfaz de usuario de Git, en mi humilde opinión.
usuario
¿Comparando la primera opción con git checkout: git reset --establece solo el índice, mientras git checkout --establece solo el árbol de trabajo?
seeker_of_bacon
4

Asegúrese de poner una barra diagonal entre el origen o el flujo ascendente (fuente) y la rama real:

git reset --hard origin/branch

o

git reset --hard upstream/branch`
Pascal Nitcheu
fuente
Por favor lea la pregunta nuevamente.
Xerus
3

Hay una razón muy importante detrás de eso: los principios de checkoutyreset .

En términos de Git, pagar significa "traer al árbol de trabajo actual". Y con git checkoutnosotros podemos llenar el árbol de trabajo con datos de cualquier área, ya sea desde un commit en el repositorio o archivos individuales desde un commit o el área de ensayo (que es el valor predeterminado).

A su vez, git reset no tiene esta función. Como su nombre indica, restablecerá la referencia actual pero siempre tendrá el repositorio como fuente, independientemente del "alcance" (--soft, --mixed o --hard).

Resumen:

  • pago : desde cualquier lugar (confirmación de índice / repositorio) -> árbol de trabajo
  • restablecer : confirmación de repositorio -> Sobrescribir HEAD (y opcionalmente índice y árbol de trabajo)

Por lo tanto, lo que puede ser un poco confuso es la existencia de, git reset COMMIT -- filesya que "sobrescribir HEAD" con solo algunos archivos no tiene sentido.

En ausencia de una explicación oficial, solo puedo especular que los desarrolladores de git descubrieron que resettodavía era el mejor nombre de un comando para descartar los cambios realizados en el área de preparación y, dado que la única fuente de datos era el repositorio, entonces " ampliemos el funcionalidad "en lugar de crear un nuevo comando.

Entonces, de alguna manera git reset -- <files>ya es un poco excepcional: no sobrescribirá el HEAD. En mi humilde opinión, todas esas variaciones serían excepciones. Incluso si podemos concebir una --hardversión, otras (por ejemplo --soft) no tendrían sentido.

F Pereira
fuente
Me gusta esta respuesta Realmente, git reset -- <files>cayó como si se hubiera agregado porque esta es una característica útil, pero nadie estaba seguro de en qué comando se debería poner. Afortunadamente, ahora tenemos mucho más sano git restoreque tiene una funcionalidad git checkout -- <path> git checkout <commit> -- <path>y git reset [<commit>] -- <path>con valores predeterminados mucho más sanos e incluso más funciones que no podía hacer antes (Contrariamente a lo que dice la respuesta aceptada. Ahora finalmente puede restaurar fácilmente el árbol de trabajo, sin tocar el índice).
Mariusz Pawelski
0

Explicación

El git resetmanual enumera 3 formas de invocación:

  • 2 son de archivo: estos no afectan el árbol de trabajo , pero operan solo en los archivos en el índice especificado por <paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 es commit-wise: funciona en todos los archivos de la referencia <commit>y puede afectar el árbol de trabajo:

    • git reset [<mode>] [<commit>]

No hay ningún modo de invocación que funcione solo en archivos específicos y afecte al árbol de trabajo.

Solución alterna

Si quieres ambos:

  • Restablecer la versión de índice / caché de un archivo (s)
  • Verifique los archivos (es decir, haga que el árbol de trabajo coincida con el índice y la versión de confirmación)

Puede usar este alias en su archivo de configuración de git:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

Luego puede hacer uno de:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Mnenonic para reco: reset && check out)

Tom Hale
fuente
-2

git reset --soft HEAD ~ 1 filename deshace la confirmación pero los cambios permanecen en local. nombre de archivo podría ser - para todos los archivos comprometidos

Peiti Li
fuente
66
fatalCannot do soft reset with paths.
alt