R0KernelPath
module 103 / 262

The Release Cycle: Merge Window, -rc, linux-next

The Linux kernel's 10-week heartbeat: how 15,000 commits per cycle travel from a contributor's inbox through maintainer trees, linux-next, and Linus's merge window to the kernel your devices run.

~8h focused study12 concepts

Overview

The Linux kernel is one of the most complex, actively developed software projects in human history — with thousands of contributors, millions of lines of code, and releases every 9-10 weeks like clockwork. Understanding how that machine works is not optional for a contributor; it is the difference between having your patch accepted and watching it disappear into the void.

The release cycle is the heartbeat of the kernel project. Every feature, every driver, every bug fix has to travel a specific path through a specific set of trees, at a specific time, reviewed by specific humans, before Linus Torvalds ever sees it. Get the timing wrong by a single week and your patch waits another 10 weeks. Get the tree wrong and it may never arrive at all.

This module traces the full lifecycle of kernel development: from the moment a new cycle opens (the merge window), through the seven or eight release-candidate snapshots (-rc1 through -rc8), to the final release, and then into the stable and LTS maintenance streams that keep production systems safe for years. You'll learn about subsystem maintainer trees, the linux-next integration-testing tree, and the precise social and technical machinery that lets thousands of people collaborate without chaos.

What makes this beautiful is that the entire system is low-tech by design. There is no ticket system, no mandatory CI gate at the center, no monolithic repo server. It is a web of Git trees, mailing lists, and trust — and it scales to 70,000+ commits per release because the trust is real, the process is respected, and everyone understands the rules. By the end of this module, you will understand those rules well enough to navigate them yourself.

why this matters for the kernel

A patch that arrives at the wrong time, to the wrong tree, is not rejected on technical grounds — it is simply invisible. Maintainers follow the cycle religiously; a patch sent during the merge window to a subsystem tree that has already been pulled will sit in a queue until the next cycle. For a first-time contributor, not understanding this is the single most common reason a technically correct patch never gets merged. Knowing the cycle turns your effort from a lottery into a navigable process.

Beyond timing, the cycle reflects a deep philosophy about stability and velocity that shapes every architectural decision in the kernel. The strict separation between the bleeding-edge development tree and the stable/LTS trees is not bureaucracy — it is the reason your Android phone, your cloud server, and your router can all run Linux kernels that are reliable enough for production, even though the mainline tree is changing hundreds of times a day. Understanding this duality — fast upstream, conservative stable — is foundational to understanding why the kernel is the way it is.

Linux Kernel Release Cycle and Patch Flow

rendering diagram…

The full kernel development cycle: patches accumulate in subsystem trees all cycle long, flow through linux-next for integration testing, then flood into Linus's tree during the merge window. After release, stable and LTS trees carry critical fixes forward to production systems.

The concepts

01The Big Picture: One Cycle, ~10 Weeks

A Linux kernel development cycle runs roughly 9 to 10 weeks from start to finish. It begins the moment Linus releases a new kernel (say, v6.9), immediately opens a two-week merge window, then enters a stabilization phase of roughly 7-8 weekly release candidates (-rc1, -rc2, ..., -rcN), and ends with the next final release (v6.10).

The versioning scheme is straightforward: v<major>.<minor>. As of the modern era (post-v3.0), the major number almost never changes — Linus increments the minor number every cycle. There is no fixed calendar date for a release; Linus decides when -rcN is stable enough, typically after 7 or 8 candidates. The whole process repeats indefinitely.

Think of it as a river with a flood season and a dry season. During the merge window, the floodgates open and huge volumes of new code pour in. Then the floodgates close, and the next several weeks are spent calmly letting the sediment settle — fixing bugs, not adding features. By the time the river reaches the sea (final release), it is clear.

# Check the current kernel version on a running Linux system
uname -r
# Example output: 6.9.3-arch1-1
#                 ^   ^   ^
#                 |   |   +-- distro/local patch level
#                 |   +------ stable update number
#                 +---------- kernel version (major.minor)

# On kernel.org, development is tracked like this:
# v6.9   -- released, starts v6.10 merge window
# v6.10-rc1  -- first release candidate
# v6.10-rc7  -- late stabilization
# v6.10      -- final release

02The Merge Window: Two Weeks of Maximum Velocity

The merge window is the only time new features, new subsystems, new drivers, and significant refactors can enter Linus's tree (the official torvalds/linux repository on kernel.org). It lasts approximately two weeks after the previous release.

During this window, subsystem maintainers send Linus a pull request — a Git pull request in the literal Git sense, not a GitHub PR. They send an email with a signed Git tag pointing to their subsystem tree, and Linus executes git pull to merge it. Thousands of commits can arrive in a single pull. In recent cycles, the merge window absorbs 10,000-15,000 commits.

There is a crucial prerequisite: the code being merged during the window must already be reviewed, tested, and staged in a maintainer's subsystem tree. Maintainers do not scramble to collect patches during the merge window — they have been accumulating and reviewing patches for the entire previous cycle. The merge window is just the time those already-reviewed batches flow upward to Linus.

This is a key insight: the two-week window looks like chaos from the outside, but it is actually the harvest phase of a 10-week growing season. The real work happened earlier.

# What a maintainer's pull request email looks like (simplified):
# From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
# To: Linus Torvalds <torvalds@linux-foundation.org>
# Subject: [GIT PULL] driver core changes for v6.10-rc1
#
# The following changes since commit abc123...:
#
# Please pull the following Linus git tree:
#
#   git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
#   tags/driver-core-6.10-rc1
#
# Shortlog:
#   ...(list of commits)...

# Linus runs something like:
git pull \
  git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git \
  tags/driver-core-6.10-rc1

03Release Candidates: -rc1 Through -rcN

Once Linus closes the merge window (usually by issuing -rc1 and sending an email declaring it closed), the kernel enters stabilization mode. No new features. Only bug fixes, regression fixes, and documentation improvements.

Each Sunday (roughly), Linus releases a new release candidate snapshot: -rc1, -rc2, ..., typically up to -rc7 or -rc8. Each -rc is a real, bootable kernel. Testers worldwide download and run these kernels on diverse hardware, and bug reports flow back to maintainers and Linus via the mailing lists.

-rc1 is the roughest. It contains all the newly merged code and often has regressions — bugs in code that used to work but broke due to new changes. These are treated with extreme urgency; Linus is famously vocal about regressions and his policy is clear: a regression is always a bug.

-rc4 to -rc6 is typically where things stabilize. Patch volume drops sharply. Only high-confidence fixes make it in.

-rc7 or -rc8 is essentially a release rehearsal. If no critical bugs appear, Linus declares it final.

The release candidate phase is where you as a tester can contribute enormously, even before writing code. Running linux-next or -rc kernels and reporting bugs (with git bisect to pinpoint the offending commit) is valued work.

# Fetch and build an -rc kernel from kernel.org
# (assumes you have build dependencies installed)

# 1. Clone the mainline tree (shallow for speed)
git clone --depth=1 \
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git \
  linux-mainline
cd linux-mainline

# 2. Check out a release candidate tag
git fetch --tags
git checkout v6.10-rc5

# 3. Use your running kernel's config as a base
cp /boot/config-$(uname -r) .config
make olddefconfig   # accept defaults for new options

# 4. Build (use all cores)
make -j$(nproc)

# 5. Install (distro-specific; here: Debian/Ubuntu style)
sudo make modules_install
sudo make install

04Subsystem Maintainer Trees: The Real Architecture

Linus does not review individual patches. That would be physically impossible — there are thousands of patches per cycle. Instead, the kernel is divided into subsystems, each maintained by one or two trusted maintainers who do review patches in their area.

Examples:

  • Greg Kroah-Hartman maintains the USB subsystem, driver core, staging, tty, and more
  • David S. Miller (and Jakub Kicinski) maintain the networking stack
  • Tejun Heo maintains cgroups and block I/O
  • Thomas Gleixner maintains x86 arch code, timers, and IRQ subsystems

Each maintainer has a public Git tree on kernel.org (or elsewhere). Their workflow is:

  1. Receive patches on the relevant mailing list (e.g., linux-usb@vger.kernel.org)
  2. Review, request changes, re-review
  3. Apply to their subsystem tree (often with git am from an mbox)
  4. During the merge window, send a pull request to Linus

Where are these trees listed? In MAINTAINERS — a file in the kernel source that maps every file, directory, and subsystem to its maintainer, mailing list, and Git tree URL. This file is your map.

# Find the maintainer for a specific file in the kernel source
# The kernel ships a helper script for this
cd linux-mainline

# Who maintains the USB HID driver?
scripts/get_maintainer.pl drivers/hid/usbhid/usbmouse.c
# Output might look like:
# Jiri Kosina <jkosina@suse.cz> (maintainer:HID CORE LAYER)
# Benjamin Tissoires <benjamin.tissoires@redhat.com> (maintainer)
# linux-input@vger.kernel.org (open list:HID CORE LAYER)
# linux-kernel@vger.kernel.org (open list)

# Look up the MAINTAINERS entry directly
grep -A 10 '^NETWORKING \[IPv4/IPv6\]' MAINTAINERS
# Shows: maintainer names, mailing list, git tree URL, files covered

# Check what tree a subsystem uses
grep -A 5 'F:\s*net/' MAINTAINERS | grep '^T:'

05linux-next: The Integration Testing Tree

Here is the problem: suppose the networking maintainer and the filesystems maintainer both accept patches that independently look fine, but together they break the build or cause a runtime bug. Nobody would know until they landed in Linus's tree during the merge window, which is exactly the wrong time to find out.

The solution is linux-next, maintained by Stephen Rothwell. Every day (on working days), Stephen pulls the 'next' branch of approximately 200+ subsystem trees into a single integration tree and publishes it. If the combined tree fails to build or boot, he notifies the relevant maintainer.

linux-next is the early warning system for the kernel. It is always the tip of what will enter the next merge window. Developers testing on linux-next catch cross-subsystem conflicts weeks before they would be a problem.

Important: linux-next is not a stable tree. It resets constantly. You should not run it on a machine you depend on. But for kernel developers and serious testers, it is invaluable.

As a contributor, having your patch land in a subsystem's 'next' branch means it is in linux-next and will likely enter the next merge window. That is a strong signal your patch has been accepted.

# Clone linux-next
git clone \
  https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
cd linux-next

# linux-next is tagged daily: next-YYYYMMDD
git tag -l 'next-*' | tail -5
# next-20240610
# next-20240611
# next-20240612
# next-20240613
# next-20240614

# Check out the latest daily snapshot
git checkout next-20240614

# To keep it updated (Stephen rebases and re-tags daily)
git fetch origin
git checkout next-$(date +%Y%m%d)  # today's snapshot

06Stable and LTS Trees: Production's Safety Net

When Linus releases v6.10, his job with that version is done. He moves on to v6.11. But the rest of the world — embedded devices, server distros, Android, long-lived appliances — cannot upgrade every 10 weeks. They need bug fixes and security patches backported to the version they ship.

This is the job of the stable tree, maintained by Greg Kroah-Hartman and Sasha Levin at stable/linux-stable. The rules for what gets backported are strict (documented in Documentation/process/stable-kernel-rules.rst):

  1. The fix must already be in Linus's mainline tree
  2. It must fix a real bug (no features, no cleanups)
  3. It must be small and clearly correct
  4. It must not introduce new regressions

Versions get stable updates: v6.10.1, v6.10.2, etc., until the next release makes them irrelevant (usually 2-4 months).

LTS (Long Term Support) kernels are special stable kernels maintained for 2-6 years. LTS kernels are announced at kernel.org and are chosen because they coincide with major Android releases or important enterprise cycles. Recent LTS versions include 6.6, 6.1, 5.15, 5.10, 5.4, and 4.19.

A patch can carry a Cc: stable@vger.kernel.org tag to request backporting, or a maintainer can submit it manually. The stable team reviews all candidates.

# A commit that requests stable backporting looks like this in its commit message:

# commit abc123def456...
# Author: Jane Developer <jane@example.com>
# Date:   Mon Jun 10 12:00:00 2024
#
#     net: fix null pointer dereference in tcp_recvmsg
#
#     When the socket is closed while a recv is in progress,
#     sk->sk_receive_queue is accessed after being invalidated.
#     Add a NULL check before dereferencing.
#
#     Fixes: deadbeef1234 ("net: tcp: rework recvmsg path")
#     Cc: stable@vger.kernel.org  # 6.6+
#     Signed-off-by: Jane Developer <jane@example.com>
#     Reviewed-by: Senior Maintainer <sm@kernel.org>

# The 'Fixes:' tag identifies the commit that introduced the bug
# The 'Cc: stable' tag requests backporting to stable trees >= 6.6

07How a Patch Actually Reaches Linus: The Full Journey

Let's trace the complete lifecycle of a real patch from author's keyboard to Linus's tree.

Week 0 (anytime during the cycle): You write a fix for a USB driver bug. You run scripts/get_maintainer.pl to find the USB maintainer and mailing list. You format your patch with git format-patch and send it with git send-email.

Week 1-3: The maintainer and community review your patch on the mailing list. You receive feedback (Reviewed-by, Tested-by, or requests for changes). You incorporate changes, resend as v2, v3...

Week 4-8 (still in the current cycle): The maintainer applies your patch to their subsystem's 'next' branch. It appears in linux-next within a day. Testing continues at scale.

End of cycle (Linus releases v6.X): The merge window opens. The USB maintainer sends a pull request to Linus containing your patch (along with hundreds of others). Linus pulls it.

Day 3 of merge window: Your patch is in torvalds/linux. -rc1 a couple weeks later will contain it.

~10 weeks after merge window: v6.(X+1) is released, containing your fix. If you tagged it Cc: stable, the stable team may backport it within days.

Total elapsed time from first send to final release: 2-5 months, depending on where in the cycle you started.

# The patch submission workflow in shell commands

# 1. Create a branch for your work
git checkout -b fix/usb-null-deref v6.10-rc5

# 2. Make your fix, commit it with a proper message
git add drivers/usb/core/message.c
git commit -s  # -s adds your Signed-off-by automatically

# 3. Format it as a patch file
git format-patch -1 HEAD --subject-prefix='PATCH'
# Creates: 0001-usb-core-fix-null-pointer-in-usb_submit_urb.patch

# 4. Check it passes basic style/correctness tests
scripts/checkpatch.pl 0001-usb-core-fix-null-pointer-in-usb_submit_urb.patch

# 5. Find who to send it to
scripts/get_maintainer.pl \
  0001-usb-core-fix-null-pointer-in-usb_submit_urb.patch

# 6. Send it via email
git send-email \
  --to='Greg Kroah-Hartman <gregkh@linuxfoundation.org>' \
  --cc='linux-usb@vger.kernel.org' \
  --cc='linux-kernel@vger.kernel.org' \
  0001-usb-core-fix-null-pointer-in-usb_submit_urb.patch

08The MAINTAINERS File and Patch Routing

The MAINTAINERS file at the root of the kernel source is 20,000+ lines and maps the entire kernel to its human stewards. Every patch must be sent to the right people; sending to the wrong list causes delays or silence.

Each entry has fields:

  • M: — Maintainer name/email
  • R: — Reviewer (not full maintainer but should be CC'd)
  • L: — Mailing list
  • T: — Git tree (type + URL)
  • S: — Status (Maintained, Odd Fixes, Orphan, Obsolete...)
  • F: — Files/patterns this entry covers
  • K: — Keyword regex to match commit messages

The get_maintainer.pl script parses this file automatically. Always use it — do not guess. A patch sent to the wrong list may be politely redirected, but it wastes everyone's time.

If the status is Orphan or Obsolete, the subsystem has no active maintainer, which changes how you contribute (patches go directly to Linus or a staging tree).

# Example MAINTAINERS entry (from actual kernel source, simplified)
#
# USB SUBSYSTEM
# M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
# L: linux-usb@vger.kernel.org
# S: Supported
# T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
# F: Documentation/driver-api/usb/
# F: drivers/usb/
# F: include/linux/usb.h
# F: include/linux/usb/

# Find all entries covering a given file:
scripts/get_maintainer.pl --file drivers/usb/core/hub.c

# List all SUPPORTED subsystems (not orphaned)
grep -B5 'S:\s*Supported' MAINTAINERS | grep '^M:' | wc -l

# Check the git tree for the arm64 architecture
grep -A 15 '^ARM64 ARCHITECTURE' MAINTAINERS | grep '^T:'

09Tags in Commit Messages: The Social Protocol

Linux kernel commits carry a rich set of structured tags in the commit message body. These are not decoration — they are a legally significant chain of accountability and a machine-parseable workflow record.

Signed-off-by: (mandatory) — By adding this line with git commit -s, you certify under the Developer's Certificate of Origin (DCO) that you have the right to submit this code, that it is your original work or properly licensed, and that you understand it will be incorporated under the kernel's license (GPL-2.0). Every person who handles the patch (author, co-author, maintainer) adds their own Signed-off-by.

Reviewed-by: — A named person has read the patch and believes it is correct. Adds credibility; multiple reviewers make acceptance faster.

Tested-by: — A named person has tested the patch and it worked. Hardware-specific patches especially benefit from this.

Acked-by: — The maintainer of affected code agrees with the approach, but isn't the primary reviewer.

Fixes: — Points to the commit that introduced the bug being fixed. Format: Fixes: <12-char-hash> ("commit subject"). This is critical for stable backporting — the stable team uses it to identify which kernels need the fix.

Cc: stable@vger.kernel.org — Request backport to stable trees. Can include version range like # 5.15+.

# A complete, well-tagged kernel commit message:

# net: ipv4: fix use-after-free in ip_options_compile
#
# When ip_options_compile() encounters an error partway through
# parsing, it calls kfree() on an allocated buffer but then
# continues to dereference the pointer. Move the error path to
# skip the dereference.
#
# This was introduced by commit a1b2c3d4e5f6 which restructured
# the error handling path without noticing the implicit assumption
# about buffer lifetime.
#
# Fixes: a1b2c3d4e5f6 ("net: ipv4: restructure options parsing")
# Cc: stable@vger.kernel.org  # 5.15+
# Cc: networking@vger.kernel.org
# Reported-by: Fuzzer Bot <bot@example.com>
# Signed-off-by: Jane Developer <jane@example.com>
# Reviewed-by: Senior Netdev <sr@kernel.org>
# Tested-by: Jane Developer <jane@example.com>
# Signed-off-by: David S. Miller <davem@davemloft.net>

10Timing Your Patch: When NOT to Send

Understanding when to send a patch is as important as the patch itself. The kernel community has strong norms about timing.

Best time to send: Immediately after a new release (v6.X.0 is out), when the merge window is opening. Your patch has an entire cycle to be reviewed and staged in a maintainer's tree.

Worst time to send: During or just after the merge window. Maintainers are overwhelmed pulling trees and doing merges. Your patch will be missed or explicitly deferred.

For bug fixes: Bug fixes (especially regressions) can be sent at any time and will be expedited regardless of cycle phase. Regressions during -rc phase are the highest priority.

For new features: Features must be staged in a subsystem tree before the merge window opens. If your feature misses staging by even a day, it waits a full cycle.

Watch the mailing list tone: Around -rc6/-rc7, Linus starts posting "I'm almost done, expecting to release next week." That is your signal that the merge window is imminent.

A practical rule: if you are new, aim to have your patch reviewed and in a maintainer's 'next' branch by -rc4 of the current cycle. That gives it the whole rest of the cycle to bake in linux-next before the merge window.

# Monitor the kernel mailing list for cycle announcements
# Linus posts release announcements to lkml and oss-security

# Subscribe to the Linux Kernel Mailing List digest:
# https://subspace.kernel.org/vger.kernel.org.html
# Or browse via: https://lore.kernel.org/lkml/

# Check the current kernel release status:
curl -s https://www.kernel.org/ | grep -E 'stable|mainline|longterm' | head -20

# Or use the kernel.org JSON API:
curl -s https://www.kernel.org/releases.json | \
  python3 -c "
import json,sys
data=json.load(sys.stdin)
for r in data['releases'][:5]:
    print(r['moniker'], r['version'], r['released']['isodate'])
"

11Git Bisect: Your Most Important Testing Tool

One of the most valuable things a kernel tester can do is identify which specific commit introduced a regression. This transforms a vague bug report into an actionable, pinpointed fix request. The tool for this is git bisect.

The idea is binary search through commit history. You tell Git: "version X was good, version Y is broken." Git checks out the commit exactly halfway between them and asks: good or bad? You test, answer, and Git narrows it down. After log₂(N) steps, you have the exact offending commit.

For kernel bisecting, each step requires: building the kernel, installing it, rebooting, testing the bug, and reporting back. It is slow (30-60 minutes per step) but incredibly powerful. A typical bisect through 10,000 commits takes only 13-14 steps.

Proper bug reports to the mailing list always include: kernel version where it broke, last known good version, hardware info (lspci -v, dmesg), and ideally a git bisect result naming the offending commit.

# Full git bisect workflow for a kernel regression
# Suppose 6.9 works, 6.10-rc3 does not

cd linux-mainline
git bisect start

# Mark the broken state
git bisect bad v6.10-rc3

# Mark the last known good state  
git bisect good v6.9

# Git checks out the midpoint commit and prints:
# Bisecting: 7500 revisions left to test after this
# [abc123] some commit in the middle

# Now: build and test
make -j$(nproc) && sudo make modules_install && sudo make install
# reboot into the new kernel, test the bug

# If the bug is present:
git bisect bad
# If the bug is absent:
git bisect good

# Repeat until Git prints:
# abc123def is the first bad commit
# commit abc123def
# Author: ...

# Finish and return to original HEAD
git bisect reset

# For automated bisect (if you have a test script that exits 0=good, 1=bad):
git bisect run ./test_my_bug.sh

12The Role of Linus: Benevolent Dictator and Quality Gate

Linus Torvalds is the creator of Linux and its Benevolent Dictator for Life (BDFL). He has final say on what enters his tree. But as the kernel has grown, his role has evolved from hands-on reviewer to orchestrator and quality arbiter.

Linus reviews the pull requests from maintainers. He does not usually review individual commits. If a pull request contains bad code, he pushes back on the maintainer, who is responsible for what they submitted. This creates a strong accountability chain: maintainers know their reputation depends on sending Linus clean, well-reviewed work.

Linus is famous for blunt, sometimes harsh feedback when standards are not met — particularly around security, regression, or API stability. His emails are archived on lkml and are worth reading to understand what the kernel community values. Some famous examples: his rejection of C++ in the kernel ("C++ is a horrible language"), his insistence that regressions are always bugs, and his periodic architectural rejections of entire subsystem approaches.

That said, the kernel's success is partly because of this centralized quality gate. The decentralized maintainer network handles scale; Linus handles coherence. New contributors almost never interact with Linus directly — your world is the subsystem maintainer and the mailing list.

# You can read Linus's public commit messages and pull request responses
# directly in the git log of torvalds/linux:

# Browse merge commits (which are Linus's pull responses)
git log --merges --oneline --author='Linus Torvalds' v6.9..v6.10-rc1 | head -20

# A typical merge commit from Linus looks like:
# Merge tag 'usb-6.10-rc1' of git://git.kernel.org/...
# Merge tag 'net-6.10-rc1' of git://git.kernel.org/...
# Merge tag 'arm64-6.10' of git://git.kernel.org/...

# The merge commit message often contains Linus's commentary on
# the pull request, written in a conversational, sometimes irreverent style
git show --stat $(git log --merges --oneline -1 v6.10-rc1 | cut -d' ' -f1)

Key insights

  • ✦The merge window is a harvest, not a sprint — new code must be reviewed and staged *before* the window opens. Showing up during the window with a new feature is too late.
  • ✦linux-next is the smoke-detector for cross-subsystem fires. If your patch lands in a maintainer's 'next' branch and linux-next still builds, you are on track.
  • ✦Regressions are the kernel's highest-priority bug class, always. A kernel that breaks something that used to work is worse than one that never supported the feature at all.
  • ✦The commit tags (Signed-off-by, Fixes, Cc: stable) are not bureaucratic formalities — they are a legally meaningful, machine-parseable provenance chain that powers the stable backport pipeline.
  • ✦Your subsystem maintainer is your real gateway to the kernel, not Linus. Invest in that relationship: respond to review feedback promptly, test your fixes thoroughly, and read the list before posting.
  • ✦Stable/LTS trees extend the value of your upstream fix to millions of production systems. The Fixes: tag is the bridge — use it.
  • ✦git bisect is the most underused kernel contribution tool. A bisect result in a bug report is worth ten times a vague description.

Common pitfalls

  • ⚠Sending a new feature patch during or after the merge window. The window has already closed; your patch waits a full cycle. Send as soon as the previous release is tagged.
  • ⚠Not using scripts/get_maintainer.pl before sending. Mailing the wrong list or wrong person means your patch is invisible to the people who can accept it.
  • ⚠Missing the Fixes: tag on a bug fix. Without it, the stable team may never backport your fix to affected kernels, leaving production systems vulnerable.
  • ⚠Sending a patch series as separate top-level emails instead of a proper [PATCH 0/N] cover letter thread. Use git format-patch -N with --cover-letter and send-email's --thread option.
  • ⚠Re-sending a patch before giving the maintainer reasonable time to respond (at least 1-2 weeks). Following up too quickly is considered impolite; following up after 2-3 weeks with a polite ping is normal.
  • ⚠Running linux-next on a machine you depend on. It is not stable — it resets daily, may fail to boot, and is for testing only.
  • ⚠Confusing 'my patch is in linux-next' with 'my patch will definitely be in the next release.' linux-next is a staging area, not a guarantee; a maintainer can still pull back a patch.
  • ⚠Submitting to multiple subsystem lists simultaneously when the patch touches boundaries. Coordinate with the primary maintainer first about which tree owns the change.

Practice

  1. 01
    easy

    Clone the linux-next tree and check out today's (or the most recent) daily snapshot tag. Run `git log --oneline -20` to see recent commits. Find a commit from a subsystem you are interested in and trace its origin: what subsystem tree did it come from? Use the commit message to identify the maintainer and mailing list.

  2. 02
    medium

    Find a bug fix commit in torvalds/linux (any recent release) that has both a `Fixes:` tag and a `Cc: stable` tag. Verify that the fix actually landed in the corresponding stable tree by cloning `stable/linux-stable` and using `git log --grep` to search for the commit subject.

  3. 03
    medium

    Set up a kernel build environment (VM or bare metal), build and boot a recent -rc kernel, and intentionally introduce a one-line bug (e.g., change a `>=` to `>` in a non-critical path like a proc file). Practice `git bisect` between two artificial tags to find your own introduced commit.

  4. 04
    easy

    Write a minimal but complete kernel patch (fix a documentation typo, improve a comment, or fix a trivial style issue reported by checkpatch.pl in a driver you are interested in). Format it with `git format-patch`, run it through `scripts/checkpatch.pl`, and use `scripts/get_maintainer.pl` to find exactly where it should be sent. Do NOT send it yet — write out the full `git send-email` command you would use.

  5. 05
    easy

    Subscribe to one kernel subsystem mailing list (linux-usb, linux-input, or linux-doc are beginner-friendly). Read one week of traffic. Write a one-page summary: how many patch series were submitted, how many were v2 or later revisions, what kinds of feedback did reviewers give, and did you see any timing-related deferrals (patches held for the next cycle)?

  6. 06
    medium

    Write a shell script that queries the kernel.org releases JSON API and prints a human-readable status line for each kernel branch: version number, release date, whether it is an LTS kernel, and how many days since its last update. Identify which versions are currently receiving stable updates.

  7. 07
    hard

    Find the MAINTAINERS entry for three different subsystems of your choice. For each, clone their Git tree, check out their 'next' branch, and count how many commits are staged there that are NOT yet in Linus's mainline. These commits are the ones waiting for the next merge window.

Resources

📄Linux Kernel Development Process (kernel.org official doc)
docsfree

The canonical, authoritative description of the entire development cycle, written by Jonathan Corbet. Read this before anything else.

📄How to Participate in the Linux Community (kernel.org)
docsfree

The official 'how to become a kernel developer' document — covers patch workflow, mailing lists, and cycle timing.

📄Stable Kernel Rules (kernel.org)
docsfree

Exact criteria for what gets backported to stable. Required reading before tagging a patch Cc: stable.

✎LWN.net — Kernel development coverage
articlepaid

LWN provides the best deep-dive reporting on kernel releases, merge windows, and development process. The weekly kernel development articles (free after ~1 week) are invaluable.

📄KernelNewbies — Kernel Versions
docsfree

Plain-English summaries of what changed in each kernel release. Great for understanding what a given cycle's merge window actually brought in.

🔧linux-next tree (Stephen Rothwell)
toolfree

The actual linux-next integration tree. Clone it to stay at the bleeding edge of what will enter the next merge window.

🔧lore.kernel.org — Kernel Mailing List Archives
toolfree

Authoritative, searchable archive of all kernel mailing lists. Use to read patch review threads, announcements, and development discussions.

📕Linux Kernel Development (3rd Edition)
bookpaidRobert Love, Addison-Wesley. The classic guide to kernel internals; Chapter 1 covers the development model and process.

Still the most readable introduction to kernel development culture and process, despite its age.

▶Greg Kroah-Hartman's talks on kernel development
videofree

Greg's 'Write and Submit your first Linux kernel Patch' talk from various conferences. Highly practical and current.

🔧kernel.org release monitoring
toolfree

The source of truth for current kernel versions, LTS status, and release dates. Check this weekly when contributing.

Checkpoints — you can now…

  • ✓You can explain the 9-10 week kernel release cycle from memory, naming each phase (merge window, -rc stabilization, release) and its approximate duration.
  • ✓You can use scripts/get_maintainer.pl on any kernel source file and identify the correct maintainer, mailing list, and subsystem git tree for a patch.
  • ✓You can clone linux-next, check out a specific daily snapshot tag, and explain what it represents relative to the mainline tree.
  • ✓You can read a kernel commit message and identify all standard tags (Signed-off-by, Fixes, Cc: stable, Reviewed-by) and explain what each one does mechanically.
  • ✓You can run git bisect on a kernel tree, given a good and bad version, and step through the binary search to identify a regressing commit.
  • ✓You can explain the difference between the mainline tree, a subsystem maintainer tree, linux-next, the stable tree, and an LTS tree — and describe when code lives in each.
  • ✓You can determine, given today's date and the current kernel cycle phase, whether sending a new feature patch right now is appropriate or whether it should wait.