tipos tag repositorio etiquetas eliminar crear git

repositorio - git push tag



Establecer el puntero padre de git en un padre diferente (4)

Si tengo un compromiso en el pasado que apunta a uno de los padres, pero quiero cambiar el padre al que apunta, ¿cómo podría hacer eso?


Si resulta que debe evitar volver a establecer las correlaciones posteriores (p. Ej., Porque una reescritura del historial sería insostenible), puede usar el reemplazo de git (disponible en Git 1.6.5 y posterior).

# …---o---A---o---o---… # # …---o---B---b---b---… # # We want to transplant B to be "on top of" A. # The tree of descendants from B (and A) can be arbitrarily complex. replace_first_parent() { old_parent=$(git rev-parse --verify "${1}^1") || return 1 new_parent=$(git rev-parse --verify "${2}^0") || return 2 new_commit=$( git cat-file commit "$1" | sed -e ''1,/^$/s/^parent ''"$old_parent"''$/parent ''"$new_parent"''/'' | git hash-object -t commit -w --stdin ) || return 3 git replace "$1" "$new_commit" } replace_first_parent B A # …---o---A---o---o---… # / # C---b---b---… # # C is the replacement for B.

Con el reemplazo anterior establecido, cualquier solicitud para el objeto B realmente devolverá el objeto C. El contenido de C es exactamente el mismo que el contenido de B, excepto para el primer padre (los mismos padres (excepto el primero), el mismo árbol, el mismo mensaje de confirmación).

Los reemplazos están activos por defecto, pero se pueden desactivar utilizando la --no-replace-objects para git (antes del nombre del comando) o configurando la variable de entorno GIT_NO_REPLACE_OBJECTS . Los reemplazos se pueden compartir presionando refs/replace/* (además de los refs/heads/* normales).

Si no te gusta commit-munging (hecho con sed arriba), entonces puedes crear tu commit de reemplazo usando comandos de nivel superior:

git checkout B~0 git reset --soft A git commit -C B git replace B HEAD git checkout -

La gran diferencia es que esta secuencia no propaga los padres adicionales si B es una combinación de fusión.


Para aclarar las respuestas anteriores y sin pudor, conecte mi propio guión:

Depende de si desea "rebase" o "reparent". Una rebase , según lo sugerido por Amber , se mueve alrededor de diffs . Un reparador , como lo sugirieron Jakub y Chris , mueve instantáneas de todo el árbol. Si desea reparen, sugiero usar git reparent lugar de hacer el trabajo manualmente.

Comparación

Supongamos que tiene la imagen de la izquierda y quiere que se vea como en la imagen de la derecha:

C'' / A---B---C A---B---C

Tanto el rebasamiento como el reparenting producirán la misma imagen, pero la definición de C'' . Con git rebase --onto AB , C'' no contendrá ningún cambio introducido por B Con git reparent -p A , C'' será idéntico a C (excepto que B no estará en el historial).


Tenga en cuenta que cambiar una confirmación en Git requiere que se modifiquen todas las confirmaciones que siguen. Esto se desaconseja si ha publicado esta parte de la historia, y alguien podría haber construido su trabajo en la historia que era antes del cambio.

La solución alternativa a git rebase mencionada en la respuesta de Amber es usar el mecanismo de injertos (ver definición de injertos Git en Git Glossary y documentación del archivo .git/info/grafts en la documentación de Git Repository Layout ) para cambiar el padre de una confirmación, verificar que lo hizo Lo correcto con algún visor de historial ( gitk , git log --graph , etc.) y luego use git filter-branch (como se describe en la sección "Ejemplos" de su página de manual) para hacerlo permanente (y luego eliminar injerto, y opcionalmente eliminar las referencias originales respaldadas por git filter-branch o repositorio reclone):

echo "$commit-id $graft-id" >> .git/info/grafts git filter-branch $graft-id..HEAD

NOTA !!! Esta solución es diferente de la solución de rebase en que la base de datos de git rebase cambios de base / trasplante, mientras que la solución basada en injertos simplemente reparará las confirmaciones tal cual , sin tomar en cuenta las diferencias entre el padre antiguo y el nuevo padre.


Usando git rebase . Es el genérico "tomar commit (s) y colocarlo / plop / them en un comando diferente (base)" en Git.

Algunas cosas que debe saber, sin embargo:

  1. Como comprometer SHA involucran a sus padres, cuando cambias el padre de un compromiso determinado, su SHA cambiará, al igual que los SHA de todos los commits que vengan después (más recientes que él) en la línea de desarrollo.

  2. Si está trabajando con otras personas, y ya ha empujado el compromiso en cuestión al público hasta donde lo han extraído, modificar el compromiso es probablemente una Idea Mala ™. Esto se debe al n. ° 1 y, por lo tanto, a la confusión resultante que encontrarán los repositorios de otros usuarios al tratar de descubrir qué sucedió debido a que sus SHA ya no coinciden con los suyos para los "mismos" commits. (Consulte la sección "RECUPERACIÓN DE UPSTREAM REBASE" de la página man vinculada para más detalles).

Dicho esto, si actualmente se encuentra en una sucursal con algunas confirmaciones que desea transferir a un nuevo padre, se vería algo como esto:

git rebase --onto <new-parent> <old-parent>

Eso moverá todo después de <old-parent> en la rama actual para situarse en la parte superior de <new-parent> .