Use when the user says "/git-commit-and-push" or asks to commit and push current git changes. Commits on a feature branch and pushes to remote, presenting the MR/PR creation link from the push output. Handles multiple repositories when changes span backend and frontend.
Commit current git changes on a feature branch and push to remote. Supports multi-repo sessions.
For each affected repo, check if GitButler is initialized:
but status --json 2>/dev/null
but is not installed, use the Standard Git workflow.Uses but for all operations — committing, pushing, and PR/MR creation. Never mix in git write commands or glab/gh CLI tools.
Run but status --json in every working directory from the current session. A repo is "affected" if it has or uncommitted changes in stacks.
unassignedChangesFor each affected repo:
a. Run but status --json to get change IDs and existing stacks/branches.
b. Review changes: check unassignedChanges and any stack changes to understand what changed.
c. Determine the branch to use:
use branch name feature/foo), use it.stacked on <old-branch> was also given, the new branch must be created on top of the old one (see step d).but status --json: create one with but branch new <descriptive-name>.but status --json): use its ID from the status output.
d. If stacking is required (stacked on <old-branch> hint was given):
After creating the new branch, immediately stack it on the old one:but branch move <new-branch> <old-branch>
Then re-run but status --json to get fresh IDs before committing.
e. Commit with explicit change IDs:
but branch new): use -c to create-and-commit in one step:
but commit <branch> -c -m "<message>" --changes <id1>,<id2> --json --status-after
-c — that would recreate the branch head and rewrite history, forcing a force-push:
but commit <branch> -m "<message>" --changes <id1>,<id2> --json --status-after
The --status-after output has fresh IDs — no need for a redundant but status.
For each committed repo:
a. Check if a PR/MR already exists:
but branch show <branch> --review --json
Inspect the reviews array in the output.
PR/MR already exists and is open (no mergedAt): push the new commit(s) with a normal push — do not force-push:
but push <branch>
Note the existing PR/MR URL from the reviews array and present it to the user.
PR/MR already exists but is merged (has mergedAt): the previous PR was completed but the session continued with new work. Push first, then create a new PR via the forge CLI since but pr new will refuse to create a duplicate:
but push <branch>
gh pr create --base master --head <branch> --title "<commit title>" --body "<commit body>"
For GitLab, use glab mr create --fill --yes --source-branch <branch> --target-branch develop --remove-source-branch --squash-before-merge instead.
This is the one exception to the "never use gh/glab in GitButler repos" rule.
b. If no PR/MR exists, create one:
but pr new <branch> -t --json --status-after
-t uses the commit message as the default title/description, skipping interactive prompts. This command handles both the push and PR/MR creation in one step. The target branch is determined by the project's GitButler target config (but config target).
Note: If forge auth is not configured, but pr new will fail. In that case, fall back to pushing with but push <branch> and inform the user to run but config forge auth to enable PR creation, or create the PR manually on the forge.
After a successful MR creation on GitLab, enable "Delete source branch" and "Squash commits" on the MR.
The glab mr update flags --remove-source-branch and --squash-before-merge toggle those settings, so instead use the GitLab REST API directly to force them true regardless of their current state:
MR_IID=$(glab mr list --source-branch=<branch> | grep -oP '(?<=!)\d+' | head -1)
glab api --method PUT "projects/:id/merge_requests/$MR_IID" --field squash=true --field should_remove_source_branch=true
Present all PR/MR links to the user, clearly labeled by repo.
but status --json output; never hardcode IDs.--changes with comma-separated file/hunk IDs: --changes a1,b2.--json --status-after to mutation commands.but push (not git push) for pushing.glab or gh in GitButler repos — use but pr instead.For repos where GitButler is not initialized. Uses standard git + glab/gh.
Check git status in every working directory from the current session. A repo is "affected" if it has staged or unstaged changes.
For each affected repo:
git status and git diff to understand changes.develop or master — suggest a feature branch and confirm with user first.For each committed repo:
a. Push the branch:
git push -u origin <branch-name>
b. Check if an MR already exists:
glab mr list --source-branch=<branch-name>
Parse the text output (glab mr list has no --output json flag).
c. If no existing MR found, create one:
glab mr create --fill --yes --source-branch <branch-name> --target-branch develop --remove-source-branch --squash-before-merge
Present all MR links to the user, clearly labeled by repo.
cd into each repo's directory before running any but, git, glab, or gh commands for that repo. Many CLI tools (especially glab api with projects/:id) resolve the project from the git remote in the current working directory. When a session spans multiple repos, running commands from the wrong directory will target the wrong project.develop or master.feature/ prefix with a descriptive name: feature/add-user-auth, feature/fix-logout-hang. Never use fix/, bugfix/, or other prefixes — always feature/.