diff --git a/CHANGELOG.md b/CHANGELOG.md index ad0a83d..f557d3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ All notable changes to this project are documented in this file. ### Fixed - **n8n 2.1.0+ compatibility** - Switch to static ffmpeg binary (apk removed upstream in n8n 2.1.0) +### Changed +- **Git sync** - Replaced `git pull` with `git fetch + reset` for more reliable updates (handles accidental local commits) + ## [November 2025] ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 3ad6b4b..538b89f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,6 +21,7 @@ This is **n8n-install**, a Docker Compose-based installer that provides a compre - `.env`: Generated secrets and configuration (from `.env.example`) - `scripts/install.sh`: Main installation orchestrator (runs numbered scripts 01-08 in sequence) - `scripts/utils.sh`: Shared utility functions (sourced by all scripts via `source "$(dirname "$0")/utils.sh" && init_paths`) +- `scripts/git.sh`: Git utilities (sync with origin, branch detection, configuration) - `scripts/03_generate_secrets.sh`: Secret generation and bcrypt hashing - `scripts/04_wizard.sh`: Interactive service selection using whiptail - `scripts/05_configure_services.sh`: Service-specific configuration logic @@ -30,10 +31,10 @@ This is **n8n-install**, a Docker Compose-based installer that provides a compre - `scripts/07_final_report.sh`: Post-install credential summary - `scripts/08_fix_permissions.sh`: Fixes file ownership for non-root access - `scripts/generate_n8n_workers.sh`: Generates dynamic worker/runner compose file -- `scripts/update.sh`: Update orchestrator (pulls latest code and images) +- `scripts/update.sh`: Update orchestrator (syncs with origin and updates images) - `scripts/update_preview.sh`: Preview available updates without applying (dry-run) - `scripts/doctor.sh`: System diagnostics (DNS, SSL, containers, disk, memory) -- `scripts/apply_update.sh`: Applies updates after git pull +- `scripts/apply_update.sh`: Applies updates after git sync - `scripts/docker_cleanup.sh`: Removes unused Docker resources (used by `make clean`) - `scripts/download_top_workflows.sh`: Downloads community n8n workflows @@ -52,7 +53,7 @@ This is **n8n-install**, a Docker Compose-based installer that provides a compre 7. `07_final_report.sh` - Display credentials and URLs 8. `08_fix_permissions.sh` - Fix file ownership for non-root access -The update flow (`scripts/update.sh`) similarly orchestrates: git pull → service selection → `apply_update.sh` → restart. +The update flow (`scripts/update.sh`) similarly orchestrates: git fetch + reset → service selection → `apply_update.sh` → restart. ## Common Development Commands @@ -275,6 +276,7 @@ docker compose -p localai config --quiet # Bash script syntax (validate all key scripts) bash -n scripts/utils.sh +bash -n scripts/git.sh bash -n scripts/databases.sh bash -n scripts/telemetry.sh bash -n scripts/03_generate_secrets.sh diff --git a/scripts/01_system_preparation.sh b/scripts/01_system_preparation.sh index 4a55993..d231931 100755 --- a/scripts/01_system_preparation.sh +++ b/scripts/01_system_preparation.sh @@ -18,6 +18,9 @@ set -e source "$(dirname "$0")/utils.sh" init_paths +# Source git utilities +source "$SCRIPT_DIR/git.sh" + export DEBIAN_FRONTEND=noninteractive # System Update @@ -39,8 +42,7 @@ apt install -y \ apt-transport-https python3-dotenv python3-yaml # Configure git to use rebase on pull (prevents merge commits during updates) -log_info "Configuring git pull strategy..." -git config --global pull.rebase true +git_configure_pull_rebase # Configuring Firewall (UFW) log_subheader "Firewall (UFW)" diff --git a/scripts/apply_update.sh b/scripts/apply_update.sh index 41d6c07..f089664 100755 --- a/scripts/apply_update.sh +++ b/scripts/apply_update.sh @@ -2,7 +2,7 @@ # ============================================================================= # apply_update.sh - Service update and restart logic # ============================================================================= -# Called by update.sh after git pull. Performs the actual service updates: +# Called by update.sh after git sync. Performs the actual service updates: # 1. Updates .env with any new variables (03_generate_secrets.sh --update) # 2. Runs service selection wizard (04_wizard.sh) to update profiles # 3. Configures services (05_configure_services.sh) diff --git a/scripts/git.sh b/scripts/git.sh new file mode 100644 index 0000000..95e694b --- /dev/null +++ b/scripts/git.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# ============================================================================= +# git.sh - Git utilities for n8n-install scripts +# ============================================================================= +# Provides git-related functions for repository management. +# +# Functions: +# - require_git: Verify git is installed +# - git_get_current_branch: Get current branch name (main/develop) +# - git_sync_with_origin: Fetch and reset to origin/ +# - git_configure_pull_rebase: Configure git to use rebase on pull +# +# Usage: source "$(dirname "$0")/git.sh" +# Note: Requires utils.sh to be sourced first for logging functions. +# ============================================================================= + +# Supported branches for this project +GIT_SUPPORTED_BRANCHES=("main" "develop") +GIT_DEFAULT_BRANCH="main" + +#============================================================================= +# GIT CHECKS +#============================================================================= + +# Check if git is installed +# Usage: require_git || exit 1 +require_git() { + if ! command -v git &> /dev/null; then + log_error "'git' command not found. Please install git." + return 1 + fi + return 0 +} + +#============================================================================= +# BRANCH MANAGEMENT +#============================================================================= + +# Get current git branch name +# Returns default branch if on detached HEAD or unknown branch +# Usage: branch=$(git_get_current_branch) +git_get_current_branch() { + local branch + branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "") + + # If empty (detached HEAD), use default + if [[ -z "$branch" ]]; then + echo "$GIT_DEFAULT_BRANCH" + return 0 + fi + + # Check if branch is in supported list + local is_supported=0 + for supported in "${GIT_SUPPORTED_BRANCHES[@]}"; do + if [[ "$branch" == "$supported" ]]; then + is_supported=1 + break + fi + done + + if [[ $is_supported -eq 0 ]]; then + log_warning "Unknown branch '$branch', using $GIT_DEFAULT_BRANCH" + echo "$GIT_DEFAULT_BRANCH" + return 0 + fi + + echo "$branch" +} + +#============================================================================= +# SYNC OPERATIONS +#============================================================================= + +# Sync local repository with origin +# Fetches latest changes and resets to origin/ +# This discards any local commits to ensure clean sync with remote +# Usage: git_sync_with_origin [target_branch] +# Returns: 0 on success, 1 on failure +git_sync_with_origin() { + local target_branch="${1:-}" + + # Determine target branch if not specified + if [[ -z "$target_branch" ]]; then + target_branch=$(git_get_current_branch) + fi + + # Fetch latest changes from origin + log_info "Fetching latest changes from origin..." + if ! git fetch origin; then + log_error "Git fetch failed. Check your internet connection." + return 1 + fi + + # Reset to origin/ + log_info "Resetting to origin/$target_branch..." + if ! git reset --hard "origin/$target_branch"; then + log_error "Git reset to origin/$target_branch failed." + return 1 + fi + + log_info "Successfully synced with origin/$target_branch" + return 0 +} + +#============================================================================= +# CONFIGURATION +#============================================================================= + +# Configure git to use rebase on pull (prevents merge commits) +# Usage: git_configure_pull_rebase +git_configure_pull_rebase() { + if [[ -z "$(git config --global pull.rebase 2>/dev/null)" ]]; then + log_info "Configuring git pull strategy (rebase)..." + git config --global pull.rebase true + fi +} diff --git a/scripts/update.sh b/scripts/update.sh index efeca34..5376133 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -4,7 +4,7 @@ # ============================================================================= # Performs a full system and service update: # 1. Backs up user-customizable directories (e.g., python-runner/) -# 2. Pulls latest changes from the git repository (git reset --hard + pull) +# 2. Fetches and resets to origin/ (discards any local commits) # 3. Restores backed up directories to preserve user modifications # 4. Updates Ubuntu system packages (apt-get update && upgrade) # 5. Delegates to apply_update.sh for service updates @@ -12,6 +12,10 @@ # This two-stage approach ensures apply_update.sh itself gets updated before # running, so new update logic is always applied. # +# Git strategy: We use `git fetch` + `git reset --hard origin/` instead +# of `git pull` to ensure we always sync with remote, even if the user has +# accidental local commits that would cause rebase conflicts. +# # Preserved directories: Defined in PRESERVE_DIRS array in utils.sh. # These directories contain user-customizable content that survives git reset. # @@ -24,6 +28,9 @@ set -e source "$(dirname "$0")/utils.sh" init_paths +# Source git utilities +source "$SCRIPT_DIR/git.sh" + # Source telemetry functions source "$SCRIPT_DIR/telemetry.sh" @@ -57,60 +64,44 @@ fi log_info "Starting update process..." set_telemetry_stage "git_update" -# Pull the latest repository changes -log_info "Pulling latest repository changes..." +# Sync with the latest repository changes +log_info "Syncing with latest repository changes..." + # Check if git is installed -if ! command -v git &> /dev/null; then - log_warning "'git' command not found. Skipping repository update." - # Decide if we should proceed without git pull or exit. Exiting is safer. - log_error "Cannot proceed with update without git. Please install git." +if ! require_git; then exit 1 - # Or, if allowing update without pull: - # log_warning "Proceeding without pulling latest changes..." -else - # Change to project root for git pull - cd "$PROJECT_ROOT" || { log_error "Failed to change directory to $PROJECT_ROOT"; exit 1; } - - # Ensure git pull.rebase is configured (fallback for older installations) - if [ -z "$(git config --global pull.rebase)" ]; then - git config --global pull.rebase true - fi - - # Backup user-customizable directories before git reset (uses PRESERVE_DIRS from utils.sh) - if ! BACKUP_PATH=$(backup_preserved_dirs); then - log_error "Backup failed. Aborting update to prevent data loss." - exit 1 - fi - - if [ -n "$BACKUP_PATH" ]; then - log_info "Backup created at: $BACKUP_PATH" - fi - - # Git operations - if ! git reset --hard HEAD; then - log_error "Git reset failed." - restore_preserved_dirs "$BACKUP_PATH" - exit 1 - fi - - if ! git pull; then - log_error "Git pull failed." - restore_preserved_dirs "$BACKUP_PATH" - exit 1 - fi - - # Restore user-customizable directories after git pull - if ! restore_preserved_dirs "$BACKUP_PATH"; then - log_error "Failed to restore user directories from backup." - log_error "Backup may still be available at: $BACKUP_PATH" - BACKUP_PATH="" # Prevent cleanup from deleting it - exit 1 - fi - - # Clear backup path after successful restore - BACKUP_PATH="" fi +# Change to project root for git operations +cd "$PROJECT_ROOT" || { log_error "Failed to change directory to $PROJECT_ROOT"; exit 1; } + +# Backup user-customizable directories before git reset (uses PRESERVE_DIRS from utils.sh) +if ! BACKUP_PATH=$(backup_preserved_dirs); then + log_error "Backup failed. Aborting update to prevent data loss." + exit 1 +fi + +if [ -n "$BACKUP_PATH" ]; then + log_info "Backup created at: $BACKUP_PATH" +fi + +# Sync with origin (fetch + reset to remote branch) +if ! git_sync_with_origin; then + restore_preserved_dirs "$BACKUP_PATH" + exit 1 +fi + +# Restore user-customizable directories after git reset +if ! restore_preserved_dirs "$BACKUP_PATH"; then + log_error "Failed to restore user directories from backup." + log_error "Backup may still be available at: $BACKUP_PATH" + BACKUP_PATH="" # Prevent cleanup from deleting it + exit 1 +fi + +# Clear backup path after successful restore +BACKUP_PATH="" + # Update Ubuntu packages before running apply_update set_telemetry_stage "git_system_packages" log_info "Updating system packages..." diff --git a/scripts/utils.sh b/scripts/utils.sh index 310f455..7c3ff81 100755 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -749,7 +749,7 @@ backup_preserved_dirs() { return 0 } -# Restore preserved directories after git pull +# Restore preserved directories after git reset # Usage: restore_preserved_dirs # Returns: 0 on success, 1 on failure restore_preserved_dirs() { @@ -784,7 +784,7 @@ restore_preserved_dirs() { fi if [ -d "$backup_base/$dir" ]; then - log_info "Restoring $dir/ after git pull..." + log_info "Restoring $dir/ after git reset..." # Remove the git-restored version if [ -d "$PROJECT_ROOT/$dir" ]; then