Pull.. Commit.. And Push Bash Script
Utility script to update all repos within a directory.
4 Minutes, 6 Seconds
2024-07-14 03:36 +0000
Push Committed and Uncommitted Changes Script
This script traverses a specified directory of git repositories, pulls updates for all branches, checks for committed and uncommitted changes across all branches, and pushes those changes to the remote repository. For uncommitted changes, it creates a new branch called uncommitted
, commits the changes with a message detailing the original branch, and then pushes the new branch to the remote. For the main
branch, if there are committed changes, it moves those changes to a new branch called bad-practice
and then pushes that branch to the remote repository.
Prerequisites
- Bash shell
- Git installed
- Proper permissions to access and modify the repositories
Installation
2. Create the script:
Save the following script to a file named push_committed_changes.sh
:
#!/bin/bash
# Define the default root directory where your repos are located
DEFAULT_ROOT_DIR="/home/cobra/Repos"
# Define the default blacklist file location
BLACKLIST_FILE="/etc/commit_push_blacklist.conf"
# Define the GitHub username to check against
GITHUB_USERNAME="your_github_username"
# Parse arguments
LOCAL_MODE=false
while [[ $# -gt 0 ]]; do
case $1 in
--local)
LOCAL_MODE=true
shift
;;
*)
ROOT_DIR=$1
shift
;;
esac
done
# Set ROOT_DIR to default if not set
ROOT_DIR=${ROOT_DIR:-$DEFAULT_ROOT_DIR}
# Export the BLACKLIST_FILE and GITHUB_USERNAME variables so they are available in subshells
export BLACKLIST_FILE
export GITHUB_USERNAME
# Function to check if a repository is blacklisted
is_blacklisted() {
local repo_dir=$1
echo " Checking for Blacklisted $repo_dir in $BLACKLIST_FILE"
if [ -z "$BLACKLIST_FILE" ]; then
echo " BLACKLIST_FILE is not set"
return 1
fi
if [ ! -f "$BLACKLIST_FILE" ]; then
echo " Blacklist file does not exist: $BLACKLIST_FILE"
return 1
fi
grep -qxF "$repo_dir" "$BLACKLIST_FILE"
local result=$?
if [ $result -eq 0 ]; then
echo " $repo_dir is blacklisted"
else
echo " $repo_dir is not blacklisted"
fi
return $result
}
# Function to check if a repository belongs to the specified user
belongs_to_user() {
local repo_dir=$1
local remote_url=$(git -C "$repo_dir" remote get-url origin 2>/dev/null)
if [[ "$remote_url" == *"$GITHUB_USERNAME"* ]]; then
return 0
else
return 1
fi
}
# Function to check if a remote branch exists
remote_branch_exists() {
local branch=$1
local repo_dir=$2
git -C "$repo_dir" ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1
return $?
}
# Function to pull all branches
pull_all_branches() {
local repo_dir=$1
echo "Pulling updates in $repo_dir"
cd "$repo_dir" || return
# Fetch all branches
git fetch --all
# Get a list of all branches
branches=$(git branch -r | grep -v '\->')
# Checkout and pull each branch
for branch in $branches; do
local_branch=${branch#origin/}
git checkout "$local_branch" || git checkout -b "$local_branch" "origin/$local_branch"
git pull origin "$local_branch"
done
cd - || return
}
# Function to push only committed changes across all branches
push_committed_changes() {
local repo_dir=$1
echo "Processing repository in $repo_dir"
cd "$repo_dir" || return
if is_blacklisted "$repo_dir"; then
echo " Repository is blacklisted, skipping $repo_dir"
cd - || return
return
fi
if ! belongs_to_user "$repo_dir"; then
echo " Repository does not belong to user $GITHUB_USERNAME, skipping $repo_dir"
cd - || return
return
fi
# Pull all branches first
pull_all_branches "$repo_dir"
# Get all branches
branches=$(git for-each-ref --format='%(refname:short)' refs/heads/)
for branch in $branches; do
git checkout "$branch"
# Handle uncommitted changes
if [ -n "$(git status --porcelain)" ]; then
echo " Uncommitted changes found on branch $branch in $repo_dir"
git checkout -b uncommitted
git add .
git commit -m "Uncommitted changes from branch $branch"
git push --set-upstream origin uncommitted
echo " Uncommitted changes have been committed and pushed to uncommitted branch in $repo_dir"
fi
if [ "$branch" == "main" ]; then
# Check if there are committed changes on the main branch
if git log origin/main..HEAD | grep -q "."; then
echo " Committed changes found on main branch in $repo_dir"
# Create and switch to the bad-practice branch
git checkout -b bad-practice
# Check if remote branch bad-practice exists, create if it doesn't
if ! remote_branch_exists "bad-practice" "$repo_dir"; then
git push --set-upstream origin bad-practice
else
git push origin bad-practice
fi
echo " Changes have been moved to and pushed on the bad-practice branch in $repo_dir"
else
echo " No committed changes to push on the main branch in $repo_dir"
fi
else
# Check if there are committed changes to push on the current branch
if remote_branch_exists "$branch" "$repo_dir"; then
if git log origin/"$branch"..HEAD | grep -q "."; then
echo " Committed changes found on branch $branch in $repo_dir"
git push origin "$branch"
echo " Changes have been pushed to remote branch $branch in $repo_dir"
else
echo " No committed changes to push on branch $branch in $repo_dir"
fi
else
echo " Remote branch $branch does not exist, pushing for the first time"
git push --set-upstream origin "$branch"
fi
fi
done
cd - || return
}
# Export the functions so they can be used by find -exec
export -f push_committed_changes
export -f pull_all_branches
export -f is_blacklisted
export -f belongs_to_user
export -f remote_branch_exists
if $LOCAL_MODE; then
echo "Running in local mode. Processing the current working directory."
push_committed_changes "$(pwd)"
else
echo "Starting push process for repositories in $ROOT_DIR"
# Ensure the blacklist file exists
if [ ! -f "$BLACKLIST_FILE" ]; then
echo "Blacklist file not found: $BLACKLIST_FILE"
exit 1
fi
# Find all .git directories and push committed changes across all branches
find "$ROOT_DIR" -name ".git" -type d -exec bash -c 'push_committed_changes "$(dirname "{}")"' \;
fi
echo "All repositories processed."
2. Make the Script Executable:
chmod +x your-script-name
3. Create the Blacklist File:
sudo touch /etc/commit_push_blacklist.conf
4. Set Your Git Username in the Script
- Run The Script
- In every repo
./push_committed_changes.sh [path_to_repos]
- Locally
./push_committed_changes.sh --local