# push
Push a feature branch to the remote. Automatically detects the remote type and uses the appropriate push strategy.
## Usage
```
git loom push [branch] [--no-pr]
```
### Arguments
| `[branch]` | Branch name or short ID (optional; interactive picker if omitted) |
### Flags
| `--no-pr` | Push without creating a PR or Gerrit review (see below) |
## Remote Type Detection
Detection priority (first match wins):
1. **Explicit config** — `git config loom.remote-type` set to `github`, `azure`, or `gerrit`
2. **URL heuristics** — remote URL contains `github.com` → GitHub
3. **URL heuristics** — remote URL contains `dev.azure.com` → Azure DevOps
4. **Hook inspection** — `.git/hooks/commit-msg` contains "gerrit" → Gerrit
5. **Fallback** — Plain Git
## Push Remote Selection
Detection priority (first match wins):
1. **Explicit config** — `git config loom.push-remote <remote>`
2. **GitHub fork convention** — if the integration remote is named `upstream` and `origin` exists, push to `origin`
3. **Fallback** — integration branch's remote
For non-standard fork setups (e.g., integration branch tracks `origin` but you push to `personal`), set:
```bash
git config loom.push-remote personal
```
## Push Strategies
### Plain Git (default)
```bash
git push --force-with-lease --force-if-includes -u <remote> <branch>
```
Uses `--force-with-lease` because woven branches are frequently rebased. `--force-if-includes` adds extra safety.
### GitHub
Pushes the branch with `--force-with-lease`, then checks whether a PR already exists for the branch:
- **PR exists** — prints the PR URL (`PR updated: https://github.com/owner/repo/pull/42`) without opening the browser
- **No PR** — creates the PR via `gh pr create` with an auto-generated title and description (see [PR Title and Description](#pr-title-and-description) below)
If `gh` is not installed, the push succeeds with a message suggesting to install it.
In a **fork workflow** (tracking `upstream/main`), pushes go to `origin` (your fork) and the PR targets the upstream repository automatically.
If the branch being pushed is the upstream target branch itself, PR creation is skipped.
### Azure DevOps
Pushes the branch with `--force-with-lease`, then checks whether a PR already exists for the branch:
- **PR exists** — prints the PR URL (`PR updated: https://dev.azure.com/...`) without opening the browser
- **No PR** — creates the PR via `az repos pr create` with an auto-generated title and description (see [PR Title and Description](#pr-title-and-description) below)
`--detect` auto-detects the organization and project from the remote URL. If `az` is not installed, the push succeeds with a message suggesting to install it.
### Gerrit
```bash
git push -o topic=<branch> <remote> <branch>:refs/for/<target>
```
Uses the `refs/for/` refspec and sets the topic to the branch name. After pushing, any review URLs returned by Gerrit are extracted from the remote output and displayed below the success message.
## PR Title and Description
When creating a new PR (GitHub or Azure DevOps), *git-loom* auto-generates the title and description from the branch's commits:
- **Single commit** — the commit subject becomes the PR title and the commit body becomes the description.
- **Multiple commits** — you are prompted for a PR title. The description is built by concatenating all commit messages (oldest to newest), separated by `---` dividers.
- **Empty branch** — the branch name is used as the title with an empty description.
## Pushing Without a PR or Review
Use `--no-pr` when you want to push a branch to the remote without triggering PR or review creation — for example, to back up a branch, share work-in-progress, or push to a staging ref.
| Plain | Same as normal (force-with-lease push) |
| GitHub | Skips `gh pr create` |
| Azure DevOps | Skips `az repos pr create` |
| Gerrit | Plain push to branch ref instead of `refs/for/` (see below) |
### Gerrit: `wip/` prefix warning
In Gerrit, pushing directly to a branch ref (not `refs/for/`) creates a remote branch that requires a **project admin** to delete. To protect against accidental non-deletable branches, `--no-pr` on Gerrit prompts when the branch name doesn't start with `wip/`:
```
? Branch `feature-a` is not prefixed with `wip/` — a Gerrit admin will be needed to delete the remote branch later
> Push as `feature-a` (admin required to delete it later)
Push as `wip/feature-a` instead
Cancel
```
- **Push as-is** — pushes to `remote/feature-a`; an admin is needed to delete it later
- **Push as `wip/<branch>`** — pushes with refspec `feature-a:wip/feature-a`; your local branch name is unchanged
- **Cancel** — aborts the push
If the branch already starts with `wip/`, no prompt is shown.
## Examples
### Push to a plain remote
```bash
git loom push feature-a
# Pushed 'feature-a' to origin
```
### Push to GitHub (new PR)
```bash
git loom push feature-a
# Pushed 'feature-a' to origin
# (browser opens to PR creation page)
```
### Push to GitHub (PR already exists)
```bash
git loom push feature-a
# Pushed 'feature-a' to origin
# PR updated: https://github.com/owner/repo/pull/42
```
### Push to Azure DevOps (new PR)
```bash
git loom push feature-a
# Pushed 'feature-a' to origin
# (browser opens to PR creation page)
```
### Push to Azure DevOps (PR already exists)
```bash
git loom push feature-a
# Pushed 'feature-a' to origin
# PR updated: https://dev.azure.com/org/project/_git/repo/pullrequest/42
```
### Push to Gerrit
```bash
git loom push feature-a
# Pushed 'feature-a' to origin (Gerrit: refs/for/main)
# › https://gerrit.example.com/c/project/+/12345
```
### Interactive selection
```bash
git loom push
# ? Select branch to push
# > feature-a
# feature-b
# Pushed 'feature-a' to origin
```
### Push without opening a PR (GitHub)
```bash
git loom push feature-a --no-pr
# Pushed 'feature-a' to origin
```
### Push without a review, renaming to wip/ (Gerrit)
```bash
git loom push feature-a --no-pr
# ? Branch `feature-a` is not prefixed with `wip/`...
# > Push as `wip/feature-a` instead
# Pushed 'feature-a' to origin as 'wip/feature-a'
```
### Override remote type
```bash
git config loom.remote-type gerrit
git loom push feature-a
# Pushed 'feature-a' to origin (Gerrit: refs/for/main)
# › https://gerrit.example.com/c/project/+/12345
```
## Prerequisites
- Must be on an integration branch with upstream tracking
- The target branch must be woven into the integration branch
- Network access to the remote
- `gh` CLI (optional, for GitHub PR creation)
- `az` CLI (optional, for Azure DevOps PR creation)