5

If I want help on the git status command, I can enter git help status, and a help page is returned that says the name is "git-status". But "git-status" is not the command, the command is git status with a space, not a hyphen.

If I enter git-status or git git-status I get an error. So why does the help page call it git-status?

Git does this same thing with every command in the help pages. Why?

markg
  • 424
  • 3
  • 10

3 Answers3

4

Note that for in the beginning (2005-2008, Git 1.6.0), the git subcommands were referenced as git-xxx, in your $PATH.

See Git 1.6.0 release notes:

With the default Makefile settings, most of the programs are now installed outside your $PATH, except for "git", "gitk" and some server side programs that need to be accessible for technical reasons.

Invoking a git subcommand as "git-xyzzy" from the command line has been deprecated since early 2006 (and officially announced in 1.5.4 release notes).
Use of them from your scripts after adding output from "git --exec-path" to the $PATH is still supported in this release, but users are again strongly encouraged to adjust their scripts to use "git xyzzy" form, as we will stop installing "git-xyzzy" hardlinks for built-in commands in later releases.

This 2006 thread adds:

I think some historical background is in order.

We started without bindir vs execdir distinction but we wanted a way to someday migrate out of putting everything in bindir.
As > one part of the solution, "git" wrapper was invented, and as the result of that effort, some parts of the scripts, and lot of documentation pages and sample scripts, lost dashes.

Historically, git tools have always wanted everything git-* to be found on user's PATH, and we were alarmed to see 100+ git-* commands in /usr/bin.
That's why "git" wrapper and GIT_EXEC_PATH environment were invented.

People can have /usr/bin/git and no other git-* on their PATH, because that "git" knows where to find the rest of git-* commands.
For that to work, the scripts should know where to find the rest -- and cleanest way is to run others via "git foo" form.

Consistency via s/git-foo/git foo/g is the goal, but that kind of change interferes with the other patches that do the real work, and it is kind of boring, so nobody has done wholesale clean-up of all the scripts.


With Git 2.29 (Q4 2020), the installation procedure learned to optionally omit "git-foo" executable files for each 'foo' built-in subcommand, which are only required by old timers that still rely on the age old promise that prepending "git --exec-path" output to PATH early in their script will keep the "git-foo" calls they wrote working.

The old attempt to remove these executables from the disk failed in the 1.6 era; it may be worth attempting again later.

See commit ef60e9f, commit 179227d, commit a8b5355 (21 Sep 2020) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit 94de88c, 04 Oct 2020)

Git:Optionally skip linking/copying the built-ins

Signed-off-by: Johannes Schindelin

For a long time already, the non-dashed form of the built-ins is the recommended way to write scripts, i.e. it is better to call git merge [...](man) than to call git-merge [...].

While Git still supports the dashed form (by hard-linking the git executable to the dashed name in libexec/git-core/), in practice, it is probably almost irrelevant.

However, we do care about keeping people's scripts working (even if they were written before the non-dashed form started to be recommended).

Keeping this backwards-compatibility is not necessarily cheap, though: even so much as amending the tip commit in a git.git checkout will require re-linking all of those dashed commands.
On this developer's laptop, this makes a noticeable difference:

$ touch version.c && time make
    CC version.o
    AR libgit.a
    LINK git-bugreport.exe
    [... 11 similar lines ...]
    LN/CP git-remote-https.exe
    LN/CP git-remote-ftp.exe
    LN/CP git-remote-ftps.exe
    LINK git.exe
    BUILTIN git-add.exe
    [... 123 similar lines ...]
    BUILTIN all
    SUBDIR git-gui
    SUBDIR gitk-git
    SUBDIR templates
    LINK t/helper/test-fake-ssh.exe
    LINK t/helper/test-line-buffer.exe
    LINK t/helper/test-svn-fe.exe
    LINK t/helper/test-tool.exe



real    0m36.633s
user    0m3.794s
sys     0m14.141s



$ touch version.c && time make SKIP_DASHED_BUILT_INS=1
    CC version.o
    AR libgit.a
    LINK git-bugreport.exe
    [... 11 similar lines ...]
    LN/CP git-remote-https.exe
    LN/CP git-remote-ftp.exe
    LN/CP git-remote-ftps.exe
    LINK git.exe
    BUILTIN git-receive-pack.exe
    BUILTIN git-upload-archive.exe
    BUILTIN git-upload-pack.exe
    BUILTIN all
    SUBDIR git-gui
    SUBDIR gitk-git
    SUBDIR templates
    LINK t/helper/test-fake-ssh.exe
    LINK t/helper/test-line-buffer.exe
    LINK t/helper/test-svn-fe.exe
    LINK t/helper/test-tool.exe



real    0m23.717s
user    0m1.562s
sys     0m5.210s

Also, .zip files do not have any standardized support for hard-links, therefore "zipping up" the executables will result in inflated disk usage. (To keep down the size of the "MinGit" variant of Git for Windows, which is distributed as a .zip file, the hard-links are excluded specifically.)

In addition to that, some programs that are regularly used to assess disk usage fail to realize that those are hard-links, and heavily overcount disk usage.
Most notably, this was the case with Windows Explorer up until the last couple of Windows 10 versions. See e.g. msysgit/msysgit issue 58.

To save on the time needed to hard-link these dashed commands, with the plan to eventually stop shipping with those hard-links on Windows, let's introduce a Makefile knob to skip generating them.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • thanks for the thorough answer, that clears it up. A couple other answers were helpful too. – markg Apr 16 '17 at 01:02
2

Actually there is a command git-status and one for all the other git commands. You just don't have your PATH set to these commands because git is enough. In Windows for example you can find all the command executables here: C:\Program Files (x86)\Git\libexec\git-core. Git was developed in a very unix way with lots of simple commands that do one thing but do it right. This is still reflected in the help, maybe for historic reasons.

A Person
  • 1,062
  • 9
  • 17
  • 1
    Incidentally, `git --exec-path` *prints* the path where Git finds all its internal commands. This is particularly important when you have, for some reason, multiple different Git versions installed, or are developing Git itself (the "new" Git needs to run its new commands out of its development area, not run the old ones out of the installed area). – torek Apr 16 '17 at 00:16
  • 1
    This is great info. On Windows 7 my path is as you show above for all these dashed commands. On OSX I found them at `/Library/Developer/CommandLineTools/user/libexec/git-core`. – markg Apr 16 '17 at 01:05
2

The correct answer is "history".

Back in the Dim Time (2005ish), each Git command was a single thing:

$ git-init
[initialized new repository ...]
$ git-add Makefile README
$ git-status
...
$ git-commit

People who use bash command completion, though, would soon type git-TAB and get 47,981 obscure git commands such as git-block-area and git-hammer-branch (these are made up, but I hope bring the point across fairly well :-) ). It was time to divide things up into user oriented commands, called porcelain, and low-level commands used internally, called plumbing.

All the commands were renamed and Git added a single front-end command, git. For those using bash command completion, bash reads a "completions file", which lists only the user-oriented porcelain commands. So now gitTAB only lists 30 to 40 or so commands, instead of 100-plus.

All the documentation, however, retains the historic format.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775