tipos - ¿Cómo anteponer el pasado a un repositorio git?
git ver archivos modificados (3)
Recibí un código fuente y decidí usar git porque mi compañero de trabajo usaba el enfoque mkdir $VERSION
etc. Si bien el pasado del código actualmente no parece importante, me gustaría ponerlo bajo control git también para comprender mejor el proceso de desarrollo. Asi que:
¿Cuál es una forma conveniente de poner esas versiones pasadas en mi repositorio git ya existente? Actualmente no hay ningún repositorio remoto, así que no me importa reescribir el historial, pero una solución que tenga en cuenta los repositorios remotos será, por supuesto, preferible a menos que sea mucho más complicado. Puntos de bonificación para una secuencia de comandos que no necesita más interacción en función de un directorio o un archivo basado en el historial de archivos.
El enfoque más fácil es, por supuesto, crear un nuevo repositorio de git, comprometer la historia para anteponer primero y luego volver a aplicar los parches del antiguo repositorio. Pero preferiría una solución que consuma menos tiempo mediante la automatización.
Para importar las instantáneas antiguas, algunas de las herramientas del directorio contrib / fast-git de Git son útiles. O bien, si ya tiene cada instantánea anterior en un directorio, puede hacer algo como esto:
# Assumes the v* glob will sort in the right order
# (i.e. zero padded, fixed width numeric fields)
# For v1, v2, v10, v11, ... you might try:
# v{1..23} (1 through 23)
# v?{,?} (v+one character, then v+two characters)
# v?{,?{,?}} (v+{one,two,three} characters)
# $(ls -v v*) (GNU ls has "version sorting")
# Or, just list them directly: ``for d in foo bar baz quux; do''''
(git init import)
for d in v*; do
if mv import/.git "$d/"; then
(cd "$d" && git add --all && git commit -m"pre-Git snapshot $d")
mv "$d/.git" import/
fi
done
(cd import && git checkout HEAD -- .)
A continuación, busque el historial anterior en su repositorio en funcionamiento:
cd work && git fetch ../import master:old-history
Una vez que tenga tanto el historial anterior como el historial basado en Git en el mismo repositorio, tiene un par de opciones para la operación de anteponer: injertos y reemplazos.
Los injertos son un mecanismo por repositorio para (posiblemente temporalmente) editar el origen de varias confirmaciones existentes. Los injertos están controlados por el $GIT_DIR/info/grafts
(descrito en "información / injertos" de la página de manual de gitrepository-layout ).
INITIAL_SHA1=$(git rev-list --reverse master | head -1)
TIP_OF_OLD_HISTORY_SHA1=$(git rev-parse old-history)
echo $INITIAL_SHA1 $TIP_OF_OLD_HISTORY_SHA1 >> .git/info/grafts
Con el injerto en su lugar (el compromiso inicial original no tenía padres, el injerto le dio uno de los padres), puede usar todas las herramientas normales de Git para buscar y ver el historial extendido (p. Ej., El git log
ahora debería mostrar el antiguo historia después de sus compromisos).
El principal problema con los injertos es que están limitados a su repositorio. Pero, si decides que deberían ser una parte permanente del historial, puedes usar git filter-branch para hacerlos así (primero haz una copia de seguridad de tar / zip de tu dir .git
; git filter-branch guardará los refs originales, pero a veces es más fácil usar una copia de seguridad simple).
git filter-branch --tag-name-filter cat -- --all
rm .git/info/grafts
El mecanismo de reemplazo es más nuevo (Git 1.6.5 +), pero pueden deshabilitarse por cada comando ( git --no-replace-objects …
) y pueden presionarse para compartirlo más fácilmente. El reemplazo funciona en objetos individuales (blobs, árboles, confirmaciones o etiquetas anotadas), por lo que el mecanismo también es más general. El mecanismo de reemplazo está documentado en la página de manual de git replace . Debido a la generalidad, la configuración de "anteponer" es un poco más complicada (tenemos que crear un nuevo compromiso en lugar de simplemente nombrar al nuevo padre):
# the last commit of old history branch
oldhead=$(git rev-parse --verify old-history)
# the initial commit of current branch
newinit=$(git rev-list master | tail -n 1)
# create a fake commit based on $newinit, but with a parent
# (note: at this point, $oldhead must be a full commit ID)
newfake=$(git cat-file commit "$newinit" /
| sed "/^tree [0-9a-f]/+/$/aparent $oldhead" /
| git hash-object -t commit -w --stdin)
# replace the initial commit with the fake one
git replace -f "$newinit" "$newfake"
Compartir este reemplazo no es automático. Tienes que empujar una parte (o la totalidad de) refs/replace
para compartir el reemplazo.
git push some-remote ''refs/replace/*''
Si decide hacer el reemplazo permanente, use git filter-branch (lo mismo que con los injertos, primero haga una copia de seguridad de tar / zip de su directorio .git
):
git filter-branch --tag-name-filter cat -- --all
git replace -d $INITIAL_SHA1
Si no desea cambiar las confirmaciones en su repositorio, puede usar injertos para anular la información principal para una confirmación. Esto es lo que hace el repositorio de Linux Kernel para obtener el historial antes de que comenzaran a usar Git.
Este mensaje: http://marc.info/?l=git&m=119636089519572 parece tener la mejor documentación que puedo encontrar.
Deberías crear una secuencia de confirmaciones relacionadas con tu historial previo al git, luego usar el archivo .git/info/grafts
para hacer que Git use el último commit en esa secuencia como padre del primer commit que generaste usando Git.