<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Git - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Git - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 13:55:49 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/tag/git/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Error: fallo al enviar algunas referencias – Cómo solucionarlo en Git ]]>
                </title>
                <description>
                    <![CDATA[ Al colaborar con otros desarrolladores utilizando Git, es posible que te encuentres con el error error: failed to push some refs to [repositorio remoto]. Este error ocurre principalmente cuando intentas enviar tus cambios locales a GitHub, pero el repositorio local aún no está actualizado con los cambios realizados en el ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/error-fallo-al-enviar-algunas-referencias-como-solucionarlo-en-git/</link>
                <guid isPermaLink="false">67fe72756d1e700499f40228</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Eduardo Macias ]]>
                </dc:creator>
                <pubDate>Tue, 15 Apr 2025 14:53:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2025/04/roman-synkevych-wX2L8L-fGeA-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/error-failed-to-push-some-refs-to-how-to-fix-in-git/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Error: failed to push some refs to – How to Fix in Git</a>
      </p><p>Al colaborar con otros desarrolladores utilizando Git, es posible que te encuentres con el error <code>error: failed to push some refs to [repositorio remoto]</code>.</p><p>Este error ocurre principalmente cuando intentas enviar tus cambios locales a GitHub, pero el repositorio local aún no está actualizado con los cambios realizados en el repositorio remoto.</p><p>En esencia, Git te está indicando que actualices el repositorio local con los cambios actuales del repositorio remoto antes de enviar tus propios cambios. Esto es necesario para evitar sobrescribir los cambios realizados por otros.</p><p>A continuación, discutiremos dos posibles formas de solucionar este error.</p><h2 id="c-mo-solucionar-el-error-error-failed-to-push-some-refs-to-en-git">Cómo solucionar el error <code>error: failed to push some refs to</code> en Git</h2><p>Podemos solucionar el error <code>error: failed to push some refs to [repositorio remoto]</code> en Git utilizando los comandos <code>git pull origin [rama]</code> o <code>git pull --rebase origin [rama]</code>. En la mayoría de los casos, la segunda opción ( <code>git pull --rebase origin [rama]</code>) resuelve el error.</p><p>Veamos cómo puedes usar los comandos mencionados.</p><h3 id="c-mo-solucionar-el-error-error-failed-to-push-some-refs-to-en-git-usando-git-pull">Cómo solucionar el error <code>error: failed to push some refs to</code> en Git usando <code>git pull</code></h3><p>Ejecutar <code>git pull</code> implica obtener los nuevos cambios realizados en el repositorio remoto y fusionarlos con el repositorio local.</p><p>Una vez que se haya realizado la fusión, podrás enviar tus propios cambios de código a GitHub.</p><p>En este caso, estamos intentando solucionar el error <code>error: failed to push some refs to [repositorio remoto]</code> ejecutando <code>git pull</code>.</p><p>Aquí te mostramos cómo hacerlo:</p><pre><code>git pull origin main
</code></pre><p>Si estás trabajando en una rama diferente, deberás reemplazar <code>main</code> en el ejemplo anterior con el nombre de tu rama.</p><p>Ten en cuenta que existe la posibilidad de que este comando no logre sincronizar tus repositorios remoto y local, y por lo tanto, no resuelva el error. Si la solicitud se completa correctamente, continúa y ejecuta el siguiente comando para enviar tus propios cambios:</p><pre><code>git push -u origin main
</code></pre><p>Si el error persiste, obtendrás un error que dice: <code>fatal: refusing to merge unrelated histories</code>. En ese caso, utiliza la solución que se presenta en la siguiente sección.</p><h3 id="c-mo-solucionar-el-error-error-failed-to-push-some-refs-to-en-git-usando-git-pull-rebase">Cómo solucionar el error <code>error: failed to push some refs to</code> en Git usando <code>git pull --rebase</code></h3><p>El comando <code>git pull --rebase</code> es útil cuando tu rama local está un commit por detrás de la rama remota.</p><p>Para solucionar el error, ejecuta los siguientes comandos:</p><pre><code>git pull --rebase origin main
git push -u origin main
</code></pre><p>Si el primer comando se ejecuta correctamente, deberías obtener una respuesta que diga: <code>Successfully rebased and updated refs/heads/main</code>.</p><p>El segundo comando envía el estado actual de tu repositorio local a la rama remota.</p><h2 id="resumen">Resumen</h2><p>En este artículo, abordamos el error <code>error: failed to push some refs to [repositorio remoto]</code>.</p><p>Este error se produce cuando intentas enviar tus cambios locales al repositorio remoto sin actualizar tu repositorio local con los cambios más recientes del repositorio remoto.</p><p>Discutimos dos comandos que puedes usar para solucionar este error: <code>git pull origin [rama]</code> y <code>git pull --rebase origin [rama]</code>.</p><p>Espero que esto te ayude a resolver el error.</p><p>¡Feliz codificación!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo funciona internamente la autenticación SSH con GitHub ]]>
                </title>
                <description>
                    <![CDATA[ El SSH (Shell Seguro) es un protocolo cliente-servidor para conectarse y autenticarse a un servidor remoto. La autenticación significa que el servidor remoto puede verificar que eres tú mismo no alguien más hablando por ti. Podrías ya estar usando la autenticación SSH de Github, ¿pero sabes cómo funciona en sí? ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-funciona-internamente-la-autenticacion-ssh-con-github/</link>
                <guid isPermaLink="false">67c4da6aa3e1830472d3e6b6</guid>
                
                    <category>
                        <![CDATA[ SSH ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Tue, 15 Apr 2025 14:30:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2025/03/aba38efa-117c-4ef7-a844-91599c0a4d62.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/ssh-authentication-with-github-under-the-hood/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How SSH Authentication with GitHub Works Under the Hood</a>
      </p><p>El SSH (Shell Seguro) es un protocolo cliente-servidor para conectarse y autenticarse a un servidor remoto.</p><p>La autenticación significa que el servidor remoto puede verificar que eres tú mismo no alguien más hablando por ti.</p><p>Podrías ya estar usando la autenticación SSH de Github, ¿pero sabes cómo funciona en sí? En este artículo, aprenderá qué sucede de forma interna y cómo funciona en realidad la autenticación de SSH.</p><p>A lo largo, entenderás los conceptos fundamentales de criptografía que cada desarrollador debería saber: encriptación de clave simétrica, encriptación de clave asimétrica, funciones hash criptográficas, y firmas digitales.</p><p>Algunos desarrolladores usualmente no tienen la chance de aprender y entender estos fundamentos de criptografía, pero estos conceptos te ayudarán a la larga. También, te ayudarán en estar en una mejor posición para tomar decisiones de seguridad informadas para tus aplicaciones de web en producción.</p><p>Así que vamos, abróchate los cinturones de seguridad, ¡y comencemos!</p><h3 id="esto-es-lo-que-cubriremos-"><strong>Esto es lo que cubriremos:</strong></h3><ol><li><a href="#primero-por-que-autenticacion-importante">Primero, ¿por qué la Autenticación es tan importante?</a></li><li><a href="#encriptacion-clave-simetrica">Encriptación de Clave Simétrica</a> </li><li><a href="#encriptacion-llave-asimetrica">Encriptación de Clave Asimétrica</a></li><li><a href="#funciones-hash-criptograficas">Funciones de Hash Criptográficas</a> </li><li><a href="#firmas-digitales">Firmas Digitales</a></li><li><a href="#como-funciona-la-autenticacion-ssh">Cómo Funciona la Autenticación SSH</a> </li><li><a href="#resumiendo-todo">Resumiendo Todo</a></li></ol><!--kg-card-begin: html--><h2 id="primero-por-que-autenticacion-importante">Primero, ¿por qué la Autenticación es tan importante?</h2><!--kg-card-end: html--><p>Cuando ejecutamos <code>git push</code>, Github necesita verificar que la persona correcta está interactuando con Github. Imagina si un atacante podría llegar a hacer <code>git push</code> por ti.</p><p>Entonces todos tus repositorios estarían bajo el control del atacante. Podrían eliminar todo tu código juntamente con todo el historial de las confirmaciones.</p><p>Esto suena bastante peligroso, ¿no? Así que para verificar que eres tú el que está hablando con Github, y no un atacante, Github tiene varias formas de autenticarte.</p><p>El método más usado para autenticar con Github es la autenticación SSH.</p><p>Antes que entendamos cómo funciona la autenticación SSH internamente, necesitaremos entender los conceptos fundamentales de criptografía, a saber – encriptación de clave simétrica, encriptación de clave asimétrica, funciones de hash criptográficas, y firmas digitales.</p><p>¡Comencemos!</p><!--kg-card-begin: html--><h2 id="encriptacion-clave-simetrica">Encriptación de Clave Simétrica</h2><!--kg-card-end: html--><p>En los tiempos antiguos, los gobernantes idearon varios métodos de comunicar mensajes militares secretos a sus comandantes del ejército.</p><p>En los métodos más primitivos, mayormente usados por los gobernantes Griegos antiguos y posiblemente luego los Romanos, involucrados usando una vara de madera cilíndrica llamado un <strong><a href="https://es.wikipedia.org/wiki/Esc%C3%ADtala">Escítala</a></strong>.</p><p>Antes de una invasión militar, el gobernante tendría las dos mismas varas de madera cilíndricos exactas. Entonces le daría una escítala al comandante del ejército y mantener uno para sí mismo.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734514827027/b4945c3a-64d4-458b-a410-f23b1a08d9ef.png" class="kg-image" alt="A scytale with leather strip wounded and a message written on it." width="2012" height="1176" loading="lazy"></figure><p>El dispositivo funcionaba al enrollar una tira de cuero alrededor de escítala. Después de hacer esto, el gobernante escribiría el mensaje por encima de la tira de cuero enrollada de forma que solo pudiera ser leído cuando estuviere enrollada de forma apropiada nuevamente. </p><p>Supón que la escítala le permitiera escribir tres letras alrededor en un circulo y cinco letras de forma recta a lo largo de su longitud. La tira de cuero enrollada con el mensaje <code>attackfromright</code> escrito luciría así:</p><pre><code class="language-plaintext">       |   |   |   |   |   |
       | a | t | t | a | c |  |
     __| k | f | r | o | m |__|
    |  | r | i | g | h | t |
    |  |   |   |   |   |   |
</code></pre><p>Después de escribir el mensaje en la escítala, el gobernante desenrollaría la tira de cuero y lo enviaría al comandante del ejército. Cuando estaba desenrollada, la tira de cuero tendría el siguiente mensaje desordenado:</p><pre><code class="language-plaintext">----------------
akrtfitrgaohcmt
----------------
</code></pre><p>Así que ahora lo ves, incluso si la tira de cuero fuera interceptada por un espía enemigo, el mensaje no tendría sentido. ¿No es fascinante? El uso inteligente de una vara de madera y una tira de cuero, ¡podría haber ayudado a algunos gobernantes antiguos ganar batallas!</p><p>Cuando la tira de cuero alcanzaba al comandante del ejército, lo envolvería con su propia escítala (que sería exactamente el mismo que el del gobernante), y luego el comandante sería capaz de entender el mensaje apropiadamente.</p><p>Esta técnica de la escítala en realidad es un ejemplo de la encriptación de clave simétrica en la práctica.</p><p>La encriptación es un proceso en el que el mensaje origina es modificado (o codificado) de tal forma que solamente el recipiente indicado puede decodificar y ver el mensaje actual.</p><p>El mensaje original se llama texto plano, mientras que el mensaje codificado se llama texto cifrado. La encriptación convierte el <code>texto plano a texto cifrado</code> con la ayuda de una clave.</p><p>Para descifrar el mensaje, que sería convertir el <code>texto cifrado a texto plano</code>, una persona debe tener acceso a la misma llave.</p><p>Si lo comparamos a la técnica de la escítala, la escítala es la llave. El gobernantes solamente comparte la llave (escítala) con el comandante del ejército que necesita saber lo que dice el mensaje.</p><p>Así es como luce el proceso de encriptación:</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734519516607/75c926a3-faec-402a-8bcd-122039f47a01.png" class="kg-image" alt="Encryption with scytale as key." width="2023" height="526" loading="lazy"></figure><p>El proceso de descifrado lucirá así:</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734519525487/de096889-332c-4482-b2df-b28ce609a8a6.png" class="kg-image" alt="Decryption with scytale as key." width="1979" height="526" loading="lazy"></figure><p>Llamamos a esto encriptación de llave simétrica porque la misma llave se usa tanto para encriptar y descifrar el mensaje.</p><p>Esta llave (la escítala) se debe mantener resguardada del acceso del enemigo. Si el enemigo accede a esta llave, entonces será capaz de descifrar los mensajes.</p><p>Pero hay otro tipo de encriptación llamada encriptación de llave asimétrica. Ahora que entiendes la encriptación de llave simétrica, sigamos con la encriptación de llave asimétrica.</p><!--kg-card-begin: html--><h2 id="encriptacion-llave-asimetrica">Encriptación de Llave Asimétrica</h2><!--kg-card-end: html--><p>En la encriptación de llave simétrica, como vimos arriba, la misma llave era usada por el gobernante y el comandante del ejército para encriptar y descifrar el mensaje.</p><p>Pero en una encriptación de llave asimétrica, hay dos llaves (llamado un par de llaves). De las dos llaves, una es una llave privada y la otra es una llave pública.</p><p>La llave pública puede ser compartido con todos (el cual por eso se llama pública). Pero la llave privada tiene que mantenerse, ¡en secreto! Nunca debe ser revelado a nadie.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735200860039/7aca8ffa-c33a-44e5-ab1a-181492ebefd8.png" class="kg-image" alt="Public key can be shared with everyone. But the private key must be kept secret." width="2714" height="1428" loading="lazy"></figure><p>Lo interesante sobre la encriptación de llave asimétrica es eso, si un mensaje es encriptado con la llave pública, entonces puede ser descifrado solamente con la llave privada correspondiente. Ninguna otra llave puede descifrarlo.</p><p>Y funciona de la otra forma también. Si un mensaje es encriptado con la llave privada entonces puede ser descifrado solamente usando la llave pública correspondiente.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735120077350/b90901c8-b55c-428a-8eb4-1b8ffa65fa06.png" class="kg-image" alt="Illustration of public and private key mathematically linked with each other." width="948" height="835" loading="lazy"></figure><p>Las dos llaves – pública y privada – están enlazados matemáticamente uno con el otro. Mientras uno encripta, el otro descifra.</p><p>Sólo una pequeña nota, la encriptación de llave asimétrica también se le llama encriptación de llave pública. Estos dos términos son usados de forma intercambiable pero significa lo mismo.</p><!--kg-card-begin: html--><h2 id="funciones-hash-criptograficas">Funciones Hash Criptográficas</h2><!--kg-card-end: html--><p>Una función hash criptográfica está diseñada para tomar una entrada de cualquier longitud y producir una salida de longitud fijada. La salida de longitud fijada se le denomina valor hash.</p><p>Un ejemplo popular de una función hash criptográfica es SHA-256.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735030835833/201640c6-13b4-4b2b-9be3-88e245269bd1.png" class="kg-image" alt="SHA-256 calculation of &quot;freeCodeCamp.org&quot;" width="2283" height="285" loading="lazy"></figure><p>La imagen de arriba muestra el valor hash SHA-256 de la entrada "freeCodeCamp.org". Las funciones hash criptográficas tienen tres propiedades que lo hacen muy útiles (lo veremos en las próximas secciones).</p><p>Primero, es prácticamente imposible para tomar el valor hash y averiguar la entrada del valor hash.</p><p>Por ejemplo, si nos dan el valor hash <code>c9c31315ef2257e4b7698</code>, no hay forma de que averigüemos que la entrada a la función hash fuere "freeCodeCamp.org".</p><p>Segundo, si pasamos la misma entrada a la función hash, obtenemos el mismo valor hash como la salida.</p><p>Si pasamos "freeCodeCamp.org" nuevamente a la función hash SHA-256, obtendremos la misma salida hash como nuestra llamada previa.</p><p>Tercero, dos entradas distintas nunca comparten el mismo valor hash. Inclusive el cambio más ligero en la entrada produce una salida totalmente distinta.</p><p>Supón que si proveemos "freeCodeCamp" como entrada en vez de "freeCodeCamp.org" – obtenemos una salida totalmente distinta.</p><!--kg-card-begin: html--><h2 id="firmas-digitales">Firmas Digitales</h2><!--kg-card-end: html--><p>En tus vidas diarias, podrías tener que firma varios documentos. Podrían ser documentos legales, o el boletín de calificaciones de tus hijos, o tal vez algo más.</p><p>Cuando tu firma esté presente en el documento, le transmite a la otra parte que eres tú el que está de acuerdo cualquier cosa que esté escrito en ese documento.</p><p>Luego, no puedes dar marcha atrás de lo que está escrito en el documento. ¿Correcto?</p><p>De forma similar, en el mundo digital, tenemos las firmas digitales – o podemos simplemente llamarlos firmas.</p><p>Entendamos cómo funcionan las firmas usando un ejemplo. Tenemos dos usuarios llamados "Alice" y "Bob".</p><p>Bob quiere transferir algo de dinero a la cuenta bancaria de Alice. Así que Bob le pide a Alice su información de cuenta bancaria.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735042150046/034d26c5-b33d-4b82-aeb8-173e47cd8e8e.png" class="kg-image" alt="An illustration showing alice and bob's computers far away from each other and alice's bank account number." width="1972" height="1410" loading="lazy"></figure><p>Alice sabe sobre las firmas digitales y decidió usar una. Al final, entenderás por qué Alice optó por una firma digital.</p><p>Antes de que Alice pueda crear una firma digital. Alice provee a Bib su clave pública (y guarda la clave privada para sí misma).</p><p>Luego Alice crea una firma digital y lo color al final del documento.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735041977880/35313148-8820-42d7-b122-3ddf0cbaa723.png" class="kg-image" alt="Process of digital signature generation." width="1065" height="471" loading="lazy"></figure><p>Una firma digital se crea primero al pasar el contenido del documento a una función hash criptográfica como SHA-256. En el caso de Alice, el contenido del documento es su número de cuenta bancaria.</p><p>Una vez que obtenemos el valor hash, se encripta con la <strong>clave privada</strong> de Alice. La salida de esta encriptación es la firma el cual se coloca al final del documento.</p><p>Luego esto se lo envía a Bob por Internet.</p><p>Cuando Bob recibe este documento, verifica si la <strong>firma es válida o no</strong>.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735043216695/256f7707-3f40-433f-9b00-c11b27ef01e8.png" class="kg-image" alt="Process of signature verification." width="2905" height="1636" loading="lazy"></figure><p>Para verificar la firma, Bob primero descifra la firma con la clave pública de Alice. Si lo recuerdas, Alice generó la firma al encriptar el valor hash.</p><pre><code class="language-plaintext"> plaintext                         ciphertext  
     |                                 |
     |                                 |
     |                                 |
hash value --------encrypt--------&gt; signature
</code></pre><p>Así que, cuando Bob descifra la firma, obtendrá el valor hash que Alice calculó. Llamemos a este valor hash de Alice.</p><pre><code class="language-plaintext"> ciphertext                         plaintext  
     |                                 |
     |                                 |
     |                                 |
signature --------decrypt--------&gt; hash value
</code></pre><p>Luego Bob toma el número de la cuenta bancaria que esta presente en el documento y lo pasa a la función hash.</p><p>Finalmente, Bob coincide el valor hash de Alice (la firma descifrada) y el valor hash que calculó. Si ambos valores hash coinciden entonces significa que la firma es válida.</p><p>Muy bien – ¿pero por qué necesitábamos hacer todo esto? ¿Qué significa si la firma es válida?</p><p>Cuando la verificación de la firma es exitosa, prueba dos cosas.</p><p>Primero, prueba que el documento ha sido enviado por Alice solamente. Nadie más podría haber enviado este documento.</p><p>La garantía de que solamente Alice ha enviado este documento viene del hecho de que fuimos capaces de descifrar la firma usando la clave pública de Alice.</p><p>Hemos aprendido de que si algo es encriptado usando una clave privada entonces puede ser descifrado solamente usando su clave pública vinculada.</p><p>Asi que, si Bob fue capaz de descifrar la firma usando la clave pública de Alice, significa que fue descifrado utilizando la clave privada de Alice, ¿correcto?</p><p>Y solamente Alice tiene acceso a su clave privada. Esto significa que, ¡Alice es la única persona quien podría haber enviado este documento!</p><p>Segundo, prueba que el contenido del mensaje no ha sido modificado por un atacante durante la transmisión en red.</p><p>Hicimos dos cosas para verificar la firma. Desciframos la firma, y nos dio el valor hash que Alice calculó. Y también hasheamos el número de cuenta bancaria recibido.</p><p>Si el valor hash que Alice caluló y el valor hash que Bob calculó son los mismos, significa que Alice y Bob dieron exactamente la misma entrada a la función hash.</p><p>Y esto significa que el número de cuenta bancaria que Alice envió y que Bob recibió son exactamente los mismos.</p><p>Si un atacante habría cambiado el número de cuenta bancaria antes de que el documento le llegara a Bob, entonces Bob hubiera recibido un número de cuenta bancaria modificado.</p><p>Cuando Bob fuera a calcular el valor hash de este número de cuenta bancaria modificado, el valor hash hubiera sido distinto de lo que Alice había calculado.</p><p>Así que mientras coincida el valor hash de Alice (firma descifrada) y el valor hash que Bob calculó, la coincidencia fallaría. Y evitaría que Bob transfiera dinero al número de cuenta bancaria errónea.</p><p>Para concluir, cuando la firma es verificada con éxito, significa que:</p><ol><li>El documento es solamente de Alice.</li><li>El contenido del documento no fue modificado por algún tercero.</li></ol><p>Ahora has aprendido sobre encriptación de clave simétrica, encriptación de clave asimétrica, funciones de hash criptográficas, y firmas digitales. ¡Es genial!</p><p>Hemos construido una fundación realmente sólido. Ahora entender la autenticación SSH va a ser mucho más fácil para ti.</p><!--kg-card-begin: html--><h2 id="como-funciona-la-autenticacion-ssh">Cómo Funciona la Autenticación SSH</h2><!--kg-card-end: html--><p>Si no has configurado la autenticación SSH con Github, entonces después de terminar este artículo puedes seguir la <a href="https://docs.github.com/es/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account">documentación detallada de Github sobre cómo hacerlo</a>. Por ahora, por favor quédate hasta el final.</p><p>La cruz del proceso de configuración es que crees un par de claves pública y privada en tu computadora local. Luego subes tu clave pública a tu perfil de Github – ¡y eso es todo!</p><p>Después que hemos creado nuestro par de claves pública y privada, en Ubuntu, el par de claves se almacenan dentro de la carpeta <code>~/.ssh</code>.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735035539565/1f837d9b-9717-44fa-a5e0-5801276113df.png" class="kg-image" alt="Showing my public key from my terminal." width="4380" height="243" loading="lazy"></figure><p>La imagen de arriba muestra mi clave pública. Tengo esta clave pública cargada en mi perfil de Github:</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735035898284/1ef9133a-895b-4847-a7ac-6157fdcc3143.png" class="kg-image" alt="Showing my GitHub profile settings where my public key is uploaded for SSH authentication with GitHub." width="4287" height="1398" loading="lazy"></figure><p>Ahora, cuando ejecuto <code>git push</code> o cualquier otro comando que se quiera comunicar con Github, estaré autenticado usando la autenticación SSH.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735053545173/6fb293f1-f90a-4b64-b026-082d8676afae.png" class="kg-image" alt="The illustration of SSH authentication process between client and GitHub server." width="4082" height="2574" loading="lazy"></figure><p>SSH es un protocolo cliente-servidor. Nuestra computadora que ejecuta <code>git push</code> es el cliente SSH. Github es el servidor SSH.</p><p>El cliente comienza con el proceso de autenticación al solicitar nuestra clave pública que tenemos dentro de <code>~/.ssh</code>.</p><p>Luego el cliente prepara un mensaje el cual tiene nuestra clave pública. Y luego el cliente genera la firma usando la clave privada correspondiente.</p><p>La clave pública y la firma se envían a Github. Al recibir este mensaje, Github hace dos cosas:</p><p>Primero, verifica si la clave pública mencionada en el mensaje se conecta a un perfil de Gihtub o no. Ya que subimos nuestra clave pública a Github, este paso se realizó con éxito.</p><p>Segundo, Github verifica la firma usando la clave pública que hemos subido.</p><p>Hemos aprendido que si la verificación de la firma termina siendo exitoso significa que solamente la persona quién está en posesión de la clave privada correspondiente podría haber enviado el mensaje.</p><p>Ya que solamente tenemos la clave privada vinculada a la clave pública cargada, esto prueba a Github que en realidad somos nosotros intentando comunicarse con Github y no un atacante.</p><p>Ahora, Github es 100% seguro que somos la persona correcta, estamos autenticados exitosamente, y a nuestro <code>git push</code> se le permite proceder.</p><p>Ves, se volvió fácil de entender la autenticación SSH ya que aprendiste los fundamentos.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735120630613/e9a8bbba-3cc4-43e7-8369-865ab377fb87.png" class="kg-image" alt="A xkcd comic depicting Cueball thinking to share his private key. A dangerous move!" width="733" height="282" loading="lazy"></figure><p>La imagen de arriba es del cómic popular xkcd. El personaje allí (llamado Cueball) está pensando en revelar su clave privada. Espero que ahora sepas por qué está mal revelar tu clave privada.</p><p>Si revelas tu clave privada entonces alguien más puede autenticarse a Github en tu nombre. No quieres que eso suceda, ¿verdad? ;)</p><p>Así que, siempre asegúrate de mantener tu clave privada para ti mismo nada más.</p><!--kg-card-begin: html--><h2 id="resumiendo-todo">Resumiendo Todo</h2><!--kg-card-end: html--><p>Si has llegado hasta acá, entonces felicitaciones 🥳.</p><p>Has aprendido como funciona en realidad la autenticación SSH – cuando la firma fue verificado exitosamente por Github, le confirma a Github que somos nosotros quienes le estamos hablando, no un atacante.</p><p>A lo largo adquiriste una comprensión fundamental de la encriptación de clave simétrica, encriptación de clave asimétrica, funciones hash criptográficas y firmas digitales.</p><p>Gracias por estar conmigo en esta, espero que te vayas con algunos nuevos y valiosos aprendizajes.</p><p>Pongo ideas y recursos útiles en mi Twitter. <a href="https://twitter.com/vkwebdev"><strong>Deberías seguirme allí</strong></a>. Respetaré tu tiempo.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Gitting Things Done – Una guía visual y práctica para Git [Libro completo] ]]>
                </title>
                <description>
                    <![CDATA[ Introducción Git es increíble. La mayoría de los desarrolladores de software usan Git en el día a día. Pero, ¿cuántos realmente entienden Git? ¿Sientes que sabes lo que está pasando por detrás a medida que usas Git para ejecutar varias tareas?  Por ejemplo, ¿qué sucede cuando usas git commit? ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/gitting-things-done-una-guia-visual-y-practica-para-git-libro-completo/</link>
                <guid isPermaLink="false">65a96be751a59a0455c92eb1</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Thu, 10 Oct 2024 20:48:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/01/Gitting-Things-Done-Cover-with-Photo.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/gitting-things-done-book/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Gitting Things Done – A Visual and Practical Guide to Git [Full Book]</a>
      </p><!--kg-card-begin: html--><h1 id="intro">Introducción</h1><!--kg-card-end: html--><p>Git es increíble.</p><p>La mayoría de los desarrolladores de software usan Git en el día a día. Pero, ¿cuántos realmente entienden Git? ¿<em>Sientes</em> que sabes lo que está pasando por detrás a medida que usas Git para ejecutar varias tareas? </p><p>Por ejemplo, ¿qué sucede cuando usas <code>git commit</code>? ¿Qué se almacena entre las confirmaciones? ¿Es sólo un diff entre la confirmación actual y el anterior? Si es así, ¿cómo se codifica el diff? O, ¿es una copia instantánea entero cada vez que el repositorio se almacena?</p><p>La mayoría de las personas que usan Git no saben las respuestas a estas preguntas de arriba. Pero, ¿esto importa realmente? ¿Realmente tienes que saber todas esas cosas?</p><p>Yo argumentaría que sí importa. Como profesionales, deberíamos esforzarnos en entender las herramientas que usamos, especialmente si los usamos todo el tiempo, como Git.</p><p>Aún más preciso. He encontrado que entender realmente cómo funciona Git es <strong>beneficioso</strong> en muchos escenarios – si estás resolviendo conflictos de fusión, viendo cómo conducir un rebase interesante, o inclusive cuando algo va mal ligeramente.</p><p>Muchísimas veces he recibido preguntas sobre Git de gente con experiencia, ingenieros de software altamente talentosos. He visto desarrolladores maravillosos reaccionar con miedo cuando algo sucede en su historial de confirmaciones, y simplemente no saben qué hacer. Esto no tiene que ser así.</p><p>Al leer este libro, obtendrás una nueva perspectiva de Git. Te sentirás <strong>con confianza</strong> cuando trabajes con Git, y <strong>entenderás</strong> los mecanismos subyacentes de Git, al menos aquellos que son beneficiosos de entender. Le vas a captar. </p><h1 id="tabla-de-contenidos"><strong>Tabla de Contenidos</strong></h1><ul><li><a href="#intro">Introducción</a></li><li><a href="#part-1">Parte 1 - Objetos principales e Introduciendo cambios</a></li><li><a href="#cap-1">Capítulo 1 - Objetos de Git</a></li><li><a href="#cap-2">Capítulo 2 - Ramas en Git</a></li><li><a href="#cap-3">Capítulo 3 - Cómo registrar cambios en Git</a></li><li><a href="#cap-4">Capítulo 4 - ¿Cómo crear un repo desde cero?</a></li><li><a href="#cap-5">Capítulo 5 - Cómo trabajar con las ramas en Git – Por debajo</a></li><li><a href="#part-2">Parte 2 - Ramificando e Integrando Cambios</a></li><li><a href="#cap-6">Capítulo 6 - Diffs y Parches</a></li><li><a href="#cap-7">Capítulo 7 - Entendiendo la Fusión de Git</a></li><li><a href="#cap-8">Capítulo 8 - Entendiendo Git Rebase</a></li><li><a href="#part-3">Parte 3 - Deshacer cambios</a></li><li><a href="#cap-9">Capítulo 9 - Git Reset</a></li><li><a href="#cap-10">Capítulo 10 - Herramientas adicionales para deshacer cambios</a></li><li><a href="#cap-11">Capítulo 11 - Ejercicios</a></li><li><a href="#part-4">Parte 4 - Herramientas de Git Fantásticas y Útiles</a></li><li><a href="#cap-12">Capítulo 12 - Git Log</a></li><li><a href="#cap-13">Capítulo 13 - Git Bisect</a></li><li><a href="#cap-14">Capítulo 14 - Otros comandos útiles</a></li><li><a href="#resumen">Resumen</a></li><li><a href="#apendices">Apéndices</a></li></ul><h2 id="-para-qui-n-es-este-libro">¿Para quién es este Libro?</h2><p>Para cualquier desarrollador de software que quiera profundizar su conocimiento sobre Git.</p><p>Si ya tienes experiencia con Git – Estoy seguro que serás capaz de profundizar tus conocimientos. Inclusive si eres nuevo en Git - empezaré con una vista general del mecanismo de Git, y los términos usados a lo largo de este libro.</p><p>Este libro es para ti. Lo escribí así para que puedas aprender más sobre Git, y también llegues a apreciar, o inclusive amar a Git.</p><p>También notarás que uso un estilo casual en todo el libro. Creo que aprender Git debe de ser intuitivo y divertido. Aprender cosas nuevas siempre es difícil, y pensé que escribir en un estilo menos casual realmente no haría un buen servicio. Y como ya mencioné - Este libro es para ti.</p><h2 id="-qui-n-soy-yo">¿Quién soy yo?</h2><p>Este libro es sobre ti, y tu jornada con Git. Pero me gustaría decirte un poco sobre por qué pienso que puedo contribuir a tu jornada.</p><p>Soy el CTO y uno de los co-fundadores de <a href="https://swimm.io">Swimm.io</a>, una herramienta de gestión de conocimiento para código. Parte de lo que hacemos es enlazar partes del código en repositorios de Git a partes de la documentación, y luego rastrear cambios en el repositorio para actualizar la documentación si es necesario.</p><p>En Swimm, tengo que diseccionar partes de Git, entender sus mecanismos subyacentes y también ganar intuición sobre por qué se implementa Git de la manera que se hace.</p><p>Antes de fundar Swimm practiqué enseñando en muchos entornos diferentes - entre ellos, gestionar el cyber track del Desafío Tech de Israel, fundar la Academia de Seguridad de Punto de Verificación (en inglés <strong>Check Point Security Academy</strong>), y escribir un libro completo de texto.</p><p>Este libro es mi intento de aprovechar lo máximo de ambos mundos - mi experiencia de enseñanza así como mi experiencia práctica profunda con Git, y darte la mejor experiencia de aprendizaje que puedo.</p><h2 id="el-enfoque-de-este-libro">El enfoque de este libro</h2><p>Este no es definitivamente el primer libro sobre Git. Cuando me senté a escribirlo, tuve tres principios en mente.</p><ol><li><strong>Práctico</strong> - en este libro, aprenderás cómo lograr las cosas en Git. Cómo introducir cambios, cómo deshacerlos, y cómo arreglar las cosas cuando salen mal. Entenderás cómo funciona Git no sólo por el hecho de entender, sino con una mentalidad práctica. A veces me refiero a esto como el "principio práctico" - el cual me guía en decidir si incluyo ciertos tópicos, y en qué medida.</li><li><strong>A profundidad</strong> - te sumergirás en la forma de operar de Git, entender sus mecanismos. Construirás tu entendimiento gradualmente, y siempre enlazarás tus conocimientos a escenarios reales que podrías encontrar en tu trabajo. Para alcanzar un entendimiento a profundidad, casi siempre prefiero la línea de comandos en vez de interfaces gráficas, así realmente puedes ver qué comandos estoy ejecutando.</li><li><strong>Visual</strong> - a medida que me esfuerzo en proveerte con intuición, los capítulos estarán acompañados de ayudas visuales.</li></ol><h2 id="-por-qu-este-libro-est-disponible-p-blicamente">¿Por qué este libro está disponible públicamente?</h2><p>Pienso que todos deberían tener acceso a contenido de alta calidad sobre Git, y me gustaría que este libro llegue a tantas personas como sea posible.</p><p>Si te gustaría apoyar este libro, eres bienvenido en comprar la <a href="https://www.amazon.com/dp/B0CQXTJ5V5">versión física</a>, un <a href="https://www.buymeacoffee.com/omerr/e/197232">libro electrónico</a>, o <a href="https://www.buymeacoffee.com/omerr">comprarme un café</a>. ¡Gracias!</p><h2 id="videos-acompa-antes">Videos Acompañantes</h2><p>He cubierto muchos tópicos de este libro en mi canal de Youtube - <a href="https://www.youtube.com/@BriefVid">@BriefVid</a>. Eres bienvenido en verificarlos también.</p><h2 id="a-trabajar">A trabajar</h2><p>A lo largo de este libro, mayormente usaré el singular en segunda persona - y directamente te escribiré a ti. También <strong>te pediré</strong> que trabajes, que ejecutes los comandos tú mismo, así llegas a <strong>sentir</strong> lo que es usar las cosas con Git, no sólo leerlo.</p><h2 id="los-sentimientos-de-git">Los sentimientos de Git</h2><p>A lo largo de este libro, a veces me refiero a Git con palabras tales como "cree", "piensa", o "quiere". Como puedes argumentar, Git no es humano, y no tiene sentimientos o creencias. Bueno, eso es verdad, pero para que nosotros disfrutemos al jugar con Git, y ayudarte en que disfrutes leer (y yo escribiendo), siento que referirme a Git más que sólo código lo hace muchos más divertido.</p><!--kg-card-begin: html--><h2 id="my-setup">Mi configuración</h2><!--kg-card-end: html--><p>Incluiré capturas de pantalla. No hay necesidad de que configures para coincidir con lo mío, pero si sientes curiosidad sobre mi configuración, entonces:</p><ul><li>Estoy usando Ubuntu 20.04 (WSL).</li><li>Para mi terminal, use <a href="https://ohmyz.sh/">Oh My Zsh</a></li><li>También uso plugins para Oh My Zsh, puedes <a href="https://www.freecodecamp.org/espanol/news/mejora-tu-terminal-zsh-en-siete-pasos-una-guia-visual/">seguir este tutorial en freeCodeCamp</a></li><li><a href="https://gist.github.com/Omerr/8134a61b56ca82dd90e546e7ef04eb77">El alias</a> <code>git lol</code></li><li><a href="https://github.com/mlange-42/git-graph">git-graph (mi alias es <code>gg</code>)</a></li></ul><h2 id="los-comentarios-son-bienvenidos">Los comentarios son bienvenidos</h2><p>Este libro ha sido creado para ayudarte y las personas como tú aprendan, entiendan Git, y apliquen ese conocimiento en la vida real.</p><p>Desde el principio, pedí comentarios y fui afortunado en recibirlo de grandes personas (ve <a href="https://www.freecodecamp.org/news/gitting-things-done-book/#acknowledgements">reconocimientos</a>) para asegurarte que el libro alcanza estos objetivos. Si te gustó algo sobre este libro, sentiste que algo le faltó, o que algo necesita mejorar - Me encantaría escucharlo de ti. Por favor encuéntrame en: <a>gitting.things@gmail.com</a>.</p><h2 id="nota"><strong>Nota</strong></h2><p>Este libro es provisto gratuitamente en freeCodeCamp como se describe arriba y de acuerdo a la licencia <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</a>.</p><p>Si te gustaría apoyar este libro, eres bienvenido en comprar la <a href="https://www.amazon.com/dp/B0CQXTJ5V5">versión física</a>, una <a href="https://www.buymeacoffee.com/omerr/e/197232">versión electrónica</a>, o <a href="https://www.buymeacoffee.com/omerr">comprarme un café</a>. ¡Gracias!</p><!--kg-card-begin: html--><h1 id="part-1">Parte 1 - Objetos Principales e Introduciendo cambios</h1><!--kg-card-end: html--><!--kg-card-begin: html--><h2 id="cap-1">Capítulo 1 - Objetos de Git</h2><!--kg-card-end: html--><p>Es tiempo de empezar tu jornada en las profundidades de Git. En este capítulo - empezamos con lo básico - aprenderás sobre los objetos de Git más importantes, y adoptar una forma de pensar sobre Git. ¡Vamos a ello!</p><h3 id="git-como-un-sistema-para-mantener-un-sistema-de-archivos">Git como un Sistema para mantener un Sistema de archivos</h3><p>Siendo que hay diferentes formas de usar Git, adoptaré aquí una forma que he aprendido que es la más clara y útil: viendo a Git como un sistema que mantiene un sistema de archivos, y específicamente - copias instantáneas de ese sistema de archivos con el tiempo.</p><p>Un sistema de archivos con un directorio raíz (en sistemas basados en UNIX, <code>/</code>), el cual usualmente contiene otros directorios (por ejemplo, <code>/usr</code> o <code>/bin</code>). Estos directorios contienen otros directorios, y/o archivos (por ejemplo, <code>/usr/1.txt</code>). En una máquina Windows, un directorio raíz de un disco sería <code>C:\</code>, y un sub-directorio podría ser <code>C:\users</code>. Adoptaré la convención de los sistemas basados en UNIX a lo largo de este libro.</p><h3 id="blobs"><strong>Blobs</strong></h3><p>En Git, los contenidos de los archivos son almacenados en objetos llamados <strong>blob</strong>s, abreviado para <strong>b</strong>inary <strong>l</strong>arge <strong>ob</strong>jects (objetos grandes de binario).</p><p>La diferencia entre blobs y archivos es que los archivos también contienen meta-datos. Por ejemplo, un archivo "recuerda" cuando fue creado, de esa forma si tu mueves ese archivo de un directorio a otro, su tiempo de creación permanece el mismo.</p><p>Los blobs, en contraste, son sólo corrientes de binario de datos, como el contenido de un archivo. Un blob no registra su fecha de creación, su nombre, o cualquier otra cosa más que su contenido.</p><p>Cada blob en Git es identificado por su <a href="https://en.wikipedia.org/wiki/SHA-1">hash SHA-1</a>. Los hashes SHA-1 consisten de 20 bytes, usualmente representados por 40 caracteres en forma hexadecimal. A lo largo de este libro a veces mostraré sólo los primeros caracteres de ese hash. Como los hashes, y específicamente los hashes SHA-1 son ubicuos en Git, es importante que entiendas las características básicas de los hashes.</p><h3 id="hashes"><strong>Hashes</strong></h3><p>Un hash es una función determinista y matemática unidireccional.</p><p><em>Determinista</em> significa que la misma entrada proveerá la misma salida. Eso es - tomas una corriente de datos, ejecutas una función hash en esa corriente, y obtienes un resultado.</p><p>Por ejemplo, si provees la función hash SHA-1 con la corriente <code>hello</code>, obtendrás <code>0xaaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d</code>. Si ejecutas la función hash SHA-1 nuevamente, desde una máquina diferente, y le provees los mismos datos (<code>hello</code>), obtendrás el mismo valor.</p><p>Git usa SHA-1 como su función hash para identificar objetos. Se basa en ella siendo determinista, y de esa forma un objeto siempre tendrá el mismo identificador.</p><p>Una función <strong>unidireccional</strong> es una función que es difícil de invertir dado una entrada. Eso es, es imposible (o al menos, muy difícil) de determinar, dado el resultado de la función hash (por ejemplo <code>0xaaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d</code>), qué entrada produce ese resultado (en este ejemplo <code>hello</code>).</p><h3 id="de-vuelta-a-git">De vuelta a Git</h3><p>De vuelta a Git - Blobs, como cualquier otro objeto de Git, tienen hashes SHA-1 asociados a ellos.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/blob_sha.png" class="kg-image" alt="Blobs have corresponding SHA-1 values" width="600" height="400" loading="lazy"><figcaption>Los Blobs tienen valores SHA-1 correspondientes</figcaption></figure><p>Como dije al principio, Git puede ser visto como un sistema para mantener un sistema de archivos. Sistemas de archivos consisten en archivos y directorios. Un blob es el objeto de Git representando los contenidos de un archivo.</p><h3 id="-rboles">Árboles</h3><p>En Git, el equivalente de un directorio es un <strong>árbol</strong>. Un árbol es básicamente un listado de directorios, refiriéndose a blobs, así también como otros árboles.</p><p>Los árboles son identificados por sus hashes SHA-1 también. Referirse a estos objetos, sean blobs u otros árboles, sucede por medio del hash SHA-1 de los objetos.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_objs.png" class="kg-image" alt="A tree is a directory listing" width="600" height="400" loading="lazy"><figcaption>Un árbol es un listado de directorios</figcaption></figure><p>Considera el dibujo de arriba. Fíjate que el árbol <code>CAFE7</code> se refiere al blob <code>F92A0</code> como el archivo <code>pic.png</code>. En otro árbol, el mismo blob podría tener otro nombre - pero siempre y cuando los contenidos sean lo mismo, será el mismo objeto blob, y todavía tendrá el mismo valor SHA-1.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_sub_trees.png" class="kg-image" alt="A tree may contain sub-trees, as well as blobs" width="600" height="400" loading="lazy"><figcaption>Un árbol podría contener sub-árboles, así también como blobs</figcaption></figure><p>El diagrama de arriba es equivalente a un sistema de archivos con un directorio raíz que tiene un archivo en <code>/test.js</code>, y un directorio llamado <code>/docs</code> consistiendo de dos archivos: <code>/docs/pic.png</code>, y <code>/docs/1.txt</code>.</p><h3 id="confirmaciones">Confirmaciones</h3><p>Ahora es tiempo de tomar una copia instantánea de ese sistema de archivos – y almacenar todos los archivos que existieron en ese tiempo, juntamente con sus contenidos.</p><p>En Git, una copia instantánea es una <strong>confirmación</strong>. Un objeto de confirmación incluye un puntero al árbol principal (el directorio raíz del sistema de archivos), así también como otros meta-datos tales como el confirmador (el usuario que autorizó la confirmación), un mensaje de la confirmación, y el tiempo de la confirmación.</p><p>En la mayoría de los casos, una confirmación también tiene uno o más confirmaciones padres – la copia instantánea anterior (o copias instantáneas). Por supuesto, los objetos de confirmación son también identificados por sus hashes SHA-1. Estos son los hashes que probablemente estás acostumbrado de ver cuando usas los comandos tales como <code>git log</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit.png" class="kg-image" alt="A commit is a snapshot in time. It refers to the root tree. As this is the first commit, it has no parents" width="600" height="400" loading="lazy"><figcaption>Una confirmación es una copia instantánea en el tiempo. Se refiere al árbol raíz. Ya que este es la primer confirmación, no tiene padres</figcaption></figure><p>Cada confirmación retiene la copia instantánea completa, no solo las diferencias entre sí mismo y su confirmación o confirmaciones padres.</p><p>¿Cómo puede funcionar eso? ¿No significa que Git tiene que almacenar un montón de datos para cada confirmación?</p><p>Examina lo que pasa si cambias los contenidos de un archivo. Digamos que editas el archivo <code>1.txt</code>, y agregas un signo de exclamación – eso es, cambiaste el contenido de <code>HELLO WORLD</code>, a <code>HELLO WORLD!</code>.</p><p>Bueno, este cambio significa que Git crea un nuevo objeto blob, con un nuevo hash SHA-1. Esto tiene sentido, ya que <code>sha1("HELLO WORLD")</code> es diferente de <code>sha1("HELLO WORLD!")</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_blob_new_sha.png" class="kg-image" alt="Changing the blob results in a new SHA-1" width="600" height="400" loading="lazy"><figcaption>Cambiando los resultados blob en un nuevo SHA-1</figcaption></figure><p>Ya que tienes un nuevo hash, entonces el listado del árbol debería también cambiar. Después de todo, tu árbol ya no apunta al blob <code>73D8A</code>, sino al blob <code>62E7A</code>. Desde el momento que cambies los contenidos del árbol, también cambias su hash.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_tree_new_hash.png" class="kg-image" alt="The tree that points to the changed blob needs to change as well" width="600" height="400" loading="lazy"><figcaption>El árbol que apunta al blob cambiado necesita cambiar también</figcaption></figure><p>Y ahora, ya que el hash de ese árbol es diferente, también necesitas cambiar el árbol padre – ya que el último ya no apunta al árbol <code>CAFE7</code>, sino al árbol <code>24601</code>. Consecuentemente, el árbol padre también tendrá un nuevo hash.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_root_tree.png" class="kg-image" alt="The root tree also changes, and so does its hash" width="600" height="400" loading="lazy"><figcaption>El árbol raíz también cambia, y así lo hace su hash</figcaption></figure><p>Casi listo para crear un nuevo objeto de confirmación, y parece que vas a almacenar un montón de datos – el sistema de archivos entero, ¡una vez más! ¿Pero es eso realmente necesario?</p><p>En realidad, algunos objetos, específicamente los objetos blob, no han cambiado ya que la confirmación anterior – el blob <code>F92A0</code> permaneció intacto, y así también el blob <code>F00D1</code>.</p><p>Así que este es el truco – siempre y cuando un objeto no cambie, Git no lo almacena nuevamente. En este caso, Git no necesita almacenar el blob <code>F92A0</code> o el blob <code>F00D1</code> una vez más. Git se puede referir a ellos usando solamente sus valores hash. Entonces puedes crear tu objeto de confirmación.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_commit.png" class="kg-image" alt="Blobs that remained intact are referenced by their hash values" width="600" height="400" loading="lazy"><figcaption>Blobs que permanecieron intactos son referenciados por sus valores hash</figcaption></figure><p>Ya que esta confirmación no es la primer confirmación, también tiene una confirmación padre – la confirmación <code>A1337</code>.</p><h3 id="considerando-hashes">Considerando Hashes</h3><p>Después de introducir blobs, árboles, y confirmaciones - considera los hashes de estos objetos. Digamos que escribí la cadena <code>Git is awesome!</code>, y de ahí creé un objeto blob. Tú hiciste lo mismo en tu sistema. ¿Tendríamos el mismo hash?</p><p>La respuesta es – Sí. Ya que los blobs consisten de los mismos datos, tendrán los mismos valores SHA-1.</p><p>¿Qué tal si hiciera un árbol que referencia al blob de <code>Git is awesome!</code>, y le diera un nombre específico y metadatos, y tú hicieras exactamente lo mismo en tu sistema? ¿Tendríamos el mismo hash?</p><p>De nuevo, sí. Ya que los objetos árboles son los mismos, tendrían el mismo hash.</p><p>¿Qué tal si creara una confirmación apuntando a ese árbol con el mensaje de confirmación <code>Hello</code>, y tú también hicieras lo mismo en tu sistema? ¿Tendrían el mismo hash?</p><p>En este caso, la respuesta es – No. Aunque nuestros objetos de confirmación se refieren al mismo árbol, tienen diferentes detalles de confirmación – tiempo, confirmador, y así sucesivamente.</p><h3 id="-c-mo-son-almacenados-los-objetos">¿Cómo son almacenados los Objetos?</h3><p>Ahora entiendes el propósito de los blobs, los árboles y las confirmaciones. En los próximos capítulos, también crearás estos objetos tú mismo. A pesar de ser interesante, entender en realidad cómo estos objetos son codificados y almacenados no es vital para tu entendimiento.</p><h4 id="peque-a-recapitulaci-n-objetos-de-git">Pequeña recapitulación - Objetos de Git</h4><p>Para recapitular, en esta sección introdujimos tres objetos de Git:</p><ul><li><strong>Blob</strong> – contenidos de un archivo.</li><li><strong>Árbol</strong> – un listado de directorios (de blobs y árboles).</li><li><strong>Confirmación</strong> – una copia instantánea del árbol de trabajo.</li></ul><p>En el próximo capítulo, entenderemos sobre las ramas en Git.</p><!--kg-card-begin: html--><h2 id="cap-2">Capítulo 2 - Las ramas en Git</h2><!--kg-card-end: html--><p>En el capítulo anterior, sugerí que deberíamos ver a Git como un sistema para mantener un sistema de archivos.</p><p>Una de las maravillas de Git es que permite a múltiples personas trabajar en ese sistema de archivos, en paralelo, (mayormente) sin interferir en el trabajo de otros. La mayoría de las personas dirían que están "trabajando en la rama <code>X</code>." ¿Pero qué significa eso <em>en realidad</em>?</p><p><strong>Una rama es sólo una referencia nombrada a una confirmación.</strong></p><p>Siempre puedes referenciar a una confirmación por su hash SHA-1, pero los humanos usualmente prefieren otras formas de llamar a los objetos. Una rama es una forma de referenciar a una confirmación, pero realmente es eso nada más.</p><p>En la mayoría de los repositorios, la línea principal del desarrollo está hecho en una rama llamada <code>main</code>. Esto es sólo un nombre, y es creado cuando usas <code>git init</code>, haciéndolo que sea ampliamente usado. Sin embargo, podrías usar cualquier otro nombre que quisieres.</p><p>Típicamente, la rama apunta a la última confirmación en la línea de desarrollo en el que estás trabajando actualmente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/branch_01.png" class="kg-image" alt="A branch is just a named reference to a commit" width="600" height="400" loading="lazy"><figcaption>Una rama es solo una referencia nombrada a una confirmación</figcaption></figure><p>Para crear otra rama, puedes usar el comando <code>git branch</code>. Cuando haces eso, Git crea otro puntero. Si creaste una rama llamada <code>test</code>, usando <code>git branch test</code>, estarías creando otro puntero que apunta a la misma confirmación como la rama en la que se encuentra:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_branch.png" class="kg-image" alt="Usando  crea otro puntero" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git branch</code> creates another pointer</figcaption></figure><p>¿Cómo sabe Git la rama en que te encuentras actualmente? Mantiene otro puntero designado, llamado <code>HEAD</code>. Usualmente, <code>HEAD</code> apunta a una rama, que a su vez apunta a una confirmación. En el caso descrito, <code>HEAD</code> podría apuntar a <code>main</code>, que a su vez apunta a la confirmación <code>B2424</code>. En algunos casos, <code>HEAD</code> también puede apuntar a una confirmación directamente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/head_main.png" class="kg-image" alt=" points to the branch you are currently on" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> points to the branch you are currently on</figcaption></figure><p>Para cambiar la rama activa a ser <code>test</code>, puedes usar el comando <code>git checkout test</code>, o <code>git switch test</code>. Ahora ya puedes adivinar lo que hace este comando en realidad – solo cambia a <code>HEAD</code> a que apunte a <code>test</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/head_test.png" class="kg-image" alt=" changes where  points" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git checkout test</code> changes where <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> points</figcaption></figure><p>También podrías usar <code>git checkout -b test</code> antes de crear la rama <code>test</code>, el cual es el equivalente de ejecutar <code>git branch test</code> para crear la rama, y luego <code>git checkout test</code> para mover el <code>HEAD</code> a que apunte a la nueva rama.</p><p>Al punto representado en el dibujo de arriba, ¿qué sucedería si hicieras algunos cambios y crearas una nueva confirmación usando <code>git commit</code>? ¿A qué rama será agregada la nueva confirmación?</p><p>La respuesta es la rama <code>test</code>, ya que éste es la rama activa (ya que <code>HEAD</code> apunta a éste). Después, el puntero <code>test</code> se moverá a la nueva confirmación agregada recientemente. Fíjate que <code>HEAD</code> todavía apunta a <code>test</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/test_commit-1.png" class="kg-image" alt="Every time we use , the branch pointer moves to the newly created commit" width="600" height="400" loading="lazy"><figcaption>Every time we use <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git commit</code>, the branch pointer moves to the newly created commit</figcaption></figure><p>Si vuelves atrás a <code>main</code> usando <code>git checkout main</code>, Git moverá el <code>HEAD</code> a que apunta a <code>main</code> nuevamente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/back_to_main-1.png" class="kg-image" alt="The resulting state after using " width="600" height="400" loading="lazy"><figcaption>The resulting state after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git checkout main</code></figcaption></figure><p>Ahora, si creas otra confirmación, ¿a qué rama será agregado?</p><p>Así es, será agregado a la rama <code>main</code> (y su padre sería la confirmación <code>B2424</code>).</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_to_main-1.png" class="kg-image" alt="The resulting state after creating another commit on the  branch" width="600" height="400" loading="lazy"><figcaption>The resulting state after creating another commit on the <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code> branch</figcaption></figure><h3 id="peque-a-recapitulaci-n-las-ramas">Pequeña recapitulación - Las ramas</h3><ul><li>Una rama es una referencia nombrada a una confirmación.</li><li>Cuando uses <code>git commit</code>, Git crea un objeto de confirmación, y mueve la rama a que apunte a la confirmación creada recientemente.</li><li><code>HEAD</code> es un puntero especial que le dice a Git qué rama es la rama activa (en casos excepcionales, puede apuntar directamente a una confirmación).</li></ul><p>En los próximos capítulos, aprenderás cómo introducir cambios a Git. Crearás un repositorio desde cero – sin usar <code>git init</code>, <code>git add</code>, o <code>git commit</code>. Esto te permitirá profundizar tu entendimiento de lo que está pasando por debajo cuando trabajes con Git. También crearás nuevas ramas, cambiarás ramas, y crearás confirmaciones adicionales – todo sin usar <code>git branch</code> o <code>git checkout</code>. No lo sé tú, pero yo ¡ya estoy entusiasmado!</p><!--kg-card-begin: html--><h2 id="cap-3">Capítulo 3 - Cómo registrar cambios en Git</h2><!--kg-card-end: html--><p>Hasta ahora, hemos aprendido sobre cuatros entidades distintas en Git:</p><ol><li><strong>Blob</strong> – &nbsp;contenidos de un archivo.</li><li><strong>Árbol</strong> – un lista de directorios (de blobs y árboles).</li><li><strong>Confirmación</strong> – una copia instantánea del árbol de trabajo, con algunos metadatos tales como el tiempo o el mensaje de confirmación.</li><li><strong>Rama</strong> – una referencia nombrada a una confirmación.</li></ol><p>Los primeros tres son <em>objetos</em>, donde el cuarto es una forma de referirse a objetos (específicamente, confirmaciones).</p><p>Ahora, es tiempo de entender cómo introducir cambios en Git.</p><p>Cuando trabajas en tu código fuente, trabajas desde un <strong>directorio de trabajo</strong>. Un dir(ectorio) de trabajo (también llamado "árbol de trabajo") es cualquier directorio en tu sistema de archivos el cual tiene un repositorio asociado. Contiene las carpetas y los archivos de tu proyecto, y también un directorio llamado <code>.git</code> del cual hablaremos más adelante. Recuerda que dijimos que Git es un sistema para mantener un sistema de archivos. El directorio de trabajo es la raíz del sistema de archivos para Git.</p><p>Después de que haces algunos cambios, podrías querer registrarlos en tu repositorio. Un <strong>repositorio</strong> (en corto: "repo") es una colección de confirmaciones, cada uno de los cuales es un archivo de lo que el árbol de trabajo del proyecto parecía en una fecha anterior, sea en tu máquina o la de alguien más. Eso es, como dije antes, una confirmación es una copia instantánea del árbol de trabajo.</p><p>Un repositorio también incluye otras cosas además de tus archivos de código, tales como <code>HEAD</code> y <code>ramas</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_repo.png" class="kg-image" alt="A working dir alongside the repository" width="600" height="400" loading="lazy"><figcaption>Un directorio de trabajo junto al repositorio</figcaption></figure><p>Fíjate las convenciones del dibujo que uso: incluyo <code>.git</code> dentro del directorio de trabajo, para recordarte que es una carpeta dentro de la carpeta del proyecto en el sistema de archivos. La carpeta <code>.git</code> en realidad contiene los objetos del repositorio, como veremos en el <a href="#cap-4">capítulo 4</a>.</p><p>Hay otros sistemas de control de versión donde los cambios son confirmados directamente desde el directorio de trabajo al repositorio. En Git, este no es el caso. En sí, los cambios son primero registrados en algo llamado el <strong>índice</strong>, o el <strong>área de staging</strong>.</p><p>Ambos términos se refieren a la misma cosa, son usados frecuentemente en la documentación de Git. Usaré estos términos indistintamente a lo largo de este libro, ya que te sentirás mas cómodo con ambos.</p><p>Puedes imaginarte el agregar cambios al índice como una forma de "confirmando" tus cambios, uno por uno, antes de crear una confirmación (el cual registra todos los cambios aprobados de una sola vez).</p><p>Cuando haces <code>checkout</code> a una rama, Git popula el índice y el directorio de trabajo con los contenidos de los archivos ya que existen en la confirmación a la rama al cual está apuntando. Cuando usas <code>git commit</code>, Git crea un nuevo objeto de confirmación basado en el estado de ese índice.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo.png" class="kg-image" alt="The three &quot;states&quot; - working dir, index, and repository" width="600" height="400" loading="lazy"><figcaption>Los tres "estados" - directorio de trabajo, índice, y repositorio</figcaption></figure><p>Usando el índice te permite preparar cuidadosamente cada confirmación. Por ejemplo, podrías tener dos archivos con cambios en tu directorio de trabajo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo_02.png" class="kg-image" alt="Working dir includes two files with changes" width="600" height="400" loading="lazy"><figcaption>Working dir includes two files with changes</figcaption></figure><p>Por ejemplo, digamos que estos dos archivos son <code>1.txt</code> y <code>2.txt</code>. Es posible agregar solamente uno de ellos (por ejemplo, <code>1.txt</code>) al índice, usando <code>git add 1.txt</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo_03.png" class="kg-image" alt="The state after staging " width="600" height="400" loading="lazy"><figcaption>The state after staging <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">1.txt</code></figcaption></figure><p>Como resultado, el estado del índice coincide con el estado del <code>HEAD</code> (en este caso, "Commit 2"), con la excepción del archivo 1.txt, el cual coincide el estado de <code>1.txt</code> en el directorio de trabajo. Ya que no pusiste en el área de preparación a <code>2.txt</code>, el índice no incluye a la versión actualizada de <code>2.txt</code>. Así que el estado de <code>2.txt</code> en el índice coincide con el estado de <code>2.txt</code> en el "Commit 2".</p><p>En detrás de escena - una vez que pones en el área de preparación una versión de un archivo, Git crea un objeto blob con los contenidos del archivo. Este objeto blob es agregado luego al índice. Siempre y cuando solamente modifiques el archivo en el directorio de trabajo, sin ponerlo en el área de preparación, los cambios que hagas no son registrados en los objetos blob.</p><p>Cuando consideramos la figura previa, fíjate que no dibujo la versión del área de preparación del archivo como parte del "repositorio", ya que esta representación, el "repositorio" se refiere a un árbol de confirmaciones y sus referencias, y este blob no ha sido parte de ninguna confirmación.</p><p>Ahora, puedes usar <code>git commit</code> para registrar el cambio a <code>1.txt</code> <em>solamente</em>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/working_dir_index_repo_04.png" class="kg-image" alt="The state after using " width="600" height="400" loading="lazy"><figcaption>The state after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git commit</code></figcaption></figure><p>Usando <code>git commit</code> ejecuta dos operaciones principales:</p><ol><li>Crea un nuevo objeto de confirmación. Este objeto de confirmación refleja el estado del índice cuando ejecutaste el comando <code>git commit</code>.</li><li>Actualiza a la rama activa para que apunte a la confirmación creada recientemente. En este ejemplo, el <code>main</code> ahora apunta al "Commit 3", el nuevo objeto de confirmación.</li></ol><h3 id="c-mo-crear-un-repo-la-forma-convencional">Cómo crear un repo – La Forma Convencional</h3><p>Vamos a asegurarnos que entiendas cómo los términos que hemos introducidos se relacionan al proceso de crear un nuevo repositorio. Este es un vistazo rápido de alto nivel, antes de sumergirnos más profundamente en este proceso.</p><p>Inicializa un nuevo repositorio usando <code>git init my_repo</code>, y luego cambia tu directorio al repositorio usando <code>cd my_repo</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_init.png" class="kg-image" alt="git_init" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git init</code></figcaption></figure><p>Usando <code>tree -f .git</code> puedes ver que ejecutando <code>git init my_repo</code> resultó en unos pocos sub-directorios dentro de <code>.git</code>. (El argumento <code>-f</code> incluye archivos en la salida del árbol).</p><p>Nota: si estás usando Windows, ejecuta <code>tree /f .git</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_init_tree_f.png" class="kg-image" alt="The output of  after using " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">tree -f .git</code> after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git init</code></figcaption></figure><p>Crea un archivo dentro del directorio <code>my_repo</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_f_txt.png" class="kg-image" alt="Creating " width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">f.txt</code></figcaption></figure><p>Este archivo está dentro de tu directorio de trabajo. Si ejecutas <code>git status</code>, verás este archivo no está rastreado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_f_txt_git_status.png" class="kg-image" alt="The result of " width="600" height="400" loading="lazy"><figcaption>The result of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code></figcaption></figure><p>Los archivos en tu directorio de trabajo puede ser uno de los dos estados: <strong>rastreados</strong> o <strong>no rastreados</strong>.</p><p>Los archivos <strong>rastreados</strong> son archivos que Git "conoce". Ellos estuvieron en la última confirmación, o están en el área de preparación ahora (eso es, están en el área staging).</p><p>Los archivos <strong>no rastreados</strong> son todos los demás – cualquier archivo en tu directorio de trabajo que no estuvieron en tu última confirmación, y que no están en tu área de preparación.</p><p>El nuevo archivo (<code>f.txt</code>) no está rastreado actualmente, ya que no lo has agregado al área de preparación, y no ha sido incluido en la confirmación anterior.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/drawing_new_untracked_file.png" class="kg-image" alt=" is in the working directory (and untracked)" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">f.txt</code> is in the working directory (and untracked)</figcaption></figure><p>Ahora puedes agregar este archivo al área de preparación (también referido como poner en staging este archivo) usando <code>git add f.txt</code>. Puedes verificar que ha sido puesto en el área de preparación ejecutando <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_add_status.png" class="kg-image" alt="Adding the new file to the staging area" width="600" height="400" loading="lazy"><figcaption>Adding the new file to the staging area</figcaption></figure><p>Así que ahora el estado del índice coincide con el directorio de trabajo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/drawing_new_staged_file.png" class="kg-image" alt="The state after adding the new file" width="600" height="400" loading="lazy"><figcaption>The state after adding the new file</figcaption></figure><p>Ahora puedes crear una confirmación usando <code>git commit</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/initial_commit.png" class="kg-image" alt="Committing an initial commit" width="600" height="400" loading="lazy"><figcaption>Committing an initial commit</figcaption></figure><p>Si ejecutas <code>git status</code> nuevamente, verás que el estado está limpio - eso es, el estado de <code>HEAD</code> (el cal apunta a tu confirmación inicial) equivale al estado del índice, y también el estado del directorio de trabajo. Usando <code>git log</code> verás en realidad que <code>HEAD</code> apunta a <code>main</code> el cual a su vez apunta a la nueva confirmación:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/initial_commit_git_log.png" class="kg-image" alt="The output of  after introducing the first commit" width="600" height="400" loading="lazy"><figcaption>The output of `git log` after introducing the first commit</figcaption></figure><p>¿Ha cambiado algo dentro del directorio <code>.git</code>? Ejecuta <code>tree -f .git</code> para verificar:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_f_after_initial_commit.png" class="kg-image" alt="A lot of things have changed within " width="600" height="400" loading="lazy"><figcaption>A lot of things have changed within <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">.git</code></figcaption></figure><p>Aparentemente, un montón ha cambiado. Es tiempo de sumergirnos más profundo en la estructura de <code>.git</code> y entender qué está pasando por detrás cuando ejecutas <code>git init</code>, <code>git add</code> o <code>git commit</code>. Eso es exactamente lo que cubrirá el próximo capítulo.</p><h3 id="recapitulaci-n-c-mo-registrar-cambios-en-git">Recapitulación - Cómo registrar cambios en Git</h3><p>Aprendiste sobre los tres "estados" distintos del sistema de archivos que Git mantiene:</p><ul><li><strong>Dir(ectorio) de trabajo</strong> (también llamado "árbol de trabajo") - cualquier directorio en tu sistema de archivos el cual tiene un repositorio asociado.</li><li><strong>Índice</strong>, o el <strong>Área de preparación</strong> - un espacio de interacción para la próxima confirmación.</li><li><strong>Repositorio</strong> (en corto: "repo") - una colección de confirmaciones, el cual cada una es una copia instantánea del árbol de trabajo.</li></ul><p>Cuando introduces cambios en Git, casi siempre sigue este orden:</p><ol><li>Cambias el directorio de trabajo primero</li><li>Luego pones estos cambios en el área de preparación (o algunos de ellos) al índice</li><li>Y finalmente, confirmas estos cambios - de esta forma actualiza el repositorio con una nueva confirmación. El estado de esta nueva confirmación coincide con el estado del índice</li></ol><p>¿Listo para sumergirte más profundo?</p><!--kg-card-begin: html--><h2 id="cap-4">Capítulo 4 - ¿Cómo crear un repo desde cero?</h2><!--kg-card-end: html--><p>Hasta ahora hemos cubiertos algunos fundamentos de Git, y ahora deberías estar listo para realmente continuar con <em>Git</em>.</p><p>Para entender profundamente cómo funciona Git, crearás un repositorio, pero esta vez – lo construirás desde cero. Como en otros capítulos, te animo a intentar los comandos a lo largo de este capítulo.</p><h3 id="c-mo-configurar-git">Cómo configurar <code>.git</code></h3><p>Crea un nuevo directorio, y ejecuta <code>git status</code> dentro:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_dir_git_status.png" class="kg-image" alt=" in a new directory" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> in a new directory</figcaption></figure><p>Muy bien, parece que Git no está feliz ya que no tiene una carpeta <code>.git</code> todavía. Lo natural por hacer sería crear ese directorio e intentarlo otra vez:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/mkdir_git_git_status.png" class="kg-image" alt=" after creating " width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> after creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">.git</code></figcaption></figure><p>Aparentemente, crear un directorio <code>.git</code> no es suficiente. Necesitas agregar algún contenido a ese directorio.</p><p>Un repositorio de Git tiene dos conceptos principales:</p><ul><li>Una colección de <strong>objetos</strong> – blobs, árboles, y confirmaciones.</li><li>Un sistema de <strong>nombramiento</strong> de esos objetos – llamados referencias.</li></ul><p>Un repositorio también podría contener otras cosas, tales como hooks, pero a lo menos – debe incluir objetos y referencias.</p><p>Crear un repositorio para los objetos en <code>.git/objets</code>, y un directorio para las referencias (en forma corta: "refs") en <code>.git/refs</code> (en sistemas Windows – <code>.git\objects</code> y <code>.git\refs</code>, respectivamente).</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_folders_git_tree.png" class="kg-image" alt="Considering the directory tree" width="600" height="400" loading="lazy"><figcaption>Considering the directory tree</figcaption></figure><p>Un tipo de referencia son las ramas. Internamente, Git llama a las ramas por el nombre de <code>heads</code>. Crea un directorio para las ramas – <code>.git/refs/heads</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_heads_folder_git_tree.png" class="kg-image" alt="The directory tree" width="600" height="400" loading="lazy"><figcaption>The directory tree</figcaption></figure><p>Esto todavía no cambia el resultado de <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_heads_folder_git_status.png" class="kg-image" alt=" after creating " width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> after creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">.git/refs/heads</code></figcaption></figure><p>¿Cómo sabe Git dónde comenzar cuando busca una confirmación en el repositorio? Como expliqué antes, busca el <code>HEAD</code>, el cual apunta a la rama actual activa (o la confirmación, en algunos casos).</p><p>Así que, necesitas crear el <code>HEAD</code>, el cual es sólo un archivo que reside en <code>.git/HEAD</code>. Puedes aplicar lo siguiente:</p><p>En UNIX:</p><pre><code class="language-bash">echo "ref: refs/heads/main" &gt; .git/HEAD
</code></pre><p>En Windows:</p><pre><code class="language-bash">echo ref: refs/heads/main &gt; .git\HEAD
</code></pre><p>Así que ahora sabes cómo se implementa <code>HEAD</code> – es simplemente un archivo, y su contenido describe a qué apunta.</p><p>Siguiendo el comando de arriba, <code>git status</code> parece cambiar su pensamiento:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_head_git_status.png" class="kg-image" alt=" is just a file" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> is just a file</figcaption></figure><p>Fíjate que Git "cree" que estás en la rama llamada <code>main</code>, aunque no has creado esta rama. <code>main</code> es sólo un nombre. También puedes hacer creer a Git que estás en una rama llamada <code>banana</code> si quieres:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/banana.png" class="kg-image" alt="Creating a branch named " width="600" height="400" loading="lazy"><figcaption>Creating a branch named <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">banana</code></figcaption></figure><p>Vuelve al <code>main</code>, ya que continuarás trabajando (mayormente) allí a lo largo de este capítulo, sólo para aderirnos a la convención regular:</p><pre><code class="language-bash">echo "ref: refs/heads/main" &gt; .git/HEAD
</code></pre><p>Ahora que tienes tu directorio <code>.git</code> listo, puedes trabajar a tu manera para hacer una confirmación (de nuevo, sin usar <code>git add</code> o <code>git commit</code>).</p><h3 id="comandos-de-plomer-a-vs-comandos-de-porcelana-en-git">Comandos de plomería vs comandos de porcelana en Git</h3><p>A este punto, debería ser bueno hacer una distinción entre dos tipos de comandos de Git: de plomería y de porcelana. La aplicación de los términos extrañamente viene de los baños, tradicionalmente los hechos de porcelana, y la infraestructura de la plomería (las cañerías y los drenajes).</p><p>La capa de porcelana provee una interfaz amigable para el usuario en la plomería. La mayoría de la gente solamente manejan la porcelana. Aún así, cuando las cosas van (terriblemente) mal, y alguien quiere entender el por qué, tendrían que remangarse y tratar con la plomería.</p><p>Git usa esta terminología como una analogía para separar los comandos de bajo nivel que los usuarios usualmente no necesitan usar directamente (comandos "de plomería") de los comandos de alto nivel (comandos "de porcelana").</p><p>Hasta ahora, has lidiado con comandos de porcelana – <code>git init</code>, <code>git add</code> o <code>git commit</code>. Es tiempo de ir más profundo, y que te familiarices con algunos comandos de plomería.</p><h3 id="c-mo-crear-objetos-en-git">Cómo crear objetos en Git</h3><p>Empieza por crear un objeto y escríbelo dentro de la base de datos de los objetos de Git, que reside dentro de <code>.git/objects</code>. Para saber el valor del hash SHA-1 de un blob, puedes usar <code>git hash-object</code>. (Sí, un comando de plomería), de la siguiente forma:</p><p>En UNIX:</p><pre><code class="language-bash">echo "Git is awesome" | git hash-object --stdin
</code></pre><p>En Windows:</p><pre><code class="language-bash">&gt; echo Git is awesome | git hash-object --stdin
</code></pre><p>Usando <code>--stdin</code> estás instruyendo a <code>git hash-object</code> que tome su entrada de la entrada estándar. Esto te proveerá con el valor del hash relevante:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/hash_object.png" class="kg-image" alt="Getting a blob's SHA-1" width="600" height="400" loading="lazy"><figcaption>Getting a blob's SHA-1</figcaption></figure><p>En realidad para escribir ese blob dentro de la base de datos de objetos de Git, puedes agregar el conmutador <code>-w</code> por <code>git hash-object</code>. Después, verifica el contenido de la carpeta <code>.git</code>, y mira si han cambiado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/write_blob.png" class="kg-image" alt="Writing a blob to the objects' database" width="600" height="400" loading="lazy"><figcaption>Writing a blob to the objects' database</figcaption></figure><p>Puedes ver que el hash de tu blob es <code>7a9bd34a0244eaf2e0dda907a521f43d417d94f6</code>. También puedes ver que un directorio ha sido creado como <code>.git/objects</code>, un directorio llamado <code>7a</code>, y dentro, un archivo con el nombre de <code>7a9bd34a0244eaf2e0dda907a521f43d417d94f6</code>.</p><p>Lo que Git hizo aquí es tomar los primeros dos caracteres del hash SHA-1, y usarlos como el nombre de un directorio. Los caracteres sobrantes son usados como el nombre de archivo para el archivo que en realidad contiene el blob.</p><p>¿Por qué eso es así? Considera un repositorio considerablemente grande, uno que tiene 400,000 objetos (blobs, árboles, y confirmaciones) en su base de datos. Buscar un hash dentro de esa lista de 400,000 hashes podría tomar un buen rato. Así, Git simplemente divide ese problema por <code>256</code>.</p><p>Para buscar el hash de arriba, Git primero miraría el directorio llamado <code>7a</code> dentro del directorio <code>.git/objects</code>, el cual tendría hasta 256 directorios (<code>00</code> hasta <code>FF</code>). Luego, buscaría dentro de ese directorio, acortando la búsqueda a medida que continúa.</p><p>De vuelta al proceso de generar una confirmación. Has creado un objeto solamente. ¿Cuál es el tipo de ese objeto? Puedes usar otro comando de plomería, <code>git cat-file -t</code> (<code>-t</code> significa "type" - "tipo"), para verificar eso:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_t_blob.png" class="kg-image" alt="Using  reveals the type of the Git object" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git cat-file -t &lt;object_sha&gt;</code> reveals the type of the Git object</figcaption></figure><p>No sorprendentemente, este objeto es un blob. También puedes usar <code>git cat-file -p</code> (<code>-p</code> significa "pretty-print" - "imprimir-bonito") para ver su contenido:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_p_blob.png" class="kg-image" alt="cat_file_p_blob" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git cat-file -p</code></figcaption></figure><p>Este proceso de crear un objeto blob como <code>.git/objects</code> usualmente sucede cuando agregas algo al área de preparación – eso es, cuando usas <code>git add</code>. Así que los blobs no son creados cada vez que guardes un archivo al sistema de archivos (el directorio de trabajo), sino solamente cuando lo pongas en el área de preparación.</p><p>Recuerda que Git crea un blob del archivo <em>entero</em> que se pone en el área de preparación. Inclusive si un solo caracter es modificado o agregado, el archivo tiene un nuevo blob con un nuevo hash (como en el ejemplo del <a href="#cap-1">capítulo 1</a> donde agregaste <code>!</code> al final de la línea).</p><p>¿Habrá algún cambio a <code>git status</code>?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_blob.png" class="kg-image" alt=" after creating a blob object" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> after creating a blob object</figcaption></figure><p>Aparentemente, no. Agregar un objeto blob a la base de datos interno de Git no cambia el estado, ya que Git no sabe de ningún archivo con seguimiento (o sin seguimiento) en esta área de preparación.</p><p>Necesitas rastrear este archivo – agregarlo al área de preparación. Para hacer eso, puedes usar otro comando de plomería, <code>git update-index</code>, así:</p><pre><code class="language-bash">git update-index --add --cacheinfo 100644 &lt;blob-hash&gt; &lt;filename&gt;
</code></pre><p><strong>Nota</strong>: El <code>cacheinfo</code> es un modo de archivo de 16-bits almacenado por Git, siguiendo el diseño de los tipos y modos de POSIX. Esto no está dentro del enfoque de este libro, ya que no es realmente importante para que hagas las cosas.</p><p>Ejecutar el comando de arriba resultará en un cambio al contenido de <code>.git</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/update_index.png" class="kg-image" alt="The state of  after updating the index" width="600" height="400" loading="lazy"><figcaption>The state of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">.git</code> after updating the index</figcaption></figure><p>¿Puedes encontrar el cambio? Un nuevo archivo con el nombre de <code>index</code> ha sido creado. Eso es todo – el famoso índice (o área de preparación), es básicamente un archivo que reside dentro de <code>.git/index</code>.</p><p>Así que ahora que tu blob ha sido agregado al índice, ¿esperas que <code>git status</code> luzca diferente?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_update_index.png" class="kg-image" alt=" after using " width="600" height="400" loading="lazy"><figcaption>`git status` after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git update-index</code></figcaption></figure><p>¡Eso es interesante! Dos cosas pasaron aquí.</p><p>Primero, puedes ver que <code>awesome.txt</code> aparece en <em>verde</em>, en el área "Changes to be committed" ("Cambios a ser confirmados"). Eso es así porque el índice ahora incluye a <code>awesome.txt</code>, esperando a ser confirmado.</p><p>Segundo, podemos ver que <code>awesome.txt</code> aparece en <em>rojo</em> – porque Git cree que el archivo <code>awesome.txt</code> ha sido eliminado, y el hecho que el archivo ha sido eliminado sino que no está en el área de preparación.</p><p>(Nota: te habrás dado cuenta que a veces me refiero a Git con palabras tales como "cree", "piensa", o "quiere". Como expliqué en la <a href="#intro">introducción de este libro</a> - para que disfrutemos jugando con Git, y leer (y escribir) este libro, siento que referirse a Git más que sólo código lo hace mucho más divertido.)</p><p>Esto sucede ya que agregaste el blob con el contenido <code>Git is awesome</code> a la base de datos de los objetos, y actualizaste el índice que el archivo <code>awesome.txt</code> retiene el contenido de ese blob, pero en realidad nunca creaste ese archivo en el disco.</p><p>Fácilmente puedes resolver esto tomando el contenido de ese blob y escribirlo a nuestro sistema de archivos, a un archivo llamado <code>awesome.txt</code>:</p><pre><code class="language-bash">echo "Git is awesome" &gt; awesome.txt
</code></pre><p>Como resultado, ya no aparecerá en rojo por <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_creating_file_on_disk.png" class="kg-image" alt=" after creating  on disk" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> after creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">awesome.txt</code> on disk</figcaption></figure><p>Así que ahora es tiempo de crear un objeto de confirmación desde tu área de preparación. Como expliqué en el <a href="#cap-1">capítulo 1</a>, un objeto de confirmación tiene una referencia a un árbol, así que necesitas crear un árbol.</p><p>Puedes lograr esto usando el comando <code>git write-tree</code>, el cual registra los contenidos del índice en un objeto árbol. Por supuesto, puedes usar <code>git cat-file -t</code> para ver que en sí es un árbol:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/write_tree.png" class="kg-image" alt="Creating a tree object with the contents of the index" width="600" height="400" loading="lazy"><figcaption>Creating a tree object with the contents of the index</figcaption></figure><p>Y puedes usar <code>git cat-file -p</code> para ver su contenido:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_p_tree.png" class="kg-image" alt=" to see the tree's contents" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git cat-file -p</code> to see the tree's contents</figcaption></figure><p>Genial, así que creaste un árbol, y ahora necesitas crear un objeto de confirmación que referencia a este árbol. Para hacer eso, puedes usar el comando:</p><pre><code class="language-bash">git commit-tree &lt;tree-hash&gt; -m &lt;commit message&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit-tree.png" class="kg-image" alt="Committing using the tree object" width="600" height="400" loading="lazy"><figcaption>Committing using the tree object</figcaption></figure><p>Ahora deberías sentirte cómodo con los comandos usados para verificar el tipo de objeto creado, e imprimir su contenido:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_object_cat_file.png" class="kg-image" alt="Creating a commit object" width="600" height="400" loading="lazy"><figcaption>Creating a commit object</figcaption></figure><p>Fíjate que este objeto de confirmación no tiene un padre, porque no es la primer confirmación. Cuando agregas otra confirmación probablemente querrás declarar su padre – no te preocupes, lo harás así más tarde.</p><p>El último hash que tuvimos – <code>b6d05ee40344ef5d53502539772086da14ad2b07</code> – es un hash de la confirmación. En realidad deberías estar acostumbrado en usar estos hashes – probablemente los ves todo el tiempo (cuando usas <code>git log</code>, por ejemplo). Fíjate que el objeto de confirmación apunta a un objeto de árbol, con su propio hash, el cual raramente especificas explícitamente.</p><p>¿Cambiará algo en <code>git status</code>?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_creating_commit_object.png" class="kg-image" alt=" after creating a commit object" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> after creating a commit object</figcaption></figure><p>No, nada ha cambiado. ¿Por qué es eso?</p><p>Bueno, para saber que tu archivo ha sido confirmado, Git necesita saber sobre la última confirmación. ¿Cómo sabe Git eso? Va al <code>HEAD</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/looking_at_head_1.png" class="kg-image" alt="Looking at the contents of " width="600" height="400" loading="lazy"><figcaption>Looking at the contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p><code>HEAD</code> apunta a <code>main</code>, pero, ¿qué es <code>main</code>? Aún no lo has creado.</p><p>Como explicamos en el <a href="#cap-2">capítulo 2</a>, una rama es simplemente una referencia nombrada a una confirmación. Y en este caso, nos gustaría que <code>main</code> se refiriera al objeto de confirmación con el hash <code>b6d05ee40344ef5d53502539772086da14ad2b07</code>.</p><p>Puedes lograr esto creando un archivo en <code>.git/refs/heads/main</code>, con el contenido de este hash, así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/creating_main.png" class="kg-image" alt="Creating " width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>En resumen, una rama es sólo un archivo dentro de <code>.git/refs/heads</code>, que contiene un hash de la confirmación a la que se refiere.</p><p>Ahora, finalmente, <code>git status</code> y <code>git log</code> parecen apreciar nuestros esfuerzos:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_commit_1.png" class="kg-image" alt="git_status_commit_1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code></figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_commit_1.png" class="kg-image" alt="git_log_commit_1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code></figcaption></figure><p>¡Has creado con éxito una confirmación sin usar comandos de porcelana! ¿No es genial eso?</p><h3 id="recapitulaci-n-c-mo-crear-un-repo-desde-cero">Recapitulación - Cómo crear un repo desde cero</h3><p>En este capítulo, sin miedo te sumergiste en profundidad en Git. Paraste de usar comandos de porcelana y te cambiaste a los comandos de plomería.</p><p>Al usar echo y comandos de nivel bajo tales como <code>git hash-object</code>, fuiste capaz de crear un blob, agregarlo al índice, crear un árbol del índice, y crear un objeto de confirmación apuntando a ese árbol.</p><p>También aprendiste que <code>HEAD</code> es un archivo, localizado en <code>.git/HEAD</code>. Las ramas son archivos también, localizados en <code>.git/refs/heads</code>. Cuando entiendes cómo opera Git, esas nociones abstractas de <code>HEAD</code> o "ramas" se vuelven muy tangibles.</p><p>En el próximo capítulo profundizarás tu entendimiento de cómo trabajan las ramas por detrás.</p><!--kg-card-begin: html--><h2 id="cap-5">Capítulo 5 - Cómo trabajar con las ramas en Git – Por debajo</h2><!--kg-card-end: html--><p>En el capítulo anterior creaste un repositorio y una confirmación sin usar <code>git init</code>, <code>git add</code> o <code>git commit</code>. En este capítulo, crearemos y cambiaremos entre ramas sin usar comandos de porcelana (<code>git branch</code>, <code>git switch</code>, o <code>git checkout</code>).</p><p>Es perfectamente entendible si estás emocionado, ¡yo también lo estoy!</p><p>Continuando con lo del capítulo anterior - solamente tienes una rama, llamada <code>main</code>. Para crear otra con el nombre de <code>test</code> (como el equivalente de <code>git branch test</code>), necesitarías crear un archivo llamado <code>test</code> dentro de <code>.git/refs/heads</code>, y el contenido de ese archivo sería el mismo hash de la confirmación al que apunta la rama <code>main</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_test_branch.png" class="kg-image" alt="Creating  branch" width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test</code> branch</figcaption></figure><p>Si usas <code>git log</code>, puedes ver que esto en sí es el caso – ambos <code>main</code> y <code>test</code> apuntan a esta confirmación:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_creating_test_branch.png" class="kg-image" alt=" after creating  branch" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> after creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test</code> branch</figcaption></figure><p>(Nota: si ejecutas este comando y no ves una salida válida, podrías haber escrito algo más que el hash de la confirmación en <code>.git/refs/heads/test</code>.)</p><p>Siguiente, cambiar a nuestra rama creada recientemente (el equivalente de <code>git checkout test</code>). ¿Cómo harías eso? Intenta responderte a ti mismo antes de que nos movamos al siguiente párrafo.</p><p>Para cambiar la rama activa, debería cambiar el <code>HEAD</code> a que apunte a tu nueva rama:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/change_head_to_test.png" class="kg-image" alt="Switching to branch  by changing " width="600" height="400" loading="lazy"><figcaption>Switching to branch <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test</code> by changing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>Como puedes ver, <code>git status</code> confirma que <code>HEAD</code> ahora apunta a <code>test</code>, el cual es, por lo tanto, la rama activa.</p><p>Ahora puedes usar los comandos que ya has usado en el capítulo anterior para crear otro archivo y agregarlo al índice:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/writing_another_file.png" class="kg-image" alt="Writing and staging another file" width="600" height="400" loading="lazy"><figcaption>Writing and staging another file</figcaption></figure><p>Siguiendo los comandos de arriba, tu:</p><ul><li>Creas un blob con el contenido de <code>Another file</code> (usando <code>git hash-object</code>).</li><li>Agregas al índice con el nombre de <code>another_file.txt</code> (usando <code>git update-index</code>).</li><li>Creas un archivo correspondiente en el disco con el contenido del blob (usando <code>git cat-file -p</code>).</li><li>Creas un objeto árbol representando al índice (usando <code>git write-tree</code>).</li></ul><p>Ahora es tiempo de crear una confirmación que referencie a este árbol. Esta vez, también deberías especificar el padre de esta confirmación – el cual debería ser la confirmación anterior. Especificas el padre usando el argumento <code>-p</code> de <code>git commit-tree</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2.png" class="kg-image" alt="Creating another commit object" width="600" height="400" loading="lazy"><figcaption>Creating another commit object</figcaption></figure><p>Hemos creado una confirmación, con un árbol así también como un padre, como puedes ver:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file_commit_2.png" class="kg-image" alt="Observing the new commit object" width="600" height="400" loading="lazy"><figcaption>Observing the new commit object</figcaption></figure><p>¿<code>git log</code> nos mostrará la nueva confirmación?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_creating_commit_2.png" class="kg-image" alt=" after creating &quot;Commit 2&quot;" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> after creating "Commit 2"</figcaption></figure><p>Como puedes ver, <code>git log</code> no nos muestra nada nuevo. ¿Por qué es eso?</p><p>Recuerda que <code>git log</code> rastrea las ramas para encontrar confirmaciones relevantes para mostrar. Nos muestra ahora <code>test</code> y la confirmación a la que apunta, y también nos muestra a <code>main</code> el cual apunta a la misma confirmación.</p><p>Así es – necesitas hacer que <code>test</code> apunte al nuevo objeto de confirmación. Puedes hacer eso cambiando el contenido de <code>.git/refs/heads/test</code>:</p><pre><code class="language-bash">echo 22267a945af8fde78b62ee7f705bbecfdd276b3d &gt; .git/refs/heads/test
</code></pre><p>Y ahora si ejecutas <code>git log</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_updating_test_branch.png" class="kg-image" alt=" after updating  branch" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> after updating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test</code> branch</figcaption></figure><p>¡Funcionó!</p><p><code>git log</code> va al <code>HEAD</code>, el cual le dice a Git que vaya a la rama <code>test</code>, el cual apunta a la confirmación <code>222..3d</code>, el cual se enlaza a su confirmación padre <code>b6d..07</code>.</p><p>Admira la belleza de Git 😊</p><p>Al inspeccionar la carpeta de tu repositorio, puedes ver que tienes seis objetos distintos en la carpeta <code>.git/objects</code> - estos son los dos blobs que creaste (uno para <code>awesome.txt</code> y uno para <code>file.txt</code>), dos objetos de confirmación ("Commit 1" y "Commit 2"), y los tres objetos - cada uno apuntado por uno de los objetos de confirmación.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/tree_after_commit_2.png" class="kg-image" alt="The tree listing after creating &quot;Commit 2&quot;" width="600" height="400" loading="lazy"><figcaption>The tree listing after creating "Commit 2"</figcaption></figure><p>También tienes a <code>.git/HEAD</code> que apunta a la rama o confirmación activa, y dos ramas - dentro de <code>.git/refs/heads</code>.</p><h3 id="recapitulaci-n-c-mo-trabajar-con-las-ramas-en-git-por-debajo">Recapitulación - Cómo trabajar con las ramas en Git – Por debajo</h3><p>En este capítulo entendiste cómo trabajan realmente las ramas en Git.</p><p>Las cosas principales que cubrimos:</p><ul><li>Una rama es un archivo en la carpeta <code>.git/refs/heads</code>, donde el contenido del archivo es una valor SHA-1 de una confirmación.</li><li>Para crear una nueva rama, Git simplemente crea un nuevo archivo en la carpeta <code>.git/refs/heads</code> con el nombre de la rama - por ejemplo, <code>.git/refs/heads/my_branch</code> para la rama <code>my_branch</code>.</li><li>Para cambiar la rama activa, Git modifica el contenido de <code>.git/HEAD</code> para referirse a la nueva rama activa. <code>.git/HEAD</code> también podría apunta a un objeto de confirmación directamente.</li><li>Cuando se confirma usando <code>git commit</code>, Git crea un objeto de confirmación, y también mueve la rama actual (eso es, el contenido del archivo en <code>.git/refs/heads</code>) a que apunte al objeto de confirmación recientemente creado.</li></ul><h2 id="parte-1-resumen">Parte 1 - Resumen</h2><p>Esta parte te introdujo lo interno de Git. Empezamos cubriendo <a href="#cap-1">los objetos básicos – blobs, árboles, y confirmaciones</a>.</p><p>Aprendiste que un <strong>blob</strong> contiene el contenido de un archivo. Un <strong>árbol</strong> es un listado de directorios, conteniendo blobs y/o sub árboles. Una <strong>confirmación</strong> es una copia instantánea de nuestro directorio de trabajo, con algunos meta datos tales como el tiempo o el mensaje de confirmación.</p><p>Aprendiste sobre <a href="#cap-2">las ramas</a>, viendo que no son más que una referencia nombrada a una confirmación.</p><p>Aprendiste el proceso de <a href="#cap-3">registrar cambios en Git</a>, y que involucra el <strong>directorio de trabajo</strong>, un directorio que tiene un repositorio al que se asocia, el <strong>área de preparación (índice)</strong> el cual contiene el árbol para la próxima confirmación, y el <strong>repositorio</strong>, el cual es una colección de confirmaciones y referencias.</p><p>Clarificamos cómo estos términos se relacionan a los comandos de Git que conocemos al crear un nuevo repositorio y confirmando un archivo usando los comandos bien conocidos <code>git init</code>, <code>git add</code> y <code>git commit</code>.</p><p>Luego <a href="#cap-4">creaste un nuevo repositorio desde cero</a>, usando <code>echo</code> y comandos de bajo nivel tales como <code>git hash-object</code>. Creaste un blob, le agregaste al índice, creaste un objeto de árbol representando al índice, e inclusive creaste un objeto de confirmación apuntando a ese árbol.</p><p>También fuiste capaz de crear y cambiar entre ramas modificando los archivos directamente. ¡Felicitaciones para aquellos que lo intentaron por sí mismos!</p><p>Todo junto ya, después de seguirme en esta parte, deberías sentir que has profundizado tu entendimiento de lo que está pasando por debajo cuando trabajas con Git.</p><p>La próxima parte explorarás diferentes estrategias para integrar cambios cuando se trabaja en diferentes ramas en Git - específicamente, merge y rebase.</p><!--kg-card-begin: html--><h1 id="part-2">Parte 2 - Ramificando e Integrando Cambios</h1><!--kg-card-end: html--><!--kg-card-begin: html--><h2 id="cap-6">Capítulo 6 - Diffs y Parches</h2><!--kg-card-end: html--><p>En la parte 1 aprendiste cómo funciona Git por detrás, los diferentes objetos de Git, y cómo crear un repo desde cero.</p><p>Cuando los equipos trabajan con Git, introducen secuencias de cambios, usualmente en ramas, y luego necesitan combinar diferente historiales de cambios juntos. Para realmente entender cómo se logra esto, deberías aprender cómo trata Git a los diffs y a los parches. Luego aplicarás tus conocimientos para entender el proceso de merge y rebase.</p><p>Muchos de los procesos interesantes de Git como fusión, rebasing, o inclusive confirmar están basados en los diffs y parches. Los desarrolladores trabajan con diffs todo el tiempo, estés usando Git directamente o basándote en la vista diff del IDE. En este capítulo, aprenderás cómo son los diffs y parches, su esctructura, y cómo aplicar parches.</p><p>Como recordatorio del <a href="#cap-1">capítulo de Objetos de Git</a>, una confirmación es una copia instantánea del árbol de trabajo en un cierto punto en el tiempo, además de algunos metadatos.</p><p>Aún así, es realmente difícil entender las confirmaciones individuales al mirar el árbol entero de trabajo. En sí, es más útil mirar cuán diferente es una confirmación de su confirmación padre, eso es, la diff entre estas confirmaciones.</p><p>Así que, ¿a qué me refiero cuando digo "diff"? Empecemos con algo de historia.</p><h3 id="la-historia-de-diff-de-git">La historia de diff de Git</h3><p>El <code>diff</code> de Git está basado en la utilidad diff de sistemas UNIX. <code>diff</code> fue desarrollado a principios de los '70 en el sistema operativo Unix. La primer versión lanzada se envió con la Quinta Edición de Unix en 1974.</p><p><code>git diff</code> es un comando que toma dos entradas, y calcula la diferencia entre ellos. Las entradas pueden ser confirmaciones, pero también archivos, e inclusive archivos que nunca han sido introducidos al repositorio.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_definition.png" class="kg-image" alt="Git diff takes two inputs, which can be commits or files" width="600" height="400" loading="lazy"><figcaption>Git diff takes two inputs, which can be commits or files</figcaption></figure><p>Esto es importante - <code>git diff</code> calcula la <em>diferencia</em> entre dos cadenas, el cual la mayor de las veces llega a consistir en código, pero no necesariamente.</p><h3 id="tiempo-de-manos-a-la-obra">Tiempo de manos a la obra</h3><p>Como siempre, se te anima a que ejecutes los comandos tu mismo al leer este capítulo. A menos que se diga otra cosa, usaré el siguiente repositorio:</p><p><a href="https://github.com/Omerr/gitting_things_repo.git">https://github.com/Omerr/gitting_things_repo.git</a></p><p>Lo puedes clonar localmente y tener el mismo punto de comienzo que estoy usando para este capítulo.</p><p>Considera este archivo de texto corto en mi máquina, llamado <code>file.txt</code>, el cual consiste de 6 líneas:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/file_txt_1.png" class="kg-image" alt=" consists of six lines" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">file.txt</code> consists of six lines</figcaption></figure><p>Ahora, modifica este archivo un poco. Quita la segunda línea, e inserta una nueva línea como la línea cuatro. Agrega un signo de admiración (<code>!</code>) al final de la última línea, así obtienes este resultado:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_txt_1.png" class="kg-image" alt="After modifying , we get different six lines" width="600" height="400" loading="lazy"><figcaption>After modifying <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">file.txt</code>, we get different six lines</figcaption></figure><p>Guarda este archivo con un nuevo nombre, <code>new_line.txt</code>.</p><p>Ahora puedes ejecutar <code>git diff</code> para calcular la diferencia entre los archivos así:</p><pre><code class="language-bash">git diff --no-index file.txt new_file.txt
</code></pre><p>(Explicaré el argumento <code>--no-index</code> de este comando más tarde. Por ahora es suficiente saberlo para que nos permita comparar dos archivos que no son partes de un repositorio de Git.)</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff --no-index file.txt new_file.txt</code></figcaption></figure><p>La salida de <code>git diff</code> muestra bastante cosas.</p><p>Enfócate en la parte empezando con <code>This is a file</code>. Puedes ver que la línea agregada (<code>// new test</code>) es precedida por un signo <code>+</code>. La línea eliminada es precedida por un símbolo <code>-</code>.</p><p>Curiosamente, fíjate que Git ve a la línea modificada como una secuencia de dos cambios - borrar una línea y agregar una nueva. Así que el parche incluye eliminar la última línea, y agregar una nueva línea que es igual a esa línea, con la suma de un <code>!</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_format_lines.png" class="kg-image" alt="Addition lines are preceded by , deletion lines by , and modification lines are sequences of deletions and additions" width="600" height="400" loading="lazy"><figcaption>Addition lines are preceded by <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">+</code>, deletion lines by <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">-</code>, and modification lines are sequences of deletions and additions</figcaption></figure><p>Ahora sería bueno discutir los términos "patch" y "diff". Estos dos son usados con frecuencia indistintamente, aunque hay una distinción, al menos históricamente.</p><p>Un <strong>diff</strong> muestra las diferencias entre dos archivos, o copias instantáneas, y puede ser bastante mínimo en hacerlo así. Un <strong>patch (parche)</strong> es una extensión de un diff, aumentado con más información tales como líneas de contexto y nombre de archivos, el cual le permite ser <em>aplicado</em> más ampliamente. Es un documento de texto que describe cómo alterar un archivo existente o base de código.</p><p>En estos días, el programa <code>diff</code> de Unix, y <code>git diff</code>, pueden producir parches de varios tipos.</p><p>Un parche es una representación compacta de las diferencias entre dos archivos. Describe cómo convertir un archivo en otro.</p><p>En otras palabras, si aplicas las "instrucciones" producidas por <code>git diff</code> en <code>file.txt</code> - eso es, quitar la segunda línea, insertar <code>// new test</code> como la cuarta línea, quitar la última línea, y agregar una línea con el mismo contenido y <code>!</code> - tendrás el contenido de <code>new_file.txt</code>.</p><p>Otra cosa importante a notar es que un parche es <strong>asimétrico</strong>: el parche de <code>file.txt</code> a <code>new_file.txt</code> no es el mismo que el parche para la otra dirección. Generar un parche entre <code>new_file.txt</code> y <code>file.txt</code>, en este orden, significaría exactamente las instrucciones opuestas que antes - agregar la segunda línea en vez de quitarla, y así sucesivamente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/patch_asymmetric.png" class="kg-image" alt="A patch consists of asymmetric instructions to get from one file to another" width="600" height="400" loading="lazy"><figcaption>A patch consists of asymmetric instructions to get from one file to another</figcaption></figure><p>Inténtalo:</p><pre><code class="language-bash">git diff --no-index new_file.txt file.txt
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_2.png" class="kg-image" alt="Running git diff in the reverse direction yields the reverse instructions - add a line instead of removing it, and so on" width="600" height="400" loading="lazy"><figcaption>Running git diff in the reverse direction yields the reverse instructions - add a line instead of removing it, and so on</figcaption></figure><p>El formato del parche usa contexto, así también como números de líneas, para localizar diferentes regiones de archivos. Esto permite a un parche ser aplicado a alguna versión más antigua o más reciente de la primera línea a aquel del que se derivó, siempre y cuando el programa que se aplica aún pueda localizar el contexto del cambio. Veremos cómo son usados exactamente.</p><h3 id="la-estructura-de-un-diff">La Estructura de un Diff</h3><p>Es tiempo de indagar más profundamente.</p><p>Genera un diff de <code>file.txt</code> a <code>new_file.txt</code> nuevamente, y considera la salida más cuidadosamente:</p><pre><code class="language-bash">git diff --no-index file.txt new_file.txt
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1-1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff --no-index file.txt new_file.txt</code></figcaption></figure><p>La primer línea introduce los archivos comparados. Git siempre le da a un archivo el nombre de <code>a</code>, y al otro el nombre de <code>b</code>. Así que en este caso <code>file.txt</code> se llama <code>a</code>, donde <code>new_file.txt</code> se llama <code>b</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_1.png" class="kg-image" alt="The first line in 's output introduces the files being compared" width="600" height="400" loading="lazy"><figcaption>The first line in <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">diff</code>'s output introduces the files being compared</figcaption></figure><p>Luego la segunda línea, comenzando con <code>index</code>, incluye los SHAs del blob de estos archivos. Así que aunque en nuestro caso inclusive no se guardan dentro de un repo de Git, Git muestra sus valores SHA-1 correspondientes.</p><p>El tercer valor en esta línea, <code>100644</code>, es el "modo bits", indicando que esto es un archivo "regular": no ejecutable y no es un enlace simbólico.</p><p>El uso de dos puntos (<code>..</code>) aquí entre los SHAs del blob es sólo como un separador (a diferencia de otros casos donde se usa dentro de Git).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_2.png" class="kg-image" alt="The second line in 's output includes the blob SHAs of the compared files, as well as the mode bits" width="600" height="400" loading="lazy"><figcaption>The second line in <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">diff</code>'s output includes the blob SHAs of the compared files, as well as the mode bits</figcaption></figure><p>Otras líneas de encabezado pueden indicar el modo bits antiguo y nuevo si han cambiado, nombres de archivos antiguos y nuevos si los archivos fueron renombrados, y así sucesivamente.</p><p>Los SHAs del blob (también llamados "blob IDs") son útiles si este parche luego se aplica por Git al mismo proyecto y hay conflictos al aplicarse. Entenderás mejor qué significa esto cuando aprendas sobre las fusiones en <a href="#cap-7">el próximo capítulo</a>.</p><p>Luego de los IDs del blob, tenemos dos líneas: una comenzando con signos <code>-</code>, y los otros comenzando con signos <code>+</code>. Este es el encabezado "diff unificado" tradicional, de nuevo mostrando los archivos siendo comparados y la dirección de los cambios: signos <code>-</code> muestra líneas en la versión A que faltan de la versión B, y signos <code>-</code> muestra líneas que faltan en la versión A pero que están presentes en el B.</p><p>Si el parche de este archivo estuviera siendo agregado o eliminado en su totalidad, entonces uno de estos serían <code>/dev/null</code> para señalar eso.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_3.png" class="kg-image" alt=" signs show lines in the A version but missing from the B version; and  signs, lines missing in A version but present in B" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">-</code> signs show lines in the A version but missing from the B version, and <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">+</code> signs, lines missing in A version but present in B</figcaption></figure><p>Considera el caso donde eliminas un archivo:</p><pre><code class="language-bash">rm awesome.txt
</code></pre><p>Y luego usa <code>git diff</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rm_diff.png" class="kg-image" alt="'s output for a deleted file" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code>'s output for a deleted file</figcaption></figure><p>La versión <code>A</code>, representando el estado del índice, es actualmente <code>awesome.txt</code>, comparado al directorio de trabajo donde este archivo no existe, así que es <code>/dev/null</code>. Todas las líneas son precedidas por signos <code>-</code> ya que existen solamente en la versión <code>A</code>.</p><p>Por ahora, deshace la eliminación (más sobre deshaciendo cambios en la Parte 3):</p><pre><code class="language-bash">git restore awesome.txt
</code></pre><p>Volviendo al diff con el que comenzamos:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1-2.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff --no-index file.txt new_file.txt</code></figcaption></figure><p>Después de este encabezado diff unificado, llegamos a la parte principal del diff, consistiendo de "secciones de diferencia", también llamados "hunks" o "chunks" en Git. Fíjate que estos términos son usados indistintamente, y podrías encontrarte con uno de ellos en la documentación y tutoriales de Git, así también como código fuente de Git.</p><p>Cada hunk comienza con una sola línea, comenzando con dos signos <code>@</code>. Estos signos son seguidos en la mayoría de veces por cuatro números, y luego un encabezado para el chunk - el cual es una suposición educada por Git. Usualmente, incluirá el comienzo de una función o una clase, cuando fuese posible.</p><p>En este ejemplo no incluye nada ya que este es un archivo de texto, así que considera otro ejemplo por un momento:</p><pre><code class="language-bash">git diff --no-index example.py example_changed.py
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_example_changed.png" class="kg-image" alt="When possible, Git includes a header for each hunk, for example a function or class definition" width="600" height="400" loading="lazy"><figcaption>When possible, Git includes a header for each hunk, for example a function or class definition</figcaption></figure><p>En la imagen de arriba, el encabezado del hunk incluye el comienzo de la función que incluye las líneas cambiados - <code>def example_function(x)</code>.</p><p>De vuelta a nuestro ejemplo previo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_1-3.png" class="kg-image" alt="Back to the previous diff" width="600" height="400" loading="lazy"><figcaption>Back to the previous diff</figcaption></figure><p>Después de dos signos <code>@</code>, encontrarás cuatro números:</p><p>Los primeros números son precedidos por un signo <code>-</code> ya que se refieren a <code>file A</code>. El primer número representa el número de línea correspondiente a la primer línea en <code>file A</code> a la que este hunk se refiere. En el ejemplo de arriba, es <code>1</code>, lo que significa que la línea <code>This is a file</code> corresponde al número de línea <code>1</code> en la versión de <code>file A</code>.</p><p>Este número es seguido por una coma (<code>,</code>), y luego el número de líneas del que este chunk consiste en el <code>file A</code>. Este número incluye todas las líneas de contexto (las líneas precedidas con un espacio en el <code>diff</code>), o líneas marcadas con un signo <code>-</code>, ya que son parte de <code>file A</code>, pero no las líneas marcadas con un signo <code>+</code>, ya que no existen en <code>file A</code>.</p><p>En nuestro ejemplo, este número es <code>6</code>, contando la línea de contexto <code>This is a file</code>, la línea <code>-</code> es <code>It has a nice poem:</code>, luego las tres líneas de contexto, y por último <code>Are belong to you</code>.</p><p>Como puedes ver, las líneas que comienzan con un caracter de espacio son líneas de contexto, lo que significa que aparecen como se muestran en ambos <code>file A</code> y <code>file B</code>.</p><p>Luego, tenemos un signo <code>+</code> para marcar a los dos números que se refieren a <code>file B</code>. Primero, está el número de línea correspondiente a la primer línea en <code>file B</code>, seguido del número de líneas del que este chunk consiste en <code>file B</code>.</p><p>Este número incluye todas las líneas de contexto, así también como las líneas marcadas con el signo <code>+</code>, ya que son parte de <code>file B</code>, pero no las líneas marcadas con un signo <code>-</code>.</p><p>Estos cuatros números son seguidos por dos signos <code>@</code> adicionales.</p><p>Después del encabezado del chunk, obtenemos las líneas actuales - sean las líneas de contexto, <code>-</code> o <code>+</code>.</p><p>Típicamente y por defecto, un hunk comienza y termina con tres líneas de contexto. Por ejemplo, si modificas las líneas 4-5 en un archivo con diez líneas:</p><ul><li>Línea 1 - línea de contexto (antes de las líneas cambiadas)</li><li>Línea 2 - línea de contexto (antes de las líneas cambiadas)</li><li>Línea 3 - línea de contexto (antes de las líneas cambiadas)</li><li>Línea 4 - línea cambiada (antes de las líneas cambiadas)</li><li>Línea 5 - otra línea cambiada</li><li>Línea 6 - línea de contexto (después de las líneas cambiadas)</li><li>Línea 7 - línea de contexto (después de las líneas cambiadas)</li><li>Línea 8 - línea de contexto (después de las líneas cambiadas)</li><li>Línea 9 - esta línea no será parte del hunk</li></ul><p>Así que por defecto, cambiar las líneas 4-5 resulta en un hunk consistiendo de las líneas 1-8, eso es, tres líneas antes y tres líneas después de las líneas modificadas.</p><p>Si ese archivo no tiene nueve líneas, sino seis líneas - entonces el hunk contendrá solamente una línea de contexto después de las líneas cambiadas, y no tres. De forma similar, si cambias la segunda línea de un archivo, entonces habría solamente una línea de contexto antes de las líneas cambiadas.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_structure_4.png" class="kg-image" alt="The patch format by " width="600" height="400" loading="lazy"><figcaption>The patch format by <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code></figcaption></figure><h3 id="c-mo-producir-diffs">Cómo producir diffs</h3><p>El último ejemplo que consideramos muestra un diff entre dos archivos. Un solo archivo parche puede contener las diferencias para <em>cualquier</em> número de archivos, y <code>git diff</code> produce diffs para todos los archivos alterados en el repositorio en un solo parche.</p><p>Frecuentemente, verás la salida de <code>git diff</code> mostrando dos versiones del mismo archivo y la diferencia entre ellos.</p><p>Para demostrar, considera el estado en otra rama llamada <code>diffs</code>:</p><pre><code class="language-bash">git checkout diffs
</code></pre><p>De nuevo, te animo a ejecutar los comandos conmigo - asegúrate de clonar el repositorio de</p><p><a href="https://github.com/Omerr/gitting_things_repo.git">https://github.com/Omerr/gitting_things_repo.git</a></p><p>En el estado actual, el directorio activo es un repositorio de Git, con una estado limpio:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_branch_diffs.png" class="kg-image" alt="git_status_branch_diffs" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code></figcaption></figure><p>Toma un archivo existente, <code>my_file.py</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_my_file.png" class="kg-image" alt="An example file - " width="600" height="400" loading="lazy"><figcaption>An example file - <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_file.py</code></figcaption></figure><p>Y cambia la segunda línea de <code>print('An example function!')</code> a <code>print('An example function! And it has been changed!')</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_my_file_after_change.png" class="kg-image" alt="The contents of  after modifying the second line" width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_file.py</code> after modifying the second line</figcaption></figure><p>Guarda tus cambios, pero no lo pongas en el área de preparación o no lo confirmes. Luego, ejecuta <code>git diff</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_my_file.png" class="kg-image" alt="The output of  for  after changing it" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> for <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_file.py</code> after changing it</figcaption></figure><p>La salida de <code>git diff</code> muestra la diferencia entre las versiones de <code>my_file.py</code> en el área de preparación, el cual en este caso es el mismo que la última confirmación (<code>HEAD</code>), y la versión en el directorio de trabajo.</p><p>Cubrí los términos "directorio de trabajo", "área de preparación", y "confirmación" en el <a href="#cap-1">capítulo de objetos de Git</a>, así que échale un vistazo en caso que te gustaría refrescar tu memoria. Como un recordatorio, los términos "área de preparación" e "índice" son intercambiables, y ambos son ampliamente usados.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_commit_2_staging_area.png" class="kg-image" alt="At this state, the status of the working dir is different from the status of the index. The status of the index is the same as that of " width="600" height="400" loading="lazy"><figcaption>At this state, the status of the working dir is different from the status of the index. The status of the index is the same as that of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>Para ver la diferencia entre el <strong>directorio de trabajo</strong> y el <strong>área de preparación</strong>, usa <code>git diff</code>, sin ningún argumento adicional.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_commit_2_git_diff-1.png" class="kg-image" alt="Without switches,  shows the difference between the staging area and the working directory" width="600" height="400" loading="lazy"><figcaption>Without switches, <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> shows the difference between the staging area and the working directory</figcaption></figure><p>Como puedes ver, <code>git diff</code> aquí lista <code>file A</code> y <code>file B</code> apuntando a <code>my_file.py</code>. <code>file A</code> aquí se refiere a la versión de <code>my_file.py</code> en el área de preparación, donde <code>file B</code> se refiere a su versión en el directorio de trabajo.</p><p>Fíjate que si modificas <code>my_file.py</code> en un editor de texto, y no guardas el archivo, entonces <code>git diff</code> no estará al tanto de los cambios que has hecho. Esto se debe a que no han sido guardados en el directorio de trabajo.</p><p>Podemos proveer unos pocos cambios a <code>git diff</code> para obtener el diff entre el directorio de trabajo y una confirmación específica, o entre el área de preparación y la última confirmación, o entre dos confirmaciones, y así sucesivamente.</p><p>Primero crea un nuevo archivo, <code>new_file.txt</code>, y guárdalo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_new_file.png" class="kg-image" alt="A simple new file saved as new_file.txt" width="600" height="400" loading="lazy"><figcaption>A simple new file saved as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_file.txt</code></figcaption></figure><p>Actualmente el archivo está en el directorio de trabajo, y actualmente está sin seguimiento en Git.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_working_dir.png" class="kg-image" alt="A new, untracked file" width="600" height="400" loading="lazy"><figcaption>A new, untracked file</figcaption></figure><p>Ahora pónlo en el área de preparación y confirma este archivo:</p><pre><code class="language-bash">git add new_file.txt
git commit -m "Commit 3"
</code></pre><p>Ahora, el estado de <code>HEAD</code> es el mismo que el estado del área de preparación, así también como el árbol de trabajo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_commit_3.png" class="kg-image" alt="The state of HEAD is the same as the index and the working dir" width="600" height="400" loading="lazy"><figcaption>The state of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> is the same as the index and the working dir</figcaption></figure><p>Luego, edita <code>new_file.txt</code> agregando una nueva línea al principio y otra nueva línea al final:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_edited.png" class="kg-image" alt="Modifying  by adding a line in the beginning and another in the end" width="600" height="400" loading="lazy"><figcaption>Modifying <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_file.txt</code> by adding a line in the beginning and another in the end</figcaption></figure><p>Como resultado, el estado es como sigue:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_start_end.png" class="kg-image" alt="After saving, the state in the working dir is different than that of the index or " width="600" height="400" loading="lazy"><figcaption>After saving, the state in the working dir is different than that of the index or <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>Un lindo truco sería usar <code>git add -p</code>, el cual te permite dividir los cambios inclusive dentro de un archivo, y considerar cuáles te gustaría ponerlos en el área de preparación.</p><p>En este caso, agrega la primera línea al índice, pero no la última línea. Para hacer eso, puedes dividir el hunk usando <code>s</code>, luego acepta el primer hunk al área de preparación (usando <code>y</code>), y no la segunda parte (usando <code>n</code>).</p><p>Si no estás seguro qué significa cada letra, siempre puedes usar un <code>?</code> y Git te dirá.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p.png" class="kg-image" alt="Using , you can stage only the first change" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git add -p</code>, you can stage only the first change</figcaption></figure><p>Así que ahora el estado en <code>HEAD</code> están sin ninguna de esas nuevas líneas. En el área de preparación tienes la primer línea pero no la última línea, y en el directorio de trabajo tienes las dos nuevas líneas.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/repo_state_after_add_p.png" class="kg-image" alt="The state after staging only the first line" width="600" height="400" loading="lazy"><figcaption>The state after staging only the first line</figcaption></figure><p>Si usas <code>git diff</code>, ¿qué sucederá?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_3.png" class="kg-image" alt=" shows the difference between the index and the working dir" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> shows the difference between the index and the working dir</figcaption></figure><p>Bueno, como se dijo antes, obtienes el diff entre el área de preparación y el árbol de trabajo.</p><p>¿Qué sucede si quiere obtener el diff entre el <code>HEAD</code> y el área de preparación? Para eso, puedes usar <code>git diff --cached</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_cached.png" class="kg-image" alt=" shows the difference between  and the index" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff --cached</code> shows the difference between <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> and the index</figcaption></figure><p>¿Y qué pasa si quieres la diferencia entre el <code>HEAD</code> y el árbol de trabajo? Para eso puedes ejecutar <code>git diff HEAD</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_HEAD.png" class="kg-image" alt=" shows the difference between  and the working dir" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff HEAD</code> shows the difference between <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> and the working dir</figcaption></figure><p>Para resumir los diferentes cambios para git diff que hemos visto hasta ahora, aquí hay un diagrama:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_diagram_1.png" class="kg-image" alt="Different switches for " width="600" height="400" loading="lazy"><figcaption>Different switches for <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code></figcaption></figure><p>Como un recordatorio, al principio de este capítulo usaste <code>git diff --no-index</code>. Con el conmutador <code>--no-index</code>, puedes comparar dos archivos que no son parte del repositorio - o de cualquier área de preparación.</p><p>Ahora, confirma los cambios que tienes en el área de preparación:</p><pre><code class="language-bash">git commit -m "Commit 4"
</code></pre><p>Para observar el diff entre esta confirmación y su confirmación padre, puedes ejecutar el siguiente comando:</p><pre><code class="language-bash">git diff HEAD~1 HEAD
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_HEAD_1_HEAD.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff HEAD~1 HEAD</code></figcaption></figure><p>Por cierto, puedes omitir el <code>1</code> de arriba y escribir <code>HEAD~</code>, y obtener el mismo resultado. Usando <code>1</code> es la forma explícita para expresar que te refieres al primer padre de la confirmación.</p><p>Fíjate que escribir la confirmación padre aquí, <code>HEAD~1</code>, primero resulta en un diff mostrando cómo obtener <em>de</em> la confirmación padre <em>a la</em> confirmación actual. Por supuesto, podría también generar el diff en reversa al escribir:</p><pre><code class="language-bash">git diff HEAD HEAD~1
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_HEAD_HEAD_1.png" class="kg-image" alt="The output of  generates the reverse patch" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff HEAD HEAD~1</code> generates the reverse patch</figcaption></figure><p>Para resumir todos los diferentes cambios para git diff que cubrimos en esta sección, mira este diagrama:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_diagram_2.png" class="kg-image" alt="The different switches for " width="600" height="400" loading="lazy"><figcaption>The different switches for <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code></figcaption></figure><p>Una forma corta de ver el diff entre una confirmación y su padre es usando <code>git show</code>, por ejemplo:</p><pre><code class="language-bash">git show HEAD
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD.png" class="kg-image" alt="git_show_HEAD" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD</code></figcaption></figure><p>Esto es lo mismo que escribir:</p><pre><code class="language-bash">git diff HEAD~ HEAD
</code></pre><p>Ahora podemos actualizar nuestro diagrama:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_diagram_3.png" class="kg-image" alt=" is used to show the difference between commits" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff HEAD~ HEAD</code> is used to show the difference between commits</figcaption></figure><p>Puedes volver a este diagrama como una referencia cuando sea necesario.</p><p>Como un recordatorio, las confirmaciones de Git son copias instantáneas - del directorio de trabajo completo del repositorio, en un cierto punto en el tiempo. A pesar de todo, a veces no es útil considerar a una confirmación como una copia instantánea completa, sino más bien por los <strong>cambios</strong> que esta confirmación específica introdujo. En otras palabras, por el diff entre una confirmación padre a la confirmación siguiente.</p><p>Como aprendiste en el <a href="#cap-1">capítulo de Objetos de Git</a>, Git almacena las copias instantáneas <strong>enteros</strong>. El diff es generado dinámicamente de los datos de la copia instantánea - al comparar los árboles principales de la confirmación y su padre.</p><p>Por supuesto, Git puede comparar cualquiera de las dos copias instantáneas en el tiempo, no sólo confirmaciones adyacentes, y también generar un diff de archivos que no son incluidos en un repositorio.</p><h3 id="c-mo-aplicar-parches">Cómo aplicar Parches</h3><p>Al usar <code>git diff</code> puedes ver un parche que Git genera, y luego puedes aplicar este patch usando <code>git apply</code>.</p><h4 id="nota-hist-rica">Nota Histórica</h4><p>En realidad, compartir parches solía ser la principal forma de compartir código al comienzo del código abierto. Pero ahora - virtualmente todos los proyectos se han movido a compartir confirmaciones de Git directamente a través de pull requests (llamados "merge requests - peticiones de fusión" en algunas plataformas).</p><p>El mayor problema con usar parches es que es difícil de aplicar un parche cuando tu directorio de trabajo no coincide con la confirmación previa del emisor. Perder el historial de la confirmación lo vuelve difícil para resolver conflictos. Entenderás mejor esto a medida que indagues más profundamente en el proceso de <code>git apply</code>, especialmente en el próximo capítulo donde cubrimos las fusiones.</p><h4 id="un-simple-parche">Un Simple Parche</h4><p>¿Qué significa aplicar un parche? ¡Es tiempo de intentarlo!</p><p>Toma la salida de <code>git diff</code>:</p><pre><code class="language-bash">git diff HEAD~1 HEAD
</code></pre><p>Y almacénalo en un archivo:</p><pre><code class="language-bash">git diff HEAD~1 HEAD &gt; my_patch.patch
</code></pre><p>Usa <code>reset</code> para deshacer la última confirmación:</p><pre><code class="language-bash">git reset --hard HEAD~1
</code></pre><p>No te preocupes del último comando - te lo explicaré en detalle en la Parte 3, donde discutimos deshacer cambios. En breve, nos permite "resetear" el estado a donde <code>HEAD</code> está apuntando, así también como el estado del índice y del directorio de trabajo. En el ejemplo de arriba, todos están puestos al estado de <code>HEAD~1</code>, o "Confirmación 3" en el diagrama.</p><p>Así que después de ejecutar el comando reset, los contenidos del archivo son como sigue (el estado de "Confirmación 3"):</p><pre><code class="language-bash">nano new_file.txt
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/nano_new_file-1.png" class="kg-image" alt="nano_new_file-1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_file.txt</code></figcaption></figure><p>Y aplicarás este parche que recién has guardado:</p><pre><code class="language-bash">nano my_patch.patch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/my_patch.png" class="kg-image" alt="The patch you are about to apply, as generated by git diff" width="600" height="400" loading="lazy"><figcaption>The patch you are about to apply, as generated by git diff</figcaption></figure><p>Este parche le dice a Git que encuentre las líneas:</p><pre><code class="language-txt">This is a new file
With new content!
</code></pre><p>Esas líneas solían ser el número de línea 1 y número de línea 2 en <code>new_file.txt</code>, y agrega una línea con el contenido <code>START!</code> justo arriba de ellos.</p><p>Ejecuta este comando para aplicar el parche:</p><pre><code class="language-bash">git apply my_patch.patch
</code></pre><p>Y como resultado, obtienes esta versión de tu archivo, justo como la confirmación que has creado antes:</p><pre><code class="language-bash">nano new_file.txt
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_file_after_applying.png" class="kg-image" alt="The contents of  after applying the patch" width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_file.txt</code> after applying the patch</figcaption></figure><h4 id="entendiendo-la-l-neas-de-contexto">Entendiendo la Líneas de Contexto</h4><p>Para entender la importancia de las líneas de contexto, considera un escenario más avanzado. ¿Qué sucede si los números de líneas han cambiado desde que creaste el archivo parche?</p><p>Para probar, comienza por crear otro archivo:</p><pre><code class="language-bash">nano test.text
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file.png" class="kg-image" alt="Creating another file - " width="600" height="400" loading="lazy"><figcaption>Creating another file - <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test.txt</code></figcaption></figure><p>Pónlo en el área de preparación y confirma este archivo:</p><pre><code class="language-bash">git add test.txt

git commit -m "Test file"
</code></pre><p>Ahora, cambia este archivo al agregar una nueva línea, y también eliminando la línea antes de la última:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_modified.png" class="kg-image" alt="Changes to " width="600" height="400" loading="lazy"><figcaption>Changes to <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test.txt</code></figcaption></figure><p>Observa la diferencia entre la versión original del archivo y la versión incluyendo tus cambios:</p><pre><code class="language-bash">git diff -- test.txt
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_diff.png" class="kg-image" alt="The output for git diff -- " width="600" height="400" loading="lazy"><figcaption>The output for <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff -- test.txt</code></figcaption></figure><p>(Usando <code>--test.txt</code> le dice a Git que ejecute el comando <code>diff</code>, tomando en consideración solamente a <code>test.txt</code>, así no obtienes el diff para otros archivos.)</p><p>Almacena este diff en un archivo parche:</p><pre><code class="language-bash">git diff -- test.txt &gt; new_patch.patch
</code></pre><p>Ahora, resetea tu estado a ese antes de introducir los cambios:</p><pre><code class="language-bash">git reset --hard
</code></pre><p>Si llegaras a aplicar new_patch.patch ahora, simplemente funciona.</p><p>Ahora consideremos un caso más interesante. Modifica a <code>test.txt</code> nuevamente al agregar una nueva línea al principio:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_added_first_line.png" class="kg-image" alt="Adding a new line at the beginning of " width="600" height="400" loading="lazy"><figcaption>Adding a new line at the beginning of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">test.txt</code></figcaption></figure><p>Como resultado, los números de líneas son diferentes de la versión original donde el parche ha sido creado. Considera el parche que creaste antes:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_patch.png" class="kg-image" alt="new_patch" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_patch.patch</code></figcaption></figure><p>Asume que la línea <code>With more text</code> es la segunda línea en <code>test.txt</code>, el cual no es más el caso. Así que... ¿funcionará <code>git apply</code>?</p><pre><code class="language-bash">git apply new_patch.patch
</code></pre><p>¡Funcionó!</p><p>Por defecto, Git busca las 3 líneas de contexto antes y después de cada cambio introducido en el parche - como puedes ver, son incluidos en el archivo parche. Si tomas tres líneas antes y después de la línea agregada, y tres líneas antes y después de la línea eliminada (en realidad solamente una línea después, ya que no existen otras líneas) - llegas al archivo parche. Si todas estas líneas existen - entonces aplicar el parche funciona, inclusive si los números de línea cambiaron.</p><p>Resetea el estado de nuevo:</p><pre><code class="language-bash">git reset --hard
</code></pre><p>¿Qué sucede si cambias una de las líneas de contexto? Intenta cambiando la línea <code>With more text</code> a <code>With more text!</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/testing_file_modifying_second_line.png" class="kg-image" alt="Changing the line  to " width="600" height="400" loading="lazy"><figcaption>Changing the line `With more text` to <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">With more text!</code></figcaption></figure><p>Y ahora:</p><pre><code class="language-bash">git apply new_patch.patch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_new_patch.png" class="kg-image" alt=" doesn't apply the patch" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git apply</code> doesn't apply the patch</figcaption></figure><p>Bueno, no. El parche no se aplica. Si no estás seguro por qué, o solo quieres entender mejor el proceso que Git está realizando, puedes agregar el argumento <code>--verbose</code> a <code>git apply</code>, así:</p><pre><code class="language-bash">git apply --verbose new_patch.patch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_new_patch_verbose.png" class="kg-image" alt=" shows the process Git is taking to apply the patch" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git apply --verbose</code> shows the process Git is taking to apply the patch</figcaption></figure><p>Parece que Git buscó líneas del archivo, incluyendo la línea "With more text", justo antes de la línea "It has some really nice lines". Esta secuencia de líneas ya no existen en el archivo. Ya que Git no puede encontrar esta secuencia, no puede aplicar el parche.</p><p>Como se mencionó antes, por defecto, Git busca 3 líneas de contexto antes y después de cada cambio introducido en el parche. Si las tres líneas circundantes no existen, Git no puede aplicar el parche.</p><p>Le puedes pedir a Git que se base en menos líneas de contexto, usando el argumento <code>-C</code>. Por ejemplo, para pedir a Git que busque 1 línea de contexto circundante, ejecuta el siguiente comando:</p><pre><code class="language-bash">git apply -C1 new_patch.patch
</code></pre><p>¡El parche se aplica!</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_c1.png" class="kg-image" alt="git_apply_c1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git apply -C1 new_patch.patch</code></figcaption></figure><p>¿Por qué es eso? Considera el parche nuevamente:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_patch-1.png" class="kg-image" alt="new_patch-1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_patch.patch</code></figcaption></figure><p>Cuando se aplica el parche con la opción <code>-C1</code>, Git está buscando las líneas:</p><pre><code class="language-txt">Like this one
And that one
</code></pre><p>para agregar la línea <code>!!!This is the new line!!!</code> entre estas dos líneas. Estas líneas existen (e, importantemente, aparecen justo después de la otra). Como resultado, Git puede agregar la línea entre ellos con éxito, aunque los números de línea cambiaron.</p><p>De manera similar, Git buscaría las líneas:</p><pre><code class="language-txt">How wonderful
So we are writing an example
Git is awesoome!
</code></pre><p>Ya que Git puede encontrar estas líneas, Git puede eliminar el del medio.</p><p>Si cambiamos una de estas líneas, digamos, cambiamos "How wonderful" a "How very wondeful", entonces Git no sería capaz de encontrar la cadena de arriba, y así el parche no se aplicaría.</p><h3 id="recapitulando-git-diff-y-patch">Recapitulando - Git Diff y Patch</h3><p>En este capítulo, aprendiste qué es un diff, y la diferencia entre un diff y un parche. Aprendiste cómo generar varios parches usando diferentes conmutadores para <code>git diff</code>. También aprendiste cómo luce la salida de git diff, y cómo se construye. Por último, aprendiste cómo se aplican los patches, y específicamente la importancia del contexto.</p><p>Entender los diff es un hito importante para entender muchos otros procesos dentro de Git - por ejemplo, fusionando o rebasing, los cuales exploraremos en los próximos capítulos.</p><!--kg-card-begin: html--><h2 id="cap-7">Capítulo 7 - Entendiendo la Fusión de Git</h2><!--kg-card-end: html--><p>Al leer este capítulo, vas a entender realmente <code>git merge</code>, una de las operaciones más comunes que ejecutarás en tus repositorios de Git.</p><h3 id="-qu-es-un-merge-fusi-n-en-git"><strong>¿Qué es un Merge (Fusión) en Git?</strong></h3><p>Fusionar es el proceso de combinar los cambios recientes de varias ramas en una sola nueva confirmación. Esta confirmación apunta a estas ramas.</p><p>De una forma, fusionar es el complemento de ramificación en control de versiones: una rama te permite trabajar de manera simultánea con otros en un conjunto particular de archivos, donde una fusión te permite luego combinar trabajos separados en ramas que difieren de una confirmación padre en común.</p><p>Muy bien, vamos poco a poco.	</p><p>Recuerda que en Git, una rama es sólo un nombre que apunta a una confirmación única. Cuando pensamos sobre las confirmaciones como si estuvieran sólo "en" una rama específica, en realidad son accesibles a través de la cadena principal desde la confirmación a la que la rama está apuntando.</p><p>Eso es, si consideras este gráfico de confirmación:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_graph_1.png" class="kg-image" alt="Commit graph with " width="600" height="400" loading="lazy"><figcaption>Commit graph with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">feature_1</code></figcaption></figure><p>Ves la rama <code>feature_1</code>, el cual apunta a una confirmación con el valor de SHA-1 de <code>ba0d2</code>. Como en los capítulos previos, solamente escribo los primeros 5 dígitos del valor de SHA-1 para brevedad.</p><p>Fíjate que la confirmación <code>54a9d</code> está también "en" esta rama, ya que es la confirmación antecesora de <code>bad0d2</code>. Si comienzas desde el puntero de <code>feature_1</code>, llegas a <code>ba0d2</code>, el cual luego apunta a <code>54a9d</code>. Puedes continuar en la cadena de padres, y todas estas confirmaciones accesibles son considerados estar "en" el <code>feature_1</code>.</p><p>Cuando fusionas con Git, fusionas confirmaciones. Casi siempre, fusionamos dos confirmaciones al referirnos a ellos con los nombres de rama a los que apuntan. De esa forma decimos que "fusionamos ramas" - aunque por debajo, en realidad fusionamos confirmaciones.</p><h3 id="tiempo-de-manos-a-la-obra-1"><strong>Tiempo de manos a la obra</strong></h3><p>Para este capítulo, usaré el siguiente repositorio:</p><p><a href="https://github.com/Omerr/gitting_things_merge.git">https://github.com/Omerr/gitting_things_merge.git</a></p><p>Como en capítulos previos, te animo a clonarlo localmente y tener el mismo punto de comienzo que estoy usando para este capítulo.</p><p>Muy bien, digamos que tenemos este simple repositorio aquí, con una rama llamada <code>main</code>, y unas pocas confirmaciones con los mensajes de confirmación de "Commit 1", "Commit 2", y "Commit 3":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commits_1_3.png" class="kg-image" alt="A simple repository with three commits" width="600" height="400" loading="lazy"><figcaption>A simple repository with three commits</figcaption></figure><p>Luego, crea una rama feature al escribir <code>git branch new_feature</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_branch_new_feature.png" class="kg-image" alt="Creating a new branch with " width="600" height="400" loading="lazy"><figcaption>Creating a new branch with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git branch</code></figcaption></figure><p>Y cambia a <code>HEAD</code> para que apunte a esta nueva rama, usando <code>git checkout new_feature</code> (o <code>git switch new_feature</code>). Puedes ver la salida usando git log:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_checkout_new_feature.png" class="kg-image" alt="The output of  after using " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git checkout new_feature</code></figcaption></figure><p>Como recordatorio, podrías también escribir <code>git checkout -b new_feature</code>, el cual crearía una nueva rama y cambiar el <code>HEAD</code> a que apunte a esta nueva rama.</p><p>Si necesitas un recordatorio sobre las ramas y cómo son implementados por debajo, por favor mira el <a href="#cap-2">capítulo 2</a>. Sí, míralo. 😇</p><p>Ahora, en la rama <code>new_feature</code>, implementa una nueva característica. En este ejemplo, editaré un archivo que ya existe que luce así antes de editarlo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_before_changes.png" class="kg-image" alt=" before editing it" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">code.py</code> before editing it</figcaption></figure><p>Y ahora lo editaré para que incluya una nueva función:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_new_feature.png" class="kg-image" alt="Implementing " width="600" height="400" loading="lazy"><figcaption>Implementing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_feature</code></figcaption></figure><p>Y afortunadamente, este no es un libro de programación, así que esta función es correcta 😇</p><p>Luego, colócalo en el área de preparación y confirma esta confirmación:</p><pre><code class="language-bash">git add code.py

git commit -m "Commit 4"
</code></pre><p>Viendo al historial, tienes el <code>branch new_feature</code>, ahora apuntando a "Commit 4", el cual apunta a su antecesor, "Commit 3". La rama principal también está apuntando a "Commit 3".</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commits_1_4.png" class="kg-image" alt="The history after committing &quot;Commit 4&quot;" width="600" height="400" loading="lazy"><figcaption>The history after committing "Commit 4"</figcaption></figure><p>¡Es tiempo de fusionar la nueva característica! Eso es, fusionar estas dos ramas, <code>main</code> y <code>new_feature</code>. O, en la jerga de Git, fusionar <code>new_feature</code> <em><em>dentro de</em> </em><code>main</code>. Esto significa fusionar "Commit 4" y "Commit 3". Esto es muy trivial, ya que después de todo, "Commit 3" es un ancestro de "Commit 4".</p><p>Verifica la rama principal (con <code>git checkout main</code>), y ejecuta la fusión usando <code>git merge new_feature</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_merge_new_feature.png" class="kg-image" alt="Merging  into " width="600" height="400" loading="lazy"><figcaption>Merging <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_feature</code> into <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Ya que <code>new_feature</code> en realidad nunca difirió de main, Git podría realizar una fusión directa. Así que, ¿qué pasó aquí? Considera el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_ff_merge.png" class="kg-image" alt="The result of a fast-forward merge" width="600" height="400" loading="lazy"><figcaption>The result of a fast-forward merge</figcaption></figure><p>Aunque usaste <code>git merge</code>, no hubo una fusión en sí aquí. En realidad, Git hizo algo muy sencillo - <code>resetea</code> la rama principal para que apunte a la misma confirmación como la rama <code>new_feature</code>.</p><p>En caso que no quieres que eso suceda, sino que quieres que Git realmente realice una fusión, podrías cambiar la configuración de Git, o ejecutar el comando de fusión con el argumento <code>--no-ff</code>.</p><p>Primero, deshace la última confirmación:</p><pre><code class="language-bash">git reset --hard HEAD~1
</code></pre><p>Recordatorio: si esta forma de usar reset no te queda claro, no te preocupes - los cubriremos en detalle en la Parte 3. No es crucial para esta introducción de merge. Por ahora, es importante entender que básicamente deshace la operación de fusión.</p><p>Sólo para clarificar, ahora si verificas a <code>new_feature</code> nuevamente:</p><pre><code class="language-bash">git checkout new_feature
</code></pre><p>El historial luciría igual como antes de la fusión:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_reset_after_merge.png" class="kg-image" alt="The history after using " width="600" height="400" loading="lazy"><figcaption>The history after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --hard HEAD~1</code></figcaption></figure><p>Luego, realiza la fusión con el argumento <code>--no-fast-forward</code> (en corto <code>--no-ff</code>):</p><pre><code class="language-bash">git checkout main
git merge new_feature --no-ff
</code></pre><p>Ahora, si miramos el historial usando <code>git lol</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_1.png" class="kg-image" alt="History after merging with the  flag" width="600" height="400" loading="lazy"><figcaption>History after merging with the <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">--no-ff</code> flag</figcaption></figure><p>(Recordatorio: <code>git lol</code> es un alias que agregué a Git para ver visiblemente el historial de una manera gráfica. Lo puedes encontrar, junto con los otros componentes de mi configuración, en la parte de <a href="#my-setup">Mi Configuración</a> del capítulo de <a href="#intro">Introducción</a>.)</p><p>Considera este historial, puedes ver que Git creó una nueva confirmación, una confirmación de fusión.</p><p>Si consideras esta confirmación un poco más de cerca:</p><pre><code class="language-bash">git log -n1
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_lol_1.png" class="kg-image" alt="The merge commit has two parents" width="600" height="400" loading="lazy"><figcaption>The merge commit has two parents</figcaption></figure><p>Verás que esta confirmación en realidad tiene dos padres - "Commit 4", el cual fue la confirmación a la que <code>new_feature</code> apuntó cuando ejecutaste <code>git merge</code>, y "Commit 3", el cual fue la confirmación a la que <code>main</code> apuntó.</p><p><strong><strong>Una confirmación de fusión tiene dos padres: las dos confirmaciones que fusionó.</strong></strong></p><p>La confirmación de fusión nos muestra el concepto de fusión bastante bien. Git toma dos confirmaciones, usualmente referenciados por dos ramas diferentes, y los fusiona juntos.</p><p>Después de la fusión, comenzaste el proceso desde <code>main</code>, estás todavía en <code>main</code>, y el historial de <code>new_feature</code> ha sido <em><em>fusionado</em></em> dentro de esta rama. Ya que comenzaste con <code>main</code>, luego "Commit 3", a la que apuntó <code>main</code>, es el primer antecesor de la confirmación de fusión, mientras que "Commit 4", la cual la fusionaste dentro de <code>main</code>, es el segundo antecesor de la confirmación de fusión.</p><p>Fíjate que empezaste en <code>main</code> cuando éste apuntaba a "Commit 3", y Git te ayudó bastante. Cambió el árbol de trabajo, el índice, y también el <code>HEAD</code> y creó un nuevo objeto de confirmación. Al menos cuando usas <code>git merge</code> sin el argumento <code>--no-commit</code> y cuando no es una fusión directa, Git hace todo eso.</p><p>Esto fue un caso super sencillo, donde las ramas que fusionaste no difirieron para nada. Pronto consideraremos casos más interesantes.</p><p>A propósito, puedes usar <code>git merge</code> para fusionar más de dos confirmaciones - en realidad, cualquier número de confirmaciones. Esto se hace raras veces, y para adherirnos al principio de practicidad de este libro, no lo profundizaremos.</p><p>Otra forma de ver a <code>git merge</code> es uniendo dos o más historiales de desarrollo juntos. Eso es, cuando fusionas, incorporas cambios desde las confirmaciones nombradas, desde el momento en que sus historiales difirieron <em><em>de</em></em> la rama actual, <em><em>en</em></em> la rama actual. Usé el término "rama" aquí, pero estoy enfatizando esto nuevamente - <strong><strong>en realidad estamos fusionando confirmaciones</strong></strong>.</p><h3 id="es-tiempo-de-un-caso-m-s-avanzado"><strong>Es tiempo de un Caso más Avanzado</strong></h3><p>Es tiempo de considerar un caso más avanzado, lo cual es probablemente el caso más común donde usamos <code>git merge</code> explícitamente - donde necesitas fusionar ramas que sí difieren uno del otro.</p><p>Supón que tenemos dos personas trabajando en este repo ahora, John y Paul.</p><p>John creó una rama:</p><pre><code class="language-bash">git checkout -b john_branch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_john_branch.png" class="kg-image" alt="A new branch, " width="600" height="400" loading="lazy"><figcaption>A new branch, <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">john_branch</code></figcaption></figure><p>Y John ha escrito una nueva canción en un nuevo archivo, <code>lucy_in_the_sky_with_diamonds.md</code>. Bueno, creo que John Lennon realmente no escribió en formato Markdown, o no usó Git para ese asunto, pero pretendamos que lo hizo para esta explicación.</p><pre><code class="language-bash">git add lucy_in_the_sky_with_diamonds.md
git commit -m "Commit 5"
</code></pre><p>Mientras John estaba trabajando en esta canción, Paul también estaba escribiendo, en otra rama. Paul había comenzado desde main:</p><pre><code class="language-bash">git checkout main
</code></pre><p>Y creó su propia rama:</p><pre><code class="language-bash">git checkout -b paul_branch
</code></pre><p>Y Paul escribió su canción en un archivo llamado <code>penny_lane.md</code>. Paul puso en el área de preparación y confirmó este archivo:</p><pre><code class="language-bash">git add penny_lane.md
git commit -m "Commit 6"
</code></pre><p>Así que ahora nuestro historial luce así - donde tenemos dos ramas distintas, que se ramifican desde <code>main</code>, con historiales distintos:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_6.png" class="kg-image" alt="The history after John and Paul committed" width="600" height="400" loading="lazy"><figcaption>The history after John and Paul committed</figcaption></figure><p>John está feliz con su rama (eso es, su canción), así que él decide fusionarlo en la rama <code>main</code>:</p><pre><code class="language-bash">git checkout main
git merge john_branch
</code></pre><p>En realidad, este es una fusión directa, como hemos aprendido antes. Puedes validar eso al ver el historial (usando <code>git lol</code>, por ejemplo):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_after_commit_6.png" class="kg-image" alt="Merging  into  results in a fast-forward merge" width="600" height="400" loading="lazy"><figcaption>Merging <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">john_branch</code> into <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code> results in a fast-forward merge</figcaption></figure><p>A este punto, Paul también quiere fusionar su rama dentro de <code>main</code>, pero ahora una fusión directa ya no es relevante - hay dos diferentes historiales aquí: el historial de <code>main</code> y el de <code>paul_branch</code>. No es que <code>paul_branch</code> solamente agrega confirmaciones encima de la rama main o vice versa.</p><p>Ahora las cosas se ponen interesante. 😎😎</p><p>Primero, dejemos a Git que haga el trabajo duro por ti. Después de eso, entenderemos lo que en realidad está sucediendo por debajo.</p><pre><code class="language-bash">git merge paul_branch
</code></pre><p>Considera este historial ahora:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_after_commit_6_paul_branch.png" class="kg-image" alt="When you merge , you get a new merge commit\label{fig-history-after-git-merge}" width="600" height="400" loading="lazy"><figcaption>When you merge <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">paul_branch</code>, you get a new merge commit</figcaption></figure><p>Lo que tienes es una nueva confirmación, con dos antecesores - "Commit 5" y "Commit 6".</p><p>En el directorio de trabajo, puedes ver que la canción de John así también como la canción de Paul están ahí (si usas <code>ls</code>, verás ambos archivos en el directorio de trabajo).</p><p>Bien, Git realmente fusionó los cambios por ti. ¿Pero cómo hace que eso suceda?</p><p>Deshace la última confirmación:</p><pre><code class="language-bash">git reset --hard HEAD~
</code></pre><h3 id="c-mo-realizar-una-fusi-n-de-tres-v-as-en-git"><strong>Cómo realizar una Fusión de Tres Vías en Git</strong></h3><p>Es tiempo de entender lo que realmente está pasando por debajo. 😎</p><p>Lo que Git ha hecho aquí se le llama una <strong><strong>fusión de 3 vías</strong></strong>. Al delinear el proceso de una fusión de 3 vías, usaré el término "rama" para simplicidad, pero deberías recordar que podrías también fusionar dos (o más) confirmaciones que no son referenciados por una rama.</p><p>El proceso de fusión de 3 vías incluye estas etapas:</p><p>Primero, Git localiza el ancestro común de las dos ramas. Eso es, la confirmación común desde el cual las ramas de fusión difirieron más recientemente. Técnicamente, esto en realidad es la primer confirmación que es accesible desde ambas ramas. A esta confirmación entonces se le llama la base de fusión.</p><p>Segundo, Git calcula dos diffs - un diff de la base de fusión a la primer rama, y otro diff desde la base de fusión a la segunda rama. Git genera parches basados en esos diffs.</p><p>Tercero, Git aplica ambos parches a la base de fusión usando un algoritmo de fusión de 3 vías. El resultado es el estado de la nueva confirmación de fusión.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge.png" class="kg-image" alt="The three steps of the 3-way merge algorithm: (1) locate the common ancestor; (2) calculate diffs from the merge base to the first branch, and from the merge base to the second branch; (3) apply both patches together" width="600" height="400" loading="lazy"><figcaption>The three steps of the 3-way merge algorithm: (1) locate the common ancestor (2) calculate diffs from the merge base to the first branch, and from the merge base to the second branch (3) apply both patches together</figcaption></figure><p>Así que, devuelta a nuestro ejemplo.</p><p>En el primer paso, Git mira desde ambas ramas - <code>main</code> y <code>paul_branch</code> - y atraviesa el historial para encontrar la primera confirmación que es accesible desde ambos. En este caso, este sería.. ¿cuál confirmación?</p><p>Correcto, la confirmación de fusión (el que tiene a "Commit 3" y "Commit 4" como sus predecesores).</p><p>Si no estás seguro, siempre puedes preguntarle a Git directamente:</p><pre><code class="language-bash">git merge-base main paul_branch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_base.png" class="kg-image" alt="The merge base is the merge commit with &quot;Commit 3&quot; and &quot;Commit 4&quot; as its parents. Note: the previous commit merge is blurred as it is not reachable via the current history following the  command" width="600" height="400" loading="lazy"><figcaption>The merge base is the merge commit with "Commit 3" and "Commit 4" as its parents. Note: the previous commit merge is blurred as it is not reachable via the current history following the <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">reset</code> command</figcaption></figure><p>A propósito, este es el caso más común y sencillo, donde tenemos una única elección obvia para la base de fusión. En casos más complicados, podría haber múltiples posibilidades para una base de fusión, pero esto no está dentro de nuestro enfoque.</p><p>En el segundo paso, Git calcula las diferencias. Así que primero calcula la diferencia entre la confirmación de fusión y "Commit 5":</p><pre><code class="language-bash">git diff 4f90a62 4683aef
</code></pre><p>(Los valores de SHA-1 serán distintas en tu máquina.)</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_4_5.png" class="kg-image" alt="The diff between the merge commit and &quot;Commit 5&quot;\label{fig-john-patch}" width="600" height="400" loading="lazy"><figcaption>The diff between the merge commit and "Commit 5"</figcaption></figure><p>Si no te sientes cómodo con la salida de <code>git diff</code>, puedes leer el capítulo anterior donde lo describí en detalle.</p><p>Puedes almacenar esa diferencia en un archivo:</p><pre><code class="language-bash">git diff 4f90a62 4683aef &gt; john_branch_diff.patch
</code></pre><p>Luego, Git calcula la diferencia entre la confirmación de fusión y "Commit 6":</p><pre><code class="language-bash">git diff 4f90a62 c5e4951
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_4_6.png" class="kg-image" alt="The diff between the merge commit and &quot;Commit 6&quot;" width="600" height="400" loading="lazy"><figcaption>The diff between the merge commit and "Commit 6"</figcaption></figure><p>Escribe esto en un archivo también:</p><pre><code class="language-bash">git diff 4f90a62 c5e4951 &gt; paul_branch_diff.patch
</code></pre><p>Ahora Git aplica esos parches en la base de fusión.</p><p>Primero, intenta eso directamente - aplica los parches (te lo explicaré en un momento). Esto no es lo que realmente hace Git por defecto, pero te ayudará a ganar un mejor entendimiento de por qué Git necesita hacer algo distinto.</p><p>Verifica la base de fusión primero, eso es, la confirmación de fusión:</p><pre><code class="language-bash">git checkout 4f90a62
</code></pre><p>Y aplica el parche de John primero (como recordatorio, este es el parche que se muestra en la imagen con el subtítulo "The diff between the merge commit and "Commit 5""):</p><pre><code class="language-bash">git apply --index john_branch_diff.patch
</code></pre><p>Fíjate que por ahora no hay una confirmación de fusión. <code>git apply</code> actualiza el directorio de trabajo así también como el índice, ya que usamos el conmutador <code>--index</code>.</p><p>Puedes observar el estado usando <code>git status</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_apply_john.png" class="kg-image" alt="Applying John's patch on the merge commit" width="600" height="400" loading="lazy"><figcaption>Applying John's patch on the merge commit</figcaption></figure><p>Así que ahora la nueva canción de John se incorpora en el índice. Aplica el otro parche:</p><pre><code class="language-bash">git apply --index paul_branch_diff.patch
</code></pre><p>Como resultado, el índice contiene los cambios desde ambas ramas.</p><p>Ahora es tiempo de confirmar tu fusión. Ya que el comando de porcelana <code>git commit</code> siempre genera una confirmación con un solo predecesor, necesitarías el comando de plomería subyacente - <code>git commit-tree</code>.</p><p>Si necesitas un recordatorio sobre los comandos de porcelana vs de plomería, mira el <a href="#cap-4">capítulo 4</a> donde expliqué estos términos, y creé un repo entero desde cero.</p><p>Recuerda que cada objeto de confirmación de Git apunta a un sólo árbol. Así que necesitas registrar los contenidos del índice en un árbol:</p><pre><code class="language-bash">git write-tree
</code></pre><p>Ahora obtienes el valor de SHA-1 del árbol creado, y puedes crear un objeto de confirmación usando <code>git commit-tree</code>:</p><pre><code class="language-bash">git commit-tree &lt;TREE_SHA&gt; -p &lt;COMMIT_5&gt; -p &lt;COMMIT_6&gt; -m "Merge commit!"
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_merge_commit.png" class="kg-image" alt="Creating a merge commit" width="600" height="400" loading="lazy"><figcaption>Creating a merge commit</figcaption></figure><p>Genial, ¡así que has creado un objeto de confirmación!</p><p>Recuerda que <code>git merge</code> también cambia el <code>HEAD</code> para que apunte al nuevo objeto de confirmación de fusión. Así que puedes simplemente hacer lo mismo:</p><pre><code class="language-bash">git reset --hard db315a
</code></pre><p>Si miras al historial ahora:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_reset_to_merge_commit_git_lol.png" class="kg-image" alt="The history after creating a merge commit and resetting " width="600" height="400" loading="lazy"><figcaption>The history after creating a merge commit and resetting <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>(Nota: en este estado, <code>HEAD</code> está "separado" - eso es, directamente apunta a un objeto de confirmación en vez de una referencia nombrada. <code>gg</code> no muestra el <code>HEAD</code> cuando está "separado", así que no te confundas si no puedes ver el <code>HEAD</code> en la salida de <code>gg</code>.)</p><p>Esto es casi lo que queríamos. Recuerda que cuando ejecutaste <code>git merge</code>, el resultado fue <code>HEAD</code> apuntando a <code>main</code> el cual apuntó a la nueva confirmación creada (como se muestra en la imagen con el subtítulo "When you merge <code>paul_branch</code>), obtienes una nueva confirmación de fusión". ¿Qué deberías hacer entonces?</p><p>Bueno, lo que quieres es modificar a <code>main</code>, así que lo puedes apuntar a la nueva confirmación:</p><pre><code class="language-bash">git checkout main
git reset --hard db315a
</code></pre><p>Y ahora tienes el mismo resultado cuando ejecutaste <code>git merge</code>: <code>main</code> apunta a la nueva confirmación, el cual tiene "Commit 5" y Commit 6" como sus predecesores. Puedes usar <code>git lol</code> para verificar eso.</p><p>Así que esto es exactamente el mismo resultado como la fusión hecha por Git, con la excepción de la marca de tiempo y así el valor de SHA-1, por supuesto.</p><p>Sobretodo, tienes que fusionar los contenidos de las dos confirmaciones - eso es, el estado de los archivos, y también el historial de esas confirmaciones - creando una confirmación de fusión que apunta a ambos historiales.</p><p>En este caso sencillo, podrías en realidad aplicar los parches usando <code>git apply</code> y todo funciona bastante bien.</p><h3 id="r-pida-recapitulaci-n-de-una-fusi-n-de-tres-v-as"><strong>Rápida recapitulación de una Fusión de tres vías</strong></h3><p>Así que para recapitular rápidamente, en una fusión de tres vías, Git:</p><ul><li>Primero, localiza la base de fusión - el ancestro común de las dos ramas. Eso es, la primer confirmación que es accesible de ambas ramas.</li><li>Segundo, Git calcula los dos diffs - un diff de la base de fusión a la primera rama, y otro diff de la base de fusión a la segunda rama.</li><li>Tercero, Git aplica ambos parches a la base de fusión, usando un algoritmo de fusión de tres vías. No he explicado la fusión de tres vías todavía, pero lo explicaré más tarde. El resultado es el estado de la nueva confirmación de fusión.</li></ul><p>También puedes entender por qué se llama una "fusión de 3 vías": Git fusiona, tres estados diferentes - el de la primera rama, el de la segunda rama, y su ancestro en común. En nuestro ejemplo anterior, <code>main</code>, <code>paul_branch</code>, y la confirmación de fusión (con "Commit 3" y "Commit 4" como predecesores), respectivamente.</p><p>Esto es improbable, digamos, los ejemplos directos que vimos antes. Los ejemplos directos son en realidad un caso de una fusión de dos vías, ya que Git solamente compara dos estados - por ejemplo, a donde <code>main</code> apuntó, y a donde <code>john_branch</code> apuntó.</p><h3 id="continuando"><strong>Continuando</strong></h3><p>Todavía, esto fue un sencillo caso de una fusión de 3 vías. John y Paul crearon canciones distintos, así que cada uno de ellos tocaron un archivo distinto. Fue bastante directo para ejecutar la fusión.</p><p>¿Qué hay sobre casos más interesantes?</p><p>Digamos que ahora John y Paul son co-autores de una nueva canción.</p><p>Así que, John verificó la rama <code>main</code> y comenzó a escribir la canción:</p><pre><code class="language-bash">git checkout main
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_md.png" class="kg-image" alt="John's new song" width="600" height="400" loading="lazy"><figcaption>John's new song</figcaption></figure><p>Él lo puso en el área de preparación y lo confirmó ("Commit 7"):</p><pre><code class="language-bash">git add a_day_in_the_life.md
git commit -m "Commit 7"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_7.png" class="kg-image" alt="John's new song is committed" width="600" height="400" loading="lazy"><figcaption>John's new song is committed</figcaption></figure><p>Ahora, Paul hace una rama:</p><pre><code class="language-bash">git checkout -b paul_branch_2
</code></pre><p>Y edita la canción, agregando otro verso:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_paul_verse.png" class="kg-image" alt="Paul added a new verse" width="600" height="400" loading="lazy"><figcaption>Paul added a new verse</figcaption></figure><p>Por supuesto, la canción original no incluye el título "Paul's Verse", pero lo agregué para claridad.</p><p>Paul pone en el área de preparación y confirma los cambios:</p><pre><code class="language-bash">git add a_day_in_the_life.md
git commit -m "Commit 8"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_8.png" class="kg-image" alt="The history after introducing &quot;Commit 8&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 8"</figcaption></figure><p>John también hace una rama tomando de main y agrega unas dos líneas adicionales al final:</p><pre><code class="language-bash">git checkout main
git checkout -b john_branch_2
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_john_addition.png" class="kg-image" alt="John added the two last lines" width="600" height="400" loading="lazy"><figcaption>John added the two last lines</figcaption></figure><p>John pone en el área de preparación y confirma sus cambios también ("Commit 9"):</p><pre><code class="language-bash">git add a_day_in_the_life.md
git commit -m "Commit 9"
</code></pre><p>Este es el historial resultante:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_9.png" class="kg-image" alt="The history after John's last commit" width="600" height="400" loading="lazy"><figcaption>The history after John's last commit</figcaption></figure><p>Así que, Paul y John modificó el mismo archivo en diferentes ramas. ¿Tendrá éxito Git al fusionarlos?</p><p>Digamos que ahora no vamos por <code>main</code>, sino que John intentará fusionar la nueva rama de Paul en su rama:</p><pre><code class="language-bash">git merge paul_branch_2
</code></pre><p>¡Espera! ¡No ejecutes este comando! ¿Por qué le dejarías a Git hacer todo el trabajo duro? Estás intentando de entender el proceso aquí.</p><p>Así que, primero, Git necesita encontrar la base de fusión. ¿Puedes ver cual confirmación sería?</p><p>Correcto, sería la última confirmación en la rama <code>main</code>, donde los dos difieren - eso es, "Commit 7".</p><p>Puedes verificar eso usando:</p><pre><code class="language-bash">git merge-base john_branch_2 paul_branch_2
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_base_2.png" class="kg-image" alt="&quot;Commit 7&quot; is the merge base" width="600" height="400" loading="lazy"><figcaption>"Commit 7" is the merge base</figcaption></figure><p>Cambia a la base de fusión así más tarde puedes aplicar los parches que crearás:</p><pre><code class="language-bash">git checkout main
</code></pre><p>Genial, ahora Git debería calcular los diffs y generar los parches. Puedes observar los diffs directamente:</p><pre><code class="language-bash">git diff main paul_branch_2
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_main_paul_branch_2.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main paul_branch_2</code></figcaption></figure><p>¿Tendrá éxito en aplicar este parche? Bueno, sin problema, Git tiene todas las líneas de contexto en lugar.</p><p>Cambia a la base de fusión (el cual es "Commit 7", también referenciado por <code>main</code>), y pide a Git que aplique este parche:</p><pre><code class="language-bash">git checkout main
git diff main paul_branch_2 &gt; paul_branch_2.patch
git apply --index paul_branch_2.patch
</code></pre><p>Y esto funcionó, sin problemas para nada.</p><p>Ahora, calcula la diff entre la nueva rama de John y la base de fusión. Fíjate que no has confirmado los cambios aplicados, así que <code>john_branch_2</code> todavía apunta a la misma confirmación como antes, "Commit 9":</p><pre><code class="language-bash">git diff main john_branch_2
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_main_john_branch_2.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main john_branch_2</code></figcaption></figure><p>¿Funcionará si se aplica este diff?</p><p>Bueno, de hecho, sí. Fíjate que aunque los números de líneas han cambiado en la versión actual del archivo, gracias a las líneas de contexto que Git es capaz de localizar donde necesita agregar estas líneas...</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diff_main_john_branch_2_context.png" class="kg-image" alt="Git can rely on the context lines" width="600" height="400" loading="lazy"><figcaption>Git can rely on the context lines</figcaption></figure><p>Guarda este parche y luego aplícalo:</p><pre><code class="language-bash">git diff main john_branch_2 &gt; john_branch_2.patch
git apply --index john_branch_2.patch
</code></pre><p>Observa el archivo resultante:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/a_day_in_the_life_after_merge.png" class="kg-image" alt="The result after applying Paul's patch" width="600" height="400" loading="lazy"><figcaption>The result after applying Paul's patch</figcaption></figure><p>Genial, exactamente lo que queríamos.</p><p>Ahora puedes crear el árbol y la confirmación relevante:</p><pre><code class="language-bash">git write-tree
</code></pre><p>No te olvides de especificar ambos predesores:</p><pre><code class="language-bash">git commit-tree &lt;TREE-ID&gt; -p paul_branch_2 -p john_branch_2 -m "Merging new changes"
</code></pre><p>¿Viste cómo usé los nombres de rama aquí? Después de todo, sólo son punteros a las confirmaciones que queremos.</p><p>Genial, mira el log de la nueva confirmación:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_merging_new_changes.png" class="kg-image" alt=" after creating the merge commit" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol &lt;SHA_OF_THE_MERGE_COMMIT&gt;</code> after creating the merge commit</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merging_new_changes_commit.png" class="kg-image" alt="The history after creating the merge commit" width="600" height="400" loading="lazy"><figcaption>The history after creating the merge commit</figcaption></figure><p>Exactamente lo que queríamos.</p><p>También puedes dejar a Git que haga el trabajo para ti. Puedes cambiar a <code>john_branch_2</code>, el cual no has movido - así que todavía apunta a la misma confirmación como lo hizo antes de la fusión. Así que todo lo que necesitas es ejecutar:</p><pre><code class="language-bash">git checkout john_branch_2
git merge paul_branch_2
</code></pre><p>Observa el historial resultante:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_branches_2.png" class="kg-image" alt=" after letting Git perform the merge" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol</code> after letting Git perform the merge</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merging_with_git.png" class="kg-image" alt="A visualization of the history after letting Git perform the merge" width="600" height="400" loading="lazy"><figcaption>A visualization of the history after letting Git perform the merge</figcaption></figure><p>Como antes, tienes una confirmación de fusión apuntando a "Commit 8" y "Commit 9" como sus predecesores. "Commit 9" es el primer predecesor ya que lo fusionaste.</p><p>Pero esto fue bastante sencillo... John y Paul trabajaron en el mismo archivo, pero en partes muy distintas. También podrías directamente aplicar los cambios de Paul a la rama de John. Si vuelves a la rama de John antes de la fusión:</p><pre><code class="language-bash">git reset --hard HEAD~
</code></pre><p>Y ahora aplica los cambios de Paul:</p><pre><code class="language-bash">git apply --index paul_branch_2.patch
</code></pre><p>Obtendrías el mismo resultado.</p><p>Pero, ¿qué sucede cuando las dos ramas incluyen cambios en los mismos archivos, en las mismas ubicaciones?</p><h3 id="casos-de-fusi-n-de-git-m-s-avanzados"><strong>Casos de Fusión de Git más avanzados</strong></h3><p>¿Qué sucedería si John y Paul fueran a coordinar una nueva canción, y lo realizan juntos?</p><p>En este caso, John crea la primer versión de esta canción en la rama main:</p><pre><code class="language-bash">git checkout main
nano everyone.md
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_1.png" class="kg-image" alt="The contents of  prior to the first commit" width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">everyone.md</code> prior to the first commit</figcaption></figure><p>A propósito, este texto es de hecho tomado de la versión que John Lennon grabó para una demo en 1968. Pero esto no es un libro sobre los Beatles. Si estás interesado sobre el proceso por el que los Beatles atravesaron mientras escribían esta canción, puedes seguir los enlaces al final de este capítulo.</p><pre><code class="language-bash">git add everyone.md
git commit -m "Commit 10"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_commit_10.png" class="kg-image" alt="Introducing &quot;Commit 10&quot;" width="600" height="400" loading="lazy"><figcaption>Introducing "Commit 10"</figcaption></figure><p>Ahora John y Paul se separon. Paul crea un nuevo verso al principio:</p><pre><code class="language-bash">git checkout -b paul_branch_3
nano everyone.md
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_2.png" class="kg-image" alt="Paul added a new verse in the beginning" width="600" height="400" loading="lazy"><figcaption>Paul added a new verse in the beginning</figcaption></figure><p>También, mientras hablando con John, decidieron cambiar la palabra "feet" a "foot", así que Paul agrega este cambio también.</p><p>Y Paul agrega y confirma sus cambios al repo:</p><pre><code class="language-bash">git add everyone.md
git commit -m "Commit 11"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_11.png" class="kg-image" alt="The history after introducing &quot;Commit 11&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 11"</figcaption></figure><p>Puedes observar los cambios de Paul, comparando este estado de la rama al estado de la rama <code>main</code>:</p><pre><code class="language-bash">git diff main
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main.png" class="kg-image" alt="The output of  from Paul's branch" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main</code> from Paul's branch</figcaption></figure><p>Almacena este diff en un archivo parche:</p><pre><code class="language-bash">git diff main &gt; paul_3.patch
</code></pre><p>Ahora devuelta a <code>main</code>...</p><pre><code class="language-bash">git checkout main
</code></pre><p>John decide hacer otro cambio, en su propia nueva rama:</p><pre><code class="language-bash">git checkout -b john_branch_3
</code></pre><p>Y reemplaza la línea "Everyone had the boot in" con la línea "Everyone had a wet dream". Además, John cambió la plabra "feet" a "foot", siguiendo su charla con Paul.</p><p>Observa el diff:</p><pre><code class="language-bash">git diff main
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_2.png" class="kg-image" alt="The output of  from John's branch" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main</code> from John's branch</figcaption></figure><p>Almacena esta salida también:</p><pre><code class="language-bash">git diff main &gt; john_3.patch
</code></pre><p>Ahora, pónlo en el área de preparación y confirma:</p><pre><code class="language-bash">git add everyone.md
git commit -m "Commit 12"
</code></pre><p>Este debería ser tu historial actual:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_12.png" class="kg-image" alt="The history after introducing &quot;Commit 12&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 12"</figcaption></figure><p>Fíjate que eliminé <code>john_branch_2</code> y <code>paul_branch_2</code> para simplicidad. Por supuesto, puedes eliminarlos de Git usando <code>git branch -D &lt;branch_name&gt;</code>. Como resultado, estos nombres de ramas no aparecerán en la salida de <code>git log</code> u otros comandos similares.</p><p>Esto también se aplica a las confirmaciones que ya no son accesibles desde ninguna referencia nombrada, tales como "Commit 8" o "Commit 9". Ya que ya no son accesibles desde ninguna referencia nombrada por medio de la cadena de los antecesores, no serán incluidos en la salida de comandos tales como <code>git log</code>.</p><p>Devuelta a nuestra historia - Paul y John han agregado un nuevo verso, así que a John le gustaría fusionar los cambios de Paul.</p><p>¿Puede John simplemente aplicar el parche de Paul?</p><p>Considera el parche de nuevo:</p><pre><code class="language-bash">git diff main paul_branch_3
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main-1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main paul_branch_3</code></figcaption></figure><p>Como puedes ver, este diff se basa en la línea "Everyone had the boot in", pero esta línea ya no existe en la rama de John. Como resultado, podrías esperar que aplicar el parche falle. Continúa, inténtalo:</p><pre><code class="language-bash">git apply paul_3.patch
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_paul_3.png" class="kg-image" alt="Applying the patch failed" width="600" height="400" loading="lazy"><figcaption>Applying the patch failed</figcaption></figure><p>De hecho, puedes ver que falló.</p><p>¿Pero debería fallar realmente?</p><p>Como expliqué anteriormente, <code>git merge</code> usa un algoritmo de 3 vías, y esto puede ser útil aquí. ¿Cuál sería el primer paso de este algoritmo?	</p><p>Bueno, primero, Git encontraría la base de fusión - eso es, el ancestro común de la rama de Paul y de la rama de John. Considera el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_12-1.png" class="kg-image" alt="The history after introducing &quot;Commit 12&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 12"</figcaption></figure><p>Así que el ancestro común de "Commit 11" y Commit 12" es "Commit 10". Puedes verificarlo ejecutando el comando:</p><pre><code class="language-bash">git merge-base john_branch_3 paul_branch_3
</code></pre><p>Ahora podemos tomar los parches que generamos desde los diffs en ambas ramas, y aplicarlos al <code>main</code>. ¿Funcionaría?</p><p>Primero, intenta aplicar el parche de John, y luego el parche de Paul.</p><p>Considera el diff:</p><pre><code class="language-bash">git diff main john_branch_3
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_2-1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main john_branch_3</code></figcaption></figure><p>Podemos almacenarlo en un archivo:</p><pre><code class="language-bash">git diff main john_branch_3 &gt; john_3.patch
</code></pre><p>Y aplicar este parche en el main:</p><pre><code class="language-bash">git checkout main
git apply john_3.patch
</code></pre><p>Consideremos el resultado:</p><pre><code class="language-bash">nano everyone.md
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_3.png" class="kg-image" alt="The contents of  after applying John's patch" width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">everyone.md</code> after applying John's patch</figcaption></figure><p>La línea cambió como se esperaba. Bien 😎</p><p>Ahora, ¿puede Git aplicar el parche de Paul? Para recordarte, este es el parche. Bueno, Git no puede aplicar este parche, porque este parche asume que la línea "Everyone had the boot in" existe. Tratar de aplicarlo es probable que falle:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main-2.png" class="kg-image" alt="The contents of Paul's patch" width="600" height="400" loading="lazy"><figcaption>The contents of Paul's patch</figcaption></figure><p>Bueno, Git no puede aplicar este parche, porque este parche asume que la línea "Everyone had the boot in" existe. Tratar de aplicarlo es probable que falle:</p><pre><code class="language-bash">git apply -v paul_3.branch
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_v_paul_3.png" class="kg-image" alt="Applying Paul's patch failed" width="600" height="400" loading="lazy"><figcaption>Applying Paul's patch failed</figcaption></figure><p>Lo que intentaste de hacer ahora, aplicar el parche de Paul en la rama <code>main</code> después de aplicar el parche de John, es lo mismo que estar en <code>john_branch_3</code>, e intentar de aplicar el parche. Eso es, ejecutando:</p><pre><code class="language-bash">git apply paul_3.patch
</code></pre><p>¿Qué sucedería si intentaramos al revés?</p><p>Primero, limpia el estado:</p><pre><code class="language-bash">git reset --hard
</code></pre><p>Y comienza desde la rama de Paul:</p><pre><code class="language-bash">git checkout paul_branch_3
</code></pre><p>¿Podemos aplicar el parche de Paul? Como recordatorio, este es el estado de <code>everyone.md</code> en esta rama:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_2-1.png" class="kg-image" alt="The contents of  on " width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">everyone.md</code> on <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">paul_branch_3</code></figcaption></figure><p>Y este es el parche de John:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_2-2.png" class="kg-image" alt="The contents of John's patch" width="600" height="400" loading="lazy"><figcaption>The contents of John's patch</figcaption></figure><p>¿Funcionaría aplicar el parche de John?</p><p>Intenta contestarte a tí mismo antes de continuar leyendo.</p><p>Puedes intentar:</p><pre><code class="language-bash">git apply john_3.patch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_3_john_3.png" class="kg-image" alt="Git fails to apply John's patch" width="600" height="400" loading="lazy"><figcaption>Git fails to apply John's patch</figcaption></figure><p>Bueno, ¡no! De nuevo, si estás seguro de lo que pasó, siempre puedes pedir con <code>git apply</code> para que sea un poco más verboso:</p><pre><code class="language-bash">git apply -v john_3.patch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_v_john_3.png" class="kg-image" alt="You can get more information by using the  flag" width="600" height="400" loading="lazy"><figcaption>You can get more information by using the <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">-v</code> flag</figcaption></figure><p>Git está buscando "Everyone put the feet down", pero Paul ya ha cambiado esta línea así que ahora consiste de la palabra "foot" en vez de "feet". Como resultado, aplicar este parche falla.</p><p>Fíjate que cambiar el número de las líneas de contexto aquí (eso es, usando <code>git apply</code> con el argumento <code>-C</code>, como se discutió en el <a href="#cap-6">capítulo anterior</a>) es irrelevante - Git es incapaz de localizar la línea actual que el parche está intentando de eliminar.</p><p>Pero en realidad, Git puede hacer que esto funcione, si sólo agregas un argumento para aplicar, diciéndole que haga una fusión de tres vías por debajo:</p><pre><code class="language-bash">git apply -3 john_3.patch
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_apply_3_john_3-1.png" class="kg-image" alt="Applying with  flag succeeds" width="600" height="400" loading="lazy"><figcaption>Applying with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">-3</code> flag succeeds</figcaption></figure><p>Y considera el resultado:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_4.png" class="kg-image" alt="The contents of  after the merge" width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">everyone.md</code> after the merge</figcaption></figure><p>¡Exactamente lo que queríamos! ¡Tienes el verso de Paul, y los de John!</p><p>Así que, ¿cómo Git fue capaz de lograr eso?</p><p>Bueno, como mencioné, Git realmente hizo una <strong><strong>fusión de 3 vías</strong></strong>, y con este ejemplo, será un buen momento para indagar lo que esto realmente significa.</p><h3 id="c-mo-funciona-el-algoritmo-de-fusi-n-de-3-v-as-de-git"><strong>Cómo funciona el Algoritmo de Fusión de 3 vías de Git</strong></h3><p>Vuelve al estado antes de aplicar este parche:</p><pre><code class="language-bash">git reset --hard
</code></pre><p>Ahora tienes tres versiones: la base de fusión, el cual es "Commit 10", la rama de Paul, y la rama de John. En términos generales, podemos decir que estos son el <code>merge base</code>, <code>commit A</code> y <code>commit B</code>. Fíjate que el <code>merge base</code> es por definición un ancestro de ambos <code>commit A</code> y <code>commit B</code>.</p><p>Para realizar una fusión, Git mira al diff entre las tres diferentes versiones del archivo en cuestión de estas tres revisiones. En tu caso, es el archivo <code>everyone.md</code>, y las revisiones son "Commit 10", la rama de Paul - eso es, "Commit 11", y la rama de John, eso es, "Commit 12".</p><p>Git hace la decisión de fusión basado en el estado de cada línea en cada una de estas versiones.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions.png" class="kg-image" alt="The three versions considered for the 3-way merge" width="600" height="400" loading="lazy"><figcaption>The three versions considered for the 3-way merge</figcaption></figure><p>En caso que no todas las tres versiones coincidan, eso es un conflicto. Git puede resolver muchos de estos conflictos automáticamente, como veremos ahora.</p><p>Consideremos líneas específicas.</p><p>Las primeras líneas aquí existen solamente en la rama de Paul:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_1.png" class="kg-image" alt="Lines that appear on Paul's branch only" width="600" height="400" loading="lazy"><figcaption>Lines that appear on Paul's branch only</figcaption></figure><p>Esto significa que el estado de la rama de John es igual al estado de la base de fusión. Así que la fusión de 3 vías va a la par con la versión de Paul.</p><p>En general, si el estado de la base de fusión es el mismo que el <code>A</code>, el algoritmo va la par con <code>B</code>. La razón se debe a que la base de fusión es el ancestro de <code>A</code> y de <code>B</code>, Git asume que esta línea no ha cambiado en <code>A</code>, y <em><em>ha</em></em> cambiado en <code>B</code>, el cual es la versión más reciente para esa línea, y por lo tanto debería ser tomado en cuenta.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_1.png" class="kg-image" alt="If the state of the merge base is the same as , and this state is different from , the algorithm goes with " width="600" height="400" loading="lazy"><figcaption>If the state of the merge base is the same as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">A</code>, and this state is different from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">B</code>, the algorithm goes with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">B</code></figcaption></figure><p>Luego, puedes ver líneas donde toda las tres versiones están de acuerdo - están en la base de fusión, <code>A</code> y <code>B</code>, con datos iguales.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_2.png" class="kg-image" alt="Lines where all three versions agree" width="600" height="400" loading="lazy"><figcaption>Lines where all three versions agree</figcaption></figure><p>En este caso el algoritmo tiene una opción trivial - sólo toma esa versión.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_2.png" class="kg-image" alt="In case all three versions agree, the algorithm goes with that single version" width="600" height="400" loading="lazy"><figcaption>In case all three versions agree, the algorithm goes with that single version</figcaption></figure><p>En un ejemplo previo, vimos que si la base de fusión y <code>A</code> están de acuerdo, y la versión de <code>B</code> es diferente, el agoritmo toma <code>B</code>. Esto funciona en la otra dirección también - por ejemplo, aquí tienes una línea que existe en la rama de John, distinto al de la base de fusión y al de la rama de Paul.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_3.png" class="kg-image" alt="A line where Paul's version matches the merge base's version, and John has a different version" width="600" height="400" loading="lazy"><figcaption>A line where Paul's version matches the merge base's version, and John has a different version</figcaption></figure><p>Por lo tanto, la versión de John es elegida:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_3.png" class="kg-image" alt="If the state of the merge base is the same as , and this state is different from , the algorithm goes with " width="600" height="400" loading="lazy"><figcaption>If the state of the merge base is the same as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">B</code>, and this state is different from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">A</code>, the algorithm goes with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">A</code></figcaption></figure><p>Ahora considera otro caso, donde <code>A</code> y <code>B</code> están de acuerdo en una línea, pero el valor en el que están de acuerdo es distinta del de la base de fusión: ambos John y Paul acordaron en cambiar la línea "Everyone put their feet down" a "Everyone put their foot down":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_versions_4.png" class="kg-image" alt="A line where Paul's version matches John's version; yet the merge base has a different version" width="600" height="400" loading="lazy"><figcaption>A line where Paul's version matches John's version, yet the merge base has a different version</figcaption></figure><p>En este caso, el algoritmo toma la versión de <code>A</code> y de <code>B</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_4.png" class="kg-image" alt="In case A and B agree on a version which is different from the merge base's version, the algorithm picks the version on both A and B" width="600" height="400" loading="lazy"><figcaption>In case <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">A</code> and <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">B</code> agree on a version which is different from the merge base's version, the algorithm picks the version on both <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">A</code> and <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">B</code></figcaption></figure><p>Fíjate que esto no es un voto democrático. En el caso previo, el algoritmo tomó la versión minoritaria, ya que se parecía a la versión más reciente de esta línea. En este caso, llega a tomar la mayoría - pero solamente porque <code>A</code> y <code>B</code> son las revisiones que acordan en la nueva versión.</p><p>Lo mismo sucedería si usaramos <code>git merge</code>:</p><pre><code class="language-bash">git merge john_branch_3
</code></pre><p>Sin especificar ningún argumento, <code>git merge</code> por defecto usará una <code>fusión de 3 vías</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_merge_default.png" class="kg-image" alt="By default,  uses a 3-way merge algorithm" width="600" height="400" loading="lazy"><figcaption>By default, <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git merge</code> uses a 3-way merge algorithm</figcaption></figure><p>El estado de <code>everyone.md</code> después de ejecutar <code>git merge john_branch</code> sería el mismo que el resultado que alcanzaste al aplicar los parches con <code>git apply -3</code>.</p><p>Si consideras el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merge.png" class="kg-image" alt="Git's history after performing the merge" width="600" height="400" loading="lazy"><figcaption>Git's history after performing the merge</figcaption></figure><p>Verás que la confirmación de fusión tiene dos antecesores: el primero es el "Commit 11", eso es, a donde apuntó <code>paul_branch_3</code> antes de la fusión. El segundo es "Commit 12", a donde <code>john_branch_3</code> apuntó, y a donde todavía apunta ahora.</p><p>¿Qué sucederá si ahora fusionas desde <code>main</code>? Eso es, cambiar a la rama <code>main</code>, el cual apunta al "Commit 10":</p><pre><code class="language-bash">git checkout main
</code></pre><p>¿Y luego fusionar la rama de Paul?</p><pre><code class="language-bash">git merge paul_branch_3
</code></pre><p>De hecho, obtenemos una fusión directa - como antes de ejecutar este comando, <code>main</code> era un ancestro de <code>paul_branch_3</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/fast_forward_merge.png" class="kg-image" alt="A fast-forward merge" width="600" height="400" loading="lazy"><figcaption>A fast-forward merge</figcaption></figure><p>Así que, esto es una fusión de 3 vías. En general, si todas las versiones acuerdan en una línea, luego esta línea es usada. Si <code>A</code> y la base de fusión coinciden, y <code>B</code> tiene otra versión, <code>B</code> es tomado. En el caso opuesto, donde la base de fusión y <code>B</code> coinciden, la versión <code>A</code> es seleccionado. Si <code>A</code> y <code>B</code> coinciden, esta versión es tomada, sea que la base de fusión esté de acuerdo o no.</p><p>Esta descripción deja una pregunta abierta: ¿qué sucede en casos donde todas las tres versiones están en desacuerdo?</p><p>Bueno, eso es un conflicto que Git no lo resuelve automáticamente. En estos casos, Git pide ayuda de un humano.</p><h3 id="c-mo-resolver-conflictos-de-fusi-n"><strong>Cómo resolver conflictos de fusión</strong></h3><p>Siguiendo hasta ahora, deberías entender las bases del comando <code>git merge</code>, y cómo Git puede resolver automáticamente algunos conflictos. También entiendes qué casos son resueltos automáticamente.</p><p>Ahora, consideremos un caso más avanzado.</p><p>Digamos que Paul y John continúan trabajando en esta canción.</p><p>Paul crea una nueva rama:</p><pre><code class="language-bash">git checkout -b paul_branch_4
</code></pre><p>Y él decide agregar algunos "Yeah" a la canción, así que él cambia este verso como sigue:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/paul_branch_4_additions.png" class="kg-image" alt="Paul's additions" width="600" height="400" loading="lazy"><figcaption>Paul's additions</figcaption></figure><p>Así que Paul pone en el área de preparación y confirma estos cambios:</p><pre><code class="language-bash">git add everyone.md
git commit -m "Commit 13"
</code></pre><p>Paul también crea otra canción, <code>let_it_be.md</code> y lo agrega al repo:</p><pre><code class="language-bash">git add let_it_be.md
git commit -m "Commit 14"
</code></pre><p>Este es el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_14.png" class="kg-image" alt="The history after Paul introduced &quot;Commit 14&quot;" width="600" height="400" loading="lazy"><figcaption>The history after Paul introduced "Commit 14"</figcaption></figure><p>Volviendo a <code>main</code>:</p><pre><code class="language-bash">git checkout main
</code></pre><p>John también crea una rama:</p><pre><code class="language-bash">git checkout -b john_branch_4
</code></pre><p>Y John también trabaja en la canción "Everyone had a hard year", luego para ser llamado "I've got a feeling" (de nuevo, esto no es un libro sobre los Beatles, así que no daré mas detalles aquí. Mira los enlaces adicionales si tienes curiosidad).</p><p>John decide cambiar todas las ocurrencias de "Everyone" to "Everybody":</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_5.png" class="kg-image" alt="John changes all occurrences of &quot;Everyone&quot; to &quot;Everybody&quot;" width="600" height="400" loading="lazy"><figcaption>John changes all occurrences of "Everyone" to "Everybody"</figcaption></figure><p>Él pone en el área de preparación y confirma esta canción al repo:</p><pre><code class="language-bash">git add everyone.md
git commit -m "Commit 15"
</code></pre><p>Bien. Ahora John también crea otra canción, <code>across_the_universe.md</code>. Él lo agrega al repo también:</p><pre><code class="language-bash">git add across_the_universe.md
git commit -m "Commit 16"
</code></pre><p>Observa el historial nuevamente:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_16.png" class="kg-image" alt="The history after John introduced &quot;Commit 16&quot;" width="600" height="400" loading="lazy"><figcaption>The history after John introduced "Commit 16"</figcaption></figure><p>Puedes ver que el historial difiere de <code>main</code>, a dos ramas distintas - <code>paul_branch_4</code>, y <code>john_branch_4</code>.</p><p>A este punto, a John le gustaría fusionar los cambios introducidos por Paul.</p><p>¿Qué va a pasar aquí?</p><p>Recuerda los cambios introducidos por Paul:</p><pre><code class="language-bash">git diff main paul_branch_4
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_paul_branch_4.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff main paul_branch_4</code></figcaption></figure><p>¿Qué piensas? ¿La fusión funcionará?</p><p>Inténtalo:</p><pre><code class="language-bash">git merge paul_branch_4
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/merge_conflict.png" class="kg-image" alt="A merge conflict" width="600" height="400" loading="lazy"><figcaption>A merge conflict</figcaption></figure><p>¡Tenemos un conflicto!</p><p>Git no puede fusionar estas ramas por sí mismo. Puedes obtener una vista general del estado de fusión, usando <code>git status</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_merge_failed.png" class="kg-image" alt="The output of  right after the merge operation" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> right after the merge operation</figcaption></figure><p>Los cambios que Git no tuvo problema resolviendo están en el área de preparación para confimar. Y hay una sección separada para "rutas no fusionadas" - estos son archivos con conflictos que Git no podría resolver por sí mismo.</p><p>Es tiempo de entender por qué y cuando estos conflictos suceden, cómo resolverlos, y también cómo Git los maneja por debajo.</p><p>¡Muy bien entonces! Espero que al menos estés emocionado como yo. 😇</p><p>Recordemos lo que sabemos sobre fusiones de 3 vías:</p><p>Primero, Git buscará la base de fusión - el ancestro común de <code>john_branch_4</code> y <code>paul_branch_4</code>. ¿Cuál confirmación sería ese?</p><p>Sería la punta de la rama <code>main</code>, la confirmación en el cual fusionamos <code>john_branch_3</code> en <code>paul_branch_3</code>.</p><p>De vuelta, si no estás seguro, puedes verificar eso ejecutando:</p><pre><code class="language-bash">git merge-base john_branch_4 paul_branch_4
</code></pre><p>Y en el estado actual, <code>git status</code> sabe qué archivos están en el área de preparación y cuáles no.</p><p>Considera el proceso para cada <em><em>archivo</em></em>, el cual es el mismo que el algoritmo de fusión de 3 vías que consideramos por línea, pero a nivel de archivo:</p><p><code>across_the_universe.md</code> existe en la rama de John, pero no existe en la base de fusión o en la rama de Paul. Así que Git elige incluir este archivo. Ya que ya estás en la rama de John y este archivo es incluido en la punta de esta rama, no es mencionado por <code>git status</code>.</p><p><code>let_it_be.md</code> existe en la rama de Paul, pero no existe en la base de fusión o en la rama de John. Así que <code>git merge</code> "elige" incluirlo.</p><p>¿Qué hay sobre <code>everyone.md</code>? Bueno, aquí tenemos tres estados distintos de este archivo: su estado en la base de fusión, su estado en la rama de John, y su estado en la rama de Paul. Mientras se realiza una fusión, Git almacena todas estas versiones en el índice.</p><p>Observemos eso mirando directamente al índice con el comando <code>git ls-files</code>:</p><pre><code class="language-bash">git ls-files -s --abbrev
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ls_files_abbrev.png" class="kg-image" alt="The output of  after the merge operation" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git ls-files -s --abbrev</code> after the merge operation</figcaption></figure><p>Puedes ver que <code>everyone.md</code> tiene tres entradas diferentes. Git le asigna a cada versión un número que representa la "fusión" del archivo, y esta es una propiedad distinta de una entrada de índice, junto con el nombre del archivo y el modo bits.</p><p>Cuando no hay conflicto de fusión en cuanto a un archivo, su "área de preparación" es <code>0</code>. Esto es de hecho el estado para <code>across_the_universe.md</code>, y para <code>let_it_be.md</code>.</p><p>En un estado de conflicto, tenemos:</p><ul><li>Estado <code>1</code> - el cual es la base de fusión.</li><li>Estado <code>2</code> - el cual es "tu" versión. Eso es, la versión del archivo en la rama <em><em>en</em></em> la que estás fusionando. En nuestro ejemplo, este sería <code>john_branch_4</code>.</li><li>Estado <code>3</code>- el cual es "su" versión, también llamado el <code>MERGE_HEAD</code>. Eso es, la versión en la rama que estás fusionando (en la rama actual). En nuestro ejemplo, ese es <code>paul_branch_4</code>.</li></ul><p>Para observar los contenidos del archivo en un estado específico, puedes usar un comando que introduje en un post previo, <code>git cat-file</code>, y proveer el SHA del blob:</p><pre><code class="language-bash">git cat-file -p &lt;BLOB_SHA_FOR_STAGE_2&gt;
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cat_file.png" class="kg-image" alt="Using -file to present the content of the file on John's branch, right from its state in the index" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git cat-file</code> to present the content of the file on John's branch, right from its state in the index</figcaption></figure><p>Y justamente, este es el contenido que esperábamos - de la rama de John, donde las líneas comienzan con "Everybody" en vez de "Everyone".</p><p>Un lindo truco que te permite ver el contenido rápidamente sin proveer el valor SHA-1 del blob, es usando <code>git show</code>, así:</p><pre><code class="language-bash">git show :&lt;STAGE&gt;:everyone.md
</code></pre><p>Por ejemplo, para obtener el contenido de la misma versión como con <code>git cat-file -p &lt;BLOB_SHA_FOR_STAGE_2&gt;</code>, puedes escribir <code>git show :2:everyone.md</code>.</p><p>Git registra los tres estados de los tres confirmaciones en el índice de esta forma al comienzo de la fusión. Luego continúa con el algoritmo de fusión de tres vías para resolver rápidamente los casos sencillos.</p><p>En el caso que todas las tres áreas de preparación coincidan, entonces la selección es trivial.</p><p>Si un lado hiciera un cambio mientras los otros no lo hicieron - eso es, área de preparación <code>1</code> coincide con el área de preparación <code>2</code> - entonces elegimos el área de preparación <code>3</code>, o vice versa. Eso es exactamente lo que sucedió con <code>let_it_be.md</code> y <code>across_the_universe.md</code>.</p><p>En caso de una supresión en la rama entrante, por ejemplo, y dado que no hubieron cambios en la rama actual, entonces veríamos que el stage <code>1</code> coincide con el stage <code>2</code>, pero no hay stage <code>3</code>. En este caso, <code>git merge</code> quita el archivo para la versión fusionada.</p><p>Lo que es realmente interesante aquí es para coincidir, Git no necesita los archivos actuales. Más bien, se puede basar en los valores SHA-1 de los blobs correspondientes. De esta forma, Git puede detectar fácilmente el estado en el que se encuentra un archivo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_way_merge_4-1.png" class="kg-image" alt="Git performs the same 3-way merge algorithm on a files level" width="600" height="400" loading="lazy"><figcaption>Git performs the same 3-way merge algorithm on a files level</figcaption></figure><p>Para <code>everyone.md</code> tiene este caso especial - donde el área de preparación <code>1</code>, el área de preparación <code>2</code> y el área de preparación <code>3</code> son todos distintos uno del otro. Eso es, tienen SHAs de blob distintos. Es momento de ir más profundo y entender el conflicto de fusión. 😊</p><p>Una forma de hacer eso sería simplemente usar <code>git diff</code>. En un <a href="#cap-6">capítulo anterior</a>, examinamos git diff en detalle, y vimos que muestra las diferencias entre varias combinaciones del árbol de trabajo, del índice o de las confirmaciones.</p><p>Pero <code>git diff</code> también tiene un modo especial para ayudar con los conflictos de fusión:</p><pre><code class="language-bash">git diff
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_conflict.png" class="kg-image" alt="The output of  during a merge conflict" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> during a merge conflict</figcaption></figure><p>Esta salida podría ser confuso al principio, pero una vez que te acostumbras, es bastante claro. Empecemos por entenderlo, y luego veamos cómo puede resolver los conflictos con otras herramientas mas visuales.</p><p>La sección en conflictos está separado por los signos "iguales" &nbsp;(<code>===</code>), y marcado con las ramas correspondientes. En este contexto, "el nuestro" es la rama actual. En este ejemplo, sería <code>john_branch_4</code>, la rama a la que <code>HEAD</code> estaba apuntando cuando iniciamos el comando <code>git merge</code>. "El suyo" es el <code>MERGE_HEAD</code>, la rama que estamos fusionando - en este caso, <code>paul_branch_4</code>.</p><p>Así que <code>git diff</code> sin ningun argumento especial muestra los cambios entre el árbol de trabajo y el índice - el cual en este caso son los conflictos aún por resolver. La salida no incluye cambios en el área de preparación, lo cual es conveniente para resolver el conflicto.</p><p>Es tiempo de resolver esto manualmente. ¡Qué divertido!</p><p>Así, ¿por qué esto es un conflicto?</p><p>Para Git, Paul y John hicieron distintos cambios a la misma línea, por unas pocas líneas. John lo cambió a una cosa, y Paul lo cambió a otra cosa. Git no puede decidir cuál es el correcto.</p><p>Este es no es el caso para las últimas líneas, como la línea solía ser "Everyone had a hard year" en la base de fusión. Paul no ha cambiado esta línea, o las líneas que le rodean, así su versión en paul_branch_4 o "el suyo" en nuestro caso, se pone de acuerdo con el <code>merge_base</code>. Aunque la versión de John, "el nuestro", es distinto. Así <code>git merge</code> puede decidir fácilmente que tome esta versión.</p><p>Pero, ¿qué hay sobre las líneas en conflicto?</p><p>En este caso, sé lo que quiero, y eso es en realidad una combinación de estas líneas. Quiero que las líneas comiencen con "Everybody", siguiendo el cambio de John, pero también que incluya los "yeah" de Paul. Así que ve y crea la versión deseada editando a <code>everyone.md</code>:</p><pre><code class="language-bash">nano everyone.md
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/everyone_6.png" class="kg-image" alt="Editing the file manually to achieve the desired state" width="600" height="400" loading="lazy"><figcaption>Editing the file manually to achieve the desired state</figcaption></figure><p>Para comparar el archivo resultante con lo que tenías en la rama previa a la fusión, puedes ejecutar:</p><pre><code class="language-bash">git diff --ours
</code></pre><p>De manera similar, si deseas ver cuánto difiere el resultado de la fusión de la rama que fusionaste en nuestra rama, puedes ejecutar:</p><pre><code class="language-bash">git diff --theirs
</code></pre><p>Inclusive puedes ver cuán distinto es el resultado de ambos lados usando:</p><pre><code class="language-bash">git diff --base
</code></pre><p>Ahora puedes poner en el área de preparación la versión arreglada:</p><pre><code class="language-bash">git add everyone.md
</code></pre><p>Después de poner en el área de preparación, si miras en <code>git status</code>, no verás conflictos:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_manual_fix.png" class="kg-image" alt="After staging the fixed version , there are no conflicts" width="600" height="400" loading="lazy"><figcaption>After staging the fixed version <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">everyone.md</code>, there are no conflicts</figcaption></figure><p>Ahora puedes simplemente usar <code>git commit</code>, y Git te presentará con un mensaje de confirmación conteniendo los detalles sobre la fusión. Puedes modificarlo si quisieras, o dejarlo como está. Sin importar del mensaje de confirmación, Git creará un "mensaje de fusión" - eso es, una confirmación con más de un precesor.</p><p>Para validar eso, considera el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_merge_2.png" class="kg-image" alt="The history after completing the merge operation" width="600" height="400" loading="lazy"><figcaption>The history after completing the merge operation</figcaption></figure><p><code>john_branch_4</code> ahora apunta a la nueva confirmación de fusión. La rama entrante, "el suyo", en este caso, <code>paul_branch_4</code>, se mantiene donde estaba.</p><h3 id="c-mo-usar-vs-code-para-resolver-los-conflictos"><strong>Cómo usar VS Code para resolver los conflictos</strong></h3><p>Ahora verás cómo resolver el mismo conflicto usando una herramienta gráfica. Para este ejemplo, use VS Code, el cual es un editor de código popular y gratis. Hay muchas otras herramientas, pero el proceso es similar, así que solo mostraré VS Code como un ejemplo.</p><p>Primero, volvamos al estado antes de la fusión:</p><pre><code class="language-bash">git reset --hard HEAD~
</code></pre><p>E intentemos fusionar otra vez:</p><pre><code class="language-bash">git merge paul_branch_4
</code></pre><p>Deberías estar nuevamente al mismo estado:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_merge_failed-1.png" class="kg-image" alt="Back at the conflicting status" width="600" height="400" loading="lazy"><figcaption>Back at the conflicting status</figcaption></figure><p>Veamos cómo aparece esto en VS Code:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/vs_code_1.png" class="kg-image" alt="Conflict resolution with VS Code" width="600" height="400" loading="lazy"><figcaption>Conflict resolution with VS Code</figcaption></figure><p>VS Code marca las distintas versiones con "Current Change" - el cual es la versión de la "nuestra", el actual <code>HEAD</code>, y "Cambio Entrante" para la rama que estamos fusionando en la rama activa. Puedes aceptar uno de los cambios (o ambos) haciendo clic en una de las opciones.</p><p>Si hiciste clic en <code>Resolver en Editor de Fusión</code>, obtendrás una vista mas visual del estado. VS Code muestra el estado de cada línea:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/vs_code_2-1.png" class="kg-image" alt="VS Code's Merge Editor" width="600" height="400" loading="lazy"><figcaption>VS Code's Merge Editor</figcaption></figure><p>Si miras con atención, verás que VS Code muestra cambios dentro de las palabras - por ejemplo, muestra que "Every<strong><strong>one</strong></strong>" fue cambiado a "Every<strong><strong>body</strong></strong>", marcando las partes cambiadas.</p><p>Puedes aceptar cualquier versión, o puedes aceptar una combinación. En este caso, si haces clic en "Aceptar Combinación", obtienes este resultado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/vs_code_3.png" class="kg-image" alt="VS Code's Merge Editor after clicking on &quot;Accept Combination&quot;" width="600" height="400" loading="lazy"><figcaption>VS Code's Merge Editor after clicking on "Accept Combination"</figcaption></figure><p>¡VS Code hizo un excelente trabajo! El mismo algoritmo de fusión de tres vías fue implementado aquí y usado a el nivel de <em><em>palabra</em></em> en vez a nivel de <em><em>línea</em></em>. Así que VS Code fue capaz en realidad de resolver este conflicto de una forma impresionante. Por supuesto, puedes modificar la sugerencia de VS Code, pero proveyó un comienzo <em><em>muy</em></em> bueno.</p><h3 id="una-herramienta-poderosa-adicional"><strong>Una Herramienta Poderosa adicional</strong></h3><p>Bueno, este fue la primera vez en este libro que he usado una herramienta con una interfaz de usuario gráfica. De hecho, las interfaces gráficas pueden ser convenientes para entender lo que está sucediendo cuando estás resolviendo conflictos de fusión.</p><p>Sin embargo, como en muchos otros casos, cuando necesitamos realmente entender lo que está sucediendo, la línea de comando se vuelve práctico. Así que, volvamos a la línea de comandos y aprendamos una herramienta que nos puede venir bien en casos mas complicados.</p><p>De nuevo, vuelve al estado antes de la fusión:</p><pre><code class="language-bash">git reset --hard HEAD~
</code></pre><p>Y fusiona:</p><pre><code class="language-bash">git merge paul_branch_4
</code></pre><p>Y digamos, no estás seguro exactamente de lo que pasó. ¿Por qué hay un conflicto? Un comando muy útil sería:</p><pre><code class="language-bash">git log -p --merge
</code></pre><p>Como recordatorio, <code>git log</code> muestra el historial de confirmaciones que son alcanzables desde <code>HEAD</code>. Agregando <code>-p</code> le dice a <code>git log</code> que muestre las confirmaciones juntamente con los diffs que introdujeron. El argumento <code>--merge</code> hace que el comando muestre todas las confirmaciones que contienen cambios relevantes a cualquier archivo que no están en el área de preparación, en cualquier rama, junto con sus diffs.</p><p>Esto te puede ayudar en identificar los cambios en el historial que llevaron a los conflictos. Así que en este ejemplo, verías:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_p_merge.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log -p --merge</code></figcaption></figure><p>La primer confirmación que vemos es "Commit 15", ya que en ésta confirmación John modificó <code>everyone.md</code>, un archivo que todavía tiene conflictos. Luego, Git muestra "Commit 13", donde Paul cambió <code>everyone.md</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_p_merge_2.png" class="kg-image" alt="The output of  - continued" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log -p --merge</code> - continued</figcaption></figure><p>Fíjate que <code>git log --merge</code> no mencionó confirmaciones previas que cambiaron a <code>everyone.md</code> antes de "Commit 13", ya que no afectaron el conflicto actual.</p><p>De esta forma, <code>git log</code> te dice que todo lo que necesitas saber para entender el proceso que te llevó al estado de conflicto actual. ¡Genial! 😎</p><p>Usando la línea de comandos, también puedes preguntarle a Git que tome solamente un lado de los cambios - sea "el nuestro" o "el suyo", inclusive para un archivo específico.</p><p>También puedes instruir a Git que tome algunas partes de los diffs de un archivo y otro de otro archivo. Proveeré enlances que describen cómo hacer eso en los <a href="#cap-6">recursos adicionales de este capítulo en el apéndice</a>.</p><p>Para la mayor parte, puedes lograr eso bastante fácil, sea manualmente o desde la UI de tu IDE favorito.</p><p>Por ahora, es tiempo de recapitular.</p><h3 id="recapitulando-entendiendo-git-merge"><strong>Recapitulando - Entendiendo Git Merge</strong></h3><p>En este capítulo, tuviste una vista general extensiva de fusión con Git. Aprendiste que fusionar es el proceso de combinar los cambios recientes desde varias ramas en una sola confirmación. La nueva confirmación tiene dos predecesores - esas confirmaciones los cuales han sido las puntas de las ramas que fueron fusionados.</p><p>Consideramos una fusión directa sencilla, lo cual es posible cuando una rama difiere de la rama base, y luego agregamos confirmaciones por encima de la rama base.</p><p>Luego consideramos fusiones de tres vías, y explicamos el proceso de tres estados:</p><ul><li>Primero, Git localiza la base de fusión. Como recordatorio, este es la primer confirmación que es alcanzable desde ambas ramas.</li><li>Segudno, Git calcula los dos diffs - un diff desde la base de fusión a la <em><em>primer</em></em> rama, y otro diff desde la base de fusión a la <em><em>segunda</em></em> rama. Git genera parches basados en esos diffs.</li><li>Tercero y último, Git aplica ambos parches a la base de fusión usando un algoritmo de fusión de 3 vías. El resultado es el estado de la nueva confirmación de fusión.</li></ul><p>Indagamos profundamente en el proceso de fusión de 3 vías, sea a nivel de archivo o a nivel de hunk. Consideramos cuando Git es capaz de basarse en una fusión de 3 vías para resolver automáticamente los conflictos, y cuando no puede.</p><p>Viste la salida de <code>git diff</code> cuando estamos en un estado de conflicto, y cómo resolver los conficltos manualmente o con VS Code.</p><p>Hay mucho más que decir sobre las fusiones - diferentes estrategias de fusión, fusiones recursivas, y así sucesivamente. Con todo, creo que este capítulo cubrió todo lo necesario de esa forma tienes un entendimiento robusto de lo que es una fusión, y qué sucede por debajo en la vasta mayoría de casos.</p><h3 id="recursos-relacionados-a-los-beatles"><strong>Recursos relacionados a los Beatles</strong></h3><ul><li><a href="https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/">https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/</a></li><li><a href="https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/">https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/</a></li><li><a href="http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html">http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html</a></li></ul><!--kg-card-begin: html--><h2 id="cap-8">Capítulo 8 - Entendiendo Git Rebase</h2><!--kg-card-end: html--><p>Una de las herramientas más poderosas que tiene un desarrollador en su caja de herramientas es <code>git rebase</code>. Aunque es notorio por ser complejo e incomprendido.</p><p>La verdad es, si entiendes lo que hace en realidad, <code>git rebase</code> es una herramienta muy elegante, y directa para alcanzar muchísimas cosas diferentes en Git.</p><p>En los capítulos previos en esta parte, aprendiste qué son los diffs de Git, lo que es una fusión, y cómo Git resuelve los conflictos de fusión. En este capítulo, entenderás lo que es rebase de Git, por qué es diferente de merge, y cómo hacer rebase (sobrescribir la base) con confianza.</p><h3 id="recapitulaci-n-corta-qu-es-git-merge"><strong>Recapitulación Corta - ¿Qué es Git Merge?</strong></h3><p>Por debajo, <code>git rebase</code> y <code>git merge</code> son cosas muy muy distintas. Entonces, ¿por qué la gente los compara todo el tiempo?</p><p>La razón es su uso. Cuando se trabaja con Git, usualmente trabajamos en distintas ramas e introducimos cambios a esas ramas.</p><p>En el capítulo previo, consideramos el ejemplo donde John y Paul (de los Beatles) eran co-autores de nueva canción. Comenzaron desde la rama <code>main</code>, y luego cada uno difirió, modificaron la letra, y confirmaron sus cambios.</p><p>Luego, los dos querían <em><em>integrar</em></em> sus cambios, lo cual es algo que sucede muy frecuente cuando se trabaja con Git.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diverging_history_commit_9.png" class="kg-image" alt="A diverging history -  and  diverged from " width="600" height="400" loading="lazy"><figcaption>A diverging history - <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">paul_branch</code> and <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">john_branch</code> diverged from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Hay dos formas principales para integrar cambios introducidos en diferentes ramas en Git, o en otras palabras, en diferentes confirmaciones e historiales de confirmación. Estos son merge y rebase.</p><p>En el capítulo anterior, llegamos a saber <code>git merge</code> bastante bien. Vimos que cuando realizamos una fusión, creamos una <strong><strong>confirmación de fusión</strong></strong> - donde los contenidos de esta confirmación son una combinación de las dos ramas, y también tiene dos predecesores, una en cada rama.</p><p>Así que, digamos que estás en la rama <code>john_branch</code> (asumiendo el historial representado en el dibujo de arriba), y ejecutas <code>git merge paul_branch</code>. Llegarás a este estado - donde en <code>john_branch</code>, hay una nueva confirmación con dos predecesores. El primero será la confirmación en la rama <code>john_branch</code> donde el <code>HEAD</code> estaba apuntando a un estado antes de realizar la fusión - en este caso, "Commit 6". El segundo será la confirmación a la que apunta <code>paul_branch</code>, "Commit 9".</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_merge_paul_branch.png" class="kg-image" alt="The result of running : a new Merge Commit with two parents" width="600" height="400" loading="lazy"><figcaption>The result of running <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git merge paul_branch</code>: a new Merge Commit with two parents</figcaption></figure><p>Mira otra vez al gráfico del historial: creaste un historial <strong><strong>divergente</strong></strong>. Puedes ver dónde se ramificó y dónde se fusionó nuevamente.</p><p>Así que cuando usas <code>git merge</code>, no puedes reescribir el historial - sino, que agregas una confirmación al historial existente. Y específicamente, una confirmación que crea un historial divergente.</p><h3 id="-c-mo-se-diferencia-git-rebase-de-git-merge"><strong>¿Cómo se diferencia <code>git rebase</code> de <code>git merge</code>?</strong></h3><p>Cuando se usa <code>git rebase</code>, algo distinto ocurre.</p><p>Comencemos con el panorama general: si estás en <code>paul_branch</code>, y usas <code>git rebase john_branch</code>, Git va al ancestro común de la rama de John y de Paul. Luego tomas los parches introducidos en las confirmaciones de la rama de Paul, y aplicar esos cambios a la rama de John.</p><p>Así que aquí, usas <code>rebase</code> para tomar los cambios que fueron confirmados en una rama - la rama de Paul - y reproducirlos en una rama distinta, <code>john_branch</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_rebase_john_branch.png" class="kg-image" alt="The result of running : the commits on  were &quot;replayed&quot; on top of " width="600" height="400" loading="lazy"><figcaption>The result of running `git rebase john_branch`: the commits on `paul_branch` were "replayed" on top of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">john_branch</code></figcaption></figure><p>Espera, ¿qué significa eso?</p><p>Ahora tomaremos esto poco a poco para asegurarnos que entiendes completamente lo que estás sucediendo por debajo 😎.</p><h3 id="cherry-pick-como-una-base-para-rebase"><strong><code>cherry-pick</code> como una base para Rebase</strong></h3><p>Es útil pensar de rebase como realizar <code>git cherry-pick</code> - un comando que toma una confirmación, calcula el parche que ésta confirmación introduce al calcular la diferencia entre la confirmación del predecesor y la confirmación misma, y luego cherry-pick "repite" esta diferencia.</p><p>Hagamos esto manualmente.</p><p>Si miramos la diferencia introducido por "Commit 5" al hacer <code>git diff main &lt;SHA_OF_COMMIT-5&gt;</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5.png" class="kg-image" alt="Running  to observe the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy"><figcaption>Running <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> to observe the patch introduced by "Commit 5"</figcaption></figure><p>Como siempre, se te anima en ejecutar los comandos tú mismo mientras lees este capítulo. A menos que se diga otra cosa, usaré el siguiente repositorio:</p><p><a href="https://github.com/Omerr/rebase_playground.git">https://github.com/Omerr/rebase_playground.git</a></p><p>Te recomiendo que lo clones de forma local y tener el mismo punto de inicio que estoy usando para este capítulo.</p><p>Puedes ver eso en esta confirmación, John comenzó trabajando en una canción llamada "Lucy in the Sky with Diamonds":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5_output.png" class="kg-image" alt="The output of  - the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> - the patch introduced by "Commit 5"</figcaption></figure><p>Como recordatorio, también puedes usar el comando <code>git show</code> para obtener la misma salida:</p><pre><code class="language-bash">git show &lt;SHA_OF_COMMIT_5&gt;
</code></pre><p>Ahora, si haces <code>cherry-pick</code> a esta confirmación, introducirás <em><em>este cambio</em></em> específicamente, en la rama activa. Cambia a <code>main</code> primero:</p><pre><code class="language-bash">git checkout main (or git switch main)
</code></pre><p>Y crea otra rama:</p><pre><code class="language-bash">git checkout -b my_branch (or git switch -c my_branch)
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_my_branch.png" class="kg-image" alt="Creating  that branches from " width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_branch</code> that branches from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Luego, haz <code>cherry-pick</code> a "Commit 5":</p><pre><code class="language-bash">git cherry-pick &lt;SHA_OF_COMMIT_5&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cherry_pick_commit_5.png" class="kg-image" alt="Using  to apply the changes introduced in &quot;Commit 5&quot; onto " width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">cherry-pick</code> to apply the changes introduced in "Commit 5" onto <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Considera el log (salida de <code>git lol</code>):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_commit_5.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol</code></figcaption></figure><p>Parece que copiaste-pegaste el "Commit 5". Recuerda que inclusive tiene el mismo mensaje de confirmación, e introduce los mismos cambios, e inclusive apunta al mismo objeto de árbol como el "Commit 5" original en este caso - todavía es un objeto de confirmación distinto, como si fuese creado con una marca de tiempo distinto.</p><p>Mirando a los cambios, usando <code>git show HEAD</code></p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD</code></figcaption></figure><p>Son lo mismo como los "Commit 5".</p><p>Y por supuesto, si miras al archivo (digamos, usando <code>nano lucy_in_the_sky_with_diamonds.md</code>), estará en el mismo estado que estaba después del "Commit 5" original.</p><p>¡Genial! 😎</p><p>Ahora puedes quitar la nueva rama así no aparece en tu historial cada vez:</p><pre><code class="language-bash">git checkout main
git branch -D my_branch
</code></pre><h3 id="m-s-all-de-cherry-pick-c-mo-usar-git-rebase"><strong>Más allá de <code>cherry-pick</code> - Cómo usar <code>git rebase</code></strong></h3><p>Puedes ver a <code>git rebase</code> como una forma de realizar múltiples <code>cherry-pick</code> uno después del otro - eso es, "repetir" múltiples confirmaciones. Esto no es lo único que puedes hacer con rebase, pero es un buen punto de comienzo para nuestra explicación.</p><p>¡Es tiempo de jugar con <code>git rebase</code>!</p><p>Antes, hiciste fusión de <code>paul_branch</code> en <code>john_branch</code>. ¿Qué debería de pasar si hicieras <em><em>rebase</em></em> de <code>paul_branch</code> por encima de <code>john_branch</code>? Obtendrías un historial muy distinto.</p><p>En esencia, parecería como si tomáramos los cambios introducidos en las confirmaciones de <code>paul_branch</code>, y repitiéramos en <code>john_branch</code>. El resultado sería un historial linear.</p><p>Para entender el proceso, te proveeré la vista de alto nivel, y luego indagaré más profundo en cada paso. El proceso de hacer rebase en una rama por encima de otra rama es como lo siguiente:</p><ol><li>Encuentra el ancestro común.</li><li>Identifica las confirmaciones a ser "repetidos".</li><li>Para cada confirmación <code>X</code>, calcula <code>diff(parent(X), X)</code>, y lo almacena como un <code>patch(X)</code>.</li><li>Mueve a <code>HEAD</code> a la nueva base.</li><li>Aplica los parches generados en orden en la rama de destino. Cada vez, crea un nuevo objeto de confirmación con el nuevo estado.</li></ol><p>El proceso de hacer nuevas confirmaciones con el mismo conjunto de cambios que los existentes también se le llama "<strong><strong>repe</strong>t<strong>ir</strong></strong>" esas confirmaciones, un término que ya hemos usado.</p><h3 id="tiempo-de-practicar-con-rebase"><strong>Tiempo de practicar con Rebase</strong></h3><p>Antes de ejecutar el siguiente comando, asegúrate de tener a <code>john_branch</code> localmente, así que ejecuta:</p><pre><code class="language-bash">git checkout john_branch
</code></pre><p>Comienza desde la rama de Paul:</p><pre><code class="language-bash">git checkout paul_branch
</code></pre><p>Este es el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/diverging_history_commit_9-1.png" class="kg-image" alt="Commit history before performing " width="600" height="400" loading="lazy"><figcaption>Commit history before performing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git rebase</code></figcaption></figure><p>Y ahora, la parte emocionante:</p><pre><code class="language-bash">git rebase john_branch
</code></pre><p>Y observa el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase.png" class="kg-image" alt="The history after rebasing" width="600" height="400" loading="lazy"><figcaption>The history after rebasing</figcaption></figure><p>Con <code>git merge</code> agregaste al historial, mientras que con <code>git rebase</code> <strong><strong>reescribes el historial</strong></strong>. Creas <strong><strong>nuevos</strong></strong> objetos de confirmación. Además, el resultado es un gráfico de historial linear - en vez de un gráfico divergente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase_2.png" class="kg-image" alt="The history after rebasing" width="600" height="400" loading="lazy"><figcaption>The history after rebasing</figcaption></figure><p>En esencia, "copiaste" las confirmaciones que estaban en <code>paul_branch</code> y que fueron introducidos después de "Commit 4", y los "pegaste" por encima de <code>john_branch</code>.</p><p>El comando se llama "rebase", porque cambia la confirmación base de la rama de donde se ejecuta. Eso es, en tu caso, antes de ejecutar <code>git rebase</code>, la base de <code>paul_branch</code> era "Commit 4" - ya que aquí es donde la rama "nació" (desde <code>main</code>). Con <code>rebase</code>, le pediste a Git que le diera otra base - eso es, pretender que haya nacido desde "Commit 6".</p><p>Para hacer eso, Git tomó lo que solía ser "Commit 7", y "repitió" los cambios introducidos en esta confirmación en "Commit 6". Luego creó un nuevo objeto de confirmación. Este objeto difiere del "Commit 7" &nbsp;original en tres aspectos:</p><ol><li>Tiene una marca de tiempo distinto.</li><li>Tiene una confirmación antecesora distinta - "Commit 6", en vez de "Commit 4".</li><li>El objeto árbol al que está apuntado es distinto - como si los cambios fueran introducidos en el árbol apuntado por "Commit 6", y no el árbol apuntado por "Commit 4".</li></ol><p>Fíjate la última confirmación aquí, "Commit 9". &nbsp;La copia instantánea que representa (eso es, el árbol al que apunta) es exactamente el mismo árbol que obtendrías al hacer fusión de las dos ramas. El estado de los archivos en tu repositorio Git sería <strong><strong>el mismo</strong></strong> como si usaras <code>git merge</code>. Es solamente el <em><em>historial</em></em> que es diferente, y los objetos de confirmación por supuesto.</p><p>Ahora, puedes usar simplemente:</p><pre><code class="language-bash">git checkout main
git merge paul_branch
</code></pre><p>Hm..... ¿qué sucedería si ejecutas este último comando? Considera el historial de confirmación de nuevo, después de verificar a <code>main</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_checkout_main.png" class="kg-image" alt="The history after rebasing and checking out " width="600" height="400" loading="lazy"><figcaption>The history after rebasing and checking out <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>¿Qué significaría el hacer fusión de <code>main</code> y <code>paul_branch</code>?</p><p>En efecto, Git puede simplemente hacer una fusión directa, ya que el historial es completamente linear (si necesitas un recordatorio sobre fusiones directos, mira el capítulo previo). Como resultado, <code>main</code> y <code>paul_branch</code> ahora apunta a la misma confirmación:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/fast_forward_merge_result.png" class="kg-image" alt="The result of a fast-forward merge" width="600" height="400" loading="lazy"><figcaption>The result of a fast-forward merge</figcaption></figure><h3 id="rebase-avanzado-en-git"><strong>Rebase avanzado en Git</strong></h3><p>Ahora que entiendes lo básico de rebase, es tiempo de considerar casos más avanzados, donde conmutadores y argumentos adicionales al comando rebase serán útiles.</p><p>En el ejemplo previo, cuando solamente usaste <code>rebase</code> (sin conmutadores adicionales), Git repitió todas las confirmaciones desde el ancestro común a la punta de la rama actual.</p><p>Pero rebase es un super poder. Es un comando todopoderoso capaz de.. bueno, reescribir el historial. Y puede ser útil si quieres modificar el historial para hacer el tuyo propio.</p><p>Deshaz la última fusión haciendo que <code>main</code> apunte a "Commit 4" nuevamente:</p><pre><code class="language-bash">git reset --hard &lt;ORIGINAL_COMMIT 4&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_1.png" class="kg-image" alt="&quot;Undoing&quot; the last merge operation" width="600" height="400" loading="lazy"><figcaption>"Undoing" the last merge operation</figcaption></figure><p>Y deshaz el rebasing usando:</p><pre><code class="language-bash">git checkout paul_branch
git reset --hard &lt;ORIGINAL_COMMIT 9&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_2.png" class="kg-image" alt="&quot;Undoing&quot; the rebase operation" width="600" height="400" loading="lazy"><figcaption>"Undoing" the rebase operation</figcaption></figure><p>Fíjate que obtuviste exactamente el mismo historial que solías tener:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_undoing_rebase.png" class="kg-image" alt="Visualizing the history after &quot;undoing&quot; the rebase operation" width="600" height="400" loading="lazy"><figcaption>Visualizing the history after "undoing" the rebase operation</figcaption></figure><p>Para ser claro, "Commit 9" no sólo desaparece cuando no es alcanzable desde el <code>HEAD</code> actual. Al contrario, todavía es almacenado en la base de datos de objetos. Y como usaste <code>git reset</code> ahora para hacer que <code>HEAD</code> apunte a esta confirmación, fuiste capaz de recuperarlo, y también sus confirmaciones antecesoras ya que también están almacenados en la base de datos. Bastante genial, ¿hah? 😎</p><p>Aprenderás más sobre <code>git reset</code> en la próxima parte, donde discutimos sobre deshacer cambios en Git.</p><p>Mira los cambios que Paul introdujo:</p><pre><code class="language-bash">git show HEAD
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD_2.png" class="kg-image" alt=" shows the patch introduced by &quot;Commit 9&quot;" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD</code> shows the patch introduced by "Commit 9"</figcaption></figure><p>Sigue yendo hacia atrás en el gráfico de confirmación:</p><pre><code class="language-bash">git show HEAD~
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-.png" class="kg-image" alt=" (same as ) shows the patch introduced by &quot;Commit 8&quot;" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD~</code> (same as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD~1</code>) shows the patch introduced by "Commit 8"</figcaption></figure><p>Y una confirmación más allá:</p><pre><code class="language-bash">git show HEAD~2
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-2.png" class="kg-image" alt=" shows the patch introduced by &quot;Commit 7&quot;" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD~2</code> shows the patch introduced by "Commit 7"</figcaption></figure><p>Tal vez Paul no quiere este tipo de historial. Más bien, quiere que parezca como si se introdujera los cambios en "Commit 7" y "Commit 8" como una sola confirmación.</p><p>Para eso, puedes usar un <strong><strong>rebase interactivo</strong></strong>. Para hacer eso, agregamos el conmutador <code>-i</code> (o <code>--interactive</code>) al comando rebase:</p><pre><code class="language-bash">git rebase -i &lt;SHA_OF_COMMIT_4&gt;
</code></pre><p>O, ya que main está apuntando a "Commit 4" , podemos ejecutar:</p><pre><code class="language-bash">git rebase -i main
</code></pre><p>Ejecutando este comando, le dices a Git que use una nueva base, "Commit 4". Así que le pides a Git que vuelva atrás a todas las confirmaciones que fueron introducidos después de "Commit 4" y que son alcanzables &nbsp;desde el <code>HEAD</code> actual, y repita esas confirmaciones.</p><p>Para cada confirmación que es repetido, Git nos pregunta que nos gustaría hacer con él:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_1.png" class="kg-image" alt=" prompts you to select what to do with each commit" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git rebase -i main</code> prompts you to select what to do with each commit</figcaption></figure><p>En este contexto es útil imaginarse de una confirmación como un parche. Eso es, "Commit 7", como "el parche que "Commit 7" introdujo por encima de su antecesor".</p><p>Una opción es usar <code>pick</code>. Este es el comportamiento predeterminado, el cual le dice a Git que repita los cambios introducidos en esta confirmación. En este caso, si sólo lo dejas como está - y haces <code>pick</code> de todas las confirmaciones - obtendrás el mismo historial, y Git no creará nuevos objetos de confirmación.</p><p>Otra opción es <code>squash</code>. Una confirmación <em>aplastada</em> (del inglés "squashed") tendrá su contenido "doblado" (del inglés "folded") en los contenidos de la confirmación que le precede. Así que en nuestro caso, a Paul le gustaría aplastar "Commit 8" en "Commit 7":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_2.png" class="kg-image" alt="Squashing &quot;Commit 8&quot; into &quot;Commit 7&quot;" width="600" height="400" loading="lazy"><figcaption>Squashing "Commit 8" into "Commit 7"</figcaption></figure><p>Como puedes ver, <code>git rebase -i</code> provee opciones adicionales, pero no lo veremos en este capítulo. Si permites a rebase que se ejecute, se te mostrará una ventana para seleccionar un mensaje de confirmación para la nueva confirmación creada (eso es, el que introdujo los cambios de "Commit 7" y "Commit 8"):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_3.png" class="kg-image" alt="Providing the commit message: Commits 7+8" width="600" height="400" loading="lazy"><figcaption>Providing the commit message: Commits 7+8</figcaption></figure><p>Y mira el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_interactive_rebase.png" class="kg-image" alt="The history after the interactive rebase" width="600" height="400" loading="lazy"><figcaption>The history after the interactive rebase</figcaption></figure><p>¡Exactamente lo que queríamos! En <code>paul_branch</code>, tenemos "Commit 9" (por supuesto, es un objeto distinto que el "Commit 9" original). Este objeto apunta a "Commit 7+8", el cual es una confirmación única que introduce los cambios del "Commit 7" original y el "Commit 8" original. El antecesor de la confirmación es "Commit 4", a donde <code>main</code> está apuntando.</p><p>Oh wow, ¿no es genial? 😎</p><p><code>git rebase</code> te concede control sin límites sobre la figura de cualquier rama. Puedes usarlo para re-ordenar confirmaciones, o para quitar cambios incorrectos, o modificar un cambio en retrospectiva. Alternativamente, tal vez podrías mover la base de tu rama en otra confirmación, cualquier confirmación que desees.</p><h3 id="c-mo-usar-el-conmutador-onto-de-git-rebase"><strong>Cómo usar el conmutador <code>--onto</code> de <code>git rebase</code></strong></h3><p>Consideremos un ejemplo más. Vuelve a <code>main</code> nuevamente:</p><pre><code class="language-bash">git checkout main
</code></pre><p>Y elimina los punteros de paul_branch y john_branch así ya no los ves en el gráfico de la confirmación:</p><pre><code class="language-bash">git branch -D paul_branch
git branch -D john_branch
</code></pre><p>Luego, haz una nueva rama desde <code>main</code>:</p><pre><code class="language-bash">git checkout -b new_branch
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_new_branch.png" class="kg-image" alt="Creating  that diverges from " width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_branch</code> that diverges from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Este es el historial limpio que deberías tener:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_new_branch.png" class="kg-image" alt="A clean history with  that diverges from " width="600" height="400" loading="lazy"><figcaption>A clean history with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_branch</code> that diverges from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Ahora, cambia el archivo <code>code.py</code> (por ejemplo, agrega una nueva función) y confirma tus cambios:</p><pre><code class="language-bash">nano code.py
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_1.png" class="kg-image" alt="Adding the function  to " width="600" height="400" loading="lazy"><figcaption>Adding the function <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new_branch</code> to <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">code.py</code></figcaption></figure><pre><code class="language-bash">git add code.py
git commit -m "Commit 10"
</code></pre><p>Vuelve a <code>main</code>:</p><pre><code class="language-bash">git checkout main
</code></pre><p>E introduce otro cambio - agregando una cadena de documentos al principio del archivo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_2.png" class="kg-image" alt="Added a docstring at the beginning of the file" width="600" height="400" loading="lazy"><figcaption>Added a docstring at the beginning of the file</figcaption></figure><p>Es tiempo de poner en el área de preparación y confirmar estos cambios:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 11"
</code></pre><p>Y aún otro cambio, tal vez agrega <code>@Author</code> a la cadena de documentos:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_3.png" class="kg-image" alt="Added  to the docstring" width="600" height="400" loading="lazy"><figcaption>Added <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">@Author</code> to the docstring</figcaption></figure><p>Confirma este cambio también:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 12"
</code></pre><p>Oh espera, ahora me doy cuenta que quería que tú hicieras los cambios introducidos en "Commit 11" como parte de <code>new_branch</code>. Ugh. ¿Qué puedes hacer?</p><p>Considera el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_12-2.png" class="kg-image" alt="The history after introducing &quot;Commit 12&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 12"</figcaption></figure><p>En vez de tener que "Commit 11" resida solamente en la rama <code>main</code>, quiero que esté en <em><em>ambas</em></em> ramas <code>main</code> y <code>new_branch</code>. Visualmente, quisiera <em><em>moverlo</em></em> hacia abajo en el gráfico aquí:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/push_commit_10_down.png" class="kg-image" alt="Visually, I want you to &quot;push down&quot; &quot;Commit 10&quot;" width="600" height="400" loading="lazy"><figcaption>Visually, I want you to "push down" "Commit 10"</figcaption></figure><p>¿Puedes ver a dónde estoy yendo? 😇</p><p>Bueno, <code>rebase</code> te permite básicamente repetir los cambios introducidos en <code>new_branch</code>, aquellos introducidos en "Commit 10", como si hayan sido originalmente realizados sobre "Commit 11", en vez de "Commit 4".</p><p>Para hacer eso, puedes usar otros argumentos de <code>git rebase</code>. Específicamente, puedes usar <code>git rebase --onto</code>, el cual opcionalmente toma tres parámetros:</p><pre><code class="language-bash">git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt; &lt;until&gt;
</code></pre><p>Eso es, tomas todas las confirmaciones entre <code>old_parent</code> y <code>until</code>, y los "cortas" y "pegas" <em><em>en</em> </em><code>new_parent</code>.</p><p>En este caso, le dirías a Git que quieres tomar todo el historial introducidos entre el ancestro común de <code>main</code> y <code>new_branch</code>, el cual es "Commit 4", y que sea la nueva base para ese historial "Commit 11". Para hacer eso, usa:</p><pre><code class="language-bash">git rebase --onto &lt;SHA_OF_COMMIT_11&gt; main new_branch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_1.png" class="kg-image" alt="The history before and after the rebase, &quot;Commit 10&quot; has been &quot;pushed&quot;" width="600" height="400" loading="lazy"><figcaption>The history before and after the rebase, "Commit 10" has been "pushed"</figcaption></figure><p>¡Y mira nuestro hermoso historial! 😍</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_2.png" class="kg-image" alt="The history before and after the rebase, &quot;Commit 10&quot; has been &quot;pushed&quot;" width="600" height="400" loading="lazy"><figcaption>The history before and after the rebase, "Commit 10" has been "pushed"</figcaption></figure><p>Consideremos otro caso.</p><p>Digamos que empecé a trabajar en una nueva característica, y por error comencé a trabajar desde <code>feature_branch_1</code>, en lugar de <code>main</code>.</p><p>Así que para emular esto, crea <code>feature_branch_1</code>:</p><pre><code class="language-bash">git checkout main
git checkout -b feature_branch_1
</code></pre><p>Y elimina <code>new_branch</code> así ya no lo ves en el gráfico:</p><pre><code class="language-bash">git branch -D new_branch
</code></pre><p>Crea un archivo Python sencillo llamado <code>1.py</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_py_1.png" class="kg-image" alt="A new file, , with " width="600" height="400" loading="lazy"><figcaption>A new file, <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">1.py</code>, with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">print('Hello world!')</code></figcaption></figure><p>Pónlo en el área de preparación y confirma este archivo:</p><pre><code class="language-bash">git add 1.py
git commit -m  "Commit 13"
</code></pre><p>Ahora haz una nueva rama desde <code>feature_branch_1</code> (este es el error arreglará luego):</p><pre><code class="language-bash">git checkout -b feature_branch_2
</code></pre><p>Y crea otro archivo, <code>2.py</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/2_py_1.png" class="kg-image" alt="Creating " width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">2.py</code></figcaption></figure><p>Pónlo en el área de preparación y confirma este archivo también:</p><pre><code class="language-bash">git add 2.py
git commit -m  "Commit 14"
</code></pre><p>E introduce algo de código a <code>2.py</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/2_py_2.png" class="kg-image" alt="Modifying " width="600" height="400" loading="lazy"><figcaption>Modifying <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">2.py</code></figcaption></figure><p>Pónlo en el área de preparación y confirma estos cambios también:</p><pre><code class="language-bash">git add 2.py
git commit -m  "Commit 15"
</code></pre><p>Hasta ahora tendrías este historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_15.png" class="kg-image" alt="The history after introducing &quot;Commit 15&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 15"</figcaption></figure><p>Vuelve a <code>feature_branch_1</code> y edita <code>1.py</code>:</p><pre><code class="language-bash">git checkout feature_branch_1
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_py_2.png" class="kg-image" alt="Modifying " width="600" height="400" loading="lazy"><figcaption>Modifying <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">1.py</code></figcaption></figure><p>Ahora pónlo en el área de preparación y confirma:</p><pre><code class="language-bash">git add 1.py
git commit -m  "Commit 16"
</code></pre><p>Tu historial debería lucir así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_16-1.png" class="kg-image" alt="The history after introducing &quot;Commit 16&quot;" width="600" height="400" loading="lazy"><figcaption>The history after introducing "Commit 16"</figcaption></figure><p>Digamos que ahora te das cuenta que cometiste un error. En realidad querías que <code>feature_branch_2</code> naciera de la rama <code>main</code>, en vez de <code>feature_branch_1</code>.</p><p>¿Cómo puedes lograr eso?</p><p>Trata de imaginarlo dado el gráfico del historial y lo que has aprendido sobre el argumento <code>--onto</code> para el comando <code>rebase</code>.</p><p>Bueno, quieres "reemplazar" el antecesor de tu primera confirmación en <code>feature_branch_2</code>, el cual es "Commit 14", que está por encima de la rama <code>main</code> - en este caso, "Commit 12" - en vez del comienzo de <code>feature_branch_1</code> - en este caso, "Commit 13". Así que devuelta, estarás creando una <em><em>nueva base</em></em>, esta vez para la primera confirmación en <code>feature_branch_2</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/plan_commit14_15.png" class="kg-image" alt="You want to move around &quot;Commit 14&quot; and &quot;Commit 15&quot;" width="600" height="400" loading="lazy"><figcaption>You want to move around "Commit 14" and "Commit 15"</figcaption></figure><p>¿Cómo harías eso?</p><p>Primero, cambia a <code>feature_branch_2</code>:</p><pre><code class="language-bash">git checkout feature_branch_2
</code></pre><p>Y ahora puedes usar:</p><pre><code class="language-bash">git rebase --onto main &lt;SHA_OF_COMMIT_13&gt;
</code></pre><p>Esto le dice a Git que tome el historial con "Commit 13" como una base, y cambia esa base para que sea "Commit 12" (apuntado por <code>main</code>).</p><p>Como resultado, tienes a <code>feature_branch_2</code> que tiene su base en <code>main</code> en vez de <code>feature_branch_1</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_3.png" class="kg-image" alt="The commit history after performing rebase" width="600" height="400" loading="lazy"><figcaption>The commit history after performing rebase</figcaption></figure><p>La sintaxis del comando es:</p><pre><code class="language-bash">git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt;
</code></pre><!--kg-card-begin: html--><h3 id="rebase-single-branch">Cómo hacer rebase en una sola rama</h3><!--kg-card-end: html--><p>También puedes usar <code>git rebase</code> mientras miras el historial de una sola rama.</p><p>Veamos si puedes ayudarme aquí.</p><p>Digamos que trabajé en <code>feature_branch_2</code>, específicamente edité el archivo <code>code.py</code>. Comencé cambiando todas las cadenas para que sean envueltos por doble comillas en vez de comillas simples.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_4.png" class="kg-image" alt="Changing  into  in " width="600" height="400" loading="lazy"><figcaption>Changing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">'</code> into <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">"</code> in <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">code.py</code></figcaption></figure><p>Luego, los puse en el área de preparación y los confirmé:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 17"
</code></pre><p>Luego decidí agregar una nueva función al principio del archivo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_5.png" class="kg-image" alt="Adding the function " width="600" height="400" loading="lazy"><figcaption>Adding the function <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">another_feature</code></figcaption></figure><p>Nuevamente, los puse en el área de preparación y confirmé:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 18"
</code></pre><p>Y ahora me doy cuenta que en realidad me olvidé de cambiar las comillas simples a comillas dobles envolviendo a <code>__main__</code> (como has notado), así que hice eso también:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_6.png" class="kg-image" alt="Changing  into " width="600" height="400" loading="lazy"><figcaption>Changing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">'__main__'</code> into <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">"__main__"</code></figcaption></figure><p>Por supuesto. puse este cambio en el área de preparación y confirmé:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 19"
</code></pre><p>Ahora, considera el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_19.png" class="kg-image" alt="The commit history after introducing &quot;Commit 19&quot;" width="600" height="400" loading="lazy"><figcaption>The commit history after introducing "Commit 19"</figcaption></figure><p>¿No es genial, no? O sea, tengo dos confirmaciones que están relacionados el uno al otro, "Commit 17" y "Commit 19" (cambiando los <code>'</code> a <code>"</code>), pero están separados por "Commit 18" que no está relacionado (donde agregué una nueva función). ¿Qué podemos hacer? ¿Puedes ayudarme?</p><p>Intuitivamente, quiero editar el historial aquí:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/plan_edit_commits_17_18.png" class="kg-image" alt="These are the commits I want to edit" width="600" height="400" loading="lazy"><figcaption>These are the commits I want to edit</figcaption></figure><p>Así que, ¿qué harías?</p><p>¡Exacto!</p><p>Puedo hacer <code>rebase</code> del historial de "Commit 17" a "Commit 19", por encima de "Commit 15". Para hacer eso:</p><pre><code class="language-bash">git rebase --interactive --onto &lt;SHA_OF_COMMIT_15&gt; &lt;SHA_OF_COMMIT_15&gt;
</code></pre><p>Fíjate que especifiqué "Commit 15" como el comienzo del rango de confirmaciones, excluyendo esta confirmación. Y no necesité especificar explícitamente a <code>HEAD</code> como el último parámetro.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_4.png" class="kg-image" alt="Using  on a single branch" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">rebase --onto</code> on a single branch</figcaption></figure><p>(Nota: si sigues los pasos de arriba con mi repositorio y obtienes un conflicto de fusión, podrías tener una configuración distinta al de mi máquina debido a los caracteres de espacio en blanco en las líneas finales. En ese caso, puedes agregar el argumento <code>--ignore-whitespace</code>) al comando <code>rebase</code>, resultando en el siguiente comando: <code>git rebase --ignore-whitspace --interactive --onto &lt;SHA_OF_COMMIT_15&gt; &lt;SHA_OF_COMMIT_15&gt;</code>. Si quisieras saber más sobre este problema, busca <code>autocrlf</code>.)</p><p>Después de seguir tu consejo y ejecutar el comando <code>rebase</code> (¡gracias! 😇) obtengo la siguiente pantalla:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_4.png" class="kg-image" alt="Interactive rebase" width="600" height="400" loading="lazy"><figcaption>Interactive rebase</figcaption></figure><p>Así que, ¿qué haría? Quiero poner a "Commit 19" antes de "Commit 18", de esa forma viene después de "Commit 17". Puedo ir más lejos y hacer <code>squash</code> (aplastarlos juntos), así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_5.png" class="kg-image" alt="Interactive rebase - changing the order of commit and squashing" width="600" height="400" loading="lazy"><figcaption>Interactive rebase - changing the order of commit and squashing</figcaption></figure><p>Ahora cuando se me aparece una ventana para un mensaje de confirmación, puedo proveer el mensaje "Commit 17+19":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_6.png" class="kg-image" alt="Providing a commit message" width="600" height="400" loading="lazy"><figcaption>Providing a commit message</figcaption></figure><p>Y ahora, mira nuestro hermoso historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_5.png" class="kg-image" alt="The resulting history" width="600" height="400" loading="lazy"><figcaption>The resulting history</figcaption></figure><p>¡Gracias nuevamente!</p><h3 id="m-s-casos-de-uso-de-rebase-m-s-pr-ctica"><strong>Más casos de uso de Rebase + Más práctica</strong></h3><p>Por ahora espero que te sientas cómodo con la sintaxis de rebase. La mejora forma de entenderlo en sí es considerar varios casos y averiguar cómo resolverlos tú mismo.</p><p>Con los casos que vienen, te recomiendo enérgicamente que dejes de leer después de lo que introduje en cada caso de uso, y luego intentes resolverlo por ti mismo.</p><h4 id="c-mo-excluir-confirmaciones">Cómo excluir confirmaciones</h4><p>Digamos que tienes este historial en otro repo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/another_history_1.png" class="kg-image" alt="Another commit history" width="600" height="400" loading="lazy"><figcaption>Another commit history</figcaption></figure><p>Antes de jugar con él, almacena una etiqueta a "Commit F" así puedes recuperarlo más tarde:</p><pre><code class="language-bash">git tag original_commit_f
</code></pre><p>(Una etiqueta es una referencia nombrada a una confirmación, como una rama - pero no cambia cuando agregas confirmaciones adicionales. Es como una referencia nombrada constante.)</p><p>Ahora, en realidad no quieres los cambios en "Commit C" y "Commit D" que sean incluidos. Podrías usar un rebase interactivo como antes y quitar sus cambios. O, podrías usar <code>git rebase --onto</code> de nuevo. ¿Cómo usarías <code>--onto</code> para "quitar" estas dos confirmaciones?</p><p>Puedes hacer rebase de <code>HEAD</code> por encima de "Commit B", donde el antecesor viejo era en realidad "Commit D", y ahora debería ser "Commit B". Considera el historial nuevamente:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/another_history_1-1.png" class="kg-image" alt="The history again" width="600" height="400" loading="lazy"><figcaption>The history again</figcaption></figure><p>Hacer rebase para que "Commit B" sea la base de "Commit E" significa "mover" ambos "Commit E" y "Commit F", y darles otra base - "Commit B". ¿Puedes idearte el comando tú mismo?</p><pre><code class="language-bash">git rebase --onto &lt;SHA_OF_COMMIT_B&gt; &lt;SHA_OF_COMMIT_D&gt; HEAD
</code></pre><p>Fíjate que usar la sintaxis de arriba (exactamente como se proveyó) <em><em>no</em></em> haría que <em><em>main</em></em> apunte a la nueva confirmación, para que el resultado sea un <code>HEAD</code> "separado". Si usas <code>gg</code> u otra herramienta que muestra el historial alcanzable desde las ramas, te podría confundir:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_6.png" class="kg-image" alt="Rebasing with  results in a detached " width="600" height="400" loading="lazy"><figcaption>Rebasing with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">--onto</code> results in a detached <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>Pero si simplemente usas <code>git log</code> (o mi alias <code>git lol</code>), verás el historial deseado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol.png" class="kg-image" alt="The resulting history" width="600" height="400" loading="lazy"><figcaption>The resulting history</figcaption></figure><p>No sé tú, pero este tipo de cosas me hacen realmente feliz. 😊😇</p><p>Por cierto, podría omitir el <code>HEAD</code> del comando previo como si este fuera el valor predeterminado para el tercer parámetro. Así que usar:</p><pre><code class="language-bash">git rebase --onto &lt;SHA_OF_COMMIT_B&gt; &lt;SHA_OF_COMMIT_D&gt;
</code></pre><p>Tendría el mismo efecto. El último parámetro en realidad le dice a Git donde está el final de la secuencia actual de las confirmaciones para hacerles rebase. Así que la sintaxis de <code>git rebase --onto</code> con los tres argumentos es:</p><pre><code class="language-bash">git rebase --onto &lt;new_parent&gt; &lt;old_parent&gt; &lt;until&gt;
</code></pre><h4 id="c-mo-mover-confirmaciones-a-trav-s-de-las-ramas">Cómo mover confirmaciones a través de las ramas</h4><p>Así que digamos que obtenemos el mismo historial que antes:</p><pre><code class="language-bash">git checkout original_commit_f
</code></pre><p>Y ahora quiero solamente que "Commit E" esté en una rama que tenga su base en "Commit B". Eso es, quiero tener una nueva rama, que venga desde "Commit B", que tenga solamente a "Commit E".</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/another_history_2.png" class="kg-image" alt="The current history, considering &quot;Commit E&quot;" width="600" height="400" loading="lazy"><figcaption>The current history, considering "Commit E"</figcaption></figure><p>Así que, ¿qué significa esto en términos de <code>rebase</code>? Considera la imagen de arriba. ¿Qué confirmación (o confirmaciones) debería hacer rebase, y qué confirmación debería ser la nueva base?</p><p>Sé que puedo contar contigo aquí 😉</p><p>Lo que quiero es tomar el "Commit E", y solamente esta confirmación, y cambiar su base para que sea "Commit B". En otras palabras, repetir los cambios introducidos en "Commit E" en "Commit B".</p><p>¿Puedes aplicar esa lógica a la sintaxis de git rebase?</p><p>Aquí está (esta vez estoy escribiendo <code>&lt;COMMIT_X&gt;</code> en vez de <code>&lt;SHA_OF_COMMIT_X&gt;</code>, para brevedad):</p><pre><code class="language-bash">git rebase --onto &lt;COMMIT_B&gt; &lt;COMMIT_D&gt; &lt;COMMIT_E&gt;
</code></pre><p>Ahora el historial luce así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase_3.png" class="kg-image" alt="The history after rebase" width="600" height="400" loading="lazy"><figcaption>The history after rebase</figcaption></figure><p>Fíjate que <code>rebase</code> movió a <code>HEAD</code>, pero ninguna otra referencia nombrada (tales como una rama o una etiqueta). En otras palabras, estás en un estado de <code>HEAD</code> separado. Así que aquí también, usando <code>gg</code> u otra herramienta que muestre el historial alcanzable desde las ramas y de las etiquetas te podría confundir. Puedes usar <code>git log</code> (o mi alias <code>git lol</code>) para mostrar el historial alcanzable desde <code>HEAD</code>.</p><p>¡Genial!</p><h3 id="una-nota-sobre-los-conflictos"><strong>Una Nota sobre los Conflictos</strong></h3><p>Fíjate que cuando haces un rebase, podrías entrar en conflictos así como al fusionar. Podrías tener conflictos porque, cuando haces rebase, estás intentando aplicar parches en una base distinta, tal vez donde los parches no apliquen.</p><p>Por ejemplo, considera el repositorio nuevamente, y específicamente, considera el cambio introducido en "Commit 12", que es apuntado por <code>main</code>:</p><pre><code class="language-bash">git show main
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/patch_commit_12.png" class="kg-image" alt="The patch introduced in &quot;Commit 12&quot;" width="600" height="400" loading="lazy"><figcaption>The patch introduced in "Commit 12"</figcaption></figure><p>Ya cubrí el formato de <code>git diff</code> en detalle en el <a href="#cap-6">capítulo 6</a>, pero como un recordatorio rápido, esta confirmación le instruye a Git que agregue una línea después de las dos líneas de contexto:</p><pre><code class="language-patch">```
This is a sample file
</code></pre><p>Y antes de estas tres líneas de contexto:</p><pre><code class="language-patch">```
def new_feature():
  print('new feature')
</code></pre><p>Digamos que estás intentando hacer rebase de "Commit 12" en otra confirmación. Si, por alguna razón, estas líneas de contexto no existen como sí existen en el parche de la confirmación en la que estás haciendo rebase, entonces tendrías un conflicto.</p><h3 id="al-jandose-para-ver-el-panorama-general"><strong>Aléjandose para ver el panorama general</strong></h3><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/compare_rebase_merge.png" class="kg-image" alt="Comparing rebase and merge" width="600" height="400" loading="lazy"><figcaption>Comparing rebase and merge</figcaption></figure><p>Al principio de este capítulo, comencé mencionando la similaridad entre <code>git merge</code> y <code>git rebase</code>: ambos son usados para integrar cambios introducidos en historiales distintos.</p><p>Pero, como ahora sabes, son muy distintos en cómo operan. Mientras se fusionan resultados en un historial <em><em>divergente</em></em>, hacer rebase resulta en un historial <em><em>linear</em></em>. Los conflictos son posibles en ambos casos. Y hay una columna más descrita en la tabla de arriba que requiere más atención.</p><p>Ahora que sabes qué es "Git rebase", y cómo usar el rebase interactivo o rebase <code>--onto</code>, como espero que estés de acuerdo, <code>git rebase</code> es una herramienta super poderosa. Aunque, tiene una desventaja grande cuando se compara con fusionar.</p><p><strong><strong>Git rebase cambia el historial.</strong></strong></p><p>Esto significa que <strong><strong>no</strong></strong> deberías hacer rebase de las confirmaciones que existen fuera de tu copia local del repositorio, y que otras personas podrían tener su base en sus confirmaciones.</p><p>En otras palabras, si sólo las confirmaciones en cuestión son aquellos que creaste de manera local - adelante, use rebase, enloquécete.</p><p>Pero si las confirmaciones han sido empujados (enviados), eso puede llevarte a un gran problema - ya que alguien más podría basarse en estas confirmaciones que tu luego sobreescribas, y después tú y ellos tendrás distintas versiones del repositorio.</p><p>Esto es distinto a <code>merge</code> el cual, como hemos visto, no modifica el historial.</p><p>Por ejemplo, considera el último caso donde cambiamos la base y resultó en este historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_rebase_3-1.png" class="kg-image" alt="The history after rebase" width="600" height="400" loading="lazy"><figcaption>The history after rebase</figcaption></figure><p>Ahora, digamos que ya empujé esta rama al remoto. Y después que he empujado la rama, otro desarrollador lo empujó e hizo una rama desde "Commit C". El otro desarrollador no sabía que mientras tanto, estuve haciendo rebase de mi rama de forma local, y luego lo subiría (empujaría) nuevamente.</p><p>Esto resulta en una inconsistencia: el otro desarrollador trabaja desde una confirmación que ya no está disponible en mi copia del repositorio.</p><p>No elaboraré exactamente lo que esto causa en este libro, ya que mi mensaje principal es que deberías evitar definitivamente tales casos. Si estás interesado en qué sucedería en sí, te dejaré un enlace a un recurso útil en las <a href="#apendices">referencias adicionales</a>. Por ahora, resumamos lo que hemos cubierto.</p><h3 id="recapitulaci-n-entendiendo-git-rebase"><strong>Recapitulación - Entendiendo Git rebase</strong></h3><p>En este capítulo, aprendiste sobre <code>git rebase</code>, una herramienta super poderosa para reescribir el histoiral en Git. Consideraste unos pocos casos donde git rebase puede ser útil, y cómo usarlo en uno, dos, o tres parámetros, con y sin el conmutador <code>--onto</code>.</p><p>Espero que haya sido capaz de convencerte que <code>git rebase</code> es poderoso - pero también que es bastante sencillo una vez que entiendes la esencia. Es una herramienta que puedes usar para "copiar-pegar" confirmaciones (o, más acertadamente, parches). Y es una herramienta útil para tener en tu cinto. En esencia, <code>git rebase</code> toma los parches introducidos por las confirmaciones, y repetirlos en un otra confirmación. Como se describió en este capítulo, esto es útil en muchos escenarios distintos.</p><h2 id="parte-2-resumen"><strong>Parte 2 - Resumen</strong></h2><p>En esta parte aprendiste a hacer ramas e integrar cambios en Git.</p><p>Aprendiste lo que es un <strong><strong>diff</strong></strong>, y la diferencia entre un diff y un <strong><strong>parche</strong></strong>. También aprendiste cómo se construye la salida de <code>git diff</code>.</p><p>Entender los diffs es un hito mayor para entender muchos otros procesos dentro de Git tales como fusionar o hacer rebase.</p><p>Después, tuviste una vista general extensiva sobre fusionar con Git. Aprendiste que la <strong><strong>fusión</strong></strong> es el proceso de <strong><strong>combinar los cambios recientes de varias ramas en una sola nueva confirmación</strong></strong>. La nueva confirmación tiene múltiples antecesores - esas confirmaciones han sido las puntas de las ramas que fueron fusionadas. En la mayoría de los casos, la fusión combina los cambios de dos ramas, y entonces la confirmación de fusión resultante tiene dos predecesores - uno de cada rama.	</p><p>Consideramos una fusión sencilla y directa, la cual es posible cuando una rama difiere de la rama base, y luego agregamos confirmaciones por encima de la rama base.</p><p>Después consideramos fusiones de tres vías, y explicamos el proceso de tres etapas:</p><ul><li>Primero, Git localiza la base de fusión. Como recordatorio, este es la primera confirmación que es alcanzable desde ambas ramas.</li><li>Segundo, Git calcula dos diffs - un diff desde la base de fusión a la <em><em>primer</em></em> rama, y otro diff desde la base de fusión a la <em><em>segunda</em></em> rama. Git genera parches basados en esos diffs.</li><li>Tercero y último, Git aplica ambos parches a la base de fusión usando un algoritmo de fusión de 3 vías. El resultado es el estado de la nueva confirmación de fusión.</li></ul><p>Viste la salida de <code>git diff</code> cuando estamos en un estado de conflicto, y cómo resolver conflictos sea de forma manual o con VS Code.</p><p>Por último, aprendiste Git rebase. Viste que <code>git rebase</code> es poderoso - pero también es bastante sencillo una vez que entiendes lo que hace. Es una herramienta para "copiar-pegar" confirmaciones (o, más específicamente, parches).</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/compare_rebase_merge-1.png" class="kg-image" alt="Comparing rebase and merge" width="600" height="400" loading="lazy"><figcaption>Comparing rebase and merge</figcaption></figure><p>Ambos <code>git merge</code> y <code>git rebase</code> se usan para integrar cambios introducidos en diferentes historiales.</p><p>Aunque, difieren en cómo operan. Mientras que la fusión resulta en un historial <em><em>divergente</em></em>, los resultados de hacer rebase resulta en un historial <em><em>linear</em></em>. <code>git rebase</code> <em><em>cambia</em></em> el historial, mientras que <code>git merge</code> agrega al historial existente.</p><p>Con este entendimiento profundo de diffs, parches, fusión y rebase, deberías sentirte confiado al introducir cambios a un repositorio git.</p><p>La próxima parte se enfocará en lo que sucede cuando las cosas salen mal - cómo puedes cambiar el historial (con o sin <code>git rebase</code>), o encontrar confirmaciones "perdidas".</p><!--kg-card-begin: html--><h1 id="part-3">Parte 3 - Deshacer cambios</h1><!--kg-card-end: html--><p>Alguna vez llegaste a un punto donde dijiste: "Oh-oh, ¿qué es lo que hice?" Supongo que lo hiciste, así como cualquiera que usa Git.</p><p>Tal vez confirmaste a la rama equivocada. Tal vez perdiste algo de código que has escrito. Tal vez confirmaste algo que no era tu intención de hacer.</p><p>Esta parte te dará las herramientas para reescribir el historial con confianza, de esa forma "deshacer" todo tipos de cambios en Git.</p><p>Así como las otras partes del libro, esta parte será practica aunque a profundidad - así que en vez de proveerte una lista de qué a hacer cuando las cosas salen mal, entenderemos los mecanismos subyacentes, así te sentirás confiable cuando sea que llegues al momento "oh-oh". En realidad, encontrarás estos momentos como oportunidades para un desafió interesante, en vez de un escenario espantoso.</p><!--kg-card-begin: html--><h2 id="cap-9">Capítulo 9 - Git Reset</h2><!--kg-card-end: html--><p>Nuestro trayecto comienza con un comando potente que puede ser usado para deshacer muchas diferentes acciones con Git - <code>git reset</code>.</p><h3 id="un-peque-o-recordatorio-registrando-cambios"><strong>Un pequeño recordatorio - Registrando cambios</strong></h3><p>En el <a href="#cap-3">capítulo 3</a>, aprendiste cómo registrar cambios en Git. Si recuerdas todo de esta parte, puedes saltar la próxima sección.</p><p>Es útil imaginarse a Git como un sistema para registrar copias instantáneas de un sistema de archivos en el tiempo. Considerando un repositorio de Git, tiene tres "estados" o "árboles":</p><ol><li>El <strong><strong>directorio de trabajo</strong></strong>, un directorio que tiene un repositorio asociado.</li><li>El <strong>área de preparación<strong> (índice)</strong></strong> el cual tiene el árbol para la próxima confirmación.</li><li>El <strong><strong>repositorio</strong></strong>, el cual es una colección de confirmaciones y referencias.</li></ol><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/3_trees.png" class="kg-image" alt="The three &quot;trees&quot; of a Git repo" width="600" height="400" loading="lazy"><figcaption>The three "trees" of a Git repo</figcaption></figure><p>Fíjate que con respecto a las convenciones de dibujo que utilizo: incluyo <code>.git</code> dentro del directorio de trabajo, para recordarte es una carpeta dentro de la carpeta del proyecto en el sistema de archivos. La carpeta <code>.git</code> en realidad contiene los objetos y las referencias del repositorio, como se explicó en el <a href="#cap-4">capítulo 4</a>.</p><h3 id="demostraci-n-pr-ctica"><strong>Demostración práctica</strong></h3><p>Usa <code>git init</code> para inicializar un nuevo repositorio. Escribe algo de texto en un archivo llamado <code>1.txt</code>:</p><pre><code class="language-bash">mkdir my_repo
cd my_repo
git init
echo Hello world &gt; 1.txt
</code></pre><p>De los tres estados descritos arriba, ¿dónde está <code>1.txt</code> ahora?</p><p>En el árbol de trabajo, ya que todavía no ha sido introducido al índice.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_txt_working_dir.png" class="kg-image" alt="The file  is now a part of the working dir only" width="600" height="400" loading="lazy"><figcaption>The file <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">1.txt</code> is now a part of the working dir only</figcaption></figure><p>Para ponerlo en <em>área de preparación</em>, para agregarlo al índice, usa:</p><pre><code class="language-bash">git add 1.txt
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/1_txt_index.png" class="kg-image" alt="Using  stages the file so it is now in the index as well" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git add</code> stages the file so it is now in the index as well</figcaption></figure><p>Fíjate que una vez que pones en el área de preparación <code>1.txt</code>, Git crea un objeto blob con el contenido de este archivo, y lo agrega a la base de datos de objetos interno (dentro de la carpeta <code>.git</code>), como se cubrió en el <a href="#cap-3">capítulo 3</a> y <a href="#cap-4">capítulo 4</a>. No lo dibujo como parte del "repositorio" ya que en esta representación, el "repositorio" se refiere a un árbol de confirmaciones y sus referencias, y este blob no ha sido parte de ninguna confirmación.</p><p>Ahora, usa <code>git commit</code> para confirmar tus cambios al repositorio:</p><pre><code class="language-bash">git commit -m "Commit 1"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_1.png" class="kg-image" alt="Using  creates a commit object in the repository" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git commit</code> creates a commit object in the repository</figcaption></figure><p>Creaste un nuevo objeto de <strong><strong>confirmación</strong></strong>, el cual incluye un puntero a un <strong><strong>árbol</strong></strong> que describe todo el <strong><strong>árbol de trabajo</strong></strong>. En este caso, este árbol consiste solamente de <code>1.txt</code> dentro de la carpeta raíz. Además de un puntero al árbol, el objeto de confirmación incluye metadatos, tales como marcas de tiempo e información del autor.</p><p>Cuando se considera los diagramas, fíjate que solamente tenemos una sola copia del archivo <code>1.txt</code> en el disco, y un objeto blob correspondiente en la base de datos de objetos de Git. El árbol del "repositorio" ahora muestra este archivo ya que es parte de la confirmación activa - eso es, el objeto de confirmación "Commit 1" apunta a un árbol que apunta al blob con los contenidos de <code>1.txt</code>, el mismo blob al que el índice está apuntando.</p><p>Para más información sobre los objetos en Git (tales como confirmaciones y árboles), ve al <a href="#cap-1">capítulo 1</a>.</p><p>Luego, crea un nuevo archivo, y agrégalo al índice, como antes:</p><pre><code class="language-bash">echo second file &gt; 2.txt
git add 2.txt
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/2_txt_index.png" class="kg-image" alt="The file  is in the working dir and the index after staging it with " width="600" height="400" loading="lazy"><figcaption>The file <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">2.txt</code> is in the working dir and the index after staging it with <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git add</code></figcaption></figure><p>Luego, confirma:</p><pre><code class="language-bash">git commit -m "Commit 2"
</code></pre><p>Muy importante, <code>git commit</code> hace dos cosas:</p><p>Primero, crea un <strong><strong>objeto de confirmación</strong></strong>, así que hay un objeto dentro de la base de datos de objetos interno de Git con un valor SHA-1 correspondiente. Este nuevo objeto de confirmación también apunta a la confirmación antecesor. Ese es la confirmación al que <code>HEAD</code> estaba apuntando cuando escribiste el comando <code>git commit</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/new_commit_object.png" class="kg-image" alt="A new commit object has been created, at first —  still points to the previous commit" width="600" height="400" loading="lazy"><figcaption>A new commit object has been created, at first - <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code> still points to the previous commit</figcaption></figure><p>Segundo, <code>git commit</code> <strong><strong>mueve el puntero de la rama activa</strong></strong> – en nuestro caso, eso sería <code>main</code>, a que apunte al objeto de confirmación creado recientemente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_updates_active_branch.png" class="kg-image" alt=" also updates the active branch to point to the newly created commit object" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git commit</code> also updates the active branch to point to the newly created commit object</figcaption></figure><h3 id="introduciendo-git-reset"><strong>Introduciendo <code>git reset</code></strong></h3><p>Ahora aprenderás cómo revertir el proceso de introducir una confirmación. Para eso, aprenderás el comando <code>git reset</code>.</p><h4 id="git-reset-soft"><strong><code>git reset --soft</code></strong></h4><p>El último paso que hiciste antes fue <code>git commit</code>, el cual en realidad significa dos cosas – Git creó un objeto de confirmación y movió a <code>main</code>, la rama activa. Para deshacer este paso, usa el siguiente comando:</p><pre><code class="language-bash">git reset --soft HEAD~1
</code></pre><p>La sintaxis <code>HEAD~1</code> se refiere al primer antecesor de <code>HEAD</code>. Considera un caso donde tenía más de una confirmación en el gráfico de confirmaciones, digamos que "Commit 3" está apuntando a "Commit 2", el cual, en sí, está apuntando a "Commit 1". Y considera que <code>HEAD</code> estaba apuntando a "Commit 3". Podrías usar <code>HEAD~1</code> para referirte a "Commit 2", y <code>HEAD~2</code> se referiría a "Commit 1".</p><p>Así que, devuelta al comando: <code>git reset --soft HEAD~1</code>.</p><p>Este comando le pide a Git que cambie cualquier <code>HEAD</code> al que está apuntando. (Nota: En los diagramas de abajo, uso <code>*HEAD</code> para "cualquier <code>HEAD</code> al que está apuntando".) En nuestro ejemplo, el <code>HEAD</code> está apuntando a <code>main</code>. Así que Git solamente cambiará el puntero de <code>main</code> a que apunte a <code>HEAD~1</code>. Eso es, <code>main</code> apuntará al "Commit 1".</p><p>Sin embargo, este comando <strong><strong>no</strong></strong> afectará el estado del índice o el árbol de trabajo. Así que si usas <code>git status</code> verás que <code>2.txt</code> está en el área de preparación, justo como antes que ejecutaste <code>git commit</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_status_after_reset_soft.png" class="kg-image" alt=" shows that  is in the index, but not in the active commit" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git status</code> shows that <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">2.txt</code> is in the index, but not in the active commit</figcaption></figure><p>El estado es ahora:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_soft_1.png" class="kg-image" alt="Resetting  to &quot;Commit 1&quot;" width="600" height="400" loading="lazy"><figcaption>Resetting <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code> to "Commit 1"</figcaption></figure><p>(Nota: quité <code>2.txt</code> del "repositorio" en el diagrama ya que no es parte de la confirmación activa - eso es, el árbol apuntado por el "Commit 1" no referencia a este archivo. Sin embargo, no ha sido quitado del sistema de archivos - ya que existe en el árbol de trabajo y el índice.)</p><p>¿Qué hay sobre <code>git log</code>? Comenzará desde el <code>HEAD</code>, va al <code>main</code>, y luego a "Commit 1":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_after_reset_soft.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code></figcaption></figure><p>Fíjate que esto significa que "Commit 2" ya no es alcanzable desde nuestro historial.</p><p>¿Eso significa que el objeto de confirmación de "Commit 2" se elimina?</p><p>No, no se elimina. Todavía residen dentro de la base de datos de objetos interno de Git.</p><p>Si subes el historial actual ahora, usando <code>git push</code>, Git no empujará el "Commit 2" al servidor remoto (ya que no es alcanzable desde el <code>HEAD</code> actual), pero el objeto de confirmación <em><em>todavía</em></em> existe en tu copia local del repositorio.</p><p>Ahora, confirma nuevamente - y use el mensaje de confirmación de "Commit 2.1" para diferenciar este nuevo objeto desde el "Commit 2" original:</p><pre><code class="language-bash">git commit -m "Commit 2.1"
</code></pre><p>Este el estado resultante:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_1.png" class="kg-image" alt="Creating a new commit" width="600" height="400" loading="lazy"><figcaption>Creating a new commit</figcaption></figure><p>Omití el "Commit 2" ya que no es alcanzable desde el <code>HEAD</code>, aunque su objeto existe en la base de datos de objetos interno de Git.</p><p>¿Por qué "Commit 2" y "Commit 2.1" son distintos? Inclusive si usáramos el mismo mensaje de confirmación, y aunque apunten al mismo objeto de árbol (de la carpeta raíz consistiendo de <code>1.txt</code> y <code>2.txt</code>), todavía tienen distintas marcas de tiempo, ya que fueron creados en diferentes tiempos. Ambos "Commit 2" y "Commit 2.1" ahora apuntan a "Commit 1", sino que solamente "Commit 2.1" es alcanzable desde el <code>HEAD</code>.</p><h4 id="git-reset-mixed"><strong><code>git reset --mixed</code></strong></h4><p>Es tiempo de deshacer aún mas allá. Esta vez, usa:</p><pre><code class="language-bash">git reset --mixed HEAD~1
</code></pre><p>(Nota: <code>--mixed</code> es el conmutador predeterminado para <code>git reset</code>.)</p><p>Este comando comienza de la misma forma que <code>git reset --soft HEAD~1</code>. Eso es, el comando toma el puntero de cualquier <code>HEAD</code> que está apuntando ahora, el cual es la rama <code>main</code>, y lo establece a <code>HEAD~1</code>, en nuestro ejemplo - "Commit 1".</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_mixed_1.png" class="kg-image" alt="The first step of  is the same as " width="600" height="400" loading="lazy"><figcaption>The first step of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --mixed</code> is the same as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --soft</code></figcaption></figure><p>Luego, Git va más allá, efectivamente deshaciendo los cambios que hicimos al índice. Eso es, cambiar el índice para que coincida con el <code>HEAD</code> actual, el nuevo <code>HEAD</code> después de establecerlo en el primer paso.</p><p>Si ejecutáramos <code>git reset --mixed HEAD~1</code>, entonces el <code>HEAD</code> (<code>main</code>) sería puesto al <code>HEAD~1</code> ("Commit 1"), y luego Git coincidiría el índice al estado de "Commit 1" - en este caso, significa que <code>2.txt</code> ya no sería parte del índice.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_mixed_2.png" class="kg-image" alt="The second step of  is to match the index with the new " width="600" height="400" loading="lazy"><figcaption>The second step of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --mixed</code> is to match the index with the new <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>Es tiempo de crear una nueva confirmación con el estado del "Commit 2" original. Esta vez necesita poner en el área de preparación a <code>2.txt</code> nuevamente antes de crearlo:</p><pre><code class="language-bash">git add 2.txt
git commit -m "Commit 2.2"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_2.png" class="kg-image" alt="Creating &quot;Commit 2.2&quot;" width="600" height="400" loading="lazy"><figcaption>Creating "Commit 2.2"</figcaption></figure><p>De forma similar a "Commit 2.1", "nombro" a esta confirmación "Commit 2.2" para diferenciarlo del del "Commit 2" original o "Commit 2.1" - estas confirmaciones resultan en el mismo estado que el "Commit 2" original, pero son distintos objetos de confirmación.</p><h4 id="git-reset-hard"><strong><code>git reset --hard</code></strong></h4><p>Continúa, ¡deshaz aún más!</p><p>Esta vez, usa el conmutador <code>--hard</code>, y ejecuta:</p><pre><code class="language-bash">git reset --hard HEAD~1
</code></pre><p>Una vez más, Git comienza con el paso <code>--soft</code>, estableciendo cualquier <code>HEAD</code> que esté apuntando a (<code>main</code>), a que apunte a <code>HEAD~1</code> ("Commit 1").</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_1-1.png" class="kg-image" alt="The first step of  is the same as " width="600" height="400" loading="lazy"><figcaption>The first step of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --hard</code> is the same as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --soft</code></figcaption></figure><p>Luego, moviéndonos al siguiente paso <code>--mixed</code>, coincidiendo con el índice con <code>HEAD</code>. Eso es, Git deshace el paso de <code>2.txt</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_2-1.png" class="kg-image" alt="The second step of  is the same as " width="600" height="400" loading="lazy"><figcaption>The second step of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --hard</code> is the same as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --mixed</code></figcaption></figure><p>Luego viene el paso de <code>--hard</code>, donde Git va mas allá y coincide con el directorio de trabajo con la etapa del índice. En este caso, significa también quitar <code>2.txt</code> del directorio de trabajo.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_hard_3.png" class="kg-image" alt="The third step of  matches the state of the working dir with that of the index" width="600" height="400" loading="lazy"><figcaption>The third step of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --hard</code> matches the state of the working dir with that of the index</figcaption></figure><p>(<strong>Nota</strong>: en este caso específico, el archivo no está registrado, así que no será eliminado del sistema de archivos; no es realmente importante para entender <code>git reset</code>.)</p><p>Así que para introducir un cambio en Git, tienes tres pasos: cambias el directorio de trabajo, el índice, o el área de preparación, y luego confirmas una nueva copia instantánea con esos cambios. Para deshacer estos cambios:</p><ul><li>Si usamos <code>git reset --soft</code>, deshacemos el último paso.</li><li>Si usamos <code>git reset --mixed</code>, también deshacemos el paso del copia instantánea.</li><li>Si usamos <code>git reset --hard</code>, deshacemos los cambios al directorio de trabajo.</li></ul><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_switches.png" class="kg-image" alt="The three main switches of " width="600" height="400" loading="lazy"><figcaption>The three main switches of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset</code></figcaption></figure><h3 id="escenarios-de-la-vida-real"><strong>Escenarios de la vida real</strong></h3><!--kg-card-begin: html--><h4 id="scenery-1">Escenario #1</h4><!--kg-card-end: html--><p>Así que en un escenario de la vida real, escribe "I love Git" en un archivo (<code>love.txt</code>), ya que todos amamos Git 😍. Adelante, pónlo en el área de preparación y confirmas esto también:</p><pre><code class="language-bash">echo I love Git &gt; love.txt
git add love.txt
git commit -m "Commit 2.3"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_3.png" class="kg-image" alt="Creating &quot;Commit 2.3&quot;" width="600" height="400" loading="lazy"><figcaption>Creating "Commit 2.3"</figcaption></figure><p>También, guarda una etiqueta así puedes volver a esta confirmación más tarde si es necesario:</p><pre><code class="language-bash">git tag scenario-1
</code></pre><p>Oh, oops!</p><p>En realidad, no quería que lo confirmaras.</p><p>Lo que en realidad quería que hicieras era escribir algunas otras palabras lindas en este archivo antes de confirmarlo.</p><p>¿Qué puedes hacer?</p><p>Bueno, una forma de superar esto sería usar <code>git reset --mixed HEAD~1</code>, efectivamente deshaciendo tanto la confirmación y las acciones del área de preparación que tomaste:</p><pre><code class="language-bash">git reset --mixed HEAD~1
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_commit_2_3.png" class="kg-image" alt="Undoing the staging and committing steps" width="600" height="400" loading="lazy"><figcaption>Undoing the staging and committing steps</figcaption></figure><p>Así que <code>main</code> apunta a "Commit 1" nuevamente, y <code>love.txt</code> ya no es una parte del índice. Sin embargo, el archivo permanece en el directorio de trabajo. Ahora puedes agregarle mas contenido:</p><pre><code class="language-bash">echo and Gitting Things Done &gt;&gt; love.txt
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/adding_love_lyrics.png" class="kg-image" alt="Adding more love lyrics" width="600" height="400" loading="lazy"><figcaption>Adding more love lyrics</figcaption></figure><p>Pónlo en el área de preparación y confirma tu archivo:</p><pre><code class="language-bash">git add love.txt
git commit -m "Commit 2.4"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_2_4.png" class="kg-image" alt="Introducing &quot;Commit 2.4&quot;" width="600" height="400" loading="lazy"><figcaption>Introducing "Commit 2.4"</figcaption></figure><p>¡Bien hecho!</p><p>Lo tienes claro, lindo historial de "Commit 2.4" apuntando a "Commit 1".</p><p>Ahora tienes una nueva herramienta en tu caja de herramientas, <code>git reset</code>.</p><p>Esta herramienta es super, super útil, y puedes logar casi cualquier cosa con él. No es siempre la herramienta más conveniente, pero es capaz de resolver casi cualquier escenario de reescritura de historial si lo usas con cuidado.</p><p>Para principiantes, te recomiendo usar solamente <code>git reset</code> para casi cualquier vez que quieras deshacer en Git. Una vez que te sientas cómodo con él, continúa con otras herramientas.</p><h4 id="escenario-2">Escenario #2</h4><p>Consideremos otro caso.</p><p>Crea un nuevo archivo llamado <code>new.txt</code>; pónlo en el área de preparación y confirma:</p><pre><code class="language-bash">echo this is a new file &gt; new.txt
git add new.txt
git commit -m "Commit 3"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_3.png" class="kg-image" alt="Creating  and &quot;Commit 3&quot;" width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">new.txt</code> and "Commit 3"</figcaption></figure><p>(Nota: En el dibujo omití los archivos del repositorio para evitar desorden. Commit 3 incluye <code>1.txt</code>, <code>love.txt</code> y <code>new.txt</code> en esta etapa.)</p><p>Ups. En realidad, eso es un error. Estabas en <code>main</code>, y quería que crearas esta confirmación en una rama feature. Mi culpa 😇</p><p>Hay dos herramientas mas importantes que quiero que tomes de este capítulo. El <em><em>segundo</em></em> es <code>git reset</code>. El primero y el más importante es limpiar el estado actual versus el estado en el que quieres que esté.</p><p>Para este escenario, el estado actual y el estado deseado lucen así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_2.png" class="kg-image" alt="Scenario #2: current-vs-desired states" width="600" height="400" loading="lazy"><figcaption>Scenario #2: current-vs-desired states</figcaption></figure><p>(Nota: En las diagramas siguientes, me referiré al estado actual como el estado "original" - antes de empezar el proceso de reescribir el historial.)</p><p>Notarás tres cambios:</p><ol><li><code>main</code> apunta a "Commit 3" (el azul) en el estado actual, pero apunta a "Commit 2.4" en el estado deseado.</li><li><code>feature_branch</code> no existe en el estado actual, aunque existe y apunta al "Commit 3" en el estado deseado.</li><li><code>HEAD</code> apunta a <code>main</code> en el estado actual, y apunta a <code>feature_branch</code> en el estado deseado.</li></ol><p>Si lo puedes dibujar y sabes cómo usar <code>git reset</code>, puedes definitivamente salir de esta situación.</p><p>Así que nuevamente, lo más importante es tomar un respiro y dibujarlo.</p><p>Observando el dibujo de arriba, ¿cómo llegas al estado deseado del estado actual?</p><p>Hay unas pocas formas por supuesto, pero te presentaré una opción solamente para cada escenario. Siéntete libre de jugar con otras opciones también.	</p><p>Puedes comenzar usando <code>git reset --soft HEAD~1</code>. Esto pondría a <code>main</code> a que apunte a la confirmación previa, "Commit 2.4":</p><pre><code class="language-bash">git reset --soft HEAD~1
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_2_1.png" class="kg-image" alt="Changing ; &quot;Commit 3 is still there, just not reachable from " width="600" height="400" loading="lazy"><figcaption>Changing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code>: "Commit 3" is still there, just not reachable from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code></figcaption></figure><p>Mirando el diagrama actual-vs-deseado (original-vs-desired) nuevamente, puedes ver que necesitas una nueva rama, ¿no? Puedes usar <code>git switch -c feature_branch</code> para eso, o <code>git checkout -b feature_branch</code> (el cual hace lo mismo):</p><pre><code class="language-bash">git switch -c feature_branch
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_2_2.png" class="kg-image" alt="Creating  branch" width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">feature_branch</code> branch</figcaption></figure><p>Este comando también actualiza el <code>HEAD</code> a que apunte a la nueva rama.</p><p>Ya que usaste <code>git reset --soft</code>, no cambiaste el índice, así que actualmente tiene exactamente el estado que quieres confirmar - ¡qué conveniente! Puedes simplemente confirmar a <code>feature_branch</code>:</p><pre><code class="language-bash">git commit -m "Commit 3.1"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_3_1.png" class="kg-image" alt="Committing to  branch" width="600" height="400" loading="lazy"><figcaption>Committing to <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">feature_branch</code> branch</figcaption></figure><p>Y llegas al estado deseado.</p><h4 id="escenario-3">Escenario #3</h4><p>¿Listo para aplicar tus conocimientos para casos adicionales?</p><p>Todavía en <code>feature_branch</code>, agrega algunos cambios a <code>love.txt</code>, y crea un nuevo archivo llamado <code>cool.txt</code>. Pónlos en el área de preparación y confirma:</p><pre><code class="language-bash">echo Some changes &gt;&gt; love.txt
echo Git is cool &gt; cool.txt
git add love.txt
git add cool.txt
git commit -m "Commit 4"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_4.png" class="kg-image" alt="The history, as well as the state of the index and the working dir after creating &quot;Commit 4&quot;" width="600" height="400" loading="lazy"><figcaption>The history, as well as the state of the index and the working dir after creating "Commit 4"</figcaption></figure><p>Oh, ups, en realidad quería que crearas dos confirmaciones <em><em>separadas</em></em>, una con cada cambio...</p><p>¿Quieres intentar este por ti mismo (antes de seguir leyendo)?</p><p>Puedes deshacer los pasos de confirmación y del área de preparación:</p><pre><code class="language-bash">git reset --mixed HEAD~1
</code></pre><p>Siguiendo este comando, el índice ya no incluye esos dos cambios, pero todavía están en tu sistema de archivos:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_commit_4.png" class="kg-image" alt="Resulting state after using " width="600" height="400" loading="lazy"><figcaption>Resulting state after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --mixed HEAD~1</code></figcaption></figure><p>Así que ahora, si solamente pones en el área de preparación a <code>love.tx</code>, puedes confirmarlo de forma separada:</p><pre><code class="language-bash">git add love.txt
git commit -m "Love"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_love.png" class="kg-image" alt="Resulting state after committing the changes to " width="600" height="400" loading="lazy"><figcaption>Resulting state after committing the changes to <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">love.txt</code></figcaption></figure><p>Luego, haz lo mismo para <code>cool.txt</code>:</p><pre><code class="language-bash">git add cool.txt
git commit -m "Cool"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_separately.png" class="kg-image" alt="Committing separately" width="600" height="400" loading="lazy"><figcaption>Committing separately</figcaption></figure><p>¡Genial!</p><h4 id="escenario-4">Escenario #4</h4><p>Para limpiar el estado, cambia a <code>main</code> y usa <code>reset --hard</code> para hacer que apunte a "Commit 3.1", mientras pones el índice y el directorio de trabajo al estado de "Commit 3.1":</p><pre><code class="language-bash">git checkout main
git reset --hard &lt;SHA_OF_COMMIT_3_1&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_main_commit_3_1.png" class="kg-image" alt="Resetting  to &quot;Commit 3.1&quot;" width="600" height="400" loading="lazy"><figcaption>Resetting <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code> to "Commit 3.1"</figcaption></figure><p>Crea otro archivo (<code>another.txt</code>) con algo de texto, y agrega algo de texto a <code>love.txt</code>. Pónlos en el área de preparación ambos cambios, y confirmarlos:</p><pre><code class="language-bash">echo Another file &gt; another.txt
echo More love &gt;&gt; love.txt
git add another.txt
git add love.txt
git commit -m "Commit 4.1"
</code></pre><p>Este debería ser el resultado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_more_changes.png" class="kg-image" alt="A new commit" width="600" height="400" loading="lazy"><figcaption>A new commit</figcaption></figure><p>Ups...</p><p>Así que esta vez, quería que esté en otra rama, pero no una nueva rama, sino - una rama ya existente.</p><p>Así que, ¿qué puedes hacer?</p><p>Te daré una pista. La respuesta es realmente corta y fácil. ¿Qué hacemos primero?</p><p>No, no <code>reset</code>. <em><em>Dibujemos</em></em>. Esto es lo primero en hacer, ya que haría todo lo demás más fácil. Así que este es el estado actual:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_4.png" class="kg-image" alt="The new commit on  appears blue" width="600" height="400" loading="lazy"><figcaption>The new commit on <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code> appears blue</figcaption></figure><p>¿Y el estado deseado?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/scenario_4_1-1.png" class="kg-image" alt="We want the &quot;blue&quot; commit to be on another, , branch\label{fig-scenario-4-1}" width="600" height="400" loading="lazy"><figcaption>We want the "blue" commit to be on another, <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">existing</code>, branch</figcaption></figure><p>¿Cómo obtienes el estado actual al estado deseado, qué sería más fácil?</p><p>Una forma sería usar <code>git reset</code> como hiciste antes, pero hay otra forma que me gustaría intentar.</p><p>Fíjate que los siguientes comandos en sí asumen que la rama <code>existing</code> existe en tu repositorio, aunque no lo has creado anteriormente. Para coincidir un estado donde esta rama existe, puedes usar los siguientes comandos:</p><pre><code class="language-bash">git checkout &lt;SHA_OF_COMMIT_1&gt;
git checkout -b existing
echo "Hello" &gt; x.txt
git add x.txt
git commit -m "Commit X"
git checkout &lt;SHA_OF_COMMIT_3_1&gt; -- love.txt
git commit -m "Commit Y"
git checkout main
</code></pre><p>(El comando <code>git checkout &lt;SHA_OF _COMMIT_3_1&gt; -- love.txt</code> copia los contenidos de <code>love.txt</code> desde "Commit 3.1" al &nbsp;índice y el directorio de trabajo, así puedes confirmarlo en la rama <code>existing</code>. Necesitamos el estado de <code>love.txt</code> en el "Commit Y" que sea lo mismo que "Commit 3.1" para evitar conflictos.)</p><p>Ahora tu historial debería coincidir con el que se muestra en la imagen con el subtítulo "Queremos que la confirmación "blue" esté en otra rama, <code>existing</code>".</p><p>Primero, haz que el <code>HEAD</code> apunte a la rama existente:</p><pre><code class="language-bash">git switch existing
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/switch_existing.png" class="kg-image" alt="Switch to the  branch" width="600" height="400" loading="lazy"><figcaption>Switch to the <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">existing</code> branch</figcaption></figure><p>Intuitivamente, lo que quieres hacer es tomar los cambios introducidos en el "Commit 4.1", y aplicar estos cambios ("copiar-pegar") por encima de la rama <code>exisitng</code>. Y Git tiene una herramienta para eso.</p><p>Para pedirle a Git que tome los cambios introducidos entre una confirmación y su confirmación antecesor y sólo aplicar estos cambios en la rama activa, puedes usar <code>git cherry-pick</code>, un comando que introducimos en el <a href="#cap-8">capítulo 8</a>. Este comando toma los cambios introducidos en la versión específicada y aplicarlos al estado de la confirmación activa. Ejecuta:</p><pre><code class="language-bash">git cherry-pick &lt;SHA_OF_COMMIT_4_1&gt;
</code></pre><p>Puedes especificar el identificador SHA-1 de la confirmación deseada, pero también puedes usar <code>git cherry-pick main</code>, &nbsp;como la confirmación cuyos cambios estás aplicando es al que está apuntando <code>main</code>.</p><p><code>git cherry-pick</code> también crea un nuevo objeto de confirmación, y actualiza la rama activa a que apunte a este nuevo objeto, así que el estado resultante sería:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cherry_pick.png" class="kg-image" alt="The result after using " width="600" height="400" loading="lazy"><figcaption>The result after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git cherry-pick</code></figcaption></figure><p>Marco a la confirmación como "Commit 4.2" ya que tiene una marca de tiempo, un antecesor y un valor SHA-1 distinto de "Commit 4.1", aunque los cambios que introducen son los mismos.</p><p>Hiciste buen progreso - la confirmación deseada está ahora en la rama ¡<code>existing</code>! Pero no queremos que estos cambios existan el rama <code>main</code>. &nbsp;<code>git cherry-pick</code> solamente aplicó los cambios a la rama existente. ¿Cómo puedes quitarlos del <code>main</code>?</p><p>Una forma sería volver a <code>main</code>, y luego hacer <code>reset</code>:</p><pre><code class="language-bash">git switch main
git reset --hard HEAD~1
</code></pre><p>Y el resultado:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reset_cherry_pick.png" class="kg-image" alt="The resulting state after resetting " width="600" height="400" loading="lazy"><figcaption>The resulting state after resetting <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>¡Lo hiciste!</p><p>Fíjate que <code>git cherry-pick</code> en realidad calcula la diferencia entre la confirmación especificada y su antecesor, y luego aplica la diferencia a la confirmación activa. Esto significa que a veces, Git no será capaz de aplicar esos cambios debido a un conflicto.</p><p>También, fíjate que puedes pedirle a Git que haga <code>cherry-pick</code> de los cambios introducidos en cualquier confirmación, no solamente las confirmaciones referenciadas por una rama.</p><h3 id="recapitulaci-n-git-reset"><strong>Recapitulación - Git Reset</strong></h3><p>En este capítulo, aprendimos cómo <code>git reset</code> opera, y clarificó sus tres modos principales de operación:</p><ul><li><code>git reset --soft &lt;commit&gt;</code>, el cual cambia cualquier <code>HEAD</code> al que esté apuntando - a <code>&lt;commit&gt;</code>.</li><li><code>git reset --mixed &lt;commit&gt;</code>, el cual pasa por la etapa <code>--soft</code>, y también establece el estado del índice para que coincida con el de <code>HEAD</code>.</li><li><code>git reset --hard &lt;commit&gt;</code>, el cual pasa por las etapas <code>--soft</code> y <code>--mixed</code>, y luego pone el estado del directorio de trabajo para que coincide con el del índice.</li></ul><p>Luego aplica tus conocimientos sobre <code>git reset</code> para que resuelva algunos problemas de la vida real que surgen cuando se usa Git.</p><p>Al entender la forma en que Git opera, y al limpiar el estado actual versus el estado deseado, puedes abarcar con toda confianza todo tipo de escenarios.</p><p>En capítulos futuros, cubriremos comandos de Git adicionales y cómo nos pueden ayudar a resolver todo tipos de situaciones no deseadas.</p><!--kg-card-begin: html--><h2 id="cap-10">Capítulo 10 - Herramientas adicionales para deshacer cambios</h2><!--kg-card-end: html--><p>En el capítulo previo, conociste a <code>git reset</code>. De hecho, <code>git reset</code> es una herramienta super poderosa, y te recomiendo mucho usarlo hasta que te sientas completamente confiado con él.</p><p>Aunque, <code>git reset</code> no es la única herramienta a nuestra disposición. Algunas veces, no es la herramienta más conveniente para usar. En otras veces, no es suficiente. Este corto capítulo abordo algunas herramientas que son útiles para deshacer cambios en Git.</p><h3 id="git-commit-amend"><strong><code>git commit --amend</code></strong></h3><p>Considera el <a href="#scenery-1">Escenario #1</a> del capítulo anterior nuevamente. Como recordatorio, escribiste "I love Git" en un archivo (<code>love.txt</code>), lo pusiste en el área de preparación y confirmaste este archivo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-52.png" class="kg-image" alt="image-52" width="600" height="400" loading="lazy"><figcaption>The state after creating "Commit 2.3"</figcaption></figure><p>Y luego me di cuenta que no quería que lo confirmaras a ese estado, sino - que escribieras algunas palabras de amor en este archivo antes de confirmarlo.</p><p>Para coincidir con este estado, simplemente revisa la etiqueta que creaste, el cual apunta a "Commit 2.3":</p><pre><code class="language-bash">git checkout scenario-1
</code></pre><p>En el capítulo previo, cuando introdujimos <code>git reset</code>, resolviste este error usando <code>git reset --mixed HEAD~1</code>, deshaciendo efectivamente las acciones de confirmación y las acciones puesto en el área de preparación que hiciste.</p><p>Ahora me gustaría considerar otro enfoque. Continúa trabajando en el estado de la última confirmación introducida ("Commit 2.3", referenciado por la etiqueta "scenario-1"), y haz los cambios que quieras:</p><pre><code class="language-bash">echo And I love this book &gt;&gt; love.txt
</code></pre><p>Agrega este cambio al índice:</p><pre><code class="language-bash">git add love.txt
</code></pre><p>Ahora, puedes usar <code>git commit</code> con el conmutador <code>--ammend</code>, el cual le dice que sobreescriba la confirmación al que <code>HEAD</code> está apuntando. En realidad, creará otra nueva confirmación, que apunta a <code>HEAD~1</code> ("Commit 1" en nuestro ejemplo), y hará que <code>HEAD</code> apunte a esta nueva confirmación creada. Proveyendo el argumento <code>-m</code> puedes especificar un nuevo mensaje de confirmación también:</p><pre><code class="language-bash">git commit --amend -m "Commit 2.4"
</code></pre><p>Después de ejecutar este comando, <code>HEAD</code> apunta a <code>main</code>, el cual apunta a "Commit 2.4", el cual en sí apunta a "Commit 1". El "Commit 2.3" previo ya no es alcanzable desde el historial.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_amend-1.png" class="kg-image" alt="commit_amend-1" width="600" height="400" loading="lazy"><figcaption>The state after using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git commit --amend</code> (Commit "2.3" is unreachable and thus not included in the drawing)</figcaption></figure><p>Esta herramienta es útil cuando quieras sobrescribir rápidamente la última confirmación que creaste. De hecho, podrías usar <code>git reset</code> para lograr lo mismo, pero puedes ver <code>git commit --ammend</code> como un atajo más conveniente.</p><h3 id="git-revert"><strong><code>git revert</code></strong></h3><p>Muy bien, otro día, otro problema.</p><p>Agrega el siguiente texto a <code>love.txt</code>, pónlo en el área de preparación y confirma como sigue:</p><pre><code class="language-bash">echo This is more tezt &gt;&gt; love.txt
git add love.txt
git commit -m "Commit 3"</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_revert_1-1.png" class="kg-image" alt="Committing &quot;More changes&quot;" width="600" height="400" loading="lazy"><figcaption>The state after committing "Commit 3"</figcaption></figure><p>Y empújalo al servidor remoto:</p><pre><code class="language-bash">git push origin HEAD
</code></pre><p>Am, ups 😓…</p><p>Noté algo. Tuve un error de tipado aquí. Escribí "This is more tezt" en vez de "This is more text". Woops. Así que, ¿cuál es el problema grande ahora? Hice <code>push</code>, lo que significa que alguien más ya podría haber hecho <code>push</code> de esos cambios.</p><p>Si sobrescribo esos cambios usando <code>git reset</code>, tendremos historiales distintos, y todo el infierno podría desatarse. Puedes sobrescribir tu propia copia del repo &nbsp;tanto como quieras hasta que hagas <code>push</code>.</p><p>Una vez que hagas <code>push</code> del cambio, necesitas estar seguro que nadie más ha solicitado esos cambios si vas a reescribir el historial.</p><p>De forma alternativa, puedes usar otra herramienta llamada <code>git revert</code>. Este comando toma la confirmación que le estás proveyendo y calcula el diff de su confirmación antecesor, así como <code>git cherry-pick</code>, pero esta vez, calcula los cambios <em>inversos</em>. Eso es, si en la confirmación especificada agregaste una línea, el servidor eliminaría la línea, y vice versa.</p><p>En nuestro caso estamos revirtiendo "Commit 3", así que la reversa sería eliminar la línea "This is more tezt" de <code>love.txt</code>. Ya que "Commit 3" está referenciado por <code>main</code> y <code>HEAD</code>, podemos usar cualquier de las referencias nombradas en este comando:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_revert_2.png" class="kg-image" alt="Using  to undo the changes" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git revert</code> to undo the changes</figcaption></figure><p><code>git revert</code> creó un nuevo objeto de confirmación, lo cual significa que es una adición al historial. Al usar <code>git revert</code>, no reescribiste el historial. Admitiste tu error pasado, y esta confirmación es un reconocimiento que cometiste un error y ahora lo arreglaste.</p><p>Alguno diría esta es la forma más madura. Alguno diría que no es un historial tan limpio como lo obtendrías si usaras <code>git reset</code> para reescribir la confirmación previa. Pero este es una forma de evitar reescribir el historial.</p><p>Ahora puedes arreglar el error de tipado y confirmar nuevamente:</p><pre><code class="language-bash">echo This is more text &gt;&gt; love.txt
git add love.txt
git commit -m "Commit 3.1"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_revert_3.png" class="kg-image" alt="Redoing the changes" width="600" height="400" loading="lazy"><figcaption>The resulting state after redoing the changes</figcaption></figure><p>Puedes usar <code>git revert</code> para revertir una confirmación que no sea <code>HEAD</code>. Digamos que quieres revertir el antecesor de <code>HEAD</code>, puedes usar:</p><pre><code class="language-bash">git revert HEAD~1
</code></pre><p>O podrías proveer el SHA-1 de la confirmación para revertir.</p><p>Fíjate ya que Git aplicará el parche de reversa del parche anterior - esta operación podría fallar, ya que el parche ya no se podría aplicar y tendrías un conflicto.</p><h3 id="git-rebase-como-una-herramienta-para-deshacer-cosas">Git Rebase como una herramienta para deshacer cosas</h3><p>En el <a href="#cap-8">capítulo 8</a>, aprendiste sobre Git rebase. Lo consideramos principalmente como una herramienta para combinar cambios introducidos en diferentes ramas. Sin embargo, siempre y cuando no hayas hecho <code>push</code> de tus cambios, usando <code>rebase</code> en tu propia rama puede ser una forma muy conveniente para reordenar tu historial de confirmaciones.</p><p>Para ello, usualmente <a href="#rebase-single-branch">harías rebase en una sola rama</a>, y usa el rebase interactivo. Considera nuevamente este ejemplo abarcado en el <a href="#cap-8">capítulo 8</a>, donde trabajé desde <code>feature_branch_2</code>, y específicamente edité el archivo <code>code.py</code>. Comencé por cambiar todas las cadenas para que sean envueltas por comillas dobles en vez de comillas simples:	</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_4-1.png" class="kg-image" alt="Changing  into  in " width="600" height="400" loading="lazy"><figcaption>Changing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">'</code> into <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">"</code> in <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">code.py</code></figcaption></figure><p>Luego, lo puse en el área de preparación y confirmé:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 17"
</code></pre><p>Luego decidí agregar una nueva función al principio del archivo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_5-1.png" class="kg-image" alt="Adding the function " width="600" height="400" loading="lazy"><figcaption>Adding the function <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">another_feature</code></figcaption></figure><p>Nuevamente, lo puse en el área de preparación y confirmé:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 18"
</code></pre><p>Y ahora me di cuenta que en realidad me olvidé de cambiar las comillas simples a comillas dobles al envuelto de <code>__main__</code> (como lo has visto), así que hice eso también:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/code_py_6-1.png" class="kg-image" alt="Changing  into " width="600" height="400" loading="lazy"><figcaption>Changing <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">'__main__'</code> into <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">"__main__"</code></figcaption></figure><p>Por supuesto, lo puse en el área de preparación y confirmé este cambio:</p><pre><code class="language-bash">git add code.py
git commit -m "Commit 19"
</code></pre><p>Ahora, considera el historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/history_after_commit_19-1.png" class="kg-image" alt="The commit history after introducing &quot;Commit 19&quot;" width="600" height="400" loading="lazy"><figcaption>The commit history after introducing "Commit 19"</figcaption></figure><p>Como expliqué en el <a href="#cap-8">capítulo 8</a>, obtuve un estado con dos confirmaciones que están relacionados uno con el otro, "Commit 17" y "Commit 19" (cambiando <code>'</code> a <code>"</code>), pero están separados por el "Commit 18" que no está relacionado (donde agregué una nueva función).</p><p>Este es un caso básico donde <code>git rebase</code> sería práctico, para deshacer los cambios locales antes de hacer <code>push</code> de un historial limpio.</p><p>Intuitivamente, quiero editar el historial aquí:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/plan_edit_commits_17_18-1.png" class="kg-image" alt="These are the commits I want to edit" width="600" height="400" loading="lazy"><figcaption>These are the commits I want to edit</figcaption></figure><p>Puedo hacer <code>rebase</code> del historial desde "Commit 17" a "Commit 19", por encima de "Commit 15". Para hacer eso:</p><pre><code class="language-bash">git rebase --interactive --onto &lt;SHA_OF_COMMIT_15&gt; &lt;SHA_OF_COMMIT_15&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_4-1.png" class="kg-image" alt="Using  on a single branch" width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">rebase --onto</code> on a single branch</figcaption></figure><p>Esto resulta en la siguiente pantalla:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_4-1.png" class="kg-image" alt="Interactive rebase" width="600" height="400" loading="lazy"><figcaption>Interactive rebase</figcaption></figure><p>Así que, ¿qué haría? Quiero poner a "Commit 19" antes de "Commit 18", así viene justo después de "Commit 17". Puedo ir más lejos y hacerles <code>squash</code> ("aplastarlos", de manera figurativa), así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_5-1.png" class="kg-image" alt="Interactive rebase - changing the order of commit and squashing" width="600" height="400" loading="lazy"><figcaption>Interactive rebase - changing the order of commit and squashing</figcaption></figure><p>Ahora cuando recibo una pantalla para escribir un mensaje de confirmación, puedo proveer el mensaje "Commit 17+19":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/interactive_rebase_6-1.png" class="kg-image" alt="Providing a commit message" width="600" height="400" loading="lazy"><figcaption>Providing a commit message</figcaption></figure><p>Y ahora, vemos nuestro precioso historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/rebase_onto_5-1.png" class="kg-image" alt="The resulting history" width="600" height="400" loading="lazy"><figcaption>The resulting history</figcaption></figure><p>La sintaxis usada arriba, <code>git rebase --interactive --onto &lt;COMMIT X&gt; &lt;COMMIT X&gt;</code> sería la sintaxis más usada comúnmente por aquellos que usan <code>rebase</code> regularmente. La manera de pensar que estos desarrolladores usualmente tienen es crear confirmaciones atómicas mientras trabajan, todo el tiempo, sin asustarse de cambiarlos luego. Entonces, antes de hacer <code>push</code> de sus cambios, harían <code>rebase</code> a todo el conjunto de cambios desde el último <code>push</code>, y re-arreglarlo así el historial se vuelve coherente.</p><h3 id="git-reflog"><code>git reflog</code></h3><p>Es tiempo de considerar un caso más alarmante.</p><p>Vuelve al "Commit 2.4":</p><pre><code class="language-bash">git reset --hard &lt;SHA_OF_COMMIT_2_4&gt;
</code></pre><p>Haz algo, escribe algo de código, y agrégalo a <code>love.txt</code>. Pónlo en el área de preparación a este cambio, y confírmalo:</p><pre><code class="language-bash">echo lots of work &gt;&gt; love.txt
git add love.txt
git commit -m "Commit 3.2"
</code></pre><p>(Estoy usando "Commit 3.2" para indicar que este no es la misma confirmación que "Commit 3" que usamos cuando explicamos sobre <code>git revert</code>.)</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_commit_3-1.png" class="kg-image" alt="Another commit" width="600" height="400" loading="lazy"><figcaption>Another commit - "Commit 3.2"</figcaption></figure><p>Hice lo mismo en mi máquina, y usé la tecla flecha arriba <code>Up</code> en mi teclado para volver a los comandos anteriores, y luego presioné <code>Enter</code>, y... Wow.</p><p>Whoops.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_commit_3_reset.png" class="kg-image" alt="Did I just ?" width="600" height="400" loading="lazy"><figcaption>Did I just <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset -- hard</code>?</figcaption></figure><p>¿Acaso usé <code>git reset --hard</code>? 😨</p><p>¿Pero qué pasó en realidad? Como aprendiste en el capítulo previo, Git movió el puntero a <code>HEAD~1</code>, de esa forma la última confirmación, con todo mi trabajo precioso, no es alcanzable desde el historial actual. Git también quitó todos los cambios desde el área de preparación, y luego hice coincidir el directorio de trabajo con el del estado del área de preparación.</p><p>Eso es, todo coincide con este estado donde mi trabajo... se ha ido.</p><p>Momento de terror. Me voy asustando.</p><p>Pero, realmente, ¿hay una razón para asustarse? No realmente... Somos personas relajadas. ¿Qué hacemos? Bueno, intuitivamente, ¿realmente, realmente se ha ido la última confirmación?</p><p>No. ¿Y por qué no? Todavía existe dentro de la base de datos interno de Git.</p><p>Si tan solo supiera dónde está, sabría el valor <code>SHA-1</code> que identifica a esta confirmación, y podríamos restaurarlo. Inclusive podría deshacer lo deshecho, y hacer <code>reset</code> y volver a esta confirmación.</p><p>En realidad, lo único que realmente necesito aquí es el <code>SHA-1</code> de la confirmación "eliminada".</p><p>Ahora la pregunta es, ¿cómo lo encuentro? ¿<code>git log</code> sería útil?</p><p>Bueno, no realmente. <code>git log</code> iría al <code>HEAD</code>, el cual apunta a <code>main</code>, el cual apunta a la confirmación antecesora de la confirmación que estamos buscando. Luego, <code>git log</code> recorrería a través de la cadena de antecesores, el cual no incluye la confirmación con mi trabajo precioso.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_git_log.png" class="kg-image" alt=" doesn't help in this case" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> doesn't help in this case</figcaption></figure><p>Afortunadamente, los genios que crearon Git también crearon un plan de recuperación para nosotros, y se llama el <code>reflog</code>.</p><p>Mientras trabajas con Git, cuando sea que cambies el <code>HEAD</code>, lo cual lo puedes hacer usando <code>git reset</code>, pero también con otros comandos como <code>git switch</code> o <code>git checkout</code>, Git agrega una entrada al <code>reflog</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reflog.png" class="kg-image" alt=" shows us where  was" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reflog</code> shows us where <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">HEAD</code> was</figcaption></figure><p>¡Encontramos nuestra confirmación! Es el que comienza con <code>0fb929e</code>.</p><p>También podemos relacionarlo por su "nickname" - <code>HEAD@{1}</code>. De forma similar Git usa al <code>HEAD~1</code> para obtener el primer antecesor de <code>HEAD</code>, y <code>HEAD~2</code> para que se refiera al segundo antecesor de <code>HEAD</code>, y así sucesivamente, Git usa <code>HEAD@{1}</code> para referirse al primer <em>reflog</em> antecesor de <code>HEAD</code>, eso es, a donde apuntaba <code>HEAD</code> en el paso anterior.</p><p>También podemos pedirle a <code>git rev-parse</code> que nos muestre su valor:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/reflog_revparse.png" class="kg-image" alt="Using " width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git rev-parse HEAD@{1}</code></figcaption></figure><p>Nota: En caso que estés usando Windows, podrías necesitar envolverlo con comillas - así:</p><pre><code class="language-bash">git rev-parse "HEAD@{1}"
</code></pre><p>Otra forma de ver el <code>reflog</code> es usando <code>git log -g</code>, el cual le pide a <code>git log</code> que considere el <code>reflog</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_g.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log -g</code></figcaption></figure><p>Puedes ver en la salida de <code>git log -g</code> que la entrada de <code>reflogHEAD@{0}</code>, justo como el <code>HEAD</code>, apunta a <code>main</code>, el cual apunta a "Commit 2". Pero el antecesor de esa entrada en el <code>reflog</code> apunta a "Commit 3".</p><p>Así que para volver a "Commit 3", puedes usar <code>git reset --hard HEAD@{1}</code> (o el valor <code>SHA-1</code> de "Commit 3"):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reflog_reset.png" class="kg-image" alt="git_reflog_reset" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --hard HEAD@{1}</code></figcaption></figure><p>Y ahora, si haces <code>git log</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_2.png" class="kg-image" alt="Our history is back!!!" width="600" height="400" loading="lazy"><figcaption>Our history is back!!!</figcaption></figure><p>¡Nos salvamos!</p><p>¿Qué sucedería si usara este comando nuevamente? ¿Y ejecutara <code>git reset --hard HEAD@{1}</code>?</p><p>Git pondría al <code>HEAD</code> a dónde <code>HEAD</code> estaba apuntando antes del último <code>reset</code>, lo que significa a "Commit 2". Podemos continuar todo el día:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_reset_again.png" class="kg-image" alt=" again" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git reset --hard</code> again</figcaption></figure><h3 id="recapitulaci-n-herramientas-adicionales-para-deshacer-cambios">Recapitulación - Herramientas adicionales para Deshacer Cambios</h3><p>En el capítulo anterior, aprendiste cómo usar <code>git reset</code> para deshacer cambios.</p><p>En este capítulo, agrandaste tu caja de herramientas para deshacer cambios en Git con algunos comandos nuevos:</p><ul><li><code>git commit --ammend</code> - el cual "sobreescribe" la última confirmación con el área de preparación del índice. Mayoritariamente útil cuando confirmaste algo y quieres modificar la última confirmación.</li><li><code>git revert</code> - el cual crea una nueva confirmación, que revierte una confirmación anterior agregando una nueva confirmación al historial con los cambios revertidos. Especialmente útil cuando la confirmación "defectuosa" ya ha sido subida al remoto.</li><li><code>git rebase</code> - el cual ya los conocías desde el <a href="#cap-8">capítulo 8</a>, y es útil para reescribir el historial de confirmaciones múltiples, especialmente antes de empujarlos.</li><li><code>git reflog</code> (y <code>git log -g</code>) - el cual rastrea todos los cambios hasta el <code>HEAD</code>, así puedes encontrar el valor SHA-1 de una confirmación al que necesitas volver.</li></ul><p>La herramienta más importante, inclusive más importante que las herramientas que listé, es limpiar la situación actual vs el desado. Créeme en esta, hará que cada situación parezca menos intimidante y la solución más clara.</p><p>Hay herramientas adicionales que te permiten revertir cambios en Git (proveeré enlaces en el <a href="#apendices">apéndice</a>), pero la colección de herramientas que cubrí aquí debería prepararte para abarcar cualquier desafío con confianza.</p><!--kg-card-begin: html--><h2 id="cap-11">Capítulo 11 - Ejercicios</h2><!--kg-card-end: html--><p>Este capítulo incluye algunos ejercicios para profundizar tus conocimientos de las herramientas que aprendiste en la Parte 3. La versión completa de este libro también incluye soluciones detalladas de cada una.</p><p>Los ejercicios se encuentran en este repositorio:</p><p><a href="https://github.com/Omerr/undo-exercises.git">https://github.com/Omerr/undo-exercises.git</a></p><p>Cada ejercicio está en una rama con el nombre <code>exercise_XX</code>, así que el Ejercicio 1 se encuentra en la rama <code>exercise_01</code>, el Ejercicio 2 se encuentra en la rama <code>exercise_02</code> y así sucesivamente.</p><p><strong>Nota</strong>: como se explicó en los capítulos previos, si trabajas con confirmaciones que pueden ser encontradas en un servidor remoto (los cuales son en la que estás en este caso, ya que estás usando mi repositorio "undo-exercises"), deberías probablemente usar <code>git revert</code> en vez de <code>git reset</code>. De la misma forma con <code>git rebase</code>, el comando <code>git reset</code> también reescribe el historial - y así te refrenas de usarlo en las confirmaciones en las que otros podían basarse.</p><p>Para los propósitos de estos ejercicios, puedes asumir que nadie ha clonado o haya descargado (pull) el código del repositorio remoto. Sólo recuerda - en la vida real, probablemente deberías usar <code>git revert</code> en vez de comandos que reescriben el historial en tales casos.</p><h3 id="ejercicio-1">Ejercicio 1</h3><p>En la rama <code>execise_01</code>, considera el archivo <code>hello.txt</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_01_1.png" class="kg-image" alt="The file " width="600" height="400" loading="lazy"><figcaption>The file <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">hello.txt</code></figcaption></figure><p>Este archivo incluye un error de tipado (en el último caracter). Encuentra la confirmación que introdujo este error de tipado.</p><h4 id="ejercicio-1a-">Ejercicio (1a)</h4><p>Quita esta confirmación del historial alcanzable usando <code>git reset</code> (con los argumentos correctos), arregla el error de tipado, y confirma nuevamente. Considera tu historial.</p><p>Revierte al estado previo.</p><h4 id="ejercicio-1b-">Ejercicio (1b)</h4><p>Quita la confirmación defectuosa usando <code>git commit --ammend</code>, y vuelve al mismo estado del historial como al final del ejercicio (1a).</p><p>Revierte al estado previo.</p><h4 id="ejercicio-1c-">Ejercicio (1c)</h4><p>Haz <code>revert</code> de la confirmación defectuosa usando <code>git revert</code> y arregla el error de tipado. Considera tu historial.</p><p>Revierte al estado previo.</p><h4 id="ejercicio-1d-">Ejercicio (1d)</h4><p>Usando <code>git rebase</code>, vuelve al misma estado como al final del ejercicio (1a).</p><h3 id="ejercicio-2">Ejercicio 2</h3><p>Cambia a la rama <code>exercise_02</code>, y considera los contenidos de <code>exercise_02.txt</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_02_1.png" class="kg-image" alt="The contents of " width="600" height="400" loading="lazy"><figcaption>The contents of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">exercise_02.txt</code></figcaption></figure><p>Un archivo sencillo, con un caracter en cada línea.</p><p>Considera el historial (usando <code>git lol</code>):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_02_2.png" class="kg-image" alt="ex_02_2" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol</code></figcaption></figure><p>Oh mi. Cada caracter fue introducido en una confirmación separada. ¡Eso no tiene sentido!</p><p>Usa las herramientas que has adquirido para crear un historial donde la creación de <code>exercise_02.txt</code> está hecho en una sola confirmación.</p><h3 id="ejercicio-3">Ejercicio 3</h3><p>Considera el historial en la rama <code>exercise_03</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_03_1.png" class="kg-image" alt="The history on " width="600" height="400" loading="lazy"><figcaption>The history on <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">exercise_03</code></figcaption></figure><p>Esto parece un desastre. Notarás que:</p><ul><li>El orden está sesgado. Necesitamos que "Commit 1" sea la primera confirmación en esta rama, y tenga a "Initial Commit" como su antecesor, seguido de "Commit 2" y así sucesivamente.</li><li>No deberíamos tener "Commit 2a" y "Commit 2b", o "Commit 4a" y "Commit 4b" - estos dos pares necesitan ser combinados en una sola confirmación cada uno - "Commit 2" y "Commit 4".</li><li>Hay un error de tipado en el mensaje de confirmación de "Commit 1", no debería tener 3 <code>m</code>.</li></ul><p>Arregla estos errores, pero básate en los cambios de cada confirmación original. El historial resultante debería lucir así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_03_2.png" class="kg-image" alt="The desired history" width="600" height="400" loading="lazy"><figcaption>The desired history</figcaption></figure><h3 id="ejercicio-4">Ejercicio 4</h3><p>Este ejercicio en realidad consiste de tres ramas: <code>exercise_04</code>, <code>exercise_04_a</code>, y <code>exercise_04_b</code>.</p><p>Para ver el historial de estas ramas sin las otras, usa la siguiente sintaxis:</p><pre><code class="language-bash">git lol --branches="exercise_04*"
</code></pre><p>El resultado es:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_04_1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol --branches="exercise_04*"</code></figcaption></figure><p>Tu objetivo es hacer que <code>exercise_04_b</code> sea independiente de <code>exercise_04_a</code>. Eso es, obtener este historial:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/ex_04_2.png" class="kg-image" alt="The desired history" width="600" height="400" loading="lazy"><figcaption>The desired history</figcaption></figure><p><strong>¡Buena suerte!</strong></p><!--kg-card-begin: html--><h1 id="part-4">Parte 4 - Herramientas de Git Fantásticas y Útiles</h1><!--kg-card-end: html--><p>Git tiene un montón de comandos, y estos comandos tienen muchísimas opciones y argumentos. Podría intentar cubrirlos todos (aunque cambian con el tiempo), pero no veo el punto en ello. Probablemente deberías conocer un sub-conjunto de estos comandos realmente bien, aquellos que usas regularmente. Luego, siempre puedes buscar por un comando específico para realizar una tarea a mano.</p><p>Esta parte se basa en las bases que adquiriste en las partes previas, y cubre comandos específicos y opciones que podrías encontrar útiles. Dado tu entendimiento de cómo funciona Git, tener estas pequeñas herramientas puede hacerte un verdadero pro para llevar a Git a cabo.</p><!--kg-card-begin: html--><h2 id="cap-12">Capítulo 12 - Git Log</h2><!--kg-card-end: html--><p>Usaste <code>git log</code> muchas veces a lo largo de los distintos capítulos, y probablemente lo has usado muchas veces antes de leer este libro.</p><p>La mayoría de los desarrolladores usan <code>git log</code>, pocos lo usan de forma efectiva. En este capítulo aprenderás ajustes útiles para sacar el mayor provecho a <code>git log</code>. Una vez que te sientas cómodo con los diferentes conmutadores de este comando, será un verdadero cambio en tu día a día trabajando con Git.</p><p>Pensando en ello, <code>git log</code> abarca la esencia de cada versión del sistema de control - es decir, para registrar cambios en las versiones. Registras versiones de esa forma puedes considerar el historial de tu proyecto - tal vez revertir o aplicar cambios específicos, preferir cambiar a un punto distinto en el tiempo y probar las cosas allí. Tal vez te gustaría saber quién contribuyó una cierta pieza de código o cuando lo hicieron.</p><p>Mientras que <code>git</code> sí preserva esta información usando objetos de confirmación, eso también apunta a sus confirmaciones antecesoras, y referencias a objetos de confirmación (tales como ramas o <code>HEAD</code>), este almacenamiento de versiones no es suficiente. Sin ser capaz de encontrar la confirmación relevante que te gustaría considerar, o reunir información relevante sobre ello, tener estos datos almacenados es bastante inútil.</p><p>Puedes imaginarte a tus objetos de confirmación como distintos libros que se apilan en un pila gigante, o en una biblioteca, llenando largos estantes. La información que podrías necesitar está en estos libros, pero si no tienes un índice - una forma para saber en qué libro yace la información que buscas, o dónde este libro se localiza dentro de la biblioteca - no serías capaz de hacer uso de él. <code>git log</code> es esta indexación de tu biblioteca - es una forma de encontrar las confirmaciones relevantes y la información sobre ellos.</p><p>Los argumentos útiles para <code>git log</code> que aprenderás en este capítulo dan formato en cómo se muestran las confirmaciones en el log, o filtran confirmaciones específicas.</p><p><code>git lol</code>, un alias que he usado a lo largo de este libro, usa algunos de estos conmutadores, como lo demostraré. Siéntete libre de ajustar este alias (o crea otro desde cero) después de leer este capítulo.</p><p>Como en otros capítulos, el objetivo no es proveer una referencia completa, por lo tanto no proveeré <em>todos</em> los diferentes conmutadores de <code>git lol</code>. Me enfocaré en los conmutadores que creo que los encontrarás útiles.</p><h3 id="filtrando-comandos">Filtrando comandos</h3><p>Considera la salida predeterminada de <code>git log</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_1.png" class="kg-image" alt="The output of  without additional switches" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> without additional switches</figcaption></figure><p>El log comienza desde el <code>HEAD</code>, y sigue la cadena de antecesores.</p><h4 id="las-confirmaciones-no-alcanzables-desde-">Las Confirmaciones (no) alcanzables desde...</h4><p>Cuando escribes <code>git log &lt;revision&gt;</code>, <code>git log</code> incluirá todas las entradas accesibles desde <code>&lt;revision&gt;</code>. Con "accesible", me refiero accesible al seguir la cadena de antecesores. Así que ejecutando <code>git log</code> sin argumentos es lo mismo que ejecutar <code>git log HEAD</code>.</p><p>Puedes especificar múltiples revisiones para <code>git log</code>- si escribes <code>git log branch_1 branch_2</code>, le pides a <code>git log</code> que incluya cada confirmación que es alcanzable desde <code>branch_1</code> o <code>branch_2</code> (o ambos).</p><p><code>git log</code><strong> excluirá</strong> cualquier confirmación que sea alcanzable desde las revisiones precedidos por un <code>^</code>.</p><p>Por ejemplo, el siguiente comando:</p><pre><code class="language-bash">git log branch_1 ^branch_2
</code></pre><p>le pide a <code>git log</code> que incluya cada confirmación que es accesible desde <code>branch_1</code>, pero no aquellos que son accesibles desde <code>branch_2</code>.</p><p>Considera el historial cuando uso <code>git log feature_branch_2</code> en este repo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_2-1.png" class="kg-image" alt="git_log_2-1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log feature_branch_1</code></figcaption></figure><p>El historial incluye todas las confirmaciones accesibles por <code>feature_branch_1</code>. Ya que esta rama "se creó" desde <code>main</code> (eso es, "Commit 12", al que apunta <code>main</code>, es accesible desde la cadena de antecesores) - el log también incluye todas las confirmaciones accesibles desde <code>main</code>.</p><p>¿Qué sucedería si ejecutara este comando?</p><pre><code class="language-bash">git log feature_branch_1 ^main
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_3.png" class="kg-image" alt="git_log_3" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log feature_branch_1 ^main</code></figcaption></figure><p>En efecto, <code>git log</code> muestra sólo "Commit 13" y "Commit 16", los cuales son accesibles desde <code>feature_branch_1</code> pero no desde <code>main</code>.</p><h4 id="git-log-all"><strong><code>git log --all</code></strong></h4><p>Para seguir las confirmaciones que son accesibles desde cualquier referencia nombrada o (cualquier ref en <code>refs/</code>) o desde el <code>HEAD</code>.</p><h4 id="por-autor">Por Autor</h4><p>Si sabes que estás buscando una confirmación que tiene una persona específica como autor, puedes filtrar estas confirmaciones usando el nombre del usuario o su email, así:</p><pre><code class="language-bash">git log --author="Name"
</code></pre><p>Puedes usar expresiones regulares para buscar los nombres de los autores que coinciden con un patrón específico, por ejemplo:</p><pre><code class="language-bash">git log --author="John\|Jane"
</code></pre><p>filtrará las confirmaciones cuyo autor es John o Jane.</p><h4 id="por-fecha">Por Fecha</h4><p>Cuando sabes que el cambio que estás buscando ha sido confirmado dentro de una fracción de tiempo específico, puedes usar <code>--before</code> o <code>--after</code> para filtrar las confirmaciones desde esa fracción de tiempo.</p><p>Por ejemplo, para obtener todas las confirmaciones introducidos después del 12 de Abril de 2023 (inclusivo), usa:</p><pre><code class="language-bash">git log --after="2023-04-12"
</code></pre><h4 id="por-rutas">Por Rutas</h4><p>Puedes pedir a <code>git log</code> que sólo muestre las confirmaciones donde los <em>cambios</em> han sido introducidos en rutas específicas. Fíjate que no significa que cualquier confirmación que apunte a un árbol que incluya los archivos en cuestión, sino más bien que si calculamos la diferencia entre la confirmación en cuestión y sus antecesores, veríamos que al menos uno de las rutas ha sido modificado.</p><p>Por ejemplo, puedes usar:</p><pre><code class="language-bash">git log --all -- 1.py
</code></pre><p>para encontrar todas las confirmaciones que son accesibles desde cualquier puntero nombrado, o <code>HEAD</code>, e introducir un cambio a <code>1.py</code>. Puedes especificar múltiples rutas:</p><pre><code class="language-bash">git log --all -- 1.py 2.py
</code></pre><p>El comando previo hará que <code>git log</code> incluya confirmaciones accesibles que introdujeron un cambio a <code>1.py</code> o <code>2.py</code> (o ambos).</p><p>También puedes usar un patrón glob, por ejemplo:</p><pre><code class="language-bash">git log -- *.py
</code></pre><p>incluirá las confirmaciones que son accesibles desde el <code>HEAD</code> que incluye un cambio a cualquier archivo en el directorio raíz cuyo nombre termina con un <code>.py</code>. Para buscar un archivo que termine con <code>.py</code>, puedes usar:</p><pre><code class="language-bash">git log -- **/*.py
</code></pre><h4 id="por-mensaje-de-confirmaci-n">Por Mensaje de Confirmación</h4><p>Si conoces el mensaje de confirmación (o partes de él) de la confirmación que estás buscando, puedes usar el conmutador <code>--grep</code> para "git log", por ejemplo:</p><pre><code class="language-bash">git log --grep="Commit 12"
</code></pre><p>devuelve la confirmación con el mensaje "Commit 12".</p><h4 id="por-contenido-de-diff">Por Contenido de Diff</h4><p>Este es super útil, y me ha salvado incontables veces. Al usar <code>git log -S</code>, puedes buscar confirmaciones que introducen o quitan una línea en particular del código fuente.</p><p>Esto es práctico, por ejemplo, cuando sabes que has creado algo en el repo, pero no sabes dónde está ahora. No puedes encontrarlo en ningún lugar de tu sistema de archivos (no está en el <code>HEAD</code>), y sabes que debe estar ahí - acechando en algún lugar en esta librería (montón de confirmaciones) que tienes.</p><p>Digamos que recuerdo dónde escribí una línea con el texto <code>Git is awesome</code>, pero no puedo encontrarlo ahora. Podría ejecutar:</p><pre><code class="language-bash">git log --all -S"Git is awesome"
</code></pre><p>Fíjate que usé <code>--all</code> para evitar limitarme a confirmaciones alcanzables desde el <code>HEAD</code>.</p><p>También puedes buscar una expresión regular, usando <code>-G</code>:</p><pre><code class="language-bash">git log --all -G"Git .* awesome"
</code></pre><h3 id="formateando-el-log">Formateando el Log</h3><p>Considera la salida predeterminada de <code>git log</code> nuevamente:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_1-1.png" class="kg-image" alt="The output of  without additional switches" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log</code> without additional switches</figcaption></figure><p>El log comienza desde el <code>HEAD</code>, y sigue la cadena de antecesores.</p><p>Cada entrada del log comienza con una línea con <code>commit</code> y luego el SHA-1 de la confirmación, tal vez seguida de punteros adicionales que apuntan a esta confirmación.<br>Luego es seguido por el autor, fecha, y mensaje de confirmación.</p><h4 id="-oneline"><strong><code>--oneline</code></strong></h4><p>La principal dificultad con la salida predeterminada de <code>git log</code> es que es difícil de entender un historial con más de unas pocas confirmaciones, ya que simplemente no los ves a todos.</p><p>En la salida de <code>git log</code> que se muestra abajo, solamente cuatro objetos de confirmación aparecieron en mi pantalla. Usando <code>git log --oneline</code> provee una vista más concisa, mostrando el SHA-1 de la confirmación, al lado de su mensaje, y referencia nombradas si son relevantes:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_5.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline</code></figcaption></figure><p>Si deseas omitir las referencias nombradas, puedes agregar el conmutador <code>--no-decorate</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_6.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline --no-decorate</code></figcaption></figure><p>Para pedirle a <code>git log</code> explícitamente que muestre decoraciones, puedes usar <code>git log --decorate</code>.</p><h4 id="-graph"><strong><code>--graph</code></strong></h4><p><code>git log --oneline</code> muestra una representación compacta. Eso es genial cuando tenemos un historial linear, tal vez en una sola rama. Pero, ¿qué sucede cuando tenemos múltiples ramas, que podría diferir uno del otro?</p><p>Considera la salida del siguiente comando en mi repositorio:</p><pre><code class="language-bash">git log --oneline feature_branch_1 feature_branch_2
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_7.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline feature_branch_1 feature_branch_2</code></figcaption></figure><p><code>git log</code> muestra cualquier confirmación accesible por <code>feature_branch_1</code>, <code>feature_branch_2</code>, o ambos. Pero, ¿cómo se ve el historial? ¿<code>feature_branch_2</code> difirió de <code>feature_branch_1</code>? ¿O difirió de <code>main</code>? Es imposible distinguirlo desde esta vista.</p><p>Aquí es donde <code>--graph</code> viene a mano, dibujando un gráfico ASCII representando la estructura de la rama del historial de confirmaciones. Si agregamos esta opción al comando previo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_8.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline --graph feature_branch_1 feature_branch_2</code></figcaption></figure><p>En realidad puedes <em>ver</em> que <code>feature_branch_1</code> se creó desde <code>main</code> (ya que "Commit 12", <code>main</code>, es el antecesor de "Commit 13"), y también que <code>feature_branch_2</code> se creó desde <code>main</code> (ya que el antecesor de "Commit 14" también es "Commit 12").</p><p>El símbolo <code>*</code> nos dice "en" qué rama está una cierta confirmación, así sabes con certeza que "Commit 13" está en <code>feature_branch_1</code>, y no en <code>feature_branch_2</code>.</p><h4 id="-pretty-format"><strong><code>--pretty=format</code></strong></h4><p>El resultado de arriba, ¡ya es muy útil! Aunque, le falta un par de cosas. No sabemos el autor o el tiempo de la confirmación. Estos dos detalles fueron incluidos en la salida predeterminada de <code>git log</code> el cual fue muy largo. Tal vez, ¿los podemos agregar de una forma más compacta?</p><p>Al usar <code>--pretty=format:</code>, puedes mostrar la información de cada confirmación en varias formas usando marcadores de posición al estilo de <code>printf</code>.</p><p>En el siguiente comando, los marcadores de posición <code>%s</code>, <code>%an</code> y <code>%cd</code> son reemplazados por el sujeto de la confirmación (mensaje), nombre de autor, y la fecha de la confirmación, respectivamente.</p><pre><code class="language-bash">git log --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:"%s (%an) [%cd]"
</code></pre><p>La salida luce así:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_9.png" class="kg-image" alt="git_log_9" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:"%s (%an) [%cd]</code></figcaption></figure><p>Eso es útil, pero no bueno al mirarlo. Entonces podemos usar otros trucos de formateo, específicamente <code>%C(color)</code> que cambiará el color a <code>color</code>, hasta que alcance un <code>%Creset</code> que resetea el color. Para hacer que el nombre del autor sea amarillo, puedes usar:</p><pre><code class="language-bash">git log --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:"%s %C(yellow)(%an)%Creset [%cd]"
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_10.png" class="kg-image" alt="git_log_10" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline --graph feature_branch_1 feature_branch_2 --pretty=format:"%s %C(yellow)(%an)%Creset [%cd]"</code></figcaption></figure><p>Para algunos colores, como <code>rojo</code> o <code>verde</code>, es innecesario incluir el paréntesis, así que <code>rojo</code> es suficiente.</p><h3 id="-c-mo-se-estructura-git-lol">¿Cómo se estructura <code>git lol</code>?</h3><p>Cuando ejecuto <code>git lol</code>, en realidad ejecuta lo siguiente:</p><p><code>git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset' --abbrev-commit</code></p><p>¿Puedes tomar esto poco a poco?</p><p>Ya conoces <code>--graph</code>, el cual hace que la salida incluya un gráfico ASCII.</p><p><code>--abbrev-commit</code> usa un prefijo corto del SHA-1 completo de la confirmación (en mi configuración, los siete primero caracteres).</p><p>El resto es sólo el coloreamiento de varios detalles sobre la confirmación:</p><pre><code class="language-bash">git lol --all
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_log_11.png" class="kg-image" alt="git_log_11" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol --all</code></figcaption></figure><p>Me gusta esta salida porque lo encuentro claro. Me da la información que necesito, con colores suficientes así cada detalles se destaca sin lastimar mis ojos. Pero si prefieres otra información, otros colores, un diferente orden, o cualquier cosa - adelante y ajústalo a tu gusto.</p><h3 id="definiendo-un-alias">Definiendo un alias</h3><p>Como sabes, defino a <code>git lol</code> como un alias - eso es, cuando ejecuto <code>git lol</code>, ejecuta el comando largo que proveí anteriormente.</p><p>¿Cómo puedes crear un alias en Git?</p><p>La forma mas fácil es usar <code>git alias</code>, así:</p><pre><code class="language-bash">git config --global alias.co checkout
</code></pre><p>Este comando pone <code>co</code> para que sea un alias para el comando <code>checkout</code>, así puedes usar <code>git co main</code> en vez de <code>git checkout main</code>.</p><p>Para definir <code>git lol</code> como un alias, puedes usar:</p><pre><code class="language-bash">git config --global alias.lol 'log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset' --abbrev-commit'
</code></pre><!--kg-card-begin: html--><h2 id="cap-13">Capítulo 13 - Git Bisect</h2><!--kg-card-end: html--><p>Ups.</p><p>Tengo un error.</p><p>Sí, sucede a veces, a todos nosotros. Algo en mi sistema está roto, y no puedo distinguir por qué. He estado depurando por un rato, pero la solución no está clara.</p><p>Puedo decir que dos semanas atrás, esto no sucedió. Afortunadamente para mí, he estado usando Git (obviamente lo sé...), así que puedo volver en el tiempo y probar una versión anterior de mi código. En efecto, en esta versión - todo funcionó bien.</p><p>Pero... he hecho muchos cambios en estas dos semanas. Ay, no solo yo - mi equipo completo ha contribuido con confirmaciones que agregan, eliminan, o modifican partes del código base. ¿Por dónde comienzo? ¿Debería ir por cada cambio introducido en esas dos semanas?</p><p>Ingresa - <code>git bisect</code>.</p><p>El objetivo de <code>git bisect</code> es ayudarte a encontrar la confirmación donde un error fue introducido, de una manera efectiva.</p><h3 id="-c-mo-funciona-git-bisect">¿Cómo funciona <code>git bisect</code>?</h3><p><code>git bisect</code> primero te pide que marques una confirmación como "mala" (donde el error ocurre), y otra confirmación como "buena" (una sin el error). Luego, verifica una confirmación a medio camino entre estas dos confirmaciones, y luego te pide que identifiques la confirmación como "buena" o "mala". Este proceso se repite hasta que encuentres la primer confirmación "mala".</p><p>La clave aquí es usar la búsqueda binaria - mirando al punto a medio camino y decidir si es la nueva punta o el piso de la lista de confirmaciones, puedes encontrar la confirmación correcta de forma eficiente. Inclusive si tienes 10,000 confirmaciones que cazar, solamente toma un máximo de 13 pasos para encontrar la primer confirmación que introdujo el error.</p><h3 id="ejemplo-de-git-bisect">Ejemplo de <code>git bisect</code></h3><p>Para este ejemplo, usaré el repositorio en <a href="https://github.com/Omerr/bisect-exercise.git">https://github.com/Omerr/bisect-exercise.git</a>. Para crearlo, adaptaré el repositorio de código abierto <a href="https://github.com/bast/git-bisect-exercise">https://github.com/bast/git-bisect-exercise</a> (acorde a su licencia).</p><p>En este repositorio, tenemos un archivo python sencillo que se usa para calcular el valor de pi (el cual es aproximadamente <code>3.14</code>). Si ejecutas <code>python3 get_pi.py</code> en el <code>main</code>, sin embargo, obtendrás un resultado erróneo:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_1.png" class="kg-image" alt="A wrong result, we have a bug" width="600" height="400" loading="lazy"><figcaption>A wrong result, we have a bug</figcaption></figure><p>Esta rama consiste de más de 500 confirmaciones.</p><p>Encuentra la primer confirmación en esta rama usando:</p><pre><code class="language-bash">git log --oneline | tail -n 1
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_2.png" class="kg-image" alt="bisect_2" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git log --oneline | tail -n 1</code></figcaption></figure><p>Si ejecutas <code>checkout</code> para esta confirmación y ejecutas <code>python3 get_pi.py</code> nuevamente, el resultado es correcto:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/commit_1_pi.png" class="kg-image" alt="From the first commit, the result is valid" width="600" height="400" loading="lazy"><figcaption>From the first commit, the result is valid</figcaption></figure><p>Así que en algún lugar entre el <code>HEAD</code> y la confirmación <code>f0ea950</code>, un cambio fue introducido que resultó en esta salida errónea.</p><p>Para encontrarlo usando <code>git bisect</code>, <code>comienza</code> el proceso de bisect, y marca esta confirmación como "buena":</p><pre><code class="language-bash">git bisect start
git bisect good
</code></pre><p>Por defecto, <code>git bisect good</code> tomaría el <code>HEAD</code> como la confirmación "buena". Para marcar a <code>main</code> como "mala", puedes usar <code>git bisect bad main</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_3.png" class="kg-image" alt="bisect_3" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git bisect bad main</code></figcaption></figure><p><code>git bisect</code> comprobó el número de confirmación <code>251</code>, el "punto medio" de la rama <code>main</code>. ¿El estado de esta confirmación produce la saluda correcta o errónea?</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_4.png" class="kg-image" alt="Trying again..." width="600" height="400" loading="lazy"><figcaption>Trying again...</figcaption></figure><p>Todavía obtenemos la salida errónea, lo cual significa que podemos descartar las confirmaciones <code>252</code> hasta el <code>500</code> (y confirmaciones adicionales después de ese), y acortar nuestra búsqueda desde la confirmación <code>2</code> hasta el <code>251</code>. Marca a éste como "mala":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_5.png" class="kg-image" alt="Mark as " width="600" height="400" loading="lazy"><figcaption>Mark as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">bad</code></figcaption></figure><p><code>git bisect</code> comprobó la confirmación "media" (número <code>126</code>), y ejecutando el código nuevamente resulta en la respuesta, ¡correcta! Esto significa que esta confirmación es "buena", y que la primer confirmación "mala" está en algún lugar entre <code>127</code> y <code>251</code>. Márcalo como "buena".</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/bisect_6.png" class="kg-image" alt="Mark as " width="600" height="400" loading="lazy"><figcaption>Mark as <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">good</code></figcaption></figure><p>Genial, <code>git bisect</code> nos toma a la confirmación <code>188</code>, ya que esta es la confirmación "media" entre <code>127</code> y <code>251</code>. Al ejecutar el código nuevamente, puedes ver que el resultado es incorrecto, así que este es en realidad una confirmación "mala", lo que significa que la primer confirmación defectuosa se encuentre en algún lugar entre <code>127</code> y <code>188</code>. Como puedes ver, <code>git bisect</code> achica el espacio de búsqueda a la mitad en cada iteración.</p><p>Vamos, ahora es tu turno - ¡continúa desde aquí! Prueba el resultado de <code>python3 get_pi.py</code> y usa <code>git bisect good</code> o <code>git bisect bad</code> para marcar la confirmación según sea el caso. ¿Cuál es la confirmación defectuosa?</p><p>Cuando estés listo, usa <code>git bisect reset</code> para detener el proceso bisect.</p><h3 id="git-bisect-autom-tico"><code>git bisect</code> automático</h3><p>En el ejemplo previo, podrías simplemente ejecutar <code>pytho3 get_pi.py</code> y verificar el resultado. En otras veces, el proceso de validar si una cierta confirmación es "buena" o "mala" puede ser tramposo, propenso a errores, o solo lleva mucho tiempo.</p><p>Es posible automatizar el proceso de <code>git bisect</code> al crear código que debería ser ejecutado en cada iteración, devolviendo <code>0</code> cuando la confirmación actual es "buena", y un valor entre <code>1-127</code> (inclusivo), excepto <code>125</code>, si debería ser considerada "mala".</p><p>La sintaxis es:</p><pre><code class="language-bash">git bisect run my_script arguments
</code></pre><p>Ya que este libro no trata sobre programación y no se asume que conoces un lenguaje de programación específico, no mostraré un ejemplo de la implementación <code>my_script</code>. El archivo <code>README.md</code> en el repositorio usado en este capítulo (<a href="https://github.com/Omerr/bisect-exercise.git">https://github.com/Omerr/bisect-exercise.git</a>) incluye un ejemplo para un script que puedes ejecutar con <code>git bisect run</code> para encontrar automáticamente la confirmación defectuosa para el ejemplo previo.</p><!--kg-card-begin: html--><h2 id="cap-14">Capítulo 14 - Otros comandos útiles</h2><!--kg-card-end: html--><p>Este capítulo resalta algunos comandos que ya han sido mencionados en los capítulos anteriores. Los estoy poniendo aquí juntos así puedes revisarlos como una referencia cuando sea necesario.</p><h3 id="git-cherry-pick"><strong><code>git cherry-pick</code></strong></h3><p>Introducido en el <a href="#cap-8">capítulo 8</a>, este comando toma una confirmación dada, calcula el <strong>parche</strong> que esta confirmación introduce al calcular la diferencia entre la confirmación del antecesor y la confirmación misma, y luego <code>git bisect</code> "repite" esta diferencia. Es como "copiar-pegar" una confirmación, es decir, el diff de esta confirmación introducida.</p><p>En el <a href="#cap-8">capítulo 8</a> consideramos la diferencia introducida por el "Commit 5" (usando <code>git diff main &lt;SHA_OF_COMMIT_5&gt;</code>):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5-1.png" class="kg-image" alt="Running  to observe the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy"><figcaption>Running <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> to observe the patch introduced by "Commit 5"</figcaption></figure><p>Puedes ver que en esta confirmación, John comenzó a trabajar en una canción llamada "Lucy in the Sky with Diamonds":</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_diff_main_commit_5_output-1.png" class="kg-image" alt="The output of  - the patch introduced by &quot;Commit 5&quot;" width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git diff</code> - the patch introduced by "Commit 5"</figcaption></figure><p>Como recordatorio, también puedes usar el comando <code>git show</code> para obtener la misma salida:</p><pre><code class="language-bash">git show &lt;SHA_OF_COMMIT_5&gt;
</code></pre><p>Ahora, si haces <code>cherry-pick</code> a esta confirmación, introducirás <strong>este cambio</strong> específicamente, en la rama activa. Puedes cambiar a la rama <code>main</code>:</p><pre><code class="language-bash">git checkout main (or git switch main)
</code></pre><p>Y crear otra rama:</p><pre><code class="language-bash">git checkout -b my_branch (or git switch -c my_branch)
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/create_my_branch-1.png" class="kg-image" alt="Creating  that branches from " width="600" height="400" loading="lazy"><figcaption>Creating <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_branch</code> that branches from <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Luego, haz <code>cherry-pick</code> al "Commit 5":</p><pre><code class="language-bash">git cherry-pick &lt;SHA_OF_COMMIT_5&gt;
</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/cherry_pick_commit_5-1.png" class="kg-image" alt="Using  to apply the changes introduced in &quot;Commit 5&quot; onto " width="600" height="400" loading="lazy"><figcaption>Using <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">cherry-pick</code> to apply the changes introduced in "Commit 5" onto <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">main</code></figcaption></figure><p>Considera el log (salida de <code>git lol</code>):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_lol_commit_5-1.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git lol</code></figcaption></figure><p>Parece que <em>copiaste-pegaste</em> a "Commit 5". Recuerda que inclusive tiene el mismo mensaje de confirmación, e introduce los mismos cambios, e inclusive apunta al mismo objeto árbol como el "Commit 5" original en este caso - todavía es un objeto de confirmación distinto, ya que fue creado con una marca de tiempo distinto.</p><p>Mirando a los cambios, usando <code>git show HEAD</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/git_show_HEAD-3.png" class="kg-image" alt="The output of " width="600" height="400" loading="lazy"><figcaption>The output of <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git show HEAD</code></figcaption></figure><p>Son los mismos como los de "Commit 5".</p><h3 id="git-revert-1"><strong><code>git revert</code></strong></h3><p><code>git revert</code> es esencialmente la reversa de <code>git cherry-pick</code>, introducido en el <a href="#cap-10">capítulo 10</a>. Este comando toma la confirmación con el que le estás proveyendo y calcula el diff desde su confirmación antecesora, así como <code>git cherry-pick</code>, pero esta vez, calcula los cambios de <em>reversa</em>. Eso es, si en la confirmación especificada agregaste una línea, la reversa eliminaría la línea, y vice versa.</p><h3 id="git-add-p"><strong><code>git add -p</code></strong></h3><p>Poniendo en el área de preparación los cambios es una parte integral de introducir cambios a Git. A veces, deseas poner en el área de preparación todos los cambios juntos (con <code>git add .</code>), o tal vez poner en stage todos los cambios de un archivo específico (usando <code>git add &lt;file_path&gt;</code>). Aunque hay veces donde sería conveniente poner en stage solamente ciertas partes de los archivos modificados.</p><p>En el <a href="#cap-6">capítulo 6</a>, introdujimos <code>git add -p</code>. Este comando te permite poner en stage ciertas partes de los archivos, al separarlos en pequeños trozos (<code>p</code> significa <code>parche</code>). Por ejemplo, digamos que tienes este archivo, <code>my_file.py</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/my_file_py_1.png" class="kg-image" alt="my_file_py_1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_file.py</code></figcaption></figure><p>Luego modificas este archivo - al cambiar el texto dentro de <code>function_1</code>, y también agregando una nueva función, <code>function_5</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/my_file_py_2.png" class="kg-image" alt=" after the changes" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">my_file.py</code> after the changes</figcaption></figure><p>Si usaste <code>git add my_file.py</code> a este punto, pondrías en el área de preparación ambos de estos cambios juntos. En caso de que quieras separarlos en confirmaciones distintas, podrías usar <code>git add -p</code>, el cual separa estos dos cambios y te pregunta sobre cada uno como un pedazo independiente:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p_1.png" class="kg-image" alt="add_p_1" width="600" height="400" loading="lazy"><figcaption><code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">git add -p</code></figcaption></figure><p>Al tipear <code>?</code>, puedes ver qué significan cada opción distinta:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p_2.png" class="kg-image" alt="Using a  to get a description of the different options" width="600" height="400" loading="lazy"><figcaption>Using a <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">?</code> to get a description of the different options</figcaption></figure><p>En este caso, digamos que solamente queremos poner en el área de preparación el cambio introduciendo <code>function_5</code>. No queremos poner en el área de preparación el cambio de <code>function_1</code>, así que seleccionamos <code>n</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/12/add_p_3.png" class="kg-image" alt="Not staging the change to " width="600" height="400" loading="lazy"><figcaption>Not staging the change to <code style="box-sizing: inherit; margin: 0px; padding: 0px 5px 2px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 400 !important; font-stretch: inherit; line-height: 1em; font-family: &quot;Roboto Mono&quot;, monospace; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 0.8em; vertical-align: baseline; background: var(--gray15);">function_1</code></figcaption></figure><p>Luego, nos aparece una ventana para el segundo cambio - el que introduce <code>function_5</code>. Queremos poner en el área de preparación este pedazo, así podemos tipear <code>y</code>.</p><!--kg-card-begin: html--><h1 id="resumen">Resumen</h1><!--kg-card-end: html--><p>Bueno, ¡esto fue divertido!</p><p>¿Puedes creer cuánto has aprendido?</p><p>En la <strong>Parte 1</strong> aprendiste sobre blobs, árboles y confirmaciones.</p><p>Luego aprendiste sobre las <strong>ramas</strong>, viendo que no son mas que una referencia nombrada a una confirmación.</p><p>Aprendiste el proceso de registrar cambios en Git, y que involucra el <strong>directorio de trabajo</strong>, el <strong>área de preparación (índice)</strong>, y el <strong>repositorio</strong>.</p><p>Luego - creaste un nuevo repositorio desde cero, al usar <code>echo</code> y comandos de bajo nivel tales como <code>git hash-object</code>. Creaste un blob, un árbol, y un objeto de confirmación apuntando a ese árbol.</p><p>En la <strong>Parte 2</strong> aprendiste sobre hacer ramas e integrar cambios en Git.</p><p>Aprendiste lo que es un <strong>diff</strong>, y la diferencia entre un diff y un <strong>parche</strong>. También aprendiste cómo se construye la salida de <code>git diff</code>.</p><p>Luego, tuviste un vistazo extensivo sobre fusionar con Git, específicamente entendiendo el algoritmo de fusión de tres vías. Entendiste cuándo los <strong>conflictos de fusión</strong> ocurren, cuándo Git los puede resolver automáticamente, y cómo los resuelve de forma manual cuando sea necesario.</p><p>Viste que <code>git rebase</code> es poderoso - pero también es bastante sencillo una vez que entiendes lo que hace. Entendiste las diferencias entre fusionar y hacer rebase, y cuando deberías usar cada uno.</p><p>En la <strong>Parte 3</strong> aprendiste cómo <strong>deshacer cambios</strong> en Git - especialmente cuando las cosas van mal. Aprendiste cómo usar un par de herramientas, como <code>git reset</code>, <code>git commit --ammend</code>, <code>git revert</code>, <code>git reflog</code> (y <code>git log -g</code>).</p><p>La herramienta más importante, aún más importante que las herramientas que listé, es limpiar la situación actual vs el que se desea. Créeme en esta, hará que cada situación parezca menos intimidante y la solución más claro.</p><p>En la <strong>Parte 4</strong> adquiriste herramientas poderosas adicionales, como diferentes conmutadores de <code>git log</code>, <code>git bisect</code>, <code>git cherry-pick</code>, <code>git revert</code> y <code>git add -p</code>.</p><p>Wow, ¡deberías sentirte orgulloso!</p><h3 id="un-mensaje-de-m-para-t-">Un mensaje de mí para tí</h3><p>En efecto, eso fue divertido, pero todas las cosas deben pasar. Terminaste de leer este libro, pero no significa que tu jornada de aprendizaje termina aquí.</p><p>Lo que has adquirido, más que cualquier herramienta específica, es intuición y entendimiento de cómo opera Git, y cómo pensar sobre varias operaciones en Git. Sigue investigando, leyendo, y usando Git. Estoy seguro que serás capaz de enseñarme algo nuevo, y por todos los medios - hazlo por favor.</p><p>Si te gustó este libro, por favor compártelo con más personas.</p><p>Si quieres leer más de mis artículos de Git y manuales, aquí están:</p><ol><li><a href="https://www.freecodecamp.org/news/git-rebase-handbook/">The Git Rebase Handbook</a></li><li><a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">The Git Merge Handbook</a></li><li><a href="https://www.freecodecamp.org/news/git-diff-and-patch/">The Git Diff and Patch Handbook</a></li><li><a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">Git Internals - Objects, Branches, and How to Create a Repo</a></li><li><a href="https://www.freecodecamp.org/news/save-the-day-with-git-reset/">Git Reset Command Explained</a></li></ol><h3 id="reconocimientos">Reconocimientos</h3><p>Mucha gente ayudó en hacer este libro lo mejor que se podía. Entre ellos, fui afortunado de tener muchos lectores beta que me dieron comentarios así podía mejorar el libro. Específicamente, me gustaría agradecer a Jason S. Shapiro, Anna Łapińska, C. Bruce Hilbert, y Jonathon McKitrick por sus revisiones exhaustivas.</p><p>Abbey Rennemeyer ha sido una editor maravillosa. Después que ha revisado mis publicaciones para freeCodeCamp por tres años, fue claro que le pidiera que fuera el editor de este libro también. Ella me ayudó en mejorar el libro de muchas formas, y estoy agradecido por su ayuda.</p><p>Quincy Larson fundó la maravillosa comunidad en freeCodeCamp, me motivó por medio de emails y discusiones de cara a cara. Le agradezco por generar esta increíble comunidad, y por su amistad.</p><p>Estefania Cassingena Navone diseñó la portada de este libro. Estoy agradecido por su trabajo profesional y su paciencia con mis pedidos y perfeccionismo.</p><p>El sitio web de Daphne Gray-Grant, <a href="https://www.publicationcoach.com/">"Publication Coach"</a>, me dio inspiración así también como consejos técnicos que me ayudó mucho con mi proceso de escritura.</p><h3 id="si-deseas-apoyar-este-libro">Si deseas apoyar este libro</h3><p>Si te gustaría apoyar este libro, puedes comprar la <a href="https://www.amazon.com/dp/B0CQXTJ5V5">versión en papel</a>, un <a href="https://www.buymeacoffee.com/omerr/e/197232">versión E-Book (libro electrónico)</a>, o <a href="https://www.buymeacoffee.com/omerr">comprarme un café</a>. ¡Gracias!</p><h3 id="cont-ctame">Contáctame</h3><p>Este libro ha sido creado para ayudarte y gente como tú aprenda, entienda Git, y aplique sus conocimientos en la vida real.</p><p>Bien al principio, pedí comentarios y fui afortunado de recibirlo de gente estupenda (mencionado en los Reconocimientos) para asegurar que el libro alcanzara estos objetivos. Si te gustó algo de este libro, sentiste que algo estaba faltando o necesitaba mejorar - me encantaría que me lo dijeras. Por favor háblame en: <code>gitting.things@gmail.com</code>.</p><p>Gracias por aprender y permitirme ser parte de tu jornada.</p><p>- Omer Rosenbaum</p><!--kg-card-begin: html--><h1 id="apendices">Apéndices</h1><!--kg-card-end: html--><h2 id="referencias-adicionales-por-parte">Referencias Adicionales - Por Parte</h2><p>(Nota - esta es una lista corta. Puedes encontrar una lista más larga de referencias en la versión <a href="https://www.buymeacoffee.com/omerr/e/197232">E-Book</a> o la <a href="https://www.amazon.com/dp/B0CQXTJ5V5">impresa</a>.)</p><h3 id="parte-1"><em>Parte 1</em></h3><ul><li>Lista de reproducción de Youtube sobre los Componentes Internos de Git - por Brief:<br><a href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7">https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7</a></li><li>Conferencia de Tim Berglund - "Git From the Bits Up":<br><a href="https://www.youtube.com/watch?v=MYP56QJpDr4">https://www.youtube.com/watch?v=MYP56QJpDr4</a></li><li>como prometí, la documentación: Git for the confused:<br><a href="https://www.gelato.unsw.edu.au/archives/git/0512/13748.html">https://www.gelato.unsw.edu.au/archives/git/0512/13748.html</a></li></ul><h3 id="parte-2">Parte 2</h3><h4 id="diffs-y-parches">Diffs y Parches</h4><p>Algoritmos de Diffs de Git:</p><ul><li><a href="https://es.wikipedia.org/wiki/Diff">https://es.wikipedia.org/wiki/Diff</a></li></ul><p>El algoritmo de diff más predeterminado en Git es Myers:</p><ul><li><a href="https://www.nathaniel.ai/myers-diff/">https://www.nathaniel.ai/myers-diff/</a></li><li><a href="https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/">https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/</a></li><li><a href="https://blog.robertelder.org/diff-algorithm/">https://blog.robertelder.org/diff-algorithm/</a></li></ul><h4 id="git-merge"><strong>Git Merge</strong></h4><ul><li><a href="https://git-scm.com/book/es/v2/Herramientas-de-Git-Fusi%C3%B3n-Avanzada">https://git-scm.com/book/es/v2/Herramientas-de-Git-Fusión-Avanzada</a></li><li><a href="https://blog.plasticscm.com/2010/11/live-to-merge-merge-to-live.html">https://blog.plasticscm.com/2010/11/live-to-merge-merge-to-live.html</a></li></ul><h4 id="git-rebase"><strong>Git Rebase</strong></h4><ul><li><a href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/7-branching-and-the-power-of-rebase.html">https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/7-branching-and-the-power-of-rebase.html</a></li><li><a href="https://git-scm.com/book/es/v2/Ramificaciones-en-Git-Reorganizar-el-Trabajo-Realizado">https://git-scm.com/book/es/v2/Ramificaciones-en-Git-Reorganizar-el-Trabajo-Realizado</a></li></ul><h4 id="recursos-relacionados-a-los-beatles-1"><strong>Recursos relacionados a los Beatles</strong></h4><ul><li><a href="https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/">https://www.the-paulmccartney-project.com/song/ive-got-a-feeling/</a></li><li><a href="https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/">https://www.cheatsheet.com/entertainment/did-john-lennon-or-paul-mccartney-write-the-classic-a-day-in-the-life.html/</a></li><li><a href="http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html">http://lifeofthebeatles.blogspot.com/2009/06/ive-got-feeling-lyrics.html</a></li></ul><h3 id="part-3"><strong>Part 3</strong></h3><ul><li><a href="https://git-scm.com/book/es/v2/Herramientas-de-Git-Reiniciar-Desmitificado">https://git-scm.com/book/es/v2/Herramientas-de-Git-Reiniciar-Desmitificado</a></li><li><a href="https://www.edureka.co/blog/common-git-mistakes/">https://www.edureka.co/blog/common-git-mistakes/</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Error: failed to push some refs to – ¿Cómo arreglamos esto en Git? ]]>
                </title>
                <description>
                    <![CDATA[ Cuando colaboras con otros desarrolladores utilizando Git, es posible que te encuentres con el error: failed to push some refs to [remote repo]. Este error ocurre principalmente cuando intentas enviar tus cambios locales a GitHub, mientras que el repositorio local aún no ha sido actualizado con los cambios realizados en ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/error-failed-to-push-some-refs-to-como-arreglamos-esto-en-git/</link>
                <guid isPermaLink="false">6609aabf6e403a04017ccf7b</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrés  Torres ]]>
                </dc:creator>
                <pubDate>Tue, 23 Apr 2024 13:48:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/03/roman-synkevych-wX2L8L-fGeA-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/error-failed-to-push-some-refs-to-how-to-fix-in-git/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Error: failed to push some refs to – How to Fix in Git</a>
      </p><p>Cuando colaboras con otros desarrolladores utilizando Git, es posible que te encuentres con el error:<strong> </strong><code>failed to push some refs to [remote repo]</code><strong>.</strong></p><p>Este error ocurre principalmente cuando intentas enviar tus cambios locales a GitHub, mientras que el repositorio local aún no ha sido actualizado con los cambios realizados en el repositorio remoto.</p><p>Entonces, Git está tratando de decirte que actualices el repositorio local con los cambios actuales en el remoto antes de enviar tus propios cambios. Esto es necesario para que no sobrescribas los cambios hechos por otros.</p><p>Discutiremos dos posibles formas de solucionar este error en las secciones que siguen.</p><h2 id="-c-mo-solucionar-el-error-failed-to-push-some-refs-to-en-git">¿Cómo solucionar el error: <code>failed to push some refs to</code> en Git?</h2><p>Podemos solucionar el error: <code>failed to push some refs to [remote repo]</code> en Git usando los comandos <code>git pull origin [branch]</code> o <code>git pull --rebase origin [branch]</code>. En la mayoría de los casos, el último comando soluciona el error.</p><p>Veamos cómo puedes usar los comandos mencionados anteriormente.</p><h2 id="-c-mo-solucionar-el-error-failed-to-push-some-refs-to-en-git-usando-git-pull">¿Cómo solucionar el error: <code>failed to push some refs to</code> en Git usando <code>git pull</code>?</h2><p>Enviar una solicitud de extracción (<em>pull request</em>) significa "buscar" nuevos cambios realizados en el repositorio remoto y fusionarlos con el repositorio local.</p><p>Una vez que se haya completado la fusión, puedes enviar tus propios cambios de código a GitHub.</p><p>En nuestro caso, estamos tratando de deshacernos del error: <code>failed to push some refs to [remote repo]</code> enviando una solicitud de extracción.</p><p>Así es como puedes hacerlo:</p><pre><code class="language-bash">git pull origin main</code></pre><p>Si estás trabajando con una rama diferente, entonces tendrías que reemplazar <code>main</code> en el ejemplo anterior con el nombre de tu rama.</p><p>Solo ten en cuenta que existen posibilidades de fallo al usar este comando para sincronizar tus repositorios remotos y locales y así deshacerte del error. <strong>Si la solicitud tiene éxito</strong>, entonces continúa y ejecuta el siguiente comando para enviar tus propios cambios:</p><pre><code class="language-bash">git push -u origin main</code></pre><p><strong>Si el error persiste</strong>, obtendrás un error que dirá: <code>fatal: refusing to merge unrelated histories</code>. En este caso, utiliza la solución disponible en la siguiente sección. </p><h2 id="-c-mo-arreglar-el-error-failed-to-push-some-refs-to-en-git-usando-git-pull-rebase">¿Cómo arreglar el <code>error:failed to push some refs to</code> en Git usando <code>git pull --rebase</code>?</h2><p>El comando <code>git pull --rebase</code> &nbsp;es útil en situaciones donde tu rama local es un <strong><em><a href="https://www.freecodecamp.org/espanol/news/el-comando-git-commit-explicado/">commit </a></em></strong>por detrás de la rama remota</p><p>Para arreglar el error, emplea los siguientes comandos:</p><pre><code class="language-bash">git pull --rebase origin main

git push -u origin main </code></pre><p>Si el primer comando anterior se ejecuta con éxito, deberías recibir una respuesta que diga: <code>Successfully rebased and updated refs/heads/main</code>.</p><p>El segundo comando envía el estado actual de tu repositorio local a la rama remota.</p><h2 id="resumen">Resumen</h2><p>En este artículo, discutimos el error <code>error: failed to push some refs to [remote repo]</code>.</p><p>Este error ocurre cuando intentas enviar tus cambios locales al repositorio remoto sin antes actualizar tu repositorio local con los cambios más recientes del repositorio remoto.</p><p>Exploramos dos comandos para abordar este error: los comandos <code>git pull origin [branch]</code> y <code>git pull --rebase origin [branch]</code>.</p><p>Espero que esta información te ayude a resolver el error.</p><p>¡Feliz programación!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ ¿Cómo crear y sincronizar repositorios con Git y GitHub? ]]>
                </title>
                <description>
                    <![CDATA[ > Nota del traductor: Este post contiene muchos videos que sirven para complementar la información del mismo, los videos están en inglés pero es posible verlos con los subtítulos autogenerados que proporciona YouTube. Trabajar con Git y GitHub suele ser una parte esencial de sus tareas diarias de programación. En ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-y-sincronizar-repositorios-con-git-y-github/</link>
                <guid isPermaLink="false">660aeb236e403a04017cd01a</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Tue, 23 Apr 2024 01:09:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/04/thumbnail-4-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/create-and-sync-git-and-github-repositories/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Create and Sync Git and GitHub Repositories</a>
      </p><blockquote><strong>Nota del traductor: </strong>Este post contiene muchos videos que sirven para complementar la información del mismo, los videos están en inglés pero es posible verlos con los subtítulos autogenerados que proporciona YouTube.</blockquote><p>Trabajar con Git y GitHub suele ser una parte esencial de sus tareas diarias de programación. En muchos casos, necesitarás tanto un repositorio Git local como un repositorio GitHub remoto para un proyecto.</p><ul><li>Con el <strong>repositorio local</strong>, trabajas en tu propia copia del proyecto. Usted realiza y prueba los cambios de forma independiente antes de enviarlos al repositorio remoto para que otros los revisen y combinen.</li><li>El<strong> repositorio remoto</strong> se usa para almacenamiento externo y para compartir el proyecto con otros.</li></ul><p>Este tutorial se divide en 2 escenarios:</p><ul><li><strong>Local primero</strong>: primero crea un repositorio local y envía su código a ese repositorio. Más adelante, creará un repositorio remoto. Con los dos repositorios instalados, querrás mantenerlos sincronizados. Este escenario es común si ha iniciado un proyecto por su cuenta y luego desea compartirlo.</li><li><strong>Remoto primero</strong>: en este escenario, existe un repositorio remoto y desea trabajar con ese código. Utilice ese repositorio remoto para crear su repositorio local para poder realizar y probar cambios localmente. Con los dos repositorios instalados, querrás mantenerlos sincronizados. Este escenario es común si está trabajando en un equipo o en un proyecto de código abierto que tiene un repositorio de GitHub existente.</li></ul><p>Esto es lo que trataremos en este tutorial:</p><ol><li>¿<a href="#significan">Qué significan Git, GitHub y Repositorio?</a></li><li>¿<a href="#instalar">Cómo instalar Git y GitHub</a>?</li><li><a href="#primero">Escenario 1: Primero local</a></li><li><a href="#crear">¿Cómo crear un repositorio local?</a></li><li><a href="#confirmar">¿Cómo confirmar archivos en el repositorio local?</a></li><li><a href="#remoto">¿Cómo crear un repositorio remoto de GitHub?</a></li><li><a href="#conectar">¿Cómo conectar Git y Github?</a></li><li><a href="#sincronizar">¿Cómo sincronizar los repositorios local y remoto?</a></li><li><a href="#escenario-2">Escenario 2: Primero remoto</a></li><li><a href="#clonar">¿Cómo clonar un repositorio</a>?</li><li><a href="#terminando">Terminando</a></li></ol><p>Comencemos con una breve introducción a los términos que estamos usando y luego pasemos a nuestros dos escenarios.</p><!--kg-card-begin: html--><h2 id="significan">¿Qué significan Git, GitHub y repositorio?</h2><!--kg-card-end: html--><p>Un repositorio, o "repo" para abreviar, almacena y rastrea las versiones de los archivos de su proyecto. A medida que realiza cambios en esos archivos, confirma (o copia) esos archivos en el repositorio para su custodia. El repositorio mantiene una lista de todos los cambios confirmados, denominada<strong> historial de confirmaciones </strong>o <strong>commit history</strong> en inglés. </p><p><strong>Git </strong>es un sistema de control de versiones popular y ampliamente utilizado para crear y trabajar con repositorios. Se ejecuta localmente en su computadora. Puedes descargar, instalar y usar Git en cualquier plataforma sin ningún costo ni tarifa. Con Git, creas un repositorio local en la carpeta de trabajo de tu proyecto y Git almacena el <strong>historial de confirmación</strong> de los archivos en esa carpeta.</p><p>Si eres nuevo en Git, considera ver este vídeo como introducción:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/hfOeWgWp__E?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Understanding Git (Clip 2): Gentle Introduction to Git and GitHub" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p><strong>GitHub </strong>es un sitio web que aloja repositorios remotos en Internet. Una cuenta básica de GitHub también es <strong>gratuita</strong>. Utilice GitHub para crear un repositorio remoto para su proyecto. Con un repositorio remoto, puede almacenar su código fuera del sitio, colaborar con otros, trabajar en proyectos de la empresa o de código abierto y mostrar su portafolio a posibles empleadores.</p><p>Si eres nuevo en GitHub, considera ver este vídeo como introducción:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/Uf2LLF7UKMw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Understanding GitHub (Clip 4): Gentle Introduction to Git and GitHub" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><p>Antes de saltar a nuestros escenarios, necesitamos instalar Git y crear una cuenta de GitHub.</p><!--kg-card-begin: html--><h2 div="instalar">¿Cómo instalar Git y GitHub?</h2><!--kg-card-end: html--><p>Si desea trabajar con los ejemplos presentados en este tutorial, existen algunos pasos preparatorios. Pero no dudes en pasar a la siguiente sección si ya tienes estas herramientas instaladas o prefieres leer este artículo sin codificar.</p><p>Primero, instala Git en tu computadora si aún no lo tienes. Para obtener instrucciones paso a paso sobre cómo instalar Git, vea la segunda parte de este video:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/Xzy-hSdNGOI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Installing VS Code and Git (Clip 14): Gentle Introduction to Git and GitHub" name="fitvid2"></iframe>
          </div>
        </div>
      </figure><p>A continuación, cree una cuenta de GitHub, si aún no tiene una. Este video proporciona instrucciones paso a paso sobre cómo crear una cuenta de GitHub:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/GrWL62j3gTU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Creating a GitHub Account (Clip 8): Gentle Introduction to Git and GitHub" name="fitvid3"></iframe>
          </div>
        </div>
      </figure><p>Por último, cree una carpeta de trabajo en su computadora (yo nombré <strong>mis recetas</strong> en mi carpeta de documentos). Luego cree dos archivos de texto simples en esa carpeta: <code>archivo1.txt</code> y <code>archivo2.txt</code>. Aunque estemos usando archivos de texto, el proceso de sincronización cubierto en este artículo es el mismo con cualquier tipo de archivos de código.</p><p>Ahora estamos listos para analizar nuestros dos escenarios: primero el local y primero el remoto.</p><!--kg-card-begin: html--><h2 id="primero">Escenario 1: Primero local</h2><!--kg-card-end: html--><p>Supongamos que desea crear un sitio web de recetas (o tal vez una aplicación) para recopilar y administrar recetas. Crea un repositorio local para poder rastrear fácilmente sus cambios en los archivos del proyecto.</p><p>Más tarde decide que también desea un repositorio remoto para mantener una copia de sus archivos fuera del sitio y compartir el proyecto con otros. Una vez que tenga el repositorio remoto, querrá mantener su repositorio local sincronizado con ese repositorio remoto.</p><p>Este escenario se muestra en la Figura 1:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure1-local-repo.png" class="kg-image" alt="Figure1-local-repo" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure1-local-repo.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure1-local-repo.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure1-local-repo.png 1557w" sizes="(min-width: 720px) 720px" width="1557" height="980" loading="lazy"><figcaption>Figura 1: creando un repositorio local primero.</figcaption></figure><p>Según los números de la Figura 1:</p><ol><li>Primero se crea el repositorio local, representado como un cuadro.</li><li>El repositorio remoto se crea con GitHub algún tiempo después.</li><li>Los dos repositorios se mantienen sincronizados.</li></ol><p>Repasemos estos pasos en detalle.</p><!--kg-card-begin: html--><h2 id="crear">¿Cómo crear un repositorio local?</h2><!--kg-card-end: html--><p>Ya preparamos una carpeta de trabajo y creamos dos archivos que son el comienzo de nuestro proyecto. </p><p>Para crear un <strong>repositorio local</strong> para ese proyecto, abra su terminal o símbolo del sistema y navegue hasta esa carpeta de trabajo. </p><p>Luego inicializa un nuevo repositorio Git usando el siguiente comando:</p><pre><code class="language-git">git init</code></pre><p>Este comando inicializa un nuevo repositorio Git en la carpeta actual. El proceso de inicialización crea una carpeta <code>.git</code> dentro de la carpeta del proyecto que almacena los archivos y datos del repositorio.</p><p>Esta carpeta <code>.git</code> puede estar oculta de forma predeterminada. En el Finder de Mac, use <code>Command + Mayús +.</code> (punto) para que aparezcan carpetas y archivos ocultos. En Windows, use la pestaña Ver del Explorador de archivos y marque Elementos Ocultos para mostrar carpetas y archivos ocultos.</p><p>¡Ahora tenemos un repositorio local! Agreguemos nuestros dos archivos de proyecto en ese repositorio.</p><!--kg-card-begin: html--><h2 id="confirmar">¿Cómo confirmar archivos en el repositorio local?</h2><!--kg-card-end: html--><p>Cada vez que creamos archivos nuevos, cambiamos archivos existentes o eliminamos archivos, enviamos esos cambios a nuestro repositorio local. Esto asegura que el repositorio rastree el estado actual de nuestro proyecto.</p><p>Enviar archivos a un repositorio local requiere dos pasos:</p><ol><li>Stage (Área de preparación)</li><li>Commit (Confirmación)</li></ol><p>Primero, agregue los archivos al área de preparación de Git:</p><pre><code class="language-git">git add .</code></pre><p>Le decimos a Git qué archivos queremos incluir en esa confirmación agregándolos a un área de preparación. La puesta en escena nos permite elegir selectivamente qué cambios incluir en una confirmación.</p><p>Utilizando el <code>.</code> (punto) agrega todos los archivos en la carpeta de trabajo (y sus subcarpetas) al área de preparación. Si solo desea agregar archivos específicos, puede enumerarlos.</p><p>A continuación, confirmamos los archivos preparados en el repositorio local:</p><pre><code>git commit -m "Confirmación inicial"</code></pre><p>Este comando envía los archivos en el área de preparación de Git al repositorio local.</p><p>La opción <code>-m</code> es para un mensaje de confirmación. Siga la <code>-m</code> con el mensaje, entre comillas. Asegúrese de definir un mensaje claro que describa los cambios que está realizando.</p><p>Para obtener más información sobre cómo definir excelentes mensajes de confirmación, vea este video:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/9UlmPCMZ4tc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Creating Great Git Commit Messages (Clip 13): Gentle Introduction to GitHub for Beginners" name="fitvid4"></iframe>
          </div>
        </div>
      </figure><p>Después de estos pasos, el terminal aparece como se muestra a continuación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure2-git-init-1.png" class="kg-image" alt="Figure2-git-init-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure2-git-init-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure2-git-init-1.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure2-git-init-1.png 1355w" sizes="(min-width: 720px) 720px" width="1355" height="441" loading="lazy"><figcaption>Figura 2. Creación de un repositorio local, luego preparación y confirmación de los archivos del proyecto.</figcaption></figure><p>El comando <code>init</code> muestra un mensaje de estado que nos indica que creó un repositorio Git vacío.</p><p>El comando <code>add</code> no proporciona ningún resultado.</p><p>El comando <code>commit</code> muestra la rama en la que estamos ( <code>main</code> en este ejemplo), los primeros caracteres de la identificación de la confirmación y el mensaje de confirmación. Luego enumera los archivos modificados. En este ejemplo, se cambiaron 2 archivos y ambos fueron inserciones (archivos nuevos).</p><p>El número después del modo de creación indica el tipo de archivo y los permisos. <code>100644</code> significa que se trata de archivos normales, no carpetas, con permisos de lectura y escritura del propietario.</p><p>Con nuestro repositorio local implementado, es hora de crear nuestro repositorio remoto.</p><!--kg-card-begin: html--><h2 id="remoto">¿Cómo crear un repositorio remoto en GitHub?</h2>
<!--kg-card-end: html--><p>Ahora crearemos un repositorio remoto en GitHub. Vaya al sitio web de GitHub en <a href="https://github.com/">www.github.com</a> e inicie sesión. Si no tiene una cuenta de GitHub, consulte la sección "Cómo instalar Git y GitHub" anteriormente en este tutorial para conocer los pasos para crear una cuenta.</p><p>Mire este video para ver el proceso de creación de un repositorio de GitHub:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/QuCdgrYph98?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Initializing a GitHub Repository (Clip 9): Gentle Introduction to Git and GitHub" name="fitvid5"></iframe>
          </div>
        </div>
      </figure><p>Después de iniciar sesión en GitHub, se le dirigirá a su panel personal. Su panel personal de GitHub proporciona información sobre sus repositorios y proyectos.</p><p>Si es la primera vez que creas un repositorio en GitHub, proporciona el botón <code>Crear Repositorio</code> para ayudarte a comenzar. Si ya ha estado usando GitHub, verá un botón <code>Nuevo</code> en su lugar.</p><p>En cualquier caso, al hacer clic en el botón se accede a la página <code>Crear un nuevo repositorio</code>, como se muestra en la Figura 3.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure3-create-new-repo.png" class="kg-image" alt="Figure3-create-new-repo" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure3-create-new-repo.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure3-create-new-repo.png 705w" width="705" height="1192" loading="lazy"><figcaption>Figura 3. Cree un nuevo repositorio remoto con GitHub.</figcaption></figure><p>Comience ingresando el nombre del repositorio. El nombre de un repositorio debe ser breve, pero descriptivo de su proyecto. Debe ser único dentro de su cuenta de GitHub. GitHub lo comprueba por ti.</p><p>Las convenciones generales para los nombres de los repositorios sugieren el uso de minúsculas. Si hay varias palabras, utilice guiones entre las palabras, como <code>libro- de-recetas</code>.</p><p>Llamé a mi repositorio de <code>recetas</code>. Y la flecha verde al lado del nombre significa que es único dentro de esta cuenta de GitHub.</p><p>Opcionalmente, puede proporcionar una descripción. Aquí es donde puedes poner más información sobre el repositorio, si lo deseas.</p><p>A continuación, tienes la opción de crear un repositorio público o privado. Si crea un repositorio público, cualquiera en Internet puede verlo. Pero sólo los colaboradores que tú elijas pueden comprometerse con ello. Así que no tienes que preocuparte de que extraños cambien tus archivos. Si crea un repositorio privado, será privado excepto para los colaboradores elegidos.</p><p>Considere hacer públicos sus repositorios para compartir su código con otros, a menos que su código sea propietario.</p><p>Luego tiene la opción de crear un archivo <code>Readme</code> (Léame). Un archivo <code>Readme</code> les da a quienes miran un repositorio una idea de para qué sirve ese repositorio e instrucciones sobre cómo usarlo. Marque la casilla para agregar un archivo <code>Readme</code>.</p><p>Una plantilla <code>.gitignore</code> le ayuda a identificar qué archivos de su carpeta de trabajo no desea incluir en el seguimiento de versiones de Git. Para una aplicación, no desea incluir archivos de compilación intermedios, por ejemplo, ya que suelen ser grandes y pueden reconstruirse fácilmente a partir de archivos fuente. Para este proyecto simple, no necesitamos una plantilla <code>.gitignore</code>.</p><p>Lo siguiente es elegir una licencia. Una licencia permite a otros desarrolladores saber qué pueden hacer con el código de su repositorio. Por ejemplo, si podrían utilizar libremente el código para sus propios proyectos.</p><p>GitHub proporciona un sitio web para ayudarle a tomar una decisión. Haga clic en obtener más información en la opción Elegir una licencia para ir a la documentación de GitHub. En la página de documentación, encontrará un enlace de <code>choosealicense.com</code> para obtener ayuda para seleccionar qué licencia es adecuada para su proyecto.</p><p>Para mi repositorio de recetas, haré que la licencia sea simple y permisiva y elegiré una licencia MIT.</p><p>Cierre la pestaña del navegador de documentación, regrese a la pestaña GitHub y seleccione la licencia deseada de la lista.</p><p>Justo encima del botón <code>Crear Repositorio</code>, GitHub proporciona un resumen para que puedas verificar la acción que estás a punto de realizar. Luego haga clic en <code>Crear Repositorio</code>.</p><p>Crea el repositorio como se muestra en la Figura 4. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure4-github-repo.png" class="kg-image" alt="Figure4-github-repo" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure4-github-repo.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure4-github-repo.png 833w" sizes="(min-width: 720px) 720px" width="833" height="677" loading="lazy"><figcaption>Figura 4. Nuestro repositorio remoto de GitHub.</figcaption></figure><p>Como puede ver en la Figura 4, ¡GitHub realizó automáticamente nuestra primera confirmación! Esa confirmación es una instantánea de los dos archivos que le dijimos que agregara al repositorio: nuestro archivo de licencia y el archivo Léame. Estableció un mensaje de confirmación de "compromiso inicial". Y de forma predeterminada, GitHub muestra el contenido de nuestro archivo Léame.</p><p>En este punto, nuestro repositorio local contiene nuestros dos archivos de texto. Y nuestro repositorio remoto contiene nuestra licencia y archivos Léame. Queremos que los dos repositorios coincidan.</p><!--kg-card-begin: html--><h2 id="conectar">¿Cómo conectar Git y Github?</h2><!--kg-card-end: html--><p>Antes de poder sincronizar los repositorios local y remoto, debe establecer una conexión entre ellos. Básicamente, necesita indicarle a su repositorio local dónde encontrar el repositorio remoto. </p><p>Identificamos un repositorio remoto por su URL. En la Figura 4 anterior, observe el botón verde <code>Código</code>. Haga clic en ese botón para ver detalles sobre el repositorio (Figura 5).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure5-repo-link.png" class="kg-image" alt="Figure5-repo-link" width="516" height="476" loading="lazy"><figcaption>Figura 5. Encontrar la URL del repositorio de GitHub.</figcaption></figure><p>Asegúrese de que la pestaña HTTPS esté seleccionada y haga clic en el icono de copiar para copiar la URL de este repositorio de GitHub.</p><p>De vuelta en la ventana de comandos de su máquina local, agregue el repositorio remoto al repositorio local. Luego enumere los controles remotos para confirmar que se creó el control remoto.</p><pre><code class="language-git">git remote add recipes-gh https://github.com/DeborahK/recipes.git
git remote</code></pre><p>El comando <code>remote add</code> agrega el repositorio remoto en la URL proporcionada. Y le permite asignar un alias para ese repositorio para que no tenga que escribir la URL cuando haga referencia al repositorio remoto.</p><p>Un alias común para el repositorio remoto es <code>origin</code>, pero algunos encuentran ese nombre un poco confuso, especialmente si el repositorio remoto no fue el origen del proyecto. En ese caso, a veces uso el nombre del repositorio local con <code>-gh</code> (para GitHub) como apodo del repositorio remoto, para poder recordarlo fácilmente. Pero siéntete libre de usar cualquier nombre.</p><p>El comando <code>remote</code> por sí solo muestra la lista de controles remotos que conoce su repositorio local. Así es como se ve:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure6-add-remote.png" class="kg-image" alt="Figure6-add-remote" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure6-add-remote.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure6-add-remote.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/04/Figure6-add-remote.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure6-add-remote.png 1739w" sizes="(min-width: 720px) 720px" width="1739" height="260" loading="lazy"><figcaption>Figura 6. Estableciendo una conexión con el repositorio remoto.</figcaption></figure><p>Nuestro repositorio Git local ahora sabe dónde encontrar su repositorio remoto asociado. El siguiente paso es sincronizar los repositorios para que coincida su historial de confirmaciones.</p><!--kg-card-begin: html--><h2 id="sincronizar">¿Cómo sincronizar un Repositorio Local con un Repositorio Remoto?</h2><!--kg-card-end: html--><p>Para sincronizar nuestros repositorios local y remoto, primero recuperamos el historial de cambios del repositorio remoto y lo fusionamos en nuestro repositorio local usando el comando <code>pull</code>. Luego enviamos nuestro historial de cambios local al repositorio remoto usando el comando <code>push</code>.</p><p>Si prefieres sincronizar repositorios usando VS Code, mira este video:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/5vYPLUMP6dg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Committing and Syncing Files using VS Code (Clip 16): Gentle Introduction to Git and GitHub" name="fitvid6"></iframe>
          </div>
        </div>
      </figure><p>Para extraer del repositorio remoto y fusionarlo con nuestro repositorio local usando un comando de Git:</p><pre><code class="language-git">git pull recetas-gh main --allow-unrelated-histories

dir		// En Windows
o
ls		// En Mac</code></pre><p>El comando <code>pull</code> requiere el alias del repositorio remoto (<code>recetas-gh</code>) y el nombre de la rama. Como no hemos creado ninguna rama adicional, especificamos la rama principal ( <code>main</code> ).</p><p>La bandera <code>--allow-un related-histories</code> es necesaria la primera vez que extraemos porque queremos fusionar dos repositorios que se crearon por separado y actualmente no comparten un historial relacionado.</p><p>Después de la primera vez, el comando <code>git pull</code> no requiere esa bandera:</p><pre><code class="language-git">git pull recetas-gh main</code></pre><p>En cualquier caso, el comando <code>pull</code> busca la URL apropiada para el repositorio remoto usando el apodo proporcionado ( <code>recetas-gh</code> ).</p><p>Luego recupera el historial de confirmaciones y otros datos de la rama especificada ( <code>main</code> ) del repositorio remoto que no está en esa rama del repositorio local.</p><p>Fusiona esos datos en el repositorio local. Si hay algún conflicto, deberá resolverlo manualmente antes de que Git combine los cambios.</p><p>Por último, actualiza la carpeta de trabajo local con todos los archivos de la confirmación más reciente.</p><p>Usando el comando <code>dir</code> en Windows, o el comando <code>ls</code> en una Mac, vemos que nuestro repositorio local ahora tiene nuestros archivos originales más los archivos de licencia y Léame de nuestro repositorio remoto, como se muestra en la Figura 7.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure7-pull.png" class="kg-image" alt="Figure7-pull" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure7-pull.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure7-pull.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure7-pull.png 1526w" sizes="(min-width: 720px) 720px" width="1526" height="798" loading="lazy"><figcaption>Figura 7. Extrayendo el historial de cambios del repositorio remoto.</figcaption></figure><p>Ahora nuestro repositorio local contiene todo el historial de confirmaciones del repositorio remoto.</p><p>A continuación, enviamos el historial de cambios desde nuestro repositorio local a nuestro repositorio remoto usando el comando <code>push</code>.</p><pre><code class="language-git">git push recetas-gh main</code></pre><p>El comando <code>push</code> requiere el nombre del repositorio remoto ( <code>recetas-gh</code> ) y el nombre de la rama. Como no hemos creado ninguna rama adicional, especificamos la rama principal ( <code>main</code> ).</p><p>Este comando fusiona el historial de cambios local con el repositorio remoto. Si hay algún conflicto, deberá resolverlo manualmente antes de que Git combine los cambios. Consulte la Figura 8 para ver el resultado:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure8-push.png" class="kg-image" alt="Figure8-push" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure8-push.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure8-push.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure8-push.png 1079w" sizes="(min-width: 720px) 720px" width="1079" height="395" loading="lazy"><figcaption>Figura 8. Enviar el historial de cambios local al repositorio remoto.</figcaption></figure><p>Para confirmar que nuestro repositorio remoto incluye todos nuestros archivos, vea el repositorio remoto en GitHub. En la Figura 9, vemos que los archivos de nuestro repositorio local ahora están en nuestro repositorio remoto y ¡nuestros repositorios están sincronizados!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure9-github-repo.png" class="kg-image" alt="Figure9-github-repo" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure9-github-repo.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure9-github-repo.png 936w" sizes="(min-width: 720px) 720px" width="936" height="504" loading="lazy"><figcaption>Figura 9. Nuestro repositorio remoto con los archivos de nuestro repositorio local.</figcaption></figure><p>En resumen, sincronizar sus repositorios local y remoto implica extraer cualquier cambio del repositorio remoto a su repositorio local, resolver conflictos y luego enviar sus cambios locales nuevamente al repositorio remoto.</p><p>Eso es todo para el primer escenario. Creamos un repositorio local a partir de nuestros archivos existentes. Luego creamos un repositorio remoto, configuramos una conexión a ese repositorio remoto y sincronizamos nuestros archivos. Repita los comandos <code>pull</code> y <code>push</code> para sincronizar los repositorios mientras trabaja en su proyecto.</p><!--kg-card-begin: html--><h2 id="escenario-2">Escenario 2: Primero remoto</h2><!--kg-card-end: html--><p>Para nuestro segundo escenario, el repositorio remoto ya existe. Este será el caso si te unes a un equipo que tiene código existente en GitHub. O si quieres trabajar en un proyecto de código abierto. O si encontró algún código en GitHub que le gustaría usar como punto de partida para su proyecto.</p><p>Quiere crear su repositorio local a partir de un repositorio remoto existente. Hay tres formas básicas de obtener código de un repositorio remoto, como se muestra en la Figura 10.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure10-remote-first.png" class="kg-image" alt="Figure10-remote-first" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure10-remote-first.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure10-remote-first.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/04/Figure10-remote-first.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure10-remote-first.png 1920w" sizes="(min-width: 720px) 720px" width="1920" height="1080" loading="lazy"><figcaption>Figura 10. Obtener código de un repositorio remoto.</figcaption></figure><p>En el lado izquierdo de la Figura 10, tenemos un escenario: si posee o tiene derechos de acceso para modificar el repositorio remoto, puede clonar el repositorio remoto para crear su repositorio local. Luego puede sincronizar directamente los cambios entre los dos repositorios.</p><p>El segundo escenario se muestra en el medio de la Figura 10: si no es propietario del repositorio remoto o no tiene derechos de acceso para modificarlo, primero use GitHub para bifurcar el repositorio. Esto crea una copia del repositorio remoto en su cuenta de GitHub. Luego clona tu copia para crear tu repositorio local.</p><p>Este será el caso si estás trabajando en un proyecto de código abierto o quieres usar el código en el repositorio de otra persona como punto de partida para tu proyecto.</p><p>El tercer escenario se muestra a la derecha de la Figura 10; también existe la opción de descargar un archivo zip del código en el repositorio. Esto no crea un repositorio local. Utilice esta opción si desea ver el código de un repositorio de GitHub, pero no planea realizar un seguimiento de los cambios.</p><p>Para configurar el ejemplo de este escenario, necesita un repositorio remoto que actualmente no tenga un repositorio local asociado. Puede utilizar el repositorio remoto de <code>recetas</code> que ya creó en el primer escenario. Si prefieres utilizar el repositorio de otra persona para este ejemplo, asegúrate de bifurcarlo primero.</p><p>Una vez que tenga un repositorio remoto, asegúrese de que no haya ningún repositorio local asociado a él. Si está utilizando el repositorio remoto de <code>recetas</code>, elimine la carpeta de <code>recetas</code> de su sistema local. Eso elimina su repositorio local.</p><p>Ahora está listo para crear un nuevo repositorio local desde su repositorio remoto en GitHub.</p><!--kg-card-begin: html--><h2 id="clonar">¿Cómo clonar un repositorio?</h2><!--kg-card-end: html--><p>Para crear un repositorio local desde un repositorio remoto en GitHub, use el comando <code>clone</code>.</p><p>Si prefieres clonar un repositorio usando la aplicación GitHub Desktop, mira este video:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/GpqIr0y2rvc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Using GitHub Desktop to Clone a Repository (Clip 11): Gentle Introduction to Git and GitHub" name="fitvid7"></iframe>
          </div>
        </div>
      </figure><p>Para clonar usando un comando de Git, primero necesitamos la URL del repositorio remoto.</p><p>Navegue a GitHub, inicie sesión y verá su panel personal. Localice el repositorio que desea clonar. Haga clic en el botón verde <code>Código</code> para ver los detalles sobre el repositorio como se muestra anteriormente en la Figura 5. Haga clic en el botón copiar al lado de la URL para copiarlo.</p><p>A continuación, abra su terminal o símbolo del sistema en su computadora. Navegue hasta la carpeta donde desea crear la carpeta de trabajo del proyecto. Navegaré a mi carpeta de <code>documentos</code>.</p><p>Entonces estamos listos para clonar ese repositorio:</p><pre><code class="language-git">git clone https://github.com/DeborahK/recetas.git</code></pre><p>El comando <code>clone</code> requiere la URL del repositorio remoto. Acabamos de copiar esa URL de GitHub, así que péguela como parte de este comando.</p><p>Cuando se ejecuta el comando, primero crea la carpeta de trabajo para el repositorio utilizando el nombre del repositorio remoto de la URL, que son <code>recetas</code> en este ejemplo. Luego copia el historial de confirmaciones del repositorio remoto en la URL proporcionada.</p><p>El proceso de clonación también vincula automáticamente el nuevo repositorio local con su repositorio remoto. Y asigna al repositorio remoto un alias de <code>origen</code>. Luego podemos hacer referencia al repositorio remoto usando ese alias en lugar de su URL.</p><p>Por último, el proceso de clonación copia todos los archivos de la confirmación más reciente a la carpeta de trabajo local. Luego puede agregar, editar o eliminar archivos en esa carpeta de trabajo mientras trabaja localmente en el proyecto.</p><p>Navegue hacia abajo hasta la carpeta de nuevas <code>recetas</code>. Luego use el comando remoto para ver el repositorio remoto vinculado. Y como se muestra en la Figura 11, efectivamente tiene el alias <code>origen</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure11-git-clone.png" class="kg-image" alt="Figure11-git-clone" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure11-git-clone.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure11-git-clone.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure11-git-clone.png 1348w" sizes="(min-width: 720px) 720px" width="1348" height="506" loading="lazy"><figcaption>Figura 11. Clonación de un repositorio.</figcaption></figure><p>Observe el resultado de la operación de clonación en la Figura 11. Git enumera (o encuentra) 10 objetos. Sólo tenemos cuatro archivos en el repositorio remoto de <code>recetas</code>. Entonces, ¿por qué encuentra 10 objetos? Esto se debe a que el proceso de clonación copia todo el historial de confirmaciones, no solo los archivos.</p><p>Utilice el comando <code>rev-list</code> con las banderas <code>--objects</code> y <code>--all</code> para ver la lista de objetos.</p><pre><code class="language-git">git rev-list --objects --all</code></pre><p>La Figura 12 muestra el resultado de ese comando:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure12-git-rev-list.png" class="kg-image" alt="Figure12-git-rev-list" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure12-git-rev-list.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/04/Figure12-git-rev-list.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure12-git-rev-list.png 1114w" sizes="(min-width: 720px) 720px" width="1114" height="442" loading="lazy"><figcaption>Figura 12. Lista de objetos en el repositorio.</figcaption></figure><p>Cada uno de los objetos anteriores se muestra como un identificador SHA o algoritmo hash seguro. El SHA se utiliza como identificación para identificar de forma única los objetos en nuestro repositorio.</p><p>Los primeros tres objetos de esta lista (objetos 1 a 3) son las tres confirmaciones realizadas en este repositorio. Al observar la lista de confirmaciones en GitHub (Figura 13), cada confirmación muestra los primeros caracteres de su SHA. Estos coinciden con los primeros tres objetos:</p><ul><li>La fusión se confirma cuando fusionamos los dos repositorios. </li><li>El commit inicial que GitHub realizó en el repositorio remoto creando los archivos <code>LICENCIA</code> y <code>README.md</code>. </li><li>El commit inicial que realizamos en el repositorio local confirmando <code>file1.txt</code> y <code>file2.txt</code>.</li></ul><p>Los objetos del medio en la lista que se muestra en la Figura 12 (objetos 5-8) son los cuatro archivos comprometidos.</p><p>Los tres objetos restantes (objetos 4, 9, 10) son objetos de árbol. Un objeto de árbol representa el estado de una carpeta, incluidos los archivos y subcarpetas de esa carpeta. Mantiene la jerarquía de la carpeta.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure13-commit-history.png" class="kg-image" alt="Figure13-commit-history" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure13-commit-history.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure13-commit-history.png 910w" sizes="(min-width: 720px) 720px" width="910" height="660" loading="lazy"><figcaption>Figura 13. Historial de confirmaciones, cada uno identificado por los primeros valores de SHA.</figcaption></figure><p>Usando el comando <code>dir</code> en Windows o el comando <code>ls</code> en Mac, vemos que nuestra carpeta de trabajo ahora contiene todos los archivos de nuestro repositorio remoto.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure14-working-folder.png" class="kg-image" alt="Figure14-working-folder" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/04/Figure14-working-folder.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2024/04/Figure14-working-folder.png 997w" sizes="(min-width: 720px) 720px" width="997" height="530" loading="lazy"><figcaption>Figura 14. Un directorio de los archivos en nuestra carpeta de trabajo.</figcaption></figure><p>Ahora que hemos clonado el repositorio, nuestros repositorios local y remoto coinciden. Para mantenerlos sincronizados, utilizamos <code>pull</code> y <code>push</code> como vimos en la sección "Cómo sincronizar repositorios locales y remotos" anteriormente en este artículo.</p><p>Tenga en cuenta que si está trabajando con un repositorio remoto que no es de su propiedad, es posible que no tenga acceso para enviar sus cambios directamente al repositorio. En su lugar, deberás emitir un <code>Pull Request</code>.</p><p>Un <code>Pull Request</code>, o PR, les dice a los propietarios u otros contribuyentes que usted ha enviado cambios y que está solicitando que esos cambios se revisen y extraigan, o se fusionen, en el repositorio remoto.</p><p>Vea este vídeo para obtener más información sobre los <code>Pull Request</code>:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/y_A8O3cpDyM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Pull Requests and Merging Branches in GitHub (Clip 18): Gentle Introduction to Git and GitHub" name="fitvid8"></iframe>
          </div>
        </div>
      </figure><h1 id="terminando">Terminando</h1><p>En el primer escenario, teníamos código existente y creamos un repositorio local a partir de ese código. Luego creamos un repositorio remoto para mantener una copia de los archivos fuera del sitio y compartir el proyecto con otros.</p><p>En el segundo escenario, teníamos un repositorio remoto existente creado en GitHub por nuestro equipo o por un colaborador de código abierto. Luego clonamos ese repositorio para crear nuestro repositorio local. De esa manera, podemos trabajar en nuestra propia copia del proyecto y realizar y probar cambios de forma independiente antes de enviar esos cambios al repositorio remoto para que otros los revisen y fusionen.</p><p>Ya sea que cree primero su repositorio local o primero su repositorio remoto de GitHub, una vez que tenga ambos repositorios en su lugar, puede mantenerlos sincronizados con los comandos <code>pull</code> y <code>push</code> de Git. O enviando solicitudes de extracción o relaciones públicas.</p><p>Para obtener más detalles sobre cómo aprender Git y GitHub, consulte este curso:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/pICJdbC7j0Q?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Introduction to Git and GitHub (Clip 1): Gentle Introduction to Git and GitHub" name="fitvid9"></iframe>
          </div>
        </div>
      </figure><p>Obtener una comprensión sólida de los repositorios locales y remotos, y cómo mantenerlos sincronizados, es esencial cuando se trabaja en su propio código. Es aún más importante cuando se trabaja en un equipo o en un proyecto de código abierto.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Reiniciar Origen en Git: Cómo reiniciar una rama local a la rama de seguimiento remoto ]]>
                </title>
                <description>
                    <![CDATA[ Git es un sistema de control de versiones gratuito y de código abierto. Es el sistema de control de versiones más popular en uso hoy en día. Git realiza un seguimiento de los cambios realizados en un proyecto a lo largo del tiempo. Esto permite a múltiples desarrolladores colaborar y ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/reiniciar-origen-en-git-como-reiniciar-una-rama-local-a-la-rama-de-seguimiento-remoto/</link>
                <guid isPermaLink="false">65edfce8e41e0704006c1b97</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrés  Torres ]]>
                </dc:creator>
                <pubDate>Tue, 26 Mar 2024 19:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/03/tanner-van-dera-oaQ2mTeaP7o-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-reset-origin-how-to-reset-a-local-branch-to-remote-tracking-branch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Reset Origin – How to Reset a Local Branch to Remote Tracking Branch</a>
      </p><p><strong>Git es un sistema de control de versiones gratuito y de código abierto. Es el sistema de control de versiones más popular en uso hoy en día.</strong></p><p>Git realiza un seguimiento de los cambios realizados en un proyecto a lo largo del tiempo. Esto permite a múltiples desarrolladores colaborar y trabajar en el mismo proyecto en paralelo, sin importar dónde se encuentren en el mundo.</p><p>Permite a los desarrolladores ver el historial del proyecto y ver quién realizó qué cambios y por qué se realizaron esos cambios en primer lugar. Además, con Git, puedes revertir a una versión anterior del código si es necesario.</p><p>Básicamente, Git garantiza a los desarrolladores que están todos en la misma página y sepan qué está sucediendo en el proyecto.</p><p>Cuando trabajas en un proyecto, uno de los desafíos que puedes enfrentar es tratar de sincronizar tu trabajo, específicamente, sincronizar las ramas locales y remotas.</p><p>En este artículo, aprenderás cómo restablecer y hacer coincidir exactamente una rama Git local con una rama remota.</p><p>Esto es lo que cubriremos:</p><ul><li><a href="#git-branch">¿Qué es una rama en Git?</a></li><li><a href="#branch-differences">¿Cuál es la diferencia entre las ramas locales, remotas y las ramas de seguimiento remoto?</a></li><li><a href="#reset-branch">¿Cómo restablecer una rama local de Git a la remota?</a></li><li><a href="#save-state">Guardar el estado actual de tu rama local</a></li><li><a href="#git-checkout">Hacer un git checkout</a></li><li><a href="#get-origin">Hacer fetch de origen</a></li><li><a href="#reset-repo">Restablecer el repositorio local</a></li><li><a href="#clean-changes">Limpiar cualquier cambio no rastreado</a></li><li><a href="#conclusion">Conclusión</a></li></ul><!--kg-card-begin: html--><h2 id="git-branch">¿Qué es una rama en Git? Ramas de Git en pocas palabras para principiantes</h2><!--kg-card-end: html--><p>La ramificación es un aspecto fundamental del control de versiones y un concepto importante de aprender.</p><p>Gracias a la ramificación, los desarrolladores pueden colaborar de una manera más flexible. La ramificación hace que el proceso de desarrollo diario sea más fluido y eficiente.</p><p>La ramificación es una forma de gestionar diferentes versiones de tu código y actúa como un puntero a una instantánea de tus cambios.</p><p>Cuando creas por primera vez un repositorio Git para tu proyecto, en ese mismo momento se crea también la rama principal.</p><p>La rama principal es la rama primaria y predeterminada de tu proyecto. Representa la versión libre de errores, estable y utilizable de tu código que está lista para ser lanzada y compartida con el público. Es la base de código principal.</p><p>Pero, ¿qué sucede cuando quieres añadir una nueva característica a tu proyecto?</p><p>Antes de añadirla, necesitas probarla y asegurarte de que no introduce nuevos errores o interfiere con el código existente.</p><p>Debe haber una forma de trabajar en la nueva característica sin afectar la base de código.</p><p>Y aquí es donde la ramificación resulta útil.</p><p>Las ramas son espacios aislados para experimentar y probar código nuevo sin afectar al código en la rama principal.</p><p>Puedes crear una nueva rama y hacer los cambios que desees. Si estás satisfecho con los cambios, puedes añadirlos a la rama principal fusionándolos. Si no lo estás, puedes eliminar esa rama sin interferir con el código principal en el proyecto.</p><p>Las ramas también permiten a los desarrolladores trabajar en diferentes características al mismo tiempo sin interferir en el trabajo de los demás.</p><p>Para obtener más información sobre las ramas en Git, echa un vistazo a este <a href="https://www.youtube.com/watch?v=e2IbNHi4uCI">vídeo</a> que explica cómo funcionan, y marca este <a href="https://www.freecodecamp.org/news/how-to-use-branches-in-git/">artículo </a>que proporciona una hoja de trucos sobre cómo usarlas.</p><!--kg-card-begin: html--><h3 id="branch-differences">Ramas locales VS remotas VS ramas de seguimiento remoto en Git - ¿Cuál es la diferencia?</h3><!--kg-card-end: html--><p>Una rama local es una rama que solo es accesible en tu máquina local y existe allí de manera aislada. Desde aquí, puedes agregar archivos y hacer confirmaciones de cualquier cambio que realices. Esos cambios se guardarán localmente y solo serán visibles para ti y estarán disponibles en tu máquina física local.</p><p>Los otros desarrolladores no podrán ver tu trabajo ni los cambios que hayas hecho.</p><p>Puedes crear una rama local llamada <code>my_branch</code> usando el siguiente comando:</p><pre><code class="language-bash">git branch my_branch
</code></pre><p>Y para luego listar todas tus ramas locales, solo necesitas usar el comando <code>git branch</code>.</p><p>Para colaborar con otros desarrolladores en el mismo proyecto y para que ellos puedan ver cualquier cambio que realices, necesitas enviar los cambios desde tu rama local a un repositorio remoto. Esto nos lleva a las ramas remotas. </p><p>Una rama remota se refiere a una rama que existe en un repositorio remoto. Un repositorio remoto, también conocido como remoto, típicamente será un repositorio alojado en algún lugar en Internet, en una ubicación remota como en los servidores de GitHub. </p><p>El nombre predeterminado de un repositorio remoto es <code>origin</code>.</p><p>Ahora, una rama de seguimiento remoto se refiere a una referencia local del estado de la rama remota. Por defecto, las ramas no tienen conexión entre sí. Dicho esto, puedes indicarle a una rama local que siga a una remota.</p><!--kg-card-begin: html--><h2 id="reset-branch">Cómo restablecer una rama local de Git a la remota</h2><!--kg-card-end: html--><p>Es posible que hayas estado trabajando en tu rama local, realizando diversos cambios y modificaciones en un proyecto, y hayas concluido que esos cambios ya no son necesarios.</p><p>Quieres eliminarlos y restablecer la rama a la rama remota.</p><p>Además, otro desarrollador puede haber realizado cambios y los haya enviado a la rama remota, por lo que necesitas obtener esos últimos cambios del repositorio remoto para estar al día.</p><p>Los pasos que necesitas seguir para lograr esto son los siguientes:</p><ul><li>Guardar el estado actual de tu rama local (opcional). </li><li>Obtener la última versión del código desde el remoto. </li><li>Restablecer la rama local. </li><li>Limpiar archivos (opcional).</li></ul><!--kg-card-begin: html--><h3 id="save-state">Guardar el Estado Actual de tu Rama Local</h3><!--kg-card-end: html--><p>Antes de comenzar, es posible que desees guardar el estado de tu rama actual en otra rama.</p><p>Cuando restableces una rama local de Git a la remota, perderás los cambios que hayas realizado localmente.</p><p>Este paso es opcional, y puedes elegir hacerlo en caso de que algo salga mal o desees volver a ese trabajo nuevamente en el futuro.</p><p>Para guardar el trabajo utiliza los siguientes comandos: </p><pre><code class="language-bash">git commit -a -m "Estoy guardando mi trabajo"
git branch backup_trabajo</code></pre><p>Tu trabajo se guardó como <code>backup_trabajo</code>.</p><!--kg-card-begin: html--><h3 id="git-checkout">Hacer un git checkout</h3><!--kg-card-end: html--><p>Por lo general, habrá una rama de seguimiento remoto local con el mismo nombre que la remota a la que deseas restablecer, como <code>main</code>.</p><p>Para este proceso usamos:</p><pre><code class="language-bash">git checkout main
</code></pre><p>Si estás utilizando un nombre diferente para esta rama, reemplaza <code>main</code> con el nombre que estés utilizando.</p><!--kg-card-begin: html--><h3 id="get-origin">Obtener origen</h3><!--kg-card-end: html--><p>Para obtener el repositorio remoto y el estado y la versión más recientes del código en el repositorio remoto, introduce el siguiente comando:</p><pre><code class="language-bash">git fetch origin
</code></pre><p><code>origin</code> es un alias creado por Git y especifica la URL remota del repositorio remoto. Por lo general, Git asume automáticamente que el nombre del repositorio remoto es <code>origin</code>.</p><p>Si tienes un nombre remoto diferente, reemplaza <code>origin</code> con el nombre que estés usando.</p><!--kg-card-begin: html--><h3 id="reset-repo">Restablecer el repositorio local</h3><!--kg-card-end: html--><p>Ahora, restablece la rama local <code>main</code> al repositorio remoto utilizando el siguiente comando:</p><pre><code class="language-bash">git reset --hard origin/main
</code></pre><!--kg-card-begin: html--><h3 id="clean-changes">Limpiar cualquier cambio no rastreado</h3><!--kg-card-end: html--><p>Este paso es opcional. Después de usar los comandos anteriores, es posible que te encuentres con algunos archivos no rastreados. Utiliza el siguiente comando para limpiar cualquier cambio no rastreado:</p><pre><code class="language-bash">git clean -xdf
</code></pre><p>Vamos a desglosar la bandera <code>-xdf</code> y explicar qué hace cada parte: </p><ol><li>La bandera <code>-x</code> elimina archivos ignorados. </li><li>La bandera <code>-d</code> elimina carpetas no rastreadas. </li><li>La bandera <code>-f</code> elimina archivos no rastreados.</li></ol><!--kg-card-begin: html--><h2 id="conclusion">Conclusión</h2><!--kg-card-end: html--><p>Y ahí lo tienes: ahora has restablecido tu rama local a la remota. Esperemos que hayas encontrado útil este artículo. </p><p>Para aprender más sobre Git, echa un vistazo a los siguientes recursos gratuitos:</p><ul><li><a href="https://www.youtube.com/watch?v=RGOj5yH7evk">Git y GitHub para Principiantes - Curso Intensivo</a></li><li><a href="https://www.youtube.com/watch?v=Uszj_k0DGsg">Tutorial de Git para Profesionales - Herramientas y Conceptos para Dominar el Control de Versiones con Git</a></li><li><a href="https://www.youtube.com/watch?v=qsTthZi23VE">Tutorial Avanzado de Git - Rebase Interactivo, Cherry-Picking, Reflog, Submódulos y más </a></li></ul><p>¡Gracias por leer y feliz codificación!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo usar el comando Git Stash ]]>
                </title>
                <description>
                    <![CDATA[ Digamos que estás trabajando en una característica importante de una rama en Git – como sería renovar la sección hero de tu página de marketing. Querrás comenzar a hacer experimentos en tu rama Revamp/Marketing-page-hero-section sin arruinar la rama master o main. Después de repente te llama tu compañero de trabajo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-usar-el-comando-git-stash/</link>
                <guid isPermaLink="false">65a7d3f551a59a0455c92db5</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Mon, 05 Feb 2024 02:41:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/01/stahs-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-stash-commands/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use the Git Stash Command</a>
      </p><p>Digamos que estás trabajando en una característica importante de una rama en Git – como sería renovar la sección hero de tu página de marketing. Querrás comenzar a hacer experimentos en tu rama <code>Revamp/Marketing-page-hero-section</code> sin arruinar la rama <code>master</code> o <code>main</code>.</p><p>Después de repente te llama tu compañero de trabajo para arreglar algunos errores en la rama <code>login-page</code>. Es un problema serio. Así que, intentas cambiar a la rama <code>login-page</code> usando <code>git switch login-page</code> o <code>git checkout login-page</code>. </p><p>Si estás cambiando ramas con cambios "staged" y "unstaged", te podrías encontrar con cualquiera de los siguientes escenarios:</p><p>Primero, mientras cambias a la rama <code>login-page</code>, los cambios "staged" y "unstaged" de la rama <code>Revamp/Marketing-page-hero-section</code> vendrán contigo a la rama <code>login-page</code>.</p><p>La rama <code>Revamp/Marketing-page-hero-section</code> contiene algunos cambios "staged" y "unstaged" en el <code>index.html</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/stash-1.png" class="kg-image" alt="stash-1" width="600" height="400" loading="lazy"></figure><p>Si cambiamos a la rama <code>login-page</code>, los cambios "staged" y "unstaged" en la rama <code>Revamp/Marketing-page-hero-section</code> vienen al <code>login-page</code> también.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/stash-1-1.png" class="kg-image" alt="stash-1-1" width="600" height="400" loading="lazy"></figure><p>Esto embarra a la rama <code>login-page</code>.</p><p>Luego, a veces Git no te permite cambiar ramas sin confirmar esos cambios. Esto es porque podrías perder los cambios que hiciste en tu rama actual o podrían entrar en conflicto con el destino (<code>login-page</code>). Cualquiera sea la razón, no podemos cambiar la rama sin confirmar o almacenar los cambios.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/error.png" class="kg-image" alt="error" width="600" height="400" loading="lazy"></figure><p>Al mismo tiempo, no puedes confirmar la rama feature medio hecho.</p><p>Para ello, puedes usar <strong>Git stashing</strong>. Stash significa almacenar (cambios) de manera segura en un lugar oculto (la pila stash).</p><p>Almacenar los cambios o archivos sin seguimiento del directorio de trabajo actual y almacenarlos en la pila de almacenamiento, revierte el directorio de trabajo actual a la última confirmación. </p><p>Esto es bueno saberlo, ¿no? Comencemos a trabajar con los comandos stash.</p><h2 id="tabla-de-contenidos"><strong>Tabla<strong><strong> </strong></strong>de<strong><strong> </strong></strong>contenidos</strong></h2><ul><li><a href="#stash-changes">Cómo ocultar tus cambios 🤐</a></li><li><a href="#stash-untracked-files">Cómo ocultar archivos sin rastrear❗</a></li><li><a href="#list-stashes">Cómo listar los stashs 📃</a></li><li><a href="#stash-format">Entendiendo el formato de stash</a></li><li><a href="#show-last-stash">Cómo mostrar el último stash 📺</a></li><li><a href="#show-single-stash">Cómo mostrar un stash individual 📺</a></li><li><a href="#apply-stash">Cómo aplicar el stash 🖊️</a></li><li><a href="#delete-stash">Cómo eliminar un stash ☠️</a></li><li><a href="#create-branch-from-stash">Cómo crear una rama de un stash</a></li></ul><!--kg-card-begin: html--><h2 id="stash-changes">Cómo ocultar tus cambios 🤐</h2><!--kg-card-end: html--><p>Puedes usar cualquiera de los comandos de abajo para <strong>ocultar cambios staged y unstaged en la pila de stash</strong>. Este anula las cosas al último commit y no elimina los cambios, los cuales están almacenados en la pila stash.</p><pre><code class="language-bash">git stash</code></pre><p>o</p><pre><code class="language-bash">git stash save</code></pre><!--kg-card-begin: html--><h2 id="stash-untracked-files">Cómo ocultar archivos sin rastrear❗</h2><!--kg-card-end: html--><p>¿Quieres ocultar tus archivos sin rastrear en la pila de stash? Solo usa la bandera <code>--include-untracked</code> al final del comando.</p><pre><code class="language-bash">git stash --include-untracked</code></pre><p>o usa <code>-u</code> al final del comando:</p><pre><code class="language-bash">git stash -u</code></pre><!--kg-card-begin: html--><h2 id="list-stashes">Cómo listar los stashes 📃</h2><!--kg-card-end: html--><p>Usa el comando de abajo para listar todos los stashs almacenados en la pila de stash:</p><pre><code class="language-bash">git stash list</code></pre><p>Lista los stashs de esta forma,</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/list-1.png" class="kg-image" alt="list-1" width="600" height="400" loading="lazy"></figure><ul><li>Los últimos stashs (stash@{0}) estarán en la parte superior de la pila.</li><li>Los stashs anteriores (stash@{1}) estarán en la parte inferior de la pila.</li></ul><!--kg-card-begin: html--><h2 id="stash-format">Entendiendo el formato de stash</h2><!--kg-card-end: html--><p>El comando stash lista los stashs en el siguiente formato:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/03/stash-list.jpg" class="kg-image" alt="stash-list" width="600" height="400" loading="lazy"><figcaption>Un formato de stash</figcaption></figure><p>Si no te queda bien claro lo que está diciendo 😅, no hay problema. Exploremos algunos de los términos de la lista de stash:</p><ul><li><strong><strong><code>Stash@{0}</code></strong></strong> – esto es sólo una referencia de stash. Se refiere al stash particular. Por defecto, <code>Stash@{0}</code> siempre es el último stash.</li></ul><p><em><em>Not</em>a<em>:</em> stashs con números más elevados como<em> stash@{3} </em>son<em> stashs</em> más antiguos<em>. </em>Los últimos<em> stashs </em>siempre tienen el número más bajo<em>.</em></em></p><ul><li><code><strong><strong>WIP On fake</strong></strong></code><strong><strong> –</strong></strong> <em><em>fake</em></em> es sólo un nombre de una rama como cualquier otra rama y WIP significa Work In Progress (Trabajo En Progreso). "<em><em>WIP on fake"</em></em> significa que <code>stash@{0}</code> fue creado en la rama "fake".</li><li><strong><strong><code>fc99b30 add head line</code></strong></strong> – <em><em>fc99b30</em></em> es una hash de<strong><strong> </strong></strong>Commit y <em><em>add head line</em></em> es un mensaje de<strong><strong> </strong></strong>confirmación. Al tiempo de la creación del stash, <em><em>fc99b30 add head line</em></em> es la última confirmación.</li></ul><p>Tal vez tengas múltiples stashs en tu pila de stash y no eres capaz de distinguir cuál referencia de stash sostiene tales cambios.</p><p>Así que, antes de que apliques stashs en la rama de trabajo actual, puedes confirmar y mostrar los cambios registrados en el stash con el comando de abajo:</p><pre><code class="language-bash">git stash show</code></pre><p>Por defecto, <code>git stash show</code> muestra los cambios registrados en el <strong>último</strong> stash (stash@{0}) en el formato <code>--stat</code>.</p><p>El formato <code>--stat</code> solamente muestra cuántas líneas has agregado y eliminado en cada uno de los archivos modificados.</p><pre><code class="language-text">readme.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)</code></pre><p>Si quieres mostrar los cambios registrados en el último stash en el <strong>patch view,</strong> usa la bandera <code>-p</code> al final del comando, así:</p><pre><code class="language-bash">git stash show -p</code></pre><p>Si también quieres mostrar <strong>archivos sin rastrear</strong>, usa la bandera <code>-u</code>.</p><pre><code class="language-bash">git stash show -u
</code></pre><p>o puedes usar la bandera <code>--include-untracked</code> así:</p><pre><code class="language-bash">git stash show --include-untracked</code></pre><p>Puedes mostrar archivos sin rastrear con el <strong>formato patch</strong>:</p><pre><code class="language-bash">git stash show -p -u</code></pre><p>Puedes también mostrar <strong>solamente </strong>archivos sin rastrear con el formato patch así:</p><pre><code class="language-bash">git stash show -p --only-untracked</code></pre><p>Vaya ya has aprendido más de 10 comandos de stash 🎉🎉</p><p>Miremos algunos más así puedes aprovechar lo máximo de stash.</p><!--kg-card-begin: html--><h2 id="show-single-stash">Cómo mostrar un stash individual 📺</h2><!--kg-card-end: html--><p>Puedes mostrar los cambios registrados de un stash individual usando <strong>referencia de stash</strong>.</p><pre><code class="language-bash">git stash show stash@{1}
</code></pre><p>Para el formato patch, adivinaste bien 👏🏻👏🏻 – usa la bandera <code>-p </code>.</p><pre><code class="language-bash">git stash show stash@{1} -p
</code></pre><p>¿Quieres mostrar un stash con archivos sin rastrear? Usa este comando:</p><pre><code class="language-bash">git stash show stash@{1} -u
</code></pre><p>o este:</p><pre><code class="language-bash">git stash show stash@{1} --include-untracked
</code></pre><p>Donde sea que puedas hacer esto para mostrar archivos sin rastrear solamente:</p><pre><code class="language-bash">git stash show stash@{1} --only-untracked</code></pre><!--kg-card-begin: html--><h2 id="apply-stash">Cómo aplicar el stash 🖊️</h2><!--kg-card-end: html--><p>Para aplicar los cambios registrados de tu último stash en la rama de trabajo actual, así también como quitar ese stash de la pila de stash, ejecuta este comando:</p><pre><code class="language-bash">git stash pop
</code></pre><p><em><em>Not</em>a<em>: </em>Podemos aplicar stashs en cualquier rama<em>. </em>No es específico a la rama donde el stash fue creado<em>.</em></em></p><p>También puedes aplicar el último stash sin quitar el stash de la pila de stash así:</p><pre><code class="language-bash">git stash apply
</code></pre><p>Puedes aplicar un stash anterior usando la referencia de stash:</p><pre><code class="language-bash">git stash apply stash@{3}</code></pre><!--kg-card-begin: html--><h2 id="delete-stash">Cómo eliminar un stash ☠️</h2><!--kg-card-end: html--><p>¿Quieres limpiar todos los stashs de la pila de stash? Usa este comando:</p><pre><code class="language-bash">git stash clear
</code></pre><p>¿Quieres eliminar un stash en particular? ¡Sí! Estás en lo cierto – usa la referencia de stash:</p><pre><code class="language-bash">git stash drop stash@{2}</code></pre><!--kg-card-begin: html--><h2 id="create-branch-from-stash">Cómo crear una rama de stash</h2><!--kg-card-end: html--><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/03/branch-stash.png" class="kg-image" alt="branch-stash" width="600" height="400" loading="lazy"></figure><p>Sí, puedes crear una nueva rama de tu último stash. Sólo usa este comando:</p><pre><code class="language-bash">git stash branch &lt;branch_name&gt;
</code></pre><p>Por ejemplo,</p><pre><code class="language-bash">git stash branch demo
</code></pre><p>Si quieres crear una rama de un stash anterior, también es posible usando la referencia de stash:</p><pre><code class="language-bash">git stash branch &lt;branch_name&gt; stash@{revision}</code></pre><p>Por ejemplo,</p><pre><code class="language-bash">git stash branch purple stash@{3}</code></pre><h2 id="concluyendo"><strong>Concluyendo</strong></h2><p>¡Qué largo viaje! – hubo un montón por cubrir. Si no puedes recordar cada comando, está bien. Cuanto más uses estos comandos, más fácilmente los recordarás. Te puedes referir a mi <a href="https://gist.github.com/Preethi-Dev/fa8ae46a75761356dc1fa711376c8345"><strong>hoja de trucos de comandos de stash de git</strong></a> para una referencia rápida.</p><p>Espero que hoy hayas captado nuevas cosas sobre el stash de git. Es tiempo de relajarse y tomar un café o un té 🍵. ¡Hazme saber si tienes preguntas!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Listar ramas remotas en Git ]]>
                </title>
                <description>
                    <![CDATA[ Hay cuatro comandos diferentes de Git que puedes usar para enumerar todas las ramas remotas de repositorio. Le mostraré ejemplos de código de cada uno de estos. Todos los ejemplos están disponibles en el repositorio abierto de freeCodeCamp [https://github.com/freeCodeCamp/freeCodeCamp/]. Comando #1: git branch -r Este comando te mostrará ramas remotas. ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/listar-ramas-remotas-en-git/</link>
                <guid isPermaLink="false">656b3e74d31b7f03fd1e129f</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Tue, 12 Dec 2023 15:55:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/12/niko-photos-tGTVxeOr_Rs-unsplash-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-list-remote-branches/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git List Remote Branches</a>
      </p><p>Hay cuatro comandos diferentes de Git que puedes usar para enumerar todas las ramas remotas de repositorio. Le mostraré ejemplos de código de cada uno de estos.</p><p>Todos los ejemplos están disponibles en el <a href="https://github.com/freeCodeCamp/freeCodeCamp/">repositorio abierto de freeCodeCamp</a>.</p><h2 id="comando-1-git-branch-r">Comando #1: <code>git branch -r</code></h2><p>Este comando te mostrará ramas remotas. La bandera <code>-r</code> es la abreviación de <code>--remotes</code>.</p><pre><code class="language-bash">freecodecamp➜~/web/freeCodeCamp(main)» git branch -r

Output: 
  origin/HEAD -&gt; origin/main
  origin/i18n-sync-client
  origin/main
  origin/prod-current
  origin/prod-staging
  origin/renovate/react-i18next-11.x
  origin/renovate/typescript-eslint-monorepo</code></pre><p>Este es el comando que uso personalmente. Entonces, si lo deseas, puedes dejar de leer aquí y usar <code>git branch -r</code> siempre que quieras enumerar las remas remotas en Git.</p><p>Pero para completar, he incluido otros tres comandos que puedes usar y que devuelven listas diferentes.</p><h2 id="comando-2-git-ls-remote-heads">Comando #2: <code>git ls-remote --heads</code></h2><p>Este comando regresa la misma información, pero también incluye el hash de las ramas remotas. </p><pre><code class="language-bash">freecodecamp➜~/web/freeCodeCamp(main)» git ls-remote --heads

Output: 
From git@github.com:freeCodeCamp/freeCodeCamp
12d742a4f0dfdcfae25d1b71aa738b4e91bfcb61	refs/heads/i18n-sync-client
f05262b823f5a578787e5387357383f09df9c5c1	refs/heads/main
6d89576b6c588e3e3daa90bdaf226a6f5cc3d9c5	refs/heads/prod-current
6d89576b6c588e3e3daa90bdaf226a6f5cc3d9c5	refs/heads/prod-staging
750af5a018008c9a7eac683b064adc016b990659	refs/heads/renovate/react-i18next-11.x
08e06f10363ab1d33156b83b2b01cad005c3a2cf	refs/heads/renovate/typescript-eslint-monorepo</code></pre><h2 id="comando-3-git-ls-remote">Comando #3: <code>git ls-remote</code></h2><p>Este comando muestra no solo los nombres de los repositorios remotos, sino también su información de referencia, incluido el hash de confirmación de Git.</p><pre><code class="language-bash">freecodecamp➜~/web/freeCodeCamp(main)» git ls-remote

Output:

! [origin/HEAD] chore(deps): update dependency @types/validator to v13.7.3
 ! [origin/i18n-sync-client] fix(client): prevent lower jaw breaking on code evaluation (#46154)
  ! [origin/main] chore(deps): update dependency @types/validator to v13.7.3
   ! [origin/prod-current] fix(curriculum): don't block fragment links (#46246)
    ! [origin/prod-staging] fix(curriculum): don't block fragment links (#46246)
     ! [origin/renovate/react-i18next-11.x] fix(deps): update dependency react-i18next to v11.17.0
      ! [origin/renovate/typescript-eslint-monorepo] chore(deps): update typescript-eslint monorepo to v5.27.0
-------</code></pre><p>Hay muchos resultados con formato especial, así que solo incluiré una captura de pantalla para darte una idea:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/12/freeCodeCamp_-_freecodecamp_MacBook-Pro_-____freeCodeCamp_-_-zsh_-_136-36-2.png" class="kg-image" alt="freeCodeCamp_-_freecodecamp_MacBook-Pro_-____freeCodeCamp_-_-zsh_-_136-36-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/12/freeCodeCamp_-_freecodecamp_MacBook-Pro_-____freeCodeCamp_-_-zsh_-_136-36-2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/12/freeCodeCamp_-_freecodecamp_MacBook-Pro_-____freeCodeCamp_-_-zsh_-_136-36-2.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2023/12/freeCodeCamp_-_freecodecamp_MacBook-Pro_-____freeCodeCamp_-_-zsh_-_136-36-2.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2023/12/freeCodeCamp_-_freecodecamp_MacBook-Pro_-____freeCodeCamp_-_-zsh_-_136-36-2.png 1900w" sizes="(min-width: 720px) 720px" width="1900" height="1006" loading="lazy"><figcaption>Sí desea códigos de colores y marcas de tiempo en su terminal, recomiendo usar OhMyZSH</figcaption></figure><h2 id="comando-4-git-show-branch-r">Comando #4: <code>git show-branch -r</code></h2><p>La razón principal por la que usarías este comando es porque muestra casi todo, por lo que puedes presionar <code>ctrl+f</code> para encontrar un hash en particular.</p><p>No recuerdo haber usado esto antes.</p><pre><code class="language-bash">freecodecamp➜~/web/freeCodeCamp(main)» git show-branch -r

Output:

From git@github.com:freeCodeCamp/freeCodeCamp
f05262b823f5a578787e5387357383f09df9c5c1	HEAD
12d742a4f0dfdcfae25d1b71aa738b4e91bfcb61	refs/heads/i18n-sync-client
f05262b823f5a578787e5387357383f09df9c5c1	refs/heads/main
6d89576b6c588e3e3daa90bdaf226a6f5cc3d9c5	refs/heads/prod-current
6d89576b6c588e3e3daa90bdaf226a6f5cc3d9c5	refs/heads/prod-staging
750af5a018008c9a7eac683b064adc016b990659	refs/heads/renovate/react-i18next-11.x
08e06f10363ab1d33156b83b2b01cad005c3a2cf	refs/heads/renovate/typescript-eslint-monorepo
36380c5a67938de35d7011e33855d45bb545300b	refs/pull/10/head
d12e25f250b91afc01a43af0067d7026c39473fa	refs/pull/100/head
56ff814f24385e5f76dc29bc4276c84e38ca9c5f	refs/pull/10006/head
f84bb9a94ea33e0994e2d40c779416f3caa3aa04	refs/pull/10007/head
7193b9c725ed97cd8cc99aba72ceffa40a79c8f8	refs/pull/10008/head

[30,000 more lines]

9656d9030eb472341eebf5e0fb46a3538740701b	refs/pull/9991/head
0545010ab9e1dac4aedca071669b6a86b35cabdc	refs/pull/9995/head
b5365d3106e188fa6782388221b1184dfb2ffc88	refs/pull/9995/merge
0545010ab9e1dac4aedca071669b6a86b35cabdc	refs/pull/9996/head
b5365d3106e188fa6782388221b1184dfb2ffc88	refs/pull/9996/merge
7e35af7b67c22b502cdfdf4663fafc788e75eeec	refs/pull/9997/head
d8f3a9cb2e6d41a95f610ac72efae30ca9952d6f	refs/remotes/origin/pr-39112-with-my-additional-commits-for-tests
d3aaa5a11e09f5996cfd5eb2f8b55f63785b4947	refs/remotes/upstream/master
56d78a11198a0d244bd131a8b9386b247212c5a1	refs/remotes/upstream/production-current
b73c7eac62d30fdc5e533f617dcd1b5e95306984	refs/remotes/upstream/staging</code></pre><p>Para el repositorio FreeCodeCamp, este comando devolvió más de 30.000 líneas de ramas. Por tanto, no recomendaría usar este comando a no ser que sea absolutamente necesario verlo todo. 😅</p><p>Eso es todo. Espero que tengas un día fantástico y feliz codificación. </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Archivo Git Revert: Revertir un archivo a un commit anterior ]]>
                </title>
                <description>
                    <![CDATA[ Git es un sistema de control de versiones que ayuda a equipos e individuos a rastrear y registrar los cambios realizados en un archivo o en un proyecto completo. Cuando trabajas con Git, a menudo confirmas tus cambios y luego los envías a un repositorio remoto. Supongamos que has realizado ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/archivo-git-revert-revertir-un-archivo-a-un-commit-anterior/</link>
                <guid isPermaLink="false">6557b137bcc2a003e70e2b01</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fran Martinez ]]>
                </dc:creator>
                <pubDate>Tue, 12 Dec 2023 15:37:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/12/cover-template--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-revert-file-reverting-a-file-to-a-previous-commit/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Revert File – Reverting a File to a Previous Commit</a>
      </p><p>Git es un sistema de control de versiones que ayuda a equipos e individuos a rastrear y registrar los cambios realizados en un archivo o en un proyecto completo.</p><p>Cuando trabajas con Git, a menudo confirmas tus cambios y luego los envías a un repositorio remoto.</p><p>Supongamos que has realizado muchas confirmaciones y luego te das cuenta de que tu versión actual de cambios es errónea. O descubres una situación que requiere que reviertas a una confirmación anterior, como un error extraño.</p><p>Cambiar manualmente cada línea de código en tu archivo a su estado original o a un estado de confirmación específico y hacer una nueva confirmación puede llevar a un historial de confirmaciones desordenado. Revertir el archivo es una forma mucho más limpia de manejarlo.</p><p>Hay muchos enfoques posibles, pero en este artículo aprenderás el mejor enfoque, el método <code>git checkout</code>.</p><p>Si tienes prisa, aquí está el comando:</p><pre><code class="language-bash">$ git checkout SHA-HASH -- archivo/ruta-del-archivo</code></pre><p>Pero supongamos que no tienes prisa. Primero aprendamos cómo localizar todas las confirmaciones previas y sus códigos hash SHA. Luego veremos cómo revertir un archivo a una confirmación anterior.</p><h2 id="c-mo-encontrar-el-sha-id-de-confirmaci-n">Cómo encontrar el SHA/ID de confirmación</h2><p>Hay muchas formas de obtener el SHA y los detalles de cada confirmación. El mejor método es usar el siguiente comando en tu terminal:</p><pre><code class="language-bash">$ git log
</code></pre><p>Este comando mostrará una lista de todas las confirmaciones que has realizado en tu proyecto para todos los archivos y sus códigos hash:</p><figure class="kg-card kg-image-card"><img src="https://paper-attachments.dropbox.com/s_E7BE213D0AE03E619B0ABFE8B0450BCDCD832D2BDB3CB303964F1820DADBA52A_1660857327507_image.png" class="kg-image" alt="s_E7BE213D0AE03E619B0ABFE8B0450BCDCD832D2BDB3CB303964F1820DADBA52A_1660857327507_image" width="600" height="400" loading="lazy"></figure><p>Pero un comando más simple de usar es el siguiente, donde añades la opción <code>oneline</code>:</p><pre><code class="language-bash">$ git log -- oneline
</code></pre><p><strong>Nota<strong>:</strong></strong> La opción <code>oneline</code> muestra la salida como una confirmación por línea.</p><pre><code class="language-bash">198d425 (HEAD -&gt; main) initial
c368a1c new removal
bcbef35 updated readme 2
da9cc5f (origin/main) updated Readme
a5150af first commit
</code></pre><p>Usando solo este comando devolvería todas las confirmaciones realizadas en ese proyecto. Si deseas revertir un archivo en particular a una confirmación anterior, primero debes ver todas las confirmaciones realizadas a ese archivo.</p><p>Para hacer esto, agrega el nombre del archivo al comando:</p><pre><code class="language-bash">$ git log -- oneline README.md
</code></pre><p>En una situación donde el archivo se encuentra en otra carpeta, puedes navegar mediante tu terminal a esa carpeta o usar la ruta del archivo en el comando como se ve a continuación:</p><pre><code class="language-bash">$ git log -- oneline src/App.js
</code></pre><p>Esto devolverá solo las confirmaciones para el archivo especificado y el código hash SHA de la confirmación seguido por el mensaje de confirmación. Utilizarás el hash SHA para revertir tu archivo:</p><pre><code class="language-bash">198d425 (HEAD -&gt; main) initial
c368a1c new removal
bcbef35 updated readme 2
da9cc5f (origin/main) updated Readme
a5150af first commit
</code></pre><h2 id="c-mo-revertir-un-archivo-a-una-confirmaci-n-previa">Cómo revertir un archivo a una confirmación previa</h2><p>Ahora que sabes cómo obtener el código SHA, puedes usar el comando <code>git checkout</code> para revertir tu archivo a cualquier confirmación que deseas, pasando también el nombre del archivo o la ruta del archivo:</p><pre><code class="language-bash">$ git checkout da9cc5f -- README.md

Ó

$ git checkout 55a1dff -- src/App.js
</code></pre><p>Solo asegúrate de querer revertir ese archivo antes de hacerlo, porque vas a descartar tus cambios locales y actuales del archivo. Git reemplazará el archivo con la versión confirmada especificada. Usa esto solo si estás seguro y no quieres esos cambios locales no guardados.</p><h2 id="resumiendo">Resumiendo</h2><p>En este artículo, has aprendido cómo revertir un archivo a una confirmación previa con el comando <code>git checkout</code>.</p><p>Es importante saber que cuando reviertes, necesitarás confirmar los cambios nuevamente (los cambios revertidos). Puedes hacer esto con el comando confirmar estándar:</p><pre><code class="language-bash">$ Git commit -m 'mensaje de confirmación'
</code></pre><p>Luego puedes enviar esa confirmación al repositorio remoto que desees.</p><p>Puedes aprender más sobre Git y GitHub en este curso completo de 5+ horas, <a href="https://www.freecodecamp.org/espanol/news/aprende-git-y-github-curso-desde-cero/">video</a> o estos <a href="https://www.freecodecamp.org/espanol/news/search?query=git">artículos</a>.</p><p>¡Diviértete programando!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git push rama local a remota: Cómo publicar una nueva rama en git ]]>
                </title>
                <description>
                    <![CDATA[ Las ramas Git (del inglés branches) te permiten agregar nuevas características sin modificar la versión "viva" (de producción) de tu proyecto. Y si trabajas en un equipo, distintos desarrolladores podrían tener ramas independientes o únicas en las que trabajar. Al largo plazo tendrás que empujar (subir) esas ramas independientes a ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/git-push-rama-local-a-remota-como-publicar-una-nueva-rama-en-git/</link>
                <guid isPermaLink="false">6524252537996103e26caef9</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Tue, 12 Dec 2023 15:25:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/11/code-5290465_1920.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-push-local-branch-to-remote-how-to-publish-a-new-branch-in-git/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Push Local Branch to Remote – How to Publish a New Branch in Git</a>
      </p><p>Las ramas Git (del inglés branches) te permiten agregar nuevas características sin modificar la versión "viva" (de producción) de tu proyecto. Y si trabajas en un equipo, distintos desarrolladores podrían tener ramas independientes o únicas en las que trabajar.</p><p>Al largo plazo tendrás que empujar (subir) esas ramas independientes a un servidor remoto como, por ejemplo; GitHub, GitLab, entre otros.</p><p>En este artículo te voy a mostrar cómo puedes empujar una rama Git de tu entorno local a un servidor remoto. No importa si todavía no has empujado ninguna rama, tampoco si ya has empujado solo la rama principal de tu repositorio y quieres empujar otras. Te voy a enseñar todo desde cero.</p><h2 id="como-empujar-la-rama-principal-al-remoto"><strong>Como empujar la rama principal al remoto</strong></h2><p>Si quieres empujar la rama main (principal) al servidor remoto por primera vez, necesitarás asegurarte de que hayas ejecutado antes los siguientes comandos: </p><ul><li><code>git init</code> para inicializar el repositorio local.</li><li><code>git add .</code> para agregar todos los archivos al repositorio local</li><li><code>git commit -m ‘mensaje descriptivo del commit’</code> para guardar los cambios realizados a los archivos que contiene el repositorio</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss1-2.png" class="kg-image" alt="ss1-2" width="600" height="400" loading="lazy"></figure><p>Para empujar el repositorio "main", será necesario primero agregar el servidor remoto a Git ejecutando <code>git remote add &lt;url&gt;</code>.</p><p> Para confirmar que se ha agregado el servidor remoto, ejecuta <code>git remote -v</code>: </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss2-2.png" class="kg-image" alt="ss2-2" width="600" height="400" loading="lazy"></figure><p>Finalmente, para empujar el repo ejecuta <code>git push -u origin &lt;branch-name&gt;</code> ("main" es el nombre de la rama que yo estoy empujando). La rama principal podría ser "master" o "main" para ti, ya que antes "master" era el nombre por defecto, pero ahora es "main". &nbsp;Pero puedes ejecutar &nbsp;<code>git branch -M main</code> en caso de que se llame "master" para cambiarle el nombre a "main" si así lo prefieres.</p><p>Si has configurado Git para usar el asistente de credenciales, se te pedirá tu nombre de usuario GitHub y el PAT (del inglés, Personal Access Token): </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss3-2.png" class="kg-image" alt="ss3-2" width="600" height="400" loading="lazy"></figure><p>Así es como empujas la rama principal (main) por primera </p><h2 id="como-empujar-una-rama-nueva-al-repositorio-remoto"><strong>Como </strong>empujar una rama nueva al repositorio remoto</h2><p>Si tienes otra rama con la que has trabajado que quieres empujar al repositorio remoto, también usaras el comando <code>git push</code>, pero de manera ligeramente distinta.</p><p>Como recordatorio, para crear una nueva rama debes ejecutar <code>git branch nombre-rama</code>. Y para cambiarte a esa rama, para poder trabajar en ella, tienes que ejecutar <code>git switch branch-name</code> o <code>git checkout branch-name</code></p><p>Para empujar la rama al servidor remoto, ejecuta <code>git push -u origin &lt;branch name&gt;</code>. En mi caso, el nombre de esa rama es <code>bug-fixes</code>. Asi que ya he ejecutado <code>git push -u &nbsp;origin bug-fixes</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss4-2.png" class="kg-image" alt="ss4-2" width="600" height="400" loading="lazy"></figure><p>Para confirmar que la rama ha sido empujada correctamente, ve a GitHub y haz clic en el menú colapsable que muestra la rama actual y las disponibles. Deberías ver la nueva rama ahí:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss5-2.png" class="kg-image" alt="ss5-2" width="600" height="400" loading="lazy"></figure><h2 id="conclusi-n">Conclusión</h2><p>Este artículo te ha mostrado como empujar una rama a un repositorio remoto. Además de eso, también vimos cómo puedes hacerlo por primera vez.</p><p>Si quieres aprender más acerca de git, revisa los otros artículos de <a href="https://www.freecodecamp.org/espanol/news/tag/git/">freeCodeCamp en español que cubren los temas de Git y GitHub</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Quitar ramas remotas: cómo eliminar una rama remota en Git ]]>
                </title>
                <description>
                    <![CDATA[ Cuando trabaja con Git, es posible que desee eliminar ramas remotas enviadas a plataformas como GitHub por varios motivos. En este artículo, te mostraré cómo eliminar una rama remota en Git. Pero primero, veamos cómo eliminar una rama local. Usaré Git bash en este artículo porque hace que trabajar con ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/eliminar-ramas-remotas-como-eliminar-ramas-remotas-en-git/</link>
                <guid isPermaLink="false">6557750fbcc2a003e70e295a</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Tue, 21 Nov 2023 17:11:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/11/pexels-nidhi-tokas-dahiya-867677.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-delete-remote-branch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Delete Remote Branch – How to Remove a Remote Branch in Git</a>
      </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/size/w2000/2022/08/pexels-nidhi-tokas-dahiya-867677.jpg" class="kg-image" alt="Git Delete Remote Branch – How to Remove a Remote Branch in Git" width="600" height="400" loading="lazy"></figure><p>Cuando trabaja con Git, es posible que desee eliminar ramas remotas enviadas a plataformas como GitHub por varios motivos.</p><p>En este artículo, te mostraré cómo eliminar una rama remota en Git. Pero primero, veamos cómo eliminar una rama local.</p><p>Usaré Git bash en este artículo porque hace que trabajar con Git sea más fácil que con cualquier otro terminal. Pero está bien si usas otro terminal. Los comandos siguen siendo los mismos. </p><h1 id="c-mo-eliminar-una-rama-local-en-git">Cómo eliminar una rama local en Git</h1><p>Ejecute <code>git branch</code> o <code>git branch -a</code> para ver las ramas que ha creado para su proyecto. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss1-3.png" class="kg-image" alt="ss1-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss1-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss1-3.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss1-3.png 1463w" sizes="(min-width: 720px) 720px" width="1463" height="396" loading="lazy"></figure><p>Si ejecuta <code>git branch -a</code> en particular, hará que enliste las ramas remotas sean por separado. Esta es una característica que he visto sólo en Git bash.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss2-3-7.png" class="kg-image" alt="ss2-3-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss2-3-7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss2-3-7.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss2-3-7.png 1463w" sizes="(min-width: 720px) 720px" width="1463" height="403" loading="lazy"></figure><p>En esta situación, <code>test-branch2</code> es una rama local que todavía tengo que mandar a GitHub. </p><p>Para eliminar una rama local, ejecute <code>git branch -d nombre-rama</code>.</p><p>Si escribe el comando correctamente, recibirá una respuesta de que la rama ha sido eliminada. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss3-3.png" class="kg-image" alt="ss3-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss3-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss3-3.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss3-3.png 1452w" sizes="(min-width: 720px) 720px" width="1452" height="396" loading="lazy"></figure><h1 id="c-mo-eliminar-una-rama-remota-en-git">Cómo eliminar una rama remota en Git</h1><p>Si intenta eliminar una rama remota con el mismo comando que se usa para eliminar una rama local, recibirá un mensaje de que la rama ha sido eliminada. Pero si ejecuta <code>git branch -a</code>, la rama seguirá apareciendo en la lista. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss4-4-7.png" class="kg-image" alt="ss4-4-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss4-4-7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss4-4-7.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss4-4-7.png 1462w" sizes="(min-width: 720px) 720px" width="1462" height="404" loading="lazy"></figure><p>Y si revisas GitHub, la rama seguirá ahí:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss5-4.png" class="kg-image" alt="ss5-4" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss5-4.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss5-4.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss5-4.png 1139w" sizes="(min-width: 720px) 720px" width="1139" height="518" loading="lazy"></figure><p>Para eliminar completamente una rama remota, debe usar el comando <code>git push origin</code> con la bandera <code>-d</code> y luego especificar el nombre de la rama remota.</p><p>Entonces, la sintaxis que representa el comando para eliminar una rama remota se ve así: <code>git push origin -d nombre-rama</code>.</p><p>Por ejemplo, para eliminar la rama <code>test-branch1</code> ejecute <code>git push origin -d test-branch1</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss6-3.png" class="kg-image" alt="ss6-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss6-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss6-3.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss6-3.png 1461w" sizes="(min-width: 720px) 720px" width="1461" height="426" loading="lazy"></figure><p>Para verificar que la rama remota se haya eliminado, ejecute <code>git branch -a</code> nuevamente.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss7-2.png" class="kg-image" alt="ss7-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss7-2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss7-2.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss7-2.png 1468w" sizes="(min-width: 720px) 720px" width="1468" height="335" loading="lazy"></figure><p>Puede ver que la rama remota, <code>test-branch1</code>, ya no aparece en la lista.</p><p>Si revisas nuevamente GitHub, no estará allí:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss8-2.png" class="kg-image" alt="ss8-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/11/ss8-2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/11/ss8-2.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/11/ss8-2.png 1383w" sizes="(min-width: 720px) 720px" width="1383" height="481" loading="lazy"></figure><h1 id="para-terminar-">Para terminar...</h1><p>Tenga en cuenta que, para eliminar completamente una rama de Git de su proyecto, debe usar el comando <code>git push origin</code>.</p><p>Eso es porque ya has mandado la rama a GitHub. Entonces, ejecutar el comando <code>git branch -d</code> solo eliminará la rama localmente. </p><p>Si tienes problemas para trabajar con Git, te sugiero que cambies tu terminal a Git bash. Esto se debe a que tiene resaltado de sintaxis para todo, lo que facilita el trabajo con Git. </p><p>Gracias por leer. </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo crear una rama local en Git ]]>
                </title>
                <description>
                    <![CDATA[ Al realizar cambios en un repositorio de Git, la mejor práctica es hacer push de los cambios a una rama diferente. Esto permite comparar los cambios antes de hacer un pull request y finalmente fusionar las ramas.  Esto es esencialmente crucial cuando se trabaja con otros desarrolladores. La rama ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-una-rama-local-en-git/</link>
                <guid isPermaLink="false">65402204e76d6303de0db7a5</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Tue, 07 Nov 2023 06:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/10/cover-template.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-create-a-local-git-branch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Create a Local Branch in Git</a>
      </p><p>Al realizar cambios en un repositorio de Git, la mejor práctica es hacer push de los cambios a una rama diferente. Esto permite comparar los cambios antes de hacer un pull request y finalmente fusionar las ramas. </p><p>Esto es esencialmente crucial cuando se trabaja con otros desarrolladores.</p><p>La rama <code>main</code> de tu repositorio es considerada como la rama principal, es la única rama presente por defecto. Ahora repasemos rápidamente cómo crear ramas en Git. </p><h2 id="c-mo-crear-ramas-en-git"><strong>Cómo crear ramas en Git</strong></h2><p>En esencia, hay dos métodos para crear ramas en Git.</p><p>Puede usar un sólo comando para crear la rama y moverse a ella. O bien, puede crear la rama primero con un comando y luego moverse a ella con otro comando cuando desee trabajar en esa rama. </p><p>Aquí está una versión rápida del código:</p><pre><code class="language-bash">// crear una rama y moverse a esa rama
$ git checkout -b &lt;nombre-rama&gt;

// crear sólo una rama
$ git branch &lt;nombre-rama&gt;</code></pre><h3 id="c-mo-crear-una-rama-en-git-y-moverse-a-esa-nueva-rama"><strong>Cómo crear una rama en Git y moverse a esa nueva rama</strong></h3><p>Podemos crear una nueva rama y moverse a ella usando el comando <code>git checkout</code> con la opción <code>-b</code> y <code>&lt;nombre-rama&gt;</code>. Se ve así: </p><pre><code class="language-bash">$ git checkout -b &lt;branch-name&gt;</code></pre><p>Supongamos que queremos crear una nueva rama de Git llamada "paginación" a partir de la rama <code>main</code>. Para lograr esto, usaremos el comando <code>git checkout</code> con la opción <code>-b</code> seguido del nombre de la rama "paginación".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/10/s_E7E3F14C4905C4CE20AE3FDC33EFE78C3CAFED59288B605B89A9E40497700515_1657112003074_branch.gif" class="kg-image" alt="s_E7E3F14C4905C4CE20AE3FDC33EFE78C3CAFED59288B605B89A9E40497700515_1657112003074_branch" width="1456" height="608" loading="lazy"></figure><p>Como puede ver, creamos una nueva rama y el comando checkout hizo que nuestra rama cambiara automáticamente de "main" a "paginación".</p><p>Veamos ahora cómo crear una rama en Git sin movernos a ella. </p><h2 id="c-mo-crear-una-rama-en-git-sin-movernos-a-la-nueva-rama"><strong>Cómo crear una rama en Git sin movernos a la nueva rama</strong></h2><p>Este es el método estándar para crear una rama usando el comando <code>git branch</code> y especificando el nombre de la rama en Git que desea crear.</p><pre><code class="language-bash">$ git branch &lt;nombre-rama&gt;</code></pre><p>Por ejemplo, como hicimos anteriormente, podemos crear una rama "paginación" para reemplazar con "paginación". Así es como se vería: </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/10/s_E7E3F14C4905C4CE20AE3FDC33EFE78C3CAFED59288B605B89A9E40497700515_1657114781462_switch.gif" class="kg-image" alt="s_E7E3F14C4905C4CE20AE3FDC33EFE78C3CAFED59288B605B89A9E40497700515_1657114781462_switch" width="1456" height="608" loading="lazy"></figure><p>Como puede ver, la rama no cambió, pero se creó una nueva rama. Para ver una lista de todas las ramas disponibles, puede usar este comando:</p><pre><code class="language-git">$ git branch
</code></pre><p>Finalmente, supongamos que más tarde deseamos cambiar a nuestra nueva rama en Git o a cualquier otra rama que hayamos creado anteriormente. En este caso, podemos hacer uso del comando <code>git checkout</code>.</p><pre><code class="language-bash">$ git checkout &lt;branch-name&gt;
</code></pre><h2 id="conclusi-n"><strong>Conclusión</strong> </h2><p>En este artículo, aprendimos a usar comandos de Git en nuestra terminal para crear una rama localmente. </p><p>Si queremos agregar esta rama de forma remota, todo lo que tenemos que hacer es enviarla a nuestro proveedor de Git como GitHub usando el siguiente comando:</p><pre><code class="language-bash">$ git push -u origin &lt;nombre-rama&gt;</code></pre><p>Aprende a <a href="https://joelolawanle.com/posts/how-to-clone-a-specific-branch-with-git">clonar una rama específica con Git con este artículo</a>. &nbsp;</p><p>¡Feliz codificación! </p><p>Puedes acceder a más de 200 de mis artículos <a href="https://joelolawanle.com/contents">visitando mi sitio web</a>. También puedes usar el campo de búsqueda para ver si he escrito un artículo específico. </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Hoja de referencia de Git: 50 comandos de Git que debes conocer ]]>
                </title>
                <description>
                    <![CDATA[ Git es un sistema de control de versiones distribuido que ayuda a los desarrolladores a colaborar en proyectos de cualquier escala. Linus Torvalds, el desarrollador del kernel de Linux, creó Git en 2005 para ayudar a controlar el desarrollo de este. ¿Qué es un sistema de control de versiones distribuido? ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/hoja-de-referencia-de-git-50-comandos-de-git-que-debe-conocer-2/</link>
                <guid isPermaLink="false">62f5b5ab7b4ec209a4023368</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miguel Rendón ]]>
                </dc:creator>
                <pubDate>Wed, 15 Mar 2023 14:40:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/03/git.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-cheat-sheet/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Cheat Sheet – 50 Git Commands You Should Know</a>
      </p><p>Git es un sistema de control de versiones distribuido que ayuda a los desarrolladores a colaborar en proyectos de cualquier escala.</p><p>Linus Torvalds, el desarrollador del kernel de Linux, creó Git en 2005 para ayudar a controlar el desarrollo de este.</p><h2 id="-qu-es-un-sistema-de-control-de-versiones-distribuido">¿Qué es un sistema de control de versiones distribuido?</h2><p>Un sistema de control de versiones distribuido es un sistema que ayuda a realizar un seguimiento de los cambios hechos en los archivos de tu proyecto.</p><p>Este historial de cambios vive en tu máquina local y te permite volver a una versión anterior de tu proyecto con facilidad en caso de que algo salga mal.</p><p>Git facilita la colaboración. Cada miembro del equipo puede mantener una copia de seguridad completa de los repositorios en los que está trabajando en su máquina local. Luego, gracias a un servidor externo como BitBucket, GitHub o GitLab, puede almacenar el repositorio de forma segura en un solo lugar.</p><p>De esta forma, diferentes miembros del equipo pueden copiarlo localmente y todos tienen una clara visión general de todos los cambios realizados por todo el equipo.</p><p>Git tiene muchos comandos diferentes que puedes usar. Y descubrí que estos cincuenta son los que uso con más frecuencia (y, por lo tanto, son los más útiles para recordar).</p><p>Así que los anoté y pensé que sería bueno compartirlos con la comunidad. Espero que los encuentres útiles – Disfrútalos.</p><h2 id="c-mo-verificar-tu-configuraci-n-de-git-">Cómo verificar tu configuración de Git:</h2><p>El siguiente comando devuelve una lista de información sobre tu configuración de Git, incluido el nombre de usuario y el correo electrónico:</p><pre><code>git config -l
</code></pre><h2 id="c-mo-configurar-tu-nombre-de-usuario-de-git-">Cómo configurar tu nombre de usuario de Git:</h2><p>Con el siguiente comando puedes configurar tu nombre de usuario:</p><pre><code>git config --global user.name "Fabio"
</code></pre><h2 id="c-mo-configurar-tu-usuario-de-correo-electr-nico-de-git-">Cómo configurar tu usuario de correo electrónico de Git:</h2><p>Este comando te permite configurar la dirección de correo electrónico del usuario que utilizarás en tus confirmaciones.</p><pre><code>git config --global user.email "inscripciones@fabiopacifici.com"</code></pre><h2 id="c-mo-almacenar-en-cach-tus-credenciales-de-inicio-de-sesi-n-en-git-">Cómo almacenar en caché tus credenciales de inicio de sesión en Git:</h2><p>Puedes almacenar las credenciales de inicio de sesión en el caché para que no tengas que escribirlas cada vez. Solo usa este comando:</p><pre><code>git config --global credential.helper cache
</code></pre><h2 id="c-mo-inicializar-un-repositorio-git-">Cómo inicializar un repositorio Git:</h2><p>Todo comienza desde aquí. El primer paso es inicializar un nuevo repositorio de Git localmente en la raíz de tu proyecto. Puedes hacerlo con el siguiente comando:</p><pre><code>git init
</code></pre><h2 id="c-mo-agregar-un-archivo-al-rea-de-preparaci-n-en-git-">Cómo agregar un archivo al área de preparación en Git:</h2><p>El siguiente comando agregará un archivo al área de preparación. Simplemente, reemplaza el <code>nombre_de_archivo_aquí</code> con el nombre del archivo que deseas agregar al área de preparación.</p><pre><code>git add nombre_de_archivo_aquí
</code></pre><h2 id="c-mo-agregar-todos-los-archivos-en-el-rea-de-preparaci-n-en-git">Cómo agregar todos los archivos en el área de preparación en Git</h2><p>Si deseas agregar todos los archivos de tu proyecto al área de preparación, puedes usar un comodín <code>.</code> y cada archivo se agregará para ti.</p><pre><code>git add .
</code></pre><h2 id="c-mo-agregar-ciertos-archivos-al-rea-de-preparaci-n-en-git">Cómo agregar ciertos archivos al área de preparación en Git</h2><p>Con el asterisco en el siguiente comando, puedes agregar todos los archivos que comienzan con <code>fil</code> en el área de preparación.</p><pre><code>git add fil*
</code></pre><h2 id="c-mo-verificar-el-estado-de-un-repositorio-en-git-">Cómo verificar el estado de un repositorio en Git:</h2><p>Este comando mostrará el estado del repositorio actual, incluidos los archivos preparados, no preparados y sin seguimiento.</p><pre><code>git status
</code></pre><h2 id="c-mo-confirmar-cambios-en-el-editor-en-git-">Cómo confirmar cambios en el editor en Git:</h2><p>Este comando abrirá un editor de texto en la terminal donde podrás escribir un mensaje de confirmación completo.</p><p>Un mensaje de confirmación se compone de un breve resumen de los cambios, una línea vacía y una descripción completa de los cambios posteriores.</p><pre><code>git commit
</code></pre><h2 id="c-mo-confirmar-cambios-con-un-mensaje-en-git-">Cómo confirmar cambios con un mensaje en Git:</h2><p>Puedes agregar un mensaje de confirmación sin abrir el editor. Este comando solo te permite especificar un breve resumen para tu mensaje de confirmación.</p><pre><code>git commit -m "tu mensaje de confirmación aquí"
</code></pre><h2 id="c-mo-confirmar-cambios-y-omitir-el-rea-de-preparaci-n-en-git-">Cómo confirmar cambios (y omitir el área de preparación) en Git:</h2><p>Puedes agregar y confirmar archivos rastreados con un solo comando utilizando las opciones <code>-a</code> y <code>-m</code>.</p><pre><code>git commit -a -m"tu mensaje de confirmación aquí"
</code></pre><h2 id="c-mo-ver-tu-historial-de-confirmaciones-en-git-">Cómo ver tu historial de confirmaciones en Git:</h2><p>Este comando muestra el historial de confirmación del repositorio actual:</p><pre><code>git log
</code></pre><h2 id="c-mo-ver-tu-historial-de-confirmaciones-incluidos-los-cambios-en-git-">Cómo ver tu historial de confirmaciones, incluidos los cambios en Git:</h2><p>Este comando muestra el historial de confirmaciones, incluidos todos los archivos y sus cambios:</p><pre><code>git log -p
</code></pre><h2 id="c-mo-ver-una-confirmaci-n-espec-fica-en-git-">Cómo ver una confirmación específica en Git:</h2><p>Este comando muestra una confirmación específica.</p><p>Reemplaza <code>commit-id</code> con el <code>id</code> de la confirmación que se encuentra en el registro de confirmación después de la palabra <code>commit</code>.</p><pre><code>git show commit-id
</code></pre><h2 id="c-mo-ver-las-estad-sticas-de-registro-en-git-">Cómo ver las estadísticas de registro en Git:</h2><p>Este comando hará que el registro de Git muestre algunas estadísticas sobre los cambios en cada confirmación, incluidas las líneas cambiadas y los nombres de los archivos.</p><pre><code>git log --stat
</code></pre><h2 id="c-mo-ver-los-cambios-realizados-antes-de-confirmarlos-usando-diff-en-git-">Cómo ver los cambios realizados antes de confirmarlos usando "diff" en Git:</h2><p>Puedes pasar un archivo como parámetro para ver solo los cambios en un archivo específico.<br><code>git diff</code> muestra solo los cambios sin preparar de forma predeterminada.</p><p>Podemos llamar a diff con el indicador <code>--staged</code> para ver cualquier cambio por etapas.</p><pre><code>git diff
git diff mi_archivo.py
git diff --staged
</code></pre><h2 id="c-mo-ver-los-cambios-usando-git-add-p-">Cómo ver los cambios usando "git add -p":</h2><p>Este comando abre un aviso y te pregunta si deseas realizar cambios o no, e incluye otras opciones.</p><pre><code>git add -p
</code></pre><h2 id="c-mo-eliminar-archivos-rastreados-del-rbol-de-trabajo-actual-en-git-">Cómo eliminar archivos rastreados del árbol de trabajo actual en Git:</h2><p>Este comando espera un mensaje de confirmación para explicar por qué se eliminó el archivo.</p><pre><code>git rm nombre_del_archivo
</code></pre><h2 id="c-mo-cambiar-el-nombre-de-los-archivos-en-git-">Cómo cambiar el nombre de los archivos en Git:</h2><p>Este comando prepara los cambios, luego espera un mensaje de confirmación.</p><pre><code>git mv archivo_viejo archivo_nuevo
</code></pre><h2 id="c-mo-ignorar-archivos-en-git-">Cómo ignorar archivos en Git:</h2><p>Crea un archivo <code>.gitignore</code> y confírmalo.</p><h2 id="c-mo-revertir-cambios-no-preparados-en-git-">Cómo revertir cambios no preparados en Git:</h2><pre><code>git checkout nombre_del_archivo
</code></pre><h2 id="c-mo-revertir-los-cambios-por-etapas-en-git-">Cómo revertir los cambios por etapas en Git:</h2><p>Puedes usar el indicador &nbsp;<code>-p</code> para especificar los cambios que deseas restablecer.</p><pre><code>git reset HEAD nombre_del_archivo
git reset HEAD -p
</code></pre><h2 id="c-mo-modificar-la-confirmaci-n-m-s-reciente-en-git-">Cómo modificar la confirmación más reciente en Git:</h2><p><code>git commit --amend</code> te permite modificar y agregar cambios a la confirmación más reciente.</p><pre><code>git commit --amend
</code></pre><p>!Nota!: Arreglar una confirmación local con <code>ammend</code> es excelente y puedes enviarlo a un repositorio compartido después de que lo hayas arreglado. Pero debes evitar modificar las confirmaciones que ya se han hecho públicas.</p><h2 id="c-mo-revertir-la-ltima-confirmaci-n-en-git-">Cómo revertir la última confirmación en Git:</h2><p><code>git revert</code> creará una nueva confirmación que es lo opuesto a todo en la confirmación dada. Podemos revertir la última confirmación usando el alias principal como este:</p><pre><code>git revert HEAD
</code></pre><h2 id="c-mo-revertir-una-confirmaci-n-antigua-en-git-">Cómo revertir una confirmación antigua en Git:</h2><p>Puedes revertir una confirmación anterior usando su <code>id</code> de confirmación. Esto abre el editor para que pueda agregar un mensaje de confirmación.</p><pre><code>git revert confirmación_id_aquí
</code></pre><h2 id="c-mo-crear-una-nueva-rama-en-git-">Cómo crear una nueva rama en Git:</h2><p>Por defecto, tienes una rama, la rama principal. Con este comando, puedes crear una nueva rama. Git no lo cambiará automáticamente; deberás hacerlo manualmente con el siguiente comando.</p><pre><code>git branch nombre_de_la_rama
</code></pre><h2 id="c-mo-cambiar-a-una-rama-reci-n-creada-en-git-">Cómo cambiar a una rama recién creada en Git:</h2><p>Cuando quieras usar una rama diferente o recién creada, puedes usar este comando:</p><pre><code>git checkout nombre_de_la_rama
</code></pre><h2 id="c-mo-listar-ramas-en-git-">Cómo listar ramas en Git:</h2><p>Puedes ver todas las ramas creadas usando el comando <code>git branch</code>. Mostrará una lista de todas las ramas y marcará la rama actual con un asterisco y la resaltará en verde.</p><pre><code>git branch
</code></pre><h2 id="c-mo-crear-una-rama-en-git-y-cambiar-a-ella-inmediatamente-">Cómo crear una rama en Git y cambiar a ella inmediatamente:</h2><p>Con un solo comando, puedes crear y cambiar a una nueva rama de inmediato.</p><pre><code>git checkout -b nombre_de_la_rama
</code></pre><h2 id="c-mo-eliminar-una-rama-en-git-">Cómo eliminar una rama en Git:</h2><p>Cuando hayas terminado de trabajar con una rama y la hayas fusionado, puedes eliminarla usando el siguiente comando:</p><pre><code>git branch -d nombre_de_la_rama
</code></pre><h2 id="c-mo-fusionar-dos-ramas-en-git-">Cómo fusionar dos ramas en Git:</h2><p>Para fusionar el historial de la rama en la que te encuentras actualmente con el <code>nombre_de_otra_rama</code>, debes usar el siguiente comando:</p><pre><code>git merge nombre_de_otra_rama
</code></pre><h2 id="c-mo-mostrar-el-registro-de-confirmaci-n-como-un-gr-fico-en-git-">Cómo mostrar el registro de confirmación como un gráfico en Git:</h2><p>Podemos usar <code>--graph</code> para que el registro de confirmación se muestre como un gráfico. Además, <code>--oneline</code> limitará los mensajes de confirmación a una sola línea.</p><pre><code>git log --graph --oneline
</code></pre><h2 id="c-mo-mostrar-el-registro-de-confirmaci-n-como-un-gr-fico-de-todas-las-ramas-en-git-">Cómo mostrar el registro de confirmación como un gráfico de todas las ramas en Git:</h2><p>Hace lo mismo que el comando anterior, pero para todas las ramas.</p><pre><code>git log --graph --oneline --all
</code></pre><h2 id="c-mo-cancelar-una-fusi-n-conflictiva-en-git-">Cómo cancelar una fusión conflictiva en Git:</h2><p>Si deseas descartar una fusión y comenzar de nuevo, puedes ejecutar el siguiente comando:</p><pre><code>git merge --abort
</code></pre><h2 id="c-mo-agregar-un-repositorio-remoto-en-git">Cómo agregar un repositorio remoto en Git</h2><p>Este comando agrega un repositorio remoto a tu repositorio local (simplemente reemplaza <code>https://repositorio_aquí</code> con la URL de su repositorio remoto).</p><pre><code>git add remote https://repositorio_aquí
</code></pre><h2 id="c-mo-ver-las-url-remotas-en-git-">Cómo ver las URL remotas en Git:</h2><p>Puedes ver todos los repositorios remotos de tu repositorio local con este comando:</p><pre><code>git remote -v
</code></pre><h2 id="c-mo-obtener-m-s-informaci-n-sobre-un-repositorio-remoto-en-git-">Cómo obtener más información sobre un repositorio remoto en Git:</h2><p>Simplemente reemplaza <code>origin</code> con el nombre del repositorio remoto obtenido al ejecutar el comando <code>git remote -v</code>.</p><pre><code>git remote show origin
</code></pre><h2 id="c-mo-enviar-cambios-a-un-repositorio-remoto-en-git-">Cómo enviar cambios a un repositorio remoto en Git:</h2><p>Cuando todo tu trabajo esté listo para guardarse en un repositorio remoto, puedes enviar todos los cambios con el siguiente comando:</p><pre><code>git push
</code></pre><h2 id="c-mo-extraer-cambios-de-un-repositorio-remoto-en-git-">Cómo extraer cambios de un repositorio remoto en Git:</h2><p>Si otros miembros del equipo están trabajando en tu repositorio, puedes recuperar los últimos cambios realizados en el repositorio remoto con el siguiente comando:</p><pre><code>git pull
</code></pre><h2 id="c-mo-verificar-las-ramas-remotas-que-git-est-rastreando-">Cómo verificar las ramas remotas que Git está rastreando:</h2><p>Este comando muestra el nombre de todas las ramas remotas que Git está rastreando para el repositorio actual:</p><pre><code>git branch -r

</code></pre><h2 id="c-mo-obtener-cambios-de-repositorios-remotos-en-git-">Cómo obtener cambios de repositorios remotos en Git:</h2><p>Este comando descargará los cambios desde un repositorio remoto, pero no realizará una fusión en tu rama local (ya que git pull lo hace en su lugar).</p><pre><code>git fetch
</code></pre><h2 id="c-mo-verificar-el-registro-de-confirmaciones-actual-de-un-repositorio-remoto-en-git">Cómo verificar el registro de confirmaciones actual de un repositorio remoto en Git</h2><p>Confirmación tras confirmación, Git crea un registro. Puedes encontrar el registro del repositorio remoto usando este comando:</p><pre><code>git log origin/main
</code></pre><h2 id="c-mo-fusionar-un-repositorio-remoto-con-tu-repositorio-local-en-git-">Cómo fusionar un repositorio remoto con tu repositorio local en Git:</h2><p>Si el repositorio remoto tiene cambios que deseas fusionar con tu repositorio local, este comando lo hará por ti:</p><pre><code>git merge origin/main
</code></pre><h2 id="c-mo-obtener-el-contenido-de-ramas-remotas-en-git-sin-fusionarlas-autom-ticamente-">Cómo obtener el contenido de ramas remotas en Git sin fusionarlas automáticamente:</h2><p>Esto te permite actualizar la rama remota sin fusionar ningún contenido en las ramas locales. Puedes llamar a <code>git merge</code> o <code>git checkout</code> para realizar la fusión.</p><pre><code>git remote update
</code></pre><h2 id="c-mo-enviar-una-nueva-rama-a-un-repositorio-remoto-en-git-">Cómo enviar una nueva rama a un repositorio remoto en Git:</h2><p>Si deseas enviar una rama a un repositorio remoto, puedes usar el siguiente comando. Solo recuerda agregar <code>-u</code> para crear la rama upstream:</p><pre><code>git push -u origin nombre_de_la_rama

</code></pre><h2 id="c-mo-eliminar-una-rama-remota-en-git-">Cómo eliminar una rama remota en Git:</h2><p>Si ya no necesitas una sucursal remota, puedes eliminarla usando el siguiente comando:</p><pre><code>git push --delete origin nombre_de_la_rama_aquí
</code></pre><h2 id="c-mo-usar-git-rebase-">Cómo usar Git rebase:</h2><p>Puedes transferir el trabajo completado de una rama a otra usando <code>git rebase</code>.</p><pre><code>git rebase nombre_de_la_rama_aquí
</code></pre><p>Git Rebase puede complicarse mucho si no lo haces correctamente. Antes de usar este comando, te sugiero que vuelvas a leer la documentación oficial <a href="https://www.freecodecamp.org/espanol/news/la-guia-definitiva-para-git-merge-y-git-rebase/">aquí</a>.</p><h2 id="c-mo-ejecutar-rebase-de-forma-interactiva-en-git-">Cómo ejecutar rebase de forma interactiva en Git:</h2><p>Puedes ejecutar git rebase de forma interactiva usando el indicador <code>-i</code>. Abrirá el editor y presentará un conjunto de comandos que puedes usar. </p><pre><code>git rebase -i master
# p, pick = usar confirmación.
# r, reword = usar confirmación pero editar el mensaje de confirmación.
# e, edit = usar confirmación pero detenerse para modificar.
# s, squash = usar confirmación pero fusionarla con la confirmación anterior.
# f, fixup = como "squash", pero descartando el mensaje de confirmación.
# x, exec = ejecutar comando (el resto de la linea) usando shell.
# d, drop = eliminar confirmación.
</code></pre><h2 id="c-mo-forzar-una-solicitud-push-en-git-">Cómo forzar una solicitud push en Git:</h2><p>Este comando forzará una solicitud de inserción <code>(push)</code>. Por lo general, esto está bien para las ramas de solicitud de extracción <code>(pull request)</code>, &nbsp;porque nadie más debería haberlas clonado. Pero esto no es algo que desees hacer con repositorios públicos.</p><pre><code>git push -f
</code></pre><h2 id="conclusi-n">Conclusión</h2><p>Estos comandos pueden mejorar drásticamente tu productividad en Git. No tienes que recordarlos todos, por eso he escrito esta hoja de trucos. Marca esta página para futuras referencias o imprímela si lo deseas.</p><p>¡Gracias por leer! Por cierto, soy Fabio, desarrollador web full-stack, docente, y profesional certificado en automatización de IT con Python.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de la rama remota Git Checkout ]]>
                </title>
                <description>
                    <![CDATA[ Git es una herramienta de control de versiones que le permite mantener y ver diferentes versiones de su aplicación. Cuando una nueva actualización rompe su aplicación, Git le permite revertir esos cambios a la versión anterior. Además del control de versiones, Git le permite trabajar en múltiples entornos al mismo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-de-la-rama-remota-git-checkout/</link>
                <guid isPermaLink="false">63cb2378700708073437bf6e</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Tue, 24 Jan 2023 18:44:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screen-Shot-2023-01-20-at-7.10.52-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-checkout-remote-branch-tutorial/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Checkout Remote Branch Tutorial</a>
      </p><p>Git es una herramienta de control de versiones que le permite mantener y ver diferentes versiones de su aplicación. Cuando una nueva actualización rompe su aplicación, Git le permite revertir esos cambios a la versión anterior.</p><p>Además del control de versiones, Git le permite trabajar en múltiples entornos al mismo tiempo. Múltiples entornos en este contexto significa <strong>ramas</strong>.</p><h2 id="-por-qu-necesitas-ramas"><strong>¿Por qué necesitas ramas?</strong></h2><p>Cuando trabajes con git, tendrás un entorno maestro (también llamado principal) (rama). Esta rama en particular contiene el código fuente que se implementa cuando su aplicación está lista para la producción.</p><p>Cuando desees actualizar su aplicación, también puedes agregar más cambios (commits) a esta rama. Para cambios menores, esto puede no ser un gran problema, pero para cambios grandes, hacer esto no es lo ideal. Y es por eso que existen otras ramas.</p><p>Para crear y usar una nueva rama, usa el siguiente comando en tu terminal en el directorio del proyecto:</p><pre><code class="language-shell"># crear una nueva rama
git branch rama-nombre
# cambiar el ambiente a la nueva rama
git checkout rama-nombre
</code></pre><p>En esta nueva rama, puede crear los nuevos cambios. Luego, cuando hayas terminado, puedes combinarlos con la rama maestra.</p><p>Otro beneficio de las ramas es que permiten que varios desarrolladores trabajen en el mismo proyecto simultáneamente. Si tienes varios desarrolladores trabajando en la misma rama maestra, puede ser desastroso. Tiene demasiados cambios entre el código de cada desarrollador, y esto generalmente termina en conflictos de combinación.</p><p>Con Git, puede saltar a otra rama (otro entorno) y realizar cambios allí, mientras se trabaja en otras ramas.</p><h2 id="-qu-significa-rama-remota-de-git-checkout"><strong>¿Qué significa rama remota de Git Checkout?</strong></h2><p>Cuando comienzas un proyecto con Git, obtiene dos entornos: la rama maestra local (que existe en su computadora) y la rama maestra remota (que existe en una plataforma compatible con Git como GitHub).</p><p>Puedes enviar cambios desde la rama principal local a la rama principal remota y también extraer cambios de la rama remota.</p><p>Cuando creas una rama localmente, solo existe localmente hasta que se envía a GitHub, donde se convierte en la rama remota. Esto se muestra en el siguiente ejemplo:</p><pre><code class="language-shell"># crear una nueva rama
git branch nueva-rama
# cambiar el ambiente a la nueva rama
git checkout nueva-rama
# crear un cambio
touch nuevo-archivo.js
# cometer el cambio
git add .
git commit -m "añadir nuevo archivo"
# empujar a una nueva rama
git push --set-upstream origin nueva-rama
</code></pre><p>Del ejemplo anterior, <code>origin nueva-rama</code> se convierte en la rama remota. Como habrás notado, creamos una nueva rama y confirmamos un cambio en ella antes de pasar a la nueva rama remota.</p><p>Pero, ¿qué pasaría si la rama remota ya existiera y quisiéramos llevar la rama y todos sus cambios a nuestro entorno local?</p><p>Ahí es donde hacemos una "Rama Remota de Git Checkout".</p><h2 id="c-mo-hacer-git-checkout-en-una-rama-remota">Cómo hacer Git Checkout en una rama remota</h2><p>Digamos que hay una rama remota creada por otro desarrollador y desea extraer esa rama. Así es como lo haces:</p><h3 id="1-recuperar-todas-las-ramas-remotas"><strong>1. Recuperar todas las ramas remotas</strong></h3><pre><code class="language-shell">git fetch origin
</code></pre><p>Esto recupera todas las ramas remotas del repositorio. <code>origin</code> es el nombre remoto al que se dirige. Entonces, si tenía un nombre remoto <code>upstream</code>, puedes llamar a <code>git fetch upstream</code>.</p><h3 id="2-enumera-las-ramas-disponibles-para-checkout"><strong>2. Enumera las ramas disponibles para checkout</strong></h3><p>Para ver las ramas disponibles para checkout, ejecute lo siguiente:</p><pre><code class="language-shell">git branch -a
</code></pre><p>El resultado de este comando es la lista de ramas disponibles para checkout. Para las ramas remotas, las encontrará con el prefijo <code>remotes/origin</code>.</p><h3 id="3-obtener-cambios-de-una-rama-remota"><strong>3. Obtener cambios de una rama remota</strong></h3><p>Tenga en cuenta que no puedes hacer cambios directamente en una rama remota. Por lo tanto, necesitas una copia de esa rama. Digamos que deseas copiar <code>fix-failing-tests</code> de la rama remota, así es como lo harías:</p><pre><code class="language-shell">git checkout -b fix-failing-tests origin/fix-failing-tests
</code></pre><p>Lo que esto hace es:</p><ul><li>crea una nueva rama llamada <code>fix-failing-tests</code></li><li><code>checkout</code> esa rama</li><li>extrae los cambios desde el origin/fix-failing-tests a esa rama</li></ul><p>Y ahora tienes una copia de esa rama remota. Además, puedes enviar confirmaciones a esa rama remota. Por ejemplo, puedes empujar un nuevo compromiso así:</p><pre><code class="language-shell">touch nuevo-archivo.js
git add .
git commit -m "añadir nuevo archivo"
git push
</code></pre><p>Esto empujará los cambios comprometidos a <code>origin/fix-failing-tests</code>. Si te diste cuenta, no tuvimos que especificar dónde estábamos enviando los cambios (como <code>git push origin fix-failing-tests</code>). Eso es porque git configura automáticamente la rama local para rastrear la rama remota.</p><h2 id="conclusi-n">Conclusión</h2><p>La ramificación de Git facilita mucho la colaboración durante el desarrollo de aplicaciones.</p><p>Con las ramas, diferentes desarrolladores pueden trabajar fácilmente en diferentes partes de la aplicación simultáneamente.</p><p>Con la rama remota de Checkout, la colaboración se vuelve incluso más fluida, ya que los desarrolladores también pueden copiar ramas remotas localmente en sus sistemas, realizar cambios y enviarlos a las ramas remotas.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Push a una rama remota:  Cómo cargar una rama local al origen ]]>
                </title>
                <description>
                    <![CDATA[ El comando básico para cargar o subir una rama local a un repositorio remoto es  git push. Este comando tiene una variedad de opciones y parámetros que puedes pasarle, y en este artículo aprenderás los que usarás más a menudo. Cómo subir una rama local de Git al origen ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/git-push-a-una-rama-remota/</link>
                <guid isPermaLink="false">632359eb70a5cb0907d6826e</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sonia Garcia Alcaraz ]]>
                </dc:creator>
                <pubDate>Fri, 21 Oct 2022 00:13:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/09/git-push-to-remote-branch-article.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-push-to-remote-branch-how-to-push-a-local-branch-to-origin/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">https://www.freecodecamp.org/news/git-push-to-remote-branch-how-to-push-a-local-branch-to-origin/</a>
      </p><p>El comando básico para cargar o subir una rama local a un repositorio remoto es <code>git push</code>.</p><p>Este comando tiene una variedad de opciones y parámetros que puedes pasarle, y en este artículo aprenderás los que usarás más a menudo.</p><h2 id="c-mo-subir-una-rama-local-de-git-al-origen-origin-">Cómo subir una rama local de Git al origen (origin)<em> </em></h2><p>Si ejecutas el comando simple <code>git push</code>, por defecto, Git elegirá dos parámetros más por ti: el <strong>repositorio remoto</strong> y la <strong>rama </strong>a la que subir.</p><p>La forma general del comando es esta:</p><figure class="kg-card kg-code-card"><pre><code>$ git push &lt;remote&gt; &lt;branch&gt;</code></pre><figcaption>remote: repositorio remoto / branch: rama</figcaption></figure><p>Por defecto, Git elige <code>origin</code> como remoto y tu <em>rama actual</em> como la rama a la que subir.</p><p>Si tu rama actual es <code>main</code>, el comando <code>git push</code> suministrará los dos parámetros por defecto — ejecutándolo así <code>git push origin main</code>.</p><p>En el ejemplo de abajo, el remoto &nbsp;<code>origin</code> es un repositorio de GitHub, y la rama actual es <code>main</code>:</p><pre><code>(main)$ git remote -v 
origin  git@github.com:johnmosesman/burner-repo.git (fetch)
origin  git@github.com:johnmosesman/burner-repo.git (push)

(main)$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 274 bytes | 274.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/burner-repo.git
   b7f661f..ab77dd6  main -&gt; main
</code></pre><p>De la salida se puede ver que la rama local &nbsp;<code>main</code> fue subida a la rama remota &nbsp;<code>main</code>:</p><pre><code>To github.com:johnmosesman/burner-repo.git
   b7f661f..ab77dd6  main -&gt; main
</code></pre><h2 id="c-mo-forzar-la-subida-a-una-rama-en-git">Cómo forzar la subida a una rama en Git</h2><p>Normalmente, subirás una rama y añadirás a su historial de confirmaciones.</p><p>Sin embargo, hay ocasiones en las que es necesario <strong>sobrescribir </strong>a la fuerza el historial de una rama.</p><p>Hay un par de razones por las que puedes querer hacer esto.</p><p>La primera razón es para corregir un error - aunque probablemente sea mejor hacer una nueva confirmación <a href="https://www.atlassian.com/es/git/tutorials/undoing-changes/git-revert">que revierta los cambios</a> (<a href="https://git-scm.com/docs/git-revert">git revert</a>).</p><p>El segundo y más común escenario es después de una acción como un <strong><a href="https://www.atlassian.com/es/git/tutorials/rewriting-history/git-rebase">rebase</a></strong>, que cambia el historial de confirmaciones:</p><blockquote>Internamente, Git [hace un rebase] creando nuevas confirmaciones y aplicándolas a la base especificada. Es muy importante entender que, aunque la rama parece la misma, se compone de nuevas confirmaciones por completo.</blockquote><p>Un rebase crea <em>confirmaciones completamente nuevas</em>.</p><p>Esto significa que si intentas cargar una rama que ha sido rebasada localmente - pero no en el remoto - el repositorio remoto reconocerá que el historial de confirmaciones ha cambiado, y te impedirá subir los cambios hasta que arregles las diferencias:</p><pre><code>(my-feature)$ git push
To github.com:johnmosesman/burner-repo.git
 ! [rejected]        my-feature -&gt; my-feature (non-fast-forward)
error: failed to push some refs to 'git@github.com:johnmosesman/burner-repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
</code></pre><p>Puedes hacer un <code>git pull</code> para fusionar las diferencias, pero si <em>realmente </em>quieres sobrescribir el repositorio remoto puedes añadir la marca <code>--force</code> :</p><pre><code>(my-feature)$ git push --force origin my-feature
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 184 bytes | 184.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/burner-repo.git
 + edb64e2...52f54da my-feature -&gt; my-feature (forced update)
</code></pre><p>(<strong>Nota:</strong> puedes usar la versión abreviada <code>-f</code> en vez de &nbsp;<code>--force</code>.)</p><p>Una subida forzada es una acción destructiva - úsala solo cuando tengas la certeza de que es lo que quieres hacer.</p><h3 id="forzar-la-subida-con-contrato-force-with-lease-">Forzar la subida con contrato (<code>--force-with-lease</code>)</h3><p>A veces puedes querer forzar la subida - pero solo si nadie más ha contribuido a la rama.</p><p>Si alguien más contribuye a tu rama y empuja sus cambios a la remota - y tú fuerzas, tu subida sobre ella - sobrescribirás sus cambios.</p><p>Para evitar este escenario, puedes utilizar la opción <code>--force-with-lease</code>.</p><p>De nuevo <a href="https://git-scm.com/docs/git-push">de la documentación oficial en inglés:</a></p><blockquote><em>--force-with-lease</em> solo, sin especificar los detalles, protegerá todas las referencias remotas que vayan a ser actualizadas requiriendo que su valor actual sea el mismo que la rama de seguimiento remoto que tenemos para ellas.</blockquote><p>Básicamente, le estás diciendo a Git que fuerce la actualización de esta rama <em>solo si </em>tiene el mismo aspecto que la última vez que la viste.</p><p>Si está colaborando con otros en tu rama, sería bueno evitar usar <code>--force</code> o al menos usar <code>--force-with-lease</code> para evitar perder los cambios que otros colaboradores han hecho.</p><h2 id="c-mo-subir-cambios-a-una-rama-con-diferente-nombre-en-git">Cómo subir cambios a una rama con diferente nombre en Git</h2><p>Normalmente, subirás tu rama local a una rama remota con el mismo nombre - pero no siempre.</p><p>Para subir a una rama con un nombre diferente, necesitas especificar <em>la rama de la que quieres subir los cambios</em> (nombre de la rama local) y el nombre de <em>la rama a la que quieres subir</em> (nombre de la rama remota) separadas con dos puntos (<code>:</code>).</p><p>Por ejemplo, si quieres subir de una rama llamada <code>some-branch</code> a <code>my-feature</code>:</p><figure class="kg-card kg-code-card"><pre><code>(some-branch)$ git push origin some-branch:my-feature
Total 0 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/burner-repo.git
 + 728f0df...8bf04ea some-branch -&gt; my-feature</code></pre><figcaption>some-branch: alguna-rama; my-feature: mi-funcionalidad</figcaption></figure><h3 id="c-mo-subir-todas-las-ramas-locales-al-remoto">Cómo subir todas las ramas locales al remoto</h3><p>No necesitarás subir todas las ramas de tu local muy a menudo, pero si lo haces puedes hacerlo añadiendo la marca <code>--all</code>:</p><pre><code>(main)$ git branch
* main
  my-feature

(main)$ git push --all
...
To github.com:johnmosesman/burner-repo.git
   b7f661f..6e36148  main -&gt; main
 * [new branch]      my-feature -&gt; my-feature
</code></pre><h2 id="conclusi-n">Conclusión</h2><p>El comando <code>git push</code> es uno de los que más a menudo vas a utilizar, y hay un montón de opciones que se pueden utilizar con él. Te animo a leer <a href="https://www.atlassian.com/es/git/tutorials/syncing/git-push">la documentación oficial</a>, para encontrar más opciones y atajos útiles.</p><p>Si te ha gustado este tutorial, también hablo de temas como este <a href="https://twitter.com/johnmosesman">en Twitter</a>, y escribo sobre ellos <a href="https://johnmosesman.com/">en mi página web</a>. </p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
