说,我有一个相当大的Git存储库,有1000多个提交。提交日期从2013年8月到现在(2014年8月)。所有提交都由一个用户(我)完成。
现在,出于某种原因,我需要让存储库中的所有提交似乎都发生在2014年3月到现在。
这可以通过更改现有存储库,或通过创建新存储库并重新提交所有更改来实现。
如果是少数几次提交,我会手动检查每个修订版本并使用--date
开关将状态提交到新的存储库,如Git documentation中所述。
但是,根据提交次数,这是不可能的。
答案 0 :(得分:2)
这就是git filter-branch
所做的事情。
使用git filter-branch
列出应该使用的提交和分支名称。正如文档所说(有些隐晦):
该命令只会重写命令行中提到的正引用...
在您的情况下,这可能意味着您希望--all
覆盖所有分支,巧合(或不巧合,真的)也告诉过滤分支脚本查看要在其中找到的所有内容存储库(即所有提交,以及所有标记/注释标记)。这是因为--all
参数被赋予git rev-list
,其中列出了所有提交(和带注释的标签)。
filter-branch脚本通过遍历每个命名修订来工作。对于那些提交,它适用于所有指定(非标记)过滤器。这里最合适的一个是--env-filter
。
(对于那些标签,它应用给定的标签名称过滤器,如果有的话。如果没有给出,它对标签没有任何作用。因此,你可能需要--tag-name-filter cat
,如示例。有关详细信息,请参阅文档。)
一旦脚本应用了您的过滤器,它就会进行新的提交, 1 ,无论您做了什么更改。您的过滤器通常是 2 馈送到shell的eval
,它允许您设置环境变量。在这种情况下,关键环境变量是控制提交时间戳的两个变量:GIT_AUTHOR_DATE
和GIT_COMMITTER_DATE
。
您的环境过滤器应首先从提交中提取现有日期,其ID在$GIT_COMMIT
中提供给您。如果这些日期在之外要修改的范围,您可以取消设置相应的环境变量,或将其设置为原始提交的日期,以便现有的日期和时间戳记也将在新提交中使用。但是,如果 更改范围",则需要将变量设置(并再次export
)到所需的新值。
你需要/需要改进这个(可能很多,并且它是非常未经测试的),但是env过滤器可能看起来像这样:
--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=...
命令的输出(因为,同样,您提供的过滤器的输出将被输入{{ 1}})。 (但是,出于测试目的,如果将commit-ID作为参数,它可能效果最好。然后,在将其用作环境过滤器之前,您可以手动确保它使用各种样本提交做正确的事情。)
一旦eval
脚本完成了所有这些新提交,它就会进行引用名称重写,将每个引用名称指向与原始引用相对应的新副本。例如,如果filter-branch
用于指向提交refs/heads/master
而badface
的副本为badface
,则脚本会使deadb17
指向refs/heads/master
}。这几乎是所有git命令的工作方式:它们只是将新东西添加到存储库中,同时保留旧的东西,并创建或移动引用标签以指向新的东西。如果旧内容最终未被引用,deadb17
可以在此时将其删除。
1 此时它实际上运行了您的提交过滤器,但提供了一个进行新提交的默认过滤器。如果您提供自己的提交过滤器,则提交您的责任;这允许你省略一些提交。
2 git gc
规则适用于除提交过滤器之外的所有内容。您可以自己检查过滤器分支脚本以查看:它位于eval
目录中,通常位于git-core
或/usr/local/libexec/git-core
,具体取决于git安装。
答案 1 :(得分:-1)
BASH吧:) 请注意,以下内容是从内存中编写的,尚未经过测试,因此我将提供评论以帮助解释
# Run git logs to get all the commit ids you want
git log --before={2014-03-01} --after={2013-01-01} --author="your name" > filename
# Run grep, so you can isolate the commit ids
grep "commit" filename > commit_ids
# Run a bash loop on those ids and change date
for i in $(cat commit_ids); do echo $i; git commit --amend --date "`date`" $i; done;