22
33** Split Rust crates from monorepos, keep them in sync**
44
5- Split Rust crates from Cargo workspaces into standalone repos with full git history. Bidirectional sync keeps monorepo and split repos in line. Release automation with semver checks and topological publishing.
5+ Split Rust crates from Cargo workspaces into standalone repos with full git history. Bidirectional sync keeps monorepo and split repos in line.
66
77[ ![ Crates.io] ( https://img.shields.io/crates/v/cargo-rail.svg )] ( https://crates.io/crates/cargo-rail )
88[ ![ License: MIT] ( https://img.shields.io/badge/License-MIT-blue.svg )] ( https://github.com/loadingalias/cargo-rail/blob/main/LICENSE )
@@ -12,27 +12,24 @@ Split Rust crates from Cargo workspaces into standalone repos with full git hist
1212## Status: Production Ready (v0.1)
1313
1414** Split & Sync:** ✅ Production-ready
15- ** Release Commands:** ✅ Complete (` plan ` , ` prepare ` , ` publish ` , ` finalize ` )
1615** Documentation:** ✅ Complete
1716** CI Coverage:** ✅ 4 platforms (Linux/Windows x86_64/ARM64) + macOS local
1817
19- All features stable. Ready for v1.0 release.
18+ All features stable. Focused on split/sync only - use cargo- release or release-plz for publishing .
2019
2120---
2221
2322## Why cargo-rail?
2423
25- | Feature | cargo-rail | cargo-workspaces | release-plz | git-subtree | Copybara |
26- | ---------| ------------| ------------------| -------------| -------------| ----------|
27- | Split crates | Full history | ❌ | ❌ | One-way | Complex |
28- | Bidirectional sync | ✓ | ❌ | ❌ | ❌ | ✓ |
29- | Cargo-aware | ✓ | ✓ | ✓ | ❌ | ❌ |
30- | Release automation | ✓ | Basic | ✓ | ❌ | ❌ |
31- | Semver checks | ✓ | ❌ | ✓ | ❌ | ❌ |
32- | Dry-run by default | ✓ | ❌ | Partial | ❌ | ❌ |
33- | Setup | One TOML | Easy | Easy | Complex | Very complex |
24+ | Feature | cargo-rail | git-subtree | Copybara |
25+ | ---------| ------------| -------------| ----------|
26+ | Split crates | Full history | One-way | Complex |
27+ | Bidirectional sync | ✓ | ❌ | ✓ |
28+ | Cargo-aware transforms | ✓ | ❌ | ❌ |
29+ | Dry-run by default | ✓ | ❌ | ❌ |
30+ | Setup | One TOML | Complex | Very complex |
3431
35- ** cargo-rail = cargo-workspaces + release-plz + git-subtree **
32+ ** cargo-rail = git-subtree + cargo transforms + bidirectional sync **
3633
3734---
3835
@@ -49,15 +46,6 @@ All features stable. Ready for v1.0 release.
4946- Conflict resolution (ours, theirs, manual, union)
5047- Two modes: single crate → repo, or multiple crates → combined repo
5148
52- ** Release Automation:**
53-
54- - Semver enforcement with breaking change detection (cargo-semver-checks)
55- - Topological publishing (dependencies first)
56- - Changelog generation from conventional commits (git-cliff)
57- - Tag management across monorepo and split repos
58- - Parallel analysis with progress indicators
59- - Dry-run by default with colorized diffs
60-
6149---
6250
6351## Installation
@@ -149,54 +137,50 @@ my-project/
149137
150138---
151139
152- ## Modes Explained
153-
154- ### Single Mode
140+ ## Workflow Example: 25-Crate Monorepo
155141
156- - ** One crate → One repo**
157- - Use when: Publishing independent crates to crates.io
158- - Example: Split ` crates/http-client ` → ` http-client ` standalone repo
142+ ** Scenario:** 5 proprietary crates, 20 OSS (5 split to separate repos, 15 stay in monorepo)
159143
160- ### Combined Mode
144+ ### Development (Monorepo)
161145
162- - ** Multiple crates → One repo**
163- - Use when: Related crates that should live together
164- - Example: Split ` crates/{client,server,common} ` → ` my-project ` workspace repo
165- - Maintains workspace structure in split repo
166- - All crates keep their workspace dependencies
146+ ``` bash
147+ cd monorepo/
148+ # ... make changes to crates/my-oss-lib ...
149+ git commit -am " feat: Add feature"
167150
168- ---
151+ # Sync to split repo
152+ cargo rail sync my-oss-lib --apply
153+ ```
169154
170- ## Sync Workflow
155+ ### Publishing
171156
172- ### Monorepo → Split Repo
157+ ** Option 1: Monorepo-only crates** (20 crates)
158+ ``` bash
159+ cd monorepo/
160+ cargo release --workspace # or release-plz
161+ ```
173162
163+ ** Option 2: Split crates** (5 crates)
174164``` bash
175- cd your-workspace/
176- # Make changes in crates/my-crate/
177- git commit -am " feat: Add feature"
165+ # Ensure synced
166+ cargo rail sync my-oss-lib --apply
178167
179- # Sync to split repo (pushes automatically)
180- cargo rail sync my-crate --apply
168+ # Publish from split repo
169+ cd ../my-oss-lib-split/
170+ cargo release
171+ # Contributors see a normal standalone crate
181172```
182173
183- ### Split Repo → Monorepo
174+ ### External Contributions
184175
185176``` bash
186- cd my-crate-split/
187- # Make changes
188- git commit -am " fix: Bug fix"
189- git push origin main
190-
191- cd ../your-workspace/
192- # Sync from split repo (creates PR branch)
193- cargo rail sync my-crate --apply
194- # Creates branch: rail/sync/my-crate/2025-11-11-143022
195- # Review and merge PR manually
177+ # PR comes into split repo
178+ cd ../monorepo/
179+ cargo rail sync my-oss-lib --apply
180+ # Creates PR branch: rail/sync/my-oss-lib/1763010755
181+ # Review and merge manually
196182```
197183
198- ** Security:** Split→mono syncs NEVER commit directly to main. Always creates PR branch for review.
199-
200184---
201185
202186## Commands
@@ -211,12 +195,6 @@ cargo rail sync --all --apply # Sync all configured splits
211195cargo rail doctor # Run health checks
212196cargo rail status # Show configured splits
213197cargo rail mappings < name> # Inspect git-notes mappings
214-
215- # Release commands
216- cargo rail release plan # Preview releases
217- cargo rail release prepare --apply # Update versions, changelogs
218- cargo rail release publish --apply # Publish to crates.io
219- cargo rail release finalize --apply # Create tags, sync to splits
220198```
221199
222200---
@@ -235,13 +213,6 @@ require_signed_commits = false
235213pr_branch_pattern = " rail/sync/{crate}/{timestamp}"
236214protected_branches = [" main" , " master" ]
237215
238- [release ]
239- strategy = " conventional" # or "manual"
240- tag_format = " {name}@v{version}"
241- publish_delay = 30 # seconds between dependent publishes
242- create_github_releases = true
243- auto_sync_split_repos = true
244-
245216# Single mode example
246217[[splits ]]
247218name = " http-client"
@@ -303,36 +274,13 @@ cargo rail sync my-crate --apply --conflict=union # combine both (risky)
303274 │ │ │ │ │ (standalone) │
304275 └──────────┘ └──────────┘ └─────────────────┘
305276 │ │ │
306- │ publish │ publish │ publish
277+ │ cargo release │ cargo release │ cargo release
307278 ↓ ↓ ↓
308279 ┌────────────────────────────────────────────────┐
309280 │ crates.io registry │
310281 └────────────────────────────────────────────────┘
311282```
312283
313- ### Split Modes
314-
315- ** Single Mode:**
316-
317- ```
318- Monorepo Split Repo
319- crates/my-crate/ → my-crate/
320- ├── src/ ├── src/
321- ├── Cargo.toml ├── Cargo.toml (transformed)
322- └── README.md └── README.md
323- ```
324-
325- ** Combined Mode:**
326-
327- ```
328- Monorepo Split Repo
329- crates/ → my-project/
330- ├── tool-a/ ├── tool-a/
331- ├── tool-b/ ├── tool-b/
332- └── tool-common/ ├── tool-common/
333- └── Cargo.toml (workspace)
334- ```
335-
336284### Sync Flow
337285
338286```
@@ -357,65 +305,6 @@ SPLIT → MONOREPO (PR Branch - Security)
357305└──────────────────────────────────────────────┘
358306```
359307
360- ### Release Flow
361-
362- ```
363- ┌────────────┐
364- │ PLAN │ Analyze commits, detect API changes
365- └──────┬─────┘
366- │
367- ↓
368- ┌────────────┐
369- │ PREPARE │ Bump versions, generate changelogs
370- └──────┬─────┘
371- │
372- ↓
373- ┌────────────┐
374- │ PUBLISH │ Publish to crates.io (topological order)
375- └──────┬─────┘
376- │
377- ↓
378- ┌────────────┐
379- │ FINALIZE │ Create tags, sync to split repos
380- └────────────┘
381- ```
382-
383- ### Key Concepts
384-
385- ** Git-Notes Mapping:**
386-
387- ```
388- refs/notes/rail/{split-name}
389-
390- monorepo_commit_sha → split_commit_sha
391- abc123def456... → 789abc012def...
392- ```
393-
394- ** Transform Pipeline:**
395-
396- ```
397- Monorepo Cargo.toml Split Repo Cargo.toml
398- [dependencies] → [dependencies]
399- my-core = { path = "../my-core" } my-core = "0.1.0"
400-
401- Split Repo Cargo.toml Monorepo Cargo.toml
402- [dependencies] → [dependencies]
403- my-core = "0.1.0" my-core = { path = "../my-core" }
404- ```
405-
406- ** Topological Publishing:**
407-
408- ```
409- Dependency Graph:
410- my-common (no deps)
411- ↓
412- my-core (depends on my-common)
413- ↓
414- my-client (depends on my-core)
415-
416- Publish Order: my-common → my-core → my-client
417- ```
418-
419308---
420309
421310## Security Model
@@ -470,29 +359,26 @@ jobs:
470359 env : { SSH_PRIVATE_KEY: '${{ secrets.DEPLOY_KEY }}' }
471360` ` `
472361
473- ### Release on Tag
362+ ---
474363
475- ` .github/workflows/rail-release.yml`:
364+ ## Publishing Workflow
476365
477- ` ` ` yaml
478- name: Release
479- on:
480- push:
481- tags: ['v*']
366+ cargo-rail focuses on split/sync. Use existing tools for releases:
482367
483- jobs:
484- release:
485- runs-on: ubuntu-latest
486- steps:
487- - uses: actions/checkout@v4
488- - uses: dtolnay/rust-toolchain@stable
489- - run: cargo install cargo-rail
490- - run: |
491- cargo rail release prepare --apply
492- cargo rail release publish --apply --yes
493- cargo rail release finalize --apply
494- env:
495- CARGO_REGISTRY_TOKEN: '${{ secrets.CARGO_TOKEN }}'
368+ **Recommended:**
369+ - [cargo-release](https://github.com/crate-ci/cargo-release) - Simple, battle-tested
370+ - [release-plz](https://github.com/MarcoIeni/release-plz) - Automated releases from CI
371+ - [git-cliff](https://github.com/orhun/git-cliff) - Changelog generation
372+
373+ ` ` ` bash
374+ # Monorepo-only crates
375+ cd monorepo/
376+ cargo release --workspace
377+
378+ # Split crates
379+ cargo rail sync my-crate --apply # Ensure synced
380+ cd ../my-crate-split/
381+ cargo release # Publish from split repo
496382```
497383
498384---
@@ -501,7 +387,6 @@ jobs:
501387
502388- [ USER_GUIDE.md] ( docs/USER_GUIDE.md ) - Complete walkthrough
503389- [ SECURITY.md] ( docs/SECURITY.md ) - Threat model and mitigations
504- - [RELEASE_GUIDE.md](docs/RELEASE_GUIDE.md) - Release workflow
505390- [ E2E_TESTING_SETUP.md] ( E2E_TESTING_SETUP.md ) - End-to-end testing guide
506391- [ STATUS.md] ( STATUS.md ) - Development status
507392
@@ -536,36 +421,11 @@ cargo rail sync my-crate --apply
536421
537422## Comparison
538423
539- **vs cargo-workspaces:** cargo-rail adds split/sync + release (complete workflow)
540- **vs release-plz:** cargo-rail adds split/sync to release automation
541424** vs git-subtree:** cargo-rail is bidirectional + Cargo-aware
542425** vs Copybara:** cargo-rail is simpler (one TOML vs Starlark)
543426** vs git-filter-repo:** cargo-rail preserves monorepo (non-destructive)
544-
545- ---
546-
547- # # Roadmap
548-
549- # ## v1.0 (Ready for Release)
550-
551- - ✅ Split & sync (single and combined modes)
552- - ✅ Release automation
553- - Semver checking (cargo-semver-checks)
554- - Conventional commits parsing
555- - Changelog generation (git-cliff)
556- - Topological publishing
557- - Tag management
558- - ✅ Complete documentation
559- - ✅ CI coverage (6 platforms)
560-
561- # ## v1.1+
562-
563- - Watch mode (`cargo rail watch`)
564- - Performance optimizations (parallel sync)
565- - Homebrew formula
566- - CI templates (GitHub + GitLab)
567-
568- See [STATUS.md](https://github.com/loadingalias/cargo-rail/blob/main/STATUS.md) for details.
427+ ** vs cargo-workspaces:** cargo-rail adds split/sync
428+ ** vs release-plz:** cargo-rail adds split/sync (use release-plz for releases!)
569429
570430---
571431
@@ -589,7 +449,6 @@ MIT - see [LICENSE](https://github.com/loadingalias/cargo-rail/blob/main/LICENSE
589449
590450- Inspired by Google's Copybara and Meta's Sapling
591451- Built on [ gitoxide] ( https://github.com/Byron/gitoxide ) (pure Rust git)
592- - Semver checking via [cargo-semver-checks](https://github.com/obi1kenobi/cargo-semver-checks)
593452
594453---
595454
@@ -610,8 +469,11 @@ A: cargo-rail never commits directly to monorepo main. All syncs create PR branc
610469** Q: Can I sync multiple splits at once?**
611470A: Yes: ` cargo rail sync --all --apply `
612471
472+ ** Q: How do I publish crates?**
473+ A: Use cargo-release or release-plz. cargo-rail focuses on split/sync only.
474+
613475** Q: Large monorepos (100+ crates)?**
614- A : v1.0 focuses on 5-50 crates. Larger workspaces need performance tuning (v1.2) .
476+ A: Current focus is 5-50 crates. Larger workspaces may need performance tuning.
615477
616478---
617479
0 commit comments