[go_router] Allow any number of the same page on the stack (#2339)

diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index 2ddd57a..465df98 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 4.2.3
+
+- Fixes a bug where the ValueKey to be the same when a page was pushed multiple times.
+
 ## 4.2.2
 
 - Fixes a bug where go_router_builder wasn't detecting annotations.
diff --git a/packages/go_router/lib/src/delegate.dart b/packages/go_router/lib/src/delegate.dart
index 1af969c..29f0f25 100644
--- a/packages/go_router/lib/src/delegate.dart
+++ b/packages/go_router/lib/src/delegate.dart
@@ -45,10 +45,27 @@
   final GlobalKey<NavigatorState> _key = GlobalKey<NavigatorState>();
 
   RouteMatchList _matches = RouteMatchList.empty();
+  final Map<String, int> _pushCounts = <String, int>{};
 
-  /// Push the given location onto the page stack
+  /// Pushes the given location onto the page stack
   void push(RouteMatch match) {
-    _matches.push(match);
+    // Remap the pageKey to allow any number of the same page on the stack
+    final String fullPath = match.fullpath;
+    final int count = (_pushCounts[fullPath] ?? 0) + 1;
+    _pushCounts[fullPath] = count;
+    final ValueKey<String> pageKey = ValueKey<String>('$fullPath-p$count');
+    final RouteMatch newPageKeyMatch = RouteMatch(
+      route: match.route,
+      subloc: match.subloc,
+      fullpath: match.fullpath,
+      encodedParams: match.encodedParams,
+      queryParams: match.queryParams,
+      extra: match.extra,
+      error: match.error,
+      pageKey: pageKey,
+    );
+
+    _matches.push(newPageKeyMatch);
     notifyListeners();
   }
 
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index 4c8da3d..0b2d6f0 100644
--- a/packages/go_router/pubspec.yaml
+++ b/packages/go_router/pubspec.yaml
@@ -1,7 +1,7 @@
 name: go_router
 description: A declarative router for Flutter based on Navigation 2 supporting
   deep linking, data-driven routes and more
-version: 4.2.2
+version: 4.2.3
 repository: https://github.com/flutter/packages/tree/main/packages/go_router
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
 
diff --git a/packages/go_router/test/delegate_test.dart b/packages/go_router/test/delegate_test.dart
index a85d536..b4a4173 100644
--- a/packages/go_router/test/delegate_test.dart
+++ b/packages/go_router/test/delegate_test.dart
@@ -16,6 +16,7 @@
     initialLocation: '/',
     routes: <GoRoute>[
       GoRoute(path: '/', builder: (_, __) => const DummyStatefulWidget()),
+      GoRoute(path: '/a', builder: (_, __) => const DummyStatefulWidget()),
       GoRoute(
         path: '/error',
         builder: (_, __) => const ErrorScreen(null),
@@ -56,6 +57,38 @@
     });
   });
 
+  group('push', () {
+    testWidgets(
+      'It should return different pageKey when push is called',
+      (WidgetTester tester) async {
+        final GoRouter goRouter = await createGoRouter(tester);
+        expect(goRouter.routerDelegate.matches.matches.length, 1);
+        expect(
+          goRouter.routerDelegate.matches.matches[0].pageKey,
+          null,
+        );
+
+        goRouter.push('/a');
+        await tester.pumpAndSettle();
+
+        expect(goRouter.routerDelegate.matches.matches.length, 2);
+        expect(
+          goRouter.routerDelegate.matches.matches[1].pageKey,
+          const Key('/a-p1'),
+        );
+
+        goRouter.push('/a');
+        await tester.pumpAndSettle();
+
+        expect(goRouter.routerDelegate.matches.matches.length, 3);
+        expect(
+          goRouter.routerDelegate.matches.matches[2].pageKey,
+          const Key('/a-p2'),
+        );
+      },
+    );
+  });
+
   group('canPop', () {
     testWidgets(
       'It should return false if there is only 1 match in the stack',