
A Faster Workflow for Quick Edits at Ecenica
If you’re making small edits to your codebase, the traditional Git workflow can feel unnecessarily heavy. Switching branches, creating feature branches, pushing, opening PRs, reviewing, merging…it’s a lot of ritual for updating a README or fixing a typo.
At Ecenica, we focus on speed and simplicity. That’s why we redesigned our workflow for small fixes using two simple Git aliases powered by the GitHub CLI.
The Problem
For tiny edits like fixing spelling, updating docs, or tweaking a config file, the standard workflow pulls you into a long sequence:
- Switch to develop
- Pull latest
- Create feature branch
- Edit files
- Stage changes
- Commit
- Push
- Open PR
- Review
- Merge
- Delete branch
- Switch back
- Pull updates
That’s a lot of steps for a one-line fix.
The Solution: Two Git Aliases That Do Everything
By combining Git + GitHub CLI + GitHub Copilot (optional), we condensed the entire flow into:
git start
git finish
Just two commands.
Step 1 – Create Your Git Tools Directory
mkdir -p ~/.git-tools
Step 2 – Create git-start
Create the file:
nano ~/.git-tools/git-start
Paste:
#!/usr/bin/env bash
set -euo pipefail
# -------------------------------------------------------
# git start — Create a properly named feature/fix branch
# Supports:
# git start feat/login-page
# git start feat login-page
# git start fix bug-123
# -------------------------------------------------------
# --- Normalize input ---
# Convert "feat/foo-bar" → ("feat" "foo-bar")
if [[ $# -eq 1 && "$1" == */* ]]; then
TYPE_PART="${1%%/*}"
DESC_PART="${1#*/}"
set -- "$TYPE_PART" "$DESC_PART"
fi
# --- Validate argument count ---
if [[ $# -lt 2 ]]; then
echo "❌ Usage:"
echo " git start <type> <description>"
echo " git start <type>/<description>"
echo
echo "Valid types: feat, fix, docs, style, refactor, test, chore"
exit 1
fi
TYPE="$1"
DESC="$2"
# --- Validate branch type ---
VALID_TYPES="feat fix docs style refactor test chore"
if ! echo "$VALID_TYPES" | grep -qw "$TYPE"; then
echo "❌ Invalid branch type: '$TYPE'"
echo "Valid types: $VALID_TYPES"
exit 1
fi
# --- Sanitize description ---
# lowercase + replace spaces with hyphens
DESC=$(echo "$DESC" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
BRANCH="${TYPE}/${DESC}"
# --- Ensure we're on develop/main before branching ---
CURRENT_BRANCH=$(git branch --show-current)
if [[ "$CURRENT_BRANCH" != "develop" && "$CURRENT_BRANCH" != "main" ]]; then
echo "⚠️ You are on '$CURRENT_BRANCH'"
read -rp "Switch to 'develop' before creating a branch? (Y/n) " REPLY
if [[ -z "$REPLY" || "$REPLY" =~ ^[Yy]$ ]]; then
git checkout develop
git pull --rebase
else
echo "❌ Aborted."
exit 1
fi
fi
# --- Create the branch ---
echo "🌱 Creating branch: $BRANCH"
git checkout -b "$BRANCH"
echo "⬆️ Pushing upstream..."
git push -u origin "$BRANCH"
echo "✅ Branch ready!"
echo " → $BRANCH"
echo " You can now begin committing."
Make executable:
chmod +x ~/.git-tools/git-start
Register alias:
git config --global alias.start '!~/.git-tools/git-start'
Step 3 – Create git-finish
Create:
nano ~/.git-tools/git-finish
Paste:
#!/usr/bin/env bash
COMMIT_MSG=""
# ---- Parse flags ----
while [ "$#" -gt 0 ]; do
case "$1" in
-m|--message)
COMMIT_MSG="$2"
shift
;;
*)
echo "❌ Unknown option: $1"
echo "Usage: git finish [-m message]"
exit 1
;;
esac
shift
done
# ---- Dependency check ----
if ! command -v gh >/dev/null 2>&1; then
echo "⚠️ GitHub CLI missing — install with: brew install gh"
exit 1
fi
CURRENT_BRANCH=$(git branch --show-current) || exit 1
# ---- Branch format check ----
if ! echo "$CURRENT_BRANCH" | grep -qE '^(fix|feat|docs|style|refactor|test|chore)/'; then
echo "⚠️ Warning: Branch does not follow conventional format (type/description)"
echo "Current branch: $CURRENT_BRANCH"
read -p "Continue anyway? (y/N) " -n 1 -r
echo
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
fi
# ---- Check for changes ----
if git diff-index --quiet HEAD --; then
echo "✨ Nothing to commit — working tree clean"
echo "📖 Opening existing PR..."
else
# ---- Generate commit message if needed ----
if [ -z "$COMMIT_MSG" ]; then
if command -v copilot >/dev/null 2>&1; then
echo "🧠 Generating commit message with Copilot..."
COMMIT_MSG=$(
copilot \
-p "suggest a conventional commit message for these git changes" \
--allow-all-tools 2>/dev/null |
grep -E '^(feat|fix|docs|style|refactor|test|chore):' |
head -1
)
[ -z "$COMMIT_MSG" ] && COMMIT_MSG="chore: update"
echo "💬 Generated: $COMMIT_MSG"
else
echo "⚠️ Copilot CLI not installed — using default commit message."
BRANCH_TYPE=$(echo "$CURRENT_BRANCH" | cut -d'/' -f1)
COMMIT_MSG="${BRANCH_TYPE}: update"
fi
fi
git add -A &&
git commit -m "$COMMIT_MSG" &&
git push -u origin "$CURRENT_BRANCH" || exit 1
fi
# ---- PR handling ----
if gh pr view &>/dev/null; then
echo "📖 PR already exists — opening..."
else
echo "📝 Creating PR..."
gh pr create --base develop --fill || exit 1
fi
read -p "Press Enter to open PR..."
gh pr view --web
read -p "Press Enter after reviewing to merge..."
gh pr merge --squash --delete-branch
git checkout develop &&
git pull &&
echo "✅ Merged and back on develop!"
Make executable:
chmod +x ~/.git-tools/git-finish
Register alias:
git config --global alias.finish '!~/.git-tools/git-finish'
Usage
git start fix readme-typo git finish
What Happens Behind the Scenes
When you run git finish:
- Branch validation — Checks if your branch follows conventional format (
type/description) - Smart commit handling — If working tree is clean, skips commit and goes straight to PR
- Intelligent commit message generation — If you don’t provide a message with
-m, Copilot analyses your changes using programmatic mode (copilot -p) and suggests an appropriate conventional commit message. Falls back to extracting the type from your branch name if Copilot is unavailable. - Automatic staging & commit — All changes are staged and committed (if needed)
- Push & PR creation — Your branch is pushed and a PR is automatically opened against
develop(or opens existing PR if one already exists) - Manual review — The PR opens in your browser so you can review the changes yourself
- One-click merge — After reviewing, press Enter to squash merge and delete the branch
- Clean return — Automatically switches back to
developand pulls the latest changes
Requirements
- Git
- GitHub CLI
brew install gh
- GitHub Copilot CLI (optional, but recommended for auto-generated commit messages)
npm install -g @github/copilot
- GitHub Authentication
gh auth login Select GitHub.com Select SSH Select key Authenticate with GitHub gh auth setup-git
Note: We use the new
@github/copilotCLI (installed via npm) which replaced the deprecatedgh-copilotextension in October 2025.
If you encounter the error ‘No ‘origin’ remote found in this repo’, run ‘git remote -v’ to check your configured remote names. This script assumes a remote named ‘origin’ exists. If your remote has a different name, either rename it to ‘origin’ or modify the script accordingly.
How We Use This at Ecenica
We’re constantly building and enhancing our services, from WordPress hosting infrastructure to client management tools. Our development flow demands both speed and quality, which is why these aliases have become essential to our daily workflow.
Whether we’re:
- Fixing bugs in production services (
git start fix api-timeout) - Building new features for client dashboards (
git start feat billing-alerts) - Updating documentation for our internal APIs (
git start docs webhook-endpoints) - Refactoring legacy code for better performance (
git start refactor database-queries)
…we use git start and git finish dozens of times per day across our team.
The result? Our engineers spend less time wrestling with Git mechanics and more time focused on what matters: delivering reliable, high-quality services to our clients. Quick documentation updates no longer require 10 minutes of workflow overhead. Small bug fixes get deployed faster. Code review becomes the focus, not the Git ceremony around it.
Why This Matters
Small changes shouldn’t require heavyweight workflows.
With auto-generated commit messages, smart handling of existing PRs, and instant merging, this workflow reduces mental load and saves valuable engineering time. Instead of context-switching through 13 steps, you get two commands that handle everything intelligently.
At Ecenica, speed and simplicity drive our development culture and these small improvements add up quickly. When you’re managing hosting infrastructure, client services, and continuous deployments, every minute saved on workflow friction is a minute gained for building better products.