tag restaurar conflictos git merge git-submodules git-subtree

restaurar - git tag



Error de fusión después de convertir el submódulo de Git en subárbol (4)

Tengo un proyecto donde originalmente estaba usando submódulos para algún código dependiente. Resulta que los submódulos no son realmente apropiados para este proyecto (y son difíciles de usar en la práctica), por lo que estoy convirtiendo cada submódulo en un subárbol (usando la nueva función git-subtree ).

En mi repositorio de trabajo, he eliminado con éxito cada submódulo y he agregado el antiguo repositorio de submódulo como un subárbol. No hay problema con esto.

Cuando voy a otro clon e intento extraer el primero, obtengo el siguiente error del paso de combinación:

error: The following untracked working tree files would be overwritten by merge: sub/.gitignore sub/Makefile sub/README sub/src/main.c ... and so on for all files in sub/ Aborting

Parece que esto se debe a que los archivos en sub/ nunca realmente existieron en el repositorio principal en primer lugar, y cuando Git aplica el parche para actualizar .gitmodules , no elimina el directorio con los archivos de submódulos. Cuando se procesa la próxima confirmación, donde Git intenta crear los nuevos archivos en sub/ que ahora forman parte del repositorio principal, todos esos archivos entran en conflicto con los archivos aún existentes en sub/ .

La solución que he encontrado es usar rm -rf sub antes de git pull , lo que evita este problema.

Mi pregunta es, ¿hay algún interruptor de línea de comando que pueda usar con git merge que diga "Sobrescribir cualquier archivo que exista en el directorio de trabajo"? Aún mejor sería una característica en la que git merge vería el contenido del archivo existente, y si el contenido es idéntico al archivo que iba a crear de todos modos, suprima el mensaje de error y continúe.

ACTUALIZACIÓN : He creado repositorios Git que demuestran este problema, para mostrar exactamente de lo que estoy hablando. Reproducir:

$ git clone https://github.com/ghewgill/q14224966.git $ cd q14224966 $ git submodule init $ git submodule update $ git merge origin/branch

Esto debería resultar en el mensaje de error

error: The following untracked working tree files would be overwritten by merge: sub/Makefile sub/README sub/src/main.c Please move or remove them before you can merge. Aborting


(Advertencia: nunca he trabajado con subárboles y no sé qué tan complicado es tu repo real, por lo que estas soluciones pueden no funcionar para ti).

Después de jugar con su muestra de ejemplo, he encontrado dos soluciones que parecen funcionar, aunque producen diferentes árboles de compromiso:

  1. Usar git merge -s resolve origin/branch

    ~/q14224966[master]> git reset --hard origin/master HEAD is now at a231acd add submodule ~/q14224966[master]> touch other.c && git add . && git commit -m "New commit." [master bc771ac] New commit. 0 files changed create mode 100644 other.c ~/q14224966[master]> git merge -s resolve origin/branch Trying really trivial in-index merge... error: Merge requires file-level merging Nope. Trying simple merge. Simple merge failed, trying Automatic merge. Adding sub/Makefile Adding sub/README Adding sub/src/main.c Merge made by the ''resolve'' strategy. .gitmodules | 3 --- sub | 1 - sub/Makefile | 1 + sub/README | 1 + sub/src/main.c | 1 + 5 files changed, 3 insertions(+), 4 deletions(-) delete mode 160000 sub create mode 100644 sub/Makefile create mode 100644 sub/README create mode 100644 sub/src/main.c ~/q14224966[master]> ls README main.c other.c sub/ ~/q14224966[master]> cd sub/ ~/q14224966/sub[master]> ls Makefile README src/ ~/q14224966/sub[master]> git status # On branch master # Your branch is ahead of ''origin/master'' by 5 commits. # nothing to commit (working directory clean) ~/q14224966/sub[master]> cd .. ~/q14224966[master]> git status # On branch master # Your branch is ahead of ''origin/master'' by 5 commits. # nothing to commit (working directory clean)

    Aquí está el árbol de confirmación resultante:

  2. Utilice un rebase en lugar de una combinación:

    ~/q14224966[master]> git reset --hard origin/master HEAD is now at a231acd add submodule ~/q14224966[master]> touch other.c && git add . && git commit -m "New commit." [master ae66060] New commit. 0 files changed create mode 100644 other.c ~/q14224966[master]> git rebase origin/branch First, rewinding head to replay your work on top of it... Applying: New commit. ~/q14224966[master]> ls README main.c other.c sub/ ~/q14224966[master]> cd sub/ ~/q14224966/sub[master]> ls Makefile README src/ ~/q14224966/sub[master]> git status # On branch master # Your branch is ahead of ''origin/master'' by 4 commits. # nothing to commit (working directory clean) ~/q14224966/sub[master]> cd .. ~/q14224966[master]> git status # On branch master # Your branch is ahead of ''origin/master'' by 4 commits. # nothing to commit (working directory clean)

    Aquí está el árbol de confirmación resultante:


Lo intentó

ir a buscar - todo

git reset - hard origin / master

pero no funciona

Puedes usar la estrategia de fusión ''nuestra'':

git merge -s nuestro viejo maestro

También puedes usar git-stash para guardar tus cambios y luego aplicar git-stash para restaurarlos.


No puedes hacer que git-merge (o cualquier otro comando) pegue a la fuerza archivos que no cree que conozcan, no. Git trata bastante duro de no hacer nada totalmente irreversible.

Pero con muchos submódulos, puede hacer que su eliminación sea un poco más fácil y segura con git submodule foreach :

$ git submodule foreach ''rm -rf $toplevel/$path'' Entering ''sub'' $ git merge origin/branch Updating a231acd..6b4d2f4 Fast-forward ...


Sé que su pregunta fue específica para fusionar, pero he tenido problemas similares con la fusión de submódulos de git. Creo que esta solución funcionará con su problema, incluso si no está abordando directamente la pregunta de combinación.

Descubrí que al forzar la comprobación de la rama que desea fusionar y luego volver a dominar, todo funciona con submódulos.

Para que las cosas funcionen en tu ejemplo:

$ git clone https://github.com/ghewgill/q14224966.git $ cd q14224966 $ git submodule init $ git submodule update $ git checkout -f origin/branch $ git checkout master $ git merge origin/branch

Esto funciona porque básicamente está haciendo su paso rm -rf por usted. Por supuesto, esto es un poco indirecto, y tal vez no valga la pena hacerlo si solo tiene el submódulo como lo hace su ejemplo. Pero he encontrado que es bastante el ahorro de tiempo cuando se trabaja en un proyecto con muchos submódulos.

Además, como se ha señalado en los comentarios, si desea evitar realizar cambios en el árbol de trabajo, puede utilizar esto:

$ git clone https://github.com/ghewgill/q14224966.git $ cd q14224966 $ git submodule init $ git submodule update $ git reset origin/branch $ git reset --hard master

Esto funciona aproximadamente de la misma manera, pero evita ver otros archivos en el proceso. No he tenido la oportunidad de usar esto en la naturaleza, pero parece un método de sonido.

También hay $ git merge -s subtree origin/branch . Funciona con su ejemplo, pero he tenido resultados inesperados con más de un submódulo. Aunque podrías tener mejor suerte.