¿Cómo soluciono un subárbol git después de que la fuerza del proyecto aguas arriba empuje al maestro?

13

He estado experimentando con el uso de git subtree y me he encontrado con la siguiente situación.

Utilicé git subtree para agregar un proyecto externo a mi repositorio, guardé intencionalmente todo el historial del proyecto ascendente, ya que quiero poder referirme al historial del proyecto y también contribuir al proyecto ascendente más adelante.

Como resultado, otro contribuyente al proyecto ascendente introdujo accidentalmente un archivo grande en la rama maestra. Para solucionar esto, el proyecto aguas arriba reescribió la historia y la fuerza empujada al maestro. Al crear mi "monorepo", incluí este commit y también me gustaría eliminarlo.

¿Cómo puedo actualizar mi repositorio para reflejar el nuevo historial del subárbol?

Mi primer intento fue usar filter-branch para eliminar completamente el subárbol y todo el historial.

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

Una vez que se eliminó la versión anterior del subárbol, pude volver a agregar el subárbol usando el nuevo maestro ascendente. Sin embargo, esto no funcionó porque, por alguna razón, el historial de confirmación aún se muestra en la salida del registro git.

Actualizar

He escrito los pasos para crear un ejemplo mínimamente reproducible.

  1. Primero crea un repositorio git vacío.

    git init test-monorepo
    cd ./test-monorepo
    
  2. Crea una confirmación inicial.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. Ahora agregue un subárbol para un proyecto externo.

    git remote add thirdparty [email protected]:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. Haz algunos compromisos en el monorepo

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. Ahora intente usar git filter-branch para eliminar el subárbol.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. Examine la salida del registro de git, espero ver solo mi confirmación inicial.

    git log
    
csnate
fuente
¿Has intentado git gc --prune = ahora para descartar los commits antiguos? ¿Hay algunas referencias a los commits de la versión anterior?
Damiano
1
¿Todavía no probé esto, pero no git gc --prune=nowsolo eliminaría las confirmaciones que no aparecen git log?
csnate
El uso de git branch -all (que supongo que está utilizando para ver los commits "antiguos") debería mostrar también los commits no relacionados con su rama actual.
Damiano
1
En realidad, solo estaba haciendo git log, sin argumentos y todavía veo los viejos commits.
csnate
¿Puedes publicar tu registro de git --pretty --all --graph? Solo para entender tu situación
Damiano

Respuestas:

0

ya tiene el mal compromiso en su historial y necesita deshacerse de él antes de continuar

supongamos que se masterdesvió la última confirmación y no he podido hacer nada más (realmente no tengo sus ramas a la vista, así que necesito asumir algo para comenzar)

puede pasar por el commit anterior y empujar su marcador de rama 1 paso hacia atrás (o X pasos hacia atrás), lo que sería inofensivo en cualquier caso y luego volver a tirar

p.ej

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 para verificar el compromiso principal del maestro, git advierte que estamos fuera de las sucursales
  2. git branch master -f para forzar que la comprobación actual vuelva a ser maestra, es decir, en realidad rebobina la rama maestra a su compromiso anterior (o X compromiso anterior), y desde aquí, no importa si el flujo ascendente hizo una fuerza o no, podemos reanudar normalmente, o incluso Si es necesario, regrese al paso anterior, solo podemos extraer el master nuevamente, sin perder nada del flujo ascendente (que para nosotros también podría ser de solo lectura, no empujaremos nada para esto)
  3. git checkout master para estar en nuestra rama maestra "rebobinada", el mismo compromiso al que nos dirigimos, pero ahora estamos en la rama
  4. git pullpara extraer el master nuevamente (puede ser con o sin --prune), si se desvía aguas arriba, volveremos a la pista desde aquí, si no, obtendremos lo mismo que teníamos, si obtuvimos lo mismo y no se suponía, tal vez necesita volver al primer paso anterior y rebobinar más confirmaciones, por ejemplo, git checkout master~5o lo que sea (según sea necesario)
arhak
fuente
No creo que esto funcionegit subtree
csnate
@csnate es posible verificar las confirmaciones anteriores de un subrepo y seguir un procedimiento muy similar, si crea un MCVE, sería más fácil decirle los comandos exactos para seguir stackoverflow.com/help/minimal-reproducible-example
arhak
Intentaré crear un repositorio de muestra en GitHub.
csnate
Creé un conjunto de pasos en la pregunta original que muestra el problema.
csnate
0
  1. en su repositorio, limpie el historial de confirmaciones para este control remoto:

    git fetch upstream
    
  2. Si uno de sus propios commits tiene un commit que incluye el archivo grande, reescriba su historial para que este archivo grande ya no sea referenciado

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

Con estos dos pasos, el archivo grande ya no será referenciado por ningún commit en su repositorio.
Además, se eliminará de su disco duro en algún momento, cuando git ejecuta su recolector de basura y se han alcanzado los retrasos de caducidad de las gotas colgantes.


Si tiene una necesidad urgente de eliminar este archivo grande lo antes posible de su disco duro:

Ejecutar manualmente

git gc --prune=now
LeGEC
fuente