# Re: Triangular workflows

2 messages from 2026-01-05 to 2026-01-05. Participants: D. Ben Knoble.
Thread: https://gitlist.dev/t/64730

## D. Ben Knoble, 2026-01-05 22:19

Subject: Re: Triangular workflows
Message-ID: <CALnO6CB7-w0tNMiYn5=SCBow637vRRrKRj_9k1h1DS4crJaVtQ@mail.gmail.com>
URL: https://gitlist.dev/e/CALnO6CB7-w0tNMiYn5%3DSCBow637vRRrKRj_9k1h1DS4crJaVtQ%40mail.gmail.com
In-Reply-To: <CAHwyqnWwJuD4T9tuCArW5eY=rPCHKT71LroRRx-aYfDGwr8E9g@mail.gmail.com>

```
On Thu, Jan 1, 2026 at 2:43 PM Harald Nordgren <haraldnordgren@gmail.com> wrote:
>
> Hi Ben!
>
> Did you ever get to this? And does it match what I do in the tests for PATCH v10:
>
> ˋˋˋ
> git config remote.pushDefault origin
> git branch --set-upstream-to upstream/main
> ˋˋˋ
>
>
> Harald

Yeah, that's definitely part of it for me. I've been meaning to write
this down elsewhere for a while, but here's what my setup for
triangular workflows looks like.

First, there are typically 2 remotes (but not always!). In the
examples, I'll use "origin" (the place I usually cloned from first,
the most official version of the code, etc.; also the place I pull
from) and "benknoble" (the place I push to). The setup works just fine
with a single origin, though.

Next, I globally configure

    push.default = current
    pull.rebase = true
    branch.autoSetupRebase = always

The first works with other settings to make the @{push} ref work (and
to make "git push" work without arguments). I really like the @{push}
ref, and I'm not aware of any other way to enable it.

Then, when setting up a repository I configure remotes and make sure
to configure

    remote.pushDefault = benknoble

(if there is such a remote).

The next step is usually starting a branch:

    git switch -c branch origin # or origin/main, or whatever

With the above settings, I immediately have
- branch@{upstream} (@{u}) -> origin/…
- branch@{push} (@{push}) -> benknoble/branch (or origin/branch,
depending on the case)



-- 
D. Ben Knoble

```

## D. Ben Knoble, 2026-01-05 22:36

Subject: Re: Triangular workflows
Message-ID: <CALnO6CAUSU-Pq_r-WYm3o0to6H8MdqiYOuoKaRfL1PTt30VaoQ@mail.gmail.com>
URL: https://gitlist.dev/e/CALnO6CAUSU-Pq_r-WYm3o0to6H8MdqiYOuoKaRfL1PTt30VaoQ%40mail.gmail.com
In-Reply-To: <CALnO6CB7-w0tNMiYn5=SCBow637vRRrKRj_9k1h1DS4crJaVtQ@mail.gmail.com>

```
On Mon, Jan 5, 2026 at 5:19 PM D. Ben Knoble <ben.knoble@gmail.com> wrote:
>
> On Thu, Jan 1, 2026 at 2:43 PM Harald Nordgren <haraldnordgren@gmail.com> wrote:
> >
> > Hi Ben!
> >
> > Did you ever get to this? And does it match what I do in the tests for PATCH v10:
> >
> > ˋˋˋ
> > git config remote.pushDefault origin
> > git branch --set-upstream-to upstream/main
> > ˋˋˋ
> >
> >
> > Harald
>
> Yeah, that's definitely part of it for me. I've been meaning to write
> this down elsewhere for a while, but here's what my setup for
> triangular workflows looks like.
>
> First, there are typically 2 remotes (but not always!). In the
> examples, I'll use "origin" (the place I usually cloned from first,
> the most official version of the code, etc.; also the place I pull
> from) and "benknoble" (the place I push to). The setup works just fine
> with a single origin, though.
>
> Next, I globally configure
>
>     push.default = current
>     pull.rebase = true
>     branch.autoSetupRebase = always
>
> The first works with other settings to make the @{push} ref work (and
> to make "git push" work without arguments). I really like the @{push}
> ref, and I'm not aware of any other way to enable it.
>
> Then, when setting up a repository I configure remotes and make sure
> to configure
>
>     remote.pushDefault = benknoble
>
> (if there is such a remote).
>
> The next step is usually starting a branch:
>
>     git switch -c branch origin # or origin/main, or whatever
>
> With the above settings, I immediately have
> - branch@{upstream} (@{u}) -> origin/…
> - branch@{push} (@{push}) -> benknoble/branch (or origin/branch,
> depending on the case)

Premature send :/

Anyway, after working for a bit, I can use "git pull" to synchronize
with upstream via rebasing (since it's WIP, I don't mind, though for
Git I have to remember to --keep-base anytime I rebase). Ditto for
"git rebase" without a fetch, or when squashing ("git rs" = "git
rebase --autosquash"). When I want to send out a new version, I "git
push" (or "pf", an alias for "push --force-with-lease"; additionally
I've already configured push.useForceIfIncludes = true); I typically
first take a range-diff as described in my other mail (alias: rdup
does "git range-diff @{upstream} @{push} @" and rdupc does "git rdup |
copy-range-diff").

The last piece of the puzzle for me are "interrogation commands": like
"git status", where am I wrt to all these branches? I use 2

- "git sbup" is my alias for "git show-branch HEAD HEAD@{upstream} HEAD@{push}"
- "git div" is described at [1], but it draws a graph between my HEAD
and either upstream or push, depending on whether I've already pushed
out the current version (the newest version [2] is a bit smarter than
the original post describes). The graph uses cherry-mark and some
other options so I can decide how to handle divergence: do I need to
integrate someone else's changes? From which branch? How? I also use
this a lot to look between a new release candidate and a past release
at work to make sure we're not missing any patches that might have
gone in on the last release branch but not into the latest candidate.
And with repositories that commit accepted patches to the trunk, I
know I can delete my branch when "git div" shows all "=", even though
Git refuses without "--force" (for good and clear reasons, just a
note).

Anyway, my workflow for this all came about because I wanted to "git
pull" and "git push" (and "git rebase") without arguments and still be
able to sync from upstream while sending to another place for PR-style
review.

The only downside so far is that "git div" in git.git can show too
much information due to all the topic branch merges. Adding
--first-parent helps, but the --boundary commits still make a mess for
trying to view things. But in repositories that commit accepted
patches directly to the main branch, it works great. (If anyone has a
version of "show me the graph of divergence" that doesn't turn into a
spider web when looking at git.git, LMK. A good test case is the
recent je/doc-reset topic. I have a remote "broken-out" pointing at
gitster/git on GitHub, and "git div broken-out/je/doc-reset
origin/master" is difficult to read after the first few lines. But if
you rebase it atop the latest master, it's very easy to see what's
going on.)

[1]: https://benknoble.github.io/blog/2024/11/15/useful-utilities/#git
[2]: https://github.com/benknoble/Dotfiles/blob/master/links/bin/git-div

-- 
D. Ben Knoble

```
