Fix version parsing to use git tag --points-at (#63505)

diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart
index 9c83b62..0e0b41d 100644
--- a/packages/flutter_tools/lib/src/version.dart
+++ b/packages/flutter_tools/lib/src/version.dart
@@ -760,22 +760,20 @@
       }
     }
     final List<String> tags = _runGit(
-      'git tag --contains HEAD', processUtils, workingDirectory).split('\n');
+      'git tag --points-at HEAD', processUtils, workingDirectory).trim().split('\n');
 
     // Check first for a stable tag
     final RegExp stableTagPattern = RegExp(r'^\d+\.\d+\.\d+$');
     for (final String tag in tags) {
-      final String trimmedTag = tag.trim();
-      if (stableTagPattern.hasMatch(trimmedTag)) {
-        return parse(trimmedTag);
+      if (stableTagPattern.hasMatch(tag.trim())) {
+        return parse(tag);
       }
     }
     // Next check for a dev tag
     final RegExp devTagPattern = RegExp(r'^\d+\.\d+\.\d+-\d+\.\d+\.pre$');
     for (final String tag in tags) {
-      final String trimmedTag = tag.trim();
-      if (devTagPattern.hasMatch(trimmedTag)) {
-        return parse(trimmedTag);
+      if (devTagPattern.hasMatch(tag.trim())) {
+        return parse(tag);
       }
     }
 
diff --git a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
index 8ce7b23..d7186b5 100644
--- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
+++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
@@ -323,7 +323,7 @@
         fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
           const FakeCommand(
             command: <String>[
-              'git', 'tag', '--contains', 'HEAD',
+              'git', 'tag', '--points-at', 'HEAD',
             ],
             stdout: '',
           ),
diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
index ada250f..26639b1 100644
--- a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
+++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
@@ -185,7 +185,7 @@
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
         when(processManager.runSync('git fetch https://github.com/flutter/flutter.git --tags'.split(' '),
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
-        when(processManager.runSync('git tag --contains HEAD'.split(' '),
+        when(processManager.runSync('git tag --points-at HEAD'.split(' '),
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
         when(processManager.runSync('git describe --match *.*.* --first-parent --long --tags'.split(' '),
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart
index 38711f5..67439b8 100644
--- a/packages/flutter_tools/test/general.shard/version_test.dart
+++ b/packages/flutter_tools/test/general.shard/version_test.dart
@@ -7,6 +7,7 @@
 import 'package:collection/collection.dart' show ListEquality;
 import 'package:flutter_tools/src/base/context.dart';
 import 'package:flutter_tools/src/base/io.dart';
+import 'package:flutter_tools/src/base/logger.dart';
 import 'package:flutter_tools/src/base/platform.dart';
 import 'package:flutter_tools/src/base/process.dart';
 import 'package:flutter_tools/src/base/time.dart';
@@ -458,27 +459,66 @@
     );
   });
 
-  testUsingContext('determine favors stable tags over dev tags', () {
-    final MockProcessUtils mockProcessUtils = MockProcessUtils();
-    when(mockProcessUtils.runSync(
-      <String>['git', 'tag', '--contains', 'HEAD'],
-      workingDirectory: anyNamed('workingDirectory'),
-      environment: anyNamed('environment'),
-    )).thenReturn(RunResult(
-      ProcessResult(1, 0, '1.2.3-0.0.pre\n1.2.3\n1.2.3-0.1.pre', ''),
-      <String>['git', 'tag', '--contains', 'HEAD'],
-    ));
-    final GitTagVersion version = GitTagVersion.determine(mockProcessUtils, workingDirectory: '.');
-    expect(version.gitTag, '1.2.3');
-    expect(version.devPatch, null);
-    expect(version.devVersion, null);
-    // We shouldn't have to fallback to git describe, because we are exactly
-    // on a release tag.
-    verifyNever(mockProcessUtils.runSync(
-      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
-      workingDirectory: anyNamed('workingDirectory'),
-      environment: anyNamed('environment'),
-    ));
+  testUsingContext('determine reports correct stable version if HEAD is at a tag', () {
+    const String stableTag = '1.2.3';
+    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
+      <FakeCommand>[
+        const FakeCommand(
+          command: <String>['git', 'tag', '--points-at', 'HEAD'],
+          stdout: stableTag,
+        ),
+      ],
+    );
+    final ProcessUtils processUtils = ProcessUtils(
+      processManager: fakeProcessManager,
+      logger: BufferLogger.test(),
+    );
+    final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: '.');
+    expect(gitTagVersion.frameworkVersionFor('abcd1234'), stableTag);
+  });
+
+  testUsingContext('determine favors stable tag over dev tag if both idenitfy HEAD', () {
+    const String stableTag = '1.2.3';
+    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
+      <FakeCommand>[
+        const FakeCommand(
+          command: <String>['git', 'tag', '--points-at', 'HEAD'],
+          // This tests the unlikely edge case where a dev release made it to stable without any cherry picks
+          stdout: '1.2.3-6.0.pre\n$stableTag',
+        ),
+      ],
+    );
+    final ProcessUtils processUtils = ProcessUtils(
+      processManager: fakeProcessManager,
+      logger: BufferLogger.test(),
+    );
+    final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: '.');
+    expect(gitTagVersion.frameworkVersionFor('abcd1234'), stableTag);
+  });
+
+  testUsingContext('determine reports correct git describe version if HEAD is not at a tag', () {
+    const String devTag = '1.2.3-2.0.pre';
+    const String headRevision = 'abcd1234';
+    const String commitsAhead = '12';
+    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
+      <FakeCommand>[
+        const FakeCommand(
+          command: <String>['git', 'tag', '--points-at', 'HEAD'],
+          stdout: '', // no tag
+        ),
+        const FakeCommand(
+          command: <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
+          stdout: '$devTag-$commitsAhead-g$headRevision',
+        ),
+      ],
+    );
+    final ProcessUtils processUtils = ProcessUtils(
+      processManager: fakeProcessManager,
+      logger: BufferLogger.test(),
+    );
+    final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: '.');
+    // reported version should increment the number after the dash
+    expect(gitTagVersion.frameworkVersionFor(headRevision), '1.2.3-3.0.pre.12');
   });
 
   testUsingContext('determine does not call fetch --tags', () {
@@ -494,12 +534,12 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
     when(processUtils.runSync(
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(
       RunResult(ProcessResult(110, 0, '', ''),
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
     ));
 
     GitTagVersion.determine(processUtils, workingDirectory: '.');
@@ -539,12 +579,12 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
     when(processUtils.runSync(
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(
       RunResult(ProcessResult(108, 0, '', ''),
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
     ));
 
     GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
@@ -579,12 +619,12 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(109, 0, '', ''), <String>['git', 'fetch']));
     when(processUtils.runSync(
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(
       RunResult(ProcessResult(110, 0, '', ''),
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
     ));
     when(processUtils.runSync(
       <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
@@ -624,12 +664,12 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(109, 0, '', ''), <String>['git', 'fetch']));
     when(processUtils.runSync(
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(
       RunResult(ProcessResult(110, 0, '', ''),
-      <String>['git', 'tag', '--contains', 'HEAD'],
+      <String>['git', 'tag', '--points-at', 'HEAD'],
     ));
     when(processUtils.runSync(
       <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
@@ -765,7 +805,7 @@
     environment: anyNamed('environment'),
   )).thenReturn(ProcessResult(105, 0, '', ''));
   when(pm.runSync(
-    <String>['git', 'tag', '--contains', 'HEAD'],
+    <String>['git', 'tag', '--points-at', 'HEAD'],
     workingDirectory: anyNamed('workingDirectory'),
     environment: anyNamed('environment'),
   )).thenReturn(ProcessResult(106, 0, '', ''));