)]}'
{
  "log": [
    {
      "commit": "c89dc44d4bddfc7d2d34051c7d5aebf7755c6f2e",
      "tree": "6c6b7f92c5147dbbacecf96a6fcabf15b175178e",
      "parents": [
        "07782a0f6bee9e78546d250abd59dd099849a0a8"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon Jul 27 14:26:53 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon Jul 27 14:39:15 2026 -0700"
      },
      "message": "Show batch progress in PushOne queue tasks\n\nUpdate the running task display during batched pushes to append the\ncurrent batch progress, so users can track long-running replication\nwork from the queue.\n\nChange-Id: I29dae9ee62452bbb3bd3d945ea04c6c7a8cd5261\n"
    },
    {
      "commit": "07782a0f6bee9e78546d250abd59dd099849a0a8",
      "tree": "d5f7a6937a46026d5bd5de4180be6a34314bf62f",
      "parents": [
        "7e7c2417c7a9cccd6e408955acf271c68c359bb3"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon Jul 27 11:14:12 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon Jul 27 11:28:03 2026 -0700"
      },
      "message": "Update docs to clarify \u0027excludedRefsPattern\u0027 uses Java regex\n\nDocument that remote.NAME.excludedRefsPattern accepts only Java\nregular expressions and that the expression must fully match the\nref name.\n\nChange-Id: I95ba705a1c5ef0768359817299abcdb1dfdb9e24\n"
    },
    {
      "commit": "7e7c2417c7a9cccd6e408955acf271c68c359bb3",
      "tree": "6d8f7cef36ebbbabbbe360f28cded82a522d72dd",
      "parents": [
        "54898d71ffa30bcdaa0f37f968efb0985d9bca64"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Wed Jul 22 12:37:16 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Thu Jul 23 13:27:43 2026 -0700"
      },
      "message": "Allow setting remote.NAME.threads\u003d0 for persist-only mode\n\nSetting \u0027remote.NAME.threads\u0027 to 0 now puts a remote into a\npersist-only mode on the current node. No thread pool is created and\nthe node performs no pushes, project deletions or HEAD updates for\nthat remote. Replication tasks are still written to the task storage.\n\nThis supports multi-primary deployments where a user-facing primary\nonly records replication work, while a separate non user-facing\nprimary (configured with threads \u003e 0 and distributor enabled) picks\nthe tasks up from the shared storage and performs the actual pushes.\nAlso, when a node has no push-enabled remotes, both recovery and the\nstartup replay are skipped entirely.\n\nA caveat to setting threads to \u00270\u0027 is that project deletions and HEAD\nupdates originating on a persist-only node are not replicated by other\nnodes, as they are not persisted to the task storage. If needed, support\nfor persisting them can be added in future changes.\n\nChange-Id: I022865cbd7105563b5760ca05ae85847e0d7b97b\n"
    },
    {
      "commit": "54898d71ffa30bcdaa0f37f968efb0985d9bca64",
      "tree": "545c5cdf78ef694c6c392a484c5c4cd4c5ae3da0",
      "parents": [
        "0f4eec70496e7589dba4d7e432deb427c22b6069",
        "a418c12074e796ab8e01484c715804a071370e4a"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon Jul 20 09:08:35 2026 -0700"
      },
      "committer": {
        "name": "Gerrit Code Review",
        "email": "noreply-gerritcodereview@google.com",
        "time": "Mon Jul 20 09:08:35 2026 -0700"
      },
      "message": "Merge \"Auto-repair replication on missing necessary objects error\""
    },
    {
      "commit": "0f4eec70496e7589dba4d7e432deb427c22b6069",
      "tree": "e09f1e19c483de8dfc1af30953cef95c345ed05a",
      "parents": [
        "1b609b02f0b60df09c43baf1edca452a375924ca"
      ],
      "author": {
        "name": "Thomas Dräbing",
        "email": "thomas.draebing@sap.com",
        "time": "Mon Jul 20 11:23:59 2026 +0200"
      },
      "committer": {
        "name": "Thomas Draebing",
        "email": "thomas.draebing@sap.com",
        "time": "Mon Jul 20 03:55:28 2026 -0700"
      },
      "message": "Log exception data in JSON log\n\nWhen logging in JSON format, the exception data, e.g. stacktrace, which\nthe replication plugin logs into its own log are not logged to file.\n\nThe implementation was copied from\n`com.google.gerrit.pgm.util.ErrorJsonLogEntry` in Gerrit core.\n\nChange-Id: I690b9c21584d98dc69eabaf41fb2d4365f734ce0\n"
    },
    {
      "commit": "a418c12074e796ab8e01484c715804a071370e4a",
      "tree": "75ee12ee5add5a48a50abed3007253ab000c79b0",
      "parents": [
        "4296f7364429ffe5e537756199cd14daab2d3353"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon May 18 16:32:53 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Wed Jul 15 09:39:27 2026 -0700"
      },
      "message": "Auto-repair replication on missing necessary objects error\n\nWhen a replication push fails because the remote git-receive-pack\nreports \u0027missing necessary objects\u0027, the destination is likely corrupt\nand requires manual intervention. Detect that error and, when enabled,\nschedule an asynchronous repair.\n\nRepair only runs for plain SSH destinations (not gerrit+ssh, http, or\ngit protocols) since rsync over SSH is required. Attempts are tracked\nper project+destination and gated by three new config options:\n\n  * autoRepairMaxAttempts (default 0, disabled): maximum number of\n    auto-repair attempts per project on each destination URL\n  * autoRepairInterval (default 3days): minimum spacing between\n    attempts for the same (project, destination)\n  * autoRepairConcurrencyLimit (default 2): maximum number of\n    auto-repair tasks allowed to run concurrently\n\nTracker state is in-memory and resets on plugin reload or Gerrit\nrestart, so the cap is best-effort rather than persistent. Enabling\nauto-repair in a clustered deployment can lead to redundant repairs as\nstate is not shared across nodes. This could be improved later if\ndesired, perhaps by persisting the state using the replication task\nstorage.\n\nAuto-repair deliberately uses the failing destination URI instead of\nround-robin failover, since repairs target corruption errors and are\nmore likely to succeed on the URL that just reported the problem.\n\nRelease-Notes: Auto-repair replication on missing objects errors\nChange-Id: I815f620af93b484fa801d0c953d56b6a6b00be66\n"
    },
    {
      "commit": "1b609b02f0b60df09c43baf1edca452a375924ca",
      "tree": "88042b28a6209ff8c117afff06f54fec7834c1bf",
      "parents": [
        "4296f7364429ffe5e537756199cd14daab2d3353",
        "28ee207f72e3acb7910ab39d0a033c9da38b699c"
      ],
      "author": {
        "name": "Martin Fick US",
        "email": "mfick@nvidia.com",
        "time": "Tue Jul 14 09:26:42 2026 -0700"
      },
      "committer": {
        "name": "Gerrit Code Review",
        "email": "noreply-gerritcodereview@google.com",
        "time": "Tue Jul 14 09:26:42 2026 -0700"
      },
      "message": "Merge \"Retry failovers by applying url distribution strategy\""
    },
    {
      "commit": "28ee207f72e3acb7910ab39d0a033c9da38b699c",
      "tree": "9d7b763dc9f00bd26c88555e2ee17c00ac75d92f",
      "parents": [
        "681d9ab03db4d2ac3b7bfc81f64e490ddaceebfb"
      ],
      "author": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Mon Jun 01 23:33:58 2026 -0500"
      },
      "committer": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Mon Jul 13 18:32:13 2026 -0500"
      },
      "message": "Retry failovers by applying url distribution strategy\n\nPreviously, a push with urlDistributionStrategy\u003droundRobin retried the\nsame URL after a transport error - a single unreachable replica could\nblock replication for any push the rotation happened to land on it. Fix\nit to apply the distribution strategy on retries.\n\nChange-Id: Id8ff42afdcd40a315fbab1ecb272b5e87bd0880d\n"
    },
    {
      "commit": "4296f7364429ffe5e537756199cd14daab2d3353",
      "tree": "8e44b2a2e83dc049ea07452b0be17bf496b967c1",
      "parents": [
        "681d9ab03db4d2ac3b7bfc81f64e490ddaceebfb"
      ],
      "author": {
        "name": "Bhoomika Srinivas",
        "email": "bhoomikas@nvidia.com",
        "time": "Tue May 05 14:48:01 2026 -0700"
      },
      "committer": {
        "name": "Bhoomika Srinivas",
        "email": "bhoomikas@nvidia.com",
        "time": "Wed Jul 08 11:37:32 2026 +0530"
      },
      "message": "Add --ref option to start command\n\nUsers can now trigger replication for a specific reference using the\n--ref \u003cRefName\u003e option. This allows for targeted replication of\nindividual branches or tags rather than forcing a full project sync.\n\nExample usage:\n  ssh -p 29418 host replication start --ref refs/heads/master my-project\n\nChange-Id: If6d208411e2a1645fff4f7a6d2e6c5428b87e3f3\nRelease-Notes: Add --ref \u003cRefName\u003e option to start command\n"
    },
    {
      "commit": "681d9ab03db4d2ac3b7bfc81f64e490ddaceebfb",
      "tree": "93a5ab5b50562296b269a607ee7128b3ff0e24a2",
      "parents": [
        "7ee2a87d66715cca69a75c69670c5c16a416c011",
        "7c9a80f4b0b1f64439a0a658d3d62b3c1afe7417"
      ],
      "author": {
        "name": "Adithya C",
        "email": "achakilam@nvidia.com",
        "time": "Tue Jun 09 14:20:15 2026 -0700"
      },
      "committer": {
        "name": "Gerrit Code Review",
        "email": "noreply-gerritcodereview@google.com",
        "time": "Tue Jun 09 14:20:15 2026 -0700"
      },
      "message": "Merge \"Destination: remove unused method\""
    },
    {
      "commit": "7c9a80f4b0b1f64439a0a658d3d62b3c1afe7417",
      "tree": "d9cba729719c3cc24656752fbd87db70fae7523f",
      "parents": [
        "57636c9a0273f0671209b9bb8051c42504df1a90"
      ],
      "author": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Tue Jun 09 15:45:18 2026 -0500"
      },
      "committer": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Tue Jun 09 15:45:18 2026 -0500"
      },
      "message": "Destination: remove unused method\n\nChange-Id: I97fb13b03694572c1925f65abdc941cffd9fbe8b\n"
    },
    {
      "commit": "7ee2a87d66715cca69a75c69670c5c16a416c011",
      "tree": "cc2bdd583e277edb285db95f2bca465476df5425",
      "parents": [
        "3e623c75033c815b97b5aa9b112dcc75c17dc018"
      ],
      "author": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Fri May 29 12:14:23 2026 -0500"
      },
      "committer": {
        "name": "Adithya C",
        "email": "achakilam@nvidia.com",
        "time": "Mon Jun 01 15:21:52 2026 -0700"
      },
      "message": "Add config option to disable replication event emission\n\nThe plugin posts a stream event at every point of the replication\nlifecycle (ref-replicated, replication-scheduled, replication-done,\nproject-deletion-*). When no listener is configured these events are\npure overhead. The cost is especially visible in multi-primary\ndeployments running an events-sharing plugin that fans every\nreplication event out to all the other primaries, even though nothing\non either end consumes it.\n\nIntroduce \u0027replication.emitEvents\u0027 (default true, so existing behavior\nis preserved) to suppress emission at the source.\n\nChange-Id: I32972d371ec83856e6783164bad9a229d1c8f934\n"
    },
    {
      "commit": "3e623c75033c815b97b5aa9b112dcc75c17dc018",
      "tree": "21f42cce401c5211ae465a61fe026dc09a1a8ee5",
      "parents": [
        "57636c9a0273f0671209b9bb8051c42504df1a90",
        "33fc916b0425bdbfbba6fc96047de5b5a0bb8777"
      ],
      "author": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Thu May 28 18:56:52 2026 -0500"
      },
      "committer": {
        "name": "Adithya C",
        "email": "achakilam@nvidia.com",
        "time": "Thu May 28 17:42:05 2026 -0700"
      },
      "message": "Merge branch \u0027stable-3.13\u0027\n\n* origin/stable-3.13:\n  Fix --remote option to replication start\n  Add RoundRobin URL selection per remote\n  Improve the wording to explain url matching\n\nRelease-Notes: skip\nChange-Id: I7939ec71984a80496f7baf0bb9d86fb749316d7a\n"
    },
    {
      "commit": "33fc916b0425bdbfbba6fc96047de5b5a0bb8777",
      "tree": "9a0d315bfa884b8f7f79ff59eaa71f6d450c92c1",
      "parents": [
        "163612b4daba5f3966d9dc646cb755a654a7bb66",
        "7a8f3429ed555d3576ddc598cf6d6c6ecb453cbd"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu May 28 21:03:23 2026 +0200"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu May 28 22:16:33 2026 +0200"
      },
      "message": "Merge branch \u0027stable-3.12\u0027 into stable-3.13\n\n* stable-3.12:\n  Fix --remote option to replication start\n  Add RoundRobin URL selection per remote\n  Improve the wording to explain url matching\n\nRelease-Notes: skip\nChange-Id: I98294fefeca033b53b0d3bc7c12372656e1c9ec9\n"
    },
    {
      "commit": "7a8f3429ed555d3576ddc598cf6d6c6ecb453cbd",
      "tree": "228cbebd87d0df6b0335e51d30f0af568ec29c03",
      "parents": [
        "4698ef08af7776834fbe14aa859654ac16c45dba",
        "e2c75745275cff5560921917769176431d9a2433"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu May 28 21:00:58 2026 +0200"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu May 28 21:00:58 2026 +0200"
      },
      "message": "Merge branch \u0027stable-3.11\u0027 into stable-3.12\n\n* stable-3.11:\n  Fix --remote option to replication start\n  Add RoundRobin URL selection per remote\n  Improve the wording to explain url matching\n\nRelease-Notes: skip\nChange-Id: Ice84b2af7a2c5d794538fdb2c909942223f8f5c4\n"
    },
    {
      "commit": "57636c9a0273f0671209b9bb8051c42504df1a90",
      "tree": "3b3c511040559764854a2eff4f3d255d87b6dbd8",
      "parents": [
        "fbf435c148d0edded8d37dcb7588e2c28195208d"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Wed May 20 12:32:14 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Wed May 20 12:37:40 2026 -0700"
      },
      "message": "Extract pack-copy logic into ProjectRepairer\n\nMove the pack-copy logic from RepairCommand into a new shared\nProjectRepairer class so it can be reused by other callers (for\nexample, an automated repair flow). RepairCommand now delegates the\nper-destination copy to ProjectRepairer.\n\nChange-Id: I86166730f02bf66963ce603cc929c49fbd895fff\n"
    },
    {
      "commit": "fbf435c148d0edded8d37dcb7588e2c28195208d",
      "tree": "f744a113ce9b374bee3064ae34446b82ddb6a8b7",
      "parents": [
        "19b159df1ccfdd0916d0f5701aa0cacf58507d9f"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Wed May 20 12:31:52 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Wed May 20 12:35:05 2026 -0700"
      },
      "message": "Repair destinations end-to-end in repair command\n\nPreviously, the SSH \u0027repair\u0027 command copied packs to all destinations\nfirst and then issued a single replication start for the project. A\nfailure during the copy phase still left a replication attempt queued\nfor the affected destination, which is not desired. Rework the command\nto drive one destination at a time so that the follow-up replication\nis only triggered when its preceding pack copy succeeds.\n\nChange-Id: Ibcc8cd5ee8a005b0c29d4fe9f4f8e1af96524d32\n"
    },
    {
      "commit": "19b159df1ccfdd0916d0f5701aa0cacf58507d9f",
      "tree": "8f198b89d054fec988c2609bfc1299fc4396881f",
      "parents": [
        "6c7ba5381d40017d64d309ce8babeb7fb1bdb058"
      ],
      "author": {
        "name": "Martin Fick",
        "email": "mfick@nvidia.com",
        "time": "Thu Jul 03 11:35:46 2025 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Tue May 19 12:38:04 2026 -0700"
      },
      "message": "Add explicit project exclusion support\n\nWhile it was previously possible to exclude projects with the \u0027projects\u0027\nkeyword by creating a negative match regular expression, this required\nall the excluded projects to be specified in a single ORed regex which\nis very ugly and error prone. Instead, introduce an explicit keyword,\n\u0027excludeProjects\u0027, which may be specified more than once to handle\nproject exclusions in a straight forward manner.\n\nAlso, bump ReplicationIT test target timeout to long. It defaulted to\nBazel\u0027s \u0027moderate\u0027 timeout bucket (300s). With new test additions in\nthis change, it will reach that ceiling and fail with a timeout. Set\nits \u0027timeout\u0027 to long (900s).\n\nRelease-Notes: Add explicit project exclusion support\nChange-Id: I4e50f923f734537bc32b6a350d3268dbc286d818\n"
    },
    {
      "commit": "6c7ba5381d40017d64d309ce8babeb7fb1bdb058",
      "tree": "46ae6c1059cf60610018254613aaa1c703c7384c",
      "parents": [
        "aa3f6318ff40d11566c3cf181ebeae0fea4b069a"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Tue Mar 24 23:42:25 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Mon May 18 12:39:38 2026 -0700"
      },
      "message": "Add SSH command to repair projects\n\nIntroduce a new \u0027replication repair PROJECT --copy-packs\u0027 SSH command\nthat copies the pack files for a single project to desired destinations\nand then triggers a \u0027replication start\u0027.\n\nChange-Id: Ic9f55e42f195a1261ae076c9fdc9a320b75b292a\n"
    },
    {
      "commit": "aa3f6318ff40d11566c3cf181ebeae0fea4b069a",
      "tree": "dfdd1f86d189b5a92c64627c0d47eeed1a8ffb45",
      "parents": [
        "bdf6d450db1a3524ed48d5d66801396300c43492"
      ],
      "author": {
        "name": "David Ostrovsky",
        "email": "david@ostrovsky.org",
        "time": "Wed May 13 12:47:11 2026 +0200"
      },
      "committer": {
        "name": "David Ostrovsky",
        "email": "david@ostrovsky.org",
        "time": "Fri May 15 12:30:48 2026 +0200"
      },
      "message": "Avoid string concatenation in Flogger log statements\n\nMove shared log message prefixes into log arguments instead of\nconcatenating them at logging sites.\n\nThis keeps format placeholders and arguments validated by Flogger while\npreserving the existing logging behavior for multi-primary setups.\n\nChange-Id: I09d97fa45a294b0f42fec43d935f3597f3cbcf7b\n"
    },
    {
      "commit": "bdf6d450db1a3524ed48d5d66801396300c43492",
      "tree": "7fe69aacc594af3b706742325efc60e443bf53e1",
      "parents": [
        "87a975dd6a62d383fc2d3914162365976123e1c2"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Thu May 07 11:48:30 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Tue May 12 09:04:23 2026 -0700"
      },
      "message": "Support configurable git binary path for SSH remotes\n\nSome SSH destinations may not expose \u0027git\u0027 on the non-interactive\nshell\u0027s PATH, causing \u0027create project\u0027 and \u0027update head\u0027 operations\nto fail. Add a new \u0027remote.NAME.gitPath\u0027 config option that lets\nadmins provide the absolute path to the \u0027git\u0027 binary on the remote\nhost.\n\nChange-Id: I01e32cff5240cb55cf9e0fc0539344b340361ac4\n"
    },
    {
      "commit": "e2c75745275cff5560921917769176431d9a2433",
      "tree": "c28091e20ec611130f1691c84bf1954aa34422c5",
      "parents": [
        "d8ae6cc531c634c5e594470fef5fb4902cb0f048"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Tue May 05 14:48:01 2026 -0700"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@oss.qualcomm.com",
        "time": "Tue May 12 08:41:11 2026 -0700"
      },
      "message": "Fix --remote option to replication start\n\nDeclaring --remote as a \u0027Set\u003cString\u003e\u0027 field trips args4j\u0027s\nSetters.create(), which only treats List, Map, and Arrays as\nmulti-value containers. Use a method-based @Option that adds\neach --remote value into a Set\u003cString\u003e to work around this.\n\nChange-Id: Ic4b4242f3c9ac05b822f2b62141ba34270619f70\n(cherry picked from commit 87a975dd6a62d383fc2d3914162365976123e1c2)\n"
    },
    {
      "commit": "d8ae6cc531c634c5e594470fef5fb4902cb0f048",
      "tree": "c444e79f75d2d238f95cf2a2a9aed5f86e6bdfef",
      "parents": [
        "64ac69d2a6f5f66935ae20d6160f1624de4eb8d4",
        "2bac45ee6400abd7afd1782bb587bda19d7aac20"
      ],
      "author": {
        "name": "Martin Fick",
        "email": "mfick@nvidia.com",
        "time": "Tue May 05 16:02:25 2026 -0700"
      },
      "committer": {
        "name": "Martin Fick",
        "email": "mfick@nvidia.com",
        "time": "Tue May 05 16:16:29 2026 -0700"
      },
      "message": "Merge branch \u0027stable-3.10\u0027 into stable-3.11\n\n* stable-3.10:\n  Improve the wording to explain url matching\n\nRelease-Notes: skip\nChange-Id: Ifbb127d334c5a7c9cb74b5ffb6c64e9f1c7b00ca\n"
    },
    {
      "commit": "87a975dd6a62d383fc2d3914162365976123e1c2",
      "tree": "a35141346b3dc29eea03b7333ba268b69c64a7db",
      "parents": [
        "9b78af806be9cc7131a856f81051ee78d4f8c0e9"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Tue May 05 14:48:01 2026 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "klingarkar@nvidia.com",
        "time": "Tue May 05 14:50:27 2026 -0700"
      },
      "message": "Fix --remote option to replication start\n\nDeclaring --remote as a \u0027Set\u003cString\u003e\u0027 field trips args4j\u0027s\nSetters.create(), which only treats List, Map, and Arrays as\nmulti-value containers. Use a method-based @Option that adds\neach --remote value into a Set\u003cString\u003e to work around this.\n\nChange-Id: Ic4b4242f3c9ac05b822f2b62141ba34270619f70\n"
    },
    {
      "commit": "64ac69d2a6f5f66935ae20d6160f1624de4eb8d4",
      "tree": "89c77e0230bdf1d4cb4f811b8e13eca7cc85ad22",
      "parents": [
        "24b0f4b53a6cd48295a3aa78f57aa4d59531b639"
      ],
      "author": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Fri Apr 24 12:29:21 2026 -0500"
      },
      "committer": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Mon May 04 14:46:20 2026 -0500"
      },
      "message": "Add RoundRobin URL selection per remote\n\nIntroduce a `urlDistributionStrategy` config flag on remote sections.\nWhen set to `roundRobin`, each replication push selects one URL from the\nconfigured list in round-robin order rather than pushing to all URLs\nsimultaneously.\n\nThis is particularly useful in high-availability setups where multiple\nreplica hosts share a single NFS backend. Pushing to all URLs at once\nwould result in redundant writes to the same underlying storage.\nRound-robin distributes push load evenly across hosts while ensuring\neach push is executed exactly once.\n\nChange-Id: Id67cddcf9e7f7a6f47f259eb78b0f53f0977f536\n"
    },
    {
      "commit": "2bac45ee6400abd7afd1782bb587bda19d7aac20",
      "tree": "4f249968d5a9b8bb9aee1b8ca842c31a33c60d6d",
      "parents": [
        "5be3cc55304ebdef853fb43ec184a51f59fdf07f",
        "5aef8b8aa6ffdea9865f2f252b49324d2cff8ced"
      ],
      "author": {
        "name": "Martin Fick",
        "email": "mfick@nvidia.com",
        "time": "Tue Apr 28 14:24:34 2026 -0700"
      },
      "committer": {
        "name": "Martin Fick",
        "email": "mfick@nvidia.com",
        "time": "Tue Apr 28 14:34:05 2026 -0700"
      },
      "message": "Merge branch \u0027stable-3.9\u0027 into stable-3.10\n\n* stable-3.9:\n  Improve the wording to explain url matching\n\nRelease-Notes: skip\nChange-Id: Ie8ac890468c101ea9f4658ad7f9792ca838e7594\n"
    },
    {
      "commit": "9b78af806be9cc7131a856f81051ee78d4f8c0e9",
      "tree": "a074f7a6489c3ad1ff54df8f0b5c028e538978aa",
      "parents": [
        "1af23a265ad1fba98915e69b5bf928a747c5f5c4",
        "163612b4daba5f3966d9dc646cb755a654a7bb66"
      ],
      "author": {
        "name": "Antonio Barone",
        "email": "syntonyze@gmail.com",
        "time": "Mon Apr 27 17:49:23 2026 +0200"
      },
      "committer": {
        "name": "Antonio Barone",
        "email": "syntonyze@gmail.com",
        "time": "Mon Apr 27 17:49:23 2026 +0200"
      },
      "message": "Merge branch \u0027stable-3.13\u0027\n\n* stable-3.13:\n\nChange-Id: I6d695149a9d1120bcfbc8755cbdc89f6c19f6620\n"
    },
    {
      "commit": "163612b4daba5f3966d9dc646cb755a654a7bb66",
      "tree": "fe8cead676835039d341ce81169716cf967f0c63",
      "parents": [
        "8dafd933a883bdd15135a382753e1b9ea447daa0",
        "4698ef08af7776834fbe14aa859654ac16c45dba"
      ],
      "author": {
        "name": "Antonio Barone",
        "email": "syntonyze@gmail.com",
        "time": "Mon Apr 27 17:30:03 2026 +0200"
      },
      "committer": {
        "name": "Antonio Barone",
        "email": "syntonyze@gmail.com",
        "time": "Mon Apr 27 17:30:03 2026 +0200"
      },
      "message": "Merge branch \u0027stable-3.12\u0027 into stable-3.13\n\n* stable-3.12:\n  Add --remote switch to replication start command\n\nChange-Id: Ifa94395155956f48dae777e0e41222a79554afbd\n"
    },
    {
      "commit": "1af23a265ad1fba98915e69b5bf928a747c5f5c4",
      "tree": "a074f7a6489c3ad1ff54df8f0b5c028e538978aa",
      "parents": [
        "d638cebddd6ba09f7adbfe774147eba9f32dd747",
        "4698ef08af7776834fbe14aa859654ac16c45dba"
      ],
      "author": {
        "name": "Antonio Barone",
        "email": "syntonyze@gmail.com",
        "time": "Mon Apr 27 15:44:46 2026 +0200"
      },
      "committer": {
        "name": "Antonio Barone",
        "email": "syntonyze@gmail.com",
        "time": "Mon Apr 27 15:44:46 2026 +0200"
      },
      "message": "Merge branch \u0027stable-3.12\u0027\n\n* stable-3.12:\n  Add --remote switch to replication start command\n\nChange-Id: Ic61ad77a3bb4f4347b2e9488b0dba49af9666c15\n"
    },
    {
      "commit": "4698ef08af7776834fbe14aa859654ac16c45dba",
      "tree": "f2317ec05ba3f1b850ae7a5cf5a62ddbc58e59ad",
      "parents": [
        "b0e7aa63cf3e6ee2afb82d96aa117e38600b0015",
        "24b0f4b53a6cd48295a3aa78f57aa4d59531b639"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Apr 27 14:05:03 2026 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Apr 27 14:05:03 2026 +0100"
      },
      "message": "Merge branch \u0027stable-3.11\u0027 into stable-3.12\n\n* stable-3.11:\n  Add --remote switch to replication start command\n\nChange-Id: I414161edf66faf9de4d2b384b479b338bdcb9880\n"
    },
    {
      "commit": "24b0f4b53a6cd48295a3aa78f57aa4d59531b639",
      "tree": "b24036979653359450be691dfbe5731862fba830",
      "parents": [
        "83e15b020a4693bbc0daa24acf6e08bb9e8f8864"
      ],
      "author": {
        "name": "Adithya Chakilam",
        "email": "achakilam@nvidia.com",
        "time": "Thu Apr 23 15:38:44 2026 -0500"
      },
      "committer": {
        "name": "Adithya C",
        "email": "achakilam@nvidia.com",
        "time": "Thu Apr 23 19:11:23 2026 -0700"
      },
      "message": "Add --remote switch to replication start command\n\nAllow specifying one or more remote names to limit replication to\nthose destinations, without needing to know their URLs.\n\nUnlike --url which does substring matching on the URL, --remote\nmatches the exact remote name as configured in replication.config.\n\nChange-Id: I9db7a195d7a1ea8bef92d008a76386a01d0c9286\n"
    },
    {
      "commit": "d638cebddd6ba09f7adbfe774147eba9f32dd747",
      "tree": "4770ea8af868763b102144d0ace404050fc8c571",
      "parents": [
        "8dafd933a883bdd15135a382753e1b9ea447daa0"
      ],
      "author": {
        "name": "Thomas Dräbing",
        "email": "thomas.draebing@sap.com",
        "time": "Fri Dec 19 09:00:11 2025 +0100"
      },
      "committer": {
        "name": "Thomas Dräbing",
        "email": "thomas.draebing@sap.com",
        "time": "Tue Apr 07 14:10:08 2026 +0200"
      },
      "message": "Use of gerrit_plugin and gerrit_plugin_tests rules from bazlets\n\nChange-Id: If0c4d82b3f77cedccf94b6b74f775176a9d0bf6d\n"
    },
    {
      "commit": "5aef8b8aa6ffdea9865f2f252b49324d2cff8ced",
      "tree": "71ccc70105e8ac43ea155dd6402e3c6e06f7570b",
      "parents": [
        "5cfb07aa0e1e133a066ae81951b8e156d7dfd4e4"
      ],
      "author": {
        "name": "Martin Fick",
        "email": "mfick@nvidia.com",
        "time": "Fri Dec 05 11:47:28 2025 -0800"
      },
      "committer": {
        "name": "Martin Fick US",
        "email": "mfick@nvidia.com",
        "time": "Fri Feb 27 11:43:24 2026 -0800"
      },
      "message": "Improve the wording to explain url matching\n\nEverytime I use this switch I struggle and end up having to look a the\ncode to figure out how it works. Help clarify how the match works.\n\nChange-Id: I1001e83d677483bf8372febc4cc6f3eea15b8341\n"
    },
    {
      "commit": "8dafd933a883bdd15135a382753e1b9ea447daa0",
      "tree": "c50542badd3bff28ac87c32032cda7030104f1dc",
      "parents": [
        "5fc8c9e190b9427a864227c55bb4e7cb1ba93c8b"
      ],
      "author": {
        "name": "David Ostrovsky",
        "email": "david@ostrovsky.org",
        "time": "Mon Jan 05 14:29:04 2026 +0000"
      },
      "committer": {
        "name": "David Ostrovsky",
        "email": "david@ostrovsky.org",
        "time": "Mon Jan 05 14:31:00 2026 +0000"
      },
      "message": "Replace legacy non-Javadoc comment with {@inheritDoc}\n\nChange-Id: I3cf468b60ba4bfb8e948a17681cd6ab91df62f2a\n"
    },
    {
      "commit": "5fc8c9e190b9427a864227c55bb4e7cb1ba93c8b",
      "tree": "fa2e02d4ca90b21e32a27b17b8cb4b7459aa31b4",
      "parents": [
        "b859e22bbcfbafb2237daf5302b9118917e4747e"
      ],
      "author": {
        "name": "David Ostrovsky",
        "email": "david@ostrovsky.org",
        "time": "Mon Jan 05 14:24:07 2026 +0000"
      },
      "committer": {
        "name": "David Ostrovsky",
        "email": "david@ostrovsky.org",
        "time": "Mon Jan 05 14:30:37 2026 +0000"
      },
      "message": "Suppress UnnecessaryAssignment in withBaseOnly factory method\n\nwithBaseOnly() intentionally assigns an @Inject field to support an\nalternate construction path. Suppress Error Prone\u0027s\nUnnecessaryAssignment warning for this method.\n\nChange-Id: I30cc92f830d562d87bd0437d8ac374ed0a2f7295\n"
    },
    {
      "commit": "b859e22bbcfbafb2237daf5302b9118917e4747e",
      "tree": "5a710e69d283ea54b8412aba77566b062b2a9d3d",
      "parents": [
        "fbd8be05f18a18aba10661be97b07435167c1788"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Dec 11 08:36:14 2025 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Dec 11 01:00:16 2025 -0800"
      },
      "message": "Introduce an educated guess comment on why reflog is disabled on replicas\n\nWhen repositories are replicated, their reflog is turned off on the\nreplica side. Add a comment explaining why that choice was possibly made\nover a decade ago.\n\nThe author of the change is Shawn who passed years ago. The change did\nnot go through reviews at that time so there is no track record of the\nchoice.\n\nChange-Id: I04de480df0d6012e3a4539fda945d15fc3f4eaa3\n"
    },
    {
      "commit": "fbd8be05f18a18aba10661be97b07435167c1788",
      "tree": "21e8b7e07180467408ed6ab52bf9e513369ec249",
      "parents": [
        "ead0da3314f71a334400e3bbb140998c15554fec"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Nov 28 15:31:46 2025 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Dec 11 01:00:04 2025 -0800"
      },
      "message": "Allow to specify whether to store reflog for new projects\n\nIntroduce a new remote.NAME.storeRefLog for configuring the\ncore.logallrefupdates in the new repository\u0027s config file when it is\ncreated by replication.\n\nRelease-Notes: Allow configuring the reflog for newly created repositories with remote.NAME.storeRefLog config.\nBug: Issue 464210139\nChange-Id: Ia14a4b5829cceb226a537c0651d08f2057fce8aa\n"
    },
    {
      "commit": "ead0da3314f71a334400e3bbb140998c15554fec",
      "tree": "d173d3aa93797faee8b8bb9b48c8398529176147",
      "parents": [
        "071e64c36ef8028e59947c570f9bc71c8092b86f"
      ],
      "author": {
        "name": "Thomas Dräbing",
        "email": "thomas.draebing@sap.com",
        "time": "Tue Nov 25 11:37:28 2025 +0100"
      },
      "committer": {
        "name": "Thomas Dräbing",
        "email": "thomas.draebing@sap.com",
        "time": "Mon Dec 01 15:09:31 2025 +0100"
      },
      "message": "Fix error_prone pattern AssertEqualsArgumentOrderChecker\n\nChange-Id: I98d9a8bff87189e2c2349dbcd27fc8ce05263442\n"
    },
    {
      "commit": "071e64c36ef8028e59947c570f9bc71c8092b86f",
      "tree": "9010b33325dcd521bcdab92d9fa3c5e92ba4ab75",
      "parents": [
        "00228d21334cd67fd029eb5322eea66e6c555665"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Nov 28 15:20:33 2025 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Nov 28 09:54:33 2025 -0800"
      },
      "message": "Remove redundant public modifier in AdminApi interface\n\nChange-Id: I5296d802a857466d5267e9b77879760efbe1abf8\n"
    },
    {
      "commit": "00228d21334cd67fd029eb5322eea66e6c555665",
      "tree": "e849b9388370f5536f508083ec8675e0f3fe111a",
      "parents": [
        "b62454c285f78f23996864c9f920473f8f3d0f6a"
      ],
      "author": {
        "name": "Jacek Centkowski",
        "email": "geminica.programs@gmail.com",
        "time": "Fri Oct 31 07:30:07 2025 +0100"
      },
      "committer": {
        "name": "Jacek Centkowski",
        "email": "geminica.programs@gmail.com",
        "time": "Sun Nov 02 15:21:06 2025 +0100"
      },
      "message": "Catch `URISyntaxException` in TestUriUpdates constructor\n\nAnd retrow as RuntimeException so that it doesn\u0027t have to be caught in\ntests (sometimes with empty catch block that is being flagged as ERROR\nafter migration to newer errorprone).\n\nBug: Issue 303819949\nChange-Id: Ia7a9427f0472bb464104ed7cc24b850e08869118\n"
    },
    {
      "commit": "b62454c285f78f23996864c9f920473f8f3d0f6a",
      "tree": "a4f652e8a8f4782caf460a6476821a6ec7f6582b",
      "parents": [
        "721b87a89e3a1bd2c368e051dec12445697680c5",
        "79b50b0020bfc69d863bbd5811baadec3c8a19d2"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@oss.qualcomm.com",
        "time": "Mon Jul 07 12:35:04 2025 -0700"
      },
      "committer": {
        "name": "Gerrit Code Review",
        "email": "noreply-gerritcodereview@google.com",
        "time": "Mon Jul 07 12:35:04 2025 -0700"
      },
      "message": "Merge \"docs/config: document inverted matches cancel each others\""
    },
    {
      "commit": "79b50b0020bfc69d863bbd5811baadec3c8a19d2",
      "tree": "ee09096d290885fcfeefd619ceaa4b4783113a00",
      "parents": [
        "ede3010e0455b7ce68da62695a5eeb76e7cff420"
      ],
      "author": {
        "name": "Antoine Musso",
        "email": "hashar@free.fr",
        "time": "Thu Apr 17 12:37:00 2025 +0200"
      },
      "committer": {
        "name": "Antoine Musso (hashar)",
        "email": "hashar@free.fr",
        "time": "Wed Jul 02 01:02:55 2025 -0700"
      },
      "message": "docs/config: document inverted matches cancel each others\n\nOur config had two inverted matches to exclude projects:\n\n  [remote \"github\"]\n    projects \u003d ^(?:(?!apps\\\\/android\\\\/).)*$\n    projects \u003d ^(?:(?!apps\\\\/ios\\\\/).)*$\n\nI have been wondering why `apps/android/wikipedia` is excluded given it\nmatches the first regex. The reason is ReplicationFilter applies each\npattern and when one matches it accepts the project. In this case, the\nproject is matched by the second and is thus accepted.\n\nRef: https://phabricator.wikimedia.org/T392198\nChange-Id: I2846a40d2aabe80c0db305dc4f64dd1aa885b07d\n"
    },
    {
      "commit": "721b87a89e3a1bd2c368e051dec12445697680c5",
      "tree": "ae9ede5809abcf82468d573f1b2c6403b1998d70",
      "parents": [
        "38a79f76b4432679b69736dd7cea4ed254a6f09d",
        "b0e7aa63cf3e6ee2afb82d96aa117e38600b0015"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 01 10:54:12 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 01 10:54:12 2025 +0100"
      },
      "message": "Merge branch \u0027stable-3.12\u0027\n\n* stable-3.12:\n  Fix concurrent pushes to the same target URI\n\nChange-Id: I04170e0108bca0d17be8b75a1198fc565cb1fccc\n"
    },
    {
      "commit": "b0e7aa63cf3e6ee2afb82d96aa117e38600b0015",
      "tree": "5e546deba4d82594a02f7efd9f4d002e25fbec6f",
      "parents": [
        "e94dfc98f0d68f2699daf43dc3ee56b18a4c9fc7",
        "83e15b020a4693bbc0daa24acf6e08bb9e8f8864"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 01 10:53:46 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 01 10:53:46 2025 +0100"
      },
      "message": "Merge branch \u0027stable-3.11\u0027 into stable-3.12\n\n* stable-3.11:\n  Fix concurrent pushes to the same target URI\n\nChange-Id: I7b5778de0a757023180e5d02f934bbf57e354936\n"
    },
    {
      "commit": "83e15b020a4693bbc0daa24acf6e08bb9e8f8864",
      "tree": "c34bcfa51d05a50120c903c6aad5b970e2503cd3",
      "parents": [
        "d29aa0d4cf02690e224ca3c896716f5d4f433b38"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Jun 30 19:12:10 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 01 00:59:11 2025 -0700"
      },
      "message": "Fix concurrent pushes to the same target URI\n\nWhen performing the refactoring of stripe locks, the runway request was\noverlooked and completely ignored, leading to all tasks being allowed to\nbe executed concurrently with existing pushes on the runway.\n\nThe issue has created significant overload on the replication plugin for\nhigh-load repositories, where the rate of replication events scheduled\nis higher than the push time.\n\nBug: Issue 428670066\nRelease-Notes: Fix the prevention of concurrent PushOps the same target URI when using multiple threads\nChange-Id: I6863944e997e3541186dfc13cab0d7add29b7805\n"
    },
    {
      "commit": "38a79f76b4432679b69736dd7cea4ed254a6f09d",
      "tree": "b99c70121c438f59ca80419648c5cbda7e5f8db0",
      "parents": [
        "9522db215bbdd9cb23220da7d4402ffe027c008b",
        "e94dfc98f0d68f2699daf43dc3ee56b18a4c9fc7"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 20 15:32:46 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 20 15:32:46 2025 +0100"
      },
      "message": "Merge branch \u0027stable-3.12\u0027\n\n* stable-3.12:\n  Make excludedRefsPattern() to return an empty list by default\n  Do not push deletes for refs configured to be skipped\n  Add a remote config to exclude replicating desired refs\n  Auto-format source code using gjf\n\nChange-Id: I57e2f34aa6b3012d2aaca69ac13899ab2bc392c2\n"
    },
    {
      "commit": "e94dfc98f0d68f2699daf43dc3ee56b18a4c9fc7",
      "tree": "d4ed1e0433e1c713a6d2e8e8bb2bd1a6a8db447f",
      "parents": [
        "ede3010e0455b7ce68da62695a5eeb76e7cff420",
        "d29aa0d4cf02690e224ca3c896716f5d4f433b38"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 20 15:19:32 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 20 15:24:08 2025 +0100"
      },
      "message": "Merge branch \u0027stable-3.11\u0027 into stable-3.12\n\n* stable-3.11:\n  Make excludedRefsPattern() to return an empty list by default\n  Do not push deletes for refs configured to be skipped\n  Add a remote config to exclude replicating desired refs\n  Auto-format source code using gjf\n\nChange-Id: I0b5d42ee5e0f6cc342ef2947d209f89edbaf2c76\n"
    },
    {
      "commit": "d29aa0d4cf02690e224ca3c896716f5d4f433b38",
      "tree": "09148f8970785eae8b4728910c2e05880eec77b7",
      "parents": [
        "12f3a1abd0f112adac582c2c17a9beae217b5ffd",
        "5be3cc55304ebdef853fb43ec184a51f59fdf07f"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 20 15:16:18 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 20 15:16:18 2025 +0100"
      },
      "message": "Merge branch \u0027stable-3.10\u0027 into stable-3.11\n\n* stable-3.10:\n  Make excludedRefsPattern() to return an empty list by default\n  Do not push deletes for refs configured to be skipped\n\nChange-Id: Icab5579c4d3f1d8c8d2fac06492d063f6cab03d9\n"
    },
    {
      "commit": "5be3cc55304ebdef853fb43ec184a51f59fdf07f",
      "tree": "c1d881a7293af34b166b35ae6a1546cdff51e6e0",
      "parents": [
        "f01716cb201ba38178d817701665ecf315ef926c"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 19 23:17:42 2025 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 19 23:22:18 2025 +0100"
      },
      "message": "Make excludedRefsPattern() to return an empty list by default\n\nThe extension of the replication endpoints configuration done\nwith I42366148cfb1f introduced a breaking change that made other\nplugins (e.g. pull-replication) to fail.\n\nRestore a backward compatible implementation of the new\nexcludedRefPattern configuration and amend the documentation to\nspecify that is empty by default.\n\nChange-Id: Iee92281ed41ca70819de783b3563832363c245fb\n"
    },
    {
      "commit": "f01716cb201ba38178d817701665ecf315ef926c",
      "tree": "731d6645129a00d86504c93bef4be72fbb39bfb3",
      "parents": [
        "4161f94990ee146fd78789b96a3a4729a584a5d4"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasserg@qti.qualcomm.com",
        "time": "Fri Jun 06 16:18:06 2025 -0700"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasserg@qti.qualcomm.com",
        "time": "Fri Jun 06 16:33:56 2025 -0700"
      },
      "message": "Do not push deletes for refs configured to be skipped\n\nWhen pushing a delta set of refs, instead of treating non-existent and\n!canPush() refs the same, use the same logic as when pushing all refs\nand log and skip any !canPush() refs.\n\nRelease-Notes: refs configured to be skipped are not pushed as deletes\nChange-Id: I3491c907580b16ea23493a5eaa325d2ef7d6d108\n"
    },
    {
      "commit": "12f3a1abd0f112adac582c2c17a9beae217b5ffd",
      "tree": "9958aee6f37e8485783fc00681d29c81dcfcb7b1",
      "parents": [
        "0af31d2a5df62329162a750beec2e9dc0adf8e72",
        "4161f94990ee146fd78789b96a3a4729a584a5d4"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasserg@qti.qualcomm.com",
        "time": "Thu Jun 05 13:01:22 2025 -0700"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasserg@qti.qualcomm.com",
        "time": "Thu Jun 05 13:01:22 2025 -0700"
      },
      "message": "Merge branch \u0027stable-3.10\u0027 into stable-3.11\n\n* stable-3.10:\n  Add a remote config to exclude replicating desired refs\n  Auto-format source code using gjf\n\nChange-Id: I0ba471d5649b5852c57e40244353210dbc330ecc\n"
    },
    {
      "commit": "4161f94990ee146fd78789b96a3a4729a584a5d4",
      "tree": "f6cf2ef887b6c9a8aa1729039d738ccaf2a4032e",
      "parents": [
        "28ea10317799d065fa511036220fb33d20fc7d5e"
      ],
      "author": {
        "name": "Kaushik Lingarkar",
        "email": "kaushikl@qti.qualcomm.com",
        "time": "Fri May 30 14:56:25 2025 -0700"
      },
      "committer": {
        "name": "Kaushik Lingarkar",
        "email": "kaushikl@qti.qualcomm.com",
        "time": "Mon Jun 02 11:08:09 2025 -0700"
      },
      "message": "Add a remote config to exclude replicating desired refs\n\nAllow admins to exclude specific refs from replication when they are\nnot needed on replicas. For instance, refs created by certain plugins\ncan now be skipped. This config helps improve replication performance\nand stability, especially on busy servers that create a large number\nof such unwanted refs.\n\nChange-Id: I42366148cfb1f9da35904ad8e07d3fc103966a53\n"
    },
    {
      "commit": "28ea10317799d065fa511036220fb33d20fc7d5e",
      "tree": "3cacab670de3dc773be5a56cc0c9d97620049a53",
      "parents": [
        "9a750e2384ccb8975560b4ca76b9b92c535362af"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Fri Mar 07 02:10:16 2025 +0100"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasserg@qti.qualcomm.com",
        "time": "Fri May 30 15:54:09 2025 -0700"
      },
      "message": "Auto-format source code using gjf\n\nChange-Id: I73004740248ec95eaa02a7dbe1a483c5f2abc528\n(cherry picked from commit 729e562946ae7357774c9e8572ef9052c15a6e9e)\n"
    },
    {
      "commit": "9522db215bbdd9cb23220da7d4402ffe027c008b",
      "tree": "c15afbaa8524f46ffbc7de3b50c37c5dbbcf1edd",
      "parents": [
        "ede3010e0455b7ce68da62695a5eeb76e7cff420"
      ],
      "author": {
        "name": "Thomas Dräbing",
        "email": "thomas.draebing@sap.com",
        "time": "Fri Feb 07 15:55:07 2025 +0100"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Sat Mar 22 23:05:23 2025 +0100"
      },
      "message": "Add support for JSON-formatted replication_log\n\nChange-Id: Ifaa2c4b331b2898ae780eec041d34dc4f44d34b1\n"
    },
    {
      "commit": "ede3010e0455b7ce68da62695a5eeb76e7cff420",
      "tree": "2b1b58ecc466b20366dadf18c576f3331c9ed77c",
      "parents": [
        "729e562946ae7357774c9e8572ef9052c15a6e9e"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Wed Mar 12 14:18:38 2025 +0100"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Wed Mar 12 14:20:22 2025 +0100"
      },
      "message": "Ensure ExecutorService used in test is shutdown\n\nChange-Id: Ic757b4cc1edb5c02b4be8c9ef7abfaaaf63ac410\n"
    },
    {
      "commit": "729e562946ae7357774c9e8572ef9052c15a6e9e",
      "tree": "7a480134f658c3901c76423e35ecff3401a79173",
      "parents": [
        "a9f44a14c64efaa44afdf8f553a3b3211ef4342b"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Fri Mar 07 02:10:16 2025 +0100"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Fri Mar 07 02:10:16 2025 +0100"
      },
      "message": "Auto-format source code using gjf\n\nChange-Id: I73004740248ec95eaa02a7dbe1a483c5f2abc528\n"
    },
    {
      "commit": "a9f44a14c64efaa44afdf8f553a3b3211ef4342b",
      "tree": "6b9f41e09b8769c3415c63ff7d652cd39db27767",
      "parents": [
        "62218e2cd25b7c0c2e4086109770765eb7d093bf"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Feb 10 21:42:47 2025 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Feb 10 23:25:59 2025 +0000"
      },
      "message": "Use try-with-resource to close Repository in PushOne\n\nPushOne used an instance variable to store and share\nthe Repository object across the intermediate invocations\nof its internal push phases.\n\nUsing an instance variable for Repository is causing\nflakiness as it may not be properly cleaned up as also\nshown in the tests executions with reference counting\nenforced checks introduced with I303706438.\n\nChange-Id: Ibb2fe90ae714e0be3a4f272fa992a555e2bf145f\n"
    },
    {
      "commit": "62218e2cd25b7c0c2e4086109770765eb7d093bf",
      "tree": "42a036271f9527090cbbef36c6aa39306e45d65b",
      "parents": [
        "1138cb1645f68aa04cc4c067e204616a416fb650"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Feb 03 20:46:03 2025 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Feb 03 20:46:30 2025 +0000"
      },
      "message": "Remove duplicate sitePaths already injected in AbstractDaemonTest\n\nRelease-Notes: skip\nChange-Id: I027dc29e1836aca39b5808c7dc3234b4f4ce1a78\n"
    },
    {
      "commit": "1138cb1645f68aa04cc4c067e204616a416fb650",
      "tree": "4039f6fd03674e17e712826a416da0e863b9b0c0",
      "parents": [
        "0af31d2a5df62329162a750beec2e9dc0adf8e72"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Sun Feb 02 15:11:25 2025 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Sun Feb 02 15:13:44 2025 +0000"
      },
      "message": "Avoid casting RepositoryManager to LocalDiskRepositoryManager\n\nInject directly the expected class of LocalDiskRepositoryManager\nwithout assuming that the one provided by the AbstractDaemonTest.\n\nThe Change I8d288fa3 will replace the repository manager\nwith a wrapping repository tracking system, therefore the casting\nmay not be satisfied anymore and it may fail at runtime.\n\nRelease-Notes: skip\nChange-Id: I8e410ae6a489b1127ef09d4c203ab9aa1d711d8d\n"
    },
    {
      "commit": "0af31d2a5df62329162a750beec2e9dc0adf8e72",
      "tree": "306c36bf6a5e45b115762fcefbac32c293df799f",
      "parents": [
        "90c64204e1e27ec245f41b3d08b10f431dd72faf"
      ],
      "author": {
        "name": "Alvaro Vilaplana Garcia",
        "email": "alvaro.vilaplana@gmail.com",
        "time": "Wed Nov 13 15:35:29 2024 +0000"
      },
      "committer": {
        "name": "Alvaro Vilaplana Garcia",
        "email": "alvaro.vilaplana@gmail.com",
        "time": "Thu Nov 14 16:23:36 2024 +0000"
      },
      "message": "Fix PushOne toString() to show the right refs and hidden number\n\nInclude all refs without applying any limit when `maxRefsToShow`\nis set to 0 and limit the displayed refs to the specified maximum\nwhen `maxRefsToShow` is greater than 0. Previously, the method\nalways limited the number of refs to `maxRefsToShow`, and\n`maxRefsToShow` was updated to the batch count when initially\nset to 0.\n\nRemove the calculation of hidden refs to avoid performance\nissues with millions of refs.\n\nBug: Issue 375798125\nRelease-Notes: skip\nChange-Id: I30aae0cebf4fe28309542808baeeb316e1e7fb52\n"
    },
    {
      "commit": "90c64204e1e27ec245f41b3d08b10f431dd72faf",
      "tree": "a4176bace562960fa83155feb324f97cc2a05e12",
      "parents": [
        "60693efae661105fb6278c16cae9502d29bfa7f3",
        "9a750e2384ccb8975560b4ca76b9b92c535362af"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Fri Oct 11 23:06:55 2024 -0700"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Fri Oct 11 23:10:11 2024 -0700"
      },
      "message": "Merge branch \u0027stable-3.10\u0027\n\n* stable-3.10:\n  synchronizePendingEvents: Fix stuck replaying flag\n\nRelease-Notes: skip\nChange-Id: If0a080b81639d072cf20828e4cd6c9cbce010a8d\n"
    },
    {
      "commit": "9a750e2384ccb8975560b4ca76b9b92c535362af",
      "tree": "443a68b5fd341efe98be0d22a95df555841d3d46",
      "parents": [
        "445cd037108a9ad478c187aeb31cb14a8e889a0f",
        "5cfb07aa0e1e133a066ae81951b8e156d7dfd4e4"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Fri Oct 11 23:00:23 2024 -0700"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Fri Oct 11 23:01:40 2024 -0700"
      },
      "message": "Merge branch \u0027stable-3.8\u0027 into stable-3.10\n\n* stable-3.8:\n  synchronizePendingEvents: Fix stuck replaying flag\n\nRelease-Notes: skip\nChange-Id: I277e4bbfefee4895615976d1b26440d55a1eef58\n"
    },
    {
      "commit": "5cfb07aa0e1e133a066ae81951b8e156d7dfd4e4",
      "tree": "8734ccd523c5d66708f33181cd07531fb676ed67",
      "parents": [
        "584aea1a8968a9162d78460422a285a87910f502"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Wed Oct 09 14:31:15 2024 -0700"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Wed Oct 09 14:31:15 2024 -0700"
      },
      "message": "synchronizePendingEvents: Fix stuck replaying flag\n\nSimilar to change I4628a574, the replaying flag has a chance to become\nstuck as true if an exception is thrown while accumulating prunable\nreplication tasks, which happens before the earlier fix is relevant.\nCatch and log the exception and continue since synchronizing with a\nsubset of prunable tasks isn\u0027t much of a problem.\n\nChange-Id: I935c3252e8c3da63ac248b051380558b749ea76e\nRelease-Notes: Fixed chance for exceptions to block future distributor runs\n"
    },
    {
      "commit": "60693efae661105fb6278c16cae9502d29bfa7f3",
      "tree": "e8c730ff6f8244fc7d23edeec9ba307b5019c99b",
      "parents": [
        "660fcd4caca607625728f7d2066478f7ce0c1468"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Tue Apr 02 01:06:18 2024 +0200"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Mon Sep 16 13:23:57 2024 +0200"
      },
      "message": "Destination: extract StateLock class to simplify lock handling\n\nChange-Id: If46d2b1ece73e32a7463c02988ccd1d4e2f769aa\n"
    },
    {
      "commit": "660fcd4caca607625728f7d2066478f7ce0c1468",
      "tree": "e9a9056cf9625d411d43c98874aac6bc34aaf908",
      "parents": [
        "cf0aea56d2efad79bcb84df37edc32c01bf8afb7"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Sun Mar 31 00:41:53 2024 +0100"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Mon Sep 16 13:18:50 2024 +0200"
      },
      "message": "Destination: use striped lock to reduce lock contention\n\nDestination used a single lock to serialize pushes to the same\ndestination. When many repositories are replicated via one\ndestination this may cause lock contention and unnecessarily\nthrottle replication throughput.\n\nHence use a striped lock with up to 16 stripes to reduce lock\ncontention but still serialize replication per repository.\nDon\u0027t use more stripes than the number of projects to be\nreplicated if the projects are configured explicitly.\n\nAvoid copying the pending and in-flight maps of PushOnes to be\nexecuted for reading them. Instead directly access the maps held\nby a destination and use thread-safe ConcurrentHashMaps for both.\n\nChange-Id: I0ad2f51249ffba429fc61b422056fa85d88b1de4\n"
    },
    {
      "commit": "cf0aea56d2efad79bcb84df37edc32c01bf8afb7",
      "tree": "2b6fc3a74a6614534f1f14c3525a4dbd59b47f45",
      "parents": [
        "3982574d28f254b525b093c2ecae8caa47825910",
        "445cd037108a9ad478c187aeb31cb14a8e889a0f"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 17:25:15 2024 -0600"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 17:25:15 2024 -0600"
      },
      "message": "Merge branch \u0027stable-3.10\u0027\n\n* stable-3.10:\n  PushOne: Remove unused addRef() method\n  TasksStorage: Remove synchronized from methods\n  Place the replaying flag clearing in a finally\n  Demote delete errors when distributor is enabled\n  distributor: Reduce log level for no-op consolidations\n\nChange-Id: I3ce1519c44ec6cbae7725527ea626e55401cc488\nRelease-Notes: skip\n"
    },
    {
      "commit": "445cd037108a9ad478c187aeb31cb14a8e889a0f",
      "tree": "abbfbbff20f2382c23ded30586e9a18fd3951290",
      "parents": [
        "56b8ffbab5bf619c0b6b5d44f0255fd41b9e1c89",
        "584aea1a8968a9162d78460422a285a87910f502"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 16:58:06 2024 -0600"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 16:58:06 2024 -0600"
      },
      "message": "Merge branch \u0027stable-3.8\u0027 into stable-3.10\n\n* stable-3.8:\n  PushOne: Remove unused addRef() method\n  TasksStorage: Remove synchronized from methods\n  Place the replaying flag clearing in a finally\n  Demote delete errors when distributor is enabled\n  distributor: Reduce log level for no-op consolidations\n\nChange-Id: I15eb65d0f379a6e562d3c86e1089cfb7d9e6752c\nRelease-Notes: skip\n"
    },
    {
      "commit": "584aea1a8968a9162d78460422a285a87910f502",
      "tree": "c29d833faa4fec69e9040218bde42f4e213381ca",
      "parents": [
        "0ef3c3437366b126c5e04f76a4fc47932bf4e8ca",
        "694b34084ca623756a9ec7e6a60631ab6027d5c2"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 14:24:41 2024 -0600"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 14:24:41 2024 -0600"
      },
      "message": "Merge branch \u0027stable-3.5\u0027 into stable-3.8\n\n* stable-3.5:\n  TasksStorage: Remove synchronized from methods\n  Place the replaying flag clearing in a finally\n  Demote delete errors when distributor is enabled\n  distributor: Reduce log level for no-op consolidations\n\nChange-Id: Iaa6d4a59d5cb26879500f2d36852eaa30efc5d7b\nRelease-Notes: skip\n"
    },
    {
      "commit": "0ef3c3437366b126c5e04f76a4fc47932bf4e8ca",
      "tree": "56372d895f4e220236d089f69918d5e199ca1aa3",
      "parents": [
        "8fd3c271ce0a21480e3d04da5ad2112efea3bedf"
      ],
      "author": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 13:54:55 2024 -0600"
      },
      "committer": {
        "name": "Nasser Grainawi",
        "email": "nasser.grainawi@linaro.org",
        "time": "Mon Jul 29 13:54:55 2024 -0600"
      },
      "message": "PushOne: Remove unused addRef() method\n\nThis is only used by tests and should have been removed when\naddRefBatch() superseded it.\n\nChange-Id: If9de1df29fd56a595fa4d4b2b4f5716264a67e11\nRelease-Notes: skip\n"
    },
    {
      "commit": "3982574d28f254b525b093c2ecae8caa47825910",
      "tree": "1f0e421b4045efc95c764d5eb2c9f3d39668bc8a",
      "parents": [
        "eac5d4e844c6103b37e8d35ee1ef3eb5ddf117ea"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 09 19:46:42 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 09 19:52:12 2024 +0000"
      },
      "message": "Fix FanoutConfigurationResource update API\n\nWhen updating the FanoutConfigurationResource, the remote subsection\nneeds to be removed as the subsection name is part of the config\nfilename.\n\nBug: Issue 351843807\nChange-Id: Ib434a434a82de7e237387c7d7df8eb0e78cfa5a6\n"
    },
    {
      "commit": "eac5d4e844c6103b37e8d35ee1ef3eb5ddf117ea",
      "tree": "aea0930aa001d0b1cfe12fcc52901f8fef688b26",
      "parents": [
        "69c66c8919533635bb7ef36cdd660f48f6647c09"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Sat Jul 06 00:57:20 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 09 19:51:55 2024 +0000"
      },
      "message": "Delay the fetching of credentials until push time\n\nThe replication plugin can be configured to reload dynamically\nthe credentials when changed on the filesystem or in the SecureStore\nbackend.\n\nThe overall reloading mechanism worked as long as a new PushOne\nobject was created per replication task; however, when a push was\nfailing because of credentials issues, the PushOne object was\nrequeued without being recreated, causing a chicken \u0026 egg situation\n\nUntil the PushOne was retried, the old credentials were stored\nin the instance and therefore any retry would have failed.\nEven though the replication.config was configured for reloading\ndynamically the credentials, any task stuck in retry would have\nnot been able to pass the correct credentials.\n\nDelay the creation of the credentials provider until push\ntime, so that even in case of retrying replication tasks\nthe credentials can be dynamically reloaded when changed\non the filesystem.\n\nChange-Id: I2f069a8433651a0db2681b6675f392ff894f27fc\n"
    },
    {
      "commit": "69c66c8919533635bb7ef36cdd660f48f6647c09",
      "tree": "dfc7de5dfa2228756d2740d186e7dc3d82369829",
      "parents": [
        "69c0c4dd67a942f42cb36ed3f89e4257d7de575e"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jul 05 22:08:04 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jul 09 20:46:09 2024 +0100"
      },
      "message": "Improve FanoutConfigurationResource loading performance\n\nWhen using replication remotes as individual files under\n$GERRIT_SITE/etc/replication the time requested to load the remotes,\nparsing them and merging them together can be very significant,\nespecially when having a lot of remote configurations.\n\nOn GerritHub.io with 12k remotes configured, the time to load,\nparse and merge them in a unique FileBasedConfig object reaches\nseveral minutes.\n\nThe main issue found during profiling is the manual merging of\nConfig through one call per setting using Config.setStringList()\nrather than merging them first and then parsing them as a whole.\n\nRefactor the overall parsing logic by splitting the process in\nthree parts:\n- load of all replication remotes a list of String\n- expanding them as individual strings and adding the remote names\n- merging them together with the base config using the JGit\u0027s\n  default mechanism\n\nFrom an external perspective, the API work exactly as before, including\nthe config validation process; from a performance perspective, the\nloading of 12k remotes is reduced by 20x times, taking under 1 minute.\n\nChange-Id: I2880428b881034e6253d07ab0ba368c0a97eecc0\n"
    },
    {
      "commit": "69c0c4dd67a942f42cb36ed3f89e4257d7de575e",
      "tree": "f23ccc62a8be4d77e7fe11d54649d5a18d3a9fcf",
      "parents": [
        "05c096ed827467645776abcec6b39523b4e76843"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jul 05 22:01:34 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Jul 08 22:10:16 2024 +0100"
      },
      "message": "FanoutConfigResourceTest: assert configuration updates being visible\n\nWhen updating a remote configuration using the FanoutConfigResource,\nthe updated values should be also visible in-memory and not simply\nstored on the underlying filesystem.\n\nFix an issue where the updates to the remotes performed using\n$GERRIT_SITE/etc/replication/remote.config fan-out config scheme\nwas persisted on disk but left a stale in-memory copy.\n\nChange-Id: I2360ba447ffbc3695faad72e5674ca883f75081a\n"
    },
    {
      "commit": "05c096ed827467645776abcec6b39523b4e76843",
      "tree": "54ac17bdcfc08a6f48664f95042aa3573b3724e5",
      "parents": [
        "2e2a6415a979e74e454a11e6e1637cb0d9d7a20a"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 27 23:35:36 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 28 22:02:53 2024 +0000"
      },
      "message": "Move ReplicationQueue and associated bindings to ReplicationModule\n\nDuring the refactoring in I8003ec6c827f the ReplicationQueue and its\nassociated bindings were moved to the ReplicationConfigModule for\nallowing the users of the replication APIs to be able to have the\nfull bindings of all the internal replication plugin mechanisms.\n\nHowever, the change was reverted in I461cd1bef because of the\nbreakages generated and later a new approch has been introduced\nwith I349461e29d where the APIs are exposed via DynamicItem\u003c\u003e\nand the caller isn\u0027t required anymore to have the full Guice\nbindings to re-create the replication objects.\n\nAs a result, the bindings of the replication plugin internals\nremained in the ReplicationConfigModule with nasty consequences\nof other plugins (e.g. pull-replication) to inadvertently generate\njust-in-time bindings of the replication plugin classes.\n\nWhen using the pull-replication and replication plugins together\nthe just-in-time bindings would then eventually conflict\nwith the explicit bindings done in the replication plugin.\n\nExample:\n\n[2024-06-27T22:23:19.471+01:00] [main] WARN  com.google.gerrit.server.plugins.PluginLoader : Cannot load plugin replication\ncom.google.inject.CreationException: Unable to create injector, see the following errors:\n\n1) [Guice/JitBindingAlreadySet]: A just-in-time binding to DynamicSet\u003cReplicationStateListener\u003e was already configured on a parent injector.\n  at DynamicSet.setOf(DynamicSet.java:88)\n\n1 error\nDynamicSet:               \"com.google.gerrit.extensions.registration.DynamicSet\"\nReplicationStateListener: \"com.googlesource.gerrit.plugins.replication.ReplicationStateListener\"\n\nBy moving back the replication plugin internal classes\nbindings into its proper ReplicationModule the problem is fully\nresolved and there aren\u0027t just-in-time bindings created\nimplicitly anymore.\n\nChange-Id: I2bf9dab0d2555310b4d1b0c66528b2aaa2cc5106\n"
    },
    {
      "commit": "2e2a6415a979e74e454a11e6e1637cb0d9d7a20a",
      "tree": "ca531c7bd62fd3ae07c16789b6d1f98140dec70e",
      "parents": [
        "b4bf5d2057cb748a7e50acc6c83727b8d64105e1"
      ],
      "author": {
        "name": "Jacek Centkowski",
        "email": "geminica.programs@gmail.com",
        "time": "Tue Jun 25 13:40:10 2024 +0200"
      },
      "committer": {
        "name": "Jacek Centkowski",
        "email": "geminica.programs@gmail.com",
        "time": "Tue Jun 25 13:40:10 2024 +0200"
      },
      "message": "Follow-up to \u0027Revert \"Reduce visibility of *CredentialsFact...\u0027\n\nMark these public factories with `UsedAt` so there it is no longer\ntempting to package-protect them.\n\nChange-Id: Icd4bec980472851dfb769159c1abb528e353cbd9\n"
    },
    {
      "commit": "b4bf5d2057cb748a7e50acc6c83727b8d64105e1",
      "tree": "fbacf5be5b0c8c964ff1c854eaf81223684e9793",
      "parents": [
        "6b4bc775bfabf8cc1862443b67a247731a79bcf1"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 21 23:50:08 2024 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Fri Jun 21 23:56:46 2024 +0000"
      },
      "message": "Revert \"Reduce visibility of *CredentialsFactory* classes\"\n\nThis reverts commit 499bbea5a16ec443cafb8da95ccdc33f6e381d55.\n\nReason for revert: Broke the pull-replication plugin\n\nChange-Id: If850c72fb7ab55a92754a655051a8d3e8077bbe4\n"
    },
    {
      "commit": "6b4bc775bfabf8cc1862443b67a247731a79bcf1",
      "tree": "83c6edfce5f40468ea5cdcc1dda9bd554636c2b5",
      "parents": [
        "cc32fe20832ea07c3a3388e87df777258686e5d5"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Wed Jun 19 17:49:43 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 20 09:47:27 2024 +0100"
      },
      "message": "Fix updating replication credentials using te RepicationRemotesApi\n\nThe implementation of the ReplicationRemotesApi for updating a remote\nintroduced with I8003ec6c827 has wrongly saved the credentials (username)\nin the repication.config rather than in the SecureStore, causing\nthe generation of non-functioning replication configs.\n\nThe credentials are read from the secure.config (or other SecureStore)\nas documented in [1].\n\n[1] https://gerrit.googlesource.com/plugins/replication/+/refs/heads/master/src/main/resources/Documentation/config.md#file-2\n\nChange-Id: I644d73bc69589189a8762de98d1c58c263abcfd4\n"
    },
    {
      "commit": "cc32fe20832ea07c3a3388e87df777258686e5d5",
      "tree": "b9d83fbd8cbd8059ca06d7ab6439213c9ef5a8e2",
      "parents": [
        "d1ad7d504171c8f68d2cf956bb3422fa84a8194f"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Wed Jun 19 08:53:19 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Wed Jun 19 11:36:10 2024 +0000"
      },
      "message": "Prevent replication plugin start with invalid remotes\n\nAllow the Gerrit admin to detect early a configuration\nissue with the remotes. Implement the credentials validation\nas first step; more validations to follow.\n\nChange-Id: I128422677f9fa9e70aae539ca7a591bddc07008e\n"
    },
    {
      "commit": "d1ad7d504171c8f68d2cf956bb3422fa84a8194f",
      "tree": "5b268461fd03507b00cafd3305716028e72cb375",
      "parents": [
        "499bbea5a16ec443cafb8da95ccdc33f6e381d55"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 13 17:56:43 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Wed Jun 19 12:35:38 2024 +0100"
      },
      "message": "Use SecureStore to access replication credentials\n\nGerrit introduced the SecureStore in Ibbb15ad2aa over 10 years\nago, however, the replication plugin was never adapted and then\nunable to access the remote endpoint credentials when Gerrit\nhas a custom secure provider installed that would provide\ndata encryption at rest.\n\nReplace the direct reading of the secure.config with the abstract\nimplementation of the Gerrit SecureStore, so that it can still\nbe working as expected with encrypted credentials.\n\nExisting installations may have used a mix of encrypted and clear text\ncredentials in secure.config, leveraging the replication plugin bug\nthat was not accessing it using the correct API. Introduce a legacy\nfeature flag \u0027gerrit.useLegacyCredentials\u0027 that allow the Gerrit\nadmin to still use the legacy mode.\n\nWhenever the replication plugin detects the legacy mode, it displays\na warning explaining what is happening and how to adjust the\nconfiguration and enable full encryption in secure.config.\n\nRelease-Notes: Use SecureStore for reading username/password credentials\nBug: Issue 320715545\nChange-Id: Ie5b6339d65d144536416cf070d52f11342b39fe6\n"
    },
    {
      "commit": "499bbea5a16ec443cafb8da95ccdc33f6e381d55",
      "tree": "e8e5d95a76b4e703969a04c12c3a3d2e2b5bfa43",
      "parents": [
        "89fc47e52a7734fde83ea37bea77a980a23a8f71"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jun 18 14:53:07 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jun 18 15:49:07 2024 +0000"
      },
      "message": "Reduce visibility of *CredentialsFactory* classes\n\nThe SecureCredentialsFactory and AutoReloadSecureCredentialsFactoryDecorator\nfactories do not need to be public as they are not intended to be\ndirectly used outside of the replication plugin.\n\nChange-Id: If8e828815eae135ffba1b437e48dee875ccc030d\n"
    },
    {
      "commit": "89fc47e52a7734fde83ea37bea77a980a23a8f71",
      "tree": "d2ca3fb3caa3de43a18ebd1b2bc3f623065f4e65",
      "parents": [
        "16ccc30b16ab678a53ce7e773cda32754adf0aa2"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Jun 17 08:53:34 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jun 18 12:42:05 2024 +0100"
      },
      "message": "Introduce API for retrieving the remote config\n\nExtend the ReplicationRemotesApi for retrieving the\nconfiguration associated with multiple replication remotes.\n\nNOTE: The configuration would not include passwords\nfor the sake of not exposing them when not necessarily needed.\n\nChange-Id: I26b6f098dd7b6331adf929315b2cc1cebdf0eb4a\n"
    },
    {
      "commit": "16ccc30b16ab678a53ce7e773cda32754adf0aa2",
      "tree": "d87fa580105ea34c07e1099db704127ae9c976a8",
      "parents": [
        "e66fbef958c0c9bc9b45ae4af59d336c7ed26c02"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jun 18 12:36:12 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Tue Jun 18 12:39:25 2024 +0100"
      },
      "message": "Allow to update base/override remote configs from MergedConfigResource\n\nExpose the ability to update base or override remote configs\nwith a single method at MergedConfigResource, as a follow-up of the\nintroduction of the API to update replication configs from other\nplugins.\n\nChange-Id: If9cb404c88e4397bd1c292c2dd1339d14fcc77af\n"
    },
    {
      "commit": "e66fbef958c0c9bc9b45ae4af59d336c7ed26c02",
      "tree": "3531aa6a03fdd4cff3963df638e5d14b7b49128d",
      "parents": [
        "30079cf09e68f4a5e7d26b073212243cfb1442ff"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Tue Jun 18 00:37:10 2024 +0200"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Tue Jun 18 00:37:10 2024 +0200"
      },
      "message": "Format source code using google-java-Format\n\nChange-Id: I827d60f9714a8c7dcab91d896530665a0b6489e1\n"
    },
    {
      "commit": "30079cf09e68f4a5e7d26b073212243cfb1442ff",
      "tree": "862529b0bc540eebfa1170227b6cf3f922aebd60",
      "parents": [
        "1c16901e971c96c20705b272703ad59b9b46200a"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Jun 17 08:49:03 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Jun 17 08:50:33 2024 +0100"
      },
      "message": "Rename ReplicationRemotesUpdater as ReplicationRemotesApi\n\nUpdating the replication remotes implies to have access to the\ncurrent configuration and amending it. Whilst the update interface\nwas introduced, there was no way to get the current remotes.\n\nRename the ReplicationRemotesUpdater as ReplicationRemotesApi\nas preparation for adding the method to access the current remotes\nconfigs.\n\nChange-Id: Ife70ed06c1cad94e056fd5503873a88196be5295\n"
    },
    {
      "commit": "1c16901e971c96c20705b272703ad59b9b46200a",
      "tree": "f0664800d581a5486cd1d4449f46ba49f7f57db1",
      "parents": [
        "aacb8b2a20267e88ccda811d27293bac66e2006b"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 13 07:44:59 2024 +0100"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Jun 13 07:47:21 2024 +0100"
      },
      "message": "Annotate ReplicationRemotesUpdater as @DynamicItem.Final\n\nMake sure that no plugins other than the replication\nbind an implementation of ReplicationRemotesUpdater.\n\nThe ReplicationRemotesUpdater is an API exposed by the\nreplication plugin to allow other plugins to update the\nreplication remotes independently from how they are stored\nand what is the backend that would store the data.\n\nDepends-On: https://gerrit-review.googlesource.com/c/gerrit/+/429017\nBug: Issue 338786480\nChange-Id: Ia99f6d536ab5a60f81212600fe4ab92be20789d7\n"
    },
    {
      "commit": "aacb8b2a20267e88ccda811d27293bac66e2006b",
      "tree": "cd5e5908e9c7b7b2491f334e617c2e1c74763e61",
      "parents": [
        "88efdc57266b579534dc97edac8a909f7e7b6e5e"
      ],
      "author": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Mon May 20 22:07:45 2024 +0100"
      },
      "committer": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Mon Jun 10 22:03:56 2024 +0100"
      },
      "message": "Temporarily bind ReplicationRemotesUpdater as DynamicItem\n\nTo unblock other work around the github and pull_replication plugins,\nbind the `ReplicationRemotesUpdater` as a `DynamicItem`. This allows us\nto keep the API definition in the ApiModule and hide all of the\nimplementation details in the main replication plugin.\n\nThe `DynamicItem` is not an ideal choice here as it can be bound by any\nplugin which could lead to unpredicted behaviour.\n\nHopefully, in the future, we\u0027ll be able to move to _StaticItem_ (Issue\n338786480). Or refactor the plugin in a way that configuration details\ncould be moved into the `.api` package and stay hidden there.\n\nFor now, the best choice is to go with `DynamicItem`.\n\nBug: Issue 330495476\nChange-Id: I349461e29d8cbd7a6d5e10c1e07ae8b7451b9f4d\n"
    },
    {
      "commit": "88efdc57266b579534dc97edac8a909f7e7b6e5e",
      "tree": "e2b7ba0e4a57ee462fe405a9646a69d1cd8df21b",
      "parents": [
        "eaeaf1d0ab94743b7d843849994a48de9bd7ccf2"
      ],
      "author": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Sat May 04 23:16:24 2024 +0100"
      },
      "committer": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Sun May 05 19:30:38 2024 +0100"
      },
      "message": "Fix bindings in ReplicationConfigModule\n\nFix conflicting bindings in `pull-replication` plugin by moving them\nfrom `ReplicationConfigModule` to the main `ReplicationModule`. This way\nboth plugins will be loaded successfully.\n\nChange-Id: I56890f980022f2605bcfc3fe381251514f6c0e19\n"
    },
    {
      "commit": "eaeaf1d0ab94743b7d843849994a48de9bd7ccf2",
      "tree": "3321c23a2f6c2976639a23d8e6d26f76a57e8432",
      "parents": [
        "56b8ffbab5bf619c0b6b5d44f0255fd41b9e1c89"
      ],
      "author": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Mon Apr 15 14:57:40 2024 +0100"
      },
      "committer": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Sun May 05 19:26:27 2024 +0100"
      },
      "message": "Reapply \"Expose API to update remotes\u0027 configurations\"\n\nThis reverts commit aab69373db6152ea98e7627f816fa3d777d5fe46.\n\nAs mentioned in the revered commit message, the plan was to only revert\nthat change in order to make 3.10 release. Now, when the release is\ndone we can get `ReplicatonRemotesUpdater` back.\n\nImportantly, this reapply doesn\u0027t effectively bring back the\n`ReplicationRemotesUpdater` API back in, as the definition of\n`ApiModule` is still moved to `replication-api` artefact.\n\nChange-Id: Id03d8d50cc662fca4af4c9a1a86d7ddb9f6254c0\n"
    },
    {
      "commit": "56b8ffbab5bf619c0b6b5d44f0255fd41b9e1c89",
      "tree": "cc78f590ac65e6b777711da8dc96d4c41b95d048",
      "parents": [
        "aab69373db6152ea98e7627f816fa3d777d5fe46"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Sun Apr 07 10:19:59 2024 -0700"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Mon Apr 08 05:26:28 2024 +0000"
      },
      "message": "Load replication configuration only once\n\nReuse the same instance across requests in ReplicationConfigImpl.\nThis avoids reloading the configuration from disk continuously.\n\nPreviously, the config was retrieved on-demand with the Provider\u003c\u003e.get()\nparadigm. However, the Provider\u003c\u003e.get() would trigger the creation of a\nnew instance of the Config every time it is invoked, causing the full\nscan and parsing of the replication configs.\n\nOn GerritHub.io, the processing of all replication configs (12k files)\nwould take around 5 minutes, causing a catastrophic overload of the CPU\nand preventing the plugin that use ReplicationConfigImpl (replication\nand pull-replication) to even start.\n\nWith regards to the configVersion, the description of the interface has\nbeen amended to reflect the expected behaviour to report the\n*latest actual* version on the storage, regardless of the in-memory copy.\n\nThe AutoReloadConfigDectorator relies on the configVersion to reflect\nthe storage version for triggering a configuration reload by forcibly\nre-creating the config resources and therefore triggering the reload and\nparsing of the replication configs from the underlying storage.\n\nAutoReloadConfigDecorator should not reload the configuration again\nin his constructor because the AutoReloadRunnable has already loaded\nthe initial state and therefore can reuse that one as valid starting\npoint.\n\nChange-Id: I6f9c3a35d1ecbfa87f3daeeb464face0c6b6400e\n"
    },
    {
      "commit": "aab69373db6152ea98e7627f816fa3d777d5fe46",
      "tree": "6e7f30d0274edd2c5b7072fb456a79130edc8bfe",
      "parents": [
        "5e33f8344e3855478914a5c530a327f888bd8c8e"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Apr 04 16:54:06 2024 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Apr 04 17:13:21 2024 +0000"
      },
      "message": "Revert \"Expose API to update remotes\u0027 configurations\"\n\nThis reverts commit 68ce459ba2dd7d5625e03712635caf78957e1c1e.\n\nThe plan is:\n- Revert master\n- cut stable-3.10\n- Re-apply on master and expose the new API properly\n\nReason for revert: Broke the pull-replication plugin\n\nChange-Id: I461cd1bef6d74d48763662c0c26db47bafe5d422\n"
    },
    {
      "commit": "5e33f8344e3855478914a5c530a327f888bd8c8e",
      "tree": "aa165c959667b40da1fbe41d6a36b93f85715dd8",
      "parents": [
        "012f04240eafe6dfa21fd94e012e97498881c621"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Sat Feb 10 21:55:12 2024 +0000"
      },
      "committer": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Thu Apr 04 15:51:24 2024 +0100"
      },
      "message": "Decouple replication-api.jar from the main replication plugin\n\nThe Change Ib7a04eea5 made the whole replication plugin an ApiModule\nwhich becomes the base injector for all plugins and forbids reloads,\n(see the  Iac2851022ea for enforcing it at Gerrit level)\neven when there is no intention to use th extension points.\n\nAll plugins that expose an ApiModule have the following limitations:\n- Cannot add extra dependencies\n- Cannot be reloaded\n- Are the base injectors for all plugins\n\nThe above limitations aren\u0027t acceptable for the whole replication\nplugin when used standalone without extensions.\n\nDefine a new replication-api target that generates the sole ApiModule\nneeded for extending the replication plugin functionality.\nAll the classes that are part of the replication-api are moved\ninto a separate c.g.g.p.replication.api package so that can be\nincluded in the replication-api.jar plugin.\n\nThe gerrit.war will continue to include only the replication.jar which\nwill still work out of the box. Anyone willing to customise its behaviour\nthrough the API will have to build the replication-api target.\nAlso fix the MergedConfigResource that was assuming that the ApiModule\nwas always installed and was binding DynamicItem\u003cReplicationConfigOverrides\u003e.\n\nBug: Issue 324462734\nRelease-Notes: Decouple replication-api.jar from the main replication plugin\nChange-Id: Ic432fc77daf1162368abd65f64c463e4ef4f5d6d\n"
    },
    {
      "commit": "012f04240eafe6dfa21fd94e012e97498881c621",
      "tree": "caabf11346d53f6567639897a3dadd786e9c43bf",
      "parents": [
        "cc47d53d4870e2c285c3b72202ebe6f3fdd67b57"
      ],
      "author": {
        "name": "Saša Živkov",
        "email": "sasa.zivkov@sap.com",
        "time": "Tue Apr 02 12:17:17 2024 +0200"
      },
      "committer": {
        "name": "Saša Živkov",
        "email": "sasa.zivkov@sap.com",
        "time": "Tue Apr 02 13:48:50 2024 +0200"
      },
      "message": "Remove remaining event posting from synchronized sections\n\nPosting events sometimes can take significant time, mainly due to the\nevent visibility checks. When this is done from a synchronized block\nthen all other threads trying to schedule replication to the same\n(locked) Destination get blocked. Even worse, the synchronization\nhappens on the Destination level, so even operations on unrelated\nrepositories block each other.\n\nChange-Id: I7498c7b36ee4b0b2d915a414a0fb1054160e8a1c\n"
    },
    {
      "commit": "cc47d53d4870e2c285c3b72202ebe6f3fdd67b57",
      "tree": "f04d274fb0db78487095cda3ca21f85fd58936ef",
      "parents": [
        "cf510966724cb0963976c9d09aabfdd2bf32d8b6"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Thu Mar 28 19:25:33 2024 +0100"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Thu Mar 28 19:58:03 2024 +0100"
      },
      "message": "Destination#pushWasCanceled: minimize time spent in critical section\n\nWhen cancelling a push to a replication destination don\u0027t notify\nlisteners about not attempted push during the critical section where the\nstateLock is held but do this immediately after the critical section.\n\nWe observed in a high-availability setup with 2 primaries that\ncancelling a replication push blocked \u003e90 other threads trying to\nupdate some refs which tried to create new replication tasks via\nsynchronous events. Cancelling the push was stuck on visibility checks\ndone in EventBroker#fireEvent triggered by Destination#pushWasCanceled.\nThis visibility check was slow since the affected repository is huge\n(30GiB) and we use NFS for sharing repositories between primaries.\n\nMoving the call to PushOne#notifyNotAttempted outside the critical\nsection should reduce the impact of this critical section on other\nrequests updating refs concurrently.\n\nChange-Id: I085700c3f4cad95ef62521527ac4b920a59c76c2\nSigned-off-by: Matthias Sohn \u003cmatthias.sohn@sap.com\u003e\n"
    },
    {
      "commit": "cf510966724cb0963976c9d09aabfdd2bf32d8b6",
      "tree": "daa01696bd98f6d18e0e36b4ecc80febe138cc2c",
      "parents": [
        "2f6c7ceeb0cc50bc73d018cd9f990392d58804ab"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Thu Mar 28 19:24:55 2024 +0100"
      },
      "committer": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@sap.com",
        "time": "Thu Mar 28 19:57:59 2024 +0100"
      },
      "message": "Auto-format source code\n\nChange-Id: I5ad6ff9555239442fa3cc86952bf6a313b9bda92\n"
    },
    {
      "commit": "2f6c7ceeb0cc50bc73d018cd9f990392d58804ab",
      "tree": "b649adf30da1ca238c62ffa31ecf0daf3294d001",
      "parents": [
        "aac252809094b8e4d4e26d69dab75a23d2da1770"
      ],
      "author": {
        "name": "Edwin Kempin",
        "email": "ekempin@google.com",
        "time": "Mon Mar 18 14:57:18 2024 +0000"
      },
      "committer": {
        "name": "Edwin Kempin",
        "email": "ekempin@google.com",
        "time": "Mon Mar 18 14:57:18 2024 +0000"
      },
      "message": "ReplicationModule: Remove unused import\n\nChange-Id: I2d497abfa6ca4f4b79accb0f1584e3ff2462826d\nSigned-off-by: Edwin Kempin \u003cekempin@google.com\u003e\n"
    },
    {
      "commit": "aac252809094b8e4d4e26d69dab75a23d2da1770",
      "tree": "2845736d083cf7fd5bd2515907f770136b5e1fe8",
      "parents": [
        "d91399e3ff6205e22d065dbe8757f5128890bfac",
        "3e168ff4f358ccf972af06137fc3c4b22bd36c57"
      ],
      "author": {
        "name": "Matthias Sohn",
        "email": "matthias.sohn@gmail.com",
        "time": "Mon Mar 11 13:32:13 2024 +0000"
      },
      "committer": {
        "name": "Gerrit Code Review",
        "email": "noreply-gerritcodereview@google.com",
        "time": "Mon Mar 11 13:32:13 2024 +0000"
      },
      "message": "Merge \"Prevent ConcurrentModificationException for PushOne.refBatchesToPush\""
    },
    {
      "commit": "3e168ff4f358ccf972af06137fc3c4b22bd36c57",
      "tree": "7cfbfb463ccb0c05e1d891e1b27939aa2fc004ab",
      "parents": [
        "877f52684857aa1e5cf6d7146d493cbe9702e314"
      ],
      "author": {
        "name": "Saša Živkov",
        "email": "sasa.zivkov@sap.com",
        "time": "Mon Mar 11 13:23:11 2024 +0100"
      },
      "committer": {
        "name": "Saša Živkov",
        "email": "sasa.zivkov@sap.com",
        "time": "Mon Mar 11 13:23:11 2024 +0100"
      },
      "message": "Prevent ConcurrentModificationException for PushOne.refBatchesToPush\n\nThe PushOne.refBatchesToPush was a plain HashSet but r/w access to it\nwasn\u0027t synchronized. Under some circumstances, traversing a stream\ncreated on refBatchesToPush threw ConcurrentModificationException [1]\nwhich caused the thread to die. As a side effect of the thread-death,\nthe replication task would never reschedule itself but would remain in\nthe pending tasks and all follow-up replications to the same URI would\nbe consolidated into that pending task which would never run. Only a\nrestart of the replication plugin would resolve the issue.\n\n[1]\nERROR com.google.gerrit.server.git.WorkQueue : WorkQueue thread ReplicateTo-some-uri-2 threw exception\njava.util.ConcurrentModificationException\n        at java.base/java.util.HashMap$KeySpliterator.tryAdvance(HashMap.java:1730)\n        at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)\n        at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)\n        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)\n        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)\n        at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)\n        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)\n        at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)\n        at com.googlesource.gerrit.plugins.replication.PushOne.getLimitedRefs(PushOne.java:255)\n        at com.googlesource.gerrit.plugins.replication.PushOne.toString(PushOne.java:221)\n        at com.google.gerrit.server.git.WorkQueue$ProjectTask.toString(WorkQueue.java:760)\n        at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)\n        at com.google.gerrit.server.git.WorkQueue$Task.run(WorkQueue.java:678)\n        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)\n        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)\n        at java.base/java.lang.Thread.run(Thread.java:840)\n\nChange-Id: I3f29779fd150868412e4994d307303d1dd8bde7b\n"
    },
    {
      "commit": "d91399e3ff6205e22d065dbe8757f5128890bfac",
      "tree": "790dbbac51fc822e6d59913bcadd31b041c92178",
      "parents": [
        "56ea64394e8a58b213c0d859c219036fe6c78b0c",
        "68ce459ba2dd7d5625e03712635caf78957e1c1e"
      ],
      "author": {
        "name": "Luca Milanesio",
        "email": "luca.milanesio@gmail.com",
        "time": "Sat Mar 09 02:46:29 2024 +0000"
      },
      "committer": {
        "name": "Gerrit Code Review",
        "email": "noreply-gerritcodereview@google.com",
        "time": "Sat Mar 09 02:46:29 2024 +0000"
      },
      "message": "Merge \"Expose API to update remotes\u0027 configurations\""
    },
    {
      "commit": "68ce459ba2dd7d5625e03712635caf78957e1c1e",
      "tree": "bfa63881e7fa490eb6595b63360e320b2df0cec9",
      "parents": [
        "877f52684857aa1e5cf6d7146d493cbe9702e314"
      ],
      "author": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Mon Feb 05 17:53:32 2024 +0000"
      },
      "committer": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Thu Mar 07 10:29:52 2024 +0000"
      },
      "message": "Expose API to update remotes\u0027 configurations\n\nIntroduce `ReplicationRemotesUpdater` class to add or update remotes\nconfiguration programmatically.\n\nTo propagate changes to different configuration resources, both\n`ConfigResource` and `ReplicationConfigOverrides` got new method `void\nudpate(Config config)`. That lets persist changes in other configuration\nresources.\n\nIn order to make Guice happy with all of the required bindings, some\nwere moved from `ReplicationModule` to `ReplicationConfigModule`.\n\nFinally, the `ReplicationRemotesUpdater`, will use `SecureStore` to\npersist `remote.$name.password` in a secure manner.\n\nFor end-to-end testing replication-remote-updates[1] can be used.\n\n[1] https://github.com/dluksza/replication-remote-updates\n\nBug: Issue 322146238\nChange-Id: I8003ec6c827f865eb383092db8f07033e92da488\n"
    },
    {
      "commit": "56ea64394e8a58b213c0d859c219036fe6c78b0c",
      "tree": "855cf663ba4deb1c2b1e77e912073302438f3c88",
      "parents": [
        "d464511adf2f5560f1aea9932fc6a80e0cf3595d"
      ],
      "author": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Mon Dec 11 22:41:10 2023 +0000"
      },
      "committer": {
        "name": "Dariusz Luksza",
        "email": "dariusz.luksza@gmail.com",
        "time": "Tue Mar 05 17:52:36 2024 +0000"
      },
      "message": "Set SSH timeouts from configuration file\n\nIt looks like during the refactoring in I253a6d94, `sshCommandTimeout`\nand `sshConnectionTimeout` fields were not initialized with values from\nthe `replication.config`.\n\nThis is restoring code present before change mentioned above.\n\nChange-Id: Id1f8e9f17a2a8bf7c1dfbd48b6cd005513e7b187\n"
    }
  ],
  "next": "d464511adf2f5560f1aea9932fc6a80e0cf3595d"
}
