Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion app/(docs)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { TypeTable } from "fumadocs-ui/components/type-table"
import { Accordion, Accordions } from "fumadocs-ui/components/accordion"
import ImageSection from "@/app/components/ImageSection"
import CliBlock from "@/app/components/CliBlock"
import { getCommandPageComponents } from "@/app/components/CommandPageComponents"
import type { ComponentProps, FC } from "react"

interface Param {
Expand Down Expand Up @@ -75,6 +76,10 @@ export default async function Page(props: { params: Promise<Param> }): Promise<R
</>
)

// Detect if this is a command page
const isCommandPage = page.file.path.includes('commands/')
const commandComponents = getCommandPageComponents(isCommandPage)

return (
<DocsPage
toc={page.data.toc}
Expand All @@ -89,12 +94,20 @@ export default async function Page(props: { params: Promise<Param> }): Promise<R
footer
}}
>
<DocsTitle>{page.data.title.replace(/`/g, '')}</DocsTitle>
{isCommandPage ? (
<div className="flex items-center gap-3 mb-4">
<span className="text-emerald-500 dark:text-emerald-400 font-mono text-4xl font-bold select-none">&gt;_</span>
<DocsTitle className="font-mono">{page.data.title.replace(/`/g, '')}</DocsTitle>
</div>
) : (
<DocsTitle>{page.data.title.replace(/`/g, '')}</DocsTitle>
)}
<DocsDescription>{page.data.description}</DocsDescription>
<DocsBody>
<page.data.body
components={{
...defaultComponents,
...commandComponents,
Popup,
PopupContent,
PopupTrigger,
Expand Down
104 changes: 104 additions & 0 deletions app/components/CommandPageComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type { ComponentProps, ReactNode, ReactElement } from 'react'
import { Children, isValidElement, cloneElement } from 'react'

// Custom H1 for command pages - adds terminal prompt icon
export function CommandH1({ children }: { children: ReactNode }) {
return (
<div className="flex items-center gap-3 mb-6 mt-0">
<span className="text-emerald-500 dark:text-emerald-400 font-mono text-xl">&gt;_</span>
<h1 className="text-3xl font-bold m-0 p-0">{children}</h1>
</div>
)
}

// Custom strong/bold for options - styles them as green pills
export function CommandStrong({ children }: ComponentProps<'strong'>) {
const text = String(children)

// Check if this looks like option syntax with Usage:
if (text.includes('Usage:')) {
return <strong>{children}</strong>
}

return <strong>{children}</strong>
}

// Helper to check if content looks like an option/argument
function isOptionOrArgument(text: string): boolean {
return (
text.startsWith('-') ||
text.includes('--') ||
text.startsWith('<') && text.endsWith('>') ||
text.match(/^-[a-z],\s+--[a-z-]+/i) !== null
)
}

// Custom code for inline code - adds green background for options
export function CommandCode({ children, className, ...props }: ComponentProps<'code'>) {
// If it's in a pre tag (code block), don't style it
if (className?.includes('language-')) {
return <code className={className} {...props}>{children}</code>
}

// Check if this looks like an option flag or argument
const text = String(children)

if (isOptionOrArgument(text)) {
return (
<code
className="inline-block px-3 py-1.5 bg-emerald-50 dark:bg-emerald-950/30 text-emerald-700 dark:text-emerald-400 rounded font-mono text-sm whitespace-nowrap not-prose"
{...props}
>
{children}
</code>
)
}

return <code className={className} {...props}>{children}</code>
}

// Custom list item for options/arguments
export function CommandLi({ children, ...props }: ComponentProps<'li'>) {
// Process children to find code elements
let hasOptionCode = false

Children.forEach(children, (child) => {
if (isValidElement(child) && child.type === 'code') {
const childProps = child.props as any
const text = String(childProps.children || '')
if (isOptionOrArgument(text)) {
hasOptionCode = true
}
}
})

if (hasOptionCode) {
return (
<li className="flex items-start gap-3 my-3 list-none" {...props}>
<div className="flex items-start gap-3 w-full">{children}</div>
</li>
)
}

return <li {...props}>{children}</li>
}

// Custom unordered list
export function CommandUl({ children, ...props }: ComponentProps<'ul'>) {
return <ul className="space-y-1" {...props}>{children}</ul>
}

// Wrapper to detect command pages and apply custom styling
export function getCommandPageComponents(isCommandPage: boolean): Record<string, any> {
if (!isCommandPage) {
return {}
}

return {
h1: CommandH1,
code: CommandCode,
li: CommandLi,
ul: CommandUl,
strong: CommandStrong,
} as Record<string, any>
}
10 changes: 4 additions & 6 deletions content/docs/commands/but-absorb.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ title: "`but absorb`"
description: "Amends changes into the appropriate commits where they belong."
---

# Amends changes into the appropriate commits where they belong.

Amends changes into the appropriate commits where they belong.

The semantic for finding "the appropriate commit" is as follows:

- If a change has a dependency to a particular commit, it will be amended into that particular commit
Expand All @@ -20,9 +16,11 @@ Optionally an identifier to an Uncommitted File or a Branch (stack) may be provi
- If a Branch (stack) id is provided, absorb will be performed for all changes staged to that stack
- If no source is provided, absorb is performed for all uncommitted changes

If --dry-run is specified, no changes will be made; instead, the absorption plan (what changes would be absorbed by which commits) will be shown.
If `--dry-run` is specified, no changes will be made; instead, the absorption plan
(what changes would be absorbed by which commits) will be shown.

If --new is specified, new commits will be created for absorbed changes instead of amending existing commits.
If `--new` is specified, new commits will be created for absorbed changes
instead of amending existing commits.

**Usage:** `but absorb [SOURCE] [OPTIONS]`

Expand Down
24 changes: 13 additions & 11 deletions content/docs/commands/but-alias.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@ title: "`but alias`"
description: "Manage command aliases."
---

# Manage command aliases.
Aliases allow you to create shortcuts for commonly used commands.
They are stored in git config under the `but.alias.*` namespace.

Manage command aliases.

Aliases allow you to create shortcuts for commonly used commands. They are stored in git config under the but.alias.* namespace.

Examples
## Examples

List all configured aliases:

but alias
```text
but alias
```

Create a new alias:

but alias add st status
but alias add stv "status --verbose"
```text
but alias add st status
but alias add stv "status --verbose"
```

Remove an alias:

but alias remove st

```text
but alias remove st
```

**Usage:** `but alias <COMMAND>`

Expand Down
4 changes: 0 additions & 4 deletions content/docs/commands/but-amend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ title: "`but amend`"
description: "Amend a file change into a specific commit and rebases any dependent commits."
---

# Amend a file change into a specific commit and rebases any dependent commits.

Amend a file change into a specific commit and rebases any dependent commits.

Wrapper for `but rub <file> <commit>`.

**Usage:** `but amend <FILE> <COMMIT>`
Expand Down
7 changes: 2 additions & 5 deletions content/docs/commands/but-branch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ title: "`but branch`"
description: "Commands for managing branches."
---

# Commands for managing branches.

Commands for managing branches.

This includes creating, deleting, listing, showing details about, and applying and unapplying branches.
This includes creating, deleting, listing, showing details about, and
applying and unapplying branches.

By default without a subcommand, it will list the branches.

Expand Down
14 changes: 10 additions & 4 deletions content/docs/commands/but-commit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ title: "`but commit`"
description: "Commit changes to a stack."
---

# Commit changes to a stack.

Commit changes to a stack.

The `but commit` command allows you to create a new commit
on a specified branch (stack) with the current uncommitted changes.

Expand Down Expand Up @@ -82,3 +78,13 @@ If a target is provided without --before or --after, defaults to --before behavi
* `--before` `<BEFORE>` — Insert the blank commit before this commit or branch
* `--after` `<AFTER>` — Insert the blank commit after this commit or branch

## Options

* `-m`, `--message` `<MESSAGE>` — Commit message
* `-f`, `--file` `<FILE>` — Read commit message from file
* `-c`, `--create` — Whether to create a new branch for this commit. If the branch name given matches an existing branch, that branch will be used instead. If no branch name is given, a new branch with a generated name will be created
* `-o`, `--only` — Only commit staged files, not unstaged files
* `-n`, `--no-hooks` — Bypass pre-commit hooks
* `-i`, `--ai` `<AI>` — Generate commit message using AI with optional user summary
* `-F`, `--files` `<FILES>` — Uncommitted file or hunk CLI IDs to include in the commit. Can be specified multiple times or as comma-separated values. If not specified, all uncommitted changes (or changes staged to the target branch) are committed

34 changes: 20 additions & 14 deletions content/docs/commands/but-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,42 @@ title: "`but config`"
description: "View and manage GitButler configuration."
---

# View and manage GitButler configuration.
Without a subcommand, displays an overview of important settings including
user information, target branch, forge configuration, and AI setup.

View and manage GitButler configuration.

Without a subcommand, displays an overview of important settings including user information, target branch, forge configuration, and AI setup.

Examples
## Examples

View configuration overview:

but config
```text
but config
```

View/set user configuration:

but config user
but config user set name "John Doe"
but config user set email john@example.com
```text
but config user
but config user set name "John Doe"
but config user set email john@example.com
```

View/set forge configuration:

but config forge
```text
but config forge
```

View/set target branch:

but config target
```text
but config target
```

View/set metrics:

but config metrics

```text
but config metrics
```

**Usage:** `but config <COMMAND>`

Expand Down
8 changes: 2 additions & 6 deletions content/docs/commands/but-diff.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@ title: "`but diff`"
description: "Displays the diff of changes in the repo."
---

# Displays the diff of changes in the repo.

Displays the diff of changes in the repo.

Without any arguments, it shows the diff of all uncommitted changes. Optionally, a CLI ID argument can be provided, which chan show the diff specific to

Without any arguments, it shows the diff of all uncommitted changes.
Optionally, a CLI ID argument can be provided, which chan show the diff specific to
- an uncommitted file
- a branch
- an entire stack
Expand Down
17 changes: 8 additions & 9 deletions content/docs/commands/but-discard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ title: "`but discard`"
description: "Discard uncommitted changes from the worktree."
---

# Discard uncommitted changes from the worktree.
This command permanently discards changes to files, restoring them to their
state in the HEAD commit. Use this to undo unwanted modifications.

Discard uncommitted changes from the worktree.
The ID parameter should be a file ID as shown in `but status`. You can
discard a whole file or specific hunks within a file.

This command permanently discards changes to files, restoring them to their state in the HEAD commit. Use this to undo unwanted modifications.

The ID parameter should be a file ID as shown in but status. You can discard a whole file or specific hunks within a file.

Examples
## Examples

Discard all changes to a file:

but discard a1

```text
but discard a1
```

**Usage:** `but discard <ID>`

Expand Down
12 changes: 5 additions & 7 deletions content/docs/commands/but-gui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ title: "`but gui`"
description: "Open the GitButler GUI for the current project."
---

# Open the GitButler GUI for the current project.
Running `but gui` will launch the GitButler graphical user interface
in the current directory's GitButler project.

Open the GitButler GUI for the current project.
This provides a visual way to manage branches, commits, and uncommitted
changes, complementing the command-line interface.

Running but gui will launch the GitButler graphical user interface in the current directory's GitButler project.

This provides a visual way to manage branches, commits, and uncommitted changes, complementing the command-line interface.

You can also just run but . as a shorthand to open the GUI.
You can also just run `but .` as a shorthand to open the GUI.

**Usage:** `but gui`

Loading