When running 'git-receive-pack(1)', there is no way for the server to
intercept and modify the status report before it is sent back to the
client. Servers with custom logic may need to transform or gate the
report based on the outcome of external logic post reference updates.
This is specially needed for our usecase at GitLab where we have custom
MVCC logic on top of Git which creates a new version for each push
operation. The new version is only committed when certain external
operations post reference transaction succeed. So reporting the correct
message based on the outcome of these operations is important.
The outcome of these operations is only known after `execute_commands()`
has returned and before the report is written. There is no point in
receive-pack where the server can act on that.
We cannot use any of the existing hooks as:
- The pre-receive hook runs too early, as we haven't updated
references at that point yet and we need to have the full view of
all resulting updates (both objects and references).
- The update hook is too inefficient as it runs once per reference,
and we cannot trivially determine the last update.
- The reference-transaction hook is not suited for this. It fires from
within `ref_transaction_commit()`, which is before the outcome we
need to report is known, so there is no phase at which it could give
us the answer. It also does not contain any knowledge regarding the
push and cannot communicate with the clients.
- The proc-receive hook replaces execute_commands() for references
matching 'receive.procReceiveRefs'. We need to gate the report for
the push as a whole.
- The post-receive and post-update hooks cannot be used as they run
too late, at the point where we have already reported success to the
client.
Introduce a new 'receive-report' hook. The hook receives the complete
pkt-line encoded status report on standard input, after all ref updates
have been applied to the repository by execute_commands() but before the
report is sent to the client. See linkgit:gitprotocol-pack[5] details on
the protocol structure.
The hook's stdout fully replaces the report sent to the client.
receive-pack fully buffers the hook's stdout before acting on the exit
status, so the exit code is known before the client receives anything.
This gives two distinct behaviors depending on exit status:
- Exit 0: the hook's stdout is used as the report. The hook can
rewrite 'ok' lines to 'ng' lines to signal per-ref rejection to the
client while receive-pack itself exits cleanly. The client marks
rejected refs as '[remote rejected]' and exits with a non-zero
status if any ref is 'ng'.
- Non-zero exit: the hook's stdout is discarded, receive-pack modifies
all references to be rejected with a 'receive-report hook failed'
error.
In both cases, any output the hook writes to standard error is
forwarded to the client over the sideband channel and appears as
'remote:' lines on the client terminal. Writing to stderr alone does
not affect the push outcome.
Reference updates applied by execute_commands() are not rolled back in
either failure mode. The hook can cause the client to perceive the push
as failed, but cannot undo server-side changes. This creates a
divergence that the server cannot resolve: the client leaves its
remote-tracking reference at the old value while the update is in fact
applied, and a later fetch may reveal the update that the push reported
as rejected.
The hook is therefore only appropriate for servers which can guarantee
that a rejected update is not observable by any reader. In our case the
transaction committed by execute_commands() produces a candidate version
which is not visible to other readers and is only published once the
subsequent operations succeed, so a report of 'ng' corresponds to a
version that is discarded rather than published. On a repository where a
committed reference update is immediately visible, rejecting a push from
this hook would instead leave the pusher with a view that does not match
the server.
This hook does not use the config-based hook infrastructure, which
supports running multiple scripts per hook event. This hook is a
bidirectional filter: it receives the report on stdin and writes a
modified version to stdout. Running multiple such scripts sequentially
would require piping the output of one into the input of the next,
which the current hook infrastructure does not support. A single-script
design is therefore a natural fit, and is consistent with how
'proc-receive' is structured for the same reason.
Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
||
|---|---|---|
| .github | ||
| Documentation | ||
| bin-wrappers | ||
| block-sha1 | ||
| builtin | ||
| ci | ||
| compat | ||
| compiler-tricks | ||
| contrib | ||
| ewah | ||
| git-gui | ||
| gitk-git | ||
| gitweb | ||
| mergetools | ||
| negotiator | ||
| odb | ||
| oss-fuzz | ||
| perl | ||
| po | ||
| refs | ||
| reftable | ||
| sha1 | ||
| sha1collisiondetection@855827c583 | ||
| sha1dc | ||
| sha256 | ||
| src | ||
| subprojects | ||
| t | ||
| templates | ||
| tools | ||
| trace2 | ||
| xdiff | ||
| .b4-config | ||
| .b4-cover-template | ||
| .cirrus.yml | ||
| .clang-format | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| .gitmodules | ||
| .mailmap | ||
| .tsan-suppressions | ||
| CODE_OF_CONDUCT.md | ||
| COPYING | ||
| Cargo.toml | ||
| GIT-BUILD-OPTIONS.in | ||
| GIT-VERSION-FILE.in | ||
| GIT-VERSION-GEN | ||
| INSTALL | ||
| LGPL-2.1 | ||
| Makefile | ||
| README.md | ||
| RelNotes | ||
| SECURITY.md | ||
| abspath.c | ||
| abspath.h | ||
| aclocal.m4 | ||
| add-interactive.c | ||
| add-interactive.h | ||
| add-patch.c | ||
| add-patch.h | ||
| advice.c | ||
| advice.h | ||
| alias.c | ||
| alias.h | ||
| alloc.c | ||
| alloc.h | ||
| apply.c | ||
| apply.h | ||
| archive-tar.c | ||
| archive-zip.c | ||
| archive.c | ||
| archive.h | ||
| attr.c | ||
| attr.h | ||
| banned.h | ||
| base85.c | ||
| base85.h | ||
| bisect.c | ||
| bisect.h | ||
| blame.c | ||
| blame.h | ||
| blob.c | ||
| blob.h | ||
| bloom.c | ||
| bloom.h | ||
| branch.c | ||
| branch.h | ||
| build.rs | ||
| builtin.h | ||
| bundle-uri.c | ||
| bundle-uri.h | ||
| bundle.c | ||
| bundle.h | ||
| cache-tree.c | ||
| cache-tree.h | ||
| cbtree.c | ||
| cbtree.h | ||
| chdir-notify.c | ||
| chdir-notify.h | ||
| checkout.c | ||
| checkout.h | ||
| chunk-format.c | ||
| chunk-format.h | ||
| color.c | ||
| color.h | ||
| column.c | ||
| column.h | ||
| combine-diff.c | ||
| command-list.txt | ||
| commit-graph.c | ||
| commit-graph.h | ||
| commit-reach.c | ||
| commit-reach.h | ||
| commit-slab-decl.h | ||
| commit-slab-impl.h | ||
| commit-slab.h | ||
| commit.c | ||
| commit.h | ||
| common-exit.c | ||
| common-init.c | ||
| common-init.h | ||
| common-main.c | ||
| config.c | ||
| config.h | ||
| config.mak.dev | ||
| config.mak.in | ||
| config.mak.uname | ||
| configure.ac | ||
| connect.c | ||
| connect.h | ||
| connected.c | ||
| connected.h | ||
| convert.c | ||
| convert.h | ||
| copy.c | ||
| copy.h | ||
| credential.c | ||
| credential.h | ||
| csum-file.c | ||
| csum-file.h | ||
| ctype.c | ||
| daemon.c | ||
| date.c | ||
| date.h | ||
| decorate.c | ||
| decorate.h | ||
| delta-islands.c | ||
| delta-islands.h | ||
| delta.h | ||
| diagnose.c | ||
| diagnose.h | ||
| diff-delta.c | ||
| diff-lib.c | ||
| diff-merges.c | ||
| diff-merges.h | ||
| diff-no-index.c | ||
| diff.c | ||
| diff.h | ||
| diffcore-break.c | ||
| diffcore-delta.c | ||
| diffcore-order.c | ||
| diffcore-pickaxe.c | ||
| diffcore-rename.c | ||
| diffcore-rotate.c | ||
| diffcore.h | ||
| dir-iterator.c | ||
| dir-iterator.h | ||
| dir.c | ||
| dir.h | ||
| editor.c | ||
| editor.h | ||
| entry.c | ||
| entry.h | ||
| environment.c | ||
| environment.h | ||
| exec-cmd.c | ||
| exec-cmd.h | ||
| fetch-negotiator.c | ||
| fetch-negotiator.h | ||
| fetch-object-info.c | ||
| fetch-object-info.h | ||
| fetch-pack.c | ||
| fetch-pack.h | ||
| fmt-merge-msg.c | ||
| fmt-merge-msg.h | ||
| for-each-ref.h | ||
| fsck.c | ||
| fsck.h | ||
| fsmonitor--daemon.h | ||
| fsmonitor-ipc.c | ||
| fsmonitor-ipc.h | ||
| fsmonitor-ll.h | ||
| fsmonitor-path-utils.h | ||
| fsmonitor-settings.c | ||
| fsmonitor-settings.h | ||
| fsmonitor.c | ||
| fsmonitor.h | ||
| gettext.c | ||
| gettext.h | ||
| git-archimport.perl | ||
| git-compat-util.h | ||
| git-curl-compat.h | ||
| git-cvsexportcommit.perl | ||
| git-cvsimport.perl | ||
| git-cvsserver.perl | ||
| git-difftool--helper.sh | ||
| git-filter-branch.sh | ||
| git-instaweb.sh | ||
| git-merge-octopus.sh | ||
| git-merge-one-file.sh | ||
| git-merge-resolve.sh | ||
| git-mergetool--lib.sh | ||
| git-mergetool.sh | ||
| git-p4.py | ||
| git-quiltimport.sh | ||
| git-request-pull.sh | ||
| git-send-email.perl | ||
| git-sh-i18n.sh | ||
| git-sh-setup.sh | ||
| git-submodule.sh | ||
| git-svn.perl | ||
| git-web--browse.sh | ||
| git-zlib.c | ||
| git-zlib.h | ||
| git.c | ||
| git.rc.in | ||
| gpg-interface.c | ||
| gpg-interface.h | ||
| graph.c | ||
| graph.h | ||
| grep.c | ||
| grep.h | ||
| hash-lookup.c | ||
| hash-lookup.h | ||
| hash.c | ||
| hash.h | ||
| hashmap.c | ||
| hashmap.h | ||
| help.c | ||
| help.h | ||
| hex-ll.c | ||
| hex-ll.h | ||
| hex.c | ||
| hex.h | ||
| hook.c | ||
| hook.h | ||
| http-backend.c | ||
| http-fetch.c | ||
| http-push.c | ||
| http-walker.c | ||
| http.c | ||
| http.h | ||
| ident.c | ||
| ident.h | ||
| imap-send.c | ||
| iterator.h | ||
| json-writer.c | ||
| json-writer.h | ||
| khash.h | ||
| kwset.c | ||
| kwset.h | ||
| levenshtein.c | ||
| levenshtein.h | ||
| line-log.c | ||
| line-log.h | ||
| line-range.c | ||
| line-range.h | ||
| linear-assignment.c | ||
| linear-assignment.h | ||
| list-objects-filter-options.c | ||
| list-objects-filter-options.h | ||
| list-objects-filter.c | ||
| list-objects-filter.h | ||
| list-objects.c | ||
| list-objects.h | ||
| list.h | ||
| lockfile.c | ||
| lockfile.h | ||
| log-tree.c | ||
| log-tree.h | ||
| loose.c | ||
| loose.h | ||
| ls-refs.c | ||
| ls-refs.h | ||
| mailinfo.c | ||
| mailinfo.h | ||
| mailmap.c | ||
| mailmap.h | ||
| match-trees.c | ||
| match-trees.h | ||
| mem-pool.c | ||
| mem-pool.h | ||
| merge-blobs.c | ||
| merge-blobs.h | ||
| merge-ll.c | ||
| merge-ll.h | ||
| merge-ort-wrappers.c | ||
| merge-ort-wrappers.h | ||
| merge-ort.c | ||
| merge-ort.h | ||
| merge.c | ||
| merge.h | ||
| mergesort.h | ||
| meson.build | ||
| meson_options.txt | ||
| midx-write.c | ||
| midx.c | ||
| midx.h | ||
| name-hash.c | ||
| name-hash.h | ||
| notes-cache.c | ||
| notes-cache.h | ||
| notes-merge.c | ||
| notes-merge.h | ||
| notes-utils.c | ||
| notes-utils.h | ||
| notes.c | ||
| notes.h | ||
| object-file-convert.c | ||
| object-file-convert.h | ||
| object-file.c | ||
| object-file.h | ||
| object-name.c | ||
| object-name.h | ||
| object.c | ||
| object.h | ||
| odb.c | ||
| odb.h | ||
| oid-array.c | ||
| oid-array.h | ||
| oidmap.c | ||
| oidmap.h | ||
| oidset.c | ||
| oidset.h | ||
| oidtree.c | ||
| oidtree.h | ||
| pack-bitmap-write.c | ||
| pack-bitmap.c | ||
| pack-bitmap.h | ||
| pack-check.c | ||
| pack-mtimes.c | ||
| pack-mtimes.h | ||
| pack-objects.c | ||
| pack-objects.h | ||
| pack-refs.c | ||
| pack-refs.h | ||
| pack-revindex.c | ||
| pack-revindex.h | ||
| pack-write.c | ||
| pack.h | ||
| packfile-list.c | ||
| packfile-list.h | ||
| packfile.c | ||
| packfile.h | ||
| pager.c | ||
| pager.h | ||
| parallel-checkout.c | ||
| parallel-checkout.h | ||
| parse-options-cb.c | ||
| parse-options.c | ||
| parse-options.h | ||
| parse.c | ||
| parse.h | ||
| patch-delta.c | ||
| patch-ids.c | ||
| patch-ids.h | ||
| path-walk.c | ||
| path-walk.h | ||
| path.c | ||
| path.h | ||
| pathspec.c | ||
| pathspec.h | ||
| pkt-line.c | ||
| pkt-line.h | ||
| preload-index.c | ||
| preload-index.h | ||
| pretty.c | ||
| pretty.h | ||
| prio-queue.c | ||
| prio-queue.h | ||
| progress.c | ||
| progress.h | ||
| promisor-remote.c | ||
| promisor-remote.h | ||
| prompt.c | ||
| prompt.h | ||
| protocol-caps.c | ||
| protocol-caps.h | ||
| protocol.c | ||
| protocol.h | ||
| prune-packed.c | ||
| prune-packed.h | ||
| pseudo-merge.c | ||
| pseudo-merge.h | ||
| quote.c | ||
| quote.h | ||
| range-diff.c | ||
| range-diff.h | ||
| reachable.c | ||
| reachable.h | ||
| read-cache-ll.h | ||
| read-cache.c | ||
| read-cache.h | ||
| rebase-interactive.c | ||
| rebase-interactive.h | ||
| rebase.c | ||
| rebase.h | ||
| ref-filter.c | ||
| ref-filter.h | ||
| reflog-walk.c | ||
| reflog-walk.h | ||
| reflog.c | ||
| reflog.h | ||
| refs.c | ||
| refs.h | ||
| refspec.c | ||
| refspec.h | ||
| remote-curl.c | ||
| remote.c | ||
| remote.h | ||
| repack-cruft.c | ||
| repack-filtered.c | ||
| repack-geometry.c | ||
| repack-midx.c | ||
| repack-promisor.c | ||
| repack.c | ||
| repack.h | ||
| replace-object.c | ||
| replace-object.h | ||
| replay.c | ||
| replay.h | ||
| repo-settings.c | ||
| repo-settings.h | ||
| repository.c | ||
| repository.h | ||
| rerere.c | ||
| rerere.h | ||
| reset.c | ||
| reset.h | ||
| resolve-undo.c | ||
| resolve-undo.h | ||
| revision.c | ||
| revision.h | ||
| run-command.c | ||
| run-command.h | ||
| sane-ctype.h | ||
| scalar.c | ||
| send-pack.c | ||
| send-pack.h | ||
| sequencer.c | ||
| sequencer.h | ||
| serve.c | ||
| serve.h | ||
| server-info.c | ||
| server-info.h | ||
| setup.c | ||
| setup.h | ||
| sh-i18n--envsubst.c | ||
| sha1dc_git.c | ||
| sha1dc_git.h | ||
| shallow.c | ||
| shallow.h | ||
| shared.mak | ||
| shell.c | ||
| shortlog.h | ||
| sideband.c | ||
| sideband.h | ||
| sigchain.c | ||
| sigchain.h | ||
| simple-ipc.h | ||
| sparse-index.c | ||
| sparse-index.h | ||
| split-index.c | ||
| split-index.h | ||
| stable-qsort.c | ||
| statinfo.c | ||
| statinfo.h | ||
| strbuf.c | ||
| strbuf.h | ||
| string-list.c | ||
| string-list.h | ||
| strmap.c | ||
| strmap.h | ||
| strvec.c | ||
| strvec.h | ||
| sub-process.c | ||
| sub-process.h | ||
| submodule-config.c | ||
| submodule-config.h | ||
| submodule.c | ||
| submodule.h | ||
| symlinks.c | ||
| symlinks.h | ||
| tag.c | ||
| tag.h | ||
| tar.h | ||
| tempfile.c | ||
| tempfile.h | ||
| thread-utils.c | ||
| thread-utils.h | ||
| tmp-objdir.c | ||
| tmp-objdir.h | ||
| trace.c | ||
| trace.h | ||
| trace2.c | ||
| trace2.h | ||
| trailer.c | ||
| trailer.h | ||
| transport-helper.c | ||
| transport-internal.h | ||
| transport.c | ||
| transport.h | ||
| tree-diff.c | ||
| tree-walk.c | ||
| tree-walk.h | ||
| tree.c | ||
| tree.h | ||
| unicode-width.h | ||
| unimplemented.sh | ||
| unix-socket.c | ||
| unix-socket.h | ||
| unix-stream-server.c | ||
| unix-stream-server.h | ||
| unpack-trees.c | ||
| unpack-trees.h | ||
| upload-pack.c | ||
| upload-pack.h | ||
| url.c | ||
| url.h | ||
| urlmatch.c | ||
| urlmatch.h | ||
| usage.c | ||
| userdiff.c | ||
| userdiff.h | ||
| utf8.c | ||
| utf8.h | ||
| varint.c | ||
| varint.h | ||
| version-def.h.in | ||
| version.c | ||
| version.h | ||
| versioncmp.c | ||
| versioncmp.h | ||
| walker.c | ||
| walker.h | ||
| wildmatch.c | ||
| wildmatch.h | ||
| worktree.c | ||
| worktree.h | ||
| wrapper.c | ||
| wrapper.h | ||
| write-or-die.c | ||
| write-or-die.h | ||
| ws.c | ||
| ws.h | ||
| wt-status.c | ||
| wt-status.h | ||
| xdiff-interface.c | ||
| xdiff-interface.h | ||
README.md
Git - fast, scalable, distributed revision control system
Git is a fast, scalable, distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals.
Git is an Open Source project covered by the GNU General Public License version 2 (some parts of it are under different licenses, compatible with the GPLv2). It was originally written by Linus Torvalds with help of a group of hackers around the net.
Please read the file INSTALL for installation instructions.
Many Git online resources are accessible from https://git-scm.com/ including full documentation and Git related tools.
See Documentation/gittutorial.adoc to get started, then see
Documentation/giteveryday.adoc for a useful minimum set of commands, and
Documentation/git-<commandname>.adoc for documentation of each command.
If git has been correctly installed, then the tutorial can also be
read with man gittutorial or git help tutorial, and the
documentation of each command with man git-<commandname> or git help <commandname>.
CVS users may also want to read Documentation/gitcvs-migration.adoc
(man gitcvs-migration or git help cvs-migration if git is
installed).
The user discussion and development of Git take place on the Git mailing list -- everyone is welcome to post bug reports, feature requests, comments and patches to git@vger.kernel.org (read Documentation/SubmittingPatches for instructions on patch submission and Documentation/CodingGuidelines).
Those wishing to help with error message, usage and informational message
string translations (localization l10) should see po/README.md
(a po file is a Portable Object file that holds the translations).
To subscribe to the list, send an email to git+subscribe@vger.kernel.org (see https://subspace.kernel.org/subscribing.html for details). The mailing list archives are available at https://lore.kernel.org/git/, https://marc.info/?l=git and other archival sites.
Issues which are security relevant should be disclosed privately to the Git Security mailing list git-security@googlegroups.com.
The maintainer frequently sends the "What's cooking" reports that list the current status of various development topics to the mailing list. The discussion following them give a good reference for project status, development direction and remaining tasks.
The name "git" was given by Linus Torvalds when he wrote the very first version. He described the tool as "the stupid content tracker" and the name as (depending on your mood):
- random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of "get" may or may not be relevant.
- stupid. contemptible and despicable. simple. Take your pick from the dictionary of slang.
- "global information tracker": you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
- "goddamn idiotic truckload of sh*t": when it breaks