Introduce `getPackageNameFromGitRepo` in package API (#4630)

diff --git a/lib/pub.dart b/lib/pub.dart
index d7b5653..12f364c 100644
--- a/lib/pub.dart
+++ b/lib/pub.dart
@@ -8,6 +8,7 @@
 import 'src/exceptions.dart';
 import 'src/http.dart';
 import 'src/pub_embeddable_command.dart';
+import 'src/source/git.dart';
 import 'src/system_cache.dart';
 
 export 'src/executable.dart'
@@ -67,3 +68,39 @@
   String message;
   ResolutionFailedException._(this.message);
 }
+
+/// Given a Git repo that contains a pub package, gets the name of the pub
+/// package.
+///
+/// Will download the repo to the system cache under the assumption that the
+/// package will be downloaded afterwards.
+///
+/// [url] points to the git repository. If it is a relative url, it is resolved
+/// as a file url relative to the path [relativeTo].
+///
+/// [ref] is the commit, tag, or branch name where the package should be looked
+/// up when fetching the name. If omitted, 'HEAD' is used.
+///
+/// [tagPattern] is a string containing `'{{version}}'` as a substring, the
+/// latest tag matching the pattern will be used for fetching the name.
+///
+/// Only one of [ref] and [tagPattern] can be used.
+///
+/// If [isOffline], only the already cached versions of the repo is used.
+Future<String> getPackageNameFromGitRepo(
+  String url, {
+  String? ref,
+  String? path,
+  String? tagPattern,
+  String? relativeTo,
+  bool isOffline = false,
+}) async {
+  return await GitSource.instance.getPackageNameFromRepo(
+    url,
+    ref,
+    path,
+    SystemCache(isOffline: isOffline),
+    relativeTo: relativeTo,
+    tagPattern: tagPattern,
+  );
+}
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart
index 91d55af..39ea66d 100644
--- a/lib/src/source/git.dart
+++ b/lib/src/source/git.dart
@@ -290,7 +290,7 @@
     String? ref,
     String? path,
     SystemCache cache, {
-    required String relativeTo,
+    required String? relativeTo,
     required String? tagPattern,
   }) async {
     assert(