I’d like to lay out the branching strategy for future Rust releases. The 1.0 release is going to be a bit different than the rest, but will initiate the ‘usual’ process going on into the future.
Why have a different process for 1.0? There are two reasons:
- We’re already past the point of the ‘usual’ process. That is, we haven’t actually started branching yet. Doing it the usual way would require a time machine.
- 1.0 has special requirements, as we’ll be backporting basically all patches from
master
for this initial period, and so branching too early just adds overhead.
Let’s get to it. I’m going to be using graphs like this to show the branching:
master: A - B - C
\
release: D - C'
The branch name is on the left, and commits are capital letters. Primes ('
)
are used to indicate backported commits. release
branched off of master
at
B
, and C'
was backported from C
on master, in this diagram.
Rust has more than three commits on master so far, but we’ll pretend like all that history doesn’t exist for simplification purposes.
Here’s Rust development today:
master: A - B
At some point, preferably on the 24th of April, halfway through the beta cycle, we’ll
cut a branch for 1.0, called 1.0-beta
:
master: A - B
\
1.0-beta:
All regular work will keep going on the master
branch:
master: A - B - C - D
\
1.0-beta:
This is the important part of this strategy. Everything lands on master
first. master
is the canonical source of truth from which all else flows.
New -beta
branches always end up forking off of master
.
When a committer determines that a commit should be backported to the beta branch, they’ll open a second PR against the beta branch directly. We could also possibly automate this through @bors, though some commits may need massaging, of course. And generally speaking, after 1.0, backports should be relatively rare.
master: A - B - C - D - E
\
1.0-beta: E'
And work continues...
master: A - B - C - D - E - F
\
1.0-beta: E'
And other commits are backported:
master: A - B - C - D - E - F - G
\
1.0-beta: E' - G'
I’m going to shorten the commits a tad to make it smaller:
master: A - B - C - ... - G
\
1.0-beta: E' - G'
Anyway, then, on May 15, the release happens. At that time, we cut a
1.0-stable
branch from 1.0-beta
:
master: A - B - C - ... - G
\
1.0-beta: E' - G'
\
1.0-stable:
Just like -beta
branches always come off of master
, -stable
branches
always come off of their associated -beta
branch.
Speaking of which, we cut a new, 1.1-beta branch from master
:
master: A - B - C - ... - G
\ \
1.1-beta: \
\
1.0-beta: E' - G'
\
1.0-stable:
Ideally, the 1.0-*
branches won’t need anything more than that. But let’s say
we discover a critical security, and fix it with H
:
master: A - B - C - ... - G - H
\ \
1.1-beta: \ H'
\
1.0-beta: E' - G' - H''
\
1.0-stable: H'''
H
needs to be backported against every relevant branch, possibly a number of
them.
Let’s do some more work:
master: A - B - C - ... - G - H - I
\ \
1.1-beta: \ H'
\
1.0-beta: E' - G' - H''
\
1.0-stable: H'''
and backport a new commit to 1.1-beta
:
master: A - B - C - ... - G - H - I - J
\ \
1.1-beta: \ H' - J'
\
1.0-beta: E' - G' - H''
\
1.0-stable: H'''
Now it’s time to release 1.1. We do the same as before: we make a new
1.1-stable
and 1.2-beta
branches:
master: A - B - C - ... - G - H - I - J
\ \ \
1.2-beta: \ \
\ \
1.1-beta: \ H' - J'
\ \
1.1-stable: \
\
1.0-beta: E' - G' - H''
\
1.0-stable: H'''
And more work gets done on master
:
master: A - B - C - ... - G - H - I - J - K
\ \ \
1.2-beta: \ \
\ \
1.1-beta: \ H' - J'
\ \
1.1-stable: \
\
1.0-beta: E' - G' - H''
\
1.0-stable: H'''
And backported to 1.2-beta
where need be:
master: A - B - C - ... - G - H - I - J - K - L
\ \ \
1.2-beta: \ \ L'
\ \
1.1-beta: \ H' - J'
\ \
1.1-stable: \
\
1.0-beta: E' - G' - H''
\
1.0-stable: H'''
Until 1.2 gets released, when a new 1.2-stable
and 1.3-beta
branches get
made. And so on and so on and so on.