docs: cadence 7–13 min jitter; commit often, push only at end
Soft range instead of fixed 9m; helper defaults to no push.
This commit is contained in:
parent
cce1fcbe09
commit
140b3bd16f
2 changed files with 94 additions and 55 deletions
|
|
@ -1,22 +1,24 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# git-cadence-commit-push.sh — optional WIP commit + push on the historical cadence
|
# git-cadence-commit.sh — optional local WIP commit on a soft cadence
|
||||||
#
|
#
|
||||||
# Model (from koopa-admin-log / francpaysan-admin-log histories, 2026-07):
|
# Model (koopa-admin-log / francpaysan-admin-log histories + ops preference):
|
||||||
# - message: area: short description (monitoring: … / landings: … / docs: …)
|
# - message: area: short description
|
||||||
# - size: small logical steps, not giant dumps
|
# - size: small logical steps; **prefer more commits over few**
|
||||||
# - interval: about **7–11 minutes** while work is in progress (sometimes denser)
|
# - interval: soft range **7–13 minutes** while work is open (not a strict timer;
|
||||||
# - push: after each commit when the remote accepts credentials
|
# denser bursts of 0–2 min are fine for tiny follow-ups)
|
||||||
|
# - push: **only at the end of a work session** (CADENCE_PUSH=1), never by default
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./scripts/git-cadence-commit-push.sh # this repo
|
# ./scripts/git-cadence-commit-push.sh # commit only if dirty
|
||||||
# ./scripts/git-cadence-commit-push.sh /path/to/repo
|
# ./scripts/git-cadence-commit-push.sh /path/to/repo
|
||||||
# CADENCE_MSG='monitoring: wip ladder' ./scripts/git-cadence-commit-push.sh
|
# CADENCE_MSG='monitoring: wip ladder' ./scripts/git-cadence-commit-push.sh
|
||||||
# CADENCE_DRY=1 ./scripts/git-cadence-commit-push.sh # show only
|
# CADENCE_DRY=1 ./scripts/git-cadence-commit-push.sh
|
||||||
|
# CADENCE_PUSH=1 ./scripts/git-cadence-commit-push.sh # explicit push (end of work)
|
||||||
|
# CADENCE_MIN_AGE_S=420 # skip if last commit younger than this (default 0)
|
||||||
#
|
#
|
||||||
# Cron / agent every ~9 min:
|
# Soft timer (7–13 min, not fixed): fire often, skip until age ∈ [7,13] min target.
|
||||||
# */9 * * * * $HOME/src/koopa/koopa-admin-log/scripts/git-cadence-commit-push.sh
|
# # agent/cron every 7m — script enforces random target in range when CADENCE_JITTER=1
|
||||||
# */9 * * * * $HOME/src/koopa/koopa-admin-log/scripts/git-cadence-commit-push.sh \
|
# CADENCE_JITTER=1 ./scripts/git-cadence-commit-push.sh
|
||||||
# $HOME/taler/src/francpaysan-admin-log
|
|
||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
|
@ -28,7 +30,14 @@ REPO="$(cd "$REPO" && pwd)"
|
||||||
cd "$REPO"
|
cd "$REPO"
|
||||||
|
|
||||||
CADENCE_DRY="${CADENCE_DRY:-0}"
|
CADENCE_DRY="${CADENCE_DRY:-0}"
|
||||||
# Never auto-add secrets
|
# Push only when explicitly requested (end of session) — default OFF
|
||||||
|
CADENCE_PUSH="${CADENCE_PUSH:-0}"
|
||||||
|
# Soft range 7–13 minutes (seconds)
|
||||||
|
CADENCE_RANGE_MIN_S="${CADENCE_RANGE_MIN_S:-420}" # 7 min
|
||||||
|
CADENCE_RANGE_MAX_S="${CADENCE_RANGE_MAX_S:-780}" # 13 min
|
||||||
|
CADENCE_JITTER="${CADENCE_JITTER:-0}"
|
||||||
|
CADENCE_MIN_AGE_S="${CADENCE_MIN_AGE_S:-0}"
|
||||||
|
|
||||||
SKIP_GLOBS=(
|
SKIP_GLOBS=(
|
||||||
'secrets.env'
|
'secrets.env'
|
||||||
'**/secrets.env'
|
'**/secrets.env'
|
||||||
|
|
@ -47,29 +56,66 @@ branch=$(git rev-parse --abbrev-ref HEAD)
|
||||||
remote=$(git remote 2>/dev/null | head -1 || true)
|
remote=$(git remote 2>/dev/null | head -1 || true)
|
||||||
: "${remote:=origin}"
|
: "${remote:=origin}"
|
||||||
|
|
||||||
# Dirty? (tracked + untracked, ignoring unreadable)
|
# Jitter: only proceed if last commit is at least a random target in [7,13] min
|
||||||
|
if [ "$CADENCE_JITTER" = "1" ]; then
|
||||||
|
last=$(git log -1 --format=%ct 2>/dev/null || echo 0)
|
||||||
|
now=$(date +%s)
|
||||||
|
age=$((now - last))
|
||||||
|
# stable-ish target per hour so repeated 7m fires don't all commit
|
||||||
|
target=$(python3 -c "
|
||||||
|
import random, time
|
||||||
|
random.seed(int(time.time()) // 60) # changes every minute
|
||||||
|
print(random.randint(${CADENCE_RANGE_MIN_S}, ${CADENCE_RANGE_MAX_S}))
|
||||||
|
" 2>/dev/null || echo 600)
|
||||||
|
if [ "$age" -lt "$target" ]; then
|
||||||
|
echo "jitter wait · age=${age}s < target=${target}s (range ${CADENCE_RANGE_MIN_S}-${CADENCE_RANGE_MAX_S}s) · $REPO"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
elif [ "${CADENCE_MIN_AGE_S}" -gt 0 ] 2>/dev/null; then
|
||||||
|
last=$(git log -1 --format=%ct 2>/dev/null || echo 0)
|
||||||
|
now=$(date +%s)
|
||||||
|
age=$((now - last))
|
||||||
|
if [ "$age" -lt "$CADENCE_MIN_AGE_S" ]; then
|
||||||
|
echo "min-age wait · age=${age}s < ${CADENCE_MIN_AGE_S}s · $REPO"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
do_push() {
|
||||||
|
local ahead
|
||||||
|
ahead=$(git rev-list --count "${remote}/${branch}..HEAD" 2>/dev/null || echo 0)
|
||||||
|
if [ "${ahead:-0}" -le 0 ]; then
|
||||||
|
echo "nothing to push · $REPO · $branch"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "ahead of ${remote}/${branch} by $ahead"
|
||||||
|
if [ "$CADENCE_DRY" = "1" ]; then
|
||||||
|
echo "DRY: git push $remote $branch"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$CADENCE_PUSH" != "1" ]; then
|
||||||
|
echo "skip push (CADENCE_PUSH!=1 — push only at end of work)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
git push "$remote" "$branch" || {
|
||||||
|
echo "WARN: push failed for $REPO ($remote $branch)" >&2
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
echo "pushed · $remote $branch"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean working tree → maybe push only
|
||||||
if git diff --quiet && git diff --cached --quiet \
|
if git diff --quiet && git diff --cached --quiet \
|
||||||
&& [ -z "$(git ls-files --others --exclude-standard)" ]; then
|
&& [ -z "$(git ls-files --others --exclude-standard)" ]; then
|
||||||
echo "clean · $REPO · $branch (nothing to commit)"
|
echo "clean · $REPO · $branch (nothing to commit)"
|
||||||
# still try push if ahead
|
do_push
|
||||||
ahead=$(git rev-list --count "${remote}/${branch}..HEAD" 2>/dev/null || echo 0)
|
|
||||||
if [ "${ahead:-0}" -gt 0 ]; then
|
|
||||||
echo "ahead of ${remote}/${branch} by $ahead — push"
|
|
||||||
if [ "$CADENCE_DRY" = "1" ]; then
|
|
||||||
echo "DRY: git push $remote $branch"
|
|
||||||
else
|
|
||||||
git push "$remote" "$branch" || echo "WARN: push failed (auth?)" >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Stage safe paths only
|
|
||||||
git add -A
|
git add -A
|
||||||
for g in "${SKIP_GLOBS[@]}"; do
|
for g in "${SKIP_GLOBS[@]}"; do
|
||||||
git reset -q -- "$g" 2>/dev/null || true
|
git reset -q -- "$g" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
# unstage anything still matching secret names
|
|
||||||
while IFS= read -r f; do
|
while IFS= read -r f; do
|
||||||
case "$f" in
|
case "$f" in
|
||||||
*secret*|*password*|*token*|secrets.env)
|
*secret*|*password*|*token*|secrets.env)
|
||||||
|
|
@ -83,7 +129,6 @@ if git diff --cached --quiet; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Message from paths (historical area: style)
|
|
||||||
msg="${CADENCE_MSG:-}"
|
msg="${CADENCE_MSG:-}"
|
||||||
if [ -z "$msg" ]; then
|
if [ -z "$msg" ]; then
|
||||||
files=$(git diff --cached --name-only | head -20)
|
files=$(git diff --cached --name-only | head -20)
|
||||||
|
|
@ -103,14 +148,10 @@ fi
|
||||||
if [ "$CADENCE_DRY" = "1" ]; then
|
if [ "$CADENCE_DRY" = "1" ]; then
|
||||||
echo "DRY commit: $msg"
|
echo "DRY commit: $msg"
|
||||||
git diff --cached --stat
|
git diff --cached --stat
|
||||||
echo "DRY push: $remote $branch"
|
[ "$CADENCE_PUSH" = "1" ] && echo "DRY push: $remote $branch" || echo "DRY: no push"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git commit -m "$msg"
|
git commit -m "$msg"
|
||||||
echo "committed · $msg"
|
echo "committed · $msg"
|
||||||
if ! git push "$remote" "$branch"; then
|
do_push
|
||||||
echo "WARN: push failed for $REPO ($remote $branch) — commit is local" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "pushed · $remote $branch"
|
|
||||||
|
|
|
||||||
|
|
@ -9,49 +9,47 @@ default ops laptop yet.
|
||||||
|
|
||||||
## Git commit / push cadence (existing model)
|
## Git commit / push cadence (existing model)
|
||||||
|
|
||||||
Observed in `koopa-admin-log` and `francpaysan-admin-log` histories
|
Observed in `koopa-admin-log` / `francpaysan-admin-log` histories, plus ops preference:
|
||||||
(active work on 2026-07-17):
|
|
||||||
|
|
||||||
| Rule | Practice |
|
| Rule | Practice |
|
||||||
|------|----------|
|
|------|----------|
|
||||||
| **Interval** | About **7–11 minutes** between publishable steps while a topic is open (bursts of 0–2 min are fine for tiny follow-ups) |
|
| **Commits** | **Prefer frequent** small commits over rare large ones |
|
||||||
| **Message** | `area: short description` — e.g. `monitoring: …`, `landings: …`, `docs: …`, `scripts: …`, `todo: …` |
|
| **Interval** | Soft range **7–13 minutes** while a topic is open — **not** a fixed 9‑minute metronome; denser 0–2 min bursts for tiny follow-ups are fine |
|
||||||
| **Size** | One logical change (or a tight bundle), not end-of-day megacommits |
|
| **Message** | `area: short description` — e.g. `monitoring: …`, `landings: …`, `docs: …` |
|
||||||
| **Push** | After each commit when the remote accepts auth (`git push origin …`) |
|
| **Push** | **Only at the end of a work session** (`CADENCE_PUSH=1` or manual `git push`) — not after every commit |
|
||||||
|
|
||||||
### Agent / human workflow
|
### Agent / human workflow
|
||||||
|
|
||||||
1. Finish a small slice of work.
|
1. Finish a small slice → commit (`area: …`). Repeat often.
|
||||||
2. `git status` / diff → commit with the area-prefix style.
|
2. Do **not** push after each commit.
|
||||||
3. `git push` (or run the helper below).
|
3. When the topic/session is done → one `git push` (or `CADENCE_PUSH=1`).
|
||||||
4. Continue; next commit window ~**7–11 min** later (or sooner if the next slice is ready).
|
4. Soft next-commit window: about **7–13 min** (jitter), sooner if the next slice is ready.
|
||||||
|
|
||||||
### Helper script
|
### Helper script
|
||||||
|
|
||||||
From the admin-log root:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# dry-run
|
# dry-run
|
||||||
CADENCE_DRY=1 ./scripts/git-cadence-commit-push.sh
|
CADENCE_DRY=1 ./scripts/git-cadence-commit-push.sh
|
||||||
|
|
||||||
# commit + push this repo if dirty (skips secrets.env / *password* / *token*)
|
# commit only if dirty (default: no push; skips secrets)
|
||||||
./scripts/git-cadence-commit-push.sh
|
./scripts/git-cadence-commit-push.sh
|
||||||
|
|
||||||
# other checkout
|
|
||||||
./scripts/git-cadence-commit-push.sh ~/taler/src/francpaysan-admin-log
|
./scripts/git-cadence-commit-push.sh ~/taler/src/francpaysan-admin-log
|
||||||
|
|
||||||
|
# end of session — push commits that are already local
|
||||||
|
CADENCE_PUSH=1 ./scripts/git-cadence-commit-push.sh
|
||||||
|
|
||||||
|
# soft timer: only commit if last commit age ≥ random target in 7–13 min
|
||||||
|
CADENCE_JITTER=1 ./scripts/git-cadence-commit-push.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional timer (every 9 min ≈ mid of 7–11):
|
Optional user cron (check every 7 min; **jitter** keeps effective gaps in **7–13 min**):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# user crontab example
|
*/7 * * * * CADENCE_JITTER=1 $HOME/src/koopa/koopa-admin-log/scripts/git-cadence-commit-push.sh >>$HOME/.cache/git-cadence-koopa.log 2>&1
|
||||||
*/9 * * * * $HOME/src/koopa/koopa-admin-log/scripts/git-cadence-commit-push.sh >>$HOME/.cache/git-cadence-koopa.log 2>&1
|
|
||||||
*/9 * * * * $HOME/src/koopa/koopa-admin-log/scripts/git-cadence-commit-push.sh $HOME/taler/src/francpaysan-admin-log >>$HOME/.cache/git-cadence-lfp.log 2>&1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Auth note (this host):** `francpaysan-admin-log` → `ssh://git@git.gnunet.org/…` works.
|
**Auth note:** `francpaysan-admin-log` (gnunet SSH) pushes OK.
|
||||||
`koopa-admin-log` → `https://git.hacktivism.ch/…` needs credentials / SSH key for
|
`koopa-admin-log` (hacktivism HTTPS) needs credentials/SSH key before end-of-session push works from this host.
|
||||||
`git.hacktivism.ch` (push may stay local until that is fixed).
|
|
||||||
|
|
||||||
## What runs without Android
|
## What runs without Android
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue