====== 2. Control de Versiones Avanzado ====== En este tema vamos a ver sobre todo a tratar con ramas, merges y conflictos. Mas información: * [[https://learngitbranching.js.org/|Git Branching: Aprender Jugando con ramas en Git]]: Permite probar Git con ejemplos interactivos * [[https://www.youtube.com/watch?v=mxoSIF-Qm7g|17 Ways to Undo Mistakes with Git]] * [[https://craftquest.io/guides/git/how-git-works/the-plumbing|The Plumbing Guide]]: Comandos de bajo nivel de Git {{:clase:daw:daw:1eval:camino_git.png|}} ===== Worktrees ===== Normalmente un repositorio de Git tiene **una sola carpeta de trabajo** y en ella solo puede haber una rama activa a la vez. Si estamos en la rama ''lorenzo_45'' y queremos trabajar en ''lorenzo_46'' tenemos que hacer un ''git switch'', y los ficheros de la carpeta cambian por los de la otra rama. Un **worktree** (árbol de trabajo) es **otra carpeta de trabajo del mismo repositorio**. Cada worktree tiene su propia rama activa y sus propios ficheros, pero todos comparten el mismo repositorio (''.git''): los mismos commits, las mismas ramas y el mismo ''origin''. Es decir, un commit hecho en un worktree se ve inmediatamente desde los demás sin necesidad de hacer ''push'' ni ''fetch''. Por eso, a partir de ahora el flujo de trabajo cambia: **cada vez que se crea una rama de feature, se crea también un worktree para esa feature**. Así: * La carpeta principal del repositorio se queda **siempre** en la rama ''develop''. Ahí se actualizan ''develop'', ''release'' y ''master'' y se hacen los merges entre ellas. * Cada feature vive en su propia carpeta, **hermana** de la principal, llamada ''-wt-''. * Al acabar la feature, se borra su worktree y su rama. Por ejemplo, si el repositorio está en ''/home/lorenzo/dev/mi-proyecto'': /home/lorenzo/dev/ ├── mi-proyecto <- carpeta principal, siempre en develop ├── mi-proyecto-wt-lorenzo_45 <- worktree de la rama lorenzo_45 └── mi-proyecto-wt-lorenzo_46 <- worktree de la rama lorenzo_46 **¿Por qué usar worktrees?** Para que **los agentes de IA (como Claude Code, Codex, etc.) puedan trabajar en paralelo con varias features**. Si dos agentes trabajan en la misma carpeta, uno haría un ''git switch'' y le cambiaría los ficheros al otro a mitad de su trabajo, o mezclarían sus cambios en la misma rama. Con un worktree por feature, cada agente tiene su propia carpeta y su propia rama, y no se molestan entre ellos. Mientras tanto, nosotros podemos seguir trabajando en otra feature o revisando lo que hacen. Las órdenes básicas de worktrees son: # Crear la rama lorenzo_45 desde develop y su worktree en una carpeta hermana git worktree add -b lorenzo_45 ../mi-proyecto-wt-lorenzo_45 develop # Ver los worktrees que hay (la primera línea es la carpeta principal) git worktree list # Borrar el worktree (la carpeta) de la rama lorenzo_45 git worktree remove ../mi-proyecto-wt-lorenzo_45 * Una rama solo puede estar activa en **un** worktree a la vez. Por eso desde el worktree de una feature no se puede hacer ''git switch develop'' (''develop'' ya está activa en la carpeta principal). Para trabajar con ''develop'' hay que ir a la carpeta principal. * No se puede borrar una rama que tiene un worktree. Primero hay que borrar el worktree con ''git worktree remove'' y luego la rama. * ''git worktree remove'' falla si hay ficheros modificados o sin seguimiento en el worktree. No uséis ''--force'': revisad primero qué ficheros son. * No borréis la carpeta de un worktree a mano con ''rm -rf''. Si ya lo habéis hecho, ejecutad ''git worktree prune'' para que Git se olvide de él. Mas información: * [[https://git-scm.com/docs/git-worktree|git-worktree]]: Documentación oficial ===== Necesidad de Ramas ===== El siguiente esquema muestra el sistema de ramas que se va a usar en clase. Mas información en [[http://nvie.com/posts/a-successful-git-branching-model/|A successful Git branching model]] {{:clase:daw:daw:1eval:git-flow.png?600|}} {{:clase:daw:daw:2eval:drinkinggame.jpg|}} Ejemplo de Ramas * [[https://github.com/lgonzalezmislata/probarGit/network|Caos en las ramas]] * [[https://github.com/fpempresa/fpempresa/network|Ramas lineales]] Ramas a crear: * develop: Lo que se ha desarrollando y el equipo de desarrollo dice que ya funciona. Cuando se quiera se pasa a ''release''. * release: Lo que se esta probando en un entorno similar al de producción. Cuando está probado, se copia a ''master''. * master: Lo que ya se puede instalar en el producción. * rama de funcionalidad: Cada vez que alguien quiere hacer algo , crea una rama desde ''develop'' y cuando acaba la fusiona en ''develop''. En la rama de funcionalidad se pueden hacer todos los commits que queramos ya que luego se van a unificar en uno solo. Es lo que llamamos "microcommits". Es así ya que son commits //parciales// que se hacen para acabar la tarea pero finalmente en la rama ''develop'' queremos que sean un solo commit. Pasos a seguir para hacer una modificación. * Crea la rama ''feature'' desde ''develop'' **y su worktree** en una carpeta hermana (''-wt-feature''). * Ir a la carpeta del worktree y realizar la tarea con tantos commits como sea necesario. * En el worktree, mergear la rama ''develop'' en ''feature'' ya que así se resuelven los problemas de mergeo en la rama ''feature'' * Ir a la carpeta principal (que está en ''develop'') y mergear la rama ''feature'' con ''--squash'' * Subir la rama ''develop'' * Borrar el worktree de la ''feature'' y luego la rama ''feature'' * Mergear la rama ''develop'' en ''release'' y subir ''release'' * Mergear la rama ''release'' en ''master'' y subir ''master'' ===== Usando Ramas ===== Veamos ahora como se trabaja con ramas * Crear una rama nueva y subirla git branch nuevaRama git switch nuevaRama git push --set-upstream origin nuevaRama git push -u origin nuevaRama \\ \\ * Crear una rama de feature desde ''develop'' con su worktree y subirla (es lo que haremos siempre a partir de ahora). Se hace desde la carpeta principal: git worktree add -b lorenzo_45 ../mi-proyecto-wt-lorenzo_45 develop cd ../mi-proyecto-wt-lorenzo_45 git push --set-upstream origin lorenzo_45 \\ \\ * Borrar el worktree de una rama (antes de borrar la rama). Se hace desde la carpeta principal: git worktree remove ../mi-proyecto-wt-lorenzo_45 \\ \\ * Bajar una nueva rama git fetch --prune git switch nuevaRama * ''fetch'':Se pone ''--prune'' , para que borre las referencias locales de ramas remotas que ya no están. * ''switch'': Por defecto al cambiar a la nueva rama ya se hace un ''--track'' a ''origin/nuevaRama'' \\ \\ * Borrar una rama en local que ha sido mergeada o subida git branch --delete miRama git branch -d miRama \\ \\ * Borrar una rama en local que NO ha sido mergeada ni subida (hay 3 formas distintas). Pero es usar el modificador ''-f'' o ''--force'' git branch --delete --force miRama git branch -d -f miRama git branch -D miRama \\ \\ * Borrar una rama en remoto git push origin --delete miRama \\ \\ ===== Merge ===== El merge es unir los commit de una rama en otra. Hay muchas formas de hacer un merge , veamos algunas de ellas. ^ Comando ^ Características ^ Cuando usarlo ^ | ''git rebase rama'' | Pone los commits en la nueva rama siempre después de los que ya hay, es decir que los reordena | Poner los commits de origin/develop en nuestra develop porque hay commits distintos en cada rama pero del mismo commit origen | | ''git merge --squash rama'' | Junta todos los "microcommits" de la rama en uno solo en la rama destino. **Es necesario acto seguido el commit** | De una rama feature a develop | | ''git merge --ff-only rama'' | Nunca crea nuevos commits en la rama destino pero falla si es necesario crear un nuevo commit, \\ por lo que ''--ff-only'' ayuda a detectar si hay algún problema | De develop a Release \\ De release a master o para actualizar cualquier rama desde GitHub cuando no hay commits nuevos en local| | ''git merge rama'' | Es el merge normal que puede crear nuevos commits | De una rama develop a feature.\\ Para resolver los conflictos desde nuestra rama feature ya que nos da igual si hay nuevos commits| \\ ==== git rebase rama ==== Pone los commits en la nueva rama siempre después de los que ya hay, es decir que los reordena. Se usa para poner los commits de origin/develop en nuestra develop de antes que lo de develop porque hay commits distintos en cada rama pero del mismo commit origen {{:clase:daw:daw:2eval:rebase.png?direct|}} ''git commit -m "E"'' %%{init: { 'logLevel': 'debug', 'theme': 'default','themeVariables': { 'git0': '#6D97CA','git1': '#00ffff' }, 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'origin/develop','rotateCommitLabel': false}} }%% gitGraph commit id: "A" commit id: "B" branch develop commit id: "E" \\ ''git fetch --prune'' %%{init: { 'logLevel': 'debug', 'theme': 'default','themeVariables': { 'git0': '#6D97CA','git1': '#00ffff' }, 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'origin/develop','rotateCommitLabel': false}} }%% gitGraph commit id: "A" commit id: "B" branch develop commit id: "E" checkout origin/develop commit id: "C" commit id: "D" \\ '' git switch develop'' \\ ''git rebase origin/develop'' %%{init: { 'logLevel': 'debug', 'theme': 'default','themeVariables': { 'git0': '#6D97CA','git1': '#00ffff' }, 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'origin/develop','rotateCommitLabel': false}} }%% gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch develop commit id: "E" checkout origin/develop ==== git merge --squash rama ==== Junta todos los "microcommits" de la rama en uno solo en la rama destino. **Es necesario acto seguido el commit** Se usa para pasar los microcommits de una rama feature a develop {{:clase:daw:daw:2eval:squash.png?direct|}} \\ ==== git merge --ff-only rama ==== Solo adelanta el puntero de donde está la rama. Nunca crea nuevos commits en la rama destino pero falla si es necesario crear un nuevo commit, \\ por lo que ''--ff-only'' ayuda a detectar si hay algún problema. Se usa De develop a Release.De release a master o para actualizar cualquier rama desde GitHub cuando no hay commits nuevos en local {{:clase:daw:daw:2eval:ff-only.png?direct|}} \\ %%{init: { 'logLevel': 'debug', 'theme': 'default','themeVariables': { 'git0': '#6D97CA','git1': '#00ffff' }, 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'develop','rotateCommitLabel': false}} }%% gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" \\ ''git fetch --prune'' %%{init: { 'logLevel': 'debug', 'theme': 'default','themeVariables': { 'git0': '#6D97CA','git1': '#00ffff' }, 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'develop','rotateCommitLabel': false}} }%% gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch origin/develop commit id: "E" commit id: "F" \\ ''git merge --ff-only origin/develop'' %%{init: { 'logLevel': 'debug', 'theme': 'default','themeVariables': { 'git0': '#6D97CA','git1': '#00ffff' }, 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'develop y origin/develop','rotateCommitLabel': false}} }%% gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" commit id: "E" commit id: "F" ==== git merge rama ==== Es el merge normal que puede crear nuevos commits | De una rama develop a feature. Se usa para resolver los conflictos desde nuestra rama feature ya que nos da igual si hay nuevos commits {{:clase:daw:daw:2eval:merge.png?direct|}} ===== Usos de Merge ===== * Bajar (o actualizar) una rama ( como master, release o develop) desde Github,suponiendo que no va a haber problemas. Es decir que no hemos hecho nosotros un commit en ese rama desde la última vez que la bajamos. git fetch --prune git switch develop git merge --ff-only origin/develop git fetch --prune git switch release git merge --ff-only origin/release git fetch --prune git switch master git merge --ff-only origin/master \\ \\ * mergear , develop en release o release en master (suponiendo que están actualizadas ambas ramas porque las hemos actualizado con las órdenes anteriores) y que no hemos hecho commits directamente ni en release ni en master. git switch release git merge --ff-only develop git switch master git merge --ff-only release \\ \\ * Mergear (rebase) los cambios de origin/develop en nuestra develop si hay commits distintos en develop y origin/develop. git fetch --prune git switch develop git rebase origin/develop Lo normal es hacer el rebase cuando al hacer un ''git push'' se produce el siguiente error: ! [rejected] develop -> develop (fetch first) error: falló el push de algunas referencias a 'https://github.com/usuario/repositorio.git' ayuda: Actualizaciones fueron rechazadas porque el remoto contiene trabajo que ayuda: no existe localmente. Esto es causado usualmente por otro repositorio ayuda: realizando push a la misma ref. Quizás quiera integrar primero los cambios ayuda: remotos (ej. 'git pull ...') antes de volver a hacer push. ayuda: Vea 'Notes about fast-forwards0 en 'git push --help' para detalles. \\ \\ * Merge en develop de nuestra rama de feature **con un solo commit** con ''--squash'' (Antes hemos actualizado develop desde GitHub). Se hace desde la carpeta principal, que ya está en ''develop''. cd ../mi-proyecto git merge --squash lorenzo_42 git commit -am "feat(#42):pantalla de Login" Recuerda hacer siempre después del ''git merge --squash'' el commit \\ \\ * Mergear los cambios de develop en nuestra rama para ir solucionado los conflictos poco a poco (Antes hemos actualizado develop desde GitHub en la carpeta principal). Se hace desde el worktree de la feature. Como todos los worktrees comparten el repositorio, la rama ''develop'' que hemos actualizado en la carpeta principal ya está disponible en el worktree. cd ../mi-proyecto-wt-lorenzo_42 git merge develop \\ \\ A partir de la versión 2.27 , al hacer un ''git pull'' aparece el siguiente mensaje logongas@beren:~/Documentos/ensenyament/2daw-daw/prueba_daw$ git pull ayuda: Hacer un pull sin especificar cómo reconciliar las ramas es poco ayuda: recomendable. Puedes eliminar este mensaje usando uno de los ayuda: siguientes comandos antes de tu siguiente pull: ayuda: ayuda: git config pull.rebase false # hacer merge (estrategia por defecto) ayuda: git config pull.rebase true # aplicar rebase ayuda: git config pull.ff only # aplicar solo fast-forward ayuda: ayuda: Puedes reemplazar "git config" con "git config --global" para aplicar ayuda: la preferencia en todos los repositorios. Puedes también pasar --rebase, ayuda: --no-rebase, o --ff-only en el comando para sobreescribir la configuración ayuda: por defecto en cada invocación. ayuda: Es decir que avisa que se configure para saber que hacer en caso de problemas, si con Fast-Forward, con un rebase o con merge. Así que como siempre hemos recomendado , es mejor no usar ''git pull'' ya que así decidimos nosotros que hacer o en el peor de los casos indicar para que haga siempre un ''--ff-only'' mediante al orden: git config --global pull.ff only De esa forma podremos hacer un ''git pull'' de forma segura (siempre y cuando no estés en otro ordenador donde no lo hayan configurado así :-(). Aunque mejor aun es dehabilitar ''git pull'': [[https://stackoverflow.com/questions/22944178/can-i-disable-git-pull|Can I disable git pull?]] Mas información: * [[https://blog.sffc.xyz/post/185195398930/why-you-should-use-git-pull-ff-only-git-is-a|Why You Should Use git pull –ff-only]] * [[https://coderwall.com/p/7aymfa/please-oh-please-use-git-pull-rebase|Please, oh please, use git pull --rebase]] Mas información: * [[http://stackoverflow.com/questions/3697178/git-merge-all-changes-from-another-branch-as-a-single-commit|Git: merge all changes from another branch as a single commit]] * [[https://bitbucket.org/blog/git-squash-commits-merging-bitbucket|Squash commits when merging a Git branch with Bitbucket]] * [[http://www.getlaura.com/handling-merge-conflicts-with-git-rebase/|Handling merge conflicts with git rebase]] ===== Conflictos ===== En caso de hacer un ''git merge'' o un ''git rebase'', etc. se puede producir un conflicto. Que consiste en que git no sabe como fusionar los ficheros. En ese caso lo primero es resolver cada conflicto en cada fichero. Imaginemos el mismo fichero ''index.html'' en 2 ramas distintas: ^ Nuestra Rama ^ Rama a Fusionar ^ |

Hola mundo

|

Adios planeta

| Cuando se produce el conflicto, el fichero resultante queda de la siguiente forma: <<<<<<< HEAD

Hola mundo

=======

Adios planeta

>>>>>>> Rama a Fusionar
Ahora tenemos que decidir como resolver el conflicto que el resultado definitivo ya depende del código que estemos fusionando. Un posible resultado podría ser:

Hola y Adios mundo

==== git rebase rama ==== Imaginemos que queremos mergear la rama ''origin/develop'' sobre ''develop''. Si hay un conflicto se producirá el siguiente mensaje: En primer lugar, rebobinando HEAD para después reproducir tus cambios encima de ésta... Aplicando: feat(#50):Cabecera tercera Usando la información del índice para reconstruir un árbol base... M index.html Retrocediendo para parchar base y fusión de 3-vías... Auto-fusionando index.html CONFLICTO (contenido): Conflicto de fusión en index.html error: Falló al fusionar en los cambios. El parche falló en 0001 feat(#50):Cabecera tercera Use 'git am --show-current-patch' para ver el parche fallido Resuelva todos los conflictos manualmente ya sea con "git add/rm ", luego ejecute "git rebase --continue". Si prefieres saltar este parche, ejecuta "git rebase --skip" . Para abortar y regresar al estado previo al "git rebase", ejecuta "git rebase --abort". Ahora debemos como antes arreglar el conflicto editando el fichero ''index.html'' pero ahora deberemos hacer dos cosas mas: git add index.html git rebase --continue Es decir añadir el fichero que ha dado el conflicto con un ''git add'' y luego hacer un ''git rebase --continue'' para que se acabe de fusionar. El ejemplo completo lo podemos ver aquí: git switch develop git rebase origin/develop vi index.html #Arreglar el conflicto git add index.html git rebase --continue \\ ==== git merge --squash rama ==== Imaginemos que queremos mergear una rama de una funcionalidad llamada "Lorenzo_3" sobre ''develop''. Si hay un conflicto se producirá el siguiente mensaje: Auto-fusionando index.html CONFLICTO (contenido): Conflicto de fusión en index.html Commit de squash -- no actualizando HEAD Fusión automática falló; arregle los conflictos y luego realice un commit con el resultado. Ahora debemos como antes arreglar el conflicto editando el fichero ''index.html'' y hacer el commit que de todas formas ya íbamos a hacer git commit -am "feat(#45):Nueva cabecera" El ejemplo completo lo podemos ver aqui: cd ../mi-proyecto #La carpeta principal, que está en develop git merge --squash Lorenzo_3 vi index.html #Arreglar el conflicto git commit -am "feat(#45):Nueva cabecera" \\ ==== git merge --ff-only rama ==== Con un fast-forward nunca se puede producir un conflicto. ==== git merge rama ==== Imaginemos que queremos mergear los cambios de ''develop'' en la rama ''Lorenzo_3'' Si hay un conflicto se producirá el siguiente mensaje: Auto-fusionando index.html CONFLICTO (contenido): Conflicto de fusión en index.html Fusión automática falló; arregle los conflictos y luego realice un commit con el resultado. Ahora debemos como antes arreglar el conflicto editando el fichero ''index.html'' y el ''--continue'': git add index.html git merge --continue Es decir añadir el fichero que ha dado el conflicto con un ''git add'' y luego hacer un ''git merge --continue'' para que se acabe de mergear. El ejemplo completo lo podemos ver aqui: cd ../mi-proyecto-wt-Lorenzo_3 #El worktree de la rama Lorenzo_3 git merge develop vi index.html #Arreglar el conflicto git add index.html git merge --continue \\ ===== Recetas ===== Las recetas que trabajan con ''develop'', ''release'' y ''master'' se ejecutan **siempre en la carpeta principal** del repositorio, nunca en el worktree de una feature. * Bajarse lo último de las 3 ramas. git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop * Hacer un merge de las 3 ramas git switch release && git merge --ff-only develop && git switch master && git merge --ff-only release && git switch develop * Subir las 3 ramas git switch master && git push && git switch release && git push && git switch develop && git push * Proceso completo para hacer una modificacion en la propia rama (con su worktree) y ponerla en develop. Suponemos que el repositorio está en la carpeta ''mi-proyecto'' #Día 1:Lunes # Crear el issue. Tiene número 45 cd mi-proyecto #Carpeta principal, siempre en develop git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop git worktree add -b lorenzo_45 ../mi-proyecto-wt-lorenzo_45 develop cd ../mi-proyecto-wt-lorenzo_45 #A partir de aquí se trabaja en el worktree git push --set-upstream origin lorenzo_45 git commit -m "micro-commit-dia-1-a" git push git commit -m "micro-commit-dia-1-b" git push git commit -m "micro-commit-dia-1-c" git push #Día 2:Martes cd ../mi-proyecto git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop cd ../mi-proyecto-wt-lorenzo_45 git merge develop git commit -m "micro-commit-dia-2-a" git push git commit -m "micro-commit-dia-2-b" git push git commit -m "micro-commit-dia-2-c" git push #Día 3:Miercoles cd ../mi-proyecto git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop cd ../mi-proyecto-wt-lorenzo_45 git merge develop git commit -m "micro-commit-dia-3-a" git push git commit -m "micro-commit-dia-3-b" git push git commit -m "micro-commit-dia-3-c" git push #Día 4: Jueves cd ../mi-proyecto git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop cd ../mi-proyecto-wt-lorenzo_45 git merge develop git commit -m "micro-commit-dia-4-a" git push git commit -m "micro-commit-dia-4-b" git push git commit -m "micro-commit-dia-4-c" git push #Día 5: Viernes cd ../mi-proyecto git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop cd ../mi-proyecto-wt-lorenzo_45 git merge develop cd ../mi-proyecto #Volvemos a la carpeta principal, que está en develop git merge --squash lorenzo_45 git commit -am "feat(#45):Crear la pantalla de login" git push #Si falla el push hacer el fetch y rebase git fetch --prune git rebase origin/develop git push git push origin --delete lorenzo_45 git worktree remove ../mi-proyecto-wt-lorenzo_45 #Primero el worktree, luego la rama git branch --delete --force lorenzo_45 #Cerrar el issue 45 ===== Ejercicios ===== En los ejercicios hay 2 usuarios: el **usuario A** y el **usuario B**. Cada uno trabaja en su propia carpeta (puede ser en el mismo ordenador) y ambos suben sus cambios al mismo repositorio de GitHub. Antes de empezar: * Crea un repositorio en GitHub con las ramas ''master'' (o ''main''), ''release'' y ''develop'' y con los ficheros ''A.txt'', ''B.txt'' y ''comun.txt''. * Usuario A y usuario B: clonad el repositorio cada uno en su carpeta. ==== Ejercicio 1 ==== Un solo usuario, sin conflictos. * Usuario A: Crea la rama ''A1'' desde ''develop''. * Usuario A: Haz un cambio en ''A.txt'', haz commit y push. * Usuario A: Haz otro cambio en ''A.txt'', haz commit y push. * Usuario A: Ve a ''develop'' y baja la última versión de ''develop'' desde GitHub. * Usuario A: Mergea la rama ''A1'' en ''develop'' con ''--squash''. * Usuario A: Sube los cambios de ''develop''. * Usuario A: Borra la rama ''A1'' en local y en remoto. ==== Ejercicio 2 ==== Dos usuarios que modifican ficheros distintos, por lo que el segundo que sube ''develop'' tendrá que hacer un ''rebase'' pero sin conflictos. * Usuario A y usuario B: Actualizad ''develop'' desde GitHub. * Usuario A: Crea la rama ''A2'' desde ''develop''. * Usuario B: Crea la rama ''B2'' desde ''develop''. * Usuario A: Haz un cambio en ''A.txt'', haz commit y push. * Usuario B: Haz un cambio en ''B.txt'', haz commit y push. * Usuario A: Ve a ''develop'' y baja la última versión de ''develop'' desde GitHub. * Usuario B: Ve a ''develop'' y baja la última versión de ''develop'' desde GitHub. * Usuario A: Mergea la rama ''A2'' en ''develop'' con ''--squash''. * Usuario B: Mergea la rama ''B2'' en ''develop'' con ''--squash''. * Usuario A: Sube los cambios de ''develop''. * Usuario B: Sube los cambios de ''develop''. No te dejará. Haz un ''rebase'' de ''origin/develop'' y vuelve a subirlos. * Usuario A: Borra la rama ''A2'' en local y en remoto. * Usuario B: Borra la rama ''B2'' en local y en remoto. ==== Ejercicio 3 ==== Dos usuarios que modifican el mismo fichero, por lo que el conflicto aparecerá al hacer el ''rebase'' en ''develop''. * Usuario A y usuario B: Actualizad ''develop'' desde GitHub. * Usuario A: Crea la rama ''A3'' desde ''develop''. * Usuario B: Crea la rama ''B3'' desde ''develop''. * Usuario A: Haz un cambio en ''comun.txt'', haz commit y push. * Usuario B: Haz un cambio en ''comun.txt'' en las mismas líneas, haz commit y push. * Usuario A: Ve a ''develop'' y baja la última versión de ''develop'' desde GitHub. * Usuario B: Ve a ''develop'' y baja la última versión de ''develop'' desde GitHub. * Usuario A: Mergea la rama ''A3'' en ''develop'' con ''--squash''. * Usuario B: Mergea la rama ''B3'' en ''develop'' con ''--squash''. * Usuario A: Sube los cambios de ''develop''. * Usuario B: Sube los cambios de ''develop''. No te dejará. Haz un ''rebase'' de ''origin/develop'', resuelve el conflicto y vuelve a subirlos. * Usuario A: Borra la rama ''A3'' en local y en remoto. * Usuario B: Borra la rama ''B3'' en local y en remoto. ==== Ejercicio 4 ==== Dos usuarios que modifican el mismo fichero, pero ahora el conflicto se resuelve **en la rama de feature** mergeando ''develop'' en ella, que es la forma recomendada de trabajar. * Usuario A y usuario B: Actualizad ''develop'' desde GitHub. * Usuario A: Crea la rama ''A4'' desde ''develop''. Modifica ''comun.txt'', haz commit y push. * Usuario B: Crea la rama ''B4'' desde ''develop''. Modifica ''comun.txt'' en las mismas líneas, haz commit y push. * Usuario A: Ve a ''develop'', actualiza ''develop'' desde GitHub, mergea ''A4'' con ''--squash'' y haz push. * Usuario A: Borra la rama ''A4'' en local y en remoto. * Usuario B: Ve a ''develop'' y actualiza ''develop'' desde GitHub. * Usuario B: Ve a la rama ''B4'', mergea ''develop'', resuelve el conflicto y haz push. * Usuario B: Ve a ''develop'' y actualiza ''develop'' desde GitHub. * Usuario B: Mergea ''B4'' en ''develop'' con ''--squash'' y haz push. Ahora no habrá conflicto, ya que se resolvió en la rama ''B4''. * Usuario B: Borra la rama ''B4'' en local y en remoto. ==== Ejercicio 5 ==== * Usuario A: Baja la última versión de ''develop'' desde GitHub. * Usuario A: Baja la última versión de ''release'' desde GitHub. * Usuario A: Mergea en ''release'' la rama ''develop'' con ''--ff-only'' y haz push. ==== Ejercicio 6 ==== * Usuario B: Baja la última versión de ''release'' desde GitHub. * Usuario B: Baja la última versión de ''master'' (o ''main'') desde GitHub. * Usuario B: Mergea en ''master'' (o ''main'') la rama ''release'' con ''--ff-only'' y haz push. ==== Ejercicio 7 ==== Es como el ejercicio 1 pero ahora usando un worktree para la rama de feature (ver el apartado [[#worktrees|Worktrees]]). La carpeta donde clonaste el repositorio será la carpeta principal y se quedará siempre en ''develop''. En este ejercicio se trabaja en **2 carpetas distintas**. Suponiendo que el repositorio se clonó en ''mi-proyecto'': dev/ ├── mi-proyecto <- carpeta principal, siempre en develop └── mi-proyecto-wt-A8 <- worktree de la rama A8 En cada paso se indica entre corchetes en qué carpeta hay que estar. Si en algún momento no sabes en qué carpeta ni en qué rama estás, ejecuta ''pwd'' y ''git branch --show-current''. * Usuario A **[''mi-proyecto'']**: Crea la rama ''A8'' desde ''develop'' y su worktree en la carpeta hermana ''mi-proyecto-wt-A8''. * Usuario A **[''mi-proyecto'']**: Comprueba con ''git worktree list'' que existen los 2 worktrees. * Usuario A **[''mi-proyecto-wt-A8'']**: Haz ''cd ../mi-proyecto-wt-A8'' y sube la rama ''A8'' a GitHub. * Usuario A **[''mi-proyecto-wt-A8'']**: Haz un cambio en ''A.txt'', haz commit y push. * Usuario A **[''mi-proyecto-wt-A8'']**: Haz otro cambio en ''A.txt'', haz commit y push. * Usuario A **[''mi-proyecto'']**: Haz ''cd ../mi-proyecto'' y comprueba que ''A.txt'' sigue sin los cambios, ya que esta carpeta está en ''develop''. * Usuario A **[''mi-proyecto'']**: Baja la última versión de ''develop'' desde GitHub. * Usuario A **[''mi-proyecto'']**: Mergea la rama ''A8'' en ''develop'' con ''--squash''. * Usuario A **[''mi-proyecto'']**: Sube los cambios de ''develop''. * Usuario A **[''mi-proyecto'']**: Borra el worktree de ''A8'' con ''git worktree remove ../mi-proyecto-wt-A8'' y comprueba que ya no existe la carpeta ''mi-proyecto-wt-A8''. * Usuario A **[''mi-proyecto'']**: Borra la rama ''A8'' en local y en remoto. ===== Skills ===== * Para seguir el flujo de trabajo se recomienda el siguiente skills:{{ :clase:daw:daw:1eval:git-flow-skill.md |}}