{"id":176,"date":"2011-05-21T02:23:27","date_gmt":"2011-05-21T00:23:27","guid":{"rendered":"http:\/\/www.edy.es\/dev\/?page_id=176"},"modified":"2024-02-12T16:14:46","modified_gmt":"2024-02-12T15:14:46","slug":"git-guia-rapida","status":"publish","type":"page","link":"https:\/\/www.edy.es\/dev\/docs\/git-guia-rapida\/","title":{"rendered":"GIT &#8211; Gu\u00eda r\u00e1pida"},"content":{"rendered":"<p>Notas:<\/p>\n<ul>\n<li><em>Cambios locales<\/em>\u00a0se refiere a los ficheros del directorio de trabajo (<em>working dir<\/em>) que hayan sido modificados desde el \u00faltimo commit.<\/li>\n<li><em>COMMIT<\/em>\u00a0es <a href=\"http:\/\/www.kernel.org\/pub\/software\/scm\/git\/docs\/gitrevisions.html\">un indicador cualquiera en el repositorio<\/a>: SHA1 de un commit, tag, HEAD (ultimo commit de la rama actual), HEAD~1 (antecesor de HEAD)&#8230; La mayor\u00eda de las veces, si no se indica se asume HEAD (\u00faltimo commit de la rama actual).<\/li>\n<\/ul>\n<p>Enlaces:<\/p>\n<ul>\n<li><a href=\"http:\/\/git-scm.org\">http:\/\/git-scm.org<\/a><\/li>\n<li><a href=\"http:\/\/www-cs-students.stanford.edu\/~blynn\/gitmagic\/intl\/es\/ch02.html\">http:\/\/www-cs-students.stanford.edu\/~blynn\/gitmagic\/intl\/es\/ch02.html<\/a><\/li>\n<\/ul>\n<h4>Inicializar repositorio<\/h4>\n<pre>$ git init\r\n$ git add .                           # Marca todos los ficheros para el pr\u00f3ximo commit.\r\n$ git commit -m \"Estado inicial\"      # Crea un nuevo commit con los ficheros marcados.<\/pre>\n<h4>Crear ramas<\/h4>\n<p>Una rama es un puntero a un commit espec\u00edfico en el repositorio.<\/p>\n<pre>$ git branch &lt;nombre&gt; \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # Crear la rama en el punto actual. Es necesario hacer checkout a la misma.\r\n$ git branch &lt;nombre&gt; &lt;COMMIT&gt; \u00a0 \u00a0 \u00a0 \u00a0# Crea la rama a partir del commit dado. Es necesario hacer checkout para cambiar a la rama.\r\n$ git checkout -b &lt;nombre&gt; \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0# Crear rama en el punto actual y hacerle checkout.\r\n$ git checkout -b &lt;nombre&gt; &lt;COMMIT&gt; \u00a0 # Crear la rama a partir del commit dado y hacerle checkout.\r\n$ git branch -m &lt;actual&gt; &lt;nuevo&gt; \u00a0 \u00a0 \u00a0# Renombrar la rama\r\n$ git branch -d &lt;nombre&gt;              # Borrar la rama<\/pre>\n<p>Al crear una rama nueva y hacerle checkout los cambios locales se trasladan a esa rama, con lo que el siguiente commit ser\u00e1 sobre la rama nueva.<\/p>\n<h4>Listar ramas<\/h4>\n<pre>$ git branch            \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # Listar todas las ramas\r\n$ git branch -v                    \u00a0 \u00a0# Mostrar \u00faltimo commit en cada rama y su situaci\u00f3n respecto a su rama remota (si hay)\r\n$ git branch --merged                 # Mostrar ramas que se han fusionado con la actual, y por tanto pueden borrarse\r\n$ git branch --no-merged              # Mostrar ramas con trabajos sin funsionar. Intentar borrarlas dar\u00e1 un error.<\/pre>\n<h4>Moverse a una rama o a un commit espec\u00edfico<\/h4>\n<pre>$ git checkout &lt;COMMIT&gt;            # No toca los cambios locales\r\n$ git checkout -f &lt;COMMIT&gt;         # Sobreescribe los cambios locales<\/pre>\n<p>Se puede hacer una rama desde el commit actual para continuar el desarrollo (git branch). Si se hacen cambios en un commit intermedio (no es un\u00a0<em>HEAD<\/em>) y se commitean sin hacer una rama, se crea un commit separado que sale del actual (rama sin nombre).<\/p>\n<h4>Fusionar ramas (merge)<\/h4>\n<pre>$ git merge &lt;nombre&gt; \u00a0 \u00a0 \u00a0         # Fusiona la rama indicada en la rama actual<\/pre>\n<p>Las diferencias se resuelven autom\u00e1ticamente si es posible. En caso de conflictos (c\u00f3digo o ficheros binarios modificados en ambas ramas) el proceso se detiene (<em>merging<\/em>) a la espera de una resoluci\u00f3n manual.<\/p>\n<p><strong>Resolver conflictos de fusionado:<\/strong><\/p>\n<p>Dentro de cada fichero en conflicto se a\u00f1aden marcas alrededor del c\u00f3digo conflictivo, mostrando al mismo tiempo la versi\u00f3n de una y otra rama (excepto en ficheros binarios).<\/p>\n<pre>$ git status \u00a0 \u00a0 \u00a0 \u00a0 \u00a0             # Muestra la situaci\u00f3n actual del merge (Unmerged paths)\r\n$ git diff                         # Muestra los ficheros conflictivos y las diferencias\r\n$ git add &lt;file&gt;                   # Marca el fichero como corregido una vez resuelto el conflicto\r\n$ git rm &lt;file&gt;                    # Marca el fichero como eliminado en la revisi\u00f3n resuelta<\/pre>\n<p>La secci\u00f3n &#8220;Unmerged paths&#8221; de\u00a0<em>git status<\/em>\u00a0muestra los ficheros que requieren atenci\u00f3n. Debe resolverse cada conflicto manualmente dentro del fichero (eliminando las marcas agregadas por git) y marcarlo como resuelto con\u00a0<em>git add<\/em>.<\/p>\n<p>En vez de editar los ficheros es posible escoger una de las dos versiones disponibles (rama actual o rama que se est\u00e1 fusionando):<\/p>\n<pre>$ git checkout --ours -- &lt;file&gt;    # Obtener la versi\u00f3n del fichero en la rama actual\r\n$ git checkout --theirs -- &lt;file&gt;  # Obtener la versi\u00f3n del fichero en la rama que se est\u00e1 fusionando con la actual<\/pre>\n<p>Para abortar la acci\u00f3n o anularla una vez realizada:<\/p>\n<pre>$ git reset --hard HEAD            # Abortar el proceso y volver a la situaci\u00f3n anterior al intento de merge\r\n$ git reset --hard ORIG_HEAD       # Deshacer si ya se hab\u00eda confirmado con <em>git commit<\/em><\/pre>\n<p>Una vez resueltos todos los conflictos se confirma el proceso:<\/p>\n<pre>$ git commit                       # Confirmar la fusi\u00f3n (merge) una vez resueltos todos los conflictos<\/pre>\n<p><strong>Resoluci\u00f3n gr\u00e1fica de conflictos:<\/strong><\/p>\n<pre>$ git mergetool                    # Inicia la herramienta gr\u00e1fica de resoluci\u00f3n de conflictos<\/pre>\n<p>La herramienta crea ficheros adicionales por cada fichero en conflicto (backup, base, local, remote) para que la herramienta de resoluci\u00f3n pueda mostrarlos al usuario al mismo tiempo y \u00e9ste establecer la versi\u00f3n final. Estos ficheros deber\u00edan borrarse autom\u00e1ticamente tras la edici\u00f3n (en caso de que persistan es necesario borrarlos manualmente).<\/p>\n<p>La resoluci\u00f3n b\u00e1sica s\u00f3lo sirve para ficheros de texto. En ficheros binarios usar\u00a0<em>git checkout &#8211;ours<\/em>\u00a0o\u00a0<em>git checkout &#8211;theirs<\/em>\u00a0para escoger una de las dos versiones disponibles.<\/p>\n<p>Configurar una herramienta gr\u00e1fica para resolver conflictos:<br \/>\n<a href=\"http:\/\/www.davesquared.net\/2010\/03\/easier-way-to-set-up-diff-and-merge.html\">http:\/\/www.davesquared.net\/2010\/03\/easier-way-to-set-up-diff-and-merge.html (Windows)<\/a><br \/>\n<a href=\"http:\/\/gitguru.com\/2009\/02\/22\/integrating-git-with-a-visual-merge-tool\">http:\/\/gitguru.com\/2009\/02\/22\/integrating-git-with-a-visual-merge-tool (Mac)<\/a><\/p>\n<h4>Deshacer cambios<\/h4>\n<pre>$ git revert &lt;COMMIT&gt;              # Deshacer de forma segura los cambios introducidos por un commit cualquiera\r\n$ git reset --hard                 # Deshace los cambios locales\r\n$ git reset --hard HEAD~1          # Elimina el \u00faltimo commit<\/pre>\n<p>Recuperar una versi\u00f3n determinada de un fichero o path:<\/p>\n<pre>$ git reset &lt;COMMIT&gt; -- &lt;path&gt;     # git reset NO sobreescribe cambios locales\r\n$ git reset -p &lt;COMMIT&gt; -- &lt;path&gt;  # Seleccionar interactivamente las partes a restaurar\r\n$ git checkout &lt;COMMIT&gt; -- &lt;path&gt;  # Sobreescribe cambios locales sin preguntar<\/pre>\n<p>En Windows se puede abrir git-bash directamente en cualquier subcarpeta carpeta del proyecto (boton derecho &#8211; git bash here). Entonces para recuperar un fichero o path local:<\/p>\n<pre>$ git checkout &lt;COMMIT&gt; -- .\/&lt;path&gt;<\/pre>\n<h4>Conocer el historial de un fichero<\/h4>\n<pre>$ git log &lt;path&gt;                       # Mostrar todos los commits para un fichero especifico con info detallada\r\n$ git log -n 2 --\u00a0&lt;path&gt;               # Mostrar s\u00f3lo los dos \u00faltimos commits para ese fichero\r\n$ git log -oneline -- &lt;path&gt;           # Formato abreviado con id de commit y comentario<\/pre>\n<pre>$ git log &lt;SINCE&gt;..&lt;UNTIL&gt; -- &lt;path&gt;   # Mostrar los commits para ese fichero entre dos commits indicados<\/pre>\n<p>Abrir GITK mostrando gr\u00e1ficamente el historial para un fichero o ruta dado:<\/p>\n<pre>$ gitk &lt;path&gt;<\/pre>\n<h4>Localizar y restaurar ficheros borrados<\/h4>\n<pre>$ git log --diff-filter=D --summary      # Mostrar los ficheros borrados en los \u00faltimos commits\r\n$ git checkout &lt;COMMIT&gt;^ -- &lt;path&gt;       # Restaurar un fichero que fue borrado en un commit dado<\/pre>\n<p>El ^ al final del commit es para restaurar el fichero desde el commit anterior al que fue borrado. Equivale a &lt;commit&gt;~1.<\/p>\n<h4>Guardar cambios actuales para recuperarlos despu\u00e9s<\/h4>\n<p>Guarda los cambios desde el \u00faltimo commit. Al recuperarlos, si hay colisiones se hace un\u00a0<em>merge<\/em>.<\/p>\n<pre>$ git stash                    # Guarda cambios hechos desde el ultimo commit\r\n$ git stash pop                # Recupera los cambios guardados\r\n$ git stash list               # Lista los estados guardados\r\n$ git stash apply              # Aplica cambios guardados sin borrarlos de la lista<\/pre>\n<h4>Marcar el commit actual (Tag)<\/h4>\n<pre>$ git tag -s &lt;nombre&gt; -m &lt;mensaje&gt;<\/pre>\n<p>El tag queda firmado usando la firma GPG asociada al autor (ver\u00a0<a href=\"http:\/\/codaset.com\/codaset\/codaset\/wiki\/creating-ssh-keys\">Creating SSH keys<\/a>).<\/p>\n<p>El nombre identifica al tag y se usa en los dem\u00e1s comandos (ej. git checkout). Por ejemplo, v2.32.45r1<\/p>\n<pre>$ git tag                              # Mostrar lista de tags\r\n$ git tag -n                           # Mostrar lista y descripci\u00f3n<\/pre>\n<pre>$ git tag -d &lt;nombre&gt;                  # Eliminar Tag\r\n$ git tag -a &lt;nombre&gt;                  # Crear Tag no firmado\r\n$ git push --tags                      # Subir Tags al repositorio remoto\r\n$ git push origin :refs\/tags\/&lt;nombre&gt;  # Eliminar Tag remoto borrado localmente<\/pre>\n<h4>Localizar ficheros con una cadena de texto<\/h4>\n<pre>$ git grep &lt;texto&gt;                     # Mira en todos los ficheros del repositorio\r\n$ git grep &lt;texto&gt; -- &lt;ruta&gt;           # Mira s\u00f3lo en la ruta o rutas especificadas\r\n                                       # Admite patrones (ej. *.cpp)<\/pre>\n<h2>Trabajo con repositorios remotos<\/h2>\n<h4>Obtener el repositorio desde otra localizaci\u00f3n (<em>fork<\/em>):<\/h4>\n<pre>$ git clone &lt;ruta al repositorio&gt;      # Clonar y hacer checkout del HEAD de la rama actual\r\n$ git clone -n &lt;ruta al repositorio    # Clonar pero no hacer checkout<\/pre>\n<p>No hay que hacer\u00a0<em>git init<\/em>\u00a0ni crear directorio (se crea autom\u00e1ticamente a partir de la carpeta actual). La ruta puede ser una carpeta local, carpeta en red, URL, o cualquier otra referencia a un repositorio remoto.\u00a0Si es privado ser\u00e1 necesario tener la clave SSH configurada adecuadamente (<a href=\"http:\/\/projects.edy.es\/trac\/edy_vehicle-physics\/wiki\/GitSetup\">ejemplo<\/a>).<\/p>\n<h4>Recibir los cambios desde el repositorio original:<\/h4>\n<pre>$ git pull<\/pre>\n<p>Es equivalente a:<\/p>\n<pre>$ git fetch                            # Trae los cambios\r\n$ git merge origin                     # Fusionarlos con la versi\u00f3n actual<\/pre>\n<h4>Subir cambios al repositorio:<\/h4>\n<pre>$ git push origin &lt;branch&gt;             # Subir s\u00f3lo la rama indicada\r\n$ git push --all                       # Subir y actualizar todas las referencias remotas<\/pre>\n<h4>Gestionar Tags en el repositorio:<\/h4>\n<pre>$ git push --tags                      # Subir Tags (no suben de otra forma)\r\n$ git push origin :refs\/tags\/&lt;nombre&gt;  # Eliminar Tag borrado localmente<\/pre>\n<h4>Borrar una rama remota:<\/h4>\n<pre>$ git push origin :&lt;branch&gt;\r\n$ git push origin --delete &lt;branch&gt;    # GIT versi\u00f3n 1.7.0+<\/pre>\n<h4>Listar los repositorios remotos y sus URLs:<\/h4>\n<pre>$ git remote -v show<\/pre>\n<h4>Cambiar la URL de un repositorio remoto (cambia ambos fetch y push)<\/h4>\n<pre>$ git remote set-url origin &lt;nueva URL&gt;<\/pre>\n<h4>Revertir un commit en local y tambi\u00e9n en el repositorio remoto:<\/h4>\n<p>(lo l\u00f3gico es que no hubiera sido subido)<\/p>\n<pre>$ git reset --hard HEAD~1\r\n$ git push origin +master:master<\/pre>\n<p><em>&#8220;The +master:master thing is necessary to tell git that you really do want to rewind the history here, (it&#8217;s definitely not part of the normal flow).&#8221;<\/em><\/p>\n<p><a href=\"http:\/\/www.zorched.net\/2008\/04\/14\/start-a-new-branch-on-your-remote-git-repository\/\">Tutorial<\/a><\/p>\n<p><a href=\"http:\/\/www.gitready.com\/beginner\/2009\/02\/02\/push-and-delete-branches.html\">Push and delete branches<\/a><\/p>\n<h2>Tareas especiales<\/h2>\n<h4>Marcar para commit s\u00f3lo determinadas partes de un fichero<\/h4>\n<pre>$ git add --patch              # Preguntar individualmente por cada cambio en todos los ficheros modificados\r\n$ git add --patch &lt;file&gt;       # Preguntar individualmente por cada cambio en un fichero determinado<\/pre>\n<p>Se muestra cada cambio en el fichero individualmente y se pregunta qu\u00e9 hacer con \u00e9l. Respuestas inmediatas:<\/p>\n<pre>    y     aceptar este cambio para que entre en el pr\u00f3ximo commit.\r\n    n     no marcar este cambio. No entrar\u00e1 en el pr\u00f3ximo commit.\r\n    q     no marcar este cambio y salir. Se mantendr\u00e1n los que ya se hayan marcado pero no los restantes.\r\n    a     marcar este cambio y todos los dem\u00e1s de este fichero.\r\n    d     no marcar este cambio ni ninguno de los restantes de este fichero.<\/pre>\n<p><a href=\"https:\/\/www.kernel.org\/pub\/software\/scm\/git\/docs\/git-add.html\">Otras respuestas disponibles<\/a>\u00a0permiten saltar entre los cambios (g j k), reducirlos a partes m\u00e1s peque\u00f1as (s), o editarlos manualmente (e).<\/p>\n<h4>A\u00f1adir un nuevo fichero o patr\u00f3n a .gitignore<\/h4>\n<p>A\u00f1adirlo a\u00a0<strong><em>.gitignore<\/em><\/strong>\u00a0sigue controlando aquellos ficheros que ya est\u00e1n en el repositorio, y<\/p>\n<pre>git rm &lt;file&gt;<\/pre>\n<p>eliminar\u00eda el fichero del directorio de trabajo.<\/p>\n<p>Para dejar de controlar el fichero o patr\u00f3n manteniendo las copias actuales a\u00f1adirlo a .gitignore y entonces:<\/p>\n<pre>$ git rm --cached &lt;file&gt;\r\n$ git rm --cached -r &lt;pattern&gt;        # Eliminar ocurrencias en todo el arbol<\/pre>\n<p>Borrar el fichero completamente del repositorio implica\u00a0<a href=\"http:\/\/github.com\/guides\/completely-remove-a-file-from-all-revisions\">reescribir toda la historia<\/a>. Nada recomendable.<\/p>\n<h4>Localizar el cambio que origin\u00f3 un problema<\/h4>\n<pre>$ git bisect start\r\n$ git bisect bad                      # La versi\u00f3n actual va mal\r\n$ git bisect good v2.6.13-rc2         # Esta versi\u00f3n es buena<\/pre>\n<p><a href=\"http:\/\/www-cs-students.stanford.edu\/~blynn\/gitmagic\/ch05.html#_where_did_it_all_go_wrong\">Informaci\u00f3n<\/a><\/p>\n<p><a href=\"http:\/\/www.kernel.org\/pub\/software\/scm\/git\/docs\/git-bisect.html\">Manual para git bisect<\/a><\/p>\n<h2>Trabajar con subm\u00f3dulos (<em>submodules<\/em>)<\/h2>\n<p>Los subm\u00f3dulos son carpetas dentro de un repositorio cuyo contenido es a su vez un repositorio de GIT autogestionado.<\/p>\n<h4>A\u00f1adir un subm\u00f3dulo a un repositorio<\/h4>\n<pre>$ git submodule add &lt;ruta al repositorio&gt; &lt;carpeta&gt;       # A\u00f1ade el repositorio dado como subm\u00f3dulo \r\n                                                          # en la carpeta indicada del repositorio actual.<\/pre>\n<p>El subm\u00f3dulo se inicializa en la carpeta indicada y se le hace checkout a la rama Master.<\/p>\n<p>Los cambios locales en el repositorio anfitri\u00f3n se limitan al fichero <em>.gitmodules<\/em> y a la nueva carpeta, pero no al contenido (<em>untracked content<\/em>).\u00a0Desde el punto de vista del repositorio anfitri\u00f3n, un subm\u00f3dulo s\u00f3lo consta de una definici\u00f3n en el fichero .gitmodules y de una carpeta.\u00a0Esta carpeta es especial y hace referencia a un <em>commit<\/em>\u00a0determinado en el origen del subm\u00f3dulo.<\/p>\n<p>La carpeta con el subm\u00f3dulo es un repositorio GIT independiente. Se pueden usar comandos GIT desde esa carpeta, o\u00a0<em>git gui\u00a0\/ gitk<\/em> en ella. Los cambios afectar\u00e1n s\u00f3lo al contenido de la misma. Es posible crear y usar ramas, sincronizar con el origen, etc.<\/p>\n<p>Notas:<\/p>\n<ul>\n<li>El repositorio a a\u00f1adir como subm\u00f3dulo debe tener contenido (no sirve un repositorio reci\u00e9n creado, sin commits).<\/li>\n<li>Si \u00a0agregar el subm\u00f3dulo produce alguno de estos fallos:<\/li>\n<\/ul>\n<p style=\"padding-left: 60px;\">fatal: Not a git repository:\u00a0&lt;carpeta&gt;\/..\/..\/.git\/&lt;carpeta&gt;<\/p>\n<p>The following path is ignored by one of your .gitignore files: &lt;carpeta&gt;<\/p>\n<p style=\"padding-left: 30px;\">La soluci\u00f3n es: (<a href=\"http:\/\/stackoverflow.com\/a\/11764522\">fuente<\/a>)<\/p>\n<pre style=\"padding-left: 30px;\">$ rm -fr &lt;carpeta&gt; .git\/modules\/&lt;carpeta&gt;<\/pre>\n<h4>Actualizar los subm\u00f3dulos<\/h4>\n<p>El repositorio anfitri\u00f3n gestiona\u00a0<strong>la referencia<\/strong>\u00a0a un\u00a0<em>commit<\/em>\u00a0en el origen del subm\u00f3dulo, pero no gestiona el contenido de ese commit. Esta referencia se puede mover entre ramas, clonar, sincronizar con el origen, etc. Esto significa, por ejemplo, que al clonar un repositorio los subm\u00f3dulos estar\u00e1n vac\u00edos. El valor de la referencia s\u00f3lo cambia (aparece en\u00a0<em>git status<\/em>) cuando el subm\u00f3dulo se hace apuntar a un <em>commit<\/em> diferente en el origen. Por ejemplo, como resultado de commits locales en el subm\u00f3dulo, cambios de ramas, o sincronizaci\u00f3n con el origen.<\/p>\n<p>Cuando la referencia cambia por operaciones en el repositorio anfitri\u00f3n (ej. cambios de rama o <em>checkout<\/em>\u00a0a revisiones anteriores), \u00a0es necesario recrear el contenido apropiado dentro del subm\u00f3dulo para que coincida con el <em>commit<\/em> al que apuntaba en la revisi\u00f3n actual del anfitri\u00f3n.<\/p>\n<pre>$ git submodule update --init \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   # Clona los subm\u00f3dulos que falten por clonar y hace checkout del commit referenciado.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # --init asegura que los subm\u00f3dulos est\u00e9n inicializados (ej. tras un clone).\r\n$ git submodule update --init --recursive \u00a0 # Si los subm\u00f3dulos contienen otros subm\u00f3dulos, actualizarlos a su vez.<\/pre>\n<p>El contenido de los subm\u00f3dulos se actualiza y gestiona con las operaciones GIT normales dentro del subm\u00f3dulo.<\/p>\n<h4>Mover un subm\u00f3dulo a otra carpeta del repositorio<\/h4>\n<p>Asegurarse que el repositorio y los subm\u00f3dulos est\u00e1n actualizados. Entonces seguir las instrucciones (<a href=\"http:\/\/stackoverflow.com\/a\/10363449\/2519774\">fuente<\/a>).<\/p>\n<p>Ejemplo: mover un subm\u00f3dulo desde &#8220;Datos&#8221; a &#8220;var\/Datos&#8221;.<\/p>\n<ol>\n<li>Editar .gitmodules cambiando name y path a &#8220;var\/Datos&#8221;<\/li>\n<li>Mover la carpeta GIT del subm\u00f3dulo desde &#8220;.git\/modules\/Datos&#8221; a &#8220;.git\/modules\/var\/Datos&#8221;<\/li>\n<li>Mover la carpeta del subm\u00f3dulo desde &#8220;Datos&#8221; a &#8220;var\/Datos&#8221;<\/li>\n<li>Editar &#8220;.git\/modules\/var\/Datos\/config&#8221; y corregir la linea <code>[core] worktree<\/code>. En este ejemplo cambia de\u00a0<code>..\/..\/..\/Datos<\/code>\u00a0a\u00a0<code>..\/..\/..\/..\/var\/Datos<\/code><\/li>\n<li>Editar &#8220;ext\/Datos\/.git&#8221; y corregir\u00a0<code>gitdir<\/code>. Aqu\u00ed cambia de\u00a0<code>..\/.git\/modules\/Datos<\/code>\u00a0a\u00a0<code>..\/..\/git\/modules\/var\/Datos<\/code><\/li>\n<li><code>git add .gitmodules<\/code><\/li>\n<li><code>git rm --cached Datos<\/code><\/li>\n<li><code>git submodule add -f &lt;url&gt; var\/Datos<\/code><\/li>\n<\/ol>\n<p>En git status aparece<\/p>\n<pre><code># On branch master\r\n# Changes to be committed:\r\n#   (use \"git reset HEAD &lt;file&gt;...\" to unstage)\r\n#\r\n#   modified:   .gitmodules\r\n#   renamed:    Datos -&gt; var\/Datos\r\n<\/code><\/pre>\n<p>En el \u00faltimo paso podr\u00eda aparecer alguno de los fallos descritos al final del apartado\u00a0<em>A\u00f1adir un subm\u00f3dulo a un repositorio.<\/em> En ese caso aplicar la misma resoluci\u00f3n y repetir el paso 8.<\/p>\n<h4>Hacer un subm\u00f3dulo de una carpeta existente en un repositorio<\/h4>\n<p>El nuevo repositorio con el subm\u00f3dulo conservar\u00e1 el historial de los cambios en los ficheros de la carpeta (<a href=\"http:\/\/stackoverflow.com\/a\/17864475\/2519774\">Fuente 1<\/a>,\u00a0<a href=\"http:\/\/stackoverflow.com\/a\/1307969\/2519774\">Fuente 2<\/a>).<\/p>\n<p><strong style=\"line-height: 1.5em;\">1.<\/strong> Usar\u00a0<em>git subtree<\/em> para crear una nueva rama que s\u00f3lo contendr\u00e1 a esa carpeta<\/p>\n<pre>$ git subtree split -P &lt;carpeta&gt; -b &lt;nueva-rama&gt;<\/pre>\n<p><strong>2.<\/strong> Borrar la carpeta en la rama actual del repositorio<\/p>\n<pre>$ git rm -rf &lt;carpeta&gt;<\/pre>\n<p><strong>3.<\/strong> Recrear la carpeta e inicializar un nuevo repositorio GIT en ella. El repositorio remoto para el subm\u00f3dulo debe estar ya creado.<\/p>\n<pre>$ mkdir &lt;carpeta&gt;\r\n$ pushd &lt;carpeta&gt;\r\n$ git init\r\n$\u00a0git remote add origin &lt;ruta-al-repositorio-submodulo&gt;<\/pre>\n<p><strong>4.<\/strong> Traer (<em>pull<\/em>) al nuevo repositorio el contenido de &lt;nueva-rama&gt; en el repositorio anfitri\u00f3n, y subir al repositorio remoto.<\/p>\n<pre>$ git pull ..\/ &lt;nueva-rama&gt;              # usar ..\/..\/ \u00f3 ..\/..\/..\/ etc. seg\u00fan la profundidad de &lt;carpeta&gt;\r\n$ git push origin -u master<\/pre>\n<p>..\/ es la carpeta ra\u00edz del repositorio anfitri\u00f3n. Si &lt;carpeta&gt; tiene varios niveles de profundidad ser\u00e1 necesario encadenar ..\/..\/ \u00f3 ..\/..\/..\/ etc hasta llegar a la ra\u00edz del anfitri\u00f3n.<\/p>\n<p><strong>5.<\/strong> A\u00f1adir &lt;carpeta&gt; como subm\u00f3dulo al repositorio anfitri\u00f3n<\/p>\n<pre>$ popd\r\n$ git\u00a0submodule add &lt;ruta-al-repositorio-submodulo&gt; &lt;carpeta&gt;<\/pre>\n<p>Hacer <em>commit<\/em> de los cambios para completar el proceso.<\/p>\n<h4>Eliminar un subm\u00f3dulo de un repositorio<\/h4>\n<p>Debe hacerse manualmente, no hay un comando para ello:<\/p>\n<p><strong>1.<\/strong> Eliminar la entrada del subm\u00f3dulo en el fichero <em>.gitmodules<\/em>. Si s\u00f3lo hay un subm\u00f3dulo se puede borrar el fichero entero. Ejemplo:<\/p>\n<p style=\"padding-left: 30px;\">[submodule &#8220;Assets\/Common&#8221;]\npath = Assets\/Common<br \/>\nurl = ssh:\/\/git@gitserver.com\/user\/assets-common.git<\/p>\n<p><strong>2.<\/strong> Eliminar la entrada del subm\u00f3dulo en el fichero .git\/config. Ejemplo:<\/p>\n<p style=\"padding-left: 30px;\">[submodule &#8220;Assets\/Common&#8221;]\nurl = ssh:\/\/git@gitserver.com\/user\/assets-common.git<\/p>\n<p><strong>3.<\/strong> Borrar del \u00edndice la carpeta del subm\u00f3dulo<\/p>\n<pre>$ git rm --cached &lt;carpeta&gt;<\/pre>\n<p><strong>4.<\/strong> Borrar las carpetas del subm\u00f3dulo en en el repositorio anfitri\u00f3n<\/p>\n<pre>$ rm -fr &lt;carpeta&gt; .git\/modules\/&lt;carpeta&gt;<\/pre>\n<p>Hecho. El subm\u00f3dulo queda completamente eliminado del repositorio.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Notas: Cambios locales\u00a0se refiere a los ficheros del directorio de trabajo (working dir) que hayan sido modificados desde el \u00faltimo commit. COMMIT\u00a0es un indicador cualquiera en el repositorio: SHA1 de un commit, tag, HEAD (ultimo commit de la rama actual), HEAD~1 (antecesor de HEAD)&#8230; La mayor\u00eda de las veces, si no se indica se asume [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":255,"parent":228,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"page-c.php","meta":{"footnotes":""},"class_list":["post-176","page","type-page","status-publish","has-post-thumbnail","hentry"],"jetpack_shortlink":"https:\/\/wp.me\/P1PjRF-2Q","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/comments?post=176"}],"version-history":[{"count":47,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/176\/revisions"}],"predecessor-version":[{"id":1740,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/176\/revisions\/1740"}],"up":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/pages\/228"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/media\/255"}],"wp:attachment":[{"href":"https:\/\/www.edy.es\/dev\/wp-json\/wp\/v2\/media?parent=176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}