Compare commits

...

5 Commits

Author SHA1 Message Date
a74e14514b add pull 2026-01-05 22:11:42 -05:00
01f552b7ec update docs 2026-01-05 20:22:18 -05:00
b6c05ced0a add bbin install docs 2026-01-05 02:47:23 -05:00
02922ccc55 update docs 2026-01-05 02:43:46 -05:00
9fecfeee46 update docs 2026-01-05 02:42:15 -05:00
4 changed files with 212 additions and 64 deletions
+23 -11
View File
@@ -23,30 +23,42 @@ The entire implementation is a single Babashka script (`commitly`) with these ke
- `has-changes?` - Uses `git status --porcelain` to detect uncommitted changes
- `commit-changes` - Executes `git add -A` and `git commit -m` for a repo
- `push-changes` - Executes `git push` for a repo
- `commitly` - Main orchestration function that coordinates the workflow
- `pull-changes` - Executes `git pull` for a repo
- `status-all` - Shows git status for all modified repositories
- `commitly` - Main orchestration function that coordinates commit workflow
- `push-all` - Pushes all repositories without committing
- `pull-all` - Pulls changes for all repositories
- `-main` - CLI argument parsing and entry point
### Workflow
1. Scan current directory for subdirectories with `.git` folders
2. Filter to only repos with uncommitted changes
2. Filter to only repos with uncommitted changes (for commit operations)
3. For each modified repo: stage all changes and commit with provided message
4. If `-p` flag is present, push each successfully committed repo
4. If `push` subcommand is used, push each successfully committed repo (or all repos if no commit message)
5. Report success/failure for each repository
## Common Commands
### Basic Usage
**Note:** These examples assume `commitly` is in your PATH.
```bash
# Commit changes across all modified subrepos
./commitly "commit message"
# Show status of all modified subrepos
commitly status
# Commit changes across all modified subrepos (no push)
commitly "commit message"
# Commit and push changes
./commitly -p "commit message"
commitly push "commit message"
# Push only (no commit) - useful after manual commits
./commitly -p
commitly push
# Pull changes for all subrepos
commitly pull
```
### Running via Babashka Tasks
@@ -61,7 +73,7 @@ bb run "commit message"
The script is self-contained with no external dependencies beyond Babashka standard library (`babashka.process`, `babashka.fs`). To modify:
1. Edit the `commitly` script directly
2. Test changes by running `./commitly` with test arguments
2. Test changes by running `commitly` with test arguments (or `./commitly` if running from the repo directory)
3. The script is executable via shebang `#!/usr/bin/env bb`
## Important Implementation Details
@@ -73,9 +85,9 @@ The script is self-contained with no external dependencies beyond Babashka stand
- Non-zero exit code (1) if any operations fail
- Empty commit message validation prevents accidental empty commits
### Special `-p` Flag Behavior
### Push Subcommand Behavior
The `-p` flag has dual behavior:
The `push` subcommand has dual behavior:
- With commit message: commits then pushes
- Without commit message: pushes only (skips committing)
@@ -85,7 +97,7 @@ This allows workflows like:
cd service-manager && git commit -m "specific message"
cd ../www && git commit -m "different message"
cd ..
./commitly -p # Push all repos
commitly push # Push all repos
```
### Process Execution
+54 -4
View File
@@ -10,14 +10,31 @@ A CLI tool for making commits to many subrepos after a distributed change.
- Automatically detects which subrepos have uncommitted changes
- Creates commits with a single message across all modified subrepos
- Push changes to remote repositories after committing
- Pull changes from remote repositories across all subrepos
- View status of all modified repositories
- Reports commit status for each subrepo
- Written in Babashka for fast startup and easy distribution
## Usage
**Note:** These examples assume `commitly` is in your PATH (e.g., installed via bbin or symlinked).
```bash
# Show status of all modified subrepos
commitly status
# Commit changes across all modified subrepos
./commitly "Your commit message here"
commitly "Your commit message here"
# Commit and push changes
commitly push "Your commit message here"
# Push only (without committing)
commitly push
# Pull changes for all subrepos
commitly pull
```
## Requirements
@@ -26,19 +43,52 @@ A CLI tool for making commits to many subrepos after a distributed change.
## Installation
### Using bbin (Recommended)
Install directly from Gitea using SSH:
```bash
# Install from your Gitea repository via SSH
bbin install git@git.ajet.fyi:ajet-industries/commitly.git
# Install a specific version using a git tag
bbin install git@git.ajet.fyi:ajet-industries/commitly.git --git/tag v1.0.0
# Install the latest commit
bbin install git@git.ajet.fyi:ajet-industries/commitly.git --latest-sha
```
This will install `commitly` to `~/.local/bin/commitly` (make sure `~/.local/bin` is in your PATH).
**Note:** Requires [bbin](https://github.com/babashka/bbin) to be installed first:
```bash
bash < <(curl -s https://raw.githubusercontent.com/babashka/bbin/main/bbin)
```
### Manual Installation
```bash
# Clone the repository
git clone git@git.ajet.fyi:ajet-industries/commitly.git
cd commitly
# Make the script executable
chmod +x commitly
# Optionally, symlink to a directory in your PATH
ln -s $(pwd)/commitly /usr/local/bin/commitly
# Symlink to a directory in your PATH
ln -s $(pwd)/commitly ~/.local/bin/commitly
```
## How It Works
1. Scans parent directory for git repositories
2. Checks each repository for uncommitted changes (staged or unstaged)
3. Commits changes in each modified repository with the provided message
3. Depending on the command:
- `status`: Shows git status for all modified repositories
- `<message>`: Commits changes in each modified repository with the provided message
- `push <message>`: Commits and pushes changes to remote
- `push` (no message): Pushes all repositories without committing
- `pull`: Pulls changes from remote for all repositories
4. Reports success/failure for each repository
## Use Case
+90 -36
View File
@@ -18,11 +18,16 @@
(not (str/blank? (:out result)))))
(defn find-subrepos [parent-dir]
"Find all git repositories in parent directory"
(->> (fs/list-dir parent-dir)
(filter fs/directory?)
(filter git-repo?)
(map str)))
"Find all git repositories in parent directory, including parent itself"
(let [child-repos (->> (fs/list-dir parent-dir)
(filter fs/directory?)
(filter git-repo?)
(map str))
parent-is-repo? (git-repo? parent-dir)
repos (if parent-is-repo?
(cons (str parent-dir) child-repos)
child-repos)]
repos))
(defn commit-changes [repo-path message]
"Commit all changes in repository with given message"
@@ -57,6 +62,20 @@
(catch Exception e
{:success false :repo repo-path :error (.getMessage e)})))
(defn pull-changes [repo-path]
"Pull changes from remote repository"
(try
(let [pull-result (process/shell {:dir repo-path
:out :string
:err :string
:continue true}
"git pull")]
(if (zero? (:exit pull-result))
{:success true :repo repo-path}
{:success false :repo repo-path :error (:err pull-result)}))
(catch Exception e
{:success false :repo repo-path :error (.getMessage e)})))
(defn show-status [repo-path]
"Show git status for a repository"
(let [result (process/shell {:dir (str repo-path)
@@ -126,50 +145,85 @@
(println (format "\n%d repositories failed to push" (count failed)))
(System/exit 1))))))))
(defn push-all []
"Push all repositories without committing"
(let [current-dir (fs/cwd)
subrepos (find-subrepos current-dir)]
(println "\nPushing changes...")
(let [push-results (map push-changes subrepos)]
(doseq [result push-results]
(if (:success result)
(println (format "✓ %s" (fs/file-name (:repo result))))
(println (format "✗ %s: %s" (fs/file-name (:repo result)) (:error result)))))
(let [failed (filter #(not (:success %)) push-results)]
(when (seq failed)
(println (format "\n%d repositories failed to push" (count failed)))
(System/exit 1))))))
(defn pull-all []
"Pull changes for all repositories"
(let [repos (find-subrepos (fs/cwd))
pull-results (map pull-changes repos)
successful (filter :success pull-results)
failed (filter #(not (:success %)) pull-results)]
;; Report successes
(doseq [result successful]
(println (format "✓ %s" (fs/file-name (:repo result)))))
;; Report failures
(when (seq failed)
(println (format "\n%d repositories failed to pull:" (count failed)))
(doseq [result failed]
(println (format "✗ %s" (fs/file-name (:repo result))))
(println (format " Error: %s" (:error result))))
(System/exit 1))
(println (format "\nSuccessfully pulled %d repositories." (count successful)))))
;; CLI entry point
(defn -main [& args]
(if (empty? args)
(do
(println "Usage: commitly [-p] <commit-message>")
(println "Usage: commitly <commit-message>")
(println " commitly status")
(println " commitly push [<commit-message>]")
(println " commitly pull")
(println "")
(println "Options:")
(println " -p Push changes after committing (or just push if no message)")
(println " status Show git status for all subrepos with changes")
(println "Commands:")
(println " status Show git status for all subrepos with changes")
(println " push Push all repositories without committing")
(println " push <commit-message> Commit and push changes across all modified subrepos")
(println " pull Pull changes for all repositories")
(println " <commit-message> Commit changes across all modified subrepos (no push)")
(System/exit 1))
(let [first-arg (first args)]
(let [first-arg (first args)
rest-args (rest args)]
(cond
;; Status command
(= "status" first-arg)
(status-all)
;; Commit/push command
;; Pull command
(= "pull" first-arg)
(pull-all)
;; Push command
(= "push" first-arg)
(if (empty? rest-args)
;; Push only (no commit)
(push-all)
;; Commit and push
(let [commit-message (str/join " " rest-args)]
(commitly commit-message :push? true)))
;; Commit command (no push)
:else
(let [push? (some #(= "-p" %) args)
message-args (remove #(= "-p" %) args)
commit-message (str/join " " message-args)]
(if (and (str/blank? commit-message) push?)
;; If -p is enabled and no message, just push without committing
(do
(println "No commit message provided with -p flag. Pushing only...")
(let [current-dir (fs/cwd)
subrepos (find-subrepos current-dir)]
(println "\nPushing changes...")
(let [push-results (map push-changes subrepos)]
(doseq [result push-results]
(if (:success result)
(println (format "✓ %s" (fs/file-name (:repo result))))
(println (format "✗ %s: %s" (fs/file-name (:repo result)) (:error result)))))
(let [failed (filter #(not (:success %)) push-results)]
(when (seq failed)
(println (format "\n%d repositories failed to push" (count failed)))
(System/exit 1))))))
;; Otherwise, require commit message
(do
(when (str/blank? commit-message)
(println "Error: commit message cannot be empty")
(System/exit 1))
(commitly commit-message :push? push?))))))))
(let [commit-message (str/join " " args)]
(when (str/blank? commit-message)
(println "Error: commit message cannot be empty")
(System/exit 1))
(commitly commit-message :push? false))))))
(when (= *file* (System/getProperty "babashka.file"))
(apply -main *command-line-args*))
+45 -13
View File
@@ -4,41 +4,73 @@ Use this skill when you need to commit and/or push changes across multiple git r
## What is Commitly?
Commitly is a Babashka script located at `commitly/commitly` that commits and pushes changes across all modified git subrepositories in the ajet-industries monorepo.
Commitly is a Babashka CLI tool that commits and pushes changes across all modified git subrepositories in the ajet-industries monorepo.
## Installation
```bash
# Install via bbin (recommended)
bbin install git@git.ajet.fyi:ajet-industries/commitly.git
```
This installs `commitly` to `~/.local/bin/commitly` (ensure `~/.local/bin` is in your PATH).
## Usage
**Note:** These examples assume `commitly` is in your PATH.
```bash
./commitly/commitly [-p] <commit-message>
commitly status # Show status of modified repos
commitly <commit-message> # Commit changes (no push)
commitly push [<commit-message>] # Push (and optionally commit) changes
commitly pull # Pull changes for all repos
```
### Options
### Commands
- `-p` - Push changes after committing. If no commit message is provided with `-p`, it will skip committing and just push all subrepos.
- `status` - Show git status for all modified repositories
- `<commit-message>` - Commit changes across all modified repositories (no push)
- `push` - Push all repositories without committing
- `push <commit-message>` - Commit and push changes across all modified repositories
- `pull` - Pull changes from remote for all repositories
### Examples
**Commit all modified repos with a message:**
**Show status of all modified repos:**
```bash
./commitly/commitly "fix: update configuration"
commitly status
```
**Commit all modified repos with a message (no push):**
```bash
commitly "fix: update configuration"
```
**Commit and push all modified repos:**
```bash
./commitly/commitly -p "feat: add new feature"
commitly push "feat: add new feature"
```
**Just push all repos (no commit):**
```bash
./commitly/commitly -p
commitly push
```
**Pull changes for all repos:**
```bash
commitly pull
```
## How It Works
1. **Discovery**: Scans the current directory for subdirectories containing `.git` folders
2. **Detection**: Checks each repository for uncommitted changes using `git status --porcelain`
3. **Commit**: Runs `git add -A` and `git commit -m "<message>"` for each modified repo
4. **Push**: If `-p` flag is present, runs `git push` for each successfully committed repo (or all repos if no message provided)
3. **Action**: Depending on the command:
- `status`: Shows full `git status` output for each modified repo
- `<message>`: Runs `git add -A` and `git commit -m "<message>"` for each modified repo (no push)
- `push <message>`: Commits and then runs `git push` for each successfully committed repo
- `push` (no message): Runs `git push` for all repos without committing
- `pull`: Runs `git pull` for all repos
## When to Use
@@ -51,18 +83,18 @@ The monorepo contains multiple independent git repositories:
- `www/` - Dashboard website
- `gateway/` - Nginx reverse proxy
- `commitly/` - This tool itself
- `just-vibes/` - Other projects
- Other service repositories as needed
Each has its own `.git` directory and is deployed independently via Gitea Actions when pushed to main.
## Error Handling
- If any repository fails to commit, commitly exits with code 1 and reports which repos failed
- If any repository fails to push (when `-p` is used), commitly exits with code 1 and reports which repos failed
- If any repository fails to push (when `push` subcommand is used), commitly exits with code 1 and reports which repos failed
- Repos are processed independently - one failure doesn't stop others from being processed
## Requirements
- Babashka must be installed (`bb` command available)
- The script must be executable: `chmod +x commitly/commitly`
- `commitly` must be in your PATH (install via bbin or manual symlink)
- Each subrepo must have a git remote configured for pushing