Back to Lazygit

Custom Command Keybindings

docs/Custom_Command_Keybindings.md

0.61.118.7 KB
Original Source

Custom Command Keybindings

You can add custom command keybindings in your config.yml (accessible by pressing 'e' on the status panel from within lazygit) like so:

yml
customCommands:
  - key: '<c-r>'
    context: 'commits'
    command: 'hub browse -- "commit/{{.SelectedLocalCommit.Hash}}"'
  - key: 'a'
    context: 'files'
    command: "git {{if .SelectedFile.HasUnstagedChanges}} add {{else}} reset {{end}} {{.SelectedFile.Name | quote}}"
    description: 'Toggle file staged'
  - key: 'C'
    context: 'global'
    command: "git commit"
    output: terminal
  - key: 'n'
    context: 'localBranches'
    prompts:
      - type: 'menu'
        title: 'What kind of branch is it?'
        key: 'BranchType'
        options:
          - name: 'feature'
            description: 'a feature branch'
            value: 'feature'
          - name: 'hotfix'
            description: 'a hotfix branch'
            value: 'hotfix'
          - name: 'release'
            description: 'a release branch'
            value: 'release'
      - type: 'input'
        title: 'What is the new branch name?'
        key: 'BranchName'
        initialValue: ''
    command: "git flow {{.Form.BranchType}} start {{.Form.BranchName}}"
    loadingText: 'Creating branch'

Looking at the command assigned to the 'n' key, here's what the result looks like:

Custom command keybindings will appear alongside inbuilt keybindings when you view the keybindings menu by pressing '?':

For a given custom command, here are the allowed fields:

fielddescriptionrequired
keyThe key to trigger the command. Use a single letter or one of the values from here. Custom commands without a key specified can be triggered by selecting them from the keybindings (?) menuno
commandThe command to run (using Go template syntax for placeholder values)yes
contextThe context in which to listen for the key (see below)yes
promptsA list of prompts that will request user input before running the final commandno
loadingTextText to display while waiting for command to finishno
descriptionLabel for the custom command when displayed in the keybindings menuno
outputWhere the output of the command should go. 'none' discards it, 'terminal' suspends lazygit and runs the command in the terminal (useful for commands that require user input), 'log' streams it to the command log, 'logWithPty' is like 'log' but runs the command in a pseudo terminal (can be useful for commands that produce colored output when the output is a terminal), and 'popup' shows it in a popup.no
outputTitleThe title to display in the popup panel if output is set to 'popup'. If left unset, the command will be used as the title.no
afterActions to take after the command has completedno

Here are the options for the after key:

fielddescriptionrequired
checkForConflictstrue/false. If true, check for merge conflictsno

Contexts

The permitted contexts are:

contextdescription
statusThe 'Status' tab
filesThe 'Files' tab
worktreesThe 'Worktrees' tab
submodulesThe 'Submodules' tab
localBranchesThe 'Local Branches' tab
remotesThe 'Remotes' tab
remoteBranchesThe context you get when pressing enter on a remote in the remotes tab
tagsThe 'Tags' tab
commitsThe 'Commits' tab
reflogCommitsThe 'Reflog' tab
subCommitsThe context you see when pressing enter on a branch
commitFilesThe context you see when pressing enter on a commit or stash entry (warning, might be renamed in future)
stashThe 'Stash' tab
globalThis keybinding will take affect everywhere

Bonus

You can use a comma-separated string, such as context: 'commits, subCommits', to make it effective in multiple contexts.

Prompts

Common fields

These fields are applicable to all prompts.

fielddescriptionrequired
typeOne of 'input', 'confirm', 'menu', 'menuFromCommand'yes
titleThe title to display in the popup panelno
keyUsed to reference the entered value from within the custom command. E.g. a prompt with key: 'Branch' can be referred to as {{.Form.Branch}} in the commandyes
conditionA Go template expression; if it resolves to empty string or false, the prompt is skipped. See Conditional promptsno

Input

fielddescriptionrequired
initialValueThe initial value to appear in the text boxno
suggestionsShows suggestions as the input is entered. See below for detailsno

The permitted suggestions fields are:

fielddescriptionrequired
presetUses built-in logic to obtain the suggestions. One of 'authors', 'branches', 'files', 'refs', 'remotes', 'remoteBranches', 'tags'no
commandCommand to run such that each line in the output becomes a suggestion. Mutually exclusive with 'preset' field.no

Here's an example of passing a preset:

yml
customCommands:
  - key: 'a'
    command: 'echo {{.Form.Branch | quote}}'
    context: 'commits'
    prompts:
      - type: 'input'
        title: 'Which branch?'
        key: 'Branch'
        suggestions:
          preset: 'branches' # use built-in logic for obtaining branches

Here's an example of passing a command directly:

yml
customCommands:
  - key: 'a'
    command: 'echo {{.Form.Branch | quote}}'
    context: 'commits'
    prompts:
      - type: 'input'
        title: 'Which branch?'
        key: 'Branch'
        suggestions:
          command: "git branch --format='%(refname:short)'"

Here's an example of passing an initial value for the input:

yml
customCommands:
  - key: 'a'
    command: 'echo {{.Form.Remote | quote}}'
    context: 'commits'
    prompts:
    - type: 'input'
      title: 'Remote:'
      key: 'Remote'
      initialValue: "{{.SelectedRemote.Name}}"

Confirm

fielddescriptionrequired
bodyThe immutable body text to appear in the text boxno

Example:

yml
customCommands:
  - key: 'a'
    command: 'echo "pushing to remote"'
    context: 'commits'
    prompts:
    - type: 'confirm'
      title: 'Push to remote'
      body: 'Are you sure you want to push to the remote?'
fielddescriptionrequired
optionsThe options to display in the menuyes

The permitted option fields are:

fielddescriptionrequired
nameThe first part of the labelno
descriptionThe second part of the labelno
valuethe value that will be used in the commandyes
keyKeybinding to invoke this menu option without needing to navigate to it. Can be a single letter or one of the values from hereno

If an option has no name the value will be displayed to the user in place of the name, so you're allowed to only include the value like so:

yml
customCommands:
  - key: 'a'
    command: 'echo {{.Form.BranchType | quote}}'
    context: 'commits'
    prompts:
      - type: 'menu'
        title: 'What kind of branch is it?'
        key: 'BranchType'
        options:
          - value: 'feature'
          - value: 'hotfix'
          - value: 'release'

Here's an example of supplying more detail for each option:

yml
customCommands:
  - key: 'a'
    command: 'echo {{.Form.BranchType | quote}}'
    context: 'commits'
    prompts:
      - type: 'menu'
        title: 'What kind of branch is it?'
        key: 'BranchType'
        options:
          - value: 'feature'
            name: 'feature branch'
            description: 'branch based off develop'
          - value: 'hotfix'
            name: 'hotfix branch'
            description: 'branch based off main for fast bug fixes'
          - value: 'release'
            name: 'release branch'
            description: 'branch for a release'

Here's an example of supplying keybindings for menu options:

yml
customCommands:
  - key: 'a'
    command: 'echo {{.Form.BranchType | quote}}'
    context: 'commits'
    prompts:
      - type: 'menu'
        title: 'What kind of branch is it?'
        key: 'BranchType'
        options:
          - value: 'feature'
            name: 'feature branch'
            description: 'branch based off develop'
            key: 'f'
          - value: 'hotfix'
            name: 'hotfix branch'
            description: 'branch based off main for fast bug fixes'
            key: 'h'
          - value: 'release'
            name: 'release branch'
            description: 'branch for a release'
            key: 'r'

In this example, pressing 'f', 'h', or 'r' will directly select the corresponding option without needing to navigate to it first.

fielddescriptionrequired
commandThe command to run to generate menu optionsyes
filterThe regexp to run specifying groups which are going to be kept from the command's outputno
valueFormatHow to format matched groups from the filter to construct a menu item's valueno
labelFormatLike valueFormat but for the labels. If labelFormat is not specified, valueFormat is shown instead.no

Here's an example using named groups in the regex. Notice how we can pipe the label to a colour function for coloured output (available colours here)

yml
  - key : 'a'
    description: 'Checkout a remote branch as FETCH_HEAD'
    command: "git fetch {{.Form.Remote}} {{.Form.Branch}} && git checkout FETCH_HEAD"
    context: 'remotes'
    prompts:
      - type: 'menuFromCommand'
        title: 'Remote branch:'
        key: 'Branch'
        command: 'git branch  -r --list {{.SelectedRemote.Name }}/*'
        filter: '.*{{.SelectedRemote.Name }}/(?P<branch>.*)'
        valueFormat: '{{ .branch }}'
        labelFormat: '{{ .branch | green }}'

Here's an example using unnamed groups:

yml
  - key : 'a'
    description: 'Checkout a remote branch as FETCH_HEAD'
    command: "git fetch {{.Form.Remote}} {{.Form.Branch}} && git checkout FETCH_HEAD"
    context: 'remotes'
    prompts:
      - type: 'menuFromCommand'
        title: 'Remote branch:'
        key: 'Branch'
        command: 'git branch  -r --list {{.SelectedRemote.Name }}/*'
        filter: '.*{{.SelectedRemote.Name }}/(.*)'
        valueFormat: '{{ .group_1 }}'
        labelFormat: '{{ .group_1 | green }}'

Here's an example using a command but not specifying anything else: so each line from the command becomes the value and label of the menu items

yml
  - key : 'a'
    description: 'Checkout a remote branch as FETCH_HEAD'
    command: "open {{.Form.File | quote}}"
    context: 'global'
    prompts:
      - type: 'menuFromCommand'
        title: 'File:'
        key: 'File'
        command: 'ls'

Conditional prompts

Here's an example of a conditional prompt:

yml
customCommands:
  - key: 'a'
    context: 'localBranches'
    prompts:
      - type: 'menu'
        title: 'How do you want to create the branch?'
        key: 'Method'
        options:
          - value: 'simple'
            name: 'Simple'
            description: 'just a branch name'
          - value: 'prefix'
            name: 'With prefix'
            description: 'with a category prefix'
      - type: 'menu'
        title: 'Branch prefix'
        key: 'Prefix'
        condition: '{{ eq .Form.Method "prefix" }}'
        options:
          - value: 'feature/'
          - value: 'hotfix/'
          - value: 'release/'
      - type: 'input'
        title: 'Branch name'
        key: 'Name'
    command: "git checkout -b '{{.Form.Prefix}}{{.Form.Name}}'"

In this example the 'Branch prefix' menu only appears if the user chose 'With prefix'. Otherwise it is skipped and .Form.Prefix defaults to empty string.

Placeholder values

Your commands can contain placeholder strings using Go's template syntax. The template syntax is pretty powerful, letting you do things like conditionals if you want, but for the most part you'll simply want to be accessing the fields on the following objects:

SelectedCommit
SelectedCommitRange
SelectedFile
SelectedPath
SelectedSubmodule
SelectedLocalBranch
SelectedRemoteBranch
SelectedRemote
SelectedTag
SelectedStashEntry
SelectedCommitFile
SelectedWorktree
CheckedOutBranch

(For legacy reasons, SelectedLocalCommit, SelectedReflogCommit, and SelectedSubCommit are also available, but they are deprecated.)

To see what fields are available on e.g. the SelectedFile, see here (all the modelling lives in the same file).

We don't support accessing all elements of a range selection yet. We might add this in the future, but as a special case you can access the range of selected commits by using SelectedCommitRange, which has two properties .To and .From which are the hashes of the bottom and top selected commits, respectively. This is useful for passing them to a git command that operates on a range of commits. For example, to create patches for all selected commits, you might use

yml
  command: "git format-patch {{.SelectedCommitRange.From}}^..{{.SelectedCommitRange.To}}"

We support the following functions:

Quoting

Quote wraps a string in quotes with necessary escaping for the current platform.

git {{.SelectedFile.Name | quote}}

Running a command

Runs a command and returns the output. If the command outputs more than a single line, it will produce an error.

initialValue: "username/{{ runCommand "date +\"%Y/%-m\"" }}/"

Keybinding collisions

If your custom keybinding collides with an inbuilt keybinding that is defined for the same context, only the custom keybinding will be executed. This also applies to the global context. However, one caveat is that if you have a custom keybinding defined on the global context for some key, and there is an in-built keybinding defined for the same key and for a specific context (say the 'files' context), then the in-built keybinding will take precedence. See how to change in-built keybindings here

For custom commands that are not used very frequently it may be preferable to hide them in a menu; you can assign a key to open the menu, and the commands will appear inside. This has the advantage that you don't have to come up with individual unique keybindings for all those commands that you don't use often; the keybindings for the commands in the menu only need to be unique within the menu. Here is an example:

yml
customCommands:
- key: X
  description: "Copy/paste commits across repos"
  commandMenu:
  - key: c
    command: 'git format-patch --stdout {{.SelectedCommitRange.From}}^..{{.SelectedCommitRange.To}} | pbcopy'
    context: commits, subCommits
    description: "Copy selected commits to clipboard"
  - key: v
    command: 'pbpaste | git am'
    context: "commits"
    description: "Paste selected commits from clipboard"

If you use the commandMenu property, none of the other properties except key and description can be used.

Debugging

If you want to verify that your command actually does what you expect, you can wrap it in an 'echo' call and set output: popup so that it doesn't actually execute the command but you can see how the placeholders were resolved.

More Examples

See the wiki page for more examples, and feel free to add your own custom commands to this page so others can benefit!