{"thread":{"id":"66095","subject":"[PATCH] ci: cancel stale pull request workflow runs","startedAt":"2026-07-31T10:10:54Z","lastAt":"2026-08-31T16:18:18Z","messageCount":8,"participants":["Harald Nordgren via GitGitGadget","Harald Nordgren","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"549341","messageId":"pull.2369.git.git.1785492641983.gitgitgadget@gmail.com","threadId":"66095","inReplyTo":null,"subject":"[PATCH] ci: cancel stale pull request workflow runs","fromName":"Harald Nordgren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-31T10:10:41Z","receivedAt":"2026-07-31T10:10:54Z","isPatch":true,"body":"From: Harald Nordgren <haraldnordgren@gmail.com>\n\nThe CI workflow groups runs by commit hash, so every push to a pull\nrequest starts a separate workflow run. Group pull request runs by pull\nrequest number and cancel runs superseded by a newer push, while keeping\npush events grouped by commit hash for the skip-if-redundant behavior.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n    ci: cancel stale pull request workflow runs\n    \n    Group CI workflow runs by pull request and cancel older revisions so\n    only the latest push consumes runner capacity.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2369%2FHaraldNordgren%2Fcancel-stale-pr-ci-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2369/HaraldNordgren/cancel-stale-pr-ci-v1\nPull-Request: https://github.com/git/git/pull/2369\n\n .github/workflows/main.yml | 20 +++++++++++---------\n 1 file changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/.github/workflows/main.yml b/.github/workflows/main.yml\nindex 85cfedf5b0..1dc4ca121c 100644\n--- a/.github/workflows/main.yml\n+++ b/.github/workflows/main.yml\n@@ -5,18 +5,20 @@ on: [push, pull_request]\n env:\n   DEVELOPER: 1\n \n-# If more than one workflow run is triggered for the very same commit hash\n-# (which happens when multiple branches pointing to the same commit), only\n-# the first one is allowed to run, the second will be kept in the \"queued\"\n-# state. This allows a successful completion of the first run to be reused\n-# in the second run via the `skip-if-redundant` logic in the `config` job.\n+# For pull requests, only the latest workflow run is allowed to proceed.\n+# Older runs are canceled when a new revision is pushed.\n #\n-# The only caveat is that if a workflow run is triggered for the same commit\n-# hash that another run is already being held, that latter run will be\n-# canceled. For more details about the `concurrency` attribute, see:\n+# For pushes, if more than one workflow run is triggered for the very same\n+# commit hash (which happens when multiple branches point to the same commit),\n+# only the first one is allowed to run. This allows a successful completion of\n+# the first run to be reused in the second run via the `skip-if-redundant`\n+# logic in the `config` job.\n+#\n+# For more details about the `concurrency` attribute, see:\n # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency\n concurrency:\n-  group: ${{ github.sha }}\n+  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n+  cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n \n jobs:\n   ci-config:\n\nbase-commit: a97fcc37c2bc6340a8d7ce78dedf227aac4e9aa7\n-- \ngitgitgadget\n"},{"id":"550999","messageId":"CAHwyqnVteA1AfqXsFXTAvFdbTZmep3o84RMNZQWVaHDHtODOqQ@mail.gmail.com","threadId":"66095","inReplyTo":"pull.2369.git.git.1785492641983.gitgitgadget@gmail.com","subject":"Re: [PATCH] ci: cancel stale pull request workflow runs","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2026-08-21T11:14:28Z","receivedAt":"2026-08-21T11:15:07Z","isPatch":true,"body":"Hi!\n\nIt would be nice to get some review here, this will save a lot of CI money.\n\n\nHarald\n"},{"id":"551310","messageId":"xmqqa4q8fyjh.fsf@gitster.g","threadId":"66095","inReplyTo":"pull.2369.git.git.1785492641983.gitgitgadget@gmail.com","subject":"Re: [PATCH] ci: cancel stale pull request workflow runs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-26T19:54:10Z","receivedAt":"2026-08-26T19:54:15Z","isPatch":true,"body":"\"Harald Nordgren via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\nNobody seems interested in reviewing this patch, and I am not\nhappy leaving too many topics in the \"Needs review\" state.  So\nhere is my attempt to think aloud, based primarily on what I read\nin the proposed commit log message.  Consider any misunderstanding\non my part a sign that the proposed log message is lacking.\n\n> -  group: ${{ github.sha }}\n> +  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n> +  cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n\nWe used to assign each commit to its own group.  For a pull-request\nevent, the new configuration instead assigns it to the concurrency\ngroup <workflow>-<pull-request-number> (e.g., \"main-workflow-42\"),\nso if you are impatient and update an existing pull request before\nthe CI working on it finishes, the new request will be placed in the\nsame group.\n\nFor other events, <workflow>-<commit-object-name> is the group used\nfor the commit, which differs from the original behavior, but\narguably in a good way.  If three or more workflows sharing the same\nconcurrency group are triggered at the same time for the same\ncommit, because there will be at most one active run and one pending\nrun in the same group, we may see some workflows fail to run on the\ncommit.\n\n  NOTE NOTE NOTE: The previous paragraph is based on my incomplete\n  understanding of how GitHub Actions works, gathered from skimming\n  the documentation.  It needs to be verified, and if correct, it\n  should be added to the commit log message.  If it is not correct,\n  a revised description discussing how this change does NOT affect\n  non-PR events negatively should be included in the commit log\n  message instead.\n\nThe original configuration did not specify 'cancel-in-progress' at\nall, so these jobs did not cancel each other.  Now, for pull-request\nevents, an earlier run in the same group is canceled when another\none is triggered.  If you are impatient and update an existing pull\nrequest before the CI working on it finishes, the new request will\ncancel the currently running one and replace it.  \n\nFor non pull-request events, it is as if no 'cancel-in-progress'\nwere specified, as it defaults to false, so there is no regression\nthere.  We _might_ want to have two pushes back to back that causes\nthe CI work on the same commit to drop one of them, but that can be\nleft out as an independent issue.\n\nThanks.\n\n\n"},{"id":"551470","messageId":"pull.2369.v2.git.git.1788087560290.gitgitgadget@gmail.com","threadId":"66095","inReplyTo":"pull.2369.git.git.1785492641983.gitgitgadget@gmail.com","subject":"[PATCH v2] ci: cancel stale pull request workflow runs","fromName":"Harald Nordgren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-30T10:59:20Z","receivedAt":"2026-08-30T10:59:24Z","isPatch":true,"body":"From: Harald Nordgren <haraldnordgren@gmail.com>\n\nThe CI workflow previously grouped all runs by commit hash using\n`group: ${{ github.sha }}`.  This meant every push to a pull\nrequest started a separate workflow run, and all workflows\ntriggered by the same commit shared the same concurrency group.\n\nWith this change, pull request runs are grouped by pull request\nnumber instead of commit hash, and runs superseded by a newer\npush are canceled.  The concurrency group becomes\n`${{ github.workflow }}-${{ github.event.pull_request.number ||\ngithub.sha }}` and `cancel-in-progress` is set to true for\npull request events.\n\nFor pull request events, the group is `<workflow>-<pull-request-number>`\n(e.g., \"main-workflow-42\").  If you push a new commit to an\nexisting pull request before the CI working on it finishes, the\nnew request will be placed in the same group and cancel the\ncurrently running run.\n\nFor non-pull-request events, the group is `${{ github.workflow }}-${{\ngithub.sha }}` and `cancel-in-progress` defaults to false, so\nthere is no regression in behavior.\n\nNote that the previous configuration used `group: ${{ github.sha }}`,\nwhich meant all workflows sharing the same commit hash were in the\nsame group.  The new configuration includes the workflow name in\nthe group, so each workflow has its own concurrency group per\ncommit/PR.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n    ci: cancel stale pull request workflow runs\n    \n    Group CI workflow runs by pull request and cancel older revisions so\n    only the latest push consumes runner capacity.\n    \n    Changes in v2:\n    \n     * Explain behavior in commit message.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2369%2FHaraldNordgren%2Fcancel-stale-pr-ci-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2369/HaraldNordgren/cancel-stale-pr-ci-v2\nPull-Request: https://github.com/git/git/pull/2369\n\nRange-diff vs v1:\n\n 1:  a0a618d8cc ! 1:  2773cc5a84 ci: cancel stale pull request workflow runs\n     @@ Metadata\n       ## Commit message ##\n          ci: cancel stale pull request workflow runs\n      \n     -    The CI workflow groups runs by commit hash, so every push to a pull\n     -    request starts a separate workflow run. Group pull request runs by pull\n     -    request number and cancel runs superseded by a newer push, while keeping\n     -    push events grouped by commit hash for the skip-if-redundant behavior.\n     +    The CI workflow previously grouped all runs by commit hash using\n     +    `group: ${{ github.sha }}`.  This meant every push to a pull\n     +    request started a separate workflow run, and all workflows\n     +    triggered by the same commit shared the same concurrency group.\n     +\n     +    With this change, pull request runs are grouped by pull request\n     +    number instead of commit hash, and runs superseded by a newer\n     +    push are canceled.  The concurrency group becomes\n     +    `${{ github.workflow }}-${{ github.event.pull_request.number ||\n     +    github.sha }}` and `cancel-in-progress` is set to true for\n     +    pull request events.\n     +\n     +    For pull request events, the group is `<workflow>-<pull-request-number>`\n     +    (e.g., \"main-workflow-42\").  If you push a new commit to an\n     +    existing pull request before the CI working on it finishes, the\n     +    new request will be placed in the same group and cancel the\n     +    currently running run.\n     +\n     +    For non-pull-request events, the group is `${{ github.workflow }}-${{\n     +    github.sha }}` and `cancel-in-progress` defaults to false, so\n     +    there is no regression in behavior.\n     +\n     +    Note that the previous configuration used `group: ${{ github.sha }}`,\n     +    which meant all workflows sharing the same commit hash were in the\n     +    same group.  The new configuration includes the workflow name in\n     +    the group, so each workflow has its own concurrency group per\n     +    commit/PR.\n      \n          Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n      \n\n\n .github/workflows/main.yml | 20 +++++++++++---------\n 1 file changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/.github/workflows/main.yml b/.github/workflows/main.yml\nindex 205325eb33..4fff344874 100644\n--- a/.github/workflows/main.yml\n+++ b/.github/workflows/main.yml\n@@ -5,18 +5,20 @@ on: [push, pull_request]\n env:\n   DEVELOPER: 1\n \n-# If more than one workflow run is triggered for the very same commit hash\n-# (which happens when multiple branches pointing to the same commit), only\n-# the first one is allowed to run, the second will be kept in the \"queued\"\n-# state. This allows a successful completion of the first run to be reused\n-# in the second run via the `skip-if-redundant` logic in the `config` job.\n+# For pull requests, only the latest workflow run is allowed to proceed.\n+# Older runs are canceled when a new revision is pushed.\n #\n-# The only caveat is that if a workflow run is triggered for the same commit\n-# hash that another run is already being held, that latter run will be\n-# canceled. For more details about the `concurrency` attribute, see:\n+# For pushes, if more than one workflow run is triggered for the very same\n+# commit hash (which happens when multiple branches point to the same commit),\n+# only the first one is allowed to run. This allows a successful completion of\n+# the first run to be reused in the second run via the `skip-if-redundant`\n+# logic in the `config` job.\n+#\n+# For more details about the `concurrency` attribute, see:\n # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency\n concurrency:\n-  group: ${{ github.sha }}\n+  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n+  cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n \n jobs:\n   ci-config:\n\nbase-commit: c73e85354c275c9d409b26445089bc16940fc527\n-- \ngitgitgadget\n"},{"id":"551489","messageId":"xmqqqzjfz0ba.fsf@gitster.g","threadId":"66095","inReplyTo":"pull.2369.v2.git.git.1788087560290.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] ci: cancel stale pull request workflow runs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T22:54:33Z","receivedAt":"2026-08-30T22:54:35Z","isPatch":true,"body":"\"Harald Nordgren via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Harald Nordgren <haraldnordgren@gmail.com>\n>\n> The CI workflow previously grouped all runs by commit hash using\n> `group: ${{ github.sha }}`.  This meant every push to a pull\n> request started a separate workflow run, and all workflows\n> triggered by the same commit shared the same concurrency group.\n\nThat's the current status that we normally describe in the present\ntense, no?\n\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n> ...\n> +# For more details about the `concurrency` attribute, see:\n>  # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency\n>  concurrency:\n> -  group: ${{ github.sha }}\n> +  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n> +  cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n\nIf a user has CI enabled on their own repository, pushes a commit\nthere, and opens a pull request, wouldn't GitHub Actions trigger\ntwo events for the same commit at the tip of the pushed branch?\n\nBefore this change, both events are assigned to the same concurrency\ngroup (the commit object name).  One waits while the other runs, and\nthe skip-if-redundant logic stops the second one early without\nwasting cycles on the same commit.  With this change, the\nconcurrency groups for these two events are separate.  Would we end\nup building and testing the same commit twice in parallel?\n\nI suspect this may not be a problem in practice given how our\ncontributors use GitHub Actions in our official repositories (either\nthose owned by gitgitgadget or git).  They push to their own\nrepositories where CI may not be enabled, so 'push' does not\ntrigger.  Still, I thought it better to bring this up before the\nchange gets merged and wastes build cycles.\n"},{"id":"551540","messageId":"CAHwyqnV5YTJsAnDDHQj0gwmoWXEgnPSJ8tJCcXrg12vBvtwFfA@mail.gmail.com","threadId":"66095","inReplyTo":"xmqqqzjfz0ba.fsf@gitster.g","subject":"Re: [PATCH v2] ci: cancel stale pull request workflow runs","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2026-08-31T11:12:32Z","receivedAt":"2026-08-31T11:13:12Z","isPatch":true,"body":"> If a user has CI enabled on their own repository, pushes a commit\n> there, and opens a pull request, wouldn't GitHub Actions trigger\n> two events for the same commit at the tip of the pushed branch?\n>\n> Before this change, both events are assigned to the same concurrency\n> group (the commit object name).  One waits while the other runs, and\n> the skip-if-redundant logic stops the second one early without\n> wasting cycles on the same commit.  With this change, the\n> concurrency groups for these two events are separate.  Would we end\n> up building and testing the same commit twice in parallel?\n>\n> I suspect this may not be a problem in practice given how our\n> contributors use GitHub Actions in our official repositories (either\n> those owned by gitgitgadget or git).  They push to their own\n> repositories where CI may not be enabled, so 'push' does not\n> trigger.  Still, I thought it better to bring this up before the\n> change gets merged and wastes build cycles.\n\nConcurrency groups don't span repos, so I don't see a solution to that.\n\n\nHarald\n"},{"id":"551561","messageId":"xmqqa4q2z7e9.fsf@gitster.g","threadId":"66095","inReplyTo":"CAHwyqnV5YTJsAnDDHQj0gwmoWXEgnPSJ8tJCcXrg12vBvtwFfA@mail.gmail.com","subject":"Re: [PATCH v2] ci: cancel stale pull request workflow runs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-31T14:33:50Z","receivedAt":"2026-08-31T14:33:53Z","isPatch":true,"body":"Harald Nordgren <haraldnordgren@gmail.com> writes:\n\n>> If a user has CI enabled on their own repository, pushes a commit\n>> there, and opens a pull request, wouldn't GitHub Actions trigger\n>> two events for the same commit at the tip of the pushed branch?\n>>\n>> Before this change, both events are assigned to the same concurrency\n>> group (the commit object name).  One waits while the other runs, and\n>> the skip-if-redundant logic stops the second one early without\n>> wasting cycles on the same commit.  With this change, the\n>> concurrency groups for these two events are separate.  Would we end\n>> up building and testing the same commit twice in parallel?\n>>\n>> I suspect this may not be a problem in practice given how our\n>> contributors use GitHub Actions in our official repositories (either\n>> those owned by gitgitgadget or git).  They push to their own\n>> repositories where CI may not be enabled, so 'push' does not\n>> trigger.  Still, I thought it better to bring this up before the\n>> change gets merged and wastes build cycles.\n>\n> Concurrency groups don't span repos, so I don't see a solution to that.\n\nOK, then I do not see a need for solution to begin with---it is not\na problem, in other words ;-).\n\nThanks.\n"},{"id":"551574","messageId":"pull.2369.v3.git.git.1788193095825.gitgitgadget@gmail.com","threadId":"66095","inReplyTo":"pull.2369.git.git.1785492641983.gitgitgadget@gmail.com","subject":"[PATCH v3] ci: cancel stale pull request workflow runs","fromName":"Harald Nordgren via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-31T16:18:15Z","receivedAt":"2026-08-31T16:18:18Z","isPatch":true,"body":"From: Harald Nordgren <haraldnordgren@gmail.com>\n\nThe CI workflow groups all runs by commit hash using\n`group: ${{ github.sha }}`.  This means every push to a pull\nrequest starts a separate workflow run, and all workflows\ntriggered by the same commit share the same concurrency group.\n\nWith this change, pull request runs are grouped by pull request\nnumber instead of commit hash, and runs superseded by a newer\npush are canceled.  The concurrency group becomes\n`${{ github.workflow }}-${{ github.event.pull_request.number ||\ngithub.sha }}` and `cancel-in-progress` is set to true for\npull request events.\n\nFor pull request events, the group is `<workflow>-<pull-request-number>`\n(e.g., \"main-workflow-42\").  If you push a new commit to an\nexisting pull request before the CI working on it finishes, the\nnew request will be placed in the same group and cancel the\ncurrently running run.\n\nFor non-pull-request events, the group is `${{ github.workflow }}-${{\ngithub.sha }}` and `cancel-in-progress` defaults to false, so\nthere is no regression in behavior.\n\nNote that the previous configuration used `group: ${{ github.sha }}`,\nwhich meant all workflows sharing the same commit hash were in the\nsame group.  The new configuration includes the workflow name in\nthe group, so each workflow has its own concurrency group per\ncommit/PR.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n    ci: cancel stale pull request workflow runs\n    \n    Group CI workflow runs by pull request and cancel older revisions so\n    only the latest push consumes runner capacity.\n    \n    Changes in v3:\n    \n     * Status quo in present tense in commit message.\n    \n    Changes in v2:\n    \n     * Explain behavior in commit message.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2369%2FHaraldNordgren%2Fcancel-stale-pr-ci-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2369/HaraldNordgren/cancel-stale-pr-ci-v3\nPull-Request: https://github.com/git/git/pull/2369\n\nRange-diff vs v2:\n\n 1:  2773cc5a84 ! 1:  61fb54612d ci: cancel stale pull request workflow runs\n     @@ Metadata\n       ## Commit message ##\n          ci: cancel stale pull request workflow runs\n      \n     -    The CI workflow previously grouped all runs by commit hash using\n     -    `group: ${{ github.sha }}`.  This meant every push to a pull\n     -    request started a separate workflow run, and all workflows\n     -    triggered by the same commit shared the same concurrency group.\n     +    The CI workflow groups all runs by commit hash using\n     +    `group: ${{ github.sha }}`.  This means every push to a pull\n     +    request starts a separate workflow run, and all workflows\n     +    triggered by the same commit share the same concurrency group.\n      \n          With this change, pull request runs are grouped by pull request\n          number instead of commit hash, and runs superseded by a newer\n\n\n .github/workflows/main.yml | 20 +++++++++++---------\n 1 file changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/.github/workflows/main.yml b/.github/workflows/main.yml\nindex 205325eb33..4fff344874 100644\n--- a/.github/workflows/main.yml\n+++ b/.github/workflows/main.yml\n@@ -5,18 +5,20 @@ on: [push, pull_request]\n env:\n   DEVELOPER: 1\n \n-# If more than one workflow run is triggered for the very same commit hash\n-# (which happens when multiple branches pointing to the same commit), only\n-# the first one is allowed to run, the second will be kept in the \"queued\"\n-# state. This allows a successful completion of the first run to be reused\n-# in the second run via the `skip-if-redundant` logic in the `config` job.\n+# For pull requests, only the latest workflow run is allowed to proceed.\n+# Older runs are canceled when a new revision is pushed.\n #\n-# The only caveat is that if a workflow run is triggered for the same commit\n-# hash that another run is already being held, that latter run will be\n-# canceled. For more details about the `concurrency` attribute, see:\n+# For pushes, if more than one workflow run is triggered for the very same\n+# commit hash (which happens when multiple branches point to the same commit),\n+# only the first one is allowed to run. This allows a successful completion of\n+# the first run to be reused in the second run via the `skip-if-redundant`\n+# logic in the `config` job.\n+#\n+# For more details about the `concurrency` attribute, see:\n # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency\n concurrency:\n-  group: ${{ github.sha }}\n+  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n+  cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n \n jobs:\n   ci-config:\n\nbase-commit: c73e85354c275c9d409b26445089bc16940fc527\n-- \ngitgitgadget\n"}]}