¿Por qué hay dos formas de eliminar un archivo en Git?

13 minutos de lectura

avatar de usuario
Sentencia

A veces git sugiere git rm --cached para desorganizar un archivo, a veces git reset HEAD file. ¿Cuándo debo usar cuál?

EDITAR:

D:\code\gt2>git init
Initialized empty Git repository in D:/code/gt2/.git/
D:\code\gt2>touch a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       a
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a
#
D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a

D:\code\gt2>touch b

D:\code\gt2>git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       b
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add b

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

  • ¿Por qué? Diría que es porque la interfaz de línea de comandos de git evolucionó orgánicamente y nunca ha estado sujeta a una reestructuración importante para que las cosas sean consistentes. (Si no está de acuerdo, observe cómo git rm ambos pueden escenario a supresión y también fuera del escenario un suma)

    – Román Starkov

    12 de enero de 2014 a las 14:07


  • @romkyns: Estoy de acuerdo en que la interfaz de Git tiene varias rarezas porque evolucionó orgánicamente, pero una eliminación es sin duda una función inversa de una adición, así que ¿no es lógico para rm deshacer add? Cómo crees que rm ¿debería comportarse?

    – Zaz

    25 de agosto de 2014 a las 20:04

  • La única respuesta real a su pregunta es que justo después de un git init no hay HEAD para restablecer a.

    – Ruta Millas

    2 de diciembre de 2016 a las 0:43

  • Los mejores documentos para esto: help.github.com/articles/cambiando-un-remoto-s-url

    – ScottyBlades

    24/10/2018 a las 20:09

  • @Zaz, daré mi opinión. rm implica eliminación en un contexto Unix. No es lo contrario de agregar al índice. Una función para eliminar archivos no debe sobrecargarse con funciones para cambiar el estado de preparación. Si hay detalles de implementación que hacen que sea conveniente combinarlos, eso simplemente apunta a la falta de una capa reflexiva de abstracción en git, lo que dejaría en claro la usabilidad.

    – Josué Goldberg

    2 mayo 2019 a las 15:30


avatar de usuario
ryan stewart

git rm --cached <filePath> no desescenifica un archivo, en realidad etapas la eliminación de los archivos del repositorio (suponiendo que ya se haya confirmado antes) pero deja el archivo en su árbol de trabajo (dejándolo con un archivo sin seguimiento).

git reset -- <filePath> voluntad fuera del escenario cualquier cambio por etapas para los archivos dados.

Dicho esto, si usaste git rm --cached en un archivo nuevo que está preparado, básicamente parecería que lo acabas de quitar, ya que nunca antes se había confirmado.

Actualizar git 2.24

En esta nueva versión de git puedes usar git restore --staged en vez de git reset. Ver documentos de git.

  • yo diría git rm --cached deshace el archivo pero no lo elimina del directorio de trabajo.

    – Pierre de LESPINAY

    11 de diciembre de 2012 a las 14:46

  • Quitar un archivo preparado para agregarlo de modo que ya no esté preparado seguramente se puede llamar “quitar un archivo preparado para agregarlo”, ¿verdad? el resultado final es no es una eliminación por etapaseso es seguro, por lo que creo que el malentendido es totalmente comprensible.

    – Román Starkov

    12 de enero de 2014 a las 14:16

  • Por lo general, uno usaría git rm --cached <filePath> para eliminar algunos archivos del repositorio después darse cuenta de que nunca debería haber estado en el repositorio: lo más probable es que ejecute este comando y luego agregue los archivos relevantes a gitignore. ¿Estoy en lo correcto?

    – Adrián Be

    2 de marzo de 2016 a las 7:34

  • Con tantos votos tanto en la pregunta como en la respuesta, diría que aparentemente queremos tener una unstage mando en git.

    – milosmns

    20 de marzo de 2019 a las 13:19

  • “git status” aconseja ahora: use “git restore –staged …” para quitar la etapa

    – yucer

    28 de agosto de 2019 a las 11:25


git rm --cached se utiliza para eliminar un archivo del índice. En el caso de que el archivo ya esté en el repositorio, git rm --cached eliminará el archivo del índice, dejándolo en el directorio de trabajo y una confirmación ahora también lo eliminará del repositorio. Básicamente, después de la confirmación, habría desversionado el archivo y conservado una copia local.

git reset HEAD file (que por defecto está usando el --mixed flag) es diferente en el caso de que el archivo ya esté en el repositorio, reemplaza la versión de índice del archivo con la del repositorio (HEAD), eliminando efectivamente el modificaciones lo.

En el caso de un archivo no versionado, se eliminará el archivo completo ya que el archivo no estaba allí en HEAD. En este aspecto git reset HEAD file y git rm --cached son iguales, pero no son iguales (como se explica en el caso de los archivos que ya están en el repositorio)

a la pregunta de Why are there 2 ways to unstage a file in git? – nunca hay realmente una sola forma de hacer algo en git. esa es la belleza de esto 🙂

  • Tanto la respuesta aceptada como esta son excelentes y explican por qué usaría una frente a la otra. Pero no responden directamente a la pregunta implícita de por qué Git sugiere dos métodos diferentes. En el primer caso en el ejemplo del OP, se acaba de hacer un git init. En ese caso, git sugiere “git rm –cached” porque en ese momento no hay confirmaciones en el repositorio y, por lo tanto, HEAD no es válido. “git reset HEAD — a” produce: “fatal: no se pudo resolver ‘HEAD’ como referencia válida”.

    – hollín

    16 de agosto de 2014 a las 13:56


  • con ‘git checkout’, ¿no perdería todos los cambios que realizó en el archivo? Eso no es lo mismo que desmontar un archivo, a menos que esté malinterpretando.

    – John Deighan

    21 de septiembre de 2017 a las 0:33

  • there is never really only one way to do anything in git. that is the beauty of it – Hmm por que ? siempre es genial, cuando solo hay una forma obvia. esto ahorra mucho de nuestro tiempo y memoria en el cerebro))

    –Oto Shavadze

    3 de diciembre de 2019 a las 12:24


avatar de usuario
Waldyrio

Muy simple:

  • git rm --cached <file> hace que git deje de rastrear el archivo por completo (dejándolo en el sistema de archivos, a diferencia del simple git rm*)
  • git reset HEAD <file> anula cualquier modificación realizada en el archivo desde la última confirmación (pero no los revierte en el sistema de archivos, al contrario de lo que podría sugerir el nombre del comando**). El archivo permanece bajo control de revisión.

Si el archivo no estaba en control de revisión antes (es decir, está eliminando un archivo que acababa de git added por primera vez), entonces los dos comandos tienen el mismo efecto, de ahí la apariencia de que estos son “dos formas de hacer algo”.

* Tenga en cuenta la advertencia que @DrewT menciona en su respuesta, con respecto a git rm --cached de un archivo que fue previamente comprometido al repositorio. En el contexto de esta pregunta, de un archivo recién agregado y aún no confirmado, no hay nada de qué preocuparse.

** Tuve miedo durante un tiempo vergonzosamente largo de usar el comando git reset debido a su nombre, y todavía hoy a menudo busco la sintaxis para asegurarme de no equivocarme. (actualizar: Finalmente me tomé el tiempo para resumir el uso de git reset en una pagina tldrasí que ahora tengo un mejor modelo mental de cómo funciona y una referencia rápida para cuando se me olvida algún detalle).

  • Es git rm <file> --cached

    – compañero de neón

    10 de julio de 2015 a las 9:25

  • Realmente no creo que la edición del 4 de agosto de 2015 a esta respuesta haya sido una mejora general. Podría haber corregido la corrección técnica (no me siento calificado para evaluar eso), pero me temo que hizo que el tono de la respuesta fuera mucho menos accesible, al introducir un lenguaje como “deshabilita el imperativo de comenzar a rastrear un archivo actualmente sin rastrear “, y usando jerga como “índice” y “HEAD”, precisamente el tipo de cosas que asustan a los principiantes. Si alguien puede, edite para restaurar un idioma más amigable para los recién llegados.

    – Waldyrious

    12/08/2015 a las 17:50


  • De acuerdo con @waldyrious. Es posible que la respuesta original no haya salido directamente del libro de texto de git, pero respondió la pregunta con un nivel técnico suficiente. Los detalles técnicos deberían haberse aclarado en los comentarios, no como una edición que oscureciera la intención original.

    – Simón Robb

    19 de octubre de 2015 a las 0:38

  • He revertido la edición. Creo que la comunidad ha validado lo suficiente (en los comentarios anteriores y los votos sobre ellos) que la edición fue perjudicial para la claridad de la respuesta.

    – Waldyrious

    26 de julio de 2016 a las 15:52

  • Nota @DrewT advierte que si usa rm --cached y presionando, cualquiera que tire de la misma rama tendrá los archivos eliminados de su árbol de trabajo.

    – Tom Hale

    3 de agosto de 2016 a las 12:57

avatar de usuario
daniel aliso

Este hilo es un poco viejo, pero aún quiero agregar una pequeña demostración ya que todavía no es un problema intuitivo:

me$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   to-be-added
#   modified:   to-be-modified
#   deleted:    to-be-removed
#

me$ git reset -q HEAD to-be-added

    # ok

me$ git reset -q HEAD to-be-modified

    # ok

me$ git reset -q HEAD to-be-removed

    # ok

# or alternatively:

me$ git reset -q HEAD to-be-added to-be-removed to-be-modified

    # ok

me$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   to-be-modified
#   deleted:    to-be-removed
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   to-be-added
no changes added to commit (use "git add" and/or "git commit -a")

git reset HEAD (sin que -q) da una advertencia sobre el archivo modificado y su código de salida es 1, lo que se considerará como un error en un script.

Editar: git checkout HEAD to-be-modified to-be-removed también funciona para anular la puesta en escena, pero elimina el cambio por completo del espacio de trabajo

Actualizar git 2.23.0: De vez en cuando, los comandos cambian. Ahora, git status dice:

  (use "git restore --staged <file>..." to unstage)

… que funciona para los tres tipos de cambio

avatar de usuario
ives

Si accidentalmente ha preparado archivos que no le gustaría confirmar y quiere asegurarse de mantener los cambios, también puede usar:

git stash
git stash pop

esto realiza un restablecimiento a HEAD y vuelve a aplicar sus cambios, lo que le permite volver a organizar archivos individuales para la confirmación. esto también es útil si olvidó crear una rama de función para solicitudes de extracción (git stash ; git checkout -b <feature> ; git stash pop).

  • Esta es una solución limpia y mucho menos preocupante que escribir “git rm”

    – Subimagen

    18 de julio de 2017 a las 21:47

  • git stash tiene otros beneficios relacionados, porque crea entradas en el registro de referencia que luego están disponibles en el futuro. en caso de duda, siga adelante y haga una git stash (p.ej git stash save -u "WIP notes to self" (el ‘-u’ es para incluir cualquier archivo nuevo/sin seguimiento en la confirmación oculta) … luego intente git reflog show stash para ver la lista de confirmaciones de almacenamiento y sus sha. Recomiendo un alias de shell como alias grs="git reflog show stash"

    – cada semana

    12 de febrero de 2019 a las 18:32

Estos 2 comandos tienen varias diferencias sutiles si el archivo en cuestión ya está en el repositorio y bajo control de versión (previamente confirmado, etc.):

  • git reset HEAD <file> deshace el archivo en la confirmación actual.
  • git rm --cached <file> también eliminará el archivo para futuras confirmaciones. No está organizado hasta que se vuelve a agregar con git add <file>.

Y hay una diferencia más importante:

  • despues de correr git rm --cached <file> y empuje su rama al control remoto, cualquier persona que extraiga su rama del control remoto obtendrá el archivo REALMENTE eliminado de su carpeta, aunque en su conjunto de trabajo local el archivo simplemente no se rastrea (es decir, no se elimina físicamente de la carpeta).

Esta última diferencia es importante para los proyectos que incluyen un archivo de configuración en el que cada desarrollador del equipo tiene una configuración diferente (es decir, una configuración de puerto, IP o URL base diferente), por lo que si está utilizando git rm --cached <file> cualquiera que extraiga su rama tendrá que volver a crear manualmente la configuración, o puede enviarles la suya y pueden volver a editarla a su configuración de IP (etc.), porque la eliminación solo afecta a las personas que extraen su rama desde el control remoto .

  • Esta es una solución limpia y mucho menos preocupante que escribir “git rm”

    – Subimagen

    18 de julio de 2017 a las 21:47

  • git stash tiene otros beneficios relacionados, porque crea entradas en el registro de referencia que luego están disponibles en el futuro. en caso de duda, siga adelante y haga una git stash (p.ej git stash save -u "WIP notes to self" (el ‘-u’ es para incluir cualquier archivo nuevo/sin seguimiento en la confirmación oculta) … luego intente git reflog show stash para ver la lista de confirmaciones de almacenamiento y sus sha. Recomiendo un alias de shell como alias grs="git reflog show stash"

    – cada semana

    12 de febrero de 2019 a las 18:32

avatar de usuario
DEEPAK

En la versión más nueva que es> 2.2 puede usar git restore --staged <file_name>. Tenga en cuenta aquí que si desea eliminar (mover a los cambios) sus archivos uno a la vez, use el comando anterior con su nombre de archivo. p.ej

git restore --staged abc.html

Ahora, si desea eliminar todo su archivo a la vez, puede hacer algo como esto

git restore --staged .

tenga en cuenta espacio y punto (.) lo que significa que se considerarán preparados todos los archivos.

¿Ha sido útil esta solución?