Add Rebase Rules

SkillFiles & storage

Generates .rebase add/override/replace rules from a commit that changes code/ files, updates rebase.sh conflict routing, and appends .rebase/CHANGELOG.md. Use when asked to add rebasing rules for a commit or PR.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Add Rebase Rules skill

What this skill tells your AI

The instructions your AI receives, as published by che-incubator/che-code in .claude/skills/add-rebase-rules/SKILL.md and read by ahel’s review.

Create or update rebasing rules for Che-specific changes that touch VS Code subtree files under code/.

Use this skill when the user gives a commit SHA (or PR/commit URL) and asks to add rebasing rules.

Required input

  • A commit SHA is expected in $ARGUMENTS.
  • If $ARGUMENTS is empty, ask the user for a commit SHA before proceeding.

Scope and exclusions

Only consider changed files under code/.

Never create rebasing rules for:

  • code/extensions/che-*/**
  • any **/package-lock.json

Important:

  • A file can be under code/ and still be Che-only (for example code/src/.../che/... newly created by Che). Do not create a rule for such files if they are not upstream VS Code files.
  • Still create rules for the upstream file(s) that import/use those Che-only helpers.

Workflow

  1. Resolve the target commit and collect changed files

    • If input is a URL, extract the SHA.
    • Get changed files:
      • git show --name-only --pretty='' <sha> | sort -u
    • Filter to the rule candidate set:
      • include: files starting with code/
      • exclude: code/extensions/che-*/**
      • exclude: **/package-lock.json
  2. Classify each candidate file

    • */package.json -> JSON merge rule (.rebase/add/ and/or .rebase/override/)
    • Other modified upstream files -> replace rule (.rebase/replace/<path>.json)
    • Newly added Che-only files with no upstream counterpart -> skip (no rule needed)
  3. Create or update JSON merge rules for package.json

    • Preserve only minimal changed subtree (do not copy entire package.json).
    • Use:
      • .rebase/add/<path> for new keys or additive nested values
      • .rebase/override/<path> when overriding existing values must be explicit
    • It is valid to use both for one file.
    • Keep file formatting consistent with existing .rebase JSON style (2-space indentation).
    • Choosing add vs override for dependency version pins (e.g. CVE fixes):
      • If the dependency already exists in the upstream package.json (in dependencies, devDependencies, etc.) and we need a different version → use .rebase/override/ with the correct section. This is an override of an existing upstream value.
      • If the fix uses npm overrides (the npm feature that pins transitive dependency versions) and the override key does not exist in upstream's overrides section → use .rebase/add/. This is additive content absent from upstream.
      • Prefer the JSON merge mechanism (add or override) over .rebase/replace/ for package.json changes. However, .rebase/replace/ is acceptable when the change cannot be expressed by JSON merge alone — for example, rewriting a dependency URL format (e.g. fixing a Git URL — see .rebase/replace/code/extensions/emmet/package.json.json) or inserting a new entry at a specific position among existing keys.
      • Place each entry in the file where the dependency actually lives in upstream. For example, if @vitest/coverage-v8 is a devDependency of code/extensions/copilot/package.json, its override rule belongs in .rebase/override/code/extensions/copilot/package.json, not in a sibling package.
  4. Create or update replace rules for non-JSON files

    • File path: .rebase/replace/<original-path>.json
    • Format: JSON array of objects with from and by.
    • Add one rule per changed hunk, using stable and unique snippets.
    • Ensure from appears exactly once in the upstream file. Both sed and perl handlers replace all occurrences — if from matches multiple places, all will be replaced, which is almost always wrong. Extend the snippet with more surrounding context to make it unique.
    • Prefer the smallest safe snippet that is unlikely to change accidentally, but large enough to be unique in the file.
    • If replacement is multiline, encode using escaped newlines/tabs in JSON consistently with existing files.
    • For multiline from snippets, start at the first non-whitespace token (avoid anchoring on leading indentation only).
    • Prefer replacing the whole logical block (if (...) { ... }) rather than only an inner line fragment, so closing braces remain structurally correct.
    • Encode special characters correctly for the handler used in rebase.sh. See the encoding tables below.

Sed encoding (apply_changes)

Values go through: JSON parse → jq -rescape_litteral → sed.

Character in targetfrom encodingby encoding
Newline\\\n\\\n
Tab\\\t\\\t
&literal\\&
*\\*literal
$, [, ]literal (escape_litteral handles)literal
"\\\"\\\"

Common pitfall — & in sed by values: In sed replacement strings, & means "the entire matched text". Writing && in a by value produces the matched from text repeated twice instead of a literal &&. Always escape as \\&\\&. This applies to any & in by, not just &&.

Perl encoding (apply_changes_multi_line / apply_multi_line_replace)

Values go through: JSON parse → jq -r → env var → perl \Q\E (from) / literal (by).

Character in targetfrom encodingby encoding
Newline\n\n
Tab\t\t
Any special charliteralliteral

Prefer multiline (perl) for new rules — simpler encoding, handles all cases, no & pitfall.

  1. Update rebase.sh conflict routing

    • Ensure each file that now has a new rebasing rule is routable in resolve_conflicts.
    • For package.json files:
      • add elif branch calling apply_package_changes_by_path "$conflictingFile" (or equivalent existing pattern).
    • For non-JSON replace rules:
      • use apply_changes "$conflictingFile" for line-based replacements.
      • For multiline replacements, rebase.sh has two handlers — do not always default to one:
        • apply_changes_multi_line "$conflictingFile" — higher-level wrapper that resets the file (git checkout --theirs), calls apply_multi_line_replace, then stages the result (git add).
        • apply_multi_line_replace "$conflictingFile" — low-level function that performs the Perl multiline replacement directly, without git checkout/add.
      • Before adding a routing branch, inspect the existing resolve_conflicts block in rebase.sh and look at how other files in the same area are routed. Match the handler already used for similar files. For example, if neighboring entries call apply_multi_line_replace directly, use that; if they use apply_changes_multi_line, use that instead.
    • Do not add duplicate branches.
  2. Update .rebase/CHANGELOG.md

    • Append a new entry in existing format:
      • #### @<author>
      • commit/PR link (or commit SHA if no link is available)
      • list only files for which rebasing rules were added/updated
      • separator ---
  3. Validate before finishing

    • Determine the upstream ref from rebase.sh and use that exact ref for validation (do not hardcode a release branch in the skill output).
      • Example source of truth in rebase.sh: UPSTREAM_VERSION=$(git rev-parse upstream-code/release/1.108)
      • If the script later points to upstream-code/main or another release branch, use that new ref instead.
    • bash -n rebase.sh
    • JSON validation for changed .rebase/**/*.json files (jq empty <file>)
    • For each changed .rebase/replace/**/*.json, verify every from exists in the upstream file content before finishing.
      • Example: git show <upstream-ref>:<path-without-code-prefix> and compare with the from snippet.
      • path-without-code-prefix means the same file path but without the leading code/ (because upstream-code stores VS Code sources at repo root).
    • Verify each from appears exactly once in the upstream file. If it matches multiple times, the rule will silently replace all of them. Extend the from snippet with more context until it is unique.
    • Dry-run the generated rule using the same replacement path as rebase.sh (Perl-based multiline replace), not a language-native .replace(...).
    • Include at least one test case where from/by contains $ (for example template literals like ${key}) and confirm replacement still succeeds.
    • Re-check exclusions:
      • no rules for code/extensions/che-*
      • no rules for package-lock.json
    • Ensure every changed rule file is actually referenced by logic in rebase.sh when required.
  4. Verify completeness — no uncovered Che-specific changes

    • For each file that was updated or created in .rebase/replace/, simulate the full rule application:
      1. Start with the upstream file at CURRENT_UPSTREAM_VERSION.
      2. Apply all rule entries from the JSON (not just the newly added ones) plus any custom inline replacements from rebase.sh.
      3. Diff the result against the che-code working tree file.
    • If the diff is empty → all Che changes are covered. Good.
    • If there is a remaining diff → there are Che-specific changes in the working tree that are not covered by any rule. These changes would be silently lost during rebase.
      • If the uncovered changes are from the same commit being processed, add additional rule entries for them.
      • If the uncovered changes are pre-existing (from earlier commits), report them to the user as a warning: "Pre-existing Che-specific changes at lines X-Y have no rebase rule and would be lost during rebase."

Decision notes

  • Goal is to protect Che-specific behavior during upstream subtree rebases while keeping deltas in upstream files minimal.
  • Prefer moving larger Che logic into Che-owned files and keeping upstream file edits small; then create replace rules only for the upstream file edits.
  • When unsure between add vs override for JSON, follow existing .rebase conventions in neighboring files and keep the smallest rule payload that reproduces the required result.

Examples

  • Dependency override updates across many code/**/package.json files:

    • Example commit: 04b7984047fec31dd6993bd299f6698750c63d08
    • Matching rule-update style: eec9cd1e9e199ce9a0eb2f6e3bd1dad6fc258413
  • Source-level VS Code file changes protected by replace rules:

    • Example PR changes: https://github.com/che-incubator/che-code/pull/617/changes
    • Matching rule commit: https://github.com/che-incubator/che-code/pull/617/changes/e794c63f01d116b0b92d5ecd220247e13a5ba946

Signals

GitHub stars
35
Forks
50
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
add-rebase-rules
Source
github.com/che-incubator/che-code