¿Por qué `git checkout <branch> <file>` escenifica el cambio?

Si comienzo desde un tree de trabajo limpio y ejecuto git checkout <branch> <file> , donde <branch> tiene una versión diferente de este file, termino con un cambio por etapas en lugar de un cambio de escenario.

¿Cuál es el motivo de esto? ¿Esto es solo por coinheritance con otros commands como git mv , que esperarías realizar cambios? ¿Es por conveniencia cuando se usa git checkout para resolver conflictos de combinación? ¿O hay alguna otra razón?

Me parece algo extraño porque el solo hecho de usar git checkout <branch> <file> no ofrece ninguna indicación de si planeo comprometer el cambio.

En realidad, es un detalle de implementación que los autores de Git eligieron para mostrarse.

Git no puede, o mejor dicho, en un punto, no leer los files directamente del repository en el tree de trabajo. Tiene (o tuvo) que pasarlos primero por un intermediario: tenía que copyrlos, o al less sus statistics vitales, 1 en otro lugar. Solo entonces pudo Git copyr los datos en un file de tree de trabajo. 2 El "otro lugar" es una input de índice . El índice también se llama área de ensayo.

Cuando git checkout un commit completo, esto es lo que quieres de todos modos. Entonces, la limitación interna, de copyr al índice primero y solo después al tree de trabajo, en realidad era una ventaja. Entonces, este mecanismo, de copyr en el índice primero, y solo luego en el tree de trabajo, se incrustó en la implementación. Luego, eventualmente, el front end de git checkout orientado al usuario obtuvo la capacidad de verificar un file individual, o un pequeño subset de files … y continuó haciéndolo a través del índice. El detalle de la implementación se convirtió en una característica documentada.

Tenga en count que a veces, el índice está en uso como área auxiliar durante una fusión conflictiva. En este caso, para algunos files F , hay hasta tres inputs, en las ranuras numeradas 1 (base), 2 ( --ours ) y 3 ( --theirs ), en lugar de solo una input en la ranura normal – cero . Cuando esto es así, puede extraer cualquiera de las tres inputs de ranuras de índice al tree de trabajo sin alterar el índice. Pero si usa git checkout para extraer un file de otro commit-o-tree, Git copy el file en el índice, escribiéndolo en el slot cero. ¡Esto tiene el efecto secundario de eliminar las ranuras con numbers más altos, resolviendo el conflicto de fusión!


1 El principal es la identificación hash. Como ElpieKay notó en un comentario , Git tiene que resolver el hash de confirmación de un hash de tree, luego search en los diversos treees para encontrar el / los file / s de interés, de modo que pueda get el hash blob. Sin embargo, la input del índice también tiene muchos más datos, incluidos los datos de la estructura stat para el file del tree de trabajo, para hacer que Git vaya rápido.

2 Aún puede usar este flujo de trabajo, usando git read-tree para copyr un tree en el índice, luego usando git checkout-index para copyr el índice al tree de trabajo. Originalmente, Git consistía en un set de scripts de shell como git-checkout envuelto alnetworkingedor de algunas piezas fundamentales codificadas en C como git-read-tree . (Todos los nombres estaban divididos en guiones como este y no había ningún command de input git ).