tag - Desmodular un submódulo git.
git tag best practices (11)
¿Cómo descompongo un submódulo de git (devuelvo todo el código al núcleo)?
Como en cómo "debería" yo, como en "Mejor procedimiento" ...
-
git rm --cached the_submodule_path
- elimine la sección de submódulos del archivo
.gitmodules
, o si es el único submódulo, elimine el archivo. - hacer un commit "eliminado submódulo xyz"
-
git add the_submodule_path
- otro commit "añadido codebase de xyz"
No encontré ninguna manera más fácil todavía. Puede comprimir 3-5 en un solo paso a través de git commit -a
- cuestión de gustos.
Aquí hay una versión ligeramente mejorada (IMHO) de la respuesta principal actual:
En un directorio separado (para hacer que los errores sean más fáciles de limpiar e intentar nuevamente) revisa tanto el repositorio superior como el subrepo.
git clone ../main_repo main.tmp
git clone ../main_repo/sub_repo sub.tmp
Primero edite el subrepo para mover todos los archivos al subdirectorio deseado
cd sub.tmp
mkdir sub_repo_path
git mv `ls | grep -v sub_repo_path` sub_repo_path/
git commit -m "Moved entire subrepo into sub_repo_path"
Toma nota de la CABEZA
SUBREPO_HEAD=`git reflog | awk ''{ print $1; exit; }''`
Ahora quita el subrepo del repositorio principal
cd ../main.tmp
rmdir sub_repo_path
vi .gitmodules # remove config for submodule
git add -A
git commit -m "Removed submodule sub_repo_path in preparation for merge"
Y finalmente, simplemente fusionarlos
git fetch ../sub.tmp
git merge $SUBREPO_HEAD
¡Y hecho! Con seguridad y sin magia.
Basado en la respuesta de VonC , he creado un simple script de bash que hace esto. El add
al final tiene que usar comodines, de lo contrario, deshará el rm
anterior para el submódulo. Es importante agregar el contenido del directorio de submódulos y no nombrar el directorio en sí en el comando add
.
En un archivo llamado git-integrate-submodule
:
#!/usr/bin/env bash
mv "$1" "${1}_"
git submodule deinit "$1"
git rm "$1"
mv "${1}_" "$1"
git add "$1/**"
Desde git 1.8.5 (noviembre de 2013 ) ( sin guardar la historia del submódulo ):
mv yoursubmodule yoursubmodule_tmp
git submodule deinit yourSubmodule
git rm yourSubmodule
mv yoursubmodule_tmp yoursubmodule
git add yoursubmodule
Esa voluntad:
- anular el registro y descargar (es decir, eliminar el contenido de ) el submódulo (
deinit
, de ahí elmv
primero ), - limpia los
.gitmodules
para ti (rm
), - y elimine la entrada especial que representa ese submódulo SHA1 en el índice del repositorio principal (
rm
).
Una vez que se completa la eliminación del submódulo ( deinit
y git rm
), puede cambiar el nombre de la carpeta a su nombre original y agregarla al repositorio de git como una carpeta normal.
Nota: si el submódulo fue creado por un Git antiguo (<1.8), es posible que deba eliminar la carpeta .git
anidada dentro del propio submódulo, como lo commented Simon East.
Si necesita mantener el historial del submódulo, vea la answer jsears , que usa git filter-branch
.
Hay muchas respuestas aquí, pero todas parecen ser demasiado complejas y es probable que no hagan lo que usted quiere. Estoy seguro de que la mayoría de la gente quiere mantener su historia.
Para este ejemplo, el repositorio principal será [email protected]:main/main.git
y el repositorio de submódulos será [email protected]:main/child.git
. Esto supone que el submódulo se encuentra en el directorio raíz del repositorio principal. Ajuste las instrucciones según sea necesario.
Comience por clonar el repositorio principal y eliminar el submódulo anterior.
git clone [email protected]:main/main.git
git submodule deinit child
git rm child
git add --all
git commit -m "remove child submodule"
Ahora agregaremos los repos del niño en sentido ascendente al repositorio principal.
git remote add upstream [email protected]:main/child.git
git fetch upstream
git checkout -b merge-prep upstream/master
El siguiente paso supone que desea mover los archivos en la rama de combinación de preparación a la misma ubicación que el submódulo que estaba arriba, aunque puede cambiar fácilmente la ubicación cambiando la ruta del archivo.
mkdir child
mueva todas las carpetas y archivos excepto la carpeta .git a la carpeta secundaria.
git add --all
git commit -m "merge prep"
Ahora puede simplemente fusionar sus archivos de nuevo en la rama maestra.
git checkout master
git merge merge-prep # --allow-unrelated-histories merge-prep flag may be required
Mire a su alrededor y asegúrese de que todo se vea bien antes de ejecutar git push
Lo único que debes recordar ahora es que git log no sigue de forma predeterminada los archivos movidos; sin embargo, al ejecutar git log --follow filename
, puedes ver el historial completo de tus archivos.
He creado un script que traducirá un submódulo a un directorio simple, al tiempo que conserva todo el historial de archivos. No sufre los problemas de git log --follow <file>
que sufren las otras soluciones. También es una invocación de una línea muy fácil que hace todo el trabajo por ti. G''luck
Se basa en el excelente trabajo de Lucas Jenß, descrito en su entrada del blog " Integración de un submódulo en el repositorio principal ", pero automatiza todo el proceso y limpia algunos otros casos de esquina.
El código más reciente se mantendrá con las correcciones de errores en github en https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewrite , pero por el bien del protocolo de respuesta de adecuado, he incluido el Solución en su totalidad a continuación.
Uso:
$ git-submodule-rewrite <submodule-name>
git-submodule-rewrite
#!/usr/bin/env bash
# This script builds on the excellent work by Lucas Jenß, described in his blog
# post "Integrating a submodule into the parent repository", but automates the
# entire process and cleans up a few other corner cases.
# https://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html
function usage(){
echo "Merge a submodule into a repo, retaining file history."
echo "Usage: $0 <submodule-name>"
echo ""
echo "options:"
echo " -h, --help Print this message"
echo " -v, --verbose Display verbose output"
}
function abort {
echo "$(tput setaf 1)$1$(tput sgr0)"
exit 1
}
function request_confirmation {
read -p "$(tput setaf 4)$1 (y/n) $(tput sgr0)"
[ "$REPLY" == "y" ] || abort "Aborted!"
}
function warn() {
cat << EOF
This script will convert your "${sub}" git submodule into
a simple subdirectory in the parent repository while retaining all
contents and file history.
The script will:
* delete the ${sub} submodule configuration from .gitmodules and
.git/config and commit it.
* rewrite the entire history of the ${sub} submodule so that all
paths are prefixed by ${path}.
This ensures that git log will correctly follow the original file
history.
* merge the submodule into its parent repository and commit it.
NOTE: This script might completely garble your repository, so PLEASE apply
this only to a fresh clone of the repository where it does not matter if
the repo is destroyed. It would be wise to keep a backup clone of your
repository, so that you can reconstitute it if need be. You have been
warned. Use at your own risk.
EOF
request_confirmation "Do you want to proceed?"
}
function git_version_lte() {
OP_VERSION=$(printf "%03d%03d%03d%03d" $(echo "$1" | tr ''.'' ''/n'' | head -n 4))
GIT_VERSION=$(git version)
GIT_VERSION=$(printf "%03d%03d%03d%03d" $(echo "${GIT_VERSION#git version}" | tr ''.'' ''/n'' | head -n 4))
echo -e "${GIT_VERSION}/n${OP_VERSION}" | sort | head -n1
[ ${OP_VERSION} -le ${GIT_VERSION} ]
}
function main() {
warn
if [ "${verbose}" == "true" ]; then
set -x
fi
# Remove submodule and commit
git config -f .gitmodules --remove-section "submodule.${sub}"
if git config -f .git/config --get "submodule.${sub}.url"; then
git config -f .git/config --remove-section "submodule.${sub}"
fi
rm -rf "${path}"
git add -A .
git commit -m "Remove submodule ${sub}"
rm -rf ".git/modules/${sub}"
# Rewrite submodule history
local tmpdir="$(mktemp -d -t submodule-rewrite-XXXXXX)"
git clone "${url}" "${tmpdir}"
pushd "${tmpdir}"
local tab="$(printf ''/t'')"
local filter="git ls-files -s | sed /"s/${tab}/${tab}${path}////" | GIT_INDEX_FILE=/${GIT_INDEX_FILE}.new git update-index --index-info && mv /${GIT_INDEX_FILE}.new /${GIT_INDEX_FILE}"
git filter-branch --index-filter "${filter}" HEAD
popd
# Merge in rewritten submodule history
git remote add "${sub}" "${tmpdir}"
git fetch "${sub}"
if git_version_lte 2.8.4
then
# Previous to git 2.9.0 the parameter would yield an error
ALLOW_UNRELATED_HISTORIES=""
else
# From git 2.9.0 this parameter is required
ALLOW_UNRELATED_HISTORIES="--allow-unrelated-histories"
fi
git merge -s ours --no-commit ${ALLOW_UNRELATED_HISTORIES} "${sub}/master"
rm -rf tmpdir
# Add submodule content
git clone "${url}" "${path}"
rm -rf "${path}/.git"
git add "${path}"
git commit -m "Merge submodule contents for ${sub}"
git config -f .git/config --remove-section "remote.${sub}"
set +x
echo "$(tput setaf 2)Submodule merge complete. Push changes after review.$(tput sgr0)"
}
set -euo pipefail
declare verbose=false
while [ $# -gt 0 ]; do
case "$1" in
(-h|--help)
usage
exit 0
;;
(-v|--verbose)
verbose=true
;;
(*)
break
;;
esac
shift
done
declare sub="${1:-}"
if [ -z "${sub}" ]; then
>&2 echo "Error: No submodule specified"
usage
exit 1
fi
shift
if [ -n "${1:-}" ]; then
>&2 echo "Error: Unknown option: ${1:-}"
usage
exit 1
fi
if ! [ -d ".git" ]; then
>&2 echo "Error: No git repository found. Must be run from the root of a git repository"
usage
exit 1
fi
declare path="$(git config -f .gitmodules --get "submodule.${sub}.path")"
declare url="$(git config -f .gitmodules --get "submodule.${sub}.url")"
if [ -z "${path}" ]; then
>&2 echo "Error: Submodule not found: ${sub}"
usage
exit 1
fi
if ! [ -d "${path}" ]; then
>&2 echo "Error: Submodule path not found: ${path}"
usage
exit 1
fi
main
La mejor respuesta a esto que he encontrado está aquí:
Este artículo explica muy bien el procedimiento.
Me pareció más conveniente (también?) Obtener datos de confirmación local del submódulo, porque de lo contrario los perdería. (No pude empujarlos ya que no tengo acceso a ese control remoto). Así que agregué submódulo / .git como remote_origin2, obtuve los confirmados y los fusioné desde esa rama. No estoy seguro si todavía necesito el submódulo remoto como origen, ya que todavía no estoy lo suficientemente familiarizado con git.
Nos ocurrió que creamos 2 repositorios para 2 proyectos que estaban tan acoplados que no tenía sentido separarlos, así que los fusionamos.
Mostraré cómo fusionar las ramas maestras en cada una y luego explicaré cómo puede extender esto a cada una de las ramas que tiene, espero que le sirva de ayuda.
Si tiene el submódulo en funcionamiento y desea convertirlo en un directorio, puede hacerlo:
git clone project_uri project_name
Aquí hacemos un clon limpio para trabajar. Para este proceso no necesita inicializar o actualizar los submódulos, así que simplemente omítalo.
cd project_name
vim .gitmodules
Edite .gitmodules
con su editor favorito (o Vim) para eliminar el submódulo que planea reemplazar. Las líneas que necesitas eliminar deberían verse así:
[submodule "lib/asi-http-request"]
path = lib/asi-http-request
url = https://github.com/pokeb/asi-http-request.git
Después de guardar el archivo,
git rm --cached directory_of_submodule
git commit -am "Removed submodule_name as submodule"
rm -rf directory_of_submodule
Aquí eliminamos completamente la relación de submódulo para que podamos crear traer el otro repositorio al proyecto en el lugar.
git remote add -f submodule_origin submodule_uri
git fetch submodel_origin/master
Aquí vamos a buscar el repositorio de submódulos para fusionar.
git merge -s ours --no-commit submodule_origin/master
Aquí comenzamos una operación de fusión de los 2 repositorios, pero paramos antes de confirmar.
git read-tree --prefix=directory_of_submodule/ -u submodule_origin/master
Aquí enviamos el contenido del maestro en el submódulo al directorio donde estaba antes de prefijar un nombre de directorio
git commit -am "submodule_name is now part of main project"
Aquí completamos el procedimiento realizando una confirmación de los cambios en la combinación.
Después de terminar esto, puede presionar, y comenzar nuevamente con cualquier otra rama para fusionar, simplemente verifique la rama en su repositorio que recibirá los cambios y cambie la rama que traiga en las operaciones de fusión y lectura en árbol.
Para cuando
git rm [-r] --cached submodule_path
devoluciones
fatal: pathspec ''emr/normalizers/'' did not match any files
Contexto: realicé rm -r .git*
en mis carpetas de submódulos antes de darme cuenta de que debían ser desmodificados en el proyecto principal al que acababa de agregarlos. Recibí el error anterior al descomponer algunos, pero no todos. De todos modos, los arreglé ejecutando, (después, por supuesto, el rm -r .git*
)
mv submodule_path submodule_path.temp
git add -A .
git commit -m "De-submodulization phase 1/2"
mv submodule_path.temp submodule_path
git add -A .
git commit -m "De-submodulization phase 2/2"
Tenga en cuenta que esto no conserva la historia.
Si todo lo que desea es poner su código de submódulo en el repositorio principal, solo necesita eliminar el submódulo y volver a agregar los archivos en el repositorio principal:
git rm --cached submodule_path # delete reference to submodule HEAD (no trailing slash)
git rm .gitmodules # if you have more than one submodules,
# you need to edit this file instead of deleting!
rm -rf submodule_path/.git # make sure you have backup!!
git add submodule_path # will add files instead of commit reference
git commit -m "remove submodule"
Si también desea conservar el historial del submódulo, puede hacer un pequeño truco: "fusionar" el submódulo en el repositorio principal para que el resultado sea el mismo que antes, excepto que los archivos del submódulo ahora están en el repositorio principal.
En el módulo principal deberá hacer lo siguiente:
# Fetch the submodule commits into the main repository
git remote add submodule_origin git://url/to/submodule/origin
git fetch submodule_origin
# Start a fake merge (won''t change any files, won''t commit anything)
git merge -s ours --no-commit submodule_origin/master
# Do the same as in the first solution
git rm --cached submodule_path # delete reference to submodule HEAD
git rm .gitmodules # if you have more than one submodules,
# you need to edit this file instead of deleting!
rm -rf submodule_path/.git # make sure you have backup!!
git add submodule_path # will add files instead of commit reference
# Commit and cleanup
git commit -m "removed submodule"
git remote rm submodule_origin
El repositorio resultante se verá un poco raro: habrá más de un compromiso inicial. Pero no causará ningún problema para git.
En esta segunda solución, tendrá la gran ventaja de que aún puede ejecutar git blame o git log en los archivos que estaban originalmente en los submódulos. De hecho, lo que hizo aquí es cambiar el nombre de muchos archivos dentro de un repositorio, y git debería autodetectar esto. Si aún tiene problemas con el registro de git, pruebe algunas opciones (--follow, -M, -C) que hacen un mejor cambio de nombre / detección de copia.