@@ -357,6 +357,50 @@ enum class rev_match {
357357 return git_error::ok;
358358}
359359
360+ [[nodiscard]] static git_error repository_checkout (::git_repository *repository, std::string const & rev)
361+ {
362+ ::git_object *rev_obj = nullptr ;
363+ ::git_reference *rev_ref = nullptr ;
364+ if (auto const result = ::git_revparse_ext (&rev_obj, &rev_ref, repository, rev.c_str ()); result != GIT_OK) {
365+ if (result == GIT_ENOTFOUND) {
366+ // The rev was not found in the repository.
367+ return git_error::not_found;
368+ }
369+ return make_git_error (result);
370+ }
371+ auto const d1 = defer{[&] {
372+ ::git_object_free (rev_obj);
373+ ::git_reference_free (rev_ref);
374+ }};
375+
376+ ::git_object *peeled_rev_obj = nullptr ;
377+ if (auto const result = ::git_object_peel (&peeled_rev_obj, rev_obj, GIT_OBJECT_COMMIT); result != GIT_OK) {
378+ return make_git_error (result);
379+ }
380+ auto const d2 = defer{[&] { ::git_object_free (peeled_rev_obj); }};
381+
382+ auto checkout_options = ::git_checkout_options{};
383+ if (::git_checkout_options_init (&checkout_options, GIT_CHECKOUT_OPTIONS_VERSION) != 0 ) {
384+ return git_error::error;
385+ }
386+ checkout_options.checkout_strategy = GIT_CHECKOUT_FORCE;
387+
388+ if (auto const result = ::git_checkout_tree (repository, peeled_rev_obj, &checkout_options); result != GIT_OK) {
389+ return make_git_error (result);
390+ }
391+
392+ auto const *commit_oid = ::git_object_id (peeled_rev_obj);
393+ if (commit_oid == nullptr ) {
394+ return git_error::error;
395+ }
396+
397+ if (auto const result = ::git_repository_set_head_detached (repository, commit_oid); result != GIT_OK) {
398+ return make_git_error (result);
399+ }
400+
401+ return git_error::ok;
402+ }
403+
360404[[nodiscard]] git_error git_fetch_and_update (std::string const & url, std::string const & rev, std::filesystem::path path, git_checkout_flags flags)
361405{
362406 auto const & _ = git_lib_initialize ();
0 commit comments