This document compares the current Go/Bazel Braid tool with the original Ruby Braid tool from https://github.com/cristibalan/braid. It is for users deciding whether to migrate and for maintainers checking what behavior might change.
Comparison baseline:
- Original Ruby Braid:
cristibalan/braidv1.1.10(16729390a2a8e6b45919545b056a1a7ac83c14d6). - Current Go Braid: the development version after
v0.9.8(52e331f5bd9285035c3edb364de2a67d52dbaddc). - Initial Go-port migration notes: https://github.com/realityforge/braid/blob/d024c502c5eb988f47ac54944f0c5be16bd3b045/docs/migration.md.
The Go tool records named upstream sources in .braids.json. Each source can
provide one or more local mirrors in the downstream repository. Its main
workflows are add, status, diff, pull, push, sync, and remove.
pull is the preferred spelling for updating mirror content; update and up
remain accepted aliases.
In short, existing Ruby Braid repositories need a one-time config migration, scripts need a few command-line changes, and exact console output is not compatible. The sections below explain the changes that affect everyday use and automation.
Ruby Braid is installed as a Ruby gem and needs a compatible Ruby, RubyGems, and
runtime gem environment. The Go tool is released as raw platform binaries with
SHA256SUMS; it does not need Ruby or Go on the target machine.
Current release automation builds native artifacts for Linux amd64/arm64, macOS
amd64/arm64, and Windows amd64. Release binaries are stamped to print the
release version, for example braid 0.9.4. A local unstamped Bazel development
run prints braid 0.0.0-dev.
Migration impact:
- Remove
gem install braid,bundle exec braid, and Gemfile pinning from project setup if they only existed for Braid. - Install the platform binary on
PATHand verify it withSHA256SUMS. - Check the Git version. Ruby Braid required Git 2.8.0 or newer; current Go
Braid requires Git 2.45.0 or newer because pull conflict handling uses newer
git merge-treebehavior.
Ruby Braid refused to run unless the current directory was the downstream Git worktree root. Current Go Braid commands run from any directory inside the worktree.
When a command takes a mirror path, the path is resolved relative to the
directory where Braid was invoked and stored in .braids.json as a
repo-root-relative path. Commands without a path, such as braid status,
braid diff, braid pull, and braid sync, still operate on
the repository-wide mirror set.
Migration impact:
- Existing root-level workflows still work.
- Scripts that assumed Braid would reject subdirectory execution may need to normalize their working directory or pass explicit paths.
- Conflict recovery commands printed by Go Braid are written for the directory where Braid was invoked.
Ruby Braid's write commands generally required the whole repository to be clean
and used git reset --hard to recover from some errors. Current Go Braid scopes
its preflight checks and automatic commits to the Braid-owned paths for the
command.
For add, pull, and remove, unrelated staged, unstaged, and untracked work
outside .braids.json and the selected mirror paths is preserved and is not
included in Braid's automatic commit. These commands accept --no-commit to
stage .braids.json and selected mirror paths without creating the automatic
commit. upgrade-config --no-commit similarly stages only .braids.json. The
paths owned by each command still have to be clean unless the command explicitly
supports a different flow.
Migration impact:
- You can run Braid with unrelated work in progress more safely.
- Use
--no-commitonadd,pull,remove, orupgrade-configwhen the change belongs in the same downstream commit as other related changes. - If unrelated files are already staged during
--no-commit, they remain staged and can be included in the next manual commit unless you unstage them. - Dirty selected mirror paths still stop
add,pull,remove, andsyncunlesssync --autostashis used. - On pull conflict, unrelated staged files remain staged. Go Braid warns about
that because a manual
git commitafter conflict resolution could include those files unless you unstage them.
Ruby Braid has no sync command. Current Go Braid adds:
braid sync [selector...] [--pull-only] [--autostash] [--keep]The default sync workflow pushes committed local changes only for
branch-tracking sources configured with "sync_push": true, then pulls every
mirror in each selected source to the new upstream revision. Add a new opted-in
source with braid add <url> <path> --sync-push. Sources with omitted or false
sync_push are pull-only during sync, even when explicitly selected.
--pull-only skips the push phase for every source. With no selectors, sync
selects all branch and tag sources in lexicographic source-name order and skips
revision-locked sources, matching no-selector pull selection. A selector may
be :source or one of its mirror paths; aliases are deduplicated.
--autostash is path-scoped to selected mirrors. It saves selected mirror-path
tracked changes, untracked files, ignored files, and selected-path index state,
runs the sync, then restores that selected state. It does not push uncommitted
changes; the push phase still uses the mirror content recorded in downstream
HEAD.
Migration impact:
- Set
"sync_push": trueon branch sources that should participate in sync's push phase; omission is pull-only and requires no config version upgrade. - Use
syncfor the common "push opted-in local mirror commits upstream, then pull the downstream recorded revision" workflow. - Use
sync --pull-onlyas a stricter, scoped pull workflow when you do not want any push attempt. - Tag-tracking and revision-locked sources cannot enable
sync_push; usebraid push <path> --branch <branch>explicitly.
Both tools push mirror changes through an isolated temporary repository. The Go tool keeps that model but tightens the user-facing behavior:
pushuses the mirror content recorded in downstreamHEAD. Uncommitted mirror edits are ignored for push planning; commit them downstream first.- If there are no committed local mirror changes in
HEAD, Go Braid printsBraid: No local changes found in downstream HEAD. Stopping. - For branch-tracking sources, omitting
--branchpushes to the tracked branch. Tag-tracking and revision-locked sources still require an explicit--branch. - The editor starts with commented provenance guidance when Braid can compute downstream commits that touched the mirror since the recorded upstream state.
push --message <message>uses the supplied upstream commit message directly without opening the editor or running the generated-message command.BRAID_PUSH_COMMIT_MESSAGE_COMMANDcan optionally run a trusted local POSIX shell command to generate a draft upstream commit message. The editor still opens for review. This generator is disabled by default and is not supported on Windows.
Migration impact:
- Commit downstream mirror edits before
braid pushorbraid sync. - Existing editor-based push workflows still apply, but users will see additional commented guidance in the commit message buffer.
- Treat
BRAID_PUSH_COMMIT_MESSAGE_COMMANDas trusted local shell code, not as a sandboxed plugin mechanism.
| Area | Ruby Braid | Current Go Braid | Migration impact |
|---|---|---|---|
| Commands | add, update, remove, diff, push, setup, version, status, upgrade-config |
pull is the preferred mirror-update command; update and up are aliases. setup is removed. sync and completion are new. |
Remove setup from scripts, prefer pull, and use Go Braid's upgrade-config only for .braids.json version 1 to 2 migration. |
| Help form | braid help, braid add help, braid add --help; the old README also advertised braid help add, but the v1.1.10 gem does not provide command-specific help through that form |
braid help, braid add help, braid add --help |
Prefer braid <command> help or braid <command> --help. |
| Verbose flag | Per-command --verbose/-v |
Global --verbose/-v before the command |
Use braid -v pull ..., not braid pull -v .... |
| Quiet flag | No global quiet flag | Global --quiet before the command; incompatible with --verbose |
Use braid --quiet <command> ... in automation that wants data, warnings, errors, and recovery output without progress or informational chatter. |
| Cache flags | Environment variables only | Global --no-cache or --global-cache-dir <path> before the command, plus environment variables |
Put cache flags before the command name. |
| Bash completion | No documented generated completion command | braid completion bash prints a Bash completion script |
Load it from shell startup or install it in the Bash completion directory to complete global options, commands, command options, and configured mirror paths. |
update --head |
Accepted as an option, then errors with a deprecation message | Unknown flag for pull and its aliases |
Remove it; use --branch, --tag, or --revision with an explicit mirror path. |
update without path |
Updates all configured mirrors through Ruby's all-update flow | pull without a selector updates branch/tag sources in lexicographic source-name order, skips revision-locked sources, and reports skipped names; update and up behave the same way |
Locked sources are no longer touched by all-update. |
Strategy flags with no-path update |
Accepted by the Ruby parser, with inconsistent all-mirror behavior | Rejected for no-path pull and its aliases |
Pass a local path when changing branch, tag, or revision. |
diff pass-through |
Arguments after -- are passed to git diff |
Same | Output formatting is not exact Ruby text parity. |
The Go tool supports the named-source .braids.json shape with
config_version: 2, a top-level sources object, and a local-to-upstream
mirrors object inside each source. Version 1 JSON config can be grouped and
migrated with braid upgrade-config.
Supported source attributes are:
urlbranchtagrevisionpartial_clone(optional)mirrors(required and non-empty)
Important differences:
- Legacy
.braidsYAML/PStore config is not read or upgraded. - Older
.braids.jsonlayouts withoutconfig_versionare not upgraded. upgrade-configdoes not migrate legacy.braidsYAML/PStore data.- Unknown root and source fields fail validation; mirror values must be strings.
- Missing
config_version, missingsources, missingmirrors, missingurl, missingrevision, or a source with bothbranchandtagfails validation. - The current Go code no longer has a special legacy
.braidsdiagnostic. A project that still has only.braidswill look like it has no Go-readable.braids.json.
Migration impact:
- If a project is still on
.braidsor an old.braids.jsonformat, run Ruby Braidv1.1.10braid upgrade-configfirst and commit the resulting.braids.json. - Check generated or hand-edited
.braids.jsonfiles for unknown fields. Ruby Braid was more tolerant in some old upgrade paths; Go Braid is intentionally strict. - Do not rely on Go Braid to remove or migrate
.braids.
The Go tool validates paths earlier and more strictly for cross-platform safety.
Configured local mirror paths and upstream mirror values must use /
separators and must not contain parent traversal, empty elements, absolute
paths, Windows drive paths, colon characters, or path elements ending in a space
or dot. Local mirror paths also reject .git and Windows reserved basenames.
CLI local path arguments may use / or \; Braid normalizes them before
lookup or storage. Absolute local path arguments are accepted only when they are
inside the downstream worktree. The upstream side of
local_path=upstream_path is a Git path and should use /.
Migration impact:
- Some existing Ruby-created configs may be rejected if they contain paths that worked on one platform but are unsafe or ambiguous on another.
- Remote names are checked for collisions after Braid's sanitization step. Ruby Braid noted this collision risk but did not reject it up front.
Both tools enable a local mirror cache by default, but the cache layout changed.
Ruby Braid defaults to ~/.braid/cache and derives cache child paths by
sanitizing the upstream URL. Current Go Braid defaults to repository-local
per-URL bare object caches under .git/braid/cache and derives cache child
paths from a SHA-256-derived key covering the normalized upstream URL. Sources
with the same URL share objects while retaining source-scoped refs.
Current controls:
BRAID_USE_LOCAL_CACHE=falseor--no-cachedisables the cache.BRAID_GLOBAL_CACHE_DIR=<path>or--global-cache-dir <path>selects a shared full-cache directory.--no-cacheand--global-cache-dircannot be used together.BRAID_LOCAL_CACHE_DIRand--cache-dirhave been replaced byBRAID_GLOBAL_CACHE_DIRand--global-cache-dir.
Migration impact:
- Do not depend on the old
~/.braid/cachelayout or old cache path names. - Repository-local caches are disposable. If one is deleted, Braid can rebuild it
only while upstream still serves the recorded revisions from
.braids.json. Shallow repository-local caches can also make Git report the downstream repository as shallow because Braid source objects are recorded in.git/shallow. - Tag-tracking sources work when the Go cache is disabled. Ruby Braid could not retrieve tag revisions with the cache disabled.
Non-conflicting pulls still create Braid commits such as:
Braid: Update source 'example' to 'abcdef0'
Conflict handling differs in details. Ruby Braid documented that users should
resolve conflicts and manually run git commit, or use git reset --hard to
abandon the pull. Current Go Braid prints the exact git add and
git commit -F <MERGE_MSG> commands for the invocation directory.
Current Go Braid stages the updated .braids.json, writes .git/MERGE_MSG, and
restores conflict-marker files in the mirror path. It also warns if unrelated
staged changes are present.
Migration impact:
- Follow the printed commands after a Go Braid conflict rather than old root-only instructions.
- To abandon a conflicted Go Braid pull while preserving unrelated work,
restore only the mirror path and
.braids.jsonfromHEAD, then remove.git/MERGE_MSG.
The Go tool does not preserve exact Ruby help text, progress messages, blank
lines, or status banners. Stable automation should rely on exit codes,
.braids.json, Git state, and documented command behavior rather than exact
Ruby wording.
Go Braid intentionally restores Ruby-like feedback for operations that may
contact upstream repositories or the local cache. It prints semantic start and
completion progress to stderr for cache updates, mirror fetches, pull checks,
mirror updates, upstream pushes, status remote checks, diff remote hydration,
and temporary remote changes. Interactive terminals append . about every five
seconds during long-running operations; non-interactive output is line-based.
The stream contract is explicit:
- Command-requested data stays on
stdout, includingstatus,diff,help, andversion. - Progress and informational output goes to
stderr. - Warnings, errors, conflict recovery instructions, skipped revision-locked
mirror lists, and push stop messages remain visible under
--quiet. --quietsuppresses progress and informational output only; it is global and must appear before the command name.
Known output differences include:
- Error messages use
braid: ...style for Go command failures rather than Ruby'sBraid: Error: ...style. statusprints mirror lines without Ruby's top-level "Listing all mirrors" banner.diffstill labels all-mirror output withBraid: Diffing mirror <path>, but exact separators and paging behavior are not a compatibility target.- Verbose Git tracing uses Go's deterministic argv representation and is
incompatible with
--quiet.
- Upgrade legacy projects with Ruby Braid first:
gem install braid -v 1.1.10andbraid upgrade-config. - Confirm every developer and CI runner has Git 2.45.0 or newer.
- Install the Go release binary for the target platform and verify
SHA256SUMS. - Remove or update automation that uses Ruby's
setupor legacyupgrade-configflows,update --head,braid help <command>, or per-command--verbose. - Run
braid statusandbraid diffon a clean checkout and compare the result with expected mirror state. - Review
.braids.jsonfor unknown fields, unsafe paths, and remote-name collisions. - Decide whether repository-local caches are acceptable; set
BRAID_GLOBAL_CACHE_DIRor use--global-cache-dirif you need a controlled shared full-cache path. - For push workflows, make sure local mirror edits are committed downstream
before
braid pushorbraid sync. - Enable
sync_pushonly for branch sources that should be pushed, then usebraid syncfor the push-then-pull workflow. - Optionally install Bash completion with
braid completion bash.