如何按日期在Git签出?

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

我目前的观点也有阶段性的变化,我不想失去这些变化。理想情况下,我希望在当前源文件和基于之前日期的某个我感兴趣的版本之间来回切换。

180628 次浏览
看起来你需要这样的东西: 基于日期的Git签出 < / p > 换句话说,你使用rev-list来找到提交,然后使用签出

如果你不想失去你的阶段性变化,最简单的事情就是 创建一个新分支,并将它们提交给该分支。你可以随时换回去

编辑:链接断开了,下面是命令:

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

保持当前的更改

你可以用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`

如果你只想要你的历史记录而不是合并带来的版本,请注意——“首席家长。这就是你通常想要的。

安迪的解决办法对我没用。在这里,我找到了另一种方法:

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

Git: checkout by date

进一步使用rev-list选项,如果你想找到从你的主分支到你的生产分支的最近的合并提交(作为一个纯假设的例子):

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

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

对于那些喜欢管道替换而不是命令替换的人

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

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

其他答案提供了在某个时间将存储库返回到分支中最近提交的技术——但它们可能并不总是足够的。例如,如果您从一个分支构建,然后稍后删除该分支,或者从一个稍后重新基于的分支构建,那么您从任何当前分支构建的提交在git中都可能变得“不可访问”。git中不可达的对象最终可能会在存储库压缩时被删除。

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

在我的例子中,-n 1选项不起作用。在Windows上,我发现下面的命令序列工作得很好:

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

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

git checkout SHA

@Andy提出的git rev-parse解决方案很好,如果你感兴趣的日期是提交的日期。然而,如果你想基于作者的日期签出,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 }
)

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

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

取打印出来的字符串(例如XXXX),然后做:

git checkout XXXX

如果你达到reflog的限制,你只需要做一点改变(从其他笔记来看,你克隆回购的日期或90天的历史)

git checkout `git rev-list -1 --before="Jan 17 2020" HEAD`

你也可以用

git checkout `git rev-list -1 --before="Jan 17 2020 8:06 UTC-8" HEAD`

它会检查之前的提交与日期或你输入的日期-时间相关,看到你可以使用日期修饰符,我猜如果你不使用UTC+-N它只使用UTC时间。

看到我只把master改为HEAD,即使你没有reflog到你想要检查的日期,它似乎也能工作!!

如果希望在特定日期签出单个文件,可以将文件路径传递给两个命令。

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

要从签出创建一个新分支,使用-b选项和新分支名称。

git checkout -b 19July2021 `git rev-list -n1 --before=2021-7-19 master`

当你处于“分离HEAD”状态时,你可以避免git switch

提醒,自Git 2.23(2019年8月)起

  • 切换到一个新的分支从过去的提交日期:

    git switch -c newBranch $(git rev-list -n1 --before=yyyy-mm-dd main)
    
  • 恢复当前工作树中过去日期的文件

    git restore -SW -s $(git rev-list -n1 --before=yyyy-mm-dd main) -- path/to/file
    

2021/2022年不要使用旧的,过时的和令人困惑的git checkout命令: git switchgit restore准确地描述了它们正在做的事情(只使用git switch的分支,只使用git restore的文件)

不要在过时的反标记语法上使用' ':更喜欢更现代的$(command substitution)语法

下面是我用来按相对时间签出的别名版本:

[alias]
parsedate = "!set -x ;arg1=\"$1\" && shift && which gdate &> /dev/null && gdate -d \"$arg1\" || date -d \"$arg1\""
codate = "!d=\"$(git parsedate \"$1\")\" && shift && git checkout \"$(git rev-list -n1 --first-parent --before=\"$d\" HEAD)\""

这允许你使用以下命令将2个月前的更改签入一个名为test的新分支:

git codate '2 months ago' -b test

这不会工作在一个浅克隆,所以不浅它首先与:

git fetch --unshallow

如果你得到一个非浅错误,你可能会从Git致命:错误的对象:unshallow的优秀答案中找到帮助

需要GNU coreutils,并使用brew在Linux和macOS上工作。

在macos上使用brew install coreutils安装。