¿Cómo hago un commit de Git en el pasado?

Estoy convirtiendo todo en Git para mi uso personal y encontré algunas versiones antiguas de un file que ya están en el repository. ¿Cómo lo aplico al historial en el order correcto según la "date de modificación" del file, así que tengo un historial preciso del file?

Me dijeron que algo como esto funcionaría:

git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all 

El consejo que le dieron es defectuoso. La configuration incondicional de GIT_AUTHOR_DATE en un --env-filter reescribirá la date de cada confirmación. Además, sería inusual usar git commit inside --index-filter .

Aquí se enfrentan múltiples problemas independientes.

Especificación de dates distintas de "ahora"

Cada commit tiene dos dates: la date del autor y la date del committer. Puede sobrescribir cada uno proporcionando valores a través de las variables de entorno GIT_AUTHOR_DATE y GIT_COMMITTER_DATE para cualquier command que escriba una nueva confirmación. Consulte "Formatos de date" en git-commit (1) o a continuación:

 Git internal format = <unix timestamp> <time zone offset>, eg 1112926393 +0200 RFC 2822 = eg Thu, 07 Apr 2005 22:13:13 +0200 ISO 8601 = eg 2005-04-07T22:13:13 

El único command que escribe una nueva confirmación durante el uso normal es git commit . También tiene una opción – date que le permite especificar directamente la date del autor. Su uso anticipado incluye git filter-branch --env-filter también utiliza las variables de entorno mencionadas anteriormente (estas son parte del "env" después del cual se nombra la opción, vea "Opciones" en git-filter-branch (1) y el command "plomería" subyacente git-commit-tree (1) .

Insertar un file en un solo historial de ref

Si tu repository es muy simple (es decir, solo tienes una sola twig, no hay tags), entonces probablemente puedas usar git rebase para hacer el trabajo.

En los siguientes commands, use el nombre del object (SHA-1 hash) de la confirmación en lugar de "A". No olvide utilizar uno de los methods de "anulación de date" 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 include el nuevo file (en lugar de crear un nuevo compromiso donde se haya agregado), utilice git commit --amend lugar de git commit . El resultado sería así:

 ---A'---B'---C'---o---o---o master 

Lo anterior funciona siempre que puedas nombrar la confirmación que debería ser el padre de tu nueva confirmación. Si realmente desea que su nuevo file 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 forms de hacer lo mismo que funcionan en versiones anteriores de Git.

Insertar un file en un historial de refracción múltiple

Si su repository es más complejo (es decir, tiene más de un ref (twigs, tags, etc.)), entonces probablemente necesite usar git filter-branch . Antes de usar git filter-branch , debe hacer una copy de security de todo su repository. Un file tar simple de todo su tree de trabajo (incluido el directory .git) es suficiente. git filter-branch hace refs de respaldo, pero a menudo es más fácil recuperarse de un filtrado no del todo correcto simplemente borrando su directory .git y restaurándolo desde su respaldo.

Nota: Los ejemplos a continuación usan el command de nivel más bajo git update-index --add lugar de git add . Podría usar git add , pero primero tendría que copyr el file desde una location externa a la ruta esperada ( --index-filter ejecuta su command en un GIT_WORK_TREE temporal que está vacío).

Si desea que su nuevo file 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 dates de las confirmaciones existentes con --env-filter 'GIT_AUTHOR_DATE=…' . Si lo usaste, lo harías condicional para que reescriba la date de cada confirmación.

Si desea que su nuevo file aparezca solo en las confirmaciones después de una 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 file se agregue a través de una nueva confirmación que se insertá en el medio de su historial, deberá generar la nueva confirmación antes de usar git filter-branch y agregar --parent-filter a git filter -branco :

 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 -es/$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 podría hacer arreglos para que el file se agregue primero en una nueva confirmación raíz: cree su nueva confirmación raíz a través del método "huérfano" de la sección git rebase ( new_commit en new_commit ), use el --index-filter incondicional, y a --parent-filter como "sed -e \"s/^$/-p $new_commit/\"" .

Puede crear la confirmación de la forma habitual, pero cuando la GIT_AUTHOR_DATE , configure las variables de entorno GIT_AUTHOR_DATE y GIT_COMMITTER_DATE en los GIT_COMMITTER_DATE apropiados.

Por supuesto, esto hará que la confirmación se realice en la punta de su twig (es decir, delante del compromiso HEAD actual). Si desea llevarlo más lejos en el repository, tiene que ser un poco sofisticado. Digamos que tienes esta historia:

 o--o--o--o--o 

Y desea que su nueva confirmación (marcada como "X") aparezca en segundo lugar :

 o--X--o--o--o--o 

La forma más fácil sería realizar una bifurcación desde la primera confirmación, agregar la nueva confirmación y luego volver a establecer la base de todas las demás confirmaciones sobre la nueva. Al igual que:

 $ git checkout -b new_commit $desinetworking_parent_of_new_commit $ git add new_file $ GIT_AUTHOR_DATE='your date' GIT_COMMITTER_DATE='your date' git commit -m 'new (old) files' $ git checkout master $ git rebase new_commit $ git branch -d new_commit 

En mi caso, con el time había guardado un montón de versiones de myfile como myfile_bak, myfile_old, myfile_2010, backups / myfile, etc. Quería poner la historia de myfile en git usando sus dates de modificación. Así que cambie el nombre de la más antigua a mifile, git add myfile , luego git commit --date=(modification date from ls -l) myfile , renombrar next oldest a myfile, otro git commit con –date, repeat …

Para automatizar esto de alguna manera, puede usar shell-foo para get la hora de modificación del file. Empecé con ls -l y cut , pero stat (1) es más directo

 git commit --date = "` stat -c% y myfile `" mifile

Sé que esta pregunta es bastante antigua, pero eso fue lo que realmente funcionó para mí:

 git commit --date="10 day ago" -m "Your commit message" 

En mi caso, al usar la opción –date, mi process de git se colgó. Puede ser que hice algo terrible. Y como resultado, apareció un file index.lock. Así que eliminé manualmente los files .lock de la carpeta .git y los ejecuté, para que todos los files modificados se confirmaran en las dates aprobadas y funcionó esta vez. Gracias por todas las respuestas aquí.

 git commit --date="`date --date='2 day ago'`" -am "update" 

Lo siguiente es lo que uso para confirmar cambios en foo a N=1 días en el pasado:

 git add foo git commit -m "Update foo" git commit --amend --date="$(date -v-1d)" 

Si desea comprometerse con una date aún más antigua, digamos 3 días atrás, simplemente cambie el argumento de date -v-3d : date -v-3d .

Eso es realmente útil cuando olvidas cometer algo ayer, por ejemplo.

ACTUALIZACIÓN : --date también acepta expresiones como --date "3 days ago" o incluso – --date "yesterday" . Entonces podemos networkingucirlo a un command de línea:

 git add foo ; git commit --date "yesterday" -m "Update"