fix: keep the git directory for worktree-enabled installations
Git worktrees do not include the full .git directory - only a pointer to the actual directory - when keep-git-dir is set to true, which is incorrect for built containers. This change special-cases that combination, allowing folks on newer git installs to actually keep the .git directory during the build process. Closes #4415
This commit is contained in:
@@ -109,6 +109,8 @@ dokku git:set node-js-app keep-git-dir false
|
|||||||
dokku git:set node-js-app keep-git-dir ""
|
dokku git:set node-js-app keep-git-dir ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Please keep in mind that setting `keep-git-dir` to `true` may result in unstaged changes shown within the built container due to the build process generating application changes within the built app directory.
|
||||||
|
|
||||||
### Initializing an app repository from a remote repository
|
### Initializing an app repository from a remote repository
|
||||||
|
|
||||||
> The application must exist before the repository can be initialized
|
> The application must exist before the repository can be initialized
|
||||||
|
|||||||
@@ -9,19 +9,10 @@ set -eo pipefail
|
|||||||
|
|
||||||
use_git_worktree() {
|
use_git_worktree() {
|
||||||
declare desc="detects whether to use git worktree"
|
declare desc="detects whether to use git worktree"
|
||||||
local GIT_VERSION MAJOR_VERSION MINOR_VERSION
|
declare deprecated=true
|
||||||
|
dokku_log_warn "Deprecated: fn-git-use-worktree"
|
||||||
|
|
||||||
GIT_VERSION=$(git --version | awk '{split($0,a," "); print a[3]}')
|
fn-git-use-worktree
|
||||||
MAJOR_VERSION=$(echo "$GIT_VERSION" | awk '{split($0,a,"."); print a[1]}')
|
|
||||||
MINOR_VERSION=$(echo "$GIT_VERSION" | awk '{split($0,a,"."); print a[2]}')
|
|
||||||
|
|
||||||
if [[ "$MAJOR_VERSION" -ge "3" ]]; then
|
|
||||||
return 0
|
|
||||||
elif [[ "$MAJOR_VERSION" -eq "2" ]] && [[ "$MINOR_VERSION" -ge "11" ]]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
git_build_app_repo() {
|
git_build_app_repo() {
|
||||||
@@ -35,49 +26,13 @@ git_build_app_repo() {
|
|||||||
local GIT_BUILD_APP_REPO_TMP_WORK_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
|
local GIT_BUILD_APP_REPO_TMP_WORK_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
|
||||||
trap "rm -rf '$GIT_BUILD_APP_REPO_TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT
|
trap "rm -rf '$GIT_BUILD_APP_REPO_TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT
|
||||||
|
|
||||||
local TMP_TAG="dokku/$REV"
|
|
||||||
chmod 755 "$GIT_BUILD_APP_REPO_TMP_WORK_DIR"
|
chmod 755 "$GIT_BUILD_APP_REPO_TMP_WORK_DIR"
|
||||||
unset GIT_DIR GIT_WORK_TREE
|
unset GIT_DIR GIT_QUARANTINE_PATH GIT_WORK_TREE
|
||||||
|
|
||||||
! plugn trigger app-exists "$APP" >/dev/null 2>&1 && plugn trigger app-maybe-create "$APP"
|
! plugn trigger app-exists "$APP" >/dev/null 2>&1 && plugn trigger app-maybe-create "$APP"
|
||||||
|
|
||||||
if use_git_worktree; then
|
fn-git-setup-build-dir "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV"
|
||||||
# git worktree - this method uses git worktree which was introduced in git 2.5
|
pushd "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" >/dev/null
|
||||||
pushd "$DOKKU_ROOT/$APP" >/dev/null
|
|
||||||
# unset the git quarantine path to allow us to use 2.13.0+
|
|
||||||
# See this issue for more information: https://github.com/dokku/dokku/issues/2796
|
|
||||||
suppress_output env -u GIT_QUARANTINE_PATH git worktree add "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV"
|
|
||||||
popd >/dev/null 2>&1 || pushd "/tmp" >/dev/null
|
|
||||||
pushd "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" >/dev/null
|
|
||||||
else
|
|
||||||
# git clone - this method creates a new git repository and adds the primary
|
|
||||||
# repo as a remote, then does a fetch depth=1 to avoid cloning
|
|
||||||
# the entire repo.
|
|
||||||
# Not working for git >= 2.11.0 due to changes introduced
|
|
||||||
# in this merge:
|
|
||||||
# https://github.com/git/git/commit/25ab004c53cdcfea485e5bf437aeaa74df47196d
|
|
||||||
pushd "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" >/dev/null
|
|
||||||
GIT_DIR="$DOKKU_ROOT/$APP" git tag -d "$TMP_TAG" &>/dev/null || true
|
|
||||||
GIT_DIR="$DOKKU_ROOT/$APP" git tag "$TMP_TAG" "$REV" &>/dev/null
|
|
||||||
git init &>/dev/null
|
|
||||||
git config advice.detachedHead false
|
|
||||||
git remote add origin "$DOKKU_ROOT/$APP" &>/dev/null
|
|
||||||
git fetch --depth=1 origin "refs/tags/$TMP_TAG" &>/dev/null
|
|
||||||
git reset --hard FETCH_HEAD &>/dev/null
|
|
||||||
GIT_DIR="$DOKKU_ROOT/$APP" git tag -d "$TMP_TAG" &>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
suppress_output env -u GIT_QUARANTINE_PATH git submodule update --init --recursive
|
|
||||||
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
|
|
||||||
if [[ "$DOKKU_KEEP_GIT_DIR" != "true" ]]; then
|
|
||||||
find . -name .git -prune -exec rm -rf {} \; >/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
if use_git_worktree; then
|
|
||||||
pushd "$DOKKU_ROOT/$APP" >/dev/null
|
|
||||||
git worktree prune
|
|
||||||
popd >/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
local DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_DISABLE_ANSI_PREFIX_REMOVAL
|
local DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_DISABLE_ANSI_PREFIX_REMOVAL
|
||||||
DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL=$(config_get "$APP" DOKKU_DISABLE_ANSI_PREFIX_REMOVAL || true)
|
DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL=$(config_get "$APP" DOKKU_DISABLE_ANSI_PREFIX_REMOVAL || true)
|
||||||
|
|||||||
@@ -257,3 +257,88 @@ fn-git-deploy-branch() {
|
|||||||
echo "$DEFAULT_BRANCH"
|
echo "$DEFAULT_BRANCH"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn-git-setup-build-dir() {
|
||||||
|
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
|
||||||
|
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
|
||||||
|
|
||||||
|
if ! fn-git-use-worktree; then
|
||||||
|
fn-git-setup-build-dir-old "$APP" "$GIT_WORKDIR" "$REV"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DOKKU_KEEP_GIT_DIR" == "true" ]]; then
|
||||||
|
fn-git-setup-build-dir-new "$APP" "$GIT_WORKDIR" "$REV"
|
||||||
|
else
|
||||||
|
fn-git-setup-build-dir-worktree "$APP" "$GIT_WORKDIR" "$REV"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn-git-setup-build-dir-new() {
|
||||||
|
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
|
||||||
|
local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")"
|
||||||
|
|
||||||
|
# repo workaround from https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52249
|
||||||
|
# and https://docs.gitlab.com/ee/user/project/repository/repository_mirroring.html#preventing-conflicts-using-a-pre-receive-hook
|
||||||
|
env -u GIT_QUARANTINE_PATH git -C "$DOKKU_ROOT/$APP" archive "$REV" | tar x --warning=none -C "${GIT_WORKDIR}"
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" clone --bare "$DOKKU_ROOT/$APP" .git
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" config --local gc.auto 0
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" config --local --bool core.bare false
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" config --local receive.denyCurrentBranch ignore
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" symbolic-ref HEAD "refs/heads/$DOKKU_DEPLOY_BRANCH"
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" reset "$REV" -- .
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" push $GIT_WORKDIR $REV:refs/heads/$DOKKU_DEPLOY_BRANCH
|
||||||
|
fn-git-setup-build-dir-submodules "$APP" "$GIT_WORKDIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn-git-setup-build-dir-old() {
|
||||||
|
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
|
||||||
|
local TMP_TAG="dokku/$REV"
|
||||||
|
|
||||||
|
suppress_output git -C "$DOKKU_ROOT/$APP" tag -d "$TMP_TAG" &>/dev/null || true
|
||||||
|
suppress_output git -C "$DOKKU_ROOT/$APP" tag "$TMP_TAG" "$REV"
|
||||||
|
suppress_output git -C "$GIT_WORKDIR" init
|
||||||
|
suppress_output git -C "$GIT_WORKDIR" config advice.detachedHead false
|
||||||
|
suppress_output git -C "$GIT_WORKDIR" remote add origin "$DOKKU_ROOT/$APP"
|
||||||
|
suppress_output git -C "$GIT_WORKDIR" fetch --depth=1 origin "refs/tags/$TMP_TAG"
|
||||||
|
suppress_output git -C "$GIT_WORKDIR" reset --hard FETCH_HEAD
|
||||||
|
suppress_output git -C "$DOKKU_ROOT/$APP" git tag -d "$TMP_TAG" &>/dev/null || true
|
||||||
|
fn-git-setup-build-dir-submodules "$APP" "$GIT_WORKDIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn-git-setup-build-dir-worktree() {
|
||||||
|
declare APP="$1" GIT_WORKDIR="$2" REV="$3"
|
||||||
|
|
||||||
|
# unset the git quarantine path to allow us to use 2.13.0+
|
||||||
|
# See this issue for more information: https://github.com/dokku/dokku/issues/2796
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$DOKKU_ROOT/$APP" worktree add "$GIT_WORKDIR" "$REV"
|
||||||
|
fn-git-setup-build-dir-submodules "$APP" "$GIT_WORKDIR"
|
||||||
|
suppress_output git -C "$DOKKU_ROOT/$APP" worktree prune
|
||||||
|
}
|
||||||
|
|
||||||
|
fn-git-setup-build-dir-submodules() {
|
||||||
|
declare APP="$1" GIT_WORKDIR="$2"
|
||||||
|
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
|
||||||
|
|
||||||
|
suppress_output env -u GIT_QUARANTINE_PATH git -C "$GIT_WORKDIR" submodule update --init --recursive
|
||||||
|
if [[ "$DOKKU_KEEP_GIT_DIR" != "true" ]]; then
|
||||||
|
find "$GIT_WORKDIR" -name .git -prune -exec rm -rf {} \; >/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn-git-use-worktree() {
|
||||||
|
declare desc="detects whether to use git worktree"
|
||||||
|
local GIT_VERSION MAJOR_VERSION MINOR_VERSION
|
||||||
|
|
||||||
|
GIT_VERSION=$(git --version | awk '{split($0,a," "); print a[3]}')
|
||||||
|
MAJOR_VERSION=$(echo "$GIT_VERSION" | awk '{split($0,a,"."); print a[1]}')
|
||||||
|
MINOR_VERSION=$(echo "$GIT_VERSION" | awk '{split($0,a,"."); print a[2]}')
|
||||||
|
|
||||||
|
if [[ "$MAJOR_VERSION" -ge "3" ]]; then
|
||||||
|
return 0
|
||||||
|
elif [[ "$MAJOR_VERSION" -eq "2" ]] && [[ "$MINOR_VERSION" -ge "11" ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,3 +71,35 @@ teardown() {
|
|||||||
echo "status: $status"
|
echo "status: $status"
|
||||||
assert_output_exists
|
assert_output_exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "(git) keep-git-dir" {
|
||||||
|
run /bin/bash -c "dokku git:set $TEST_APP keep-git-dir true"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run deploy_app
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run /bin/bash -c "dokku enter $TEST_APP web ls .git"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output_contains "branches"
|
||||||
|
assert_output_contains "config"
|
||||||
|
assert_output_contains "description"
|
||||||
|
assert_output_contains "HEAD"
|
||||||
|
assert_output_contains "hooks"
|
||||||
|
assert_output_contains "index"
|
||||||
|
assert_output_contains "info"
|
||||||
|
assert_output_contains "logs"
|
||||||
|
assert_output_contains "objects"
|
||||||
|
assert_output_contains "refs"
|
||||||
|
|
||||||
|
run /bin/bash -c "dokku enter $TEST_APP web test -d .git"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user