From: Junio C Hamano Date: Sun, 19 May 2019 07:45:33 +0000 (+0900) Subject: Merge branch 'es/check-non-portable-pre-5.10' X-Git-Tag: v2.22.0-rc1~10 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/dd5b7dc8ed2d02a693411aaae98f97d42c7a536c?hp=142997d4895b2b39ade3560da774f181f0131086 Merge branch 'es/check-non-portable-pre-5.10' Developer support update. * es/check-non-portable-pre-5.10: check-non-portable-shell: support Perl versions older than 5.10 --- diff --git a/Documentation/RelNotes/2.22.0.txt b/Documentation/RelNotes/2.22.0.txt index 776e15512b..114f147fd6 100644 --- a/Documentation/RelNotes/2.22.0.txt +++ b/Documentation/RelNotes/2.22.0.txt @@ -95,6 +95,10 @@ UI, Workflows & Features * "git clone" learned a new --server-option option when talking over the protocol version 2. + * The connectivity bitmaps are created by default in bare + repositories now; also the pathname hash-cache is created by + default to avoid making crappy deltas when repacking. + Performance, Internal Implementation, Development Support etc. @@ -158,6 +162,22 @@ Performance, Internal Implementation, Development Support etc. achieve better performance by batching the request for these promised blobs. + * During an initial "git clone --depth=..." partial clone, it is + pointless to spend cycles for a large portion of the connectivity + check that enumerates and skips promisor objects (which by + definition is all objects fetched from the other side). This has + been optimized out. + + * Mechanically and systematically drop "extern" from function + declarlation. + + * The script to aggregate perf result unconditionally depended on + libjson-perl even though it did not have to, which has been + corrected. + + * The internal implementation of "git rebase -i" has been updated to + avoid forking a separate "rebase--interactive" process. + Fixes since v2.21 ----------------- @@ -436,6 +456,24 @@ Fixes since v2.21 corrected. (merge b71e56a683 vk/autoconf-gettext later to maint). + * Fix index-pack perf test so that the repeated invocations always + run in an empty repository, which emulates the initial clone + situation better. + (merge 775c71e16d jk/p5302-avoid-collision-check-cost later to maint). + + * A "ls-files" that emulates "find" to enumerate files in the working + tree resulted in duplicated Makefile rules that caused the build to + issue an unnecessary warning during a trial build after merge + conflicts are resolved in working tree *.h files but before the + resolved results are added to the index. This has been corrected. + + * "git chery-pick" (and "revert" that shares the same runtime engine) + that deals with multiple commits got confused when the final step + gets stopped with a conflict and the user concluded the sequence + with "git commit". Attempt to fix it by cleaning up the state + files used by these commands in such a situation. + (merge 4a72486de9 pw/clean-sequencer-state-upon-final-commit later to maint). + * Code cleanup, docfix, build fix, etc. (merge 11f470aee7 jc/test-yes-doc later to maint). (merge 90503a240b js/doc-symref-in-proto-v1 later to maint). @@ -471,3 +509,4 @@ Fixes since v2.21 (merge dbe7b41019 js/t3301-unbreak-notes-test later to maint). (merge d8083e4180 km/t3000-retitle later to maint). (merge 9e4cbccbd7 tz/git-svn-doc-markup-fix later to maint). + (merge da9ca955a7 jk/ls-files-doc-markup-fix later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index d87846faa6..7e2a6f61f5 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -422,6 +422,8 @@ include::config/submodule.txt[] include::config/tag.txt[] +include::config/trace2.txt[] + include::config/transfer.txt[] include::config/uploadarchive.txt[] diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt index 425c73aa52..9cdcfa7324 100644 --- a/Documentation/config/pack.txt +++ b/Documentation/config/pack.txt @@ -124,6 +124,4 @@ pack.writeBitmapHashCache:: bitmapped and non-bitmapped objects (e.g., when serving a fetch between an older, bitmapped pack and objects that have been pushed since the last gc). The downside is that it consumes 4 - bytes per object of disk space, and that JGit's bitmap - implementation does not understand it, causing it to complain if - Git and JGit are used on the same repository. Defaults to false. + bytes per object of disk space. Defaults to true. diff --git a/Documentation/config/repack.txt b/Documentation/config/repack.txt index a5c37813fd..9c413e177e 100644 --- a/Documentation/config/repack.txt +++ b/Documentation/config/repack.txt @@ -24,4 +24,4 @@ repack.writeBitmaps:: packs created for clones and fetches, at the cost of some disk space and extra time spent on the initial repack. This has no effect if multiple packfiles are created. - Defaults to false. + Defaults to true on bare repos, false otherwise. diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.txt new file mode 100644 index 0000000000..a5f409c1c1 --- /dev/null +++ b/Documentation/config/trace2.txt @@ -0,0 +1,56 @@ +Trace2 config settings are only read from the system and global +config files; repository local and worktree config files and `-c` +command line arguments are not respected. + +trace2.normalTarget:: + This variable controls the normal target destination. + It may be overridden by the `GIT_TR2` environment variable. + The following table shows possible values. + +trace2.perfTarget:: + This variable controls the performance target destination. + It may be overridden by the `GIT_TR2_PERF` environment variable. + The following table shows possible values. + +trace2.eventTarget:: + This variable controls the event target destination. + It may be overridden by the `GIT_TR2_EVENT` environment variable. + The following table shows possible values. ++ +include::../trace2-target-values.txt[] + +trace2.normalBrief:: + Boolean. When true `time`, `filename`, and `line` fields are + omitted from normal output. May be overridden by the + `GIT_TR2_BRIEF` environment variable. Defaults to false. + +trace2.perfBrief:: + Boolean. When true `time`, `filename`, and `line` fields are + omitted from PERF output. May be overridden by the + `GIT_TR2_PERF_BRIEF` environment variable. Defaults to false. + +trace2.eventBrief:: + Boolean. When true `time`, `filename`, and `line` fields are + omitted from event output. May be overridden by the + `GIT_TR2_EVENT_BRIEF` environment variable. Defaults to false. + +trace2.eventNesting:: + Integer. Specifies desired depth of nested regions in the + event output. Regions deeper than this value will be + omitted. May be overridden by the `GIT_TR2_EVENT_NESTING` + environment variable. Defaults to 2. + +trace2.configParams:: + A comma-separated list of patterns of "important" config + settings that should be recorded in the trace2 output. + For example, `core.*,remote.*.url` would cause the trace2 + output to contain events listing each configured remote. + May be overridden by the `GIT_TR2_CONFIG_PARAMS` environment + variable. Unset by default. + +trace2.destinationDebug:: + Boolean. When true Git will print error messages when a + trace target destination cannot be opened for writing. + By default, these errors are suppressed and tracing is + silently disabled. May be overridden by the + `GIT_TR2_DST_DEBUG` environment variable. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 0cd87ddeff..6ebd512b4f 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -45,7 +45,11 @@ argument is missing it defaults to `HEAD` (i.e. the tip of the current branch). The command's second form creates a new branch head named -which points to the current `HEAD`, or if given. +which points to the current `HEAD`, or if given. As a +special case, for , you may use `"A...B"` as a shortcut for +the merge base of `A` and `B` if there is exactly one merge base. You +can leave out at most one of `A` and `B`, in which case it defaults to +`HEAD`. Note that this will create the new branch, but it will not switch the working tree to it; use "git checkout " to switch to the diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 877e5f503a..964f912d29 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -313,6 +313,10 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`. :: The name of a commit at which to start the new branch; see linkgit:git-branch[1] for details. Defaults to HEAD. ++ +As a special case, you may use `"A...B"` as a shortcut for the +merge base of `A` and `B` if there is exactly one merge base. You can +leave out at most one of `A` and `B`, in which case it defaults to `HEAD`. :: Tree to checkout from (when paths are given). If not specified, diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 96c26e6aa8..484c485fd0 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -90,7 +90,9 @@ instead. `--no-symlinks` is the default on Windows. When 'git-difftool' is invoked with the `-g` or `--gui` option the default diff tool will be read from the configured `diff.guitool` variable instead of `diff.tool`. The `--no-gui` - option can be used to override this setting. + option can be used to override this setting. If `diff.guitool` + is not set, we will fallback in the order of `merge.guitool`, + `diff.tool`, `merge.tool` until a tool is found. --[no-]trust-exit-code:: 'git-difftool' invokes a diff tool individually on each file. diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 5298f1bc30..8461c0e83e 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -118,6 +118,7 @@ OPTIONS linkgit:git-status[1] `--short` or linkgit:git-diff[1] `--name-status` for more user-friendly alternatives. + +-- This option identifies the file status with the following tags (followed by a space) at the start of each line: @@ -128,6 +129,7 @@ a space) at the start of each line: C:: modified/changed K:: to be killed ?:: other +-- -v:: Similar to `-t`, but use lowercase letters for files diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt index 055550b2bc..4da9d24096 100644 --- a/Documentation/git-mergetool--lib.txt +++ b/Documentation/git-mergetool--lib.txt @@ -28,7 +28,9 @@ to define the operation mode for the functions listed below. FUNCTIONS --------- get_merge_tool:: - returns a merge tool. + returns a merge tool. the return code is 1 if we returned a guessed + merge tool, else 0. '$GIT_MERGETOOL_GUI' may be set to 'true' to + search for the appropriate guitool. get_merge_tool_cmd:: returns the custom command for a merge tool. diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 0c7975a050..6b14702e78 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -83,7 +83,9 @@ success of the resolution after the custom tool has exited. --gui:: When 'git-mergetool' is invoked with the `-g` or `--gui` option the default merge tool will be read from the configured - `merge.guitool` variable instead of `merge.tool`. + `merge.guitool` variable instead of `merge.tool`. If + `merge.guitool` is not set, we will fallback to the tool + configured under `merge.tool`. --no-gui:: This overrides a previous `-g` or `--gui` setting and reads the diff --git a/Documentation/git.txt b/Documentation/git.txt index 6d1f2fd9ae..72adfcc5e2 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -660,6 +660,27 @@ of clones and fetches. When a curl trace is enabled (see `GIT_TRACE_CURL` above), do not dump data (that is, only dump info lines and headers). +`GIT_TR2`:: + Enables more detailed trace messages from the "trace2" library. + Output from `GIT_TR2` is a simple text-based format for human + readability. ++ +The `GIT_TR2` variables can take many values. Any value available to +the `GIT_TRACE` variables is also available to `GIT_TR2`. The `GIT_TR2` +variables can also specify a Unix Domain Socket. See +link:technical/api-trace2.html[Trace2 documentation] for full details. + +`GIT_TR2_EVENT`:: + This setting writes a JSON-based format that is suited for machine + interpretation. See link:technical/api-trace2.html[Trace2 documentation] + for full details. + +`GIT_TR2_PERF`:: + In addition to the text-based messages available in `GIT_TR2`, this + setting writes a column-based format for understanding nesting + regions. See link:technical/api-trace2.html[Trace2 documentation] + for full details. + `GIT_REDACT_COOKIES`:: This can be set to a comma-separated list of strings. When a curl trace is enabled (see `GIT_TRACE_CURL` above), whenever a "Cookies:" header diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index 2337a995ec..82c1e5754e 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -65,7 +65,7 @@ some output processing may assume ref names in UTF-8. '@':: '@' alone is a shortcut for `HEAD`. -'@{}', e.g. 'master@\{yesterday\}', 'HEAD@{5 minutes ago}':: +'[]@{}', e.g. 'master@\{yesterday\}', 'HEAD@{5 minutes ago}':: A ref followed by the suffix '@' with a date specification enclosed in a brace pair (e.g. '\{yesterday\}', '{1 month 2 weeks 3 days 1 hour 1 @@ -95,7 +95,7 @@ some output processing may assume ref names in UTF-8. The construct '@{-}' means the th branch/commit checked out before the current one. -'@\{upstream\}', e.g. 'master@\{upstream\}', '@\{u\}':: +'[]@\{upstream\}', e.g. 'master@\{upstream\}', '@\{u\}':: The suffix '@\{upstream\}' to a branchname (short form '@\{u\}') refers to the branch that the branch specified by branchname is set to build on top of (configured with `branch..remote` and @@ -103,7 +103,7 @@ some output processing may assume ref names in UTF-8. current one. These suffixes are also accepted when spelled in uppercase, and they mean the same thing no matter the case. -'@\{push\}', e.g. 'master@\{push\}', '@\{push\}':: +'[]@\{push\}', e.g. 'master@\{push\}', '@\{push\}':: The suffix '@\{push}' reports the branch "where we would push to" if `git push` were run while `branchname` was checked out (or the current `HEAD` if no branchname is specified). Since our push destination is @@ -131,7 +131,7 @@ from one location and push to another. In a non-triangular workflow, This suffix is also accepted when spelled in uppercase, and means the same thing no matter the case. -'{caret}', e.g. 'HEAD{caret}, v1.5.1{caret}0':: +'{caret}[]', e.g. 'HEAD{caret}, v1.5.1{caret}0':: A suffix '{caret}' to a revision parameter means the first parent of that commit object. '{caret}' means the th parent (i.e. '{caret}' @@ -139,7 +139,9 @@ thing no matter the case. '{caret}0' means the commit itself and is used when '' is the object name of a tag object that refers to a commit object. -'{tilde}', e.g. 'master{tilde}3':: +'{tilde}[]', e.g. 'HEAD{tilde}, master{tilde}3':: + A suffix '{tilde}' to a revision parameter means the first parent of + that commit object. A suffix '{tilde}' to a revision parameter means the commit object that is the th generation ancestor of the named commit object, following only the first parents. I.e. '{tilde}3' is @@ -159,12 +161,12 @@ thing no matter the case. '{caret}0' is a short-hand for '{caret}\{commit\}'. + -'rev{caret}\{object\}' can be used to make sure 'rev' names an -object that exists, without requiring 'rev' to be a tag, and -without dereferencing 'rev'; because a tag is already an object, +'{caret}\{object\}' can be used to make sure '' names an +object that exists, without requiring '' to be a tag, and +without dereferencing ''; because a tag is already an object, it does not have to be dereferenced even once to get to an object. + -'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an +'{caret}\{tag\}' can be used to ensure that '' identifies an existing tag object. '{caret}{}', e.g. 'v0.99.8{caret}{}':: @@ -194,19 +196,16 @@ existing tag object. Depending on the given text, the shell's word splitting rules might require additional quoting. -':', e.g. 'HEAD:README', ':README', 'master:./README':: +':', e.g. 'HEAD:README', 'master:./README':: A suffix ':' followed by a path names the blob or tree at the given path in the tree-ish object named by the part before the colon. - ':path' (with an empty part before the colon) - is a special case of the syntax described next: content - recorded in the index at the given path. A path starting with './' or '../' is relative to the current working directory. The given path will be converted to be relative to the working tree's root directory. This is most useful to address a blob or tree from a commit or tree that has the same tree structure as the working tree. -'::', e.g. ':0:README', ':README':: +':[:]', e.g. ':0:README', ':README':: A colon, optionally followed by a stage number (0 to 3) and a colon, followed by a path, names a blob object in the index at the given path. A missing stage number (and the colon @@ -302,7 +301,7 @@ The 'r1{caret}@' notation means all parents of 'r1'. The 'r1{caret}!' notation includes commit 'r1' but excludes all of its parents. By itself, this notation denotes the single commit 'r1'. -The '{caret}-' notation includes '' but excludes the th +The '{caret}-[]' notation includes '' but excludes the th parent (i.e. a shorthand for '{caret}..'), with '' = 1 if not given. This is typically useful for merge commits where you can just pass '{caret}-' to get all the commits in the branch diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt index d0948ba250..9e585b8e79 100644 --- a/Documentation/technical/api-trace2.txt +++ b/Documentation/technical/api-trace2.txt @@ -22,21 +22,41 @@ Targets are defined using a VTable allowing easy extension to other formats in the future. This might be used to define a binary format, for example. +Trace2 is controlled using `trace2.*` config values in the system and +global config files and `GIT_TR2*` environment variables. Trace2 does +not read from repo local or worktree config files or respect `-c` +command line config settings. + == Trace2 Targets Trace2 defines the following set of Trace2 Targets. Format details are given in a later section. -`GIT_TR2` (NORMAL):: +=== The Normal Format Target + +The normal format target is a tradition printf format and similar +to GIT_TRACE format. This format is enabled with the `GIT_TR` +environment variable or the `trace2.normalTarget` system or global +config setting. + +For example - a simple printf format like GIT_TRACE. -+ ------------ $ export GIT_TR2=~/log.normal $ git version git version 2.20.1.155.g426c96fcdb ------------ -+ + +or + +------------ +$ git config --global trace2.normalTarget ~/log.normal +$ git version +git version 2.20.1.155.g426c96fcdb +------------ + +yields + ------------ $ cat ~/log.normal 12:28:42.620009 common-main.c:38 version 2.20.1.155.g426c96fcdb @@ -46,81 +66,86 @@ $ cat ~/log.normal 12:28:42.621250 trace2/tr2_tgt_normal.c:124 atexit elapsed:0.001265 code:0 ------------ -`GIT_TR2_PERF` (PERF):: +=== The Performance Format Target + +The performance format target (PERF) is a column-based format to +replace GIT_TRACE_PERFORMANCE and is suitable for development and +testing, possibly to complement tools like gprof. This format is +enabled with the `GIT_TR2_PERF` environment variable or the +`trace2.perfTarget` system or global config setting. + +For example - a column-based format to replace GIT_TRACE_PERFORMANCE suitable for - development and testing, possibly to complement tools like gprof. -+ ------------ $ export GIT_TR2_PERF=~/log.perf $ git version git version 2.20.1.155.g426c96fcdb ------------ -+ + +or + +------------ +$ git config --global trace2.perfTarget ~/log.perf +$ git version +git version 2.20.1.155.g426c96fcdb +------------ + +yields + ------------ $ cat ~/log.perf 12:28:42.620675 common-main.c:38 | d0 | main | version | | | | | 2.20.1.155.g426c96fcdb -12:28:42.621001 common-main.c:39 | d0 | main | start | | | | | git version +12:28:42.621001 common-main.c:39 | d0 | main | start | | 0.001173 | | | git version 12:28:42.621111 git.c:432 | d0 | main | cmd_name | | | | | version (version) 12:28:42.621225 git.c:662 | d0 | main | exit | | 0.001227 | | | code:0 12:28:42.621259 trace2/tr2_tgt_perf.c:211 | d0 | main | atexit | | 0.001265 | | | code:0 ------------ -`GIT_TR2_EVENT` (EVENT):: +=== The Event Format Target + +The event format target is a JSON-based format of event data suitable +for telemetry analysis. This format is enabled with the `GIT_TR2_EVENT` +environment variable or the `trace2.eventTarget` system or global config +setting. + +For example - a JSON-based format of event data suitable for telemetry analysis. -+ ------------ $ export GIT_TR2_EVENT=~/log.event $ git version git version 2.20.1.155.g426c96fcdb ------------ -+ ------------- -$ cat ~/log.event -{"event":"version","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.620713","file":"common-main.c","line":38,"evt":"1","exe":"2.20.1.155.g426c96fcdb"} -{"event":"start","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621027","file":"common-main.c","line":39,"argv":["git","version"]} -{"event":"cmd_name","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621122","file":"git.c","line":432,"name":"version","hierarchy":"version"} -{"event":"exit","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621236","file":"git.c","line":662,"t_abs":0.001227,"code":0} -{"event":"atexit","sid":"1547659722619736-11614","thread":"main","time":"2019-01-16 17:28:42.621268","file":"trace2/tr2_tgt_event.c","line":163,"t_abs":0.001265,"code":0} ------------- - -== Enabling a Target -A Trace2 Target is enabled when the corresponding environment variable -(`GIT_TR2`, `GIT_TR2_PERF`, or `GIT_TR2_EVENT`) is set. The following -values are recognized. +or -`0`:: -`false`:: - - Disables the target. - -`1`:: -`true`:: - - Enables the target and writes stream to `STDERR`. - -`[2-9]`:: +------------ +$ git config --global trace2.eventTarget ~/log.event +$ git version +git version 2.20.1.155.g426c96fcdb +------------ - Enables the target and writes to the already opened file descriptor. +yields -``:: +------------ +$ cat ~/log.event +{"event":"version","sid":"sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"1","exe":"2.20.1.155.g426c96fcdb"} +{"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]} +{"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"} +{"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0} +{"event":"atexit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621268Z","file":"trace2/tr2_tgt_event.c","line":163,"t_abs":0.001265,"code":0} +------------ - Enables the target, opens and writes to the file in append mode. +=== Enabling a Target - If the target already exists and is a directory, the traces will be - written to files (one per process) underneath the given directory. They - will be named according to the last component of the SID (optionally - followed by a counter to avoid filename collisions). +To enable a target, set the corresponding environment variable or +system or global config value to one of the following: -`af_unix:[:]`:: +include::../trace2-target-values.txt[] - Enables the target, opens and writes to a Unix Domain Socket - (on platforms that support them). -+ -Socket type can be either `stream` or `dgram`. If the socket type is -omitted, Git will try both. +If the target already exists and is a directory, the traces will be +written to files (one per process) underneath the given directory. They +will be named according to the last component of the SID (optionally +followed by a counter to avoid filename collisions). == Trace2 API @@ -165,17 +190,23 @@ purposes. These are concerned with the lifetime of the overall git process. +`void trace2_initialize_clock()`:: + + Initialize the Trace2 start clock and nothing else. This should + be called at the very top of main() to capture the process start + time and reduce startup order dependencies. + `void trace2_initialize()`:: Determines if any Trace2 Targets should be enabled and - initializes the Trace2 facility. This includes starting the - elapsed time clocks and thread local storage (TLS). + initializes the Trace2 facility. This includes setting up the + Trace2 thread local storage (TLS). + This function emits a "version" message containing the version of git and the Trace2 protocol. + This function should be called from `main()` as early as possible in -the life of the process. +the life of the process after essential process initialization. `int trace2_is_enabled()`:: @@ -242,15 +273,16 @@ significantly affects program performance or behavior, such as Emits a "def_param" messages for "important" configuration settings. + -The environment variable `GIT_TR2_CONFIG_PARAMS` can be set to a +The environment variable `GIT_TR2_CONFIG_PARAMS` or the `trace2.configParams` +config value can be set to a list of patterns of important configuration settings, for example: `core.*,remote.*.url`. This function will iterate over all config settings and emit a "def_param" message for each match. `void trace2_cmd_set_config(const char *key, const char *value)`:: - Emits a "def_param" message for a specific configuration - setting IFF it matches the `GIT_TR2_CONFIG_PARAMS` pattern. + Emits a "def_param" message for a new or updated key/value + pair IF `key` is considered important. + This is used to hook into `git_config_set()` and catch any configuration changes and update a value previously reported by @@ -417,9 +449,6 @@ recursive tree walk. === NORMAL Format -NORMAL format is enabled when the `GIT_TR2` environment variable is -set. - Events are written as lines of the form: ------------ @@ -436,8 +465,8 @@ Events are written as lines of the form: Note that this may contain embedded LF or CRLF characters that are not escaped, so the event may spill across multiple lines. -If `GIT_TR2_BRIEF` is true, the `time`, `filename`, and `line` fields -are omitted. +If `GIT_TR2_BRIEF` or `trace2.normalBrief` is true, the `time`, `filename`, +and `line` fields are omitted. This target is intended to be more of a summary (like GIT_TRACE) and less detailed than the other targets. It ignores thread, region, and @@ -445,9 +474,6 @@ data messages, for example. === PERF Format -PERF format is enabled when the `GIT_TR2_PERF` environment variable -is set. - Events are written as lines of the form: ------------ @@ -507,8 +533,8 @@ This field is in anticipation of in-proc submodules in the future. 15:33:33.532712 wt-status.c:2331 | d0 | main | region_leave | r1 | 0.127568 | 0.001504 | status | label:print ------------ -If `GIT_TR2_PERF_BRIEF` is true, the `time`, `file`, and `line` -fields are omitted. +If `GIT_TR2_PERF_BRIEF` or `trace2.perfBrief` is true, the `time`, `file`, +and `line` fields are omitted. ------------ d0 | main | region_leave | r1 | 0.011717 | 0.009122 | index | label:preload @@ -519,9 +545,6 @@ during development and is quite noisy. === EVENT Format -EVENT format is enabled when the `GIT_TR2_EVENT` environment -variable is set. - Each event is a JSON-object containing multiple key/value pairs written as a single line and followed by a LF. @@ -539,11 +562,11 @@ The following key/value pairs are common to all events: ------------ { "event":"version", - "sid":"1547659722619736-11614", + "sid":"20190408T191827.272759Z-H9b68c35f-P00003510", "thread":"main", - "time":"2019-01-16 17:28:42.620713", + "time":"2019-04-08T19:18:27.282761Z", "file":"common-main.c", - "line":38, + "line":42, ... } ------------ @@ -575,9 +598,9 @@ The following key/value pairs are common to all events: `"repo":`:: when present, is the integer repo-id as described previously. -If `GIT_TR2_EVENT_BRIEF` is true, the `file` and `line` fields are omitted -from all events and the `time` field is only present on the "start" and -"atexit" events. +If `GIT_TR2_EVENT_BRIEF` or `trace2.eventBrief` is true, the `file` +and `line` fields are omitted from all events and the `time` field is +only present on the "start" and "atexit" events. ==== Event-Specific Key/Value Pairs @@ -600,6 +623,7 @@ from all events and the `time` field is only present on the "start" and { "event":"start", ... + "t_abs":0.001227, # elapsed time in seconds "argv":["git","version"] } ------------ @@ -887,7 +911,7 @@ visited. The `category` field may be used in a future enhancement to do category-based filtering. + -The `GIT_TR2_EVENT_NESTING` environment variable can be used to +`GIT_TR2_EVENT_NESTING` or `trace2.eventNesting` can be used to filter deeply nested regions and data events. It defaults to "2". `"region_leave"`:: @@ -1117,7 +1141,7 @@ $ git status $ cat ~/log.perf d0 | main | version | | | | | 2.20.1.160.g5676107ecd.dirty -d0 | main | start | | | | | git status +d0 | main | start | | 0.001173 | | | git status d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw d0 | main | cmd_name | | | | | status (status) ... @@ -1162,7 +1186,7 @@ $ git status ... $ cat ~/log.perf d0 | main | version | | | | | 2.20.1.162.gb4ccea44db.dirty -d0 | main | start | | | | | git status +d0 | main | start | | 0.001173 | | | git status d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw d0 | main | cmd_name | | | | | status (status) ... @@ -1218,7 +1242,7 @@ $ git status ... $ cat ~/log.perf d0 | main | version | | | | | 2.20.1.156.gf9916ae094.dirty -d0 | main | start | | | | | git status +d0 | main | start | | 0.001173 | | | git status d0 | main | def_repo | r1 | | | | worktree:/Users/jeffhost/work/gfw d0 | main | cmd_name | | | | | status (status) d0 | main | region_enter | r1 | 0.001791 | | index | label:do_read_index .git/index diff --git a/Documentation/trace2-target-values.txt b/Documentation/trace2-target-values.txt new file mode 100644 index 0000000000..27d3c64e66 --- /dev/null +++ b/Documentation/trace2-target-values.txt @@ -0,0 +1,10 @@ +-- +* `0` or `false` - Disables the target. +* `1` or `true` - Writes to `STDERR`. +* `[2-9]` - Writes to the already opened file descriptor. +* `` - Writes to the file in append mode. +* `af_unix:[:]` - Write to a +Unix DomainSocket (on platforms that support them). Socket +type can be either `stream` or `dgram`; if omitted Git will +try both. +-- diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 3fc4065da2..8a5009caf9 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.21.GIT +DEF_VER=v2.22.0-rc0 LF=' ' diff --git a/Makefile b/Makefile index 5143cab9bd..8a7e235352 100644 --- a/Makefile +++ b/Makefile @@ -439,6 +439,9 @@ all:: # # Define FILENO_IS_A_MACRO if fileno() is a macro, not a real function. # +# Define NEED_ACCESS_ROOT_HANDLER if access() under root may success for X_OK +# even if execution permission isn't granted for any user. +# # Define PAGER_ENV to a SP separated VAR=VAL pairs to define # default environment variables to be passed when a pager is spawned, e.g. # @@ -817,12 +820,12 @@ VCSSVN_LIB = vcs-svn/lib.a GENERATED_H += command-list.h -LIB_H := $(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \ +LIB_H := $(sort $(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \ $(FIND) . \ -name .git -prune -o \ -name t -prune -o \ -name Documentation -prune -o \ - -name '*.h' -print) + -name '*.h' -print)) LIB_OBJS += abspath.o LIB_OBJS += advice.o @@ -999,6 +1002,7 @@ LIB_OBJS += trace2/tr2_cfg.o LIB_OBJS += trace2/tr2_cmd_name.o LIB_OBJS += trace2/tr2_dst.o LIB_OBJS += trace2/tr2_sid.o +LIB_OBJS += trace2/tr2_sysenv.o LIB_OBJS += trace2/tr2_tbuf.o LIB_OBJS += trace2/tr2_tgt_event.o LIB_OBJS += trace2/tr2_tgt_normal.o @@ -1105,7 +1109,6 @@ BUILTIN_OBJS += builtin/push.o BUILTIN_OBJS += builtin/range-diff.o BUILTIN_OBJS += builtin/read-tree.o BUILTIN_OBJS += builtin/rebase.o -BUILTIN_OBJS += builtin/rebase--interactive.o BUILTIN_OBJS += builtin/receive-pack.o BUILTIN_OBJS += builtin/reflog.o BUILTIN_OBJS += builtin/remote.o @@ -1168,8 +1171,11 @@ PTHREAD_CFLAGS = SPARSE_FLAGS ?= SP_EXTRA_FLAGS = -# For the 'coccicheck' target +# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will +# usually result in less CPU usage at the cost of higher peak memory. +# Setting it to 0 will feed all files in a single spatch invocation. SPATCH_FLAGS = --all-includes --patch . +SPATCH_BATCH_SIZE = 1 include config.mak.uname -include config.mak.autogen @@ -1833,6 +1839,11 @@ ifdef FILENO_IS_A_MACRO COMPAT_OBJS += compat/fileno.o endif +ifdef NEED_ACCESS_ROOT_HANDLER + COMPAT_CFLAGS += -DNEED_ACCESS_ROOT_HANDLER + COMPAT_OBJS += compat/access.o +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK = NoThanks endif @@ -2799,12 +2810,14 @@ endif %.cocci.patch: %.cocci $(COCCI_SOURCES) @echo ' ' SPATCH $<; \ - ret=0; \ - for f in $(COCCI_SOURCES); do \ - $(SPATCH) --sp-file $< $$f $(SPATCH_FLAGS) || \ - { ret=$$?; break; }; \ - done >$@+ 2>$@.log; \ - if test $$ret != 0; \ + if test $(SPATCH_BATCH_SIZE) = 0; then \ + limit=; \ + else \ + limit='-n $(SPATCH_BATCH_SIZE)'; \ + fi; \ + if ! echo $(COCCI_SOURCES) | xargs $$limit \ + $(SPATCH) --sp-file $< $(SPATCH_FLAGS) \ + >$@+ 2>$@.log; \ then \ cat $@.log; \ exit 1; \ diff --git a/advice.h b/advice.h index cb5d361614..e50f02cdfe 100644 --- a/advice.h +++ b/advice.h @@ -32,7 +32,7 @@ int git_default_advice_config(const char *var, const char *value); __attribute__((format (printf, 1, 2))) void advise(const char *advice, ...); int error_resolve_conflict(const char *me); -extern void NORETURN die_resolve_conflict(const char *me); +void NORETURN die_resolve_conflict(const char *me); void NORETURN die_conclude_merge(void); void detach_advice(const char *new_name); diff --git a/archive.h b/archive.h index dd022a6b46..e60e3dd31c 100644 --- a/archive.h +++ b/archive.h @@ -23,9 +23,9 @@ struct archiver_args { /* main api */ -extern int write_archive(int argc, const char **argv, const char *prefix, - struct repository *repo, - const char *name_hint, int remote); +int write_archive(int argc, const char **argv, const char *prefix, + struct repository *repo, + const char *name_hint, int remote); const char *archive_format_from_filename(const char *filename); @@ -39,21 +39,21 @@ struct archiver { unsigned flags; void *data; }; -extern void register_archiver(struct archiver *); +void register_archiver(struct archiver *); -extern void init_tar_archiver(void); -extern void init_zip_archiver(void); -extern void init_archivers(void); +void init_tar_archiver(void); +void init_zip_archiver(void); +void init_archivers(void); typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const struct object_id *oid, const char *path, size_t pathlen, unsigned int mode); -extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry); -extern void *object_file_to_archive(const struct archiver_args *args, - const char *path, const struct object_id *oid, - unsigned int mode, enum object_type *type, - unsigned long *sizep); +int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry); +void *object_file_to_archive(const struct archiver_args *args, + const char *path, const struct object_id *oid, + unsigned int mode, enum object_type *type, + unsigned long *sizep); #endif /* ARCHIVE_H */ diff --git a/bisect.h b/bisect.h index 821d16e4dd..4e69a11ea8 100644 --- a/bisect.h +++ b/bisect.h @@ -11,14 +11,14 @@ struct repository; * Otherwise, it will be either all non-SAMETREE commits or the single * best commit, as chosen by `find_all`. */ -extern void find_bisection(struct commit_list **list, int *reaches, int *all, - int find_all); +void find_bisection(struct commit_list **list, int *reaches, int *all, + int find_all); -extern struct commit_list *filter_skipped(struct commit_list *list, - struct commit_list **tried, - int show_all, - int *count, - int *skipped_first); +struct commit_list *filter_skipped(struct commit_list *list, + struct commit_list **tried, + int show_all, + int *count, + int *skipped_first); #define BISECT_SHOW_ALL (1<<0) #define REV_LIST_QUIET (1<<1) @@ -31,14 +31,14 @@ struct rev_list_info { const char *header_prefix; }; -extern int bisect_next_all(struct repository *r, - const char *prefix, - int no_checkout); +int bisect_next_all(struct repository *r, + const char *prefix, + int no_checkout); -extern int estimate_bisect_steps(int all); +int estimate_bisect_steps(int all); -extern void read_bisect_terms(const char **bad, const char **good); +void read_bisect_terms(const char **bad, const char **good); -extern int bisect_clean_state(void); +int bisect_clean_state(void); #endif diff --git a/blame.h b/blame.h index 2a285eb027..d62f80fa74 100644 --- a/blame.h +++ b/blame.h @@ -177,6 +177,6 @@ struct blame_entry *blame_entry_prepend(struct blame_entry *head, long start, long end, struct blame_origin *o); -extern struct blame_origin *get_blame_suspects(struct commit *commit); +struct blame_origin *get_blame_suspects(struct commit *commit); #endif /* BLAME_H */ diff --git a/branch.c b/branch.c index 28b81a7e02..a594cc23e2 100644 --- a/branch.c +++ b/branch.c @@ -5,6 +5,7 @@ #include "refs.h" #include "refspec.h" #include "remote.h" +#include "sequencer.h" #include "commit.h" #include "worktree.h" @@ -268,7 +269,7 @@ void create_branch(struct repository *r, } real_ref = NULL; - if (get_oid(start_name, &oid)) { + if (get_oid_mb(start_name, &oid)) { if (explicit_tracking) { if (advice_set_upstream_failure) { error(_(upstream_missing), start_name); @@ -339,8 +340,7 @@ void create_branch(struct repository *r, void remove_branch_state(struct repository *r) { - unlink(git_path_cherry_pick_head(r)); - unlink(git_path_revert_head(r)); + sequencer_post_commit_cleanup(r); unlink(git_path_merge_head(r)); unlink(git_path_merge_rr(r)); unlink(git_path_merge_msg(r)); diff --git a/branch.h b/branch.h index 29c1afa4d0..6f38db14e9 100644 --- a/branch.h +++ b/branch.h @@ -50,7 +50,7 @@ void create_branch(struct repository *r, * Return 1 if the named branch already exists; return 0 otherwise. * Fill ref with the full refname for the branch. */ -extern int validate_branchname(const char *name, struct strbuf *ref); +int validate_branchname(const char *name, struct strbuf *ref); /* * Check if a branch 'name' can be created as a new branch; die otherwise. @@ -58,7 +58,7 @@ extern int validate_branchname(const char *name, struct strbuf *ref); * Return 1 if the named branch already exists; return 0 otherwise. * Fill ref with the full refname for the branch. */ -extern int validate_new_branchname(const char *name, struct strbuf *ref, int force); +int validate_new_branchname(const char *name, struct strbuf *ref, int force); /* * Remove information about the state of working on the current @@ -72,26 +72,26 @@ void remove_branch_state(struct repository *r); * Returns 0 on success. */ #define BRANCH_CONFIG_VERBOSE 01 -extern int install_branch_config(int flag, const char *local, const char *origin, const char *remote); +int install_branch_config(int flag, const char *local, const char *origin, const char *remote); /* * Read branch description */ -extern int read_branch_desc(struct strbuf *, const char *branch_name); +int read_branch_desc(struct strbuf *, const char *branch_name); /* * Check if a branch is checked out in the main worktree or any linked * worktree and die (with a message describing its checkout location) if * it is. */ -extern void die_if_checked_out(const char *branch, int ignore_current_worktree); +void die_if_checked_out(const char *branch, int ignore_current_worktree); /* * Update all per-worktree HEADs pointing at the old ref to point the new ref. * This will be used when renaming a branch. Returns 0 if successful, non-zero * otherwise. */ -extern int replace_each_worktree_head_symref(const char *oldref, const char *newref, - const char *logmsg); +int replace_each_worktree_head_symref(const char *oldref, const char *newref, + const char *logmsg); #endif diff --git a/builtin.h b/builtin.h index ac552ff0d2..ec7e0954c4 100644 --- a/builtin.h +++ b/builtin.h @@ -102,7 +102,7 @@ extern const char git_more_info_string[]; #define PRUNE_PACKED_DRY_RUN 01 #define PRUNE_PACKED_VERBOSE 02 -extern void prune_packed_objects(int); +void prune_packed_objects(int); struct fmt_merge_msg_opts { unsigned add_title:1, @@ -110,8 +110,8 @@ struct fmt_merge_msg_opts { int shortlog_len; }; -extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out, - struct fmt_merge_msg_opts *); +int fmt_merge_msg(struct strbuf *in, struct strbuf *out, + struct fmt_merge_msg_opts *); /** * If a built-in has DELAY_PAGER_CONFIG set, the built-in should call this early @@ -123,131 +123,131 @@ extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out, * You should most likely use a default of 0 or 1. "Punt" (-1) could be useful * to be able to fall back to some historical compatibility name. */ -extern void setup_auto_pager(const char *cmd, int def); +void setup_auto_pager(const char *cmd, int def); -extern int is_builtin(const char *s); +int is_builtin(const char *s); -extern int cmd_add(int argc, const char **argv, const char *prefix); -extern int cmd_am(int argc, const char **argv, const char *prefix); -extern int cmd_annotate(int argc, const char **argv, const char *prefix); -extern int cmd_apply(int argc, const char **argv, const char *prefix); -extern int cmd_archive(int argc, const char **argv, const char *prefix); -extern int cmd_bisect__helper(int argc, const char **argv, const char *prefix); -extern int cmd_blame(int argc, const char **argv, const char *prefix); -extern int cmd_branch(int argc, const char **argv, const char *prefix); -extern int cmd_bundle(int argc, const char **argv, const char *prefix); -extern int cmd_cat_file(int argc, const char **argv, const char *prefix); -extern int cmd_checkout(int argc, const char **argv, const char *prefix); -extern int cmd_checkout_index(int argc, const char **argv, const char *prefix); -extern int cmd_check_attr(int argc, const char **argv, const char *prefix); -extern int cmd_check_ignore(int argc, const char **argv, const char *prefix); -extern int cmd_check_mailmap(int argc, const char **argv, const char *prefix); -extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix); -extern int cmd_cherry(int argc, const char **argv, const char *prefix); -extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix); -extern int cmd_clone(int argc, const char **argv, const char *prefix); -extern int cmd_clean(int argc, const char **argv, const char *prefix); -extern int cmd_column(int argc, const char **argv, const char *prefix); -extern int cmd_commit(int argc, const char **argv, const char *prefix); -extern int cmd_commit_graph(int argc, const char **argv, const char *prefix); -extern int cmd_commit_tree(int argc, const char **argv, const char *prefix); -extern int cmd_config(int argc, const char **argv, const char *prefix); -extern int cmd_count_objects(int argc, const char **argv, const char *prefix); -extern int cmd_credential(int argc, const char **argv, const char *prefix); -extern int cmd_describe(int argc, const char **argv, const char *prefix); -extern int cmd_diff_files(int argc, const char **argv, const char *prefix); -extern int cmd_diff_index(int argc, const char **argv, const char *prefix); -extern int cmd_diff(int argc, const char **argv, const char *prefix); -extern int cmd_diff_tree(int argc, const char **argv, const char *prefix); -extern int cmd_difftool(int argc, const char **argv, const char *prefix); -extern int cmd_fast_export(int argc, const char **argv, const char *prefix); -extern int cmd_fetch(int argc, const char **argv, const char *prefix); -extern int cmd_fetch_pack(int argc, const char **argv, const char *prefix); -extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix); -extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix); -extern int cmd_format_patch(int argc, const char **argv, const char *prefix); -extern int cmd_fsck(int argc, const char **argv, const char *prefix); -extern int cmd_gc(int argc, const char **argv, const char *prefix); -extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix); -extern int cmd_grep(int argc, const char **argv, const char *prefix); -extern int cmd_hash_object(int argc, const char **argv, const char *prefix); -extern int cmd_help(int argc, const char **argv, const char *prefix); -extern int cmd_index_pack(int argc, const char **argv, const char *prefix); -extern int cmd_init_db(int argc, const char **argv, const char *prefix); -extern int cmd_interpret_trailers(int argc, const char **argv, const char *prefix); -extern int cmd_log(int argc, const char **argv, const char *prefix); -extern int cmd_log_reflog(int argc, const char **argv, const char *prefix); -extern int cmd_ls_files(int argc, const char **argv, const char *prefix); -extern int cmd_ls_tree(int argc, const char **argv, const char *prefix); -extern int cmd_ls_remote(int argc, const char **argv, const char *prefix); -extern int cmd_mailinfo(int argc, const char **argv, const char *prefix); -extern int cmd_mailsplit(int argc, const char **argv, const char *prefix); -extern int cmd_merge(int argc, const char **argv, const char *prefix); -extern int cmd_merge_base(int argc, const char **argv, const char *prefix); -extern int cmd_merge_index(int argc, const char **argv, const char *prefix); -extern int cmd_merge_ours(int argc, const char **argv, const char *prefix); -extern int cmd_merge_file(int argc, const char **argv, const char *prefix); -extern int cmd_merge_recursive(int argc, const char **argv, const char *prefix); -extern int cmd_merge_tree(int argc, const char **argv, const char *prefix); -extern int cmd_mktag(int argc, const char **argv, const char *prefix); -extern int cmd_mktree(int argc, const char **argv, const char *prefix); -extern int cmd_multi_pack_index(int argc, const char **argv, const char *prefix); -extern int cmd_mv(int argc, const char **argv, const char *prefix); -extern int cmd_name_rev(int argc, const char **argv, const char *prefix); -extern int cmd_notes(int argc, const char **argv, const char *prefix); -extern int cmd_pack_objects(int argc, const char **argv, const char *prefix); -extern int cmd_pack_redundant(int argc, const char **argv, const char *prefix); -extern int cmd_patch_id(int argc, const char **argv, const char *prefix); -extern int cmd_prune(int argc, const char **argv, const char *prefix); -extern int cmd_prune_packed(int argc, const char **argv, const char *prefix); -extern int cmd_pull(int argc, const char **argv, const char *prefix); -extern int cmd_push(int argc, const char **argv, const char *prefix); -extern int cmd_range_diff(int argc, const char **argv, const char *prefix); -extern int cmd_read_tree(int argc, const char **argv, const char *prefix); -extern int cmd_rebase(int argc, const char **argv, const char *prefix); -extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix); -extern int cmd_receive_pack(int argc, const char **argv, const char *prefix); -extern int cmd_reflog(int argc, const char **argv, const char *prefix); -extern int cmd_remote(int argc, const char **argv, const char *prefix); -extern int cmd_remote_ext(int argc, const char **argv, const char *prefix); -extern int cmd_remote_fd(int argc, const char **argv, const char *prefix); -extern int cmd_repack(int argc, const char **argv, const char *prefix); -extern int cmd_rerere(int argc, const char **argv, const char *prefix); -extern int cmd_reset(int argc, const char **argv, const char *prefix); -extern int cmd_rev_list(int argc, const char **argv, const char *prefix); -extern int cmd_rev_parse(int argc, const char **argv, const char *prefix); -extern int cmd_revert(int argc, const char **argv, const char *prefix); -extern int cmd_rm(int argc, const char **argv, const char *prefix); -extern int cmd_send_pack(int argc, const char **argv, const char *prefix); -extern int cmd_shortlog(int argc, const char **argv, const char *prefix); -extern int cmd_show(int argc, const char **argv, const char *prefix); -extern int cmd_show_branch(int argc, const char **argv, const char *prefix); -extern int cmd_show_index(int argc, const char **argv, const char *prefix); -extern int cmd_status(int argc, const char **argv, const char *prefix); -extern int cmd_stash(int argc, const char **argv, const char *prefix); -extern int cmd_stripspace(int argc, const char **argv, const char *prefix); -extern int cmd_submodule__helper(int argc, const char **argv, const char *prefix); -extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix); -extern int cmd_tag(int argc, const char **argv, const char *prefix); -extern int cmd_tar_tree(int argc, const char **argv, const char *prefix); -extern int cmd_unpack_file(int argc, const char **argv, const char *prefix); -extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix); -extern int cmd_update_index(int argc, const char **argv, const char *prefix); -extern int cmd_update_ref(int argc, const char **argv, const char *prefix); -extern int cmd_update_server_info(int argc, const char **argv, const char *prefix); -extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); -extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); -extern int cmd_upload_pack(int argc, const char **argv, const char *prefix); -extern int cmd_var(int argc, const char **argv, const char *prefix); -extern int cmd_verify_commit(int argc, const char **argv, const char *prefix); -extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); -extern int cmd_version(int argc, const char **argv, const char *prefix); -extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); -extern int cmd_worktree(int argc, const char **argv, const char *prefix); -extern int cmd_write_tree(int argc, const char **argv, const char *prefix); -extern int cmd_verify_pack(int argc, const char **argv, const char *prefix); -extern int cmd_show_ref(int argc, const char **argv, const char *prefix); -extern int cmd_pack_refs(int argc, const char **argv, const char *prefix); -extern int cmd_replace(int argc, const char **argv, const char *prefix); +int cmd_add(int argc, const char **argv, const char *prefix); +int cmd_am(int argc, const char **argv, const char *prefix); +int cmd_annotate(int argc, const char **argv, const char *prefix); +int cmd_apply(int argc, const char **argv, const char *prefix); +int cmd_archive(int argc, const char **argv, const char *prefix); +int cmd_bisect__helper(int argc, const char **argv, const char *prefix); +int cmd_blame(int argc, const char **argv, const char *prefix); +int cmd_branch(int argc, const char **argv, const char *prefix); +int cmd_bundle(int argc, const char **argv, const char *prefix); +int cmd_cat_file(int argc, const char **argv, const char *prefix); +int cmd_checkout(int argc, const char **argv, const char *prefix); +int cmd_checkout_index(int argc, const char **argv, const char *prefix); +int cmd_check_attr(int argc, const char **argv, const char *prefix); +int cmd_check_ignore(int argc, const char **argv, const char *prefix); +int cmd_check_mailmap(int argc, const char **argv, const char *prefix); +int cmd_check_ref_format(int argc, const char **argv, const char *prefix); +int cmd_cherry(int argc, const char **argv, const char *prefix); +int cmd_cherry_pick(int argc, const char **argv, const char *prefix); +int cmd_clone(int argc, const char **argv, const char *prefix); +int cmd_clean(int argc, const char **argv, const char *prefix); +int cmd_column(int argc, const char **argv, const char *prefix); +int cmd_commit(int argc, const char **argv, const char *prefix); +int cmd_commit_graph(int argc, const char **argv, const char *prefix); +int cmd_commit_tree(int argc, const char **argv, const char *prefix); +int cmd_config(int argc, const char **argv, const char *prefix); +int cmd_count_objects(int argc, const char **argv, const char *prefix); +int cmd_credential(int argc, const char **argv, const char *prefix); +int cmd_describe(int argc, const char **argv, const char *prefix); +int cmd_diff_files(int argc, const char **argv, const char *prefix); +int cmd_diff_index(int argc, const char **argv, const char *prefix); +int cmd_diff(int argc, const char **argv, const char *prefix); +int cmd_diff_tree(int argc, const char **argv, const char *prefix); +int cmd_difftool(int argc, const char **argv, const char *prefix); +int cmd_fast_export(int argc, const char **argv, const char *prefix); +int cmd_fetch(int argc, const char **argv, const char *prefix); +int cmd_fetch_pack(int argc, const char **argv, const char *prefix); +int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix); +int cmd_for_each_ref(int argc, const char **argv, const char *prefix); +int cmd_format_patch(int argc, const char **argv, const char *prefix); +int cmd_fsck(int argc, const char **argv, const char *prefix); +int cmd_gc(int argc, const char **argv, const char *prefix); +int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix); +int cmd_grep(int argc, const char **argv, const char *prefix); +int cmd_hash_object(int argc, const char **argv, const char *prefix); +int cmd_help(int argc, const char **argv, const char *prefix); +int cmd_index_pack(int argc, const char **argv, const char *prefix); +int cmd_init_db(int argc, const char **argv, const char *prefix); +int cmd_interpret_trailers(int argc, const char **argv, const char *prefix); +int cmd_log(int argc, const char **argv, const char *prefix); +int cmd_log_reflog(int argc, const char **argv, const char *prefix); +int cmd_ls_files(int argc, const char **argv, const char *prefix); +int cmd_ls_tree(int argc, const char **argv, const char *prefix); +int cmd_ls_remote(int argc, const char **argv, const char *prefix); +int cmd_mailinfo(int argc, const char **argv, const char *prefix); +int cmd_mailsplit(int argc, const char **argv, const char *prefix); +int cmd_merge(int argc, const char **argv, const char *prefix); +int cmd_merge_base(int argc, const char **argv, const char *prefix); +int cmd_merge_index(int argc, const char **argv, const char *prefix); +int cmd_merge_ours(int argc, const char **argv, const char *prefix); +int cmd_merge_file(int argc, const char **argv, const char *prefix); +int cmd_merge_recursive(int argc, const char **argv, const char *prefix); +int cmd_merge_tree(int argc, const char **argv, const char *prefix); +int cmd_mktag(int argc, const char **argv, const char *prefix); +int cmd_mktree(int argc, const char **argv, const char *prefix); +int cmd_multi_pack_index(int argc, const char **argv, const char *prefix); +int cmd_mv(int argc, const char **argv, const char *prefix); +int cmd_name_rev(int argc, const char **argv, const char *prefix); +int cmd_notes(int argc, const char **argv, const char *prefix); +int cmd_pack_objects(int argc, const char **argv, const char *prefix); +int cmd_pack_redundant(int argc, const char **argv, const char *prefix); +int cmd_patch_id(int argc, const char **argv, const char *prefix); +int cmd_prune(int argc, const char **argv, const char *prefix); +int cmd_prune_packed(int argc, const char **argv, const char *prefix); +int cmd_pull(int argc, const char **argv, const char *prefix); +int cmd_push(int argc, const char **argv, const char *prefix); +int cmd_range_diff(int argc, const char **argv, const char *prefix); +int cmd_read_tree(int argc, const char **argv, const char *prefix); +int cmd_rebase(int argc, const char **argv, const char *prefix); +int cmd_rebase__interactive(int argc, const char **argv, const char *prefix); +int cmd_receive_pack(int argc, const char **argv, const char *prefix); +int cmd_reflog(int argc, const char **argv, const char *prefix); +int cmd_remote(int argc, const char **argv, const char *prefix); +int cmd_remote_ext(int argc, const char **argv, const char *prefix); +int cmd_remote_fd(int argc, const char **argv, const char *prefix); +int cmd_repack(int argc, const char **argv, const char *prefix); +int cmd_rerere(int argc, const char **argv, const char *prefix); +int cmd_reset(int argc, const char **argv, const char *prefix); +int cmd_rev_list(int argc, const char **argv, const char *prefix); +int cmd_rev_parse(int argc, const char **argv, const char *prefix); +int cmd_revert(int argc, const char **argv, const char *prefix); +int cmd_rm(int argc, const char **argv, const char *prefix); +int cmd_send_pack(int argc, const char **argv, const char *prefix); +int cmd_shortlog(int argc, const char **argv, const char *prefix); +int cmd_show(int argc, const char **argv, const char *prefix); +int cmd_show_branch(int argc, const char **argv, const char *prefix); +int cmd_show_index(int argc, const char **argv, const char *prefix); +int cmd_status(int argc, const char **argv, const char *prefix); +int cmd_stash(int argc, const char **argv, const char *prefix); +int cmd_stripspace(int argc, const char **argv, const char *prefix); +int cmd_submodule__helper(int argc, const char **argv, const char *prefix); +int cmd_symbolic_ref(int argc, const char **argv, const char *prefix); +int cmd_tag(int argc, const char **argv, const char *prefix); +int cmd_tar_tree(int argc, const char **argv, const char *prefix); +int cmd_unpack_file(int argc, const char **argv, const char *prefix); +int cmd_unpack_objects(int argc, const char **argv, const char *prefix); +int cmd_update_index(int argc, const char **argv, const char *prefix); +int cmd_update_ref(int argc, const char **argv, const char *prefix); +int cmd_update_server_info(int argc, const char **argv, const char *prefix); +int cmd_upload_archive(int argc, const char **argv, const char *prefix); +int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); +int cmd_upload_pack(int argc, const char **argv, const char *prefix); +int cmd_var(int argc, const char **argv, const char *prefix); +int cmd_verify_commit(int argc, const char **argv, const char *prefix); +int cmd_verify_tag(int argc, const char **argv, const char *prefix); +int cmd_version(int argc, const char **argv, const char *prefix); +int cmd_whatchanged(int argc, const char **argv, const char *prefix); +int cmd_worktree(int argc, const char **argv, const char *prefix); +int cmd_write_tree(int argc, const char **argv, const char *prefix); +int cmd_verify_pack(int argc, const char **argv, const char *prefix); +int cmd_show_ref(int argc, const char **argv, const char *prefix); +int cmd_pack_refs(int argc, const char **argv, const char *prefix); +int cmd_replace(int argc, const char **argv, const char *prefix); #endif diff --git a/builtin/clone.c b/builtin/clone.c index 31a47d190a..85b0d3155d 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -99,10 +99,7 @@ static struct option builtin_clone_options[] = { N_("don't use local hardlinks, always copy")), OPT_BOOL('s', "shared", &option_shared, N_("setup as shared repository")), - { OPTION_CALLBACK, 0, "recursive", &option_recurse_submodules, - N_("pathspec"), N_("initialize submodules in the clone"), - PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, recurse_submodules_cb, - (intptr_t)"." }, + OPT_ALIAS(0, "recursive", "recurse-submodules"), { OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules, N_("pathspec"), N_("initialize submodules in the clone"), PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." }, @@ -660,7 +657,8 @@ static void update_remote_refs(const struct ref *refs, const char *branch_top, const char *msg, struct transport *transport, - int check_connectivity) + int check_connectivity, + int check_refs_only) { const struct ref *rm = mapped_refs; @@ -669,6 +667,7 @@ static void update_remote_refs(const struct ref *refs, opt.transport = transport; opt.progress = transport->progress; + opt.check_refs_only = !!check_refs_only; if (check_connected(iterate_ref_map, &rm, &opt)) die(_("remote did not send all necessary objects")); @@ -1230,7 +1229,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) update_remote_refs(refs, mapped_refs, remote_head_points_at, branch_top.buf, reflog_msg.buf, transport, - !is_local); + !is_local, filter_options.choice); update_head(our_head_points_at, remote_head, reflog_msg.buf); diff --git a/builtin/commit.c b/builtin/commit.c index bd4b180c43..1c9e8e2228 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1658,8 +1658,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("%s", err.buf); } - unlink(git_path_cherry_pick_head(the_repository)); - unlink(git_path_revert_head(the_repository)); + sequencer_post_commit_cleanup(the_repository); unlink(git_path_merge_head(the_repository)); unlink(git_path_merge_msg(the_repository)); unlink(git_path_merge_mode(the_repository)); diff --git a/builtin/difftool.c b/builtin/difftool.c index 04ffa1d943..53188df714 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -24,7 +24,6 @@ #include "object-store.h" #include "dir.h" -static char *diff_gui_tool; static int trust_exit_code; static const char *const builtin_difftool_usage[] = { @@ -34,11 +33,6 @@ static const char *const builtin_difftool_usage[] = { static int difftool_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, "diff.guitool")) { - diff_gui_tool = xstrdup(value); - return 0; - } - if (!strcmp(var, "difftool.trustexitcode")) { trust_exit_code = git_config_bool(var, value); return 0; @@ -735,8 +729,11 @@ int cmd_difftool(int argc, const char **argv, const char *prefix) setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(get_git_work_tree()), 1); } - if (use_gui_tool && diff_gui_tool && *diff_gui_tool) - setenv("GIT_DIFF_TOOL", diff_gui_tool, 1); + if (use_gui_tool + !!difftool_cmd + !!extcmd > 1) + die(_("--gui, --tool and --extcmd are mutually exclusive")); + + if (use_gui_tool) + setenv("GIT_MERGETOOL_GUI", "true", 1); else if (difftool_cmd) { if (*difftool_cmd) setenv("GIT_DIFF_TOOL", difftool_cmd, 1); diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index ae6e476ad5..72dfd3dadc 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -46,7 +46,7 @@ int cmd_multi_pack_index(int argc, const char **argv, if (!strcmp(argv[0], "write")) return write_midx_file(opts.object_dir); if (!strcmp(argv[0], "verify")) - return verify_midx_file(opts.object_dir); + return verify_midx_file(the_repository, opts.object_dir); die(_("unrecognized verb: %s"), argv[0]); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index d7743f110b..41d7fc5983 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -97,7 +97,7 @@ static off_t reuse_packfile_offset; static int use_bitmap_index_default = 1; static int use_bitmap_index = -1; static int write_bitmap_index; -static uint16_t write_bitmap_options; +static uint16_t write_bitmap_options = BITMAP_OPT_HASH_CACHE; static int exclude_promisor_objects; @@ -1080,7 +1080,7 @@ static int want_object_in_pack(const struct object_id *oid, for (m = get_multi_pack_index(the_repository); m; m = m->next) { struct pack_entry e; - if (fill_midx_entry(oid, &e, m)) { + if (fill_midx_entry(the_repository, oid, &e, m)) { struct packed_git *p = e.p; off_t offset; diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index f3353564f9..cfbd5c36c7 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "parse-options.h" #include "refs.h" #include "repository.h" @@ -16,6 +17,7 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix) OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE), OPT_END(), }; + git_config(git_default_config, NULL); if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0)) usage_with_options(pack_refs_usage, opts); return refs_pack_refs(get_main_ref_store(the_repository), flags); diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c deleted file mode 100644 index 4535523bf5..0000000000 --- a/builtin/rebase--interactive.c +++ /dev/null @@ -1,377 +0,0 @@ -#define USE_THE_INDEX_COMPATIBILITY_MACROS -#include "builtin.h" -#include "cache.h" -#include "config.h" -#include "parse-options.h" -#include "sequencer.h" -#include "rebase-interactive.h" -#include "argv-array.h" -#include "refs.h" -#include "rerere.h" -#include "run-command.h" - -static GIT_PATH_FUNC(path_state_dir, "rebase-merge/") -static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") -static GIT_PATH_FUNC(path_interactive, "rebase-merge/interactive") - -static int add_exec_commands(struct string_list *commands) -{ - const char *todo_file = rebase_path_todo(); - struct todo_list todo_list = TODO_LIST_INIT; - int res; - - if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) - return error_errno(_("could not read '%s'."), todo_file); - - if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, - &todo_list)) { - todo_list_release(&todo_list); - return error(_("unusable todo list: '%s'"), todo_file); - } - - todo_list_add_exec_commands(&todo_list, commands); - res = todo_list_write_to_file(the_repository, &todo_list, - todo_file, NULL, NULL, -1, 0); - todo_list_release(&todo_list); - - if (res) - return error_errno(_("could not write '%s'."), todo_file); - return 0; -} - -static int rearrange_squash_in_todo_file(void) -{ - const char *todo_file = rebase_path_todo(); - struct todo_list todo_list = TODO_LIST_INIT; - int res = 0; - - if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) - return error_errno(_("could not read '%s'."), todo_file); - if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, - &todo_list)) { - todo_list_release(&todo_list); - return error(_("unusable todo list: '%s'"), todo_file); - } - - res = todo_list_rearrange_squash(&todo_list); - if (!res) - res = todo_list_write_to_file(the_repository, &todo_list, - todo_file, NULL, NULL, -1, 0); - - todo_list_release(&todo_list); - - if (res) - return error_errno(_("could not write '%s'."), todo_file); - return 0; -} - -static int transform_todo_file(unsigned flags) -{ - const char *todo_file = rebase_path_todo(); - struct todo_list todo_list = TODO_LIST_INIT; - int res; - - if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) - return error_errno(_("could not read '%s'."), todo_file); - - if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, - &todo_list)) { - todo_list_release(&todo_list); - return error(_("unusable todo list: '%s'"), todo_file); - } - - res = todo_list_write_to_file(the_repository, &todo_list, todo_file, - NULL, NULL, -1, flags); - todo_list_release(&todo_list); - - if (res) - return error_errno(_("could not write '%s'."), todo_file); - return 0; -} - -static int edit_todo_file(unsigned flags) -{ - const char *todo_file = rebase_path_todo(); - struct todo_list todo_list = TODO_LIST_INIT, - new_todo = TODO_LIST_INIT; - int res = 0; - - if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) - return error_errno(_("could not read '%s'."), todo_file); - - strbuf_stripspace(&todo_list.buf, 1); - res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags); - if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file, - NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS))) - res = error_errno(_("could not write '%s'"), todo_file); - - todo_list_release(&todo_list); - todo_list_release(&new_todo); - - return res; -} - -static int get_revision_ranges(const char *upstream, const char *onto, - const char **head_hash, - char **revisions, char **shortrevisions) -{ - const char *base_rev = upstream ? upstream : onto, *shorthead; - struct object_id orig_head; - - if (get_oid("HEAD", &orig_head)) - return error(_("no HEAD?")); - - *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); - *revisions = xstrfmt("%s...%s", base_rev, *head_hash); - - shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV); - - if (upstream) { - const char *shortrev; - struct object_id rev_oid; - - get_oid(base_rev, &rev_oid); - shortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV); - - *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead); - } else - *shortrevisions = xstrdup(shorthead); - - return 0; -} - -static int init_basic_state(struct replay_opts *opts, const char *head_name, - const char *onto, const char *orig_head) -{ - FILE *interactive; - - if (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir())) - return error_errno(_("could not create temporary %s"), path_state_dir()); - - delete_reflog("REBASE_HEAD"); - - interactive = fopen(path_interactive(), "w"); - if (!interactive) - return error_errno(_("could not mark as interactive")); - fclose(interactive); - - return write_basic_state(opts, head_name, onto, orig_head); -} - -static int do_interactive_rebase(struct replay_opts *opts, unsigned flags, - const char *switch_to, const char *upstream, - const char *onto, const char *onto_name, - const char *squash_onto, const char *head_name, - const char *restrict_revision, char *raw_strategies, - struct string_list *commands, unsigned autosquash) -{ - int ret; - const char *head_hash = NULL; - char *revisions = NULL, *shortrevisions = NULL; - struct argv_array make_script_args = ARGV_ARRAY_INIT; - struct todo_list todo_list = TODO_LIST_INIT; - - if (prepare_branch_to_be_rebased(opts, switch_to)) - return -1; - - if (get_revision_ranges(upstream, onto, &head_hash, - &revisions, &shortrevisions)) - return -1; - - if (raw_strategies) - parse_strategy_opts(opts, raw_strategies); - - if (init_basic_state(opts, head_name, onto, head_hash)) { - free(revisions); - free(shortrevisions); - - return -1; - } - - if (!upstream && squash_onto) - write_file(path_squash_onto(), "%s\n", squash_onto); - - argv_array_pushl(&make_script_args, "", revisions, NULL); - if (restrict_revision) - argv_array_push(&make_script_args, restrict_revision); - - ret = sequencer_make_script(the_repository, &todo_list.buf, - make_script_args.argc, make_script_args.argv, - flags); - - if (ret) - error(_("could not generate todo list")); - else { - discard_cache(); - if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, - &todo_list)) - BUG("unusable todo list"); - - ret = complete_action(the_repository, opts, flags, shortrevisions, onto_name, - onto, head_hash, commands, autosquash, &todo_list); - } - - free(revisions); - free(shortrevisions); - todo_list_release(&todo_list); - argv_array_clear(&make_script_args); - - return ret; -} - -static const char * const builtin_rebase_interactive_usage[] = { - N_("git rebase--interactive []"), - NULL -}; - -int cmd_rebase__interactive(int argc, const char **argv, const char *prefix) -{ - struct replay_opts opts = REPLAY_OPTS_INIT; - unsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0; - int abbreviate_commands = 0, rebase_cousins = -1, ret = 0; - const char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL, - *squash_onto = NULL, *upstream = NULL, *head_name = NULL, - *switch_to = NULL, *cmd = NULL; - struct string_list commands = STRING_LIST_INIT_DUP; - char *raw_strategies = NULL; - enum { - NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH, - SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC - } command = 0; - struct option options[] = { - OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), - OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")), - OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, - N_("allow commits with empty messages")), - OPT_BOOL(0, "rebase-merges", &rebase_merges, N_("rebase merge commits")), - OPT_BOOL(0, "rebase-cousins", &rebase_cousins, - N_("keep original branch points of cousins")), - OPT_BOOL(0, "autosquash", &autosquash, - N_("move commits that begin with squash!/fixup!")), - OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")), - OPT__VERBOSE(&opts.verbose, N_("be verbose")), - OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), - CONTINUE), - OPT_CMDMODE(0, "skip", &command, N_("skip commit"), SKIP), - OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list"), - EDIT_TODO), - OPT_CMDMODE(0, "show-current-patch", &command, N_("show the current patch"), - SHOW_CURRENT_PATCH), - OPT_CMDMODE(0, "shorten-ids", &command, - N_("shorten commit ids in the todo list"), SHORTEN_OIDS), - OPT_CMDMODE(0, "expand-ids", &command, - N_("expand commit ids in the todo list"), EXPAND_OIDS), - OPT_CMDMODE(0, "check-todo-list", &command, - N_("check the todo list"), CHECK_TODO_LIST), - OPT_CMDMODE(0, "rearrange-squash", &command, - N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), - OPT_CMDMODE(0, "add-exec-commands", &command, - N_("insert exec commands in todo list"), ADD_EXEC), - OPT_STRING(0, "onto", &onto, N_("onto"), N_("onto")), - OPT_STRING(0, "restrict-revision", &restrict_revision, - N_("restrict-revision"), N_("restrict revision")), - OPT_STRING(0, "squash-onto", &squash_onto, N_("squash-onto"), - N_("squash onto")), - OPT_STRING(0, "upstream", &upstream, N_("upstream"), - N_("the upstream commit")), - OPT_STRING(0, "head-name", &head_name, N_("head-name"), N_("head name")), - { OPTION_STRING, 'S', "gpg-sign", &opts.gpg_sign, N_("key-id"), - N_("GPG-sign commits"), - PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, - OPT_STRING(0, "strategy", &opts.strategy, N_("strategy"), - N_("rebase strategy")), - OPT_STRING(0, "strategy-opts", &raw_strategies, N_("strategy-opts"), - N_("strategy options")), - OPT_STRING(0, "switch-to", &switch_to, N_("switch-to"), - N_("the branch or commit to checkout")), - OPT_STRING(0, "onto-name", &onto_name, N_("onto-name"), N_("onto name")), - OPT_STRING(0, "cmd", &cmd, N_("cmd"), N_("the command to run")), - OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto), - OPT_BOOL(0, "reschedule-failed-exec", &opts.reschedule_failed_exec, - N_("automatically re-schedule any `exec` that fails")), - OPT_END() - }; - - sequencer_init_config(&opts); - git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands); - - opts.action = REPLAY_INTERACTIVE_REBASE; - opts.allow_ff = 1; - opts.allow_empty = 1; - - if (argc == 1) - usage_with_options(builtin_rebase_interactive_usage, options); - - argc = parse_options(argc, argv, NULL, options, - builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0); - - opts.gpg_sign = xstrdup_or_null(opts.gpg_sign); - - flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0; - flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0; - flags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0; - flags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0; - flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0; - - if (rebase_cousins >= 0 && !rebase_merges) - warning(_("--[no-]rebase-cousins has no effect without " - "--rebase-merges")); - - if (cmd && *cmd) { - string_list_split(&commands, cmd, '\n', -1); - - /* rebase.c adds a new line to cmd after every command, - * so here the last command is always empty */ - string_list_remove_empty_items(&commands, 0); - } - - switch (command) { - case NONE: - if (!onto && !upstream) - die(_("a base commit must be provided with --upstream or --onto")); - - ret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto, - onto_name, squash_onto, head_name, restrict_revision, - raw_strategies, &commands, autosquash); - break; - case SKIP: { - struct string_list merge_rr = STRING_LIST_INIT_DUP; - - rerere_clear(the_repository, &merge_rr); - /* fallthrough */ - case CONTINUE: - ret = sequencer_continue(the_repository, &opts); - break; - } - case EDIT_TODO: - ret = edit_todo_file(flags); - break; - case SHOW_CURRENT_PATCH: { - struct child_process cmd = CHILD_PROCESS_INIT; - - cmd.git_cmd = 1; - argv_array_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL); - ret = run_command(&cmd); - - break; - } - case SHORTEN_OIDS: - case EXPAND_OIDS: - ret = transform_todo_file(flags); - break; - case CHECK_TODO_LIST: - ret = check_todo_list_from_file(the_repository); - break; - case REARRANGE_SQUASH: - ret = rearrange_squash_in_todo_file(); - break; - case ADD_EXEC: - ret = add_exec_commands(&commands); - break; - default: - BUG("invalid command '%d'", command); - } - - string_list_clear(&commands, 0); - return !!ret; -} diff --git a/builtin/rebase.c b/builtin/rebase.c index 966b953e86..ba3a574e40 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -25,6 +25,8 @@ #include "commit-reach.h" #include "rerere.h" #include "branch.h" +#include "sequencer.h" +#include "rebase-interactive.h" static char const * const builtin_rebase_usage[] = { N_("git rebase [-i] [options] [--exec ] [--onto ] " @@ -35,6 +37,8 @@ static char const * const builtin_rebase_usage[] = { NULL }; +static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto") +static GIT_PATH_FUNC(path_interactive, "rebase-merge/interactive") static GIT_PATH_FUNC(apply_dir, "rebase-apply") static GIT_PATH_FUNC(merge_dir, "rebase-merge") @@ -86,6 +90,437 @@ struct rebase_options { int use_legacy_rebase; }; +#define REBASE_OPTIONS_INIT { \ + .type = REBASE_UNSPECIFIED, \ + .flags = REBASE_NO_QUIET, \ + .git_am_opts = ARGV_ARRAY_INIT, \ + .git_format_patch_opt = STRBUF_INIT \ + } + +static struct replay_opts get_replay_opts(const struct rebase_options *opts) +{ + struct replay_opts replay = REPLAY_OPTS_INIT; + + replay.action = REPLAY_INTERACTIVE_REBASE; + sequencer_init_config(&replay); + + replay.signoff = opts->signoff; + replay.allow_ff = !(opts->flags & REBASE_FORCE); + if (opts->allow_rerere_autoupdate) + replay.allow_rerere_auto = opts->allow_rerere_autoupdate; + replay.allow_empty = 1; + replay.allow_empty_message = opts->allow_empty_message; + replay.verbose = opts->flags & REBASE_VERBOSE; + replay.reschedule_failed_exec = opts->reschedule_failed_exec; + replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt); + replay.strategy = opts->strategy; + if (opts->strategy_opts) + parse_strategy_opts(&replay, opts->strategy_opts); + + return replay; +} + +enum action { + ACTION_NONE = 0, + ACTION_CONTINUE, + ACTION_SKIP, + ACTION_ABORT, + ACTION_QUIT, + ACTION_EDIT_TODO, + ACTION_SHOW_CURRENT_PATCH, + ACTION_SHORTEN_OIDS, + ACTION_EXPAND_OIDS, + ACTION_CHECK_TODO_LIST, + ACTION_REARRANGE_SQUASH, + ACTION_ADD_EXEC +}; + +static const char *action_names[] = { "undefined", + "continue", + "skip", + "abort", + "quit", + "edit_todo", + "show_current_patch" }; + +static int add_exec_commands(struct string_list *commands) +{ + const char *todo_file = rebase_path_todo(); + struct todo_list todo_list = TODO_LIST_INIT; + int res; + + if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) + return error_errno(_("could not read '%s'."), todo_file); + + if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, + &todo_list)) { + todo_list_release(&todo_list); + return error(_("unusable todo list: '%s'"), todo_file); + } + + todo_list_add_exec_commands(&todo_list, commands); + res = todo_list_write_to_file(the_repository, &todo_list, + todo_file, NULL, NULL, -1, 0); + todo_list_release(&todo_list); + + if (res) + return error_errno(_("could not write '%s'."), todo_file); + return 0; +} + +static int rearrange_squash_in_todo_file(void) +{ + const char *todo_file = rebase_path_todo(); + struct todo_list todo_list = TODO_LIST_INIT; + int res = 0; + + if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) + return error_errno(_("could not read '%s'."), todo_file); + if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, + &todo_list)) { + todo_list_release(&todo_list); + return error(_("unusable todo list: '%s'"), todo_file); + } + + res = todo_list_rearrange_squash(&todo_list); + if (!res) + res = todo_list_write_to_file(the_repository, &todo_list, + todo_file, NULL, NULL, -1, 0); + + todo_list_release(&todo_list); + + if (res) + return error_errno(_("could not write '%s'."), todo_file); + return 0; +} + +static int transform_todo_file(unsigned flags) +{ + const char *todo_file = rebase_path_todo(); + struct todo_list todo_list = TODO_LIST_INIT; + int res; + + if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) + return error_errno(_("could not read '%s'."), todo_file); + + if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, + &todo_list)) { + todo_list_release(&todo_list); + return error(_("unusable todo list: '%s'"), todo_file); + } + + res = todo_list_write_to_file(the_repository, &todo_list, todo_file, + NULL, NULL, -1, flags); + todo_list_release(&todo_list); + + if (res) + return error_errno(_("could not write '%s'."), todo_file); + return 0; +} + +static int edit_todo_file(unsigned flags) +{ + const char *todo_file = rebase_path_todo(); + struct todo_list todo_list = TODO_LIST_INIT, + new_todo = TODO_LIST_INIT; + int res = 0; + + if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) + return error_errno(_("could not read '%s'."), todo_file); + + strbuf_stripspace(&todo_list.buf, 1); + res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags); + if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file, + NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS))) + res = error_errno(_("could not write '%s'"), todo_file); + + todo_list_release(&todo_list); + todo_list_release(&new_todo); + + return res; +} + +static int get_revision_ranges(struct commit *upstream, struct commit *onto, + const char **head_hash, + char **revisions, char **shortrevisions) +{ + struct commit *base_rev = upstream ? upstream : onto; + const char *shorthead; + struct object_id orig_head; + + if (get_oid("HEAD", &orig_head)) + return error(_("no HEAD?")); + + *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ); + *revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid), + *head_hash); + + shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV); + + if (upstream) { + const char *shortrev; + + shortrev = find_unique_abbrev(&base_rev->object.oid, + DEFAULT_ABBREV); + + *shortrevisions = xstrfmt("%s..%s", shortrev, shorthead); + } else + *shortrevisions = xstrdup(shorthead); + + return 0; +} + +static int init_basic_state(struct replay_opts *opts, const char *head_name, + struct commit *onto, const char *orig_head) +{ + FILE *interactive; + + if (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir())) + return error_errno(_("could not create temporary %s"), merge_dir()); + + delete_reflog("REBASE_HEAD"); + + interactive = fopen(path_interactive(), "w"); + if (!interactive) + return error_errno(_("could not mark as interactive")); + fclose(interactive); + + return write_basic_state(opts, head_name, onto, orig_head); +} + +static void split_exec_commands(const char *cmd, struct string_list *commands) +{ + if (cmd && *cmd) { + string_list_split(commands, cmd, '\n', -1); + + /* rebase.c adds a new line to cmd after every command, + * so here the last command is always empty */ + string_list_remove_empty_items(commands, 0); + } +} + +static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) +{ + int ret; + const char *head_hash = NULL; + char *revisions = NULL, *shortrevisions = NULL; + struct argv_array make_script_args = ARGV_ARRAY_INIT; + struct todo_list todo_list = TODO_LIST_INIT; + struct replay_opts replay = get_replay_opts(opts); + struct string_list commands = STRING_LIST_INIT_DUP; + + if (prepare_branch_to_be_rebased(the_repository, &replay, + opts->switch_to)) + return -1; + + if (get_revision_ranges(opts->upstream, opts->onto, &head_hash, + &revisions, &shortrevisions)) + return -1; + + if (init_basic_state(&replay, + opts->head_name ? opts->head_name : "detached HEAD", + opts->onto, head_hash)) { + free(revisions); + free(shortrevisions); + + return -1; + } + + if (!opts->upstream && opts->squash_onto) + write_file(path_squash_onto(), "%s\n", + oid_to_hex(opts->squash_onto)); + + argv_array_pushl(&make_script_args, "", revisions, NULL); + if (opts->restrict_revision) + argv_array_push(&make_script_args, + oid_to_hex(&opts->restrict_revision->object.oid)); + + ret = sequencer_make_script(the_repository, &todo_list.buf, + make_script_args.argc, make_script_args.argv, + flags); + + if (ret) + error(_("could not generate todo list")); + else { + discard_cache(); + if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, + &todo_list)) + BUG("unusable todo list"); + + split_exec_commands(opts->cmd, &commands); + ret = complete_action(the_repository, &replay, flags, + shortrevisions, opts->onto_name, opts->onto, head_hash, + &commands, opts->autosquash, &todo_list); + } + + string_list_clear(&commands, 0); + free(revisions); + free(shortrevisions); + todo_list_release(&todo_list); + argv_array_clear(&make_script_args); + + return ret; +} + +static int run_rebase_interactive(struct rebase_options *opts, + enum action command) +{ + unsigned flags = 0; + int abbreviate_commands = 0, ret = 0; + + git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands); + + flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0; + flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0; + flags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0; + flags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0; + flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0; + + switch (command) { + case ACTION_NONE: { + if (!opts->onto && !opts->upstream) + die(_("a base commit must be provided with --upstream or --onto")); + + ret = do_interactive_rebase(opts, flags); + break; + } + case ACTION_SKIP: { + struct string_list merge_rr = STRING_LIST_INIT_DUP; + + rerere_clear(the_repository, &merge_rr); + } + /* fallthrough */ + case ACTION_CONTINUE: { + struct replay_opts replay_opts = get_replay_opts(opts); + + ret = sequencer_continue(the_repository, &replay_opts); + break; + } + case ACTION_EDIT_TODO: + ret = edit_todo_file(flags); + break; + case ACTION_SHOW_CURRENT_PATCH: { + struct child_process cmd = CHILD_PROCESS_INIT; + + cmd.git_cmd = 1; + argv_array_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL); + ret = run_command(&cmd); + + break; + } + case ACTION_SHORTEN_OIDS: + case ACTION_EXPAND_OIDS: + ret = transform_todo_file(flags); + break; + case ACTION_CHECK_TODO_LIST: + ret = check_todo_list_from_file(the_repository); + break; + case ACTION_REARRANGE_SQUASH: + ret = rearrange_squash_in_todo_file(); + break; + case ACTION_ADD_EXEC: { + struct string_list commands = STRING_LIST_INIT_DUP; + + split_exec_commands(opts->cmd, &commands); + ret = add_exec_commands(&commands); + string_list_clear(&commands, 0); + break; + } + default: + BUG("invalid command '%d'", command); + } + + return ret; +} + +static const char * const builtin_rebase_interactive_usage[] = { + N_("git rebase--interactive []"), + NULL +}; + +int cmd_rebase__interactive(int argc, const char **argv, const char *prefix) +{ + struct rebase_options opts = REBASE_OPTIONS_INIT; + struct object_id squash_onto = null_oid; + enum action command = ACTION_NONE; + struct option options[] = { + OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"), + REBASE_FORCE), + OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")), + OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, + N_("allow commits with empty messages")), + OPT_BOOL(0, "rebase-merges", &opts.rebase_merges, N_("rebase merge commits")), + OPT_BOOL(0, "rebase-cousins", &opts.rebase_cousins, + N_("keep original branch points of cousins")), + OPT_BOOL(0, "autosquash", &opts.autosquash, + N_("move commits that begin with squash!/fixup!")), + OPT_BOOL(0, "signoff", &opts.signoff, N_("sign commits")), + OPT_BIT('v', "verbose", &opts.flags, + N_("display a diffstat of what changed upstream"), + REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT), + OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), + ACTION_CONTINUE), + OPT_CMDMODE(0, "skip", &command, N_("skip commit"), ACTION_SKIP), + OPT_CMDMODE(0, "edit-todo", &command, N_("edit the todo list"), + ACTION_EDIT_TODO), + OPT_CMDMODE(0, "show-current-patch", &command, N_("show the current patch"), + ACTION_SHOW_CURRENT_PATCH), + OPT_CMDMODE(0, "shorten-ids", &command, + N_("shorten commit ids in the todo list"), ACTION_SHORTEN_OIDS), + OPT_CMDMODE(0, "expand-ids", &command, + N_("expand commit ids in the todo list"), ACTION_EXPAND_OIDS), + OPT_CMDMODE(0, "check-todo-list", &command, + N_("check the todo list"), ACTION_CHECK_TODO_LIST), + OPT_CMDMODE(0, "rearrange-squash", &command, + N_("rearrange fixup/squash lines"), ACTION_REARRANGE_SQUASH), + OPT_CMDMODE(0, "add-exec-commands", &command, + N_("insert exec commands in todo list"), ACTION_ADD_EXEC), + { OPTION_CALLBACK, 0, "onto", &opts.onto, N_("onto"), N_("onto"), + PARSE_OPT_NONEG, parse_opt_commit, 0 }, + { OPTION_CALLBACK, 0, "restrict-revision", &opts.restrict_revision, + N_("restrict-revision"), N_("restrict revision"), + PARSE_OPT_NONEG, parse_opt_commit, 0 }, + { OPTION_CALLBACK, 0, "squash-onto", &squash_onto, N_("squash-onto"), + N_("squash onto"), PARSE_OPT_NONEG, parse_opt_object_id, 0 }, + { OPTION_CALLBACK, 0, "upstream", &opts.upstream, N_("upstream"), + N_("the upstream commit"), PARSE_OPT_NONEG, parse_opt_commit, + 0 }, + OPT_STRING(0, "head-name", &opts.head_name, N_("head-name"), N_("head name")), + { OPTION_STRING, 'S', "gpg-sign", &opts.gpg_sign_opt, N_("key-id"), + N_("GPG-sign commits"), + PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, + OPT_STRING(0, "strategy", &opts.strategy, N_("strategy"), + N_("rebase strategy")), + OPT_STRING(0, "strategy-opts", &opts.strategy_opts, N_("strategy-opts"), + N_("strategy options")), + OPT_STRING(0, "switch-to", &opts.switch_to, N_("switch-to"), + N_("the branch or commit to checkout")), + OPT_STRING(0, "onto-name", &opts.onto_name, N_("onto-name"), N_("onto name")), + OPT_STRING(0, "cmd", &opts.cmd, N_("cmd"), N_("the command to run")), + OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_autoupdate), + OPT_BOOL(0, "reschedule-failed-exec", &opts.reschedule_failed_exec, + N_("automatically re-schedule any `exec` that fails")), + OPT_END() + }; + + opts.rebase_cousins = -1; + + if (argc == 1) + usage_with_options(builtin_rebase_interactive_usage, options); + + argc = parse_options(argc, argv, NULL, options, + builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0); + + if (!is_null_oid(&squash_onto)) + opts.squash_onto = &squash_onto; + + if (opts.rebase_cousins >= 0 && !opts.rebase_merges) + warning(_("--[no-]rebase-cousins has no effect without " + "--rebase-merges")); + + return !!run_rebase_interactive(&opts, command); +} + static int is_interactive(struct rebase_options *opts) { return opts->type == REBASE_INTERACTIVE || @@ -184,14 +619,13 @@ static int read_basic_state(struct rebase_options *opts) &buf)) return -1; if (!strcmp(buf.buf, "--rerere-autoupdate")) - opts->allow_rerere_autoupdate = 1; + opts->allow_rerere_autoupdate = RERERE_AUTOUPDATE; else if (!strcmp(buf.buf, "--no-rerere-autoupdate")) - opts->allow_rerere_autoupdate = 0; + opts->allow_rerere_autoupdate = RERERE_NOAUTOUPDATE; else warning(_("ignoring invalid allow_rerere_autoupdate: " "'%s'"), buf.buf); - } else - opts->allow_rerere_autoupdate = -1; + } if (file_exists(state_dir_path("gpg_sign_opt", opts))) { strbuf_reset(&buf); @@ -223,7 +657,7 @@ static int read_basic_state(struct rebase_options *opts) return 0; } -static int write_basic_state(struct rebase_options *opts) +static int rebase_write_basic_state(struct rebase_options *opts) { write_file(state_dir_path("head-name", opts), "%s", opts->head_name ? opts->head_name : "detached HEAD"); @@ -241,10 +675,11 @@ static int write_basic_state(struct rebase_options *opts) if (opts->strategy_opts) write_file(state_dir_path("strategy_opts", opts), "%s", opts->strategy_opts); - if (opts->allow_rerere_autoupdate >= 0) + if (opts->allow_rerere_autoupdate > 0) write_file(state_dir_path("allow_rerere_autoupdate", opts), "-%s-rerere-autoupdate", - opts->allow_rerere_autoupdate ? "" : "-no"); + opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ? + "" : "-no"); if (opts->gpg_sign_opt) write_file(state_dir_path("gpg_sign_opt", opts), "%s", opts->gpg_sign_opt); @@ -608,9 +1043,9 @@ static int run_am(struct rebase_options *opts) argv_array_push(&am.args, "--rebasing"); argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg); argv_array_push(&am.args, "--patch-format=mboxrd"); - if (opts->allow_rerere_autoupdate > 0) + if (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE) argv_array_push(&am.args, "--rerere-autoupdate"); - else if (opts->allow_rerere_autoupdate == 0) + else if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE) argv_array_push(&am.args, "--no-rerere-autoupdate"); if (opts->gpg_sign_opt) argv_array_push(&am.args, opts->gpg_sign_opt); @@ -623,12 +1058,12 @@ static int run_am(struct rebase_options *opts) } if (is_directory(opts->state_dir)) - write_basic_state(opts); + rebase_write_basic_state(opts); return status; } -static int run_specific_rebase(struct rebase_options *opts) +static int run_specific_rebase(struct rebase_options *opts, enum action action) { const char *argv[] = { NULL, NULL }; struct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT; @@ -637,77 +1072,19 @@ static int run_specific_rebase(struct rebase_options *opts) if (opts->type == REBASE_INTERACTIVE) { /* Run builtin interactive rebase */ - struct child_process child = CHILD_PROCESS_INIT; - - argv_array_pushf(&child.env_array, "GIT_CHERRY_PICK_HELP=%s", - resolvemsg); + setenv("GIT_CHERRY_PICK_HELP", resolvemsg, 1); if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) { - argv_array_push(&child.env_array, - "GIT_SEQUENCE_EDITOR=:"); + setenv("GIT_SEQUENCE_EDITOR", ":", 1); opts->autosquash = 0; } + if (opts->gpg_sign_opt) { + /* remove the leading "-S" */ + char *tmp = xstrdup(opts->gpg_sign_opt + 2); + free(opts->gpg_sign_opt); + opts->gpg_sign_opt = tmp; + } - child.git_cmd = 1; - argv_array_push(&child.args, "rebase--interactive"); - - if (opts->action) - argv_array_pushf(&child.args, "--%s", opts->action); - if (opts->keep_empty) - argv_array_push(&child.args, "--keep-empty"); - if (opts->rebase_merges) - argv_array_push(&child.args, "--rebase-merges"); - if (opts->rebase_cousins) - argv_array_push(&child.args, "--rebase-cousins"); - if (opts->autosquash) - argv_array_push(&child.args, "--autosquash"); - if (opts->flags & REBASE_VERBOSE) - argv_array_push(&child.args, "--verbose"); - if (opts->flags & REBASE_FORCE) - argv_array_push(&child.args, "--no-ff"); - if (opts->restrict_revision) - argv_array_pushf(&child.args, - "--restrict-revision=^%s", - oid_to_hex(&opts->restrict_revision->object.oid)); - if (opts->upstream) - argv_array_pushf(&child.args, "--upstream=%s", - oid_to_hex(&opts->upstream->object.oid)); - if (opts->onto) - argv_array_pushf(&child.args, "--onto=%s", - oid_to_hex(&opts->onto->object.oid)); - if (opts->squash_onto) - argv_array_pushf(&child.args, "--squash-onto=%s", - oid_to_hex(opts->squash_onto)); - if (opts->onto_name) - argv_array_pushf(&child.args, "--onto-name=%s", - opts->onto_name); - argv_array_pushf(&child.args, "--head-name=%s", - opts->head_name ? - opts->head_name : "detached HEAD"); - if (opts->strategy) - argv_array_pushf(&child.args, "--strategy=%s", - opts->strategy); - if (opts->strategy_opts) - argv_array_pushf(&child.args, "--strategy-opts=%s", - opts->strategy_opts); - if (opts->switch_to) - argv_array_pushf(&child.args, "--switch-to=%s", - opts->switch_to); - if (opts->cmd) - argv_array_pushf(&child.args, "--cmd=%s", opts->cmd); - if (opts->allow_empty_message) - argv_array_push(&child.args, "--allow-empty-message"); - if (opts->allow_rerere_autoupdate > 0) - argv_array_push(&child.args, "--rerere-autoupdate"); - else if (opts->allow_rerere_autoupdate == 0) - argv_array_push(&child.args, "--no-rerere-autoupdate"); - if (opts->gpg_sign_opt) - argv_array_push(&child.args, opts->gpg_sign_opt); - if (opts->signoff) - argv_array_push(&child.args, "--signoff"); - if (opts->reschedule_failed_exec) - argv_array_push(&child.args, "--reschedule-failed-exec"); - - status = run_command(&child); + status = run_rebase_interactive(opts, action); goto finished_rebase; } @@ -747,9 +1124,9 @@ static int run_specific_rebase(struct rebase_options *opts) add_var(&script_snippet, "action", opts->action ? opts->action : ""); add_var(&script_snippet, "signoff", opts->signoff ? "--signoff" : ""); add_var(&script_snippet, "allow_rerere_autoupdate", - opts->allow_rerere_autoupdate < 0 ? "" : opts->allow_rerere_autoupdate ? - "--rerere-autoupdate" : "--no-rerere-autoupdate"); + opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ? + "--rerere-autoupdate" : "--no-rerere-autoupdate" : ""); add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : ""); add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : ""); add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt); @@ -991,14 +1368,7 @@ static int check_exec_cmd(const char *cmd) int cmd_rebase(int argc, const char **argv, const char *prefix) { - struct rebase_options options = { - .type = REBASE_UNSPECIFIED, - .flags = REBASE_NO_QUIET, - .git_am_opts = ARGV_ARRAY_INIT, - .allow_rerere_autoupdate = -1, - .allow_empty_message = 1, - .git_format_patch_opt = STRBUF_INIT, - }; + struct rebase_options options = REBASE_OPTIONS_INIT; const char *branch_name; int ret, flags, total_argc, in_progress = 0; int ok_to_skip_pre_rebase = 0; @@ -1006,23 +1376,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) struct strbuf revisions = STRBUF_INIT; struct strbuf buf = STRBUF_INIT; struct object_id merge_base; - enum { - NO_ACTION, - ACTION_CONTINUE, - ACTION_SKIP, - ACTION_ABORT, - ACTION_QUIT, - ACTION_EDIT_TODO, - ACTION_SHOW_CURRENT_PATCH, - } action = NO_ACTION; - static const char *action_names[] = { N_("undefined"), - N_("continue"), - N_("skip"), - N_("abort"), - N_("quit"), - N_("edit_todo"), - N_("show_current_patch"), - NULL }; + enum action action = ACTION_NONE; const char *gpg_sign = NULL; struct string_list exec = STRING_LIST_INIT_NODUP; const char *rebase_merges = NULL; @@ -1090,10 +1444,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) OPT_SET_INT('p', "preserve-merges", &options.type, N_("(DEPRECATED) try to recreate merges instead of " "ignoring them"), REBASE_PRESERVE_MERGES), - OPT_BOOL(0, "rerere-autoupdate", - &options.allow_rerere_autoupdate, - N_("allow rerere to update index with resolved " - "conflict")), + OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate), OPT_BOOL('k', "keep-empty", &options.keep_empty, N_("preserve empty commits during rebase")), OPT_BOOL(0, "autosquash", &options.autosquash, @@ -1139,6 +1490,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) trace_repo_setup(prefix); setup_work_tree(); + options.allow_empty_message = 1; git_config(rebase_config, &options); if (options.use_legacy_rebase || @@ -1180,7 +1532,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) builtin_rebase_options, builtin_rebase_usage, 0); - if (action != NO_ACTION && total_argc != 2) { + if (action != ACTION_NONE && total_argc != 2) { usage_with_options(builtin_rebase_usage, builtin_rebase_options); } @@ -1193,7 +1545,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) warning(_("git rebase --preserve-merges is deprecated. " "Use --rebase-merges instead.")); - if (action != NO_ACTION && !in_progress) + if (action != ACTION_NONE && !in_progress) die(_("No rebase in progress?")); setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0); @@ -1293,7 +1645,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) options.action = "show-current-patch"; options.dont_finish_rebase = 1; goto run_rebase; - case NO_ACTION: + case ACTION_NONE: break; default: BUG("action: %d", action); @@ -1791,7 +2143,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) options.revisions = revisions.buf; run_rebase: - ret = !!run_specific_rebase(&options); + ret = !!run_specific_rebase(&options, action); cleanup: strbuf_release(&revisions); diff --git a/builtin/repack.c b/builtin/repack.c index 67f8978043..caca113927 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -14,7 +14,7 @@ static int delta_base_offset = 1; static int pack_kept_objects = -1; -static int write_bitmaps; +static int write_bitmaps = -1; static int use_delta_islands; static char *packdir, *packtmp; @@ -343,6 +343,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix) (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE))) die(_("--keep-unreachable and -A are incompatible")); + if (write_bitmaps < 0) + write_bitmaps = (pack_everything & ALL_INTO_ONE) && + is_bare_repository(); if (pack_kept_objects < 0) pack_kept_objects = write_bitmaps; diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 6a706c02a6..6456da70cc 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "refs.h" #include "object-store.h" #include "object.h" @@ -182,6 +183,8 @@ static const struct option show_ref_options[] = { int cmd_show_ref(int argc, const char **argv, const char *prefix) { + git_config(git_default_config, NULL); + argc = parse_options(argc, argv, prefix, show_ref_options, show_ref_usage, 0); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 8c72ea864c..0bf4aa088e 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1301,7 +1301,7 @@ static int add_possible_reference_from_superproject( die(_("submodule '%s' cannot add alternate: %s"), sas->submodule_name, err.buf); case SUBMODULE_ALTERNATE_ERROR_INFO: - fprintf(stderr, _("submodule '%s' cannot add alternate: %s"), + fprintf_ln(stderr, _("submodule '%s' cannot add alternate: %s"), sas->submodule_name, err.buf); case SUBMODULE_ALTERNATE_ERROR_IGNORE: ; /* nothing */ diff --git a/builtin/tag.c b/builtin/tag.c index 1debd3a11c..ef37dccf86 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -207,7 +207,7 @@ struct create_tag_options { }; static const char message_advice_nested_tag[] = - N_("You have created a nested tag. The object referred to by your new is\n" + N_("You have created a nested tag. The object referred to by your new tag is\n" "already a tag. If you meant to tag the object that it points to, use:\n" "\n" "\tgit tag -f %s %s^{}"); diff --git a/bulk-checkin.h b/bulk-checkin.h index f438f93811..b26f3dc3b7 100644 --- a/bulk-checkin.h +++ b/bulk-checkin.h @@ -6,11 +6,11 @@ #include "cache.h" -extern int index_bulk_checkin(struct object_id *oid, - int fd, size_t size, enum object_type type, - const char *path, unsigned flags); +int index_bulk_checkin(struct object_id *oid, + int fd, size_t size, enum object_type type, + const char *path, unsigned flags); -extern void plug_bulk_checkin(void); -extern void unplug_bulk_checkin(void); +void plug_bulk_checkin(void); +void unplug_bulk_checkin(void); #endif diff --git a/cache.h b/cache.h index 67cc2e1806..b4bb2e2c11 100644 --- a/cache.h +++ b/cache.h @@ -341,7 +341,8 @@ struct index_state { initialized : 1, drop_cache_tree : 1, updated_workdir : 1, - updated_skipworktree : 1; + updated_skipworktree : 1, + fsmonitor_has_run_once : 1; struct hashmap name_hash; struct hashmap dir_hash; struct object_id oid; @@ -352,10 +353,10 @@ struct index_state { }; /* Name hashing */ -extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded); -extern void add_name_hash(struct index_state *istate, struct cache_entry *ce); -extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce); -extern void free_name_hash(struct index_state *istate); +int test_lazy_init_name_hash(struct index_state *istate, int try_threaded); +void add_name_hash(struct index_state *istate, struct cache_entry *ce); +void remove_name_hash(struct index_state *istate, struct cache_entry *ce); +void free_name_hash(struct index_state *istate); /* Cache entry creation and cleanup */ @@ -545,7 +546,7 @@ static inline enum object_type object_type(unsigned int mode) */ extern const char * const local_repo_env[]; -extern void setup_git_env(const char *git_dir); +void setup_git_env(const char *git_dir); /* * Returns true iff we have a configured git repository (either via @@ -554,29 +555,29 @@ extern void setup_git_env(const char *git_dir); int have_git_dir(void); extern int is_bare_repository_cfg; -extern int is_bare_repository(void); -extern int is_inside_git_dir(void); +int is_bare_repository(void); +int is_inside_git_dir(void); extern char *git_work_tree_cfg; -extern int is_inside_work_tree(void); -extern const char *get_git_dir(void); -extern const char *get_git_common_dir(void); -extern char *get_object_directory(void); -extern char *get_index_file(void); -extern char *get_graft_file(struct repository *r); -extern void set_git_dir(const char *path); -extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir); -extern int get_common_dir(struct strbuf *sb, const char *gitdir); -extern const char *get_git_namespace(void); -extern const char *strip_namespace(const char *namespaced_ref); -extern const char *get_super_prefix(void); -extern const char *get_git_work_tree(void); +int is_inside_work_tree(void); +const char *get_git_dir(void); +const char *get_git_common_dir(void); +char *get_object_directory(void); +char *get_index_file(void); +char *get_graft_file(struct repository *r); +void set_git_dir(const char *path); +int get_common_dir_noenv(struct strbuf *sb, const char *gitdir); +int get_common_dir(struct strbuf *sb, const char *gitdir); +const char *get_git_namespace(void); +const char *strip_namespace(const char *namespaced_ref); +const char *get_super_prefix(void); +const char *get_git_work_tree(void); /* * Return true if the given path is a git directory; note that this _just_ * looks at the directory itself. If you want to know whether "foo/.git" * is a repository, you must feed that path, not just "foo". */ -extern int is_git_directory(const char *path); +int is_git_directory(const char *path); /* * Return 1 if the given path is the root of a git repository or @@ -588,7 +589,7 @@ extern int is_git_directory(const char *path); * as we usually consider sub-repos precious, and would prefer to err on the * side of not disrupting or deleting them. */ -extern int is_nonbare_repository_dir(struct strbuf *path); +int is_nonbare_repository_dir(struct strbuf *path); #define READ_GITFILE_ERR_STAT_FAILED 1 #define READ_GITFILE_ERR_NOT_A_FILE 2 @@ -598,17 +599,17 @@ extern int is_nonbare_repository_dir(struct strbuf *path); #define READ_GITFILE_ERR_NO_PATH 6 #define READ_GITFILE_ERR_NOT_A_REPO 7 #define READ_GITFILE_ERR_TOO_LARGE 8 -extern void read_gitfile_error_die(int error_code, const char *path, const char *dir); -extern const char *read_gitfile_gently(const char *path, int *return_error_code); +void read_gitfile_error_die(int error_code, const char *path, const char *dir); +const char *read_gitfile_gently(const char *path, int *return_error_code); #define read_gitfile(path) read_gitfile_gently((path), NULL) -extern const char *resolve_gitdir_gently(const char *suspect, int *return_error_code); +const char *resolve_gitdir_gently(const char *suspect, int *return_error_code); #define resolve_gitdir(path) resolve_gitdir_gently((path), NULL) -extern void set_git_work_tree(const char *tree); +void set_git_work_tree(const char *tree); #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES" -extern void setup_work_tree(void); +void setup_work_tree(void); /* * Find the commondir and gitdir of the repository that contains the current * working directory, without changing the working directory or other global @@ -617,12 +618,12 @@ extern void setup_work_tree(void); * both have the same result appended to the buffer. The return value is * either 0 upon success and non-zero if no repository was found. */ -extern int discover_git_directory(struct strbuf *commondir, - struct strbuf *gitdir); -extern const char *setup_git_directory_gently(int *); -extern const char *setup_git_directory(void); -extern char *prefix_path(const char *prefix, int len, const char *path); -extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path); +int discover_git_directory(struct strbuf *commondir, + struct strbuf *gitdir); +const char *setup_git_directory_gently(int *); +const char *setup_git_directory(void); +char *prefix_path(const char *prefix, int len, const char *path); +char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path); /* * Concatenate "prefix" (if len is non-zero) and "path", with no @@ -634,23 +635,23 @@ extern char *prefix_path_gently(const char *prefix, int len, int *remaining, con * The return value is always a newly allocated string (even if the * prefix was empty). */ -extern char *prefix_filename(const char *prefix, const char *path); +char *prefix_filename(const char *prefix, const char *path); -extern int check_filename(const char *prefix, const char *name); -extern void verify_filename(const char *prefix, - const char *name, - int diagnose_misspelt_rev); -extern void verify_non_filename(const char *prefix, const char *name); -extern int path_inside_repo(const char *prefix, const char *path); +int check_filename(const char *prefix, const char *name); +void verify_filename(const char *prefix, + const char *name, + int diagnose_misspelt_rev); +void verify_non_filename(const char *prefix, const char *name); +int path_inside_repo(const char *prefix, const char *path); #define INIT_DB_QUIET 0x0001 #define INIT_DB_EXIST_OK 0x0002 -extern int init_db(const char *git_dir, const char *real_git_dir, - const char *template_dir, unsigned int flags); +int init_db(const char *git_dir, const char *real_git_dir, + const char *template_dir, unsigned int flags); -extern void sanitize_stdfds(void); -extern int daemonize(void); +void sanitize_stdfds(void); +int daemonize(void); #define alloc_nr(x) (((x)+16)*3/2) @@ -674,14 +675,14 @@ extern int daemonize(void); /* Initialize and use the cache information */ struct lock_file; -extern void preload_index(struct index_state *index, - const struct pathspec *pathspec, - unsigned int refresh_flags); -extern int do_read_index(struct index_state *istate, const char *path, - int must_exist); /* for testting only! */ -extern int read_index_from(struct index_state *, const char *path, - const char *gitdir); -extern int is_index_unborn(struct index_state *); +void preload_index(struct index_state *index, + const struct pathspec *pathspec, + unsigned int refresh_flags); +int do_read_index(struct index_state *istate, const char *path, + int must_exist); /* for testting only! */ +int read_index_from(struct index_state *, const char *path, + const char *gitdir); +int is_index_unborn(struct index_state *); /* For use with `write_locked_index()`. */ #define COMMIT_LOCK (1 << 0) @@ -706,11 +707,11 @@ extern int is_index_unborn(struct index_state *); * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing * is written (and the lock is rolled back if `COMMIT_LOCK` is given). */ -extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags); +int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags); -extern int discard_index(struct index_state *); -extern void move_index_extensions(struct index_state *dst, struct index_state *src); -extern int unmerged_index(const struct index_state *); +int discard_index(struct index_state *); +void move_index_extensions(struct index_state *dst, struct index_state *src); +int unmerged_index(const struct index_state *); /** * Returns 1 if istate differs from tree, 0 otherwise. If tree is NULL, @@ -719,15 +720,15 @@ extern int unmerged_index(const struct index_state *); * provided, the space-separated list of files that differ will be appended * to it. */ -extern int repo_index_has_changes(struct repository *repo, - struct tree *tree, - struct strbuf *sb); +int repo_index_has_changes(struct repository *repo, + struct tree *tree, + struct strbuf *sb); -extern int verify_path(const char *path, unsigned mode); -extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change); -extern int index_dir_exists(struct index_state *istate, const char *name, int namelen); -extern void adjust_dirname_case(struct index_state *istate, char *name); -extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase); +int verify_path(const char *path, unsigned mode); +int strcmp_offset(const char *s1, const char *s2, size_t *first_change); +int index_dir_exists(struct index_state *istate, const char *name, int namelen); +void adjust_dirname_case(struct index_state *istate, char *name); +struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase); /* * Searches for an entry defined by name and namelen in the given index. @@ -746,7 +747,7 @@ extern struct cache_entry *index_file_exists(struct index_state *istate, const c * index_name_pos(&index, "f", 1) -> -3 * index_name_pos(&index, "g", 1) -> -5 */ -extern int index_name_pos(const struct index_state *, const char *name, int namelen); +int index_name_pos(const struct index_state *, const char *name, int namelen); #define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */ #define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */ @@ -755,14 +756,14 @@ extern int index_name_pos(const struct index_state *, const char *name, int name #define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */ #define ADD_CACHE_KEEP_CACHE_TREE 32 /* Do not invalidate cache-tree */ #define ADD_CACHE_RENORMALIZE 64 /* Pass along HASH_RENORMALIZE */ -extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option); -extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name); +int add_index_entry(struct index_state *, struct cache_entry *ce, int option); +void rename_index_entry_at(struct index_state *, int pos, const char *new_name); /* Remove entry, return true if there are more entries to go. */ -extern int remove_index_entry_at(struct index_state *, int pos); +int remove_index_entry_at(struct index_state *, int pos); -extern void remove_marked_cache_entries(struct index_state *istate, int invalidate); -extern int remove_file_from_index(struct index_state *, const char *path); +void remove_marked_cache_entries(struct index_state *istate, int invalidate); +int remove_file_from_index(struct index_state *, const char *path); #define ADD_CACHE_VERBOSE 1 #define ADD_CACHE_PRETEND 2 #define ADD_CACHE_IGNORE_ERRORS 4 @@ -777,14 +778,14 @@ extern int remove_file_from_index(struct index_state *, const char *path); * the latter will do necessary lstat(2) internally before * calling the former. */ -extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags); -extern int add_file_to_index(struct index_state *, const char *path, int flags); +int add_to_index(struct index_state *, const char *path, struct stat *, int flags); +int add_file_to_index(struct index_state *, const char *path, int flags); -extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip); -extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b); -extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce); -extern int index_name_is_other(const struct index_state *, const char *, int); -extern void *read_blob_data_from_index(const struct index_state *, const char *, unsigned long *); +int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip); +int ce_same_name(const struct cache_entry *a, const struct cache_entry *b); +void set_object_name_for_intent_to_add_entry(struct cache_entry *ce); +int index_name_is_other(const struct index_state *, const char *, int); +void *read_blob_data_from_index(const struct index_state *, const char *, unsigned long *); /* do stat comparison even if CE_VALID is true */ #define CE_MATCH_IGNORE_VALID 01 @@ -798,22 +799,22 @@ extern void *read_blob_data_from_index(const struct index_state *, const char *, #define CE_MATCH_REFRESH 0x10 /* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */ #define CE_MATCH_IGNORE_FSMONITOR 0X20 -extern int is_racy_timestamp(const struct index_state *istate, - const struct cache_entry *ce); -extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); -extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); +int is_racy_timestamp(const struct index_state *istate, + const struct cache_entry *ce); +int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); +int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); #define HASH_WRITE_OBJECT 1 #define HASH_FORMAT_CHECK 2 #define HASH_RENORMALIZE 4 -extern int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); -extern int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); +int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); +int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); /* * Record to sd the data from st that we use to check whether a file * might have changed. */ -extern void fill_stat_data(struct stat_data *sd, struct stat *st); +void fill_stat_data(struct stat_data *sd, struct stat *st); /* * Return 0 if st is consistent with a file not having been changed @@ -821,11 +822,11 @@ extern void fill_stat_data(struct stat_data *sd, struct stat *st); * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED, * INODE_CHANGED, and DATA_CHANGED. */ -extern int match_stat_data(const struct stat_data *sd, struct stat *st); -extern int match_stat_data_racy(const struct index_state *istate, - const struct stat_data *sd, struct stat *st); +int match_stat_data(const struct stat_data *sd, struct stat *st); +int match_stat_data_racy(const struct index_state *istate, + const struct stat_data *sd, struct stat *st); -extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); +void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_REALLY 0x0001 /* ignore_valid */ #define REFRESH_UNMERGED 0x0002 /* allow unmerged */ @@ -834,10 +835,10 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */ #define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */ #define REFRESH_PROGRESS 0x0040 /* show progress bar if stderr is tty */ -extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg); -extern struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int); +int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg); +struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int); -extern void set_alternate_index_output(const char *); +void set_alternate_index_output(const char *); extern int verify_index_checksum; extern int verify_ce_order; @@ -1022,7 +1023,7 @@ int verify_repository_format(const struct repository_format *format, * set_git_dir() before calling this, and use it only for "are we in a valid * repo?". */ -extern void check_repository_format(void); +void check_repository_format(void); #define MTIME_CHANGED 0x0001 #define CTIME_CHANGED 0x0002 @@ -1246,7 +1247,7 @@ typedef int create_file_fn(const char *path, void *cb); int raceproof_create_file(const char *path, create_file_fn fn, void *cb); int mkdir_in_gitdir(const char *path); -extern char *expand_user_path(const char *path, int real_home); +char *expand_user_path(const char *path, int real_home); const char *enter_repo(const char *path, int strict); static inline int is_absolute_path(const char *path) { @@ -1290,26 +1291,26 @@ int looks_like_command_line_option(const char *str); * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise * "$HOME/.config/git/$filename". Return NULL upon error. */ -extern char *xdg_config_home(const char *filename); +char *xdg_config_home(const char *filename); /** * Return a newly allocated string with the evaluation of * "$XDG_CACHE_HOME/git/$filename" if $XDG_CACHE_HOME is non-empty, otherwise * "$HOME/.cache/git/$filename". Return NULL upon error. */ -extern char *xdg_cache_home(const char *filename); +char *xdg_cache_home(const char *filename); -extern int git_open_cloexec(const char *name, int flags); +int git_open_cloexec(const char *name, int flags); #define git_open(name) git_open_cloexec(name, O_RDONLY) -extern int unpack_loose_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz); -extern int parse_loose_header(const char *hdr, unsigned long *sizep); +int unpack_loose_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz); +int parse_loose_header(const char *hdr, unsigned long *sizep); -extern int check_object_signature(const struct object_id *oid, void *buf, unsigned long size, const char *type); +int check_object_signature(const struct object_id *oid, void *buf, unsigned long size, const char *type); -extern int finalize_object_file(const char *tmpfile, const char *filename); +int finalize_object_file(const char *tmpfile, const char *filename); /* Helper to check and "touch" a file */ -extern int check_and_freshen_file(const char *fn, int freshen); +int check_and_freshen_file(const char *fn, int freshen); extern const signed char hexval_table[256]; static inline unsigned int hexval(unsigned char c) @@ -1393,9 +1394,9 @@ int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid void maybe_die_on_misspelt_object_name(struct repository *repo, const char *name, const char *prefix); -extern enum get_oid_result get_oid_with_context(struct repository *repo, const char *str, - unsigned flags, struct object_id *oid, - struct object_context *oc); +enum get_oid_result get_oid_with_context(struct repository *repo, const char *str, + unsigned flags, struct object_id *oid, + struct object_context *oc); #define get_oid(str, oid) repo_get_oid(the_repository, str, oid) #define get_oid_commit(str, oid) repo_get_oid_commit(the_repository, str, oid) @@ -1409,7 +1410,7 @@ typedef int each_abbrev_fn(const struct object_id *oid, void *); int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *); #define for_each_abbrev(prefix, fn, data) repo_for_each_abbrev(the_repository, prefix, fn, data) -extern int set_disambiguate_hint_config(const char *var, const char *value); +int set_disambiguate_hint_config(const char *var, const char *value); /* * Try to read a SHA1 in hexadecimal format from the 40 characters @@ -1418,15 +1419,15 @@ extern int set_disambiguate_hint_config(const char *var, const char *value); * input, so it is safe to pass this function an arbitrary * null-terminated string. */ -extern int get_sha1_hex(const char *hex, unsigned char *sha1); -extern int get_oid_hex(const char *hex, struct object_id *sha1); +int get_sha1_hex(const char *hex, unsigned char *sha1); +int get_oid_hex(const char *hex, struct object_id *sha1); /* * Read `len` pairs of hexadecimal digits from `hex` and write the * values to `binary` as `len` bytes. Return 0 on success, or -1 if * the input does not consist of hex digits). */ -extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len); +int hex_to_bytes(unsigned char *binary, const char *hex, size_t len); /* * Convert a binary hash to its hex equivalent. The `_r` variant is reentrant, @@ -1454,7 +1455,7 @@ char *oid_to_hex(const struct object_id *oid); /* same static buffer */ * other invalid character. end is only updated on success; otherwise, it is * unmodified. */ -extern int parse_oid_hex(const char *hex, struct object_id *oid, const char **end); +int parse_oid_hex(const char *hex, struct object_id *oid, const char **end); /* * This reads short-hand syntax that not only evaluates to a commit @@ -1492,17 +1493,17 @@ int repo_interpret_branch_name(struct repository *r, #define interpret_branch_name(str, len, buf, allowed) \ repo_interpret_branch_name(the_repository, str, len, buf, allowed) -extern int validate_headref(const char *ref); +int validate_headref(const char *ref); -extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); -extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); -extern int name_compare(const char *name1, size_t len1, const char *name2, size_t len2); -extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2); +int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); +int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); +int name_compare(const char *name1, size_t len1, const char *name2, size_t len2); +int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2); -extern void *read_object_with_reference(const struct object_id *oid, - const char *required_type, - unsigned long *size, - struct object_id *oid_ret); +void *read_object_with_reference(const struct object_id *oid, + const char *required_type, + unsigned long *size, + struct object_id *oid_ret); struct object *repo_peel_to_type(struct repository *r, const char *name, int namelen, @@ -1562,24 +1563,24 @@ enum want_ident { WANT_COMMITTER_IDENT }; -extern const char *git_author_info(int); -extern const char *git_committer_info(int); -extern const char *fmt_ident(const char *name, const char *email, - enum want_ident whose_ident, - const char *date_str, int); -extern const char *fmt_name(enum want_ident); -extern const char *ident_default_name(void); -extern const char *ident_default_email(void); -extern const char *git_editor(void); -extern const char *git_sequence_editor(void); -extern const char *git_pager(int stdout_is_tty); -extern int is_terminal_dumb(void); -extern int git_ident_config(const char *, const char *, void *); +const char *git_author_info(int); +const char *git_committer_info(int); +const char *fmt_ident(const char *name, const char *email, + enum want_ident whose_ident, + const char *date_str, int); +const char *fmt_name(enum want_ident); +const char *ident_default_name(void); +const char *ident_default_email(void); +const char *git_editor(void); +const char *git_sequence_editor(void); +const char *git_pager(int stdout_is_tty); +int is_terminal_dumb(void); +int git_ident_config(const char *, const char *, void *); /* * Prepare an ident to fall back on if the user didn't configure it. */ void prepare_fallback_ident(const char *name, const char *email); -extern void reset_ident_date(void); +void reset_ident_date(void); struct ident_split { const char *name_begin; @@ -1595,7 +1596,7 @@ struct ident_split { * Signals an success with 0, but time part of the result may be NULL * if the input lacks timestamp and zone */ -extern int split_ident_line(struct ident_split *, const char *, int); +int split_ident_line(struct ident_split *, const char *, int); /* * Like show_date, but pull the timestamp and tz parameters from @@ -1612,7 +1613,7 @@ const char *show_ident_date(const struct ident_split *id, * Because there are two fields, we must choose one as the primary key; we * currently arbitrarily pick the email. */ -extern int ident_cmp(const struct ident_split *, const struct ident_split *); +int ident_cmp(const struct ident_split *, const struct ident_split *); struct checkout { struct index_state *istate; @@ -1628,14 +1629,14 @@ struct checkout { #define CHECKOUT_INIT { NULL, "" } #define TEMPORARY_FILENAME_LENGTH 25 -extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts); -extern void enable_delayed_checkout(struct checkout *state); -extern int finish_delayed_checkout(struct checkout *state, int *nr_checkouts); +int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts); +void enable_delayed_checkout(struct checkout *state); +int finish_delayed_checkout(struct checkout *state, int *nr_checkouts); /* * Unlink the last component and schedule the leading directories for * removal, such that empty directories get removed. */ -extern void unlink_entry(const struct cache_entry *ce); +void unlink_entry(const struct cache_entry *ce); struct cache_def { struct strbuf path; @@ -1649,12 +1650,12 @@ static inline void cache_def_clear(struct cache_def *cache) strbuf_release(&cache->path); } -extern int has_symlink_leading_path(const char *name, int len); -extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int); -extern int check_leading_path(const char *name, int len); -extern int has_dirs_only_path(const char *name, int len, int prefix_len); -extern void schedule_dir_for_removal(const char *name, int len); -extern void remove_scheduled_dirs(void); +int has_symlink_leading_path(const char *name, int len); +int threaded_has_symlink_leading_path(struct cache_def *, const char *, int); +int check_leading_path(const char *name, int len); +int has_dirs_only_path(const char *name, int len, int prefix_len); +void schedule_dir_for_removal(const char *name, int len); +void remove_scheduled_dirs(void); struct pack_window { struct pack_window *next; @@ -1676,14 +1677,14 @@ struct pack_entry { * usual "XXXXXX" trailer, and the resulting filename is written into the * "template" buffer. Returns the open descriptor. */ -extern int odb_mkstemp(struct strbuf *temp_filename, const char *pattern); +int odb_mkstemp(struct strbuf *temp_filename, const char *pattern); /* * Create a pack .keep file named "name" (which should generally be the output * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on * error. */ -extern int odb_pack_keep(const char *name); +int odb_pack_keep(const char *name); /* * Set this to 0 to prevent oid_object_info_extended() from fetching missing @@ -1694,10 +1695,10 @@ extern int odb_pack_keep(const char *name); extern int fetch_if_missing; /* Dumb servers support */ -extern int update_server_info(int); +int update_server_info(int); -extern const char *get_log_output_encoding(void); -extern const char *get_commit_output_encoding(void); +const char *get_log_output_encoding(void); +const char *get_commit_output_encoding(void); /* * This is a hack for test programs like test-dump-untracked-cache to @@ -1706,8 +1707,8 @@ extern const char *get_commit_output_encoding(void); */ extern int ignore_untracked_cache_config; -extern int committer_ident_sufficiently_given(void); -extern int author_ident_sufficiently_given(void); +int committer_ident_sufficiently_given(void); +int author_ident_sufficiently_given(void); extern const char *git_commit_encoding; extern const char *git_log_output_encoding; @@ -1715,22 +1716,22 @@ extern const char *git_mailmap_file; extern const char *git_mailmap_blob; /* IO helper functions */ -extern void maybe_flush_or_die(FILE *, const char *); +void maybe_flush_or_die(FILE *, const char *); __attribute__((format (printf, 2, 3))) -extern void fprintf_or_die(FILE *, const char *fmt, ...); +void fprintf_or_die(FILE *, const char *fmt, ...); #define COPY_READ_ERROR (-2) #define COPY_WRITE_ERROR (-3) -extern int copy_fd(int ifd, int ofd); -extern int copy_file(const char *dst, const char *src, int mode); -extern int copy_file_with_time(const char *dst, const char *src, int mode); +int copy_fd(int ifd, int ofd); +int copy_file(const char *dst, const char *src, int mode); +int copy_file_with_time(const char *dst, const char *src, int mode); -extern void write_or_die(int fd, const void *buf, size_t count); -extern void fsync_or_die(int fd, const char *); +void write_or_die(int fd, const void *buf, size_t count); +void fsync_or_die(int fd, const char *); -extern ssize_t read_in_full(int fd, void *buf, size_t count); -extern ssize_t write_in_full(int fd, const void *buf, size_t count); -extern ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset); +ssize_t read_in_full(int fd, void *buf, size_t count); +ssize_t write_in_full(int fd, const void *buf, size_t count); +ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset); static inline ssize_t write_str_in_full(int fd, const char *str) { @@ -1741,7 +1742,7 @@ static inline ssize_t write_str_in_full(int fd, const char *str) * Open (and truncate) the file at path, write the contents of buf to it, * and close it. Dies if any errors are encountered. */ -extern void write_file_buf(const char *path, const char *buf, size_t len); +void write_file_buf(const char *path, const char *buf, size_t len); /** * Like write_file_buf(), but format the contents into a buffer first. @@ -1751,16 +1752,16 @@ extern void write_file_buf(const char *path, const char *buf, size_t len); * write_file(path, "counter: %d", ctr); */ __attribute__((format (printf, 2, 3))) -extern void write_file(const char *path, const char *fmt, ...); +void write_file(const char *path, const char *fmt, ...); /* pager.c */ -extern void setup_pager(void); -extern int pager_in_use(void); +void setup_pager(void); +int pager_in_use(void); extern int pager_use_color; -extern int term_columns(void); -extern int decimal_width(uintmax_t); -extern int check_pager_config(const char *cmd); -extern void prepare_pager_args(struct child_process *, const char *pager); +int term_columns(void); +int decimal_width(uintmax_t); +int check_pager_config(const char *cmd); +void prepare_pager_args(struct child_process *, const char *pager); extern const char *editor_program; extern const char *askpass_program; @@ -1804,13 +1805,13 @@ void shift_tree_by(const struct object_id *, const struct object_id *, struct ob /* All WS_* -- when extended, adapt diff.c emit_symbol */ #define WS_RULE_MASK 07777 extern unsigned whitespace_rule_cfg; -extern unsigned whitespace_rule(struct index_state *, const char *); -extern unsigned parse_whitespace_rule(const char *); -extern unsigned ws_check(const char *line, int len, unsigned ws_rule); -extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws); -extern char *whitespace_error_string(unsigned ws); -extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *); -extern int ws_blank_line(const char *line, int len, unsigned ws_rule); +unsigned whitespace_rule(struct index_state *, const char *); +unsigned parse_whitespace_rule(const char *); +unsigned ws_check(const char *line, int len, unsigned ws_rule); +void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws); +char *whitespace_error_string(unsigned ws); +void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *); +int ws_blank_line(const char *line, int len, unsigned ws_rule); #define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK) /* ls-files */ @@ -1880,9 +1881,9 @@ void safe_create_dir(const char *dir, int share); * Should we print an ellipsis after an abbreviated SHA-1 value * when doing diff-raw output or indicating a detached HEAD? */ -extern int print_sha1_ellipsis(void); +int print_sha1_ellipsis(void); /* Return 1 if the file is empty or does not exists, 0 otherwise. */ -extern int is_empty_or_missing_file(const char *filename); +int is_empty_or_missing_file(const char *filename); #endif /* CACHE_H */ diff --git a/checkout.h b/checkout.h index 6b2073310c..1152133bd7 100644 --- a/checkout.h +++ b/checkout.h @@ -8,8 +8,8 @@ * tracking branch. Return the name of the remote if such a branch * exists, NULL otherwise. */ -extern const char *unique_tracking_name(const char *name, - struct object_id *oid, - int *dwim_remotes_matched); +const char *unique_tracking_name(const char *name, + struct object_id *oid, + int *dwim_remotes_matched); #endif /* CHECKOUT_H */ diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index 52a44c690a..7f6acdd803 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -12,7 +12,7 @@ case "$jobname" in linux-clang|linux-gcc) sudo apt-add-repository -y "ppa:ubuntu-toolchain-r/test" sudo apt-get -q update - sudo apt-get -q -y install language-pack-is git-svn apache2 + sudo apt-get -q -y install language-pack-is libsvn-perl apache2 case "$jobname" in linux-gcc) sudo apt-get -q -y install gcc-8 diff --git a/column.h b/column.h index 2567a5cf4d..448c7440b3 100644 --- a/column.h +++ b/column.h @@ -27,20 +27,20 @@ struct column_options { }; struct option; -extern int parseopt_column_callback(const struct option *, const char *, int); -extern int git_column_config(const char *var, const char *value, - const char *command, unsigned int *colopts); -extern int finalize_colopts(unsigned int *colopts, int stdout_is_tty); +int parseopt_column_callback(const struct option *, const char *, int); +int git_column_config(const char *var, const char *value, + const char *command, unsigned int *colopts); +int finalize_colopts(unsigned int *colopts, int stdout_is_tty); static inline int column_active(unsigned int colopts) { return (colopts & COL_ENABLE_MASK) == COL_ENABLED; } struct string_list; -extern void print_columns(const struct string_list *list, unsigned int colopts, - const struct column_options *opts); +void print_columns(const struct string_list *list, unsigned int colopts, + const struct column_options *opts); -extern int run_column_filter(int colopts, const struct column_options *); -extern int stop_column_filter(void); +int run_column_filter(int colopts, const struct column_options *); +int stop_column_filter(void); #endif diff --git a/commit-graph.c b/commit-graph.c index 7bcc9bb7e0..7c5e54875f 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -267,8 +267,10 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd, last_chunk_offset = chunk_offset; } - if (verify_commit_graph_lite(graph)) + if (verify_commit_graph_lite(graph)) { + free(graph); return NULL; + } return graph; } diff --git a/commit.h b/commit.h index cc19cb5314..f5295ca7f3 100644 --- a/commit.h +++ b/commit.h @@ -184,10 +184,10 @@ void free_commit_list(struct commit_list *list); struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ -extern int has_non_ascii(const char *text); -extern const char *logmsg_reencode(const struct commit *commit, - char **commit_encoding, - const char *output_encoding); +int has_non_ascii(const char *text); +const char *logmsg_reencode(const struct commit *commit, + char **commit_encoding, + const char *output_encoding); const char *repo_logmsg_reencode(struct repository *r, const struct commit *commit, char **commit_encoding, @@ -196,7 +196,7 @@ const char *repo_logmsg_reencode(struct repository *r, #define logmsg_reencode(c, enc, out) repo_logmsg_reencode(the_repository, c, enc, out) #endif -extern const char *skip_blank_lines(const char *msg); +const char *skip_blank_lines(const char *msg); /** Removes the first commit from a list sorted by date, and adds all * of its parents. @@ -247,22 +247,22 @@ struct commit *get_fork_point(const char *refname, struct commit *commit); struct oid_array; struct ref; -extern int register_shallow(struct repository *r, const struct object_id *oid); -extern int unregister_shallow(const struct object_id *oid); -extern int for_each_commit_graft(each_commit_graft_fn, void *); -extern int is_repository_shallow(struct repository *r); -extern struct commit_list *get_shallow_commits(struct object_array *heads, - int depth, int shallow_flag, int not_shallow_flag); -extern struct commit_list *get_shallow_commits_by_rev_list( +int register_shallow(struct repository *r, const struct object_id *oid); +int unregister_shallow(const struct object_id *oid); +int for_each_commit_graft(each_commit_graft_fn, void *); +int is_repository_shallow(struct repository *r); +struct commit_list *get_shallow_commits(struct object_array *heads, + int depth, int shallow_flag, int not_shallow_flag); +struct commit_list *get_shallow_commits_by_rev_list( int ac, const char **av, int shallow_flag, int not_shallow_flag); -extern void set_alternate_shallow_file(struct repository *r, const char *path, int override); -extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol, - const struct oid_array *extra); -extern void setup_alternate_shallow(struct lock_file *shallow_lock, - const char **alternate_shallow_file, - const struct oid_array *extra); -extern const char *setup_temporary_shallow(const struct oid_array *extra); -extern void advertise_shallow_grafts(int); +void set_alternate_shallow_file(struct repository *r, const char *path, int override); +int write_shallow_commits(struct strbuf *out, int use_pack_protocol, + const struct oid_array *extra); +void setup_alternate_shallow(struct lock_file *shallow_lock, + const char **alternate_shallow_file, + const struct oid_array *extra); +const char *setup_temporary_shallow(const struct oid_array *extra); +void advertise_shallow_grafts(int); /* * Initialize with prepare_shallow_info() or zero-initialize (equivalent to @@ -283,21 +283,21 @@ struct shallow_info { int nr_commits; }; -extern void prepare_shallow_info(struct shallow_info *, struct oid_array *); -extern void clear_shallow_info(struct shallow_info *); -extern void remove_nonexistent_theirs_shallow(struct shallow_info *); -extern void assign_shallow_commits_to_refs(struct shallow_info *info, - uint32_t **used, - int *ref_status); -extern int delayed_reachability_test(struct shallow_info *si, int c); +void prepare_shallow_info(struct shallow_info *, struct oid_array *); +void clear_shallow_info(struct shallow_info *); +void remove_nonexistent_theirs_shallow(struct shallow_info *); +void assign_shallow_commits_to_refs(struct shallow_info *info, + uint32_t **used, + int *ref_status); +int delayed_reachability_test(struct shallow_info *si, int c); #define PRUNE_SHOW_ONLY 1 #define PRUNE_QUICK 2 -extern void prune_shallow(unsigned options); +void prune_shallow(unsigned options); extern struct trace_key trace_shallow; -extern int interactive_add(int argc, const char **argv, const char *prefix, int patch); -extern int run_add_interactive(const char *revision, const char *patch_mode, - const struct pathspec *pathspec); +int interactive_add(int argc, const char **argv, const char *prefix, int patch); +int run_add_interactive(const char *revision, const char *patch_mode, + const struct pathspec *pathspec); struct commit_extra_header { struct commit_extra_header *next; @@ -306,24 +306,24 @@ struct commit_extra_header { size_t len; }; -extern void append_merge_tag_headers(struct commit_list *parents, - struct commit_extra_header ***tail); +void append_merge_tag_headers(struct commit_list *parents, + struct commit_extra_header ***tail); -extern int commit_tree(const char *msg, size_t msg_len, - const struct object_id *tree, - struct commit_list *parents, struct object_id *ret, - const char *author, const char *sign_commit); +int commit_tree(const char *msg, size_t msg_len, + const struct object_id *tree, + struct commit_list *parents, struct object_id *ret, + const char *author, const char *sign_commit); -extern int commit_tree_extended(const char *msg, size_t msg_len, - const struct object_id *tree, - struct commit_list *parents, - struct object_id *ret, const char *author, - const char *sign_commit, - struct commit_extra_header *); +int commit_tree_extended(const char *msg, size_t msg_len, + const struct object_id *tree, + struct commit_list *parents, + struct object_id *ret, const char *author, + const char *sign_commit, + struct commit_extra_header *); -extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **); +struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **); -extern void free_commit_extra_headers(struct commit_extra_header *extra); +void free_commit_extra_headers(struct commit_extra_header *extra); /* * Search the commit object contents given by "msg" for the header "key". @@ -333,24 +333,24 @@ extern void free_commit_extra_headers(struct commit_extra_header *extra); * Note that some headers (like mergetag) may be multi-line. It is the caller's * responsibility to parse further in this case! */ -extern const char *find_commit_header(const char *msg, const char *key, - size_t *out_len); +const char *find_commit_header(const char *msg, const char *key, + size_t *out_len); /* Find the end of the log message, the right place for a new trailer. */ -extern size_t ignore_non_trailer(const char *buf, size_t len); +size_t ignore_non_trailer(const char *buf, size_t len); typedef int (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra, - void *cb_data); + void *cb_data); -extern int for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data); +int for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data); struct merge_remote_desc { struct object *obj; /* the named object, could be a tag */ char name[FLEX_ARRAY]; }; -extern struct merge_remote_desc *merge_remote_util(struct commit *); -extern void set_merge_remote_desc(struct commit *commit, - const char *name, struct object *obj); +struct merge_remote_desc *merge_remote_util(struct commit *); +void set_merge_remote_desc(struct commit *commit, + const char *name, struct object *obj); /* * Given "name" from the command line to merge, find the commit object @@ -359,9 +359,9 @@ extern void set_merge_remote_desc(struct commit *commit, */ struct commit *get_merge_parent(const char *name); -extern int parse_signed_commit(const struct commit *commit, - struct strbuf *message, struct strbuf *signature); -extern int remove_signature(struct strbuf *buf); +int parse_signed_commit(const struct commit *commit, + struct strbuf *message, struct strbuf *signature); +int remove_signature(struct strbuf *buf); /* * Check the signature of the given commit. The result of the check is stored @@ -370,7 +370,7 @@ extern int remove_signature(struct strbuf *buf); * at all. This may allocate memory for sig->gpg_output, sig->gpg_status, * sig->signer and sig->key. */ -extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc); +int check_commit_signature(const struct commit *commit, struct signature_check *sigc); /* record author-date for each commit object */ struct author_date_slab; @@ -390,6 +390,6 @@ int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused) int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused); LAST_ARG_MUST_BE_NULL -extern int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...); +int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...); #endif /* COMMIT_H */ diff --git a/common-main.c b/common-main.c index d484aec209..582a7b1886 100644 --- a/common-main.c +++ b/common-main.c @@ -27,6 +27,8 @@ int main(int argc, const char **argv) { int result; + trace2_initialize_clock(); + /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids messing up when the pipes are dup'ed @@ -35,11 +37,11 @@ int main(int argc, const char **argv) sanitize_stdfds(); restore_sigpipe_to_default(); + git_resolve_executable_dir(argv[0]); + trace2_initialize(); trace2_cmd_start(argv); - trace2_collect_process_info(); - - git_resolve_executable_dir(argv[0]); + trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP); git_setup_gettext(); diff --git a/compat/access.c b/compat/access.c new file mode 100644 index 0000000000..19fda3e877 --- /dev/null +++ b/compat/access.c @@ -0,0 +1,31 @@ +#define COMPAT_CODE_ACCESS +#include "../git-compat-util.h" + +/* Do the same thing access(2) does, but use the effective uid, + * and don't make the mistake of telling root that any file is + * executable. This version uses stat(2). + */ +int git_access(const char *path, int mode) +{ + struct stat st; + + /* do not interfere a normal user */ + if (geteuid()) + return access(path, mode); + + if (stat(path, &st) < 0) + return -1; + + /* Root can read or write any file. */ + if (!(mode & X_OK)) + return 0; + + /* Root can execute any file that has any one of the execute + * bits set. + */ + if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) + return 0; + + errno = EACCES; + return -1; +} diff --git a/compat/fileno.c b/compat/fileno.c index 7b105f4cd7..8e80ef335d 100644 --- a/compat/fileno.c +++ b/compat/fileno.c @@ -1,4 +1,4 @@ -#define COMPAT_CODE +#define COMPAT_CODE_FILENO #include "../git-compat-util.h" int git_fileno(FILE *stream) diff --git a/compat/mingw.c b/compat/mingw.c index 6b04514cdc..9b6d2400e1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1714,142 +1714,10 @@ int mingw_putenv(const char *namevalue) return result ? 0 : -1; } -/* - * Note, this isn't a complete replacement for getaddrinfo. It assumes - * that service contains a numerical port, or that it is null. It - * does a simple search using gethostbyname, and returns one IPv4 host - * if one was found. - */ -static int WSAAPI getaddrinfo_stub(const char *node, const char *service, - const struct addrinfo *hints, - struct addrinfo **res) -{ - struct hostent *h = NULL; - struct addrinfo *ai; - struct sockaddr_in *sin; - - if (node) { - h = gethostbyname(node); - if (!h) - return WSAGetLastError(); - } - - ai = xmalloc(sizeof(struct addrinfo)); - *res = ai; - ai->ai_flags = 0; - ai->ai_family = AF_INET; - ai->ai_socktype = hints ? hints->ai_socktype : 0; - switch (ai->ai_socktype) { - case SOCK_STREAM: - ai->ai_protocol = IPPROTO_TCP; - break; - case SOCK_DGRAM: - ai->ai_protocol = IPPROTO_UDP; - break; - default: - ai->ai_protocol = 0; - break; - } - ai->ai_addrlen = sizeof(struct sockaddr_in); - if (hints && (hints->ai_flags & AI_CANONNAME)) - ai->ai_canonname = h ? xstrdup(h->h_name) : NULL; - else - ai->ai_canonname = NULL; - - sin = xcalloc(1, ai->ai_addrlen); - sin->sin_family = AF_INET; - /* Note: getaddrinfo is supposed to allow service to be a string, - * which should be looked up using getservbyname. This is - * currently not implemented */ - if (service) - sin->sin_port = htons(atoi(service)); - if (h) - sin->sin_addr = *(struct in_addr *)h->h_addr; - else if (hints && (hints->ai_flags & AI_PASSIVE)) - sin->sin_addr.s_addr = INADDR_ANY; - else - sin->sin_addr.s_addr = INADDR_LOOPBACK; - ai->ai_addr = (struct sockaddr *)sin; - ai->ai_next = NULL; - return 0; -} - -static void WSAAPI freeaddrinfo_stub(struct addrinfo *res) -{ - free(res->ai_canonname); - free(res->ai_addr); - free(res); -} - -static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen, - char *host, DWORD hostlen, - char *serv, DWORD servlen, int flags) -{ - const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; - if (sa->sa_family != AF_INET) - return EAI_FAMILY; - if (!host && !serv) - return EAI_NONAME; - - if (host && hostlen > 0) { - struct hostent *ent = NULL; - if (!(flags & NI_NUMERICHOST)) - ent = gethostbyaddr((const char *)&sin->sin_addr, - sizeof(sin->sin_addr), AF_INET); - - if (ent) - snprintf(host, hostlen, "%s", ent->h_name); - else if (flags & NI_NAMEREQD) - return EAI_NONAME; - else - snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr)); - } - - if (serv && servlen > 0) { - struct servent *ent = NULL; - if (!(flags & NI_NUMERICSERV)) - ent = getservbyport(sin->sin_port, - flags & NI_DGRAM ? "udp" : "tcp"); - - if (ent) - snprintf(serv, servlen, "%s", ent->s_name); - else - snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); - } - - return 0; -} - -static HMODULE ipv6_dll = NULL; -static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res); -static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service, - const struct addrinfo *hints, - struct addrinfo **res); -static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen, - char *host, DWORD hostlen, - char *serv, DWORD servlen, int flags); -/* - * gai_strerror is an inline function in the ws2tcpip.h header, so we - * don't need to try to load that one dynamically. - */ - -static void socket_cleanup(void) -{ - WSACleanup(); - if (ipv6_dll) - FreeLibrary(ipv6_dll); - ipv6_dll = NULL; - ipv6_freeaddrinfo = freeaddrinfo_stub; - ipv6_getaddrinfo = getaddrinfo_stub; - ipv6_getnameinfo = getnameinfo_stub; -} - static void ensure_socket_initialization(void) { WSADATA wsa; static int initialized = 0; - const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL }; - const char **name; if (initialized) return; @@ -1858,35 +1726,7 @@ static void ensure_socket_initialization(void) die("unable to initialize winsock subsystem, error %d", WSAGetLastError()); - for (name = libraries; *name; name++) { - ipv6_dll = LoadLibraryExA(*name, NULL, - LOAD_LIBRARY_SEARCH_SYSTEM32); - if (!ipv6_dll) - continue; - - ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *)) - GetProcAddress(ipv6_dll, "freeaddrinfo"); - ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *, - const struct addrinfo *, - struct addrinfo **)) - GetProcAddress(ipv6_dll, "getaddrinfo"); - ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *, - socklen_t, char *, DWORD, - char *, DWORD, int)) - GetProcAddress(ipv6_dll, "getnameinfo"); - if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) { - FreeLibrary(ipv6_dll); - ipv6_dll = NULL; - } else - break; - } - if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) { - ipv6_freeaddrinfo = freeaddrinfo_stub; - ipv6_getaddrinfo = getaddrinfo_stub; - ipv6_getnameinfo = getnameinfo_stub; - } - - atexit(socket_cleanup); + atexit((void(*)(void)) WSACleanup); initialized = 1; } @@ -1904,24 +1744,12 @@ struct hostent *mingw_gethostbyname(const char *host) return gethostbyname(host); } -void mingw_freeaddrinfo(struct addrinfo *res) -{ - ipv6_freeaddrinfo(res); -} - +#undef getaddrinfo int mingw_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { ensure_socket_initialization(); - return ipv6_getaddrinfo(node, service, hints, res); -} - -int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen, - char *host, DWORD hostlen, char *serv, DWORD servlen, - int flags) -{ - ensure_socket_initialization(); - return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + return getaddrinfo(node, service, hints, res); } int mingw_socket(int domain, int type, int protocol) @@ -2569,6 +2397,8 @@ void mingw_startup(void) wchar_t **wenv, **wargv; _startupinfo si; + trace2_initialize_clock(); + maybe_redirect_std_handles(); /* get wide char arguments and environment */ diff --git a/compat/mingw.h b/compat/mingw.h index 4d73f8aa9d..593bdbffe6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -295,18 +295,10 @@ int mingw_gethostname(char *host, int namelen); struct hostent *mingw_gethostbyname(const char *host); #define gethostbyname mingw_gethostbyname -void mingw_freeaddrinfo(struct addrinfo *res); -#define freeaddrinfo mingw_freeaddrinfo - int mingw_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); #define getaddrinfo mingw_getaddrinfo -int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen, - char *host, DWORD hostlen, char *serv, DWORD servlen, - int flags); -#define getnameinfo mingw_getnameinfo - int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket diff --git a/compat/win32/trace2_win32_process_info.c b/compat/win32/trace2_win32_process_info.c index 52bd62034b..8ccbd1c2c6 100644 --- a/compat/win32/trace2_win32_process_info.c +++ b/compat/win32/trace2_win32_process_info.c @@ -1,5 +1,6 @@ #include "../../cache.h" #include "../../json-writer.h" +#include "lazyload.h" #include #include @@ -137,11 +138,54 @@ static void get_is_being_debugged(void) "windows/debugger_present", 1); } -void trace2_collect_process_info(void) +/* + * Emit JSON data with the peak memory usage of the current process. + */ +static void get_peak_memory_info(void) +{ + DECLARE_PROC_ADDR(psapi.dll, BOOL, GetProcessMemoryInfo, HANDLE, + PPROCESS_MEMORY_COUNTERS, DWORD); + + if (INIT_PROC_ADDR(GetProcessMemoryInfo)) { + PROCESS_MEMORY_COUNTERS pmc; + + if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, + sizeof(pmc))) { + struct json_writer jw = JSON_WRITER_INIT; + + jw_object_begin(&jw, 0); + +#define KV(kv) #kv, (intmax_t)pmc.kv + + jw_object_intmax(&jw, KV(PageFaultCount)); + jw_object_intmax(&jw, KV(PeakWorkingSetSize)); + jw_object_intmax(&jw, KV(PeakPagefileUsage)); + + jw_end(&jw); + + trace2_data_json("process", the_repository, + "windows/memory", &jw); + jw_release(&jw); + } + } +} + +void trace2_collect_process_info(enum trace2_process_info_reason reason) { if (!trace2_is_enabled()) return; - get_is_being_debugged(); - get_ancestry(); + switch (reason) { + case TRACE2_PROCESS_INFO_STARTUP: + get_is_being_debugged(); + get_ancestry(); + return; + + case TRACE2_PROCESS_INFO_EXIT: + get_peak_memory_info(); + return; + + default: + BUG("trace2_collect_process_info: unknown reason '%d'", reason); + } } diff --git a/config.c b/config.c index c2846df3f1..296a6d9cc4 100644 --- a/config.c +++ b/config.c @@ -1676,7 +1676,9 @@ static int do_git_config_sequence(const struct config_options *opts, repo_config = NULL; current_parsing_scope = CONFIG_SCOPE_SYSTEM; - if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) + if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, + opts->system_gently ? + ACCESS_EACCES_OK : 0)) ret += git_config_from_file(fn, git_etc_gitconfig(), data); @@ -1688,14 +1690,15 @@ static int do_git_config_sequence(const struct config_options *opts, ret += git_config_from_file(fn, user_config, data); current_parsing_scope = CONFIG_SCOPE_REPO; - if (repo_config && !access_or_die(repo_config, R_OK, 0)) + if (!opts->ignore_repo && repo_config && + !access_or_die(repo_config, R_OK, 0)) ret += git_config_from_file(fn, repo_config, data); /* * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE. * But let's not complicate things before it's actually needed. */ - if (repository_format_worktree_config) { + if (!opts->ignore_worktree && repository_format_worktree_config) { char *path = git_pathdup("config.worktree"); if (!access_or_die(path, R_OK, 0)) ret += git_config_from_file(fn, path, data); @@ -1703,7 +1706,7 @@ static int do_git_config_sequence(const struct config_options *opts, } current_parsing_scope = CONFIG_SCOPE_CMDLINE; - if (git_config_from_parameters(fn, data) < 0) + if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0) die(_("unable to parse command-line config")); current_parsing_scope = CONFIG_SCOPE_UNKNOWN; @@ -1794,6 +1797,23 @@ void read_early_config(config_fn_t cb, void *data) strbuf_release(&gitdir); } +/* + * Read config but only enumerate system and global settings. + * Omit any repo-local, worktree-local, or command-line settings. + */ +void read_very_early_config(config_fn_t cb, void *data) +{ + struct config_options opts = { 0 }; + + opts.respect_includes = 1; + opts.ignore_repo = 1; + opts.ignore_worktree = 1; + opts.ignore_cmdline = 1; + opts.system_gently = 1; + + config_with_options(cb, data, NULL, &opts); +} + static struct config_set_element *configset_find_element(struct config_set *cs, const char *key) { struct config_set_element k; @@ -2011,7 +2031,7 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha /* Functions use to read configuration from a repository */ static void repo_read_config(struct repository *repo) { - struct config_options opts; + struct config_options opts = { 0 }; opts.respect_includes = 1; opts.commondir = repo->commondir; diff --git a/config.h b/config.h index ee5d3fa7b4..f0ed464004 100644 --- a/config.h +++ b/config.h @@ -55,6 +55,10 @@ typedef int (*config_parser_event_fn_t)(enum config_event_t type, struct config_options { unsigned int respect_includes : 1; + unsigned int ignore_repo : 1; + unsigned int ignore_worktree : 1; + unsigned int ignore_cmdline : 1; + unsigned int system_gently : 1; const char *commondir; const char *git_dir; config_parser_event_fn_t event_fn; @@ -68,62 +72,63 @@ struct config_options { }; typedef int (*config_fn_t)(const char *, const char *, void *); -extern int git_default_config(const char *, const char *, void *); -extern int git_config_from_file(config_fn_t fn, const char *, void *); -extern int git_config_from_file_with_options(config_fn_t fn, const char *, - void *, - const struct config_options *); -extern int git_config_from_mem(config_fn_t fn, - const enum config_origin_type, - const char *name, - const char *buf, size_t len, - void *data, const struct config_options *opts); -extern int git_config_from_blob_oid(config_fn_t fn, const char *name, - const struct object_id *oid, void *data); -extern void git_config_push_parameter(const char *text); -extern int git_config_from_parameters(config_fn_t fn, void *data); -extern void read_early_config(config_fn_t cb, void *data); -extern void git_config(config_fn_t fn, void *); -extern int config_with_options(config_fn_t fn, void *, - struct git_config_source *config_source, - const struct config_options *opts); -extern int git_parse_ssize_t(const char *, ssize_t *); -extern int git_parse_ulong(const char *, unsigned long *); -extern int git_parse_maybe_bool(const char *); -extern int git_config_int(const char *, const char *); -extern int64_t git_config_int64(const char *, const char *); -extern unsigned long git_config_ulong(const char *, const char *); -extern ssize_t git_config_ssize_t(const char *, const char *); -extern int git_config_bool_or_int(const char *, const char *, int *); -extern int git_config_bool(const char *, const char *); -extern int git_config_string(const char **, const char *, const char *); -extern int git_config_pathname(const char **, const char *, const char *); -extern int git_config_expiry_date(timestamp_t *, const char *, const char *); -extern int git_config_color(char *, const char *, const char *); -extern int git_config_set_in_file_gently(const char *, const char *, const char *); -extern void git_config_set_in_file(const char *, const char *, const char *); -extern int git_config_set_gently(const char *, const char *); -extern void git_config_set(const char *, const char *); -extern int git_config_parse_key(const char *, char **, int *); -extern int git_config_key_is_valid(const char *key); -extern int git_config_set_multivar_gently(const char *, const char *, const char *, int); -extern void git_config_set_multivar(const char *, const char *, const char *, int); -extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int); -extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); -extern int git_config_rename_section(const char *, const char *); -extern int git_config_rename_section_in_file(const char *, const char *, const char *); -extern int git_config_copy_section(const char *, const char *); -extern int git_config_copy_section_in_file(const char *, const char *, const char *); -extern const char *git_etc_gitconfig(void); -extern int git_env_bool(const char *, int); -extern unsigned long git_env_ulong(const char *, unsigned long); -extern int git_config_system(void); -extern int config_error_nonbool(const char *); +int git_default_config(const char *, const char *, void *); +int git_config_from_file(config_fn_t fn, const char *, void *); +int git_config_from_file_with_options(config_fn_t fn, const char *, + void *, + const struct config_options *); +int git_config_from_mem(config_fn_t fn, + const enum config_origin_type, + const char *name, + const char *buf, size_t len, + void *data, const struct config_options *opts); +int git_config_from_blob_oid(config_fn_t fn, const char *name, + const struct object_id *oid, void *data); +void git_config_push_parameter(const char *text); +int git_config_from_parameters(config_fn_t fn, void *data); +void read_early_config(config_fn_t cb, void *data); +void read_very_early_config(config_fn_t cb, void *data); +void git_config(config_fn_t fn, void *); +int config_with_options(config_fn_t fn, void *, + struct git_config_source *config_source, + const struct config_options *opts); +int git_parse_ssize_t(const char *, ssize_t *); +int git_parse_ulong(const char *, unsigned long *); +int git_parse_maybe_bool(const char *); +int git_config_int(const char *, const char *); +int64_t git_config_int64(const char *, const char *); +unsigned long git_config_ulong(const char *, const char *); +ssize_t git_config_ssize_t(const char *, const char *); +int git_config_bool_or_int(const char *, const char *, int *); +int git_config_bool(const char *, const char *); +int git_config_string(const char **, const char *, const char *); +int git_config_pathname(const char **, const char *, const char *); +int git_config_expiry_date(timestamp_t *, const char *, const char *); +int git_config_color(char *, const char *, const char *); +int git_config_set_in_file_gently(const char *, const char *, const char *); +void git_config_set_in_file(const char *, const char *, const char *); +int git_config_set_gently(const char *, const char *); +void git_config_set(const char *, const char *); +int git_config_parse_key(const char *, char **, int *); +int git_config_key_is_valid(const char *key); +int git_config_set_multivar_gently(const char *, const char *, const char *, int); +void git_config_set_multivar(const char *, const char *, const char *, int); +int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int); +void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); +int git_config_rename_section(const char *, const char *); +int git_config_rename_section_in_file(const char *, const char *, const char *); +int git_config_copy_section(const char *, const char *); +int git_config_copy_section_in_file(const char *, const char *, const char *); +const char *git_etc_gitconfig(void); +int git_env_bool(const char *, int); +unsigned long git_env_ulong(const char *, unsigned long); +int git_config_system(void); +int config_error_nonbool(const char *); #if defined(__GNUC__) #define config_error_nonbool(s) (config_error_nonbool(s), const_error()) #endif -extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data); +int git_config_parse_parameter(const char *, config_fn_t fn, void *data); enum config_scope { CONFIG_SCOPE_UNKNOWN = 0, @@ -133,9 +138,9 @@ enum config_scope { CONFIG_SCOPE_CMDLINE, }; -extern enum config_scope current_config_scope(void); -extern const char *current_config_origin_type(void); -extern const char *current_config_name(void); +enum config_scope current_config_scope(void); +const char *current_config_origin_type(void); +const char *current_config_name(void); struct config_include_data { int depth; @@ -144,7 +149,7 @@ struct config_include_data { const struct config_options *opts; }; #define CONFIG_INCLUDE_INIT { 0 } -extern int git_config_include(const char *name, const char *value, void *data); +int git_config_include(const char *name, const char *value, void *data); /* * Match and parse a config key of the form: @@ -159,10 +164,10 @@ extern int git_config_include(const char *name, const char *value, void *data); * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if * there is no subsection at all. */ -extern int parse_config_key(const char *var, - const char *section, - const char **subsection, int *subsection_len, - const char **key); +int parse_config_key(const char *var, + const char *section, + const char **subsection, int *subsection_len, + const char **key); struct config_set_element { struct hashmap_entry ent; @@ -192,71 +197,71 @@ struct config_set { struct configset_list list; }; -extern void git_configset_init(struct config_set *cs); -extern int git_configset_add_file(struct config_set *cs, const char *filename); -extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key); -extern void git_configset_clear(struct config_set *cs); +void git_configset_init(struct config_set *cs); +int git_configset_add_file(struct config_set *cs, const char *filename); +const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key); +void git_configset_clear(struct config_set *cs); /* * These functions return 1 if not found, and 0 if found, leaving the found * value in the 'dest' pointer. */ -extern int git_configset_get_value(struct config_set *cs, const char *key, const char **dest); -extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest); -extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest); -extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest); -extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest); -extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest); -extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest); -extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest); -extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest); +int git_configset_get_value(struct config_set *cs, const char *key, const char **dest); +int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest); +int git_configset_get_string(struct config_set *cs, const char *key, char **dest); +int git_configset_get_int(struct config_set *cs, const char *key, int *dest); +int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest); +int git_configset_get_bool(struct config_set *cs, const char *key, int *dest); +int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest); +int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest); +int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest); /* Functions for reading a repository's config */ struct repository; -extern void repo_config(struct repository *repo, config_fn_t fn, void *data); -extern int repo_config_get_value(struct repository *repo, - const char *key, const char **value); -extern const struct string_list *repo_config_get_value_multi(struct repository *repo, - const char *key); -extern int repo_config_get_string_const(struct repository *repo, - const char *key, const char **dest); -extern int repo_config_get_string(struct repository *repo, - const char *key, char **dest); -extern int repo_config_get_int(struct repository *repo, +void repo_config(struct repository *repo, config_fn_t fn, void *data); +int repo_config_get_value(struct repository *repo, + const char *key, const char **value); +const struct string_list *repo_config_get_value_multi(struct repository *repo, + const char *key); +int repo_config_get_string_const(struct repository *repo, + const char *key, const char **dest); +int repo_config_get_string(struct repository *repo, + const char *key, char **dest); +int repo_config_get_int(struct repository *repo, + const char *key, int *dest); +int repo_config_get_ulong(struct repository *repo, + const char *key, unsigned long *dest); +int repo_config_get_bool(struct repository *repo, + const char *key, int *dest); +int repo_config_get_bool_or_int(struct repository *repo, + const char *key, int *is_bool, int *dest); +int repo_config_get_maybe_bool(struct repository *repo, const char *key, int *dest); -extern int repo_config_get_ulong(struct repository *repo, - const char *key, unsigned long *dest); -extern int repo_config_get_bool(struct repository *repo, - const char *key, int *dest); -extern int repo_config_get_bool_or_int(struct repository *repo, - const char *key, int *is_bool, int *dest); -extern int repo_config_get_maybe_bool(struct repository *repo, - const char *key, int *dest); -extern int repo_config_get_pathname(struct repository *repo, - const char *key, const char **dest); +int repo_config_get_pathname(struct repository *repo, + const char *key, const char **dest); -extern int git_config_get_value(const char *key, const char **value); -extern const struct string_list *git_config_get_value_multi(const char *key); -extern void git_config_clear(void); -extern int git_config_get_string_const(const char *key, const char **dest); -extern int git_config_get_string(const char *key, char **dest); -extern int git_config_get_int(const char *key, int *dest); -extern int git_config_get_ulong(const char *key, unsigned long *dest); -extern int git_config_get_bool(const char *key, int *dest); -extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); -extern int git_config_get_maybe_bool(const char *key, int *dest); -extern int git_config_get_pathname(const char *key, const char **dest); -extern int git_config_get_index_threads(int *dest); -extern int git_config_get_untracked_cache(void); -extern int git_config_get_split_index(void); -extern int git_config_get_max_percent_split_change(void); -extern int git_config_get_fsmonitor(void); +int git_config_get_value(const char *key, const char **value); +const struct string_list *git_config_get_value_multi(const char *key); +void git_config_clear(void); +int git_config_get_string_const(const char *key, const char **dest); +int git_config_get_string(const char *key, char **dest); +int git_config_get_int(const char *key, int *dest); +int git_config_get_ulong(const char *key, unsigned long *dest); +int git_config_get_bool(const char *key, int *dest); +int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); +int git_config_get_maybe_bool(const char *key, int *dest); +int git_config_get_pathname(const char *key, const char **dest); +int git_config_get_index_threads(int *dest); +int git_config_get_untracked_cache(void); +int git_config_get_split_index(void); +int git_config_get_max_percent_split_change(void); +int git_config_get_fsmonitor(void); /* This dies if the configured or default date is in the future */ -extern int git_config_get_expiry(const char *key, const char **output); +int git_config_get_expiry(const char *key, const char **output); /* parse either "this many days" integer, or "5.days.ago" approxidate */ -extern int git_config_get_expiry_in_days(const char *key, timestamp_t *, timestamp_t now); +int git_config_get_expiry_in_days(const char *key, timestamp_t *, timestamp_t now); struct key_value_info { const char *filename; @@ -265,8 +270,8 @@ struct key_value_info { enum config_scope scope; }; -extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3))); -extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr); +NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3))); +NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr); #define LOOKUP_CONFIG(mapping, var) \ lookup_config(mapping, ARRAY_SIZE(mapping), var) diff --git a/config.mak.uname b/config.mak.uname index d916d1dc7a..b71688eeb7 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -272,6 +272,7 @@ ifeq ($(uname_S),AIX) NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -D_LARGE_FILES FILENO_IS_A_MACRO = UnfortunatelyYes + NEED_ACCESS_ROOT_HANDLER = UnfortunatelyYes ifeq ($(shell expr "$(uname_V)" : '[1234]'),1) NO_PTHREADS = YesPlease else @@ -575,13 +576,21 @@ else ifneq ($(shell expr "$(uname_R)" : '1\.'),2) # MSys2 prefix = /usr/ + # Enable DEP + BASIC_LDFLAGS += -Wl,--nxcompat + # Enable ASLR (unless debugging) + ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS)))) + BASIC_LDFLAGS += -Wl,--dynamicbase + endif ifeq (MINGW32,$(MSYSTEM)) prefix = /mingw32 HOST_CPU = i686 + BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup endif ifeq (MINGW64,$(MSYSTEM)) prefix = /mingw64 HOST_CPU = x86_64 + BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup else COMPAT_CFLAGS += -D_USE_32BIT_TIME_T BASIC_LDFLAGS += -Wl,--large-address-aware diff --git a/connect.h b/connect.h index 32aff60979..5f2382e018 100644 --- a/connect.h +++ b/connect.h @@ -7,19 +7,19 @@ #define CONNECT_DIAG_URL (1u << 1) #define CONNECT_IPV4 (1u << 2) #define CONNECT_IPV6 (1u << 3) -extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); -extern int finish_connect(struct child_process *conn); -extern int git_connection_is_socket(struct child_process *conn); -extern int server_supports(const char *feature); -extern int parse_feature_request(const char *features, const char *feature); -extern const char *server_feature_value(const char *feature, int *len_ret); -extern int url_is_local_not_ssh(const char *url); +struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); +int finish_connect(struct child_process *conn); +int git_connection_is_socket(struct child_process *conn); +int server_supports(const char *feature); +int parse_feature_request(const char *features, const char *feature); +const char *server_feature_value(const char *feature, int *len_ret); +int url_is_local_not_ssh(const char *url); struct packet_reader; -extern enum protocol_version discover_version(struct packet_reader *reader); +enum protocol_version discover_version(struct packet_reader *reader); -extern int server_supports_v2(const char *c, int die_on_error); -extern int server_supports_feature(const char *c, const char *feature, - int die_on_error); +int server_supports_v2(const char *c, int die_on_error); +int server_supports_feature(const char *c, const char *feature, + int die_on_error); #endif diff --git a/connected.c b/connected.c index 1bba888eff..1ab481fed6 100644 --- a/connected.c +++ b/connected.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "object-store.h" #include "run-command.h" #include "sigchain.h" #include "connected.h" @@ -49,6 +50,22 @@ int check_connected(oid_iterate_fn fn, void *cb_data, strbuf_release(&idx_file); } + if (opt->check_refs_only) { + /* + * For partial clones, we don't want to have to do a regular + * connectivity check because we have to enumerate and exclude + * all promisor objects (slow), and then the connectivity check + * itself becomes a no-op because in a partial clone every + * object is a promisor object. Instead, just make sure we + * received the objects pointed to by each wanted ref. + */ + do { + if (!repo_has_object_file(the_repository, &oid)) + return 1; + } while (!fn(cb_data, &oid)); + return 0; + } + if (opt->shallow_file) { argv_array_push(&rev_list.args, "--shallow-file"); argv_array_push(&rev_list.args, opt->shallow_file); diff --git a/connected.h b/connected.h index 8d5a6b3ad6..ce2e7d8f2e 100644 --- a/connected.h +++ b/connected.h @@ -46,6 +46,14 @@ struct check_connected_options { * during a fetch. */ unsigned is_deepening_fetch : 1; + + /* + * If non-zero, only check the top-level objects referenced by the + * wanted refs (passed in as cb_data). This is useful for partial + * clones, where enumerating and excluding all promisor objects is very + * slow and the commit-walk itself becomes a no-op. + */ + unsigned check_refs_only : 1; }; #define CHECK_CONNECTED_INIT { 0 } diff --git a/contrib/diff-highlight/DiffHighlight.pm b/contrib/diff-highlight/DiffHighlight.pm index 536754583b..7440aa1c46 100644 --- a/contrib/diff-highlight/DiffHighlight.pm +++ b/contrib/diff-highlight/DiffHighlight.pm @@ -4,6 +4,11 @@ package DiffHighlight; use warnings FATAL => 'all'; use strict; +# Use the correct value for both UNIX and Windows (/dev/null vs nul) +use File::Spec; + +my $NULL = File::Spec->devnull(); + # Highlight by reversing foreground and background. You could do # other things like bold or underline if you prefer. my @OLD_HIGHLIGHT = ( @@ -134,7 +139,7 @@ sub highlight_stdin { # fallback, which means we will work even if git can't be run. sub color_config { my ($key, $default) = @_; - my $s = `git config --get-color $key 2>/dev/null`; + my $s = `git config --get-color $key 2>$NULL`; return length($s) ? $s : $default; } diff --git a/csum-file.h b/csum-file.h index 3bf7184736..a98b1eee53 100644 --- a/csum-file.h +++ b/csum-file.h @@ -25,22 +25,22 @@ struct hashfile_checkpoint { git_hash_ctx ctx; }; -extern void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *); -extern int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *); +void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *); +int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *); /* finalize_hashfile flags */ #define CSUM_CLOSE 1 #define CSUM_FSYNC 2 #define CSUM_HASH_IN_STREAM 4 -extern struct hashfile *hashfd(int fd, const char *name); -extern struct hashfile *hashfd_check(const char *name); -extern struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp); -extern int finalize_hashfile(struct hashfile *, unsigned char *, unsigned int); -extern void hashwrite(struct hashfile *, const void *, unsigned int); -extern void hashflush(struct hashfile *f); -extern void crc32_begin(struct hashfile *); -extern uint32_t crc32_end(struct hashfile *); +struct hashfile *hashfd(int fd, const char *name); +struct hashfile *hashfd_check(const char *name); +struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp); +int finalize_hashfile(struct hashfile *, unsigned char *, unsigned int); +void hashwrite(struct hashfile *, const void *, unsigned int); +void hashflush(struct hashfile *f); +void crc32_begin(struct hashfile *); +uint32_t crc32_end(struct hashfile *); static inline void hashwrite_u8(struct hashfile *f, uint8_t data) { diff --git a/decorate.h b/decorate.h index 9014c1e996..ee43dee1f0 100644 --- a/decorate.h +++ b/decorate.h @@ -50,12 +50,12 @@ struct decoration { * NULL), returning the previously associated pointer. If there is no previous * association, this function returns NULL. */ -extern void *add_decoration(struct decoration *n, const struct object *obj, void *decoration); +void *add_decoration(struct decoration *n, const struct object *obj, void *decoration); /* * Return the pointer associated to the given object. If there is no * association, this function returns NULL. */ -extern void *lookup_decoration(struct decoration *n, const struct object *obj); +void *lookup_decoration(struct decoration *n, const struct object *obj); #endif diff --git a/delta.h b/delta.h index 9b67531dfa..2df5fe13d9 100644 --- a/delta.h +++ b/delta.h @@ -13,7 +13,7 @@ struct delta_index; * before free_delta_index() is called. The returned pointer must be freed * using free_delta_index(). */ -extern struct delta_index * +struct delta_index * create_delta_index(const void *buf, unsigned long bufsize); /* @@ -21,14 +21,14 @@ create_delta_index(const void *buf, unsigned long bufsize); * * Given pointer must be what create_delta_index() returned, or NULL. */ -extern void free_delta_index(struct delta_index *index); +void free_delta_index(struct delta_index *index); /* * sizeof_delta_index: returns memory usage of delta index * * Given pointer must be what create_delta_index() returned, or NULL. */ -extern unsigned long sizeof_delta_index(struct delta_index *index); +unsigned long sizeof_delta_index(struct delta_index *index); /* * create_delta: create a delta from given index for the given buffer @@ -40,7 +40,7 @@ extern unsigned long sizeof_delta_index(struct delta_index *index); * returned and *delta_size is updated with its size. The returned buffer * must be freed by the caller. */ -extern void * +void * create_delta(const struct delta_index *index, const void *buf, unsigned long bufsize, unsigned long *delta_size, unsigned long max_delta_size); @@ -75,9 +75,9 @@ diff_delta(const void *src_buf, unsigned long src_bufsize, * *trg_bufsize is updated with its size. On failure a NULL pointer is * returned. The returned buffer must be freed by the caller. */ -extern void *patch_delta(const void *src_buf, unsigned long src_size, - const void *delta_buf, unsigned long delta_size, - unsigned long *dst_size); +void *patch_delta(const void *src_buf, unsigned long src_size, + const void *delta_buf, unsigned long delta_size, + unsigned long *dst_size); /* the smallest possible delta size is 4 bytes */ #define DELTA_SIZE_MIN 4 diff --git a/dir.h b/dir.h index c23313b021..680079bbe3 100644 --- a/dir.h +++ b/dir.h @@ -202,7 +202,7 @@ struct dir_struct { }; /*Count the number of slashes for string s*/ -extern int count_slashes(const char *s); +int count_slashes(const char *s); /* * The ordering of these constants is significant, with @@ -213,27 +213,27 @@ extern int count_slashes(const char *s); #define MATCHED_RECURSIVELY 1 #define MATCHED_FNMATCH 2 #define MATCHED_EXACTLY 3 -extern int simple_length(const char *match); -extern int no_wildcard(const char *string); -extern char *common_prefix(const struct pathspec *pathspec); -extern int match_pathspec(const struct index_state *istate, - const struct pathspec *pathspec, - const char *name, int namelen, - int prefix, char *seen, int is_dir); -extern int report_path_error(const char *ps_matched, const struct pathspec *pathspec); -extern int within_depth(const char *name, int namelen, int depth, int max_depth); - -extern int fill_directory(struct dir_struct *dir, - struct index_state *istate, - const struct pathspec *pathspec); -extern int read_directory(struct dir_struct *, struct index_state *istate, - const char *path, int len, - const struct pathspec *pathspec); - -extern int is_excluded_from_list(const char *pathname, int pathlen, - const char *basename, int *dtype, - struct exclude_list *el, - struct index_state *istate); +int simple_length(const char *match); +int no_wildcard(const char *string); +char *common_prefix(const struct pathspec *pathspec); +int match_pathspec(const struct index_state *istate, + const struct pathspec *pathspec, + const char *name, int namelen, + int prefix, char *seen, int is_dir); +int report_path_error(const char *ps_matched, const struct pathspec *pathspec); +int within_depth(const char *name, int namelen, int depth, int max_depth); + +int fill_directory(struct dir_struct *dir, + struct index_state *istate, + const struct pathspec *pathspec); +int read_directory(struct dir_struct *, struct index_state *istate, + const char *path, int len, + const struct pathspec *pathspec); + +int is_excluded_from_list(const char *pathname, int pathlen, + const char *basename, int *dtype, + struct exclude_list *el, + struct index_state *istate); struct dir_entry *dir_add_ignored(struct dir_struct *dir, struct index_state *istate, const char *pathname, int len); @@ -242,39 +242,39 @@ struct dir_entry *dir_add_ignored(struct dir_struct *dir, * these implement the matching logic for dir.c:excluded_from_list and * attr.c:path_matches() */ -extern int match_basename(const char *, int, - const char *, int, int, unsigned); -extern int match_pathname(const char *, int, - const char *, int, - const char *, int, int, unsigned); - -extern struct exclude *last_exclude_matching(struct dir_struct *dir, - struct index_state *istate, - const char *name, int *dtype); - -extern int is_excluded(struct dir_struct *dir, - struct index_state *istate, - const char *name, int *dtype); - -extern struct exclude_list *add_exclude_list(struct dir_struct *dir, - int group_type, const char *src); -extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, - struct exclude_list *el, struct index_state *istate); -extern void add_excludes_from_file(struct dir_struct *, const char *fname); -extern int add_excludes_from_blob_to_list(struct object_id *oid, - const char *base, int baselen, - struct exclude_list *el); -extern void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen); -extern void add_exclude(const char *string, const char *base, - int baselen, struct exclude_list *el, int srcpos); -extern void clear_exclude_list(struct exclude_list *el); -extern void clear_directory(struct dir_struct *dir); +int match_basename(const char *, int, + const char *, int, int, unsigned); +int match_pathname(const char *, int, + const char *, int, + const char *, int, int, unsigned); + +struct exclude *last_exclude_matching(struct dir_struct *dir, + struct index_state *istate, + const char *name, int *dtype); + +int is_excluded(struct dir_struct *dir, + struct index_state *istate, + const char *name, int *dtype); + +struct exclude_list *add_exclude_list(struct dir_struct *dir, + int group_type, const char *src); +int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, + struct exclude_list *el, struct index_state *istate); +void add_excludes_from_file(struct dir_struct *, const char *fname); +int add_excludes_from_blob_to_list(struct object_id *oid, + const char *base, int baselen, + struct exclude_list *el); +void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen); +void add_exclude(const char *string, const char *base, + int baselen, struct exclude_list *el, int srcpos); +void clear_exclude_list(struct exclude_list *el); +void clear_directory(struct dir_struct *dir); int repo_file_exists(struct repository *repo, const char *path); int file_exists(const char *); -extern int is_inside_dir(const char *dir); -extern int dir_inside_of(const char *subdir, const char *dir); +int is_inside_dir(const char *dir); +int dir_inside_of(const char *subdir, const char *dir); static inline int is_dot_or_dotdot(const char *name) { @@ -283,9 +283,9 @@ static inline int is_dot_or_dotdot(const char *name) (name[1] == '.' && name[2] == '\0'))); } -extern int is_empty_dir(const char *dir); +int is_empty_dir(const char *dir); -extern void setup_standard_excludes(struct dir_struct *dir); +void setup_standard_excludes(struct dir_struct *dir); /* Constants for remove_dir_recursively: */ @@ -313,26 +313,26 @@ extern void setup_standard_excludes(struct dir_struct *dir); * This function uses path as temporary scratch space, but restores it * before returning. */ -extern int remove_dir_recursively(struct strbuf *path, int flag); +int remove_dir_recursively(struct strbuf *path, int flag); /* tries to remove the path with empty directories along it, ignores ENOENT */ -extern int remove_path(const char *path); +int remove_path(const char *path); -extern int fspathcmp(const char *a, const char *b); -extern int fspathncmp(const char *a, const char *b, size_t count); +int fspathcmp(const char *a, const char *b); +int fspathncmp(const char *a, const char *b, size_t count); /* * The prefix part of pattern must not contains wildcards. */ struct pathspec_item; -extern int git_fnmatch(const struct pathspec_item *item, - const char *pattern, const char *string, - int prefix); +int git_fnmatch(const struct pathspec_item *item, + const char *pattern, const char *string, + int prefix); -extern int submodule_path_match(const struct index_state *istate, - const struct pathspec *ps, - const char *submodule_name, - char *seen); +int submodule_path_match(const struct index_state *istate, + const struct pathspec *ps, + const char *submodule_name, + char *seen); static inline int ce_path_match(const struct index_state *istate, const struct cache_entry *ce, @@ -374,10 +374,10 @@ void remove_untracked_cache(struct index_state *istate); * When `recurse_into_nested` is set, recurse into any nested submodules, * connecting them as well. */ -extern void connect_work_tree_and_git_dir(const char *work_tree, - const char *git_dir, - int recurse_into_nested); -extern void relocate_gitdir(const char *path, - const char *old_git_dir, - const char *new_git_dir); +void connect_work_tree_and_git_dir(const char *work_tree, + const char *git_dir, + int recurse_into_nested); +void relocate_gitdir(const char *path, + const char *old_git_dir, + const char *new_git_dir); #endif diff --git a/exec-cmd.h b/exec-cmd.h index 2522453cda..8cd1df28d3 100644 --- a/exec-cmd.h +++ b/exec-cmd.h @@ -3,14 +3,14 @@ struct argv_array; -extern void git_set_exec_path(const char *exec_path); -extern void git_resolve_executable_dir(const char *path); -extern const char *git_exec_path(void); -extern void setup_path(void); -extern const char **prepare_git_cmd(struct argv_array *out, const char **argv); -extern int execv_git_cmd(const char **argv); /* NULL terminated */ +void git_set_exec_path(const char *exec_path); +void git_resolve_executable_dir(const char *path); +const char *git_exec_path(void); +void setup_path(void); +const char **prepare_git_cmd(struct argv_array *out, const char **argv); +int execv_git_cmd(const char **argv); /* NULL terminated */ LAST_ARG_MUST_BE_NULL -extern int execl_git_cmd(const char *cmd, ...); -extern char *system_path(const char *path); +int execl_git_cmd(const char *cmd, ...); +char *system_path(const char *path); #endif /* GIT_EXEC_CMD_H */ diff --git a/fmt-merge-msg.h b/fmt-merge-msg.h index b28d3a6113..01e3aa88c5 100644 --- a/fmt-merge-msg.h +++ b/fmt-merge-msg.h @@ -2,6 +2,6 @@ #define FMT_MERGE_MSG_H extern int merge_log_config; -extern int fmt_merge_msg_config(const char *key, const char *value, void *cb); +int fmt_merge_msg_config(const char *key, const char *value, void *cb); #endif /* FMT_MERGE_MSG_H */ diff --git a/fsmonitor.c b/fsmonitor.c index 665bd2d425..1dee0aded1 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -129,7 +129,6 @@ static void fsmonitor_refresh_callback(struct index_state *istate, const char *n void refresh_fsmonitor(struct index_state *istate) { - static int has_run_once = 0; struct strbuf query_result = STRBUF_INIT; int query_success = 0; size_t bol; /* beginning of line */ @@ -137,9 +136,9 @@ void refresh_fsmonitor(struct index_state *istate) char *buf; int i; - if (!core_fsmonitor || has_run_once) + if (!core_fsmonitor || istate->fsmonitor_has_run_once) return; - has_run_once = 1; + istate->fsmonitor_has_run_once = 1; trace_printf_key(&trace_fsmonitor, "refresh fsmonitor"); /* diff --git a/fsmonitor.h b/fsmonitor.h index 01017c43aa..8489fa3244 100644 --- a/fsmonitor.h +++ b/fsmonitor.h @@ -10,31 +10,31 @@ extern struct trace_key trace_fsmonitor; * Read the fsmonitor index extension and (if configured) restore the * CE_FSMONITOR_VALID state. */ -extern int read_fsmonitor_extension(struct index_state *istate, const void *data, unsigned long sz); +int read_fsmonitor_extension(struct index_state *istate, const void *data, unsigned long sz); /* * Fill the fsmonitor_dirty ewah bits with their state from the index, * before it is split during writing. */ -extern void fill_fsmonitor_bitmap(struct index_state *istate); +void fill_fsmonitor_bitmap(struct index_state *istate); /* * Write the CE_FSMONITOR_VALID state into the fsmonitor index * extension. Reads from the fsmonitor_dirty ewah in the index. */ -extern void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate); +void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate); /* * Add/remove the fsmonitor index extension */ -extern void add_fsmonitor(struct index_state *istate); -extern void remove_fsmonitor(struct index_state *istate); +void add_fsmonitor(struct index_state *istate); +void remove_fsmonitor(struct index_state *istate); /* * Add/remove the fsmonitor index extension as necessary based on the current * core.fsmonitor setting. */ -extern void tweak_fsmonitor(struct index_state *istate); +void tweak_fsmonitor(struct index_state *istate); /* * Run the configured fsmonitor integration script and clear the @@ -42,7 +42,7 @@ extern void tweak_fsmonitor(struct index_state *istate); * any corresponding untracked cache directory structures. Optimized to only * run the first time it is called. */ -extern void refresh_fsmonitor(struct index_state *istate); +void refresh_fsmonitor(struct index_state *istate); /* * Set the given cache entries CE_FSMONITOR_VALID bit. This should be diff --git a/gettext.h b/gettext.h index 71255e503e..bee52eb113 100644 --- a/gettext.h +++ b/gettext.h @@ -28,11 +28,11 @@ #define FORMAT_PRESERVING(n) __attribute__((format_arg(n))) -extern int use_gettext_poison(void); +int use_gettext_poison(void); #ifndef NO_GETTEXT -extern void git_setup_gettext(void); -extern int gettext_width(const char *s); +void git_setup_gettext(void); +int gettext_width(const char *s); #else static inline void git_setup_gettext(void) { @@ -87,6 +87,6 @@ const char *Q_(const char *msgid, const char *plu, unsigned long n) #endif const char *get_preferred_languages(void); -extern int is_utf8_locale(void); +int is_utf8_locale(void); #endif diff --git a/git-compat-util.h b/git-compat-util.h index 4386b3e1c8..cc0e7e9733 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -250,7 +250,7 @@ typedef unsigned long uintptr_t; #ifdef MKDIR_WO_TRAILING_SLASH #define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b)) -extern int compat_mkdir_wo_trailing_slash(const char*, mode_t); +int compat_mkdir_wo_trailing_slash(const char*, mode_t); #endif #ifdef NO_STRUCT_ITIMERVAL @@ -268,9 +268,9 @@ struct itimerval { #include #else #define basename gitbasename -extern char *gitbasename(char *); +char *gitbasename(char *); #define dirname gitdirname -extern char *gitdirname(char *); +char *gitdirname(char *); #endif #ifndef NO_ICONV @@ -447,15 +447,15 @@ static inline char *git_find_last_dir_sep(const char *path) struct strbuf; /* General helper functions */ -extern void vreportf(const char *prefix, const char *err, va_list params); -extern NORETURN void usage(const char *err); -extern NORETURN void usagef(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); -extern void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); +void vreportf(const char *prefix, const char *err, va_list params); +NORETURN void usage(const char *err); +NORETURN void usagef(const char *err, ...) __attribute__((format (printf, 1, 2))); +NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2))); +NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); +int error(const char *err, ...) __attribute__((format (printf, 1, 2))); +int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); +void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); +void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2))); #ifndef NO_OPENSSL #ifdef APPLE_COMMON_CRYPTO @@ -483,15 +483,15 @@ static inline int const_error(void) #define error_errno(...) (error_errno(__VA_ARGS__), const_error()) #endif -extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)); -extern void set_error_routine(void (*routine)(const char *err, va_list params)); +void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)); +void set_error_routine(void (*routine)(const char *err, va_list params)); extern void (*get_error_routine(void))(const char *err, va_list params); -extern void set_warn_routine(void (*routine)(const char *warn, va_list params)); +void set_warn_routine(void (*routine)(const char *warn, va_list params)); extern void (*get_warn_routine(void))(const char *warn, va_list params); -extern void set_die_is_recursing_routine(int (*routine)(void)); +void set_die_is_recursing_routine(int (*routine)(void)); -extern int starts_with(const char *str, const char *prefix); -extern int istarts_with(const char *str, const char *prefix); +int starts_with(const char *str, const char *prefix); +int istarts_with(const char *str, const char *prefix); /* * If the string "str" begins with the string found in "prefix", return 1. @@ -614,8 +614,8 @@ static inline int ends_with(const char *str, const char *suffix) #define mmap git_mmap #define munmap git_munmap -extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); -extern int git_munmap(void *start, size_t length); +void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +int git_munmap(void *start, size_t length); #else /* NO_MMAP || USE_WIN32_MMAP */ @@ -669,17 +669,17 @@ extern int git_munmap(void *start, size_t length); #undef stat #endif #define stat(path, buf) git_stat(path, buf) -extern int git_stat(const char *, struct stat *); +int git_stat(const char *, struct stat *); #ifdef fstat #undef fstat #endif #define fstat(fd, buf) git_fstat(fd, buf) -extern int git_fstat(int, struct stat *); +int git_fstat(int, struct stat *); #ifdef lstat #undef lstat #endif #define lstat(path, buf) git_lstat(path, buf) -extern int git_lstat(const char *, struct stat *); +int git_lstat(const char *, struct stat *); #endif #define DEFAULT_PACKED_GIT_LIMIT \ @@ -687,50 +687,50 @@ extern int git_lstat(const char *, struct stat *); #ifdef NO_PREAD #define pread git_pread -extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); +ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif /* * Forward decl that will remind us if its twin in cache.h changes. * This function is used in compat/pread.c. But we can't include * cache.h there. */ -extern ssize_t read_in_full(int fd, void *buf, size_t count); +ssize_t read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv -extern int gitsetenv(const char *, const char *, int); +int gitsetenv(const char *, const char *, int); #endif #ifdef NO_MKDTEMP #define mkdtemp gitmkdtemp -extern char *gitmkdtemp(char *); +char *gitmkdtemp(char *); #endif #ifdef NO_UNSETENV #define unsetenv gitunsetenv -extern void gitunsetenv(const char *); +void gitunsetenv(const char *); #endif #ifdef NO_STRCASESTR #define strcasestr gitstrcasestr -extern char *gitstrcasestr(const char *haystack, const char *needle); +char *gitstrcasestr(const char *haystack, const char *needle); #endif #ifdef NO_STRLCPY #define strlcpy gitstrlcpy -extern size_t gitstrlcpy(char *, const char *, size_t); +size_t gitstrlcpy(char *, const char *, size_t); #endif #ifdef NO_STRTOUMAX #define strtoumax gitstrtoumax -extern uintmax_t gitstrtoumax(const char *, char **, int); +uintmax_t gitstrtoumax(const char *, char **, int); #define strtoimax gitstrtoimax -extern intmax_t gitstrtoimax(const char *, char **, int); +intmax_t gitstrtoimax(const char *, char **, int); #endif #ifdef NO_HSTRERROR #define hstrerror githstrerror -extern const char *githstrerror(int herror); +const char *githstrerror(int herror); #endif #ifdef NO_MEMMEM @@ -762,7 +762,7 @@ char *gitstrdup(const char *s); # endif # define fopen(a,b) git_fopen(a,b) # endif -extern FILE *git_fopen(const char*, const char*); +FILE *git_fopen(const char*, const char*); #endif #ifdef SNPRINTF_RETURNS_BOGUS @@ -770,14 +770,14 @@ extern FILE *git_fopen(const char*, const char*); #undef snprintf #endif #define snprintf git_snprintf -extern int git_snprintf(char *str, size_t maxsize, - const char *format, ...); +int git_snprintf(char *str, size_t maxsize, + const char *format, ...); #ifdef vsnprintf #undef vsnprintf #endif #define vsnprintf git_vsnprintf -extern int git_vsnprintf(char *str, size_t maxsize, - const char *format, va_list ap); +int git_vsnprintf(char *str, size_t maxsize, + const char *format, va_list ap); #endif #ifdef __GLIBC_PREREQ @@ -806,11 +806,11 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t size); #ifdef NO_PTHREADS #define atexit git_atexit -extern int git_atexit(void (*handler)(void)); +int git_atexit(void (*handler)(void)); #endif typedef void (*try_to_free_t)(size_t); -extern try_to_free_t set_try_to_free_routine(try_to_free_t); +try_to_free_t set_try_to_free_routine(try_to_free_t); static inline size_t st_add(size_t a, size_t b) { @@ -846,28 +846,28 @@ static inline size_t st_sub(size_t a, size_t b) # define xalloca(size) (xmalloc(size)) # define xalloca_free(p) (free(p)) #endif -extern char *xstrdup(const char *str); -extern void *xmalloc(size_t size); -extern void *xmallocz(size_t size); -extern void *xmallocz_gently(size_t size); -extern void *xmemdupz(const void *data, size_t len); -extern char *xstrndup(const char *str, size_t len); -extern void *xrealloc(void *ptr, size_t size); -extern void *xcalloc(size_t nmemb, size_t size); -extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); -extern void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset); -extern int xopen(const char *path, int flags, ...); -extern ssize_t xread(int fd, void *buf, size_t len); -extern ssize_t xwrite(int fd, const void *buf, size_t len); -extern ssize_t xpread(int fd, void *buf, size_t len, off_t offset); -extern int xdup(int fd); -extern FILE *xfopen(const char *path, const char *mode); -extern FILE *xfdopen(int fd, const char *mode); -extern int xmkstemp(char *temp_filename); -extern int xmkstemp_mode(char *temp_filename, int mode); -extern char *xgetcwd(void); -extern FILE *fopen_for_writing(const char *path); -extern FILE *fopen_or_warn(const char *path, const char *mode); +char *xstrdup(const char *str); +void *xmalloc(size_t size); +void *xmallocz(size_t size); +void *xmallocz_gently(size_t size); +void *xmemdupz(const void *data, size_t len); +char *xstrndup(const char *str, size_t len); +void *xrealloc(void *ptr, size_t size); +void *xcalloc(size_t nmemb, size_t size); +void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset); +int xopen(const char *path, int flags, ...); +ssize_t xread(int fd, void *buf, size_t len); +ssize_t xwrite(int fd, const void *buf, size_t len); +ssize_t xpread(int fd, void *buf, size_t len, off_t offset); +int xdup(int fd); +FILE *xfopen(const char *path, const char *mode); +FILE *xfdopen(int fd, const char *mode); +int xmkstemp(char *temp_filename); +int xmkstemp_mode(char *temp_filename, int mode); +char *xgetcwd(void); +FILE *fopen_for_writing(const char *path); +FILE *fopen_or_warn(const char *path, const char *mode); /* * FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note @@ -967,13 +967,13 @@ static inline size_t xsize_t(off_t len) } __attribute__((format (printf, 3, 4))) -extern int xsnprintf(char *dst, size_t max, const char *fmt, ...); +int xsnprintf(char *dst, size_t max, const char *fmt, ...); #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 256 #endif -extern int xgethostname(char *buf, size_t len); +int xgethostname(char *buf, size_t len); /* in ctype.c, for kwset users */ extern const unsigned char tolower_trans_tbl[256]; @@ -1237,12 +1237,22 @@ struct tm *git_gmtime_r(const time_t *, struct tm *); #ifdef FILENO_IS_A_MACRO int git_fileno(FILE *stream); -# ifndef COMPAT_CODE +# ifndef COMPAT_CODE_FILENO # undef fileno # define fileno(p) git_fileno(p) # endif #endif +#ifdef NEED_ACCESS_ROOT_HANDLER +int git_access(const char *path, int mode); +# ifndef COMPAT_CODE_ACCESS +# ifdef access +# undef access +# endif +# define access(path, mode) git_access(path, mode) +# endif +#endif + /* * Our code often opens a path to an optional file, to work on its * contents when we can successfully open it. We can ignore a failure @@ -1258,7 +1268,7 @@ static inline int is_missing_file_error(int errno_) return (errno_ == ENOENT || errno_ == ENOTDIR); } -extern int cmd_main(int, const char **); +int cmd_main(int, const char **); /* * Intercept all calls to exit() and route them to trace2 to @@ -1281,7 +1291,7 @@ int trace2_cmd_exit_fl(const char *file, int line, int code); * an annotation, and does nothing in non-leak-checking builds. */ #ifdef SUPPRESS_ANNOTATED_LEAKS -extern void unleak_memory(const void *ptr, size_t len); +void unleak_memory(const void *ptr, size_t len); #define UNLEAK(var) unleak_memory(&(var), sizeof(var)) #else #define UNLEAK(var) do {} while (0) diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index d13f02da95..fc00d5946a 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -431,6 +431,7 @@ END sub safe_pipe_capture { my @output; if (my $pid = open my $child, '-|') { + binmode($child, ":crlf"); @output = (<$child>); close $child or die join(' ',@_).": $! $?"; } else { diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index 7bfb6737df..46af3e60b7 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -71,7 +71,7 @@ then then merge_tool="$GIT_DIFF_TOOL" else - merge_tool="$(get_merge_tool)" || exit + merge_tool="$(get_merge_tool)" fi fi diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index aaa4eed0bc..204a5acd66 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -80,14 +80,18 @@ show_tool_names () { } } -diff_mode() { +diff_mode () { test "$TOOL_MODE" = diff } -merge_mode() { +merge_mode () { test "$TOOL_MODE" = merge } +gui_mode () { + test "$GIT_MERGETOOL_GUI" = true +} + translate_merge_tool_path () { echo "$1" } @@ -351,20 +355,36 @@ guess_merge_tool () { } get_configured_merge_tool () { - # If first argument is true, find the guitool instead - if test "$1" = true - then - gui_prefix=gui - fi - - # Diff mode first tries diff.(gui)tool and falls back to merge.(gui)tool. - # Merge mode only checks merge.(gui)tool + keys= if diff_mode then - merge_tool=$(git config diff.${gui_prefix}tool || git config merge.${gui_prefix}tool) + if gui_mode + then + keys="diff.guitool merge.guitool diff.tool merge.tool" + else + keys="diff.tool merge.tool" + fi else - merge_tool=$(git config merge.${gui_prefix}tool) + if gui_mode + then + keys="merge.guitool merge.tool" + else + keys="merge.tool" + fi fi + + merge_tool=$( + IFS=' ' + for key in $keys + do + selected=$(git config $key) + if test -n "$selected" + then + echo "$selected" + return + fi + done) + if test -n "$merge_tool" && ! valid_tool "$merge_tool" then echo >&2 "git config option $TOOL_MODE.${gui_prefix}tool set to unknown tool: $merge_tool" @@ -404,14 +424,17 @@ get_merge_tool_path () { } get_merge_tool () { + is_guessed=false # Check if a merge tool has been configured merge_tool=$(get_configured_merge_tool) # Try to guess an appropriate merge tool if no tool has been set. if test -z "$merge_tool" then merge_tool=$(guess_merge_tool) || exit + is_guessed=true fi echo "$merge_tool" + test "$is_guessed" = false } mergetool_find_win32_cmd () { diff --git a/git-mergetool.sh b/git-mergetool.sh index 01b9ad59b2..88fa6a914a 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -389,7 +389,7 @@ print_noop_and_exit () { main () { prompt=$(git config --bool mergetool.prompt) - gui_tool=false + GIT_MERGETOOL_GUI=false guessed_merge_tool=false orderfile= @@ -416,10 +416,10 @@ main () { esac ;; --no-gui) - gui_tool=false + GIT_MERGETOOL_GUI=false ;; -g|--gui) - gui_tool=true + GIT_MERGETOOL_GUI=true ;; -y|--no-prompt) prompt=false @@ -449,12 +449,8 @@ main () { if test -z "$merge_tool" then - # Check if a merge tool has been configured - merge_tool=$(get_configured_merge_tool $gui_tool) - # Try to guess an appropriate merge tool if no tool has been set. - if test -z "$merge_tool" + if ! merge_tool=$(get_merge_tool) then - merge_tool=$(guess_merge_tool) || exit guessed_merge_tool=true fi fi diff --git a/grep.h b/grep.h index fb04893721..1875880f37 100644 --- a/grep.h +++ b/grep.h @@ -186,17 +186,17 @@ struct grep_opt { void *output_priv; }; -extern void init_grep_defaults(struct repository *); -extern int grep_config(const char *var, const char *value, void *); -extern void grep_init(struct grep_opt *, struct repository *repo, const char *prefix); +void init_grep_defaults(struct repository *); +int grep_config(const char *var, const char *value, void *); +void grep_init(struct grep_opt *, struct repository *repo, const char *prefix); void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt); -extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t); -extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t); -extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *); -extern void compile_grep_patterns(struct grep_opt *opt); -extern void free_grep_patterns(struct grep_opt *opt); -extern int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size); +void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t); +void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t); +void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *); +void compile_grep_patterns(struct grep_opt *opt); +void free_grep_patterns(struct grep_opt *opt); +int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size); struct grep_source { char *name; @@ -226,8 +226,8 @@ void grep_source_load_driver(struct grep_source *gs, int grep_source(struct grep_opt *opt, struct grep_source *gs); -extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt); -extern int grep_threads_ok(const struct grep_opt *opt); +struct grep_opt *grep_opt_dup(const struct grep_opt *opt); +int grep_threads_ok(const struct grep_opt *opt); /* * Mutex used around access to the attributes machinery if diff --git a/hashmap.h b/hashmap.h index d375d9cce7..f95593b6cf 100644 --- a/hashmap.h +++ b/hashmap.h @@ -104,11 +104,11 @@ * `memihash_cont` is a variant of `memihash` that allows a computation to be * continued with another chunk of data. */ -extern unsigned int strhash(const char *buf); -extern unsigned int strihash(const char *buf); -extern unsigned int memhash(const void *buf, size_t len); -extern unsigned int memihash(const void *buf, size_t len); -extern unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len); +unsigned int strhash(const char *buf); +unsigned int strihash(const char *buf); +unsigned int memhash(const void *buf, size_t len); +unsigned int memihash(const void *buf, size_t len); +unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len); /* * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code @@ -216,7 +216,7 @@ struct hashmap { * parameter may be used to preallocate a sufficiently large table and thus * prevent expensive resizing. If 0, the table is dynamically resized. */ -extern void hashmap_init(struct hashmap *map, +void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, const void *equals_function_data, size_t initial_size); @@ -227,7 +227,7 @@ extern void hashmap_init(struct hashmap *map, * If `free_entries` is true, each hashmap_entry in the map is freed as well * using stdlibs free(). */ -extern void hashmap_free(struct hashmap *map, int free_entries); +void hashmap_free(struct hashmap *map, int free_entries); /* hashmap_entry functions */ @@ -284,7 +284,7 @@ static inline unsigned int hashmap_get_size(struct hashmap *map) * If an entry with matching hash code is found, `key` and `keydata` are passed * to `hashmap_cmp_fn` to decide whether the entry matches the key. */ -extern void *hashmap_get(const struct hashmap *map, const void *key, +void *hashmap_get(const struct hashmap *map, const void *key, const void *keydata); /* @@ -316,7 +316,7 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map, * `entry` is the hashmap_entry to start the search from, obtained via a previous * call to `hashmap_get` or `hashmap_get_next`. */ -extern void *hashmap_get_next(const struct hashmap *map, const void *entry); +void *hashmap_get_next(const struct hashmap *map, const void *entry); /* * Adds a hashmap entry. This allows to add duplicate entries (i.e. @@ -325,7 +325,7 @@ extern void *hashmap_get_next(const struct hashmap *map, const void *entry); * `map` is the hashmap structure. * `entry` is the entry to add. */ -extern void hashmap_add(struct hashmap *map, void *entry); +void hashmap_add(struct hashmap *map, void *entry); /* * Adds or replaces a hashmap entry. If the hashmap contains duplicate @@ -335,7 +335,7 @@ extern void hashmap_add(struct hashmap *map, void *entry); * `entry` is the entry to add or replace. * Returns the replaced entry, or NULL if not found (i.e. the entry was added). */ -extern void *hashmap_put(struct hashmap *map, void *entry); +void *hashmap_put(struct hashmap *map, void *entry); /* * Removes a hashmap entry matching the specified key. If the hashmap contains @@ -344,7 +344,7 @@ extern void *hashmap_put(struct hashmap *map, void *entry); * * Argument explanation is the same as in `hashmap_get`. */ -extern void *hashmap_remove(struct hashmap *map, const void *key, +void *hashmap_remove(struct hashmap *map, const void *key, const void *keydata); /* @@ -365,10 +365,10 @@ struct hashmap_iter { }; /* Initializes a `hashmap_iter` structure. */ -extern void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter); +void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter); /* Returns the next hashmap_entry, or NULL if there are no more entries. */ -extern void *hashmap_iter_next(struct hashmap_iter *iter); +void *hashmap_iter_next(struct hashmap_iter *iter); /* Initializes the iterator and returns the first entry, if any. */ static inline void *hashmap_iter_first(struct hashmap *map, @@ -429,7 +429,7 @@ static inline void hashmap_enable_item_counting(struct hashmap *map) * * Uses a hashmap to store the pool of interned strings. */ -extern const void *memintern(const void *data, size_t len); +const void *memintern(const void *data, size_t len); static inline const char *strintern(const char *string) { return memintern(string, strlen(string)); diff --git a/help.h b/help.h index a141e209ae..b8780fbd0f 100644 --- a/help.h +++ b/help.h @@ -19,31 +19,31 @@ static inline void mput_char(char c, unsigned int num) putchar(c); } -extern void list_common_cmds_help(void); -extern void list_all_cmds_help(void); -extern void list_common_guides_help(void); -extern void list_config_help(int for_human); +void list_common_cmds_help(void); +void list_all_cmds_help(void); +void list_common_guides_help(void); +void list_config_help(int for_human); -extern void list_all_main_cmds(struct string_list *list); -extern void list_all_other_cmds(struct string_list *list); -extern void list_cmds_by_category(struct string_list *list, - const char *category); -extern void list_cmds_by_config(struct string_list *list); -extern const char *help_unknown_cmd(const char *cmd); -extern void load_command_list(const char *prefix, - struct cmdnames *main_cmds, - struct cmdnames *other_cmds); -extern void add_cmdname(struct cmdnames *cmds, const char *name, int len); +void list_all_main_cmds(struct string_list *list); +void list_all_other_cmds(struct string_list *list); +void list_cmds_by_category(struct string_list *list, + const char *category); +void list_cmds_by_config(struct string_list *list); +const char *help_unknown_cmd(const char *cmd); +void load_command_list(const char *prefix, + struct cmdnames *main_cmds, + struct cmdnames *other_cmds); +void add_cmdname(struct cmdnames *cmds, const char *name, int len); /* Here we require that excludes is a sorted list. */ -extern void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); -extern int is_in_cmdlist(struct cmdnames *cmds, const char *name); -extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds); +void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); +int is_in_cmdlist(struct cmdnames *cmds, const char *name); +void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds); /* * call this to die(), when it is suspected that the user mistyped a * ref to the command, to give suggested "correct" refs. */ -extern void help_unknown_ref(const char *ref, const char *cmd, const char *error); +void help_unknown_ref(const char *ref, const char *cmd, const char *error); static inline void list_config_item(struct string_list *list, const char *prefix, diff --git a/http.c b/http.c index 98fb06df0b..27aa0a3192 100644 --- a/http.c +++ b/http.c @@ -176,7 +176,7 @@ size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) memcpy(ptr, buffer->buf.buf + buffer->posn, size); buffer->posn += size; - return size; + return size / eltsize; } #ifndef NO_CURL_IOCTL @@ -204,12 +204,12 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) struct strbuf *buffer = buffer_; strbuf_add(buffer, ptr, size); - return size; + return nmemb; } size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf) { - return eltsize * nmemb; + return nmemb; } static void closedown_active_slot(struct active_request_slot *slot) @@ -2319,14 +2319,14 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb, BUG("curl_easy_getinfo for HTTP code failed: %s", curl_easy_strerror(c)); if (slot->http_code >= 300) - return size; + return nmemb; } do { ssize_t retval = xwrite(freq->localfile, (char *) ptr + posn, size - posn); if (retval < 0) - return posn; + return posn / eltsize; posn += retval; } while (posn < size); @@ -2339,7 +2339,7 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb, the_hash_algo->update_fn(&freq->c, expn, sizeof(expn) - freq->stream.avail_out); } while (freq->stream.avail_in && freq->zret == Z_OK); - return size; + return nmemb; } struct http_object_request *new_http_object_request(const char *base_url, diff --git a/http.h b/http.h index ddfe52f023..b429f1cf04 100644 --- a/http.h +++ b/http.h @@ -75,18 +75,18 @@ struct buffer { }; /* Curl request read/write callbacks */ -extern size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); -extern size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); -extern size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); +size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); +size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); +size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); #ifndef NO_CURL_IOCTL -extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp); +curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp); #endif /* Slot lifecycle functions */ -extern struct active_request_slot *get_active_slot(void); -extern int start_active_slot(struct active_request_slot *slot); -extern void run_active_slot(struct active_request_slot *slot); -extern void finish_all_active_slots(void); +struct active_request_slot *get_active_slot(void); +int start_active_slot(struct active_request_slot *slot); +void run_active_slot(struct active_request_slot *slot); +void finish_all_active_slots(void); /* * This will run one slot to completion in a blocking manner, similar to how @@ -98,15 +98,15 @@ int run_one_slot(struct active_request_slot *slot, struct slot_results *results); #ifdef USE_CURL_MULTI -extern void fill_active_slots(void); -extern void add_fill_function(void *data, int (*fill)(void *)); -extern void step_active_slots(void); +void fill_active_slots(void); +void add_fill_function(void *data, int (*fill)(void *)); +void step_active_slots(void); #endif -extern void http_init(struct remote *remote, const char *url, - int proactive_auth); -extern void http_cleanup(void); -extern struct curl_slist *http_copy_default_headers(void); +void http_init(struct remote *remote, const char *url, + int proactive_auth); +void http_cleanup(void); +struct curl_slist *http_copy_default_headers(void); extern long int git_curl_ipresolve; extern int active_requests; @@ -146,11 +146,11 @@ void normalize_curl_result(CURLcode *result, long http_code, char *errorstr, size_t errorlen); /* Helpers for modifying and creating URLs */ -extern void append_remote_object_url(struct strbuf *buf, const char *url, - const char *hex, - int only_two_digit_prefix); -extern char *get_remote_object_url(const char *url, const char *hex, - int only_two_digit_prefix); +void append_remote_object_url(struct strbuf *buf, const char *url, + const char *hex, + int only_two_digit_prefix); +char *get_remote_object_url(const char *url, const char *hex, + int only_two_digit_prefix); /* Options for http_get_*() */ struct http_get_options { @@ -204,11 +204,11 @@ struct http_get_options { */ int http_get_strbuf(const char *url, struct strbuf *result, struct http_get_options *options); -extern int http_fetch_ref(const char *base, struct ref *ref); +int http_fetch_ref(const char *base, struct ref *ref); /* Helpers for fetching packs */ -extern int http_get_info_packs(const char *base_url, - struct packed_git **packs_head); +int http_get_info_packs(const char *base_url, + struct packed_git **packs_head); struct http_pack_request { char *url; @@ -219,10 +219,10 @@ struct http_pack_request { struct active_request_slot *slot; }; -extern struct http_pack_request *new_http_pack_request( +struct http_pack_request *new_http_pack_request( struct packed_git *target, const char *base_url); -extern int finish_http_pack_request(struct http_pack_request *preq); -extern void release_http_pack_request(struct http_pack_request *preq); +int finish_http_pack_request(struct http_pack_request *preq); +void release_http_pack_request(struct http_pack_request *preq); /* Helpers for fetching object */ struct http_object_request { @@ -241,12 +241,12 @@ struct http_object_request { struct active_request_slot *slot; }; -extern struct http_object_request *new_http_object_request( +struct http_object_request *new_http_object_request( const char *base_url, const struct object_id *oid); -extern void process_http_object_request(struct http_object_request *freq); -extern int finish_http_object_request(struct http_object_request *freq); -extern void abort_http_object_request(struct http_object_request *freq); -extern void release_http_object_request(struct http_object_request *freq); +void process_http_object_request(struct http_object_request *freq); +int finish_http_object_request(struct http_object_request *freq); +void abort_http_object_request(struct http_object_request *freq); +void release_http_object_request(struct http_object_request *freq); /* setup routine for curl_easy_setopt CURLOPT_DEBUGFUNCTION */ void setup_curl_trace(CURL *handle); diff --git a/khash.h b/khash.h index a09163b3e3..af747a683f 100644 --- a/khash.h +++ b/khash.h @@ -69,14 +69,14 @@ static const double __ac_HASH_UPPER = 0.77; khval_t *vals; \ } kh_##name##_t; -#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ - extern kh_##name##_t *kh_init_##name(void); \ - extern void kh_destroy_##name(kh_##name##_t *h); \ - extern void kh_clear_##name(kh_##name##_t *h); \ - extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ - extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ - extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ - extern void kh_del_##name(kh_##name##_t *h, khint_t x); +#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ + kh_##name##_t *kh_init_##name(void); \ + void kh_destroy_##name(kh_##name##_t *h); \ + void kh_clear_##name(kh_##name##_t *h); \ + khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ + int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ + khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ + void kh_del_##name(kh_##name##_t *h, khint_t x); #define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ SCOPE kh_##name##_t *kh_init_##name(void) { \ diff --git a/kwset.h b/kwset.h index 583f6268ef..df99a92178 100644 --- a/kwset.h +++ b/kwset.h @@ -37,16 +37,16 @@ typedef struct kwset_t* kwset_t; if enough memory cannot be obtained. The argument if non-NULL specifies a table of character translations to be applied to all pattern and search text. */ -extern kwset_t kwsalloc(unsigned char const *); +kwset_t kwsalloc(unsigned char const *); /* Incrementally extend the keyword set to include the given string. Return NULL for success, or an error message. Remember an index number for each keyword included in the set. */ -extern const char *kwsincr(kwset_t, char const *, size_t); +const char *kwsincr(kwset_t, char const *, size_t); /* When the keyword set has been completely built, prepare it for use. Return NULL for success, or an error message. */ -extern const char *kwsprep(kwset_t); +const char *kwsprep(kwset_t); /* Search through the given buffer for a member of the keyword set. Return a pointer to the leftmost longest match found, or NULL if @@ -54,8 +54,8 @@ extern const char *kwsprep(kwset_t); the matching substring in the integer it points to. Similarly, if foundindex is non-NULL, store the index of the particular keyword found therein. */ -extern size_t kwsexec(kwset_t, char const *, size_t, struct kwsmatch *); +size_t kwsexec(kwset_t, char const *, size_t, struct kwsmatch *); /* Deallocate the given keyword set and all its associated storage. */ -extern void kwsfree(kwset_t); +void kwsfree(kwset_t); diff --git a/line-log.h b/line-log.h index e2a5ee7c6d..8ee7a2bd4a 100644 --- a/line-log.h +++ b/line-log.h @@ -25,17 +25,17 @@ struct diff_ranges { struct range_set target; }; -extern void range_set_init(struct range_set *, size_t prealloc); -extern void range_set_release(struct range_set *); +void range_set_init(struct range_set *, size_t prealloc); +void range_set_release(struct range_set *); /* Range includes start; excludes end */ -extern void range_set_append_unsafe(struct range_set *, long start, long end); +void range_set_append_unsafe(struct range_set *, long start, long end); /* New range must begin at or after end of last added range */ -extern void range_set_append(struct range_set *, long start, long end); +void range_set_append(struct range_set *, long start, long end); /* * In-place pass of sorting and merging the ranges in the range set, * to sort and make the ranges disjoint. */ -extern void sort_and_merge_range_set(struct range_set *); +void sort_and_merge_range_set(struct range_set *); /* Linked list of interesting files and their associated ranges. The * list must be kept sorted by path. @@ -54,10 +54,10 @@ struct line_log_data { struct diff_ranges diff; }; -extern void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args); +void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args); -extern int line_log_filter(struct rev_info *rev); +int line_log_filter(struct rev_info *rev); -extern int line_log_print(struct rev_info *rev, struct commit *commit); +int line_log_print(struct rev_info *rev, struct commit *commit); #endif /* LINE_LOG_H */ diff --git a/lockfile.h b/lockfile.h index 35403ccc0d..9843053ce8 100644 --- a/lockfile.h +++ b/lockfile.h @@ -159,7 +159,7 @@ struct lock_file { * timeout_ms is -1, retry indefinitely. The flags argument and error * handling are described above. */ -extern int hold_lock_file_for_update_timeout( +int hold_lock_file_for_update_timeout( struct lock_file *lk, const char *path, int flags, long timeout_ms); @@ -188,8 +188,8 @@ static inline int is_lock_file_locked(struct lock_file *lk) * of `hold_lock_file_for_update()` to lock `path`. `err` should be the * `errno` set by the failing call. */ -extern void unable_to_lock_message(const char *path, int err, - struct strbuf *buf); +void unable_to_lock_message(const char *path, int err, + struct strbuf *buf); /* * Emit an appropriate error message and `die()` following the failure @@ -197,7 +197,7 @@ extern void unable_to_lock_message(const char *path, int err, * `errno` set by the failing * call. */ -extern NORETURN void unable_to_lock_die(const char *path, int err); +NORETURN void unable_to_lock_die(const char *path, int err); /* * Associate a stdio stream with the lockfile (which must still be @@ -234,7 +234,7 @@ static inline FILE *get_lock_file_fp(struct lock_file *lk) * Return the path of the file that is locked by the specified * lock_file object. The caller must free the memory. */ -extern char *get_locked_file_path(struct lock_file *lk); +char *get_locked_file_path(struct lock_file *lk); /* * If the lockfile is still open, close it (and the file pointer if it @@ -282,7 +282,7 @@ static inline int reopen_lock_file(struct lock_file *lk) * call `commit_lock_file()` for a `lock_file` object that is not * currently locked. */ -extern int commit_lock_file(struct lock_file *lk); +int commit_lock_file(struct lock_file *lk); /* * Like `commit_lock_file()`, but rename the lockfile to the provided diff --git a/ls-refs.h b/ls-refs.h index b62877e8da..7e5646f5f6 100644 --- a/ls-refs.h +++ b/ls-refs.h @@ -4,7 +4,7 @@ struct repository; struct argv_array; struct packet_reader; -extern int ls_refs(struct repository *r, struct argv_array *keys, - struct packet_reader *request); +int ls_refs(struct repository *r, struct argv_array *keys, + struct packet_reader *request); #endif /* LS_REFS_H */ diff --git a/mailinfo.h b/mailinfo.h index 6830e1e625..79b1d6774e 100644 --- a/mailinfo.h +++ b/mailinfo.h @@ -39,8 +39,8 @@ struct mailinfo { int input_error; }; -extern void setup_mailinfo(struct mailinfo *); -extern int mailinfo(struct mailinfo *, const char *msg, const char *patch); -extern void clear_mailinfo(struct mailinfo *); +void setup_mailinfo(struct mailinfo *); +int mailinfo(struct mailinfo *, const char *msg, const char *patch); +void clear_mailinfo(struct mailinfo *); #endif /* MAILINFO_H */ diff --git a/merge-blobs.h b/merge-blobs.h index cc31038b80..13cf9669e5 100644 --- a/merge-blobs.h +++ b/merge-blobs.h @@ -4,8 +4,8 @@ struct blob; struct index_state; -extern void *merge_blobs(struct index_state *, const char *, - struct blob *, struct blob *, - struct blob *, unsigned long *); +void *merge_blobs(struct index_state *, const char *, + struct blob *, struct blob *, + struct blob *, unsigned long *); #endif /* MERGE_BLOBS_H */ diff --git a/midx.c b/midx.c index d5d2e9522f..e7e1fe4d65 100644 --- a/midx.c +++ b/midx.c @@ -192,18 +192,17 @@ void close_midx(struct multi_pack_index *m) m->fd = -1; for (i = 0; i < m->num_packs; i++) { - if (m->packs[i]) { - close_pack(m->packs[i]); - free(m->packs[i]); - } + if (m->packs[i]) + m->packs[i]->multi_pack_index = 0; } FREE_AND_NULL(m->packs); FREE_AND_NULL(m->pack_names); } -int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id) +int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id) { struct strbuf pack_name = STRBUF_INIT; + struct packed_git *p; if (pack_int_id >= m->num_packs) die(_("bad pack-int-id: %u (%u total packs)"), @@ -215,9 +214,18 @@ int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id) strbuf_addf(&pack_name, "%s/pack/%s", m->object_dir, m->pack_names[pack_int_id]); - m->packs[pack_int_id] = add_packed_git(pack_name.buf, pack_name.len, m->local); + p = add_packed_git(pack_name.buf, pack_name.len, m->local); strbuf_release(&pack_name); - return !m->packs[pack_int_id]; + + if (!p) + return 1; + + p->multi_pack_index = 1; + m->packs[pack_int_id] = p; + install_packed_git(r, p); + list_add_tail(&p->mru, &r->objects->packed_git_mru); + + return 0; } int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result) @@ -261,7 +269,10 @@ static uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos) return get_be32(m->chunk_object_offsets + pos * MIDX_CHUNK_OFFSET_WIDTH); } -static int nth_midxed_pack_entry(struct multi_pack_index *m, struct pack_entry *e, uint32_t pos) +static int nth_midxed_pack_entry(struct repository *r, + struct multi_pack_index *m, + struct pack_entry *e, + uint32_t pos) { uint32_t pack_int_id; struct packed_git *p; @@ -271,7 +282,7 @@ static int nth_midxed_pack_entry(struct multi_pack_index *m, struct pack_entry * pack_int_id = nth_midxed_pack_int_id(m, pos); - if (prepare_midx_pack(m, pack_int_id)) + if (prepare_midx_pack(r, m, pack_int_id)) die(_("error preparing packfile from multi-pack-index")); p = m->packs[pack_int_id]; @@ -301,14 +312,17 @@ static int nth_midxed_pack_entry(struct multi_pack_index *m, struct pack_entry * return 1; } -int fill_midx_entry(const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m) +int fill_midx_entry(struct repository * r, + const struct object_id *oid, + struct pack_entry *e, + struct multi_pack_index *m) { uint32_t pos; if (!bsearch_midx(oid, m, &pos)) return 0; - return nth_midxed_pack_entry(m, e, pos); + return nth_midxed_pack_entry(r, m, e, pos); } /* Match "foo.idx" against either "foo.pack" _or_ "foo.idx". */ @@ -1020,7 +1034,7 @@ static int compare_pair_pos_vs_id(const void *_a, const void *_b) display_progress(progress, _n); \ } while (0) -int verify_midx_file(const char *object_dir) +int verify_midx_file(struct repository *r, const char *object_dir) { struct pair_pos_vs_id *pairs = NULL; uint32_t i; @@ -1034,7 +1048,7 @@ int verify_midx_file(const char *object_dir) progress = start_progress(_("Looking for referenced packfiles"), m->num_packs); for (i = 0; i < m->num_packs; i++) { - if (prepare_midx_pack(m, i)) + if (prepare_midx_pack(r, m, i)) midx_report("failed to load pack in position %d", i); display_progress(progress, i + 1); @@ -1099,7 +1113,7 @@ int verify_midx_file(const char *object_dir) nth_midxed_object_oid(&oid, m, pairs[i].pos); - if (!fill_midx_entry(&oid, &e, m)) { + if (!fill_midx_entry(r, &oid, &e, m)) { midx_report(_("failed to load pack entry for oid[%d] = %s"), pairs[i].pos, oid_to_hex(&oid)); continue; diff --git a/midx.h b/midx.h index 26dd042d63..3eb29731f2 100644 --- a/midx.h +++ b/midx.h @@ -5,6 +5,7 @@ struct object_id; struct pack_entry; +struct repository; #define GIT_TEST_MULTI_PACK_INDEX "GIT_TEST_MULTI_PACK_INDEX" @@ -37,18 +38,18 @@ struct multi_pack_index { }; struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local); -int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id); +int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id); int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result); struct object_id *nth_midxed_object_oid(struct object_id *oid, struct multi_pack_index *m, uint32_t n); -int fill_midx_entry(const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m); +int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m); int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name); int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local); int write_midx_file(const char *object_dir); void clear_midx_file(struct repository *r); -int verify_midx_file(const char *object_dir); +int verify_midx_file(struct repository *r, const char *object_dir); void close_midx(struct multi_pack_index *m); diff --git a/notes.h b/notes.h index 414bc6855a..76337f2384 100644 --- a/notes.h +++ b/notes.h @@ -276,12 +276,10 @@ void init_display_notes(struct display_notes_opt *opt); /* * Append notes for the given 'object_sha1' from all trees set up by - * init_display_notes() to 'sb'. The 'flags' are a bitwise - * combination of + * init_display_notes() to 'sb'. * - * - NOTES_SHOW_HEADER: add a 'Notes (refname):' header - * - * - NOTES_INDENT: indent the notes by 4 places + * If 'raw' is false the note will be indented by 4 places and + * a 'Notes (refname):' header added. * * You *must* call init_display_notes() before using this function. */ diff --git a/object-store.h b/object-store.h index b086f5ecdb..272e01e452 100644 --- a/object-store.h +++ b/object-store.h @@ -76,7 +76,8 @@ struct packed_git { pack_keep_in_core:1, freshened:1, do_not_close:1, - pack_promisor:1; + pack_promisor:1, + multi_pack_index:1; unsigned char hash[GIT_MAX_RAWSZ]; struct revindex_entry *revindex; /* something like ".git/objects/pack/xxxxx.pack" */ @@ -128,12 +129,6 @@ struct raw_object_store { /* A most-recently-used ordered version of the packed_git list. */ struct list_head packed_git_mru; - /* - * A linked list containing all packfiles, starting with those - * contained in the multi_pack_index. - */ - struct packed_git *all_packs; - /* * A fast, rough count of the number of objects in the repository. * These two fields are not meant for direct access. Use @@ -162,10 +157,10 @@ const char *loose_object_path(struct repository *r, struct strbuf *buf, void *map_loose_object(struct repository *r, const struct object_id *oid, unsigned long *size); -extern void *read_object_file_extended(struct repository *r, - const struct object_id *oid, - enum object_type *type, - unsigned long *size, int lookup_replace); +void *read_object_file_extended(struct repository *r, + const struct object_id *oid, + enum object_type *type, + unsigned long *size, int lookup_replace); static inline void *repo_read_object_file(struct repository *r, const struct object_id *oid, enum object_type *type, @@ -180,20 +175,20 @@ static inline void *repo_read_object_file(struct repository *r, /* Read and unpack an object file into memory, write memory to an object file */ int oid_object_info(struct repository *r, const struct object_id *, unsigned long *); -extern int hash_object_file(const void *buf, unsigned long len, - const char *type, struct object_id *oid); +int hash_object_file(const void *buf, unsigned long len, + const char *type, struct object_id *oid); -extern int write_object_file(const void *buf, unsigned long len, - const char *type, struct object_id *oid); +int write_object_file(const void *buf, unsigned long len, + const char *type, struct object_id *oid); -extern int hash_object_file_literally(const void *buf, unsigned long len, - const char *type, struct object_id *oid, - unsigned flags); +int hash_object_file_literally(const void *buf, unsigned long len, + const char *type, struct object_id *oid, + unsigned flags); -extern int pretend_object_file(void *, unsigned long, enum object_type, - struct object_id *oid); +int pretend_object_file(void *, unsigned long, enum object_type, + struct object_id *oid); -extern int force_object_loose(const struct object_id *oid, time_t mtime); +int force_object_loose(const struct object_id *oid, time_t mtime); /* * Open the loose object at path, check its hash, and return the contents, @@ -227,9 +222,9 @@ int repo_has_object_file_with_flags(struct repository *r, * with the specified name. This function does not respect replace * references. */ -extern int has_loose_object_nonlocal(const struct object_id *); +int has_loose_object_nonlocal(const struct object_id *); -extern void assert_oid_type(const struct object_id *oid, enum object_type expect); +void assert_oid_type(const struct object_id *oid, enum object_type expect); struct object_info { /* Request */ diff --git a/object.h b/object.h index 796792cb32..4526979ccf 100644 --- a/object.h +++ b/object.h @@ -90,19 +90,19 @@ struct object { struct object_id oid; }; -extern const char *type_name(unsigned int type); -extern int type_from_string_gently(const char *str, ssize_t, int gentle); +const char *type_name(unsigned int type); +int type_from_string_gently(const char *str, ssize_t, int gentle); #define type_from_string(str) type_from_string_gently(str, -1, 0) /* * Return the current number of buckets in the object hashmap. */ -extern unsigned int get_max_object_index(void); +unsigned int get_max_object_index(void); /* * Return the object from the specified bucket in the object hashmap. */ -extern struct object *get_indexed_object(unsigned int); +struct object *get_indexed_object(unsigned int); /* * This can be used to see if we have heard of the object before, but @@ -118,7 +118,7 @@ extern struct object *get_indexed_object(unsigned int); */ struct object *lookup_object(struct repository *r, const unsigned char *sha1); -extern void *create_object(struct repository *r, const unsigned char *sha1, void *obj); +void *create_object(struct repository *r, const unsigned char *sha1, void *obj); void *object_as_type(struct repository *r, struct object *obj, enum object_type type, int quiet); @@ -189,6 +189,6 @@ void clear_object_flags(unsigned flags); /* * Clear the specified object flags from all in-core commit objects. */ -extern void clear_commit_marks_all(unsigned int flags); +void clear_commit_marks_all(unsigned int flags); #endif /* OBJECT_H */ diff --git a/oidmap.h b/oidmap.h index 72430b611e..7a939461ff 100644 --- a/oidmap.h +++ b/oidmap.h @@ -33,7 +33,7 @@ struct oidmap { * parameter may be used to preallocate a sufficiently large table and thus * prevent expensive resizing. If 0, the table is dynamically resized. */ -extern void oidmap_init(struct oidmap *map, size_t initial_size); +void oidmap_init(struct oidmap *map, size_t initial_size); /* * Frees an oidmap structure and allocated memory. @@ -41,13 +41,13 @@ extern void oidmap_init(struct oidmap *map, size_t initial_size); * If `free_entries` is true, each oidmap_entry in the map is freed as well * using stdlibs free(). */ -extern void oidmap_free(struct oidmap *map, int free_entries); +void oidmap_free(struct oidmap *map, int free_entries); /* * Returns the oidmap entry for the specified oid, or NULL if not found. */ -extern void *oidmap_get(const struct oidmap *map, - const struct object_id *key); +void *oidmap_get(const struct oidmap *map, + const struct object_id *key); /* * Adds or replaces an oidmap entry. @@ -57,14 +57,14 @@ extern void *oidmap_get(const struct oidmap *map, * * Returns the replaced entry, or NULL if not found (i.e. the entry was added). */ -extern void *oidmap_put(struct oidmap *map, void *entry); +void *oidmap_put(struct oidmap *map, void *entry); /* * Removes an oidmap entry matching the specified oid. * * Returns the removed entry, or NULL if not found. */ -extern void *oidmap_remove(struct oidmap *map, const struct object_id *key); +void *oidmap_remove(struct oidmap *map, const struct object_id *key); struct oidmap_iter { diff --git a/pack.h b/pack.h index da99fdd1d2..9fc0945ac9 100644 --- a/pack.h +++ b/pack.h @@ -55,7 +55,7 @@ struct pack_idx_option { uint32_t *anomaly; }; -extern void reset_pack_idx_option(struct pack_idx_option *); +void reset_pack_idx_option(struct pack_idx_option *); /* * Packed object index header @@ -79,28 +79,28 @@ struct progress; /* Note, the data argument could be NULL if object type is blob */ typedef int (*verify_fn)(const struct object_id *, enum object_type, unsigned long, void*, int*); -extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1); -extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr); -extern int verify_pack_index(struct packed_git *); -extern int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t); -extern off_t write_pack_header(struct hashfile *f, uint32_t); -extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t); -extern char *index_pack_lockfile(int fd); +const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1); +int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr); +int verify_pack_index(struct packed_git *); +int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t); +off_t write_pack_header(struct hashfile *f, uint32_t); +void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t); +char *index_pack_lockfile(int fd); /* * The "hdr" output buffer should be at least this big, which will handle sizes * up to 2^67. */ #define MAX_PACK_OBJECT_HEADER 10 -extern int encode_in_pack_object_header(unsigned char *hdr, int hdr_len, - enum object_type, uintmax_t); +int encode_in_pack_object_header(unsigned char *hdr, int hdr_len, + enum object_type, uintmax_t); #define PH_ERROR_EOF (-1) #define PH_ERROR_PACK_SIGNATURE (-2) #define PH_ERROR_PROTOCOL (-3) -extern int read_pack_header(int fd, struct pack_header *); +int read_pack_header(int fd, struct pack_header *); -extern struct hashfile *create_tmp_packfile(char **pack_tmp_name); -extern void finish_tmp_packfile(struct strbuf *name_buffer, const char *pack_tmp_name, struct pack_idx_entry **written_list, uint32_t nr_written, struct pack_idx_option *pack_idx_opts, unsigned char sha1[]); +struct hashfile *create_tmp_packfile(char **pack_tmp_name); +void finish_tmp_packfile(struct strbuf *name_buffer, const char *pack_tmp_name, struct pack_idx_entry **written_list, uint32_t nr_written, struct pack_idx_option *pack_idx_opts, unsigned char sha1[]); #endif diff --git a/packfile.c b/packfile.c index 9f52af9281..49c8544ff4 100644 --- a/packfile.c +++ b/packfile.c @@ -994,8 +994,6 @@ static void prepare_packed_git(struct repository *r) } rearrange_packed_git(r); - r->objects->all_packs = NULL; - prepare_packed_git_mru(r); r->objects->packed_git_initialized = 1; } @@ -1026,26 +1024,16 @@ struct multi_pack_index *get_multi_pack_index(struct repository *r) struct packed_git *get_all_packs(struct repository *r) { - prepare_packed_git(r); - - if (!r->objects->all_packs) { - struct packed_git *p = r->objects->packed_git; - struct multi_pack_index *m; - - for (m = r->objects->multi_pack_index; m; m = m->next) { - uint32_t i; - for (i = 0; i < m->num_packs; i++) { - if (!prepare_midx_pack(m, i)) { - m->packs[i]->next = p; - p = m->packs[i]; - } - } - } + struct multi_pack_index *m; - r->objects->all_packs = p; + prepare_packed_git(r); + for (m = r->objects->multi_pack_index; m; m = m->next) { + uint32_t i; + for (i = 0; i < m->num_packs; i++) + prepare_midx_pack(r, m, i); } - return r->objects->all_packs; + return r->objects->packed_git; } struct list_head *get_packed_git_mru(struct repository *r) @@ -1998,13 +1986,13 @@ int find_pack_entry(struct repository *r, const struct object_id *oid, struct pa return 0; for (m = r->objects->multi_pack_index; m; m = m->next) { - if (fill_midx_entry(oid, e, m)) + if (fill_midx_entry(r, oid, e, m)) return 1; } list_for_each(pos, &r->objects->packed_git_mru) { struct packed_git *p = list_entry(pos, struct packed_git, mru); - if (fill_pack_entry(oid, e, p)) { + if (!p->multi_pack_index && fill_pack_entry(oid, e, p)) { list_move(&p->mru, &r->objects->packed_git_mru); return 1; } diff --git a/parse-options-cb.c b/parse-options-cb.c index 6e2e8d6273..4b95d04a37 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -96,6 +96,23 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset) return 0; } +int parse_opt_commit(const struct option *opt, const char *arg, int unset) +{ + struct object_id oid; + struct commit *commit; + struct commit **target = opt->value; + + if (!arg) + return -1; + if (get_oid(arg, &oid)) + return error("malformed object name %s", arg); + commit = lookup_commit_reference(the_repository, &oid); + if (!commit) + return error("no such commit %s", arg); + *target = commit; + return 0; +} + int parse_opt_object_name(const struct option *opt, const char *arg, int unset) { struct object_id oid; @@ -112,6 +129,23 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset) return 0; } +int parse_opt_object_id(const struct option *opt, const char *arg, int unset) +{ + struct object_id oid; + struct object_id *target = opt->value; + + if (unset) { + *target = null_oid; + return 0; + } + if (!arg) + return -1; + if (get_oid(arg, &oid)) + return error(_("malformed object name '%s'"), arg); + *target = oid; + return 0; +} + int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) { int *target = opt->value; diff --git a/parse-options.c b/parse-options.c index cb24f1aa8a..987e27cb91 100644 --- a/parse-options.c +++ b/parse-options.c @@ -261,6 +261,35 @@ static enum parse_opt_result parse_short_opt(struct parse_opt_ctx_t *p, return PARSE_OPT_UNKNOWN; } +static int has_string(const char *it, const char **array) +{ + while (*array) + if (!strcmp(it, *(array++))) + return 1; + return 0; +} + +static int is_alias(struct parse_opt_ctx_t *ctx, + const struct option *one_opt, + const struct option *another_opt) +{ + const char **group; + + if (!ctx->alias_groups) + return 0; + + if (!one_opt->long_name || !another_opt->long_name) + return 0; + + for (group = ctx->alias_groups; *group; group += 3) { + /* it and other are from the same family? */ + if (has_string(one_opt->long_name, group) && + has_string(another_opt->long_name, group)) + return 1; + } + return 0; +} + static enum parse_opt_result parse_long_opt( struct parse_opt_ctx_t *p, const char *arg, const struct option *options) @@ -298,7 +327,8 @@ static enum parse_opt_result parse_long_opt( if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) && !strncmp(long_name, arg, arg_end - arg)) { is_abbreviated: - if (abbrev_option) { + if (abbrev_option && + !is_alias(p, abbrev_option, options)) { /* * If this is abbreviated, it is * ambiguous. So when there is no @@ -447,6 +477,10 @@ static void parse_options_check(const struct option *opts) if (opts->callback) BUG("OPTION_LOWLEVEL_CALLBACK needs no high level callback"); break; + case OPTION_ALIAS: + BUG("OPT_ALIAS() should not remain at this point. " + "Are you using parse_options_step() directly?\n" + "That case is not supported yet."); default: ; /* ok. (usually accepts an argument) */ } @@ -458,11 +492,10 @@ static void parse_options_check(const struct option *opts) exit(128); } -void parse_options_start(struct parse_opt_ctx_t *ctx, - int argc, const char **argv, const char *prefix, - const struct option *options, int flags) +static void parse_options_start_1(struct parse_opt_ctx_t *ctx, + int argc, const char **argv, const char *prefix, + const struct option *options, int flags) { - memset(ctx, 0, sizeof(*ctx)); ctx->argc = argc; ctx->argv = argv; if (!(flags & PARSE_OPT_ONE_SHOT)) { @@ -484,6 +517,14 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, parse_options_check(options); } +void parse_options_start(struct parse_opt_ctx_t *ctx, + int argc, const char **argv, const char *prefix, + const struct option *options, int flags) +{ + memset(ctx, 0, sizeof(*ctx)); + parse_options_start_1(ctx, argc, argv, prefix, options, flags); +} + static void show_negated_gitcomp(const struct option *opts, int nr_noopts) { int printed_dashdash = 0; @@ -575,6 +616,83 @@ static int show_gitcomp(const struct option *opts) return PARSE_OPT_COMPLETE; } +/* + * Scan and may produce a new option[] array, which should be used + * instead of the original 'options'. + * + * Right now this is only used to preprocess and substitue + * OPTION_ALIAS. + */ +static struct option *preprocess_options(struct parse_opt_ctx_t *ctx, + const struct option *options) +{ + struct option *newopt; + int i, nr, alias; + int nr_aliases = 0; + + for (nr = 0; options[nr].type != OPTION_END; nr++) { + if (options[nr].type == OPTION_ALIAS) + nr_aliases++; + } + + if (!nr_aliases) + return NULL; + + ALLOC_ARRAY(newopt, nr + 1); + COPY_ARRAY(newopt, options, nr + 1); + + /* each alias has two string pointers and NULL */ + CALLOC_ARRAY(ctx->alias_groups, 3 * (nr_aliases + 1)); + + for (alias = 0, i = 0; i < nr; i++) { + int short_name; + const char *long_name; + const char *source; + int j; + + if (newopt[i].type != OPTION_ALIAS) + continue; + + short_name = newopt[i].short_name; + long_name = newopt[i].long_name; + source = newopt[i].value; + + if (!long_name) + BUG("An alias must have long option name"); + + for (j = 0; j < nr; j++) { + const char *name = options[j].long_name; + + if (!name || strcmp(name, source)) + continue; + + if (options[j].type == OPTION_ALIAS) + BUG("No please. Nested aliases are not supported."); + + /* + * NEEDSWORK: this is a bit inconsistent because + * usage_with_options() on the original options[] will print + * help string as "alias of %s" but "git cmd -h" will + * print the original help string. + */ + memcpy(newopt + i, options + j, sizeof(*newopt)); + newopt[i].short_name = short_name; + newopt[i].long_name = long_name; + break; + } + + if (j == nr) + BUG("could not find source option '%s' of alias '%s'", + source, newopt[i].long_name); + ctx->alias_groups[alias * 3 + 0] = newopt[i].long_name; + ctx->alias_groups[alias * 3 + 1] = options[j].long_name; + ctx->alias_groups[alias * 3 + 2] = NULL; + alias++; + } + + return newopt; +} + static int usage_with_options_internal(struct parse_opt_ctx_t *, const char * const *, const struct option *, int, int); @@ -714,11 +832,16 @@ int parse_options(int argc, const char **argv, const char *prefix, int flags) { struct parse_opt_ctx_t ctx; + struct option *real_options; disallow_abbreviated_options = git_env_bool("GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS", 0); - parse_options_start(&ctx, argc, argv, prefix, options, flags); + memset(&ctx, 0, sizeof(ctx)); + real_options = preprocess_options(&ctx, options); + if (real_options) + options = real_options; + parse_options_start_1(&ctx, argc, argv, prefix, options, flags); switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: case PARSE_OPT_ERROR: @@ -741,6 +864,8 @@ int parse_options(int argc, const char **argv, const char *prefix, } precompose_argv(argc, argv); + free(real_options); + free(ctx.alias_groups); return parse_options_end(&ctx); } @@ -835,6 +960,12 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, fputc('\n', outfile); pad = USAGE_OPTS_WIDTH; } + if (opts->type == OPTION_ALIAS) { + fprintf(outfile, "%*s", pad + USAGE_GAP, ""); + fprintf_ln(outfile, _("alias of --%s"), + (const char *)opts->value); + continue; + } fprintf(outfile, "%*s%s\n", pad + USAGE_GAP, "", _(opts->help)); } fputc('\n', outfile); diff --git a/parse-options.h b/parse-options.h index 1dd3523c15..98ea42ffd9 100644 --- a/parse-options.h +++ b/parse-options.h @@ -7,6 +7,7 @@ enum parse_opt_type { OPTION_ARGUMENT, OPTION_GROUP, OPTION_NUMBER, + OPTION_ALIAS, /* options with no arguments */ OPTION_BIT, OPTION_NEGBIT, @@ -183,6 +184,9 @@ struct option { N_("no-op (backward compatibility)"), \ PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb } +#define OPT_ALIAS(s, l, source_long_name) \ + { OPTION_ALIAS, (s), (l), (source_long_name) } + /* * parse_options() will filter out the processed options and leave the * non-option arguments in argv[]. argv0 is assumed program name and @@ -258,6 +262,8 @@ struct parse_opt_ctx_t { const char *opt; int flags; const char *prefix; + const char **alias_groups; /* must be in groups of 3 elements! */ + struct option *updated_options; }; void parse_options_start(struct parse_opt_ctx_t *ctx, @@ -277,8 +283,12 @@ int parse_opt_abbrev_cb(const struct option *, const char *, int); int parse_opt_expiry_date_cb(const struct option *, const char *, int); int parse_opt_color_flag_cb(const struct option *, const char *, int); int parse_opt_verbosity_cb(const struct option *, const char *, int); +/* value is struct oid_array* */ int parse_opt_object_name(const struct option *, const char *, int); +/* value is struct object_id* */ +int parse_opt_object_id(const struct option *, const char *, int); int parse_opt_commits(const struct option *, const char *, int); +int parse_opt_commit(const struct option *, const char *, int); int parse_opt_tertiary(const struct option *, const char *, int); int parse_opt_string_list(const struct option *, const char *, int); int parse_opt_noop_cb(const struct option *, const char *, int); diff --git a/path.h b/path.h index 651e6157fc..2ba6ca58c8 100644 --- a/path.h +++ b/path.h @@ -13,19 +13,19 @@ struct strbuf; /* * Return a statically allocated path. */ -extern const char *mkpath(const char *fmt, ...) +const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* * Return a path. */ -extern char *mkpathdup(const char *fmt, ...) +char *mkpathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* * Construct a path and place the result in the provided buffer `buf`. */ -extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) +char *mksnpath(char *buf, size_t n, const char *fmt, ...) __attribute__((format (printf, 3, 4))); /* @@ -37,16 +37,16 @@ extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) * Constructs a path into the common git directory of repository `repo` and * append it in the provided buffer `sb`. */ -extern void strbuf_git_common_path(struct strbuf *sb, - const struct repository *repo, - const char *fmt, ...) +void strbuf_git_common_path(struct strbuf *sb, + const struct repository *repo, + const char *fmt, ...) __attribute__((format (printf, 3, 4))); /* * Return a statically allocated path into the main repository's * (the_repository) common git directory. */ -extern const char *git_common_path(const char *fmt, ...) +const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); @@ -66,30 +66,30 @@ extern const char *git_common_path(const char *fmt, ...) /* * Return a path into the git directory of repository `repo`. */ -extern char *repo_git_path(const struct repository *repo, - const char *fmt, ...) +char *repo_git_path(const struct repository *repo, + const char *fmt, ...) __attribute__((format (printf, 2, 3))); /* * Construct a path into the git directory of repository `repo` and append it * to the provided buffer `sb`. */ -extern void strbuf_repo_git_path(struct strbuf *sb, - const struct repository *repo, - const char *fmt, ...) +void strbuf_repo_git_path(struct strbuf *sb, + const struct repository *repo, + const char *fmt, ...) __attribute__((format (printf, 3, 4))); /* * Return a statically allocated path into the main repository's * (the_repository) git directory. */ -extern const char *git_path(const char *fmt, ...) +const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* * Return a path into the main repository's (the_repository) git directory. */ -extern char *git_pathdup(const char *fmt, ...) +char *git_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* @@ -97,14 +97,14 @@ extern char *git_pathdup(const char *fmt, ...) * and place it in the provided buffer `buf`, the contents of the buffer will * be overridden. */ -extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...) +char *git_path_buf(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3))); /* * Construct a path into the main repository's (the_repository) git directory * and append it to the provided buffer `sb`. */ -extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) +void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) __attribute__((format (printf, 2, 3))); /* @@ -112,7 +112,7 @@ extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...) * * If the repository doesn't have a worktree NULL is returned. */ -extern char *repo_worktree_path(const struct repository *repo, +char *repo_worktree_path(const struct repository *repo, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -122,7 +122,7 @@ extern char *repo_worktree_path(const struct repository *repo, * * If the repository doesn't have a worktree nothing will be appended to `sb`. */ -extern void strbuf_repo_worktree_path(struct strbuf *sb, +void strbuf_repo_worktree_path(struct strbuf *sb, const struct repository *repo, const char *fmt, ...) __attribute__((format (printf, 3, 4))); @@ -131,7 +131,7 @@ extern void strbuf_repo_worktree_path(struct strbuf *sb, * Return a path into a submodule's git directory located at `path`. `path` * must only reference a submodule of the main repository (the_repository). */ -extern char *git_pathdup_submodule(const char *path, const char *fmt, ...) +char *git_pathdup_submodule(const char *path, const char *fmt, ...) __attribute__((format (printf, 2, 3))); /* @@ -139,11 +139,11 @@ extern char *git_pathdup_submodule(const char *path, const char *fmt, ...) * append it to the provided buffer `sb`. `path` must only reference a * submodule of the main repository (the_repository). */ -extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path, +int strbuf_git_path_submodule(struct strbuf *sb, const char *path, const char *fmt, ...) __attribute__((format (printf, 3, 4))); -extern void report_linked_checkout_garbage(void); +void report_linked_checkout_garbage(void); /* * You can define a static memoized git path like: diff --git a/pkt-line.h b/pkt-line.h index c36cb788ed..5c62015db4 100644 --- a/pkt-line.h +++ b/pkt-line.h @@ -172,9 +172,9 @@ struct packet_reader { * Initialize a 'struct packet_reader' object which is an * abstraction around the 'packet_read_with_status()' function. */ -extern void packet_reader_init(struct packet_reader *reader, int fd, - char *src_buffer, size_t src_len, - int options); +void packet_reader_init(struct packet_reader *reader, int fd, + char *src_buffer, size_t src_len, + int options); /* * Perform a packet read and return the status of the read. @@ -186,7 +186,7 @@ extern void packet_reader_init(struct packet_reader *reader, int fd, * 'line' is set to point at the read line * PACKET_READ_FLUSH: 'pktlen' is set to '0' and 'line' is set to NULL */ -extern enum packet_read_status packet_reader_read(struct packet_reader *reader); +enum packet_read_status packet_reader_read(struct packet_reader *reader); /* * Peek the next packet line without consuming it and return the status. @@ -196,7 +196,7 @@ extern enum packet_read_status packet_reader_read(struct packet_reader *reader); * Peeking multiple times without calling 'packet_reader_read()' will return * the same result. */ -extern enum packet_read_status packet_reader_peek(struct packet_reader *reader); +enum packet_read_status packet_reader_peek(struct packet_reader *reader); #define DEFAULT_PACKET_MAX 1000 #define LARGE_PACKET_MAX 65520 diff --git a/ppc/sha1.c b/ppc/sha1.c index ec6a1926d4..1b705cee1f 100644 --- a/ppc/sha1.c +++ b/ppc/sha1.c @@ -10,8 +10,8 @@ #include #include "sha1.h" -extern void ppc_sha1_core(uint32_t *hash, const unsigned char *p, - unsigned int nblocks); +void ppc_sha1_core(uint32_t *hash, const unsigned char *p, + unsigned int nblocks); int ppc_SHA1_Init(ppc_SHA_CTX *c) { diff --git a/prio-queue.h b/prio-queue.h index 682e51867a..4f9a37e6be 100644 --- a/prio-queue.h +++ b/prio-queue.h @@ -37,24 +37,24 @@ struct prio_queue { /* * Add the "thing" to the queue. */ -extern void prio_queue_put(struct prio_queue *, void *thing); +void prio_queue_put(struct prio_queue *, void *thing); /* * Extract the "thing" that compares the smallest out of the queue, * or NULL. If compare function is NULL, the queue acts as a LIFO * stack. */ -extern void *prio_queue_get(struct prio_queue *); +void *prio_queue_get(struct prio_queue *); /* * Gain access to the "thing" that would be returned by * prio_queue_get, but do not remove it from the queue. */ -extern void *prio_queue_peek(struct prio_queue *); +void *prio_queue_peek(struct prio_queue *); -extern void clear_prio_queue(struct prio_queue *); +void clear_prio_queue(struct prio_queue *); /* Reverse the LIFO elements */ -extern void prio_queue_reverse(struct prio_queue *); +void prio_queue_reverse(struct prio_queue *); #endif /* PRIO_QUEUE_H */ diff --git a/protocol.h b/protocol.h index 2ad35e433c..cef1a4a01c 100644 --- a/protocol.h +++ b/protocol.h @@ -14,7 +14,7 @@ enum protocol_version { * 'protocol.version' config. If unconfigured, a value of 'protocol_v0' is * returned. */ -extern enum protocol_version get_protocol_version_config(void); +enum protocol_version get_protocol_version_config(void); /* * Used by a server to determine which protocol version should be used based on @@ -23,12 +23,12 @@ extern enum protocol_version get_protocol_version_config(void); * request a particular protocol version, a default of 'protocol_v0' will be * used. */ -extern enum protocol_version determine_protocol_version_server(void); +enum protocol_version determine_protocol_version_server(void); /* * Used by a client to determine which protocol version the server is speaking * based on the server's initial response. */ -extern enum protocol_version determine_protocol_version_client(const char *server_response); +enum protocol_version determine_protocol_version_client(const char *server_response); #endif /* PROTOCOL_H */ diff --git a/quote.h b/quote.h index ea992dcc91..fb08dc085c 100644 --- a/quote.h +++ b/quote.h @@ -29,9 +29,9 @@ struct strbuf; * sq_quotef() quotes the entire formatted string as a single result. */ -extern void sq_quote_buf(struct strbuf *, const char *src); -extern void sq_quote_argv(struct strbuf *, const char **argv); -extern void sq_quotef(struct strbuf *, const char *fmt, ...); +void sq_quote_buf(struct strbuf *, const char *src); +void sq_quote_argv(struct strbuf *, const char **argv); +void sq_quotef(struct strbuf *, const char *fmt, ...); /* * These match their non-pretty variants, except that they avoid @@ -45,14 +45,14 @@ void sq_quote_argv_pretty(struct strbuf *, const char **argv); * NULL if the input does not look like what sq_quote would have * produced. */ -extern char *sq_dequote(char *); +char *sq_dequote(char *); /* * Same as the above, but can be used to unwrap many arguments in the * same string separated by space. Like sq_quote, it works in place, * modifying arg and appending pointers into it to argv. */ -extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc); +int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc); /* * Same as above, but store the unquoted strings in an argv_array. We will @@ -60,24 +60,24 @@ extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc * will duplicate and take ownership of the strings. */ struct argv_array; -extern int sq_dequote_to_argv_array(char *arg, struct argv_array *); +int sq_dequote_to_argv_array(char *arg, struct argv_array *); -extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); -extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); -extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); +int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); +size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); +void quote_two_c_style(struct strbuf *, const char *, const char *, int); -extern void write_name_quoted(const char *name, FILE *, int terminator); -extern void write_name_quoted_relative(const char *name, const char *prefix, - FILE *fp, int terminator); +void write_name_quoted(const char *name, FILE *, int terminator); +void write_name_quoted_relative(const char *name, const char *prefix, + FILE *fp, int terminator); /* quote path as relative to the given prefix */ -extern char *quote_path_relative(const char *in, const char *prefix, +char *quote_path_relative(const char *in, const char *prefix, struct strbuf *out); /* quoting as a string literal for other languages */ -extern void perl_quote_buf(struct strbuf *sb, const char *src); -extern void python_quote_buf(struct strbuf *sb, const char *src); -extern void tcl_quote_buf(struct strbuf *sb, const char *src); -extern void basic_regex_quote_buf(struct strbuf *sb, const char *src); +void perl_quote_buf(struct strbuf *sb, const char *src); +void python_quote_buf(struct strbuf *sb, const char *src); +void tcl_quote_buf(struct strbuf *sb, const char *src); +void basic_regex_quote_buf(struct strbuf *sb, const char *src); #endif diff --git a/reachable.h b/reachable.h index 18b0f9f2f0..5df932ad8f 100644 --- a/reachable.h +++ b/reachable.h @@ -4,9 +4,9 @@ struct progress; struct rev_info; -extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs, - timestamp_t timestamp); -extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog, - timestamp_t mark_recent, struct progress *); +int add_unseen_recent_objects_to_traversal(struct rev_info *revs, + timestamp_t timestamp); +void mark_reachable_objects(struct rev_info *revs, int mark_reflog, + timestamp_t mark_recent, struct progress *); #endif diff --git a/read-cache.c b/read-cache.c index 61b043bac3..22e7b9944e 100644 --- a/read-cache.c +++ b/read-cache.c @@ -2326,6 +2326,7 @@ int discard_index(struct index_state *istate) free_name_hash(istate); cache_tree_free(&(istate->cache_tree)); istate->initialized = 0; + istate->fsmonitor_has_run_once = 0; FREE_AND_NULL(istate->cache); istate->cache_alloc = 0; discard_split_index(istate); @@ -3131,7 +3132,7 @@ static int write_shared_index(struct index_state *istate, trace2_region_enter_printf("index", "shared/do_write_index", the_repository, "%s", (*temp)->filename.buf); ret = do_write_index(si->base, *temp, 1); - trace2_region_enter_printf("index", "shared/do_write_index", + trace2_region_leave_printf("index", "shared/do_write_index", the_repository, "%s", (*temp)->filename.buf); if (ret) diff --git a/reflog-walk.h b/reflog-walk.h index cb3e73755d..f26408f6cc 100644 --- a/reflog-walk.h +++ b/reflog-walk.h @@ -6,21 +6,21 @@ struct commit; struct reflog_walk_info; -extern void init_reflog_walk(struct reflog_walk_info **info); -extern int add_reflog_for_walk(struct reflog_walk_info *info, - struct commit *commit, const char *name); -extern void show_reflog_message(struct reflog_walk_info *info, int, - const struct date_mode *, int force_date); -extern void get_reflog_message(struct strbuf *sb, - struct reflog_walk_info *reflog_info); -extern const char *get_reflog_ident(struct reflog_walk_info *reflog_info); -extern timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info); -extern void get_reflog_selector(struct strbuf *sb, - struct reflog_walk_info *reflog_info, - const struct date_mode *dmode, int force_date, - int shorten); +void init_reflog_walk(struct reflog_walk_info **info); +int add_reflog_for_walk(struct reflog_walk_info *info, + struct commit *commit, const char *name); +void show_reflog_message(struct reflog_walk_info *info, int, + const struct date_mode *, int force_date); +void get_reflog_message(struct strbuf *sb, + struct reflog_walk_info *reflog_info); +const char *get_reflog_ident(struct reflog_walk_info *reflog_info); +timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info); +void get_reflog_selector(struct strbuf *sb, + struct reflog_walk_info *reflog_info, + const struct date_mode *dmode, int force_date, + int shorten); -extern int reflog_walk_empty(struct reflog_walk_info *walk); +int reflog_walk_empty(struct reflog_walk_info *walk); struct commit *next_reflog_entry(struct reflog_walk_info *reflog_info); diff --git a/refs.h b/refs.h index 8f9cbf8a93..2727405b61 100644 --- a/refs.h +++ b/refs.h @@ -111,7 +111,7 @@ int should_autocreate_reflog(const char *refname); int is_branch(const char *refname); -extern int refs_init_db(struct strbuf *err); +int refs_init_db(struct strbuf *err); /* * If refname is a non-symbolic reference that refers to a tag object, diff --git a/remote.h b/remote.h index 6a1795947e..83e885672b 100644 --- a/remote.h +++ b/remote.h @@ -119,13 +119,13 @@ struct ref { #define REF_HEADS (1u << 1) #define REF_TAGS (1u << 2) -extern struct ref *find_ref_by_name(const struct ref *list, const char *name); +struct ref *find_ref_by_name(const struct ref *list, const char *name); struct ref *alloc_ref(const char *name); struct ref *copy_ref(const struct ref *ref); struct ref *copy_ref_list(const struct ref *ref); void sort_ref_list(struct ref **, int (*cmp)(const void *, const void *)); -extern int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref); +int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref); int ref_compare_name(const void *, const void *); int check_ref_type(const struct ref *ref, int flags); @@ -141,16 +141,16 @@ struct oid_array; struct packet_reader; struct argv_array; struct string_list; -extern struct ref **get_remote_heads(struct packet_reader *reader, - struct ref **list, unsigned int flags, - struct oid_array *extra_have, - struct oid_array *shallow_points); +struct ref **get_remote_heads(struct packet_reader *reader, + struct ref **list, unsigned int flags, + struct oid_array *extra_have, + struct oid_array *shallow_points); /* Used for protocol v2 in order to retrieve refs from a remote */ -extern struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, - struct ref **list, int for_push, - const struct argv_array *ref_prefixes, - const struct string_list *server_options); +struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, + struct ref **list, int for_push, + const struct argv_array *ref_prefixes, + const struct string_list *server_options); int resolve_remote_symref(struct ref *ref, struct ref *list); @@ -290,9 +290,9 @@ struct push_cas_option { int alloc; }; -extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset); +int parseopt_push_cas_option(const struct option *, const char *arg, int unset); -extern int is_empty_cas(const struct push_cas_option *); +int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); #endif diff --git a/replace-object.h b/replace-object.h index 16528df942..04ed7a85a2 100644 --- a/replace-object.h +++ b/replace-object.h @@ -16,8 +16,8 @@ void prepare_replace_object(struct repository *r); * This internal function is only declared here for the benefit of * lookup_replace_object(). Please do not call it directly. */ -extern const struct object_id *do_lookup_replace_object(struct repository *r, - const struct object_id *oid); +const struct object_id *do_lookup_replace_object(struct repository *r, + const struct object_id *oid); /* * If object sha1 should be replaced, return the replacement object's diff --git a/resolve-undo.h b/resolve-undo.h index fbe348efac..2b3f0f901e 100644 --- a/resolve-undo.h +++ b/resolve-undo.h @@ -8,12 +8,12 @@ struct resolve_undo_info { struct object_id oid[3]; }; -extern void record_resolve_undo(struct index_state *, struct cache_entry *); -extern void resolve_undo_write(struct strbuf *, struct string_list *); -extern struct string_list *resolve_undo_read(const char *, unsigned long); -extern void resolve_undo_clear_index(struct index_state *); -extern int unmerge_index_entry_at(struct index_state *, int); -extern void unmerge_index(struct index_state *, const struct pathspec *); -extern void unmerge_marked_index(struct index_state *); +void record_resolve_undo(struct index_state *, struct cache_entry *); +void resolve_undo_write(struct strbuf *, struct string_list *); +struct string_list *resolve_undo_read(const char *, unsigned long); +void resolve_undo_clear_index(struct index_state *); +int unmerge_index_entry_at(struct index_state *, int); +void unmerge_index(struct index_state *, const struct pathspec *); +void unmerge_marked_index(struct index_state *); #endif diff --git a/run-command.h b/run-command.h index a6950691c0..f769e03f01 100644 --- a/run-command.h +++ b/run-command.h @@ -55,7 +55,7 @@ struct child_process { #define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT, ARGV_ARRAY_INIT } void child_process_init(struct child_process *); void child_process_clear(struct child_process *); -extern int is_executable(const char *name); +int is_executable(const char *name); int start_command(struct child_process *); int finish_command(struct child_process *); @@ -67,10 +67,10 @@ int run_command(struct child_process *); * or disabled. Note that this points to static storage that will be * overwritten by further calls to find_hook and run_hook_*. */ -extern const char *find_hook(const char *name); +const char *find_hook(const char *name); LAST_ARG_MUST_BE_NULL -extern int run_hook_le(const char *const *env, const char *name, ...); -extern int run_hook_ve(const char *const *env, const char *name, va_list args); +int run_hook_le(const char *const *env, const char *name, ...); +int run_hook_ve(const char *const *env, const char *name, va_list args); #define RUN_COMMAND_NO_STDIN 1 #define RUN_GIT_CMD 2 /*If this is to be git sub-command */ diff --git a/sequencer.c b/sequencer.c index 4407a3f978..f88a97fb10 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2168,6 +2168,41 @@ static int parse_insn_line(struct repository *r, struct todo_item *item, return !item->commit; } +int sequencer_get_last_command(struct repository *r, enum replay_action *action) +{ + struct todo_item item; + char *eol; + const char *todo_file; + struct strbuf buf = STRBUF_INIT; + int ret = -1; + + todo_file = git_path_todo_file(); + if (strbuf_read_file(&buf, todo_file, 0) < 0) { + if (errno == ENOENT) + return -1; + else + return error_errno("unable to open '%s'", todo_file); + } + eol = strchrnul(buf.buf, '\n'); + if (buf.buf != eol && eol[-1] == '\r') + eol--; /* strip Carriage Return */ + if (parse_insn_line(r, &item, buf.buf, buf.buf, eol)) + goto fail; + if (item.command == TODO_PICK) + *action = REPLAY_PICK; + else if (item.command == TODO_REVERT) + *action = REPLAY_REVERT; + else + goto fail; + + ret = 0; + + fail: + strbuf_release(&buf); + + return ret; +} + int todo_list_parse_insn_buffer(struct repository *r, char *buf, struct todo_list *todo_list) { @@ -2251,6 +2286,57 @@ static ssize_t strbuf_read_file_or_whine(struct strbuf *sb, const char *path) return len; } +static int have_finished_the_last_pick(void) +{ + struct strbuf buf = STRBUF_INIT; + const char *eol; + const char *todo_path = git_path_todo_file(); + int ret = 0; + + if (strbuf_read_file(&buf, todo_path, 0) < 0) { + if (errno == ENOENT) { + return 0; + } else { + error_errno("unable to open '%s'", todo_path); + return 0; + } + } + /* If there is only one line then we are done */ + eol = strchr(buf.buf, '\n'); + if (!eol || !eol[1]) + ret = 1; + + strbuf_release(&buf); + + return ret; +} + +void sequencer_post_commit_cleanup(struct repository *r) +{ + struct replay_opts opts = REPLAY_OPTS_INIT; + int need_cleanup = 0; + + if (file_exists(git_path_cherry_pick_head(r))) { + unlink(git_path_cherry_pick_head(r)); + opts.action = REPLAY_PICK; + need_cleanup = 1; + } + + if (file_exists(git_path_revert_head(r))) { + unlink(git_path_revert_head(r)); + opts.action = REPLAY_REVERT; + need_cleanup = 1; + } + + if (!need_cleanup) + return; + + if (!have_finished_the_last_pick()) + return; + + sequencer_remove_state(&opts); +} + static int read_populate_todo(struct repository *r, struct todo_list *todo_list, struct replay_opts *opts) @@ -2494,14 +2580,15 @@ static void write_strategy_opts(struct replay_opts *opts) } int write_basic_state(struct replay_opts *opts, const char *head_name, - const char *onto, const char *orig_head) + struct commit *onto, const char *orig_head) { const char *quiet = getenv("GIT_QUIET"); if (head_name) write_file(rebase_path_head_name(), "%s\n", head_name); if (onto) - write_file(rebase_path_onto(), "%s\n", onto); + write_file(rebase_path_onto(), "%s\n", + oid_to_hex(&onto->object.oid)); if (orig_head) write_file(rebase_path_orig_head(), "%s\n", orig_head); @@ -3517,10 +3604,11 @@ static const char *reflog_message(struct replay_opts *opts, return buf.buf; } -static int run_git_checkout(struct replay_opts *opts, const char *commit, - const char *action) +static int run_git_checkout(struct repository *r, struct replay_opts *opts, + const char *commit, const char *action) { struct child_process cmd = CHILD_PROCESS_INIT; + int ret; cmd.git_cmd = 1; @@ -3529,26 +3617,32 @@ static int run_git_checkout(struct replay_opts *opts, const char *commit, argv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action); if (opts->verbose) - return run_command(&cmd); + ret = run_command(&cmd); else - return run_command_silent_on_success(&cmd); + ret = run_command_silent_on_success(&cmd); + + if (!ret) + discard_index(r->index); + + return ret; } -int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit) +int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts, + const char *commit) { const char *action; if (commit && *commit) { action = reflog_message(opts, "start", "checkout %s", commit); - if (run_git_checkout(opts, commit, action)) + if (run_git_checkout(r, opts, commit, action)) return error(_("could not checkout %s"), commit); } return 0; } -static int checkout_onto(struct replay_opts *opts, - const char *onto_name, const char *onto, +static int checkout_onto(struct repository *r, struct replay_opts *opts, + const char *onto_name, const struct object_id *onto, const char *orig_head) { struct object_id oid; @@ -3557,7 +3651,7 @@ static int checkout_onto(struct replay_opts *opts, if (get_oid(orig_head, &oid)) return error(_("%s: not a valid OID"), orig_head); - if (run_git_checkout(opts, onto, action)) { + if (run_git_checkout(r, opts, oid_to_hex(onto), action)) { apply_autostash(opts); sequencer_remove_state(opts); return error(_("could not detach HEAD")); @@ -4833,16 +4927,16 @@ static int skip_unnecessary_picks(struct repository *r, int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags, const char *shortrevisions, const char *onto_name, - const char *onto, const char *orig_head, struct string_list *commands, - unsigned autosquash, struct todo_list *todo_list) + struct commit *onto, const char *orig_head, + struct string_list *commands, unsigned autosquash, + struct todo_list *todo_list) { const char *shortonto, *todo_file = rebase_path_todo(); struct todo_list new_todo = TODO_LIST_INIT; struct strbuf *buf = &todo_list->buf; - struct object_id oid; + struct object_id oid = onto->object.oid; int res; - get_oid(onto, &oid); shortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV); if (buf->len == 0) { @@ -4885,7 +4979,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) || todo_list_check(todo_list, &new_todo)) { fprintf(stderr, _(edit_todo_list_advice)); - checkout_onto(opts, onto_name, onto, orig_head); + checkout_onto(r, opts, onto_name, &onto->object.oid, orig_head); todo_list_release(&new_todo); return -1; @@ -4904,7 +4998,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla todo_list_release(&new_todo); - if (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head)) + if (checkout_onto(r, opts, onto_name, &oid, orig_head)) return -1; if (require_clean_work_tree(r, "rebase", "", 1, 1)) diff --git a/sequencer.h b/sequencer.h index 75e292c03b..0c494b83d4 100644 --- a/sequencer.h +++ b/sequencer.h @@ -151,7 +151,7 @@ void todo_list_add_exec_commands(struct todo_list *todo_list, int check_todo_list_from_file(struct repository *r); int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags, const char *shortrevisions, const char *onto_name, - const char *onto, const char *orig_head, struct string_list *commands, + struct commit *onto, const char *orig_head, struct string_list *commands, unsigned autosquash, struct todo_list *todo_list); int todo_list_rearrange_squash(struct todo_list *todo_list); @@ -183,7 +183,8 @@ void commit_post_rewrite(struct repository *r, const struct commit *current_head, const struct object_id *new_head); -int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit); +int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts, + const char *commit); #define SUMMARY_INITIAL_COMMIT (1 << 0) #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1) @@ -198,4 +199,7 @@ int read_author_script(const char *path, char **name, char **email, char **date, void parse_strategy_opts(struct replay_opts *opts, char *raw_opts); int write_basic_state(struct replay_opts *opts, const char *head_name, - const char *onto, const char *orig_head); + struct commit *onto, const char *orig_head); +void sequencer_post_commit_cleanup(struct repository *r); +int sequencer_get_last_command(struct repository* r, + enum replay_action *action); diff --git a/serve.h b/serve.h index fe65ba9f46..42ddca7f8b 100644 --- a/serve.h +++ b/serve.h @@ -2,14 +2,14 @@ #define SERVE_H struct argv_array; -extern int has_capability(const struct argv_array *keys, const char *capability, - const char **value); +int has_capability(const struct argv_array *keys, const char *capability, + const char **value); struct serve_options { unsigned advertise_capabilities; unsigned stateless_rpc; }; #define SERVE_OPTIONS_INIT { 0 } -extern void serve(struct serve_options *options); +void serve(struct serve_options *options); #endif /* SERVE_H */ diff --git a/sha1-lookup.h b/sha1-lookup.h index 7678b23b36..5afcd011c6 100644 --- a/sha1-lookup.h +++ b/sha1-lookup.h @@ -3,10 +3,10 @@ typedef const unsigned char *sha1_access_fn(size_t index, void *table); -extern int sha1_pos(const unsigned char *sha1, - void *table, - size_t nr, - sha1_access_fn fn); +int sha1_pos(const unsigned char *sha1, + void *table, + size_t nr, + sha1_access_fn fn); /* * Searches for sha1 in table, using the given fanout table to determine the diff --git a/sha1-name.c b/sha1-name.c index 775a73d8ad..b4f5cadae7 100644 --- a/sha1-name.c +++ b/sha1-name.c @@ -157,6 +157,9 @@ static void unique_in_pack(struct packed_git *p, uint32_t num, i, first = 0; const struct object_id *current = NULL; + if (p->multi_pack_index) + return; + if (open_pack_index(p) || !p->num_objects) return; @@ -625,6 +628,9 @@ static void find_abbrev_len_for_pack(struct packed_git *p, struct object_id oid; const struct object_id *mad_oid; + if (p->multi_pack_index) + return; + if (open_pack_index(p) || !p->num_objects) return; diff --git a/streaming.h b/streaming.h index 32f4626771..f465a3cd31 100644 --- a/streaming.h +++ b/streaming.h @@ -8,10 +8,10 @@ /* opaque */ struct git_istream; -extern struct git_istream *open_istream(const struct object_id *, enum object_type *, unsigned long *, struct stream_filter *); -extern int close_istream(struct git_istream *); -extern ssize_t read_istream(struct git_istream *, void *, size_t); +struct git_istream *open_istream(const struct object_id *, enum object_type *, unsigned long *, struct stream_filter *); +int close_istream(struct git_istream *); +ssize_t read_istream(struct git_istream *, void *, size_t); -extern int stream_blob_to_fd(int fd, const struct object_id *, struct stream_filter *, int can_seek); +int stream_blob_to_fd(int fd, const struct object_id *, struct stream_filter *, int can_seek); #endif /* STREAMING_H */ diff --git a/string-list.h b/string-list.h index 18c718c12c..f964399949 100644 --- a/string-list.h +++ b/string-list.h @@ -174,8 +174,8 @@ struct string_list_item *string_list_insert(struct string_list *list, const char * Remove the given string from the sorted list. If the string * doesn't exist, the list is not altered. */ -extern void string_list_remove(struct string_list *list, const char *string, - int free_util); +void string_list_remove(struct string_list *list, const char *string, + int free_util); /** * Check if the given string is part of a sorted list. If it is part of the list, diff --git a/sub-process.h b/sub-process.h index 71b18ad5af..5c182fad98 100644 --- a/sub-process.h +++ b/sub-process.h @@ -42,10 +42,10 @@ struct subprocess_capability { /* subprocess functions */ /* Function to test two subprocess hashmap entries for equality. */ -extern int cmd2process_cmp(const void *unused_cmp_data, - const void *e1, - const void *e2, - const void *unused_keydata); +int cmd2process_cmp(const void *unused_cmp_data, + const void *e1, + const void *e2, + const void *unused_keydata); /* * User-supplied function to initialize the sub-process. This is diff --git a/submodule-config.h b/submodule-config.h index 4dc9b0771c..1b4e2da658 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -30,17 +30,17 @@ struct submodule { struct submodule_cache; struct repository; -extern void submodule_cache_free(struct submodule_cache *cache); +void submodule_cache_free(struct submodule_cache *cache); -extern int parse_submodule_fetchjobs(const char *var, const char *value); -extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg); +int parse_submodule_fetchjobs(const char *var, const char *value); +int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg); struct option; -extern int option_fetch_parse_recurse_submodules(const struct option *opt, - const char *arg, int unset); -extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg); -extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg); -extern void repo_read_gitmodules(struct repository *repo); -extern void gitmodules_config_oid(const struct object_id *commit_oid); +int option_fetch_parse_recurse_submodules(const struct option *opt, + const char *arg, int unset); +int parse_update_recurse_submodules_arg(const char *opt, const char *arg); +int parse_push_recurse_submodules_arg(const char *opt, const char *arg); +void repo_read_gitmodules(struct repository *repo); +void gitmodules_config_oid(const struct object_id *commit_oid); const struct submodule *submodule_from_name(struct repository *r, const struct object_id *commit_or_tree, const char *name); @@ -66,7 +66,7 @@ int check_submodule_name(const char *name); * New helpers to retrieve arbitrary configuration from the '.gitmodules' file * should NOT be added. */ -extern void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules); -extern void update_clone_config_from_gitmodules(int *max_jobs); +void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules); +void update_clone_config_from_gitmodules(int *max_jobs); #endif /* SUBMODULE_CONFIG_H */ diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 2232b2f79e..af82db06ac 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -149,6 +149,9 @@ int cmd__parse_options(int argc, const char **argv) OPT_CALLBACK(0, "expect", &expect, "string", "expected output in the variable dump", collect_expect), + OPT_GROUP("Alias"), + OPT_STRING('A', "alias-source", &string, "string", "get a string"), + OPT_ALIAS('Z', "alias-target", "alias-source"), OPT_END(), }; int i; diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index d674c88ba0..7e79b555de 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -1,14 +1,36 @@ #include "test-tool.h" #include "cache.h" +#include "config.h" int cmd__read_cache(int argc, const char **argv) { - int i, cnt = 1; + int i, cnt = 1, namelen; + const char *name = NULL; + + if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) { + namelen = strlen(name); + argc--; + argv++; + } + if (argc == 2) cnt = strtol(argv[1], NULL, 0); setup_git_directory(); + git_config(git_default_config, NULL); for (i = 0; i < cnt; i++) { read_cache(); + if (name) { + int pos; + + refresh_index(&the_index, REFRESH_QUIET, + NULL, NULL, NULL); + pos = index_name_pos(&the_index, name, namelen); + if (pos < 0) + die("%s not in index", name); + printf("%s is%s up to date\n", name, + ce_uptodate(the_index.cache[pos]) ? "" : " not"); + write_file(name, "%d\n", i); + } discard_cache(); } return 0; diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 06a81b54c7..5c1c86c193 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -76,6 +76,7 @@ PassEnv GIT_VALGRIND PassEnv GIT_VALGRIND_OPTIONS PassEnv GNUPGHOME PassEnv ASAN_OPTIONS +PassEnv LSAN_OPTIONS PassEnv GIT_TRACE PassEnv GIT_CONFIG_NOSYSTEM PassEnv GIT_TEST_SIDEBAND_ALL diff --git a/t/perf/README b/t/perf/README index be12090c38..c7b70e2d28 100644 --- a/t/perf/README +++ b/t/perf/README @@ -45,7 +45,7 @@ call the aggregation script to summarize the results: $ ./p0001-rev-list.sh [...] - $ GIT_BUILD_DIR=/path/to/other/git ./p0001-rev-list.sh + $ ./run /path/to/other/git -- ./p0001-rev-list.sh [...] $ ./aggregate.perl . /path/to/other/git ./p0001-rev-list.sh diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl index 494907a892..66554d2161 100755 --- a/t/perf/aggregate.perl +++ b/t/perf/aggregate.perl @@ -3,9 +3,9 @@ use lib '../../perl/build/lib'; use strict; use warnings; -use JSON; use Getopt::Long; use Git; +use Cwd qw(realpath); sub get_times { my $name = shift; @@ -99,18 +99,21 @@ sub format_size { while (scalar @ARGV) { my $arg = $ARGV[0]; my $dir; + my $prefix = ''; last if -f $arg or $arg eq "--"; if (! -d $arg) { my $rev = Git::command_oneline(qw(rev-parse --verify), $arg); $dir = "build/".$rev; + } elsif ($arg eq '.') { + $dir = '.'; } else { - $arg =~ s{/*$}{}; - $dir = $arg; - $dirabbrevs{$dir} = $dir; + $dir = realpath($arg); + $dirnames{$dir} = $dir; + $prefix .= 'bindir'; } push @dirs, $dir; - $dirnames{$dir} = $arg; - my $prefix = $dir; + $dirnames{$dir} ||= $arg; + $prefix .= $dir; $prefix =~ tr/^a-zA-Z0-9/_/c; $prefixes{$dir} = $prefix . '.'; shift @ARGV; @@ -312,9 +315,6 @@ sub print_codespeed_results { $environment = $reponame; } elsif (exists $ENV{GIT_PERF_REPO_NAME} and $ENV{GIT_PERF_REPO_NAME} ne "") { $environment = $ENV{GIT_PERF_REPO_NAME}; - } elsif (exists $ENV{GIT_TEST_INSTALLED} and $ENV{GIT_TEST_INSTALLED} ne "") { - $environment = $ENV{GIT_TEST_INSTALLED}; - $environment =~ s|/bin-wrappers$||; } else { $environment = `uname -r`; chomp $environment; @@ -342,7 +342,8 @@ sub print_codespeed_results { } } - print to_json(\@data, {utf8 => 1, pretty => 1, canonical => 1}), "\n"; + require JSON; + print JSON::to_json(\@data, {utf8 => 1, pretty => 1, canonical => 1}), "\n"; } binmode STDOUT, ":utf8" or die "PANIC on binmode: $!"; diff --git a/t/perf/p5302-pack-index.sh b/t/perf/p5302-pack-index.sh index 99bdb16c85..a9b3e112d9 100755 --- a/t/perf/p5302-pack-index.sh +++ b/t/perf/p5302-pack-index.sh @@ -13,35 +13,40 @@ test_expect_success 'repack' ' export PACK ' -test_expect_success 'create target repositories' ' - for repo in t1 t2 t3 t4 t5 t6 - do - git init --bare $repo - done -' - test_perf 'index-pack 0 threads' ' - GIT_DIR=t1 git index-pack --threads=1 --stdin < $PACK + rm -rf repo.git && + git init --bare repo.git && + GIT_DIR=repo.git git index-pack --threads=1 --stdin < $PACK ' test_perf 'index-pack 1 thread ' ' - GIT_DIR=t2 GIT_FORCE_THREADS=1 git index-pack --threads=1 --stdin < $PACK + rm -rf repo.git && + git init --bare repo.git && + GIT_DIR=repo.git GIT_FORCE_THREADS=1 git index-pack --threads=1 --stdin < $PACK ' test_perf 'index-pack 2 threads' ' - GIT_DIR=t3 git index-pack --threads=2 --stdin < $PACK + rm -rf repo.git && + git init --bare repo.git && + GIT_DIR=repo.git git index-pack --threads=2 --stdin < $PACK ' test_perf 'index-pack 4 threads' ' - GIT_DIR=t4 git index-pack --threads=4 --stdin < $PACK + rm -rf repo.git && + git init --bare repo.git && + GIT_DIR=repo.git git index-pack --threads=4 --stdin < $PACK ' test_perf 'index-pack 8 threads' ' - GIT_DIR=t5 git index-pack --threads=8 --stdin < $PACK + rm -rf repo.git && + git init --bare repo.git && + GIT_DIR=repo.git git index-pack --threads=8 --stdin < $PACK ' test_perf 'index-pack default number of threads' ' - GIT_DIR=t6 git index-pack --stdin < $PACK + rm -rf repo.git && + git init --bare repo.git && + GIT_DIR=repo.git git index-pack --stdin < $PACK ' test_done diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh index bb91dbb173..6a3a42531b 100755 --- a/t/perf/p5310-pack-bitmaps.sh +++ b/t/perf/p5310-pack-bitmaps.sh @@ -12,8 +12,7 @@ test_perf_large_repo # We intentionally use the deprecated pack.writebitmaps # config so that we can test against older versions of git. test_expect_success 'setup bitmap config' ' - git config pack.writebitmaps true && - git config pack.writebitmaphashcache true + git config pack.writebitmaps true ' test_perf 'repack to disk' ' diff --git a/t/perf/p5311-pack-bitmaps-fetch.sh b/t/perf/p5311-pack-bitmaps-fetch.sh index b04575951f..47c3fd7581 100755 --- a/t/perf/p5311-pack-bitmaps-fetch.sh +++ b/t/perf/p5311-pack-bitmaps-fetch.sh @@ -7,7 +7,6 @@ test_perf_default_repo test_expect_success 'create bitmapped server repo' ' git config pack.writebitmaps true && - git config pack.writebitmaphashcache true && git repack -ad ' diff --git a/t/perf/p5600-partial-clone.sh b/t/perf/p5600-partial-clone.sh new file mode 100755 index 0000000000..3e04bd2ae1 --- /dev/null +++ b/t/perf/p5600-partial-clone.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description='performance of partial clones' +. ./perf-lib.sh + +test_perf_default_repo + +test_expect_success 'enable server-side config' ' + git config uploadpack.allowFilter true && + git config uploadpack.allowAnySHA1InWant true +' + +test_perf 'clone without blobs' ' + rm -rf bare.git && + git clone --no-local --bare --filter=blob:none . bare.git +' + +test_perf 'checkout of result' ' + rm -rf worktree && + mkdir -p worktree/.git && + tar -C bare.git -cf - . | tar -C worktree/.git -xf - && + git -C worktree config core.bare false && + git -C worktree checkout -f +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index 169f92eae3..b58a43ea43 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -21,19 +21,21 @@ # because it will change our working directory. TEST_DIRECTORY=$(pwd)/.. TEST_OUTPUT_DIRECTORY=$(pwd) -ABSOLUTE_GIT_TEST_INSTALLED=$( - test -n "$GIT_TEST_INSTALLED" && cd "$GIT_TEST_INSTALLED" && pwd) TEST_NO_CREATE_REPO=t TEST_NO_MALLOC_CHECK=t . ../test-lib.sh -if test -z "$GIT_TEST_INSTALLED"; then - perf_results_prefix= -else - perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"." - GIT_TEST_INSTALLED=$ABSOLUTE_GIT_TEST_INSTALLED +if test -n "$GIT_TEST_INSTALLED" -a -z "$PERF_SET_GIT_TEST_INSTALLED" +then + error "Do not use GIT_TEST_INSTALLED with the perf tests. + +Instead use: + + ./run -- + +See t/perf/README for details." fi # Variables from test-lib that are normally internal to the tests; we @@ -179,7 +181,7 @@ test_wrapper_ () { base=$(basename "$0" .sh) echo "$test_count" >>"$perf_results_dir"/$base.subtests echo "$1" >"$perf_results_dir"/$base.$test_count.descr - base="$perf_results_dir"/"$perf_results_prefix$(basename "$0" .sh)"."$test_count" + base="$perf_results_dir"/"$PERF_RESULTS_PREFIX$(basename "$0" .sh)"."$test_count" "$test_wrapper_func_" "$@" fi diff --git a/t/perf/run b/t/perf/run index 9aaa733c77..c7b86104e1 100755 --- a/t/perf/run +++ b/t/perf/run @@ -70,6 +70,24 @@ build_git_rev () { ) || die "failed to build revision '$mydir'" } +set_git_test_installed () { + mydir=$1 + + mydir_abs=$(cd $mydir && pwd) + mydir_abs_wrappers="$mydir_abs_wrappers/bin-wrappers" + if test -d "$mydir_abs_wrappers" + then + GIT_TEST_INSTALLED=$mydir_abs_wrappers + else + # Older versions of git lacked bin-wrappers; + # fallback to the files in the root. + GIT_TEST_INSTALLED=$mydir_abs + fi + export GIT_TEST_INSTALLED + PERF_SET_GIT_TEST_INSTALLED=true + export PERF_SET_GIT_TEST_INSTALLED +} + run_dirs_helper () { mydir=${1%/} shift @@ -79,7 +97,16 @@ run_dirs_helper () { if test $# -gt 0 -a "$1" = --; then shift fi - if [ ! -d "$mydir" ]; then + + PERF_RESULTS_PREFIX= + if test "$mydir" = "." + then + unset GIT_TEST_INSTALLED + elif test -d "$mydir" + then + PERF_RESULTS_PREFIX=bindir$(cd $mydir && printf "%s" "$(pwd)" | tr -c "[a-zA-Z0-9]" "_"). + set_git_test_installed "$mydir" + else rev=$(git rev-parse --verify "$mydir" 2>/dev/null) || die "'$mydir' is neither a directory nor a valid revision" if [ ! -d build/$rev ]; then @@ -87,16 +114,12 @@ run_dirs_helper () { fi build_git_rev $rev "$mydir" mydir=build/$rev + + PERF_RESULTS_PREFIX=build_$rev. + set_git_test_installed "$mydir" fi - if test "$mydir" = .; then - unset GIT_TEST_INSTALLED - else - GIT_TEST_INSTALLED="$mydir/bin-wrappers" - # Older versions of git lacked bin-wrappers; fallback to the - # files in the root. - test -d "$GIT_TEST_INSTALLED" || GIT_TEST_INSTALLED=$mydir - export GIT_TEST_INSTALLED - fi + export PERF_RESULTS_PREFIX + run_one_dir "$@" } diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 800b3ea5f5..cebc77fab0 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -48,6 +48,12 @@ Standard options -q, --quiet be quiet --expect expected output in the variable dump +Alias + -A, --alias-source + get a string + -Z, --alias-target + get a string + EOF test_expect_success 'test help' ' @@ -224,6 +230,17 @@ test_expect_success 'non ambiguous option (after two options it abbreviates)' ' test-tool parse-options --expect="string: 123" --st 123 ' +test_expect_success 'Alias options do not contribute to abbreviation' ' + test-tool parse-options --alias-source 123 >output && + grep "^string: 123" output && + test-tool parse-options --alias-target 123 >output && + grep "^string: 123" output && + test_must_fail test-tool parse-options --alias && + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + test-tool parse-options --alias 123 >output && + grep "^string: 123" output +' + cat >typo.err <<\EOF error: did you mean `--boolean` (with two dashes ?) EOF diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh index 819430658b..71194a3623 100755 --- a/t/t0210-trace2-normal.sh +++ b/t/t0210-trace2-normal.sh @@ -3,6 +3,11 @@ test_description='test trace2 facility (normal target)' . ./test-lib.sh +# Turn off any inherited trace2 settings for this test. +sane_unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT +sane_unset GIT_TR2_BRIEF +sane_unset GIT_TR2_CONFIG_PARAMS + # Add t/helper directory to PATH so that we can use a relative # path to run nested instances of test-tool.exe (see 004child). # This helps with HEREDOC comparisons later. @@ -15,11 +20,6 @@ PATH="$TTDIR:$PATH" && export PATH # Warning: So you may see extra lines in artifact files when # Warning: interactively debugging. -# Turn off any inherited trace2 settings for this test. -unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT -unset GIT_TR2_BRIEF -unset GIT_TR2_CONFIG_PARAMS - V=$(git version | sed -e 's/^git version //') && export V # There are multiple trace2 targets: normal, perf, and event. @@ -147,4 +147,43 @@ test_expect_success 'normal stream, error event' ' test_cmp expect actual ' +sane_unset GIT_TR2_BRIEF + +# Now test without environment variables and get all Trace2 settings +# from the global config. + +test_expect_success 'using global config, normal stream, return code 0' ' + test_when_finished "rm trace.normal actual expect" && + test_config_global trace2.normalBrief 1 && + test_config_global trace2.normalTarget "$(pwd)/trace.normal" && + test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 001return 0 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:0 + atexit elapsed:_TIME_ code:0 + EOF + test_cmp expect actual +' + +test_expect_success 'using global config with include' ' + test_when_finished "rm trace.normal actual expect real.gitconfig" && + test_config_global trace2.normalBrief 1 && + test_config_global trace2.normalTarget "$(pwd)/trace.normal" && + mv "$(pwd)/.gitconfig" "$(pwd)/real.gitconfig" && + test_config_global include.path "$(pwd)/real.gitconfig" && + test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 001return 0 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:0 + atexit elapsed:_TIME_ code:0 + EOF + test_cmp expect actual +' + test_done diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh index 953e2f7847..b501e867af 100755 --- a/t/t0211-trace2-perf.sh +++ b/t/t0211-trace2-perf.sh @@ -3,6 +3,11 @@ test_description='test trace2 facility (perf target)' . ./test-lib.sh +# Turn off any inherited trace2 settings for this test. +sane_unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT +sane_unset GIT_TR2_PERF_BRIEF +sane_unset GIT_TR2_CONFIG_PARAMS + # Add t/helper directory to PATH so that we can use a relative # path to run nested instances of test-tool.exe (see 004child). # This helps with HEREDOC comparisons later. @@ -15,11 +20,6 @@ PATH="$TTDIR:$PATH" && export PATH # Warning: So you may see extra lines in artifact files when # Warning: interactively debugging. -# Turn off any inherited trace2 settings for this test. -unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT -unset GIT_TR2_PERF_BRIEF -unset GIT_TR2_CONFIG_PARAMS - V=$(git version | sed -e 's/^git version //') && export V # There are multiple trace2 targets: normal, perf, and event. @@ -50,7 +50,7 @@ test_expect_success 'perf stream, return code 0' ' perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" actual && cat >expect <<-EOF && d0|main|version|||||$V - d0|main|start|||||_EXE_ trace2 001return 0 + d0|main|start||_T_ABS_|||_EXE_ trace2 001return 0 d0|main|cmd_name|||||trace2 (trace2) d0|main|exit||_T_ABS_|||code:0 d0|main|atexit||_T_ABS_|||code:0 @@ -64,7 +64,7 @@ test_expect_success 'perf stream, return code 1' ' perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" actual && cat >expect <<-EOF && d0|main|version|||||$V - d0|main|start|||||_EXE_ trace2 001return 1 + d0|main|start||_T_ABS_|||_EXE_ trace2 001return 1 d0|main|cmd_name|||||trace2 (trace2) d0|main|exit||_T_ABS_|||code:1 d0|main|atexit||_T_ABS_|||code:1 @@ -82,7 +82,7 @@ test_expect_success 'perf stream, error event' ' perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" actual && cat >expect <<-EOF && d0|main|version|||||$V - d0|main|start|||||_EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' + d0|main|start||_T_ABS_|||_EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' d0|main|cmd_name|||||trace2 (trace2) d0|main|error|||||hello world d0|main|error|||||this is a test @@ -128,15 +128,15 @@ test_expect_success 'perf stream, child processes' ' perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" actual && cat >expect <<-EOF && d0|main|version|||||$V - d0|main|start|||||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0 + d0|main|start||_T_ABS_|||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0 d0|main|cmd_name|||||trace2 (trace2) d0|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 004child test-tool trace2 001return 0 d1|main|version|||||$V - d1|main|start|||||_EXE_ trace2 004child test-tool trace2 001return 0 + d1|main|start||_T_ABS_|||_EXE_ trace2 004child test-tool trace2 001return 0 d1|main|cmd_name|||||trace2 (trace2/trace2) d1|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 001return 0 d2|main|version|||||$V - d2|main|start|||||_EXE_ trace2 001return 0 + d2|main|start||_T_ABS_|||_EXE_ trace2 001return 0 d2|main|cmd_name|||||trace2 (trace2/trace2/trace2) d2|main|exit||_T_ABS_|||code:0 d2|main|atexit||_T_ABS_|||code:0 @@ -150,4 +150,25 @@ test_expect_success 'perf stream, child processes' ' test_cmp expect actual ' +sane_unset GIT_TR2_PERF_BRIEF + +# Now test without environment variables and get all Trace2 settings +# from the global config. + +test_expect_success 'using global config, perf stream, return code 0' ' + test_when_finished "rm trace.perf actual expect" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" actual && + cat >expect <<-EOF && + d0|main|version|||||$V + d0|main|start||_T_ABS_|||_EXE_ trace2 001return 0 + d0|main|cmd_name|||||trace2 (trace2) + d0|main|exit||_T_ABS_|||code:0 + d0|main|atexit||_T_ABS_|||code:0 + EOF + test_cmp expect actual +' + test_done diff --git a/t/t0212-trace2-event.sh b/t/t0212-trace2-event.sh index 028b6c5671..59adae8123 100755 --- a/t/t0212-trace2-event.sh +++ b/t/t0212-trace2-event.sh @@ -3,6 +3,11 @@ test_description='test trace2 facility' . ./test-lib.sh +# Turn off any inherited trace2 settings for this test. +sane_unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT +sane_unset GIT_TR2_BARE +sane_unset GIT_TR2_CONFIG_PARAMS + perl -MJSON::PP -e 0 >/dev/null 2>&1 && test_set_prereq JSON_PP # Add t/helper directory to PATH so that we can use a relative @@ -17,11 +22,6 @@ PATH="$TTDIR:$PATH" && export PATH # Warning: So you may see extra lines in artifact files when # Warning: interactively debugging. -# Turn off any inherited trace2 settings for this test. -unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT -unset GIT_TR2_BARE -unset GIT_TR2_CONFIG_PARAMS - V=$(git version | sed -e 's/^git version //') && export V # There are multiple trace2 targets: normal, perf, and event. @@ -233,4 +233,36 @@ test_expect_success JSON_PP 'basic trace2_data' ' test_cmp expect actual ' +# Now test without environment variables and get all Trace2 settings +# from the global config. + +test_expect_success JSON_PP 'using global config, event stream, error event' ' + test_when_finished "rm trace.event actual expect" && + test_config_global trace2.eventTarget "$(pwd)/trace.event" && + test-tool trace2 003error "hello world" "this is a test" && + perl "$TEST_DIRECTORY/t0212/parse_events.perl" actual && + sed -e "s/^|//" >expect <<-EOF && + |VAR1 = { + | "_SID0_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "003error", + | "hello world", + | "this is a test" + | ], + | "errors":[ + | "%s", + | "%s" + | ], + | "exit_code":0, + | "hierarchy":"trace2", + | "name":"trace2", + | "version":"$V" + | } + |}; + EOF + test_cmp expect actual +' + test_done diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh index c5014ad9a6..822381dd9d 100755 --- a/t/t2018-checkout-branch.sh +++ b/t/t2018-checkout-branch.sh @@ -60,38 +60,47 @@ test_expect_success 'setup' ' ' test_expect_success 'checkout -b to a new branch, set to HEAD' ' + test_when_finished " + git checkout branch1 && + test_might_fail git branch -D branch2" && do_checkout branch2 ' -test_expect_success 'checkout -b to a new branch, set to an explicit ref' ' - git checkout branch1 && - git branch -D branch2 && +test_expect_success 'checkout -b to a merge base' ' + test_when_finished " + git checkout branch1 && + test_might_fail git branch -D branch2" && + git checkout -b branch2 branch1... +' +test_expect_success 'checkout -b to a new branch, set to an explicit ref' ' + test_when_finished " + git checkout branch1 && + test_might_fail git branch -D branch2" && do_checkout branch2 $HEAD1 ' test_expect_success 'checkout -b to a new branch with unmergeable changes fails' ' - git checkout branch1 && - - # clean up from previous test - git branch -D branch2 && - setup_dirty_unmergeable && test_must_fail do_checkout branch2 $HEAD1 && test_dirty_unmergeable ' test_expect_success 'checkout -f -b to a new branch with unmergeable changes discards changes' ' + test_when_finished " + git checkout branch1 && + test_might_fail git branch -D branch2" && + # still dirty and on branch1 do_checkout branch2 $HEAD1 "-f -b" && test_must_fail test_dirty_unmergeable ' test_expect_success 'checkout -b to a new branch preserves mergeable changes' ' - git checkout branch1 && - - # clean up from previous test - git branch -D branch2 && + test_when_finished " + git reset --hard && + git checkout branch1 && + test_might_fail git branch -D branch2" && setup_dirty_mergeable && do_checkout branch2 $HEAD1 && @@ -99,27 +108,18 @@ test_expect_success 'checkout -b to a new branch preserves mergeable changes' ' ' test_expect_success 'checkout -f -b to a new branch with mergeable changes discards changes' ' - # clean up from previous test - git reset --hard && - - git checkout branch1 && - - # clean up from previous test - git branch -D branch2 && - + test_when_finished git reset --hard HEAD && setup_dirty_mergeable && do_checkout branch2 $HEAD1 "-f -b" && test_must_fail test_dirty_mergeable ' test_expect_success 'checkout -b to an existing branch fails' ' - git reset --hard HEAD && - + test_when_finished git reset --hard HEAD && test_must_fail do_checkout branch2 $HEAD2 ' test_expect_success 'checkout -b to @{-1} fails with the right branch name' ' - git reset --hard HEAD && git checkout branch1 && git checkout branch2 && echo >expect "fatal: A branch named '\''branch1'\'' already exists." && @@ -133,6 +133,12 @@ test_expect_success 'checkout -B to an existing branch resets branch to HEAD' ' do_checkout branch2 "" -B ' +test_expect_success 'checkout -B to a merge base' ' + git checkout branch1 && + + git checkout -B branch2 branch1... +' + test_expect_success 'checkout -B to an existing branch from detached HEAD resets branch to HEAD' ' git checkout $(git rev-parse --verify HEAD) && @@ -160,6 +166,7 @@ test_expect_success 'checkout -f -B to an existing branch with unmergeable chang ' test_expect_success 'checkout -B to an existing branch preserves mergeable changes' ' + test_when_finished git reset --hard && git checkout branch1 && setup_dirty_mergeable && @@ -168,9 +175,6 @@ test_expect_success 'checkout -B to an existing branch preserves mergeable chang ' test_expect_success 'checkout -f -B to an existing branch with mergeable changes discards changes' ' - # clean up from previous test - git reset --hard && - git checkout branch1 && setup_dirty_mergeable && diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index e9ad50b66d..e9d7084d19 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -42,6 +42,10 @@ test_expect_success 'git branch a/b/c should create a branch' ' git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c ' +test_expect_success 'git branch mb master... should create a branch' ' + git branch mb master... && test_path_is_file .git/refs/heads/mb +' + test_expect_success 'git branch HEAD should fail' ' test_must_fail git branch HEAD ' @@ -316,8 +320,8 @@ test_expect_success 'git branch --list -v with --abbrev' ' test_expect_success 'git branch --column' ' COLUMNS=81 git branch --column=column >actual && cat >expected <<\EOF && - a/b/c bam foo l * master n o/p r - abc bar j/k m/m master2 o/o q + a/b/c bam foo l * master mb o/o q + abc bar j/k m/m master2 n o/p r EOF test_cmp expected actual ' @@ -339,6 +343,7 @@ test_expect_success 'git branch --column with an extremely long branch name' ' m/m * master master2 + mb n o/o o/p @@ -356,8 +361,8 @@ test_expect_success 'git branch with column.*' ' git config --unset column.branch && git config --unset column.ui && cat >expected <<\EOF && - a/b/c bam foo l * master n o/p r - abc bar j/k m/m master2 o/o q + a/b/c bam foo l * master mb o/o q + abc bar j/k m/m master2 n o/p r EOF test_cmp expected actual ' @@ -381,6 +386,7 @@ test_expect_success 'git branch -v with column.ui ignored' ' m/m * master master2 + mb n o/o o/p diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 1a8818fbe0..9b9b4ca8d4 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -161,6 +161,25 @@ test_expect_success 'successful commit clears CHERRY_PICK_HEAD' ' test_must_fail git rev-parse --verify CHERRY_PICK_HEAD ' +test_expect_success 'successful final commit clears cherry-pick state' ' + pristine_detach initial && + + test_must_fail git cherry-pick base picked-signed && + echo resolved >foo && + test_path_is_file .git/sequencer/todo && + git commit -a && + test_must_fail test_path_exists .git/sequencer +' + +test_expect_success 'reset after final pick clears cherry-pick state' ' + pristine_detach initial && + + test_must_fail git cherry-pick base picked-signed && + echo resolved >foo && + test_path_is_file .git/sequencer/todo && + git reset && + test_must_fail test_path_exists .git/sequencer +' test_expect_success 'failed cherry-pick produces dirty index' ' pristine_detach initial && @@ -361,6 +380,26 @@ test_expect_success 'failed commit does not clear REVERT_HEAD' ' test_cmp_rev picked REVERT_HEAD ' +test_expect_success 'successful final commit clears revert state' ' + pristine_detach picked-signed && + + test_must_fail git revert picked-signed base && + echo resolved >foo && + test_path_is_file .git/sequencer/todo && + git commit -a && + test_must_fail test_path_exists .git/sequencer +' + +test_expect_success 'reset after final pick clears revert state' ' + pristine_detach picked-signed && + + test_must_fail git revert picked-signed base && + echo resolved >foo && + test_path_is_file .git/sequencer/todo && + git reset && + test_must_fail test_path_exists .git/sequencer +' + test_expect_success 'revert conflict, diff3 -m style' ' pristine_detach initial && git config merge.conflictstyle diff3 && diff --git a/t/t4253-am-keep-cr-dos.sh b/t/t4253-am-keep-cr-dos.sh index 553fe3e88e..6e1b73ec3a 100755 --- a/t/t4253-am-keep-cr-dos.sh +++ b/t/t4253-am-keep-cr-dos.sh @@ -51,14 +51,16 @@ test_expect_success 'am with dos files without --keep-cr' ' test_expect_success 'am with dos files with --keep-cr' ' git checkout -b dosfiles-keep-cr initial && - git format-patch -k --stdout initial..master | git am --keep-cr -k -3 && + git format-patch -k --stdout initial..master >output && + git am --keep-cr -k -3 output && git diff --exit-code master ' test_expect_success 'am with dos files config am.keepcr' ' git config am.keepcr 1 && git checkout -b dosfiles-conf-keepcr initial && - git format-patch -k --stdout initial..master | git am -k -3 && + git format-patch -k --stdout initial..master >output && + git am -k -3 output && git diff --exit-code master ' diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index 82d7f7f6a5..a26c8ba9a2 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -34,8 +34,7 @@ test_expect_success 'setup repo with moderate-sized history' ' bitmaptip=$(git rev-parse master) && blob=$(echo tagged-blob | git hash-object -w --stdin) && git tag tagged-blob $blob && - git config repack.writebitmaps true && - git config pack.writebitmaphashcache true + git config repack.writebitmaps true ' test_expect_success 'full repack creates bitmaps' ' @@ -269,7 +268,7 @@ test_expect_success JGIT 'we can read jgit bitmaps' ' git clone --bare . compat-jgit.git && ( cd compat-jgit.git && - rm -f .git/objects/pack/*.bitmap && + rm -f objects/pack/*.bitmap && jgit gc && git rev-list --test-bitmap HEAD ) diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh index 217adf3a63..b3c8a92450 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -62,4 +62,16 @@ test_expect_success MINGW 'remote nick cannot contain backslashes' ' test_i18ngrep ! "unable to access" err ' +test_expect_success 'unc alternates' ' + tree="$(git rev-parse HEAD:)" && + mkdir test-unc-alternate && + ( + cd test-unc-alternate && + git init && + test_must_fail git show $tree && + echo "$UNCPATH/.git/objects" >.git/objects/info/alternates && + git show $tree + ) +' + test_done diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 7411bf7fec..515c6735e9 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -181,7 +181,15 @@ test_expect_success 'background auto gc respects lock for all operations' ' # now fake a concurrent gc that holds the lock; we can use our # shell pid so that it looks valid. hostname=$(hostname || echo unknown) && - printf "$$ %s" "$hostname" >.git/gc.pid && + shell_pid=$$ && + if test_have_prereq MINGW && test -f /proc/$shell_pid/winpid + then + # In Git for Windows, Bash (actually, the MSYS2 runtime) has a + # different idea of PIDs than git.exe (actually Windows). Use + # the Windows PID in this case. + shell_pid=$(cat /proc/$shell_pid/winpid) + fi && + printf "%d %s" "$shell_pid" "$hostname" >.git/gc.pid && # our gc should exit zero without doing anything run_and_wait_for_auto_gc && diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index e285686662..6aeeb279a0 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1702,7 +1702,7 @@ test_expect_success '--points-at finds annotated tags of tags' ' test_expect_success 'recursive tagging should give advice' ' sed -e "s/|$//" <<-EOF >expect && - hint: You have created a nested tag. The object referred to by your new is + hint: You have created a nested tag. The object referred to by your new tag is hint: already a tag. If you meant to tag the object that it points to, use: hint: | hint: git tag -f nested annotated-v4.0^{} diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 458608cc1e..c1eb72555d 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -780,6 +780,24 @@ EOF test_i18ncmp expected actual ' +test_expect_success 'status when cherry-picking after committing conflict resolution' ' + git reset --hard cherry_branch && + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second one_cherry && + echo end >main.txt && + git commit -a && + cat >expected <actual && + test_i18ncmp expected actual +' + test_expect_success 'status showing detached at and from a tag' ' test_commit atag tagging && git checkout atag && @@ -857,6 +875,24 @@ EOF test_i18ncmp expected actual ' +test_expect_success 'status while reverting after committing conflict resolution' ' + test_when_finished "git revert --abort" && + git reset --hard new && + test_must_fail git revert old new && + echo reverted >to-revert.txt && + git commit -a && + cat >expected <actual && + test_i18ncmp expected actual +' + test_expect_success 'prepare for different number of commits rebased' ' git reset --hard master && git checkout -b several_commits && diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh index 3e0a61db23..81a375fa0f 100755 --- a/t/t7519-status-fsmonitor.sh +++ b/t/t7519-status-fsmonitor.sh @@ -346,4 +346,12 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' test_cmp before after ' +test_expect_success 'discard_index() also discards fsmonitor info' ' + test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" && + test_might_fail git update-index --refresh && + test-tool read-cache --print-and-refresh=tracked 2 >actual && + printf "tracked is%s up to date\n" "" " not" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index a9fb971615..5b61c10a9c 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -130,14 +130,55 @@ test_expect_success 'custom mergetool' ' test_when_finished "git reset --hard" && git checkout -b test$test_count branch1 && git submodule update -N && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && + test_must_fail git merge master && + ( yes "" | git mergetool both ) && ( yes "" | git mergetool file1 file1 ) && - ( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) && - ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && + ( yes "" | git mergetool file2 "spaced name" ) && + ( yes "" | git mergetool subdir/file3 ) && + ( yes "d" | git mergetool file11 ) && + ( yes "d" | git mergetool file12 ) && + ( yes "l" | git mergetool submod ) && + test "$(cat file1)" = "master updated" && + test "$(cat file2)" = "master new" && + test "$(cat subdir/file3)" = "master new sub" && + test "$(cat submod/bar)" = "branch1 submodule" && + git commit -m "branch1 resolved with mergetool" +' + +test_expect_success 'gui mergetool' ' + test_config merge.guitool myguitool && + test_config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\"" && + test_config mergetool.myguitool.trustExitCode true && + test_when_finished "git reset --hard" && + git checkout -b test$test_count branch1 && + git submodule update -N && + test_must_fail git merge master && + ( yes "" | git mergetool --gui both ) && + ( yes "" | git mergetool -g file1 file1 ) && + ( yes "" | git mergetool --gui file2 "spaced name" ) && + ( yes "" | git mergetool --gui subdir/file3 ) && + ( yes "d" | git mergetool --gui file11 ) && + ( yes "d" | git mergetool --gui file12 ) && + ( yes "l" | git mergetool --gui submod ) && + test "$(cat file1)" = "gui master updated" && + test "$(cat file2)" = "gui master new" && + test "$(cat subdir/file3)" = "gui master new sub" && + test "$(cat submod/bar)" = "branch1 submodule" && + git commit -m "branch1 resolved with mergetool" +' + +test_expect_success 'gui mergetool without merge.guitool set falls back to merge.tool' ' + test_when_finished "git reset --hard" && + git checkout -b test$test_count branch1 && + git submodule update -N && + test_must_fail git merge master && + ( yes "" | git mergetool --gui both ) && + ( yes "" | git mergetool -g file1 file1 ) && + ( yes "" | git mergetool --gui file2 "spaced name" ) && + ( yes "" | git mergetool --gui subdir/file3 ) && + ( yes "d" | git mergetool --gui file11 ) && + ( yes "d" | git mergetool --gui file12 ) && + ( yes "l" | git mergetool --gui submod ) && test "$(cat file1)" = "master updated" && test "$(cat file2)" = "master new" && test "$(cat subdir/file3)" = "master new sub" && @@ -153,15 +194,15 @@ test_expect_success 'mergetool crlf' ' # test_when_finished is LIFO.) test_config core.autocrlf true && git checkout -b test$test_count branch1 && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool file1 >/dev/null 2>&1 ) && - ( yes "" | git mergetool file2 >/dev/null 2>&1 ) && - ( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - ( yes "r" | git mergetool submod >/dev/null 2>&1 ) && + test_must_fail git merge master && + ( yes "" | git mergetool file1 ) && + ( yes "" | git mergetool file2 ) && + ( yes "" | git mergetool "spaced name" ) && + ( yes "" | git mergetool both ) && + ( yes "" | git mergetool subdir/file3 ) && + ( yes "d" | git mergetool file11 ) && + ( yes "d" | git mergetool file12 ) && + ( yes "r" | git mergetool submod ) && test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" && test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" && test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" && @@ -176,8 +217,8 @@ test_expect_success 'mergetool in subdir' ' git submodule update -N && ( cd subdir && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool file3 >/dev/null 2>&1 ) && + test_must_fail git merge master && + ( yes "" | git mergetool file3 ) && test "$(cat file3)" = "master new sub" ) ' @@ -188,14 +229,14 @@ test_expect_success 'mergetool on file in parent dir' ' git submodule update -N && ( cd subdir && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) && - ( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) && - ( yes "" | git mergetool ../both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) && + test_must_fail git merge master && + ( yes "" | git mergetool file3 ) && + ( yes "" | git mergetool ../file1 ) && + ( yes "" | git mergetool ../file2 ../spaced\ name ) && + ( yes "" | git mergetool ../both ) && + ( yes "d" | git mergetool ../file11 ) && + ( yes "d" | git mergetool ../file12 ) && + ( yes "l" | git mergetool ../submod ) && test "$(cat ../file1)" = "master updated" && test "$(cat ../file2)" = "master new" && test "$(cat ../submod/bar)" = "branch1 submodule" && @@ -209,9 +250,9 @@ test_expect_success 'mergetool skips autoresolved' ' git submodule update -N && test_must_fail git merge master && test -n "$(git ls-files -u)" && - ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 ) && + ( yes "d" | git mergetool file12 ) && + ( yes "l" | git mergetool submod ) && output="$(git mergetool --no-prompt)" && test "$output" = "No files need merging" ' @@ -259,9 +300,9 @@ test_expect_success 'mergetool skips resolved paths when rerere is active' ' rm -rf .git/rr-cache && git checkout -b test$test_count branch1 && git submodule update -N && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "l" | git mergetool --no-prompt submod >/dev/null 2>&1 ) && - ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) && + test_must_fail git merge master && + ( yes "l" | git mergetool --no-prompt submod ) && + ( yes "d" "d" | git mergetool --no-prompt ) && git submodule update -N && output="$(yes "n" | git mergetool --no-prompt)" && test "$output" = "No files need merging" @@ -369,9 +410,9 @@ test_expect_success 'deleted vs modified submodule' ' git checkout -b test$test_count.a test$test_count && test_must_fail git merge master && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "r" | git mergetool submod ) && rmdir submod && mv submod-movedaside submod && test "$(cat submod/bar)" = "branch1 submodule" && @@ -386,9 +427,9 @@ test_expect_success 'deleted vs modified submodule' ' git submodule update -N && test_must_fail git merge master && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "l" | git mergetool submod ) && test ! -e submod && output="$(git mergetool --no-prompt)" && @@ -400,9 +441,9 @@ test_expect_success 'deleted vs modified submodule' ' git submodule update -N && test_must_fail git merge test$test_count && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "r" | git mergetool submod ) && test ! -e submod && test -d submod.orig && @@ -416,9 +457,9 @@ test_expect_success 'deleted vs modified submodule' ' git submodule update -N && test_must_fail git merge test$test_count && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "l" | git mergetool submod ) && test "$(cat submod/bar)" = "master submodule" && git submodule update -N && @@ -440,9 +481,9 @@ test_expect_success 'file vs modified submodule' ' git checkout -b test$test_count.a branch1 && test_must_fail git merge master && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "r" | git mergetool submod ) && rmdir submod && mv submod-movedaside submod && test "$(cat submod/bar)" = "branch1 submodule" && @@ -456,9 +497,9 @@ test_expect_success 'file vs modified submodule' ' git checkout -b test$test_count.b test$test_count && test_must_fail git merge master && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "l" | git mergetool submod ) && git submodule update -N && test "$(cat submod)" = "not a submodule" && @@ -472,9 +513,9 @@ test_expect_success 'file vs modified submodule' ' git submodule update -N && test_must_fail git merge test$test_count && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "r" | git mergetool submod ) && test -d submod.orig && git submodule update -N && @@ -488,9 +529,9 @@ test_expect_success 'file vs modified submodule' ' git submodule update -N && test_must_fail git merge test$test_count && test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both>/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) && + ( yes "" | git mergetool both ) && + ( yes "d" | git mergetool file11 file12 ) && ( yes "l" | git mergetool submod ) && test "$(cat submod/bar)" = "master submodule" && git submodule update -N && @@ -543,7 +584,7 @@ test_expect_success 'submodule in subdirectory' ' git add subdir/subdir_module && git commit -m "change submodule in subdirectory on test$test_count.b" && - test_must_fail git merge test$test_count.a >/dev/null 2>&1 && + test_must_fail git merge test$test_count.a && ( cd subdir && ( yes "l" | git mergetool subdir_module ) @@ -554,7 +595,7 @@ test_expect_success 'submodule in subdirectory' ' git reset --hard && git submodule update -N && - test_must_fail git merge test$test_count.a >/dev/null 2>&1 && + test_must_fail git merge test$test_count.a && ( yes "r" | git mergetool subdir/subdir_module ) && test "$(cat subdir/subdir_module/file15)" = "test$test_count.b" && git submodule update -N && @@ -641,7 +682,7 @@ test_expect_success 'filenames seen by tools start with ./' ' test_config mergetool.myecho.trustExitCode true && test_must_fail git merge master && git mergetool --no-prompt --tool myecho -- both >actual && - grep ^\./both_LOCAL_ actual >/dev/null + grep ^\./both_LOCAL_ actual ' test_lazy_prereq MKTEMP ' @@ -658,8 +699,8 @@ test_expect_success MKTEMP 'temporary filenames are used with mergetool.writeToT test_config mergetool.myecho.trustExitCode true && test_must_fail git merge master && git mergetool --no-prompt --tool myecho -- both >actual && - ! grep ^\./both_LOCAL_ actual >/dev/null && - grep /both_LOCAL_ actual >/dev/null + ! grep ^\./both_LOCAL_ actual && + grep /both_LOCAL_ actual ' test_expect_success 'diff.orderFile configuration is honored' ' diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 6162e2a8e6..86d05160a3 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -221,5 +221,22 @@ test_expect_success 'repack --keep-pack' ' ) ' -test_done +test_expect_success 'bitmaps are created by default in bare repos' ' + git clone --bare .git bare.git && + git -C bare.git repack -ad && + bitmap=$(ls bare.git/objects/pack/*.bitmap) && + test_path_is_file "$bitmap" +' + +test_expect_success 'incremental repack does not complain' ' + git -C bare.git repack -q 2>repack.err && + test_must_be_empty repack.err +' +test_expect_success 'bitmaps can be disabled on bare repos' ' + git -c repack.writeBitmaps=false -C bare.git repack -ad && + bitmap=$(ls bare.git/objects/pack/*.bitmap 2>/dev/null || :) && + test -z "$bitmap" +' + +test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 480dd0633f..6bac9ed180 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -279,11 +279,27 @@ test_expect_success 'difftool + mergetool config variables' ' echo branch >expect && git difftool --no-prompt branch >actual && test_cmp expect actual && + git difftool --gui --no-prompt branch >actual && + test_cmp expect actual && # set merge.tool to something bogus, diff.tool to test-tool test_config merge.tool bogus-tool && test_config diff.tool test-tool && git difftool --no-prompt branch >actual && + test_cmp expect actual && + git difftool --gui --no-prompt branch >actual && + test_cmp expect actual && + + # set merge.tool, diff.tool to something bogus, merge.guitool to test-tool + test_config diff.tool bogus-tool && + test_config merge.guitool test-tool && + git difftool --gui --no-prompt branch >actual && + test_cmp expect actual && + + # set merge.tool, diff.tool, merge.guitool to something bogus, diff.guitool to test-tool + test_config merge.guitool bogus-tool && + test_config diff.guitool test-tool && + git difftool --gui --no-prompt branch >actual && test_cmp expect actual ' @@ -715,4 +731,12 @@ test_expect_success 'outside worktree' ' test_cmp expect actual ' +test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive' ' + difftool_test_setup && + test_must_fail git difftool --gui --tool=test-tool && + test_must_fail git difftool --gui --extcmd=cat && + test_must_fail git difftool --tool=test-tool --extcmd=cat && + test_must_fail git difftool --gui --tool=test-tool --extcmd=cat +' + test_done diff --git a/tag.h b/tag.h index e669c3e497..03265fbfe2 100644 --- a/tag.h +++ b/tag.h @@ -11,13 +11,13 @@ struct tag { char *tag; timestamp_t date; }; -extern struct tag *lookup_tag(struct repository *r, const struct object_id *oid); -extern int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size); -extern int parse_tag(struct tag *item); -extern void release_tag_memory(struct tag *t); -extern struct object *deref_tag(struct repository *r, struct object *, const char *, int); -extern struct object *deref_tag_noverify(struct object *); -extern int gpg_verify_tag(const struct object_id *oid, - const char *name_to_report, unsigned flags); +struct tag *lookup_tag(struct repository *r, const struct object_id *oid); +int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size); +int parse_tag(struct tag *item); +void release_tag_memory(struct tag *t); +struct object *deref_tag(struct repository *r, struct object *, const char *, int); +struct object *deref_tag_noverify(struct object *); +int gpg_verify_tag(const struct object_id *oid, + const char *name_to_report, unsigned flags); #endif /* TAG_H */ diff --git a/tempfile.h b/tempfile.h index 61d8dc4d1b..cddda0a33c 100644 --- a/tempfile.h +++ b/tempfile.h @@ -89,7 +89,7 @@ struct tempfile { * a tempfile (whose "fd" member can be used for writing to it), or * NULL on error. It is an error if a file already exists at that path. */ -extern struct tempfile *create_tempfile(const char *path); +struct tempfile *create_tempfile(const char *path); /* * Register an existing file as a tempfile, meaning that it will be @@ -97,7 +97,7 @@ extern struct tempfile *create_tempfile(const char *path); * but it can be worked with like any other closed tempfile (for * example, it can be opened using reopen_tempfile()). */ -extern struct tempfile *register_tempfile(const char *path); +struct tempfile *register_tempfile(const char *path); /* @@ -136,8 +136,8 @@ extern struct tempfile *register_tempfile(const char *path); */ /* See "mks_tempfile functions" above. */ -extern struct tempfile *mks_tempfile_sm(const char *filename_template, - int suffixlen, int mode); +struct tempfile *mks_tempfile_sm(const char *filename_template, + int suffixlen, int mode); /* See "mks_tempfile functions" above. */ static inline struct tempfile *mks_tempfile_s(const char *filename_template, @@ -159,8 +159,8 @@ static inline struct tempfile *mks_tempfile(const char *filename_template) } /* See "mks_tempfile functions" above. */ -extern struct tempfile *mks_tempfile_tsm(const char *filename_template, - int suffixlen, int mode); +struct tempfile *mks_tempfile_tsm(const char *filename_template, + int suffixlen, int mode); /* See "mks_tempfile functions" above. */ static inline struct tempfile *mks_tempfile_ts(const char *filename_template, @@ -182,7 +182,7 @@ static inline struct tempfile *mks_tempfile_t(const char *filename_template) } /* See "mks_tempfile functions" above. */ -extern struct tempfile *xmks_tempfile_m(const char *filename_template, int mode); +struct tempfile *xmks_tempfile_m(const char *filename_template, int mode); /* See "mks_tempfile functions" above. */ static inline struct tempfile *xmks_tempfile(const char *filename_template) @@ -196,7 +196,7 @@ static inline struct tempfile *xmks_tempfile(const char *filename_template) * stream is closed automatically when `close_tempfile_gently()` is called or * when the file is deleted or renamed. */ -extern FILE *fdopen_tempfile(struct tempfile *tempfile, const char *mode); +FILE *fdopen_tempfile(struct tempfile *tempfile, const char *mode); static inline int is_tempfile_active(struct tempfile *tempfile) { @@ -207,10 +207,10 @@ static inline int is_tempfile_active(struct tempfile *tempfile) * Return the path of the lockfile. The return value is a pointer to a * field within the lock_file object and should not be freed. */ -extern const char *get_tempfile_path(struct tempfile *tempfile); +const char *get_tempfile_path(struct tempfile *tempfile); -extern int get_tempfile_fd(struct tempfile *tempfile); -extern FILE *get_tempfile_fp(struct tempfile *tempfile); +int get_tempfile_fd(struct tempfile *tempfile); +FILE *get_tempfile_fp(struct tempfile *tempfile); /* * If the temporary file is still open, close it (and the file pointer @@ -220,7 +220,7 @@ extern FILE *get_tempfile_fp(struct tempfile *tempfile); * should eventually be called regardless of whether `close_tempfile_gently()` * succeeds. */ -extern int close_tempfile_gently(struct tempfile *tempfile); +int close_tempfile_gently(struct tempfile *tempfile); /* * Re-open a temporary file that has been closed using @@ -241,7 +241,7 @@ extern int close_tempfile_gently(struct tempfile *tempfile); * * * `rename_tempfile()` to move the file to its permanent location. */ -extern int reopen_tempfile(struct tempfile *tempfile); +int reopen_tempfile(struct tempfile *tempfile); /* * Close the file descriptor and/or file pointer and remove the @@ -249,7 +249,7 @@ extern int reopen_tempfile(struct tempfile *tempfile); * `delete_tempfile()` for a `tempfile` object that has already been * deleted or renamed. */ -extern void delete_tempfile(struct tempfile **tempfile_p); +void delete_tempfile(struct tempfile **tempfile_p); /* * Close the file descriptor and/or file pointer if they are still @@ -260,6 +260,6 @@ extern void delete_tempfile(struct tempfile **tempfile_p); * `rename(2)`. It is a bug to call `rename_tempfile()` for a * `tempfile` object that is not currently active. */ -extern int rename_tempfile(struct tempfile **tempfile_p, const char *path); +int rename_tempfile(struct tempfile **tempfile_p, const char *path); #endif /* TEMPFILE_H */ diff --git a/trace.h b/trace.h index 171b256d26..9fa3e7a594 100644 --- a/trace.h +++ b/trace.h @@ -17,34 +17,34 @@ extern struct trace_key trace_default_key; extern struct trace_key trace_perf_key; extern struct trace_key trace_setup_key; -extern void trace_repo_setup(const char *prefix); -extern int trace_want(struct trace_key *key); -extern void trace_disable(struct trace_key *key); -extern uint64_t getnanotime(void); -extern void trace_command_performance(const char **argv); -extern void trace_verbatim(struct trace_key *key, const void *buf, unsigned len); +void trace_repo_setup(const char *prefix); +int trace_want(struct trace_key *key); +void trace_disable(struct trace_key *key); +uint64_t getnanotime(void); +void trace_command_performance(const char **argv); +void trace_verbatim(struct trace_key *key, const void *buf, unsigned len); uint64_t trace_performance_enter(void); #ifndef HAVE_VARIADIC_MACROS __attribute__((format (printf, 1, 2))) -extern void trace_printf(const char *format, ...); +void trace_printf(const char *format, ...); __attribute__((format (printf, 2, 3))) -extern void trace_printf_key(struct trace_key *key, const char *format, ...); +void trace_printf_key(struct trace_key *key, const char *format, ...); __attribute__((format (printf, 2, 3))) -extern void trace_argv_printf(const char **argv, const char *format, ...); +void trace_argv_printf(const char **argv, const char *format, ...); -extern void trace_strbuf(struct trace_key *key, const struct strbuf *data); +void trace_strbuf(struct trace_key *key, const struct strbuf *data); /* Prints elapsed time (in nanoseconds) if GIT_TRACE_PERFORMANCE is enabled. */ __attribute__((format (printf, 2, 3))) -extern void trace_performance(uint64_t nanos, const char *format, ...); +void trace_performance(uint64_t nanos, const char *format, ...); /* Prints elapsed time since 'start' if GIT_TRACE_PERFORMANCE is enabled. */ __attribute__((format (printf, 2, 3))) -extern void trace_performance_since(uint64_t start, const char *format, ...); +void trace_performance_since(uint64_t start, const char *format, ...); __attribute__((format (printf, 1, 2))) void trace_performance_leave(const char *format, ...); @@ -132,19 +132,19 @@ void trace_performance_leave(const char *format, ...); /* backend functions, use non-*fl macros instead */ __attribute__((format (printf, 4, 5))) -extern void trace_printf_key_fl(const char *file, int line, struct trace_key *key, - const char *format, ...); +void trace_printf_key_fl(const char *file, int line, struct trace_key *key, + const char *format, ...); __attribute__((format (printf, 4, 5))) -extern void trace_argv_printf_fl(const char *file, int line, const char **argv, - const char *format, ...); -extern void trace_strbuf_fl(const char *file, int line, struct trace_key *key, - const struct strbuf *data); +void trace_argv_printf_fl(const char *file, int line, const char **argv, + const char *format, ...); +void trace_strbuf_fl(const char *file, int line, struct trace_key *key, + const struct strbuf *data); __attribute__((format (printf, 4, 5))) -extern void trace_performance_fl(const char *file, int line, - uint64_t nanos, const char *fmt, ...); +void trace_performance_fl(const char *file, int line, + uint64_t nanos, const char *fmt, ...); __attribute__((format (printf, 4, 5))) -extern void trace_performance_leave_fl(const char *file, int line, - uint64_t nanos, const char *fmt, ...); +void trace_performance_leave_fl(const char *file, int line, + uint64_t nanos, const char *fmt, ...); static inline int trace_pass_fl(struct trace_key *key) { return key->fd || !key->initialized; diff --git a/trace2.c b/trace2.c index 8bbad56887..c7b4f14d29 100644 --- a/trace2.c +++ b/trace2.c @@ -10,6 +10,7 @@ #include "trace2/tr2_cmd_name.h" #include "trace2/tr2_dst.h" #include "trace2/tr2_sid.h" +#include "trace2/tr2_sysenv.h" #include "trace2/tr2_tgt.h" #include "trace2/tr2_tls.h" @@ -120,6 +121,7 @@ static void tr2main_atexit_handler(void) tr2_sid_release(); tr2_cmd_name_release(); tr2_cfg_free_patterns(); + tr2_sysenv_release(); trace2_enabled = 0; } @@ -142,6 +144,11 @@ static void tr2main_signal_handler(int signo) raise(signo); } +void trace2_initialize_clock(void) +{ + tr2tls_start_process_clock(); +} + void trace2_initialize_fl(const char *file, int line) { struct tr2_tgt *tgt_j; @@ -150,6 +157,8 @@ void trace2_initialize_fl(const char *file, int line) if (trace2_enabled) return; + tr2_sysenv_load(); + if (!tr2_tgt_want_builtins()) return; trace2_enabled = 1; @@ -177,13 +186,19 @@ void trace2_cmd_start_fl(const char *file, int line, const char **argv) { struct tr2_tgt *tgt_j; int j; + uint64_t us_now; + uint64_t us_elapsed_absolute; if (!trace2_enabled) return; + us_now = getnanotime() / 1000; + us_elapsed_absolute = tr2tls_absolute_elapsed(us_now); + for_each_wanted_builtin (j, tgt_j) if (tgt_j->pfn_start_fl) - tgt_j->pfn_start_fl(file, line, argv); + tgt_j->pfn_start_fl(file, line, us_elapsed_absolute, + argv); } int trace2_cmd_exit_fl(const char *file, int line, int code) @@ -198,6 +213,8 @@ int trace2_cmd_exit_fl(const char *file, int line, int code) if (!trace2_enabled) return code; + trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT); + tr2main_exit_code = code; us_now = getnanotime() / 1000; @@ -428,7 +445,7 @@ void trace2_thread_start_fl(const char *file, int line, const char *thread_name) us_now = getnanotime() / 1000; us_elapsed_absolute = tr2tls_absolute_elapsed(us_now); - tr2tls_create_self(thread_name); + tr2tls_create_self(thread_name, us_now); for_each_wanted_builtin (j, tgt_j) if (tgt_j->pfn_thread_start_fl) @@ -717,7 +734,7 @@ void trace2_data_json_fl(const char *file, int line, const char *category, us_elapsed_region = tr2tls_region_elasped_self(us_now); for_each_wanted_builtin (j, tgt_j) - if (tgt_j->pfn_data_fl) + if (tgt_j->pfn_data_json_fl) tgt_j->pfn_data_json_fl(file, line, us_elapsed_absolute, us_elapsed_region, category, repo, key, value); diff --git a/trace2.h b/trace2.h index b330a54a89..f189ef5984 100644 --- a/trace2.h +++ b/trace2.h @@ -19,9 +19,27 @@ struct json_writer; * [] trace2_printf* -- legacy trace[1] messages. */ +/* + * Initialize the TRACE2 clock and do nothing else, in particular + * no mallocs, no system inspection, and no environment inspection. + * + * This should be called at the very top of main() to capture the + * process start time. This is intended to reduce chicken-n-egg + * bootstrap pressure. + * + * It is safe to call this more than once. This allows capturing + * absolute startup costs on Windows which uses a little trickery + * to do setup work before common-main.c:main() is called. + * + * The main trace2_initialize_fl() may be called a little later + * after more infrastructure is established. + */ +void trace2_initialize_clock(void); + /* * Initialize TRACE2 tracing facility if any of the builtin TRACE2 - * targets are enabled in the environment. Emits a 'version' event. + * targets are enabled in the system config or the environment. + * Emits a 'version' event. * * Cleanup/Termination is handled automatically by a registered * atexit() routine. @@ -108,10 +126,11 @@ void trace2_cmd_alias_fl(const char *file, int line, const char *alias, * Emit one or more 'def_param' events for "interesting" configuration * settings. * - * The environment variable "GIT_TR2_CONFIG_PARAMS" can be set to a - * list of patterns considered important. For example: - * - * GIT_TR2_CONFIG_PARAMS="core.*,remote.*.url" + * Use the TR2_SYSENV_CFG_PARAM setting to register a comma-separated + * list of patterns configured important. For example: + * git config --system trace2.configParams 'core.*,remote.*.url' + * or: + * GIT_TR2_CONFIG_PARAMS=core.*,remote.*.url" * * Note: this routine does a read-only iteration on the config data * (using read_early_config()), so it must not be called until enough @@ -372,13 +391,19 @@ void trace2_printf(const char *fmt, ...); * Optional platform-specific code to dump information about the * current and any parent process(es). This is intended to allow * post-processors to know who spawned this git instance and anything - * else the platform may be able to tell us about the current process. + * else that the platform may be able to tell us about the current process. */ + +enum trace2_process_info_reason { + TRACE2_PROCESS_INFO_STARTUP, + TRACE2_PROCESS_INFO_EXIT, +}; + #if defined(GIT_WINDOWS_NATIVE) -void trace2_collect_process_info(void); +void trace2_collect_process_info(enum trace2_process_info_reason reason); #else -#define trace2_collect_process_info() \ - do { \ +#define trace2_collect_process_info(reason) \ + do { \ } while (0) #endif diff --git a/trace2/tr2_cfg.c b/trace2/tr2_cfg.c index b329921ac5..caa7f06948 100644 --- a/trace2/tr2_cfg.c +++ b/trace2/tr2_cfg.c @@ -1,8 +1,7 @@ #include "cache.h" #include "config.h" -#include "tr2_cfg.h" - -#define TR2_ENVVAR_CFG_PARAM "GIT_TR2_CONFIG_PARAMS" +#include "trace2/tr2_cfg.h" +#include "trace2/tr2_sysenv.h" static struct strbuf **tr2_cfg_patterns; static int tr2_cfg_count_patterns; @@ -21,7 +20,7 @@ static int tr2_cfg_load_patterns(void) return tr2_cfg_count_patterns; tr2_cfg_loaded = 1; - envvar = getenv(TR2_ENVVAR_CFG_PARAM); + envvar = tr2_sysenv_get(TR2_SYSENV_CFG_PARAM); if (!envvar || !*envvar) return tr2_cfg_count_patterns; diff --git a/trace2/tr2_dst.c b/trace2/tr2_dst.c index c3d82ca6a4..5dda0ca1cd 100644 --- a/trace2/tr2_dst.c +++ b/trace2/tr2_dst.c @@ -1,17 +1,7 @@ #include "cache.h" #include "trace2/tr2_dst.h" #include "trace2/tr2_sid.h" - -/* - * If a Trace2 target cannot be opened for writing, we should issue a - * warning to stderr, but this is very annoying if the target is a pipe - * or socket and beyond the user's control -- especially since every - * git command (and sub-command) will print the message. So we silently - * eat these warnings and just discard the trace data. - * - * Enable the following environment variable to see these warnings. - */ -#define TR2_ENVVAR_DST_DEBUG "GIT_TR2_DST_DEBUG" +#include "trace2/tr2_sysenv.h" /* * How many attempts we will make at creating an automatically-named trace file. @@ -23,7 +13,7 @@ static int tr2_dst_want_warning(void) static int tr2env_dst_debug = -1; if (tr2env_dst_debug == -1) { - const char *env_value = getenv(TR2_ENVVAR_DST_DEBUG); + const char *env_value = tr2_sysenv_get(TR2_SYSENV_DST_DEBUG); if (!env_value || !*env_value) tr2env_dst_debug = 0; else @@ -75,7 +65,8 @@ static int tr2_dst_try_auto_path(struct tr2_dst *dst, const char *tgt_prefix) if (tr2_dst_want_warning()) warning("trace2: could not open '%.*s' for '%s' tracing: %s", (int) base_path_len, path.buf, - dst->env_var_name, strerror(errno)); + tr2_sysenv_display_name(dst->sysenv_var), + strerror(errno)); tr2_dst_trace_disable(dst); strbuf_release(&path); @@ -97,7 +88,9 @@ static int tr2_dst_try_path(struct tr2_dst *dst, const char *tgt_value) if (fd == -1) { if (tr2_dst_want_warning()) warning("trace2: could not open '%s' for '%s' tracing: %s", - tgt_value, dst->env_var_name, strerror(errno)); + tgt_value, + tr2_sysenv_display_name(dst->sysenv_var), + strerror(errno)); tr2_dst_trace_disable(dst); return 0; @@ -171,7 +164,8 @@ static int tr2_dst_try_unix_domain_socket(struct tr2_dst *dst, if (!path || !*path) { if (tr2_dst_want_warning()) warning("trace2: invalid AF_UNIX value '%s' for '%s' tracing", - tgt_value, dst->env_var_name); + tgt_value, + tr2_sysenv_display_name(dst->sysenv_var)); tr2_dst_trace_disable(dst); return 0; @@ -181,7 +175,7 @@ static int tr2_dst_try_unix_domain_socket(struct tr2_dst *dst, strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { if (tr2_dst_want_warning()) warning("trace2: invalid AF_UNIX path '%s' for '%s' tracing", - path, dst->env_var_name); + path, tr2_sysenv_display_name(dst->sysenv_var)); tr2_dst_trace_disable(dst); return 0; @@ -203,7 +197,8 @@ static int tr2_dst_try_unix_domain_socket(struct tr2_dst *dst, error: if (tr2_dst_want_warning()) warning("trace2: could not connect to socket '%s' for '%s' tracing: %s", - path, dst->env_var_name, strerror(e)); + path, tr2_sysenv_display_name(dst->sysenv_var), + strerror(e)); tr2_dst_trace_disable(dst); return 0; @@ -223,7 +218,7 @@ static void tr2_dst_malformed_warning(struct tr2_dst *dst, struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "trace2: unknown value for '%s': '%s'", - dst->env_var_name, tgt_value); + tr2_sysenv_display_name(dst->sysenv_var), tgt_value); warning("%s", buf.buf); strbuf_release(&buf); @@ -239,7 +234,7 @@ int tr2_dst_get_trace_fd(struct tr2_dst *dst) dst->initialized = 1; - tgt_value = getenv(dst->env_var_name); + tgt_value = tr2_sysenv_get(dst->sysenv_var); if (!tgt_value || !strcmp(tgt_value, "") || !strcmp(tgt_value, "0") || !strcasecmp(tgt_value, "false")) { @@ -305,7 +300,8 @@ void tr2_dst_write_line(struct tr2_dst *dst, struct strbuf *buf_line) return; if (tr2_dst_want_warning()) - warning("unable to write trace to '%s': %s", dst->env_var_name, + warning("unable to write trace to '%s': %s", + tr2_sysenv_display_name(dst->sysenv_var), strerror(errno)); tr2_dst_trace_disable(dst); } diff --git a/trace2/tr2_dst.h b/trace2/tr2_dst.h index 9a64f05b02..3adf3bac13 100644 --- a/trace2/tr2_dst.h +++ b/trace2/tr2_dst.h @@ -2,9 +2,10 @@ #define TR2_DST_H struct strbuf; +#include "trace2/tr2_sysenv.h" struct tr2_dst { - const char *const env_var_name; + enum tr2_sysenv_variable sysenv_var; int fd; unsigned int initialized : 1; unsigned int need_close : 1; diff --git a/trace2/tr2_sid.c b/trace2/tr2_sid.c index 984524a43c..5047095478 100644 --- a/trace2/tr2_sid.c +++ b/trace2/tr2_sid.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "trace2/tr2_tbuf.h" #include "trace2/tr2_sid.h" #define TR2_ENVVAR_PARENT_SID "GIT_TR2_PARENT_SID" @@ -6,6 +7,53 @@ static struct strbuf tr2sid_buf = STRBUF_INIT; static int tr2sid_nr_git_parents; +/* + * Compute the final component of the SID representing the current process. + * This should uniquely identify the process and be a valid filename (to + * allow writing trace2 data to per-process files). It should also be fixed + * length for possible use as a database key. + * + * "T.Z--" + * + * where is a 9 character string: + * "H" + * "Localhost" when no hostname. + * + * where is a 9 character string containing the least signifcant + * 32 bits in the process-id. + * "P" + * (This is an abribrary choice. On most systems pid_t is a 32 bit value, + * so limit doesn't matter. On larger systems, a truncated value is fine + * for our purposes here.) + */ +static void tr2_sid_append_my_sid_component(void) +{ + const struct git_hash_algo *algo = &hash_algos[GIT_HASH_SHA1]; + struct tr2_tbuf tb_now; + git_hash_ctx ctx; + pid_t pid = getpid(); + unsigned char hash[GIT_MAX_RAWSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; + char hostname[HOST_NAME_MAX + 1]; + + tr2_tbuf_utc_datetime(&tb_now); + strbuf_addstr(&tr2sid_buf, tb_now.buf); + + strbuf_addch(&tr2sid_buf, '-'); + if (xgethostname(hostname, sizeof(hostname))) + strbuf_add(&tr2sid_buf, "Localhost", 9); + else { + algo->init_fn(&ctx); + algo->update_fn(&ctx, hostname, strlen(hostname)); + algo->final_fn(hash, &ctx); + hash_to_hex_algop_r(hex, hash, algo); + strbuf_addch(&tr2sid_buf, 'H'); + strbuf_add(&tr2sid_buf, hex, 8); + } + + strbuf_addf(&tr2sid_buf, "-P%08"PRIx32, (uint32_t)pid); +} + /* * Compute a "unique" session id (SID) for the current process. This allows * all events from this process to have a single label (much like a PID). @@ -20,7 +68,6 @@ static int tr2sid_nr_git_parents; */ static void tr2_sid_compute(void) { - uint64_t us_now; const char *parent_sid; if (tr2sid_buf.len) @@ -38,9 +85,7 @@ static void tr2_sid_compute(void) tr2sid_nr_git_parents++; } - us_now = getnanotime() / 1000; - strbuf_addf(&tr2sid_buf, "%" PRIuMAX "-%" PRIdMAX, (uintmax_t)us_now, - (intmax_t)getpid()); + tr2_sid_append_my_sid_component(); setenv(TR2_ENVVAR_PARENT_SID, tr2sid_buf.buf, 1); } diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c new file mode 100644 index 0000000000..9025b86303 --- /dev/null +++ b/trace2/tr2_sysenv.c @@ -0,0 +1,127 @@ +#include "cache.h" +#include "config.h" +#include "dir.h" +#include "tr2_sysenv.h" + +/* + * Each entry represents a trace2 setting. + * See Documentation/technical/api-trace2.txt + */ +struct tr2_sysenv_entry { + const char *env_var_name; + const char *git_config_name; + + char *value; + unsigned int getenv_called : 1; +}; + +/* + * This table must match "enum tr2_sysenv_variable" in tr2_sysenv.h. + * + * The strings in this table are constant and must match the published + * config and environment variable names as described in the documentation. + * + * We do not define entries for the GIT_TR2_PARENT_* environment + * variables because they are transient and used to pass information + * from parent to child git processes, rather than settings. + */ +/* clang-format off */ +static struct tr2_sysenv_entry tr2_sysenv_settings[] = { + [TR2_SYSENV_CFG_PARAM] = { "GIT_TR2_CONFIG_PARAMS", + "trace2.configparams" }, + + [TR2_SYSENV_DST_DEBUG] = { "GIT_TR2_DST_DEBUG", + "trace2.destinationdebug" }, + + [TR2_SYSENV_NORMAL] = { "GIT_TR2", + "trace2.normaltarget" }, + [TR2_SYSENV_NORMAL_BRIEF] = { "GIT_TR2_BRIEF", + "trace2.normalbrief" }, + + [TR2_SYSENV_EVENT] = { "GIT_TR2_EVENT", + "trace2.eventtarget" }, + [TR2_SYSENV_EVENT_BRIEF] = { "GIT_TR2_EVENT_BRIEF", + "trace2.eventbrief" }, + [TR2_SYSENV_EVENT_NESTING] = { "GIT_TR2_EVENT_NESTING", + "trace2.eventnesting" }, + + [TR2_SYSENV_PERF] = { "GIT_TR2_PERF", + "trace2.perftarget" }, + [TR2_SYSENV_PERF_BRIEF] = { "GIT_TR2_PERF_BRIEF", + "trace2.perfbrief" }, +}; +/* clang-format on */ + +static int tr2_sysenv_cb(const char *key, const char *value, void *d) +{ + int k; + + if (!starts_with(key, "trace2.")) + return 0; + + for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) { + if (!strcmp(key, tr2_sysenv_settings[k].git_config_name)) { + free(tr2_sysenv_settings[k].value); + tr2_sysenv_settings[k].value = xstrdup(value); + return 0; + } + } + + return 0; +} + +/* + * Load Trace2 settings from the system config (usually "/etc/gitconfig" + * unless we were built with a runtime-prefix). These are intended to + * define the default values for Trace2 as requested by the administrator. + * + * Then override with the Trace2 settings from the global config. + */ +void tr2_sysenv_load(void) +{ + if (ARRAY_SIZE(tr2_sysenv_settings) != TR2_SYSENV_MUST_BE_LAST) + BUG("tr2_sysenv_settings size is wrong"); + + read_very_early_config(tr2_sysenv_cb, NULL); +} + +/* + * Return the value for the requested Trace2 setting from these sources: + * the system config, the global config, and the environment. + */ +const char *tr2_sysenv_get(enum tr2_sysenv_variable var) +{ + if (var >= TR2_SYSENV_MUST_BE_LAST) + BUG("tr2_sysenv_get invalid var '%d'", var); + + if (!tr2_sysenv_settings[var].getenv_called) { + const char *v = getenv(tr2_sysenv_settings[var].env_var_name); + if (v && *v) { + free(tr2_sysenv_settings[var].value); + tr2_sysenv_settings[var].value = xstrdup(v); + } + tr2_sysenv_settings[var].getenv_called = 1; + } + + return tr2_sysenv_settings[var].value; +} + +/* + * Return a friendly name for this setting that is suitable for printing + * in an error messages. + */ +const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var) +{ + if (var >= TR2_SYSENV_MUST_BE_LAST) + BUG("tr2_sysenv_get invalid var '%d'", var); + + return tr2_sysenv_settings[var].env_var_name; +} + +void tr2_sysenv_release(void) +{ + int k; + + for (k = 0; k < ARRAY_SIZE(tr2_sysenv_settings); k++) + free(tr2_sysenv_settings[k].value); +} diff --git a/trace2/tr2_sysenv.h b/trace2/tr2_sysenv.h new file mode 100644 index 0000000000..369b20bd87 --- /dev/null +++ b/trace2/tr2_sysenv.h @@ -0,0 +1,36 @@ +#ifndef TR2_SYSENV_H +#define TR2_SYSENV_H + +/* + * The Trace2 settings that can be loaded from /etc/gitconfig + * and/or user environment variables. + * + * Note that this set does not contain any of the transient + * environment variables used to pass information from parent + * to child git processes, such "GIT_TR2_PARENT_SID". + */ +enum tr2_sysenv_variable { + TR2_SYSENV_CFG_PARAM = 0, + + TR2_SYSENV_DST_DEBUG, + + TR2_SYSENV_NORMAL, + TR2_SYSENV_NORMAL_BRIEF, + + TR2_SYSENV_EVENT, + TR2_SYSENV_EVENT_BRIEF, + TR2_SYSENV_EVENT_NESTING, + + TR2_SYSENV_PERF, + TR2_SYSENV_PERF_BRIEF, + + TR2_SYSENV_MUST_BE_LAST +}; + +void tr2_sysenv_load(void); + +const char *tr2_sysenv_get(enum tr2_sysenv_variable); +const char *tr2_sysenv_display_name(enum tr2_sysenv_variable var); +void tr2_sysenv_release(void); + +#endif /* TR2_SYSENV_H */ diff --git a/trace2/tr2_tbuf.c b/trace2/tr2_tbuf.c index 0844910423..2498482d9a 100644 --- a/trace2/tr2_tbuf.c +++ b/trace2/tr2_tbuf.c @@ -15,7 +15,7 @@ void tr2_tbuf_local_time(struct tr2_tbuf *tb) tm.tm_min, tm.tm_sec, (long)tv.tv_usec); } -void tr2_tbuf_utc_time(struct tr2_tbuf *tb) +void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb) { struct timeval tv; struct tm tm; @@ -26,7 +26,22 @@ void tr2_tbuf_utc_time(struct tr2_tbuf *tb) gmtime_r(&secs, &tm); xsnprintf(tb->buf, sizeof(tb->buf), - "%4d-%02d-%02d %02d:%02d:%02d.%06ld", tm.tm_year + 1900, + "%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec); } + +void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb) +{ + struct timeval tv; + struct tm tm; + time_t secs; + + gettimeofday(&tv, NULL); + secs = tv.tv_sec; + gmtime_r(&secs, &tm); + + xsnprintf(tb->buf, sizeof(tb->buf), "%4d%02d%02dT%02d%02d%02d.%06ldZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, (long)tv.tv_usec); +} diff --git a/trace2/tr2_tbuf.h b/trace2/tr2_tbuf.h index 9cdefa3957..fa853d8f42 100644 --- a/trace2/tr2_tbuf.h +++ b/trace2/tr2_tbuf.h @@ -16,8 +16,9 @@ struct tr2_tbuf { void tr2_tbuf_local_time(struct tr2_tbuf *tb); /* - * Fill buffer with formatted UTC time string. + * Fill buffer with formatted UTC datatime string. */ -void tr2_tbuf_utc_time(struct tr2_tbuf *tb); +void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb); +void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb); #endif /* TR2_TBUF_H */ diff --git a/trace2/tr2_tgt.h b/trace2/tr2_tgt.h index 297bb8ffbe..7b90469212 100644 --- a/trace2/tr2_tgt.h +++ b/trace2/tr2_tgt.h @@ -15,6 +15,7 @@ typedef void(tr2_tgt_term_t)(void); typedef void(tr2_tgt_evt_version_fl_t)(const char *file, int line); typedef void(tr2_tgt_evt_start_fl_t)(const char *file, int line, + uint64_t us_elapsed_absolute, const char **argv); typedef void(tr2_tgt_evt_exit_fl_t)(const char *file, int line, uint64_t us_elapsed_absolute, int code); diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c index 1cf4f62441..c2852d1bd2 100644 --- a/trace2/tr2_tgt_event.c +++ b/trace2/tr2_tgt_event.c @@ -6,10 +6,11 @@ #include "trace2/tr2_dst.h" #include "trace2/tr2_tbuf.h" #include "trace2/tr2_sid.h" +#include "trace2/tr2_sysenv.h" #include "trace2/tr2_tgt.h" #include "trace2/tr2_tls.h" -static struct tr2_dst tr2dst_event = { "GIT_TR2_EVENT", 0, 0, 0 }; +static struct tr2_dst tr2dst_event = { TR2_SYSENV_EVENT, 0, 0, 0 }; /* * The version number of the JSON data generated by the EVENT target @@ -28,37 +29,36 @@ static struct tr2_dst tr2dst_event = { "GIT_TR2_EVENT", 0, 0, 0 }; * are primarily intended for the performance target during debugging. * * Some of the outer-most messages, however, may be of interest to the - * event target. Set this environment variable to a larger integer for - * more detail in the event target. + * event target. Use the TR2_SYSENV_EVENT_NESTING setting to increase + * region details in the event target. */ -#define TR2_ENVVAR_EVENT_NESTING "GIT_TR2_EVENT_NESTING" -static int tr2env_event_nesting_wanted = 2; +static int tr2env_event_max_nesting_levels = 2; /* - * Set this environment variable to true to omit the