fix: support hashtag and special chars in branch names for git clone

Branch names were interpolated unquoted into the git clone shell command,
so a `#` (valid in git branch names) started a shell comment and dropped
the rest of the command, causing the clone to fail (#4585).

Escape the branch name with shell-quote (already a dependency) across all
providers: gitlab, github, gitea, bitbucket and custom git.
This commit is contained in:
Mauricio Siu
2026-06-16 07:12:40 -06:00
parent 439f575669
commit dfff91c6f3
5 changed files with 10 additions and 5 deletions

View File

@@ -10,6 +10,7 @@ import {
} from "@dokploy/server/services/bitbucket";
import type { InferResultType } from "@dokploy/server/types/with";
import { TRPCError } from "@trpc/server";
import { quote } from "shell-quote";
import type { z } from "zod";
export type ApplicationWithBitbucket = InferResultType<
@@ -125,7 +126,7 @@ export const cloneBitbucketRepository = async ({
const repoclone = `bitbucket.org/${bitbucketOwner}/${repoToUse}.git`;
const cloneUrl = getBitbucketCloneUrl(bitbucket, repoclone);
command += `echo "Cloning Repo ${repoclone} to ${outputPath}: ✅";`;
command += `git clone --branch ${bitbucketBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
command += `git clone --branch ${quote([bitbucketBranch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
return command;
};

View File

@@ -4,6 +4,7 @@ import {
findSSHKeyById,
updateSSHKeyById,
} from "@dokploy/server/services/ssh-key";
import { quote } from "shell-quote";
import { execAsync, execAsyncRemote } from "../process/execAsync";
interface CloneGitRepository {
@@ -78,7 +79,7 @@ export const cloneGitRepository = async ({
command += "chmod 600 /tmp/id_rsa;";
command += `export GIT_SSH_COMMAND="${gitSshCommand}";`;
}
command += `if ! git clone --branch ${customGitBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${customGitUrl} ${outputPath}; then
command += `if ! git clone --branch ${quote([customGitBranch ?? ""])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${customGitUrl} ${outputPath}; then
echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}";
exit 1;
fi

View File

@@ -7,6 +7,7 @@ import {
} from "@dokploy/server/services/gitea";
import type { InferResultType } from "@dokploy/server/types/with";
import { TRPCError } from "@trpc/server";
import { quote } from "shell-quote";
export const getErrorCloneRequirements = (entity: {
giteaRepository?: string | null;
@@ -177,7 +178,7 @@ export const cloneGiteaRepository = async ({
);
command += `echo "Cloning Repo ${repoClone} to ${outputPath}: ✅";`;
command += `git clone --branch ${giteaBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
command += `git clone --branch ${quote([giteaBranch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
return command;
};

View File

@@ -6,6 +6,7 @@ import type { InferResultType } from "@dokploy/server/types/with";
import { createAppAuth } from "@octokit/auth-app";
import { TRPCError } from "@trpc/server";
import { Octokit } from "octokit";
import { quote } from "shell-quote";
import type { z } from "zod";
export const authGithub = (githubProvider: Github): Octokit => {
@@ -167,7 +168,7 @@ export const cloneGithubRepository = async ({
const cloneUrl = `https://oauth2:${token}@${repoclone}`;
command += `echo "Cloning Repo ${repoclone} to ${outputPath}: ✅";`;
command += `git clone --branch ${branch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
command += `git clone --branch ${quote([branch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
return command;
};

View File

@@ -8,6 +8,7 @@ import {
} from "@dokploy/server/services/gitlab";
import type { InferResultType } from "@dokploy/server/types/with";
import { TRPCError } from "@trpc/server";
import { quote } from "shell-quote";
import type { z } from "zod";
export const refreshGitlabToken = async (gitlabProviderId: string) => {
@@ -152,7 +153,7 @@ export const cloneGitlabRepository = async ({
const repoClone = getGitlabRepoClone(gitlab, gitlabPathNamespace);
const cloneUrl = getGitlabCloneUrl(gitlab, repoClone);
command += `echo "Cloning Repo ${repoClone} to ${outputPath}: ✅";`;
command += `git clone --branch ${gitlabBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
command += `git clone --branch ${quote([gitlabBranch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`;
return command;
};