🍒 Cherri
Cherry-pick PRs with ease! Automatically cherry-pick merged pull requests marked with a specific emoji in their title or with a specific label.
About the Name
Why Cherri? It's a blend of "cherry-pick" and the French "chérie" (sweetheart), because let's face it - some commits are just more loveable than others. When you mark a PR with that little cherry emoji, you're essentially saying "this one's my chérie" - it's the commit equivalent of a love letter that deserves to be cherry-picked and brought along to every important branch.
What is Cherri?
Cherri is a CLI tool that automates the process of cherry-picking commits from merged pull requests. It searches for PRs with a specific emoji (default: 🍒) in their title OR PRs with a specific label, and cherry-picks all commits from those PRs to your current branch.
Perfect for:
- Backporting features to release branches
- Maintaining LTS versions
- Selective feature deployment
- Managing hotfixes across multiple branches
Installation
Install Cherri globally using npm:
npm install -g cherriPrerequisites
- Node.js (v16 or higher)
- Git installed and configured
- GitHub Personal Access Token with repo access
- You must be in the target git repository when running the command
Setup
1. GitHub Personal Access Token
Create a GitHub Personal Access Token:
- Go to GitHub Settings → Developer settings → Personal access tokens
- Generate a new token with
reposcope - Copy the token
Set the environment variable:
export GITHUB_TOKEN="your_github_token_here"Or add it to your
.bashrc/.zshrc:echo 'export GITHUB_TOKEN="your_github_token_here"' >> ~/.bashrc
2. Git Merge Tool Configuration
Before running Cherri, please set up your merge tool for automatic conflict resolution. When conflicts occur during cherry-picking, they will be handled one by one, opening your configured editor for each conflicted file individually.
Add one of these configurations to your global ~/.gitconfig file:
For Cursor:
[merge]
tool = cursor
[mergetool "cursor"]
cmd = cursor --reuse-window --wait $MERGEDFor VS Code:
[merge]
tool = vscode
[mergetool "vscode"]
cmd = code --wait $MERGEDFor other popular editors:
# For Vim 🗿
[merge]
tool = vimdiff
# For Emacs 🤓 ( only tsoding 🗿 uses this lol )
[merge]
tool = emergeAfter adding this configuration, git will automatically open your editor when conflicts need to be resolved during cherry-picking.
Project Configuration
Instead of specifying repository details via command-line flags each time, you can create a cherri.json configuration file in your project root to define reusable profiles.
Configuration File Structure
Create a cherri.json file in your project root:
{
"profiles": [
{
"name": "main",
"configuration": {
"owner": "your-org",
"repo": "your-repo",
"emoji": "🍒",
"label": "cherry-pick",
"prTitle": "Custom Release PR Title",
"prBodyTemplate": "## 🚀 Release Backport\n\nBackporting {{prCount}} PRs to {{targetBranch}}:\n\n{{prList}}\n\n### Stats\n- Commits: {{commitCount}}\n- Date: {{date}}"
}
},
{
"name": "staging",
"configuration": {
"owner": "your-org",
"repo": "your-repo",
"emoji": "🚀",
"label": "hotfix"
}
}
]
}Using Profiles
Use the -p or --profile flag to specify which profile to use:
# Use the "main" profile configuration
cherri -p main
# Use the "staging" profile configuration
cherri -p staging
# You can still override specific options when using a profile
cherri -p main --interactive --since 2Configuration Options
Each profile's configuration object supports:
| Field | Description | Required | Default |
|---|---|---|---|
owner |
GitHub repository owner | Yes | - |
repo |
GitHub repository name | Yes | - |
emoji |
Emoji to search for in PR titles | No | 🍒 |
label |
Search for PRs with this label | No | - |
prTitle |
Custom title for the created PR (only used with --create-pr) |
No | Cherri: X PR(s) (Y selected) |
prBodyTemplate |
Custom template for PR body with variable substitution (only used with --create-pr) |
No | Default format |
Notes:
- When using
-p, you cannot specify--owneror--repoflags (they come from the profile) - Other command-line options can still be used and will override profile settings
- The configuration file is searched in the current directory and parent directories up to the git root
Usage
Basic Command
cherri -o <owner> -r <repo>Using Configuration File
cherri -p <profile-name>Options
| Option | Alias | Description | Required | Default |
|---|---|---|---|---|
--profile |
-p |
Profile name from cherri.json configuration file | No | - |
--owner |
-o |
GitHub repository owner | Yes* | - |
--repo |
-r |
GitHub repository name | Yes* | - |
--since |
-s |
Time period to look back for PRs (e.g., '1w3d4h', '7d', '2' for 2 months) | No | 1 |
--since-branch |
- | Use branch creation date as cutoff (e.g., 'main', 'release/v1.0') - alternative to --since | No | - |
--emoji |
-e |
Custom emoji to search for in PR titles and display in logo | No | 🍒 |
--interactive |
-i |
Enable interactive mode for PR selection | No | false |
--select-commits |
- | Interactively select individual commits from each PR (requires -i) |
No | false |
--source-branch |
-b |
Source branch, defaults to the default branch | No | Auto-detected |
--label |
-l |
Search for PRs with this exact label (replaces title search) | No | - |
--fail-on-conflict |
- | Exit with error when conflicts are detected instead of prompting for resolution | No | false |
--create-pr |
- | Create a PR instead of direct cherry-picking. Optionally specify target branch (defaults to source branch) | No | false |
* Required unless using --profile with a configuration file
Note: Use either --since OR --since-branch, not both. They serve the same purpose but use different methods to determine the cutoff date for PRs.
Examples
Basic usage - search for PRs with 🍒 in title
cherri -o facebook -r reactLook back 3 months for PRs
cherri -o microsoft -r vscode -s 3Look back 1 week and 2 days for PRs
cherri -o microsoft -r vscode -s 1w2dLook back 7 days for PRs
cherri -o microsoft -r vscode -s 7dLook back 2 hours for PRs
cherri -o microsoft -r vscode -s 2hAlternative: Use branch creation date as cutoff
# Use either --since OR --since-branch, not both
cherri -o your-org -r your-repo --since-branch mainGet all PRs since a release branch was created
cherri -o your-org -r your-repo --since-branch release/v2.0Use a custom emoji marker
cherri -o your-org -r your-repo -e "🚀"Interactive mode - manually select PRs
cherri -o microsoft -r vscode -iInteractive commit selection - select specific commits from each PR
cherri -o your-org -r your-repo -i --select-commitsSpecify custom source branch
cherri -o your-org -r your-repo -b release/1.0Search by exact label only (replaces title search)
cherri -o your-org -r your-repo -l "cherry-pick"Fail on conflict instead of prompting for resolution
cherri -o your-org -r your-repo --fail-on-conflictCreate PR instead of direct cherry-picking
cherri -o your-org -r your-repo --create-prCreate PR targeting a specific branch
cherri -o your-org -r your-repo --create-pr release/v1.0Create PR with specific time period
cherri -o your-org -r your-repo -s 1w --create-prCombine all options
cherri -o facebook -r react -s 2 -i -b main -l "hotfix" --fail-on-conflictTime Period Formats
The --since flag supports flexible time period specifications. Alternatively, you can use --since-branch to use a branch's creation date as the cutoff.
Supported Units
w= weeksd= daysh= hoursm= minutes
Examples
# Complex combinations
cherri -s 1w3d4h # 1 week, 3 days, 4 hours ago
cherri -s 2d12h # 2 days, 12 hours ago
cherri -s 30m # 30 minutes ago
# Individual units
cherri -s 7d # 7 days ago
cherri -s 2h # 2 hours ago
cherri -s 45m # 45 minutes ago
# Backward compatible (bare numbers = months)
cherri -s 2 # 2 months ago (same as before)
cherri -s 1 # 1 month ago (default)
# Alternative: Branch-based cutoff
cherri --since-branch main # Since main branch was created
cherri --since-branch release/v1.0 # Since release branch was createdNotes
- Backward Compatible: Bare numbers without units still work as months
- Flexible: Mix and match any combination of time units
- Precise: Calculations use milliseconds for accuracy
- Alternative: Use
--since-branchfor branch-based cutoffs instead of time calculations
PR Creation Mode
When using the --create-pr flag, Cherri will create a pull request instead of directly cherry-picking commits. This is useful for review workflows where changes need approval before merging.
How it works:
- Branch Creation: Creates a new branch with format
cherri/auto-{timestamp} - Cherry-picking: Applies all selected commits to the new branch
- PR Creation: Creates a pull request from the new branch to your target branch
- Cleanup: Switches back to your original branch
Example workflow:
# Create PR for review instead of direct cherry-picking
cherri -o your-org -r your-repo --create-pr
# Output:
# Creating branch: cherri/auto-2025-09-11T12-30-45
# Pushing branch: cherri/auto-2025-09-11T12-30-45
# Creating pull request...
# ✅ PR Created Successfully!
# PR: https://github.com/your-org/your-repo/pull/123
# Branch: cherri/auto-2025-09-11T12-30-45
# Target: mainPR Details:
- Title:
🍒 Cherry-pick: X PR(s)(where X is the number of PRs) - Body: Contains summary of cherry-picked PRs, commit counts, and generation info
- Labels: Automatically tagged as cherry-pick related
This mode is perfect for:
- Code Review Requirements: When your workflow requires PR reviews
- Staging Environments: Creating intermediate PRs for testing
- Audit Trails: Maintaining a record of all cherry-pick operations
PR Body Template Variables
Customize the PR description using template variables in your cherri.json configuration. Variables are replaced at runtime when creating PRs with --create-pr.
Available Variables
PR Variables
{{prCount}}- Number of PRs successfully cherry-picked{{prList}}- Formatted list of PRs:- #123: Title (@author){{prListPlain}}- Simple comma-separated list:#123, #456, #789{{totalSelected}}- Total number of PRs originally selected{{emoji}}- The emoji used for marking PRs
Commit Variables
{{commitCount}}- Number of commits successfully cherry-picked{{commitSkipped}}- Number of commits skipped
Branch Variables
{{targetBranch}}- Target branch for the PR{{sourceBranch}}- Source branch where commits came from
Date/Time Variables
{{date}}- Current date in ISO format (YYYY-MM-DD){{dateTime}}- Current date and time in ISO format{{timestamp}}- Unix timestamp in milliseconds
Repository Variables
{{owner}}- Repository owner{{repo}}- Repository name
Template Examples
Minimal Template
{
"prBodyTemplate": "Backporting {{prCount}} PRs to {{targetBranch}}\n\n{{prList}}"
}Detailed Template
{
"prBodyTemplate": "## {{emoji}} Cherry-pick Summary\n\nThis PR backports **{{prCount}}** pull requests to `{{targetBranch}}`:\n\n{{prList}}\n\n### Statistics\n- **Total PRs Selected**: {{totalSelected}}\n- **PRs Cherry-picked**: {{prCount}}\n- **Commits Applied**: {{commitCount}}\n- **Commits Skipped**: {{commitSkipped}}\n\n### Branch Info\n- **Source**: {{sourceBranch}}\n- **Target**: {{targetBranch}}\n\n---\nGenerated by Cherri on {{date}}"
}Team Workflow Template
{
"prBodyTemplate": "## Release Backport\n\nBackporting changes from {{sourceBranch}} to {{targetBranch}}:\n\n{{prList}}\n\n### Review Checklist\n- [ ] Code reviewed\n- [ ] Tests passing\n- [ ] Documentation updated\n- [ ] QA approved\n\n**Stats**: {{commitCount}} commits from {{prCount}} PRs\n\nCC: @release-team"
}Simple List Template
{
"prBodyTemplate": "Cherry-picking PRs: {{prListPlain}}\n\nTotal commits: {{commitCount}}"
}Usage
Add prBodyTemplate to your profile configuration:
{
"profiles": [
{
"name": "production",
"configuration": {
"owner": "your-org",
"repo": "your-repo",
"emoji": "🍒",
"prTitle": "Production Backport",
"prBodyTemplate": "## Production Release\n\nBackporting {{prCount}} PRs:\n\n{{prList}}\n\n**Date**: {{date}}\n**Target**: {{targetBranch}}"
}
}
]
}Then use with --create-pr:
cherri -p production --create-prNotes:
- If no
prBodyTemplateis specified, Cherri uses the default format - Unrecognized variables remain as-is (e.g.,
{{unknownVar}}stays unchanged) - Use
\nfor line breaks in JSON strings - Templates work only with
--create-prmode
Search Methods: Title or Labels
Cherri uses one of two search methods (not both simultaneously):
- Title Search (default): Looks for the emoji in PR titles
- Label Search: When using
--label, searches only by the exact label (ignores titles)
Search behavior:
# Title search - finds PRs with 🍒 in title
cherri -o org -r repo
# Label search - finds PRs with "cherry-pick" label (ignores titles completely)
cherri -o org -r repo -l "cherry-pick"Source Branch Detection
Cherri automatically detects your repository's default branch (main/master) using git remote show origin. You can override this with the --source-branch option if needed.
How It Works
Search Phase:
- Without
--label: Searches for merged PRs with the specified emoji in the title - With
--label: Searches for merged PRs with the specified label (ignores titles) - Time-based cutoff: Parses the
--sincetime period (supports complex formats like '1w3d4h', '7d', or '2' for months) - Branch-based cutoff: When using
--since-branch, uses the creation date of the specified branch as the cutoff date - Note: Use either
--sinceOR--since-branch, not both - they serve the same purpose - Filters PRs merged within the specified timeframe
- Without
Selection Phase:
- Interactive mode (
-i): Opens checkbox interface to select specific PRs - Non-interactive mode (default): Processes all found PRs automatically
- Interactive mode (
Processing Phase:
- Direct Mode (default): Cherry-picks commits directly to the target branch
- PR Mode (
--create-pr): Creates a new branch, cherry-picks commits, and creates a PR for review - Retrieves all commits from each selected PR
- Shows a summary of PRs and total commits to be processed
Cherry-pick Phase:
- For each commit:
- Checks if it already exists (by commit message)
- Attempts to cherry-pick
- If the commit SHA doesn't exist (rebased/squashed PRs), automatically finds the equivalent commit by message
- Handles conflicts by automatically opening your configured merge tool
- For each commit:
Conflict Resolution: Default behavior: When conflicts occur, your configured merge tool will automatically open one conflict at a time. Each conflicted file will be processed individually, allowing you to focus on resolving one conflict before moving to the next. If no merge tool is configured, you'll see:
📝 Please resolve conflicts in your editor 1. Fix the conflicted files 2. Save the files 3. Stage changes: git add . Then press: y - to continue after fixing conflicts s - to skip this commit q - to quit the processWith
--fail-on-conflict: The process will immediately exit with an error when any conflict is detected, without prompting for resolution. This is useful for automated environments like CI/CD where you want the process to fail fast on conflicts.
Interactive Selection
When you use the -i or --interactive flag, you'll see a checkbox interface:
🍒 Found 12 PRs with 🍒. Select specific PRs? Yes
? Select PRs to cherry-pick:
❯◯ #1234 Fix authentication bug (john) • 12/1/2024
◉ #1235 Add new feature (sarah) • 12/2/2024
◯ #1236 Update dependencies (bot) • 12/3/2024
Selected 1 PRs:
#1235 Add new featureControls:
- Use SPACE to select/deselect PRs
- Use ENTER to confirm selection
- Use arrow keys to navigate
Interactive Commit Selection
When you use the --select-commits flag (requires -i), you can select specific commits from each PR:
cherri -o your-org -r your-repo -i --select-commitsWorkflow:
- First, select which PRs to cherry-pick (standard interactive mode)
- Then, for each selected PR, choose which commits to include:
[PR 1/3] #123: Fix authentication (5 commits)
? Select commits to cherry-pick:
❯◉ a1b2c3d feat: Add login validation
◉ d4e5f6g fix: Handle edge case
◯ g7h8i9j test: Add unit tests (John Doe)
◉ k1l2m3n docs: Update README
◯ o4p5q6r refactor: Clean up code
✓ Selected 3/5 commits from PR #123Use Cases:
- Cherry-pick only bug fixes, skipping tests or documentation
- Exclude specific commits that might cause conflicts
- Fine-grained control over what gets backported
- Skip commits that are already present in target branch
Marking PRs for Cherry-picking
Choose one of these two methods to mark PRs for cherry-picking:
Method 1: Via Title (default behavior) Add the emoji to PR titles:
🍒 Fix: Critical bug in authentication flow
feat: Add new dashboard widget 🍒
[🍒] Update dependencies for security patchMethod 2: Via Labels (use --label flag)
- Create a label in your repository (e.g., "cherry-pick", "backport", "hotfix")
- Apply the label to PRs you want to cherry-pick
- Use the
--labelflag to search for that specific label (this will ignore titles)
# Search for PRs with "cherry-pick" label (ignores titles)
cherri -o your-org -r your-repo -l "cherry-pick"Features
✅ Smart PR selection - Choose to select specific PRs or process all automatically \ ✅ Interactive checkbox interface - Easy selection with visual feedback \ ✅ Granular commit selection - Pick individual commits from each PR for fine-grained control \ ✅ Flexible search methods - Search by emoji in titles OR by exact labels \ ✅ Branch-based timeframes - Use branch creation dates instead of calculating time periods \ ✅ PR creation mode - Create pull requests instead of direct cherry-picking for review workflows \ ✅ Automatic conflict resolution - Automatically opens your configured merge tool for conflicts \ ✅ One-by-one conflict handling - Processes conflicts individually for focused resolution \ ✅ Automatic commit resolution - Handles rebased and squashed commits by finding matching messages \ ✅ Interactive conflict resolution - Guides you through fixing conflicts when merge tool isn't configured \ ✅ Fail-fast on conflicts - Option to exit immediately on conflicts for automated environments \ ✅ Duplicate detection - Skips commits that are already in the target branch \ ✅ Progress tracking - Shows real-time progress with spinners and status updates \ ✅ Safe operation - Validates repository and branch before making changes \ ✅ Auto version checking - Notifies when updates are available \ ✅ Graceful interruption handling - Clean recovery from Ctrl+C or user cancellation \
Important Notes
⚠️ Always run from the repository root - The tool needs to be executed from within the git repository you want to modify
⚠️ Commit your work first - Ensure you have no uncommitted changes before running
⚠️ Test on a feature branch first - Before cherry-picking to important branches like main or release
⚠️ Configure your merge tool - Set up your preferred merge tool before running to ensure smooth conflict resolution
Troubleshooting
"GITHUB_TOKEN environment variable is not set"
Set your GitHub token:
export GITHUB_TOKEN="ghp_yourtoken"Process interrupted
If you interrupt the process (Ctrl+C), check your git status:
git status
# If needed, abort any in-progress cherry-pick:
git cherry-pick --abort"No PRs found"
- Title search: Check that PRs contain the emoji in their titles
- Label search: Verify PRs have the exact label you're searching for
- Time/Branch filters: Verify the
--sincetimeframe or--since-branchbranch covers when PRs were merged - Note: Remember to use either
--sinceOR--since-branch, not both - Ensure PRs are actually merged (not just closed)
Conflict resolution
merge-toolnot configured: Rungit config merge.tool <tool>to set your preferred merge tool- Merge tool fails: The tool will fall back to manual conflict resolution, but all changes you made while using the merge-tool will be reverted.
Upcoming Features
🚧 In Development:
- Dry run mode - Test cherry-picks without making changes, detect conflicts early
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. Just remember to mark it with 🍒 if you want it cherry-picked!
Made with ❤️ and 🍒