189

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

我相信结果是新分支不一定按时间顺序有提交日期。这在理论上是可能的吗?(例如使用管道命令;这里只是好奇)

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

例如,假设我有以下树:

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

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

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

这有意义吗?在 git 中甚至允许有一个历史,其中一个旧的提交有一个更新的提交作为父级?

4

6 回答 6

190

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

git am

--committer-date-is-author-date

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

注意:使用 Git 2.29(2020 年第四季度), git rebase--committer-date-is-author-date--ignore-date也将与:

  • 交互式变基 ( rebase -i/ rebase --interactive)
  • 对于根提交 ( git rebase --root)

请参阅“在变基 g​​it 分支时更改时间戳”。


(原始答案,2012 年 6 月)

你可以试试看非交互式变基
(见上文:使用 Git 2.29,2020 年第四季度,这也将与交互式变基一起使用)

git rebase --ignore-date

(来自这个SO 答案

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

 --ignore-date

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

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

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


正如Olivier在他的问题中提到的那样,作者日期永远不会因变基而改变;
来自Pro Git 书

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

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

更清楚地说,在这种情况下,正如 Olivier 评论的那样:

--ignore-date与我试图实现的目标相反
也就是说,它会删除作者的时间戳并用提交时间戳替换它们!
所以我的问题的正确答案是:
不要做任何事情,因为git rebase 默认情况下实际上不会更改作者的时间戳。


正如DylanYoung评论中添加的那样,使用“如何在 git rebase 期间通过哈希识别冲突提交? ”:

使用SEQUENCE_EDITOR变量和 rebase 交互,您只需循环当前todo列表并添加一个命令,将 设置GIT_COMMITER_DATE为原始提交的日期,然后在todo.

它有点不那么繁琐,因为你有原始提交的列表开始(你不必侵入 git 内部来找到它),但需要更多的工作,因为你必须一次处理整个列表。——</p>

一旦您能够识别原始提交,您就可以执行以下操作:

git rebase -x 'GIT_COMMITTER_DATE="git show -s --format=%ci ``get_current_commit``" git commit --amend --no-edit
于 2010-06-04T18:04:43.617 回答
134

如果您已经搞砸了提交日期(可能使用了变基)并且想要将它们重置为相应的作者日期,您可以运行:

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

于 2012-06-24T16:41:13.360 回答
39

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

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

于 2011-06-14T08:31:35.520 回答
19

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

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

在 rebase 之前,记录提交者的时间戳、作者的时间戳和所有将要 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'
于 2013-10-22T16:06:41.630 回答
2

post-rewrite

这个钩子适用于所有git rebase,git pull --rebasegit commit --amend

.git/hooks/post-rewrite

set -eu
echo post-rewrite
if [ ! "${CIROSANTILLI_GITHOOKS_DISABLE:-0}" = 1 ]; then
  declare -a olds
  declare -A oldnew
  while IFS= read -r line; do
    echo "$line"
    old="$(echo "$line" | cut -d ' ' -f1)"
    new="$(echo "$line" | cut -d ' ' -f2)"
    oldnew[$old]="$new"
    olds+=("$old")
    news+=("$new")
  done
  git reset --hard "${news[0]}~"
  for old in "${olds[@]}"; do
    new="${oldnew[$old]}"
    git cherry-pick "$new" &>/dev/null
    olddate="$(git log --format='%cd' -n 1 "$old")"
    CIROSANTILLI_GITHOOKS_DISABLE=1 \
      GIT_COMMITTER_DATE="$olddate" \
      git commit \
      --amend \
      --no-edit \
      --no-verify \
      &>/dev/null \
    ;
  done
  echo
fi

GitHub 上游.

不要忘记:

chmod +x .git/hooks/post-rewrite

--committer-date-is-author-date在有人最终修补配置以默认设置它之前,这是默认情况下在所选存储库上执行的好方法。

它也适用于--committer-date-is-author-date似乎没有暴露在git pull --rebase.

也可以看看:

在 git 2.19、Ubuntu 18.04 上测试。

于 2018-11-28T09:53:14.883 回答
0

这是我用于我的案例的命令:

GIT_AUTHOR_EMAIL=xaionaro@dx.center git rebase --root -x "bash -c 'git commit --amend --reset-author -CHEAD --date=\"\$(git show --format=%ad -s)\"'"

这里git show --format=%ad -s提取当前日期并--date重新执行它。并为每个提交rebase --root -x执行命令。bash -c 'git commit --amend --reset-author -CHEAD --date="$(git show --format=%ad -s)"'

于 2021-12-02T13:04:28.927 回答