Skip to content

Instantly share code, notes, and snippets.

@joepvd
Last active December 10, 2023 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joepvd/35ec4a4b77b7f3321f48ae279c78c63f to your computer and use it in GitHub Desktop.
Save joepvd/35ec4a4b77b7f3321f48ae279c78c63f to your computer and use it in GitHub Desktop.
git-update

git update

For automatically rebasing current branch to freshly fetched origin branch, and rebase local branches with upstream changes.

Usage:

git update

Installation

git clone https://gist.github.com/35ec4a4b77b7f3321f48ae279c78c63f.git git-update
ln -sf "$(pwd)/git-update/git-update" ~/bin/git-update

If you're daring:

git config --global alias.pull git-update

Features (any repo)

  • fetches upstream origin
  • ensures the local main branch is current with the upstream main branch
  • ensures the currently checked out branch gets the changes from origin/main in

Features for ocp-build-data

In addition to ☝ general features, ocp-build-data is treated in a special way. It:

  • ensures all openshift-$VERSION branches are up to date with their origin counterpart
  • ensures the read-only worktree checkouts under ~/ocp-ro/$VERSION are up to date with origin.
  • can run git update in read only worktree, and updates the real repository with all relevant branches, and all the read only worktree checkouts.

Wait what. "Read only worktree checkouts"?!?

Yes. Consider this a daemonless successor to gitfuse.

This makes use of the worktree feature of git. The result is a directory ~/ocp-ro, where for each relevant version, a complete and current checkout of the origin state of that version is.

The purpose of these checkouts is to easily query and compare facts between branches.

These checkouts are headless, as the local knowledge of the remote state is checked out. Files and directories in the worktree checkouts are set to be readonly, to ensure the character of "upstream truth" is maintained.

Bugs

  • Config values are hard coded
  • ocp-build-data is hard coded
  • worktree is global and hard coded
  • If current branch equals one of the versioned special branches, it will get evaluated for rebase twice
#!/usr/bin/env bash
set -euo pipefail
WORKTREE_DIR=~/ocp-ro
OCP_BUILD_DATA=~/src/github.com/openshift-eng/ocp-build-data
VERSIONS=(
3.11
4.6
4.7
4.8
4.9
4.10
4.11
4.12
4.13
4.14
4.15
4.16
)
originating_branch() {
local i res
i=0
res=""
while [[ -z "$res" && "$i" < 100 ]]; do
res=$(git branch -r --list 'origin/openshift-*' --contains "HEAD~$i" | awk '{print $1; exit}')
i=$(($i+1))
done
echo "$res"
}
if [[ "${PWD##$WORKTREE_DIR}" != "$PWD" ]]; then
echo "Changing directory to $OCP_BUILD_DATA" >/dev/stderr
cd "$OCP_BUILD_DATA"
fi
repo_path="$(git rev-parse --show-toplevel)"
reponame="$(basename "$repo_path")"
main_branch="$(
if git rev-parse --verify origin/main >/dev/null 2>&1; then
echo main
elif git rev-parse --verify origin/master >/dev/null 2>&1; then
echo master
else
echo "No main/master branch detected">/dev/stderr
exit 1
fi
)"
git diff --quiet || {
echo branch not clean. exiting >/dev/stderr
exit 1
}
branch="$(git rev-parse --abbrev-ref HEAD)"
echo "Fetching origin" >/dev/stderr
git fetch --quiet origin
update_branch() {
local_branch="$1"
remote_branch="$2"
git checkout --quiet "$local_branch"
local_head="$(git rev-parse --short HEAD)"
remote_head="$(git log --pretty=format:%h -n 1 "$remote_branch")"
if [[ "$local_head" == "$remote_head" ]]; then
echo "No updates for $local_branch" >/dev/stderr
else
echo "rebasing branch $remote_branch onto $local_branch: $local_head..$remote_head" >/dev/stderr
git rebase --quiet "$remote_branch"
fi
}
update_branch "$main_branch" "origin/$main_branch"
case "$reponame" in
ocp-build-data)
mkdir -p "$WORKTREE_DIR"
shopt -s nullglob
chmod --recursive +w "$WORKTREE_DIR"/* 2>/dev/null || true
trap "chmod --recursive -w '$WORKTREE_DIR'/*" EXIT
for v in ${VERSIONS[@]}; do
update_branch "openshift-$v" "origin/openshift-$v"
(
echo "Updating worktree $WORKTREE_DIR/$v" >/dev/stderr
if [[ -d "$WORKTREE_DIR/$v" ]]; then
cd "$WORKTREE_DIR/$v"
git checkout --quiet origin/openshift-$v
else
git worktree add "$WORKTREE_DIR/$v" origin/openshift-$v
fi
)
done
git checkout --quiet "$branch"
o="$(originating_branch)"
[[ -n "$o" ]] && update_branch "$branch" "$o"
;;
redhat-coreos)
for r in ${VERSIONS[@]}; do
git checkout "$r" || continue
git rebase "origin/$r"
done
git checkout "$branch"
o="$(originating_branch)"
[[ -n "$o" ]] && git rebase "$o"
;;
*)
# Basically, do not do this for ocp-build-data
if [[ "$branch" != "$main_branch" ]]; then
update_branch "$branch" "origin/$main_branch"
fi
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment