Continuar trabajando con la aplicación de calculadora simple en C# donde cada estudiante del equipo contribuyó con una operación diferente (suma, resta, multiplicación, división). Practicarás los siguientes comandos de Git: log, revert, checkout y reset, y verás como crear tu repositorio a partir de éste con fork.
Asumimos que has completado el desafío #1 de Git. Deberás continuar trabajando en el repositorio creado en ese ejercicio.
En este paso veremos qué puedes hacer cuando, sin darte cuenta, haces commit
de un cambio incorrecto y quieres volver atrás; con Git es posible usando git revert.
-
Primero confirma que estás en tu rama de trabajo y que no hay modificaciones pendientes. Ejecuta el siguiente comando:
git status
Deberías ver un mensaje similar al siguiente:
On branch <nombre-rama> nothing to commit, working tree clean
Recuerda que
<nombre-rama>es uno de los siguientes:- suma
- resta
- multiplica
- divide
En caso de que la rama no sea la tuya, cámbiate de rama con
git checkoutseguido del nombre de la rama. -
Introduce un cambio incorrecto en la clase que has implementado: por ejemplo, retorna
0como resultado de la operación; si la operación fuera la suma, el código debería quedar así:public class Addition { public static int Add(int a, int b) { return 0; // Cambio incorrecto } }
-
Haz commit de esos cambios, ejecutando los siguientes comandos:
git add . git commit -m "Cambio incorrecto" git push origin <nombre-rama>
Ejecuta el programa con el comando
Run | Run Without Debuggingo en la terminal mediante el siguiente comando:dotnet run --project ./src/Program/Program.csproj
Verás un resultado como el siguiente; el resultado incorrecto dependerá de la operación que hayas implementado:
0 9 9 9
Claramente hay un error —lo hicimos a propósito—; en un escenario real, recién te darías cuenta de que hay algo incorrecto cuando pruebes tu programa. Dependiendo del caso tienes dos opciones: arreglarlo, o ir hacia atrás; en este ejercicio iremos por la segunda opción.
-
Ejecuta
git logpara ver la historia de los cambios, mediante el siguiente comando:git log
La salida luce similar a la siguiente, tú vas a ver más texto:
commit 64c8f1a9812d7ade807430e10dd36d933dd35b7f (HEAD -> suma, origin/suma) Author: Luis Suárez <lucho@nacional.com> Date: Mon Jul 29 10:15:30 2024 +0200 Cambio incorrecto
Este texto no aparece directamente en la consola, sino en un editor de texto llamado
vim. Git muestra la lista en el editorvim, para que puedas recorrerla fácilmente presionando ↑ y ↓ para moverte hacia el inicio o el final, respectivamente.Utiliza el mouse para seleccionar el
<commit-id>, en el ejemplo64c8f1a9812d7ade807430e10dd36d933dd35b7f; luego copia el texto al portapapeles.[!NOTE] Es suficiente con usar los primeros 8 caracteres del
<commit-id>, pero si te da lo mismo, cópialo entero.Una vez que haz copiado el
<commit-id>, debes abandonarvimpresionando Esc, luego : y luego Q, también conocido como command quit.[!TIP] ¿No quieres usar
vimcuando Git te pide editar mensajes de commit? Puedes configurar Git para que use Visual Studio Code. Para ello, ejecuta el siguiente comando en la terminal:git config --global core.editor "code --wait" -
Deshace los cambios usando git revert, seguido del
<commit-id>. Este comando deshace los cambios realizados en el commit indicado y registra un nuevo commit. Ejecuta el siguiente comando, reemplazando<commit-id>por el que copiaste anteriormente, y<nombre-rama>por la rama en la que vienes trabajando.git revert <commit-id> git push origin <nombre-rama>
Nuevamente Git abre
vim—o Visual Studio Code si lo configuraste anteriormente— para que puedas editar tu mensaje para el commit que sem registra al final delgit revert. Puedes editar el mensaje o dejar el mensaje propuesto. En caso de que usesvim, para salir presiona Esc, luego : y luego W, también conocido como command write; a continuación abandonavimpresionando : y luego Q, o command quit. En caso de que uses Visual Studio Code, simplemente guarda y cierra el archivo temporal en el que editaste el mensaje.Puedes examinar el código para ver que luce como antes de introducir el cambio erróneo. Ejecuta el programa nuevamente haciendo clic en el botón
Run 'Program'que aparece en la esquina superior derecha de Rider; o en la terminal mediante el siguiente comando:dotnet run --project ./src/Program/Program.csproj
Verás el resultado correcto nuevamente:
9 9 9 9
Puedes ver cómo lucía el código en cualquier momento de la historia del repositorio utilizando el comando git checkout. Ya has usado este comando, pero ahora tendrá otros parámetros.
-
Utiliza
git logcomo antes para ver la historia de los cambios, mediante el siguiente comando:git log
-
Copia el
<commit-id>de uno de los primeros commits, el que diceInitial commit. Luego ejecuta el siguiente comando:git checkout <commit-id>
Git muestra un mensaje similar al siguiente:
Note: switching to <commit-id>. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example: git switch -c <new-branch-name> Or undo this operation with: git switch - Turn off this advice by setting config variable advice.detachedHead to false HEAD is now at bdd7c4d Initial commit[!TIP]
HEADes lo que usa Git para identificar "el commit donde estás trabajando ahora mismo". HabitualmenteHEADapunta a un commit en la rama actual.Detached headsignifica queHEADapunta a un commit específico en ninguna rama. Mira este link para obtener más información.Examina el código para confirmar que estás viendo la versión inicial antes de que hicieras tus primeros cambios.
[!NOTE] A menos que en este estado crees una rama y hagas algún commit en ella, lo que estás viendo es temporal, es decir, cuando te cambias a otra rama volverá a lo que había en esa rama.
Vuelve a la última versión ejecutando el siguiente comando, donde
<nombre-rama>es el nombre de la rama en la que venías trabajando:git checkout <nombre-rama>
Hay otra forma de deshacer los cambios que hiciste en el paso 1. Revertir un cambio incorrecto. Para mostrarlo vamos a hacer más cambios en nuestro programa.
-
Agrega la siguiente clase al final del archivo Program.cs:
public class Power { public static int Squared(int a) { return a * a; } }
Agrega este cambio en un nuevo commit. Ya deberías saber como hacerlo, pero si no lo recuerdas, estos serían los comandos:
git add . git commit -m "Nueva operación"
-
Agrega un comentario a esa clase, para que el código luzca así:
// Devuelve a al cuadrado public class Power { public static int Squared(int a) { return a * a; } }
Nuevamente agrega este cambio en otro commit; aquí van los comandos:
git add . git commit -m "Agrego comentario"
-
Supongamos que elevar un número al cuadrado no es una operación para nuestra calculadora simple, sino para una calculadora científica. Tenemos que eliminar los dos últimos cambios. Asumamos a efectos de este ejercicio que queremos volver a la situación anterior a agregar estos dos últimos cambios. Podemos hacerlo con git reset, seguido de una referencia a un commit.
[!NOTE] Para este comando, aunque también para otros, el parámetro que indica el commit al que quieres volver, puede ser uno de los siguientes:
HEAD~1referencia un commit antes del actual, digamos, el padre;HEAD~2referencia dos commit antes del actual, digamos, el abuelo; y así sucesivamente. Existen otras referencias, pero con que conozcas estas alcanza por ahora.
[!TIP] Recuerda que
HEADes lo que usa Git para identificar "el commit donde estás trabajando ahora mismo".Este comando tiene tres modos de operación:
-
Reinicio mixto, que es el predeterminado, o sea, cuando no indica un parámetro adicional: el modo predeterminado de
git resetes un reinicio mixto. Mueve el puntero de la rama y elHEADal commit que indiques, mientras limpia la staging area y deja tus cambios en el working folder. Esto es útil cuando deseas eliminar un commit y dejar vacía la staging area, pero mantener los cambios en el working folder. -
Reinicio suave, con el parámetro
--soft: es una forma de deshacer los cambios en tu working folder y volver a un commit específico, mientras mantienes los cambios que hubiera en la staging area. Este modo mueve el puntero de la rama y elHEADal commit que indiques, pero deja los cambios en la staging area. Un reinicio suave se usa a menudo cuando deseas deshacer un commit, pero mantener los cambios en la staging area para otro commit. -
Reinicio completo, con el parámetro
--hard: este modo mueve el puntero de la rama y elHEADal commit indicado, limpia la staging area y descarta cualquier cambio en el working folder. Ten cuidado con este modo, ya que elimina permanentemente los cambios de los que no hayas hecho commit.
La tabla a continuación, resume las diferencias:
Modo Staging area Working folder Uso típico Mixed Queda vacía Mantiene los cambios Deshacer commits recientes, pero conservar cambios para re‑seleccionar qué va al próximo commit Soft Mantiene los cambios Mantiene los cambios Rehacer commits recientes, manteniendo todo listo para volver a hacer commit Hard Queda vacía Vuelve al commit indicado Volver a un estado limpio, descartando cambios no deseados En todos los casos, el commit actual pasa a ser el que indiques al ejecutar el comando.
-
-
Ejecuta los siguientes comandos:
git reset HEAD~1 git status
Verás una salida similar a esta:
On branch ... Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: src/Program/Program.cs no changes added to commit (use "git add" and/or "git commit -a")Esto confirma que la staging area está vacía, y que el archivo
Program.csestá modificado.Examina el archivo
Program.cs, verás que tiene el comentario que hiciste en el último commit.Si ejecutas
git log, verás que el último commit es el de la nueva operación, y no el del comentario. -
Ejecuta ahora los siguientes comandos, pero
git resetcon la opción--hard:git reset --hard HEAD~1 git status
Verás una salida similar a esta:
On branch ... nothing to commit, working tree clean
Esto confirma que la staging area está vacía y que el working folder no tiene modificaciones. Si examinas el archivo
Program.cs, verás que no tiene la operación agregada en este paso. Si ejecutasgit log, verás que el último commit es que hiciste en el paso 1. Revertir un cambio incorrecto de este desafío.
En este paso vamos a ver qué cómo puedes modificar el último commit.
Warning
Idealmente debes modificar el último commit con el comando commit --amend
antes de enviar tus cambios al repositorio remoto con git push. Si el
commit ya está en el repositorio remoto, no te recomendamos usar commit --amend.
-
Agrega al comienzo del método
void Main()de la claseProgramla impresión de un mensaje en la consola conConsole.WriteLine("Demo calculadora");. El código de esa clase debería quedar así:public static class Program { public static void Main() { Console.WriteLine("Demo calculadora"); Console.WriteLine(Addition.Add(1, 2)); Console.WriteLine(Subtraction.Subtract(3, 4)); Console.WriteLine(Multiplication.Multiply(5, 6)); Console.WriteLine(Division.Divide(7, 8)); } }
-
Agrega un nuevo archivo en la raíz de tu repositorio, con el siguiente comando:
echo Demo >> file.txt
Esto crea un archivo llamado
file.txt. -
De forma intencional, a efectos de este ejercicio, haremos commit sólo del archivo
file.txt, pero no de los cambios enProgram.cs. Ejecuta los siguientes comandos:git add file.txt git commit -m "Probando amend" git statusVerás una salida como la siguiente:
On branch ... Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: src/Program/Program.cs no changes added to commit (use "git add" and/or "git commit -a")Ahora podemos querer cambiar dos cosas en el último commit; primero, agregar el archivo que faltó; y luego, cambiar el mensaje.
-
Ejecuta el siguiente comando, para cambiar solamente el mensaje del último commit:
git commit --amend -m "Mensaje en la calculadora"Esto cambiará solamente el mensaje en el último commit. Puedes confirmarlo haciendo
git statuspara ver queProgramsigue en el working folder ygit logpara ver los mensajes de los últimos commit. Si estás usandovimcomo editor para Git -verás:al final de la lista de commits-, recuerda usar Q para salir. -
Ejecuta ahora los siguientes comandos, para agregar el archivo
Program.csal último commit, y quitar el archivofile.txt:git rm --cached file.txt git add src/Program/Program.cs git commit --amend
Git puede mostrar un editor de texto; si estás usando
vimrecuerda que debes usar :, seguido de Q, para salir devim. Podrás ver que el mensaje del último commit no ha cambiado -aunque podrías cambiar el mensaje en el editor de texto-, así como el resultado del commit modificado.El comando
git commit --amendagregará el archivoProgram.csal commit y quitará el archivofile.txt. Puedes confirmarlo haciendogit statuspara ver quefile.txtsigue en el working folder ygit logpara ver los mensajes de los últimos commit. Si estás usandovimcomo editor para Git -verás:al final de la lista de commits-, recuerda usar Q para salir. -
Borra el archivo
file.txt. El working folder no debería tener ninguna modificación. Puedes confirmarlo congit status.
En el desafío Git #1 trabajaste con un repositorio que uno de los integrantes de tu equipo había creado a partir de una plantilla o template. Otra forma muy usada en GitHub de crear un repo a partir de otro es mediante un fork: una copia de un repositorio que queda en tu propia organización —en tu usuario— y que puedes modificar sin afectar al original.
Crear un repositorio mediante un fork es análogo a hacerlo desde una plantilla, pero GitHub tiene algunas funcionalidades para los repositorios creados mediante fork que no tiene para los creados desde plantillas.
Una vez creado el repositorio con fork en GitHub, trabajarás con él igual que como lo has hecho en el desafío Git #1, con una funcionalidad adicional: podrás traer y sincronizar cambios desde el repositorio original al tuyo, de forma análoga a como lo haces para traer y sincronizar cambios desde de una rama de tu propio repositorio. A continuación verás como lograrlo.
En este paso vas a crear tu propio fork del repositorio original de este desafío:
-
Abre el repositorio original de este desafío en tu navegador.
-
Haz clic en el botón
Forkque aparece arriba a la derecha.
-
En
Ownerelige tu usuario personal.
-
Deja el nombre que sugiere GitHub o elige otro nombre para tu copia.
-
Haz clic en el botón
Create fork.
Verás en el navegador tu nuevo repositorio, por ejemplo tu-usuario/PII_Git_Challenge_2_Start, con el mismo contenido que el original.
Este paso es muy parecido al paso 2. Clonar el repositorio del desafío Git #1, pero ahora la URL es la de tu fork.
-
Copia la URL HTTPS o SSH de tu fork.
-
En la terminal, ubícate en la carpeta donde guardas tus repositorios del curso y ejecuta:
git clone <url-de-tu-fork>
cd <nombre-repositorio>El comportamiento es el mismo que en el desafío Git #1: git clone crea una
copia local del repositorio, y cd te mueve a esa carpeta.
Ahora vas a decirle a tu repositorio local que, además de origin —tu fork en
GitHub—, también conozca el repositorio original como upstream. Esto te
permitirá traer cambios del original a tu fork más adelante.
Ejecuta los siguientes comandos en la terminal, dentro de la carpeta del repositorio:
git remote add upstream "https://github.com/ucudal/PII_Git_Challenge_2_Start.git"
git remote -vDeberías ver algo similar a esto:
origin <url-de-tu-fork> (fetch)
origin <url-de-tu-fork> (push)
upstream https://github.com/ucudal/PII_Git_Challenge_2_Start.git (fetch)
upstream https://github.com/ucudal/PII_Git_Challenge_2_Start.git (push)Note
El último parámetro del comando git remote add upstream, que es la URL del
repositorio original, es
https://github.com/ucudal/PII_Git_Challenge_2_Start.git en este desafío,
pero puede ser la URL de cualquier repositorio.
A partir de aquí trabajas igual que en el desafío Git #1, pero siempre contra tu fork.
Puedes crear ramas con git checkout -b <nombre-rama>, usar git add, git commit y git push origin <nombre-rama>, tal como hiciste en los pasos
3,
4,
5
y
7
del desafío Git #1, pero ahora en el fork de este repositorio del desafío #2.
Puedes seguir usando git merge entre ramas como viste en el paso
8,
y obtener cambios y hacer merge del desafío Git #1, sólo que en este desafío
no vas a enviar cambios al repositorio original, sino que todo queda en tu fork.
Aunque en este curso no modificaremos el repositorio original de este desafío, en un proyecto real el repositorio original puede seguir recibiendo cambios. Tu fork puede quedar desactualizado respecto a ese upstream.
La forma de sincronizar tu fork con los cambios del original es muy similar a lo
que hiciste en el desafío Git #1 al obtener cambios de main y hacer merge de
ramas.
-
Obtener los últimos cambios del repositorio original, que llamaremos
upstream:git fetch upstream
-
Cambiar a la rama principal de tu fork, que típicamente es
main:git checkout main
-
Combinar en tu rama
mainlos cambios de la rama principal del repositorio original:git merge upstream/main
La idea es parecida al
git merge <nombre-rama>que usaste en el paso 8 del desafío Git #1, sólo que ahora estás combinando tumaincon lamaindel repositorio original en lugar de con una rama tuya. -
Enviar la rama actualizada a tu fork en GitHub:
git push origin main
Con esto, tu fork queda sincronizado con el repositorio original: tu rama
main local y la main de tu fork en GitHub tienen los mismos cambios que la
main del repositorio upstream.