Volume XXII, number 279Tuesday, October 6, 2026Latest message 1 hour ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

pager: consider revisiting automatic LESS=FRX with custom core.pager

6 messages between Sep 19, 2026 and Oct 5, 2026, from Francisco Boni, brian m. carlson, Todd Zullinger.

Plain Markdown or JSON for tools and agents.

Francisco BoniSep 19, 2026, 12:19 UTC on lore
Hi,

I ran into a surprising interaction between Git's pager environment handling and a custom pager, and I think the longstanding automatic `LESS=FRX` behavior may be worth revisiting.

My setup is roughly:
```
[core]
    pager = delta
```
with delta eventually invoking `less`.
In my shell I had:

``` export PAGER="less" ```

but deliberately did not set `LESS`.
I also configured delta's pager explicitly as:

``` less --RAW-CONTROL-CHARS --quit-if-one-screen --quit-on-intr --ignore-case ```

What surprised me was that:

``` git diff <commit1> <commit2> ```

caused the downstream `less` process to behave as though `-X` / `--no-init` had been specified: it did not use the alternate screen, and in my terminal Page Up / Page Down also stopped behaving normally.

The `less` argv itself looked as expected and did not contain `-X`.
Eventually I tracked this down to Git setting:

``` LESS=FRX ```

when `LESS` is absent from the environment.
The particularly revealing test was:

``` LESS="" git diff <commit1> <commit2> ```

With that single change, the same delta -> less chain used the alternate screen normally and Page Up / Page Down worked again.

I understand that Git's default `LESS=FRX` behavior is old, documented, and presumably exists to provide useful defaults when Git directly invokes `less`.

What seems questionable to me is that it is also applied when `core.pager` is an arbitrary custom command.

In this case the effective chain is:

``` git -> delta -> less ```

Git is not invoking `less` itself, but the `LESS=FRX` value injected by Git is inherited by delta and then by the `less` process launched by delta. As a result, Git ends up silently configuring an implementation detail of a pager wrapper. A user who explicitly configures:

``` core.pager = delta ```

would not necessarily expect Git to alter environment variables specific to another pager that delta may or may not use internally.

There is also an unintuitive distinction between:

``` unset LESS ```

and:

``` LESS="" ```

The former causes Git to inject `FRX`, while the latter causes Git to leave the pager environment alone.

I realize simply removing the default could have substantial compatibility consequences given how longstanding this behavior is. But perhaps it would be worth considering whether the automatic `LESS` default should:

* apply only to Git's own default pager path;
* be suppressible explicitly through configuration; or
* otherwise avoid affecting arbitrary custom `core.pager` commands.
For my own setup, explicitly setting:

``` export LESS="--RAW-CONTROL-CHARS --quit-if-one-screen --quit-on-intr --ignore-case" ```

solves the issue cleanly, because Git then leaves `LESS` untouched.

So this is not primarily a request for a workaround; rather, I wanted to raise the broader behavior because the interaction with pager wrappers is quite surprising and difficult to diagnose.

Thanks, Francisco Boni

brian m. carlsonSep 19, 2026, 15:48 UTC in reply to Francisco Boni on lore

Re: pager: consider revisiting automatic LESS=FRX with custom core.pager

On 2026-09-19 at 12:19:40, Francisco Boni wrote:
> Hi,
Ney,
Show 14 quoted lines
> There is also an unintuitive distinction between:
> 
> ```
> unset LESS
> ```
> 
> and:
> 
> ```
> LESS=""
> ```
> 
> The former causes Git to inject `FRX`, while the latter causes Git to
> leave the pager environment alone.

Yes, that's because Git sets the environment iff it is unset. In the latter case, it is not unset: it is set to a zero-length value.

Show 8 quoted lines
> I realize simply removing the default could have substantial
> compatibility consequences given how longstanding this behavior is.
> But perhaps it would be worth considering whether the automatic `LESS`
> default should:
> 
> * apply only to Git's own default pager path
> * be suppressible explicitly through configuration; or
> * otherwise avoid affecting arbitrary custom `core.pager` commands.

We can't know in the general case whether the pager is less or not. On FreeBSD, `more` is less, for instance, and the pager command allows arbitrary shell commands, so determining statically which branch is taken is not always possible. Notably, Debian has `sensible-pager`, which is the default on that OS, and may (or may not) be less.

Users would be displeased if Git's pager functionality worked differently with less depending on how less was invoked or named, or if it weren't enabled in a case like the following:

    core.pager='f() { if [ "$(uname -s)" = FreeBSD ]; then more "$@"; else less "$@"; fi; };f'

A user might in fact do exactly that to make things work correctly on multiple platforms with a single gitconfig file. (This is why passing certain environment variables or options to the shell is obligatory and you cannot simply do shell parsing of the command.)

I agree that this can cause unusual behaviour in the case you've described, but that's more of the case because it's actually unusual to have commands that take arguments through the environment in this way. That's no longer really considered a good design; normally we use a config file instead these days.

I'll note that it is configurable both through the environment and through configuration, using one of the following:

    GIT_PAGER='LESS="" delta'
or:
    git config core.pager 'LESS="" delta'
or, if you prefer to be still more conservative:
    GIT_PAGER='env -i PATH="$PATH" delta'
which unsets all environment variables but the path for your pager.
> So this is not primarily a request for a workaround; rather, I wanted
> to raise the broader behavior because the interaction with pager
> wrappers is quite surprising and difficult to diagnose.

I think at this point, we're unlikely to change the behaviour and it would be a notable and unwelcome change to do so.

-- 
brian m. carlson (they/them)
Toronto, Ontario, CA
Todd ZullingerSep 19, 2026, 16:37 UTC in reply to brian m. carlson on lore

Re: pager: consider revisiting automatic LESS=FRX with custom core.pager

brian m. carlson wrote:
Show 27 quoted lines
> I agree that this can cause unusual behaviour in the case you've
> described, but that's more of the case because it's actually unusual to
> have commands that take arguments through the environment in this way.
> That's no longer really considered a good design; normally we use a
> config file instead these days.
> 
> I'll note that it is configurable both through the environment and
> through configuration, using one of the following:
> 
>     GIT_PAGER='LESS="" delta'
> 
> or:
> 
>     git config core.pager 'LESS="" delta'
> 
> or, if you prefer to be still more conservative:
> 
>     GIT_PAGER='env -i PATH="$PATH" delta'
> 
> which unsets all environment variables but the path for your pager.
> 
>> So this is not primarily a request for a workaround; rather, I wanted
>> to raise the broader behavior because the interaction with pager
>> wrappers is quite surprising and difficult to diagnose.
> 
> I think at this point, we're unlikely to change the behaviour and it
> would be a notable and unwelcome change to do so.

All good points. I wonder if it would help to add a couple of sentences to the core.pager documentation mentioning the method of setting `LESS=""` as another way to override the options? Something like:

  diff --git i/Documentation/config/core.adoc w/Documentation/config/core.adoc
  index 340329edc3..45e1fda2a2 100644
  --- i/Documentation/config/core.adoc
  +++ w/Documentation/config/core.adoc
  @@ -614,9 +614,15 @@ command to `LESS=FRX less -S`. The environment does not set the
   long lines. Similarly, setting `core.pager` to `less -+F` will
   deactivate the `F` option specified by the environment from the
   command-line, deactivating the "quit if one screen" behavior of
  -`less`.  One can specifically activate some flags for particular
  -commands: for example, setting `pager.blame` to `less -S` enables
  -line truncation only for `git blame`.
  +`less`. Another way to deactivate an option is setting `core.pager`
  +to `LESS="RX" less` or `LESS="" less` to override all options. The
  +second form is useful if the `core.pager` command eventually runs
  +`less` or a command which respects the `LESS` environment variable
  +but lacks command line options to override `LESS` options.
  ++
  +One can specifically activate some flags for particular commands: for
  +example, setting `pager.blame` to `less -S` enables line truncation
  +only for `git blame`.
   +
   Likewise, when the `LV` environment variable is unset, Git sets it
   to `-c`.  You can override this setting by exporting `LV` with

I don't know if that adds more value than the cost of increasing the verbiage of an already long document.

-- 
Todd
Francisco BoniSep 19, 2026, 16:52 UTC in reply to brian m. carlson on lore

Re: pager: consider revisiting automatic LESS=FRX with custom core.pager

On Sat, Sep 19, 2026 at 12:48 PM brian m. carlson <sandals@crustytoothpaste.net> wrote:

Show 38 quoted lines
>
> On 2026-09-19 at 12:19:40, Francisco Boni wrote:
> > Hi,
>
> Ney,
>
> > There is also an unintuitive distinction between:
> >
> > ```
> > unset LESS
> > ```
> >
> > and:
> >
> > ```
> > LESS=""
> > ```
> >
> > The former causes Git to inject `FRX`, while the latter causes Git to
> > leave the pager environment alone.
>
> Yes, that's because Git sets the environment iff it is unset.  In the
> latter case, it is not unset: it is set to a zero-length value.
>
> > I realize simply removing the default could have substantial
> > compatibility consequences given how longstanding this behavior is.
> > But perhaps it would be worth considering whether the automatic `LESS`
> > default should:
> >
> > * apply only to Git's own default pager path
> > * be suppressible explicitly through configuration; or
> > * otherwise avoid affecting arbitrary custom `core.pager` commands.
>
> We can't know in the general case whether the pager is less or not.  On
> FreeBSD, `more` is less, for instance, and the pager command allows
> arbitrary shell commands, so determining statically which branch is
> taken is not always possible.  Notably, Debian has `sensible-pager`,
> which is the default on that OS, and may (or may not) be less.
Hi Brian,

Thanks for the detailed explanation. The FreeBSD "more" case and the arbitrary-shell-command nature of core.pager clarified some assumptions I was making about how feasible it would be for Git to distinguish "direct less" from wrappers or dynamic pager selection...

That makes the compatibility argument much clearer. The suggested LESS="" delta override is useful to know about.

Also, thank you for your work on Git.

Best, Francisco Boni

Todd ZullingerOct 2, 2026, 23:41 UTC in reply to Todd Zullinger on lore

[PATCH] doc: add more examples of overriding LESS in core.pager

We set the LESS environment variable unconditionally which can surprise users of pagers which respect it but presume we'd only set LESS when `core.pager` calls less.

Provide examples of setting LESS in `core.pager` as an additional way to override the options we set in LESS.

Reported-by: Francisco Boni <boboniboni@gmail.com>
Signed-off-by: Todd Zullinger <tmz@pobox.com>
---
Now that 2.56.0 is out the door, I offer this up to see if
it feels like a useful improvement to the docs.

Cheers, Todd

 Documentation/config/core.adoc | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 0b697f53f1..bdc74d291c 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -621,9 +621,17 @@ command to `LESS=FRX less -S`. The environment does not set the
 long lines. Similarly, setting `core.pager` to `less -+F` will
 deactivate the `F` option specified by the environment from the
 command-line, deactivating the "quit if one screen" behavior of
-`less`.  One can specifically activate some flags for particular
-commands: for example, setting `pager.blame` to `less -S` enables
-line truncation only for `git blame`.
+`less`.
++
+Another way to deactivate an option is prefixing `core.pager` with
+`LESS="RX"` to remove `-F` or `LESS=""` to override all options.
+This is useful if the `core.pager` command eventually runs `less` or
+a command which respects the `LESS` environment variable but lacks
+command line options to override `LESS` options.
++
+One can specifically activate some flags for particular commands: for
+example, setting `pager.blame` to `less -S` enables line truncation
+only for `git blame`.
 +
 Likewise, when the `LV` environment variable is unset, Git sets it
 to `-c`.  You can override this setting by exporting `LV` with
-- 
2.56.0
brian m. carlsonOct 5, 2026, 23:59 UTC in reply to Todd Zullinger on lore

Re: [PATCH] doc: add more examples of overriding LESS in core.pager

On 2026-10-02 at 23:41:52, Todd Zullinger wrote:
Show 9 quoted lines
> +Another way to deactivate an option is prefixing `core.pager` with
> +`LESS="RX"` to remove `-F` or `LESS=""` to override all options.
> +This is useful if the `core.pager` command eventually runs `less` or
> +a command which respects the `LESS` environment variable but lacks
> +command line options to override `LESS` options.
> ++
> +One can specifically activate some flags for particular commands: for
> +example, setting `pager.blame` to `less -S` enables line truncation
> +only for `git blame`.

Sure, this seems like an improvement. I'm not very particular on the wording, but it's good that folks have the information that they need.

-- 
brian m. carlson (they/them)
Toronto, Ontario, CA

Back to recent threads