Skip to content

Instantly share code, notes, and snippets.

@foriequal0
Last active May 10, 2021 03:49
Show Gist options
  • Save foriequal0/2a3bb342b14dc8fa5ac042ae3e3c6784 to your computer and use it in GitHub Desktop.
Save foriequal0/2a3bb342b14dc8fa5ac042ae3e3c6784 to your computer and use it in GitHub Desktop.
git-scratch
#!/usr/bin/env bash
## Requires: (optional) git-sync
set -euo pipefail
OPTS_SPEC="\
$0 [<branch-name>] [<options>]
An opinionated git workflow for random walker.
--
h,help show the help
r,remote!=remote remote name
b,base!=branch remote base branch name
"
eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
REMOTE=$(git remote | head -n 1)
BASE=
while [ $# -gt 0 ]; do
case "$1" in
-r|--remote) REMOTE=$2; shift 2 ;;
-b|--base) BASE=$2; shift 2 ;;
--) shift; break ;;
*) >&2 echo "Unexpected option: $1"; exit 1;
esac
done
if [ -z "$REMOTE" ]; then
>&2 echo "No remote"
exit -1
fi
if [ -n "$BASE" ]; then
BASE="refs/remotes/$REMOTE/$BASE"
else
BASE=$(git symbolic-ref "refs/remotes/$REMOTE/HEAD" || true)
fi
if [ -z "$BASE" ]; then
REMOTE_HEAD=$(git remote show "$REMOTE" | sed -n 's/\s*HEAD branch: //p')
>&2 echo "Retry after setting default default base branch for $REMOTE:"
>&2 echo " git remote set-head $REMOTE --auto"
exit -1
fi
git_scratch() {
git switch scratch || git switch -c scratch
local MERGE_BASE=$(git merge-base HEAD "$BASE")
local BASE_REF=$(git rev-parse "$BASE")
if [ "$MERGE_BASE" != "$BASE_REF" ]; then
git rebase --autostash -i "$BASE"
fi
}
git_scratch_fork() {
local BRANCH="$1"
git switch scratch
git switch -c "$BRANCH"
git rebase --autostash -i "$BASE"
git push -u "$REMOTE" "$BRANCH"
}
if which git-sync > /dev/null; then
git sync
else
git remote update "$REMOTE"
fi
if [ $# -eq 0 ]; then
git_scratch
else
git_scratch_fork "$1"
fi
@foriequal0
Copy link
Author

foriequal0 commented Jun 11, 2020

There are so many git branch workflow. From classic Git flow to lightweight Github flow, and their derivatives that match every team's deploy strategies. They exist because they have pros, but they are not the silver bullet. So I've made another git branch management strategy called 'Git scratch flow' (and it is not a silver bullet, too)

When the issue management is streamlined, and the team is sufficiently grown and mature so the roles of members are divided enough, then the member can focus on a single topic.

However, I'm an only member of a team. Also, I'm not skilled at issue management, and I'm still discovering the problem domain while programming the product. Naturally, I have to handle multiple topics simultaneously, undergo trial and error, and do programming like Infinite monkey, and it looks like Brownian motion. It is hard to pick a topic in priori and come up with an appropriate name in this case. The overhead of git switch and git rebase cannot be neglected.

So, I gave up to fork a topic branch early. I dump all the commits on a scratch branch as small as possible. And keep committing until there are enough random walks commits that can make a meaningful group of commits. Now, you prepare a PR.

  1. See the commit log. Are there any commits that can be grouped into a topic? Think of a topic name in posteriori.
  2. Fork from a base branch and cherry-pick commits from the scratch branch.
  3. Send PR.
  4. Keep working on the scratch branch.
  5. Rebase scratch onto the base from time to time.

The script is a shortcut to this workflow. You can get back to work with git scratch, and prepare a PR with git scratch <topic name>. That's it. I even aliased it as git s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment