El consejo que le dieron es defectuoso. Establecer incondicionalmente GIT_AUTHOR_DATE en un --env-filter
reescribe la fecha de cada confirmación. Además, sería inusual usar git commit dentro --index-filter
.
Estás lidiando con múltiples problemas independientes aquí.
Especificar fechas distintas a "ahora"
Cada confirmación tiene dos fechas: la fecha del autor y la fecha del confirmador. Puede anular cada uno proporcionando valores a través de las variables de entorno GIT_AUTHOR_DATE y GIT_COMMITTER_DATE para cualquier comando que escriba una nueva confirmación. Consulte "Formatos de fecha" en git-commit (1) o a continuación:
Git internal format = <unix timestamp> <time zone offset>, e.g. 1112926393 +0200
RFC 2822 = e.g. Thu, 07 Apr 2005 22:13:13 +0200
ISO 8601 = e.g. 2005-04-07T22:13:13
El único comando que escribe un nuevo commit durante el uso normal es git commit . También tiene una --date
opción que le permite especificar directamente la fecha del autor. Su uso anticipado incluye git filter-branch --env-filter
también las variables de entorno mencionadas anteriormente (estas son parte del "env" después del cual se nombra la opción; consulte "Opciones" en git-filter-branch (1) y el comando subyacente "plomería" git-commit -árbol (1) .
Insertar un archivo en un solo historial de referencia
Si su repositorio es muy simple (es decir, solo tiene una sola rama, sin etiquetas), entonces probablemente pueda usar git rebase para hacer el trabajo.
En los siguientes comandos, use el nombre del objeto (hash SHA-1) de la confirmación en lugar de "A". No olvide utilizar uno de los métodos de "anulación de fecha" cuando ejecute git commit .
---A---B---C---o---o---o master
git checkout master
git checkout A~0
git add path/to/file
git commit --date='whenever'
git tag ,new-commit -m'delete me later'
git checkout -
git rebase --onto ,new-commit A
git tag -d ,new-commit
---A---N (was ",new-commit", but we delete the tag)
\
B'---C'---o---o---o master
Si desea actualizar A para incluir el nuevo archivo (en lugar de crear una nueva confirmación donde se agregó), use en git commit --amend
lugar de git commit
. El resultado se vería así:
---A'---B'---C'---o---o---o master
Lo anterior funciona siempre que pueda nombrar el commit que debería ser el padre de su nuevo commit. Si realmente desea que su nuevo archivo se agregue a través de una nueva confirmación raíz (sin padres), entonces necesita algo un poco diferente:
B---C---o---o---o master
git checkout master
git checkout --orphan new-root
git rm -rf .
git add path/to/file
GIT_AUTHOR_DATE='whenever' git commit
git checkout -
git rebase --root --onto new-root
git branch -d new-root
N (was new-root, but we deleted it)
\
B'---C'---o---o---o master
git checkout --orphan
es relativamente nuevo (Git 1.7.2), pero hay otras formas de hacer lo mismo que funcionan en versiones anteriores de Git.
Insertar un archivo en un historial de múltiples referencias
Si su repositorio es más complejo (es decir, tiene más de una referencia (ramas, etiquetas, etc.)), entonces probablemente necesitará usar git filter-branch . Antes de usar git filter-branch , debe hacer una copia de seguridad de todo su repositorio. Un archivo tar simple de todo su árbol de trabajo (incluido el directorio .git) es suficiente. git filter-branch hace referencias de copia de seguridad, pero a menudo es más fácil recuperarse de un filtro no del todo correcto simplemente borrando su .git
directorio y restableciéndolo desde su copia de seguridad.
Nota: Los siguientes ejemplos usan el comando de nivel inferior en git update-index --add
lugar de git add
. Podría usar git add , pero primero necesitaría copiar el archivo desde alguna ubicación externa a la ruta esperada ( --index-filter
ejecuta su comando en un GIT_WORK_TREE temporal que está vacío).
Si desea que su nuevo archivo se agregue a cada confirmación existente, puede hacer esto:
new_file=$(git hash-object -w path/to/file)
git filter-branch \
--index-filter \
'git update-index --add --cacheinfo 100644 '"$new_file"' path/to/file' \
--tag-name-filter cat \
-- --all
git reset --hard
Realmente no veo ninguna razón para cambiar las fechas de las confirmaciones existentes con --env-filter 'GIT_AUTHOR_DATE=…'
. Si lo usó, lo haría condicional para que reescribiera la fecha de cada confirmación.
Si desea que su nuevo archivo aparezca solo en las confirmaciones después de alguna confirmación existente ("A"), puede hacer esto:
file_path=path/to/file
before_commit=$(git rev-parse --verify A)
file_blob=$(git hash-object -w "$file_path")
git filter-branch \
--index-filter '
if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$before_commit"') &&
test -n "$x"; then
git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
fi
' \
--tag-name-filter cat \
-- --all
git reset --hard
Si desea que el archivo se agregue a través de una nueva confirmación que se insertará en la mitad de su historial, deberá generar la nueva confirmación antes de usar git filter-branch y agregar --parent-filter
a git filter-branch :
file_path=path/to/file
before_commit=$(git rev-parse --verify A)
git checkout master
git checkout "$before_commit"
git add "$file_path"
git commit --date='whenever'
new_commit=$(git rev-parse --verify HEAD)
file_blob=$(git rev-parse --verify HEAD:"$file_path")
git checkout -
git filter-branch \
--parent-filter "sed -e s/$before_commit/$new_commit/g" \
--index-filter '
if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$new_commit"') &&
test -n "$x"; then
git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
fi
' \
--tag-name-filter cat \
-- --all
git reset --hard
También puede hacer arreglos para que el archivo se agregue primero en una nueva confirmación de raíz: cree su nueva confirmación de raíz a través del método "huérfano" de la sección git rebase (capturarla new_commit
), use el incondicional --index-filter
y cosas --parent-filter
similares "sed -e \"s/^$/-p $new_commit/\""
.