Why are there so many identical executables of git when compiled from source?
git
git-add
git-annotate
git-apply
git-archive
git-bisect--helper
git-blame
git-branch
git-bundle
git-cat-file
git-check-attr
git-checkout
git-checkout-index
git-check-ref-format
git-cherry
git-cherry-pick
git-clean
git-clone
git-commit
git-commit-tree
git-config
git-count-objects
git-describe
git-diff
git-diff-files
git-diff-index
git-diff-tree
git-fast-export
git-fetch
git-fetch-pack
git-fmt-merge-msg
git-for-each-ref
git-format-patch
git-fsck
git-fsck-objects
git-gc
git-get-tar-commit-id
git-grep
git-hash-object
git-help
git-index-pack
git-init
git-init-db
git-log
git-ls-files
git-ls-remote
git-ls-tree
git-mailinfo
git-mailsplit
git-merge
git-merge-base
git-merge-file
git-merge-index
git-merge-ours
git-merge-recursive
git-merge-subtree
git-merge-tree
git-mktag
git-mktree
git-mv
git-name-rev
git-notes
git-pack-objects
git-pack-redundant
git-pack-refs
git-patch-id
git-peek-remote
git-prune
git-prune-packed
git-push
git-read-tree
git-receive-pack
git-reflog
git-remote
git-remote-ext
git-remote-fd
git-replace
git-repo-config
git-rerere
git-reset
git-revert
git-rev-list
git-rev-parse
git-rm
git-send-pack
git-shortlog
git-show
git-show-branch
git-show-ref
git-stage
git-status
git-stripspace
git-symbolic-ref
git-tag
git-tar-tree
git-unpack-file
git-unpack-objects
git-update-index
git-update-ref
git-update-server-info
git-upload-archive
git-var
git-verify-pack
git-verify-tag
git-whatchanged
git-write-tree
All these targets are of the same size: 4951925
, and their contents are identical.Why?
[root@ git-1.7.6]$ ls -il /usr/bin/git*
17823222 lrwxrwxrwx 1 root root 22 2011-01-24 11:43 /usr/bin/git -> /usr/local/git/bin/git
17823223 lrwxrwxrwx 1 root root 32 2011-01-24 11:43 /usr/bin/git-cvsserver -> /usr/local/git/bin/git-cvsserver
17823224 lrwxrwxrwx 1 root root 23 2011-01-24 11:43 /usr/bin/gitk -> /usr/local/git/bin/gitk
17823225 lrwxrwxrwx 1 root root 35 2011-01-24 11:43 /usr/bin/git-receive-pack -> /usr/local/git/bin/git-receive-pack
17823226 lrwxrwxrwx 1 root root 28 2011-01-24 11:43 /usr/bin/git-shell -> /usr/local/git/bin/git-shell
17823227 lrwxrwxrwx 1 root root 37 2011-01-24 11:43 /usr/bin/git-upload-archive -> /usr/local/git/bin/git-upload-archive
17823228 lrwxrwxrwx 1 root root 34 2011-01-24 11:43 /usr/bin/git-upload-pack -> /usr/local/git/bin/git-upload-pack
[root@ git-1.7.6]$ ls -li /usr/local/git/bin/git*
126612251 -rwxr-xr-x 107 root root 4686039 2011-01-24 11:42 /usr/local/git/bin/git
126614976 -rwxr-xr-x 2 root root 120960 2011-01-24 11:42 /usr/local/git/bin/git-cvsserver
126614978 -rwxr-xr-x 1 root root 321995 2011-01-24 11:42 /usr/local/git/bin/gitk
126612开发者_运维百科251 -rwxr-xr-x 107 root root 4686039 2011-01-24 11:42 /usr/local/git/bin/git-receive-pack
126612255 -rwxr-xr-x 2 root root 1952607 2011-01-24 11:42 /usr/local/git/bin/git-shell
126612251 -rwxr-xr-x 107 root root 4686039 2011-01-24 11:42 /usr/local/git/bin/git-upload-archive
126612252 -rwxr-xr-x 2 root root 2001993 2011-01-24 11:42 /usr/local/git/bin/git-upload-pack
I think this is being done for backward compatibility since in earlier versions of git, each git subcommand was a separate executable ( for example git-commit
instead of git commit
)
In later versions they made them actual subcommands with the only real executable being git. The others may just be links to the git
executable.
Because the only real command is git
. The rest are either symbolically linked to git
itself, or (more likely) they're all hard linked.
When two files are hard linked together they reference one copy on disk, albeit with different names. File names are just pointers to a particular inode on disk, which is how Linux/Unix keeps track of what is stored where.
You can verify this by doing:
$ ls -il /usr/bin/git*
If they all share the same number in the first column, then they're all referencing the same inode. The number just after the permissions is the number of hard links to that single inode. The actual disk space for that executable (or any hardlinked file) is not let go until that count reaches zero (all references to it go away).
(BTW... if they're symbolically linked you'll see something like git-annotate -> git
which means that the name of git-annotate
references the name git
which is then resolved to the inode which contains (a pointer to) the data of the executable)
Git itself is one program which knows how to do many things based on how it is called. You can call either git annotate
or git-annotate
and they'll both will be interpreted by the one git
binary to do the annotate operation.
The reason this is done is just for your convenience, there's nothing that git
itself needs as you can always use the git<space>command
form of its invocation.
精彩评论