Para ampliar la respuesta de Ben Jackson , que está bien, veamos de cerca la pregunta original. (Vea su respuesta para saber por qué molestarse en escribir preguntas; esto es más sobre lo que está sucediendo ).
Soy nuevo en el control de versiones y entiendo que "comprometerse" es esencialmente crear una copia de seguridad mientras se actualiza la nueva versión "actual" de lo que está trabajando.
Esto no es del todo correcto. Las copias de seguridad y el control de versiones están ciertamente relacionados (exactamente qué tan fuertemente depende de algunas cosas que son hasta cierto punto cuestiones de opinión) pero ciertamente hay algunas diferencias, aunque solo sea en la intención: las copias de seguridad generalmente están diseñadas para la recuperación de desastres (la máquina falla, el fuego destruye Todo el edificio incluyendo todos los medios de almacenamiento, etc.). El control de versiones generalmente está diseñado para interacciones más detalladas y ofrece características que las copias de seguridad no ofrecen. Normalmente, las copias de seguridad se almacenan durante algún tiempo y luego se descartan como "demasiado antiguas": una copia de seguridad más actualizada es lo único que importa. El control de versiones normalmente guarda todas las versiones comprometidas para siempre.
Lo que no entiendo es para qué es la puesta en escena desde una perspectiva práctica. ¿Es la puesta en escena algo que existe solo de nombre o tiene un propósito? Cuando te comprometes, va a comprometer todo de todos modos, ¿verdad?
Si y no. El diseño de Git aquí es algo peculiar. Existen sistemas de control de versiones que no requieren un paso de preparación por separado. Por ejemplo, Mercurial, que por lo demás se parece mucho a Git en términos de uso, no requiere un hg addpaso aparte , más allá del primero que introduce un archivo completamente nuevo. Con Mercurial, usas el hgcomando que selecciona alguna confirmación, luego haces tu trabajo, luego corres hg commity listo. Con Git, usas git checkout, 1 , luego haces tu trabajo, luego corres git addy luego git commit. ¿Por qué el git addpaso extra ?
El secreto aquí es lo que Git llama, de diversas formas, el índice o el área de preparación , o algunas veces, raramente en estos días, el caché . Todos estos son nombres para lo mismo.
Editar: Creo que puedo estar confundiendo la terminología. ¿Un archivo 'preparado' es lo mismo que un archivo 'rastreado'?
No, pero estos están relacionados. Un archivo de seguimiento es uno que existe en el índice de Git. Para comprender correctamente el índice, es bueno comenzar por comprender las confirmaciones.
Desde la versión 2.23 de Git, puede usar en git switchlugar de git checkout. Para este caso particular, estos dos comandos hacen exactamente lo mismo. El nuevo comando existe porque git checkoutse sobrecargó con demasiadas cosas; se dividieron en dos comandos separados git switchy git restore, para que sea más fácil y seguro usar Git.
Compromete
En Git, una confirmación guarda una instantánea completa de cada archivo que Git conoce. (¿Qué archivos conoce Git? Lo veremos en la siguiente sección). Estas instantáneas se almacenan en una forma especial, de solo lectura, solo de Git, comprimida y deduplicada, que en general solo Git puede leer . (Hay más cosas en cada confirmación que solo esta instantánea, pero eso es todo lo que cubriremos aquí).
La deduplicación ayuda con el espacio: normalmente solo cambiamos algunos archivos, luego hacemos una nueva confirmación. Entonces, la mayoría de los archivos de una confirmación son en su mayoría los mismos que los archivos de la confirmación anterior. Simplemente reutilizando esos archivos directamente, Git ahorra mucho espacio: si solo tocamos un archivo, la nueva confirmación solo ocupa espacio para una nueva copia. Incluso entonces está comprimido, a veces muy comprimido, aunque en realidad esto sucede más tarde, de modo que un .gitdirectorio puede ser más pequeño que los archivos que contiene, una vez que se expanden a archivos normales de uso diario. La deduplicación es segura porque los archivos comprometidos se congelan para siempre. Nadie puede cambiar uno, por lo que es seguro que los compromisos dependan de las copias de los demás.
Sin embargo, debido a que los archivos almacenados están en este formato especial, congelado para siempre, solo de Git, Git tiene que expandir cada archivo en una copia diaria normal. Esta copia ordinaria no es la copia de Git : es tu copia, haz lo que quieras. Git simplemente les escribirá cuando le digas que lo haga, para que tengas tus copias con las que trabajar. Estas copias utilizables están en su árbol de trabajo o árbol de trabajo .
Lo que esto significa es que cuando revisa alguna confirmación en particular, automáticamente hay dos copias de cada archivo:
Git tiene una copia congelada de Git en la confirmación actual . No puede cambiar esta copia (aunque, por supuesto, puede seleccionar una confirmación diferente o realizar una nueva confirmación).
Tiene, en su árbol de trabajo, una copia en formato normal. Puede hacer lo que quiera con esto, usando cualquiera de los comandos en su computadora.
Otros sistemas de control de versiones (incluido Mercurial como se mencionó anteriormente) se detienen aquí, con estas dos copias. Simplemente modifica la copia del árbol de trabajo y luego confirma. Git ... no lo hace.
El índice
Entre estas dos copias, Git almacena una tercera copia 2 de cada archivo. Esta tercera copia está en formato congelado , pero a diferencia de la copia congelada en la confirmación, puede cambiarla. Para cambiarlo, usa git add.
El git addcomando significa hacer que la copia de índice del archivo coincida con la copia del árbol de trabajo . Es decir, le estás diciendo a Git: Reemplaza la copia de formato congelado, deduplicada que está ahora en el índice, comprimiendo mi copia actualizada del árbol de trabajo, eliminándola y preparándola para congelarla en una nueva confirmación. Si no lo usa git add, el índice aún contiene la copia en formato congelado de la confirmación actual.
Cuando lo ejecuta git commit, Git empaqueta todo lo que está en el índice en ese momento para usarlo como la nueva instantánea. Como ya está en formato congelado y previamente desduplicado, Git no tiene que hacer mucho trabajo adicional.
Esto también explica de qué se tratan los archivos sin seguimiento . Un archivo sin seguimiento es un archivo que está en su árbol de trabajo pero que no está en el índice de Git en este momento . No importa cómo terminó el archivo en este estado. Quizás lo copió desde otro lugar de su computadora, en su árbol de trabajo. Tal vez lo hayas creado de nuevo aquí. Tal vez no era una copia en el índice de Git, pero se elimina con esa copia git rm --cached. De una forma u otra, hay una copia aquí en su árbol de trabajo, pero no hay una copia en el índice de Git. Si realiza una nueva confirmación ahora, ese archivo no estará en la nueva confirmación.
Tenga en cuenta que git checkoutinicialmente llena el índice de Git desde la confirmación que verifica. Entonces, el índice comienza a coincidir con la confirmación. Git también completa su árbol de trabajo desde esta misma fuente. Entonces, inicialmente, los tres coinciden. Cuando cambia archivos en su árbol de trabajo y git addellos, bueno, ahora el índice y su árbol de trabajo coinciden. Luego corres git commity Git realiza una nueva confirmación desde el índice, y ahora los tres vuelven a coincidir.
Debido a que Git realiza nuevas confirmaciones desde el índice, podemos poner las cosas de esta manera: el índice de Git contiene la siguiente confirmación que planea realizar. Esto ignora el rol ampliado que asume el índice de Git durante una fusión en conflicto, pero nos gustaría ignorar eso por ahora de todos modos. :-)
Eso es todo, ¡pero sigue siendo bastante complicado! Es particularmente complicado porque no hay una manera fácil de ver exactamente qué hay en el índice de Git. 3 Pero no es un comando de Git que te dice lo que está pasando, de una manera que es bastante útil, y que es comando git status.
2 Técnicamente, esto no es en realidad una copia . En cambio, es una referencia al archivo Git-ified, pre-deduplicado y todo. También hay más cosas aquí, como el modo, el nombre del archivo, un número de prueba y algunos datos de caché para que Git funcione más rápido. Pero a menos que empiece a trabajar con algunos de los comandos de bajo nivel de Git, git ls-files --stagey git update-indexen particular, puede pensar en ellos como una copia.
3 El git ls-files --stagecomando le mostrará los nombres y números de prueba de cada archivo en el índice de Git, pero generalmente esto no es muy útil de todos modos.
git status
El git statuscomando realmente funciona ejecutando dos git diffcomandos separados para usted (y también haciendo otras cosas útiles, como decirle en qué rama se encuentra).
La primera git diffcompara la confirmación actual, que, recuerde, está congelada para siempre, con lo que sea que esté en el índice de Git. Para archivos que son iguales , Git no dirá nada en absoluto. Para archivos que son diferentes , Git le dirá que este archivo está preparado para su confirmación . Esto incluye archivos completamente nuevos, si la confirmación no tiene sub.py, pero el índice sí lo tiene sub.py, entonces se agrega este archivo, y los archivos eliminados que estaban (y están) en la confirmación pero no están en el índice más ( git rm, quizás).
El segundo git diffcompara todos los archivos en el índice de Git con los archivos en su árbol de trabajo. Para archivos que son iguales , Git no dice nada en absoluto. Para archivos que son diferentes , Git le dirá que este archivo no está preparado para su confirmación . A diferencia de la primera diferencia, esta lista en particular no incluye archivos que sean completamente nuevos: si el archivo untrackedexiste en su árbol de trabajo, pero no en el índice de Git, Git simplemente lo agrega a la lista de archivos sin seguimiento . 4
Al final, después de haber acumulado estos archivos sin seguimiento en una lista, también git statusse anunciarán los nombres de esos archivos, pero hay una excepción especial: si el nombre de un .gitignorearchivo aparece en un archivo, eso suprime esta última lista. Tenga en cuenta que enumerar un archivo rastreado , uno que está en el índice de Git, en un .gitignoreno tiene ningún efecto aquí : el archivo está en el índice, por lo que se compara y se confirma, incluso si está incluido en .gitignore. El archivo ignorado solo suprime las quejas de "archivo sin seguimiento". 5
4 Cuando se utiliza la versión corta de git status- git status -s, los archivos sin seguimiento no están tan separados, pero el principio es el mismo. Acumular los archivos como este también permite git statusresumir un montón de nombres de archivos sin seguimiento simplemente imprimiendo un nombre de directorio, a veces. Para obtener la lista completa, use git status -uallo git status -u.
5 El listado de un archivo también hace que se agreguen en masa muchas operaciones de archivo como git add .u git add *omitir el archivo sin seguimiento. Esta parte se vuelve un poco más complicada, ya que puede usar git add --forcepara agregar un archivo que normalmente se omitiría. Hay algunos otros casos especiales normalmente menores, todos los cuales se suman a esto: el archivo .gitignorepodría llamarse más correctamente .git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-themo algo igualmente difícil de manejar. Pero eso es demasiado ridículo, así .gitignorees.
git add -u, git commit -aetc.
Hay varios atajos útiles que debe conocer aquí:
git add .agregará todos los archivos actualizados en el directorio actual y cualquier subdirectorio. Esto se respeta .gitignore, por lo que si un archivo que actualmente no está rastreado no se queja git status, no se agregará automáticamente.
git add -uagregará automáticamente todos los archivos actualizados en cualquier lugar de su árbol de trabajo . 6 Esto solo afecta a los archivos rastreados . Tenga en cuenta que si ha eliminado la copia del árbol de trabajo, esto también eliminará la copia del índice ( git addhace esto como parte de hacer que el índice coincida con el árbol de trabajo ).
git add -Aes como correr git add .desde el nivel superior de su árbol de trabajo (pero vea la nota al pie 6).
Además de estos, puede ejecutar git commit -a, lo que equivale aproximadamente a 7 ejecutar git add -uy luego git commit. Es decir, esto le proporciona el mismo comportamiento que es conveniente en Mercurial.
En general, desaconsejo el git commit -apatrón: encuentro que es mejor usarlo con git statusfrecuencia, observar de cerca la salida y, si el estado no es el esperado, averigüe por qué ese es el caso. Usando git commit -a, es muy fácil modificar accidentalmente un archivo y confirmar un cambio que no tenía la intención de realizar. Pero esto es principalmente una cuestión de gustos / opiniones.
6 Si su versión de Git es anterior a Git 2.0, tenga cuidado aquí: git add -usolo funciona en el directorio y subdirectorios actuales, por lo que primero debe subir al nivel superior de su árbol de trabajo. La git add -Aopción tiene un problema similar.
7 Digo aproximadamente equivalente porque en git commit -arealidad funciona haciendo un índice adicional y usando ese otro índice para hacer la confirmación. Si la confirmación funciona , obtiene el mismo efecto que hacerlo git add -u && git commit. Si la confirmación no funciona, si hace que Git omita la confirmación de cualquiera de las muchas formas en que puede hacerlo, entonces no se git addedita ningún archivo después, porque Git arroja el índice adicional temporal y vuelve a usar el índice principal. .
Hay complicaciones adicionales que surgen si usa git commit --onlyaquí. En este caso, Git crea un tercer índice, y las cosas se ponen muy complicadas, especialmente si usa ganchos de confirmación previa. Ésta es otra razón para utilizar git addoperaciones independientes .