如何按日期在Git中结帐?


314

我正在源代码中进行回归。我想告诉Git:“根据参数化的日期/时间检出源”。这可能吗?

我还以我当前的观点上演了一些不想失去的变化。理想情况下,我想在当前来源和我之前感兴趣的某个版本之间来回切换。


9
万一您不知道它,git bisect非常适合发现回归。我想说的是,像安迪所说的那样使用{1年前}语法来找到一个已知的良好提交,然后将其用作您的初始git bisect good要点。
MatrixFrog 2011年

我觉得这是的好用例tags
Jess

Answers:


365

保持当前更改

您可以使用保留工作,而无需提交git stash。您会习惯于git stash pop将其取回。或者,您可以(如carleeto所说)将git commit其转移到另一个分支。

使用rev-parse按日期结帐

您可以使用以下命令在特定日期之前签出提交rev-parse

git checkout 'master@{1979-02-26 18:30:00}'

有关可用选项的更多详细信息,请参见git-rev-parse

如评论中所述,此方法使用reflog在历史记录中查找提交。默认情况下,这些条目在90天后过期。尽管使用reflog的语法不太冗长,但您只能追溯到90天。

使用rev-list按日期签出

另一个不使用reflog的选项是用于通过以下rev-list方式在特定时间点获取提交:

git checkout `git rev-list -n 1 --first-parent --before="2009-07-27 13:37" master`

如果只想要历史记录,而不想要合并带来的版本,请注意--first-parent。那就是你通常想要的。


2
@Rocky您能给我们更多详细信息吗?您在命令行中输入什么,为什么说它不起作用?您是否收到错误消息?
安迪

8
@Rocky:问题在于参数需要用引号引起来,否则bash将参数分隔在空格处。尝试git co 'master@{2 days ago}'
Mark Wilden

13
注意:根据您走的距离,这可能不起作用,因为它使用了reflog(一段时间后会过期)。您将看到“警告:'master'的日志仅返回到...'。Rocky的解决方案将始终有效。git checkoutgit rev-list -n 1 --before="2009-07-27 13:37" master
Mark Nadig 2012年

3
我已经编辑了您的答案,因为反引号已过时且难以阅读。子壳$(...)是首选。
Amedee Van Gasse

1
@安迪40岁生日快乐,安迪!(假设这就是1979-02-26的意思:))
David Blevins

122

安迪的解决方案对我不起作用。在这里,我找到了另一种方法:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`

Git:按日期结帐


3
当我执行以上命令时,我有error: unknown switch `n'任何解决方法?
蒂姆(Tim)

15

看来您需要以下内容: 基于日期的Git结帐

换句话说,您可以rev-list先查找提交,然后使用checkout实际获取它。

如果不想丢失分阶段的更改,最简单的方法是创建一个新分支并将其提交到该分支。您始终可以在分支之间来回切换。

编辑:链接已关闭,所以这是命令:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`

2
很棒的链接!因此git checkout branch@{date},当reflog过期时,它将停止工作,但是您可以使用git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
cdunn2001

10

对于那些喜欢用管道命令替换的人

git rev-list -n1 --before=2013-7-4 master | xargs git checkout

9

就我而言,该-n 1选项不起作用。在Windows上,我发现以下命令序列可以正常工作:

git rev-list -1 --before="2012-01-15 12:00" master

这将返回给定日期的适当提交的SHA,然后:

git checkout SHA

4

git rev-parse如果您感兴趣的日期提交的date,则@Andy提出的解决方案可以很好地工作。但是,如果您要基于作者的日期签出,rev-parse将无法使用,因为它不提供使用该日期选择提交的选项。相反,您可以使用以下内容。

git checkout $(
  git log --reverse --author-date-order --pretty=format:'%ai %H' master |
  awk '{hash = $4} $1 >= "2016-04-12" {print hash; exit 0 }
)

(如果您还想$1 >= "2016-04-12" && $2 >= "11:37"awk谓词中指定时间使用。)


3

rev-list如果您想找到从主分支到生产分支的最新合并提交(仅作为假设的示例),请进一步选择该选项:

git checkout `git rev-list -n 1 --merges --first-parent --before="2012-01-01" production`

我需要查找给定日期生产服务器上的代码。这为我找到了。


2

如果您希望在执行构建时能够返回到存储库的精确版本,则最好标记进行构建的提交。

其他答案提供了一些技术,可以使存储库恢复到某个时间的某个分支中的最新提交-但它们可能并不总是足够的。例如,如果您从分支构建,然后删除该分支,或者从后来重新建立基础的分支构建,则您构建的提交可能会在git中从任何当前分支变为“不可访问”。压缩存储库后,最终可能会删除git中无法访问的对象。

在提交上放置标签意味着无论以后对分支做什么(除非删除标签),它都永远不会变得无法访问。


尽管这并没有给我我想要的答案,但是值得指出的是,它指出了到目前为止尚未提及的一个方面。这可能是导致您无法获得正确版本的问题的根源。
manuelvigarcia

1
git rev-list -n 1 --before="2009-07-27 13:37" origin/master

取出打印的字符串(例如XXXX)并执行以下操作:

git checkout XXXX

2
这不是@bartoszkp答案的重复吗?只是添加对起源的引用,应该是对其他答案的评论……
manuelvigarcia

是的,事实上,几乎是,只是清除了谁不知道SHA是什么的复制对象(像我一样),在我的情况下,文本不清晰,这是我找到解决方案后的代码,未复制,实际上您可以看到选项也有明显不同
卡·
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.