aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE3
-rw-r--r--README.md37
-rwxr-xr-xag122
3 files changed, 162 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1905190
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,3 @@
+CC0, No Rights Reserved
+
+https://creativecommons.org/publicdomain/zero/1.0/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8f98b20
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# ag
+
+*Adam's Git*
+
+`ag` is a trivial shell script to wrap git, adding new commands of use to me
+during my professional work. If `ag` doesn't recognize a command, it falls back
+to git.
+
+## Usage
+
+The added commands are:
+
+* `ag review`: Accepts a GitLab MR number; fails if the remote is not GitLab.
+Pulls the branch associated with that MR number if it exists, displays the
+author and description, then displays the diff compared to latest main. After
+quitting from the diff, asks whether the MR is approved. If so, approval
+is pushed to GitLab, else nothing is done. Then deletes the local branch
+and switches back to main or master if available. Requires
+[jq](https://jqlang.github.io/jq/) and
+[glab](https://gitlab.com/gitlab-org/cli).
+
+* `ag scrub`: If main or master exists (checked in that order), switches to it,
+deletes all other local branches, and pulls latest changes from remote.
+
+* `ag submit`: If on main or master branch, accepts a branch name as an
+argument, switches to that branch prefixed with `ajwh/`, commits all changes
+(opening `$EDITOR` as usual for commit message), and pushes them to the new
+branch. If already on a branch prefixed with `ajwh/`, amend prior commit and
+force-push to the current branch. If neither scenario applies, do nothing.
+
+## Motivation
+
+These commands help with workflows I perform during full-time work as a software
+engineering manager, and are therefore opinionated procedures. I don't expect
+others will get much use from this, but I display it publicly (a) for fun and
+(b) because it may inspire others to wrap git for their convenience. We're all
+better off automating. ([Within reason!](https://xkcd.com/1205/))
diff --git a/ag b/ag
new file mode 100755
index 0000000..f6caafb
--- /dev/null
+++ b/ag
@@ -0,0 +1,122 @@
+#!/bin/bash
+
+submit() {
+ current_branch=$(git rev-parse --abbrev-ref HEAD)
+
+ if [[ "$current_branch" == ajwh/* ]]; then
+ # Amend commit, opening $EDITOR for commit message modification
+ git add .
+ git commit --amend
+ git push origin "$current_branch" --force
+ elif [ "$current_branch" == "main" ] || [ "$current_branch" == "master" ]; then
+ # Check if branch name is provided
+ if [ -z "$1" ]; then
+ echo "no branch name"
+ exit 1
+ fi
+
+ # Prefix the new branch name with "ajwh/"
+ new_branch="ajwh/$1"
+
+ git checkout -b "$new_branch"
+ git add .
+ git commit
+ git push --set-upstream origin "$new_branch"
+ else
+ echo "not on main, master, or 'ajwh/'-prefixed branch"
+ fi
+}
+
+scrub() {
+ if git show-ref --verify --quiet refs/heads/main; then
+ default_branch="main"
+ elif git show-ref --verify --quiet refs/heads/master; then
+ default_branch="master"
+ else
+ echo "no main or master branch"
+ exit 1
+ fi
+
+ git checkout "$default_branch"
+ git branch | grep -v "$default_branch" | xargs git branch -D
+ git pull origin "$default_branch"
+}
+
+review() {
+ remote_url=$(git config --get remote.origin.url)
+ if [[ "$remote_url" != *"gitlab.com"* ]]; then
+ echo "remote is not a gitlab repo"
+ exit 1
+ fi
+
+ if ! glab mr view "$1" --repo "$remote_url" > /dev/null 2>&1; then
+ echo "mr #$1 does not exist in this repo"
+ exit 1
+ fi
+
+ mr_status=$(glab mr view "$1" --repo "$remote_url" --output json | jq -r .status)
+ if [[ "$mr_status" == "closed" || "$mr_status" == "merged" ]]; then
+ echo "note: mr #$1 is $mr_status"
+ sleep 1
+ fi
+
+ branch_name=$(glab mr view "$1" --repo "$remote_url" --output json | jq -r .source_branch)
+
+ git checkout "$branch_name"
+ git pull origin "$branch_name"
+
+ author_username=$(glab mr view "$1" --repo "$remote_url" --output json | jq -r .author.username)
+ echo "author: $author_username"
+ sleep 1
+
+ mr_description=$(glab mr view "$1" --repo "$remote_url" --output json | jq -r .description)
+ echo "$mr_description" | less
+
+ git fetch origin main
+ git diff "origin/main" "$branch_name"
+
+ echo -n "approve mr? [y/N]: "
+ read -r approval
+ if [[ "$approval" == [yY] ]]; then
+ glab mr approve "$1" --repo "$remote_url"
+ fi
+
+ if git show-ref --verify --quiet refs/heads/main; then
+ default_branch="main"
+ elif git show-ref --verify --quiet refs/heads/master; then
+ default_branch="master"
+ else
+ echo "no main or master branch"
+ exit 1
+ fi
+
+ git checkout "$default_branch"
+ git branch -D "$branch_name"
+}
+
+# Function to pass through to git
+fallback() {
+ git "$@"
+ exit_status=$?
+ if [ $exit_status -ne 0 ]; then
+ echo "Usage: ag <command> [arguments]"
+ echo "Commands:"
+ echo " submit [branch-name] - Create or amend a branch prefixed with 'ajwh/'."
+ echo " Branch name is required for new branches."
+ echo " scrub - Cleans local branches and resets to default branch state."
+ echo " review <mr-number> - Reviews a merge request on GitLab."
+ echo "Other commands pass to underlying git."
+ fi
+}
+
+case "$1" in
+ submit|scrub)
+ "$1" "${@:2}"
+ ;;
+ review)
+ review "$2"
+ ;;
+ *)
+ fallback "$@"
+ ;;
+esac