You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let a stack pull its compose file from a Git repo, and redeploy when there's a new commit.
Detailed description
I keep all my compose files in GitHub. When I merge a change, I want the stack to pick it up. Right now the plugin has no idea Git exists.
Issue #84 and issue #103 both point the other way. There, the plugin writes the files and Git keeps a record. I'm asking for the reverse. The repo is the source. The plugin reads from it.
What I'm after, roughly:
When adding a stack, let me give a repo URL, a branch, and the path to the compose file inside it. A username and token for private repos.
The plugin clones it somewhere local and runs compose from that copy.
To check for updates, compare the local commit to the head of that branch. Only redeploy if they differ.
Trigger it two ways. On a schedule, reusing the auto-update scheduler that's already there. And by hand, with a "Pull and redeploy" item in the stack menu. A webhook would be nice later, but polling on its own would do.
If someone edits a Git-backed stack in the editor, warn them the next pull will wipe it.
Portainer does this already, and it's the reason my stacks are still there rather than here. Everything else about this plugin is better.
Alternatives considered
I can clone the repo myself, run git pull && docker compose up -d from cron, and register the stack with an Indirect Path. That works. But the plugin can't tell that the stack came from Git, so the UI never shows whether it's current or behind.
Another alternative is to have a bare Git repo on the server that uses a post-receive hook to copy the modified files over to the compose plugin directory. I use this personally, deploying is git push prod
I too would love this, and am willing to work on coding it if you're open to contributions @mstrhakr. Figured I'd ask first so I don't start on something you're already planning to work on yourself.
The lack of git management for the compose stacks has been frustrating for me compared to hosts running Portainer or Komodo. Especially when a lot of my workflows involve scripted deployments or AI agents assisting with it.
I love contributors! I'm focused mostly on cleanup and bug fixes at the moment so if you want to jump into this I'm happy take a look at the PR when you are finished.
Awesome! I had already been working on hacking my own git management system on top of it, but making it a real part of the plugin will be much better. While working on that, I also ran into a few bugs that will be a problem later and had simple fixes, so I'm submitting those now as nice small changes that are easy to review.
Full disclosure, despite me having done PHP programing for literally decades, Claude does most of my actual coding now, with me reviewing the changes and doing some testing by hand. Claude can't even push to my github account, so it's all reviewed by me first. Hopefully that's not a problem, but I know some projects have odd rules about such things.
Before I get too far into it, I figured I'd post how I'm planning to implement things so I can get some feedback if there's anything you'd think should be done differently or for anyone who plans on using it to let me know if it fits their needs.
A git backed stack is just an external folder stack whose folder is a git clone the plugin manages.
Add New Stack will get a 4th option, 'Git repository', that asks for the URL, branch, path to the compose file, and credential. Existing stacks will be able to switch over on the sources tab, so you can put your existing compose files into git and move to git management for the stack without creating duplicate containers or stopping the current ones.
Stacks can have their own repo each, or one big repo with per stack folders, or a combination. Underneath, each stack has its own clone that deploys just its folder. The clones will live in a configurable folder in the appdata directory, not on flash, so we don't have to worry about git operations causing extra flash wear. The project folder on the flash drive will still contain the usual name, autostart, override and .env files, plus a file with its git settings.
Deploying is a new compose.sh verb that does the git work and up under the existing stack lock. It checks as much as possible before starting to avoid failed deploys - clean working tree, docker compose config check, make sure external networks, volumes and bind mounts exist, no container names or ports clash. If a .env.example file exists in the stack, it will also verify that all the keys present in the example exist in the .env file. It only compares the variable names, never the values. That's one that's personally bitten me before, forgetting to add newly required variables after an update. If anything fails, the previous commit is put back in place and nothing is touched. If everything comes up successfully, superseded images are removed the same way Update and auto-update do now.
A failed up isn't rolled back automatically. If it passes all the checks, but still fails to come up, automatic deploys get stopped and it generates a notification. Safer to have a human intervene if it's been left in an unexpected and unknown state.
Local edits stay possible. Someone is going to deploy their git server via git stacks and get themselves into a tricky situation they can't fix otherwise. The editor will show a banner warning you, any uncommitted edits will stop automatic deploys, and manually redeploying from git will offer to save a patch file of your changes first so nothing gets lost.
Updates can be triggered by new 'Pull and redeploy' and 'Check for changes' buttons in the stack menu. A per stack schedule set to off, notify or deploy runs from the existing 15-minute auto update check. There will also be a command line tool to deploy or check for updates on one stack or all of them, with output suitable for both humans and scripts/agents to parse. And if you wanted to have a bare git repo you push to like @ahal, a post-receive hook can simply call that command to update and get all the checks built in.
A new Git (HTTPS token) provider in CredentialVault stores the token for git pulls, and the credential id gets saved in git_credential_id in the project's folder. Git gets the token through a credential helper that checks the git_credential_id, makes sure the host matches, and returns the token to git securely without it ending up in any logs. Using SSH keys as an option as well is something I'm considering.
The UI gets a Git column, showing the branch and brief status information.
Long term, I'd love actual webhooks so deploys can happen automatically right away, but there's no easy way to authenticate that at the moment, so leaving that for later.
A few things I'd like your input on:
Any issue with me adding git tokens to CredentialVault, or would you rather that stay just for registries?
Hey I just remembered I never replied here, sorry about that.
A few things I'd like your input on:
Any issue with me adding git tokens to CredentialVault, or would you rather that stay just for registries?
That is totally fine, hopefully it works for this use case.
Right now a stack uses either the external folder's override file or the plugin-managed one. For git stacks I'd like to apply both (the repo's, then the plugin's labels), skipping any that don't exist (#165). OK to do that for git stacks only?
That sounds okay to me.
Git checks would use the existing 15-minute auto-update cron job. Ok to install that job when only git checks are turned on?
Yes, though you talked about webhooks, and I think thats the next logical step for git based stacks to really become useful. In my mind, webhooks would be for advanced users so a simple open port or path would be enough and the user would be on the hook for securing it with reverse proxy or whatever. I could be off base with that but if you wanted to do webhooks as part of the git PR I would be okay with that.
I definitely want to add webhooks, but probably not up front because I'd want to make sure they're well secured. Of course, anyone who wants them now can set up their own tools to use the compose-git command line tool to deploy right away. Or give your CI runner an SSH key that allows it to log in and run just the needed command.
Right now I've got it split up as 4 separate PRs that build on each other to make it easy to understand and review. The first, the core code and command line interface. That's been tested and reviewed by agent and hand, and I'm just finishing up a few small issues. It's fully usable on its own, though only against repos that don't require authentication. Expect that today or tomorrow. Then comes adding credentials for private repositories, then web UIs, then scheduled checks and notifications. Each of those is written but not fully tested or polished yet.
Apologies for putting my earlier points on #171. They were about the feature rather than the code, so they belonged here. @grantemsley answered them there. In short, unattended deploys will default to off, and tags can be resolved to a commit with git rev-parse for now.
One follow-up on migrations. Grant found that a failed migration service leaves the stack down until the next deploy, because compose has already recreated the app containers. That is the outcome we most want to avoid. Could there be an optional pre-deploy command per stack? It would run after fetch, checkout, pull and build, but before up. For example, docker compose run --rm migrate against the new commit.
A non-zero exit would then count like any other pre-flight failure. The previous commit goes back, and the running containers are never touched. That fits the rollback already in place before up. It cannot undo a migration that half-applied, but the old app stays up while someone looks.
Activity
mstrhakr commentedon Sep 4, 2026
Thanks, I think this is something that could be added.
ahal commentedon Sep 8, 2026
Another alternative is to have a bare Git repo on the server that uses a post-receive hook to copy the modified files over to the compose plugin directory. I use this personally, deploying is
git push prodgrantemsley commentedon Sep 21, 2026
I too would love this, and am willing to work on coding it if you're open to contributions @mstrhakr. Figured I'd ask first so I don't start on something you're already planning to work on yourself.
The lack of git management for the compose stacks has been frustrating for me compared to hosts running Portainer or Komodo. Especially when a lot of my workflows involve scripted deployments or AI agents assisting with it.
mstrhakr commentedon Sep 30, 2026
I love contributors! I'm focused mostly on cleanup and bug fixes at the moment so if you want to jump into this I'm happy take a look at the PR when you are finished.
grantemsley commentedon Sep 30, 2026
Awesome! I had already been working on hacking my own git management system on top of it, but making it a real part of the plugin will be much better. While working on that, I also ran into a few bugs that will be a problem later and had simple fixes, so I'm submitting those now as nice small changes that are easy to review.
Full disclosure, despite me having done PHP programing for literally decades, Claude does most of my actual coding now, with me reviewing the changes and doing some testing by hand. Claude can't even push to my github account, so it's all reviewed by me first. Hopefully that's not a problem, but I know some projects have odd rules about such things.
grantemsley commentedon Oct 3, 2026
Before I get too far into it, I figured I'd post how I'm planning to implement things so I can get some feedback if there's anything you'd think should be done differently or for anyone who plans on using it to let me know if it fits their needs.
A git backed stack is just an external folder stack whose folder is a git clone the plugin manages.
Add New Stack will get a 4th option, 'Git repository', that asks for the URL, branch, path to the compose file, and credential. Existing stacks will be able to switch over on the sources tab, so you can put your existing compose files into git and move to git management for the stack without creating duplicate containers or stopping the current ones.
Stacks can have their own repo each, or one big repo with per stack folders, or a combination. Underneath, each stack has its own clone that deploys just its folder. The clones will live in a configurable folder in the appdata directory, not on flash, so we don't have to worry about git operations causing extra flash wear. The project folder on the flash drive will still contain the usual name, autostart, override and .env files, plus a file with its git settings.
Deploying is a new compose.sh verb that does the git work and
upunder the existing stack lock. It checks as much as possible before starting to avoid failed deploys - clean working tree,docker compose configcheck, make sure external networks, volumes and bind mounts exist, no container names or ports clash. If a.env.examplefile exists in the stack, it will also verify that all the keys present in the example exist in the.envfile. It only compares the variable names, never the values. That's one that's personally bitten me before, forgetting to add newly required variables after an update. If anything fails, the previous commit is put back in place and nothing is touched. If everything comes up successfully, superseded images are removed the same way Update and auto-update do now.A failed up isn't rolled back automatically. If it passes all the checks, but still fails to come up, automatic deploys get stopped and it generates a notification. Safer to have a human intervene if it's been left in an unexpected and unknown state.
Local edits stay possible. Someone is going to deploy their git server via git stacks and get themselves into a tricky situation they can't fix otherwise. The editor will show a banner warning you, any uncommitted edits will stop automatic deploys, and manually redeploying from git will offer to save a patch file of your changes first so nothing gets lost.
Updates can be triggered by new 'Pull and redeploy' and 'Check for changes' buttons in the stack menu. A per stack schedule set to off, notify or deploy runs from the existing 15-minute auto update check. There will also be a command line tool to deploy or check for updates on one stack or all of them, with output suitable for both humans and scripts/agents to parse. And if you wanted to have a bare git repo you push to like @ahal, a post-receive hook can simply call that command to update and get all the checks built in.
A new
Git (HTTPS token)provider inCredentialVaultstores the token for git pulls, and the credential id gets saved ingit_credential_idin the project's folder. Git gets the token through a credential helper that checks thegit_credential_id, makes sure the host matches, and returns the token to git securely without it ending up in any logs. Using SSH keys as an option as well is something I'm considering.The UI gets a Git column, showing the branch and brief status information.
Long term, I'd love actual webhooks so deploys can happen automatically right away, but there's no easy way to authenticate that at the moment, so leaving that for later.
A few things I'd like your input on:
CredentialVault, or would you rather that stay just for registries?mstrhakr commentedon Oct 6, 2026
Hey I just remembered I never replied here, sorry about that.
That is totally fine, hopefully it works for this use case.
That sounds okay to me.
Yes, though you talked about webhooks, and I think thats the next logical step for git based stacks to really become useful. In my mind, webhooks would be for advanced users so a simple open port or path would be enough and the user would be on the hook for securing it with reverse proxy or whatever. I could be off base with that but if you wanted to do webhooks as part of the git PR I would be okay with that.
grantemsley commentedon Oct 6, 2026
Great!
I definitely want to add webhooks, but probably not up front because I'd want to make sure they're well secured. Of course, anyone who wants them now can set up their own tools to use the
compose-gitcommand line tool to deploy right away. Or give your CI runner an SSH key that allows it to log in and run just the needed command.Right now I've got it split up as 4 separate PRs that build on each other to make it easy to understand and review. The first, the core code and command line interface. That's been tested and reviewed by agent and hand, and I'm just finishing up a few small issues. It's fully usable on its own, though only against repos that don't require authentication. Expect that today or tomorrow. Then comes adding credentials for private repositories, then web UIs, then scheduled checks and notifications. Each of those is written but not fully tested or polished yet.
Nikosan73 commentedon Oct 7, 2026
Apologies for putting my earlier points on #171. They were about the feature rather than the code, so they belonged here. @grantemsley answered them there. In short, unattended deploys will default to off, and tags can be resolved to a commit with
git rev-parsefor now.One follow-up on migrations. Grant found that a failed migration service leaves the stack down until the next deploy, because compose has already recreated the app containers. That is the outcome we most want to avoid. Could there be an optional pre-deploy command per stack? It would run after fetch, checkout, pull and build, but before
up. For example,docker compose run --rm migrateagainst the new commit.A non-zero exit would then count like any other pre-flight failure. The previous commit goes back, and the running containers are never touched. That fits the rollback already in place before
up. It cannot undo a migration that half-applied, but the old app stays up while someone looks.Not something to hold part 1 for.
Merge pull request #171 from grantemsley/feat/git-stacks-core
Merge pull request #174 from grantemsley/feat/git-stacks-credentials
Merge pull request #178 from grantemsley/feat/git-stacks-ui
Merge pull request #181 from grantemsley/feat/git-scheduled-checks