Skip to content

Repository files navigation

⏱ GTimed

Run git later — without changing git

CI tests license node


TypeScript Node.js Git chrono-node cron-parser tsx npm GitHub Actions Windows macOS / Linux VS Code

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 push

Install

No 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 | iex

macOS, Linux, or Git Bash

curl -fsSL https://raw.githubusercontent.com/XreeceX/GTimed/master/scripts/install.sh | sh

That 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 install

npm 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:

  1. On Windows, adds npm's global folder to your user PATH so gtimed and gtm resolve.
  2. Runs a tick every minute (Task Scheduler on Windows, crontab on macOS/Linux). The PC has to be on and awake.
  3. Hooks tab completion.

Uninstall: gtimed uninstall, then npm uninstall -g gtimed.


Usage

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 --fill
gtimed 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

Times

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.

Same command overwrites

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 job

tick vs the queue

gtimed 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).


How commands are parsed

  1. Words like list / cancel / tick are GTimed's own.
  2. Anything else is a job.
  3. Git verbs (commit, push, fetch, …) get git stuck on the front.
  4. --in, --at, --when, … are pulled out wherever they sit.
  5. -- 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 --fill

Use -- if the wrapped tool also has --in / --at / --when.


Flags

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.

Shortcuts

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 --tick

If a wrapped tool also uses --to / --dry / --rt, put -- in front of that command.


Conditions

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 -A

ahead / behind use the local tracking ref. Pair with --when remote-ok or cmd:git fetch if you need a fresh remote.


Job commands

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: pendingrunningdone | 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>.


Tab completion

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.


UI

gtimed ui
gtimed ui --port 8787 --cwd . --no-open

Localhost 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.


Cloud

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 logout

gtimed 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 at dueAt, 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.

How a tick decides to run

  1. Load pending jobs.
  2. --until already past → failed.
  3. --at / --in must be due; --cron must match this minute (once per minute).
  4. --when must pass, or it stays pending.
  5. --same-branch and the branch moved → skipped.
  6. Run in the saved cwd with your normal env (ssh-agent, Git Credential Manager, …).
  7. 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.


Safety

  • 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 1m will 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 off to stop).

Sleeping laptops don't fire until the next tick after wake. --every is stored but does not change the OS timer.


Development

npm install
npm run build
npm test          # 280 tests (Ubuntu, Windows, macOS × Node 18, 20, and 22)
npx tsx src/index.ts --help
src/               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.


License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages