Schedule a commit, a push, or any other command for later, on a cron, or when the repo looks right.
git stays normal. Delay flags live on gtimed only.
Install · Usage · Flags · Conditions · Cloud · Development
gtimed commit --in 20m -m "Hello world"
gtimed push --at "tomorrow 9am"
gtimed --when clean -- git pushNo git clone needed. Copy the line for your computer, paste it, press Enter. Needs Node.js 18+ (npm is included).
Windows (PowerShell) — paste this in PowerShell, not Git Bash.
irm https://raw.githubusercontent.com/XreeceX/GTimed/master/scripts/install.ps1 | iexmacOS, Linux, or Git Bash
curl -fsSL https://raw.githubusercontent.com/XreeceX/GTimed/master/scripts/install.sh | shThat downloads GTimed, builds it, puts gtimed on PATH, and sets up the minute tick. Open a new terminal afterwards.
From a checkout you already have:
npm install
npm run build
npm install -g .
gtimed installnpm link works instead of npm install -g .. Open a new terminal so gtimed is on PATH.
gtimed install is a one-off on this machine:
- On Windows, adds npm's global folder to your user PATH so
gtimedandgtmresolve. - Runs a tick every minute (Task Scheduler on Windows, crontab on macOS/Linux). The PC has to be on and awake.
- Hooks tab completion.
Uninstall: gtimed uninstall, then npm uninstall -g gtimed.
gtimed commit --in 20m -m "fix login"
gtimed push --in 10m
gtimed push --at "tomorrow 9am"
gtimed fetch --cron "0 */4 * * *"
gtimed --when clean -- git push
gtimed --in 30m -- gh pr create --fillgtimed list # queue
gtimed --log # latest job output
gtimed logs <id>
gtimed cancel <id> # id prefix is enough
gtimed cancel last
gtimed abort # every pending job| You type | Meaning |
|---|---|
--in 30s |
30 seconds |
--in 0.1m or --in .1m |
6 seconds |
--in 5m / --in 2h / --in 1d |
5 minutes / 2 hours / 1 day |
--at "tomorrow 9am" |
local time, via chrono |
--at 2026-08-14T09:00 |
ISO |
Printed times (list, logs header, “waiting …”) use this machine’s timezone. Jobs are still stored as UTC.
Also: min, minutes, hours, days, weeks.
A second schedule for the same command in the same folder updates the pending job (same id, new time). A different -m, remote, or directory is a new job.
gtimed push --in 20m
gtimed push --in 5m # updated — fires in 5m
gtimed commit --in 1h -m "a"
gtimed commit --in 10m -m "b" # different message → second jobgtimed tick only runs jobs whose time has already arrived.
nothing due to run
still waiting:
31bc95ae git push waiting 2026-08-14 11:45:30 BST
list uses the same wording: pending jobs say waiting …, finished ones say ran ….
After gtimed install you don't need to tick by hand. gtimed run <id> fires that job now (still checks --when).
- Words like
list/cancel/tickare GTimed's own. - Anything else is a job.
- Git verbs (
commit,push,fetch, …) getgitstuck on the front. --in,--at,--when, … are pulled out wherever they sit.--means "the rest is the command".
gtimed commit -m "x" --in 1h # git commit -m x in 1h
gtimed git push origin main --in 1h
gtimed --in 1h -- git push origin main
gtimed --in 1h -- gh pr create --fillUse -- if the wrapped tool also has --in / --at / --when.
Need at least one of --at, --in, --cron, --when, or --now.
| Flag | Example | Meaning |
|---|---|---|
--in |
--in 30m |
Once, after a duration |
--at |
--at "tomorrow 5pm" |
Once, at that time |
--cron |
--cron "0 18 * * 1-5" |
Each matching minute (stays pending) |
--when |
--when clean |
Repeatable; all must pass at fire time |
--until / --til |
--til "Fri 6pm" |
Give up if conditions never match |
--now |
--now |
Run on this invocation (still honors --when) |
--dry-run / --dry |
--dry |
Log the command, don't spawn it |
--same-branch / --sb |
--sb |
Skip if HEAD moved since you scheduled |
--cwd |
--cwd ../other-repo |
Working directory (default: here) |
--name |
--name evening-push |
Label in gtimed list |
--timeout / --to |
--to 2m |
Kill the process after this |
--retry / --rt |
--rt 3 |
Extra tries after a non-zero exit |
--every |
--every 15s |
Stored on the job; OS tick is still 1 min / daemon 15s |
-h, --help |
gtimed --help |
Show usage, commands, and flags |
-V, --version |
gtimed --version |
Print version |
When a job actually runs (or is skipped / fails), GTimed plays a short sound and shows an OS balloon or notification if notify is on. Toggle with gtimed notify on and gtimed notify off (saved in ~/.gtimed/notify.json). GTIMED_NOTIFY=0 or 1 overrides that file for one process. The test runner and CI stay quiet.
Scheduling push, commit, or add when there is nothing to do still stores the job and prints a note (for example nothing to push when you are not ahead of upstream).
--at uses chrono-node. Cron is 5-field via cron-parser.
These only apply to gtimed / gtm. We do not install gt, because Graphite already uses that. Short flags like --in / --at / --now stay as they are. Git's own flags (-m, -a, -C, ffmpeg's -to, …) are left alone.
| Long | Short |
|---|---|
gtimed |
gtm |
list |
ls |
tick |
--tick |
daemon |
dm |
--timeout |
--to |
--same-branch |
--sb |
--dry-run |
--dry |
--retry |
--rt |
--until |
--til |
--when staged |
--when stg |
--when remote-ok |
--when ro |
gtimed push --in 20m --sb --to 2m --dry
gtm --tickIf a wrapped tool also uses --to / --dry / --rt, put -- in front of that command.
Every spec must pass. Checked in the job's cwd when it fires, not when you type it.
| Spec | Passes when |
|---|---|
clean |
git status --porcelain is empty |
dirty |
working tree has changes |
staged / stg |
index has staged files |
ahead |
local commits not in upstream (@{u}..HEAD) — no fetch |
behind |
upstream has commits you don't (HEAD..@{u}) — no fetch |
remote-ok / ro |
git ls-remote origin HEAD works |
branch=main |
current branch is main |
file=src/app.ts |
that path is dirty |
cmd:<shell> |
command exits 0 |
gtimed --when clean --when ahead -- git push
gtimed --when branch=main --when remote-ok -- git push
gtimed --when "file=package.json" -- git add package.json
gtimed --when "cmd:npm test" -- git push
gtimed --when dirty --until "tomorrow 6pm" -- git add -Aahead / behind use the local tracking ref. Pair with --when remote-ok or cmd:git fetch if you need a fresh remote.
gtimed list # also: ls
gtimed cancel <id>
gtimed cancel last
gtimed cancel --all
gtimed abort # same as cancel --all
gtimed logs <id>
gtimed --log # latest job
gtimed --log <id> # also: --log last
gtimed run <id>
gtimed tick # also: --tick
gtimed daemon # also: dm (tick every 15s in this terminal)
gtimed install / uninstall
gtimed completion install
gtimed completion uninstall
gtimed ui
gtimed cloud
gtimed help # also: -h, --help
gtimed version # also: -V, --version
Statuses: pending → running → done | failed | cancelled | skipped.
Cron jobs go back to pending after a success. One-shots become done. IDs are 8 hex chars; gtimed --log abc is enough if that prefix is unique. Reschedule prints updated <id>.
gtimed install (or gtimed completion install) hooks your shell.
gtimed ca<Tab> # cancel
gtimed --i<Tab> # --in
gtimed commit --w<Tab> # --when
gtimed --when c<Tab> # clean / cmd:
gtimed cancel <Tab> # job ids| Shell | Hook |
|---|---|
| PowerShell | $PROFILE |
| bash / Git Bash | ~/.bashrc if it exists |
| zsh | ~/.zshrc if it exists |
| fish | ~/.config/fish/completions/gtimed.fish |
New terminal after install. Dump a script with gtimed completion powershell. Completion is for gtimed only, not git.
gtimed ui
gtimed ui --port 8787 --cwd . --no-openLocalhost only (http://127.0.0.1:8787): stage files, type a message, pick Now / In / At / Cron, optional push.
The folder vscode-extension/ adds clock / upload buttons next to Git's Commit. See vscode-extension/README.md.
Optional. The CLI still works with no account. When cloud is on, every new schedule is stored on GTimed's hosted API (no website) instead of ~/.gtimed/jobs.json. That API is shared by every GTimed user; your jobs sit under your GitHub account, not anyone else's.
gtimed cloud login --token <github-pat>
gtimed cloud on
gtimed cloud off
gtimed cloud logoutgtimed cloud set <url> is only if you run a fork. The default host is already https://gtimed.vercel.app.
Configure once, like a git remote (gtimed cloud, not gtimed remote). Schedule commands do not gain extra flags.
- GitHub-side (
git push,gh pr create, tag push): this PC uploads a holding ref at schedule time. The API fires your GitHub token atdueAt, even if the laptop is off. - Local-only (
git commit,--when clean,npm, cron): the API only holds the row. This machine’s minute tick downloads due jobs and runs them here. - Cloud on needs network. There is no silent fallback to
jobs.json. Cloud off keeps today’s local queue.
- Load pending jobs.
--untilalready past →failed.--at/--inmust be due;--cronmust match this minute (once per minute).--whenmust pass, or it stays pending.--same-branchand the branch moved →skipped.- Run in the saved
cwdwith your normal env (ssh-agent, Git Credential Manager, …). - Non-zero exit: retry if attempts remain, else
failed.
--dry-run logs would execute … and counts as success.
Queue: ~/.gtimed/jobs.json (GTIMED_HOME to override). Logs: ~/.gtimed/logs/<id>.log.
- A scheduled push uses this machine, your remotes, your credentials, at fire time — unless cloud is on and the job is GitHub-side, in which case GTimed’s API promotes a holding ref via your GitHub token.
- Nothing is snapshotted for local jobs. Extra commits you make before a delayed local push are included. A delayed commit uses whatever is staged then.
- Cloud GitHub-side jobs snapshot the SHA you had when you scheduled (holding ref
refs/gtimed/<id>). cmd:is a shell. Don't put commands you don't trust in it.- No confirm prompt.
gtimed push --in 1mwill push. - Cloud tokens live in
~/.gtimed/cloud.json(mode 600). They are not printed in list, logs, or help. - Completing a job (success, fail, skip) plays a short sound and an OS notice when notify is on (
gtimed notify offto stop).
Sleeping laptops don't fire until the next tick after wake. --every is stored but does not change the OS timer.
npm install
npm run build
npm test # 280 tests (Ubuntu, Windows, macOS × Node 18, 20, and 22)
npx tsx src/index.ts --helpsrc/ CLI, parser, tick, store, tests
scripts/ one-line installer (install.sh / install.ps1 / install.mjs)
ui/ browser panel for gtimed ui
vscode-extension/ SCM buttons
Similar ideas: Git-Schedule, GitLater, grony. Those tend to special-case commit or push. This one wraps any command and can wait on repo state.