Categories: Fun

Jujutsu megamerges for enjoyable and revenue

This web page was created programmatically, to learn the article in its unique location you possibly can go to the hyperlink bellow:
https://isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit
and if you wish to take away this text from our web site please contact us


This article is written each for intermediate Jujutsu customers and for Git customers
who’re inquisitive about Jujutsu.

I’m an enormous Jujutsu consumer, and I’ve discovered myself relying increasingly more on
what we within the JJ group colloquially name the “megamerge” workflow for my
every day growth. It’s surprisingly under-discussed exterior of a handful of
energy customers, so I wished to share what that appears like and why it’s so helpful,
particularly if you happen to’re in a posh dev surroundings or are inclined to ship plenty of small
PRs.

In a rush? Skip to the end for some fast ideas.

Merge commits aren’t what you assume they’re

If you’re a mean Git consumer (or perhaps a Jujutsu consumer who hasn’t dug too deep
into extra superior workflows), it’s possible you’ll be stunned to be taught that there’s
completely nothing particular a couple of merge commit. It’s not some particular case
that has its personal guidelines. It’s only a regular commit that has a number of mother and father. It
doesn’t even should be empty!1

@  myzpxsys Isaac Corbrey 12 seconds in the past 634e82e2
(empty) (no description set)
mllmtkmv Isaac Corbrey 12 seconds in the past git_head() 947a52fd
├─╮  (empty) Merge the issues
│ ○  vqsqmtlu Isaac Corbrey 12 seconds in the past f41c796e
│ │  deps: Pin quantum manifold resolver
○ │  tqqymrkn Isaac Corbrey 19 seconds in the past 0426baba
├─╯  storage: Align transient cache manifolds
  zzzzzzzz root() 00000000
Gotta put all of it collectively!

You could also be much more stunned to be taught that merge commits should not restricted
to having two mother and father. We unofficially name merge commits with three or extra
mother and father “octopus merges”, and when you could also be pondering to your self “in what
world would I wish to merge greater than two branches?”, that is truly a extremely
highly effective concept. Octopus merges energy the whole megamerge workflow!

So what the hell is a megamerge?

Basically, within the megamerge workflow you might be not often working immediately off the
ideas of your branches. Instead, you create an octopus merge commit (hereafter
known as “the megamerge”) because the youngster of each working department you care
about. This means bugfixes, characteristic branches, branches you’re ready on PRs
for, different peoples’ branches you want your code to work with, native surroundings
setup branches, even non-public commits that will not be or belong in any department.
Everything you care about goes within the megamerge. It’s essential to recollect
that you don’t push the megamerge, solely the branches it composes.

@  mnrxpywt Isaac Corbrey 25 seconds in the past f1eb374e
(empty) (no description set)
wuxuwlox Isaac Corbrey 25 seconds in the past git_head() c40c2d9c
├─┬─╮  (empty) megamerge
│ │ ○  ttnyuntn Isaac Corbrey 57 seconds in the past 7d656676
│ │ │  storage: Align transient cache manifolds
│ ○ │  ptpvnsnx Isaac Corbrey 25 seconds in the past 897d21c7
│ │ │  parser: Deobfuscate fleem tokens
│ ○ │  zwpzvxmv Isaac Corbrey 37 seconds in the past 14971267
│ │ │  infra: Refactor blob allocator
│ ○ │  tqxoxrwq Isaac Corbrey 57 seconds in the past 90bf43e4
│ ├─╯  io: Unjam polarity valves
○ │  moslkvzr Isaac Corbrey 50 seconds in the past 753ef2e7
│ │  deps: Pin quantum manifold resolver
○ │  qupprxtz Isaac Corbrey 57 seconds in the past 5332c1fd
├─╯  ui: Defrobnicate structure heuristics
wwtmlyss Isaac Corbrey 57 seconds in the past 5804d1fd
│  take a look at: Add hyperfrobnication suite
  zzzzzzzz root() 00000000
Scary! Too a lot merge!

It’s okay if this feels like lots. After all, you know the way a lot effort you
put into switching contexts if it’s important to revisit an outdated PR to get it reviewed,
amongst different issues. However, this allows just a few actually invaluable issues for you:

  1. You are all the time engaged on the mixed sum of your entire work. This
    implies that in case your working copy compiles and runs with out situation, you already know
    that your work will all work together with out situation.
  2. You not often have to fret about merge conflicts. You already don’t have to
    fear about merge conflicts a ton since conflicts are a first-class idea
    in Jujutsu, however because you’re actually all the time merging your modifications collectively
    you’ll by no means be struck with shock merge conflicts on the forge facet.
    There may be the occasional situation with contributors’ modifications, however in my
    expertise this hasn’t been a significant downside.
  3. There’s approach much less friction when switching between duties. Since you’re
    all the time engaged on prime of the megamerge, you by no means have to go to your VCS to
    change duties. You can simply go edit what you should. This additionally means it’s approach
    simpler to make small PRs for drive-by refactors and bugfixes.
  4. It’s simpler to maintain your branches updated. With slightly magic, you
    can hold your whole megamerge updated together with your trunk department with a
    single rebase command. I’ll present you ways to try this afterward.

How do I make one?

Starting a megamerge is tremendous easy: simply make a brand new commit with every department
you need within the megamerge as a dad or mum. I like to offer that commit a reputation and
depart it empty, like so:

jj new x y z
jj commit --message "megamerge"
Making megamerges. It’s not so exhausting in any case!

You’re then left with an empty commit on prime of this complete factor. This is the place
you do your work! Anything above the megamerge commit is taken into account WIP. You’re
free to separate issues out as you should, make a number of branches based mostly on that
megamerge commit, no matter you wish to do. Everything you write can be based mostly on
the sum of every thing throughout the megamerge, identical to we wished!

Of course, in some unspecified time in the future you’ll be pleased with what you could have, and also you’ll be left
questioning:

How do I truly submit my modifications?

How you get your WIP modifications into your megamerge relies on the place they should
land. If you’re making modifications that ought to land in present modifications, you possibly can
use the squash command with the --to flag to shuffle them into the correct
downstream commits. If your commit comprises a number of commits’ value of modifications,
you possibly can both break up it out into a number of commits earlier than squashing them or
(what I desire) interactively squash with squash --interactive to only choose
out the precise items to maneuver.

# Squash a complete WIP commit (defaults to `--from @`)
jj squash --to x --from y

# Interactively squash a part of a WIP commit (defaults to `--from @`)
jj squash --to x --from y --interactive
Hunk, I select you!

Of course, Jujutsu is an attractive piece of software program and has some automation for
this! The soak up command will do quite a lot of this for you by figuring out which
downstream mutable commit every line or hunk of your present commit belong in and
robotically squashing them down for you. This appears like magic each time
I take advantage of it (and never the evil black field black magic form of magic the place nothing can
be understood), and it’s one of many core items of Jujutsu’s performance that
make the megamerge workflow so seamless.

# Automagically autosquash your modifications (defaults to `--from @`)
jj soak up --from x
Ope, that was quick.

Absorbing gained’t all the time catch every thing in your commit, but it surely’ll often get at
least 90% of your modifications. The relaxation are both simply squashable downstream or
unrelated to any earlier commit.

Conveniently, issues aren’t rather more sophisticated if I’ve modifications that belong
in a brand new commit. If the commit belongs in one of many branches I’m engaged on, I
can simply rebase it myself and transfer the bookmark accordingly.

jj commit
jj rebase --revision x --after y --before megamerge
jj bookmark transfer --from y --to x

Let’s break that rebase down to raised perceive the way it works:

# We're gonna transfer some commits round!
jj rebase
    # Let's transfer our WIP commit(s) x...
    --revision x
        # in order that they arrive after y (e.g. trunk())...
        --after y
            # and develop into a dad or mum of the megamerge.
            --before megamerge
Slightly little bit of rocket surgical procedure, as a deal with.

If I’ve began work on a completely new characteristic or discovered an unrelated bug to
repair, then it’s even easier! Using just a few aliases, I can tremendous simply embrace new
modifications in my megamerge:2

[revset-aliases]
# Returns the closest merge decide to `to`
"closest_merge(to)" = "heads(::to & merges())"

[aliases]
# Inserts the given revset as a brand new department underneath the megamerge.
stack = ["rebase", "--after", "trunk()", "--before", "closest_merge(@)", "--revision"]

Here’s a fast clarification of what closest_merge(to) is definitely doing:

heads(                 # Return solely the topologically tip-most commit inside...
      ::to             # the set of all commits which can be ancestors of `to`...
           & merges()) # ...which can be additionally merge commits.

Using that revset alias, stack lets us goal any revset we would like and insert it
between trunk() (your important growth department) and our megamerge commit:

jj stack x::y
Whoa, that was neat!

This is extra helpful if I’ve a number of stacks of modifications I wish to embrace in
parallel; if it’s only one, I’ve one other alias that simply will get the whole stack
of modifications after the megamerge:

[aliases]
stage = ["stack", "closest_merge(@)+:: ~ empty()"]
closest_merge(@)+::           # Return the descendants of the closest merge
                              # decide to the working copy...
                    ~ empty() # ...with none empty commits.

This one doesn’t require any enter! Just have your commits prepared and stage ‘em:

jj stage
Wait, what? You can do this?

The final lacking piece of this megamerge puzzle is (sadly) coping with
the fact that’s different individuals:

How do I hold all this crap updated?

That’s an amazing query, and one I spent a pair months attempting to reply in
a common sense. Jujutsu has a very easy approach of rebasing your whole working
tree onto your important department:

jj rebase --onto trunk()
Nice.

However, this solely works in case your whole worktree is your modifications. When you attempt
to reference commits you don’t personal (like untracked bookmarks or different individuals’s
branches) Jujutsu will cease early to guard them from being rewritten.3

Wait, not so good. How do I do that?

Let’s repair that by rebasing solely the commits we truly management. I struggled
with this one for some time, however fortunately the Jujutsu group is superior.
Kudos to Stephen Jennings for developing with this superior revset:

[aliases]
restack = ["rebase", "--onto", "trunk()", "--source", "roots(trunk()..) & mutable()", "--simplify-parents"]
roots(                       # Get the furthest upstream commits...
      trunk()..)             # ...within the set of all descendants of ::trunk()...
                 & mutable() # ...and solely return ones we're allowed to change.

Rather than attempting to rebase our whole working tree (like jj rebase --onto trunk() tries to do), this alias solely targets commits we’re truly allowed to
transfer. This leaves behind branches that we don’t management in addition to work that’s
stacked on prime of different individuals’s branches. With --simplify-parents we can also
clear up any gross edges left behind by this course of. It has but to fail me,
even with monster ninefold mixed-contributor megamerges! (Say that 5 instances
quick.)

There we go, that is higher!

TL;DR

Jujutsu megamerges are tremendous cool and allow you to work on many various streams of
work concurrently. Read the entire article for an in-depth clarification of how
they work. For a brilliant ergonomic setup, add these to your config with jj config edit --user:

[revset-aliases]
"closest_merge(to)" = "heads(::to & merges())"

[aliases]
# `jj stack ` to incorporate particular revs
stack = ["rebase", "--after", "trunk()", "--before", "closest_merge(@)", "--revision"]

# `jj stage` to incorporate the entire stack after the megamerge
stage = ["stack", "closest_merge(@)+:: ~ empty()"]

# `jj restack` to rebase your modifications onto `trunk()`
restack = ["rebase", "--onto", "trunk()", "--source", "roots(trunk()..) & mutable()", "--simplify-parents"]

Use soak up and/or squash --interactive to get new modifications into present
commits, commit and rebase to make new commits underneath your megamerge,
and commit with stack or stage to maneuver whole branches into your
megamerge.4

# Changes that belong in present commits
jj soak up
jj squash --to x --interactive

# Changes that belong in new commits
jj rebase --revision y --after x

# Stack something on prime of the megamerge into it
jj stage

# Stack particular revsets into the megamerge
jj stack w::z

Remember that megamerges aren’t actually meant to be pushed to your distant;
they’re only a handy approach of displaying your self the entire image. You’ll
nonetheless wish to publish branches individually as traditional.

I stay on this always, and you’ll too.

Megamerges will not be everybody’s cup of tea – I’ve actually gotten just a few
horrified takes care of displaying my working tree – however when you attempt them, you’ll
possible discover they allow you to bounce between duties with virtually no effort. Give them
a attempt!

Errata

  • I utterly forgot about --simplify-parents on restack! This makes it so
    you may get a clear log after restacking your commits by eliminating redundant
    edges (e.g. if A-B-C and A-C exist, simplify-parents will eradicate A-C).
  • stage ought to be utilizing closest_merge(@)+::, not closest_merge(@).. as you
    don’t wish to pull in every thing from all time! x.. does technically embrace
    x+::, but it surely’s equal to ~::x, which incorporates something that isn’t a
    direct ancestor of x!


This web page was created programmatically, to learn the article in its unique location you possibly can go to the hyperlink bellow:
https://isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit
and if you wish to take away this text from our web site please contact us

fooshya

Share
Published by
fooshya

Recent Posts

Best Bongs and Cannabis Smoking Accessories: Where to Buy Bongs Online

This web page was created programmatically, to learn the article in its unique location you'll…

1 minute ago

FIFA to place extra World Cup tickets on sale for all video games

This web page was created programmatically, to learn the article in its authentic location you'll…

7 minutes ago

The Soccer Tournament’s ‘Home Run Derby’ occasion in Cary combines baseball and soccer :: WRAL.com

This web page was created programmatically, to learn the article in its authentic location you…

9 minutes ago

A Requiem in Mild: Ming Smith’s Early Imaginative and prescient

This web page was created programmatically, to learn the article in its unique location you…

12 minutes ago

Dyson’s again with a travel-size Supersonic hair dryer

This web page was created programmatically, to learn the article in its unique location you…

21 minutes ago

ICE’s Sensible Glasses Are a Worst-Case State of affairs

This web page was created programmatically, to learn the article in its authentic location you…

25 minutes ago