Created
October 16, 2025 23:18
-
-
Save GabrielVidal1/f6457ec2d19620ebe5ed0fc67a5653dc to your computer and use it in GitHub Desktop.
Automatic django migration handling for git workflow
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ============================================================================== | |
| # Git Branch Switch with Safe Django Migrations | |
| # ============================================================================== | |
| # This script automates switching between Git branches in a Django project | |
| # while handling database migrations safely. | |
| # | |
| # It: | |
| # - Compares Django migrations between the current and target branches. | |
| # - Reverts apps to the last common migration if migrations diverged. | |
| # - Switches branches. | |
| # - Applies the latest migrations for the new branch. | |
| # | |
| # USAGE: | |
| # git pswitch <branch-name> | |
| # | |
| # EXAMPLE: | |
| # git pswitch feature/new-ui | |
| # | |
| # SETUP AS A GIT ALIAS: | |
| # 1. Save this script as `.git-pswitch` in your project root or somewhere in your PATH. | |
| # 2. Make it executable: | |
| # chmod +x .git-pswitch | |
| # 3. Add the alias to your Git configuration: | |
| # git config --global alias.pswitch '!bash .git-pswitch' | |
| # | |
| # After setup, you can simply run: | |
| # git pswitch main | |
| # | |
| # ============================================================================== | |
| set -e | |
| MIGRATE_COMMAND="python manage.py migrate" | |
| current_branch=$(git rev-parse --abbrev-ref HEAD); | |
| target_branch=$1 | |
| if [ -z \"$target_branch\" ]; then \ | |
| echo 'Usage: git pswitch <branch>'; \ | |
| return 1; \ | |
| fi; | |
| if [ "$current_branch" == "$target_branch" ]; then | |
| echo "Already on branch '$target_branch'. No switch needed." | |
| exit 0 | |
| fi | |
| if ! git show-ref --verify --quiet "refs/heads/$target_branch"; then | |
| echo "Branch '$target_branch' does not exist." | |
| exit 1 | |
| fi | |
| # The root directory where Django apps are located | |
| APPS_ROOT="apps" | |
| apps_to_revert=() | |
| # Loop over all apps | |
| while read -r migrations_dir; do | |
| app=$(basename "$(dirname "$migrations_dir")") | |
| # --- Migrations from old branch --- | |
| mapfile -t old_migrations < <( | |
| git ls-tree -r --name-only "$current_branch" -- "$migrations_dir" 2>/dev/null | | |
| grep '/[0-9]\+_.*\.py$' | | |
| xargs -n1 basename | | |
| sed 's/\.py$//' | | |
| sort | |
| ) | |
| # --- Migrations from new branch --- | |
| mapfile -t new_migrations < <( | |
| git ls-tree -r --name-only "$target_branch" -- "$migrations_dir" 2>/dev/null | | |
| grep '/[0-9]\+_.*\.py$' | | |
| xargs -n1 basename | | |
| sed 's/\.py$//' | | |
| sort | |
| ) | |
| # If the migrations are identical, skip | |
| diff_output=$(diff <(printf '%s\n' "${old_migrations[@]}") <(printf '%s\n' "${new_migrations[@]}") || true) | |
| if [ -z "$diff_output" ]; then | |
| continue | |
| fi | |
| # --- Find last common migration --- | |
| last_common="" | |
| for mig in "${old_migrations[@]}"; do | |
| if printf '%s\n' "${new_migrations[@]}" | grep -qx "$mig"; then | |
| last_common="$mig" | |
| else | |
| break | |
| fi | |
| done | |
| # If migrations are missing or diverged, record the app | |
| if [ -n "$last_common" ]; then | |
| apps_to_revert+=("$app $last_common") | |
| fi | |
| done < <(find "$APPS_ROOT" -type d -name "migrations") | |
| if [ ${#apps_to_revert[@]} -eq 0 ]; then exit 0; fi | |
| echo "The following apps will be reverted to previous migrations:" | |
| for entry in "${apps_to_revert[@]}"; do | |
| read -r app migration <<< "$entry" | |
| echo " - $app $migration" | |
| done | |
| for entry in "${apps_to_revert[@]}"; do | |
| read -r app migration <<< "$entry" | |
| $MIGRATE_COMMAND "$app" "$migration" | |
| done | |
| git switch "$target_branch" | |
| $MIGRATE_COMMAND | |
| echo "Switched to branch '$target_branch' and applied necessary migrations." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment