git_policy_cli/command_worktree.rs
1//! What:
2//! The one fact the wrapper needs about `git worktree`:
3//! whether the invocation
4//! creates or moves a worktree.
5//! Why:
6//! Only `git worktree add` and `git worktree move` are sources of ignored-state
7//! synchronization,
8//! and the worktree-copy opt-out is written after that second word.
9//!
10//! In TS you'd write (pseudocode):
11//! ```ts
12//! // changesWorktreeRegistrations(['add', '../topic']) === true
13//! ```
14
15/// What:
16/// `OsString` is owned operating-system text of raw bytes.
17/// Sibling the reader might
18/// expect:
19/// `String`,
20/// which must be valid UTF-8.
21/// Why:
22/// The region is compared as bytes and never decoded.
23///
24/// In TS you'd write (pseudocode):
25/// ```ts
26/// // string, but byte-preserving.
27/// ```
28use std::ffi::OsString;
29
30/// What:
31/// The `git worktree` subcommand words that register or re-register a worktree path.
32/// `&[&[u8]]` is a borrowed list of byte spellings baked into the program.
33/// Why:
34/// Git 2.56.0 `cmd_worktree` declares only subcommands and no option of its own
35/// (builtin/worktree.c),
36/// so the word directly after `worktree` selects the action
37/// and is never abbreviated.
38///
39/// In TS you'd write (pseudocode):
40/// ```ts
41/// const REGISTRATION_SUBCOMMANDS = ['add', 'move'];
42/// ```
43const REGISTRATION_SUBCOMMANDS: &[&[u8]] = &[b"add", b"move"];
44
45/// What:
46/// Whether the tokens after `worktree` start with `add` or `move`.
47/// `&[OsString]`
48/// borrows those tokens;
49/// `bool` is true or false.
50/// Why:
51/// The caller decides from this alone,
52/// without reading the subcommand's options,
53/// so
54/// a mistaken option table can never hide a worktree creation.
55///
56/// In TS you'd write (pseudocode):
57/// ```ts
58/// function changesWorktreeRegistrations(region: string[]): boolean;
59/// ```
60pub fn changes_worktree_registrations(region: &[OsString]) -> bool {
61 // `let Some(x) = ... else { ... };` unwraps the first token or returns for an empty region.
62 let Some(first) = region.first() else {
63 return false;
64 };
65 // `.as_encoded_bytes()` lends the raw bytes; `.contains(&x)` borrows them for the lookup.
66 return REGISTRATION_SUBCOMMANDS.contains(&first.as_encoded_bytes());
67}
68
69/// Word-position cases and a real Git 2.56.0 control stay out of the release executable.
70#[cfg(test)]
71#[path = "command_worktree_tests.rs"]
72mod tests;