Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,12 @@ below follows from that.
NOT be revived, not even for follow-up on the same topic: a merged pull
request cannot describe new work, and a closed one was set aside. Follow-up is
a new branch, cut fresh from `origin/main`.
* To carry `main`'s progress into an open branch: while the branch is yours
alone, **rebase** it onto `origin/main`; once others may have based work on
it, **merge** `origin/main` in instead. Either keeps the branch current
without rewriting what a collaborator has already pulled.
* To carry `main`'s progress into an open branch, **rebase** it onto
`origin/main`. Never merge `origin/main` into a branch (decision: ADR-0071):
the rebase that lands the branch replays its own commits onto `main`, so that
merge would put back the very shape the linear history removed. If someone
else has already based work on the branch, coordinate the force-push or split
the work in two — do not reach for a merge.
* Rewriting a branch's history — a force-push, a `git rebase -i` — is fine
while the branch is **yours alone**, and is how a commit message the lint or
a reviewer rejected gets fixed, even mid-review: a rejected message cannot be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

🌍 🇫🇷 Français (ce fichier) · 🇬🇧 [English](0070-land-pull-requests-by-rebasing-and-keep-main-linear.md)

**Statut :** Proposé
**Statut :** Accepté
**Proposé :** 2026-08-10
**Accepté :** 2026-08-10
**Décideurs :** Reefact

## Contexte
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

🌍 🇬🇧 English (this file) · 🇫🇷 [Français](0070-land-pull-requests-by-rebasing-and-keep-main-linear.fr.md)

**Status:** Proposed
**Status:** Accepted
**Proposed:** 2026-08-10
**Accepted:** 2026-08-10
**Decision Makers:** Reefact

## Context
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ADR-0071 | Rafraîchir une branche ouverte uniquement en la rebasant sur `main`

🌍 🇫🇷 Français (ce fichier) · 🇬🇧 [English](0071-refresh-an-open-branch-only-by-rebasing-it.md)

**Statut :** Accepté
**Proposé :** 2026-08-10
**Accepté :** 2026-08-10
**Décideurs :** Reefact

## Contexte

L'[ADR-0070](0070-land-pull-requests-by-rebasing-and-keep-main-linear.fr.md) a
rendu l'historique de `main` linéaire et fait du rebase la façon dont une pull
request atterrit. Elle a nommé un point qu'elle ne tranchait pas, en le laissant à
une décision distincte : `CONTRIBUTING.md` (« Branches ») propose **deux** façons
de reporter les avancées de `main` dans une branche ouverte — la rebaser sur
`origin/main` tant qu'elle n'appartient qu'à vous, ou y merger `origin/main` dès
que d'autres ont pu baser du travail dessus.

La seconde produit exactement les commits que l'ADR-0070 a supprimés. Sur les 401
commits de merge retirés de `main`, **87 étaient des `Merge branch 'main' into …`**,
créés en appliquant cette règle. Ils n'étaient pas gratuits non plus : 15 d'entre
eux portaient une résolution de conflit faite à la main, et reproduire ces
résolutions a été la partie délicate de la réécriture.

La règle ne fait d'ailleurs plus ce qu'elle annonce sous la nouvelle stratégie.
Elle a été écrite pour un dépôt à commits de merge, où un merge effectué sur une
branche restait sur la branche et où seul son résultat atteignait `main`. Avec le
*Rebase and merge*, GitHub rejoue les commits propres de la branche sur `main` :
une branche qui a mergé `main` en elle emporte donc ce merge dans ce qui
atterrit. La règle réimporte en silence le bruit que la réécriture a enlevé.

Ce que la règle protège est réel : rebaser une branche que quelqu'un d'autre a
déjà récupérée détruit son travail. Mais cette situation n'existe pas dans le
modèle de branches de ce dépôt. `CONTRIBUTING.md` énonce qu'une branche porte
**une** pull request, qu'elle est « l'espace de travail jetable d'une pull
request », et que son nom prend la forme `<author>/<short-description>` — le
propriétaire est nommé dans la ref elle-même. Une branche sur laquelle deux
personnes construisent est déjà hors du modèle, et l'option de merge est la seule
règle qui suppose le contraire.

## Décision

Une branche ouverte est mise à jour avec `main` **uniquement en la rebasant sur
`origin/main`**. On ne merge pas `origin/main` dans une branche.

## Conséquences

### Le force-push devient la façon ordinaire de rafraîchir une branche

C'est déjà le cas pour les branches que ce dépôt possède réellement.
`CONTRIBUTING.md` autorise à réécrire l'historique d'une branche tant qu'elle
n'appartient qu'à vous et impose `git push --force-with-lease` plutôt qu'un
`--force` nu ; rafraîchir, c'est la même opération. Rien de nouveau n'est
autorisé, une alternative est retirée.

### Une branche déjà récupérée par autrui n'a plus d'échappatoire, volontairement

Si une seconde personne a réellement basé du travail sur une branche ouverte, la
réponse est de coordonner le force-push ou de scinder le travail en deux branches
— pas de placer un commit de merge dans l'historique futur de `main`. Rendre ce
cas visible est précisément le but : sous la règle précédente il se réglait en
silence, par un commit que personne ne relisait.

### Le coût de la réécriture n'est pas payé une seconde fois

L'ADR-0070 enregistre que réécrire `main` est une exception unique dont la
fenêtre se referme à la 1.0.0. Laisser l'option de merge ouverte permettrait à la
forme de commit qu'elle a supprimée de réapparaître une branche à la fois, sans
qu'une seconde réécriture soit disponible pour nettoyer.

## Alternatives considérées

### Conserver l'option de merge et compter sur GitHub pour l'aplatir

Envisagée parce que le *Rebase and merge* rejoue bien les commits d'une branche,
et qu'on pourrait attendre qu'un commit de merge disparaisse au passage. Rejetée
parce que le résultat n'est pas quelque chose sur quoi s'appuyer : ce qu'un
rebase fait d'un commit de merge dépend de la forme de la branche, et une règle
dont la sûreté repose sur le comportement d'aplatissement actuel de la plateforme
est une règle qui casse en silence quand ce comportement change. L'historique du
dépôt en est la preuve — 87 commits de cette forme ont atteint `main` sous la
stratégie précédente.

### Conserver l'option de merge pour les seules branches réellement partagées

Envisagée parce que la protection offerte est réelle quand elle s'applique.
Rejetée parce qu'elle s'applique à une branche que ce dépôt n'a pas, et parce
qu'une règle assortie d'une exception se lit comme une règle assortie d'une
échappatoire. La doctrine de branche existante — une pull request, un
propriétaire, coupée fraîche, supprimée au merge — est ce qui rend l'exception
inutile ; si cette doctrine change un jour, la présente décision devra être
revue avec elle plutôt qu'affaiblie d'avance pour un cas qui ne se produit pas.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# ADR-0071 | Refresh an open branch only by rebasing it onto `main`

🌍 🇬🇧 English (this file) · 🇫🇷 [Français](0071-refresh-an-open-branch-only-by-rebasing-it.fr.md)

**Status:** Accepted
**Proposed:** 2026-08-10
**Accepted:** 2026-08-10
**Decision Makers:** Reefact

## Context

[ADR-0070](0070-land-pull-requests-by-rebasing-and-keep-main-linear.md) made
`main`'s history linear and made rebase the way a pull request lands. It named
one thing it did not settle, and left it for a separate decision: `CONTRIBUTING.md`
("Branches") offers **two** ways to carry `main`'s progress into an open branch —
rebase it onto `origin/main` while the branch is yours alone, or merge
`origin/main` into it once others may have based work on it.

The second option produces exactly the commits ADR-0070 removed. Of the 401 merge
commits deleted from `main`, **87 were `Merge branch 'main' into …`** — created by
following this rule. They were not free either: 15 of them carried a hand-made
conflict resolution, and reproducing those resolutions was the delicate part of
the rewrite.

The rule also no longer does what it says under the new strategy. It was written
for a merge-commit repository, where a merge performed on a branch stayed on the
branch and only its result reached `main`. With *Rebase and merge*, GitHub
replays the branch's own commits onto `main` — so a branch that merged `main`
into itself carries that merge into what lands. The rule quietly re-imports the
noise the rewrite removed.

What the rule protects is real: rebasing a branch someone else has already pulled
discards their work. But that situation does not exist in this repository's
branch model. `CONTRIBUTING.md` states that a branch carries **one** pull
request, that it is "the disposable workspace of one pull request", and that its
name takes the form `<author>/<short-description>` — the owner is named in the
ref itself. A branch two people build on is already outside the model, and the
merge option is the only rule that assumes otherwise.

## Decision

An open branch is brought up to date with `main` **only by rebasing it onto
`origin/main`**. Merging `origin/main` into a branch is not done.

## Consequences

### Force-push becomes the ordinary way to refresh a branch

It already is, for the branches this repository actually has. `CONTRIBUTING.md`
permits rewriting a branch's history while it is yours alone and requires
`git push --force-with-lease` rather than a bare `--force`; refreshing is that
same operation. Nothing new is allowed, and one alternative is withdrawn.

### A branch someone else has pulled has no escape hatch, by design

If a second person has genuinely based work on an open branch, the answer is to
coordinate the force-push or to split the work into two branches — not to put a
merge commit into `main`'s future history. Making that case visible is the point:
under the previous rule it was resolved silently, by a commit nobody reviewed.

### The rewrite's cost is not re-incurred

ADR-0070 records that rewriting `main` is a one-time exception that closes at
1.0.0. Leaving the merge option open would let the exact commit shape it removed
reappear one branch at a time, with no second rewrite available to clean it up.

## Alternatives Considered

### Keep the merge option, and rely on GitHub to flatten it

Considered because *Rebase and merge* does replay a branch's commits, and one
might expect a merge commit to be dropped in the process. Rejected because the
result is not something to rely on: what a rebase does with a merge commit
depends on the branch's shape, and a rule whose safety depends on the platform's
current flattening behaviour is a rule that breaks silently when that behaviour
changes. The repository's own history is the evidence — 87 such commits reached
`main` under the previous strategy.

### Keep the merge option for genuinely shared branches only

Considered because the protection it offers is real when it applies. Rejected
because it applies to a branch this repository does not have, and because a rule
with an exception is read as a rule with an escape. The existing branch doctrine —
one pull request, one owner, cut fresh, deleted on merge — is what makes the
exception unnecessary; if that doctrine ever changes, this decision should be
revisited with it rather than pre-weakened for a case that does not occur.
3 changes: 2 additions & 1 deletion doc/handwritten/for-maintainers/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,5 @@ Optional supporting material:
| [ADR-0062](0062-derive-the-build-rule-set-from-the-quality-profile.md) | Derive the build's Sonar rule set from the quality profile: generated membership, hand-written exceptions, weekly drift check | Accepted |
| [ADR-0067](0067-treat-the-cli-s-exit-codes-as-a-closed-published-contract.md) | Treat the CLI's exit codes as a closed, published contract | Accepted |
| [ADR-0069](0069-consume-justdummies-from-its-own-repository.md) | Consume JustDummies from its own repository | Accepted |
| [ADR-0070](0070-land-pull-requests-by-rebasing-and-keep-main-linear.md) | Land pull requests by rebasing, and keep `main`'s history linear | Proposed |
| [ADR-0070](0070-land-pull-requests-by-rebasing-and-keep-main-linear.md) | Land pull requests by rebasing, and keep `main`'s history linear | Accepted |
| [ADR-0071](0071-refresh-an-open-branch-only-by-rebasing-it.md) | Refresh an open branch only by rebasing it onto `main` | Accepted |
10 changes: 6 additions & 4 deletions doc/handwritten/for-users/CONTRIBUTING.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,12 @@ Tout ce qui suit en découle.
PAS être ravivée, pas même pour un suivi sur le même sujet : une pull request mergée ne
peut pas décrire un nouveau travail, et une pull request fermée a été mise de côté. Le
suivi passe par une nouvelle branche, coupée fraîchement depuis `origin/main`.
* Pour reporter la progression de `main` dans une branche ouverte : tant que la branche
n’est qu’à vous, **rebasez-la** sur `origin/main` ; dès que d’autres ont pu baser du
travail dessus, **mergez** plutôt `origin/main` dedans. L’un comme l’autre garde la
branche à jour sans réécrire ce qu’un collaborateur a déjà récupéré (pull).
* Pour reporter la progression de `main` dans une branche ouverte, **rebasez-la** sur
`origin/main`. Ne mergez jamais `origin/main` dans une branche (décision : ADR-0071) :
le rebase qui intègre la branche rejoue ses propres commits sur `main`, ce merge y
remettrait donc la forme même que l’historique linéaire a supprimée. Si quelqu’un
d’autre a déjà basé du travail sur la branche, coordonnez le force-push ou scindez le
travail en deux — ne recourez pas à un merge.
* Réécrire l’historique d’une branche — un force-push, un `git rebase -i` — est
acceptable tant que la branche n’est **qu’à vous**, et c’est ainsi qu’un message de
commit rejeté par le lint ou par un relecteur se corrige, même en cours de relecture :
Expand Down