git rebase而不更改提交时间戳

Oli*_*ier 144 git timestamp git-rebase

git rebase在保留提交时间戳的同时执行是否有意义?

我相信结果是新分支不一定按时间顺序排列日期.这在理论上是否可行?(例如使用管道命令;只是好奇这里)

如果理论上可行,那么在实践中是否可以使用rebase,而不是更改时间戳?

例如,假设我有以下树:

master <jun 2010>
  |
  :
  :
  :     oldbranch <feb 1984>
  :     /
oldcommit <jan 1984>
Run Code Online (Sandbox Code Playgroud)

现在,如果我重新oldbranch启动master,则提交日期将从1984年2月更改为2010年6月.是否可以更改该行为以便不更改提交时间戳?最后我会得到:

      oldbranch <feb 1984>
      /
 master <jun 2010>
    |
    :
Run Code Online (Sandbox Code Playgroud)

那会有意义吗?甚至允许在git中有一个旧提交最近提交作为父项的历史记录?

Von*_*onC 138

2014年6月更新:David Fraser 在评论中提到一个解决方案,该解决方案也在" 更改时间戳同时重新定位git分支 "中详细说明,使用该选项--committer-date-is-author-date(最初于2009年1月在提交3f01ad6中介绍)

请注意,该--committer-date-is-author-date选项似乎保留了作者的时间戳,并将提交者时间戳设置为与原始作者时间戳相同,这是OP Olivier Verdier所需要的.

我找到了最后一次提交正确的日期,并做了:

git rebase --committer-date-is-author-date SHA
Run Code Online (Sandbox Code Playgroud)

git am:

--committer-date-is-author-date
Run Code Online (Sandbox Code Playgroud)

默认情况下,该命令将电子邮件中的日期记录为提交作者日期,并使用提交创建时间作为提交者日期.
这允许用户使用与作者日期相同的值来说谎提交者日期.


(原始答案,2012年6月)

对于非交互式 rebase ,您可以尝试

git rebase --ignore-date
Run Code Online (Sandbox Code Playgroud)

(从这个SO回答)

这被传递给git am,提到:

 --ignore-date
Run Code Online (Sandbox Code Playgroud)

默认情况下,该命令将电子邮件中的日期记录为提交作者日期,并使用提交创建时间作为提交者日期.
这允许用户使用与提交者日期相同的值来欺骗作者日期.

对于git rebase,此选项是"与--interactive选项不兼容".

既然您可以随意更改旧提交日期(带git filter-branch)的时间戳,我想您可以使用您想要/需要的任何提交日期顺序组织您的Git历史记录,甚至可以将其设置为将来!.


正如奥利维尔在他的问题中提到的那样,作者的约会从未被改变过;
来自Pro Git Book:

  • 作者是最初写作的人,
  • 而提交者是最后一次申请工作的人.

因此,如果您向项目发送补丁并且其中一个核心成员应用了补丁,那么您都会得到信任.

更为清楚的是,在这种情况下,正如奥利维尔评论:

--ignore-date我想要达到的目标相反!
也就是说,它会删除作者的时间戳并将其替换为提交时间戳!
所以我的问题的正确答案是:
不要做任何事情,因为git rebase 默认情况下实际上并没有改变作者的时间戳.


  • 更确切地说:`--ignore-date`与我想要实现的*相反*!也就是说,它会删除作者的时间戳并将其替换为提交时间戳!所以对我的问题的正确答案是:不要做任何事情,因为`git rebase`确实没有默认改变作者的时间戳. (4认同)
  • 请注意,`--committer-date-is-author-date`选项似乎留下作者时间戳,并将提交者时间戳设置为与原作者时间戳相同,这是Olivier想要的... (4认同)
  • 关于提交的任意日期很有趣。但是,`git rebase --ignore-date` 不起作用。它更改重新提交的日期。 (2认同)
  • 感谢 VonC,作者和提交者时间戳之间的差异,这就是让一切突然变得清晰的原因。我在帖子中写了我的问题的答案,但请随时调整您的答案以反映这一点。 (2认同)

And*_*ndy 114

如果您已经搞砸了提交日期(可能带有rebase)并想要将它们重置为相应的作者日期,则可以运行:

git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; export GIT_COMMITTER_DATE'

  • 如果你已经搞砸但又不想遍历整个历史,我想添加另一种方法:`git rebase --committer-date-is-author-date <base_branch>`这样,git将仅为在<base_branch>上应用的提交重置提交日期(这可能与您在搞砸时使用的分支名称相同). (19认同)
  • 我刚刚尝试过这个,但没有效果。我得到以下输出:“警告:参考‘refs/heads/master’未更改”。我在 Linux(64 位)上使用 git 版本 1.7.9.5 (2认同)
  • @ speakman的回答在2016年10月没有用,但安迪的确没有! (2认同)
  • 这在Windows上不起作用.我能够使用Windows Bash使其工作. (2认同)

Oli*_*ier 30

关于Von C的一个关键问题帮助我理解了发生了什么:当你的rebase,提交者的时间戳发生变化,而不是作者的时间戳时,这突然变得有意义.所以我的问题实际上不够准确.

答案是,rebase实际上并没有改变作者的时间戳(你不需要为此做任何事情),这完全适合我.

  • +1 - 我有一个git别名(https://coderwall.com/p/euwpig/a-better-git-log)显然使用了提交者的时间戳,这让我很困惑.Gitk和git log都显示了作者的时间戳. (3认同)

wey*_*amz 14

默认情况下,git rebase会将提交者的时间戳设置为创建新提交的时间,但保持作者的时间戳保持不变.大多数时候,这是期望的行为,但在某些情况下,我们不希望更改提交者的时间戳.我们怎样才能做到这一点?好吧,这是我通常做的伎俩.

首先,确保您要进行rebase的每个提交都有一个唯一的提交消息和作者时间戳(这是技巧需要改进的地方,但目前它适合我的需求).

在rebase之前,记录提交者的时间戳,作者的时间戳以及将被重新绑定到文件的所有提交的提交消息.

#NOTE: BASE is the commit where your rebase begins
git log --pretty='%ct %at %s' BASE..HEAD > hashlog
Run Code Online (Sandbox Code Playgroud)

然后,让实际的rebase发生.

最后,如果使用提交消息相同,我们将当前提交者的时间戳替换为文件中记录的时间戳git filter-branch.

 git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%at %s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_COMMITTER_DATE=$__date || cat'
Run Code Online (Sandbox Code Playgroud)

如果出现问题,只需结帐git reflog或所有refs/original/参考.

更确切地说,你可以对作者的时间戳做类似的事情.

例如,如果作者的某些提交的时间戳不正常,并且没有重新排列这些提交,我们只想让作者的时间戳按顺序显示,那么以下命令将有所帮助.

git log --pretty='%at %s' COMMIT1..COMMIT2 > hashlog
join -1 1 -2 1 <(cat hashlog | cut -f 1 | sort -nr | awk '{ print NR" "$1 }') <(cat hashlog | awk '{ print NR" "$0 }') | cut -d" " -f2,4- > hashlog_
mv hashlog_ hashlog
git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_AUTHOR_DATE=$__date || cat'
Run Code Online (Sandbox Code Playgroud)


Meh*_*dad 6

真正解决方案似乎来自Reddit。稍微扩充一下,如下:

git -c rebase.instructionFormat='%s%nexec GIT_COMMITTER_DATE="%cD" git commit --amend --no-edit --allow-empty --allow-empty-message' rebase -i
Run Code Online (Sandbox Code Playgroud)