{"id":35156024,"url":"https://github.com/daniel7grant/gw","last_synced_at":"2025-12-28T17:00:24.316Z","repository":{"id":211598872,"uuid":"728886360","full_name":"daniel7grant/gw","owner":"daniel7grant","description":"Watch local git repositories, keep in sync with remote and run commands.","archived":false,"fork":false,"pushed_at":"2025-12-08T18:13:39.000Z","size":555,"stargazers_count":32,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-09T13:37:45.113Z","etag":null,"topics":["git","rust","watch"],"latest_commit_sha":null,"homepage":"https://gw.danielgrants.com","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daniel7grant.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-12-07T23:05:20.000Z","updated_at":"2025-12-08T19:21:06.000Z","dependencies_parsed_at":"2025-12-06T11:00:25.632Z","dependency_job_id":null,"html_url":"https://github.com/daniel7grant/gw","commit_stats":null,"previous_names":["daniel7grant/gw"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/daniel7grant/gw","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daniel7grant%2Fgw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daniel7grant%2Fgw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daniel7grant%2Fgw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daniel7grant%2Fgw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daniel7grant","download_url":"https://codeload.github.com/daniel7grant/gw/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daniel7grant%2Fgw/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28101588,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-28T02:00:05.685Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["git","rust","watch"],"created_at":"2025-12-28T17:00:09.109Z","updated_at":"2025-12-28T17:00:24.311Z","avatar_url":"https://github.com/daniel7grant.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gw\n\nWatch local git repositories, keep in sync with remote and run commands.\n\n## Motivation\n\n`gw` is a lightweight binary that manages a simple pull-based continuous deployment for you. It watches a local git repository, fetches if the remote changes, and builds or deploys your code. Current CD solutions either lock you into proprietary software (e.g. Netlify or Vercel) or complicated to run and manage (e.g. ArgoCD). `gw` is a service that can run everywhere (even behind NAT or VPN), synchronizes code with your remote and deploys immediately, saving your developers time and energy.\n\nFeatures of `gw`:\n- **lightweight**: it is only a 1.5MB binary (~7MB with git and ssh statically built-in)\n- **runs anywhere**: use it on baremetal or [systemd](https://gw.danielgrants.com/usage/systemd.md) on Linux (x86_64 and ARM) or in [Docker](https://gw.danielgrants.com/usage/docker.md) (Windows and MacOS is supported on a best-effort basis)\n- **open source**: written entirely in Rust, you can build it from source in a few minutes\n- **pull-based**: works on any network, even behind a NAT or VPN\n- **flexible**: build, deploy, restart or anything you can imagine\n\nIf you want to see how `gw` compare to other products: look at the [comparisons](https://gw.danielgrants.com/reference/comparison).\n\n## Installation\n\nTo get started with `gw`, you can use the install script:\n\n```sh\ncurl https://gw.danielgrants.com/install.sh | sh\n```\n\nFor more installation methods, see the [documentation](https://gw.danielgrants.com/usage/installation/).\n\n## Get started\n\n`gw` is a simple program, that you can use to pull changes from a remote repository and run scripts on the change.\n\n### Prerequisites\n\nFirst, make sure, that `gw` is installed successfully and is in your PATH:\n\n```sh\n$ gw --version\n0.4.2\n```\n\nThe other necessary part is a git repository to which you have pull access. It is recommended to use a repository that you know, but if you don't have one at hand, you can use the [daniel7grant/time](https://github.com/daniel7grant/time) repository. This is an example repository that is updated in every minute, so it is useful to test the auto update of `gw`. First clone this repository (if you are using your own, clone again), and enter the cloned directory:\n\n```sh\ngit clone https://github.com/daniel7grant/time.git\ncd time\n```\n\n### Pull files automatically\n\nTo get started, point `gw` to this local repository. By default it pulls the changes every minute. We can add the `--verbose` or `-v` flag to see when the changes occur:\n\n```sh\ngw /path/to/repo -v\n```\n\nIf you are using your own repository, create a commit in a different place, and see how it gets automatically pulled (in the case of the `time` repo, there is a commit every minute). The verbose logs should print that a git pull happened:\n\n```sh\n$ gw /path/to/repo -v\n# ...\n2024-03-10T14:48:13.447Z [DEBUG] Checked out fc23d21 on branch main.\n2024-03-10T14:48:13.447Z [INFO ] There are updates, pulling.\n```\n\nAlso check the files or the `git log` to see that it the repository has been updated:\n\n```sh\ncat DATETIME  # it should contain the latest time\ngit log -1  # it should be a commit in the last minute\n```\n\n### Run scripts on pull\n\nPulling files automatically is useful but the `--script` or `-s` flag unlocks `gw`'s potential: it can run any kind of custom script if there are any changes. For a simple example, we can print the content of a file to the log with `cat`:\n\n```sh\ngw /path/to/repo -v --script 'cat DATETIME'\n```\n\nThis will run every time there is a new commit, and after the pull it will print the file contents. You can see that the results are printed in the log:\n\n```sh\n$ gw /path/to/repo -v --script 'cat DATETIME'\n# ...\n2024-10-18T16:28:53.907Z [INFO ] There are updates, running actions.\n2024-10-18T16:28:53.907Z [INFO ] Running script \"cat\" in /path/to/repo.\n2024-10-18T16:28:53.913Z [DEBUG] [cat] 2024-10-18T16:28:00+0000\n2024-10-18T16:28:53.913Z [INFO ] Script \"cat\" finished successfully.\n```\n\nYou can add multiple scripts, which will run one after another. Use these scripts to build source files, restarts deployments and anything else that you can imagine.\n\n### Run subprocess, restart on pull\n\nIt is often enough to run scripts, but many times you also want to maintain a long-running process e.g. for web services. `gw` can help you with this, using the `-p` flag. This will start a process in the background and restart it on pull.\n\nFor example starting a python web server:\n\n```sh\n$ gw /path/to/repo -v --process \"python -m http.server\"\n# ...\n2024-10-06T21:58:21.306Z [DEBUG] Setting up ProcessAction \"python -m http.server\" on change.\n2024-10-06T21:58:21.306Z [DEBUG] Starting process: \"python\" in directory /path/to/repo.\n2024-10-06T21:58:56.211Z [DEBUG] [python] Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...\n```\n\nThis will run a python process in the background and stop and start it again if a git pull happened. Just wrap your deployment script with `gw` and see it gets updated every time you push to git.\n\n## Run actions on tags\n\nPulling on every commit might not be the fit for every product, especially ones that needs to maintains compatibility or strictly versioned. For these, you can instead trigger on tags. Use the `--on tag` flag to only pull changes if there is a tag on the current branch.\n\n```sh\n$ gw /path/to/repo -v --on tag -S 'echo $GIT_TAG_NAME'\n# ...\n2024-10-18T16:28:53.907Z [INFO ] There are updates, running actions.\n2024-10-18T16:28:53.907Z [INFO ] Running script \"echo\" in /path/to/repo.\n2024-10-18T16:28:53.913Z [DEBUG] [echo] v0.1.0\n2024-10-18T16:28:53.913Z [INFO ] Script \"echo\" finished successfully.\n```\n\nThis will always fetch the current branch, check for the latest tag on it and pull only the commits up to that tag. To match some kind of commit, you can use the `--on tag:v*` which will only pull if the tag is matching the passed glob (in this case starting with `v`).\n\n```sh\ngw /path/to/repo -v --on 'tag:v*' -S 'echo \"new version: $GIT_TAG_NAME\"'\n```\n\n## Next steps\n\nIf you like `gw`, there are multiple ways to use it for real-life use-cases.\n\nIf you want to put the `gw` script in the background, you can:\n\n- wrap into a [systemd unit](https://gw.danielgrants.com/usage/systemd), if you want to manage it with a single file;\n- start in a [docker container](https://gw.danielgrants.com/usage/docker), if you already use Docker in your workflow;\n- or run periodically with [cron](https://gw.danielgrants.com/usage/crontab), if you don't have shell access to the server.\n\nIf you are interested in some ideas on how to use `gw`:\n\n- if you only need to pull files, see [PHP guide](https://gw.danielgrants.com/guides/php);\n- if you are using a dynamic language (e.g. JavaScript, Python, Ruby), see [Guide for dynamic languages](https://gw.danielgrants.com/guides/dynamic) for example on running your process;\n- if you are using a compiled language (e.g. TypeScript, Go, Rust), see [Guide for compiled languages](https://gw.danielgrants.com/guides/compiled) for example on compiling your program;\n- if you use a `docker-compose.yaml`, see [Guide for docker-compose](guides/docker-compose);\n- if you want to easily manage configuration files as GitOps, see [Configuration guide](https://gw.danielgrants.com/guides/configuration);\n- for a full-blown example, check out [Netlify](https://gw.danielgrants.com/guides/netlify);\n- and many other things, for the incomplete list [guides page](https://gw.danielgrants.com/guides).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaniel7grant%2Fgw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaniel7grant%2Fgw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaniel7grant%2Fgw/lists"}