geet-geet 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # geet — layered template system
2
+ https://github.com/modularizer/geet
3
+
4
+ > **One working directory**. **Multiple Git repositories**. Each repo tracks a different subset of files.
5
+
6
+ Nothing moves.
7
+ Nothing is copied.
8
+ Only Git's *view* of the filesystem changes.
9
+
10
+ ## Why?
11
+ > “I built something useful, and I think that **SOME but not all of my code is re-usable**.
12
+ I want to publish some of my code for other's to use (or to re-use myself)...
13
+ but **I don't want to spend weeks refactoring** to split apart the reusable code from the implementation-specific code.
14
+ In fact, it may not even be possible to move around all my files without breaking things.
15
+ Plus, supporting this template is my **secondary task** which I want to do in tandem with my **primary development**, using my main repository's working directory and publishing some pieces to the template repo.”
16
+
17
+ - **Making code re-usable is a struggle**, especially if you want to ship an incomplete template that is not easily separated into a standalone module.
18
+ - Modern React Native / Expo apps are **extremely path-sensitive**:
19
+ * file-based routing
20
+ * config files at exact paths
21
+ * native folders
22
+ * toolchains that assume canonical layouts
23
+ - templates are not static: they evolve over time. I don't want to wait until a template is fully perfect before adding to my project, and I want to get features and fixes as the come
24
+ - syncing sucks
25
+ - submodules don't support interleaving files and folders of template code with custom app code
26
+ - I want to simultaneously develop many apps with a similar architecture
27
+
28
+ ---
29
+ ## PreReqs
30
+ 1. `git` - for pretty much everything
31
+ 2. `npm` - really just for installing `geet` globally
32
+ 3. `gh` - for use of `publish` command and `--publish`, `--private`, `--internal` flags
33
+
34
+
35
+ ---
36
+
37
+ ## Quickstart
38
+ ```bash
39
+ npm install -g geet-geet
40
+ geet
41
+ ```
42
+
43
+ Try our [Demo](/docs/DEMO.md)
44
+
45
+ ---
46
+
47
+ ## Table of Contents
48
+
49
+ 1. [Understanding geet](/docs/UNDERSTANDING_GEET.md)
50
+ 2. [Using a geet template](/docs/USING_A_TEMPLATE.md)
51
+ 3. [Publishing a geet template](/docs/PUBLISHING_A_TEMPLATE.md)
52
+ 4. [Multi-layered repos](/docs/MULTI_LAYERED_TEMPLATES.md)
53
+ 5. [Advanced: File promotion](/docs/AUTO_PROMOTE.md)
54
+ 6. [Advanced: Merge keep-ours strategy](/docs/MERGE_KEEP_OURS.md)
55
+ 7. [Advanced: Preventing app-specific code](/docs/PREVENT_COMMIT_PATTERNS.md)
56
+ 8. [Contributing to geet](/docs/CONTRIBUTING.md)
57
+ 9. [FAQ](/docs/FAQ.md)
58
+ 10. [Demo](/docs/DEMO.md)
package/bin/geet.sh ADDED
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ trap 'echo "ERR at ${BASH_SOURCE[0]}:${LINENO}: $BASH_COMMAND" >&2' ERR
4
+
5
+ NODE_BIN="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
6
+ GEET_LIB="$(cd -- "$NODE_BIN/../lib/node_modules/geet-geet/lib" && pwd)"
7
+ GEET_ARGS=("$@")
8
+ source "$GEET_LIB/digest-and-locate.sh" "$@"
9
+ debug "GEET_ARGS=${GEET_ARGS[@]}"
10
+ cmd="${1:-help}"
11
+
12
+
13
+ shift || true
14
+
15
+ case "$cmd" in
16
+ help|-h|--help)
17
+ source "$GEET_LIB/help.sh"
18
+ help
19
+ ;;
20
+
21
+ sync)
22
+ source "$GEET_LIB/sync.sh"
23
+ sync "${GEET_ARGS[@]:1}"
24
+ ;;
25
+
26
+ # Explicit non-git commands
27
+ init)
28
+ source "$GEET_LIB/init.sh"
29
+ init "${GEET_ARGS[@]:1}"
30
+ ;;
31
+
32
+ tree)
33
+ source "$GEET_LIB/tree.sh"
34
+ tree "${GEET_ARGS[@]:1}"
35
+ ;;
36
+
37
+ split)
38
+ source "$GEET_LIB/split.sh"
39
+ split "${GEET_ARGS[@]:1}"
40
+ ;;
41
+
42
+ session)
43
+ source "$GEET_LIB/session.sh"
44
+ session "${GEET_ARGS[@]:1}"
45
+ ;;
46
+
47
+ template)
48
+ source "$GEET_LIB/template.sh"
49
+ template "${GEET_ARGS[@]:1}"
50
+ ;;
51
+
52
+ doctor)
53
+ source "$GEET_LIB/doctor.sh"
54
+ doctor "${GEET_ARGS[@]:1}"
55
+ ;;
56
+
57
+ prework)
58
+ source "$GEET_LIB/prework.sh"
59
+ prework "${GEET_ARGS[@]:1}"
60
+ ;;
61
+
62
+ gh)
63
+ source "$GEET_LIB/ghcli.sh"
64
+ handle "${GEET_ARGS[@]:1}"
65
+ ;;
66
+
67
+ pub|publish)
68
+ GEET_ARGS=("${GEET_ARGS[@]:1}")
69
+ source "$GEET_LIB/ghcli.sh"
70
+ publish_cmd "${GEET_ARGS[@]}"
71
+ ;;
72
+
73
+ install)
74
+ source "$GEET_LIB/git.sh"
75
+ source "$GEET_LIB/install.sh"
76
+ GEET_ARGS=("${GEET_ARGS[@]:1}")
77
+ install "${GEET_ARGS[@]}"
78
+ ;;
79
+
80
+ soft-detach|soft_detach|slide)
81
+ source "$GEET_LIB/detach.sh"
82
+ soft_detach "${GEET_ARGS[@]:1}"
83
+ ;;
84
+
85
+ detach|hard-detach)
86
+ source "$GEET_LIB/detach.sh"
87
+ detach "${GEET_ARGS[@]:1}"
88
+ ;;
89
+
90
+ detached)
91
+ source "$GEET_LIB/detach.sh"
92
+ detached "${GEET_ARGS[@]:1}"
93
+ ;;
94
+
95
+ soft-detached|soft_detached|slid)
96
+ source "$GEET_LIB/detach.sh"
97
+ soft_detached "${GEET_ARGS[@]:1}"
98
+ ;;
99
+
100
+ retach)
101
+ source "$GEET_LIB/detach.sh"
102
+ retach "${GEET_ARGS[@]:1}"
103
+ ;;
104
+
105
+ precommit|pc)
106
+ source "$GEET_LIB/pre-commit/hook.sh"
107
+ ;;
108
+
109
+ remove|rm)
110
+ brave_guard "removing the template tracking" "Are you sure you want to call \`rm -rf \"$TEMPLATE_DIR\"\`?"
111
+ log "You asked for it! Deleting $TEMPLATE_DIR"
112
+ rm -rf "$TEMPLATE_DIR"
113
+ log "You have FULLY detached from the template and removed the git tracking of the template repo"
114
+ log "geet commands will now only work in the generic sense to create or init new projects, but will have no reference of the template repo"
115
+ ;;
116
+
117
+ destroy)
118
+ log "You asked for it! Deleting $TEMPLATE_DIR"
119
+ rm -rf "$TEMPLATE_DIR"
120
+ log "You have FULLY detached from the template and removed the git tracking of the template repo"
121
+ log "geet commands will now only work in the generic sense to create or init new projects, but will have no reference of the template repo"
122
+ ;;
123
+
124
+ bug|feature|issue|whoops|suggest)
125
+ source "$GEET_LIB/whoops.sh"
126
+ open_issue "${GEET_ARGS[@]:1}"
127
+ ;;
128
+
129
+ # Explicit escape hatch
130
+ git)
131
+ source "$GEET_LIB/git.sh"
132
+ call_cmd "${GEET_ARGS[@]:1}"
133
+ ;;
134
+
135
+ include)
136
+ source "$GEET_LIB/include.sh"
137
+ include "${GEET_ARGS[@]:1}"
138
+ ;;
139
+
140
+ ignored|included|excluded)
141
+ source "$GEET_LIB/ignored.sh"
142
+ echo "$(is_ignored "${GEET_ARGS[@]:1}")"
143
+ ;;
144
+
145
+ # Default: assume git subcommand
146
+ *)
147
+ source "$GEET_LIB/git.sh"
148
+ call_cmd "${GEET_ARGS[@]}"
149
+ ;;
150
+ esac
@@ -0,0 +1,173 @@
1
+ # Advanced: File Promotion Pattern
2
+
3
+ ## The Problem
4
+
5
+ When developing a template and app simultaneously in the same working directory, you may need different versions of certain files:
6
+
7
+ - **App's `README.md`**: Explains your specific app
8
+ - **Template's `README.md`**: Explains how to use the template
9
+
10
+ Both need to be at the root:
11
+ - App repo: `README.md` at root for your app's GitHub
12
+ - Template repo: `README.md` at root for template's GitHub
13
+
14
+ But you can't have two different `README.md` files in the same working directory!
15
+
16
+ ## The Solution: File Promotion
17
+
18
+ **Promotion** means committing a file to the template repo at a different path than it exists in the working tree.
19
+
20
+ **Example:**
21
+ - Working tree: `.mytemplate/README.md` (template's README source)
22
+ - Template repo tree: Both `README.md` AND `.mytemplate/README.md`
23
+ - App repo: `README.md` (app's README, different content)
24
+
25
+ When someone clones the template from GitHub, they get `README.md` at the root.
26
+
27
+ ## How It Works
28
+
29
+ ### Naming Convention (Future Feature)
30
+
31
+ Files matching `*-{template-name}.*` auto-promote to the base name:
32
+
33
+ ```
34
+ README-mytemplate.md → promotes to README.md
35
+ LICENSE-mytemplate.txt → promotes to LICENSE.txt
36
+ package-mytemplate.json → promotes to package.json
37
+ ```
38
+
39
+ **Process:**
40
+ 1. Edit `README-mytemplate.md` in working tree
41
+ 2. Run `geet add README-mytemplate.md`
42
+ 3. Git stages it at BOTH locations in template repo:
43
+ - `README-mytemplate.md` (source)
44
+ - `README.md` (promoted)
45
+ 4. Commit to template
46
+ 5. GitHub shows `README.md` at root
47
+
48
+ ### Avoiding Merge Conflicts
49
+
50
+ Promoted files use a custom merge strategy (`merge=keep-ours`):
51
+
52
+ - Files sync normally when content is identical
53
+ - On first divergence: auto-keeps working tree version
54
+ - After divergence: files stop syncing (no conflicts!)
55
+
56
+ This prevents the template's `README.md` from overwriting your app's `README.md` during pulls.
57
+
58
+ **Learn more:** See [Git Merge Strategy: keep-ours](/docs/MERGE_KEEP_OURS.md) for detailed explanation and other use cases.
59
+
60
+ ## Current Implementation
61
+
62
+ **As of now, only `README.md` uses promotion**, and it's set up automatically by `geet template`:
63
+
64
+ - Creates `.mytemplate/README.md` (template README source)
65
+ - Promotes to `README.md` in template repo
66
+ - Sets `merge=keep-ours` to prevent conflicts
67
+ - Creates pre-commit hook to auto-promote on future commits
68
+
69
+ **Workflow after setup:**
70
+ 1. Edit `.mytemplate/README.md`
71
+ 2. Run `geet add .mytemplate/README.md`
72
+ 3. Run `geet commit -m "Update README"`
73
+ 4. **Pre-commit hook automatically promotes to `README.md`**
74
+ 5. Both versions get committed together
75
+
76
+ ## Extending the Pre-commit Hook
77
+
78
+ The pre-commit hook created by `geet template` can be extended to promote additional files.
79
+
80
+ **Location:** `.mytemplate/dot-git/hooks/pre-commit`
81
+
82
+ **Example - promote LICENSE too:**
83
+
84
+ ```bash
85
+ # Edit .mytemplate/dot-git/hooks/pre-commit
86
+ # Add this section to the "USER CUSTOMIZATIONS" area:
87
+
88
+ if git --git-dir="$DOTGIT" diff --cached --name-only | grep -q "^.$LAYER_NAME/LICENSE$"; then
89
+ license_path=".$LAYER_NAME/LICENSE"
90
+ if [[ -f "$license_path" ]]; then
91
+ hash=$(git --git-dir="$DOTGIT" hash-object -w "$license_path")
92
+ git --git-dir="$DOTGIT" update-index --add --cacheinfo 100644 "$hash" "LICENSE"
93
+ echo "[pre-commit] Auto-promoted $license_path → LICENSE"
94
+ fi
95
+ fi
96
+ ```
97
+
98
+ Then set merge strategy for LICENSE:
99
+ ```bash
100
+ geet git config merge.keep-ours.driver "true" # if not already set
101
+ echo "LICENSE merge=keep-ours" >> .mytemplate/dot-git/info/attributes
102
+ ```
103
+
104
+ ## Manual Promotion (Advanced)
105
+
106
+ If you need to promote files without the pre-commit hook:
107
+
108
+ ```bash
109
+ # Stage file at original location
110
+ geet add .mytemplate/LICENSE.md
111
+
112
+ # Also stage it at promoted location
113
+ hash=$(geet git hash-object -w .mytemplate/LICENSE.md)
114
+ geet git update-index --add --cacheinfo 100644 "$hash" LICENSE.md
115
+
116
+ # Prevent merge conflicts
117
+ geet git config merge.keep-ours.driver "true"
118
+ echo "LICENSE.md merge=keep-ours" >> .mytemplate/dot-git/info/attributes
119
+
120
+ # Commit
121
+ geet commit -m "Add LICENSE"
122
+ ```
123
+
124
+ ## When to Use
125
+
126
+ ✅ **Good use cases:**
127
+ - `README.md` (essential for GitHub)
128
+ - `LICENSE` (if template has different license than app)
129
+
130
+ ⚠️ **Use sparingly for:**
131
+ - Config files (consider alternatives first)
132
+ - Package manifests (can be confusing)
133
+
134
+ ❌ **Avoid for:**
135
+ - Source code (use include/exclude instead)
136
+ - Files that change frequently
137
+ - Files with complex merge requirements
138
+
139
+ ## Alternatives
140
+
141
+ **Simple approach (recommended for most files):**
142
+
143
+ Store template files at their normal location:
144
+ - `.mytemplate/docs/USAGE.md`
145
+ - `.mytemplate/examples/`
146
+
147
+ Users get them at these paths when cloning. No promotion needed.
148
+
149
+ **Post-init hook:**
150
+
151
+ Copy files during initialization:
152
+
153
+ ```bash
154
+ # In .mytemplate/post-init.sh
155
+ cp .mytemplate/README.md README.md
156
+ ```
157
+
158
+ Works great if you don't need the file visible on GitHub before clone.
159
+
160
+ ## Trade-offs
161
+
162
+ **Pros:**
163
+ - ✅ Template repo looks complete on GitHub
164
+ - ✅ Files at expected locations after clone
165
+ - ✅ No merge conflicts
166
+
167
+ **Cons:**
168
+ - ⚠️ Adds complexity to git operations
169
+ - ⚠️ Can confuse collaborators
170
+ - ⚠️ Files exist at two paths in repo
171
+ - ⚠️ Custom merge strategy might surprise people
172
+
173
+ **Recommendation:** Use only when necessary, document clearly, prefer simpler alternatives when possible.
@@ -0,0 +1,142 @@
1
+ # 5. Contributing to geet
2
+
3
+ ## Development setup
4
+
5
+ ```bash
6
+ # Clone the repo
7
+ git clone https://github.com/modularizer/geet.git
8
+ cd geet
9
+
10
+ # The scripts are in lib/
11
+ ls lib/
12
+
13
+ # Test any script
14
+ bash lib/doctor.sh help
15
+ bash lib/ghcli.sh help
16
+ ```
17
+
18
+ ## Project structure
19
+
20
+ ```text
21
+ geet/
22
+ lib/
23
+ cli.sh # Main router
24
+ git.sh # Git operations wrapper
25
+ init.sh # Initialize layer
26
+ tree.sh # Inspect layer contents
27
+ split.sh # Export layer files
28
+ session.sh # Isolated build helper
29
+ doctor.sh # Health checks
30
+ gh.sh # GitHub integration
31
+ template.sh # Create new layer
32
+
33
+ bin/
34
+ geet.sh # npm executable wrapper
35
+
36
+ geetinclude.sample # Whitelist example
37
+ package.json # npm package config
38
+ ```
39
+
40
+ ## Architecture principles
41
+
42
+ **Single responsibility:** Each script does one thing well.
43
+
44
+ **Composable:** Scripts call each other via explicit paths.
45
+
46
+ **Portable:** Pure bash + git. No runtime dependencies (except `gh` for GitHub features).
47
+
48
+ **Safe by default:** Dangerous operations require explicit flags.
49
+
50
+ **Idempotent:** Running commands multiple times is safe.
51
+
52
+ ## Code style
53
+
54
+ - Use `set -euo pipefail` at the top
55
+ - Provide clear `die()` and `log()` helpers
56
+ - Include comprehensive help text
57
+ - Document non-obvious behavior
58
+ - Validate inputs early
59
+ - Fail fast with clear errors
60
+
61
+ ## Testing changes
62
+
63
+ ```bash
64
+ # Run doctor to check for issues
65
+ bash lib/doctor.sh
66
+
67
+ # Test in a real project
68
+ cd /path/to/test-project
69
+ /path/to/geet/lib/cli.sh doctor
70
+ ```
71
+
72
+ ## Common tasks
73
+
74
+ ### Adding a new command
75
+
76
+ 1. Create `lib/mycommand.sh`
77
+ 2. Add to `lib/cli.sh` router
78
+ 3. Update help text
79
+ 4. Test thoroughly
80
+
81
+ ### Updating documentation
82
+
83
+ - README.md for user-facing docs
84
+ - Inline comments for complex logic
85
+ - Help text in each script
86
+
87
+ ## Submitting changes
88
+
89
+ 1. **Fork the repo**
90
+ 2. **Create a branch:** `git checkout -b feature/my-feature`
91
+ 3. **Make changes** following code style
92
+ 4. **Test thoroughly** with `doctor` and real projects
93
+ 5. **Commit:** Clear, descriptive messages
94
+ 6. **Push:** `git push origin feature/my-feature`
95
+ 7. **Open PR** with description of changes
96
+
97
+ ## Feature requests
98
+
99
+ Open an issue with:
100
+ - Clear description of the problem
101
+ - Proposed solution (if you have one)
102
+ - Use cases / why it's needed
103
+
104
+ ## Bug reports
105
+
106
+ Open an issue with:
107
+ - What you did (exact commands)
108
+ - What you expected
109
+ - What actually happened
110
+ - Output of `geet doctor`
111
+ - geet version / git version
112
+
113
+ ## Questions
114
+
115
+ For questions about:
116
+ - **Using geet:** Open a discussion
117
+ - **Template design:** Open a discussion
118
+ - **Contributing:** Open an issue
119
+ - **Bugs:** Open an issue
120
+
121
+ ---
122
+
123
+ ## Status
124
+
125
+ This system is intentionally small, explicit, and evolvable.
126
+
127
+ It will grow **only** when real workflows demand it.
128
+
129
+ Core features:
130
+ - ✅ Cloning templates
131
+ - ✅ Init workflow
132
+ - ✅ Layered templates
133
+ - ✅ Include/exclude modes
134
+ - ✅ Introspection tools
135
+ - ✅ Export functionality
136
+ - ✅ Build sessions
137
+ - ✅ Safety rails
138
+ - ✅ Post-init hooks
139
+ - ✅ GitHub integration
140
+ - ✅ Multi-layer support
141
+
142
+ That's the core. Everything else is optional.
package/docs/DEMO.md ADDED
@@ -0,0 +1,131 @@
1
+ # geet Demo
2
+
3
+ This guide walks you through testing geet's core features in under 10 minutes.
4
+
5
+ ## Prerequisites
6
+
7
+ ```bash
8
+ npm install -g geet-geet
9
+ ```
10
+
11
+ ---
12
+
13
+ ### Step 1: Create normal sample git repo
14
+ There is nothing special about this repo. It has no clue it will become a geet template.
15
+ ```bash
16
+ # Create a minimal Expo Router app template (5 tiny files)
17
+ mkdir myapp
18
+ cd myapp
19
+
20
+ git init
21
+
22
+ # Create app directory FIRST
23
+ mkdir -p app/settings
24
+
25
+ # 1) Expo Router layout (required)
26
+ cat > app/_layout.tsx <<'EOF'
27
+ import { Stack } from "expo-router";
28
+ export default function Layout(){ return <Stack/>; }
29
+ EOF
30
+
31
+ # 2) Home screen
32
+ cat > app/index.tsx <<'EOF'
33
+ import { View, Text } from "react-native";
34
+ export default ()=> <View><Text>Home</Text></View>;
35
+ EOF
36
+
37
+ # 3) About screen
38
+ cat > app/about.tsx <<'EOF'
39
+ import { View, Text } from "react-native";
40
+ export default ()=> <View><Text>About</Text></View>;
41
+ EOF
42
+
43
+ # 4) Nested route
44
+ cat > app/settings/index.tsx <<'EOF'
45
+ import { View, Text } from "react-native";
46
+ export default ()=> <View><Text>Settings</Text></View>;
47
+ EOF
48
+
49
+ # 5) Minimal Expo config (enables expo-router)
50
+ cat > app.json <<'EOF'
51
+ { "expo": { "name":"my-template", "slug":"my-template", "plugins":["expo-router"] } }
52
+ EOF
53
+
54
+ cat > .gitignore <<'EOF'
55
+ .idea/
56
+ .claude/
57
+ .vscode/
58
+ EOF
59
+
60
+ git add .
61
+ git commit -m "Minimal Expo Router sample with multiple routes"
62
+ ```
63
+
64
+ ### Step 2: Initialize the template layer
65
+ ```bash
66
+ #make a template git repo and publish to github
67
+ geet template mytemplate "just a demo template" --private # Note: if you omit --private we wont push to github, if you use --public or --internal it will use that visibility
68
+
69
+ # Add some of the app files to the template layer (geet include modifies the .geetinclude then calls geet add)
70
+ geet include "app/index.tsx" "app/_layout.tsx" "app/about.tsx"
71
+ geet commit -m "Initial template layer"
72
+ geet push
73
+ ```
74
+
75
+ ### Step 3: Use the template in a new app
76
+
77
+ ```bash
78
+ cd ..
79
+ # Clone and set up the template
80
+ geet install <your-github-username>/mytemplate MyApp2 --private # Note: if you omit --private we wont push to github, if you use --public or --internal it will use that visibility
81
+ ```
82
+
83
+ ### Step 3: Customize your app (MyApp2)
84
+
85
+ ```bash
86
+ cd MyApp2
87
+ # Add app-specific files
88
+ cat > app/welcome.tsx <<'EOF'
89
+ import { View, Text } from "react-native";
90
+ export default ()=> <View><Text>Welcome</Text></View>;
91
+ EOF
92
+
93
+ # Commit to your app repo (normal git)
94
+ git add .
95
+ git commit -m "Add custom home page"
96
+ git push
97
+
98
+ # Your custom files are NOT in the template
99
+ geet status # Should show clean (welcome.tsx is not in the template (yet) and is ignore by the template layer)
100
+ git status # Should show clean (welcome.tsx is in app)
101
+
102
+ # validate welcome.tsx is not in the template
103
+ geet included app/welcome.tsx
104
+ geet ls-files | grep welcome
105
+ ```
106
+
107
+ ### Step 4: Update the template from MyApp2
108
+
109
+ ```bash
110
+ # Later on if you want to add welcome.tsx to the template:
111
+ geet include app/welcome.tsx
112
+ geet commit -m "Add welcome page to template"
113
+ geet push
114
+ ```
115
+
116
+ ### Step 5: Pull template updates in your app MyApp
117
+
118
+ ```bash
119
+ # Back in your app
120
+ cd ../MyApp
121
+
122
+ # Pull template updates
123
+ geet pull
124
+
125
+ # The changes appear in your working tree
126
+ git diff # Shows welcome.tsx changed
127
+
128
+ # Commit with normal git
129
+ git commit -am "Pulled in an update to welcome.tsx made by the template repo"
130
+
131
+ ```