ChatGPT解决这个技术问题 Extra ChatGPT

如何按日期在 Git 中结帐?

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

我也对我目前的观点进行了一些我不想失去的改变。理想情况下,我想在当前源和基于先前日期的某个我感兴趣的版本之间来回切换。

以防万一您不知道,git bisect 非常适合查找回归。我想说,使用像 Andy 所说的 {1 year ago} 语法来找到一个已知良好的提交,然后将其用作您的初始 git bisect good 点。
我觉得这是 tags 的一个很好的用例。

b
bebbo

保留您当前的更改

您可以使用 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 在您的历史记录中查找提交。默认情况下,这些条目 expire after 90 days。虽然使用 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。这就是你通常想要的。


@Rocky 你能给我们更多的细节吗?你在命令行上输入了什么,为什么你说它不起作用?您收到错误消息吗?
@Rocky:问题是参数需要用引号引起来,否则 bash 会在空格处分隔参数。试试 git co 'master@{2 days ago}'
注意:根据您回溯多远,这可能不起作用,因为它使用 reflog(一段时间后过期)。您将看到“警告:'master' 的日志仅返回到...”。 Rocky 的解决方案将永远有效。混帐结帐git rev-list -n 1 --before="2009-07-27 13:37" master
我编辑了您的答案,因为反引号已被弃用且难以阅读。子shell $(...) 是首选。
@Andy 40 岁生日快乐,安迪! (假设这就是 1979-02-26 的意思:))
H
Holger Bille

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

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

Git: checkout by date


当我执行上述命令时,我得到 error: unknown switch `n' 任何想法如何解决这个问题?
@Tim 分两部分运行它,首先运行 git rev-list ,然后才运行 git checkout 并使用从第一个命令获得的提交。
您应该使用 --max-count=1 而不是 -n 1
您应该解释对选项的需求。为什么是-n 1?不通过有什么区别?
这根本不适用于 Windows 的 GIT! (GIT 版本 2.30.1)。看起来 rev-list 命令总是忽略任何此类输入命令行选项。 :-\
C
Carl

看起来你需要类似这样的东西:Git checkout based on date

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

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

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

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

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

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

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

B
BartoszKP

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

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

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

git checkout SHA

D
Danyal Sandeelo

如果您感兴趣的日期是提交日期,@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"。)


Z
Zombo

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

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

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


a
antlersoft

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

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

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


虽然这并没有给我我要寻找的答案,但它确实值得一提,因为它指出了一个迄今为止没有提到的方面。这可能是导致您无法获得正确版本的问题的根源。
V
VonC

提醒,从 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 年使用 old, obsolete and confusing git checkout commandgit switchgit restore 准确描述它们正在做什么(仅使用 git switch 的分支,仅使用 git restore 的文件)

不要在过时的反引号语法上使用 ``: prefer the more modern $(command substitution) syntax


M
Murali Krishna Regandla

要从结帐中创建新分支,请使用带有新分支名称的 -b 选项。

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

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


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

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

git checkout XXXX

这不是@bartoszkp 答案的副本吗?只是添加对原点的引用,应该是对另一个答案的评论......
是的,实际上几乎,只是为不知道 SHA 是什么的人(像我一样)清除要复制的内容,在我的情况下,文本不清楚,这是我在找到解决方案后的代码,不是复制的,实际上你可以看到选项也略有不同
t
tyoc213

如果你达到了 reflog 的限制,你只需要做一点改变(你克隆 repo 的日期或 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到你想检查的日期,它似乎也能工作!!!


J
James Andariese

这是我用来按相对时间结帐的别名版本:

[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 fatal: error in object: unshallow 的优秀答案中找到帮助

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

使用 brew install coreutils 在 macOS 上安装。


M
Matt Faus

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

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