1. Introduction

Git is just a versioning system. It doesn’t handle anything outside the proper structuring, organization, and synchronization of data throughout its creation cycles. For instance, Git doesn’t include any editor for the mandatory commit messages, annotated tag messages, and interactive rebase sequences.

In this tutorial, we understand and look at ways to change the default editors in Git. First, we briefly discuss the two editor types. After that, we go over the selection procedures for both. Finally, we check different ways to configure the selection for each type of Git editor.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15 and Git 2.39.2. Unless otherwise specified, it should work in most POSIX-compliant environments.

2. Git Editors

Like other applications following the do one thing, but do it well philosophy of UNIX, Git only takes care of version handling. However, it can use more facilities to function unrestricted and in a more convenient manner.

2.1. Core Editor

One Git editor takes care of most general edits.

For instance, each commit operation requires a message:

$ git commit --message='<COMMIT_MESSAGE>' [...]

Although we can supply the message as a literal string on the command line, we can also omit the –message (-m) option and just run a git commit:

$ git commit

However, this way of performing a commit results in Git looking for an editor to open the special COMMIT_EDITMSG file that it uses to edit the current commit message. Notably, the same happens when creating annotated tag messages.

2.2. Sequence File Editor

On the other hand, when it comes to interactive rebase operations, Git uses another editor:

$ git rebase --interactive [...]

The sequence editor usually has more specific features, which enable the modification of several lines simultaneously. This is due to the repetitive nature of sequence files.

Naturally, editor selection depends on the operation that Git performs. Let’s understand how Git tries to select the appropriate editor for a given action.

3. Git Core Editor Selection

When performing general edits such as creating commit and tag messages, Git goes through several steps to select an available editor, in order of precedence:

  1. GIT_EDITOR: if this environment variable is exported, Git uses its value as the editor of choice, regardless of its validity or other settings
  2. core.editor: if this Git setting is configured locally or globally, Git uses it as long as GIT_EDITOR isn’t exported
  3. VISUAL: if this environment variable is exported, Git uses it as long as GIT_EDITOR isn’t exported and core-editor isn’t set
  4. EDITOR: if this environment variable is exported, Git uses it as long as GIT_EDITOR isn’t exported, core-editor isn’t set, and VISUAL isn’t exported
  5. /usr/lib/git-core/editor: if this path exists, Git uses it as long as none of the above holds true
  6. /usr/local/sbin/editor: if this path exists, Git uses it as long as none of the above holds true
  7. /usr/local/bin/editor: if this path exists, Git uses it as long as none of the above holds true
  8. /usr/bin/editor: if this path exists, Git uses it as long as none of the above holds true

In each case with a variable or setting value, the system interprets the value, we can include more than just the executable path.

4. Git Sequence Editor Selection

For sequence file edits, Git provides another variable, but a similar selection procedure with a predefined precedence:

  1. GIT_SEQUENCE_EDITOR: if this environment variable is exported, Git uses its value as the sequence editor of choice, regardless of its validity or other settings
  2. sequence.editor: if this Git setting is configured locally or globally, Git uses it as long as GIT_SEQUENCE_EDITOR isn’t exported
  3. GIT_EDITOR: if this environment variable is exported, Git uses its value as the editor of choice, as long as GIT_SEQUENCE_EDITOR isn’t exported and sequence.editor isn’t set
  4. VISUAL: if this environment variable is exported, Git uses it as long as none of the above holds true
  5. EDITOR: if this environment variable is exported, Git uses it as long as none of the above holds true
  6. /usr/lib/git-core/editor: if this path exists, Git uses it as long as none of the above holds true
  7. /usr/local/sbin/editor: if this path exists, Git uses it as long as none of the above holds true
  8. /usr/local/bin/editor: if this path exists, Git uses it as long as none of the above holds true
  9. /usr/bin/editor: if this path exists, Git uses it as long as none of the above holds true

Thus, we can see the two editor choice procedures overlap after the initial two steps.

5. Git Editor Configuration

Now, let’s understand each way of configuring the editor settings.

Naturally, the specific values and variables we use depend on the selection, platform, and shell.

5.1. Configure Environment Variables

There are several ways to use for each of the possible environment variables that affect the core and sequence editors.

First, we can export a variable directly:

$ export GIT_EDITOR=nano

In this case, we select nano as the value of GIT_EDITOR and export it. The benefit of this approach comes down to the fact that it’s the middle ground between convenience and flexibility. In particular, it works for a given session but resets for others.

Alternatively, we can prefix a given command with the assignment of a respective variable:

$ VISUAL=emacs git commit

Here, VISUAL is emacs for a single command.

This approach isn’t possible with all shells and environments but works with Bash.

Lastly, if we want to prevent an environment variable value from affecting any commands, we should unset it:

$ unset GIT_EDITOR

Failing to do so can result in errors.

The specific way to export or unset a variable depends on the operating system (OS) and shell.

5.2. Git Configuration

One of the most common ways to set the Git sequence or core editor comes down to the repository configuration.

Usually, it’s easier to employ the config subcommand:

$ git config --global core.editor 'nano'

In this case, we [–global]ly set the core.editor to nano.

If we want to only configure the core editor for a specific repository, we run the command without the –global flag from the root of that repository.

Similarly, we can turn to the ~/.gitconfig or .git/config files and add the respective section and entry:

$ cat .git/config
[...]
[core]
  editor = nano
[sequence]
  editor = emacs

In this case, the settings of the local repository indicate that nano should be the core editor, while emacs steps in for sequence editing.

As usual, to unset a given store, we can add the –unset flag to the Git config subcommand:

$ git config --global --unset core.editor

Naturally, we can also remove entries from the respective configuration file.

5.3. Convenience Commands

On some Linux distributions, we can use convenience commands that set editor environment variables and paths globally.

For instance, Debian and Ubuntu offer the update-alternative command:

$ update-alternatives --config editor

Here, we run an interactive editor [–config]uration. After that, Git uses the editor we select if no Git-specific methods are in use.

Further, Ubuntu offers the select-editor shorthand.

5.4. Pitfalls

If we don’t use the correct command to unset a given value store where it looks for an editor, Git might attempt to interpret an empty string as the editor command, resulting in an error:

hint: Waiting for your editor to close the file... error: cannot run : No such file or directory
error: unable to start editor ''

Thus, the selection procedure ends without success.

In addition, some editors require the –wait switch to function correctly with Git:

$ export GIT_SEQUENCE_EDITOR='code --wait'

Here, we use the code Visual Studio Code editor, which provides –wait to synchronize the call from Git with the file argument that it provides. In addition, editors like Visual Studio Code may have Git-specific settings like git.useEditorAsCommitInput.

6. Summary

In this article, we talked about Git editor selection and configuration.

In conclusion, the editor in use depends on the specific operation and several Git and system settings.