Add a Flutter version comparison function (#12959)

* add git version comparison function

* use [] in dartdoc

* Make method instance method
diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart
index ab3c0bd..fae08a9 100644
--- a/packages/flutter_tools/lib/src/version.dart
+++ b/packages/flutter_tools/lib/src/version.dart
@@ -167,6 +167,20 @@
     return _branch;
   }
 
+  /// Returns true if `tentativeDescendantRevision` is a direct descendant to
+  /// the `tentativeAncestorRevision` revision on the Flutter framework repo
+  /// tree.
+  bool checkRevisionAncestry({
+    String tentativeDescendantRevision,
+    String tentativeAncestorRevision,
+  }) {
+    final ProcessResult result = processManager.runSync(
+      <String>['git', 'merge-base', '--is-ancestor', tentativeAncestorRevision, tentativeDescendantRevision],
+      workingDirectory: Cache.flutterRoot,
+    );
+    return result.exitCode == 0;
+  }
+
   /// The amount of time we wait before pinging the server to check for the
   /// availability of a newer version of Flutter.
   @visibleForTesting
diff --git a/packages/flutter_tools/test/version_test.dart b/packages/flutter_tools/test/version_test.dart
index 41bf568..331151d 100644
--- a/packages/flutter_tools/test/version_test.dart
+++ b/packages/flutter_tools/test/version_test.dart
@@ -26,11 +26,17 @@
 
 void main() {
   group('$FlutterVersion', () {
+    ProcessManager mockProcessManager;
+
     setUpAll(() {
       Cache.disableLocking();
       FlutterVersion.kPauseToLetUserReadTheMessage = Duration.ZERO;
     });
 
+    setUp(() {
+      mockProcessManager = new MockProcessManager();
+    });
+
     testFlutterVersion('prints nothing when Flutter installation looks fresh', () async {
       fakeData(localCommitDate: _upToDateVersion);
       await FlutterVersion.instance.checkFlutterVersionFreshness();
@@ -143,6 +149,30 @@
       await version.checkFlutterVersionFreshness();
       _expectVersionMessage('');
     });
+
+    testUsingContext('versions comparison', () async {
+      when(mockProcessManager.runSync(
+        <String>['git', 'merge-base', '--is-ancestor', 'abcdef', '123456'],
+        workingDirectory: any,
+      )).thenReturn(new ProcessResult(1, 0, '', ''));
+
+      expect(
+        FlutterVersion.instance.checkRevisionAncestry(
+          tentativeDescendantRevision: '123456',
+          tentativeAncestorRevision: 'abcdef',
+        ),
+        true
+      );
+
+      verify(mockProcessManager.runSync(
+        <String>['git', 'merge-base', '--is-ancestor', 'abcdef', '123456'],
+        workingDirectory: any,
+      ));
+    },
+    overrides: <Type, Generator>{
+      FlutterVersion: () => new FlutterVersion(_testClock),
+      ProcessManager: () => mockProcessManager,
+    });
   });
 
   group('$VersionCheckStamp', () {