git rebase而不更改提交时间戳


157

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

我相信后果是新分支不一定按时间顺序排列提交日期。从理论上讲这完全可能吗?(例如,使用管道命令;只是在这里感到好奇)

如果理论上可行,那么实践中是否有可能重新设置基准而不更改时间戳?

例如,假设我有以下树:

master <jun 2010>
  |
  :
  :
  :     oldbranch <feb 1984>
  :     /
oldcommit <jan 1984>

现在,如果我oldbranch依据的话master,提交的日期将从1984年2月更改为2010年6月。是否可以更改该行为,以便不更改提交时间戳记?最后,我将获得:

      oldbranch <feb 1984>
      /
 master <jun 2010>
    |
    :

那完全有意义吗?甚至在git中允许有一个历史记录,其中旧提交作为父提交具有较新的提交?


3
有趣的是,问题的答案确实是“您无需执行任何操作-这就是默认设置的工作方式”。但是现在假设您希望在进行重新基准化时按正确的日期顺序对提交进行排序(如果考虑的话,这是很自然的情况)。现在,我无法找到实现该目标的方法,并把我的q发布为stackoverflow.com/questions/12270357/really-flatten-a-git-merge
pfalcon 2012年

1
David提到了另一个重置提交者日期的选项:git rebase --committer-date-is-author-date SHA。请参阅下面我编辑的答案
VonC 2014年

我只是在一个类似的问题上写了一个广泛的答案,其作者尝试了此处解释的答案,但无法以令人满意的方式应用它们。
axiac 2015年

Answers:


149

2014年6月更新:David Fraser 在评论中提到一个解决方案,该解决方案也在“使用git分支更改基础时更改时间戳 ”中使用了该选项--committer-date-is-author-date(最初于2009年1月在commit 3f01ad6中引入)

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

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

git rebase --committer-date-is-author-date SHA

git am

--committer-date-is-author-date

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


(原始答案,2012年6月)

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

git rebase --ignore-date

(从这个SO答案

这传递给git am,其中提到:

 --ignore-date

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

对于git rebase,此选项为“与--interactive选项不兼容”。

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


正如奥利维尔(Olivier)在他的问题中提到的那样,作者的日期永远不会因更改基准而改变。
Pro Git书中

  • 作者是最初创作该作品的人,
  • 而提交者是最后应用该作品的人。

因此,如果您向项目发送补丁程序,并且其中一个核心成员应用了补丁程序,那么你们两个都将获得荣誉。

在这种情况下,要更加清楚,正如奥利维尔(Olivier)所说:

--ignore-date与我要实现的目标相反
即,它将删除作者的时间戳,并用提交时间戳替换它们!
因此,对我的问题的正确答案是:
不要执行任何操作,因为git rebase 默认情况下实际上不会更改作者的时间戳。



1
关于提交的任意日期很有趣。但是,git rebase --ignore-date不起作用。它更改了重新提交的日期。
Olivier Verdier

@Olivier:奇怪:您是否进行了交互式的变基?在作者日期和提交者日期之间,我们确定要监视“正确的”日期吗?
VonC 2010年

1
感谢VonC,作者时间戳和提交者时间戳之间的差异,这使得所有事情都一目了然。我在帖子中写了我的问题的答案,但随时可以调整您的答案以反映这一点。
Olivier Verdier

4
更精确地说:在--ignore-date做了相反的我试图实现!即,它将删除作者的时间戳,并用提交时间戳替换它们!因此,对我的问题的正确答案是:什么都不做,因为git rebase默认情况下实际上不会更改作者的时间戳。
Olivier Verdier 2010年

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

118

如果您已经弄砸了提交日期(可能需要重新设置日期),并且想将它们重置为相应的作者日期,则可以运行:

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


1
我只是试过了,但是没有效果。我得到以下输出:WARNING: Ref 'refs/heads/master' is unchanged。我在Linux(64位)上使用git版本1.7.9.5
Markus

20
如果您已经搞砸了,但又不想遍历整个历史记录git rebase --committer-date-is-author-date <base_branch> ,我想添加另一种方法: 这样,git将仅针对在<base_branch>上应用的提交重置提交日期(可能是与您搞砸时使用的分支名称相同)。
发言人2014年

接受的答案在2016年不起作用,但是@speakman的答案却起作用了!
西奥多·R·史密斯

2
@speakman的答案在2016年10月无效,但Andy的有效!
Amedee Van Gasse

2
在Windows上不起作用。我能够使用Windows Bash使其正常工作。
vaindil'2

33

Von C的一个关键问题帮助我理解了正在发生的事情:重新设置基准时,提交者的时间戳发生了变化,而作者的时间戳却没有发生变化,而这一切都突然变得有意义了。所以我的问题实际上不够精确。

答案是,重新设置实际上并不会改变作者的时间戳(您不需要为此做任何事情),这非常适合我。


3
+ 1-我有一个git别名(coderwall.com/p/euwpig/a-better-git-log),显然使用了提交者的时间戳,这使我感到困惑。Gitk和git log都显示作者的时间戳。
1615903年

15

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

首先,确保您将要重新建立基础的每个提交都具有唯一的提交消息和作者时间戳(这是技巧需要改进的地方,尽管目前适合我的需求)。

在重新设置基准之前,请记录提交者的时间戳,作者的时间戳以及所有将基于文件的提交的提交消息。

#NOTE: BASE is the commit where your rebase begins
git log --pretty='%ct %at %s' BASE..HEAD > hashlog

然后,进行实际的变基。

最后,如果使用提交消息相同,则用文件中记录的时间戳替换当前提交者的时间戳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'

如果出了什么问题,只需结帐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'

这是一个很棒的把戏!它使我只能使用其他答案重写75次提交,而不是1100次以上。
乌登

这是太棒了!有没有办法修改脚本以保留原始提交者呢?
David DeMar '18年

@DavidDeMar应该是一样的,只是更改git log --pretty以记录原始电子邮件,并相应地修改脚本。
weynhamz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.