我如何在过去做一个Git的提交?

我将所有的东西都转换成Git供我个人使用,而且我发现版本库中已经有一些旧版本的文件了。 如何根据文件的“修改date”以正确的顺序将其提交到历史logging中,以便我有精确的文件历史logging?

我被告知这样的事情会工作:

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

你给的build议是有缺陷的。 在--env-filter无条件设置GIT_AUTHOR_DATE会重写每个提交的date。 另外,在--index-filter里面使用git commit是不正常的。

你正在处理多个独立的问题。

指定“now”以外的date

每个提交都有两个date:作者date和提交者date。 您可以通过环境variablesGIT_AUTHOR_DATE和GIT_COMMITTER_DATE为任何写入新提交的命令提供值来覆盖每个值。 请参阅git-commit(1)或以下的“date格式” :

 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 

在正常使用中写入新提交的唯一命令是git commit 。 它还有一个--date选项,可以让你直接指定作者的date。 你的预期使用包括git filter-branch --env-filter也使用上面提到的环境variables(这些是“env”的一部分,在这之后该选项被命名;参见git-filter-branch(1)和底层的“pipe道”命令git-commit-tree(1) 。

插入一个文件到一个单一的历史

如果你的仓库非常简单(即你只有一个分支,没有标签),那么你可以使用git rebase来完成这个工作。

在以下命令中,使用提交的对象名称(SHA-1散列)而不是“A”。 运行git commit时不要忘记使用“date重写”方法之一。

 ---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 

如果你想更新A来包含新文件(而不是创build一个新的提交,它添加),然后使用git commit --amend而不是git commit 。 结果如下所示:

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

只要您可以命名应该是新提交的父项的提交,上面的工作就可以了。 如果你真的想通过一个新的根提交(没有父母)添加你的新文件,那么你需要一些不同的东西:

 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是相对较新的(Git 1.7.2),但还有其他的方法可以在Git的旧版本上工作。

插入一个文件到多个参考历史

如果你的版本库比较复杂(即它有多个ref(branches,tags等)),那么你可能需要使用git filter-branch在使用git filter-branch之前,你应该为整个存储库做一个备份。 整个工作树(包括.git目录)的简单tar档案就足够了。 git filter-branch确实做了备份引用,但是通过删除.git目录并从备份中恢复,通常会更容易从不太正确的过滤中恢复。

注意:下面的例子使用低级命令git update-index --add而不是git add 。 您可以使用git add ,但是您首先需要将文件从某个外部位置复制到期望的path( --index-filter在临时的GIT_WORK_TREE中运行其命令)。

如果你想把你的新文件添加到每个现有的提交中,那么你可以这样做:

 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 

我真的没有看到有任何理由用--env-filter 'GIT_AUTHOR_DATE=…'来改变现有提交的date。 如果你确实使用了它,那么你可以使它成为有条件的,以便重写每个提交的date。

如果你希望你的新文件只出现在提交之后的提交(“A”),那么你可以这样做:

 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 

如果你想通过一个新的提交文件添加到你的历史中间,那么你需要在使用git filter-branch之前生成新的提交,并添加--parent-filtergit filter分支

 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 

您也可以安排将文件首次添加到新的根提交中:通过git rebase部分的“orphan”方法创build新的根提交(捕获它在new_commit ),使用无条件的--index-filter ,以及像"sed -e \"s/^$/-p $new_commit/\""这样的--parent-filter

您可以照常创build提交,但在提交时,将环境variablesGIT_AUTHOR_DATEGIT_COMMITTER_DATE设置为适当的date时间。

当然,这会使你的分支尖端(即在当前的HEAD提交之前)进行提交。 如果你想把它推回去,你必须有一点花哨。 假设你有这样的历史:

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

而你希望你的新提交(标记为“X”)出现第二个

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

最简单的方法是从第一个提交分支,添加新的提交,然后重新绑定所有其他提交。 像这样:

 $ git checkout -b new_commit $desired_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 

在我的情况下,随着时间的推移,我保存了myfile_bak,myfile_old,myfile_2010,backups / myfile等一堆myfile的版本。我想把myfile的历史logging放在git中,使用它们的修改date。 所以重命名最旧的myfile, git add myfile ,然后git commit --date=(modification date from ls -l) myfile ,重命名下最旧的myfile,另一个git commit –date,重复…

为了自动化,可以使用shell-foo来获取文件的修改时间。 我从ls -l开始cut ,但stat(1)更直接

 git commit --date =“`stat -c%y myfile`” myfile

在我的情况下,在使用–date选项时,我的git进程崩溃了。 可能是我做了一件可怕的事情。 结果出现了一些index.lock文件。 所以我手动删除.git文件夹中的.lock文件,并执行所有修改后的文件,在传递date中进行提交,这一次它工作。 感谢所有的答案在这里。

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

我知道这个问题是相当古老的,但这是真正为我工作的:

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

以下是我用来在过去N=1天对foo进行更改的情况:

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

如果你想提交一个更旧的date,比如3天前,只需要改变date参数: date -v-3d

例如,当你忘记昨天提交某些东西时,这非常有用。

更新 : – --date也接受expression式 – --date "3 days ago" ,甚至 – --date "yesterday" 。 所以我们可以把它减less到一行命令:

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