Skip to content

Deploy a stack from a Git repository #138

Open

Description

@Nikosan73

Summary

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.

Activity

  1. mstrhakr commented on Sep 4, 2026

    @mstrhakr
    Owner

    Thanks, I think this is something that could be added.

  2. ahal commented on Sep 8, 2026

    @ahal

    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

  3. grantemsley commented on Sep 21, 2026

    @grantemsley

    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.

  4. mstrhakr commented on Sep 30, 2026

    @mstrhakr
    Owner

    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.

  5. grantemsley commented on Sep 30, 2026

    @grantemsley

    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.

  6. grantemsley commented on Oct 3, 2026

    @grantemsley

    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?
    • 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 ([Bug]: Autostart and shutdown fail for stacks that have no override file (follow-up to #134) #165). OK to do that for git stacks only?
    • Git checks would use the existing 15-minute auto-update cron job. Ok to install that job when only git checks are turned on?
  7. mstrhakr commented on Oct 6, 2026

    @mstrhakr
    Owner

    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.

  8. grantemsley commented on Oct 6, 2026

    @grantemsley

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

  9. Nikosan73 commented on Oct 7, 2026

    @Nikosan73
    Author

    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.

    Not something to hold part 1 for.

  10. added 4 commits that reference this issue on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions