简体   繁体   English

Git rebase 保持最新的提交日期

[英]Git rebase Keep latest commit date

I've been working on a feature branch which is ready to be push to remote.我一直在研究一个准备推送到远程的功能分支。 It has 5 or so commits some are very quick commits which do not deserve it's own commit.它有 5 个左右的提交,有些是非常快速的提交,不值得它自己提交。 I would like the feature to be one commit in total before I push it to remote for review.在我将它推送到远程进行审查之前,我希望该功能总共是一次提交。

I would normally do:我通常会这样做:

git rebase -i HEAD~5 git rebase -i HEAD~5

Then fold the commits into the previous commit.然后将提交折叠到上一个提交中。 This will give me one commit as I would like however, the commit date is the date of the first commit.这将给我一个提交,但是,提交日期是第一次提交的日期。 I would like one commit with the commit date as the last commit.我想要一个以提交日期作为最后一次提交的提交。

How do I fold the commits into the last commit instead of the first commit?如何将提交折叠到最后一次提交而不是第一次提交?

You can set any arbitrary date you like on any new commit.您可以在任何新提交上设置您喜欢的任意日期。

When you combine commits together with rebase -i , you're not actually changing the old commits, you are instead making one new commit, after which you simply stop using the old commits:当您将提交与rebase -i组合在一起时,您实际上没有更改旧提交,而是进行一次新提交,之后您只需停止使用旧提交:

(before rebase -i)

A--B--C--D--E--F--G--H--I   <-- master

(after rebase -i)

           E--F--G--H--I   [abandoned]
          /
A--B--C--D--J   <-- master

where J is the new "all things combined" commit.其中J是新的“所有事物组合”提交。

The bad news is that git rebase -i is designed to retain the author date-stamp on the commit into which other commits are squash ed or fixup -ed.坏消息是git rebase -i旨在保留其他提交被squashfixup的提交上的作者日期戳。 So it already uses the "set arbitrary date" feature to force J to have E 's date.因此它已经使用“设置任意日期”功能来强制J具有E的日期。 The interactive rebase command has no flag to change this.交互式 rebase 命令没有改变这一点的标志。 1 1

But there's a simple workaround: having made new commit J as the new-and-improved variant of EFGHI , you can simply use the same general idea to abandon J in favor of even-newer, more-improved K , which is just like J except that it has the date you desire.但是有一个简单的解决方法:将新提交J作为EFGHI的新改进变体,您可以简单地使用相同的一般想法来放弃J以支持更新,更改进的K ,就像J除了它有你想要的日期。

To do this, after rebasing, run git commit --amend --date=... (supply whatever date you like for the ... part).为此,在变基后,运行git commit --amend --date=... (为...部分提供您喜欢的任何日期)。 You can change the author as well;您也可以更改作者; see the git commit documentation .请参阅git commit文档 This will make new commit K to replace J , just as J replaced EFGHI , leaving you with:这将使新的提交K替换J ,就像J替换EFGHI ,给你留下:

           E--F--G--H--I   [abandoned]
          /
A--B--C--D--K   <-- master
          \
           J   [abandoned]

The commits that you have abandoned will, if nothing else lets you find them, eventually (somewhere after 30 days or so) lose their last methods of finding them—their IDs are retained in reflogs for some expiration period in case you want them back—and once they're truly unreferenced, the garbage collection pass (as run by git gc --auto which in turn is run for you by various other Git commands) will remove them for real.你放弃的提交,如果没有别的办法让你找到它们,最终(大约在 30 天后的某个时间)失去它们的最后一种找到它们的方法——它们的 ID 会保留在reflog中一段时间​​,以防你想要它们回来——一旦它们真正未被引用,垃圾收集传递(由git gc --auto运行,而由其他各种 Git 命令为您运行)将真正删除它们。


1 The non-interactive, git am based git rebase has a flag, but doesn't have the squash feature. 1非交互式、基于git amgit rebase有一个标志,但没有壁球功能。

The answer by @torek is extensive, detailed, and excellent. @torek 的回答广泛、详细且出色。 Let me add 3 practical command-line options so you can easily copy and paste, along with a bit of background.让我添加 3 个实用的命令行选项,以便您轻松复制和粘贴,以及一些背景知识。

The Git repository keeps two pieces of time information: author-time and commit-time. Git 存储库保留两条时间信息:作者时间和提交时间。 What you want to modify is the author-time of the last commit (or HEAD in the current branch), which you have just made, as opposed to the commit-time (I believe it is difficult to modify the latter and anyway you don't need it, either, in most cases).您要修改的是您刚刚提交的最后一次提交(或当前分支中的 HEAD)的作者时间,而不是提交时间(我相信很难修改后者,无论如何您都不在大多数情况下也不需要它)。

Using the example diagram of the git history by @torek immediately after git rebase -i HEAD~5 ,git rebase -i HEAD~5之后立即使用 @torek 的 git 历史示例图,

           E--F--G--H--I   [abandoned]
          /
A--B--C--D--J   <-- master

commit J is the current head, which has the newest commit time (newer than any other commits) and author time the same as that of commit E .提交J是当前头,它具有最新的提交时间(比任何其他提交都新)和作者时间与提交E相同。

Now, what you do is to create another commit K with an author time of your choice , which will become the new HEAD (see the answer by @torek for detail).现在,您要做的是使用您选择的作者时间创建另一个提交K ,它将成为新的 HEAD (有关详细信息,请参阅@torek 的回答)。 You can make it by running git commit --amend --date=XXX , but what is your choice of the author-time " XXX "?您可以通过运行git commit --amend --date=XXX ,但是您对作者时间“ XXX ”的选择是什么?

I can think of 3 most common options:我可以想到 3 个最常见的选项:

  1. If you don't mind a slight difference in time and are fine with just the current time,如果您不介意时间略有不同并且只接受当前时间,

     git commit --amend --no-edit --date=now
  2. If your choice is the last amended time (commit-time), do either of (they are just aliases)如果您选择的是最后修改时间(提交时间),请执行以下任一操作(它们只是别名)

     git rebase --ignore-date HEAD git rebase --committer-date-is-author-date HEAD
  3. If your choice is the commit-time (and author-time) of your last git commit , ie, commit I with commit-ID of SHA_I如果您选择的是最后一次git 提交的提交时间(和作者时间),即提交 ID 为SHA_I的提交I

     git commit --amend --no-edit --date=`git log -n 1 --format=%ct SHA_I`

Note that SHA_I in (7-char) string should have been printed out when you did git commit , which created commit I .请注意,当您执行SHA_I git commit时,应该打印出 (7-char) string 中的 SHA_I ,这创建了 commit I Or, git reflog will display the list.或者, git reflog将显示列表。

If you want to confirm the commit-date before amending, do git log -n 1 --format=%ci [SHA_I] (or %cd );如果要在修改前确认提交日期,请执行git log -n 1 --format=%ci [SHA_I] (或%cd ); and for the author-date, replace %ci with %ai etc.对于作者日期,将%ci替换为%ai等。

Here's yet another (kind of cool) way to accomplish the same thing:这是完成同一件事的另一种(有点酷)方法:

Cherry-pick your top commit to make an empty copy of it: Cherry-pick 您的最高提交以制作它的空副本:

git cherry-pick --keep-redundant-commits HEAD

Now interactive rebase as you would have before, either specifying the exact commit ID or adding 1 to the previous parent count:现在像以前一样交互式变基,指定确切的提交 ID 或将 1 添加到以前的父计数:

git rebase -i HEAD~6

Now move the last commit to the top of the list (for your convenience Git will notate that the commit is empty).现在将最后一次提交移至列表顶部(为方便起见,Git 将注明该提交为空)。 Pick the top commit, and change all commits below it to "f" for "fixup".选择顶部提交,并将其下方的所有提交更改为“f”以表示“fixup”。 Save and exit, and you're done.保存退出,大功告成。

Effectively you're doing the identical squash, but using the author, date, and message of the last commit instead of the first one.实际上,您正在执行相同的挤压,但使用的是最后一次提交的作者、日期和消息,而不是第一次提交的信息。

git rebase -i SHA git rebase -i SHA

After you rebase there are 3 options available select any one of them.变基后,有 3 个选项可用,请选择其中任何一个。 Option 1 works for recent commit only.选项 1 仅适用于最近提交。 Option 2 and 3 does not work with interactive rebase hence a separate rebase call is needed else would have clubbed in above rebase call only.选项 2 和 3 不适用于交互式 rebase,因此需要单独的 rebase 调用,否则只会在上面的 rebase 调用中使用。

  1. git commit --amend --no-edit --date=now git commit --amend --no-edit --date=now
  2. git rebase --ignore-date SHA git rebase --ignore-date SHA
  3. git rebase --committer-date--is-author-date SHA git rebase --committer-date--is-author-date SHA

In your scenario you can find the latest commit date before rebase and provide that after rebase via option 1. If you are not aware of date format to use try echo $(date)在您的场景中,您可以在 rebase 之前找到最新的提交日期,并在 rebase 之后通过选项 1 提供该日期。如果您不知道要使用的日期格式,请尝试使用echo $(date)

(from this SO answers answer1 , answer2 ) (从这个 SO 回答answer1answer2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM