2009-07-07 20 views
228

Por lo que entiendo, Git realmente no necesita rastrear archivo renombrar/mover/copiar operaciones, entonces ¿cuál es el verdadero propósito de git mv? La página de manual no es especialmente descriptiva ...¿Cuál es el propósito de git-mv?

¿Está obsoleto? ¿Es un comando interno, no destinado a ser utilizado por usuarios regulares?

Respuesta

300
git mv oldname newname 

es sólo la abreviatura de:

mv oldname newname 
git add newname 
git rm oldname 

es decir, se actualiza el índice para los dos caminos antiguos y nuevos de forma automática.

+29

También tiene algunas seguridades integradas. –

+4

Gracias @CharlesBailey - ¿Git considera los archivos newNameFile y oldNameFile como diferentes? En caso afirmativo, ¿qué sucede si queremos fusionarlos? Supongamos que ramificamos un proyecto de una hormiga en la rama A y creamos la Rama B y luego mavenizamos los proyectos en B. Los nombres de los archivos son los mismos, pero se ponen diferentes caminos a medida que cambia la estructura del proyecto. Supongamos que ambas ramas crecieron durante un tiempo en paralelo. En algún momento, si queremos fusionar los proyectos, ¿cómo sabrá git que es el mismo archivo que acaba de renombrar su ruta?(si "git mv" == "git add + git rm") – Rose

+0

Supongo que es lo mismo con un 99.9999% de probabilidad. Obviamente, la autodetección podría salir mal si tiene, por ejemplo, múltiples archivos con el mismo nombre y/o el mismo contenido. – osa

59

Desde el official GitFaq:

Git tiene un comando de cambio de nombre git mv, pero eso es sólo una conveniencia. El efecto es indistinguible de la eliminación del archivo y la adición de otro con diferente nombre y el mismo contenido

+6

Entonces, ¿pierde el historial de archivos? Se suponía que cambiar el nombre mantendría la historia anterior de ese directorio ... –

+14

Bueno, sí y no. Lea el enlace oficial de GitFaq anterior sobre los cambios de nombre, y luego lea el extenso correo electrónico de Linus Torvald sobre por qué no le gusta la idea de una herramienta de SCM que rastrea archivos: http://permalink.gmane.org/gmane.comp.version- control.git/217 –

+2

@WillHancock He usado git un poco más ahora, y puedo responderte de manera más definitiva: dependiendo de tu cliente de git y sus opciones, podrás rastrear el archivo más allá del cambio de nombre si el archivo cambió internamente poco lo suficiente como para considerarlo un cambio de nombre. Sin embargo, si cambia el archivo demasiado Y le cambia el nombre, git no lo detectará, en cierto sentido dice "¡no, también podría considerar que es un archivo completamente diferente!" –

18

Como dice @Charles, git mv es una taquigrafía.

La verdadera pregunta aquí es "Otros sistemas de control de versiones (por ejemplo, Subversion y Perforce) tratan especialmente los nombres de los archivos modificados. ¿Por qué Git no?"

Linus explica en http://permalink.gmane.org/gmane.comp.version-control.git/217 con tacto característico:

Por favor, deja este "archivos de la pista" porquería. Git rastrea exactamente lo que importa, a saber, "colecciones de archivos". Nada más es relevante, e incluso pensando que es relevante solo limita su visión del mundo. Observe cómo la noción de "anotar" de CVS siempre inevitablemente limita la forma en que las personas usan . Creo que es una porquería totalmente inútil, y describí algo que creo que es un millón de veces más útil, y todo se cayó exactamente porque no estoy limitando mi pensamiento al modelo incorrecto del mundo.

+0

¿Tienes un espejo para ese enlace? Está roto ahora. – cjm

+4

Pruebe https://web.archive.org/web/20160304045715/http://permalink.gmane.org/gmane.comp.version-control.git/217 –

25

Git solo intenta adivinar lo que intenta hacer. Está haciendo todo lo posible para preservar la historia ininterrumpida. Por supuesto, no es perfecto. Entonces, git mv le permite ser explícito con su intención y evitar algunos errores.

Considere este ejemplo. A partir de un repo vacío,

git init 
echo "First" >a 
echo "Second" >b 
git add * 
git commit -m "initial commit" 
mv a c 
mv b a 
git status 

Resultado:

# 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: a 
# deleted: b 
# 
# Untracked files: 
# (use "git add <file>..." to include in what will be committed) 
# 
# c 
no changes added to commit (use "git add" and/or "git commit -a") 

detección automática no :( O lo hizo?

$ git add * 
$ git commit -m "change" 
$ git log c 

commit 0c5425be1121c20cc45df04734398dfbac689c39 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:24:56 2013 -0400 

    change 

y luego

$ git log --follow c 

Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:24:56 2013 -0400 

    change 

commit 50c2a4604a27be2a1f4b95399d5e0f96c3dbf70a 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:24:45 2013 -0400 

    initial commit 

Ahora intenta lugar (recuerde que debe eliminar la carpeta .git al experimentar):

git init 
echo "First" >a 
echo "Second" >b 
git add * 
git commit -m "initial commit" 
git mv a c 
git status 

Hasta aquí todo bien:

# On branch master 
# Changes to be committed: 
# (use "git reset HEAD <file>..." to unstage) 
# 
# renamed: a -> c 


git mv b a 
git status 

Ahora nobo dy es perfecto:

# On branch master 
# Changes to be committed: 
# (use "git reset HEAD <file>..." to unstage) 
# 
# modified: a 
# deleted: b 
# new file: c 
# 

¿Realmente? Pero, por supuesto ...

git add * 
git commit -m "change" 
git log c 
git log --follow c 

... y el resultado es el mismo que el anterior: sólo se --follow muestra el historial completo.


Ahora, tener cuidado con el cambio de nombre, como cualquiera de las opciones todavía puede producir efectos extraños. Ejemplo:

git init 
echo "First" >a 
git add a 
git commit -m "initial a" 
echo "Second" >b 
git add b 
git commit -m "initial b" 

git mv a c 
git commit -m "first move" 
git mv b a 
git commit -m "second move" 

git log --follow a 

commit 81b80f5690deec1864ebff294f875980216a059d 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:35:58 2013 -0400 

    second move 

commit f284fba9dc8455295b1abdaae9cc6ee941b66e7f 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:34:54 2013 -0400 

    initial b 

contraste con:

git init 
echo "First" >a 
git add a 
git commit -m "initial a" 
echo "Second" >b 
git add b 
git commit -m "initial b" 

git mv a c 
git mv b a 
git commit -m "both moves at the same time" 

git log --follow a 

Resultado:

commit 84bf29b01f32ea6b746857e0d8401654c4413ecd 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:37:13 2013 -0400 

    both moves at the same time 

commit ec0de3c5358758ffda462913f6e6294731400455 
Author: Sergey Orshanskiy <*****@gmail.com> 
Date: Sat Oct 12 00:36:52 2013 -0400 

    initial a 

Ups ... Ahora la historia va de nuevo a sus iniciales en un lugar deinicial b, lo cual es incorrecto. Entonces, cuando hicimos dos movimientos a la vez, Git se confundió y no siguió los cambios correctamente. Por cierto, en mis experimentos sucedió lo mismo cuando borré/creé archivos en lugar de usar git mv. Proceda con cuidado; usted ha sido advertido ...

+3

+1 para obtener una explicación detallada. He estado buscando problemas que podrían suceder en el historial de registros si los archivos se movieron en git, tu respuesta fue realmente interesante. ¡Gracias! Por cierto, ¿conoce algún otro inconveniente que deberíamos evitar al mover archivos en git? (o cualquier referencia que pueda señalar .... no muy afortunado buscando en Google) – pabrantes

+1

Bueno, mis ejemplos son pesimistas. Cuando los archivos están vacíos, es mucho más difícil interpretar correctamente los cambios. Me imagino que si te comprometes después de cada conjunto de cambios de nombre, estarás bien. – osa

6

Hay otro uso que tengo para git mv no mencionado anteriormente.

Desde que descubrí git add -p (modo de parche de git add; consulte http://git-scm.com/docs/git-add), me gusta usarlo para revisar los cambios cuando los agrego al índice. Por lo tanto, mi flujo de trabajo se convierte en (1) trabajar en el código, (2) revisar y agregar al índice, (3) confirmar.

¿Cómo encaja git mv? Si se mueve un archivo directamente y luego usando git rm y git add, todos los cambios se agregan al índice, y usar git diff para ver los cambios es menos fácil (antes de confirmar). Sin embargo, al usar git mv, se agrega la nueva ruta al índice, pero no los cambios realizados en el archivo, lo que permite que git diff y git add -p funcionen de la forma habitual.

Cuestiones relacionadas