Refine what a relative uri means in a git path (#3212)

diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart
index 1a792e3..0d26283 100644
--- a/lib/src/source/git.dart
+++ b/lib/src/source/git.dart
@@ -145,9 +145,15 @@
     return _ValidatedUrl(url, relative);
   }
 
-  /// Returns [path] normalized.
+  /// Normalizes [path].
   ///
-  /// Throws a [FormatException] if [path] isn't a relative url or null.
+  /// Throws a [FormatException] if [path] isn't a [String] parsing as a
+  /// relative URL or `null`.
+  ///
+  /// A relative url here has:
+  /// - non-absolute path
+  /// - no scheme
+  /// - no authority
   String _validatedPath(dynamic path) {
     path ??= '.';
     if (path is! String) {
@@ -157,9 +163,13 @@
 
     // Use Dart's URL parser to validate the URL.
     final parsed = Uri.parse(path);
-    if (parsed.isAbsolute) {
+    if (parsed.hasAbsolutePath ||
+        parsed.hasScheme ||
+        parsed.hasAuthority ||
+        parsed.hasFragment ||
+        parsed.hasQuery) {
       throw FormatException(
-          "The 'path' field of the description must be relative.");
+          "The 'path' field of the description must be a relative path URL.");
     }
     if (!p.url.isWithin('.', path) && !p.url.equals('.', path)) {
       throw FormatException(
diff --git a/test/get/git/path_test.dart b/test/get/git/path_test.dart
index eab018f..d26d9cb 100644
--- a/test/get/git/path_test.dart
+++ b/test/get/git/path_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:path/path.dart' as p;
+import 'package:pub/src/exit_codes.dart' as exit_codes;
 import 'package:pub/src/io.dart';
 import 'package:pub/src/lock_file.dart';
 import 'package:pub/src/source/git.dart';
@@ -86,6 +87,84 @@
         reason: 'use uris to specify the path relative to the repo');
   });
 
+  group('requires path to be absolute', () {
+    test('absolute path', () async {
+      await d.appDir({
+        'sub': {
+          'git': {'url': '../foo.git', 'path': '/subdir'}
+        }
+      }).create();
+
+      await pubGet(
+        error: contains(
+          'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.',
+        ),
+        exitCode: exit_codes.DATA,
+      );
+    });
+    test('scheme', () async {
+      await d.appDir({
+        'sub': {
+          'git': {'url': '../foo.git', 'path': 'https://subdir'}
+        }
+      }).create();
+
+      await pubGet(
+        error: contains(
+          'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.',
+        ),
+        exitCode: exit_codes.DATA,
+      );
+    });
+    test('fragment', () async {
+      await d.appDir({
+        'sub': {
+          'git': {'url': '../foo.git', 'path': 'subdir/dir#fragment'}
+        }
+      }).create();
+
+      await pubGet(
+        error: contains(
+          'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.',
+        ),
+        exitCode: exit_codes.DATA,
+      );
+    });
+
+    test('query', () async {
+      await d.appDir({
+        'sub': {
+          'git': {'url': '../foo.git', 'path': 'subdir/dir?query'}
+        }
+      }).create();
+
+      await pubGet(
+        error: contains(
+          'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.',
+        ),
+        exitCode: exit_codes.DATA,
+      );
+    });
+
+    test('authority', () async {
+      await d.appDir({
+        'sub': {
+          'git': {
+            'url': '../foo.git',
+            'path': 'bob:pwd@somewhere.example.com/subdir'
+          }
+        }
+      }).create();
+
+      await pubGet(
+        error: contains(
+          'Invalid description in the "myapp" pubspec on the "sub" dependency: The \'path\' field of the description must be a relative path URL.',
+        ),
+        exitCode: exit_codes.DATA,
+      );
+    });
+  });
+
   test('depends on a package in a deep subdirectory, non-relative uri',
       () async {
     ensureGit();