git - 重写 git 存储库以更改提交的日期范围

标签 git

比如说,我有一个相当大的 Git 存储库,有 1000 多次提交。提交日期从 2013 年 8 月到现在(2014 年 8 月)。所有提交均由一位用户(我)完成。

现在,出于某种原因,我需要使存储库中的所有提交看起来都发生在 2014 年 3 月至今。

这可以通过更改现有存储库或创建新存储库并重新提交所有更改来实现。

如果是少数提交,我会手动检查每个修订版,并使用 --date 将状态提交到新的存储库。如 Git documentation 中所述切换.

但是,对于提交的数量,这是不可能的。

最佳答案

就是这种东西 git filter-branch 做。

git filter-branch您列出应该使用的提交和分支名称。正如文档所说(有点神秘):

The command will only rewrite the positive refs mentioned in the command line ...



就您而言,这可能意味着您想要 --all覆盖所有分支,巧合地(或并非巧合,真的)也告诉过滤器分支脚本查看存储库中可以找到的所有内容(即,所有提交,以及所有标签/注释标签) .这是因为 --all参数被赋予 git rev-list ,它列出了所有提交(和带注释的标签)。

filter-branch 脚本通过迭代每个命名的修订来工作。对于那些提交,它应用所有指定的(非标签)过滤器。最适合在这里使用的是 --env-filter .

(对于那些标签,如果有的话,它应用给定的标签名称过滤器。如果没有给出,它对标签不做任何事情。因此,你可能需要 --tag-name-filter cat ,如示例中所述。请参阅文档详情。)

一旦脚本应用了您的过滤器,它就会使用您所做的任何更改进行新的提交1。您的过滤器通常 2 馈送到 shell 的 eval ,它允许您设置环境变量。在这种情况下,关键环境变量是控制提交时间戳的两个:GIT_AUTHOR_DATEGIT_COMMITTER_DATE .

您的环境过滤器应该首先从提交中提取现有日期,其 ID 在 $GIT_COMMIT 中提供给您。 .如果这些日期在要修改的范围之外,您可以取消设置相应的环境变量,或将其设置为原始提交的日期,以便在新提交中也使用现有的日期和时间戳。但是,如果它们在您的“更改范围”内,则您需要将变量设置(再次 export )为所需的新值。

你会想要/需要改进它(可能很多,而且它未经测试),但环境过滤器可能看起来像这样:
--env-filter 'at=$(git log --no-walk --pretty=format:%ai $GIT_COMMIT) \
    ct=$(git log --no-walk --pretty=format:%ci $GIT_COMMIT); \
    export GIT_AUTHOR_DATE=$($HOME/scripts/massage-time $at) \
    GIT_COMMITTER_DATE=$($HOME/scripts/massage-time $ct)'

哪里$HOME/scripts/massage-time是您编写的脚本以获取时间戳(此处,通过 %ai 和 %ci 格式化;选择您自己喜欢的格式)并将其按摩到您的转换范围内。事实上,您的 massage脚本可以使用环境变量 $GIT_COMMIT直接,并简单地产生 export GIT_AUTHOR_DATE=... 作为输出命令(因为再次将您提供的过滤器的输出馈送到 eval )。 (不过,出于测试目的,如果将 commit-ID 作为参数,它可能效果最好。然后,在将其用作环境过滤器之前,您可以手动确保它对各种示例提交执行正确的操作。)

曾经filter-branch脚本完成了所有这些新提交,然后它会重写引用名称以将每个引用名称指向与原始提交相对应的新副本提交。例如,如果 refs/heads/master用于指向提交 badfacebadface 的副本是 deadb17 , 脚本使 refs/heads/master现在指向 deadb17 .这就是几乎所有 git 命令的工作方式:它们只是向存储库添加新内容,同时保留旧内容,然后创建或移动引用标签以指向新内容。如果旧的东西最终被取消引用,git gc可以在那个时候删除它。

1此时它实际上运行了您的提交过滤器,但提供了一个进行新提交的默认过滤器。如果您提供自己的提交过滤器,则提交成为您的责任;这允许您省略一些提交。

2eval规则适用于除提交过滤器之外的所有内容。您可以自己检查过滤器分支脚本以查看:它在 git-core 中目录,通常在 /usr/local/libexec/git-core/usr/libexec/git-core取决于 git 安装。

关于git - 重写 git 存储库以更改提交的日期范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25198207/

相关文章:

git - 我不能再 git rebase --interactive

xcode - git 试图提交数千个文件

Git:从现有存储库创建 Git 子模块并将父更改反射(reflect)到子存储库

git - 取消忽略git中被忽略目录中的文件

git - 有没有办法使用git查看文件的所有版本?

git - 不能再推送到 github origin master

git - 将 .gitignore 转换为ignore.conf

git - 在提交 n 时将文件添加到 git。我如何添加它而不是提交 n-m?

git - Github 使用的 diff 算法是什么?

git - Jenkins :更新子模块时,使用子模块的最新提交重建主存储库