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.
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?
Editar: Creo que puedo estar confundiendo la terminología. ¿Un archivo 'preparado' es lo mismo que un archivo 'rastreado'?
Respuestas:
Cuando confirme, solo va a confirmar los cambios en el índice (los archivos "en etapas"). Hay muchos usos para esto, pero el más obvio es dividir los cambios de trabajo en partes más pequeñas e independientes. Quizás solucionó un error mientras implementaba una función. Puede
git add
solo ese archivo (¡ogit add -p
agregar solo una parte de un archivo!) Y luego confirmar esa corrección de error antes de enviar todo lo demás. Si está usandogit commit -a
, solo está forzando unadd
de todo justo antes de la confirmación. No lo use-a
si desea aprovechar los archivos de ensayo.También puede tratar los archivos almacenados como una copia de trabajo intermedia con los
--cached
comandos to many. Por ejemplo,git diff --cached
le mostrará en qué se diferencia la etapaHEAD
para que pueda ver lo que está a punto de realizar sin mezclar sus otros cambios de trabajo.fuente
git reset --hard
.git diff --staged
y verifique qué archivos cambió y dónde, y comience a hacer otros cambios.fuente
Un propósito práctico de la puesta en escena es la separación lógica de las confirmaciones de archivos.
Como la preparación le permite continuar haciendo ediciones en los archivos / directorio de trabajo y hacer confirmaciones en partes cuando crea que las cosas están listas, puede usar etapas separadas para ediciones no relacionadas lógicamente.
Suponga que tiene 4 archivos
fileA.html
,fileB.html
,fileC.html
yfileD.html
. Realiza cambios en los 4 archivos y está listo para confirmar, pero los cambios enfileA.html
yfileB.html
están relacionados lógicamente (por ejemplo, la implementación de la misma nueva característica en ambos archivos) mientras que los cambios enfileC.html
yfileD.html
están separados y lógicamente no están relacionados con archivos anteriores. Puede archivos de la primera etapafileA.html
yfileB.html
y comprometerse ellos.Luego, en el siguiente paso, configura y confirma los cambios en los dos archivos restantes.
fuente
git commit -m "Implemented new feature XYZ" fileA.html fileB.html
funcionaría bien sin necesidad de los comandos git add. Vengo del mundo de la subversión donde la puesta en escena no es un concepto, así que no estoy convencido de la utilidad de la puesta en escena de gitEs más fácil comprender el uso de los comandos git
add
ycommit
si imagina que se mantiene un archivo de registro en su repositorio en Github. El archivo de registro de un proyecto típico para mí puede verse así:Normalmente comienzo mi día con una
git pull
solicitud y lo termino con unagit push
solicitud. Entonces, todo dentro del registro de un día corresponde a lo que ocurre entre ellos. Durante cada día, hay una o más tareas lógicas que realizo y que requieren cambiar algunos archivos. Los archivos editados durante esa tarea se enumeran en un índice.Cada una de estas subtareas (Tarea A y Tarea B aquí) son confirmaciones individuales. El
git add
comando agrega archivos a la lista 'Índice de archivos modificados'. Este proceso también se llama estadificación. Elgit commit
comando registra / finaliza los cambios y la lista de índice correspondiente junto con un mensaje personalizado.Recuerde que todavía solo está cambiando la copia local de su repositorio y no la de Github. Después de esto, solo cuando haga un 'git push', haga todos estos cambios registrados, junto con sus archivos de índice para cada confirmación, inicie sesión en el repositorio principal (en Github).
Como ejemplo, para obtener la segunda entrada en ese archivo de registro imaginario, habría hecho:
En pocas palabras,
git add
y legit commit
permite dividir un cambio en el repositorio principal en sub-cambios lógicos sistemáticos. Como han señalado otras respuestas y comentarios, por supuesto que tienen muchos más usos. Sin embargo, este es uno de los usos más comunes y un principio impulsor de que Git sea un sistema de control de revisión de múltiples etapas a diferencia de otros populares como Svn.fuente
El área de preparación nos ayuda a elaborar los compromisos con mayor flexibilidad. Por elaboración, me refiero a dividir las confirmaciones en unidades lógicas. Esto es muy importante si desea un software que se pueda mantener. La forma más obvia de lograr esto:
Puede trabajar en múltiples funciones / errores en un solo directorio de trabajo y aún así crear confirmaciones significativas. Tener un único directorio de trabajo que contenga todo nuestro trabajo activo también es muy conveniente. (Esto se puede hacer sin un área de preparación, siempre y cuando los cambios nunca se superpongan a un archivo. Y también tiene la responsabilidad adicional de rastrear manualmente si se superponen)
Puede encontrar más ejemplos aquí: Usos del índice
Y la mejor parte es que las ventajas no terminan con esta lista de flujos de trabajo. Si surge un flujo de trabajo único, puede estar casi seguro de que el área de preparación lo ayudará.
fuente
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 ).
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.
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 add
paso aparte , más allá del primero que introduce un archivo completamente nuevo. Con Mercurial, usas elhg
comando que selecciona alguna confirmación, luego haces tu trabajo, luego correshg commit
y listo. Con Git, usasgit checkout
, 1 , luego haces tu trabajo, luego corresgit add
y luegogit commit
. ¿Por qué elgit add
paso 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.
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 switch
lugar degit checkout
. Para este caso particular, estos dos comandos hacen exactamente lo mismo. El nuevo comando existe porquegit checkout
se sobrecargó con demasiadas cosas; se dividieron en dos comandos separadosgit switch
ygit 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
.git
directorio 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 add
comando 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 usagit 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 checkout
inicialmente 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 ygit add
ellos, bueno, ahora el índice y su árbol de trabajo coinciden. Luego corresgit commit
y 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 --stage
ygit update-index
en particular, puede pensar en ellos como una copia.3 El
git ls-files --stage
comando 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 status
comando realmente funciona ejecutando dosgit diff
comandos separados para usted (y también haciendo otras cosas útiles, como decirle en qué rama se encuentra).La primera
git diff
compara 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 tienesub.py
, pero el índice sí lo tienesub.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 diff
compara 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 archivountracked
existe en su árbol de trabajo, pero no en el índice de Git, Git simplemente lo agrega a la lista de archivos sin seguimiento . 4Al final, después de haber acumulado estos archivos sin seguimiento en una lista, también
git status
se anunciarán los nombres de esos archivos, pero hay una excepción especial: si el nombre de un.gitignore
archivo 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.gitignore
no 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". 54 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 permitegit status
resumir un montón de nombres de archivos sin seguimiento simplemente imprimiendo un nombre de directorio, a veces. Para obtener la lista completa, usegit status -uall
ogit status -u
.5 El listado de un archivo también hace que se agreguen en masa muchas operaciones de archivo como
git add .
ugit add *
omitir el archivo sin seguimiento. Esta parte se vuelve un poco más complicada, ya que puede usargit add --force
para agregar un archivo que normalmente se omitiría. Hay algunos otros casos especiales normalmente menores, todos los cuales se suman a esto: el archivo.gitignore
podría llamarse más correctamente.git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-them
o algo igualmente difícil de manejar. Pero eso es demasiado ridículo, así.gitignore
es.git add -u
,git commit -a
etc.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 quejagit status
, no se agregará automáticamente.git add -u
agregará 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 add
hace esto como parte de hacer que el índice coincida con el árbol de trabajo ).git add -A
es como corrergit 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 ejecutargit add -u
y luegogit commit
. Es decir, esto le proporciona el mismo comportamiento que es conveniente en Mercurial.En general, desaconsejo el
git commit -a
patrón: encuentro que es mejor usarlo congit status
frecuencia, observar de cerca la salida y, si el estado no es el esperado, averigüe por qué ese es el caso. Usandogit 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 -u
solo funciona en el directorio y subdirectorios actuales, por lo que primero debe subir al nivel superior de su árbol de trabajo. Lagit add -A
opción tiene un problema similar.7 Digo aproximadamente equivalente porque en
git commit -a
realidad 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 hacerlogit 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 segit add
edita 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 --only
aquí. 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 utilizargit add
operaciones independientes .fuente
Veo el punto de usar el escenario para hacer las confirmaciones más pequeñas como lo mencionaron @Ben Jackson y @Tapashee Tabassum Urmi y, a veces, lo uso para ese propósito, ¡pero lo uso principalmente para hacer que mis confirmaciones sean más grandes! aquí está mi punto:
Digamos que quiero agregar una pequeña función que requiere varios pasos más pequeños. No veo ningún sentido en tener un compromiso por separado para pasos más pequeños e inundar mi línea de tiempo. Sin embargo, quiero guardar cada paso y volver si es necesario,
Simplemente coloco los pasos más pequeños uno encima del otro y cuando siento que es digno de un compromiso, me comprometo. De esta manera elimino las confirmaciones innecesarias de la línea de tiempo, pero puedo deshacer (pagar) el último paso.
Veo otras formas de hacer esto (simplificando el historial de git) que puede usar según su preferencia:
fuente
Es como una casilla de verificación que brinda la posibilidad de elegir qué archivos enviar.
por ejemplo, si he editado
fileA.txt
yfileB.txt
.Pero solo quiero confirmar cambios defileA.txt
. porque todavía no he terminadofileB.txt
.Simplemente puedo usar
git add fileA.txt
y comprometerme usandogit commit -m "changed fileA.txt"
y seguir trabajandofileB.txt
y después de terminar puedo comprometermefileB.txt
fácilmentefuente