Git在不改变提交时间戳的情况下进行改基

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

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

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

例如,假设我有以下树:

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

现在,如果我在master上重置oldbranch,提交日期将从1984年2月改为2010年6月。是否有可能改变这种行为,从而不改变提交时间戳?最后,我将得到:

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

这有意义吗?git中是否允许有历史记录,即旧的提交有最近的提交作为父?

61391 次浏览

2014年6月更新:大卫·弗雷泽提到了在评论中,这个解决方案也在“__abc3”中详细描述,使用选项--committer-date-is-author-date(最初于2009年1月在提交3 f01ad6中引入

注意,--committer-date-is-author-date选项似乎留下了作者时间戳,并将提交者时间戳设置为与原始作者时间戳相同,这是奥利维耶·维尔迪尔所需要的。

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

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

看到git am:

--committer-date-is-author-date

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

注意:在Git 2.29 (Q4 2020)中,Git rebase --committer-date-is-author-date--ignore-date也可以用于:

  • interactive rebase (rebase -i/rebase --interactive)
  • 用于根提交(git rebase --root)

看到“改变时间戳,同时重基git分支"。


(原答案,2012年6月)

你可以尝试,对于< em >非交互式< / em > rebase
(参见上文:在Git 2.29, 2020年Q4中,这也将与交互式rebase一起工作)

git rebase --ignore-date

(从this 所以回答)

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

 --ignore-date

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

对于git rebase,此选项“与——interactive选项不兼容”;

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


正如奥利维尔在他的问题中提到的,作者日期永远不会因变基而改变 从Pro Git手册:

  • 作者是最初写这部作品的人,
  • 而提交者是最后申请工作的人。

所以,如果你向一个项目发送了一个补丁,其中一个核心成员应用了这个补丁,你们两个都可以得到积分。

更清楚的是,在这种情况下,正如奥利维尔所说:

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


正如DylanYoung添加到的评论中,使用"在git重基期间,如何通过哈希识别冲突的提交?":

使用SEQUENCE_EDITOR变量和rebase interactive,你只需循环当前的todo列表,并添加一个命令,在todo中的每次提交之前,将GIT_COMMITER_DATE设置为原始提交的日期。

它不那么繁琐,因为您有原始提交的列表(您不必侵入git内部来找到它),但要做更多的工作,因为您必须一次处理整个列表。- - - - - -

一旦你能够识别最初的提交,你可以这样做:

git rebase -x 'GIT_COMMITTER_DATE="git show -s --format=%ci ``get_current_commit``" git commit --amend --no-edit

冯·C的一个关键问题帮助我理解了发生了什么:当你重基时,提交者的时间戳改变了,而作者的时间戳没有改变,这突然之间就有意义了。所以我的问题其实不够精确。

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

如果你已经搞砸了提交日期(可能是用了一个rebase),想要将它们重置为对应的作者日期,你可以运行:

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

默认情况下,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'

post-rewrite

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

. / / post-rewrite hook

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上测试。

这是我在我的案例中使用的命令:

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)"'

真正的的解决方案似乎是从Reddit。稍微放大一下,是这样的:

git -c rebase.instructionFormat='%s%nexec GIT_COMMITTER_DATE="%cD" git commit --amend --no-edit --allow-empty --allow-empty-message' rebase -i