{"id":85920,"date":"2025-04-25T09:00:37","date_gmt":"2025-04-25T16:00:37","guid":{"rendered":"https:\/\/github.blog\/?p=85920"},"modified":"2025-04-25T09:43:30","modified_gmt":"2025-04-25T16:43:30","slug":"how-the-github-cli-can-now-enable-triangular-workflows","status":"publish","type":"post","link":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/","title":{"rendered":"How the GitHub CLI can now enable triangular workflows"},"content":{"rendered":"<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\">\n<html><body><p>Most developers are familiar with the standard Git workflow. You create a branch, make changes, and push those changes back to the same branch on the main repository. Git calls this a centralized workflow. It&rsquo;s straightforward and works well for many projects.<\/p>\n<p>However, sometimes you might want to pull changes from a different branch directly into your feature branch to help you keep your branch updated without constantly needing to merge or rebase. However, you&rsquo;ll still want to push local changes to your own branch. This is where triangular workflows come in.<\/p>\n<p>It&rsquo;s possible that some of you have already used triangular workflows, even without knowing it. When you fork a repo, contribute to your fork, then open a pull request back to the original repo, you&rsquo;re working in a triangular workflow. While this can work seamlessly on github.com, the process hasn&rsquo;t always been seamless with the <a href=\"https:\/\/cli.github.com\/\">GitHub CLI<\/a>.<\/p>\n<p>The GitHub CLI team has recently made improvements (released in <a href=\"https:\/\/github.com\/cli\/cli\/releases\/tag\/v2.71.2\">v2.71.2<\/a>) to better support these triangular workflows, ensuring that the <code>gh pr<\/code> commands work smoothly with your Git configurations. So, whether you&rsquo;re working on a centralized workflow or a more complex triangular one, the GitHub CLI will be better equipped to handle your needs.<\/p>\n<p>If you&rsquo;re already familiar with how Git handles triangular workflows, feel free to skip ahead to learn about how to use <code>gh pr<\/code> commands with triangular workflows. Otherwise, let&rsquo;s get into the details of how Git and the GitHub CLI have historically differed, and how four-and-a-half years after it was first requested, we have finally unlocked managing pull requests using triangular workflows in the GitHub CLI.<\/p>\n<h2 id=\"first-a-lesson-in-git-fundamentals\" id=\"first-a-lesson-in-git-fundamentals\" ><a class=\"heading-link\" href=\"#first-a-lesson-in-git-fundamentals\">First, a lesson in Git fundamentals<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>To provide a framework for what we set out to do, it&rsquo;s important to first understand some Git basics. Git, at its core, is a way to store and catalog changes on a repository and communicate those changes between copies of that repository. This workflow typically looks like the diagram below:<\/p>\n<figure id=\"attachment_86915\"  class=\"wp-caption alignnone mx-0\"><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/triangular-image-1.png\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"457\" height=\"512\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/triangular-image-1.png?resize=457%2C512\" alt=\"Figure 1: A typical git branch setup\" class=\"width-fit size-full wp-image-86915 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/triangular-image-1.png?w=457 457w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/triangular-image-1.png?w=268 268w\" sizes=\"auto, (max-width: 457px) 100vw, 457px\" \/><\/a><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 1: A typical git branch setup<\/figcaption><\/figure>\n<p>The building blocks of this diagram illustrate two important Git concepts you likely use every day, a <strong>ref<\/strong> and <strong>push\/pull<\/strong>.<\/p>\n<h3 id=\"refs\" id=\"refs\" ><a class=\"heading-link\" href=\"#refs\">Refs<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h3>\n<p>A <strong>ref<\/strong> is a reference to a repository and branch. It has two parts: the <strong>remote<\/strong>, usually a name like <em>origin<\/em> or <em>upstream<\/em>, and the <strong>branch<\/strong>. If the remote is the local repository, it is blank. So, in the example above, <em>origin\/branch<\/em> in the purple box is a <strong>remote ref<\/strong>, referring to a branch named <em>branch<\/em> on the repository name <em>origin<\/em>, while <em>branch<\/em> in the green box is a <strong>local ref<\/strong>, referring to a branch named <em>branch<\/em> on the local machine.<\/p>\n<p>While working with GitHub, the remote ref is usually the repository you are hosting on GitHub. In the diagram above, you can consider the purple box GitHub and the green box your local machine.<\/p>\n<h3 id=\"pushing-and-pulling\" id=\"pushing-and-pulling\" ><a class=\"heading-link\" href=\"#pushing-and-pulling\">Pushing and pulling<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h3>\n<p>A <strong>push<\/strong> and a <strong>pull<\/strong> refer to the same action, but from two different perspectives. Whether you are pushing or pulling is determined by whether you are sending or receiving the changes. I can push a commit to your repo, or you can pull that commit from my repo, and the references to that action would be the same.<\/p>\n<p>To disambiguate this, we will refer to different refs as the <strong>headRef<\/strong> or <strong>baseRef<\/strong>, where the <strong>headRef<\/strong> is sending the changes (<em>pushing<\/em> them) and the <strong>baseRef<\/strong> is receiving the changes (<em>pulling<\/em> them).<\/p>\n<figure id=\"attachment_85923\"  class=\"wp-caption alignnone mx-0\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"864\" height=\"128\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image2_e1d22b.png?resize=864%2C128\" alt=\"Figure 2: Disambiguating headRef and baseRef for push\/pull operations.\" class=\"width-fit size-full wp-image-85923 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image2_e1d22b.png?w=864 864w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image2_e1d22b.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image2_e1d22b.png?w=768 768w\" sizes=\"auto, (max-width: 864px) 100vw, 864px\" \/><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 2: Disambiguating headRef and baseRef for push\/pull operations<\/figcaption><\/figure>\n<p>When dealing with a branch, we&rsquo;ll often refer to the headRef of its pull operations as its <strong>pullRef<\/strong> and the baseRef of its push operations as its <strong>pushRef<\/strong>. That&rsquo;s because, in these instances, the working branch is the pull&rsquo;s baseRef and the push&rsquo;s headRef, so they&rsquo;re already disambiguated.<\/p>\n<h4 id=\"the-push-revision-syntax\" id=\"the-push-revision-syntax\" ><a class=\"heading-link\" href=\"#the-push-revision-syntax\">The <code>@{push}<\/code> revision syntax<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h4>\n<p>Turns out, Git has a handy built-in tool for referring to the pushRef for a branch: the <code>@{push}<\/code> revision syntax. You can usually determine a branch&rsquo;s pushRef by running the following command:<\/p>\n<p><code>git rev-parse --abbrev-ref @{push}<\/code><\/p>\n<p>This will result in a human-readable ref, like <strong>origin\/branch<\/strong>, if one can be determined.<\/p>\n<h4 id=\"pull-requests\" id=\"pull-requests\" ><a class=\"heading-link\" href=\"#pull-requests\">Pull Requests<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h4>\n<p>On GitHub, a <strong>pull request<\/strong> is a proposal to integrate changes from one ref to another. In particular, they act as a simple &ldquo;pause&rdquo; before performing the actual integration operation, often called a <strong>merge<\/strong>, when changes are being pushed from ref to another. This pause allows for humans (code reviews) and robots (GitHub Copilot reviews and GitHub Actions workflows) to check the code before the changes are integrated. The name <em>pull request<\/em> came from this language specifically: You are requesting that a ref pulls your changes into itself.<\/p>\n<figure id=\"attachment_85924\"  class=\"wp-caption alignnone mx-0\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"864\" height=\"266\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image3_6e731a.png?resize=864%2C266\" alt=\"Figure 3: Demonstrating how GitHub Pull Requests correspond to pushing and pulling.\" class=\"width-fit size-full wp-image-85924 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image3_6e731a.png?w=864 864w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image3_6e731a.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image3_6e731a.png?w=768 768w\" sizes=\"auto, (max-width: 864px) 100vw, 864px\" \/><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 3: Demonstrating how GitHub Pull Requests correspond to pushing and pulling<\/figcaption><\/figure>\n<h2 id=\"common-git-workflows\" id=\"common-git-workflows\" ><a class=\"heading-link\" href=\"#common-git-workflows\">Common Git workflows<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>Now that you understand the basics, let&rsquo;s talk about the workflows we typically use with Git every day.<\/p>\n<p>A <strong>centralized workflow<\/strong> is how most folks interact with Git and GitHub. In this configuration, any given branch is pushing and pulling from a remote ref with the same branch name. For most of us, this type of configuration is set up by default when we clone a repo and push a branch. It is the situation shown in Figure 1.<\/p>\n<p>In contrast, a <strong>triangular workflow<\/strong> pushes to and pulls from <em>different<\/em> refs. A common use case for this configuration is to pull directly from a remote repository&rsquo;s default branch into your local feature branch, eliminating the need to run commands like <code>git rebase &lt;default&gt;<\/code> or <code>git merge &lt;default&gt;<\/code> on your feature branch to ensure the branch you&rsquo;re working on is always up to date with the default branch. However, when pushing changes, this configuration will typically push to a remote ref with the same branch name as the feature branch.<\/p>\n<figure id=\"attachment_86920\"  class=\"wp-caption alignnone mx-0\"><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1600\" height=\"703\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png?resize=1600%2C703\" alt=\"Figure 4: juxtaposing centralized workflows from triangular workflows.\" class=\"width-fit size-full wp-image-86920 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png?w=1600 1600w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png?w=1024 1024w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-4.png?w=1536 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 4: juxtaposing centralized workflows from triangular workflows.<\/figcaption><\/figure>\n<p>We complete the triangle when considering pull requests: the <strong>headRef<\/strong> is the <strong>pushRef<\/strong> for the local ref and the <strong>baseRef<\/strong> is the <strong>pullRef<\/strong> for the local branch:<\/p>\n<figure id=\"attachment_85926\"  class=\"wp-caption alignnone mx-0\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1549\" height=\"1069\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image5_9b14d8.png?resize=1549%2C1069\" alt=\"Figure 5: a triangular workflow\" class=\"width-fit size-full wp-image-85926 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image5_9b14d8.png?w=1549 1549w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image5_9b14d8.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image5_9b14d8.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image5_9b14d8.png?w=1024 1024w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image5_9b14d8.png?w=1536 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 5: a triangular workflow<\/figcaption><\/figure>\n<p>We can go one step further and set up triangular workflows using <em>different<\/em> remotes as well. This most commonly occurs when you&rsquo;re developing on a fork. In this situation, you usually give the fork and source remotes different names. I&rsquo;ll use <em>origin<\/em> for the fork and <em>upstream<\/em> for the source, as these are common names used in these setups. This functions exactly the same as the triangular workflows above, but the <strong>remotes<\/strong> and <strong>branches<\/strong> on the <strong>pushRef<\/strong> and <strong>pullRef<\/strong> are different:<\/p>\n<figure id=\"attachment_86922\"  class=\"wp-caption alignnone mx-0\"><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1600\" height=\"704\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png?resize=1600%2C704\" alt=\"Figure 6: juxtaposing triangular workflows and centralized workflows with different remotes such as with forks\" class=\"width-fit size-full wp-image-86922 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png?w=1600 1600w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png?w=1024 1024w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-6.png?w=1536 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 6: juxtaposing triangular workflows and centralized workflows with different remotes such as with forks<\/figcaption><\/figure>\n<h3 id=\"using-a-git-configuration-file-for-triangular-workflows\" id=\"using-a-git-configuration-file-for-triangular-workflows\" ><a class=\"heading-link\" href=\"#using-a-git-configuration-file-for-triangular-workflows\">Using a Git configuration file for triangular workflows<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h3>\n<p>There are two primary ways that you can set up a triangular workflow using the <a href=\"https:\/\/git-scm.com\/docs\/git-config\">Git configuration &ndash; typically defined in a `.git\/config` or `.gitconfig` file<\/a>. Before explaining these, let&rsquo;s take a look at what the relevant bits of a typical configuration look like in a repo&rsquo;s `.git\/config` file for a centralized workflow:<\/p>\n<pre><code class=\"language-plaintext\">[remote &ldquo;origin&rdquo;] \n    url = https:\/\/github.com\/OWNER\/REPO.git \n    fetch = +refs\/heads\/*:refs\/remotes\/origin\/*  \n[branch &ldquo;default&rdquo;]\n    remote = origin  \n    merge = refs\/heads\/default  \n[branch &ldquo;branch&rdquo;]\n    remote = origin \n    merge = refs\/heads\/branch\n<\/code><\/pre>\n<p><em>Figure 7: A typical Git configuration setup found in .git\/config<\/em><\/p>\n<p>The <code>[remote &ldquo;origin&rdquo;]<\/code> part is naming the Git repository located at <code>github.com\/OWNER\/REPO.git<\/code> to <em>origin,<\/em> so we can reference it elsewhere by that name. We can see that reference being used in the specific <code>[branch]<\/code> configurations for both the <em>default<\/em> and <em>branch<\/em> branches in their <code>remote<\/code> keys. This key, in conjunction with the branch name, typically makes up the branch&rsquo;s <strong>pushRef<\/strong>: in this example, it is <em>origin\/branch<\/em>.<\/p>\n<p>The <code>remote<\/code> and <code>merge<\/code> keys are combined to make up the branch&rsquo;s <strong>pullRef<\/strong>: in this example, it is <em>origin\/branch<\/em>.<\/p>\n<h3 id=\"setting-up-a-triangular-branch-workflow\" id=\"setting-up-a-triangular-branch-workflow\" ><a class=\"heading-link\" href=\"#setting-up-a-triangular-branch-workflow\">Setting up a triangular branch workflow<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h3>\n<p>The simplest way to assemble a triangular workflow is to set the branch&rsquo;s <code>merge<\/code> key to a different branch name, like so:<\/p>\n<pre><code class=\"language-plaintext\">[branch &ldquo;branch&rdquo;]\n    remote = origin\n    merge = refs\/heads\/default\n<\/code><\/pre>\n<p><em>Figure 8: a triangular branch&rsquo;s Git configuration found in .git\/config<\/em><\/p>\n<p>This will result in the branch <strong>pullRef<\/strong> as <em>origin\/default<\/em>, but <strong>pushRef<\/strong> as <em>origin\/branch<\/em>, as shown in Figure 9.<\/p>\n<figure id=\"attachment_86923\"  class=\"wp-caption alignnone mx-0\"><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-9.png\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1225\" height=\"1066\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-9.png?resize=1225%2C1066\" alt=\"Figure 9: A triangular branch workflow\" class=\"width-fit size-full wp-image-86923 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-9.png?w=1225 1225w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-9.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-9.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-9.png?w=1024 1024w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 9: A triangular branch workflow<\/figcaption><\/figure>\n<h3 id=\"setting-up-a-triangular-fork-workflow\" id=\"setting-up-a-triangular-fork-workflow\" ><a class=\"heading-link\" href=\"#setting-up-a-triangular-fork-workflow\">Setting up a triangular fork workflow<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h3>\n<p>Working with triangular forks requires a bit more customization than triangular branches because we are dealing with multiple remotes. Thus, our remotes in the Git config will look  different than the one shown previously in Figure 7:<\/p>\n<pre><code class=\"language-plaintext\">[remote &ldquo;upstream&rdquo;]\n    url = https:\/\/github.com\/ORIGINALOWNER\/REPO.git \n    fetch = +refs\/heads\/*:refs\/remotes\/upstream\/* \n[remote &ldquo;origin&rdquo;]\n    url = https:\/\/github.com\/FORKOWNER\/REPO.git  \n    fetch = +refs\/heads\/*:refs\/remotes\/origin\/*\n<\/code><\/pre>\n<p><em>Figure 10: a Git configuration for a multi-remote Git setup found in .git\/config<\/em><\/p>\n<p><em>Upstream<\/em> and <em>origin<\/em> are the most common names used in this construction, so I&rsquo;ve used them here, but they can be named anything you want<sup id=\"fnref-85920-1\"><a href=\"#fn-85920-1\" class=\"jetpack-footnote\" title=\"Read footnote.\">1<\/a><\/sup>.<\/p>\n<p>However, toggling a branch&rsquo;s <code>remote<\/code> key between <em>upstream<\/em> and <em>origin<\/em> won&rsquo;t actually set up a triangular fork workflow&mdash;it will just set up a centralized workflow with either of those remotes, like the centralized workflow shown in Figure 6. Luckily, there are two common Git configuration options to change this behavior.<\/p>\n<h4 id=\"setting-a-branchs-pushremote\" id=\"setting-a-branchs-pushremote\" ><a class=\"heading-link\" href=\"#setting-a-branchs-pushremote\">Setting a branch&rsquo;s <code>pushremote<\/code><span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h4>\n<p>A branch&rsquo;s configuration has a key called <code>pushremote<\/code> that does exactly what the name suggests: configures the remote that the branch will push to. A triangular fork workflow config using <code>pushremote<\/code> may look like this:<\/p>\n<pre><code class=\"language-plaintext\">[branch &ldquo;branch&rdquo;]\n    remote = upstream  \n    merge = refs\/heads\/default  \n    pushremote = origin\n<\/code><\/pre>\n<p><em>Figure 11: a triangular fork&rsquo;s Git config using pushremote found in .git\/config<\/em><\/p>\n<p>This assembles the triangular fork repo we see in Figure 12. The <strong>pullRef<\/strong> is <em>upstream\/default<\/em>, as determined by combining the <code>remote<\/code> and <code>merge<\/code> keys, while the <strong>pushRef<\/strong> is <em>origin\/branch<\/em>, as determined by combining the <code>pushremote<\/code> key and the branch name.<\/p>\n<figure id=\"attachment_86924\"  class=\"wp-caption alignnone mx-0\"><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-12.png\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1226\" height=\"1067\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-12.png?resize=1226%2C1067\" alt=\"Figure 12: A triangular fork workflow\" class=\"width-fit size-full wp-image-86924 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-12.png?w=1226 1226w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-12.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-12.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2025\/04\/triangular-image-12.png?w=1024 1024w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 12: A triangular fork workflow<\/figcaption><\/figure>\n<h4 id=\"setting-a-repos-remote-pushdefault\" id=\"setting-a-repos-remote-pushdefault\" ><a class=\"heading-link\" href=\"#setting-a-repos-remote-pushdefault\">Setting a repo&rsquo;s <code>remote.pushDefault<\/code><span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h4>\n<p>To configure all branches in a repository to have the same behavior as what you&rsquo;re seeing in Figure 12, you can instead set the repository&rsquo;s <code>pushDefault<\/code>. The config for this is below:<\/p>\n<pre><code class=\"language-plaintext\">[remote] \n    pushDefault = origin \n[branch &ldquo;branch&rdquo;]\n    remote = upstream \n    merge = refs\/heads\/default\n<\/code><\/pre>\n<p><em>Figure 13: a triangular fork&rsquo;s Git config using remote.pushDefault found in .git\/config<\/em><\/p>\n<p>This assembles the same triangular fork repo as shown in Figure 12 above, however this time the <strong>pushRef<\/strong> is determined by combining the <code>remote.pushDefault<\/code> key and the branch name, resulting in <em>origin\/branch<\/em>.<\/p>\n<p>When using the branch&rsquo;s <code>pushremote<\/code> and the repo&rsquo;s <code>remote.pushDefault<\/code> keys together, Git will preferentially resolve the branch&rsquo;s configuration over the repo&rsquo;s, so the remote set on <code>pushremote<\/code> supersedes the remote set on <code>remote.pushDefault<\/code>.<\/p>\n<h2 id=\"updating-the-gh-pr-command-set-to-reflect-git\" id=\"updating-the-gh-pr-command-set-to-reflect-git\" ><a class=\"heading-link\" href=\"#updating-the-gh-pr-command-set-to-reflect-git\">Updating the <code>gh pr<\/code> command set to reflect Git<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>Previously, the <code>gh pr<\/code> command set did not resolve <strong>pushRefs<\/strong> and <strong>pullRefs<\/strong> in the same way that Git does. This was due to technical design decisions that made this change both difficult and complex. Instead of discussing that complexity&mdash;a big enough topic for a whole article in itself&mdash;I&rsquo;m going to focus here on what you can now <em>do<\/em> with the updated <code>gh pr<\/code> command set.<\/p>\n<p><strong>If you set up triangular Git workflows in the manner described above, we will automatically resolve <code>gh pr<\/code> commands in accordance with your Git configuration.<\/strong><\/p>\n<p>To be slightly more specific, when trying to resolve a pull request for a branch, the GitHub CLI will respect whatever <code>@{push}<\/code> resolves to first, if it resolves at all. Then it will fall back to respect a branch&rsquo;s <code>pushremote,<\/code> and if that isn&rsquo;t set,  finally look for a repo&rsquo;s <code>remote.pushDefault<\/code> config settings.<\/p>\n<p>What this means is that the CLI is assuming your branch&rsquo;s <strong>pullRef<\/strong> is the pull request&rsquo;s <strong>baseRef<\/strong> and the branch&rsquo;s <strong>pushRef<\/strong> is the pull requests <strong>headRef<\/strong>. In other words, if you&rsquo;ve configured <code>git pull<\/code> and <code>git push<\/code> to work, then <code>gh pr<\/code> commands should just work.<sup id=\"fnref-85920-2\"><a href=\"#fn-85920-2\" class=\"jetpack-footnote\" title=\"Read footnote.\">2<\/a><\/sup> The diagram below, a general version of Figure 5, demonstrates this nicely:<\/p>\n<figure id=\"attachment_85930\"  class=\"wp-caption alignnone mx-0\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"965\" height=\"719\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image9.png?resize=965%2C719\" alt=\"Figure 14: the triangular workflow supported by the GitHub CLI with respect to a branch&rsquo;s pullRef and pushRef. This is the generalized version of Figure 5\" class=\"width-fit size-full wp-image-85930 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image9.png?w=965 965w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image9.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2025\/03\/image9.png?w=768 768w\" sizes=\"auto, (max-width: 965px) 100vw, 965px\" \/><figcaption class=\"text-mono color-fg-muted mt-14px f5-mktg\">Figure 14: the triangular workflow supported by the GitHub CLI with respect to a branch&rsquo;s pullRef and pushRef. This is the generalized version of Figure 5<\/figcaption><\/figure>\n<h2 id=\"conclusion\" id=\"conclusion\" ><a class=\"heading-link\" href=\"#conclusion\">Conclusion<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>We&rsquo;re constantly working to improve the GitHub CLI, and we&rsquo;d like the behavior of the GitHub CLI to reasonably reflect the behavior of Git. This was a team effort&mdash;everyone contributed to understanding, reviewing, and testing the code to enable this enhanced <code>gh pr<\/code> command set functionality.<\/p>\n<p>It also couldn&rsquo;t have happened without the support of our contributors, so we extend our thanks to them:<\/p>\n<ul>\n<li><code>@Frederick888<\/code> for opening the <a href=\"https:\/\/github.com\/cli\/cli\/pull\/9208\">original pull request<\/a>  <\/li>\n<li><code>@benknoble<\/code> for his support with pull request review and feedback  <\/li>\n<li><code>@phil-blain<\/code> for <a href=\"https:\/\/github.com\/cli\/cli\/issues\/575#issuecomment-668213138\">highlighting the configurations<\/a> we&rsquo;ve talked about here on the <a href=\"https:\/\/github.com\/cli\/cli\/issues\/575\">original issue<\/a>  <\/li>\n<li><code>@neutrinoceros<\/code> and <code>@rd-yan-farba<\/code> for reporting a <a href=\"https:\/\/github.com\/search?q=repo%3Acli%2Fcli+10352+10346&amp;type=issues\">couple of bugs<\/a> that the team fixed in <a href=\"https:\/\/github.com\/cli\/cli\/releases\/tag\/v2.66.1\">v2.66.1<\/a><\/li>\n<li><code>@pdunnavant<\/code> for <a href=\"https:\/\/github.com\/cli\/cli\/issues\/10857\">reporting the bug<\/a> that we fixed in v2.71.1<\/li>\n<li><code>@cs278<\/code> for <a href=\"https:\/\/github.com\/cli\/cli\/issues\/10862\">reporting the bug<\/a> that we fixed in v2.71.2.<\/li>\n<\/ul>\n<p>CLI native support for triangular workflows was 4.5 years in the making, and we&rsquo;re proud to have been able to provide this update for the community.<\/p>\n<p>The GitHub CLI Team<br>\n<code>@andyfeller<\/code>, <code>@babakks<\/code>, <code>@bagtoad<\/code>, <code>@jtmcg<\/code>, <code>@mxie<\/code>, <code>@RyanHecht<\/code>, and <code>@williammartin<\/code><\/p>\n<div class=\"footnotes\">\n<hr>\n<ol>\n<li id=\"fn-85920-1\">\nSome commands in gh are opinionated about remote names and will resolve remotes in this order: upstream, github, origin, <code>&lt;other remotes unstably sorted&gt;<\/code>. There is a convenience command you can run to supersede this:* <code>gh repo set-default [&lt;repository&gt;]<\/code> <em>to override the default behavior above and preferentially resolve<\/em> <code>&lt;repository&gt;<\/code> <em>as the default remote repo.<\/em>&nbsp;<a href=\"#fnref-85920-1\" title=\"Return to main content.\">&#8617;<\/a>\n<\/li>\n<li id=\"fn-85920-2\">\nIf you find a git configuration that doesn&rsquo;t work, please open an issue in the OSS repo so we can fix it.&nbsp;<a href=\"#fnref-85920-2\" title=\"Return to main content.\">&#8617;<\/a>\n<\/li>\n<\/ol>\n<\/div>\n<\/body><\/html>\n","protected":false},"excerpt":{"rendered":"<p>The GitHub CLI now supports common Git configurations for triangular workflows. Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. Then, see how you can leverage these using the GitHub CLI.<\/p>\n","protected":false},"author":2302,"featured_media":77359,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_gh_post_show_toc":"yes","_gh_post_is_no_robots":"no","_gh_post_is_featured":"yes","_gh_post_is_excluded":"no","_gh_post_is_unlisted":"no","_gh_post_related_link_1":"","_gh_post_related_link_2":"","_gh_post_related_link_3":"","_gh_post_sq_img":"","_gh_post_sq_img_id":"","_gh_post_cta_title":"","_gh_post_cta_text":"","_gh_post_cta_link":"","_gh_post_cta_button":"Click Here to Learn More","_gh_post_recirc_hide":"no","_gh_post_recirc_col_1":"78957","_gh_post_recirc_col_2":"78959","_gh_post_recirc_col_3":"78961","_gh_post_recirc_col_4":"65316","_featured_video":"","_gh_post_additional_query_params":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false,"_links_to":"","_links_to_target":""},"categories":[72,3330,67],"tags":[1735],"coauthors":[3635],"class_list":["post-85920","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","category-git","category-open-source","tag-github-cli"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.7 (Yoast SEO v27.7) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How the GitHub CLI can now enable triangular workflows - The GitHub Blog<\/title>\n<meta name=\"description\" content=\"Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. See how you can leverage them on the GitHub CLI.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How the GitHub CLI can now enable triangular workflows\" \/>\n<meta property=\"og:description\" content=\"Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. See how you can leverage them on the GitHub CLI.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/\" \/>\n<meta property=\"og:site_name\" content=\"The GitHub Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-25T16:00:37+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-04-25T16:43:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tyler McGoffin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tyler McGoffin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/\"},\"author\":{\"name\":\"Tyler McGoffin\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/7b9b9931c9f45a6063d8f6ad7765ef04\"},\"headline\":\"How the GitHub CLI can now enable triangular workflows\",\"datePublished\":\"2025-04-25T16:00:37+00:00\",\"dateModified\":\"2025-04-25T16:43:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/\"},\"wordCount\":2168,\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630\",\"keywords\":[\"GitHub CLI\"],\"articleSection\":[\"Engineering\",\"Git\",\"Open Source\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/\",\"url\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/\",\"name\":\"How the GitHub CLI can now enable triangular workflows - The GitHub Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630\",\"datePublished\":\"2025-04-25T16:00:37+00:00\",\"dateModified\":\"2025-04-25T16:43:30+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/7b9b9931c9f45a6063d8f6ad7765ef04\"},\"description\":\"Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. See how you can leverage them on the GitHub CLI.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#primaryimage\",\"url\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630\",\"contentUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630\",\"width\":1200,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/how-the-github-cli-can-now-enable-triangular-workflows\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/github.blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Open Source\",\"item\":\"https:\\\/\\\/github.blog\\\/open-source\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Git\",\"item\":\"https:\\\/\\\/github.blog\\\/open-source\\\/git\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"How the GitHub CLI can now enable triangular workflows\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/github.blog\\\/#website\",\"url\":\"https:\\\/\\\/github.blog\\\/\",\"name\":\"The GitHub Blog\",\"description\":\"Updates, ideas, and inspiration from GitHub to help developers build and design software.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/github.blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/7b9b9931c9f45a6063d8f6ad7765ef04\",\"name\":\"Tyler McGoffin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ad31ab9ea2e2e9462a00643776f6280cc8b04c927589a77fa3e433845c1d0f5b?s=96&d=mm&r=g4df5b778dea3d6c458f774fd3407af2e\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ad31ab9ea2e2e9462a00643776f6280cc8b04c927589a77fa3e433845c1d0f5b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ad31ab9ea2e2e9462a00643776f6280cc8b04c927589a77fa3e433845c1d0f5b?s=96&d=mm&r=g\",\"caption\":\"Tyler McGoffin\"},\"description\":\"Tyler is a Sr. Applied Researcher on the Copilot Applied Science team. He has an eclectic background in scientific research, education, game design\\\/development, and software. His favorite part about his current position is accelerating learning and research for his team and the organization as a whole.\",\"url\":\"https:\\\/\\\/github.blog\\\/author\\\/jtmcg\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How the GitHub CLI can now enable triangular workflows - The GitHub Blog","description":"Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. See how you can leverage them on the GitHub CLI.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/","og_locale":"en_US","og_type":"article","og_title":"How the GitHub CLI can now enable triangular workflows","og_description":"Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. See how you can leverage them on the GitHub CLI.","og_url":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/","og_site_name":"The GitHub Blog","article_published_time":"2025-04-25T16:00:37+00:00","article_modified_time":"2025-04-25T16:43:30+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png","type":"image\/png"}],"author":"Tyler McGoffin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Tyler McGoffin","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#article","isPartOf":{"@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/"},"author":{"name":"Tyler McGoffin","@id":"https:\/\/github.blog\/#\/schema\/person\/7b9b9931c9f45a6063d8f6ad7765ef04"},"headline":"How the GitHub CLI can now enable triangular workflows","datePublished":"2025-04-25T16:00:37+00:00","dateModified":"2025-04-25T16:43:30+00:00","mainEntityOfPage":{"@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/"},"wordCount":2168,"image":{"@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630","keywords":["GitHub CLI"],"articleSection":["Engineering","Git","Open Source"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/","url":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/","name":"How the GitHub CLI can now enable triangular workflows - The GitHub Blog","isPartOf":{"@id":"https:\/\/github.blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#primaryimage"},"image":{"@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630","datePublished":"2025-04-25T16:00:37+00:00","dateModified":"2025-04-25T16:43:30+00:00","author":{"@id":"https:\/\/github.blog\/#\/schema\/person\/7b9b9931c9f45a6063d8f6ad7765ef04"},"description":"Learn more about triangular workflows, how they work, and how to configure them for your Git workflows. See how you can leverage them on the GitHub CLI.","breadcrumb":{"@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#primaryimage","url":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630","contentUrl":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630","width":1200,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/github.blog\/open-source\/git\/how-the-github-cli-can-now-enable-triangular-workflows\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/github.blog\/"},{"@type":"ListItem","position":2,"name":"Open Source","item":"https:\/\/github.blog\/open-source\/"},{"@type":"ListItem","position":3,"name":"Git","item":"https:\/\/github.blog\/open-source\/git\/"},{"@type":"ListItem","position":4,"name":"How the GitHub CLI can now enable triangular workflows"}]},{"@type":"WebSite","@id":"https:\/\/github.blog\/#website","url":"https:\/\/github.blog\/","name":"The GitHub Blog","description":"Updates, ideas, and inspiration from GitHub to help developers build and design software.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/github.blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/github.blog\/#\/schema\/person\/7b9b9931c9f45a6063d8f6ad7765ef04","name":"Tyler McGoffin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ad31ab9ea2e2e9462a00643776f6280cc8b04c927589a77fa3e433845c1d0f5b?s=96&d=mm&r=g4df5b778dea3d6c458f774fd3407af2e","url":"https:\/\/secure.gravatar.com\/avatar\/ad31ab9ea2e2e9462a00643776f6280cc8b04c927589a77fa3e433845c1d0f5b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ad31ab9ea2e2e9462a00643776f6280cc8b04c927589a77fa3e433845c1d0f5b?s=96&d=mm&r=g","caption":"Tyler McGoffin"},"description":"Tyler is a Sr. Applied Researcher on the Copilot Applied Science team. He has an eclectic background in scientific research, education, game design\/development, and software. His favorite part about his current position is accelerating learning and research for his team and the organization as a whole.","url":"https:\/\/github.blog\/author\/jtmcg\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/github.blog\/wp-content\/uploads\/2024\/04\/1200x630-Collaboration-Unfurl-LIGHT-Logo.png?fit=1200%2C630","jetpack_shortlink":"https:\/\/wp.me\/pamS32-mlO","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/85920","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/users\/2302"}],"replies":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/comments?post=85920"}],"version-history":[{"count":22,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/85920\/revisions"}],"predecessor-version":[{"id":86979,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/85920\/revisions\/86979"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media\/77359"}],"wp:attachment":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media?parent=85920"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/categories?post=85920"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/tags?post=85920"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/coauthors?post=85920"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}