{ "uuid": [ { "value": "5c793601-f8ea-470d-8c64-3e669226e651" } ], "langcode": [ { "value": "en" } ], "type": [ { "target_id": "daily_email", "target_type": "node_type", "target_uuid": "8bde1f2f-eef9-4f2d-ae9c-96921f8193d7" } ], "revision_timestamp": [ { "value": "2025-05-11T09:01:00+00:00" } ], "revision_uid": [ { "target_type": "user", "target_uuid": "b8966985-d4b2-42a7-a319-2e94ccfbb849" } ], "revision_log": [], "status": [ { "value": true } ], "uid": [ { "target_type": "user", "target_uuid": "b8966985-d4b2-42a7-a319-2e94ccfbb849" } ], "title": [ { "value": "Git Worktrees and Docker Compose" } ], "created": [ { "value": "2022-08-12T00:00:00+00:00" } ], "changed": [ { "value": "2025-05-11T09:01:00+00:00" } ], "promote": [ { "value": false } ], "sticky": [ { "value": false } ], "default_langcode": [ { "value": true } ], "revision_translation_affected": [ { "value": true } ], "path": [ { "alias": "\/daily\/2022\/08\/12\/git-worktrees-docker-compose", "langcode": "en" } ], "body": [ { "value": "\n
I've recently started trialing Git worktrees again as part of my development workflow.<\/p>\n\n
If you are unfamiliar with Git worktrees, they allow you to have muliple branches of a repository checked out at the same time in different directories.<\/p>\n\n
For example, this is what I see within my local checkout of my website repository:<\/p>\n\n
.\n\u251c\u2500\u2500 config\n\u251c\u2500\u2500 HEAD\n\u251c\u2500\u2500 main\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 ansible\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 nginx\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 README.md\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 website\n\u251c\u2500\u2500 new-post\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 ansible\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 nginx\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 README.md\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 website\n\u251c\u2500\u2500 objects\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 info\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 pack\n\u251c\u2500\u2500 packed-refs\n\u251c\u2500\u2500 refs\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 heads\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 tags\n\u2514\u2500\u2500 worktrees\n \u251c\u2500\u2500 main\n \u2514\u2500\u2500 new-post\n<\/code><\/pre>\n\nThe first thing that you'll notice is, because it's a bare clone, it looks a little different to a what you usually see in a Git repository.<\/p>\n\n
Each worktree has it's own directory, so my \"main\" branch inside the main<\/code> directory.<\/p>\n\nIf I need to work on a different branch, such as new-post<\/code>, then I can create a new worktree, move into that directory and start working. I don't need to commit or stash any in-progress work and switch branches.<\/p>\n\nComplications with Docker Compose<\/h2>\n\n
I use Docker and Docker Compose for my projects, and this caused some issues for me the last time that I tried using worktrees.<\/p>\n\n
By default, Docker Compose will use the name of the directory that the Compose file is in to name its containers. If the directory name is \"oliverdavies-uk\", then the containers will be oliverdavies-uk-web_1<\/code>, oliverdavies-uk-db_1<\/code> etc.<\/p>\n\nThis doesn't work so well if the directory is a worktree called \"main\" or \"master\" as you'll have containers called main_web_1<\/code> or master_db_1<\/code>.<\/p>\n\nThe way to solve this is to use the COMPOSE_PROJECT_NAME<\/code> environment variable.<\/p>\n\nIf you prefix Docker Compose commands with COMPOSE_PROJECT_NAME=your-project<\/code>, or add it to an .env<\/code> file (Docker Compose will load this automatically), then this will override the prefix in the container names to be your-project-{service}<\/code>.<\/p>\n\nContainer names per worktree<\/h2>\n\n
Whilst you could use the same Compose project name within all of your worktrees, I prefer to include the worktree name as a suffix - something like my-project-main<\/code> or my-project-staging<\/code> - and keep these stored in an .env<\/code> file in each worktree's directory.<\/p>\n\nAs each worktree now has unique container names, I can have multiple instances of a project running at the same time, and each worktree will have it's own separate data - meaning that I can make changes and test something in one worktree without affecting any others.<\/p>\n\n
You can also use the COMPOSE_PROJECT_NAME<\/code> variable inside Docker Compose files.<\/p>\n\nFor example, if you use Traefik and needed to override the host URL for a service, the string will be interpolated and the project name would be injected as you'd expect.<\/p>\n\n
labels:\n - \"traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(\n `${COMPOSE_PROJECT_NAME}.docker.localhost`,\n `admin.${COMPOSE_PROJECT_NAME}.docker.localhost`\n )\"\n<\/code><\/pre>\n\nThis means that Traefik would continue to use a different URL for each worktree without you needing to make any changes to your Docker Compose file.<\/p>\n\n ",
"format": "full_html",
"processed": "\n
I've recently started trialing Git worktrees again as part of my development workflow.<\/p>\n\n
If you are unfamiliar with Git worktrees, they allow you to have muliple branches of a repository checked out at the same time in different directories.<\/p>\n\n
For example, this is what I see within my local checkout of my website repository:<\/p>\n\n
.\n\u251c\u2500\u2500 config\n\u251c\u2500\u2500 HEAD\n\u251c\u2500\u2500 main\n\u2502 \u251c\u2500\u2500 ansible\n\u2502 \u251c\u2500\u2500 nginx\n\u2502 \u251c\u2500\u2500 README.md\n\u2502 \u2514\u2500\u2500 website\n\u251c\u2500\u2500 new-post\n\u2502 \u251c\u2500\u2500 ansible\n\u2502 \u251c\u2500\u2500 nginx\n\u2502 \u251c\u2500\u2500 README.md\n\u2502 \u2514\u2500\u2500 website\n\u251c\u2500\u2500 objects\n\u2502 \u251c\u2500\u2500 info\n\u2502 \u2514\u2500\u2500 pack\n\u251c\u2500\u2500 packed-refs\n\u251c\u2500\u2500 refs\n\u2502 \u251c\u2500\u2500 heads\n\u2502 \u2514\u2500\u2500 tags\n\u2514\u2500\u2500 worktrees\n \u251c\u2500\u2500 main\n \u2514\u2500\u2500 new-post\n<\/code><\/pre>\n\nThe first thing that you'll notice is, because it's a bare clone, it looks a little different to a what you usually see in a Git repository.<\/p>\n\n
Each worktree has it's own directory, so my \"main\" branch inside the main<\/code> directory.<\/p>\n\nIf I need to work on a different branch, such as new-post<\/code>, then I can create a new worktree, move into that directory and start working. I don't need to commit or stash any in-progress work and switch branches.<\/p>\n\nComplications with Docker Compose<\/h2>\n\n
I use Docker and Docker Compose for my projects, and this caused some issues for me the last time that I tried using worktrees.<\/p>\n\n
By default, Docker Compose will use the name of the directory that the Compose file is in to name its containers. If the directory name is \"oliverdavies-uk\", then the containers will be oliverdavies-uk-web_1<\/code>, oliverdavies-uk-db_1<\/code> etc.<\/p>\n\nThis doesn't work so well if the directory is a worktree called \"main\" or \"master\" as you'll have containers called main_web_1<\/code> or master_db_1<\/code>.<\/p>\n\nThe way to solve this is to use the COMPOSE_PROJECT_NAME<\/code> environment variable.<\/p>\n\nIf you prefix Docker Compose commands with COMPOSE_PROJECT_NAME=your-project<\/code>, or add it to an .env<\/code> file (Docker Compose will load this automatically), then this will override the prefix in the container names to be your-project-{service}<\/code>.<\/p>\n\nContainer names per worktree<\/h2>\n\n
Whilst you could use the same Compose project name within all of your worktrees, I prefer to include the worktree name as a suffix - something like my-project-main<\/code> or my-project-staging<\/code> - and keep these stored in an .env<\/code> file in each worktree's directory.<\/p>\n\nAs each worktree now has unique container names, I can have multiple instances of a project running at the same time, and each worktree will have it's own separate data - meaning that I can make changes and test something in one worktree without affecting any others.<\/p>\n\n
You can also use the COMPOSE_PROJECT_NAME<\/code> variable inside Docker Compose files.<\/p>\n\nFor example, if you use Traefik and needed to override the host URL for a service, the string will be interpolated and the project name would be injected as you'd expect.<\/p>\n\n
labels:\n - \"traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(\n `${COMPOSE_PROJECT_NAME}.docker.localhost`,\n `admin.${COMPOSE_PROJECT_NAME}.docker.localhost`\n )\"\n<\/code><\/pre>\n\nThis means that Traefik would continue to use a different URL for each worktree without you needing to make any changes to your Docker Compose file.<\/p>\n\n ",
"summary": null
}
]
}