Skip to content
Draft
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
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,42 @@ When two venfork commands race the config update, the losing one's push is rejec

That means concurrent runs are normally invisible to the user — both updates land. Only after sustained contention (3 lease failures in a row) does venfork surface the error and ask you to re-run the command. Don't `--force` the config branch by hand to "fix" a transient lease failure; that's exactly the data-loss path the lease prevents.

#### Consumers reading `venfork-config` directly

Because every config-mutating command replaces (rather than appends to) the `venfork-config` branch tip, **a plain refspec fetch is rejected as non-fast-forward**:

```bash
# This FAILS after any venfork config update:
git fetch origin venfork-config:venfork-config
# ! [rejected] venfork-config -> venfork-config (non-fast-forward)
```

Tools that maintain a long-lived local clone and read the config branch must use a **forced refspec**:

```bash
# Force-update the local ref — safe because the branch is intentionally replaced:
git fetch origin +venfork-config:venfork-config
# or equivalently:
git fetch --force origin venfork-config:venfork-config
```
Comment on lines +515 to +530

**Preferred approach — use the venfork library helpers:** The `readVenforkConfigFromRepo` and `fetchVenforkConfig` functions exported from the `venfork` package handle this internally (they read via `FETCH_HEAD` / a fresh clone without touching any local ref), so you never hit the non-fast-forward edge case:

```js
import { readVenforkConfigFromRepo } from 'venfork';

// Always returns the current remote config — no local-ref management needed.
const config = await readVenforkConfigFromRepo('/path/to/mirror-clone');
```

Or, if you don't have a local clone:

```js
import { fetchVenforkConfig } from 'venfork';

const config = await fetchVenforkConfig('github-org/private-mirror');
```

## Complete Workflow

### Initial Setup
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
"bin": {
"venfork": "./dist/index.js"
},
"exports": {
".": "./dist/lib.js"
},
"scripts": {
"build": "bun build ./src/index.ts --outdir ./dist --target node",
"build": "bun build ./src/index.ts ./src/lib.ts --outdir ./dist --target node",
"compile": "bun build ./src/index.ts --compile --outfile ./dist/venfork",
Comment on lines +9 to 14
"dev": "bun run ./src/index.ts",
"test": "bun test",
Expand Down
23 changes: 23 additions & 0 deletions src/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Venfork public library API.
*
* Downstream tools (bots, CI scripts, triage automation) should use
* these exports to read venfork config instead of fetching the
* `venfork-config` branch directly. Both helpers handle the
* force-push semantics of the config branch internally: they never
* update a local ref, so they are safe to call from a long-lived
* clone without ever hitting a non-fast-forward rejection.
Comment on lines +6 to +9
*/
export {
fetchVenforkConfig,
readVenforkConfigFromRepo,
} from './config.js';

export type {
PulledIssue,
PulledPr,
ShippedBranch,
ShippedIssue,
VenforkConfig,
VenforkConfigPatch,
} from './config.js';
Loading