Implemented a robust git_index_update_all_branches function, to automatically perform a safe fast-forward of all local branches, if their remtoes and merge refs are configured. Can be run from a cron script to keep all repos up to date
This commit is contained in:
@@ -106,7 +106,7 @@ function git_index() {
|
|||||||
fi
|
fi
|
||||||
cd "$base_path"
|
cd "$base_path"
|
||||||
# Run git callback (either update or show changes), if we are in the root directory
|
# Run git callback (either update or show changes), if we are in the root directory
|
||||||
if [ -z "${sub_path%/}" ]; then _git_index_update_or_status; fi
|
if [ -z "${sub_path%/}" ]; then _git_index_status_if_dirty; fi
|
||||||
else
|
else
|
||||||
echo -e "$_wrn_col'$1' did not match any git repos in $GIT_REPO_DIR$_txt_col"
|
echo -e "$_wrn_col'$1' did not match any git repos in $GIT_REPO_DIR$_txt_col"
|
||||||
fi
|
fi
|
||||||
@@ -171,7 +171,7 @@ parse_git_branch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# If the working directory is clean, update the git repository. Otherwise, show changes.
|
# If the working directory is clean, update the git repository. Otherwise, show changes.
|
||||||
function _git_index_update_or_status() {
|
function _git_index_status_if_dirty() {
|
||||||
if ! [ `git status --porcelain | wc -l` -eq 0 ]; then
|
if ! [ `git status --porcelain | wc -l` -eq 0 ]; then
|
||||||
# Fall back to 'git status' if git status alias isn't configured
|
# Fall back to 'git status' if git status alias isn't configured
|
||||||
if type $git_status_command 2>&1 | grep -qv "not found"; then
|
if type $git_status_command 2>&1 | grep -qv "not found"; then
|
||||||
@@ -179,36 +179,77 @@ function _git_index_update_or_status() {
|
|||||||
else
|
else
|
||||||
git status
|
git status
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
# Check that a local 'origin' remote exists.
|
|
||||||
if (git remote -v | grep -q origin); then
|
|
||||||
# Only update the git repo if it hasn't been touched for at least 6 hours.
|
|
||||||
if $(find ".git" -maxdepth 0 -type d -mmin +360 | grep -q "\.git"); then
|
|
||||||
_git_index_update_branch_or_master
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_git_index_update_branch_or_master() {
|
|
||||||
branch=$(parse_git_branch)
|
_git_index_update_all_branches() {
|
||||||
# If we aren't on any branch, checkout master.
|
echo -e "\n## $base_path\n"
|
||||||
if [ "$branch" = "(no branch)" ]; then
|
|
||||||
echo -e "=== Checking out$_git_col master$_txt_col branch."
|
# Save current branch or HEAD revision
|
||||||
git checkout master
|
local orig_branch=$(parse_git_branch)
|
||||||
branch="master"
|
if [[ "$orig_branch" = "(no branch)" ]]; then
|
||||||
|
orig_branch=$(git rev-parse HEAD)
|
||||||
fi
|
fi
|
||||||
echo -e "=== Updating '$branch' branch in $_bld_col$base_path$_txt_col from$_git_col origin$_txt_col... (Press Ctrl+C to cancel)"
|
|
||||||
# Pull the latest code from the server
|
# If working directory is dirty, abort
|
||||||
git pull origin $branch
|
if [[ -n "$(git status --short 2> /dev/null)" ]]; then
|
||||||
|
echo "=== Working directory dirty, nothing to do."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local remotes merges branches
|
||||||
|
# Get branch configuration from .git/config
|
||||||
|
IFS=$'\n'
|
||||||
|
for branch in $(git branch 2> /dev/null | sed -e 's/.\{2\}\(.*\)/\1/'); do
|
||||||
|
# Skip '(no branch)'
|
||||||
|
if [[ "$branch" = "(no branch)" ]]; then continue; fi
|
||||||
|
|
||||||
|
local remote=$(git config --get branch.$branch.remote)
|
||||||
|
local merge=$(git config --get branch.$branch.merge)
|
||||||
|
|
||||||
|
# Ignore branch if remote and merge is not configured
|
||||||
|
if [[ -n "$remote" ]] && [[ -n "$merge" ]]; then
|
||||||
|
branches=("${branches[@]}" "$branch")
|
||||||
|
remotes=("${remotes[@]}" "$remote")
|
||||||
|
# Get branch from merge ref (refs/heads/master => master)
|
||||||
|
merges=("${merges[@]}" "$(basename $merge)")
|
||||||
|
else
|
||||||
|
echo "=== Skipping $branch: remote and merge refs are not configured."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
unset IFS
|
||||||
|
|
||||||
|
# Update all remotes if there are any branches to update
|
||||||
|
if [ -n "${branches[*]}" ]; then git fetch --all 2> /dev/null; fi
|
||||||
|
|
||||||
|
local index=0
|
||||||
|
# Iterate over branches, and update those that can be fast-forwarded
|
||||||
|
for branch in $branches; do
|
||||||
|
branch_rev="$(git rev-parse $branch)"
|
||||||
|
# Local branch can be fast-forwarded if revision is ancestor of remote revision, and not the same.
|
||||||
|
# (see http://stackoverflow.com/a/2934062/304706)
|
||||||
|
if [[ "$branch_rev" != "$(git rev-parse ${remotes[$index]}/${merges[$index]})" ]] && \
|
||||||
|
[[ "$(git merge-base $branch_rev ${remotes[$index]}/${merges[$index]})" = "$branch_rev" ]]; then
|
||||||
|
echo "=== Updating '$branch' branch in $base_path from ${remotes[$index]}/${merges[$index]}..."
|
||||||
|
# Checkout branch if we aren't already on it.
|
||||||
|
if [[ "$branch" != "$(parse_git_branch)" ]]; then git checkout $branch; fi
|
||||||
|
git merge "${remotes[$index]}/${merges[$index]}"
|
||||||
|
fi
|
||||||
|
let index++
|
||||||
|
done
|
||||||
|
|
||||||
|
# Checkout original branch/revision if we aren't already on it.
|
||||||
|
if [[ "$orig_branch" != "$(parse_git_branch)" ]]; then git checkout "$orig_branch"; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Updates all git repositories with clean working directories.
|
# Updates all git repositories with clean working directories.
|
||||||
function _git_index_update_all() {
|
function _git_index_update_all() {
|
||||||
echo -e "== Updating code in $_bld_col$(_git_index_count)$_txt_col repos...\n"
|
echo -e "== Safely updating all local branches in $_bld_col$(_git_index_count)$_txt_col repos...\n"
|
||||||
_git_index_batch_cmd _git_index_update_branch_or_master
|
_git_index_batch_cmd _git_index_update_all_branches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Runs a command for all git repos
|
# Runs a command for all git repos
|
||||||
function _git_index_batch_cmd() {
|
function _git_index_batch_cmd() {
|
||||||
cwd="$PWD"
|
cwd="$PWD"
|
||||||
|
|||||||
Reference in New Issue
Block a user