我正在对源代码进行回归。我想告诉 Git:“根据参数化的日期/时间检查源代码”。这可能吗?
我也对我目前的观点进行了一些我不想失去的改变。理想情况下,我想在当前源和基于先前日期的某个我感兴趣的版本之间来回切换。
git bisect good
点。
tags
的一个很好的用例。
保留您当前的更改
您可以使用 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。这就是你通常想要的。
安迪的解决方案对我不起作用。在这里,我找到了另一种方法:
git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
error: unknown switch `n'
任何想法如何解决这个问题?
git rev-list
,然后才运行 git checkout
并使用从第一个命令获得的提交。
--max-count=1
而不是 -n 1
看起来你需要类似这样的东西:Git checkout based on date
换句话说,您使用 rev-list
来查找提交,然后使用 checkout 来实际获取它。
如果您不想丢失分阶段的更改,最简单的方法是创建一个新分支并将它们提交到该分支。您始终可以在分支之间来回切换。
编辑:链接已关闭,所以这里是命令:
git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
git checkout branch@{date}
停止工作,但您可以使用 git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
。
对于那些喜欢管道而不是命令替换的人
git rev-list -n1 --before=2013-7-4 master | xargs git checkout
在我的情况下,-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"
。)
进一步使用 rev-list
选项,如果您想从您的主分支找到最近的合并提交到您的生产分支(作为一个纯粹的假设示例):
git checkout `git rev-list -n 1 --merges --first-parent --before="2012-01-01" production`
我需要找到截至给定日期在生产服务器上的代码。这为我找到了它。
如果您希望能够在进行构建时返回到存储库的精确版本,最好标记您进行构建的提交。
其他答案提供了将存储库返回到某个时间分支中最近提交的技术——但它们可能并不总是足够的。例如,如果您从一个分支构建,然后删除该分支,或者从一个稍后重新定位的分支构建,那么您构建的提交可能会在 git 中从任何当前分支变得“不可访问”。压缩存储库时,最终可能会删除 git 中无法访问的对象。
在提交上放置标签意味着它永远不会变得无法访问,无论您之后对分支做什么(除非删除标签)。
提醒,从 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
command:git switch
和 git restore
准确描述它们正在做什么(仅使用 git switch
的分支,仅使用 git restore
的文件)
不要在过时的反引号语法上使用 ``: prefer the more modern $(command substitution)
syntax。
要从结帐中创建新分支,请使用带有新分支名称的 -b 选项。
git checkout -b 19July2021 `git rev-list -n1 --before=2021-7-19 master`
当您处于“分离 HEAD”状态时,您可以避免 git switch
git rev-list -n 1 --before="2009-07-27 13:37" origin/master
获取打印的字符串(例如 XXXX)并执行以下操作:
git checkout XXXX
如果你达到了 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到你想检查的日期,它似乎也能工作!!!
这是我用来按相对时间结帐的别名版本:
[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 上安装。
如果要在特定日期检出单个文件,可以将文件路径传递给这两个命令。
git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master FILEPATH` FILEPATH
不定期副业成功案例分享
git co 'master@{2 days ago}'
。git rev-list -n 1 --before="2009-07-27 13:37" master
$(...)
是首选。