From: Junio C Hamano Date: Tue, 30 May 2017 02:16:40 +0000 (+0900) Subject: Merge branch 'bw/pathspec-sans-the-index' X-Git-Tag: v2.14.0-rc0~147 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/3c5a78280fa5535050fe83b51cafb9ca51e8d9e8?hp=08de9151a8a67f29a3a5a36931298237d78ca736 Merge branch 'bw/pathspec-sans-the-index' Simplify parse_pathspec() codepath and stop it from looking at the default in-core index. * bw/pathspec-sans-the-index: pathspec: convert find_pathspecs_matching_against_index to take an index pathspec: remove PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP ls-files: prevent prune_cache from overeagerly pruning submodules pathspec: remove PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE flag submodule: add die_in_unpopulated_submodule function pathspec: provide a more descriptive die message --- diff --git a/.gitattributes b/.gitattributes index 320e33c327..8ce9c6b888 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,9 @@ * whitespace=!indent,trail,space *.[ch] whitespace=indent,trail,space diff=cpp -*.sh whitespace=indent,trail,space +*.sh whitespace=indent,trail,space eol=lf +*.perl eol=lf +*.pm eol=lf +/Documentation/git-*.txt eol=lf +/command-list.txt eol=lf +/GIT-VERSION-GEN eol=lf +/mergetools/* eol=lf diff --git a/.travis.yml b/.travis.yml index 1b32c98f2c..278943d14a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,11 @@ env: matrix: include: + - env: GETTEXT_POISON=YesPlease + os: linux + compiler: + addons: + before_install: - env: Windows os: linux compiler: @@ -52,6 +57,7 @@ matrix: after_failure: - env: Linux32 os: linux + compiler: services: - docker before_install: @@ -86,14 +92,14 @@ matrix: after_failure: - env: Documentation os: linux - compiler: clang + compiler: addons: apt: packages: - asciidoc - xmlto before_install: - before_script: + before_script: gem install asciidoctor script: ci/test-documentation.sh after_failure: @@ -134,12 +140,14 @@ before_install: p4 -V | grep Rev.; echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)"; git-lfs version; - mkdir -p $HOME/travis-cache; - ln -s $HOME/travis-cache/.prove t/.prove; before_script: make --jobs=2 -script: make --quiet test +script: + - > + mkdir -p $HOME/travis-cache; + ln -s $HOME/travis-cache/.prove t/.prove; + make --quiet test; after_failure: - > diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index a4191aa388..2248cf7324 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -24,7 +24,7 @@ code. For Git in general, a few rough rules are: "Once it _is_ in the tree, it's not really worth the patch noise to go and fix it up." - Cf. http://article.gmane.org/gmane.linux.kernel/943020 + Cf. http://lkml.iu.edu/hypermail/linux/kernel/1001.3/01069.html Make your code readable and sensible, and don't try to be clever. diff --git a/Documentation/RelNotes/2.14.0.txt b/Documentation/RelNotes/2.14.0.txt new file mode 100644 index 0000000000..ee6c6075ad --- /dev/null +++ b/Documentation/RelNotes/2.14.0.txt @@ -0,0 +1,219 @@ +Git 2.14 Release Notes +====================== + +Backward compatibility notes. + + * Use of an empty string as a pathspec element that is used for + 'everything matches' is still warned and Git asks users to use a + more explicit '.' for that instead. The hope is that existing + users will not mind this change, and eventually the warning can be + turned into a hard error, upgrading the deprecation into removal of + this (mis)feature. That is not scheduled to happen in the upcoming + release (yet). + + * Git now avoids blindly falling back to ".git" when the setup + sequence said we are _not_ in Git repository. A corner case that + happens to work right now may be broken by a call to die("BUG"). + We've tried hard to locate such cases and fixed them, but there + might still be cases that need to be addressed--bug reports are + greatly appreciated. + + +Updates since v2.13 +------------------- + +UI, Workflows & Features + + * The colors in which "git status --short --branch" showed the names + of the current branch and its remote-tracking branch are now + configurable. + + * "git clone" learned the "--no-tags" option not to fetch all tags + initially, and also set up the tagopt not to follow any tags in + subsequent fetches. + + * "git archive --format=zip" learned to use zip64 extension when + necessary to go beyond the 4GB limit. + (merge 867e40ff3a rs/large-zip later to maint). + + * "git reset" learned "--recurse-submodules" option. + + * "git diff --submodule=diff" now recurses into nested submodules. + (merge 5a5221427c jk/diff-submodule-diff-inline later to maint). + + * "git repack" learned to accept the --threads= option and pass it + to pack-objects. + + +Performance, Internal Implementation, Development Support etc. + + * The default packed-git limit value has been raised on larger + platforms to save "git fetch" from a (recoverable) failure while + "gc" is running in parallel. + + * Code to update the cache-tree has been tightened so that we won't + accidentally write out any 0{40} entry in the tree object. + (merge a96d3cc3f6 jk/no-null-sha1-in-cache-tree later to maint). + + * Attempt to allow us notice "fishy" situation where we fail to + remove the temporary directory used during the test. + + * Travis CI gained a task to format the documentation with both + AsciiDoc and AsciiDoctor. + (merge 505ad91304 ls/travis-doc-asciidoctor later to maint). + + * Some platforms have ulong that is smaller than time_t, and our + historical use of ulong for timestamp would mean they cannot + represent some timestamp that the platform allows. Invent a + separate and dedicated timestamp_t (so that we can distingiuish + timestamps and a vanilla ulongs, which along is already a good + move), and then declare uintmax_t is the type to be used as the + timestamp_t. + + * We can trigger Windows auto-build tester (credits: Dscho & + Microsoft) from our existing Travis CI tester now. + + * Conversion from uchar[20] to struct object_id continues. + + + +Also contains various documentation updates and code clean-ups. + + +Fixes since v2.13 +----------------- + +Unless otherwise noted, all the fixes since v2.13 in the maintenance +track are contained in this release (see the maintenance releases' +notes for details). + + * "git gc" did not interact well with "git worktree"-managed + per-worktree refs. + + * "git cherry-pick" and other uses of the sequencer machinery + mishandled a trailer block whose last line is an incomplete line. + This has been fixed so that an additional sign-off etc. are added + after completing the existing incomplete line. + (merge 44dc738a39 jt/use-trailer-api-in-commands later to maint). + + * The codepath in "git am" that is used when running "git rebase" + leaked memory held for the log message of the commits being rebased. + (merge 721f5f1e35 jk/am-leakfix later to maint). + + * "git clone --config var=val" is a way to populate the + per-repository configuration file of the new repository, but it did + not work well when val is an empty string. This has been fixed. + (merge db4eca1fea jn/clone-add-empty-config-from-command-line later to maint). + + * Setting "log.decorate=false" in the configuration file did not take + effect in v2.13, which has been corrected. + (merge c74271aae7 ah/log-decorate-default-to-auto later to maint). + + * A few codepaths in "checkout" and "am" working on an unborn branch + tried to access an uninitialized piece of memory. + (merge 57e0ef0e0e rs/checkout-am-fix-unborn later to maint). + + * The Web interface to gmane news archive is long gone, even though + the articles are still accessible via NTTP. Replace the links with + ones to public-inbox.org. Because their message identification is + based on the actual message-id, it is likely that it will be easier + to migrate away from it if/when necessary. + (merge 5840eb9d14 ab/doc-replace-gmane-links later to maint). + + * The receive-pack program now makes sure that the push certificate + records the same set of push options used for pushing. + (merge cbaf82cc6b jt/push-options-doc later to maint). + + * Tests have been updated to pass under GETTEXT_POISON (a mechanism + to ensure that output strings that should not be translated are + not translated by mistake), and TravisCI is told to run them. + (merge b8e188f6f5 ab/fix-poison-tests later to maint). + + * "git checkout --recurse-submodules" did not quite work with a + submodule that itself has submodules. + (merge 218c883783 sb/checkout-recurse-submodules later to maint). + + * Plug some leaks and updates internal API used to implement the + split index feature to make it easier to avoid such a leak in the + future. + (merge de950c5773 nd/split-index-unshare later to maint). + + * "pack-objects" can stream a slice of an existing packfile out when + the pack bitmap can tell that the reachable objects are all needed + in the output, without inspecting individual objects. This + strategy however would not work well when "--local" and other + options are in use, and need to be disabled. + (merge da5a1f8100 jk/disable-pack-reuse-when-broken later to maint). + + * Fix memory leaks pointed out by Coverity (and people). + (merge 443a12f37b js/plug-leaks later to maint). + + * "git read-tree -m" (no tree-ish) gave a nonsense suggestion "use + --empty if you want to clear the index". With "-m", such a request + will still fail anyway, as you'd need to name at least one tree-ish + to be merged. + (merge b9b10d3681 jc/read-tree-empty-with-m later to maint). + + * Make sure our tests would pass when the sources are checked out + with "platform native" line ending convention by default on + Windows. Some "text" files out tests use and the test scripts + themselves that are meant to be run with /bin/sh, ought to be + checked out with eol=LF even on Windows. + (merge 2779f66505 js/eol-on-ourselves later to maint). + + * Introduce the BUG() macro to improve die("BUG: ..."). + (merge 3d7dd2d3b6 jk/bug-to-abort later to maint). + + * Clarify documentation for include.path and includeIf..path + configuration variables. + (merge ce933ebd5a jk/doc-config-include later to maint). + + * Git sometimes gives an advice in a rhetorical question that does + not require an answer, which can confuse new users and non native + speakers. Attempt to rephrase them. + (merge 6963893943 ja/do-not-ask-needless-questions later to maint). + + * A few http:// links that are redirected to https:// in the + documentation have been updated to https:// links. + (merge 5e68729fd9 jk/update-links-in-docs later to maint). + + * "git for-each-ref --format=..." with %(HEAD) in the format used to + resolve the HEAD symref as many times as it had processed refs, + which was wasteful, and "git branch" shared the same problem. + (merge 613a0e52ea kn/ref-filter-branch-list later to maint). + + * Regression fix to topic recently merged to 'master'. + (merge d096d7f1ef pw/rebase-i-regression-fix later to maint). + + * The shell completion script (in contrib/) learned "git stash" has + a new "push" subcommand. + (merge 3851e4483f tg/stash-push-fixup later to maint). + + * "git interpret-trailers", when used as GIT_EDITOR for "git commit + -v", looked for and appended to a trailer block at the very end, + i.e. at the end of the "diff" output. The command has been + corrected to pay attention to the cut-mark line "commit -v" adds to + the buffer---the real trailer block should appear just before it. + (merge d76650b8d1 bm/interpret-trailers-cut-line-is-eom later to maint). + + * A test allowed both "git push" and "git receive-pack" on the other + end write their traces into the same file. This is OK on platforms + that allows atomically appending to a file opened with O_APPEND, + but on other platforms led to a mangled output, causing + intermittent test failures. This has been fixed by disabling + traces from "receive-pack" in the test. + (merge 71406ed4d6 jk/alternate-ref-optim later to maint). + + * Tag objects, which are not reachable from any ref, that point at + missing objects were mishandled by "git gc" and friends (they + should silently be ignored instead) + (merge a3ba6bf10a jk/ignore-broken-tags-when-ignoring-missing-links later to maint). + + * Other minor doc, test and build updates and code cleanups. + (merge 515360f9e9 jn/credential-doc-on-clear later to maint). + (merge 0e6d899fee ab/aix-needs-compat-regex later to maint). + (merge e294e8959f jc/apply-fix-mismerge later to maint). + (merge 7f1b225153 bw/submodule-with-bs-path later to maint). + (merge c8f7c8b704 tb/dedup-crlf-tests later to maint). + (merge 449456ad47 sg/core-filemode-doc-typofix later to maint). + (merge ba4dce784e km/log-showsignature-doc later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 475e874d51..0ea247bdca 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -79,14 +79,20 @@ escape sequences) are invalid. Includes ~~~~~~~~ +The `include` and `includeIf` sections allow you to include config +directives from another source. These sections behave identically to +each other with the exception that `includeIf` sections may be ignored +if their condition does not evaluate to true; see "Conditional includes" +below. + You can include a config file from another by setting the special -`include.path` variable to the name of the file to be included. The -variable takes a pathname as its value, and is subject to tilde -expansion. `include.path` can be given multiple times. +`include.path` (or `includeIf.*.path`) variable to the name of the file +to be included. The variable takes a pathname as its value, and is +subject to tilde expansion. These variables can be given multiple times. -The included file is expanded immediately, as if its contents had been -found at the location of the include directive. If the value of the -`include.path` variable is a relative path, the path is considered to +The contents of the included file are inserted immediately, as if they +had been found at the location of the include directive. If the value of the +variable is a relative path, the path is considered to be relative to the configuration file in which the include directive was found. See below for examples. @@ -95,8 +101,7 @@ Conditional includes You can include a config file from another conditionally by setting a `includeIf..path` variable to the name of the file to be -included. The variable's value is treated the same way as -`include.path`. `includeIf..path` can be given multiple times. +included. The condition starts with a keyword followed by a colon and some data whose format and meaning depends on the keyword. Supported keywords @@ -167,8 +172,8 @@ Example [include] path = /path/to/foo.inc ; include by absolute path - path = foo ; expand "foo" relative to the current file - path = ~/foo ; expand "foo" in your `$HOME` directory + path = foo.inc ; find "foo.inc" relative to the current file + path = ~/foo.inc ; find "foo.inc" in your `$HOME` directory ; include if $GIT_DIR is /path/to/foo/.git [includeIf "gitdir:/path/to/foo/.git"] @@ -182,6 +187,12 @@ Example [includeIf "gitdir:~/to/group/"] path = /path/to/foo.inc + ; relative paths are always relative to the including + ; file (if the condition is true); their location is not + ; affected by the condition + [includeIf "gitdir:/path/to/group/"] + path = foo.inc + Values ~~~~~~ @@ -334,7 +345,7 @@ core.fileMode:: is to be honored. + Some filesystems lose the executable bit when a file that is -marked as executable is checked out, or checks out an +marked as executable is checked out, or checks out a non-executable file with executable bit on. linkgit:git-clone[1] or linkgit:git-init[1] probe the filesystem to see if it handles the executable bit correctly @@ -1137,7 +1148,10 @@ color.status.:: `untracked` (files which are not tracked by Git), `branch` (the current branch), `nobranch` (the color the 'no branch' warning is shown in, defaulting - to red), or + to red), + `localBranch` or `remoteBranch` (the local and remote branch names, + respectively, when branch and tracking information is displayed in the + status short-format), or `unmerged` (files which have unmerged changes). color.ui:: @@ -2140,6 +2154,10 @@ log.showRoot:: Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which normally hide the root commit will now show it. True by default. +log.showSignature:: + If true, makes linkgit:git-log[1], linkgit:git-show[1], and + linkgit:git-whatchanged[1] assume `--show-signature`. + log.mailmap:: If true, makes linkgit:git-log[1], linkgit:git-show[1], and linkgit:git-whatchanged[1] assume `--use-mailmap`. @@ -2620,9 +2638,8 @@ receive.advertiseAtomic:: capability, set this variable to false. receive.advertisePushOptions:: - By default, git-receive-pack will advertise the push options - capability to its clients. If you don't want to advertise this - capability, set this variable to false. + When set to true, git-receive-pack will advertise the push options + capability to its clients. False by default. receive.autogc:: By default, git-receive-pack will run "git-gc --auto" after diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt index 8ac75fcc25..78479b003e 100644 --- a/Documentation/git-bisect-lk2009.txt +++ b/Documentation/git-bisect-lk2009.txt @@ -1350,9 +1350,9 @@ References - [[[1]]] https://www.nist.gov/sites/default/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'. Nist Planning Report 02-3], see Executive Summary and Chapter 8. - [[[2]]] http://www.oracle.com/technetwork/java/codeconvtoc-136057.html['Code Conventions for the Java Programming Language'. Sun Microsystems.] - [[[3]]] https://en.wikipedia.org/wiki/Software_maintenance['Software maintenance'. Wikipedia.] -- [[[4]]] http://article.gmane.org/gmane.comp.version-control.git/45195/[Junio C Hamano. 'Automated bisect success story'. Gmane.] +- [[[4]]] https://public-inbox.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/[Junio C Hamano. 'Automated bisect success story'.] - [[[5]]] https://lwn.net/Articles/317154/[Christian Couder. 'Fully automated bisecting with "git bisect run"'. LWN.net.] - [[[6]]] https://lwn.net/Articles/277872/[Jonathan Corbet. 'Bisection divides users and developers'. LWN.net.] -- [[[7]]] http://article.gmane.org/gmane.linux.scsi/36652/[Ingo Molnar. 'Re: BUG 2.6.23-rc3 can't see sd partitions on Alpha'. Gmane.] +- [[[7]]] http://marc.info/?l=linux-kernel&m=119702753411680&w=2[Ingo Molnar. 'Re: BUG 2.6.23-rc3 can't see sd partitions on Alpha'. Linux-kernel mailing list.] - [[[8]]] https://www.kernel.org/pub/software/scm/git/docs/git-bisect.html[Junio C Hamano and the git-list. 'git-bisect(1) Manual Page'. Linux Kernel Archives.] - [[[9]]] https://github.com/Ealdwulf/bbchop[Ealdwulf. 'bbchop'. GitHub.] diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 30052cce49..83c8e9b394 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -13,7 +13,7 @@ SYNOPSIS [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o ] [-b ] [-u ] [--reference ] [--dissociate] [--separate-git-dir ] - [--depth ] [--[no-]single-branch] + [--depth ] [--[no-]single-branch] [--no-tags] [--recurse-submodules] [--[no-]shallow-submodules] [--jobs ] [--] [] @@ -215,6 +215,18 @@ objects from the source repository into a pack in the cloned repository. branch when `--single-branch` clone was made, no remote-tracking branch is created. +--no-tags:: + Don't clone any tags, and set + `remote..tagOpt=--no-tags` in the config, ensuring + that future `git pull` and `git fetch` operations won't follow + any tags. Subsequent explicit tag fetches will still work, + (see linkgit:git-fetch[1]). ++ +Can be used in conjunction with `--single-branch` to clone and +maintain a branch with no references other than a single cloned +branch. This is useful e.g. to maintain minimal clones of the default +branch of some repository for search indexing. + --recurse-submodules[=] [--depth=] +'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [--window=] [--depth=] [--threads=] DESCRIPTION ----------- @@ -92,6 +92,9 @@ other objects in that pack they already have locally. to be applied that many times to get to the necessary object. The default value for --window is 10 and --depth is 50. +--threads=:: + This option is passed through to `git pack-objects`. + --window-memory=:: This option provides an additional limit on top of `--window`; the window size will dynamically scale down so as to not take diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt index f3a75d1ce1..f970196bc1 100644 --- a/Documentation/gitcredentials.txt +++ b/Documentation/gitcredentials.txt @@ -101,16 +101,6 @@ $ git help credential-foo $ git config --global credential.helper foo ------------------------------------------- -If there are multiple instances of the `credential.helper` configuration -variable, each helper will be tried in turn, and may provide a username, -password, or nothing. Once Git has acquired both a username and a -password, no more helpers will be tried. - -If `credential.helper` is configured to the empty string, this resets -the helper list to empty (so you may override a helper set by a -lower-priority config file by configuring the empty-string helper, -followed by whatever set of helpers you would like). - CREDENTIAL CONTEXTS ------------------- @@ -162,6 +152,16 @@ helper:: shell (so, for example, setting this to `foo --option=bar` will execute `git credential-foo --option=bar` via the shell. See the manual of specific helpers for examples of their use. ++ +If there are multiple instances of the `credential.helper` configuration +variable, each helper will be tried in turn, and may provide a username, +password, or nothing. Once Git has acquired both a username and a +password, no more helpers will be tried. ++ +If `credential.helper` is configured to the empty string, this resets +the helper list to empty (so you may override a helper set by a +lower-priority config file by configuring the empty-string helper, +followed by whatever set of helpers you would like). username:: diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt index 96156e5e1f..88450589af 100644 --- a/Documentation/gitweb.txt +++ b/Documentation/gitweb.txt @@ -84,7 +84,7 @@ separator (rules for Perl's "`split(" ", $line)`"). * Fields use modified URI encoding, defined in RFC 3986, section 2.1 (Percent-Encoding), or rather "Query string encoding" (see -http://en.wikipedia.org/wiki/Query_string#URL_encoding[]), the difference +https://en.wikipedia.org/wiki/Query_string#URL_encoding[]), the difference being that SP (" ") can be encoded as "{plus}" (and therefore "{plus}" has to be also percent-encoded). + diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 36768b479e..829b558110 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -183,13 +183,13 @@ There are some macros to easily define options: scale the provided value by 1024, 1024^2 or 1024^3 respectively. The scaled value is put into `unsigned_long_var`. -`OPT_DATE(short, long, &int_var, description)`:: +`OPT_DATE(short, long, ×tamp_t_var, description)`:: Introduce an option with date argument, see `approxidate()`. - The timestamp is put into `int_var`. + The timestamp is put into `timestamp_t_var`. -`OPT_EXPIRY_DATE(short, long, &int_var, description)`:: +`OPT_EXPIRY_DATE(short, long, ×tamp_t_var, description)`:: Introduce an option with expiry date argument, see `parse_expiry_date()`. - The timestamp is put into `int_var`. + The timestamp is put into `timestamp_t_var`. `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`:: Introduce an option with argument. diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt index 5b0ba3ef20..a34917153f 100644 --- a/Documentation/technical/pack-protocol.txt +++ b/Documentation/technical/pack-protocol.txt @@ -473,13 +473,10 @@ that it wants to update, it sends a line listing the obj-id currently on the server, the obj-id the client would like to update it to and the name of the reference. -This list is followed by a flush-pkt. Then the push options are transmitted -one per packet followed by another flush-pkt. After that the packfile that -should contain all the objects that the server will need to complete the new -references will be sent. +This list is followed by a flush-pkt. ---- - update-request = *shallow ( command-list | push-cert ) [packfile] + update-requests = *shallow ( command-list | push-cert ) shallow = PKT-LINE("shallow" SP obj-id) @@ -500,12 +497,35 @@ references will be sent. PKT-LINE("pusher" SP ident LF) PKT-LINE("pushee" SP url LF) PKT-LINE("nonce" SP nonce LF) + *PKT-LINE("push-option" SP push-option LF) PKT-LINE(LF) *PKT-LINE(command LF) *PKT-LINE(gpg-signature-lines LF) PKT-LINE("push-cert-end" LF) - packfile = "PACK" 28*(OCTET) + push-option = 1*( VCHAR | SP ) +---- + +If the server has advertised the 'push-options' capability and the client has +specified 'push-options' as part of the capability list above, the client then +sends its push options followed by a flush-pkt. + +---- + push-options = *PKT-LINE(push-option) flush-pkt +---- + +For backwards compatibility with older Git servers, if the client sends a push +cert and push options, it MUST send its push options both embedded within the +push cert and after the push cert. (Note that the push options within the cert +are prefixed, but the push options after the cert are not.) Both these lists +MUST be the same, modulo the prefix. + +After that the packfile that +should contain all the objects that the server will need to complete the new +references will be sent. + +---- + packfile = "PACK" 28*(OCTET) ---- If the receiving end does not support delete-refs, the sending end MUST diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index afcf9e9abf..4f94fc7574 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.13.0 +DEF_VER=v2.13.GIT LF=' ' diff --git a/RelNotes b/RelNotes index 125bf78f3b..983f6689bd 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.13.0.txt \ No newline at end of file +Documentation/RelNotes/2.14.0.txt \ No newline at end of file diff --git a/apply.c b/apply.c index e6dbab26ad..c49cef0637 100644 --- a/apply.c +++ b/apply.c @@ -4091,181 +4091,181 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list) res = write_locked_index(&result, &lock, COMMIT_LOCK); discard_index(&result); - if (res) - return error(_("could not write temporary index to %s"), - state->fake_ancestor); + if (res) + return error(_("could not write temporary index to %s"), + state->fake_ancestor); - return 0; - } + return 0; +} - static void stat_patch_list(struct apply_state *state, struct patch *patch) - { - int files, adds, dels; +static void stat_patch_list(struct apply_state *state, struct patch *patch) +{ + int files, adds, dels; - for (files = adds = dels = 0 ; patch ; patch = patch->next) { - files++; - adds += patch->lines_added; - dels += patch->lines_deleted; - show_stats(state, patch); - } + for (files = adds = dels = 0 ; patch ; patch = patch->next) { + files++; + adds += patch->lines_added; + dels += patch->lines_deleted; + show_stats(state, patch); + } - print_stat_summary(stdout, files, adds, dels); - } + print_stat_summary(stdout, files, adds, dels); +} - static void numstat_patch_list(struct apply_state *state, - struct patch *patch) - { - for ( ; patch; patch = patch->next) { - const char *name; - name = patch->new_name ? patch->new_name : patch->old_name; - if (patch->is_binary) - printf("-\t-\t"); - else - printf("%d\t%d\t", patch->lines_added, patch->lines_deleted); - write_name_quoted(name, stdout, state->line_termination); - } - } - - static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name) - { - if (mode) - printf(" %s mode %06o %s\n", newdelete, mode, name); - else - printf(" %s %s\n", newdelete, name); - } - - static void show_mode_change(struct patch *p, int show_name) - { - if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) { - if (show_name) - printf(" mode change %06o => %06o %s\n", - p->old_mode, p->new_mode, p->new_name); - else - printf(" mode change %06o => %06o\n", - p->old_mode, p->new_mode); - } - } - - static void show_rename_copy(struct patch *p) - { - const char *renamecopy = p->is_rename ? "rename" : "copy"; - const char *old, *new; - - /* Find common prefix */ - old = p->old_name; - new = p->new_name; - while (1) { - const char *slash_old, *slash_new; - slash_old = strchr(old, '/'); - slash_new = strchr(new, '/'); - if (!slash_old || - !slash_new || - slash_old - old != slash_new - new || - memcmp(old, new, slash_new - new)) - break; - old = slash_old + 1; - new = slash_new + 1; - } - /* p->old_name thru old is the common prefix, and old and new - * through the end of names are renames - */ - if (old != p->old_name) - printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy, - (int)(old - p->old_name), p->old_name, - old, new, p->score); - else - printf(" %s %s => %s (%d%%)\n", renamecopy, - p->old_name, p->new_name, p->score); - show_mode_change(p, 0); - } - - static void summary_patch_list(struct patch *patch) - { - struct patch *p; - - for (p = patch; p; p = p->next) { - if (p->is_new) - show_file_mode_name("create", p->new_mode, p->new_name); - else if (p->is_delete) - show_file_mode_name("delete", p->old_mode, p->old_name); - else { - if (p->is_rename || p->is_copy) - show_rename_copy(p); - else { - if (p->score) { - printf(" rewrite %s (%d%%)\n", - p->new_name, p->score); - show_mode_change(p, 0); - } - else - show_mode_change(p, 1); - } - } - } - } - - static void patch_stats(struct apply_state *state, struct patch *patch) - { - int lines = patch->lines_added + patch->lines_deleted; - - if (lines > state->max_change) - state->max_change = lines; - if (patch->old_name) { - int len = quote_c_style(patch->old_name, NULL, NULL, 0); - if (!len) - len = strlen(patch->old_name); - if (len > state->max_len) - state->max_len = len; - } - if (patch->new_name) { - int len = quote_c_style(patch->new_name, NULL, NULL, 0); - if (!len) - len = strlen(patch->new_name); - if (len > state->max_len) - state->max_len = len; - } - } - - static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty) - { - if (state->update_index) { - if (remove_file_from_cache(patch->old_name) < 0) - return error(_("unable to remove %s from index"), patch->old_name); - } - if (!state->cached) { - if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) { - remove_path(patch->old_name); - } - } - return 0; - } - - static int add_index_file(struct apply_state *state, - const char *path, - unsigned mode, - void *buf, - unsigned long size) - { - struct stat st; - struct cache_entry *ce; - int namelen = strlen(path); - unsigned ce_size = cache_entry_size(namelen); - - if (!state->update_index) - return 0; - - ce = xcalloc(1, ce_size); - memcpy(ce->name, path, namelen); - ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = create_ce_flags(0); - ce->ce_namelen = namelen; - if (S_ISGITLINK(mode)) { - const char *s; - - if (!skip_prefix(buf, "Subproject commit ", &s) || - get_oid_hex(s, &ce->oid)) { +static void numstat_patch_list(struct apply_state *state, + struct patch *patch) +{ + for ( ; patch; patch = patch->next) { + const char *name; + name = patch->new_name ? patch->new_name : patch->old_name; + if (patch->is_binary) + printf("-\t-\t"); + else + printf("%d\t%d\t", patch->lines_added, patch->lines_deleted); + write_name_quoted(name, stdout, state->line_termination); + } +} + +static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name) +{ + if (mode) + printf(" %s mode %06o %s\n", newdelete, mode, name); + else + printf(" %s %s\n", newdelete, name); +} + +static void show_mode_change(struct patch *p, int show_name) +{ + if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) { + if (show_name) + printf(" mode change %06o => %06o %s\n", + p->old_mode, p->new_mode, p->new_name); + else + printf(" mode change %06o => %06o\n", + p->old_mode, p->new_mode); + } +} + +static void show_rename_copy(struct patch *p) +{ + const char *renamecopy = p->is_rename ? "rename" : "copy"; + const char *old, *new; + + /* Find common prefix */ + old = p->old_name; + new = p->new_name; + while (1) { + const char *slash_old, *slash_new; + slash_old = strchr(old, '/'); + slash_new = strchr(new, '/'); + if (!slash_old || + !slash_new || + slash_old - old != slash_new - new || + memcmp(old, new, slash_new - new)) + break; + old = slash_old + 1; + new = slash_new + 1; + } + /* p->old_name thru old is the common prefix, and old and new + * through the end of names are renames + */ + if (old != p->old_name) + printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy, + (int)(old - p->old_name), p->old_name, + old, new, p->score); + else + printf(" %s %s => %s (%d%%)\n", renamecopy, + p->old_name, p->new_name, p->score); + show_mode_change(p, 0); +} + +static void summary_patch_list(struct patch *patch) +{ + struct patch *p; + + for (p = patch; p; p = p->next) { + if (p->is_new) + show_file_mode_name("create", p->new_mode, p->new_name); + else if (p->is_delete) + show_file_mode_name("delete", p->old_mode, p->old_name); + else { + if (p->is_rename || p->is_copy) + show_rename_copy(p); + else { + if (p->score) { + printf(" rewrite %s (%d%%)\n", + p->new_name, p->score); + show_mode_change(p, 0); + } + else + show_mode_change(p, 1); + } + } + } +} + +static void patch_stats(struct apply_state *state, struct patch *patch) +{ + int lines = patch->lines_added + patch->lines_deleted; + + if (lines > state->max_change) + state->max_change = lines; + if (patch->old_name) { + int len = quote_c_style(patch->old_name, NULL, NULL, 0); + if (!len) + len = strlen(patch->old_name); + if (len > state->max_len) + state->max_len = len; + } + if (patch->new_name) { + int len = quote_c_style(patch->new_name, NULL, NULL, 0); + if (!len) + len = strlen(patch->new_name); + if (len > state->max_len) + state->max_len = len; + } +} + +static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty) +{ + if (state->update_index) { + if (remove_file_from_cache(patch->old_name) < 0) + return error(_("unable to remove %s from index"), patch->old_name); + } + if (!state->cached) { + if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) { + remove_path(patch->old_name); + } + } + return 0; +} + +static int add_index_file(struct apply_state *state, + const char *path, + unsigned mode, + void *buf, + unsigned long size) +{ + struct stat st; + struct cache_entry *ce; + int namelen = strlen(path); + unsigned ce_size = cache_entry_size(namelen); + + if (!state->update_index) + return 0; + + ce = xcalloc(1, ce_size); + memcpy(ce->name, path, namelen); + ce->ce_mode = create_ce_mode(mode); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = namelen; + if (S_ISGITLINK(mode)) { + const char *s; + + if (!skip_prefix(buf, "Subproject commit ", &s) || + get_oid_hex(s, &ce->oid)) { free(ce); - return error(_("corrupt patch for submodule %s"), path); + return error(_("corrupt patch for submodule %s"), path); } } else { if (!state->cached) { diff --git a/archive-tar.c b/archive-tar.c index 380e3aedd2..073e60ebd3 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -27,10 +27,13 @@ static int write_tar_filter_archive(const struct archiver *ar, */ #if ULONG_MAX == 0xFFFFFFFF #define USTAR_MAX_SIZE ULONG_MAX -#define USTAR_MAX_MTIME ULONG_MAX #else #define USTAR_MAX_SIZE 077777777777UL -#define USTAR_MAX_MTIME 077777777777UL +#endif +#if TIME_MAX == 0xFFFFFFFF +#define USTAR_MAX_MTIME TIME_MAX +#else +#define USTAR_MAX_MTIME 077777777777ULL #endif /* writes out the whole block, but only if it is full */ diff --git a/archive-zip.c b/archive-zip.c index b429a8d974..27563e9e26 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -11,16 +11,14 @@ static int zip_date; static int zip_time; -static unsigned char *zip_dir; -static unsigned int zip_dir_size; +/* We only care about the "buf" part here. */ +static struct strbuf zip_dir; -static unsigned int zip_offset; -static unsigned int zip_dir_offset; +static uintmax_t zip_offset; static uint64_t zip_dir_entries; static unsigned int max_creator_version; -#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024) #define ZIP_STREAM (1 << 3) #define ZIP_UTF8 (1 << 11) @@ -47,24 +45,11 @@ struct zip_data_desc { unsigned char _end[1]; }; -struct zip_dir_header { +struct zip64_data_desc { unsigned char magic[4]; - unsigned char creator_version[2]; - unsigned char version[2]; - unsigned char flags[2]; - unsigned char compression_method[2]; - unsigned char mtime[2]; - unsigned char mdate[2]; unsigned char crc32[4]; - unsigned char compressed_size[4]; - unsigned char size[4]; - unsigned char filename_length[2]; - unsigned char extra_length[2]; - unsigned char comment_length[2]; - unsigned char disk[2]; - unsigned char attr1[2]; - unsigned char attr2[4]; - unsigned char offset[4]; + unsigned char compressed_size[8]; + unsigned char size[8]; unsigned char _end[1]; }; @@ -88,6 +73,14 @@ struct zip_extra_mtime { unsigned char _end[1]; }; +struct zip64_extra { + unsigned char magic[2]; + unsigned char extra_size[2]; + unsigned char size[8]; + unsigned char compressed_size[8]; + unsigned char _end[1]; +}; + struct zip64_dir_trailer { unsigned char magic[4]; unsigned char record_size[8]; @@ -117,11 +110,15 @@ struct zip64_dir_trailer_locator { */ #define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) #define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end) +#define ZIP64_DATA_DESC_SIZE offsetof(struct zip64_data_desc, _end) #define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) #define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) #define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end) #define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \ (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags)) +#define ZIP64_EXTRA_SIZE offsetof(struct zip64_extra, _end) +#define ZIP64_EXTRA_PAYLOAD_SIZE \ + (ZIP64_EXTRA_SIZE - offsetof(struct zip64_extra, size)) #define ZIP64_DIR_TRAILER_SIZE offsetof(struct zip64_dir_trailer, _end) #define ZIP64_DIR_TRAILER_RECORD_SIZE \ (ZIP64_DIR_TRAILER_SIZE - \ @@ -168,6 +165,26 @@ static void copy_le16_clamp(unsigned char *dest, uint64_t n, int *clamped) copy_le16(dest, clamp_max(n, 0xffff, clamped)); } +static void copy_le32_clamp(unsigned char *dest, uint64_t n, int *clamped) +{ + copy_le32(dest, clamp_max(n, 0xffffffff, clamped)); +} + +static int strbuf_add_le(struct strbuf *sb, size_t size, uintmax_t n) +{ + while (size-- > 0) { + strbuf_addch(sb, n & 0xff); + n >>= 8; + } + return -!!n; +} + +static uint32_t clamp32(uintmax_t n) +{ + const uintmax_t max = 0xffffffff; + return (n < max) ? n : max; +} + static void *zlib_deflate_raw(void *data, unsigned long size, int compression_level, unsigned long *compressed_size) @@ -205,23 +222,23 @@ static void write_zip_data_desc(unsigned long size, unsigned long compressed_size, unsigned long crc) { - struct zip_data_desc trailer; - - copy_le32(trailer.magic, 0x08074b50); - copy_le32(trailer.crc32, crc); - copy_le32(trailer.compressed_size, compressed_size); - copy_le32(trailer.size, size); - write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE); -} - -static void set_zip_dir_data_desc(struct zip_dir_header *header, - unsigned long size, - unsigned long compressed_size, - unsigned long crc) -{ - copy_le32(header->crc32, crc); - copy_le32(header->compressed_size, compressed_size); - copy_le32(header->size, size); + if (size >= 0xffffffff || compressed_size >= 0xffffffff) { + struct zip64_data_desc trailer; + copy_le32(trailer.magic, 0x08074b50); + copy_le32(trailer.crc32, crc); + copy_le64(trailer.compressed_size, compressed_size); + copy_le64(trailer.size, size); + write_or_die(1, &trailer, ZIP64_DATA_DESC_SIZE); + zip_offset += ZIP64_DATA_DESC_SIZE; + } else { + struct zip_data_desc trailer; + copy_le32(trailer.magic, 0x08074b50); + copy_le32(trailer.crc32, crc); + copy_le32(trailer.compressed_size, compressed_size); + copy_le32(trailer.size, size); + write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE); + zip_offset += ZIP_DATA_DESC_SIZE; + } } static void set_zip_header_data_desc(struct zip_local_header *header, @@ -263,12 +280,14 @@ static int write_zip_entry(struct archiver_args *args, unsigned int mode) { struct zip_local_header header; - struct zip_dir_header dirent; + uintmax_t offset = zip_offset; struct zip_extra_mtime extra; + struct zip64_extra extra64; + size_t header_extra_size = ZIP_EXTRA_MTIME_SIZE; + int need_zip64_extra = 0; unsigned long attr2; unsigned long compressed_size; unsigned long crc; - unsigned long direntsize; int method; unsigned char *out; void *deflated = NULL; @@ -279,6 +298,9 @@ static int write_zip_entry(struct archiver_args *args, int is_binary = -1; const char *path_without_prefix = path + args->baselen; unsigned int creator_version = 0; + unsigned int version_needed = 10; + size_t zip_dir_extra_size = ZIP_EXTRA_MTIME_SIZE; + size_t zip64_dir_extra_payload_size = 0; crc = crc32(0, NULL, 0); @@ -356,43 +378,43 @@ static int write_zip_entry(struct archiver_args *args, extra.flags[0] = 1; /* just mtime */ copy_le32(extra.mtime, args->time); - /* make sure we have enough free space in the dictionary */ - direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE; - while (zip_dir_size < zip_dir_offset + direntsize) { - zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; - zip_dir = xrealloc(zip_dir, zip_dir_size); - } + if (size > 0xffffffff || compressed_size > 0xffffffff) + need_zip64_extra = 1; + if (stream && size > 0x7fffffff) + need_zip64_extra = 1; - copy_le32(dirent.magic, 0x02014b50); - copy_le16(dirent.creator_version, creator_version); - copy_le16(dirent.version, 10); - copy_le16(dirent.flags, flags); - copy_le16(dirent.compression_method, method); - copy_le16(dirent.mtime, zip_time); - copy_le16(dirent.mdate, zip_date); - set_zip_dir_data_desc(&dirent, size, compressed_size, crc); - copy_le16(dirent.filename_length, pathlen); - copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE); - copy_le16(dirent.comment_length, 0); - copy_le16(dirent.disk, 0); - copy_le32(dirent.attr2, attr2); - copy_le32(dirent.offset, zip_offset); + if (need_zip64_extra) + version_needed = 45; copy_le32(header.magic, 0x04034b50); - copy_le16(header.version, 10); + copy_le16(header.version, version_needed); copy_le16(header.flags, flags); copy_le16(header.compression_method, method); copy_le16(header.mtime, zip_time); copy_le16(header.mdate, zip_date); - set_zip_header_data_desc(&header, size, compressed_size, crc); + if (need_zip64_extra) { + set_zip_header_data_desc(&header, 0xffffffff, 0xffffffff, crc); + header_extra_size += ZIP64_EXTRA_SIZE; + } else { + set_zip_header_data_desc(&header, size, compressed_size, crc); + } copy_le16(header.filename_length, pathlen); - copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE); + copy_le16(header.extra_length, header_extra_size); write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE); zip_offset += ZIP_EXTRA_MTIME_SIZE; + if (need_zip64_extra) { + copy_le16(extra64.magic, 0x0001); + copy_le16(extra64.extra_size, ZIP64_EXTRA_PAYLOAD_SIZE); + copy_le64(extra64.size, size); + copy_le64(extra64.compressed_size, compressed_size); + write_or_die(1, &extra64, ZIP64_EXTRA_SIZE); + zip_offset += ZIP64_EXTRA_SIZE; + } + if (stream && method == 0) { unsigned char buf[STREAM_BUFFER_SIZE]; ssize_t readlen; @@ -415,9 +437,6 @@ static int write_zip_entry(struct archiver_args *args, zip_offset += compressed_size; write_zip_data_desc(size, compressed_size, crc); - zip_offset += ZIP_DATA_DESC_SIZE; - - set_zip_dir_data_desc(&dirent, size, compressed_size, crc); } else if (stream && method == 8) { unsigned char buf[STREAM_BUFFER_SIZE]; ssize_t readlen; @@ -473,9 +492,6 @@ static int write_zip_entry(struct archiver_args *args, zip_offset += compressed_size; write_zip_data_desc(size, compressed_size, crc); - zip_offset += ZIP_DATA_DESC_SIZE; - - set_zip_dir_data_desc(&dirent, size, compressed_size, crc); } else if (compressed_size > 0) { write_or_die(1, out, compressed_size); zip_offset += compressed_size; @@ -484,14 +500,46 @@ static int write_zip_entry(struct archiver_args *args, free(deflated); free(buffer); - copy_le16(dirent.attr1, !is_binary); + if (compressed_size > 0xffffffff || size > 0xffffffff || + offset > 0xffffffff) { + if (compressed_size >= 0xffffffff) + zip64_dir_extra_payload_size += 8; + if (size >= 0xffffffff) + zip64_dir_extra_payload_size += 8; + if (offset >= 0xffffffff) + zip64_dir_extra_payload_size += 8; + zip_dir_extra_size += 2 + 2 + zip64_dir_extra_payload_size; + } - memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); - zip_dir_offset += ZIP_DIR_HEADER_SIZE; - memcpy(zip_dir + zip_dir_offset, path, pathlen); - zip_dir_offset += pathlen; - memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE); - zip_dir_offset += ZIP_EXTRA_MTIME_SIZE; + strbuf_add_le(&zip_dir, 4, 0x02014b50); /* magic */ + strbuf_add_le(&zip_dir, 2, creator_version); + strbuf_add_le(&zip_dir, 2, version_needed); + strbuf_add_le(&zip_dir, 2, flags); + strbuf_add_le(&zip_dir, 2, method); + strbuf_add_le(&zip_dir, 2, zip_time); + strbuf_add_le(&zip_dir, 2, zip_date); + strbuf_add_le(&zip_dir, 4, crc); + strbuf_add_le(&zip_dir, 4, clamp32(compressed_size)); + strbuf_add_le(&zip_dir, 4, clamp32(size)); + strbuf_add_le(&zip_dir, 2, pathlen); + strbuf_add_le(&zip_dir, 2, zip_dir_extra_size); + strbuf_add_le(&zip_dir, 2, 0); /* comment length */ + strbuf_add_le(&zip_dir, 2, 0); /* disk */ + strbuf_add_le(&zip_dir, 2, !is_binary); + strbuf_add_le(&zip_dir, 4, attr2); + strbuf_add_le(&zip_dir, 4, clamp32(offset)); + strbuf_add(&zip_dir, path, pathlen); + strbuf_add(&zip_dir, &extra, ZIP_EXTRA_MTIME_SIZE); + if (zip64_dir_extra_payload_size) { + strbuf_add_le(&zip_dir, 2, 0x0001); /* magic */ + strbuf_add_le(&zip_dir, 2, zip64_dir_extra_payload_size); + if (size >= 0xffffffff) + strbuf_add_le(&zip_dir, 8, size); + if (compressed_size >= 0xffffffff) + strbuf_add_le(&zip_dir, 8, compressed_size); + if (offset >= 0xffffffff) + strbuf_add_le(&zip_dir, 8, offset); + } zip_dir_entries++; return 0; @@ -510,12 +558,12 @@ static void write_zip64_trailer(void) copy_le32(trailer64.directory_start_disk, 0); copy_le64(trailer64.entries_on_this_disk, zip_dir_entries); copy_le64(trailer64.entries, zip_dir_entries); - copy_le64(trailer64.size, zip_dir_offset); + copy_le64(trailer64.size, zip_dir.len); copy_le64(trailer64.offset, zip_offset); copy_le32(locator64.magic, 0x07064b50); copy_le32(locator64.disk, 0); - copy_le64(locator64.offset, zip_offset + zip_dir_offset); + copy_le64(locator64.offset, zip_offset + zip_dir.len); copy_le32(locator64.number_of_disks, 1); write_or_die(1, &trailer64, ZIP64_DIR_TRAILER_SIZE); @@ -533,11 +581,11 @@ static void write_zip_trailer(const unsigned char *sha1) copy_le16_clamp(trailer.entries_on_this_disk, zip_dir_entries, &clamped); copy_le16_clamp(trailer.entries, zip_dir_entries, &clamped); - copy_le32(trailer.size, zip_dir_offset); - copy_le32(trailer.offset, zip_offset); + copy_le32(trailer.size, zip_dir.len); + copy_le32_clamp(trailer.offset, zip_offset, &clamped); copy_le16(trailer.comment_length, sha1 ? GIT_SHA1_HEXSZ : 0); - write_or_die(1, zip_dir, zip_dir_offset); + write_or_die(1, zip_dir.buf, zip_dir.len); if (clamped) write_zip64_trailer(); write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); @@ -545,9 +593,17 @@ static void write_zip_trailer(const unsigned char *sha1) write_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ); } -static void dos_time(time_t *time, int *dos_date, int *dos_time) +static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time) { - struct tm *t = localtime(time); + time_t time; + struct tm *t; + + if (date_overflows(*timestamp)) + die("timestamp too large for this system: %"PRItime, + *timestamp); + time = (time_t)*timestamp; + t = localtime(&time); + *timestamp = time; *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 + (t->tm_year + 1900 - 1980) * 512; @@ -568,14 +624,13 @@ static int write_zip_archive(const struct archiver *ar, dos_time(&args->time, &zip_date, &zip_time); - zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE); - zip_dir_size = ZIP_DIRECTORY_MIN_SIZE; + strbuf_init(&zip_dir, 0); err = write_archive_entries(args, write_zip_entry); if (!err) write_zip_trailer(args->commit_sha1); - free(zip_dir); + strbuf_release(&zip_dir); return err; } diff --git a/archive.c b/archive.c index 60b8891986..b15a922dab 100644 --- a/archive.c +++ b/archive.c @@ -360,7 +360,7 @@ static void parse_treeish_arg(const char **argv, if (get_sha1(name, oid.hash)) die("Not a valid object name"); - commit = lookup_commit_reference_gently(oid.hash, 1); + commit = lookup_commit_reference_gently(&oid, 1); if (commit) { commit_sha1 = commit->object.oid.hash; archive_time = commit->date; @@ -369,7 +369,7 @@ static void parse_treeish_arg(const char **argv, archive_time = time(NULL); } - tree = parse_tree_indirect(oid.hash); + tree = parse_tree_indirect(&oid); if (tree == NULL) die("not a tree object"); @@ -383,7 +383,7 @@ static void parse_treeish_arg(const char **argv, if (err || !S_ISDIR(mode)) die("current working directory is untracked"); - tree = parse_tree_indirect(tree_oid.hash); + tree = parse_tree_indirect(&tree_oid); } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; diff --git a/archive.h b/archive.h index 415e0152e2..62d1d82c1a 100644 --- a/archive.h +++ b/archive.h @@ -9,7 +9,7 @@ struct archiver_args { struct tree *tree; const unsigned char *commit_sha1; const struct commit *commit; - time_t time; + timestamp_t time; struct pathspec pathspec; unsigned int verbose : 1; unsigned int worktree_attributes : 1; diff --git a/bisect.c b/bisect.c index 08c9fb7266..d88f9bc3dc 100644 --- a/bisect.c +++ b/bisect.c @@ -546,7 +546,7 @@ static unsigned get_prn(unsigned count) { /* * Custom integer square root from - * http://en.wikipedia.org/wiki/Integer_square_root + * https://en.wikipedia.org/wiki/Integer_square_root */ static int sqrti(int val) { @@ -705,7 +705,7 @@ static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout) static struct commit *get_commit_reference(const struct object_id *oid) { - struct commit *r = lookup_commit_reference(oid->hash); + struct commit *r = lookup_commit_reference(oid); if (!r) die(_("Not a valid commit name %s"), oid_to_hex(oid)); return r; diff --git a/blob.c b/blob.c index 1fcb8e44b0..fa2ab4f7a7 100644 --- a/blob.c +++ b/blob.c @@ -3,11 +3,11 @@ const char *blob_type = "blob"; -struct blob *lookup_blob(const unsigned char *sha1) +struct blob *lookup_blob(const struct object_id *oid) { - struct object *obj = lookup_object(sha1); + struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(sha1, alloc_blob_node()); + return create_object(oid->hash, alloc_blob_node()); return object_as_type(obj, OBJ_BLOB, 0); } diff --git a/blob.h b/blob.h index 59b394eea3..4460616831 100644 --- a/blob.h +++ b/blob.h @@ -9,7 +9,7 @@ struct blob { struct object object; }; -struct blob *lookup_blob(const unsigned char *sha1); +struct blob *lookup_blob(const struct object_id *oid); int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size); diff --git a/branch.c b/branch.c index ad5a2299ba..985316eb76 100644 --- a/branch.c +++ b/branch.c @@ -191,9 +191,9 @@ int validate_new_branchname(const char *name, struct strbuf *ref, if (!attr_only) { const char *head; - unsigned char sha1[20]; + struct object_id oid; - head = resolve_ref_unsafe("HEAD", 0, sha1, NULL); + head = resolve_ref_unsafe("HEAD", 0, oid.hash, NULL); if (!is_bare_repository() && head && !strcmp(head, ref->buf)) die(_("Cannot force update the current branch.")); } @@ -233,7 +233,7 @@ void create_branch(const char *name, const char *start_name, int quiet, enum branch_track track) { struct commit *commit; - unsigned char sha1[20]; + struct object_id oid; char *real_ref; struct strbuf ref = STRBUF_INIT; int forcing = 0; @@ -253,7 +253,7 @@ void create_branch(const char *name, const char *start_name, } real_ref = NULL; - if (get_sha1(start_name, sha1)) { + if (get_oid(start_name, &oid)) { if (explicit_tracking) { if (advice_set_upstream_failure) { error(_(upstream_missing), start_name); @@ -265,7 +265,7 @@ void create_branch(const char *name, const char *start_name, die(_("Not a valid object name: '%s'."), start_name); } - switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { + switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) { case 0: /* Not branching from any existing branch */ if (explicit_tracking) @@ -286,9 +286,9 @@ void create_branch(const char *name, const char *start_name, break; } - if ((commit = lookup_commit_reference(sha1)) == NULL) + if ((commit = lookup_commit_reference(&oid)) == NULL) die(_("Not a valid branch point: '%s'."), start_name); - hashcpy(sha1, commit->object.oid.hash); + oidcpy(&oid, &commit->object.oid); if (reflog) log_all_ref_updates = LOG_REFS_NORMAL; @@ -306,7 +306,7 @@ void create_branch(const char *name, const char *start_name, transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, - sha1, forcing ? NULL : null_sha1, + oid.hash, forcing ? NULL : null_sha1, 0, msg, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); @@ -353,17 +353,18 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref, int i; for (i = 0; worktrees[i]; i++) { + struct ref_store *refs; + if (worktrees[i]->is_detached) continue; - if (strcmp(oldref, worktrees[i]->head_ref)) + if (worktrees[i]->head_ref && + strcmp(oldref, worktrees[i]->head_ref)) continue; - if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]), - newref, logmsg)) { - ret = -1; - error(_("HEAD of working tree %s is not updated"), - worktrees[i]->path); - } + refs = get_worktree_ref_store(worktrees[i]); + if (refs_create_symref(refs, "HEAD", newref, logmsg)) + ret = error(_("HEAD of working tree %s is not updated"), + worktrees[i]->path); } free_worktrees(worktrees); diff --git a/builtin/add.c b/builtin/add.c index 0365a52098..d9a2491e48 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -404,7 +404,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) } /* This picks up the paths that are not tracked */ - baselen = fill_directory(&dir, &pathspec); + baselen = fill_directory(&dir, &the_index, &pathspec); if (pathspec.nr) seen = prune_directory(&dir, &pathspec, baselen); } @@ -440,8 +440,9 @@ int cmd_add(int argc, const char **argv, const char *prefix) !file_exists(path))) { if (ignore_missing) { int dtype = DT_UNKNOWN; - if (is_excluded(&dir, path, &dtype)) - dir_add_ignored(&dir, path, pathspec.items[i].len); + if (is_excluded(&dir, &the_index, path, &dtype)) + dir_add_ignored(&dir, &the_index, + path, pathspec.items[i].len); } else die(_("pathspec '%s' did not match any files"), pathspec.items[i].original); diff --git a/builtin/am.c b/builtin/am.c index a95dd8b4e6..0f63dcab16 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -879,12 +879,12 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr) if (skip_prefix(sb.buf, "# User ", &str)) fprintf(out, "From: %s\n", str); else if (skip_prefix(sb.buf, "# Date ", &str)) { - unsigned long timestamp; + timestamp_t timestamp; long tz, tz2; char *end; errno = 0; - timestamp = strtoul(str, &end, 10); + timestamp = parse_timestamp(str, &end, 10); if (errno) return error(_("invalid timestamp")); @@ -1145,7 +1145,7 @@ static int index_has_changes(struct strbuf *sb) DIFF_OPT_SET(&opt, EXIT_WITH_STATUS); if (!sb) DIFF_OPT_SET(&opt, QUICK); - do_diff_cache(head.hash, &opt); + do_diff_cache(&head, &opt); diffcore_std(&opt); for (i = 0; sb && i < diff_queued_diff.nr; i++) { if (i) @@ -1312,7 +1312,7 @@ static int parse_mail(struct am_state *state, const char *mail) } if (is_empty_file(am_path(state, "patch"))) { - printf_ln(_("Patch is empty. Was it split wrong?")); + printf_ln(_("Patch is empty.")); die_user_resolve(state); } @@ -1351,19 +1351,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail) struct strbuf sb = STRBUF_INIT; FILE *fp = xfopen(mail, "r"); const char *x; + int ret = 0; - if (strbuf_getline_lf(&sb, fp)) - return -1; - - if (!skip_prefix(sb.buf, "From ", &x)) - return -1; - - if (get_oid_hex(x, commit_id) < 0) - return -1; + if (strbuf_getline_lf(&sb, fp) || + !skip_prefix(sb.buf, "From ", &x) || + get_oid_hex(x, commit_id) < 0) + ret = -1; strbuf_release(&sb); fclose(fp); - return 0; + return ret; } /** @@ -1372,40 +1369,33 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail) */ static void get_commit_info(struct am_state *state, struct commit *commit) { - const char *buffer, *ident_line, *author_date, *msg; + const char *buffer, *ident_line, *msg; size_t ident_len; - struct ident_split ident_split; - struct strbuf sb = STRBUF_INIT; + struct ident_split id; buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding()); ident_line = find_commit_header(buffer, "author", &ident_len); - if (split_ident_line(&ident_split, ident_line, ident_len) < 0) { - strbuf_add(&sb, ident_line, ident_len); - die(_("invalid ident line: %s"), sb.buf); - } + if (split_ident_line(&id, ident_line, ident_len) < 0) + die(_("invalid ident line: %.*s"), (int)ident_len, ident_line); assert(!state->author_name); - if (ident_split.name_begin) { - strbuf_add(&sb, ident_split.name_begin, - ident_split.name_end - ident_split.name_begin); - state->author_name = strbuf_detach(&sb, NULL); - } else + if (id.name_begin) + state->author_name = + xmemdupz(id.name_begin, id.name_end - id.name_begin); + else state->author_name = xstrdup(""); assert(!state->author_email); - if (ident_split.mail_begin) { - strbuf_add(&sb, ident_split.mail_begin, - ident_split.mail_end - ident_split.mail_begin); - state->author_email = strbuf_detach(&sb, NULL); - } else + if (id.mail_begin) + state->author_email = + xmemdupz(id.mail_begin, id.mail_end - id.mail_begin); + else state->author_email = xstrdup(""); - author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL)); - strbuf_addstr(&sb, author_date); assert(!state->author_date); - state->author_date = strbuf_detach(&sb, NULL); + state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL))); assert(!state->msg); msg = strstr(buffer, "\n\n"); @@ -1413,6 +1403,7 @@ static void get_commit_info(struct am_state *state, struct commit *commit) die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid)); state->msg = xstrdup(msg + 2); state->msg_len = strlen(state->msg); + unuse_commit_buffer(commit, buffer); } /** @@ -1453,9 +1444,9 @@ static void write_index_patch(const struct am_state *state) FILE *fp; if (!get_sha1_tree("HEAD", head.hash)) - tree = lookup_tree(head.hash); + tree = lookup_tree(&head); else - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); fp = xfopen(am_path(state, "patch"), "w"); init_revisions(&rev_info, NULL); @@ -1488,7 +1479,7 @@ static int parse_mail_rebase(struct am_state *state, const char *mail) if (get_mail_commit_oid(&commit_oid, mail) < 0) die(_("could not parse %s"), mail); - commit = lookup_commit_or_die(commit_oid.hash, mail); + commit = lookup_commit_or_die(&commit_oid, mail); get_commit_info(state, commit); @@ -1618,7 +1609,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa init_revisions(&rev_info, NULL); rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS; diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix); - add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0); + add_pending_oid(&rev_info, "HEAD", &our_tree, 0); diff_setup_done(&rev_info.diffopt); run_diff_index(&rev_info, 1); } @@ -1683,7 +1674,7 @@ static void do_commit(const struct am_state *state) if (!get_sha1_commit("HEAD", parent.hash)) { old_oid = &parent; - commit_list_insert(lookup_commit(parent.hash), &parents); + commit_list_insert(lookup_commit(&parent), &parents); } else { old_oid = NULL; say(state, stderr, _("applying to an empty history")); @@ -1940,7 +1931,8 @@ static void am_resolve(struct am_state *state) if (unmerged_cache()) { printf_ln(_("You still have unmerged paths in your index.\n" - "Did you forget to use 'git add'?")); + "You should 'git add' each file with resolved conflicts to mark them as such.\n" + "You might run `git rm` on a file to accept \"deleted by them\" for it.")); die_user_resolve(state); } @@ -2045,11 +2037,11 @@ static int clean_index(const struct object_id *head, const struct object_id *rem struct tree *head_tree, *remote_tree, *index_tree; struct object_id index; - head_tree = parse_tree_indirect(head->hash); + head_tree = parse_tree_indirect(head); if (!head_tree) return error(_("Could not parse object '%s'."), oid_to_hex(head)); - remote_tree = parse_tree_indirect(remote->hash); + remote_tree = parse_tree_indirect(remote); if (!remote_tree) return error(_("Could not parse object '%s'."), oid_to_hex(remote)); @@ -2061,7 +2053,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem if (write_cache_as_tree(index.hash, 0, NULL)) return -1; - index_tree = parse_tree_indirect(index.hash); + index_tree = parse_tree_indirect(&index); if (!index_tree) return error(_("Could not parse object '%s'."), oid_to_hex(&index)); @@ -2156,7 +2148,7 @@ static void am_abort(struct am_state *state) am_rerere_clear(); curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL); - has_curr_head = !is_null_oid(&curr_head); + has_curr_head = curr_branch && !is_null_oid(&curr_head); if (!has_curr_head) hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN); diff --git a/builtin/blame.c b/builtin/blame.c index 07506a3e45..1043e5376f 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -563,7 +563,7 @@ static struct origin *find_origin(struct scoreboard *sb, diff_setup_done(&diff_opts); if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(parent->tree->object.oid.hash, &diff_opts); + do_diff_cache(&parent->tree->object.oid, &diff_opts); else diff_tree_sha1(parent->tree->object.oid.hash, origin->commit->tree->object.oid.hash, @@ -633,7 +633,7 @@ static struct origin *find_rename(struct scoreboard *sb, diff_setup_done(&diff_opts); if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(parent->tree->object.oid.hash, &diff_opts); + do_diff_cache(&parent->tree->object.oid, &diff_opts); else diff_tree_sha1(parent->tree->object.oid.hash, origin->commit->tree->object.oid.hash, @@ -1272,7 +1272,7 @@ static void find_copy_in_parent(struct scoreboard *sb, DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); if (is_null_oid(&target->commit->object.oid)) - do_diff_cache(parent->tree->object.oid.hash, &diff_opts); + do_diff_cache(&parent->tree->object.oid, &diff_opts); else diff_tree_sha1(parent->tree->object.oid.hash, target->commit->tree->object.oid.hash, @@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) struct commit_info { struct strbuf author; struct strbuf author_mail; - unsigned long author_time; + timestamp_t author_time; struct strbuf author_tz; /* filled only when asked for details */ struct strbuf committer; struct strbuf committer_mail; - unsigned long committer_time; + timestamp_t committer_time; struct strbuf committer_tz; struct strbuf summary; @@ -1578,7 +1578,7 @@ struct commit_info { */ static void get_ac_line(const char *inbuf, const char *what, struct strbuf *name, struct strbuf *mail, - unsigned long *time, struct strbuf *tz) + timestamp_t *time, struct strbuf *tz) { struct ident_split ident; size_t len, maillen, namelen; @@ -1727,11 +1727,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat) get_commit_info(suspect->commit, &ci, 1); printf("author %s\n", ci.author.buf); printf("author-mail %s\n", ci.author_mail.buf); - printf("author-time %lu\n", ci.author_time); + printf("author-time %"PRItime"\n", ci.author_time); printf("author-tz %s\n", ci.author_tz.buf); printf("committer %s\n", ci.committer.buf); printf("committer-mail %s\n", ci.committer_mail.buf); - printf("committer-time %lu\n", ci.committer_time); + printf("committer-time %"PRItime"\n", ci.committer_time); printf("committer-tz %s\n", ci.committer_tz.buf); printf("summary %s\n", ci.summary.buf); if (suspect->commit->object.flags & UNINTERESTING) @@ -1837,14 +1837,14 @@ static void assign_blame(struct scoreboard *sb, int opt) stop_progress(&pi.progress); } -static const char *format_time(unsigned long time, const char *tz_str, +static const char *format_time(timestamp_t time, const char *tz_str, int show_raw_time) { static struct strbuf time_buf = STRBUF_INIT; strbuf_reset(&time_buf); if (show_raw_time) { - strbuf_addf(&time_buf, "%lu %s", time, tz_str); + strbuf_addf(&time_buf, "%"PRItime" %s", time, tz_str); } else { const char *time_str; @@ -2253,7 +2253,7 @@ static struct commit_list **append_parent(struct commit_list **tail, const struc { struct commit *parent; - parent = lookup_commit_reference(oid->hash); + parent = lookup_commit_reference(oid); if (!parent) die("no such commit %s", oid_to_hex(oid)); return &commit_list_insert(parent, tail)->next; @@ -2461,7 +2461,7 @@ static const char *dwim_reverse_initial(struct scoreboard *sb) */ struct object *obj; struct commit *head_commit; - unsigned char head_sha1[20]; + struct object_id head_oid; if (sb->revs->pending.nr != 1) return NULL; @@ -2473,9 +2473,9 @@ static const char *dwim_reverse_initial(struct scoreboard *sb) return NULL; /* Do we have HEAD? */ - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) return NULL; - head_commit = lookup_commit_reference_gently(head_sha1, 1); + head_commit = lookup_commit_reference_gently(&head_oid, 1); if (!head_commit) return NULL; diff --git a/builtin/branch.c b/builtin/branch.c index 48a513a84d..83fcda43dc 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -124,7 +124,7 @@ static int branch_merged(int kind, const char *name, (reference_name = reference_name_to_free = resolve_refdup(upstream, RESOLVE_REF_READING, oid.hash, NULL)) != NULL) - reference_rev = lookup_commit_reference(oid.hash); + reference_rev = lookup_commit_reference(&oid); } if (!reference_rev) reference_rev = head_rev; @@ -157,7 +157,7 @@ static int check_branch_commit(const char *branchname, const char *refname, const struct object_id *oid, struct commit *head_rev, int kinds, int force) { - struct commit *rev = lookup_commit_reference(oid->hash); + struct commit *rev = lookup_commit_reference(oid); if (!rev) { error(_("Couldn't look up commit object for '%s'"), refname); return -1; @@ -211,7 +211,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, } if (!force) { - head_rev = lookup_commit_reference(head_oid.hash); + head_rev = lookup_commit_reference(&head_oid); if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 1890d7a639..9af863e791 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, die("git cat-file %s: bad file", obj_name); write_or_die(1, buf, size); + free(buf); return 0; } diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c index 7629018a56..c7b8c08897 100644 --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@ -103,7 +103,8 @@ static int check_ignore(struct dir_struct *dir, full_path = pathspec.items[i].match; exclude = NULL; if (!seen[i]) { - exclude = last_exclude_matching(dir, full_path, &dtype); + exclude = last_exclude_matching(dir, &the_index, + full_path, &dtype); } if (!quiet && (exclude || show_non_matching)) output_exclude(pathspec.items[i].original, exclude); diff --git a/builtin/checkout.c b/builtin/checkout.c index bfa5419f33..a6b2af39d3 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -235,22 +235,24 @@ static int checkout_merged(int pos, const struct checkout *state) /* * NEEDSWORK: * There is absolutely no reason to write this as a blob object - * and create a phony cache entry just to leak. This hack is - * primarily to get to the write_entry() machinery that massages - * the contents to work-tree format and writes out which only - * allows it for a cache entry. The code in write_entry() needs - * to be refactored to allow us to feed a - * instead of a cache entry. Such a refactoring would help - * merge_recursive as well (it also writes the merge result to the - * object database even when it may contain conflicts). + * and create a phony cache entry. This hack is primarily to get + * to the write_entry() machinery that massages the contents to + * work-tree format and writes out which only allows it for a + * cache entry. The code in write_entry() needs to be refactored + * to allow us to feed a instead of a cache + * entry. Such a refactoring would help merge_recursive as well + * (it also writes the merge result to the object database even + * when it may contain conflicts). */ if (write_sha1_file(result_buf.ptr, result_buf.size, blob_type, oid.hash)) die(_("Unable to add merge result for '%s'"), path); + free(result_buf.ptr); ce = make_cache_entry(mode, oid.hash, path, 2, 0); if (!ce) die(_("make_cache_entry failed for path '%s'"), path); status = checkout_entry(ce, state, NULL); + free(ce); return status; } @@ -393,7 +395,7 @@ static int checkout_paths(const struct checkout_opts *opts, die(_("unable to write new index file")); read_ref_full("HEAD", 0, rev.hash, NULL); - head = lookup_commit_reference_gently(rev.hash, 1); + head = lookup_commit_reference_gently(&rev, 1); errs |= post_checkout_hook(head, head, 0); return errs; @@ -527,10 +529,10 @@ static int merge_working_tree(const struct checkout_opts *opts, setup_standard_excludes(topts.dir); } tree = parse_tree_indirect(old->commit ? - old->commit->object.oid.hash : - EMPTY_TREE_SHA1_BIN); + &old->commit->object.oid : + &empty_tree_oid); init_tree_desc(&trees[0], tree->buffer, tree->size); - tree = parse_tree_indirect(new->commit->object.oid.hash); + tree = parse_tree_indirect(&new->commit->object.oid); init_tree_desc(&trees[1], tree->buffer, tree->size); ret = unpack_trees(2, trees, &topts); @@ -721,7 +723,7 @@ static int add_pending_uninteresting_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data) { - add_pending_sha1(cb_data, refname, oid->hash, UNINTERESTING); + add_pending_oid(cb_data, refname, oid, UNINTERESTING); return 0; } @@ -807,7 +809,7 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) add_pending_object(&revs, object, oid_to_hex(&object->oid)); for_each_ref(add_pending_uninteresting_ref, &revs); - add_pending_sha1(&revs, "HEAD", new->object.oid.hash, UNINTERESTING); + add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING); refs = revs.pending; revs.leak_pending = 1; @@ -833,7 +835,8 @@ static int switch_branches(const struct checkout_opts *opts, int flag, writeout_error = 0; memset(&old, 0, sizeof(old)); old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag); - old.commit = lookup_commit_reference_gently(rev.hash, 1); + if (old.path) + old.commit = lookup_commit_reference_gently(&rev, 1); if (!(flag & REF_ISSYMREF)) old.path = NULL; @@ -1047,10 +1050,10 @@ static int parse_branchname_arg(int argc, const char **argv, else new->path = NULL; /* not an existing branch */ - new->commit = lookup_commit_reference_gently(rev->hash, 1); + new->commit = lookup_commit_reference_gently(rev, 1); if (!new->commit) { /* not a commit */ - *source_tree = parse_tree_indirect(rev->hash); + *source_tree = parse_tree_indirect(rev); } else { parse_commit_or_die(new->commit); *source_tree = new->commit->tree; @@ -1286,9 +1289,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) * new_branch && argc > 1 will be caught later. */ if (opts.new_branch && argc == 1) - die(_("Cannot update paths and switch to branch '%s' at the same time.\n" - "Did you intend to checkout '%s' which can not be resolved as commit?"), - opts.new_branch, argv[0]); + die(_("'%s' is not a commit and a branch '%s' cannot be created from it"), + argv[0], opts.new_branch); if (opts.force_detach) die(_("git checkout: --detach does not take a path argument '%s'"), diff --git a/builtin/clean.c b/builtin/clean.c index d861f836a2..329b68c40b 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -683,7 +683,7 @@ static int filter_by_patterns_cmd(void) for_each_string_list_item(item, &del_list) { int dtype = DT_UNKNOWN; - if (is_excluded(&dir, item->string, &dtype)) { + if (is_excluded(&dir, &the_index, item->string, &dtype)) { *item->string = '\0'; changed++; } @@ -930,7 +930,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) PATHSPEC_PREFER_CWD, prefix, argv); - fill_directory(&dir, &pathspec); + fill_directory(&dir, &the_index, &pathspec); for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; diff --git a/builtin/clone.c b/builtin/clone.c index de85b85254..743f16ae2a 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -40,6 +40,7 @@ static const char * const builtin_clone_usage[] = { static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1; static int option_local = -1, option_no_hardlinks, option_shared; +static int option_no_tags; static int option_shallow_submodules; static int deepen; static char *option_template, *option_depth, *option_since; @@ -120,6 +121,8 @@ static struct option builtin_clone_options[] = { N_("deepen history of shallow clone, excluding rev")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), + OPT_BOOL(0, "no-tags", &option_no_tags, + N_("don't clone any tags, and make later fetches not to follow them")), OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules, N_("any cloned submodules will be shallow")), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), @@ -563,7 +566,7 @@ static struct ref *wanted_peer_refs(const struct ref *refs, } else get_fetch_map(refs, refspec, &tail, 0); - if (!option_mirror && !option_single_branch) + if (!option_mirror && !option_single_branch && !option_no_tags) get_fetch_map(refs, tag_refspec, &tail, 0); return local_refs; @@ -652,7 +655,7 @@ static void update_remote_refs(const struct ref *refs, if (refs) { write_remote_refs(mapped_refs); - if (option_single_branch) + if (option_single_branch && !option_no_tags) write_followtags(refs, msg); } @@ -682,7 +685,7 @@ static void update_head(const struct ref *our, const struct ref *remote, install_branch_config(0, head, option_origin, our->name); } } else if (our) { - struct commit *c = lookup_commit_reference(our->old_oid.hash); + struct commit *c = lookup_commit_reference(&our->old_oid); /* --branch specifies a non-branch (i.e. tags), detach HEAD */ update_ref(msg, "HEAD", c->object.oid.hash, NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR); @@ -739,7 +742,7 @@ static int checkout(int submodule_progress) opts.src_index = &the_index; opts.dst_index = &the_index; - tree = parse_tree_indirect(oid.hash); + tree = parse_tree_indirect(&oid); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts) < 0) @@ -773,7 +776,9 @@ static int checkout(int submodule_progress) static int write_one_config(const char *key, const char *value, void *data) { - return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0); + return git_config_set_multivar_gently(key, + value ? value : "true", + CONFIG_REGEX_NONE, 0); } static void write_config(struct string_list *config) @@ -1035,6 +1040,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix) git_config_set(key.buf, repo); strbuf_reset(&key); + if (option_no_tags) { + strbuf_addf(&key, "remote.%s.tagOpt", option_origin); + git_config_set(key.buf, "--no-tags"); + strbuf_reset(&key); + } + if (option_required_reference.nr || option_optional_reference.nr) setup_reference(); diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 605017261c..f39c2b2737 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -58,7 +58,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) if (get_sha1_commit(argv[i], oid.hash)) die("Not a valid object name %s", argv[i]); assert_sha1_type(oid.hash, OBJ_COMMIT); - new_parent(lookup_commit(oid.hash), &parents); + new_parent(lookup_commit(&oid), &parents); continue; } diff --git a/builtin/commit.c b/builtin/commit.c index 1d805f5da8..da1ba4c862 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -313,7 +313,7 @@ static void create_base_index(const struct commit *current_head) opts.dst_index = &the_index; opts.fn = oneway_merge; - tree = parse_tree_indirect(current_head->object.oid.hash); + tree = parse_tree_indirect(¤t_head->object.oid); if (!tree) die(_("failed to unpack HEAD tree object")); parse_tree(tree); @@ -1263,6 +1263,10 @@ static int parse_status_slot(const char *slot) return WT_STATUS_NOBRANCH; if (!strcasecmp(slot, "unmerged")) return WT_STATUS_UNMERGED; + if (!strcasecmp(slot, "localBranch")) + return WT_STATUS_LOCAL_BRANCH; + if (!strcasecmp(slot, "remoteBranch")) + return WT_STATUS_REMOTE_BRANCH; return -1; } @@ -1430,7 +1434,7 @@ static void print_summary(const char *prefix, const struct object_id *oid, struct strbuf author_ident = STRBUF_INIT; struct strbuf committer_ident = STRBUF_INIT; - commit = lookup_commit(oid->hash); + commit = lookup_commit(oid); if (!commit) die(_("couldn't look up newly created commit")); if (parse_commit(commit)) @@ -1654,7 +1658,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (get_sha1("HEAD", oid.hash)) current_head = NULL; else { - current_head = lookup_commit_or_die(oid.hash, "HEAD"); + current_head = lookup_commit_or_die(&oid, "HEAD"); if (parse_commit(current_head)) die(_("could not parse HEAD commit")); } @@ -1735,7 +1739,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (verbose || /* Truncate the message just before the diff, if any. */ cleanup_mode == CLEANUP_SCISSORS) - wt_status_truncate_message_at_cut_line(&sb); + strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len)); if (cleanup_mode != CLEANUP_NONE) strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL); @@ -1758,7 +1762,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1, + if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash, parents, oid.hash, author_ident.buf, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); diff --git a/builtin/config.c b/builtin/config.c index 3a554ad50c..7f6c25d4d9 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -496,6 +496,9 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_with_options(builtin_config_usage, builtin_config_options); } + if (use_local_config && nongit) + die(_("--local can only be used inside a git repository")); + if (given_config_source.file && !strcmp(given_config_source.file, "-")) { given_config_source.file = NULL; diff --git a/builtin/describe.c b/builtin/describe.c index a5cd8c513f..893c8789f4 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -79,13 +79,13 @@ static int replace_name(struct commit_name *e, struct tag *t; if (!e->tag) { - t = lookup_tag(e->oid.hash); + t = lookup_tag(&e->oid); if (!t || parse_tag(t)) return 1; e->tag = t; } - t = lookup_tag(oid->hash); + t = lookup_tag(oid); if (!t || parse_tag(t)) return 0; *tag = t; @@ -245,7 +245,7 @@ static unsigned long finish_depth_computation( static void display_name(struct commit_name *n) { if (n->prio == 2 && !n->tag) { - n->tag = lookup_tag(n->oid.hash); + n->tag = lookup_tag(&n->oid); if (!n->tag || parse_tag(n->tag)) die(_("annotated tag %s not available"), n->path); } @@ -281,7 +281,7 @@ static void describe(const char *arg, int last_one) if (get_oid(arg, &oid)) die(_("Not a valid object name %s"), arg); - cmit = lookup_commit_reference(oid.hash); + cmit = lookup_commit_reference(&oid); if (!cmit) die(_("%s is not a valid '%s' object"), arg, commit_type); @@ -309,7 +309,7 @@ static void describe(const char *arg, int last_one) struct commit *c; struct commit_name *n = hashmap_iter_first(&names, &iter); for (; n; n = hashmap_iter_next(&iter)) { - c = lookup_commit_reference_gently(n->peeled.hash, 1); + c = lookup_commit_reference_gently(&n->peeled, 1); if (c) c->util = n; } diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 326f88b657..5ea1c14317 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -9,7 +9,7 @@ static struct rev_info log_tree_opt; static int diff_tree_commit_sha1(const struct object_id *oid) { - struct commit *commit = lookup_commit_reference(oid->hash); + struct commit *commit = lookup_commit_reference(oid); if (!commit) return -1; return log_tree_commit(&log_tree_opt, commit); @@ -23,7 +23,7 @@ static int stdin_diff_commit(struct commit *commit, const char *p) /* Graft the fake parents locally to the commit */ while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) { - struct commit *parent = lookup_commit(oid.hash); + struct commit *parent = lookup_commit(&oid); if (!pptr) { /* Free the real parent list */ free_commit_list(commit->parents); @@ -44,7 +44,7 @@ static int stdin_diff_trees(struct tree *tree1, const char *p) struct tree *tree2; if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p) return error("Need exactly two trees, separated by a space"); - tree2 = lookup_tree(oid.hash); + tree2 = lookup_tree(&oid); if (!tree2 || parse_tree(tree2)) return -1; printf("%s %s\n", oid_to_hex(&tree1->object.oid), @@ -67,7 +67,7 @@ static int diff_tree_stdin(char *line) line[len-1] = 0; if (parse_oid_hex(line, &oid, &p)) return -1; - obj = parse_object(oid.hash); + obj = parse_object(&oid); if (!obj) return -1; if (obj->type == OBJ_COMMIT) diff --git a/builtin/diff.c b/builtin/diff.c index d184aafab9..8c03ddaf58 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -381,7 +381,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); add_pending_object(&rev, &tree->object, "HEAD"); } break; @@ -395,7 +395,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) const char *name = entry->name; int flags = (obj->flags & UNINTERESTING); if (!obj->parsed) - obj = parse_object(obj->oid.hash); + obj = parse_object(&obj->oid); obj = deref_tag(obj, NULL, 0); if (!obj) die(_("invalid object '%s' given."), name); @@ -408,7 +408,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); - hashcpy(blob[blobs].oid.hash, obj->oid.hash); + oidcpy(&blob[blobs].oid, &obj->oid); blob[blobs].name = name; blob[blobs].mode = entry->mode; blobs++; diff --git a/builtin/difftool.c b/builtin/difftool.c index 1354d0e462..b9a892f269 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path, hashmap_entry_init(entry, strhash(buf.buf)); hashmap_add(result, entry); } + fclose(fp); if (finish_command(&diff_files)) die("diff-files did not exit properly"); strbuf_release(&index_env); @@ -439,8 +440,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, } if (lmode && status != 'C') { - if (checkout_path(lmode, &loid, src_path, &lstate)) - return error("could not write '%s'", src_path); + if (checkout_path(lmode, &loid, src_path, &lstate)) { + ret = error("could not write '%s'", src_path); + goto finish; + } } if (rmode && !S_ISLNK(rmode)) { @@ -456,9 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, hashmap_add(&working_tree_dups, entry); if (!use_wt_file(workdir, dst_path, &roid)) { - if (checkout_path(rmode, &roid, dst_path, &rstate)) - return error("could not write '%s'", - dst_path); + if (checkout_path(rmode, &roid, dst_path, + &rstate)) { + ret = error("could not write '%s'", + dst_path); + goto finish; + } } else if (!is_null_oid(&roid)) { /* * Changes in the working tree need special @@ -473,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, ADD_CACHE_JUST_APPEND); add_path(&rdir, rdir_len, dst_path); - if (ensure_leading_directories(rdir.buf)) - return error("could not create " - "directory for '%s'", - dst_path); + if (ensure_leading_directories(rdir.buf)) { + ret = error("could not create " + "directory for '%s'", + dst_path); + goto finish; + } add_path(&wtdir, wtdir_len, dst_path); if (symlinks) { if (symlink(wtdir.buf, rdir.buf)) { @@ -497,13 +505,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, } } + fclose(fp); + fp = NULL; if (finish_command(&child)) { ret = error("error occurred running diff --raw"); goto finish; } if (!i) - return 0; + goto finish; /* * Changes to submodules require special treatment.This loop writes a @@ -626,6 +636,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, exit_cleanup(tmpdir, rc); finish: + if (fp) + fclose(fp); + free(lbase_dir); free(rbase_dir); strbuf_release(&ldir); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index e0220630d0..24e29ad7ea 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -232,7 +232,7 @@ static void export_blob(const struct object_id *oid) if (anonymize) { buf = anonymize_blob(&size); - object = (struct object *)lookup_blob(oid->hash); + object = (struct object *)lookup_blob(oid); eaten = 0; } else { buf = read_sha1_file(oid->hash, &type, &size); @@ -240,7 +240,7 @@ static void export_blob(const struct object_id *oid) die ("Could not read blob %s", oid_to_hex(oid)); if (check_sha1_signature(oid->hash, buf, size, typename(type)) < 0) die("sha1 mismatch in blob %s", oid_to_hex(oid)); - object = parse_object_buffer(oid->hash, type, size, buf, &eaten); + object = parse_object_buffer(oid, type, size, buf, &eaten); } if (!object) @@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag) oid_to_hex(&tag->object.oid)); case DROP: /* Ignore this tag altogether */ + free(buf); return; case REWRITE: if (tagged->type != OBJ_COMMIT) { @@ -765,6 +766,7 @@ static void handle_tag(const char *name, struct tag *tag) (int)(tagger_end - tagger), tagger, tagger == tagger_end ? "" : "\n", (int)message_size, (int)message_size, message ? message : ""); + free(buf); } static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name) @@ -777,7 +779,7 @@ static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name) /* handle nested tags */ while (tag && tag->object.type == OBJ_TAG) { - parse_object(tag->object.oid.hash); + parse_object(&tag->object.oid); string_list_append(&extra_refs, full_name)->util = tag; tag = (struct tag *)tag->tagged; } @@ -938,7 +940,7 @@ static void import_marks(char *input_file) /* only commits */ continue; - commit = lookup_commit(oid.hash); + commit = lookup_commit(&oid); if (!commit) die("not a commit? can't happen: %s", oid_to_hex(&oid)); diff --git a/builtin/fetch.c b/builtin/fetch.c index 5f2c2ab23e..d4d573b985 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -636,8 +636,8 @@ static int update_local_ref(struct ref *ref, return r; } - current = lookup_commit_reference_gently(ref->old_oid.hash, 1); - updated = lookup_commit_reference_gently(ref->new_oid.hash, 1); + current = lookup_commit_reference_gently(&ref->old_oid, 1); + updated = lookup_commit_reference_gently(&ref->new_oid, 1); if (!current || !updated) { const char *msg; const char *what; @@ -770,7 +770,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, continue; } - commit = lookup_commit_reference_gently(rm->old_oid.hash, 1); + commit = lookup_commit_reference_gently(&rm->old_oid, + 1); if (!commit) rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE; diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 6faa3c0d24..70137b0b7e 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -341,7 +341,7 @@ static void shortlog(const char *name, const struct object_id *oid = &origin_data->oid; int limit = opts->shortlog_len; - branch = deref_tag(parse_object(oid->hash), oid_to_hex(oid), GIT_SHA1_HEXSZ); + branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ); if (!branch || branch->type != OBJ_COMMIT) return; @@ -559,14 +559,14 @@ static void find_merge_parents(struct merge_parents *result, * "name" here and we do not want to contaminate its * util field yet. */ - obj = parse_object(oid.hash); + obj = parse_object(&oid); parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT); if (!parent) continue; commit_list_insert(parent, &parents); add_merge_parent(result, &obj->oid, &parent->object.oid); } - head_commit = lookup_commit(head->hash); + head_commit = lookup_commit(head); if (head_commit) commit_list_insert(head_commit, &parents); parents = reduce_heads(parents); @@ -633,7 +633,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out, struct commit *head; struct rev_info rev; - head = lookup_commit_or_die(head_oid.hash, "HEAD"); + head = lookup_commit_or_die(&head_oid, "HEAD"); init_revisions(&rev, NULL); rev.commit_format = CMIT_FMT_ONELINE; rev.ignore_merges = 1; diff --git a/builtin/fsck.c b/builtin/fsck.c index b5e13a4556..cb2ba6cd1b 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -377,7 +377,7 @@ static int fsck_obj(struct object *obj) return 0; } -static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type, +static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten) { /* @@ -385,10 +385,10 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type, * verify_packfile(), data_valid variable for details. */ struct object *obj; - obj = parse_object_buffer(sha1, type, size, buffer, eaten); + obj = parse_object_buffer(oid, type, size, buffer, eaten); if (!obj) { errors_found |= ERROR_OBJECT; - return error("%s: object corrupt or missing", sha1_to_hex(sha1)); + return error("%s: object corrupt or missing", oid_to_hex(oid)); } obj->flags = HAS_OBJ; return fsck_obj(obj); @@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type, static int default_refs; static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, - unsigned long timestamp) + timestamp_t timestamp) { struct object *obj; @@ -407,7 +407,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, if (timestamp && name_objects) add_decoration(fsck_walk_options.object_names, obj, - xstrfmt("%s@{%ld}", refname, timestamp)); + xstrfmt("%s@{%"PRItime"}", refname, timestamp)); obj->used = 1; mark_object_reachable(obj); } else { @@ -418,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, } static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { const char *refname = cb_data; @@ -444,7 +444,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid, { struct object *obj; - obj = parse_object(oid->hash); + obj = parse_object(oid); if (!obj) { error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid)); errors_found |= ERROR_REACHABLE; @@ -506,7 +506,7 @@ static struct object *parse_loose_object(const struct object_id *oid, if (!contents && type != OBJ_BLOB) die("BUG: read_loose_object streamed a non-blob"); - obj = parse_object_buffer(oid->hash, type, size, contents, &eaten); + obj = parse_object_buffer(oid, type, size, contents, &eaten); if (!eaten) free(contents); @@ -599,10 +599,10 @@ static int fsck_cache_tree(struct cache_tree *it) fprintf(stderr, "Checking cache tree\n"); if (0 <= it->entry_count) { - struct object *obj = parse_object(it->sha1); + struct object *obj = parse_object(&it->oid); if (!obj) { error("%s: invalid sha1 pointer in cache-tree", - sha1_to_hex(it->sha1)); + oid_to_hex(&it->oid)); errors_found |= ERROR_REFS; return 1; } @@ -781,7 +781,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) mode = active_cache[i]->ce_mode; if (S_ISGITLINK(mode)) continue; - blob = lookup_blob(active_cache[i]->oid.hash); + blob = lookup_blob(&active_cache[i]->oid); if (!blob) continue; obj = &blob->object; diff --git a/builtin/gc.c b/builtin/gc.c index 91f7696a85..f484eda43c 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -33,7 +33,7 @@ static int aggressive_window = 250; static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; static int detach_auto = 1; -static unsigned long gc_log_expire_time; +static timestamp_t gc_log_expire_time; static const char *gc_log_expire = "1.day.ago"; static const char *prune_expire = "2.weeks.ago"; static const char *prune_worktrees_expire = "3.months.ago"; diff --git a/builtin/grep.c b/builtin/grep.c index 3ffb5b4e81..c6c26e9b9e 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -866,7 +866,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec, if (exc_std) setup_standard_excludes(&dir); - fill_directory(&dir, pathspec); + fill_directory(&dir, &the_index, pathspec); for (i = 0; i < dir.nr; i++) { if (!dir_path_match(dir.entries[i], pathspec, 0, NULL)) continue; @@ -1196,7 +1196,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) break; } - object = parse_object_or_die(oid.hash, arg); + object = parse_object_or_die(&oid, arg); if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 4ff567db47..04b9dcaf0f 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -747,13 +747,13 @@ static int compare_objects(const unsigned char *buf, unsigned long size, ssize_t len = read_istream(data->st, data->buf, size); if (len == 0) die(_("SHA1 COLLISION FOUND WITH %s !"), - sha1_to_hex(data->entry->idx.sha1)); + oid_to_hex(&data->entry->idx.oid)); if (len < 0) die(_("unable to read %s"), - sha1_to_hex(data->entry->idx.sha1)); + oid_to_hex(&data->entry->idx.oid)); if (memcmp(buf, data->buf, len)) die(_("SHA1 COLLISION FOUND WITH %s !"), - sha1_to_hex(data->entry->idx.sha1)); + oid_to_hex(&data->entry->idx.oid)); size -= len; buf += len; } @@ -771,12 +771,12 @@ static int check_collison(struct object_entry *entry) memset(&data, 0, sizeof(data)); data.entry = entry; - data.st = open_istream(entry->idx.sha1, &type, &size, NULL); + data.st = open_istream(entry->idx.oid.hash, &type, &size, NULL); if (!data.st) return -1; if (size != entry->size || type != entry->type) die(_("SHA1 COLLISION FOUND WITH %s !"), - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); unpack_data(entry, compare_objects, &data); close_istream(data.st); free(data.buf); @@ -785,7 +785,7 @@ static int check_collison(struct object_entry *entry) static void sha1_object(const void *data, struct object_entry *obj_entry, unsigned long size, enum object_type type, - const unsigned char *sha1) + const struct object_id *oid) { void *new_data = NULL; int collision_test_needed = 0; @@ -794,7 +794,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, if (startup_info->have_repository) { read_lock(); - collision_test_needed = has_sha1_file_with_flags(sha1, HAS_SHA1_QUICK); + collision_test_needed = has_sha1_file_with_flags(oid->hash, HAS_SHA1_QUICK); read_unlock(); } @@ -809,31 +809,31 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, enum object_type has_type; unsigned long has_size; read_lock(); - has_type = sha1_object_info(sha1, &has_size); + has_type = sha1_object_info(oid->hash, &has_size); if (has_type < 0) - die(_("cannot read existing object info %s"), sha1_to_hex(sha1)); + die(_("cannot read existing object info %s"), oid_to_hex(oid)); if (has_type != type || has_size != size) - die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); - has_data = read_sha1_file(sha1, &has_type, &has_size); + die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid)); + has_data = read_sha1_file(oid->hash, &has_type, &has_size); read_unlock(); if (!data) data = new_data = get_data_from_pack(obj_entry); if (!has_data) - die(_("cannot read existing object %s"), sha1_to_hex(sha1)); + die(_("cannot read existing object %s"), oid_to_hex(oid)); if (size != has_size || type != has_type || memcmp(data, has_data, size) != 0) - die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); + die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid)); free(has_data); } if (strict) { read_lock(); if (type == OBJ_BLOB) { - struct blob *blob = lookup_blob(sha1); + struct blob *blob = lookup_blob(oid); if (blob) blob->object.flags |= FLAG_CHECKED; else - die(_("invalid blob object %s"), sha1_to_hex(sha1)); + die(_("invalid blob object %s"), oid_to_hex(oid)); } else { struct object *obj; int eaten; @@ -845,7 +845,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, * we do not need to free the memory here, as the * buf is deleted by the caller. */ - obj = parse_object_buffer(sha1, type, size, buf, &eaten); + obj = parse_object_buffer(oid, type, size, buf, + &eaten); if (!obj) die(_("invalid %s"), typename(type)); if (do_fsck_object && @@ -957,9 +958,10 @@ static void resolve_delta(struct object_entry *delta_obj, if (!result->data) bad_object(delta_obj->idx.offset, _("failed to apply delta")); hash_sha1_file(result->data, result->size, - typename(delta_obj->real_type), delta_obj->idx.sha1); + typename(delta_obj->real_type), + delta_obj->idx.oid.hash); sha1_object(result->data, NULL, result->size, delta_obj->real_type, - delta_obj->idx.sha1); + &delta_obj->idx.oid); counter_lock(); nr_resolved_deltas++; counter_unlock(); @@ -989,7 +991,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base, struct base_data *prev_base) { if (base->ref_last == -1 && base->ofs_last == -1) { - find_ref_delta_children(base->obj->idx.sha1, + find_ref_delta_children(base->obj->idx.oid.hash, &base->ref_first, &base->ref_last, OBJ_REF_DELTA); @@ -1130,7 +1132,8 @@ static void parse_pack_objects(unsigned char *sha1) for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; void *data = unpack_raw_entry(obj, &ofs_delta->offset, - ref_delta_sha1, obj->idx.sha1); + ref_delta_sha1, + obj->idx.oid.hash); obj->real_type = obj->type; if (obj->type == OBJ_OFS_DELTA) { nr_ofs_deltas++; @@ -1146,7 +1149,8 @@ static void parse_pack_objects(unsigned char *sha1) obj->real_type = OBJ_BAD; nr_delays++; } else - sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1); + sha1_object(data, NULL, obj->size, obj->type, + &obj->idx.oid); free(data); display_progress(progress, i+1); } @@ -1172,7 +1176,8 @@ static void parse_pack_objects(unsigned char *sha1) if (obj->real_type != OBJ_BAD) continue; obj->real_type = obj->type; - sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1); + sha1_object(NULL, obj, obj->size, obj->type, + &obj->idx.oid); nr_delays--; } if (nr_delays) @@ -1330,7 +1335,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f, obj[1].idx.offset += write_compressed(f, buf, size); obj[0].idx.crc32 = crc32_end(f); sha1flush(f); - hashcpy(obj->idx.sha1, sha1); + hashcpy(obj->idx.oid.hash, sha1); return obj; } @@ -1581,13 +1586,14 @@ static void show_pack_info(int stat_only) if (stat_only) continue; printf("%s %-6s %lu %lu %"PRIuMAX, - sha1_to_hex(obj->idx.sha1), + oid_to_hex(&obj->idx.oid), typename(obj->real_type), obj->size, (unsigned long)(obj[1].idx.offset - obj->idx.offset), (uintmax_t)obj->idx.offset); if (is_delta_type(obj->type)) { struct object_entry *bobj = &objects[obj_stat[i].base_object_no]; - printf(" %u %s", obj_stat[i].delta_depth, sha1_to_hex(bobj->idx.sha1)); + printf(" %u %s", obj_stat[i].delta_depth, + oid_to_hex(&bobj->idx.oid)); } putchar('\n'); } diff --git a/builtin/log.c b/builtin/log.c index b3b10cc1ed..a440601efe 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -110,6 +110,8 @@ static void init_log_defaults(void) { init_grep_defaults(); init_diff_ui_defaults(); + + decoration_style = auto_decoration_style(); } static void cmd_log_init_defaults(struct rev_info *rev) @@ -410,8 +412,6 @@ static int git_log_config(const char *var, const char *value, void *cb) if (decoration_style < 0) decoration_style = 0; /* maybe warn? */ return 0; - } else { - decoration_style = auto_decoration_style(); } if (!strcmp(var, "log.showroot")) { default_show_root = git_config_bool(var, value); @@ -596,7 +596,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) rev.shown_one = 1; if (ret) break; - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); if (!o) ret = error(_("Could not read object %s"), oid_to_hex(&t->tagged->oid)); @@ -878,8 +878,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids) o2 = rev->pending.objects[1].item; flags1 = o1->flags; flags2 = o2->flags; - c1 = lookup_commit_reference(o1->oid.hash); - c2 = lookup_commit_reference(o2->oid.hash); + c1 = lookup_commit_reference(&o1->oid); + c2 = lookup_commit_reference(&o2->oid); if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING)) die(_("Not a range.")); @@ -910,8 +910,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids) static void gen_message_id(struct rev_info *info, char *base) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, "%s.%lu.git.%s", base, - (unsigned long) time(NULL), + strbuf_addf(&buf, "%s.%"PRItime".git.%s", base, + (timestamp_t) time(NULL), git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT)); info->message_id = strbuf_detach(&buf, NULL); } @@ -1263,7 +1263,7 @@ static struct commit *get_base_commit(const char *base_commit, if (get_oid(upstream, &oid)) die(_("Failed to resolve '%s' as a valid ref."), upstream); - commit = lookup_commit_or_die(oid.hash, "upstream base"); + commit = lookup_commit_or_die(&oid, "upstream base"); base_list = get_merge_bases_many(commit, total, list); /* There should be one and only one merge base. */ if (!base_list || base_list->next) @@ -1819,7 +1819,7 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags) { struct object_id oid; if (get_oid(arg, &oid) == 0) { - struct commit *commit = lookup_commit_reference(oid.hash); + struct commit *commit = lookup_commit_reference(&oid); if (commit) { commit->object.flags |= flags; add_pending_object(revs, &commit->object, arg); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 1f3d478443..b376afc312 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -322,7 +322,7 @@ static void show_ru_info(void) static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce) { int dtype = ce_to_dtype(ce); - return is_excluded(dir, ce->name, &dtype); + return is_excluded(dir, &the_index, ce->name, &dtype); } static void show_files(struct dir_struct *dir) @@ -333,7 +333,7 @@ static void show_files(struct dir_struct *dir) if (show_others || show_killed) { if (!show_others) dir->flags |= DIR_COLLECT_KILLED_ONLY; - fill_directory(dir, &pathspec); + fill_directory(dir, &the_index, &pathspec); if (show_others) show_other_files(dir); if (show_killed) @@ -433,14 +433,14 @@ static int get_common_prefix_len(const char *common_prefix) void overlay_tree_on_cache(const char *tree_name, const char *prefix) { struct tree *tree; - unsigned char sha1[20]; + struct object_id oid; struct pathspec pathspec; struct cache_entry *last_stage0 = NULL; int i; - if (get_sha1(tree_name, sha1)) + if (get_oid(tree_name, &oid)) die("tree-ish %s not found.", tree_name); - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(&oid); if (!tree) die("bad tree-ish %s", tree_name); diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index d7ebeb4ce6..ee7b293b11 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -119,7 +119,7 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base, int cmd_ls_tree(int argc, const char **argv, const char *prefix) { - unsigned char sha1[20]; + struct object_id oid; struct tree *tree; int i, full_tree = 0; const struct option ls_tree_options[] = { @@ -164,7 +164,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) if (argc < 1) usage_with_options(ls_tree_usage, ls_tree_options); - if (get_sha1(argv[0], sha1)) + if (get_oid(argv[0], &oid)) die("Not a valid object name %s", argv[0]); /* @@ -180,7 +180,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) for (i = 0; i < pathspec.nr; i++) pathspec.items[i].nowildcard_len = pathspec.items[i].len; pathspec.has_wildcard = 0; - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(&oid); if (!tree) die("not a tree object"); return !!read_tree_recursive(tree, "", 0, 0, &pathspec, show_tree, NULL); diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index 30681681c1..664400b816 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, int allow_bare, do { peek = fgetc(f); + if (peek == EOF) { + if (f == stdin) + /* empty stdin is OK */ + ret = skip; + else { + fclose(f); + error(_("empty mbox: '%s'"), file); + } + goto out; + } } while (isspace(peek)); ungetc(peek, f); diff --git a/builtin/merge-base.c b/builtin/merge-base.c index cfe2a796f8..0c36a70ad8 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -41,7 +41,7 @@ static struct commit *get_commit_reference(const char *arg) if (get_oid(arg, &revkey)) die("Not a valid object name %s", arg); - r = lookup_commit_reference(revkey.hash); + r = lookup_commit_reference(&revkey); if (!r) die("Not a valid commit name %s", arg); @@ -120,7 +120,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs) if (is_null_oid(oid)) return; - commit = lookup_commit(oid->hash); + commit = lookup_commit(oid); if (!commit || (commit->object.flags & TMP_MARK) || parse_commit(commit)) @@ -132,7 +132,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs) } static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *ident, unsigned long timestamp, + const char *ident, timestamp_t timestamp, int tz, const char *message, void *cbdata) { struct rev_collect *revs = cbdata; @@ -168,7 +168,7 @@ static int handle_fork_point(int argc, const char **argv) if (get_oid(commitname, &oid)) die("Not a valid object name: '%s'", commitname); - derived = lookup_commit_reference(oid.hash); + derived = lookup_commit_reference(&oid); memset(&revs, 0, sizeof(revs)); revs.initial = 1; for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 5b7ab9b967..bad6735c76 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -161,14 +161,14 @@ static int both_empty(struct name_entry *a, struct name_entry *b) return !(a->oid || b->oid); } -static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsigned char *sha1, const char *path) +static struct merge_list *create_entry(unsigned stage, unsigned mode, const struct object_id *oid, const char *path) { struct merge_list *res = xcalloc(1, sizeof(*res)); res->stage = stage; res->path = path; res->mode = mode; - res->blob = lookup_blob(sha1); + res->blob = lookup_blob(oid); return res; } @@ -188,8 +188,8 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s return; path = traverse_path(info, result); - orig = create_entry(2, ours->mode, ours->oid->hash, path); - final = create_entry(0, result->mode, result->oid->hash, path); + orig = create_entry(2, ours->mode, ours->oid, path); + final = create_entry(0, result->mode, result->oid, path); final->link = orig; @@ -239,7 +239,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info path = entry->path; else path = traverse_path(info, n); - link = create_entry(stage, n->mode, n->oid->hash, path); + link = create_entry(stage, n->mode, n->oid, path); link->link = entry; return link; } diff --git a/builtin/merge.c b/builtin/merge.c index 703827f006..a4a098f40f 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -605,13 +605,13 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head, opts.verbose_update = 1; opts.trivial_merges_only = 1; opts.merge = 1; - trees[nr_trees] = parse_tree_indirect(common->hash); + trees[nr_trees] = parse_tree_indirect(common); if (!trees[nr_trees++]) return -1; - trees[nr_trees] = parse_tree_indirect(head->hash); + trees[nr_trees] = parse_tree_indirect(head); if (!trees[nr_trees++]) return -1; - trees[nr_trees] = parse_tree_indirect(one->hash); + trees[nr_trees] = parse_tree_indirect(one); if (!trees[nr_trees++]) return -1; opts.fn = threeway_merge; @@ -1123,7 +1123,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (!branch || is_null_oid(&head_oid)) head_commit = NULL; else - head_commit = lookup_commit_or_die(head_oid.hash, "HEAD"); + head_commit = lookup_commit_or_die(&head_oid, "HEAD"); init_diff_ui_defaults(); git_config(git_merge_config, NULL); @@ -1372,8 +1372,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) goto done; } - if (checkout_fast_forward(head_commit->object.oid.hash, - commit->object.oid.hash, + if (checkout_fast_forward(&head_commit->object.oid, + &commit->object.oid, overwrite_ignore)) { ret = 1; goto done; diff --git a/builtin/mktree.c b/builtin/mktree.c index de9b40fc63..da0fd8cd70 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss unsigned mode; enum object_type mode_type; /* object type derived from mode */ enum object_type obj_type; /* object type derived from sha */ - char *path; + char *path, *to_free = NULL; unsigned char sha1[20]; ptr = buf; @@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss struct strbuf p_uq = STRBUF_INIT; if (unquote_c_style(&p_uq, path, NULL)) die("invalid quoting"); - path = strbuf_detach(&p_uq, NULL); + path = to_free = strbuf_detach(&p_uq, NULL); } /* @@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss } append_to_tree(mode, sha1, path); + free(to_free); } int cmd_mktree(int ac, const char **av, const char *prefix) diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 92a5d8a5d2..663e26ebbd 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -10,9 +10,10 @@ typedef struct rev_name { const char *tip_name; - unsigned long taggerdate; + timestamp_t taggerdate; int generation; int distance; + int from_tag; } rev_name; static long cutoff = LONG_MAX; @@ -20,14 +21,53 @@ static long cutoff = LONG_MAX; /* How many generations are maximally preferred over _one_ merge traversal? */ #define MERGE_TRAVERSAL_WEIGHT 65535 +static int is_better_name(struct rev_name *name, + const char *tip_name, + timestamp_t taggerdate, + int generation, + int distance, + int from_tag) +{ + /* + * When comparing names based on tags, prefer names + * based on the older tag, even if it is farther away. + */ + if (from_tag && name->from_tag) + return (name->taggerdate > taggerdate || + (name->taggerdate == taggerdate && + name->distance > distance)); + + /* + * We know that at least one of them is a non-tag at this point. + * favor a tag over a non-tag. + */ + if (name->from_tag != from_tag) + return from_tag; + + /* + * We are now looking at two non-tags. Tiebreak to favor + * shorter hops. + */ + if (name->distance != distance) + return name->distance > distance; + + /* ... or tiebreak to favor older date */ + if (name->taggerdate != taggerdate) + return name->taggerdate > taggerdate; + + /* keep the current one if we cannot decide */ + return 0; +} + static void name_rev(struct commit *commit, - const char *tip_name, unsigned long taggerdate, - int generation, int distance, + const char *tip_name, timestamp_t taggerdate, + int generation, int distance, int from_tag, int deref) { struct rev_name *name = (struct rev_name *)commit->util; struct commit_list *parents; int parent_number = 1; + char *to_free = NULL; parse_commit(commit); @@ -35,7 +75,7 @@ static void name_rev(struct commit *commit, return; if (deref) { - tip_name = xstrfmt("%s^0", tip_name); + tip_name = to_free = xstrfmt("%s^0", tip_name); if (generation) die("generation: %d, but deref?", generation); @@ -45,16 +85,18 @@ static void name_rev(struct commit *commit, name = xmalloc(sizeof(rev_name)); commit->util = name; goto copy_data; - } else if (name->taggerdate > taggerdate || - (name->taggerdate == taggerdate && - name->distance > distance)) { + } else if (is_better_name(name, tip_name, taggerdate, + generation, distance, from_tag)) { copy_data: name->tip_name = tip_name; name->taggerdate = taggerdate; name->generation = generation; name->distance = distance; - } else + name->from_tag = from_tag; + } else { + free(to_free); return; + } for (parents = commit->parents; parents; @@ -72,10 +114,12 @@ static void name_rev(struct commit *commit, parent_number); name_rev(parents->item, new_name, taggerdate, 0, - distance + MERGE_TRAVERSAL_WEIGHT, 0); + distance + MERGE_TRAVERSAL_WEIGHT, + from_tag, 0); } else { name_rev(parents->item, tip_name, taggerdate, - generation + 1, distance + 1, 0); + generation + 1, distance + 1, + from_tag, 0); } } } @@ -114,7 +158,7 @@ struct name_ref_data { static struct tip_table { struct tip_table_entry { - unsigned char sha1[20]; + struct object_id oid; const char *refname; } *table; int nr; @@ -122,13 +166,13 @@ static struct tip_table { int sorted; } tip_table; -static void add_to_tip_table(const unsigned char *sha1, const char *refname, +static void add_to_tip_table(const struct object_id *oid, const char *refname, int shorten_unambiguous) { refname = name_ref_abbrev(refname, shorten_unambiguous); ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc); - hashcpy(tip_table.table[tip_table.nr].sha1, sha1); + oidcpy(&tip_table.table[tip_table.nr].oid, oid); tip_table.table[tip_table.nr].refname = xstrdup(refname); tip_table.nr++; tip_table.sorted = 0; @@ -137,16 +181,16 @@ static void add_to_tip_table(const unsigned char *sha1, const char *refname, static int tipcmp(const void *a_, const void *b_) { const struct tip_table_entry *a = a_, *b = b_; - return hashcmp(a->sha1, b->sha1); + return oidcmp(&a->oid, &b->oid); } static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data) { - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); struct name_ref_data *data = cb_data; int can_abbreviate_output = data->tags_only && data->name_only; int deref = 0; - unsigned long taggerdate = ULONG_MAX; + timestamp_t taggerdate = TIME_MAX; if (data->tags_only && !starts_with(path, "refs/tags/")) return 0; @@ -194,21 +238,25 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo return 0; } - add_to_tip_table(oid->hash, path, can_abbreviate_output); + add_to_tip_table(oid, path, can_abbreviate_output); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); deref = 1; taggerdate = t->date; } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; + int from_tag = starts_with(path, "refs/tags/"); + if (taggerdate == ULONG_MAX) + taggerdate = ((struct commit *)o)->date; path = name_ref_abbrev(path, can_abbreviate_output); - name_rev(commit, xstrdup(path), taggerdate, 0, 0, deref); + name_rev(commit, xstrdup(path), taggerdate, 0, 0, + from_tag, deref); } return 0; } @@ -216,7 +264,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo static const unsigned char *nth_tip_table_ent(size_t ix, void *table_) { struct tip_table_entry *table = table_; - return table[ix].sha1; + return table[ix].oid.hash; } static const char *get_exact_ref_match(const struct object *o) @@ -301,9 +349,9 @@ static void name_rev_line(char *p, struct name_ref_data *data) #define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f')) if (!ishex(*p)) forty = 0; - else if (++forty == 40 && + else if (++forty == GIT_SHA1_HEXSZ && !ishex(*(p+1))) { - unsigned char sha1[40]; + struct object_id oid; const char *name = NULL; char c = *(p+1); int p_len = p - p_start + 1; @@ -311,9 +359,9 @@ static void name_rev_line(char *p, struct name_ref_data *data) forty = 0; *(p+1) = 0; - if (!get_sha1(p - 39, sha1)) { + if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) { struct object *o = - lookup_object(sha1); + lookup_object(oid.hash); if (o) name = get_rev_name(o, &buf); } @@ -323,7 +371,7 @@ static void name_rev_line(char *p, struct name_ref_data *data) continue; if (data->name_only) - printf("%.*s%s", p_len - 40, p_start, name); + printf("%.*s%s", p_len - GIT_SHA1_HEXSZ, p_start, name); else printf("%.*s (%s)", p_len, p_start, name); p_start = p + 1; @@ -374,18 +422,18 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) cutoff = 0; for (; argc; argc--, argv++) { - unsigned char sha1[20]; + struct object_id oid; struct object *object; struct commit *commit; - if (get_sha1(*argv, sha1)) { + if (get_oid(*argv, &oid)) { fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", *argv); continue; } commit = NULL; - object = parse_object(sha1); + object = parse_object(&oid); if (object) { struct object *peeled = deref_tag(object, *argv, 0); if (peeled && peeled->type == OBJ_COMMIT) diff --git a/builtin/notes.c b/builtin/notes.c index 7b891471c4..f2847c41e0 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -706,7 +706,7 @@ static int merge_commit(struct notes_merge_options *o) if (get_oid("NOTES_MERGE_PARTIAL", &oid)) die(_("failed to read ref NOTES_MERGE_PARTIAL")); - else if (!(partial = lookup_commit_reference(oid.hash))) + else if (!(partial = lookup_commit_reference(&oid))) die(_("could not find commit from NOTES_MERGE_PARTIAL.")); else if (parse_commit(partial)) die(_("could not parse commit from NOTES_MERGE_PARTIAL.")); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0fe35d1b5a..80439047aa 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written; static int non_empty; static int reuse_delta = 1, reuse_object = 1; static int keep_unreachable, unpack_unreachable, include_tag; -static unsigned long unpack_unreachable_expiration; +static timestamp_t unpack_unreachable_expiration; static int pack_loose_unreachable; static int local; static int have_non_local_packs; @@ -106,12 +106,14 @@ static void *get_delta(struct object_entry *entry) void *buf, *base_buf, *delta_buf; enum object_type type; - buf = read_sha1_file(entry->idx.sha1, &type, &size); + buf = read_sha1_file(entry->idx.oid.hash, &type, &size); if (!buf) - die("unable to read %s", sha1_to_hex(entry->idx.sha1)); - base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size); + die("unable to read %s", oid_to_hex(&entry->idx.oid)); + base_buf = read_sha1_file(entry->delta->idx.oid.hash, &type, + &base_size); if (!base_buf) - die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1)); + die("unable to read %s", + oid_to_hex(&entry->delta->idx.oid)); delta_buf = diff_delta(base_buf, base_size, buf, size, &delta_size, 0); if (!delta_buf || delta_size != entry->delta_size) @@ -249,12 +251,14 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent if (!usable_delta) { if (entry->type == OBJ_BLOB && entry->size > big_file_threshold && - (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL) + (st = open_istream(entry->idx.oid.hash, &type, &size, NULL)) != NULL) buf = NULL; else { - buf = read_sha1_file(entry->idx.sha1, &type, &size); + buf = read_sha1_file(entry->idx.oid.hash, &type, + &size); if (!buf) - die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1)); + die(_("unable to read %s"), + oid_to_hex(&entry->idx.oid)); } /* * make sure no cached delta data remains from a @@ -322,7 +326,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent return 0; } sha1write(f, header, hdrlen); - sha1write(f, entry->delta->idx.sha1, 20); + sha1write(f, entry->delta->idx.oid.hash, 20); hdrlen += 20; } else { if (limit && hdrlen + datalen + 20 >= limit) { @@ -334,7 +338,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent sha1write(f, header, hdrlen); } if (st) { - datalen = write_large_blob_data(st, f, entry->idx.sha1); + datalen = write_large_blob_data(st, f, entry->idx.oid.hash); close_istream(st); } else { sha1write(f, buf, datalen); @@ -369,7 +373,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry, datalen = revidx[1].offset - offset; if (!pack_to_stdout && p->index_version > 1 && check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) { - error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1)); + error("bad packed object CRC for %s", + oid_to_hex(&entry->idx.oid)); unuse_pack(&w_curs); return write_no_reuse_object(f, entry, limit, usable_delta); } @@ -379,7 +384,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry, if (!pack_to_stdout && p->index_version == 1 && check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) { - error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1)); + error("corrupt packed object for %s", + oid_to_hex(&entry->idx.oid)); unuse_pack(&w_curs); return write_no_reuse_object(f, entry, limit, usable_delta); } @@ -404,7 +410,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry, return 0; } sha1write(f, header, hdrlen); - sha1write(f, entry->delta->idx.sha1, 20); + sha1write(f, entry->delta->idx.oid.hash, 20); hdrlen += 20; reused_delta++; } else { @@ -509,7 +515,7 @@ static enum write_one_status write_one(struct sha1file *f, recursing = (e->idx.offset == 1); if (recursing) { warning("recursive delta detected for object %s", - sha1_to_hex(e->idx.sha1)); + oid_to_hex(&e->idx.oid)); return WRITE_ONE_RECURSIVE; } else if (e->idx.offset || e->preferred_base) { /* offset is non zero if object is written already. */ @@ -1432,7 +1438,7 @@ static void check_object(struct object_entry *entry) ofs += 1; if (!ofs || MSB(ofs, 7)) { error("delta base offset overflow in pack for %s", - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); goto give_up; } c = buf[used_0++]; @@ -1441,7 +1447,7 @@ static void check_object(struct object_entry *entry) ofs = entry->in_pack_offset - ofs; if (ofs <= 0 || ofs >= entry->in_pack_offset) { error("delta base offset out of bound for %s", - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); goto give_up; } if (reuse_delta && !entry->preferred_base) { @@ -1498,7 +1504,7 @@ static void check_object(struct object_entry *entry) unuse_pack(&w_curs); } - entry->type = sha1_object_info(entry->idx.sha1, &entry->size); + entry->type = sha1_object_info(entry->idx.oid.hash, &entry->size); /* * The error condition is checked in prepare_pack(). This is * to permit a missing preferred base object to be ignored @@ -1514,7 +1520,7 @@ static int pack_offset_sort(const void *_a, const void *_b) /* avoid filesystem trashing with loose objects */ if (!a->in_pack && !b->in_pack) - return hashcmp(a->idx.sha1, b->idx.sha1); + return oidcmp(&a->idx.oid, &b->idx.oid); if (a->in_pack < b->in_pack) return -1; @@ -1560,7 +1566,8 @@ static void drop_reused_delta(struct object_entry *entry) * And if that fails, the error will be recorded in entry->type * and dealt with in prepare_pack(). */ - entry->type = sha1_object_info(entry->idx.sha1, &entry->size); + entry->type = sha1_object_info(entry->idx.oid.hash, + &entry->size); } } @@ -1852,26 +1859,29 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, /* Load data if not already done */ if (!trg->data) { read_lock(); - trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz); + trg->data = read_sha1_file(trg_entry->idx.oid.hash, &type, + &sz); read_unlock(); if (!trg->data) die("object %s cannot be read", - sha1_to_hex(trg_entry->idx.sha1)); + oid_to_hex(&trg_entry->idx.oid)); if (sz != trg_size) die("object %s inconsistent object length (%lu vs %lu)", - sha1_to_hex(trg_entry->idx.sha1), sz, trg_size); + oid_to_hex(&trg_entry->idx.oid), sz, + trg_size); *mem_usage += sz; } if (!src->data) { read_lock(); - src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz); + src->data = read_sha1_file(src_entry->idx.oid.hash, &type, + &sz); read_unlock(); if (!src->data) { if (src_entry->preferred_base) { static int warned = 0; if (!warned++) warning("object %s cannot be read", - sha1_to_hex(src_entry->idx.sha1)); + oid_to_hex(&src_entry->idx.oid)); /* * Those objects are not included in the * resulting pack. Be resilient and ignore @@ -1881,11 +1891,12 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, return 0; } die("object %s cannot be read", - sha1_to_hex(src_entry->idx.sha1)); + oid_to_hex(&src_entry->idx.oid)); } if (sz != src_size) die("object %s inconsistent object length (%lu vs %lu)", - sha1_to_hex(src_entry->idx.sha1), sz, src_size); + oid_to_hex(&src_entry->idx.oid), sz, + src_size); *mem_usage += sz; } if (!src->index) { @@ -2337,7 +2348,7 @@ static void add_tag_chain(const struct object_id *oid) if (packlist_find(&to_pack, oid->hash, NULL)) return; - tag = lookup_tag(oid->hash); + tag = lookup_tag(oid); while (1) { if (!tag || parse_tag(tag) || !tag->tagged) die("unable to pack objects reachable from tag %s", @@ -2406,7 +2417,7 @@ static void prepare_pack(int window, int depth) nr_deltas++; if (entry->type < 0) die("unable to get type of object %s", - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); } else { if (entry->type < 0) { /* @@ -2675,7 +2686,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1) static struct oid_array recent_objects; static int loosened_object_can_be_discarded(const struct object_id *oid, - unsigned long mtime) + timestamp_t mtime) { if (!unpack_unreachable_expiration) return 0; @@ -2717,7 +2728,11 @@ static void loosen_unused_packed_objects(struct rev_info *revs) */ static int pack_options_allow_reuse(void) { - return pack_to_stdout && allow_ofs_delta; + return pack_to_stdout && + allow_ofs_delta && + !ignore_packed_keep && + (!local || !have_non_local_packs) && + !incremental; } static int get_object_list_from_bitmap(struct rev_info *revs) @@ -2777,10 +2792,10 @@ static void get_object_list(int ac, const char **av) continue; } if (starts_with(line, "--shallow ")) { - unsigned char sha1[20]; - if (get_sha1_hex(line + 10, sha1)) + struct object_id oid; + if (get_oid_hex(line + 10, &oid)) die("not an SHA-1 '%s'", line + 10); - register_shallow(sha1); + register_shallow(&oid); use_bitmap_index = 0; continue; } diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index 72c815844d..cb1df1c761 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -442,6 +442,7 @@ static void minimize(struct pack_list **min) /* return if there are no objects missing from the unique set */ if (missing->size == 0) { *min = unique; + free(missing); return; } diff --git a/builtin/prune.c b/builtin/prune.c index 42633e0c6e..f0e2bff04c 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -13,7 +13,7 @@ static const char * const prune_usage[] = { }; static int show_only; static int verbose; -static unsigned long expire; +static timestamp_t expire; static int show_progress = -1; static int prune_tmp_file(const char *fullpath) @@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) }; char *s; - expire = ULONG_MAX; + expire = TIME_MAX; save_commit_buffer = 0; check_replace_refs = 0; ref_paranoia = 1; @@ -123,11 +123,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix) die(_("cannot prune in a precious-objects repo")); while (argc--) { - unsigned char sha1[20]; + struct object_id oid; const char *name = *argv++; - if (!get_sha1(name, sha1)) { - struct object *object = parse_object_or_die(sha1, name); + if (!get_oid(name, &oid)) { + struct object *object = parse_object_or_die(&oid, + name); add_pending_object(&revs, object, ""); } else diff --git a/builtin/pull.c b/builtin/pull.c index dd1a4a94e4..318c273eb3 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -523,7 +523,7 @@ static int pull_into_void(const struct object_id *merge_head, * index/worktree changes that the user already made on the unborn * branch. */ - if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0)) + if (checkout_fast_forward(&empty_tree_oid, merge_head, 0)) return 1; if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR)) @@ -698,10 +698,10 @@ static int get_octopus_merge_base(struct object_id *merge_base, { struct commit_list *revs = NULL, *result; - commit_list_insert(lookup_commit_reference(curr_head->hash), &revs); - commit_list_insert(lookup_commit_reference(merge_head->hash), &revs); + commit_list_insert(lookup_commit_reference(curr_head), &revs); + commit_list_insert(lookup_commit_reference(merge_head), &revs); if (!is_null_oid(fork_point)) - commit_list_insert(lookup_commit_reference(fork_point->hash), &revs); + commit_list_insert(lookup_commit_reference(fork_point), &revs); result = reduce_heads(get_octopus_merge_bases(revs)); free_commit_list(revs); @@ -839,7 +839,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) "fast-forwarding your working tree from\n" "commit %s."), oid_to_hex(&orig_head)); - if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0)) + if (checkout_fast_forward(&orig_head, &curr_head, 0)) die(_("Cannot fast-forward your working tree.\n" "After making sure that you saved anything precious from\n" "$ git diff %s\n" @@ -865,9 +865,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix) struct commit_list *list = NULL; struct commit *merge_head, *head; - head = lookup_commit_reference(orig_head.hash); + head = lookup_commit_reference(&orig_head); commit_list_insert(head, &list); - merge_head = lookup_commit_reference(merge_heads.oid[0].hash); + merge_head = lookup_commit_reference(&merge_heads.oid[0]); if (is_descendant_of(merge_head, list)) { /* we can fast-forward this without invoking rebase */ opt_ff = "--ff-only"; diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 23e212ee8c..78d3193659 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -23,13 +23,13 @@ static int read_empty; static struct tree *trees[MAX_UNPACK_TREES]; static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; -static int list_tree(unsigned char *sha1) +static int list_tree(struct object_id *oid) { struct tree *tree; if (nr_trees >= MAX_UNPACK_TREES) die("I cannot read more than %d trees", MAX_UNPACK_TREES); - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(oid); if (!tree) return -1; trees[nr_trees++] = tree; @@ -121,7 +121,7 @@ static struct lock_file lock_file; int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) { int i, stage = 0; - unsigned char sha1[20]; + struct object_id oid; struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; int prefix_set = 0; @@ -204,13 +204,13 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) for (i = 0; i < argc; i++) { const char *arg = argv[i]; - if (get_sha1(arg, sha1)) + if (get_oid(arg, &oid)) die("Not a valid object name %s", arg); - if (list_tree(sha1) < 0) + if (list_tree(&oid) < 0) die("failed to unpack tree object %s", arg); stage++; } - if (nr_trees == 0 && !read_empty) + if (!nr_trees && !read_empty && !opts.merge) warning("read-tree: emptying the index with no arguments is deprecated; use --empty"); else if (nr_trees > 0 && read_empty) die("passing trees as arguments contradicts --empty"); @@ -226,9 +226,10 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) setup_work_tree(); if (opts.merge) { - if (stage < 2) - die("just how do you expect me to merge %d trees?", stage-1); switch (stage - 1) { + case 0: + die("you must specify at least one tree to merge"); + break; case 1: opts.fn = opts.prefix ? bind_merge : oneway_merge; break; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index f96834f42c..b1706a5731 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -78,7 +78,7 @@ static const char *NONCE_OK = "OK"; static const char *NONCE_SLOP = "SLOP"; static const char *nonce_status; static long nonce_stamp_slop; -static unsigned long nonce_stamp_slop_limit; +static timestamp_t nonce_stamp_slop_limit; static struct ref_transaction *transaction; static enum { @@ -454,17 +454,17 @@ static void hmac_sha1(unsigned char *out, git_SHA1_Final(out, &ctx); } -static char *prepare_push_cert_nonce(const char *path, unsigned long stamp) +static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp) { struct strbuf buf = STRBUF_INIT; unsigned char sha1[20]; - strbuf_addf(&buf, "%s:%lu", path, stamp); + strbuf_addf(&buf, "%s:%"PRItime, path, stamp); hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));; strbuf_release(&buf); /* RFC 2104 5. HMAC-SHA1-80 */ - strbuf_addf(&buf, "%lu-%.*s", stamp, 20, sha1_to_hex(sha1)); + strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, 20, sha1_to_hex(sha1)); return strbuf_detach(&buf, NULL); } @@ -473,7 +473,8 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp) * after dropping "_commit" from its name and possibly moving it out * of commit.c */ -static char *find_header(const char *msg, size_t len, const char *key) +static char *find_header(const char *msg, size_t len, const char *key, + const char **next_line) { int key_len = strlen(key); const char *line = msg; @@ -486,6 +487,8 @@ static char *find_header(const char *msg, size_t len, const char *key) if (line + key_len < eol && !memcmp(line, key, key_len) && line[key_len] == ' ') { int offset = key_len + 1; + if (next_line) + *next_line = *eol ? eol + 1 : eol; return xmemdupz(line + offset, (eol - line) - offset); } line = *eol ? eol + 1 : NULL; @@ -495,8 +498,8 @@ static char *find_header(const char *msg, size_t len, const char *key) static const char *check_nonce(const char *buf, size_t len) { - char *nonce = find_header(buf, len, "nonce"); - unsigned long stamp, ostamp; + char *nonce = find_header(buf, len, "nonce", NULL); + timestamp_t stamp, ostamp; char *bohmac, *expect = NULL; const char *retval = NONCE_BAD; @@ -534,7 +537,7 @@ static const char *check_nonce(const char *buf, size_t len) retval = NONCE_BAD; goto leave; } - stamp = strtoul(nonce, &bohmac, 10); + stamp = parse_timestamp(nonce, &bohmac, 10); if (bohmac == nonce || bohmac[0] != '-') { retval = NONCE_BAD; goto leave; @@ -552,7 +555,7 @@ static const char *check_nonce(const char *buf, size_t len) * would mean it was issued by another server with its clock * skewed in the future. */ - ostamp = strtoul(push_cert_nonce, NULL, 10); + ostamp = parse_timestamp(push_cert_nonce, NULL, 10); nonce_stamp_slop = (long)ostamp - (long)stamp; if (nonce_stamp_slop_limit && @@ -575,6 +578,45 @@ static const char *check_nonce(const char *buf, size_t len) return retval; } +/* + * Return 1 if there is no push_cert or if the push options in push_cert are + * the same as those in the argument; 0 otherwise. + */ +static int check_cert_push_options(const struct string_list *push_options) +{ + const char *buf = push_cert.buf; + int len = push_cert.len; + + char *option; + const char *next_line; + int options_seen = 0; + + int retval = 1; + + if (!len) + return 1; + + while ((option = find_header(buf, len, "push-option", &next_line))) { + len -= (next_line - buf); + buf = next_line; + options_seen++; + if (options_seen > push_options->nr + || strcmp(option, + push_options->items[options_seen - 1].string)) { + retval = 0; + goto leave; + } + free(option); + } + + if (options_seen != push_options->nr) + retval = 0; + +leave: + free(option); + return retval; +} + static void prepare_push_cert_sha1(struct child_process *proc) { static int already_done; @@ -858,7 +900,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) - register_shallow(extra.oid[i].hash); + register_shallow(&extra.oid[i]); si->shallow_ref[cmd->index] = 0; oid_array_clear(&extra); @@ -986,7 +1028,8 @@ static const char *update(struct command *cmd, struct shallow_info *si) { const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; - const char *namespaced_name, *ret; + static char *namespaced_name; + const char *ret; struct object_id *old_oid = &cmd->old_oid; struct object_id *new_oid = &cmd->new_oid; @@ -997,6 +1040,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) } strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); + free(namespaced_name); namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); if (is_ref_checked_out(namespaced_name)) { @@ -1058,8 +1102,8 @@ static const char *update(struct command *cmd, struct shallow_info *si) struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - old_object = parse_object(old_oid->hash); - new_object = parse_object(new_oid->hash); + old_object = parse_object(old_oid); + new_object = parse_object(new_oid); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || @@ -1082,7 +1126,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) if (is_null_oid(new_oid)) { struct strbuf err = STRBUF_INIT; - if (!parse_object(old_oid->hash)) { + if (!parse_object(old_oid)) { old_oid = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); @@ -1929,6 +1973,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) if (use_push_options) read_push_options(&push_options); + if (!check_cert_push_options(&push_options)) { + struct command *cmd; + for (cmd = commands; cmd; cmd = cmd->next) + cmd->error_string = "inconsistent push options"; + } prepare_shallow_info(&si, &shallow); if (!si.nr_ours && !si.nr_theirs) diff --git a/builtin/reflog.c b/builtin/reflog.c index 7472775778..920c16dac0 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -16,14 +16,14 @@ static const char reflog_delete_usage[] = static const char reflog_exists_usage[] = "git reflog exists "; -static unsigned long default_reflog_expire; -static unsigned long default_reflog_expire_unreachable; +static timestamp_t default_reflog_expire; +static timestamp_t default_reflog_expire_unreachable; struct cmd_reflog_expire_cb { struct rev_info revs; int stalefix; - unsigned long expire_total; - unsigned long expire_unreachable; + timestamp_t expire_total; + timestamp_t expire_unreachable; int recno; }; @@ -55,14 +55,14 @@ struct collect_reflog_cb { #define STUDYING (1u<<11) #define REACHABLE (1u<<12) -static int tree_is_complete(const unsigned char *sha1) +static int tree_is_complete(const struct object_id *oid) { struct tree_desc desc; struct name_entry entry; int complete; struct tree *tree; - tree = lookup_tree(sha1); + tree = lookup_tree(oid); if (!tree) return 0; if (tree->object.flags & SEEN) @@ -73,7 +73,7 @@ static int tree_is_complete(const unsigned char *sha1) if (!tree->buffer) { enum object_type type; unsigned long size; - void *data = read_sha1_file(sha1, &type, &size); + void *data = read_sha1_file(oid->hash, &type, &size); if (!data) { tree->object.flags |= INCOMPLETE; return 0; @@ -85,7 +85,7 @@ static int tree_is_complete(const unsigned char *sha1) complete = 1; while (tree_entry(&desc, &entry)) { if (!has_sha1_file(entry.oid->hash) || - (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid->hash))) { + (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid))) { tree->object.flags |= INCOMPLETE; complete = 0; } @@ -126,7 +126,7 @@ static int commit_is_complete(struct commit *commit) struct commit_list *parent; c = (struct commit *)study.objects[--study.nr].item; - if (!c->object.parsed && !parse_object(c->object.oid.hash)) + if (!c->object.parsed && !parse_object(&c->object.oid)) c->object.flags |= INCOMPLETE; if (c->object.flags & INCOMPLETE) { @@ -152,7 +152,7 @@ static int commit_is_complete(struct commit *commit) for (i = 0; i < found.nr; i++) { struct commit *c = (struct commit *)found.objects[i].item; - if (!tree_is_complete(c->tree->object.oid.hash)) { + if (!tree_is_complete(&c->tree->object.oid)) { is_incomplete = 1; c->object.flags |= INCOMPLETE; } @@ -186,13 +186,13 @@ static int commit_is_complete(struct commit *commit) return !is_incomplete; } -static int keep_entry(struct commit **it, unsigned char *sha1) +static int keep_entry(struct commit **it, struct object_id *oid) { struct commit *commit; - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return 1; - commit = lookup_commit_reference_gently(sha1, 1); + commit = lookup_commit_reference_gently(oid, 1); if (!commit) return 0; @@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1) static void mark_reachable(struct expire_reflog_policy_cb *cb) { struct commit_list *pending; - unsigned long expire_limit = cb->mark_limit; + timestamp_t expire_limit = cb->mark_limit; struct commit_list *leftover = NULL; for (pending = cb->mark_list; pending; pending = pending->next) @@ -251,17 +251,17 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb) cb->mark_list = leftover; } -static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1) +static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid) { /* * We may or may not have the commit yet - if not, look it * up using the supplied sha1. */ if (!commit) { - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return 0; - commit = lookup_commit_reference_gently(sha1, 1); + commit = lookup_commit_reference_gently(oid, 1); /* Not a commit -- keep it */ if (!commit) @@ -283,8 +283,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit /* * Return true iff the specified reflog entry should be expired. */ -static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, - const char *email, unsigned long timestamp, int tz, +static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; @@ -295,13 +295,13 @@ static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, old = new = NULL; if (cb->cmd.stalefix && - (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1))) + (!keep_entry(&old, ooid) || !keep_entry(&new, noid))) return 1; if (timestamp < cb->cmd.expire_unreachable) { if (cb->unreachable_expire_kind == UE_ALWAYS) return 1; - if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1)) + if (unreachable(cb, old, ooid) || unreachable(cb, new, noid)) return 1; } @@ -318,7 +318,7 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid, struct commit *tip_commit; if (flags & REF_ISSYMREF) return 0; - tip_commit = lookup_commit_reference_gently(oid->hash, 1); + tip_commit = lookup_commit_reference_gently(oid, 1); if (!tip_commit) return 0; commit_list_insert(tip_commit, list); @@ -326,7 +326,7 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid, } static void reflog_expiry_prepare(const char *refname, - const unsigned char *sha1, + const struct object_id *oid, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; @@ -335,7 +335,7 @@ static void reflog_expiry_prepare(const char *refname, cb->tip_commit = NULL; cb->unreachable_expire_kind = UE_HEAD; } else { - cb->tip_commit = lookup_commit_reference_gently(sha1, 1); + cb->tip_commit = lookup_commit_reference_gently(oid, 1); if (!cb->tip_commit) cb->unreachable_expire_kind = UE_ALWAYS; else @@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus static struct reflog_expire_cfg { struct reflog_expire_cfg *next; - unsigned long expire_total; - unsigned long expire_unreachable; + timestamp_t expire_total; + timestamp_t expire_unreachable; char pattern[FLEX_ARRAY]; } *reflog_expire_cfg, **reflog_expire_cfg_tail; @@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len) return ent; } -static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire) +static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire) { if (!value) return config_error_nonbool(var); @@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb) { const char *pattern, *key; int pattern_len; - unsigned long expire; + timestamp_t expire; int slot; struct reflog_expire_cfg *ent; @@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) { struct expire_reflog_policy_cb cb; - unsigned long now = time(NULL); + timestamp_t now = time(NULL); int i, status, do_all; int explicit_expiry = 0; unsigned int flags = 0; @@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) } static int count_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; diff --git a/builtin/repack.c b/builtin/repack.c index 677bc7c81a..38ba4ef825 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -155,6 +155,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) int keep_unreachable = 0; const char *window = NULL, *window_memory = NULL; const char *depth = NULL; + const char *threads = NULL; const char *max_pack_size = NULL; int no_reuse_delta = 0, no_reuse_object = 0; int no_update_server_info = 0; @@ -190,6 +191,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) N_("same as the above, but limit memory size instead of entries count")), OPT_STRING(0, "depth", &depth, N_("n"), N_("limits the maximum delta depth")), + OPT_STRING(0, "threads", &threads, N_("n"), + N_("limits the maximum number of threads")), OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"), N_("maximum size of each packfile")), OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects, @@ -234,6 +237,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory); if (depth) argv_array_pushf(&cmd.args, "--depth=%s", depth); + if (threads) + argv_array_pushf(&cmd.args, "--threads=%s", threads); if (max_pack_size) argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size); if (no_reuse_delta) diff --git a/builtin/replace.c b/builtin/replace.c index ab17668f43..c921bc976f 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -328,7 +328,7 @@ static void replace_parents(struct strbuf *buf, int argc, const char **argv) struct object_id oid; if (get_oid(argv[i], &oid) < 0) die(_("Not a valid object name: '%s'"), argv[i]); - lookup_commit_or_die(oid.hash, argv[i]); + lookup_commit_or_die(&oid, argv[i]); strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid)); } @@ -355,7 +355,7 @@ static void check_one_mergetag(struct commit *commit, int i; hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash); - tag = lookup_tag(tag_oid.hash); + tag = lookup_tag(&tag_oid); if (!tag) die(_("bad mergetag in commit '%s'"), ref); if (parse_tag_buffer(tag, extra->value, extra->len)) @@ -394,7 +394,7 @@ static int create_graft(int argc, const char **argv, int force) if (get_oid(old_ref, &old) < 0) die(_("Not a valid object name: '%s'"), old_ref); - commit = lookup_commit_or_die(old.hash, old_ref); + commit = lookup_commit_or_die(&old, old_ref); buffer = get_commit_buffer(commit, &size); strbuf_add(&buf, buffer, size); diff --git a/builtin/reset.c b/builtin/reset.c index 5db2adc4c4..430602d102 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -21,6 +21,27 @@ #include "parse-options.h" #include "unpack-trees.h" #include "cache-tree.h" +#include "submodule.h" +#include "submodule-config.h" + +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; + +static int option_parse_recurse_submodules(const struct option *opt, + const char *arg, int unset) +{ + if (unset) { + recurse_submodules = RECURSE_SUBMODULES_OFF; + return 0; + } + if (arg) + recurse_submodules = + parse_update_recurse_submodules_arg(opt->long_name, + arg); + else + recurse_submodules = RECURSE_SUBMODULES_ON; + + return 0; +} static const char * const git_reset_usage[] = { N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] []"), @@ -84,7 +105,7 @@ static int reset_index(const struct object_id *oid, int reset_type, int quiet) return -1; if (reset_type == MIXED || reset_type == HARD) { - tree = parse_tree_indirect(oid->hash); + tree = parse_tree_indirect(oid); prime_cache_tree(&the_index, tree); } @@ -154,7 +175,7 @@ static int read_from_tree(const struct pathspec *pathspec, opt.format_callback = update_index_from_diff; opt.format_callback_data = &intent_to_add; - if (do_diff_cache(tree_oid->hash, &opt)) + if (do_diff_cache(tree_oid, &opt)) return 1; diffcore_std(&opt); diff_flush(&opt); @@ -282,6 +303,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix) N_("reset HEAD, index and working tree"), MERGE), OPT_SET_INT(0, "keep", &reset_type, N_("reset HEAD but keep local changes"), KEEP), + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, + "reset", "control recursive updating of submodules", + PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")), OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that removed paths will be added later")), @@ -294,6 +318,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix) PARSE_OPT_KEEP_DASHDASH); parse_args(&pathspec, argv, prefix, patch_mode, &rev); + if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) { + gitmodules_config(); + git_config(submodule_config, NULL); + set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON); + } + unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash); if (unborn) { /* reset on unborn branch: treat as reset to empty tree */ @@ -302,7 +332,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) struct commit *commit; if (get_sha1_committish(rev, oid.hash)) die(_("Failed to resolve '%s' as a valid revision."), rev); - commit = lookup_commit_reference(oid.hash); + commit = lookup_commit_reference(&oid); if (!commit) die(_("Could not parse object '%s'."), rev); oidcpy(&oid, &commit->object.oid); @@ -310,7 +340,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) struct tree *tree; if (get_sha1_treeish(rev, oid.hash)) die(_("Failed to resolve '%s' as a valid tree."), rev); - tree = parse_tree_indirect(oid.hash); + tree = parse_tree_indirect(&oid); if (!tree) die(_("Could not parse object '%s'."), rev); oidcpy(&oid, &tree->object.oid); @@ -379,7 +409,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) update_ref_status = reset_refs(rev, &oid); if (reset_type == HARD && !update_ref_status && !quiet) - print_new_head_line(lookup_commit_reference(oid.hash)); + print_new_head_line(lookup_commit_reference(&oid)); } if (!pathspec.nr) remove_branch_state(); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index bcf77f0b8a..718c6059c9 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data) } if (info->show_timestamp) - printf("%lu ", commit->date); + printf("%"PRItime" ", commit->date); if (info->header_prefix) fputs(info->header_prefix, stdout); @@ -181,7 +181,7 @@ static void finish_object(struct object *obj, const char *name, void *cb_data) if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) die("missing blob object '%s'", oid_to_hex(&obj->oid)); if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) - parse_object(obj->oid.hash); + parse_object(&obj->oid); } static void show_object(struct object *obj, const char *name, void *cb_data) diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 0513330910..efdc14473b 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -121,7 +121,7 @@ static void show_with_type(int type, const char *arg) } /* Output a revision, only if filter allows it */ -static void show_rev(int type, const unsigned char *sha1, const char *name) +static void show_rev(int type, const struct object_id *oid, const char *name) { if (!(filter & DO_REVS)) return; @@ -129,10 +129,10 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) if ((symbolic || abbrev_ref) && name) { if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) { - unsigned char discard[20]; + struct object_id discard; char *full; - switch (dwim_ref(name, strlen(name), discard, &full)) { + switch (dwim_ref(name, strlen(name), discard.hash, &full)) { case 0: /* * Not found -- not a ref. We could @@ -158,9 +158,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) } } else if (abbrev) - show_with_type(type, find_unique_abbrev(sha1, abbrev)); + show_with_type(type, find_unique_abbrev(oid->hash, abbrev)); else - show_with_type(type, sha1_to_hex(sha1)); + show_with_type(type, oid_to_hex(oid)); } /* Output a flag, only if filter allows it. */ @@ -180,11 +180,11 @@ static int show_default(void) const char *s = def; if (s) { - unsigned char sha1[20]; + struct object_id oid; def = NULL; - if (!get_sha1(s, sha1)) { - show_rev(NORMAL, sha1, s); + if (!get_oid(s, &oid)) { + show_rev(NORMAL, &oid, s); return 1; } } @@ -195,19 +195,19 @@ static int show_reference(const char *refname, const struct object_id *oid, int { if (ref_excluded(ref_excludes, refname)) return 0; - show_rev(NORMAL, oid->hash, refname); + show_rev(NORMAL, oid, refname); return 0; } static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - show_rev(REVERSED, oid->hash, refname); + show_rev(REVERSED, oid, refname); return 0; } static int show_abbrev(const struct object_id *oid, void *cb_data) { - show_rev(NORMAL, oid->hash, NULL); + show_rev(NORMAL, oid, NULL); return 0; } @@ -218,7 +218,7 @@ static void show_datestring(const char *flag, const char *datestr) /* date handling requires both flags and revs */ if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS)) return; - buffer = xstrfmt("%s%lu", flag, approxidate(datestr)); + buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr)); show(buffer); free(buffer); } @@ -242,8 +242,8 @@ static int show_file(const char *arg, int output_prefix) static int try_difference(const char *arg) { char *dotdot; - unsigned char sha1[20]; - unsigned char end[20]; + struct object_id oid; + struct object_id end; const char *next; const char *this; int symmetric; @@ -273,18 +273,18 @@ static int try_difference(const char *arg) return 0; } - if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) { - show_rev(NORMAL, end, next); - show_rev(symmetric ? NORMAL : REVERSED, sha1, this); + if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) { + show_rev(NORMAL, &end, next); + show_rev(symmetric ? NORMAL : REVERSED, &oid, this); if (symmetric) { struct commit_list *exclude; struct commit *a, *b; - a = lookup_commit_reference(sha1); - b = lookup_commit_reference(end); + a = lookup_commit_reference(&oid); + b = lookup_commit_reference(&end); exclude = get_merge_bases(a, b); while (exclude) { struct commit *commit = pop_commit(&exclude); - show_rev(REVERSED, commit->object.oid.hash, NULL); + show_rev(REVERSED, &commit->object.oid, NULL); } } *dotdot = '.'; @@ -297,7 +297,7 @@ static int try_difference(const char *arg) static int try_parent_shorthands(const char *arg) { char *dotdot; - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; struct commit_list *parents; int parent_number; @@ -327,12 +327,12 @@ static int try_parent_shorthands(const char *arg) return 0; *dotdot = 0; - if (get_sha1_committish(arg, sha1)) { + if (get_sha1_committish(arg, oid.hash)) { *dotdot = '^'; return 0; } - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (exclude_parent && exclude_parent > commit_list_count(commit->parents)) { *dotdot = '^'; @@ -340,7 +340,7 @@ static int try_parent_shorthands(const char *arg) } if (include_rev) - show_rev(NORMAL, sha1, arg); + show_rev(NORMAL, &oid, arg); for (parents = commit->parents, parent_number = 1; parents; parents = parents->next, parent_number++) { @@ -352,7 +352,7 @@ static int try_parent_shorthands(const char *arg) if (symbolic) name = xstrfmt("%s^%d", arg, parent_number); show_rev(include_parents ? NORMAL : REVERSED, - parents->item->object.oid.hash, name); + &parents->item->object.oid, name); free(name); } @@ -571,7 +571,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) int did_repo_setup = 0; int has_dashdash = 0; int output_prefix = 0; - unsigned char sha1[20]; + struct object_id oid; unsigned int flags = 0; const char *name = NULL; struct object_context unused; @@ -910,11 +910,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) name++; type = REVERSED; } - if (!get_sha1_with_context(name, flags, sha1, &unused)) { + if (!get_sha1_with_context(name, flags, oid.hash, &unused)) { if (verify) revs_count++; else - show_rev(type, sha1, name); + show_rev(type, &oid, name); continue; } if (verify) @@ -929,7 +929,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) strbuf_release(&buf); if (verify) { if (revs_count == 1) { - show_rev(type, sha1, name); + show_rev(type, &oid, name); return 0; } else if (revs_count == 0 && show_default()) return 0; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 19756595d5..4a6cc6f490 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -358,7 +358,7 @@ static void sort_ref_range(int bottom, int top) static int append_ref(const char *refname, const struct object_id *oid, int allow_dups) { - struct commit *commit = lookup_commit_reference_gently(oid->hash, 1); + struct commit *commit = lookup_commit_reference_gently(oid, 1); int i; if (!commit) @@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) base = strtoul(reflog_base, &ep, 10); if (*ep) { /* Ah, that is a date spec... */ - unsigned long at; + timestamp_t at; at = approxidate(reflog_base); read_ref_at(ref, flags, at, -1, oid.hash, NULL, NULL, NULL, &base); @@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) char *logmsg; char *nth_desc; const char *msg; - unsigned long timestamp; + timestamp_t timestamp; int tz; if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg, @@ -816,7 +816,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) MAX_REVS), MAX_REVS); if (get_sha1(ref_name[num_rev], revkey.hash)) die(_("'%s' is not a valid ref."), ref_name[num_rev]); - commit = lookup_commit_reference(revkey.hash); + commit = lookup_commit_reference(&revkey); if (!commit) die(_("cannot find commit %s (%s)"), ref_name[num_rev], oid_to_hex(&revkey)); diff --git a/builtin/tag.c b/builtin/tag.c index bdf1e88e93..1f74a56db7 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -66,7 +66,7 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con } typedef int (*each_tag_name_fn)(const char *name, const char *ref, - const unsigned char *sha1, const void *cb_data); + const struct object_id *oid, const void *cb_data); static int for_each_tag_name(const char **argv, each_tag_name_fn fn, const void *cb_data) @@ -74,17 +74,17 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn, const char **p; struct strbuf ref = STRBUF_INIT; int had_error = 0; - unsigned char sha1[20]; + struct object_id oid; for (p = argv; *p; p++) { strbuf_reset(&ref); strbuf_addf(&ref, "refs/tags/%s", *p); - if (read_ref(ref.buf, sha1)) { + if (read_ref(ref.buf, oid.hash)) { error(_("tag '%s' not found."), *p); had_error = 1; continue; } - if (fn(*p, ref.buf, sha1, cb_data)) + if (fn(*p, ref.buf, &oid, cb_data)) had_error = 1; } strbuf_release(&ref); @@ -92,16 +92,16 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn, } static int delete_tag(const char *name, const char *ref, - const unsigned char *sha1, const void *cb_data) + const struct object_id *oid, const void *cb_data) { - if (delete_ref(NULL, ref, sha1, 0)) + if (delete_ref(NULL, ref, oid->hash, 0)) return 1; - printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV)); + printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV)); return 0; } static int verify_tag(const char *name, const char *ref, - const unsigned char *sha1, const void *cb_data) + const struct object_id *oid, const void *cb_data) { int flags; const char *fmt_pretty = cb_data; @@ -110,11 +110,11 @@ static int verify_tag(const char *name, const char *ref, if (fmt_pretty) flags = GPG_VERIFY_OMIT_STATUS; - if (gpg_verify_tag(sha1, name, flags)) + if (gpg_verify_tag(oid->hash, name, flags)) return -1; if (fmt_pretty) - pretty_print_ref(name, sha1, fmt_pretty); + pretty_print_ref(name, oid->hash, fmt_pretty); return 0; } @@ -182,13 +182,13 @@ static int git_tag_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } -static void write_tag_body(int fd, const unsigned char *sha1) +static void write_tag_body(int fd, const struct object_id *oid) { unsigned long size; enum object_type type; char *buf, *sp; - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); if (!buf) return; /* skip header */ @@ -204,11 +204,11 @@ static void write_tag_body(int fd, const unsigned char *sha1) free(buf); } -static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result) +static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result) { if (sign && do_sign(buf) < 0) return error(_("unable to sign the tag")); - if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0) + if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0) return error(_("unable to write tag file")); return 0; } @@ -223,15 +223,15 @@ struct create_tag_options { } cleanup_mode; }; -static void create_tag(const unsigned char *object, const char *tag, +static void create_tag(const struct object_id *object, const char *tag, struct strbuf *buf, struct create_tag_options *opt, - unsigned char *prev, unsigned char *result) + struct object_id *prev, struct object_id *result) { enum object_type type; struct strbuf header = STRBUF_INIT; char *path = NULL; - type = sha1_object_info(object, NULL); + type = sha1_object_info(object->hash, NULL); if (type <= OBJ_NONE) die(_("bad object type.")); @@ -240,7 +240,7 @@ static void create_tag(const unsigned char *object, const char *tag, "type %s\n" "tag %s\n" "tagger %s\n\n", - sha1_to_hex(object), + oid_to_hex(object), typename(type), tag, git_committer_info(IDENT_STRICT)); @@ -254,7 +254,7 @@ static void create_tag(const unsigned char *object, const char *tag, if (fd < 0) die_errno(_("could not create file '%s'"), path); - if (!is_null_sha1(prev)) { + if (!is_null_oid(prev)) { write_tag_body(fd, prev); } else { struct strbuf buf = STRBUF_INIT; @@ -296,7 +296,7 @@ static void create_tag(const unsigned char *object, const char *tag, } } -static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb) +static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb) { enum object_type type; struct commit *c; @@ -310,17 +310,17 @@ static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb) strbuf_addstr(sb, rla); } else { strbuf_addstr(sb, "tag: tagging "); - strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV); } strbuf_addstr(sb, " ("); - type = sha1_object_info(sha1, NULL); + type = sha1_object_info(oid->hash, NULL); switch (type) { default: strbuf_addstr(sb, "object of unknown type"); break; case OBJ_COMMIT: - if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) { + if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) { subject_len = find_commit_subject(buf, &subject_start); strbuf_insert(sb, sb->len, subject_start, subject_len); } else { @@ -328,7 +328,7 @@ static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb) } free(buf); - if ((c = lookup_commit_reference(sha1)) != NULL) + if ((c = lookup_commit_reference(oid)) != NULL) strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT))); break; case OBJ_TREE: @@ -378,7 +378,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct strbuf buf = STRBUF_INIT; struct strbuf ref = STRBUF_INIT; struct strbuf reflog_msg = STRBUF_INIT; - unsigned char object[20], prev[20]; + struct object_id object, prev; const char *object_ref, *tag; struct create_tag_options opt; char *cleanup_arg = NULL; @@ -528,14 +528,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (argc > 2) die(_("too many params")); - if (get_sha1(object_ref, object)) + if (get_oid(object_ref, &object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); if (strbuf_check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); - if (read_ref(ref.buf, prev)) - hashclr(prev); + if (read_ref(ref.buf, prev.hash)) + oidclr(&prev); else if (!force) die(_("tag '%s' already exists"), tag); @@ -550,24 +550,24 @@ int cmd_tag(int argc, const char **argv, const char *prefix) else die(_("Invalid cleanup mode %s"), cleanup_arg); - create_reflog_msg(object, &reflog_msg); + create_reflog_msg(&object, &reflog_msg); if (create_tag_object) { if (force_sign_annotate && !annotate) opt.sign = 1; - create_tag(object, tag, &buf, &opt, prev, object); + create_tag(&object, tag, &buf, &opt, &prev, &object); } transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, ref.buf, object, prev, + ref_transaction_update(transaction, ref.buf, object.hash, prev.hash, create_reflog ? REF_FORCE_CREATE_REFLOG : 0, reflog_msg.buf, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); - if (force && !is_null_sha1(prev) && hashcmp(prev, object)) - printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV)); + if (force && !is_null_oid(&prev) && oidcmp(&prev, &object)) + printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV)); strbuf_release(&err); strbuf_release(&buf); diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 4532aa0831..8bc9997767 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -127,7 +127,7 @@ static void *get_data(unsigned long size) } struct delta_info { - unsigned char base_sha1[20]; + struct object_id base_oid; unsigned nr; off_t base_offset; unsigned long size; @@ -137,13 +137,13 @@ struct delta_info { static struct delta_info *delta_list; -static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1, +static void add_delta_to_list(unsigned nr, const struct object_id *base_oid, off_t base_offset, void *delta, unsigned long size) { struct delta_info *info = xmalloc(sizeof(*info)); - hashcpy(info->base_sha1, base_sha1); + oidcpy(&info->base_oid, base_oid); info->base_offset = base_offset; info->size = size; info->delta = delta; @@ -154,7 +154,7 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1, struct obj_info { off_t offset; - unsigned char sha1[20]; + struct object_id oid; struct object *obj; }; @@ -170,9 +170,9 @@ static unsigned nr_objects; */ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf) { - unsigned char sha1[20]; + struct object_id oid; - if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0) + if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0) die("failed to write object %s", oid_to_hex(&obj->oid)); obj->flags |= FLAG_WRITTEN; } @@ -237,19 +237,19 @@ static void write_object(unsigned nr, enum object_type type, void *buf, unsigned long size) { if (!strict) { - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) + if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0) die("failed to write object"); added_object(nr, type, buf, size); free(buf); obj_list[nr].obj = NULL; } else if (type == OBJ_BLOB) { struct blob *blob; - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) + if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0) die("failed to write object"); added_object(nr, type, buf, size); free(buf); - blob = lookup_blob(obj_list[nr].sha1); + blob = lookup_blob(&obj_list[nr].oid); if (blob) blob->object.flags |= FLAG_WRITTEN; else @@ -258,9 +258,10 @@ static void write_object(unsigned nr, enum object_type type, } else { struct object *obj; int eaten; - hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1); + hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash); added_object(nr, type, buf, size); - obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten); + obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf, + &eaten); if (!obj) die("invalid %s", typename(type)); add_object_buffer(obj, buf, size); @@ -296,7 +297,7 @@ static void added_object(unsigned nr, enum object_type type, struct delta_info *info; while ((info = *p) != NULL) { - if (!hashcmp(info->base_sha1, obj_list[nr].sha1) || + if (!oidcmp(&info->base_oid, &obj_list[nr].oid) || info->base_offset == obj_list[nr].offset) { *p = info->next; p = &delta_list; @@ -320,12 +321,12 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size, free(buf); } -static int resolve_against_held(unsigned nr, const unsigned char *base, +static int resolve_against_held(unsigned nr, const struct object_id *base, void *delta_data, unsigned long delta_size) { struct object *obj; struct obj_buffer *obj_buffer; - obj = lookup_object(base); + obj = lookup_object(base->hash); if (!obj) return 0; obj_buffer = lookup_object_buffer(obj); @@ -341,25 +342,25 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, { void *delta_data, *base; unsigned long base_size; - unsigned char base_sha1[20]; + struct object_id base_oid; if (type == OBJ_REF_DELTA) { - hashcpy(base_sha1, fill(20)); - use(20); + hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ)); + use(GIT_SHA1_RAWSZ); delta_data = get_data(delta_size); if (dry_run || !delta_data) { free(delta_data); return; } - if (has_sha1_file(base_sha1)) + if (has_object_file(&base_oid)) ; /* Ok we have this one */ - else if (resolve_against_held(nr, base_sha1, + else if (resolve_against_held(nr, &base_oid, delta_data, delta_size)) return; /* we are done */ else { /* cannot resolve yet --- queue it */ - hashclr(obj_list[nr].sha1); - add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size); + oidclr(&obj_list[nr].oid); + add_delta_to_list(nr, &base_oid, 0, delta_data, delta_size); return; } } else { @@ -399,8 +400,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, } else if (base_offset > obj_list[mid].offset) { lo = mid + 1; } else { - hashcpy(base_sha1, obj_list[mid].sha1); - base_found = !is_null_sha1(base_sha1); + oidcpy(&base_oid, &obj_list[mid].oid); + base_found = !is_null_oid(&base_oid); break; } } @@ -409,19 +410,19 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, * The delta base object is itself a delta that * has not been resolved yet. */ - hashclr(obj_list[nr].sha1); - add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size); + oidclr(&obj_list[nr].oid); + add_delta_to_list(nr, &null_oid, base_offset, delta_data, delta_size); return; } } - if (resolve_against_held(nr, base_sha1, delta_data, delta_size)) + if (resolve_against_held(nr, &base_oid, delta_data, delta_size)) return; - base = read_sha1_file(base_sha1, &type, &base_size); + base = read_sha1_file(base_oid.hash, &type, &base_size); if (!base) { error("failed to read delta-pack base object %s", - sha1_to_hex(base_sha1)); + oid_to_hex(&base_oid)); if (!recover) exit(1); has_errors = 1; @@ -505,7 +506,7 @@ static void unpack_all(void) int cmd_unpack_objects(int argc, const char **argv, const char *prefix) { int i; - unsigned char sha1[20]; + struct object_id oid; check_replace_refs = 0; @@ -566,12 +567,12 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) git_SHA1_Init(&ctx); unpack_all(); git_SHA1_Update(&ctx, buffer, offset); - git_SHA1_Final(sha1, &ctx); + git_SHA1_Final(oid.hash, &ctx); if (strict) write_rest(); - if (hashcmp(fill(20), sha1)) + if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash)) die("final sha1 did not match"); - use(20); + use(GIT_SHA1_RAWSZ); /* Write the last part of the buffer to stdout */ while (len) { diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index 38bedf8f9f..05b734e6d1 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -18,14 +18,14 @@ static const char * const verify_commit_usage[] = { NULL }; -static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, unsigned flags) +static int run_gpg_verify(const struct object_id *oid, const char *buf, unsigned long size, unsigned flags) { struct signature_check signature_check; int ret; memset(&signature_check, 0, sizeof(signature_check)); - ret = check_commit_signature(lookup_commit(sha1), &signature_check); + ret = check_commit_signature(lookup_commit(oid), &signature_check); print_signature_buffer(&signature_check, flags); signature_check_clear(&signature_check); @@ -35,22 +35,22 @@ static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned l static int verify_commit(const char *name, unsigned flags) { enum object_type type; - unsigned char sha1[20]; + struct object_id oid; char *buf; unsigned long size; int ret; - if (get_sha1(name, sha1)) + if (get_oid(name, &oid)) return error("commit '%s' not found.", name); - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid.hash, &type, &size); if (!buf) return error("%s: unable to read file.", name); if (type != OBJ_COMMIT) return error("%s: cannot verify a non-commit object of type %s.", name, typename(type)); - ret = run_gpg_verify(sha1, buf, size, flags); + ret = run_gpg_verify(&oid, buf, size, flags); free(buf); return ret; diff --git a/builtin/worktree.c b/builtin/worktree.c index 1722a9bdc2..793306ea51 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -31,7 +31,7 @@ struct add_opts { static int show_only; static int verbose; -static unsigned long expire; +static timestamp_t expire; static int prune_worktree(const char *id, struct strbuf *reason) { @@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix) OPT_END() }; - expire = ULONG_MAX; + expire = TIME_MAX; ac = parse_options(ac, av, prefix, options, worktree_usage, 0); if (ac) usage_with_options(worktree_usage, options); @@ -414,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len) find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV)); if (wt->is_detached) strbuf_addstr(&sb, "(detached HEAD)"); - else if (wt->head_ref) - strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0)); - else + else if (wt->head_ref) { + char *ref = shorten_unambiguous_ref(wt->head_ref, 0); + strbuf_addf(&sb, "[%s]", ref); + free(ref); + } else strbuf_addstr(&sb, "(error)"); } printf("%s\n", sb.buf); diff --git a/bulk-checkin.c b/bulk-checkin.c index ddb6070c4c..5be7ce5c73 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -69,7 +69,7 @@ static int already_written(struct bulk_checkin_state *state, unsigned char sha1[ /* Might want to keep the list sorted */ for (i = 0; i < state->nr_written; i++) - if (!hashcmp(state->written[i]->sha1, sha1)) + if (!hashcmp(state->written[i]->oid.hash, sha1)) return 1; /* This is a new object we need to keep */ @@ -242,7 +242,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state, state->offset = checkpoint.offset; free(idx); } else { - hashcpy(idx->sha1, result_sha1); + hashcpy(idx->oid.hash, result_sha1); ALLOC_GROW(state->written, state->nr_written + 1, state->alloc_written); diff --git a/bundle.c b/bundle.c index bbf4efa0a0..d15db03c84 100644 --- a/bundle.c +++ b/bundle.c @@ -12,11 +12,11 @@ static const char bundle_signature[] = "# v2 git bundle\n"; -static void add_to_ref_list(const unsigned char *sha1, const char *name, +static void add_to_ref_list(const struct object_id *oid, const char *name, struct ref_list *list) { ALLOC_GROW(list->list, list->nr + 1, list->alloc); - hashcpy(list->list[list->nr].sha1, sha1); + oidcpy(&list->list[list->nr].oid, oid); list->list[list->nr].name = xstrdup(name); list->nr++; } @@ -40,8 +40,9 @@ static int parse_bundle_header(int fd, struct bundle_header *header, /* The bundle header ends with an empty line */ while (!strbuf_getwholeline_fd(&buf, fd, '\n') && buf.len && buf.buf[0] != '\n') { - unsigned char sha1[20]; + struct object_id oid; int is_prereq = 0; + const char *p; if (*buf.buf == '-') { is_prereq = 1; @@ -54,9 +55,9 @@ static int parse_bundle_header(int fd, struct bundle_header *header, * Prerequisites have object name that is optionally * followed by SP and subject line. */ - if (get_sha1_hex(buf.buf, sha1) || - (buf.len > 40 && !isspace(buf.buf[40])) || - (!is_prereq && buf.len <= 40)) { + if (parse_oid_hex(buf.buf, &oid, &p) || + (*p && !isspace(*p)) || + (!is_prereq && !*p)) { if (report_path) error(_("unrecognized header: %s%s (%d)"), (is_prereq ? "-" : ""), buf.buf, (int)buf.len); @@ -64,9 +65,9 @@ static int parse_bundle_header(int fd, struct bundle_header *header, break; } else { if (is_prereq) - add_to_ref_list(sha1, "", &header->prerequisites); + add_to_ref_list(&oid, "", &header->prerequisites); else - add_to_ref_list(sha1, buf.buf + 41, &header->references); + add_to_ref_list(&oid, p + 1, &header->references); } } @@ -115,7 +116,7 @@ static int list_refs(struct ref_list *r, int argc, const char **argv) if (j == argc) continue; } - printf("%s %s\n", sha1_to_hex(r->list[i].sha1), + printf("%s %s\n", oid_to_hex(&r->list[i].oid), r->list[i].name); } return 0; @@ -141,7 +142,7 @@ int verify_bundle(struct bundle_header *header, int verbose) init_revisions(&revs, NULL); for (i = 0; i < p->nr; i++) { struct ref_list_entry *e = p->list + i; - struct object *o = parse_object(e->sha1); + struct object *o = parse_object(&e->oid); if (o) { o->flags |= PREREQ_MARK; add_pending_object(&revs, o, e->name); @@ -149,7 +150,7 @@ int verify_bundle(struct bundle_header *header, int verbose) } if (++ret == 1) error("%s", message); - error("%s %s", sha1_to_hex(e->sha1), e->name); + error("%s %s", oid_to_hex(&e->oid), e->name); } if (revs.pending.nr != p->nr) return ret; @@ -211,7 +212,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs) unsigned long size; enum object_type type; char *buf = NULL, *line, *lineend; - unsigned long date; + timestamp_t date; int result = 1; if (revs->max_age == -1 && revs->min_age == -1) @@ -227,7 +228,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs) line = memchr(line, '>', lineend ? lineend - line : buf + size - line); if (!line++) goto out; - date = strtoul(line, NULL, 10); + date = parse_timestamp(line, NULL, 10); result = (revs->max_age == -1 || revs->max_age < date) && (revs->min_age == -1 || revs->min_age > date); out: @@ -285,16 +286,18 @@ static int compute_and_write_prerequisites(int bundle_fd, return -1; rls_fout = xfdopen(rls.out, "r"); while (strbuf_getwholeline(&buf, rls_fout, '\n') != EOF) { - unsigned char sha1[20]; + struct object_id oid; if (buf.len > 0 && buf.buf[0] == '-') { write_or_die(bundle_fd, buf.buf, buf.len); - if (!get_sha1_hex(buf.buf + 1, sha1)) { - struct object *object = parse_object_or_die(sha1, buf.buf); + if (!get_oid_hex(buf.buf + 1, &oid)) { + struct object *object = parse_object_or_die(&oid, + buf.buf); object->flags |= UNINTERESTING; add_pending_object(revs, object, buf.buf); } - } else if (!get_sha1_hex(buf.buf, sha1)) { - struct object *object = parse_object_or_die(sha1, buf.buf); + } else if (!get_oid_hex(buf.buf, &oid)) { + struct object *object = parse_object_or_die(&oid, + buf.buf); object->flags |= SHOWN; } } @@ -366,7 +369,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) * in terms of a tag (e.g. v2.0 from the range * "v1.0..v2.0")? */ - struct commit *one = lookup_commit_reference(oid.hash); + struct commit *one = lookup_commit_reference(&oid); struct object *obj; if (e->item == &(one->object)) { @@ -378,7 +381,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) * end up triggering "empty bundle" * error. */ - obj = parse_object_or_die(oid.hash, e->name); + obj = parse_object_or_die(&oid, e->name); obj->flags |= SHOWN; add_pending_object(revs, obj, e->name); } diff --git a/bundle.h b/bundle.h index 1584e4d821..e9a4cb6a74 100644 --- a/bundle.h +++ b/bundle.h @@ -1,10 +1,12 @@ #ifndef BUNDLE_H #define BUNDLE_H +#include "cache.h" + struct ref_list { unsigned int nr, alloc; struct ref_list_entry { - unsigned char sha1[20]; + struct object_id oid; char *name; } *list; }; diff --git a/cache-tree.c b/cache-tree.c index 345ea35963..ec23d8c03d 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -225,7 +225,7 @@ int cache_tree_fully_valid(struct cache_tree *it) int i; if (!it) return 0; - if (it->entry_count < 0 || !has_sha1_file(it->sha1)) + if (it->entry_count < 0 || !has_sha1_file(it->oid.hash)) return 0; for (i = 0; i < it->subtree_nr; i++) { if (!cache_tree_fully_valid(it->down[i]->cache_tree)) @@ -253,7 +253,7 @@ static int update_one(struct cache_tree *it, *skip_count = 0; - if (0 <= it->entry_count && has_sha1_file(it->sha1)) + if (0 <= it->entry_count && has_sha1_file(it->oid.hash)) return it->entry_count; /* @@ -340,7 +340,7 @@ static int update_one(struct cache_tree *it, die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); i += sub->count; - sha1 = sub->cache_tree->sha1; + sha1 = sub->cache_tree->oid.hash; mode = S_IFDIR; contains_ita = sub->cache_tree->entry_count < 0; if (contains_ita) { @@ -354,7 +354,9 @@ static int update_one(struct cache_tree *it, entlen = pathlen - baselen; i++; } - if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) { + + if (is_null_sha1(sha1) || + (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))) { strbuf_release(&buffer); if (expected_missing) return -1; @@ -402,12 +404,13 @@ static int update_one(struct cache_tree *it, unsigned char sha1[20]; hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1); if (has_sha1_file(sha1)) - hashcpy(it->sha1, sha1); + hashcpy(it->oid.hash, sha1); else to_invalidate = 1; } else if (dryrun) - hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); - else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) { + hash_sha1_file(buffer.buf, buffer.len, tree_type, + it->oid.hash); + else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) { strbuf_release(&buffer); return -1; } @@ -417,7 +420,7 @@ static int update_one(struct cache_tree *it, #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, - sha1_to_hex(it->sha1)); + oid_to_hex(&it->oid)); #endif return i; } @@ -457,14 +460,14 @@ static void write_one(struct strbuf *buffer, struct cache_tree *it, if (0 <= it->entry_count) fprintf(stderr, "cache-tree <%.*s> (%d ent, %d subtree) %s\n", pathlen, path, it->entry_count, it->subtree_nr, - sha1_to_hex(it->sha1)); + oid_to_hex(&it->oid)); else fprintf(stderr, "cache-tree <%.*s> (%d subtree) invalid\n", pathlen, path, it->subtree_nr); #endif if (0 <= it->entry_count) { - strbuf_add(buffer, it->sha1, 20); + strbuf_add(buffer, it->oid.hash, 20); } for (i = 0; i < it->subtree_nr; i++) { struct cache_tree_sub *down = it->down[i]; @@ -521,7 +524,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) if (0 <= it->entry_count) { if (size < 20) goto free_return; - hashcpy(it->sha1, (const unsigned char*)buf); + hashcpy(it->oid.hash, (const unsigned char*)buf); buf += 20; size -= 20; } @@ -530,7 +533,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) if (0 <= it->entry_count) fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n", *buffer, it->entry_count, subtree_nr, - sha1_to_hex(it->sha1)); + oid_to_hex(&it->oid)); else fprintf(stderr, "cache-tree <%s> (%d subtrees) invalid\n", *buffer, subtree_nr); @@ -641,10 +644,10 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co subtree = cache_tree_find(index_state->cache_tree, prefix); if (!subtree) return WRITE_TREE_PREFIX_ERROR; - hashcpy(sha1, subtree->sha1); + hashcpy(sha1, subtree->oid.hash); } else - hashcpy(sha1, index_state->cache_tree->sha1); + hashcpy(sha1, index_state->cache_tree->oid.hash); if (0 <= newfd) rollback_lock_file(lock_file); @@ -663,7 +666,7 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) struct name_entry entry; int cnt; - hashcpy(it->sha1, tree->object.oid.hash); + oidcpy(&it->oid, &tree->object.oid); init_tree_desc(&desc, tree->buffer, tree->size); cnt = 0; while (tree_entry(&desc, &entry)) { @@ -671,7 +674,7 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) cnt++; else { struct cache_tree_sub *sub; - struct tree *subtree = lookup_tree(entry.oid->hash); + struct tree *subtree = lookup_tree(entry.oid); if (!subtree->object.parsed) parse_tree(subtree); sub = cache_tree_sub(it, entry.path); @@ -718,7 +721,7 @@ int cache_tree_matches_traversal(struct cache_tree *root, it = find_cache_tree_from_traversal(root, info); it = cache_tree_find(it, ent->path); - if (it && it->entry_count > 0 && !hashcmp(ent->oid->hash, it->sha1)) + if (it && it->entry_count > 0 && !oidcmp(ent->oid, &it->oid)) return it->entry_count; return 0; } diff --git a/cache-tree.h b/cache-tree.h index 41c574663a..f7b9cab7ee 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -1,6 +1,7 @@ #ifndef CACHE_TREE_H #define CACHE_TREE_H +#include "cache.h" #include "tree.h" #include "tree-walk.h" @@ -15,7 +16,7 @@ struct cache_tree_sub { struct cache_tree { int entry_count; /* negative means "invalid" */ - unsigned char sha1[20]; + struct object_id oid; int subtree_nr; int subtree_alloc; struct cache_tree_sub **down; diff --git a/cache.h b/cache.h index e1f0e182ad..d1f2c5c088 100644 --- a/cache.h +++ b/cache.h @@ -1479,18 +1479,18 @@ struct date_mode { #define DATE_MODE(t) date_mode_from_type(DATE_##t) struct date_mode *date_mode_from_type(enum date_mode_type type); -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode); -void show_date_relative(unsigned long time, int tz, const struct timeval *now, +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode); +void show_date_relative(timestamp_t time, int tz, const struct timeval *now, struct strbuf *timebuf); int parse_date(const char *date, struct strbuf *out); -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset); -int parse_expiry_date(const char *date, unsigned long *timestamp); +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset); +int parse_expiry_date(const char *date, timestamp_t *timestamp); void datestamp(struct strbuf *out); #define approxidate(s) approxidate_careful((s), NULL) -unsigned long approxidate_careful(const char *, int *); -unsigned long approxidate_relative(const char *date, const struct timeval *now); +timestamp_t approxidate_careful(const char *, int *); +timestamp_t approxidate_relative(const char *date, const struct timeval *now); void parse_date_format(const char *format, struct date_mode *mode); -int date_overflows(unsigned long date); +int date_overflows(timestamp_t date); #define IDENT_STRICT 1 #define IDENT_NO_DATE 2 @@ -2198,8 +2198,8 @@ struct commit_list; int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes); -int checkout_fast_forward(const unsigned char *from, - const unsigned char *to, +int checkout_fast_forward(const struct object_id *from, + const struct object_id *to, int overwrite_ignore); diff --git a/ci/run-windows-build.sh b/ci/run-windows-build.sh index d8f0d92f28..2d98f6b2f9 100755 --- a/ci/run-windows-build.sh +++ b/ci/run-windows-build.sh @@ -14,14 +14,33 @@ COMMIT=$2 gfwci () { local CURL_ERROR_CODE HTTP_CODE - exec 3>&1 + CONTENT_FILE=$(mktemp -t "git-windows-ci-XXXXXX") + while test -z $HTTP_CODE + do HTTP_CODE=$(curl \ -H "Authentication: Bearer $GFW_CI_TOKEN" \ --silent --retry 5 --write-out '%{HTTP_CODE}' \ - --output >(sed "$(printf '1s/^\xef\xbb\xbf//')" >cat >&3) \ + --output >(sed "$(printf '1s/^\xef\xbb\xbf//')" >$CONTENT_FILE) \ "https://git-for-windows-ci.azurewebsites.net/api/TestNow?$1" \ ) CURL_ERROR_CODE=$? + # The GfW CI web app sometimes returns HTTP errors of + # "502 bad gateway" or "503 service unavailable". + # We also need to check the HTTP content because the GfW web + # app seems to pass through (error) results from other Azure + # calls with HTTP code 200. + # Wait a little and retry if we detect this error. More info: + # https://docs.microsoft.com/en-in/azure/app-service-web/app-service-web-troubleshoot-http-502-http-503 + if test $HTTP_CODE -eq 502 || + test $HTTP_CODE -eq 503 || + grep "502 - Web server received an invalid response" $CONTENT_FILE >/dev/null + then + sleep 10 + HTTP_CODE= + fi + done + cat $CONTENT_FILE + rm $CONTENT_FILE if test $CURL_ERROR_CODE -ne 0 then return $CURL_ERROR_CODE @@ -61,7 +80,8 @@ do case "$STATUS" in inProgress|postponed|notStarted) sleep 10 ;; # continue "completed: succeeded") RESULT="success"; break;; # success - *) echo "Unhandled status: $STATUS"; break;; # failure + "completed: failed") break;; # failure + *) echo "Unhandled status: $STATUS"; break;; # unknown esac done diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh index 579d540d32..6214e6acb4 100755 --- a/ci/test-documentation.sh +++ b/ci/test-documentation.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Perform sanity checks on documentation and build it. # @@ -7,8 +7,19 @@ set -e make check-builtins make check-docs -make doc +# Build docs with AsciiDoc +make --jobs=2 doc > >(tee stdout.log) 2> >(tee stderr.log >&2) +! test -s stderr.log test -s Documentation/git.html test -s Documentation/git.xml test -s Documentation/git.1 +grep 'object.oid.hash)) { + if (oidcmp(oid, &c->object.oid)) { warning(_("%s %s is not a commit!"), - ref_name, sha1_to_hex(sha1)); + ref_name, oid_to_hex(oid)); } return c; } -struct commit *lookup_commit(const unsigned char *sha1) +struct commit *lookup_commit(const struct object_id *oid) { - struct object *obj = lookup_object(sha1); + struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(sha1, alloc_commit_node()); + return create_object(oid->hash, alloc_commit_node()); return object_as_type(obj, OBJ_COMMIT, 0); } @@ -60,13 +61,13 @@ struct commit *lookup_commit_reference_by_name(const char *name) if (get_sha1_committish(name, oid.hash)) return NULL; - commit = lookup_commit_reference(oid.hash); + commit = lookup_commit_reference(&oid); if (parse_commit(commit)) return NULL; return commit; } -static unsigned long parse_commit_date(const char *buf, const char *tail) +static timestamp_t parse_commit_date(const char *buf, const char *tail) { const char *dateptr; @@ -89,8 +90,8 @@ static unsigned long parse_commit_date(const char *buf, const char *tail) /* nada */; if (buf >= tail) return 0; - /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */ - return strtoul(dateptr, NULL, 10); + /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */ + return parse_timestamp(dateptr, NULL, 10); } static struct commit_graft **commit_graft; @@ -216,9 +217,9 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data) return ret; } -int unregister_shallow(const unsigned char *sha1) +int unregister_shallow(const struct object_id *oid) { - int pos = commit_graft_pos(sha1); + int pos = commit_graft_pos(oid->hash); if (pos < 0) return -1; if (pos + 1 < commit_graft_nr) @@ -331,7 +332,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s if (get_sha1_hex(bufptr + 5, parent.hash) < 0) return error("bad tree pointer in commit %s", oid_to_hex(&item->object.oid)); - item->tree = lookup_tree(parent.hash); + item->tree = lookup_tree(&parent); bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */ pptr = &item->parents; @@ -350,7 +351,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s */ if (graft && (graft->nr_parent < 0 || grafts_replace_parents)) continue; - new_parent = lookup_commit(parent.hash); + new_parent = lookup_commit(&parent); if (new_parent) pptr = &commit_list_insert(new_parent, pptr)->next; } @@ -358,7 +359,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s int i; struct commit *new_parent; for (i = 0; i < graft->nr_parent; i++) { - new_parent = lookup_commit(graft->parent[i].hash); + new_parent = lookup_commit(&graft->parent[i]); if (!new_parent) continue; pptr = &commit_list_insert(new_parent, pptr)->next; @@ -473,8 +474,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm static int commit_list_compare_by_date(const void *a, const void *b) { - unsigned long a_date = ((const struct commit_list *)a)->item->date; - unsigned long b_date = ((const struct commit_list *)b)->item->date; + timestamp_t a_date = ((const struct commit_list *)a)->item->date; + timestamp_t b_date = ((const struct commit_list *)b)->item->date; if (a_date < b_date) return 1; if (a_date > b_date) @@ -562,7 +563,7 @@ void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark) for (i = 0; i < a->nr; i++) { object = a->objects[i].item; - commit = lookup_commit_reference_gently(object->oid.hash, 1); + commit = lookup_commit_reference_gently(&object->oid, 1); if (commit) clear_commit_marks(commit, mark); } @@ -598,7 +599,7 @@ static void record_author_date(struct author_date_slab *author_date, const char *ident_line; size_t ident_len; char *date_end; - unsigned long date; + timestamp_t date; ident_line = find_commit_header(buffer, "author", &ident_len); if (!ident_line) @@ -607,7 +608,7 @@ static void record_author_date(struct author_date_slab *author_date, !ident.date_begin || !ident.date_end) goto fail_exit; /* malformed "author" line */ - date = strtoul(ident.date_begin, &date_end, 10); + date = parse_timestamp(ident.date_begin, &date_end, 10); if (date_end != ident.date_end) goto fail_exit; /* malformed date */ *(author_date_slab_at(author_date, commit)) = date; @@ -621,8 +622,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_, { const struct commit *a = a_, *b = b_; struct author_date_slab *author_date = cb_data; - unsigned long a_date = *(author_date_slab_at(author_date, a)); - unsigned long b_date = *(author_date_slab_at(author_date, b)); + timestamp_t a_date = *(author_date_slab_at(author_date, a)); + timestamp_t b_date = *(author_date_slab_at(author_date, b)); /* newer commits with larger date first */ if (a_date < b_date) @@ -1589,7 +1590,7 @@ struct commit *get_merge_parent(const char *name) struct object_id oid; if (get_sha1(name, oid.hash)) return NULL; - obj = parse_object(oid.hash); + obj = parse_object(&oid); commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT); if (commit && !commit->util) set_merge_remote_desc(commit, name, obj); @@ -1648,10 +1649,9 @@ const char *find_commit_header(const char *msg, const char *key, size_t *out_len /* * Inspect the given string and determine the true "end" of the log message, in * order to find where to put a new Signed-off-by: line. Ignored are - * trailing comment lines and blank lines, and also the traditional - * "Conflicts:" block that is not commented out, so that we can use - * "git commit -s --amend" on an existing commit that forgot to remove - * it. + * trailing comment lines and blank lines. To support "git commit -s + * --amend" on an existing commit, we also ignore "Conflicts:". To + * support "git commit -v", we truncate at cut lines. * * Returns the number of bytes from the tail to ignore, to be fed as * the second parameter to append_signoff(). @@ -1661,8 +1661,9 @@ int ignore_non_trailer(const char *buf, size_t len) int boc = 0; int bol = 0; int in_old_conflicts_block = 0; + size_t cutoff = wt_status_locate_end(buf, len); - while (bol < len) { + while (bol < cutoff) { const char *next_line = memchr(buf + bol, '\n', len - bol); if (!next_line) @@ -1688,5 +1689,5 @@ int ignore_non_trailer(const char *buf, size_t len) } bol = next_line - buf; } - return boc ? len - boc : 0; + return boc ? len - boc : len - cutoff; } diff --git a/commit.h b/commit.h index 7b1986d5c8..4127c298cb 100644 --- a/commit.h +++ b/commit.h @@ -17,7 +17,7 @@ struct commit { struct object object; void *util; unsigned int index; - unsigned long date; + timestamp_t date; struct commit_list *parents; struct tree *tree; }; @@ -45,18 +45,18 @@ enum decoration_type { void add_name_decoration(enum decoration_type type, const char *name, struct object *obj); const struct name_decoration *get_name_decoration(const struct object *obj); -struct commit *lookup_commit(const unsigned char *sha1); -struct commit *lookup_commit_reference(const unsigned char *sha1); -struct commit *lookup_commit_reference_gently(const unsigned char *sha1, +struct commit *lookup_commit(const struct object_id *oid); +struct commit *lookup_commit_reference(const struct object_id *oid); +struct commit *lookup_commit_reference_gently(const struct object_id *oid, int quiet); struct commit *lookup_commit_reference_by_name(const char *name); /* - * Look up object named by "sha1", dereference tag as necessary, - * get a commit and return it. If "sha1" does not dereference to + * Look up object named by "oid", dereference tag as necessary, + * get a commit and return it. If "oid" does not dereference to * a commit, use ref_name to report an error and die. */ -struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name); +struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name); int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size); int parse_commit_gently(struct commit *item, int quiet_on_missing); @@ -263,8 +263,8 @@ extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct oid_array; struct ref; -extern int register_shallow(const unsigned char *sha1); -extern int unregister_shallow(const unsigned char *sha1); +extern int register_shallow(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(void); extern struct commit_list *get_shallow_commits(struct object_array *heads, diff --git a/compat/mingw.c b/compat/mingw.c index 3fbfda5978..fe0e3ccd24 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -961,8 +961,10 @@ static char **get_path_split(void) ++n; } } - if (!n) + if (!n) { + free(envpath); return NULL; + } ALLOC_ARRAY(path, n + 1); p = envpath; diff --git a/compat/winansi.c b/compat/winansi.c index 793420f9d0..a11a0f16d2 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -105,6 +105,13 @@ static int is_console(int fd) if (!fd) { if (!GetConsoleMode(hcon, &mode)) return 0; + /* + * This code path is only reached if there is no console + * attached to stdout/stderr, i.e. we will not need to output + * any text to any console, therefore we might just as well + * use black as foreground color. + */ + sbi.wAttributes = 0; } else if (!GetConsoleScreenBufferInfo(hcon, &sbi)) return 0; @@ -133,6 +140,11 @@ static void write_console(unsigned char *str, size_t len) /* convert utf-8 to utf-16 */ int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len); + if (wlen < 0) { + wchar_t *err = L"[invalid]"; + WriteConsoleW(console, err, wcslen(err), &dummy, NULL); + return; + } /* write directly to console */ WriteConsoleW(console, wbuf, wlen, &dummy, NULL); diff --git a/config.c b/config.c index b4a3205da3..deafc17b42 100644 --- a/config.c +++ b/config.c @@ -1965,7 +1965,7 @@ int git_config_get_expiry(const char *key, const char **output) if (ret) return ret; if (strcmp(*output, "now")) { - unsigned long now = approxidate("now"); + timestamp_t now = approxidate("now"); if (approxidate(*output) >= now) git_die_config(key, _("Invalid %s: '%s'"), key, *output); } @@ -2621,7 +2621,7 @@ int git_config_rename_section_in_file(const char *config_filename, struct lock_file *lock; int out_fd; char buf[1024]; - FILE *config_file; + FILE *config_file = NULL; struct stat st; if (new_name && !section_name_is_ok(new_name)) { @@ -2703,11 +2703,14 @@ int git_config_rename_section_in_file(const char *config_filename, } } fclose(config_file); + config_file = NULL; commit_and_out: if (commit_lock_file(lock) < 0) ret = error_errno("could not write config file %s", config_filename); out: + if (config_file) + fclose(config_file); rollback_lock_file(lock); out_no_rollback: free(filename_buf); diff --git a/config.mak.uname b/config.mak.uname index 399fe19271..192629f143 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -237,6 +237,7 @@ ifeq ($(uname_S),AIX) NO_MKDTEMP = YesPlease NO_STRLCPY = YesPlease NO_NSEC = YesPlease + NO_REGEX = NeedsStartEnd FREAD_READS_DIRECTORIES = UnfortunatelyYes INTERNAL_QSORT = UnfortunatelyYes NEEDS_LIBICONV = YesPlease diff --git a/contrib/completion/.gitattributes b/contrib/completion/.gitattributes new file mode 100644 index 0000000000..19116944c1 --- /dev/null +++ b/contrib/completion/.gitattributes @@ -0,0 +1 @@ +*.bash eol=lf diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index af658995d5..45a78a0953 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1319,6 +1319,7 @@ _git_clone () --template= --depth --single-branch + --no-tags --branch --recurse-submodules --no-single-branch @@ -2387,7 +2388,9 @@ _git_config () color.status.added color.status.changed color.status.header + color.status.localBranch color.status.nobranch + color.status.remoteBranch color.status.unmerged color.status.untracked color.status.updated @@ -2810,7 +2813,7 @@ _git_show_branch () _git_stash () { local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked' - local subcommands='save list show apply clear drop pop create branch' + local subcommands='push save list show apply clear drop pop create branch' local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then case "$cur" in @@ -2825,6 +2828,9 @@ _git_stash () esac else case "$subcommand,$cur" in + push,--*) + __gitcomp "$save_opts --message" + ;; save,--*) __gitcomp "$save_opts" ;; diff --git a/contrib/workdir/.gitattributes b/contrib/workdir/.gitattributes new file mode 100644 index 0000000000..1f78c5d1bd --- /dev/null +++ b/contrib/workdir/.gitattributes @@ -0,0 +1 @@ +/git-new-workdir eol=lf diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c index 46c5937526..f3814cc47a 100644 --- a/credential-cache--daemon.c +++ b/credential-cache--daemon.c @@ -8,7 +8,7 @@ static struct tempfile socket_file; struct credential_cache_entry { struct credential item; - unsigned long expiration; + timestamp_t expiration; }; static struct credential_cache_entry *entries; static int entries_nr; @@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c) e->expiration = 0; } -static int check_expirations(void) +static timestamp_t check_expirations(void) { - static unsigned long wait_for_entry_until; + static timestamp_t wait_for_entry_until; int i = 0; - unsigned long now = time(NULL); - unsigned long next = (unsigned long)-1; + timestamp_t now = time(NULL); + timestamp_t next = TIME_MAX; /* * Initially give the client 30 seconds to actually contact us @@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out) static int serve_cache_loop(int fd) { struct pollfd pfd; - unsigned long wakeup; + timestamp_t wakeup; wakeup = check_expirations(); if (!wakeup) diff --git a/date.c b/date.c index a996331f5b..63fa99685e 100644 --- a/date.c +++ b/date.c @@ -39,14 +39,24 @@ static const char *weekday_names[] = { "Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays" }; -static time_t gm_time_t(unsigned long time, int tz) +static time_t gm_time_t(timestamp_t time, int tz) { int minutes; minutes = tz < 0 ? -tz : tz; minutes = (minutes / 100)*60 + (minutes % 100); minutes = tz < 0 ? -minutes : minutes; - return time + minutes * 60; + + if (minutes > 0) { + if (unsigned_add_overflows(time, minutes * 60)) + die("Timestamp+tz too large: %"PRItime" +%04d", + time, tz); + } else if (time < -minutes * 60) + die("Timestamp before Unix epoch: %"PRItime" %04d", time, tz); + time += minutes * 60; + if (date_overflows(time)) + die("Timestamp too large for this system: %"PRItime, time); + return (time_t)time; } /* @@ -54,7 +64,7 @@ static time_t gm_time_t(unsigned long time, int tz) * thing, which means that tz -0100 is passed in as the integer -100, * even though it means "sixty minutes off" */ -static struct tm *time_to_tm(unsigned long time, int tz) +static struct tm *time_to_tm(timestamp_t time, int tz) { time_t t = gm_time_t(time, tz); return gmtime(&t); @@ -64,13 +74,16 @@ static struct tm *time_to_tm(unsigned long time, int tz) * What value of "tz" was in effect back then at "time" in the * local timezone? */ -static int local_tzoffset(unsigned long time) +static int local_tzoffset(timestamp_t time) { time_t t, t_local; struct tm tm; int offset, eastwest; - t = time; + if (date_overflows(time)) + die("Timestamp too large for this system: %"PRItime, time); + + t = (time_t)time; localtime_r(&t, &tm); t_local = tm_to_time_t(&tm); @@ -88,11 +101,11 @@ static int local_tzoffset(unsigned long time) return offset * eastwest; } -void show_date_relative(unsigned long time, int tz, +void show_date_relative(timestamp_t time, int tz, const struct timeval *now, struct strbuf *timebuf) { - unsigned long diff; + timestamp_t diff; if (now->tv_sec < time) { strbuf_addstr(timebuf, _("in the future")); return; @@ -100,65 +113,65 @@ void show_date_relative(unsigned long time, int tz, diff = now->tv_sec - time; if (diff < 90) { strbuf_addf(timebuf, - Q_("%lu second ago", "%lu seconds ago", diff), diff); + Q_("%"PRItime" second ago", "%"PRItime" seconds ago", diff), diff); return; } /* Turn it into minutes */ diff = (diff + 30) / 60; if (diff < 90) { strbuf_addf(timebuf, - Q_("%lu minute ago", "%lu minutes ago", diff), diff); + Q_("%"PRItime" minute ago", "%"PRItime" minutes ago", diff), diff); return; } /* Turn it into hours */ diff = (diff + 30) / 60; if (diff < 36) { strbuf_addf(timebuf, - Q_("%lu hour ago", "%lu hours ago", diff), diff); + Q_("%"PRItime" hour ago", "%"PRItime" hours ago", diff), diff); return; } /* We deal with number of days from here on */ diff = (diff + 12) / 24; if (diff < 14) { strbuf_addf(timebuf, - Q_("%lu day ago", "%lu days ago", diff), diff); + Q_("%"PRItime" day ago", "%"PRItime" days ago", diff), diff); return; } /* Say weeks for the past 10 weeks or so */ if (diff < 70) { strbuf_addf(timebuf, - Q_("%lu week ago", "%lu weeks ago", (diff + 3) / 7), + Q_("%"PRItime" week ago", "%"PRItime" weeks ago", (diff + 3) / 7), (diff + 3) / 7); return; } /* Say months for the past 12 months or so */ if (diff < 365) { strbuf_addf(timebuf, - Q_("%lu month ago", "%lu months ago", (diff + 15) / 30), + Q_("%"PRItime" month ago", "%"PRItime" months ago", (diff + 15) / 30), (diff + 15) / 30); return; } /* Give years and months for 5 years or so */ if (diff < 1825) { - unsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2); - unsigned long years = totalmonths / 12; - unsigned long months = totalmonths % 12; + timestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2); + timestamp_t years = totalmonths / 12; + timestamp_t months = totalmonths % 12; if (months) { struct strbuf sb = STRBUF_INIT; - strbuf_addf(&sb, Q_("%lu year", "%lu years", years), years); + strbuf_addf(&sb, Q_("%"PRItime" year", "%"PRItime" years", years), years); strbuf_addf(timebuf, /* TRANSLATORS: "%s" is " years" */ - Q_("%s, %lu month ago", "%s, %lu months ago", months), + Q_("%s, %"PRItime" month ago", "%s, %"PRItime" months ago", months), sb.buf, months); strbuf_release(&sb); } else strbuf_addf(timebuf, - Q_("%lu year ago", "%lu years ago", years), years); + Q_("%"PRItime" year ago", "%"PRItime" years ago", years), years); return; } /* Otherwise, just years. Centuries is probably overkill. */ strbuf_addf(timebuf, - Q_("%lu year ago", "%lu years ago", (diff + 183) / 365), + Q_("%"PRItime" year ago", "%"PRItime" years ago", (diff + 183) / 365), (diff + 183) / 365); } @@ -172,14 +185,14 @@ struct date_mode *date_mode_from_type(enum date_mode_type type) return &mode; } -const char *show_date(unsigned long time, int tz, const struct date_mode *mode) +const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) { struct tm *tm; static struct strbuf timebuf = STRBUF_INIT; if (mode->type == DATE_UNIX) { strbuf_reset(&timebuf); - strbuf_addf(&timebuf, "%lu", time); + strbuf_addf(&timebuf, "%"PRItime, time); return timebuf.buf; } @@ -188,7 +201,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode) if (mode->type == DATE_RAW) { strbuf_reset(&timebuf); - strbuf_addf(&timebuf, "%lu %+05d", time, tz); + strbuf_addf(&timebuf, "%"PRItime" %+05d", time, tz); return timebuf.buf; } @@ -425,7 +438,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, return 0; } -static int match_multi_number(unsigned long num, char c, const char *date, +static int match_multi_number(timestamp_t num, char c, const char *date, char *end, struct tm *tm, time_t now) { struct tm now_tm; @@ -508,9 +521,9 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt { int n; char *end; - unsigned long num; + timestamp_t num; - num = strtoul(date, &end, 10); + num = parse_timestamp(date, &end, 10); /* * Seconds since 1970? We trigger on that for any numbers with @@ -635,7 +648,7 @@ static int match_tz(const char *date, int *offp) return end - date; } -static void date_string(unsigned long date, int offset, struct strbuf *buf) +static void date_string(timestamp_t date, int offset, struct strbuf *buf) { int sign = '+'; @@ -643,23 +656,23 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf) offset = -offset; sign = '-'; } - strbuf_addf(buf, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60); + strbuf_addf(buf, "%"PRItime" %c%02d%02d", date, sign, offset / 60, offset % 60); } /* * Parse a string like "0 +0000" as ancient timestamp near epoch, but * only when it appears not as part of any other string. */ -static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset) +static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset) { char *end; - unsigned long stamp; + timestamp_t stamp; int ofs; if (*date < '0' || '9' < *date) return -1; - stamp = strtoul(date, &end, 10); - if (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-')) + stamp = parse_timestamp(date, &end, 10); + if (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-')) return -1; date = end + 2; ofs = strtol(date, &end, 10); @@ -675,11 +688,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp, /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset) { struct tm tm; int tm_gmt; - unsigned long dummy_timestamp; + timestamp_t dummy_timestamp; int dummy_offset; if (!timestamp) @@ -747,7 +760,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) return 0; /* success */ } -int parse_expiry_date(const char *date, unsigned long *timestamp) +int parse_expiry_date(const char *date, timestamp_t *timestamp) { int errors = 0; @@ -762,7 +775,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp) * of the past, and there is nothing from the future * to be kept. */ - *timestamp = ULONG_MAX; + *timestamp = TIME_MAX; else *timestamp = approxidate_careful(date, &errors); @@ -771,7 +784,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp) int parse_date(const char *date, struct strbuf *result) { - unsigned long timestamp; + timestamp_t timestamp; int offset; if (parse_date_basic(date, ×tamp, &offset)) return -1; @@ -845,7 +858,7 @@ void datestamp(struct strbuf *out) * Relative time update (eg "2 days ago"). If we haven't set the time * yet, we need to set it from current time. */ -static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec) +static time_t update_tm(struct tm *tm, struct tm *now, time_t sec) { time_t n; @@ -1066,7 +1079,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num, time_t now) { char *end; - unsigned long number = strtoul(date, &end, 10); + timestamp_t number = parse_timestamp(date, &end, 10); switch (*end) { case ':': @@ -1114,9 +1127,9 @@ static void pending_number(struct tm *tm, int *num) } } -static unsigned long approxidate_str(const char *date, - const struct timeval *tv, - int *error_ret) +static timestamp_t approxidate_str(const char *date, + const struct timeval *tv, + int *error_ret) { int number = 0; int touched = 0; @@ -1148,12 +1161,12 @@ static unsigned long approxidate_str(const char *date, pending_number(&tm, &number); if (!touched) *error_ret = 1; - return update_tm(&tm, &now, 0); + return (timestamp_t)update_tm(&tm, &now, 0); } -unsigned long approxidate_relative(const char *date, const struct timeval *tv) +timestamp_t approxidate_relative(const char *date, const struct timeval *tv) { - unsigned long timestamp; + timestamp_t timestamp; int offset; int errors = 0; @@ -1162,10 +1175,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv) return approxidate_str(date, tv, &errors); } -unsigned long approxidate_careful(const char *date, int *error_ret) +timestamp_t approxidate_careful(const char *date, int *error_ret) { struct timeval tv; - unsigned long timestamp; + timestamp_t timestamp; int offset; int dummy = 0; if (!error_ret) @@ -1180,12 +1193,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret) return approxidate_str(date, &tv, error_ret); } -int date_overflows(unsigned long t) +int date_overflows(timestamp_t t) { time_t sys; - /* If we overflowed our unsigned long, that's bad... */ - if (t == ULONG_MAX) + /* If we overflowed our timestamp data type, that's bad... */ + if ((uintmax_t)t >= TIME_MAX) return 1; /* diff --git a/diff-lib.c b/diff-lib.c index 52447466b5..2982bf055a 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -478,7 +478,7 @@ static int oneway_diff(const struct cache_entry * const *src, } static int diff_cache(struct rev_info *revs, - const unsigned char *tree_sha1, + const struct object_id *tree_oid, const char *tree_name, int cached) { @@ -486,10 +486,10 @@ static int diff_cache(struct rev_info *revs, struct tree_desc t; struct unpack_trees_options opts; - tree = parse_tree_indirect(tree_sha1); + tree = parse_tree_indirect(tree_oid); if (!tree) return error("bad tree object %s", - tree_name ? tree_name : sha1_to_hex(tree_sha1)); + tree_name ? tree_name : oid_to_hex(tree_oid)); memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; opts.index_only = cached; @@ -512,7 +512,7 @@ int run_diff_index(struct rev_info *revs, int cached) struct object_array_entry *ent; ent = revs->pending.objects; - if (diff_cache(revs, ent->item->oid.hash, ent->name, cached)) + if (diff_cache(revs, &ent->item->oid, ent->name, cached)) exit(128); diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); @@ -522,7 +522,7 @@ int run_diff_index(struct rev_info *revs, int cached) return 0; } -int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) +int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt) { struct rev_info revs; @@ -530,7 +530,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) copy_pathspec(&revs.prune_data, &opt->pathspec); revs.diffopt = *opt; - if (diff_cache(&revs, tree_sha1, NULL, 1)) + if (diff_cache(&revs, tree_oid, NULL, 1)) exit(128); return 0; } diff --git a/diff.c b/diff.c index 74283d9001..f3546536b4 100644 --- a/diff.c +++ b/diff.c @@ -5244,7 +5244,7 @@ size_t fill_textconv(struct userdiff_driver *driver, if (driver->textconv_cache && df->oid_valid) { *outbuf = notes_cache_get(driver->textconv_cache, - df->oid.hash, + &df->oid, &size); if (*outbuf) return size; @@ -5256,7 +5256,7 @@ size_t fill_textconv(struct userdiff_driver *driver, if (driver->textconv_cache && df->oid_valid) { /* ignore errors, as we might be in a readonly repository */ - notes_cache_put(driver->textconv_cache, df->oid.hash, *outbuf, + notes_cache_put(driver->textconv_cache, &df->oid, *outbuf, size); /* * we could save up changes and flush them all at the end, diff --git a/diff.h b/diff.h index 5be1ee77a7..d75e6d15e2 100644 --- a/diff.h +++ b/diff.h @@ -354,7 +354,7 @@ extern const char *diff_aligned_abbrev(const struct object_id *sha1, int); extern int run_diff_files(struct rev_info *revs, unsigned int option); extern int run_diff_index(struct rev_info *revs, int cached); -extern int do_diff_cache(const unsigned char *, struct diff_options *); +extern int do_diff_cache(const struct object_id *, struct diff_options *); extern int diff_flush_patch_id(struct diff_options *, unsigned char *, int); extern int diff_result_code(struct diff_options *, int); diff --git a/dir.c b/dir.c index f451bfa48c..3f3167e55a 100644 --- a/dir.c +++ b/dir.c @@ -7,6 +7,7 @@ * Copyright (C) Linus Torvalds, 2005-2006 * Junio Hamano, 2005-2006 */ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "dir.h" #include "attr.h" @@ -45,9 +46,11 @@ struct cached_dir { }; static enum path_treatment read_directory_recursive(struct dir_struct *dir, - const char *path, int len, struct untracked_cache_dir *untracked, + struct index_state *istate, const char *path, int len, + struct untracked_cache_dir *untracked, int check_only, const struct pathspec *pathspec); -static int get_dtype(struct dirent *de, const char *path, int len); +static int get_dtype(struct dirent *de, struct index_state *istate, + const char *path, int len); int fspathcmp(const char *a, const char *b) { @@ -174,7 +177,9 @@ char *common_prefix(const struct pathspec *pathspec) return len ? xmemdupz(pathspec->items[0].match, len) : NULL; } -int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec) +int fill_directory(struct dir_struct *dir, + struct index_state *istate, + const struct pathspec *pathspec) { const char *prefix; size_t prefix_len; @@ -187,7 +192,7 @@ int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec) prefix = prefix_len ? pathspec->items[0].match : ""; /* Read the directory and prune it */ - read_directory(dir, prefix, prefix_len, pathspec); + read_directory(dir, istate, prefix, prefix_len, pathspec); return prefix_len; } @@ -587,7 +592,8 @@ void add_exclude(const char *string, const char *base, x->el = el; } -static void *read_skip_worktree_file_from_index(const char *path, size_t *size, +static void *read_skip_worktree_file_from_index(const struct index_state *istate, + const char *path, size_t *size, struct sha1_stat *sha1_stat) { int pos, len; @@ -596,12 +602,12 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size, void *data; len = strlen(path); - pos = cache_name_pos(path, len); + pos = index_name_pos(istate, path, len); if (pos < 0) return NULL; - if (!ce_skip_worktree(active_cache[pos])) + if (!ce_skip_worktree(istate->cache[pos])) return NULL; - data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz); + data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz); if (!data || type != OBJ_BLOB) { free(data); return NULL; @@ -609,7 +615,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size, *size = xsize_t(sz); if (sha1_stat) { memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat)); - hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash); + hashcpy(sha1_stat->sha1, istate->cache[pos]->oid.hash); } return data; } @@ -727,7 +733,7 @@ static void invalidate_directory(struct untracked_cache *uc, /* * Given a file with name "fname", read it (either from disk, or from - * the index if "check_index" is non-zero), parse it and store the + * an index if 'istate' is non-null), parse it and store the * exclude rules in "el". * * If "ss" is not NULL, compute SHA-1 of the exclude file and fill @@ -735,7 +741,8 @@ static void invalidate_directory(struct untracked_cache *uc, * ss_valid is non-zero, "ss" must contain good value as input. */ static int add_excludes(const char *fname, const char *base, int baselen, - struct exclude_list *el, int check_index, + struct exclude_list *el, + struct index_state *istate, struct sha1_stat *sha1_stat) { struct stat st; @@ -749,8 +756,8 @@ static int add_excludes(const char *fname, const char *base, int baselen, warn_on_inaccessible(fname); if (0 <= fd) close(fd); - if (!check_index || - (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL) + if (!istate || + (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL) return -1; if (size == 0) { free(buf); @@ -782,15 +789,15 @@ static int add_excludes(const char *fname, const char *base, int baselen, if (sha1_stat) { int pos; if (sha1_stat->valid && - !match_stat_data_racy(&the_index, &sha1_stat->stat, &st)) + !match_stat_data_racy(istate, &sha1_stat->stat, &st)) ; /* no content change, ss->sha1 still good */ - else if (check_index && - (pos = cache_name_pos(fname, strlen(fname))) >= 0 && - !ce_stage(active_cache[pos]) && - ce_uptodate(active_cache[pos]) && + else if (istate && + (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 && + !ce_stage(istate->cache[pos]) && + ce_uptodate(istate->cache[pos]) && !would_convert_to_git(fname)) hashcpy(sha1_stat->sha1, - active_cache[pos]->oid.hash); + istate->cache[pos]->oid.hash); else hash_sha1_file(buf, size, "blob", sha1_stat->sha1); fill_stat_data(&sha1_stat->stat, &st); @@ -821,9 +828,9 @@ static int add_excludes(const char *fname, const char *base, int baselen, int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, struct exclude_list *el, - int check_index) + struct index_state *istate) { - return add_excludes(fname, base, baselen, el, check_index, NULL); + return add_excludes(fname, base, baselen, el, istate, NULL); } struct exclude_list *add_exclude_list(struct dir_struct *dir, @@ -855,7 +862,7 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname, if (!dir->untracked) dir->unmanaged_exclude_files++; el = add_exclude_list(dir, EXC_FILE, fname); - if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0) + if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0) die("cannot use %s as an exclude file", fname); } @@ -958,7 +965,8 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, - struct exclude_list *el) + struct exclude_list *el, + struct index_state *istate) { struct exclude *exc = NULL; /* undecided */ int i; @@ -973,7 +981,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname, if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) - *dtype = get_dtype(NULL, pathname, pathlen); + *dtype = get_dtype(NULL, istate, pathname, pathlen); if (*dtype != DT_DIR) continue; } @@ -1006,16 +1014,18 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname, */ int is_excluded_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, - struct exclude_list *el) + struct exclude_list *el, struct index_state *istate) { struct exclude *exclude; - exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el); + exclude = last_exclude_matching_from_list(pathname, pathlen, basename, + dtype, el, istate); if (exclude) return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return -1; /* undecided */ } static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir, + struct index_state *istate, const char *pathname, int pathlen, const char *basename, int *dtype_p) { @@ -1027,7 +1037,7 @@ static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir, for (j = group->nr - 1; j >= 0; j--) { exclude = last_exclude_matching_from_list( pathname, pathlen, basename, dtype_p, - &group->el[j]); + &group->el[j], istate); if (exclude) return exclude; } @@ -1039,7 +1049,9 @@ static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir, * Loads the per-directory exclude list for the substring of base * which has a char length of baselen. */ -static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) +static void prep_exclude(struct dir_struct *dir, + struct index_state *istate, + const char *base, int baselen) { struct exclude_list_group *group; struct exclude_list *el; @@ -1118,6 +1130,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) int dt = DT_DIR; dir->basebuf.buf[stk->baselen - 1] = 0; dir->exclude = last_exclude_matching_from_lists(dir, + istate, dir->basebuf.buf, stk->baselen - 1, dir->basebuf.buf + current, &dt); dir->basebuf.buf[stk->baselen - 1] = '/'; @@ -1159,7 +1172,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) strbuf_addbuf(&sb, &dir->basebuf); strbuf_addstr(&sb, dir->exclude_per_dir); el->src = strbuf_detach(&sb, NULL); - add_excludes(el->src, el->src, stk->baselen, el, 1, + add_excludes(el->src, el->src, stk->baselen, el, istate, untracked ? &sha1_stat : NULL); } /* @@ -1194,19 +1207,20 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) * undecided. */ struct exclude *last_exclude_matching(struct dir_struct *dir, - const char *pathname, - int *dtype_p) + struct index_state *istate, + const char *pathname, + int *dtype_p) { int pathlen = strlen(pathname); const char *basename = strrchr(pathname, '/'); basename = (basename) ? basename+1 : pathname; - prep_exclude(dir, pathname, basename-pathname); + prep_exclude(dir, istate, pathname, basename-pathname); if (dir->exclude) return dir->exclude; - return last_exclude_matching_from_lists(dir, pathname, pathlen, + return last_exclude_matching_from_lists(dir, istate, pathname, pathlen, basename, dtype_p); } @@ -1215,10 +1229,11 @@ struct exclude *last_exclude_matching(struct dir_struct *dir, * scans all exclude lists to determine whether pathname is excluded. * Returns 1 if true, otherwise 0. */ -int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +int is_excluded(struct dir_struct *dir, struct index_state *istate, + const char *pathname, int *dtype_p) { struct exclude *exclude = - last_exclude_matching(dir, pathname, dtype_p); + last_exclude_matching(dir, istate, pathname, dtype_p); if (exclude) return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return 0; @@ -1233,18 +1248,22 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len) return ent; } -static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len) +static struct dir_entry *dir_add_name(struct dir_struct *dir, + struct index_state *istate, + const char *pathname, int len) { - if (cache_file_exists(pathname, len, ignore_case)) + if (index_file_exists(istate, pathname, len, ignore_case)) return NULL; ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc); return dir->entries[dir->nr++] = dir_entry_new(pathname, len); } -struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) +struct dir_entry *dir_add_ignored(struct dir_struct *dir, + struct index_state *istate, + const char *pathname, int len) { - if (!cache_name_is_other(pathname, len)) + if (!index_name_is_other(istate, pathname, len)) return NULL; ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc); @@ -1262,14 +1281,15 @@ enum exist_status { * the directory name; instead, use the case insensitive * directory hash. */ -static enum exist_status directory_exists_in_index_icase(const char *dirname, int len) +static enum exist_status directory_exists_in_index_icase(struct index_state *istate, + const char *dirname, int len) { struct cache_entry *ce; - if (cache_dir_exists(dirname, len)) + if (index_dir_exists(istate, dirname, len)) return index_directory; - ce = cache_file_exists(dirname, len, ignore_case); + ce = index_file_exists(istate, dirname, len, ignore_case); if (ce && S_ISGITLINK(ce->ce_mode)) return index_gitdir; @@ -1283,18 +1303,19 @@ static enum exist_status directory_exists_in_index_icase(const char *dirname, in * the files it contains) will sort with the '/' at the * end. */ -static enum exist_status directory_exists_in_index(const char *dirname, int len) +static enum exist_status directory_exists_in_index(struct index_state *istate, + const char *dirname, int len) { int pos; if (ignore_case) - return directory_exists_in_index_icase(dirname, len); + return directory_exists_in_index_icase(istate, dirname, len); - pos = cache_name_pos(dirname, len); + pos = index_name_pos(istate, dirname, len); if (pos < 0) pos = -pos-1; - while (pos < active_nr) { - const struct cache_entry *ce = active_cache[pos++]; + while (pos < istate->cache_nr) { + const struct cache_entry *ce = istate->cache[pos++]; unsigned char endchar; if (strncmp(ce->name, dirname, len)) @@ -1344,12 +1365,13 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len) * (c) otherwise, we recurse into it. */ static enum path_treatment treat_directory(struct dir_struct *dir, + struct index_state *istate, struct untracked_cache_dir *untracked, const char *dirname, int len, int baselen, int exclude, const struct pathspec *pathspec) { /* The "len-1" is to strip the final '/' */ - switch (directory_exists_in_index(dirname, len-1)) { + switch (directory_exists_in_index(istate, dirname, len-1)) { case index_directory: return path_recurse; @@ -1374,7 +1396,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir, untracked = lookup_untracked(dir->untracked, untracked, dirname + baselen, len - baselen); - return read_directory_recursive(dir, dirname, len, + return read_directory_recursive(dir, istate, dirname, len, untracked, 1, pathspec); } @@ -1455,12 +1477,13 @@ static int exclude_matches_pathspec(const char *path, int pathlen, return 0; } -static int get_index_dtype(const char *path, int len) +static int get_index_dtype(struct index_state *istate, + const char *path, int len) { int pos; const struct cache_entry *ce; - ce = cache_file_exists(path, len, 0); + ce = index_file_exists(istate, path, len, 0); if (ce) { if (!ce_uptodate(ce)) return DT_UNKNOWN; @@ -1474,12 +1497,12 @@ static int get_index_dtype(const char *path, int len) } /* Try to look it up as a directory */ - pos = cache_name_pos(path, len); + pos = index_name_pos(istate, path, len); if (pos >= 0) return DT_UNKNOWN; pos = -pos-1; - while (pos < active_nr) { - ce = active_cache[pos++]; + while (pos < istate->cache_nr) { + ce = istate->cache[pos++]; if (strncmp(ce->name, path, len)) break; if (ce->name[len] > '/') @@ -1493,14 +1516,15 @@ static int get_index_dtype(const char *path, int len) return DT_UNKNOWN; } -static int get_dtype(struct dirent *de, const char *path, int len) +static int get_dtype(struct dirent *de, struct index_state *istate, + const char *path, int len) { int dtype = de ? DTYPE(de) : DT_UNKNOWN; struct stat st; if (dtype != DT_UNKNOWN) return dtype; - dtype = get_index_dtype(path, len); + dtype = get_index_dtype(istate, path, len); if (dtype != DT_UNKNOWN) return dtype; if (lstat(path, &st)) @@ -1516,16 +1540,17 @@ static int get_dtype(struct dirent *de, const char *path, int len) static enum path_treatment treat_one_path(struct dir_struct *dir, struct untracked_cache_dir *untracked, + struct index_state *istate, struct strbuf *path, int baselen, const struct pathspec *pathspec, int dtype, struct dirent *de) { int exclude; - int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case); + int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case); if (dtype == DT_UNKNOWN) - dtype = get_dtype(de, path->buf, path->len); + dtype = get_dtype(de, istate, path->buf, path->len); /* Always exclude indexed files */ if (dtype != DT_DIR && has_path_in_index) @@ -1552,10 +1577,10 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, if ((dir->flags & DIR_COLLECT_KILLED_ONLY) && (dtype == DT_DIR) && !has_path_in_index && - (directory_exists_in_index(path->buf, path->len) == index_nonexistent)) + (directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent)) return path_none; - exclude = is_excluded(dir, path->buf, &dtype); + exclude = is_excluded(dir, istate, path->buf, &dtype); /* * Excluded? If we don't explicitly want to show @@ -1569,7 +1594,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, return path_none; case DT_DIR: strbuf_addch(path, '/'); - return treat_directory(dir, untracked, path->buf, path->len, + return treat_directory(dir, istate, untracked, path->buf, path->len, baselen, exclude, pathspec); case DT_REG: case DT_LNK: @@ -1580,6 +1605,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, static enum path_treatment treat_path_fast(struct dir_struct *dir, struct untracked_cache_dir *untracked, struct cached_dir *cdir, + struct index_state *istate, struct strbuf *path, int baselen, const struct pathspec *pathspec) @@ -1598,7 +1624,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir, * to its bottom. Verify again the same set of directories * with check_only set. */ - return read_directory_recursive(dir, path->buf, path->len, + return read_directory_recursive(dir, istate, path->buf, path->len, cdir->ucd, 1, pathspec); /* * We get path_recurse in the first run when @@ -1612,6 +1638,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir, static enum path_treatment treat_path(struct dir_struct *dir, struct untracked_cache_dir *untracked, struct cached_dir *cdir, + struct index_state *istate, struct strbuf *path, int baselen, const struct pathspec *pathspec) @@ -1620,7 +1647,7 @@ static enum path_treatment treat_path(struct dir_struct *dir, struct dirent *de = cdir->de; if (!de) - return treat_path_fast(dir, untracked, cdir, path, + return treat_path_fast(dir, untracked, cdir, istate, path, baselen, pathspec); if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_none; @@ -1630,7 +1657,7 @@ static enum path_treatment treat_path(struct dir_struct *dir, return path_none; dtype = DTYPE(de); - return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de); + return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de); } static void add_untracked(struct untracked_cache_dir *dir, const char *name) @@ -1644,6 +1671,7 @@ static void add_untracked(struct untracked_cache_dir *dir, const char *name) static int valid_cached_dir(struct dir_struct *dir, struct untracked_cache_dir *untracked, + struct index_state *istate, struct strbuf *path, int check_only) { @@ -1658,7 +1686,7 @@ static int valid_cached_dir(struct dir_struct *dir, return 0; } if (!untracked->valid || - match_stat_data_racy(&the_index, &untracked->stat_data, &st)) { + match_stat_data_racy(istate, &untracked->stat_data, &st)) { if (untracked->valid) invalidate_directory(dir->untracked, untracked); fill_stat_data(&untracked->stat_data, &st); @@ -1679,10 +1707,10 @@ static int valid_cached_dir(struct dir_struct *dir, */ if (path->len && path->buf[path->len - 1] != '/') { strbuf_addch(path, '/'); - prep_exclude(dir, path->buf, path->len); + prep_exclude(dir, istate, path->buf, path->len); strbuf_setlen(path, path->len - 1); } else - prep_exclude(dir, path->buf, path->len); + prep_exclude(dir, istate, path->buf, path->len); /* hopefully prep_exclude() haven't invalidated this entry... */ return untracked->valid; @@ -1691,12 +1719,13 @@ static int valid_cached_dir(struct dir_struct *dir, static int open_cached_dir(struct cached_dir *cdir, struct dir_struct *dir, struct untracked_cache_dir *untracked, + struct index_state *istate, struct strbuf *path, int check_only) { memset(cdir, 0, sizeof(*cdir)); cdir->untracked = untracked; - if (valid_cached_dir(dir, untracked, path, check_only)) + if (valid_cached_dir(dir, untracked, istate, path, check_only)) return 0; cdir->fdir = opendir(path->len ? path->buf : "."); if (dir->untracked) @@ -1759,9 +1788,9 @@ static void close_cached_dir(struct cached_dir *cdir) * Returns the most significant path_treatment value encountered in the scan. */ static enum path_treatment read_directory_recursive(struct dir_struct *dir, - const char *base, int baselen, - struct untracked_cache_dir *untracked, int check_only, - const struct pathspec *pathspec) + struct index_state *istate, const char *base, int baselen, + struct untracked_cache_dir *untracked, int check_only, + const struct pathspec *pathspec) { struct cached_dir cdir; enum path_treatment state, subdir_state, dir_state = path_none; @@ -1769,7 +1798,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, strbuf_add(&path, base, baselen); - if (open_cached_dir(&cdir, dir, untracked, &path, check_only)) + if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only)) goto out; if (untracked) @@ -1777,7 +1806,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, while (!read_cached_dir(&cdir)) { /* check how the file or directory should be treated */ - state = treat_path(dir, untracked, &cdir, &path, + state = treat_path(dir, untracked, &cdir, istate, &path, baselen, pathspec); if (state > dir_state) @@ -1790,7 +1819,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, path.buf + baselen, path.len - baselen); subdir_state = - read_directory_recursive(dir, path.buf, + read_directory_recursive(dir, istate, path.buf, path.len, ud, check_only, pathspec); if (subdir_state > dir_state) @@ -1812,18 +1841,18 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, switch (state) { case path_excluded: if (dir->flags & DIR_SHOW_IGNORED) - dir_add_name(dir, path.buf, path.len); + dir_add_name(dir, istate, path.buf, path.len); else if ((dir->flags & DIR_SHOW_IGNORED_TOO) || ((dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path.buf, path.len, pathspec))) - dir_add_ignored(dir, path.buf, path.len); + dir_add_ignored(dir, istate, path.buf, path.len); break; case path_untracked: if (dir->flags & DIR_SHOW_IGNORED) break; - dir_add_name(dir, path.buf, path.len); + dir_add_name(dir, istate, path.buf, path.len); if (cdir.fdir) add_untracked(untracked, path.buf + baselen); break; @@ -1848,6 +1877,7 @@ static int cmp_name(const void *p1, const void *p2) } static int treat_leading_path(struct dir_struct *dir, + struct index_state *istate, const char *path, int len, const struct pathspec *pathspec) { @@ -1875,7 +1905,7 @@ static int treat_leading_path(struct dir_struct *dir, break; if (simplify_away(sb.buf, sb.len, pathspec)) break; - if (treat_one_path(dir, NULL, &sb, baselen, pathspec, + if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec, DT_DIR, NULL) == path_none) break; /* do not recurse into it */ if (len <= baselen) { @@ -2043,8 +2073,8 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d return root; } -int read_directory(struct dir_struct *dir, const char *path, - int len, const struct pathspec *pathspec) +int read_directory(struct dir_struct *dir, struct index_state *istate, + const char *path, int len, const struct pathspec *pathspec) { struct untracked_cache_dir *untracked; @@ -2058,8 +2088,8 @@ int read_directory(struct dir_struct *dir, const char *path, * e.g. prep_exclude() */ dir->untracked = NULL; - if (!len || treat_leading_path(dir, path, len, pathspec)) - read_directory_recursive(dir, path, len, untracked, 0, pathspec); + if (!len || treat_leading_path(dir, istate, path, len, pathspec)) + read_directory_recursive(dir, istate, path, len, untracked, 0, pathspec); QSORT(dir->entries, dir->nr, cmp_name); QSORT(dir->ignored, dir->ignored_nr, cmp_name); if (dir->untracked) { @@ -2073,12 +2103,12 @@ int read_directory(struct dir_struct *dir, const char *path, dir->untracked->gitignore_invalidated, dir->untracked->dir_invalidated, dir->untracked->dir_opened); - if (dir->untracked == the_index.untracked && + if (dir->untracked == istate->untracked && (dir->untracked->dir_opened || dir->untracked->gitignore_invalidated || dir->untracked->dir_invalidated)) - the_index.cache_changed |= UNTRACKED_CHANGED; - if (dir->untracked != the_index.untracked) { + istate->cache_changed |= UNTRACKED_CHANGED; + if (dir->untracked != istate->untracked) { free(dir->untracked); dir->untracked = NULL; } diff --git a/dir.h b/dir.h index bf23a470af..17d110693d 100644 --- a/dir.h +++ b/dir.h @@ -214,12 +214,20 @@ extern int match_pathspec(const struct pathspec *pathspec, extern int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix); extern int within_depth(const char *name, int namelen, int depth, int max_depth); -extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec); -extern int read_directory(struct dir_struct *, 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 dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); +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); +struct dir_entry *dir_add_ignored(struct dir_struct *dir, + struct index_state *istate, + const char *pathname, int len); /* * these implement the matching logic for dir.c:excluded_from_list and @@ -232,14 +240,17 @@ extern int match_pathname(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, 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, int check_index); + struct exclude_list *el, struct index_state *istate); extern void add_excludes_from_file(struct dir_struct *, const char *fname); extern void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen); extern void add_exclude(const char *string, const char *base, diff --git a/entry.c b/entry.c index d2b512da90..d6b263f78e 100644 --- a/entry.c +++ b/entry.c @@ -208,7 +208,8 @@ static int write_entry(struct cache_entry *ce, sub = submodule_from_ce(ce); if (sub) return submodule_move_head(ce->name, - NULL, oid_to_hex(&ce->oid), SUBMODULE_MOVE_HEAD_FORCE); + NULL, oid_to_hex(&ce->oid), + state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0); break; default: return error("unknown file mode for %s in index", path); @@ -282,12 +283,11 @@ int checkout_entry(struct cache_entry *ce, unlink_or_warn(ce->name); return submodule_move_head(ce->name, - NULL, oid_to_hex(&ce->oid), - SUBMODULE_MOVE_HEAD_FORCE); + NULL, oid_to_hex(&ce->oid), 0); } else return submodule_move_head(ce->name, "HEAD", oid_to_hex(&ce->oid), - SUBMODULE_MOVE_HEAD_FORCE); + state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0); } if (!changed) diff --git a/environment.c b/environment.c index ff6e4f06e9..aa478e71de 100644 --- a/environment.c +++ b/environment.c @@ -169,7 +169,7 @@ static void setup_git_env(void) git_dir = getenv(GIT_DIR_ENVIRONMENT); if (!git_dir) { if (!startup_info->have_repository) - die("BUG: setup_git_env called without repository"); + BUG("setup_git_env called without repository"); git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; } gitfile = read_gitfile(git_dir); @@ -217,6 +217,8 @@ const char *get_git_dir(void) const char *get_git_common_dir(void) { + if (!git_dir) + setup_git_env(); return git_common_dir; } diff --git a/fast-import.c b/fast-import.c index cf58f875b8..e69d219682 100644 --- a/fast-import.c +++ b/fast-import.c @@ -226,7 +226,7 @@ struct tree_entry { struct atom_str *name; struct tree_entry_ms { uint16_t mode; - unsigned char sha1[20]; + struct object_id oid; } versions[2]; }; @@ -252,19 +252,19 @@ struct branch { unsigned active : 1; unsigned delete : 1; unsigned pack_id : PACK_ID_BITS; - unsigned char sha1[20]; + struct object_id oid; }; struct tag { struct tag *next_tag; const char *name; unsigned int pack_id; - unsigned char sha1[20]; + struct object_id oid; }; struct hash_list { struct hash_list *next; - unsigned char sha1[20]; + struct object_id oid; }; typedef enum { @@ -386,13 +386,15 @@ static void write_branch_report(FILE *rpt, struct branch *b) fputs(" active", rpt); if (b->branch_tree.tree) fputs(" loaded", rpt); - if (is_null_sha1(b->branch_tree.versions[1].sha1)) + if (is_null_oid(&b->branch_tree.versions[1].oid)) fputs(" dirty", rpt); fputc('\n', rpt); - fprintf(rpt, " tip commit : %s\n", sha1_to_hex(b->sha1)); - fprintf(rpt, " old tree : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1)); - fprintf(rpt, " cur tree : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1)); + fprintf(rpt, " tip commit : %s\n", oid_to_hex(&b->oid)); + fprintf(rpt, " old tree : %s\n", + oid_to_hex(&b->branch_tree.versions[0].oid)); + fprintf(rpt, " cur tree : %s\n", + oid_to_hex(&b->branch_tree.versions[1].oid)); fprintf(rpt, " commit clock: %" PRIuMAX "\n", b->last_commit); fputs(" last pack : ", rpt); @@ -470,7 +472,7 @@ static void write_crash_report(const char *err) fputs("Annotated Tags\n", rpt); fputs("--------------\n", rpt); for (tg = first_tag; tg; tg = tg->next_tag) { - fputs(sha1_to_hex(tg->sha1), rpt); + fputs(oid_to_hex(&tg->oid), rpt); fputc(' ', rpt); fputs(tg->name, rpt); fputc('\n', rpt); @@ -555,7 +557,7 @@ static void alloc_objects(unsigned int cnt) alloc_count += cnt; } -static struct object_entry *new_object(unsigned char *sha1) +static struct object_entry *new_object(struct object_id *oid) { struct object_entry *e; @@ -563,32 +565,32 @@ static struct object_entry *new_object(unsigned char *sha1) alloc_objects(object_entry_alloc); e = blocks->next_free++; - hashcpy(e->idx.sha1, sha1); + oidcpy(&e->idx.oid, oid); return e; } -static struct object_entry *find_object(unsigned char *sha1) +static struct object_entry *find_object(struct object_id *oid) { - unsigned int h = sha1[0] << 8 | sha1[1]; + unsigned int h = oid->hash[0] << 8 | oid->hash[1]; struct object_entry *e; for (e = object_table[h]; e; e = e->next) - if (!hashcmp(sha1, e->idx.sha1)) + if (!oidcmp(oid, &e->idx.oid)) return e; return NULL; } -static struct object_entry *insert_object(unsigned char *sha1) +static struct object_entry *insert_object(struct object_id *oid) { - unsigned int h = sha1[0] << 8 | sha1[1]; + unsigned int h = oid->hash[0] << 8 | oid->hash[1]; struct object_entry *e = object_table[h]; while (e) { - if (!hashcmp(sha1, e->idx.sha1)) + if (!oidcmp(oid, &e->idx.oid)) return e; e = e->next; } - e = new_object(sha1); + e = new_object(oid); e->next = object_table[h]; e->idx.offset = 0; object_table[h] = e; @@ -876,7 +878,7 @@ static struct tree_content *dup_tree_content(struct tree_content *s) a = s->entries[i]; b = new_tree_entry(); memcpy(b, a, sizeof(*a)); - if (a->tree && is_null_sha1(b->versions[1].sha1)) + if (a->tree && is_null_oid(&b->versions[1].oid)) b->tree = dup_tree_content(a->tree); else b->tree = NULL; @@ -1005,17 +1007,17 @@ static void end_packfile(void) clear_delta_base_cache(); if (object_count) { struct packed_git *new_p; - unsigned char cur_pack_sha1[20]; + struct object_id cur_pack_oid; char *idx_name; int i; struct branch *b; struct tag *t; close_pack_windows(pack_data); - sha1close(pack_file, cur_pack_sha1, 0); + sha1close(pack_file, cur_pack_oid.hash, 0); fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1, pack_data->pack_name, object_count, - cur_pack_sha1, pack_size); + cur_pack_oid.hash, pack_size); if (object_count <= unpack_limit) { if (!loosen_small_pack(pack_data)) { @@ -1041,12 +1043,14 @@ static void end_packfile(void) for (i = 0; i < branch_table_sz; i++) { for (b = branch_table[i]; b; b = b->table_next_branch) { if (b->pack_id == pack_id) - fprintf(pack_edges, " %s", sha1_to_hex(b->sha1)); + fprintf(pack_edges, " %s", + oid_to_hex(&b->oid)); } } for (t = first_tag; t; t = t->next_tag) { if (t->pack_id == pack_id) - fprintf(pack_edges, " %s", sha1_to_hex(t->sha1)); + fprintf(pack_edges, " %s", + oid_to_hex(&t->oid)); } fputc('\n', pack_edges); fflush(pack_edges); @@ -1079,13 +1083,13 @@ static int store_object( enum object_type type, struct strbuf *dat, struct last_object *last, - unsigned char *sha1out, + struct object_id *oidout, uintmax_t mark) { void *out, *delta; struct object_entry *e; unsigned char hdr[96]; - unsigned char sha1[20]; + struct object_id oid; unsigned long hdrlen, deltalen; git_SHA_CTX c; git_zstream s; @@ -1095,17 +1099,17 @@ static int store_object( git_SHA1_Init(&c); git_SHA1_Update(&c, hdr, hdrlen); git_SHA1_Update(&c, dat->buf, dat->len); - git_SHA1_Final(sha1, &c); - if (sha1out) - hashcpy(sha1out, sha1); + git_SHA1_Final(oid.hash, &c); + if (oidout) + oidcpy(oidout, &oid); - e = insert_object(sha1); + e = insert_object(&oid); if (mark) insert_mark(mark, e); if (e->idx.offset) { duplicate_count_by_type[type]++; return 1; - } else if (find_sha1_pack(sha1, packed_git)) { + } else if (find_sha1_pack(oid.hash, packed_git)) { e->type = type; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@ -1218,13 +1222,13 @@ static void truncate_pack(struct sha1file_checkpoint *checkpoint) pack_size = checkpoint->offset; } -static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) +static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) { size_t in_sz = 64 * 1024, out_sz = 64 * 1024; unsigned char *in_buf = xmalloc(in_sz); unsigned char *out_buf = xmalloc(out_sz); struct object_entry *e; - unsigned char sha1[20]; + struct object_id oid; unsigned long hdrlen; off_t offset; git_SHA_CTX c; @@ -1287,12 +1291,12 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) } } git_deflate_end(&s); - git_SHA1_Final(sha1, &c); + git_SHA1_Final(oid.hash, &c); - if (sha1out) - hashcpy(sha1out, sha1); + if (oidout) + oidcpy(oidout, &oid); - e = insert_object(sha1); + e = insert_object(&oid); if (mark) insert_mark(mark, e); @@ -1301,7 +1305,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) duplicate_count_by_type[OBJ_BLOB]++; truncate_pack(&checkpoint); - } else if (find_sha1_pack(sha1, packed_git)) { + } else if (find_sha1_pack(oid.hash, packed_git)) { e->type = OBJ_BLOB; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@ -1385,7 +1389,7 @@ static const char *get_mode(const char *str, uint16_t *modep) static void load_tree(struct tree_entry *root) { - unsigned char *sha1 = root->versions[1].sha1; + struct object_id *oid = &root->versions[1].oid; struct object_entry *myoe; struct tree_content *t; unsigned long size; @@ -1393,22 +1397,22 @@ static void load_tree(struct tree_entry *root) const char *c; root->tree = t = new_tree_content(8); - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return; - myoe = find_object(sha1); + myoe = find_object(oid); if (myoe && myoe->pack_id != MAX_PACK_ID) { if (myoe->type != OBJ_TREE) - die("Not a tree: %s", sha1_to_hex(sha1)); + die("Not a tree: %s", oid_to_hex(oid)); t->delta_depth = myoe->depth; buf = gfi_unpack_entry(myoe, &size); if (!buf) - die("Can't load tree %s", sha1_to_hex(sha1)); + die("Can't load tree %s", oid_to_hex(oid)); } else { enum object_type type; - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); if (!buf || type != OBJ_TREE) - die("Can't load tree %s", sha1_to_hex(sha1)); + die("Can't load tree %s", oid_to_hex(oid)); } c = buf; @@ -1422,13 +1426,13 @@ static void load_tree(struct tree_entry *root) e->tree = NULL; c = get_mode(c, &e->versions[1].mode); if (!c) - die("Corrupt mode in %s", sha1_to_hex(sha1)); + die("Corrupt mode in %s", oid_to_hex(oid)); e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - hashcpy(e->versions[0].sha1, (unsigned char *)c); - hashcpy(e->versions[1].sha1, (unsigned char *)c); - c += 20; + hashcpy(e->versions[0].oid.hash, (unsigned char *)c); + hashcpy(e->versions[1].oid.hash, (unsigned char *)c); + c += GIT_SHA1_RAWSZ; } free(buf); } @@ -1475,7 +1479,7 @@ static void mktree(struct tree_content *t, int v, struct strbuf *b) strbuf_addf(b, "%o %s%c", (unsigned int)(e->versions[v].mode & ~NO_DELTA), e->name->str_dat, '\0'); - strbuf_add(b, e->versions[v].sha1, 20); + strbuf_add(b, e->versions[v].oid.hash, GIT_SHA1_RAWSZ); } } @@ -1486,7 +1490,7 @@ static void store_tree(struct tree_entry *root) struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 }; struct object_entry *le = NULL; - if (!is_null_sha1(root->versions[1].sha1)) + if (!is_null_oid(&root->versions[1].oid)) return; if (!root->tree) @@ -1499,7 +1503,7 @@ static void store_tree(struct tree_entry *root) } if (!(root->versions[0].mode & NO_DELTA)) - le = find_object(root->versions[0].sha1); + le = find_object(&root->versions[0].oid); if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) { mktree(t, 0, &old_tree); lo.data = old_tree; @@ -1508,14 +1512,14 @@ static void store_tree(struct tree_entry *root) } mktree(t, 1, &new_tree); - store_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0); + store_object(OBJ_TREE, &new_tree, &lo, &root->versions[1].oid, 0); t->delta_depth = lo.depth; for (i = 0, j = 0, del = 0; i < t->entry_count; i++) { struct tree_entry *e = t->entries[i]; if (e->versions[1].mode) { e->versions[0].mode = e->versions[1].mode; - hashcpy(e->versions[0].sha1, e->versions[1].sha1); + oidcpy(&e->versions[0].oid, &e->versions[1].oid); t->entries[j++] = e; } else { release_tree_entry(e); @@ -1527,14 +1531,14 @@ static void store_tree(struct tree_entry *root) static void tree_content_replace( struct tree_entry *root, - const unsigned char *sha1, + const struct object_id *oid, const uint16_t mode, struct tree_content *newtree) { if (!S_ISDIR(mode)) die("Root cannot be a non-directory"); - hashclr(root->versions[0].sha1); - hashcpy(root->versions[1].sha1, sha1); + oidclr(&root->versions[0].oid); + oidcpy(&root->versions[1].oid, oid); if (root->tree) release_tree_content_recursive(root->tree); root->tree = newtree; @@ -1543,7 +1547,7 @@ static void tree_content_replace( static int tree_content_set( struct tree_entry *root, const char *p, - const unsigned char *sha1, + const struct object_id *oid, const uint16_t mode, struct tree_content *subtree) { @@ -1568,10 +1572,10 @@ static int tree_content_set( if (!*slash1) { if (!S_ISDIR(mode) && e->versions[1].mode == mode - && !hashcmp(e->versions[1].sha1, sha1)) + && !oidcmp(&e->versions[1].oid, oid)) return 0; e->versions[1].mode = mode; - hashcpy(e->versions[1].sha1, sha1); + oidcpy(&e->versions[1].oid, oid); if (e->tree) release_tree_content_recursive(e->tree); e->tree = subtree; @@ -1592,7 +1596,7 @@ static int tree_content_set( if (S_ISDIR(e->versions[0].mode)) e->versions[0].mode |= NO_DELTA; - hashclr(root->versions[1].sha1); + oidclr(&root->versions[1].oid); return 1; } if (!S_ISDIR(e->versions[1].mode)) { @@ -1601,8 +1605,8 @@ static int tree_content_set( } if (!e->tree) load_tree(e); - if (tree_content_set(e, slash1 + 1, sha1, mode, subtree)) { - hashclr(root->versions[1].sha1); + if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) { + oidclr(&root->versions[1].oid); return 1; } return 0; @@ -1614,18 +1618,18 @@ static int tree_content_set( e = new_tree_entry(); e->name = to_atom(p, n); e->versions[0].mode = 0; - hashclr(e->versions[0].sha1); + oidclr(&e->versions[0].oid); t->entries[t->entry_count++] = e; if (*slash1) { e->tree = new_tree_content(8); e->versions[1].mode = S_IFDIR; - tree_content_set(e, slash1 + 1, sha1, mode, subtree); + tree_content_set(e, slash1 + 1, oid, mode, subtree); } else { e->tree = subtree; e->versions[1].mode = mode; - hashcpy(e->versions[1].sha1, sha1); + oidcpy(&e->versions[1].oid, oid); } - hashclr(root->versions[1].sha1); + oidclr(&root->versions[1].oid); return 1; } @@ -1670,7 +1674,7 @@ static int tree_content_remove( if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) { for (n = 0; n < e->tree->entry_count; n++) { if (e->tree->entries[n]->versions[1].mode) { - hashclr(root->versions[1].sha1); + oidclr(&root->versions[1].oid); return 1; } } @@ -1689,8 +1693,8 @@ static int tree_content_remove( release_tree_content_recursive(e->tree); e->tree = NULL; e->versions[1].mode = 0; - hashclr(e->versions[1].sha1); - hashclr(root->versions[1].sha1); + oidclr(&e->versions[1].oid); + oidclr(&root->versions[1].oid); return 1; } @@ -1735,7 +1739,7 @@ static int tree_content_get( found_entry: memcpy(leaf, e, sizeof(*leaf)); - if (e->tree && is_null_sha1(e->versions[1].sha1)) + if (e->tree && is_null_oid(&e->versions[1].oid)) leaf->tree = dup_tree_content(e->tree); else leaf->tree = NULL; @@ -1746,34 +1750,35 @@ static int update_branch(struct branch *b) { static const char *msg = "fast-import"; struct ref_transaction *transaction; - unsigned char old_sha1[20]; + struct object_id old_oid; struct strbuf err = STRBUF_INIT; - if (is_null_sha1(b->sha1)) { + if (is_null_oid(&b->oid)) { if (b->delete) delete_ref(NULL, b->name, NULL, 0); return 0; } - if (read_ref(b->name, old_sha1)) - hashclr(old_sha1); - if (!force_update && !is_null_sha1(old_sha1)) { + if (read_ref(b->name, old_oid.hash)) + oidclr(&old_oid); + if (!force_update && !is_null_oid(&old_oid)) { struct commit *old_cmit, *new_cmit; - old_cmit = lookup_commit_reference_gently(old_sha1, 0); - new_cmit = lookup_commit_reference_gently(b->sha1, 0); + old_cmit = lookup_commit_reference_gently(&old_oid, 0); + new_cmit = lookup_commit_reference_gently(&b->oid, 0); if (!old_cmit || !new_cmit) return error("Branch %s is missing commits.", b->name); if (!in_merge_bases(old_cmit, new_cmit)) { warning("Not updating %s" " (new tip %s does not contain %s)", - b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1)); + b->name, oid_to_hex(&b->oid), + oid_to_hex(&old_oid)); return -1; } } transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, b->name, b->sha1, old_sha1, + ref_transaction_update(transaction, b->name, b->oid.hash, old_oid.hash, 0, msg, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@ -1815,7 +1820,7 @@ static void dump_tags(void) strbuf_addf(&ref_name, "refs/tags/%s", t->name); if (ref_transaction_update(transaction, ref_name.buf, - t->sha1, NULL, 0, msg, &err)) { + t->oid.hash, NULL, 0, msg, &err)) { failure |= error("%s", err.buf); goto cleanup; } @@ -1844,7 +1849,7 @@ static void dump_marks_helper(FILE *f, for (k = 0; k < 1024; k++) { if (m->data.marked[k]) fprintf(f, ":%" PRIuMAX " %s\n", base + k, - sha1_to_hex(m->data.marked[k]->idx.sha1)); + oid_to_hex(&m->data.marked[k]->idx.oid)); } } } @@ -1893,7 +1898,7 @@ static void read_marks(void) while (fgets(line, sizeof(line), f)) { uintmax_t mark; char *end; - unsigned char sha1[20]; + struct object_id oid; struct object_entry *e; end = strchr(line, '\n'); @@ -1902,14 +1907,14 @@ static void read_marks(void) *end = 0; mark = strtoumax(line + 1, &end, 10); if (!mark || end == line + 1 - || *end != ' ' || get_sha1_hex(end + 1, sha1)) + || *end != ' ' || get_oid_hex(end + 1, &oid)) die("corrupt mark line: %s", line); - e = find_object(sha1); + e = find_object(&oid); if (!e) { - enum object_type type = sha1_object_info(sha1, NULL); + enum object_type type = sha1_object_info(oid.hash, NULL); if (type < 0) - die("object not found: %s", sha1_to_hex(sha1)); - e = insert_object(sha1); + die("object not found: %s", oid_to_hex(&oid)); + e = insert_object(&oid); e->type = type; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@ -2117,21 +2122,21 @@ static char *parse_ident(const char *buf) static void parse_and_store_blob( struct last_object *last, - unsigned char *sha1out, + struct object_id *oidout, uintmax_t mark) { static struct strbuf buf = STRBUF_INIT; uintmax_t len; if (parse_data(&buf, big_file_threshold, &len)) - store_object(OBJ_BLOB, &buf, last, sha1out, mark); + store_object(OBJ_BLOB, &buf, last, oidout, mark); else { if (last) { strbuf_release(&last->data); last->offset = 0; last->depth = 0; } - stream_blob(len, sha1out, mark); + stream_blob(len, oidout, mark); skip_optional_lf(); } } @@ -2207,21 +2212,21 @@ static void construct_path_with_fanout(const char *hex_sha1, path[i++] = '/'; fanout--; } - memcpy(path + i, hex_sha1 + j, 40 - j); - path[i + 40 - j] = '\0'; + memcpy(path + i, hex_sha1 + j, GIT_SHA1_HEXSZ - j); + path[i + GIT_SHA1_HEXSZ - j] = '\0'; } static uintmax_t do_change_note_fanout( struct tree_entry *orig_root, struct tree_entry *root, - char *hex_sha1, unsigned int hex_sha1_len, + char *hex_oid, unsigned int hex_oid_len, char *fullpath, unsigned int fullpath_len, unsigned char fanout) { struct tree_content *t; struct tree_entry *e, leaf; - unsigned int i, tmp_hex_sha1_len, tmp_fullpath_len; + unsigned int i, tmp_hex_oid_len, tmp_fullpath_len; uintmax_t num_notes = 0; - unsigned char sha1[20]; + struct object_id oid; char realpath[60]; if (!root->tree) @@ -2230,7 +2235,7 @@ static uintmax_t do_change_note_fanout( for (i = 0; t && i < t->entry_count; i++) { e = t->entries[i]; - tmp_hex_sha1_len = hex_sha1_len + e->name->str_len; + tmp_hex_oid_len = hex_oid_len + e->name->str_len; tmp_fullpath_len = fullpath_len; /* @@ -2242,12 +2247,12 @@ static uintmax_t do_change_note_fanout( * of 2 chars. */ if (!e->versions[1].mode || - tmp_hex_sha1_len > 40 || + tmp_hex_oid_len > GIT_SHA1_HEXSZ || e->name->str_len % 2) continue; /* This _may_ be a note entry, or a subdir containing notes */ - memcpy(hex_sha1 + hex_sha1_len, e->name->str_dat, + memcpy(hex_oid + hex_oid_len, e->name->str_dat, e->name->str_len); if (tmp_fullpath_len) fullpath[tmp_fullpath_len++] = '/'; @@ -2256,14 +2261,14 @@ static uintmax_t do_change_note_fanout( tmp_fullpath_len += e->name->str_len; fullpath[tmp_fullpath_len] = '\0'; - if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) { + if (tmp_hex_oid_len == GIT_SHA1_HEXSZ && !get_oid_hex(hex_oid, &oid)) { /* This is a note entry */ if (fanout == 0xff) { /* Counting mode, no rename */ num_notes++; continue; } - construct_path_with_fanout(hex_sha1, fanout, realpath); + construct_path_with_fanout(hex_oid, fanout, realpath); if (!strcmp(fullpath, realpath)) { /* Note entry is in correct location */ num_notes++; @@ -2274,13 +2279,13 @@ static uintmax_t do_change_note_fanout( if (!tree_content_remove(orig_root, fullpath, &leaf, 0)) die("Failed to remove path %s", fullpath); tree_content_set(orig_root, realpath, - leaf.versions[1].sha1, + &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); } else if (S_ISDIR(e->versions[1].mode)) { /* This is a subdir that may contain note entries */ num_notes += do_change_note_fanout(orig_root, e, - hex_sha1, tmp_hex_sha1_len, + hex_oid, tmp_hex_oid_len, fullpath, tmp_fullpath_len, fanout); } @@ -2293,8 +2298,14 @@ static uintmax_t do_change_note_fanout( static uintmax_t change_note_fanout(struct tree_entry *root, unsigned char fanout) { - char hex_sha1[40], path[60]; - return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout); + /* + * The size of path is due to one slash between every two hex digits, + * plus the terminating NUL. Note that there is no slash at the end, so + * the number of slashes is one less than half the number of hex + * characters. + */ + char hex_oid[GIT_MAX_HEXSZ], path[GIT_MAX_HEXSZ + (GIT_MAX_HEXSZ / 2) - 1 + 1]; + return do_change_note_fanout(root, root, hex_oid, 0, path, 0, fanout); } /* @@ -2355,7 +2366,7 @@ static void file_change_m(const char *p, struct branch *b) static struct strbuf uq = STRBUF_INIT; const char *endp; struct object_entry *oe; - unsigned char sha1[20]; + struct object_id oid; uint16_t mode, inline_data = 0; p = get_mode(p, &mode); @@ -2378,15 +2389,14 @@ static void file_change_m(const char *p, struct branch *b) if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); - hashcpy(sha1, oe->idx.sha1); + oidcpy(&oid, &oe->idx.oid); } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ } else { - if (get_sha1_hex(p, sha1)) + if (parse_oid_hex(p, &oid, &p)) die("Invalid dataref: %s", command_buf.buf); - oe = find_object(sha1); - p += 40; + oe = find_object(&oid); if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } @@ -2399,7 +2409,7 @@ static void file_change_m(const char *p, struct branch *b) } /* Git does not track empty, non-toplevel directories. */ - if (S_ISDIR(mode) && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN) && *p) { + if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *p) { tree_content_remove(&b->branch_tree, p, NULL, 0); return; } @@ -2426,12 +2436,12 @@ static void file_change_m(const char *p, struct branch *b) p = uq.buf; } read_next_command(); - parse_and_store_blob(&last_blob, sha1, 0); + parse_and_store_blob(&last_blob, &oid, 0); } else { enum object_type expected = S_ISDIR(mode) ? OBJ_TREE: OBJ_BLOB; enum object_type type = oe ? oe->type : - sha1_object_info(sha1, NULL); + sha1_object_info(oid.hash, NULL); if (type < 0) die("%s not found: %s", S_ISDIR(mode) ? "Tree" : "Blob", @@ -2443,10 +2453,10 @@ static void file_change_m(const char *p, struct branch *b) } if (!*p) { - tree_content_replace(&b->branch_tree, sha1, mode, NULL); + tree_content_replace(&b->branch_tree, &oid, mode, NULL); return; } - tree_content_set(&b->branch_tree, p, sha1, mode, NULL); + tree_content_set(&b->branch_tree, p, &oid, mode, NULL); } static void file_change_d(const char *p, struct branch *b) @@ -2504,13 +2514,13 @@ static void file_change_cr(const char *s, struct branch *b, int rename) die("Path %s not in branch", s); if (!*d) { /* C "path/to/subdir" "" */ tree_content_replace(&b->branch_tree, - leaf.versions[1].sha1, + &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); return; } tree_content_set(&b->branch_tree, d, - leaf.versions[1].sha1, + &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); } @@ -2520,7 +2530,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa static struct strbuf uq = STRBUF_INIT; struct object_entry *oe; struct branch *s; - unsigned char sha1[20], commit_sha1[20]; + struct object_id oid, commit_oid; char path[60]; uint16_t inline_data = 0; unsigned char new_fanout; @@ -2545,15 +2555,14 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa /* or 'inline' */ if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); - hashcpy(sha1, oe->idx.sha1); + oidcpy(&oid, &oe->idx.oid); } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ } else { - if (get_sha1_hex(p, sha1)) + if (parse_oid_hex(p, &oid, &p)) die("Invalid dataref: %s", command_buf.buf); - oe = find_object(sha1); - p += 40; + oe = find_object(&oid); if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } @@ -2561,19 +2570,19 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa /* */ s = lookup_branch(p); if (s) { - if (is_null_sha1(s->sha1)) + if (is_null_oid(&s->oid)) die("Can't add a note on empty branch."); - hashcpy(commit_sha1, s->sha1); + oidcpy(&commit_oid, &s->oid); } else if (*p == ':') { uintmax_t commit_mark = parse_mark_ref_eol(p); struct object_entry *commit_oe = find_mark(commit_mark); if (commit_oe->type != OBJ_COMMIT) die("Mark :%" PRIuMAX " not a commit", commit_mark); - hashcpy(commit_sha1, commit_oe->idx.sha1); - } else if (!get_sha1(p, commit_sha1)) { + oidcpy(&commit_oid, &commit_oe->idx.oid); + } else if (!get_oid(p, &commit_oid)) { unsigned long size; - char *buf = read_object_with_reference(commit_sha1, - commit_type, &size, commit_sha1); + char *buf = read_object_with_reference(commit_oid.hash, + commit_type, &size, commit_oid.hash); if (!buf || size < 46) die("Not a valid commit: %s", p); free(buf); @@ -2586,13 +2595,13 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa p = uq.buf; } read_next_command(); - parse_and_store_blob(&last_blob, sha1, 0); + parse_and_store_blob(&last_blob, &oid, 0); } else if (oe) { if (oe->type != OBJ_BLOB) die("Not a blob (actually a %s): %s", typename(oe->type), command_buf.buf); - } else if (!is_null_sha1(sha1)) { - enum object_type type = sha1_object_info(sha1, NULL); + } else if (!is_null_oid(&oid)) { + enum object_type type = sha1_object_info(oid.hash, NULL); if (type < 0) die("Blob not found: %s", command_buf.buf); if (type != OBJ_BLOB) @@ -2600,50 +2609,51 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa typename(type), command_buf.buf); } - construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path); + construct_path_with_fanout(oid_to_hex(&commit_oid), *old_fanout, path); if (tree_content_remove(&b->branch_tree, path, NULL, 0)) b->num_notes--; - if (is_null_sha1(sha1)) + if (is_null_oid(&oid)) return; /* nothing to insert */ b->num_notes++; new_fanout = convert_num_notes_to_fanout(b->num_notes); - construct_path_with_fanout(sha1_to_hex(commit_sha1), new_fanout, path); - tree_content_set(&b->branch_tree, path, sha1, S_IFREG | 0644, NULL); + construct_path_with_fanout(oid_to_hex(&commit_oid), new_fanout, path); + tree_content_set(&b->branch_tree, path, &oid, S_IFREG | 0644, NULL); } static void file_change_deleteall(struct branch *b) { release_tree_content_recursive(b->branch_tree.tree); - hashclr(b->branch_tree.versions[0].sha1); - hashclr(b->branch_tree.versions[1].sha1); + oidclr(&b->branch_tree.versions[0].oid); + oidclr(&b->branch_tree.versions[1].oid); load_tree(&b->branch_tree); b->num_notes = 0; } static void parse_from_commit(struct branch *b, char *buf, unsigned long size) { - if (!buf || size < 46) - die("Not a valid commit: %s", sha1_to_hex(b->sha1)); + if (!buf || size < GIT_SHA1_HEXSZ + 6) + die("Not a valid commit: %s", oid_to_hex(&b->oid)); if (memcmp("tree ", buf, 5) - || get_sha1_hex(buf + 5, b->branch_tree.versions[1].sha1)) - die("The commit %s is corrupt", sha1_to_hex(b->sha1)); - hashcpy(b->branch_tree.versions[0].sha1, - b->branch_tree.versions[1].sha1); + || get_oid_hex(buf + 5, &b->branch_tree.versions[1].oid)) + die("The commit %s is corrupt", oid_to_hex(&b->oid)); + oidcpy(&b->branch_tree.versions[0].oid, + &b->branch_tree.versions[1].oid); } static void parse_from_existing(struct branch *b) { - if (is_null_sha1(b->sha1)) { - hashclr(b->branch_tree.versions[0].sha1); - hashclr(b->branch_tree.versions[1].sha1); + if (is_null_oid(&b->oid)) { + oidclr(&b->branch_tree.versions[0].oid); + oidclr(&b->branch_tree.versions[1].oid); } else { unsigned long size; char *buf; - buf = read_object_with_reference(b->sha1, - commit_type, &size, b->sha1); + buf = read_object_with_reference(b->oid.hash, + commit_type, &size, + b->oid.hash); parse_from_commit(b, buf, size); free(buf); } @@ -2653,28 +2663,28 @@ static int parse_from(struct branch *b) { const char *from; struct branch *s; - unsigned char sha1[20]; + struct object_id oid; if (!skip_prefix(command_buf.buf, "from ", &from)) return 0; - hashcpy(sha1, b->branch_tree.versions[1].sha1); + oidcpy(&oid, &b->branch_tree.versions[1].oid); s = lookup_branch(from); if (b == s) die("Can't create a branch from itself: %s", b->name); else if (s) { - unsigned char *t = s->branch_tree.versions[1].sha1; - hashcpy(b->sha1, s->sha1); - hashcpy(b->branch_tree.versions[0].sha1, t); - hashcpy(b->branch_tree.versions[1].sha1, t); + struct object_id *t = &s->branch_tree.versions[1].oid; + oidcpy(&b->oid, &s->oid); + oidcpy(&b->branch_tree.versions[0].oid, t); + oidcpy(&b->branch_tree.versions[1].oid, t); } else if (*from == ':') { uintmax_t idnum = parse_mark_ref_eol(from); struct object_entry *oe = find_mark(idnum); if (oe->type != OBJ_COMMIT) die("Mark :%" PRIuMAX " not a commit", idnum); - if (hashcmp(b->sha1, oe->idx.sha1)) { - hashcpy(b->sha1, oe->idx.sha1); + if (oidcmp(&b->oid, &oe->idx.oid)) { + oidcpy(&b->oid, &oe->idx.oid); if (oe->pack_id != MAX_PACK_ID) { unsigned long size; char *buf = gfi_unpack_entry(oe, &size); @@ -2683,15 +2693,15 @@ static int parse_from(struct branch *b) } else parse_from_existing(b); } - } else if (!get_sha1(from, b->sha1)) { + } else if (!get_oid(from, &b->oid)) { parse_from_existing(b); - if (is_null_sha1(b->sha1)) + if (is_null_oid(&b->oid)) b->delete = 1; } else die("Invalid ref name or SHA1 expression: %s", from); - if (b->branch_tree.tree && hashcmp(sha1, b->branch_tree.versions[1].sha1)) { + if (b->branch_tree.tree && oidcmp(&oid, &b->branch_tree.versions[1].oid)) { release_tree_content_recursive(b->branch_tree.tree); b->branch_tree.tree = NULL; } @@ -2711,17 +2721,17 @@ static struct hash_list *parse_merge(unsigned int *count) n = xmalloc(sizeof(*n)); s = lookup_branch(from); if (s) - hashcpy(n->sha1, s->sha1); + oidcpy(&n->oid, &s->oid); else if (*from == ':') { uintmax_t idnum = parse_mark_ref_eol(from); struct object_entry *oe = find_mark(idnum); if (oe->type != OBJ_COMMIT) die("Mark :%" PRIuMAX " not a commit", idnum); - hashcpy(n->sha1, oe->idx.sha1); - } else if (!get_sha1(from, n->sha1)) { + oidcpy(&n->oid, &oe->idx.oid); + } else if (!get_oid(from, &n->oid)) { unsigned long size; - char *buf = read_object_with_reference(n->sha1, - commit_type, &size, n->sha1); + char *buf = read_object_with_reference(n->oid.hash, + commit_type, &size, n->oid.hash); if (!buf || size < 46) die("Not a valid commit: %s", from); free(buf); @@ -2808,17 +2818,19 @@ static void parse_new_commit(const char *arg) /* build the tree and the commit */ store_tree(&b->branch_tree); - hashcpy(b->branch_tree.versions[0].sha1, - b->branch_tree.versions[1].sha1); + oidcpy(&b->branch_tree.versions[0].oid, + &b->branch_tree.versions[1].oid); strbuf_reset(&new_data); strbuf_addf(&new_data, "tree %s\n", - sha1_to_hex(b->branch_tree.versions[1].sha1)); - if (!is_null_sha1(b->sha1)) - strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(b->sha1)); + oid_to_hex(&b->branch_tree.versions[1].oid)); + if (!is_null_oid(&b->oid)) + strbuf_addf(&new_data, "parent %s\n", + oid_to_hex(&b->oid)); while (merge_list) { struct hash_list *next = merge_list->next; - strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(merge_list->sha1)); + strbuf_addf(&new_data, "parent %s\n", + oid_to_hex(&merge_list->oid)); free(merge_list); merge_list = next; } @@ -2831,7 +2843,7 @@ static void parse_new_commit(const char *arg) free(author); free(committer); - if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark)) + if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark)) b->pack_id = pack_id; b->last_commit = object_count_by_type[OBJ_COMMIT]; } @@ -2844,7 +2856,7 @@ static void parse_new_tag(const char *arg) struct branch *s; struct tag *t; uintmax_t from_mark = 0; - unsigned char sha1[20]; + struct object_id oid; enum object_type type; const char *v; @@ -2863,20 +2875,20 @@ static void parse_new_tag(const char *arg) die("Expected from command, got %s", command_buf.buf); s = lookup_branch(from); if (s) { - if (is_null_sha1(s->sha1)) + if (is_null_oid(&s->oid)) die("Can't tag an empty branch."); - hashcpy(sha1, s->sha1); + oidcpy(&oid, &s->oid); type = OBJ_COMMIT; } else if (*from == ':') { struct object_entry *oe; from_mark = parse_mark_ref_eol(from); oe = find_mark(from_mark); type = oe->type; - hashcpy(sha1, oe->idx.sha1); - } else if (!get_sha1(from, sha1)) { - struct object_entry *oe = find_object(sha1); + oidcpy(&oid, &oe->idx.oid); + } else if (!get_oid(from, &oid)) { + struct object_entry *oe = find_object(&oid); if (!oe) { - type = sha1_object_info(sha1, NULL); + type = sha1_object_info(oid.hash, NULL); if (type < 0) die("Not a valid object: %s", from); } else @@ -2902,7 +2914,7 @@ static void parse_new_tag(const char *arg) "object %s\n" "type %s\n" "tag %s\n", - sha1_to_hex(sha1), typename(type), t->name); + oid_to_hex(&oid), typename(type), t->name); if (tagger) strbuf_addf(&new_data, "tagger %s\n", tagger); @@ -2910,7 +2922,7 @@ static void parse_new_tag(const char *arg) strbuf_addbuf(&new_data, &msg); free(tagger); - if (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0)) + if (store_object(OBJ_TAG, &new_data, NULL, &t->oid, 0)) t->pack_id = MAX_PACK_ID; else t->pack_id = pack_id; @@ -2922,9 +2934,9 @@ static void parse_reset_branch(const char *arg) b = lookup_branch(arg); if (b) { - hashclr(b->sha1); - hashclr(b->branch_tree.versions[0].sha1); - hashclr(b->branch_tree.versions[1].sha1); + oidclr(&b->oid); + oidclr(&b->branch_tree.versions[0].oid); + oidclr(&b->branch_tree.versions[1].oid); if (b->branch_tree.tree) { release_tree_content_recursive(b->branch_tree.tree); b->branch_tree.tree = NULL; @@ -2944,7 +2956,7 @@ static void cat_blob_write(const char *buf, unsigned long size) die_errno("Write to frontend failed"); } -static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) +static void cat_blob(struct object_entry *oe, struct object_id *oid) { struct strbuf line = STRBUF_INIT; unsigned long size; @@ -2952,7 +2964,7 @@ static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) char *buf; if (!oe || oe->pack_id == MAX_PACK_ID) { - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); } else { type = oe->type; buf = gfi_unpack_entry(oe, &size); @@ -2963,19 +2975,19 @@ static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) */ if (type <= 0) { strbuf_reset(&line); - strbuf_addf(&line, "%s missing\n", sha1_to_hex(sha1)); + strbuf_addf(&line, "%s missing\n", oid_to_hex(oid)); cat_blob_write(line.buf, line.len); strbuf_release(&line); free(buf); return; } if (!buf) - die("Can't read object %s", sha1_to_hex(sha1)); + die("Can't read object %s", oid_to_hex(oid)); if (type != OBJ_BLOB) die("Object %s is a %s but a blob was expected.", - sha1_to_hex(sha1), typename(type)); + oid_to_hex(oid), typename(type)); strbuf_reset(&line); - strbuf_addf(&line, "%s %s %lu\n", sha1_to_hex(sha1), + strbuf_addf(&line, "%s %s %lu\n", oid_to_hex(oid), typename(type), size); cat_blob_write(line.buf, line.len); strbuf_release(&line); @@ -2992,7 +3004,7 @@ static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) static void parse_get_mark(const char *p) { struct object_entry *oe = oe; - char output[42]; + char output[GIT_MAX_HEXSZ + 2]; /* get-mark SP LF */ if (*p != ':') @@ -3002,43 +3014,43 @@ static void parse_get_mark(const char *p) if (!oe) die("Unknown mark: %s", command_buf.buf); - xsnprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1)); - cat_blob_write(output, 41); + xsnprintf(output, sizeof(output), "%s\n", oid_to_hex(&oe->idx.oid)); + cat_blob_write(output, GIT_SHA1_HEXSZ + 1); } static void parse_cat_blob(const char *p) { struct object_entry *oe = oe; - unsigned char sha1[20]; + struct object_id oid; /* cat-blob SP LF */ if (*p == ':') { oe = find_mark(parse_mark_ref_eol(p)); if (!oe) die("Unknown mark: %s", command_buf.buf); - hashcpy(sha1, oe->idx.sha1); + oidcpy(&oid, &oe->idx.oid); } else { - if (get_sha1_hex(p, sha1)) + if (parse_oid_hex(p, &oid, &p)) die("Invalid dataref: %s", command_buf.buf); - if (p[40]) + if (*p) die("Garbage after SHA1: %s", command_buf.buf); - oe = find_object(sha1); + oe = find_object(&oid); } - cat_blob(oe, sha1); + cat_blob(oe, &oid); } static struct object_entry *dereference(struct object_entry *oe, - unsigned char sha1[20]) + struct object_id *oid) { unsigned long size; char *buf = NULL; if (!oe) { - enum object_type type = sha1_object_info(sha1, NULL); + enum object_type type = sha1_object_info(oid->hash, NULL); if (type < 0) - die("object not found: %s", sha1_to_hex(sha1)); + die("object not found: %s", oid_to_hex(oid)); /* cache it! */ - oe = insert_object(sha1); + oe = insert_object(oid); oe->type = type; oe->pack_id = MAX_PACK_ID; oe->idx.offset = 1; @@ -3057,49 +3069,48 @@ static struct object_entry *dereference(struct object_entry *oe, buf = gfi_unpack_entry(oe, &size); } else { enum object_type unused; - buf = read_sha1_file(sha1, &unused, &size); + buf = read_sha1_file(oid->hash, &unused, &size); } if (!buf) - die("Can't load object %s", sha1_to_hex(sha1)); + die("Can't load object %s", oid_to_hex(oid)); /* Peel one layer. */ switch (oe->type) { case OBJ_TAG: - if (size < 40 + strlen("object ") || - get_sha1_hex(buf + strlen("object "), sha1)) + if (size < GIT_SHA1_HEXSZ + strlen("object ") || + get_oid_hex(buf + strlen("object "), oid)) die("Invalid SHA1 in tag: %s", command_buf.buf); break; case OBJ_COMMIT: - if (size < 40 + strlen("tree ") || - get_sha1_hex(buf + strlen("tree "), sha1)) + if (size < GIT_SHA1_HEXSZ + strlen("tree ") || + get_oid_hex(buf + strlen("tree "), oid)) die("Invalid SHA1 in commit: %s", command_buf.buf); } free(buf); - return find_object(sha1); + return find_object(oid); } static struct object_entry *parse_treeish_dataref(const char **p) { - unsigned char sha1[20]; + struct object_id oid; struct object_entry *e; if (**p == ':') { /* */ e = find_mark(parse_mark_ref_space(p)); if (!e) die("Unknown mark: %s", command_buf.buf); - hashcpy(sha1, e->idx.sha1); + oidcpy(&oid, &e->idx.oid); } else { /* */ - if (get_sha1_hex(*p, sha1)) + if (parse_oid_hex(*p, &oid, p)) die("Invalid dataref: %s", command_buf.buf); - e = find_object(sha1); - *p += 40; + e = find_object(&oid); if (*(*p)++ != ' ') die("Missing space after tree-ish: %s", command_buf.buf); } while (!e || e->type != OBJ_TREE) - e = dereference(e, sha1); + e = dereference(e, &oid); return e; } @@ -3143,8 +3154,8 @@ static void parse_ls(const char *p, struct branch *b) } else { struct object_entry *e = parse_treeish_dataref(&p); root = new_tree_entry(); - hashcpy(root->versions[1].sha1, e->idx.sha1); - if (!is_null_sha1(root->versions[1].sha1)) + oidcpy(&root->versions[1].oid, &e->idx.oid); + if (!is_null_oid(&root->versions[1].oid)) root->versions[1].mode = S_IFDIR; load_tree(root); } @@ -3166,7 +3177,7 @@ static void parse_ls(const char *p, struct branch *b) if (S_ISDIR(leaf.versions[1].mode)) store_tree(&leaf); - print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p); + print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, p); if (leaf.tree) release_tree_content_recursive(leaf.tree); if (!b || root != &b->branch_tree) diff --git a/fetch-pack.c b/fetch-pack.c index afb8b05024..44fa047bf4 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -78,7 +78,7 @@ static void cache_one_alternate(const char *refname, void *vcache) { struct alternate_object_cache *cache = vcache; - struct object *obj = parse_object(oid->hash); + struct object *obj = parse_object(oid); if (!obj || (obj->flags & ALTERNATE)) return; @@ -118,9 +118,9 @@ static void rev_list_push(struct commit *commit, int mark) } } -static int rev_list_insert_ref(const char *refname, const unsigned char *sha1) +static int rev_list_insert_ref(const char *refname, const struct object_id *oid) { - struct object *o = deref_tag(parse_object(sha1), refname, 0); + struct object *o = deref_tag(parse_object(oid), refname, 0); if (o && o->type == OBJ_COMMIT) rev_list_push((struct commit *)o, SEEN); @@ -131,13 +131,13 @@ static int rev_list_insert_ref(const char *refname, const unsigned char *sha1) static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - return rev_list_insert_ref(refname, oid->hash); + return rev_list_insert_ref(refname, oid); } static int clear_marks(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - struct object *o = deref_tag(parse_object(oid->hash), refname, 0); + struct object *o = deref_tag(parse_object(oid), refname, 0); if (o && o->type == OBJ_COMMIT) clear_commit_marks((struct commit *)o, @@ -183,7 +183,7 @@ static void mark_common(struct commit *commit, Get the next rev to send, ignoring the common. */ -static const unsigned char *get_rev(void) +static const struct object_id *get_rev(void) { struct commit *commit = NULL; @@ -222,7 +222,7 @@ static const unsigned char *get_rev(void) } } - return commit->object.oid.hash; + return &commit->object.oid; } enum ack_type { @@ -251,7 +251,7 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd) } } -static enum ack_type get_ack(int fd, unsigned char *result_sha1) +static enum ack_type get_ack(int fd, struct object_id *result_oid) { int len; char *line = packet_read_line(fd, &len); @@ -262,7 +262,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1) if (!strcmp(line, "NAK")) return NAK; if (skip_prefix(line, "ACK ", &arg)) { - if (!get_sha1_hex(arg, result_sha1)) { + if (!get_oid_hex(arg, result_oid)) { arg += 40; len -= arg - line; if (len < 1) @@ -293,7 +293,7 @@ static void send_request(struct fetch_pack_args *args, static void insert_one_alternate_object(struct object *obj) { - rev_list_insert_ref(NULL, obj->oid.hash); + rev_list_insert_ref(NULL, &obj->oid); } #define INITIAL_FLUSH 16 @@ -317,12 +317,12 @@ static int next_flush(struct fetch_pack_args *args, int count) } static int find_common(struct fetch_pack_args *args, - int fd[2], unsigned char *result_sha1, + int fd[2], struct object_id *result_oid, struct ref *refs) { int fetching; int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; - const unsigned char *sha1; + const struct object_id *oid; unsigned in_vain = 0; int got_continue = 0; int got_ready = 0; @@ -340,7 +340,7 @@ static int find_common(struct fetch_pack_args *args, fetching = 0; for ( ; refs ; refs = refs->next) { - unsigned char *remote = refs->old_oid.hash; + struct object_id *remote = &refs->old_oid; const char *remote_hex; struct object *o; @@ -354,12 +354,12 @@ static int find_common(struct fetch_pack_args *args, * interested in the case we *know* the object is * reachable and we have already scanned it. */ - if (((o = lookup_object(remote)) != NULL) && + if (((o = lookup_object(remote->hash)) != NULL) && (o->flags & COMPLETE)) { continue; } - remote_hex = sha1_to_hex(remote); + remote_hex = oid_to_hex(remote); if (!fetching) { struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); @@ -394,8 +394,8 @@ static int find_common(struct fetch_pack_args *args, if (args->depth > 0) packet_buf_write(&req_buf, "deepen %d", args->depth); if (args->deepen_since) { - unsigned long max_age = approxidate(args->deepen_since); - packet_buf_write(&req_buf, "deepen-since %lu", max_age); + timestamp_t max_age = approxidate(args->deepen_since); + packet_buf_write(&req_buf, "deepen-since %"PRItime, max_age); } if (args->deepen_not) { int i; @@ -410,25 +410,25 @@ static int find_common(struct fetch_pack_args *args, if (args->deepen) { char *line; const char *arg; - unsigned char sha1[20]; + struct object_id oid; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { if (skip_prefix(line, "shallow ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), line); - register_shallow(sha1); + register_shallow(&oid); continue; } if (skip_prefix(line, "unshallow ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die(_("invalid unshallow line: %s"), line); - if (!lookup_object(sha1)) + if (!lookup_object(oid.hash)) die(_("object not found: %s"), line); /* make sure that it is parsed as shallow */ - if (!parse_object(sha1)) + if (!parse_object(&oid)) die(_("error in object: %s"), line); - if (unregister_shallow(sha1)) + if (unregister_shallow(&oid)) die(_("no shallow found: %s"), line); continue; } @@ -447,9 +447,9 @@ static int find_common(struct fetch_pack_args *args, flushes = 0; retval = -1; - while ((sha1 = get_rev())) { - packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1)); - print_verbose(args, "have %s", sha1_to_hex(sha1)); + while ((oid = get_rev())) { + packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid)); + print_verbose(args, "have %s", oid_to_hex(oid)); in_vain++; if (flush_at <= ++count) { int ack; @@ -469,10 +469,10 @@ static int find_common(struct fetch_pack_args *args, consume_shallow_list(args, fd[0]); do { - ack = get_ack(fd[0], result_sha1); + ack = get_ack(fd[0], result_oid); if (ack) print_verbose(args, _("got %s %d %s"), "ack", - ack, sha1_to_hex(result_sha1)); + ack, oid_to_hex(result_oid)); switch (ack) { case ACK: flushes = 0; @@ -483,9 +483,9 @@ static int find_common(struct fetch_pack_args *args, case ACK_ready: case ACK_continue: { struct commit *commit = - lookup_commit(result_sha1); + lookup_commit(result_oid); if (!commit) - die(_("invalid commit %s"), sha1_to_hex(result_sha1)); + die(_("invalid commit %s"), oid_to_hex(result_oid)); if (args->stateless_rpc && ack == ACK_common && !(commit->object.flags & COMMON)) { @@ -493,7 +493,7 @@ static int find_common(struct fetch_pack_args *args, * on the next RPC request so the peer knows * it is in common with us. */ - const char *hex = sha1_to_hex(result_sha1); + const char *hex = oid_to_hex(result_oid); packet_buf_write(&req_buf, "have %s\n", hex); state_len = req_buf.len; /* @@ -538,10 +538,10 @@ static int find_common(struct fetch_pack_args *args, if (!got_ready || !no_done) consume_shallow_list(args, fd[0]); while (flushes || multi_ack) { - int ack = get_ack(fd[0], result_sha1); + int ack = get_ack(fd[0], result_oid); if (ack) { print_verbose(args, _("got %s (%d) %s"), "ack", - ack, sha1_to_hex(result_sha1)); + ack, oid_to_hex(result_oid)); if (ack == ACK) return 0; multi_ack = 1; @@ -555,16 +555,16 @@ static int find_common(struct fetch_pack_args *args, static struct commit_list *complete; -static int mark_complete(const unsigned char *sha1) +static int mark_complete(const struct object_id *oid) { - struct object *o = parse_object(sha1); + struct object *o = parse_object(oid); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o->flags |= COMPLETE; - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; @@ -579,11 +579,11 @@ static int mark_complete(const unsigned char *sha1) static int mark_complete_oid(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - return mark_complete(oid->hash); + return mark_complete(oid); } static void mark_recent_complete_commits(struct fetch_pack_args *args, - unsigned long cutoff) + timestamp_t cutoff) { while (complete && cutoff <= complete->item->date) { print_verbose(args, _("Marking %s as complete"), @@ -637,14 +637,15 @@ static void filter_refs(struct fetch_pack_args *args, /* Append unmatched requests to the list */ for (i = 0; i < nr_sought; i++) { - unsigned char sha1[20]; + struct object_id oid; + const char *p; ref = sought[i]; if (ref->match_status != REF_NOT_MATCHED) continue; - if (get_sha1_hex(ref->name, sha1) || - ref->name[40] != '\0' || - hashcmp(sha1, ref->old_oid.hash)) + if (parse_oid_hex(ref->name, &oid, &p) || + *p != '\0' || + oidcmp(&oid, &ref->old_oid)) continue; if ((allow_unadvertised_object_request & @@ -661,7 +662,7 @@ static void filter_refs(struct fetch_pack_args *args, static void mark_alternate_complete(struct object *obj) { - mark_complete(obj->oid.hash); + mark_complete(&obj->oid); } static int everything_local(struct fetch_pack_args *args, @@ -670,7 +671,7 @@ static int everything_local(struct fetch_pack_args *args, { struct ref *ref; int retval; - unsigned long cutoff = 0; + timestamp_t cutoff = 0; save_commit_buffer = 0; @@ -680,7 +681,7 @@ static int everything_local(struct fetch_pack_args *args, if (!has_object_file(&ref->old_oid)) continue; - o = parse_object(ref->old_oid.hash); + o = parse_object(&ref->old_oid); if (!o) continue; @@ -724,17 +725,17 @@ static int everything_local(struct fetch_pack_args *args, filter_refs(args, refs, sought, nr_sought); for (retval = 1, ref = *refs; ref ; ref = ref->next) { - const unsigned char *remote = ref->old_oid.hash; + const struct object_id *remote = &ref->old_oid; struct object *o; - o = lookup_object(remote); + o = lookup_object(remote->hash); if (!o || !(o->flags & COMPLETE)) { retval = 0; - print_verbose(args, "want %s (%s)", sha1_to_hex(remote), + print_verbose(args, "want %s (%s)", oid_to_hex(remote), ref->name); continue; } - print_verbose(args, _("already have %s (%s)"), sha1_to_hex(remote), + print_verbose(args, _("already have %s (%s)"), oid_to_hex(remote), ref->name); } return retval; @@ -873,7 +874,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); - unsigned char sha1[20]; + struct object_id oid; const char *agent_feature; int agent_len; @@ -945,7 +946,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, packet_flush(fd[1]); goto all_done; } - if (find_common(args, fd, sha1, ref) < 0) + if (find_common(args, fd, &oid, ref) < 0) if (!args->keep_pack) /* When cloning, it is not unusual to have * no common commit. diff --git a/fsck.c b/fsck.c index e6152e4e6d..b4204d772b 100644 --- a/fsck.c +++ b/fsck.c @@ -358,14 +358,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op continue; if (S_ISDIR(entry.mode)) { - obj = &lookup_tree(entry.oid->hash)->object; + obj = &lookup_tree(entry.oid)->object; if (name) put_object_name(options, obj, "%s%s/", name, entry.path); result = options->walk(obj, OBJ_TREE, data, options); } else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) { - obj = &lookup_blob(entry.oid->hash)->object; + obj = &lookup_blob(entry.oid)->object; if (name) put_object_name(options, obj, "%s%s", name, entry.path); @@ -461,7 +461,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options) return -1; if (obj->type == OBJ_NONE) - parse_object(obj->oid.hash); + parse_object(&obj->oid); switch (obj->type) { case OBJ_BLOB: @@ -691,7 +691,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option p++; if (*p == '0' && p[1] != ' ') return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date"); - if (date_overflows(strtoul(p, &end, 10))) + if (date_overflows(parse_timestamp(p, &end, 10))) return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow"); if ((end == p || *end != ' ')) return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date"); diff --git a/git-compat-util.h b/git-compat-util.h index bd04564a69..98670a3c9a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -319,6 +319,11 @@ extern char *gitdirname(char *); #define PRIo32 "o" #endif +typedef uintmax_t timestamp_t; +#define PRItime PRIuMAX +#define parse_timestamp strtoumax +#define TIME_MAX UINTMAX_MAX + #ifndef PATH_SEP #define PATH_SEP ':' #endif @@ -616,7 +621,7 @@ extern int git_lstat(const char *, struct stat *); #endif #define DEFAULT_PACKED_GIT_LIMIT \ - ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256)) + ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256)) #ifdef NO_PREAD #define pread git_pread @@ -1064,6 +1069,15 @@ static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size, #define HAVE_VARIADIC_MACROS 1 #endif +#ifdef HAVE_VARIADIC_MACROS +__attribute__((format (printf, 3, 4))) NORETURN +void BUG_fl(const char *file, int line, const char *fmt, ...); +#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__) +#else +__attribute__((format (printf, 1, 2))) NORETURN +void BUG(const char *fmt, ...); +#endif + /* * Preserves errno, prints a message, but gives no warning for ENOENT. * Returns 0 on success, which includes trying to unlink an object that does diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 2b8cdba157..aafaf708da 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -239,7 +239,7 @@ git rev-parse --no-flags --revs-only --symbolic-full-name \ sed -e '/^^/d' "$tempdir"/raw-heads >"$tempdir"/heads test -s "$tempdir"/heads || - die "Which ref do you want to rewrite?" + die "You must specify a ref to rewrite." GIT_INDEX_FILE="$(pwd)/../index" export GIT_INDEX_FILE diff --git a/git-gui/.gitattributes b/git-gui/.gitattributes index 33d07c06bd..59cd41dbff 100644 --- a/git-gui/.gitattributes +++ b/git-gui/.gitattributes @@ -2,3 +2,4 @@ * encoding=US-ASCII git-gui.sh encoding=UTF-8 /po/*.po encoding=UTF-8 +/GIT-VERSION-GEN eol=lf diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 2c9c0165b5..90b1fbe9cf 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -5,7 +5,7 @@ # Copyright (c) 2006 Johannes E. Schindelin # # The original idea comes from Eric W. Biederman, in -# http://article.gmane.org/gmane.comp.version-control.git/22407 +# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/ # # The file containing rebase commands, comments, and empty lines. # This file is created by "git rebase -i" then edited by the user. As diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7cf68f07b7..d8209c7a02 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -8085,7 +8085,7 @@ sub git_search_help {

Pattern is by default a normal string that is matched precisely (but without regard to case, except in the case of pickaxe). However, when you check the re checkbox, the pattern entered is recognized as the POSIX extended -regular expression (also case +regular expression (also case insensitive).

commit
diff --git a/help.c b/help.c index bc6cd19cf3..a07f01e6f9 100644 --- a/help.c +++ b/help.c @@ -411,8 +411,8 @@ const char *help_unknown_cmd(const char *cmd) if (SIMILAR_ENOUGH(best_similarity)) { fprintf_ln(stderr, - Q_("\nDid you mean this?", - "\nDid you mean one of these?", + Q_("\nThe most similar command is", + "\nThe most similar commands are", n)); for (i = 0; i < n; i++) diff --git a/http-backend.c b/http-backend.c index eef0a361f4..ba5ff1aa29 100644 --- a/http-backend.c +++ b/http-backend.c @@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value) strbuf_addf(hdr, "%s: %" PRIuMAX "\r\n", name, value); } -static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when) +static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when) { const char *value = show_date(when, 0, DATE_MODE(RFC2822)); hdr_str(hdr, name, value); @@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr) static void hdr_cache_forever(struct strbuf *hdr) { - unsigned long now = time(NULL); + timestamp_t now = time(NULL); hdr_date(hdr, "Date", now); hdr_date(hdr, "Expires", now + 31536000); hdr_str(hdr, "Cache-Control", "public, max-age=31536000"); @@ -431,7 +431,7 @@ static int show_text_ref(const char *name, const struct object_id *oid, { const char *name_nons = strip_namespace(name); struct strbuf *buf = cb_data; - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); if (!o) return 0; diff --git a/http-push.c b/http-push.c index f0e3108f71..67c4d4b472 100644 --- a/http-push.c +++ b/http-push.c @@ -718,13 +718,13 @@ static int fetch_indices(void) return ret; } -static void one_remote_object(const unsigned char *sha1) +static void one_remote_object(const struct object_id *oid) { struct object *obj; - obj = lookup_object(sha1); + obj = lookup_object(oid->hash); if (!obj) - obj = parse_object(sha1); + obj = parse_object(oid); /* Ignore remote objects that don't exist locally */ if (!obj) @@ -1013,26 +1013,26 @@ static void remote_ls(const char *path, int flags, void *userData); /* extract hex from sharded "xx/x{40}" filename */ -static int get_sha1_hex_from_objpath(const char *path, unsigned char *sha1) +static int get_oid_hex_from_objpath(const char *path, struct object_id *oid) { - char hex[40]; + char hex[GIT_MAX_HEXSZ]; - if (strlen(path) != 41) + if (strlen(path) != GIT_SHA1_HEXSZ + 1) return -1; memcpy(hex, path, 2); path += 2; path++; /* skip '/' */ - memcpy(hex, path, 38); + memcpy(hex, path, GIT_SHA1_HEXSZ - 2); - return get_sha1_hex(hex, sha1); + return get_oid_hex(hex, oid); } static void process_ls_object(struct remote_ls_ctx *ls) { unsigned int *parent = (unsigned int *)ls->userData; const char *path = ls->dentry_name; - unsigned char sha1[20]; + struct object_id oid; if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) { remote_dir_exists[*parent] = 1; @@ -1040,10 +1040,10 @@ static void process_ls_object(struct remote_ls_ctx *ls) } if (!skip_prefix(path, "objects/", &path) || - get_sha1_hex_from_objpath(path, sha1)) + get_oid_hex_from_objpath(path, &oid)) return; - one_remote_object(sha1); + one_remote_object(&oid); } static void process_ls_ref(struct remote_ls_ctx *ls) @@ -1312,10 +1312,10 @@ static struct object_list **process_tree(struct tree *tree, while (tree_entry(&desc, &entry)) switch (object_type(entry.mode)) { case OBJ_TREE: - p = process_tree(lookup_tree(entry.oid->hash), p); + p = process_tree(lookup_tree(entry.oid), p); break; case OBJ_BLOB: - p = process_blob(lookup_blob(entry.oid->hash), p); + p = process_blob(lookup_blob(entry.oid), p); break; default: /* Subproject commit - not in this repository */ @@ -1462,7 +1462,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls) return; } - o = parse_object(ref->old_oid.hash); + o = parse_object(&ref->old_oid); if (!o) { fprintf(stderr, "Unable to parse object %s for remote ref %s\n", @@ -1536,7 +1536,7 @@ static int remote_exists(const char *path) return ret; } -static void fetch_symref(const char *path, char **symref, unsigned char *sha1) +static void fetch_symref(const char *path, char **symref, struct object_id *oid) { char *url = xstrfmt("%s%s", repo->url, path); struct strbuf buffer = STRBUF_INIT; @@ -1549,7 +1549,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) free(*symref); *symref = NULL; - hashclr(sha1); + oidclr(oid); if (buffer.len == 0) return; @@ -1561,16 +1561,17 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) if (skip_prefix(buffer.buf, "ref: ", &name)) { *symref = xmemdupz(name, buffer.len - (name - buffer.buf)); } else { - get_sha1_hex(buffer.buf, sha1); + get_oid_hex(buffer.buf, oid); } strbuf_release(&buffer); } -static int verify_merge_base(unsigned char *head_sha1, struct ref *remote) +static int verify_merge_base(struct object_id *head_oid, struct ref *remote) { - struct commit *head = lookup_commit_or_die(head_sha1, "HEAD"); - struct commit *branch = lookup_commit_or_die(remote->old_oid.hash, remote->name); + struct commit *head = lookup_commit_or_die(head_oid, "HEAD"); + struct commit *branch = lookup_commit_or_die(&remote->old_oid, + remote->name); return in_merge_bases(branch, head); } @@ -1579,7 +1580,7 @@ static int delete_remote_branch(const char *pattern, int force) { struct ref *refs = remote_refs; struct ref *remote_ref = NULL; - unsigned char head_sha1[20]; + struct object_id head_oid; char *symref = NULL; int match; int patlen = strlen(pattern); @@ -1610,7 +1611,7 @@ static int delete_remote_branch(const char *pattern, int force) * Remote HEAD must be a symref (not exactly foolproof; a remote * symlink to a symref will look like a symref) */ - fetch_symref("HEAD", &symref, head_sha1); + fetch_symref("HEAD", &symref, &head_oid); if (!symref) return error("Remote HEAD is not a symref"); @@ -1619,7 +1620,7 @@ static int delete_remote_branch(const char *pattern, int force) if (!strcmp(remote_ref->name, symref)) return error("Remote branch %s is the current HEAD", remote_ref->name); - fetch_symref(symref, &symref, head_sha1); + fetch_symref(symref, &symref, &head_oid); } /* Run extra sanity checks if delete is not forced */ @@ -1627,10 +1628,10 @@ static int delete_remote_branch(const char *pattern, int force) /* Remote HEAD must resolve to a known object */ if (symref) return error("Remote HEAD symrefs too deep"); - if (is_null_sha1(head_sha1)) + if (is_null_oid(&head_oid)) return error("Unable to resolve remote HEAD"); - if (!has_sha1_file(head_sha1)) - return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", sha1_to_hex(head_sha1)); + if (!has_object_file(&head_oid)) + return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", oid_to_hex(&head_oid)); /* Remote branch must resolve to a known object */ if (is_null_oid(&remote_ref->old_oid)) @@ -1640,7 +1641,7 @@ static int delete_remote_branch(const char *pattern, int force) return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, oid_to_hex(&remote_ref->old_oid)); /* Remote branch must be an ancestor of remote HEAD */ - if (!verify_merge_base(head_sha1, remote_ref)) { + if (!verify_merge_base(&head_oid, remote_ref)) { return error("The branch '%s' is not an ancestor " "of your current HEAD.\n" "If you are sure you want to delete it," diff --git a/line-log.c b/line-log.c index a23b910471..b9087814b8 100644 --- a/line-log.c +++ b/line-log.c @@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c changed = process_all_files(&parent_range, rev, &queue, range); if (parent) add_line_range(rev, parent, parent_range); + free_line_log_data(parent_range); return changed; } diff --git a/list-objects.c b/list-objects.c index f3ca6aafb7..b3931fa434 100644 --- a/list-objects.c +++ b/list-objects.c @@ -110,7 +110,7 @@ static void process_tree(struct rev_info *revs, if (S_ISDIR(entry.mode)) process_tree(revs, - lookup_tree(entry.oid->hash), + lookup_tree(entry.oid), show, base, entry.path, cb_data); else if (S_ISGITLINK(entry.mode)) @@ -119,7 +119,7 @@ static void process_tree(struct rev_info *revs, cb_data); else process_blob(revs, - lookup_blob(entry.oid->hash), + lookup_blob(entry.oid), show, base, entry.path, cb_data); } diff --git a/log-tree.c b/log-tree.c index 4618dd04ca..a4ec11c2bf 100644 --- a/log-tree.c +++ b/log-tree.c @@ -105,13 +105,13 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid, warning("invalid replace ref %s", refname); return 0; } - obj = parse_object(original_oid.hash); + obj = parse_object(&original_oid); if (obj) add_name_decoration(DECORATION_GRAFTED, "replaced", obj); return 0; } - obj = parse_object(oid->hash); + obj = parse_object(oid); if (!obj) return 0; @@ -132,7 +132,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid, if (!obj) break; if (!obj->parsed) - parse_object(obj->oid.hash); + parse_object(&obj->oid); add_name_decoration(DECORATION_REF_TAG, refname, obj); } return 0; @@ -140,7 +140,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid, static int add_graft_decoration(const struct commit_graft *graft, void *cb_data) { - struct commit *commit = lookup_commit(graft->oid.hash); + struct commit *commit = lookup_commit(&graft->oid); if (!commit) return 0; add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object); @@ -184,7 +184,7 @@ static const struct name_decoration *current_pointed_by_HEAD(const struct name_d { const struct name_decoration *list, *head = NULL; const char *branch_name = NULL; - unsigned char unused[20]; + struct object_id unused; int rru_flags; /* First find HEAD */ @@ -197,7 +197,7 @@ static const struct name_decoration *current_pointed_by_HEAD(const struct name_d return NULL; /* Now resolve and find the matching current branch */ - branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags); + branch_name = resolve_ref_unsafe("HEAD", 0, unused.hash, &rru_flags); if (!(rru_flags & REF_ISSYMREF)) return NULL; @@ -456,13 +456,13 @@ static void show_signature(struct rev_info *opt, struct commit *commit) strbuf_release(&signature); } -static int which_parent(const unsigned char *sha1, const struct commit *commit) +static int which_parent(const struct object_id *oid, const struct commit *commit) { int nth; const struct commit_list *parent; for (nth = 0, parent = commit->parents; parent; parent = parent->next) { - if (!hashcmp(parent->item->object.oid.hash, sha1)) + if (!oidcmp(&parent->item->object.oid, oid)) return nth; nth++; } @@ -481,14 +481,14 @@ static void show_one_mergetag(struct commit *commit, void *data) { struct rev_info *opt = (struct rev_info *)data; - unsigned char sha1[20]; + struct object_id oid; struct tag *tag; struct strbuf verify_message; int status, nth; size_t payload_size, gpg_message_offset; - hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1); - tag = lookup_tag(sha1); + hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), oid.hash); + tag = lookup_tag(&oid); if (!tag) return; /* error message already given */ @@ -500,7 +500,7 @@ static void show_one_mergetag(struct commit *commit, &commit->parents->next->item->object.oid)) strbuf_addf(&verify_message, "merged tag '%s'\n", tag->tag); - else if ((nth = which_parent(tag->tagged->oid.hash, commit)) < 0) + else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0) strbuf_addf(&verify_message, "tag %s names a non-parent %s\n", tag->tag, tag->tagged->oid.hash); else @@ -536,7 +536,7 @@ void show_log(struct rev_info *opt) struct strbuf msgbuf = STRBUF_INIT; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; - int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; + int abbrev_commit = opt->abbrev_commit ? opt->abbrev : GIT_SHA1_HEXSZ; const char *extra_headers = opt->extra_headers; struct pretty_print_context ctx = {0}; diff --git a/mailinfo.c b/mailinfo.c index 68037758f2..f92cb9f729 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in) for (;;) { int peek; - peek = fgetc(in); ungetc(peek, in); + peek = fgetc(in); + if (peek == EOF) + break; + ungetc(peek, in); if (peek != ' ' && peek != '\t') break; if (strbuf_getline_lf(&continuation, in)) @@ -1099,6 +1102,10 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch) do { peek = fgetc(mi->input); + if (peek == EOF) { + fclose(cmitmsg); + return error("empty patch: '%s'", patch); + } } while (isspace(peek)); ungetc(peek, mi->input); diff --git a/merge-recursive.c b/merge-recursive.c index 62decd51cc..ae5238d82c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -67,7 +67,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two, } if (!oidcmp(&two->object.oid, &shifted)) return two; - return lookup_tree(shifted.hash); + return lookup_tree(&shifted); } static struct commit *make_virtual_commit(struct tree *tree, const char *comment) @@ -304,7 +304,7 @@ struct tree *write_tree_from_memory(struct merge_options *o) return NULL; } - result = lookup_tree(active_cache_tree->sha1); + result = lookup_tree(&active_cache_tree->oid); return result; } @@ -994,11 +994,11 @@ static int merge_file_1(struct merge_options *o, return ret; result->clean = (merge_status == 0); } else if (S_ISGITLINK(a->mode)) { - result->clean = merge_submodule(result->oid.hash, + result->clean = merge_submodule(&result->oid, one->path, - one->oid.hash, - a->oid.hash, - b->oid.hash, + &one->oid, + &a->oid, + &b->oid, !o->call_depth); } else if (S_ISLNK(a->mode)) { oidcpy(&result->oid, &a->oid); @@ -2042,7 +2042,7 @@ int merge_recursive(struct merge_options *o, /* if there is no common ancestor, use an empty tree */ struct tree *tree; - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } @@ -2103,7 +2103,7 @@ static struct commit *get_ref(const struct object_id *oid, const char *name) { struct object *object; - object = deref_tag(parse_object(oid->hash), name, strlen(name)); + object = deref_tag(parse_object(oid), name, strlen(name)); if (!object) return NULL; if (object->type == OBJ_TREE) diff --git a/merge.c b/merge.c index 04ee5fc911..1d441ad942 100644 --- a/merge.c +++ b/merge.c @@ -44,8 +44,8 @@ int try_merge_command(const char *strategy, size_t xopts_nr, return ret; } -int checkout_fast_forward(const unsigned char *head, - const unsigned char *remote, +int checkout_fast_forward(const struct object_id *head, + const struct object_id *remote, int overwrite_ignore) { struct tree *trees[MAX_UNPACK_TREES]; diff --git a/notes-cache.c b/notes-cache.c index 5dfc5cbd08..2843e98576 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -5,16 +5,16 @@ static int notes_cache_match_validity(const char *ref, const char *validity) { - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; struct pretty_print_context pretty_ctx; struct strbuf msg = STRBUF_INIT; int ret; - if (read_ref(ref, sha1) < 0) + if (read_ref(ref, oid.hash) < 0) return 0; - commit = lookup_commit_reference_gently(sha1, 1); + commit = lookup_commit_reference_gently(&oid, 1); if (!commit) return 0; @@ -46,8 +46,7 @@ void notes_cache_init(struct notes_cache *c, const char *name, int notes_cache_write(struct notes_cache *c) { - unsigned char tree_sha1[20]; - unsigned char commit_sha1[20]; + struct object_id tree_oid, commit_oid; if (!c || !c->tree.initialized || !c->tree.update_ref || !*c->tree.update_ref) @@ -55,19 +54,19 @@ int notes_cache_write(struct notes_cache *c) if (!c->tree.dirty) return 0; - if (write_notes_tree(&c->tree, tree_sha1)) + if (write_notes_tree(&c->tree, tree_oid.hash)) return -1; - if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL, - commit_sha1, NULL, NULL) < 0) + if (commit_tree(c->validity, strlen(c->validity), tree_oid.hash, NULL, + commit_oid.hash, NULL, NULL) < 0) return -1; - if (update_ref("update notes cache", c->tree.update_ref, commit_sha1, + if (update_ref("update notes cache", c->tree.update_ref, commit_oid.hash, NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0) return -1; return 0; } -char *notes_cache_get(struct notes_cache *c, unsigned char key_sha1[20], +char *notes_cache_get(struct notes_cache *c, struct object_id *key_oid, size_t *outsize) { const unsigned char *value_sha1; @@ -75,7 +74,7 @@ char *notes_cache_get(struct notes_cache *c, unsigned char key_sha1[20], char *value; unsigned long size; - value_sha1 = get_note(&c->tree, key_sha1); + value_sha1 = get_note(&c->tree, key_oid->hash); if (!value_sha1) return NULL; value = read_sha1_file(value_sha1, &type, &size); @@ -84,12 +83,12 @@ char *notes_cache_get(struct notes_cache *c, unsigned char key_sha1[20], return value; } -int notes_cache_put(struct notes_cache *c, unsigned char key_sha1[20], +int notes_cache_put(struct notes_cache *c, struct object_id *key_oid, const char *data, size_t size) { - unsigned char value_sha1[20]; + struct object_id value_oid; - if (write_sha1_file(data, size, "blob", value_sha1) < 0) + if (write_sha1_file(data, size, "blob", value_oid.hash) < 0) return -1; - return add_note(&c->tree, key_sha1, value_sha1, NULL); + return add_note(&c->tree, key_oid->hash, value_oid.hash, NULL); } diff --git a/notes-cache.h b/notes-cache.h index 356f88fb3c..aeeee8409d 100644 --- a/notes-cache.h +++ b/notes-cache.h @@ -12,9 +12,9 @@ void notes_cache_init(struct notes_cache *c, const char *name, const char *validity); int notes_cache_write(struct notes_cache *c); -char *notes_cache_get(struct notes_cache *c, unsigned char sha1[20], size_t +char *notes_cache_get(struct notes_cache *c, struct object_id *oid, size_t *outsize); -int notes_cache_put(struct notes_cache *c, unsigned char sha1[20], +int notes_cache_put(struct notes_cache *c, struct object_id *oid, const char *data, size_t size); #endif /* NOTES_CACHE_H */ diff --git a/notes-merge.c b/notes-merge.c index 32caaaff74..6244f6af9c 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -535,7 +535,7 @@ int notes_merge(struct notes_merge_options *o, struct notes_tree *local_tree, unsigned char *result_sha1) { - unsigned char local_sha1[20], remote_sha1[20]; + struct object_id local_oid, remote_oid; struct commit *local, *remote; struct commit_list *bases = NULL; const unsigned char *base_sha1, *base_tree_sha1; @@ -549,46 +549,46 @@ int notes_merge(struct notes_merge_options *o, o->local_ref, o->remote_ref); /* Dereference o->local_ref into local_sha1 */ - if (read_ref_full(o->local_ref, 0, local_sha1, NULL)) + if (read_ref_full(o->local_ref, 0, local_oid.hash, NULL)) die("Failed to resolve local notes ref '%s'", o->local_ref); else if (!check_refname_format(o->local_ref, 0) && - is_null_sha1(local_sha1)) + is_null_oid(&local_oid)) local = NULL; /* local_sha1 == null_sha1 indicates unborn ref */ - else if (!(local = lookup_commit_reference(local_sha1))) + else if (!(local = lookup_commit_reference(&local_oid))) die("Could not parse local commit %s (%s)", - sha1_to_hex(local_sha1), o->local_ref); - trace_printf("\tlocal commit: %.7s\n", sha1_to_hex(local_sha1)); + oid_to_hex(&local_oid), o->local_ref); + trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid)); /* Dereference o->remote_ref into remote_sha1 */ - if (get_sha1(o->remote_ref, remote_sha1)) { + if (get_oid(o->remote_ref, &remote_oid)) { /* * Failed to get remote_sha1. If o->remote_ref looks like an * unborn ref, perform the merge using an empty notes tree. */ if (!check_refname_format(o->remote_ref, 0)) { - hashclr(remote_sha1); + oidclr(&remote_oid); remote = NULL; } else { die("Failed to resolve remote notes ref '%s'", o->remote_ref); } - } else if (!(remote = lookup_commit_reference(remote_sha1))) { + } else if (!(remote = lookup_commit_reference(&remote_oid))) { die("Could not parse remote commit %s (%s)", - sha1_to_hex(remote_sha1), o->remote_ref); + oid_to_hex(&remote_oid), o->remote_ref); } - trace_printf("\tremote commit: %.7s\n", sha1_to_hex(remote_sha1)); + trace_printf("\tremote commit: %.7s\n", oid_to_hex(&remote_oid)); if (!local && !remote) die("Cannot merge empty notes ref (%s) into empty notes ref " "(%s)", o->remote_ref, o->local_ref); if (!local) { /* result == remote commit */ - hashcpy(result_sha1, remote_sha1); + hashcpy(result_sha1, remote_oid.hash); goto found_result; } if (!remote) { /* result == local commit */ - hashcpy(result_sha1, local_sha1); + hashcpy(result_sha1, local_oid.hash); goto found_result; } assert(local && remote); diff --git a/notes-utils.c b/notes-utils.c index 24a33616a4..325ff3daa3 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -7,18 +7,18 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, const char *msg, size_t msg_len, unsigned char *result_sha1) { - unsigned char tree_sha1[20]; + struct object_id tree_oid; assert(t->initialized); - if (write_notes_tree(t, tree_sha1)) + if (write_notes_tree(t, tree_oid.hash)) die("Failed to write notes tree to database"); if (!parents) { /* Deduce parent commit from t->ref */ - unsigned char parent_sha1[20]; - if (!read_ref(t->ref, parent_sha1)) { - struct commit *parent = lookup_commit(parent_sha1); + struct object_id parent_oid; + if (!read_ref(t->ref, parent_oid.hash)) { + struct commit *parent = lookup_commit(&parent_oid); if (parse_commit(parent)) die("Failed to find/parse commit %s", t->ref); commit_list_insert(parent, &parents); @@ -26,14 +26,14 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, /* else: t->ref points to nothing, assume root/orphan commit */ } - if (commit_tree(msg, msg_len, tree_sha1, parents, result_sha1, NULL, NULL)) + if (commit_tree(msg, msg_len, tree_oid.hash, parents, result_sha1, NULL, NULL)) die("Failed to commit notes tree to database"); } void commit_notes(struct notes_tree *t, const char *msg) { struct strbuf buf = STRBUF_INIT; - unsigned char commit_sha1[20]; + struct object_id commit_oid; if (!t) t = &default_notes_tree; @@ -46,9 +46,9 @@ void commit_notes(struct notes_tree *t, const char *msg) strbuf_addstr(&buf, msg); strbuf_complete_line(&buf); - create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1); + create_notes_commit(t, NULL, buf.buf, buf.len, commit_oid.hash); strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ - update_ref(buf.buf, t->update_ref, commit_sha1, NULL, 0, + update_ref(buf.buf, t->update_ref, commit_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); strbuf_release(&buf); diff --git a/object.c b/object.c index e680d881a4..06ba3a11d8 100644 --- a/object.c +++ b/object.c @@ -180,21 +180,21 @@ struct object *lookup_unknown_object(const unsigned char *sha1) return obj; } -struct object *parse_object_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten_p) +struct object *parse_object_buffer(const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p) { struct object *obj; *eaten_p = 0; obj = NULL; if (type == OBJ_BLOB) { - struct blob *blob = lookup_blob(sha1); + struct blob *blob = lookup_blob(oid); if (blob) { if (parse_blob_buffer(blob, buffer, size)) return NULL; obj = &blob->object; } } else if (type == OBJ_TREE) { - struct tree *tree = lookup_tree(sha1); + struct tree *tree = lookup_tree(oid); if (tree) { obj = &tree->object; if (!tree->buffer) @@ -206,7 +206,7 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t } } } else if (type == OBJ_COMMIT) { - struct commit *commit = lookup_commit(sha1); + struct commit *commit = lookup_commit(oid); if (commit) { if (parse_commit_buffer(commit, buffer, size)) return NULL; @@ -217,54 +217,54 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t obj = &commit->object; } } else if (type == OBJ_TAG) { - struct tag *tag = lookup_tag(sha1); + struct tag *tag = lookup_tag(oid); if (tag) { if (parse_tag_buffer(tag, buffer, size)) return NULL; obj = &tag->object; } } else { - warning("object %s has unknown type id %d", sha1_to_hex(sha1), type); + warning("object %s has unknown type id %d", oid_to_hex(oid), type); obj = NULL; } return obj; } -struct object *parse_object_or_die(const unsigned char *sha1, +struct object *parse_object_or_die(const struct object_id *oid, const char *name) { - struct object *o = parse_object(sha1); + struct object *o = parse_object(oid); if (o) return o; - die(_("unable to parse object: %s"), name ? name : sha1_to_hex(sha1)); + die(_("unable to parse object: %s"), name ? name : oid_to_hex(oid)); } -struct object *parse_object(const unsigned char *sha1) +struct object *parse_object(const struct object_id *oid) { unsigned long size; enum object_type type; int eaten; - const unsigned char *repl = lookup_replace_object(sha1); + const unsigned char *repl = lookup_replace_object(oid->hash); void *buffer; struct object *obj; - obj = lookup_object(sha1); + obj = lookup_object(oid->hash); if (obj && obj->parsed) return obj; if ((obj && obj->type == OBJ_BLOB) || - (!obj && has_sha1_file(sha1) && - sha1_object_info(sha1, NULL) == OBJ_BLOB)) { + (!obj && has_object_file(oid) && + sha1_object_info(oid->hash, NULL) == OBJ_BLOB)) { if (check_sha1_signature(repl, NULL, 0, NULL) < 0) { - error("sha1 mismatch %s", sha1_to_hex(repl)); + error("sha1 mismatch %s", oid_to_hex(oid)); return NULL; } - parse_blob_buffer(lookup_blob(sha1), NULL, 0); - return lookup_object(sha1); + parse_blob_buffer(lookup_blob(oid), NULL, 0); + return lookup_object(oid->hash); } - buffer = read_sha1_file(sha1, &type, &size); + buffer = read_sha1_file(oid->hash, &type, &size); if (buffer) { if (check_sha1_signature(repl, buffer, size, typename(type)) < 0) { free(buffer); @@ -272,7 +272,7 @@ struct object *parse_object(const unsigned char *sha1) return NULL; } - obj = parse_object_buffer(sha1, type, size, buffer, &eaten); + obj = parse_object_buffer(oid, type, size, buffer, &eaten); if (!eaten) free(buffer); return obj; diff --git a/object.h b/object.h index f52957dcb3..33e5cc9943 100644 --- a/object.h +++ b/object.h @@ -89,20 +89,20 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet); * * Returns NULL if the object is missing or corrupt. */ -struct object *parse_object(const unsigned char *sha1); +struct object *parse_object(const struct object_id *oid); /* * Like parse_object, but will die() instead of returning NULL. If the * "name" parameter is not NULL, it is included in the error message - * (otherwise, the sha1 hex is given). + * (otherwise, the hex object ID is given). */ -struct object *parse_object_or_die(const unsigned char *sha1, const char *name); +struct object *parse_object_or_die(const struct object_id *oid, const char *name); /* Given the result of read_sha1_file(), returns the object after * parsing it. eaten_p indicates if the object has a borrowed copy * of buffer and the caller should not free() it. */ -struct object *parse_object_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten_p); +struct object *parse_object_buffer(const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p); /** Returns the object, with potentially excess memory allocated. **/ struct object *lookup_unknown_object(const unsigned char *sha1); diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index e313f4f2bc..8e47a96b3b 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -73,7 +73,8 @@ void bitmap_writer_build_type_index(struct pack_idx_entry **index, break; default: - real_type = sha1_object_info(entry->idx.sha1, NULL); + real_type = sha1_object_info(entry->idx.oid.hash, + NULL); break; } @@ -96,7 +97,8 @@ void bitmap_writer_build_type_index(struct pack_idx_entry **index, default: die("Missing type information for %s (%d/%d)", - sha1_to_hex(entry->idx.sha1), real_type, entry->type); + oid_to_hex(&entry->idx.oid), real_type, + entry->type); } } } @@ -459,7 +461,7 @@ static inline void dump_bitmap(struct sha1file *f, struct ewah_bitmap *bitmap) static const unsigned char *sha1_access(size_t pos, void *table) { struct pack_idx_entry **index = table; - return index[pos]->sha1; + return index[pos]->oid.hash; } static void write_selected_commits_v1(struct sha1file *f, diff --git a/pack-bitmap.c b/pack-bitmap.c index 39bcc16846..a3ac3dccd4 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -673,7 +673,7 @@ int prepare_bitmap_walk(struct rev_info *revs) struct object *object = pending_e[i].item; if (object->type == OBJ_NONE) - parse_object_or_die(object->oid.hash, NULL); + parse_object_or_die(&object->oid, NULL); while (object->type == OBJ_TAG) { struct tag *tag = (struct tag *) object; @@ -685,7 +685,7 @@ int prepare_bitmap_walk(struct rev_info *revs) if (!tag->tagged) die("bad tag"); - object = parse_object_or_die(tag->tagged->oid.hash, NULL); + object = parse_object_or_die(&tag->tagged->oid, NULL); } if (object->flags & UNINTERESTING) diff --git a/pack-check.c b/pack-check.c index 27f70d345f..e1fcb228fa 100644 --- a/pack-check.c +++ b/pack-check.c @@ -5,7 +5,10 @@ struct idx_entry { off_t offset; - const unsigned char *sha1; + union idx_entry_object { + const unsigned char *hash; + struct object_id *oid; + } oid; unsigned int nr; }; @@ -51,7 +54,7 @@ static int verify_packfile(struct packed_git *p, off_t index_size = p->index_size; const unsigned char *index_base = p->index_data; git_SHA_CTX ctx; - unsigned char sha1[20], *pack_sig; + unsigned char hash[GIT_MAX_RAWSZ], *pack_sig; off_t offset = 0, pack_sig_ofs = 0; uint32_t nr_objects, i; int err = 0; @@ -71,9 +74,9 @@ static int verify_packfile(struct packed_git *p, remaining -= (unsigned int)(offset - pack_sig_ofs); git_SHA1_Update(&ctx, in, remaining); } while (offset < pack_sig_ofs); - git_SHA1_Final(sha1, &ctx); + git_SHA1_Final(hash, &ctx); pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL); - if (hashcmp(sha1, pack_sig)) + if (hashcmp(hash, pack_sig)) err = error("%s SHA1 checksum mismatch", p->pack_name); if (hashcmp(index_base + index_size - 40, pack_sig)) @@ -90,8 +93,8 @@ static int verify_packfile(struct packed_git *p, entries[nr_objects].offset = pack_sig_ofs; /* first sort entries by pack offset, since unpacking them is more efficient that way */ for (i = 0; i < nr_objects; i++) { - entries[i].sha1 = nth_packed_object_sha1(p, i); - if (!entries[i].sha1) + entries[i].oid.hash = nth_packed_object_sha1(p, i); + if (!entries[i].oid.hash) die("internal error pack-check nth-packed-object"); entries[i].offset = nth_packed_object_offset(p, i); entries[i].nr = i; @@ -112,7 +115,7 @@ static int verify_packfile(struct packed_git *p, if (check_pack_crc(p, w_curs, offset, len, nr)) err = error("index CRC mismatch for object %s " "from %s at offset %"PRIuMAX"", - sha1_to_hex(entries[i].sha1), + oid_to_hex(entries[i].oid.oid), p->pack_name, (uintmax_t)offset); } @@ -135,14 +138,14 @@ static int verify_packfile(struct packed_git *p, if (data_valid && !data) err = error("cannot unpack %s from %s at offset %"PRIuMAX"", - sha1_to_hex(entries[i].sha1), p->pack_name, + oid_to_hex(entries[i].oid.oid), p->pack_name, (uintmax_t)entries[i].offset); - else if (check_sha1_signature(entries[i].sha1, data, size, typename(type))) + else if (check_sha1_signature(entries[i].oid.hash, data, size, typename(type))) err = error("packed %s from %s is corrupt", - sha1_to_hex(entries[i].sha1), p->pack_name); + oid_to_hex(entries[i].oid.oid), p->pack_name); else if (fn) { int eaten = 0; - err |= fn(entries[i].sha1, type, size, data, &eaten); + err |= fn(entries[i].oid.oid, type, size, data, &eaten); if (eaten) data = NULL; } diff --git a/pack-objects.c b/pack-objects.c index 6398a8aa96..9558d13834 100644 --- a/pack-objects.c +++ b/pack-objects.c @@ -14,7 +14,7 @@ static uint32_t locate_object_entry_hash(struct packing_data *pdata, while (pdata->index[i] > 0) { uint32_t pos = pdata->index[i] - 1; - if (!hashcmp(sha1, pdata->objects[pos].idx.sha1)) { + if (!hashcmp(sha1, pdata->objects[pos].idx.oid.hash)) { *found = 1; return i; } @@ -53,7 +53,9 @@ static void rehash_objects(struct packing_data *pdata) for (i = 0; i < pdata->nr_objects; i++) { int found; - uint32_t ix = locate_object_entry_hash(pdata, entry->idx.sha1, &found); + uint32_t ix = locate_object_entry_hash(pdata, + entry->idx.oid.hash, + &found); if (found) die("BUG: Duplicate object in hash"); @@ -98,7 +100,7 @@ struct object_entry *packlist_alloc(struct packing_data *pdata, new_entry = pdata->objects + pdata->nr_objects++; memset(new_entry, 0, sizeof(*new_entry)); - hashcpy(new_entry->idx.sha1, sha1); + hashcpy(new_entry->idx.oid.hash, sha1); if (pdata->index_size * 3 <= pdata->nr_objects * 4) rehash_objects(pdata); diff --git a/pack-write.c b/pack-write.c index fa97b72559..a333ec6754 100644 --- a/pack-write.c +++ b/pack-write.c @@ -13,7 +13,7 @@ static int sha1_compare(const void *_a, const void *_b) { struct pack_idx_entry *a = *(struct pack_idx_entry **)_a; struct pack_idx_entry *b = *(struct pack_idx_entry **)_b; - return hashcmp(a->sha1, b->sha1); + return oidcmp(&a->oid, &b->oid); } static int cmp_uint32(const void *a_, const void *b_) @@ -103,7 +103,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec struct pack_idx_entry **next = list; while (next < last) { struct pack_idx_entry *obj = *next; - if (obj->sha1[0] != i) + if (obj->oid.hash[0] != i) break; next++; } @@ -122,11 +122,11 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec uint32_t offset = htonl(obj->offset); sha1write(f, &offset, 4); } - sha1write(f, obj->sha1, 20); + sha1write(f, obj->oid.hash, 20); if ((opts->flags & WRITE_IDX_STRICT) && - (i && !hashcmp(list[-2]->sha1, obj->sha1))) + (i && !oidcmp(&list[-2]->oid, &obj->oid))) die("The same object %s appears twice in the pack", - sha1_to_hex(obj->sha1)); + oid_to_hex(&obj->oid)); } if (index_version >= 2) { diff --git a/pack.h b/pack.h index 5c2158746e..8294341af1 100644 --- a/pack.h +++ b/pack.h @@ -67,7 +67,7 @@ struct pack_idx_header { * Common part of object structure used for write_idx_file */ struct pack_idx_entry { - unsigned char sha1[20]; + struct object_id oid; uint32_t crc32; off_t offset; }; @@ -75,7 +75,7 @@ struct pack_idx_entry { struct progress; /* Note, the data argument could be NULL if object type is blob */ -typedef int (*verify_fn)(const unsigned char*, enum object_type, unsigned long, void*, int*); +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); diff --git a/parse-options-cb.c b/parse-options-cb.c index 7419780a9b..c6679cb2cd 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) int parse_opt_approxidate_cb(const struct option *opt, const char *arg, int unset) { - *(unsigned long *)(opt->value) = approxidate(arg); + *(timestamp_t *)(opt->value) = approxidate(arg); return 0; } int parse_opt_expiry_date_cb(const struct option *opt, const char *arg, int unset) { - return parse_expiry_date(arg, (unsigned long *)opt->value); + return parse_expiry_date(arg, (timestamp_t *)opt->value); } int parse_opt_color_flag_cb(const struct option *opt, const char *arg, @@ -80,14 +80,14 @@ int parse_opt_verbosity_cb(const struct option *opt, const char *arg, int parse_opt_commits(const struct option *opt, const char *arg, int unset) { - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; if (!arg) return -1; - if (get_sha1(arg, sha1)) + if (get_oid(arg, &oid)) return error("malformed object name %s", arg); - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (!commit) return error("no such commit %s", arg); commit_list_insert(commit, opt->value); diff --git a/patch-ids.c b/patch-ids.c index fa8f11de82..92eba7a059 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -99,11 +99,12 @@ struct patch_id *has_commit_patch_id(struct commit *commit, struct patch_id *add_commit_patch_id(struct commit *commit, struct patch_ids *ids) { - struct patch_id *key = xcalloc(1, sizeof(*key)); + struct patch_id *key; if (!patch_id_defined(commit)) return NULL; + key = xcalloc(1, sizeof(*key)); if (init_patch_id_entry(key, commit, ids)) { free(key); return NULL; diff --git a/pretty.c b/pretty.c index d0f86f5d85..09701bd2ff 100644 --- a/pretty.c +++ b/pretty.c @@ -405,11 +405,11 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len, const char *show_ident_date(const struct ident_split *ident, const struct date_mode *mode) { - unsigned long date = 0; + timestamp_t date = 0; long tz = 0; if (ident->date_begin && ident->date_end) - date = strtoul(ident->date_begin, NULL, 10); + date = parse_timestamp(ident->date_begin, NULL, 10); if (date_overflows(date)) date = 0; else { @@ -1137,7 +1137,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ /* these depend on the commit */ if (!commit->object.parsed) - parse_object(commit->object.oid.hash); + parse_object(&commit->object.oid); switch (placeholder[0]) { case 'H': /* commit hash */ diff --git a/reachable.c b/reachable.c index a8a979bd4f..c62efbfd43 100644 --- a/reachable.c +++ b/reachable.c @@ -33,7 +33,7 @@ static int add_one_ref(const char *path, const struct object_id *oid, return 0; } - object = parse_object_or_die(oid->hash, path); + object = parse_object_or_die(oid, path); add_pending_object(revs, object, ""); return 0; @@ -55,11 +55,11 @@ static void mark_commit(struct commit *c, void *data) struct recent_data { struct rev_info *revs; - unsigned long timestamp; + timestamp_t timestamp; }; static void add_recent_object(const struct object_id *oid, - unsigned long mtime, + timestamp_t mtime, struct recent_data *data) { struct object *obj; @@ -82,13 +82,13 @@ static void add_recent_object(const struct object_id *oid, switch (type) { case OBJ_TAG: case OBJ_COMMIT: - obj = parse_object_or_die(oid->hash, NULL); + obj = parse_object_or_die(oid, NULL); break; case OBJ_TREE: - obj = (struct object *)lookup_tree(oid->hash); + obj = (struct object *)lookup_tree(oid); break; case OBJ_BLOB: - obj = (struct object *)lookup_blob(oid->hash); + obj = (struct object *)lookup_blob(oid); break; default: die("unknown object type for %s: %s", @@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid, } int add_unseen_recent_objects_to_traversal(struct rev_info *revs, - unsigned long timestamp) + timestamp_t timestamp) { struct recent_data data; int r; @@ -156,8 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs, } void mark_reachable_objects(struct rev_info *revs, int mark_reflog, - unsigned long mark_recent, - struct progress *progress) + timestamp_t mark_recent, struct progress *progress) { struct connectivity_progress cp; diff --git a/reachable.h b/reachable.h index d23efc36ec..3c00fa0526 100644 --- a/reachable.h +++ b/reachable.h @@ -3,8 +3,8 @@ struct progress; extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs, - unsigned long timestamp); + timestamp_t timestamp); extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog, - unsigned long mark_recent, struct progress *); + timestamp_t mark_recent, struct progress *); #endif diff --git a/read-cache.c b/read-cache.c index 0d0081a11b..22ab8b5b61 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1877,15 +1877,9 @@ int discard_index(struct index_state *istate) { int i; - for (i = 0; i < istate->cache_nr; i++) { - if (istate->cache[i]->index && - istate->split_index && - istate->split_index->base && - istate->cache[i]->index <= istate->split_index->base->cache_nr && - istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1]) - continue; + unshare_split_index(istate, 1); + for (i = 0; i < istate->cache_nr; i++) free(istate->cache[i]); - } resolve_undo_clear_index(istate); istate->cache_nr = 0; istate->cache_changed = 0; @@ -2197,6 +2191,7 @@ static int do_write_index(struct index_state *istate, int newfd, int entries = istate->cache_nr; struct stat st; struct strbuf previous_name_buf = STRBUF_INIT, *previous_name; + int drop_cache_tree = 0; for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) @@ -2247,6 +2242,8 @@ static int do_write_index(struct index_state *istate, int newfd, warning(msg, ce->name); else return error(msg, ce->name); + + drop_cache_tree = 1; } if (ce_write_entry(&c, newfd, ce, previous_name) < 0) return -1; @@ -2265,7 +2262,7 @@ static int do_write_index(struct index_state *istate, int newfd, if (err) return -1; } - if (!strip_extensions && istate->cache_tree) { + if (!strip_extensions && !drop_cache_tree && istate->cache_tree) { struct strbuf sb = STRBUF_INIT; cache_tree_write(&sb, istate->cache_tree); diff --git a/ref-filter.c b/ref-filter.c index 3a640448fd..3742abbf85 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -93,6 +93,7 @@ static struct used_atom { unsigned int length; } objectname; struct refname_atom refname; + char *head; } u; } *used_atom; static int used_atom_cnt, need_tagged, need_symref; @@ -287,6 +288,12 @@ static void if_atom_parser(struct used_atom *atom, const char *arg) } } +static void head_atom_parser(struct used_atom *atom, const char *arg) +{ + struct object_id unused; + + atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, unused.hash, NULL); +} static struct { const char *name; @@ -325,7 +332,7 @@ static struct { { "push", FIELD_STR, remote_ref_atom_parser }, { "symref", FIELD_STR, refname_atom_parser }, { "flag" }, - { "HEAD" }, + { "HEAD", FIELD_STR, head_atom_parser }, { "color", FIELD_STR, color_atom_parser }, { "align", FIELD_STR, align_atom_parser }, { "end" }, @@ -351,7 +358,7 @@ struct ref_formatting_state { struct atom_value { const char *s; void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state); - unsigned long ul; /* used for sorting when not FIELD_STR */ + uintmax_t value; /* used for sorting when not FIELD_STR */ struct used_atom *atom; }; @@ -677,13 +684,13 @@ int verify_ref_format(const char *format) * by the "struct object" representation, set *eaten as well---it is a * signal from parse_object_buffer to us not to free the buffer. */ -static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten) +static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten) { enum object_type type; - void *buf = read_sha1_file(sha1, &type, sz); + void *buf = read_sha1_file(oid->hash, &type, sz); if (buf) - *obj = parse_object_buffer(sha1, type, *sz, buf, eaten); + *obj = parse_object_buffer(oid, type, *sz, buf, eaten); else *obj = NULL; return buf; @@ -723,7 +730,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object if (!strcmp(name, "objecttype")) v->s = typename(obj->type); else if (!strcmp(name, "objectsize")) { - v->ul = sz; + v->value = sz; v->s = xstrfmt("%lu", sz); } else if (deref) @@ -770,8 +777,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object v->s = xstrdup(oid_to_hex(&commit->tree->object.oid)); } else if (!strcmp(name, "numparent")) { - v->ul = commit_list_count(commit->parents); - v->s = xstrfmt("%lu", v->ul); + v->value = commit_list_count(commit->parents); + v->s = xstrfmt("%lu", (unsigned long)v->value); } else if (!strcmp(name, "parent")) { struct commit_list *parents; @@ -849,7 +856,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam { const char *eoemail = strstr(buf, "> "); char *zone; - unsigned long timestamp; + timestamp_t timestamp; long tz; struct date_mode date_mode = { DATE_NORMAL }; const char *formatp; @@ -868,18 +875,18 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam if (!eoemail) goto bad; - timestamp = strtoul(eoemail + 2, &zone, 10); - if (timestamp == ULONG_MAX) + timestamp = parse_timestamp(eoemail + 2, &zone, 10); + if (timestamp == TIME_MAX) goto bad; tz = strtol(zone, NULL, 10); if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) goto bad; v->s = xstrdup(show_date(timestamp, tz, &date_mode)); - v->ul = timestamp; + v->value = timestamp; return; bad: v->s = ""; - v->ul = 0; + v->value = 0; } /* See grab_values */ @@ -1293,7 +1300,7 @@ static void populate_value(struct ref_array_item *ref) struct object *obj; int eaten, i; unsigned long size; - const unsigned char *tagged; + const struct object_id *tagged; ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value)); @@ -1366,15 +1373,10 @@ static void populate_value(struct ref_array_item *ref) v->s = xstrdup(buf + 1); } continue; - } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) { + } else if (!deref && grab_objectname(name, ref->objectname.hash, v, atom)) { continue; } else if (!strcmp(name, "HEAD")) { - const char *head; - unsigned char sha1[20]; - - head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, - sha1, NULL); - if (head && !strcmp(ref->refname, head)) + if (atom->u.head && !strcmp(ref->refname, atom->u.head)) v->s = "*"; else v->s = " "; @@ -1415,13 +1417,13 @@ static void populate_value(struct ref_array_item *ref) return; need_obj: - buf = get_obj(ref->objectname, &obj, &size, &eaten); + buf = get_obj(&ref->objectname, &obj, &size, &eaten); if (!buf) die(_("missing object %s for %s"), - sha1_to_hex(ref->objectname), ref->refname); + oid_to_hex(&ref->objectname), ref->refname); if (!obj) die(_("parse_object_buffer failed on %s for %s"), - sha1_to_hex(ref->objectname), ref->refname); + oid_to_hex(&ref->objectname), ref->refname); grab_values(ref->value, 0, obj, buf, size); if (!eaten) @@ -1438,7 +1440,7 @@ static void populate_value(struct ref_array_item *ref) * If it is a tag object, see if we use a value that derefs * the object, and if we do grab the object it refers to. */ - tagged = ((struct tag *)obj)->tagged->oid.hash; + tagged = &((struct tag *)obj)->tagged->oid; /* * NEEDSWORK: This derefs tag only once, which @@ -1449,10 +1451,10 @@ static void populate_value(struct ref_array_item *ref) buf = get_obj(tagged, &obj, &size, &eaten); if (!buf) die(_("missing object %s for %s"), - sha1_to_hex(tagged), ref->refname); + oid_to_hex(tagged), ref->refname); if (!obj) die(_("parse_object_buffer failed on %s for %s"), - sha1_to_hex(tagged), ref->refname); + oid_to_hex(tagged), ref->refname); grab_values(ref->value, 1, obj, buf, size); if (!eaten) free(buf); @@ -1687,7 +1689,7 @@ static const struct object_id *match_points_at(struct oid_array *points_at, if (oid_array_lookup(points_at, oid) >= 0) return oid; - obj = parse_object(oid->hash); + obj = parse_object(oid); if (!obj) die(_("malformed object at '%s'"), refname); if (obj->type == OBJ_TAG) @@ -1704,7 +1706,7 @@ static struct ref_array_item *new_ref_array_item(const char *refname, { struct ref_array_item *ref; FLEX_ALLOC_STR(ref, refname, refname); - hashcpy(ref->objectname, objectname); + hashcpy(ref->objectname.hash, objectname); ref->flag = flag; return ref; @@ -1782,7 +1784,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, * non-commits early. The actual filtering is done later. */ if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { - commit = lookup_commit_reference_gently(oid->hash, 1); + commit = lookup_commit_reference_gently(oid, 1); if (!commit) return 0; /* We perform the filtering for the '--contains' option... */ @@ -1941,9 +1943,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru else if (cmp_type == FIELD_STR) cmp = cmp_fn(va->s, vb->s); else { - if (va->ul < vb->ul) + if (va->value < vb->value) cmp = -1; - else if (va->ul == vb->ul) + else if (va->value == vb->value) cmp = cmp_fn(a->refname, b->refname); else cmp = 1; @@ -2090,7 +2092,7 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset) int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) { struct ref_filter *rf = opt->value; - unsigned char sha1[20]; + struct object_id oid; int no_merged = starts_with(opt->long_name, "no"); if (rf->merge) { @@ -2105,10 +2107,10 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) ? REF_FILTER_MERGED_OMIT : REF_FILTER_MERGED_INCLUDE; - if (get_sha1(arg, sha1)) + if (get_oid(arg, &oid)) die(_("malformed object name %s"), arg); - rf->merge_commit = lookup_commit_reference_gently(sha1, 0); + rf->merge_commit = lookup_commit_reference_gently(&oid, 0); if (!rf->merge_commit) return opterror(opt, "must point to a commit", 0); diff --git a/ref-filter.h b/ref-filter.h index c20167aa3c..6552024f09 100644 --- a/ref-filter.h +++ b/ref-filter.h @@ -34,7 +34,7 @@ struct ref_sorting { }; struct ref_array_item { - unsigned char objectname[20]; + struct object_id objectname; int flag; unsigned int kind; const char *symref; diff --git a/reflog-walk.c b/reflog-walk.c index 99679f5825..ed99437ad2 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -12,7 +12,7 @@ struct complete_reflogs { struct reflog_info { struct object_id ooid, noid; char *email; - unsigned long timestamp; + timestamp_t timestamp; int tz; char *message; } *items; @@ -20,7 +20,7 @@ struct complete_reflogs { }; static int read_one_reflog(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct complete_reflogs *array = cb_data; @@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref) } static int get_reflog_recno_by_time(struct complete_reflogs *array, - unsigned long timestamp) + timestamp_t timestamp) { int i; for (i = array->nr - 1; i >= 0; i--) @@ -141,7 +141,7 @@ 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) { - unsigned long timestamp = 0; + timestamp_t timestamp = 0; int recno = -1; struct string_list_item *item; struct complete_reflogs *reflogs; @@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info, if (!reflogs || reflogs->nr == 0) { struct object_id oid; char *b; - if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) { + int ret = dwim_log(branch, strlen(branch), + oid.hash, &b); + if (ret > 1) + free(b); + else if (ret == 1) { if (reflogs) { free(reflogs->ref); free(reflogs); @@ -193,17 +197,27 @@ int add_reflog_for_walk(struct reflog_walk_info *info, reflogs = read_complete_reflog(branch); } } - if (!reflogs || reflogs->nr == 0) + if (!reflogs || reflogs->nr == 0) { + if (reflogs) { + free(reflogs->ref); + free(reflogs); + } + free(branch); return -1; + } string_list_insert(&info->complete_reflogs, branch)->util = reflogs; } + free(branch); commit_reflog = xcalloc(1, sizeof(struct commit_reflog)); if (recno < 0) { commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp); if (commit_reflog->recno < 0) { - free(branch); + if (reflogs) { + free(reflogs->ref); + free(reflogs); + } free(commit_reflog); return -1; } @@ -238,13 +252,13 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) do { reflog = &commit_reflog->reflogs->items[commit_reflog->recno]; commit_reflog->recno--; - logobj = parse_object(reflog->ooid.hash); + logobj = parse_object(&reflog->ooid); } while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT)); - if (!logobj && commit_reflog->recno >= 0 && is_null_sha1(reflog->ooid.hash)) { + if (!logobj && commit_reflog->recno >= 0 && is_null_oid(&reflog->ooid)) { /* a root commit, but there are still more entries to show */ reflog = &commit_reflog->reflogs->items[commit_reflog->recno]; - logobj = parse_object(reflog->noid.hash); + logobj = parse_object(&reflog->noid); } if (!logobj || logobj->type != OBJ_COMMIT) { diff --git a/refs.c b/refs.c index df75f8e0d6..8af9641aa1 100644 --- a/refs.c +++ b/refs.c @@ -11,6 +11,7 @@ #include "object.h" #include "tag.h" #include "submodule.h" +#include "worktree.h" /* * List of all available backends @@ -713,7 +714,7 @@ int is_branch(const char *refname) struct read_ref_at_cb { const char *refname; - unsigned long at_time; + timestamp_t at_time; int cnt; int reccnt; unsigned char *sha1; @@ -722,15 +723,15 @@ struct read_ref_at_cb { unsigned char osha1[20]; unsigned char nsha1[20]; int tz; - unsigned long date; + timestamp_t date; char **msg; - unsigned long *cutoff_time; + timestamp_t *cutoff_time; int *cutoff_tz; int *cutoff_cnt; }; static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct read_ref_at_cb *cb = cb_data; @@ -777,7 +778,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, } static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct read_ref_at_cb *cb = cb_data; @@ -797,9 +798,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid return 1; } -int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt, +int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt, unsigned char *sha1, char **msg, - unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt) + timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt) { struct read_ref_at_cb cb; @@ -882,9 +883,9 @@ struct ref_update *ref_transaction_add_update( update->flags = flags; if (flags & REF_HAVE_NEW) - hashcpy(update->new_sha1, new_sha1); + hashcpy(update->new_oid.hash, new_sha1); if (flags & REF_HAVE_OLD) - hashcpy(update->old_sha1, old_sha1); + hashcpy(update->old_oid.hash, old_sha1); update->msg = xstrdup_or_null(msg); return update; } @@ -1477,32 +1478,32 @@ int resolve_gitlink_ref(const char *submodule, const char *refname, return 0; } -struct submodule_hash_entry +struct ref_store_hash_entry { struct hashmap_entry ent; /* must be the first member! */ struct ref_store *refs; - /* NUL-terminated name of submodule: */ - char submodule[FLEX_ARRAY]; + /* NUL-terminated identifier of the ref store: */ + char name[FLEX_ARRAY]; }; -static int submodule_hash_cmp(const void *entry, const void *entry_or_key, +static int ref_store_hash_cmp(const void *entry, const void *entry_or_key, const void *keydata) { - const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key; - const char *submodule = keydata ? keydata : e2->submodule; + const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key; + const char *name = keydata ? keydata : e2->name; - return strcmp(e1->submodule, submodule); + return strcmp(e1->name, name); } -static struct submodule_hash_entry *alloc_submodule_hash_entry( - const char *submodule, struct ref_store *refs) +static struct ref_store_hash_entry *alloc_ref_store_hash_entry( + const char *name, struct ref_store *refs) { - struct submodule_hash_entry *entry; + struct ref_store_hash_entry *entry; - FLEX_ALLOC_STR(entry, submodule, submodule); - hashmap_entry_init(entry, strhash(submodule)); + FLEX_ALLOC_STR(entry, name, name); + hashmap_entry_init(entry, strhash(name)); entry->refs = refs; return entry; } @@ -1513,20 +1514,23 @@ static struct ref_store *main_ref_store; /* A hashmap of ref_stores, stored by submodule name: */ static struct hashmap submodule_ref_stores; +/* A hashmap of ref_stores, stored by worktree id: */ +static struct hashmap worktree_ref_stores; + /* - * Return the ref_store instance for the specified submodule. If that - * ref_store hasn't been initialized yet, return NULL. + * Look up a ref store by name. If that ref_store hasn't been + * registered yet, return NULL. */ -static struct ref_store *lookup_submodule_ref_store(const char *submodule) +static struct ref_store *lookup_ref_store_map(struct hashmap *map, + const char *name) { - struct submodule_hash_entry *entry; + struct ref_store_hash_entry *entry; - if (!submodule_ref_stores.tablesize) + if (!map->tablesize) /* It's initialized on demand in register_ref_store(). */ return NULL; - entry = hashmap_get_from_hash(&submodule_ref_stores, - strhash(submodule), submodule); + entry = hashmap_get_from_hash(map, strhash(name), name); return entry ? entry->refs : NULL; } @@ -1553,29 +1557,24 @@ struct ref_store *get_main_ref_store(void) if (main_ref_store) return main_ref_store; - main_ref_store = ref_store_init(get_git_dir(), - (REF_STORE_READ | - REF_STORE_WRITE | - REF_STORE_ODB | - REF_STORE_MAIN)); + main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS); return main_ref_store; } /* - * Register the specified ref_store to be the one that should be used - * for submodule. It is a fatal error to call this function twice for - * the same submodule. + * Associate a ref store with a name. It is a fatal error to call this + * function twice for the same name. */ -static void register_submodule_ref_store(struct ref_store *refs, - const char *submodule) +static void register_ref_store_map(struct hashmap *map, + const char *type, + struct ref_store *refs, + const char *name) { - if (!submodule_ref_stores.tablesize) - hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0); + if (!map->tablesize) + hashmap_init(map, ref_store_hash_cmp, 0); - if (hashmap_put(&submodule_ref_stores, - alloc_submodule_hash_entry(submodule, refs))) - die("BUG: ref_store for submodule '%s' initialized twice", - submodule); + if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs))) + die("BUG: %s ref_store '%s' initialized twice", type, name); } struct ref_store *get_submodule_ref_store(const char *submodule) @@ -1592,7 +1591,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule) return get_main_ref_store(); } - refs = lookup_submodule_ref_store(submodule); + refs = lookup_ref_store_map(&submodule_ref_stores, submodule); if (refs) return refs; @@ -1611,12 +1610,39 @@ struct ref_store *get_submodule_ref_store(const char *submodule) /* assume that add_submodule_odb() has been called */ refs = ref_store_init(submodule_sb.buf, REF_STORE_READ | REF_STORE_ODB); - register_submodule_ref_store(refs, submodule); + register_ref_store_map(&submodule_ref_stores, "submodule", + refs, submodule); strbuf_release(&submodule_sb); return refs; } +struct ref_store *get_worktree_ref_store(const struct worktree *wt) +{ + struct ref_store *refs; + const char *id; + + if (wt->is_current) + return get_main_ref_store(); + + id = wt->id ? wt->id : "/"; + refs = lookup_ref_store_map(&worktree_ref_stores, id); + if (refs) + return refs; + + if (wt->id) + refs = ref_store_init(git_common_path("worktrees/%s", wt->id), + REF_STORE_ALL_CAPS); + else + refs = ref_store_init(get_git_common_dir(), + REF_STORE_ALL_CAPS); + + if (refs) + register_ref_store_map(&worktree_ref_stores, "worktree", + refs, id); + return refs; +} + void base_ref_store_init(struct ref_store *refs, const struct ref_storage_be *be) { diff --git a/refs.h b/refs.h index 07cf4cd41b..685a979a0e 100644 --- a/refs.h +++ b/refs.h @@ -5,6 +5,7 @@ struct object_id; struct ref_store; struct strbuf; struct string_list; +struct worktree; /* * Resolve a reference, recursively following symbolic refererences. @@ -317,9 +318,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err /** Reads log for the value of ref during at_time. **/ int read_ref_at(const char *refname, unsigned int flags, - unsigned long at_time, int cnt, + timestamp_t at_time, int cnt, unsigned char *sha1, char **msg, - unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt); + timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt); /** Check if a particular reflog exists */ int refs_reflog_exists(struct ref_store *refs, const char *refname); @@ -356,7 +357,7 @@ int delete_reflog(const char *refname); /* iterate over reflog entries */ typedef int each_reflog_ent_fn( struct object_id *old_oid, struct object_id *new_oid, - const char *committer, unsigned long timestamp, + const char *committer, timestamp_t timestamp, int tz, const char *msg, void *cb_data); int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname, @@ -401,16 +402,6 @@ int refs_create_symref(struct ref_store *refs, const char *refname, const char *target, const char *logmsg); int create_symref(const char *refname, const char *target, const char *logmsg); -/* - * Update HEAD of the specified gitdir. - * Similar to create_symref("relative-git-dir/HEAD", target, NULL), but - * this can update the main working tree's HEAD regardless of where - * $GIT_DIR points to. - * Return 0 if successful, non-zero otherwise. - * */ -int set_worktree_head_symref(const char *gitdir, const char *target, - const char *logmsg); - enum action_on_err { UPDATE_REFS_MSG_ON_ERR, UPDATE_REFS_DIE_ON_ERR, @@ -611,12 +602,12 @@ enum expire_reflog_flags { * unlocked again. */ typedef void reflog_expiry_prepare_fn(const char *refname, - const unsigned char *sha1, + const struct object_id *oid, void *cb_data); -typedef int reflog_expiry_should_prune_fn(unsigned char *osha1, - unsigned char *nsha1, +typedef int reflog_expiry_should_prune_fn(struct object_id *ooid, + struct object_id *noid, const char *email, - unsigned long timestamp, int tz, + timestamp_t timestamp, int tz, const char *message, void *cb_data); typedef void reflog_expiry_cleanup_fn(void *cb_data); @@ -655,5 +646,6 @@ struct ref_store *get_main_ref_store(void); * submodule==NULL. */ struct ref_store *get_submodule_ref_store(const char *submodule); +struct ref_store *get_worktree_ref_store(const struct worktree *wt); #endif /* REFS_H */ diff --git a/refs/files-backend.c b/refs/files-backend.c index 83ea080e01..cb1f528cbe 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -195,27 +195,15 @@ static const char PACKED_REFS_HEADER[] = * Return a pointer to the refname within the line (null-terminated), * or NULL if there was a problem. */ -static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1) +static const char *parse_ref_line(struct strbuf *line, struct object_id *oid) { const char *ref; - /* - * 42: the answer to everything. - * - * In this case, it happens to be the answer to - * 40 (length of sha1 hex representation) - * +1 (space in between hex and name) - * +1 (newline at the end of the line) - */ - if (line->len <= 42) + if (parse_oid_hex(line->buf, oid, &ref) < 0) return NULL; - - if (get_sha1_hex(line->buf, sha1) < 0) - return NULL; - if (!isspace(line->buf[40])) + if (!isspace(*ref++)) return NULL; - ref = line->buf + 41; if (isspace(*ref)) return NULL; @@ -260,7 +248,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE; while (strbuf_getwholeline(&line, f, '\n') != EOF) { - unsigned char sha1[20]; + struct object_id oid; const char *refname; const char *traits; @@ -273,17 +261,17 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) continue; } - refname = parse_ref_line(&line, sha1); + refname = parse_ref_line(&line, &oid); if (refname) { int flag = REF_ISPACKED; if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(refname)) die("packed refname is dangerous: %s", refname); - hashclr(sha1); + oidclr(&oid); flag |= REF_BAD_NAME | REF_ISBROKEN; } - last = create_ref_entry(refname, sha1, flag, 0); + last = create_ref_entry(refname, &oid, flag, 0); if (peeled == PEELED_FULLY || (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/"))) last->flag |= REF_KNOWS_PEELED; @@ -294,8 +282,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) line.buf[0] == '^' && line.len == PEELED_LINE_LENGTH && line.buf[PEELED_LINE_LENGTH - 1] == '\n' && - !get_sha1_hex(line.buf + 1, sha1)) { - hashcpy(last->u.value.peeled.hash, sha1); + !get_oid_hex(line.buf + 1, &oid)) { + oidcpy(&last->u.value.peeled, &oid); /* * Regardless of what the file header said, * we definitely know the value of *this* @@ -404,14 +392,14 @@ static struct ref_dir *get_packed_refs(struct files_ref_store *refs) * commit_packed_refs(). */ static void add_packed_ref(struct files_ref_store *refs, - const char *refname, const unsigned char *sha1) + const char *refname, const struct object_id *oid) { struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs); if (!packed_ref_cache->lock) die("internal error: packed refs not locked"); add_ref_entry(get_packed_ref_dir(packed_ref_cache), - create_ref_entry(refname, sha1, REF_ISPACKED, 1)); + create_ref_entry(refname, oid, REF_ISPACKED, 1)); } /* @@ -444,7 +432,7 @@ static void loose_fill_ref_dir(struct ref_store *ref_store, strbuf_add(&refname, dirname, dirnamelen); while ((de = readdir(d)) != NULL) { - unsigned char sha1[20]; + struct object_id oid; struct stat st; int flag; @@ -465,10 +453,10 @@ static void loose_fill_ref_dir(struct ref_store *ref_store, if (!refs_resolve_ref_unsafe(&refs->base, refname.buf, RESOLVE_REF_READING, - sha1, &flag)) { - hashclr(sha1); + oid.hash, &flag)) { + oidclr(&oid); flag |= REF_ISBROKEN; - } else if (is_null_sha1(sha1)) { + } else if (is_null_oid(&oid)) { /* * It is so astronomically unlikely * that NULL_SHA1 is the SHA-1 of an @@ -484,11 +472,11 @@ static void loose_fill_ref_dir(struct ref_store *ref_store, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(refname.buf)) die("loose refname is dangerous: %s", refname.buf); - hashclr(sha1); + oidclr(&oid); flag |= REF_BAD_NAME | REF_ISBROKEN; } add_entry_to_dir(dir, - create_ref_entry(refname.buf, sha1, flag, 0)); + create_ref_entry(refname.buf, &oid, flag, 0)); } strbuf_setlen(&refname, dirnamelen); strbuf_setlen(&path, path_baselen); @@ -1526,7 +1514,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags) packed_entry->flag = REF_ISPACKED; oidcpy(&packed_entry->u.value.oid, iter->oid); } else { - packed_entry = create_ref_entry(iter->refname, iter->oid->hash, + packed_entry = create_ref_entry(iter->refname, iter->oid, REF_ISPACKED, 0); add_ref_entry(packed_refs, packed_entry); } @@ -1709,10 +1697,10 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname) } static int write_ref_to_lockfile(struct ref_lock *lock, - const unsigned char *sha1, struct strbuf *err); + const struct object_id *oid, struct strbuf *err); static int commit_ref_update(struct files_ref_store *refs, struct ref_lock *lock, - const unsigned char *sha1, const char *logmsg, + const struct object_id *oid, const char *logmsg, struct strbuf *err); static int files_rename_ref(struct ref_store *ref_store, @@ -1721,7 +1709,7 @@ static int files_rename_ref(struct ref_store *ref_store, { struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_WRITE, "rename_ref"); - unsigned char sha1[20], orig_sha1[20]; + struct object_id oid, orig_oid; int flag = 0, logmoved = 0; struct ref_lock *lock; struct stat loginfo; @@ -1743,7 +1731,7 @@ static int files_rename_ref(struct ref_store *ref_store, if (!refs_resolve_ref_unsafe(&refs->base, oldrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - orig_sha1, &flag)) { + orig_oid.hash, &flag)) { ret = error("refname %s not found", oldrefname); goto out; } @@ -1765,21 +1753,21 @@ static int files_rename_ref(struct ref_store *ref_store, } if (refs_delete_ref(&refs->base, logmsg, oldrefname, - orig_sha1, REF_NODEREF)) { + orig_oid.hash, REF_NODEREF)) { error("unable to delete old %s", oldrefname); goto rollback; } /* - * Since we are doing a shallow lookup, sha1 is not the - * correct value to pass to delete_ref as old_sha1. But that - * doesn't matter, because an old_sha1 check wouldn't add to + * Since we are doing a shallow lookup, oid is not the + * correct value to pass to delete_ref as old_oid. But that + * doesn't matter, because an old_oid check wouldn't add to * the safety anyway; we want to delete the reference whatever * its current value. */ if (!refs_read_ref_full(&refs->base, newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - sha1, NULL) && + oid.hash, NULL) && refs_delete_ref(&refs->base, NULL, newrefname, NULL, REF_NODEREF)) { if (errno == EISDIR) { @@ -1812,10 +1800,10 @@ static int files_rename_ref(struct ref_store *ref_store, strbuf_release(&err); goto rollback; } - hashcpy(lock->old_oid.hash, orig_sha1); + oidcpy(&lock->old_oid, &orig_oid); - if (write_ref_to_lockfile(lock, orig_sha1, &err) || - commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) { + if (write_ref_to_lockfile(lock, &orig_oid, &err) || + commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) { error("unable to write current sha1 into %s: %s", newrefname, err.buf); strbuf_release(&err); goto rollback; @@ -1835,8 +1823,8 @@ static int files_rename_ref(struct ref_store *ref_store, flag = log_all_ref_updates; log_all_ref_updates = LOG_REFS_NONE; - if (write_ref_to_lockfile(lock, orig_sha1, &err) || - commit_ref_update(refs, lock, orig_sha1, NULL, &err)) { + if (write_ref_to_lockfile(lock, &orig_oid, &err) || + commit_ref_update(refs, lock, &orig_oid, NULL, &err)) { error("unable to write current sha1 into %s: %s", oldrefname, err.buf); strbuf_release(&err); } @@ -1986,8 +1974,8 @@ static int files_create_reflog(struct ref_store *ref_store, return 0; } -static int log_ref_write_fd(int fd, const unsigned char *old_sha1, - const unsigned char *new_sha1, +static int log_ref_write_fd(int fd, const struct object_id *old_oid, + const struct object_id *new_oid, const char *committer, const char *msg) { int msglen, written; @@ -1998,8 +1986,8 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1, maxlen = strlen(committer) + msglen + 100; logrec = xmalloc(maxlen); len = xsnprintf(logrec, maxlen, "%s %s %s\n", - sha1_to_hex(old_sha1), - sha1_to_hex(new_sha1), + oid_to_hex(old_oid), + oid_to_hex(new_oid), committer); if (msglen) len += copy_reflog_msg(logrec + len - 1, msg) - 1; @@ -2013,8 +2001,8 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1, } static int files_log_ref_write(struct files_ref_store *refs, - const char *refname, const unsigned char *old_sha1, - const unsigned char *new_sha1, const char *msg, + const char *refname, const struct object_id *old_oid, + const struct object_id *new_oid, const char *msg, int flags, struct strbuf *err) { int logfd, result; @@ -2031,7 +2019,7 @@ static int files_log_ref_write(struct files_ref_store *refs, if (logfd < 0) return 0; - result = log_ref_write_fd(logfd, old_sha1, new_sha1, + result = log_ref_write_fd(logfd, old_oid, new_oid, git_committer_info(0), msg); if (result) { struct strbuf sb = STRBUF_INIT; @@ -2063,29 +2051,29 @@ static int files_log_ref_write(struct files_ref_store *refs, * return -1. */ static int write_ref_to_lockfile(struct ref_lock *lock, - const unsigned char *sha1, struct strbuf *err) + const struct object_id *oid, struct strbuf *err) { static char term = '\n'; struct object *o; int fd; - o = parse_object(sha1); + o = parse_object(oid); if (!o) { strbuf_addf(err, "trying to write ref '%s' with nonexistent object %s", - lock->ref_name, sha1_to_hex(sha1)); + lock->ref_name, oid_to_hex(oid)); unlock_ref(lock); return -1; } if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) { strbuf_addf(err, "trying to write non-commit object %s to branch '%s'", - sha1_to_hex(sha1), lock->ref_name); + oid_to_hex(oid), lock->ref_name); unlock_ref(lock); return -1; } fd = get_lock_file_fd(lock->lk); - if (write_in_full(fd, sha1_to_hex(sha1), 40) != 40 || + if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ || write_in_full(fd, &term, 1) != 1 || close_ref(lock) < 0) { strbuf_addf(err, @@ -2103,14 +2091,14 @@ static int write_ref_to_lockfile(struct ref_lock *lock, */ static int commit_ref_update(struct files_ref_store *refs, struct ref_lock *lock, - const unsigned char *sha1, const char *logmsg, + const struct object_id *oid, const char *logmsg, struct strbuf *err) { files_assert_main_repository(refs, "commit_ref_update"); clear_loose_ref_cache(refs); if (files_log_ref_write(refs, lock->ref_name, - lock->old_oid.hash, sha1, + &lock->old_oid, oid, logmsg, 0, err)) { char *old_msg = strbuf_detach(err, NULL); strbuf_addf(err, "cannot update the ref '%s': %s", @@ -2133,18 +2121,18 @@ static int commit_ref_update(struct files_ref_store *refs, * check with HEAD only which should cover 99% of all usage * scenarios (even 100% of the default ones). */ - unsigned char head_sha1[20]; + struct object_id head_oid; int head_flag; const char *head_ref; head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD", RESOLVE_REF_READING, - head_sha1, &head_flag); + head_oid.hash, &head_flag); if (head_ref && (head_flag & REF_ISSYMREF) && !strcmp(head_ref, lock->ref_name)) { struct strbuf log_err = STRBUF_INIT; if (files_log_ref_write(refs, "HEAD", - lock->old_oid.hash, sha1, + &lock->old_oid, oid, logmsg, 0, &log_err)) { error("%s", log_err.buf); strbuf_release(&log_err); @@ -2182,12 +2170,12 @@ static void update_symref_reflog(struct files_ref_store *refs, const char *target, const char *logmsg) { struct strbuf err = STRBUF_INIT; - unsigned char new_sha1[20]; + struct object_id new_oid; if (logmsg && !refs_read_ref_full(&refs->base, target, - RESOLVE_REF_READING, new_sha1, NULL) && - files_log_ref_write(refs, refname, lock->old_oid.hash, - new_sha1, logmsg, 0, &err)) { + RESOLVE_REF_READING, new_oid.hash, NULL) && + files_log_ref_write(refs, refname, &lock->old_oid, + &new_oid, logmsg, 0, &err)) { error("%s", err.buf); strbuf_release(&err); } @@ -2240,50 +2228,6 @@ static int files_create_symref(struct ref_store *ref_store, return ret; } -int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg) -{ - /* - * FIXME: this obviously will not work well for future refs - * backends. This function needs to die. - */ - struct files_ref_store *refs = - files_downcast(get_main_ref_store(), - REF_STORE_WRITE, - "set_head_symref"); - - static struct lock_file head_lock; - struct ref_lock *lock; - struct strbuf head_path = STRBUF_INIT; - const char *head_rel; - int ret; - - strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir)); - if (hold_lock_file_for_update(&head_lock, head_path.buf, - LOCK_NO_DEREF) < 0) { - struct strbuf err = STRBUF_INIT; - unable_to_lock_message(head_path.buf, errno, &err); - error("%s", err.buf); - strbuf_release(&err); - strbuf_release(&head_path); - return -1; - } - - /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for - linked trees */ - head_rel = remove_leading_path(head_path.buf, - absolute_path(get_git_common_dir())); - /* to make use of create_symref_locked(), initialize ref_lock */ - lock = xcalloc(1, sizeof(struct ref_lock)); - lock->lk = &head_lock; - lock->ref_name = xstrdup(head_rel); - - ret = create_symref_locked(refs, lock, head_rel, target, logmsg); - - unlock_ref(lock); /* will free lock */ - strbuf_release(&head_path); - return ret; -} - static int files_reflog_exists(struct ref_store *ref_store, const char *refname) { @@ -2317,7 +2261,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c { struct object_id ooid, noid; char *email_end, *message; - unsigned long timestamp; + timestamp_t timestamp; int tz; const char *p = sb->buf; @@ -2327,7 +2271,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c parse_oid_hex(p, &noid, &p) || *p++ != ' ' || !(email_end = strchr(p, '>')) || email_end[1] != ' ' || - !(timestamp = strtoul(email_end + 2, &message, 10)) || + !(timestamp = parse_timestamp(email_end + 2, &message, 10)) || !message || message[0] != ' ' || (message[1] != '+' && message[1] != '-') || !isdigit(message[2]) || !isdigit(message[3]) || @@ -2633,7 +2577,7 @@ static int split_head_update(struct ref_update *update, new_update = ref_transaction_add_update( transaction, "HEAD", update->flags | REF_LOG_ONLY | REF_NODEREF, - update->new_sha1, update->old_sha1, + update->new_oid.hash, update->old_oid.hash, update->msg); item->util = new_update; @@ -2690,7 +2634,7 @@ static int split_symref_update(struct files_ref_store *refs, new_update = ref_transaction_add_update( transaction, referent, new_flags, - update->new_sha1, update->old_sha1, + update->new_oid.hash, update->old_oid.hash, update->msg); new_update->parent_update = update; @@ -2729,10 +2673,10 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid, struct strbuf *err) { if (!(update->flags & REF_HAVE_OLD) || - !hashcmp(oid->hash, update->old_sha1)) + !oidcmp(oid, &update->old_oid)) return 0; - if (is_null_sha1(update->old_sha1)) + if (is_null_oid(&update->old_oid)) strbuf_addf(err, "cannot lock ref '%s': " "reference already exists", original_update_refname(update)); @@ -2740,13 +2684,13 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid, strbuf_addf(err, "cannot lock ref '%s': " "reference is missing but expected %s", original_update_refname(update), - sha1_to_hex(update->old_sha1)); + oid_to_hex(&update->old_oid)); else strbuf_addf(err, "cannot lock ref '%s': " "is at %s but expected %s", original_update_refname(update), oid_to_hex(oid), - sha1_to_hex(update->old_sha1)); + oid_to_hex(&update->old_oid)); return -1; } @@ -2773,13 +2717,13 @@ static int lock_ref_for_update(struct files_ref_store *refs, { struct strbuf referent = STRBUF_INIT; int mustexist = (update->flags & REF_HAVE_OLD) && - !is_null_sha1(update->old_sha1); + !is_null_oid(&update->old_oid); int ret; struct ref_lock *lock; files_assert_main_repository(refs, "lock_ref_for_update"); - if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) + if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid)) update->flags |= REF_DELETING; if (head_ref) { @@ -2861,12 +2805,12 @@ static int lock_ref_for_update(struct files_ref_store *refs, !(update->flags & REF_DELETING) && !(update->flags & REF_LOG_ONLY)) { if (!(update->type & REF_ISSYMREF) && - !hashcmp(lock->old_oid.hash, update->new_sha1)) { + !oidcmp(&lock->old_oid, &update->new_oid)) { /* * The reference already has the desired * value, so we don't need to write it. */ - } else if (write_ref_to_lockfile(lock, update->new_sha1, + } else if (write_ref_to_lockfile(lock, &update->new_oid, err)) { char *write_err = strbuf_detach(err, NULL); @@ -3001,8 +2945,8 @@ static int files_transaction_commit(struct ref_store *ref_store, update->flags & REF_LOG_ONLY) { if (files_log_ref_write(refs, lock->ref_name, - lock->old_oid.hash, - update->new_sha1, + &lock->old_oid, + &update->new_oid, update->msg, update->flags, err)) { char *old_msg = strbuf_detach(err, NULL); @@ -3151,7 +3095,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store, struct ref_update *update = transaction->updates[i]; if ((update->flags & REF_HAVE_OLD) && - !is_null_sha1(update->old_sha1)) + !is_null_oid(&update->old_oid)) die("BUG: initial ref transaction with old_sha1 set"); if (refs_verify_refname_available(&refs->base, update->refname, &affected_refnames, NULL, @@ -3172,8 +3116,9 @@ static int files_initial_transaction_commit(struct ref_store *ref_store, struct ref_update *update = transaction->updates[i]; if ((update->flags & REF_HAVE_NEW) && - !is_null_sha1(update->new_sha1)) - add_packed_ref(refs, update->refname, update->new_sha1); + !is_null_oid(&update->new_oid)) + add_packed_ref(refs, update->refname, + &update->new_oid); } if (commit_packed_refs(refs)) { @@ -3198,7 +3143,7 @@ struct expire_reflog_cb { }; static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct expire_reflog_cb *cb = cb_data; @@ -3207,7 +3152,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid, if (cb->flags & EXPIRE_REFLOGS_REWRITE) ooid = &cb->last_kept_oid; - if ((*cb->should_prune_fn)(ooid->hash, noid->hash, email, timestamp, tz, + if ((*cb->should_prune_fn)(ooid, noid, email, timestamp, tz, message, policy_cb)) { if (!cb->newlog) printf("would prune %s", message); @@ -3215,7 +3160,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid, printf("prune %s", message); } else { if (cb->newlog) { - fprintf(cb->newlog, "%s %s %s %lu %+05d\t%s", + fprintf(cb->newlog, "%s %s %s %"PRItime" %+05d\t%s", oid_to_hex(ooid), oid_to_hex(noid), email, timestamp, tz, message); oidcpy(&cb->last_kept_oid, noid); @@ -3244,6 +3189,7 @@ static int files_reflog_expire(struct ref_store *ref_store, int status = 0; int type; struct strbuf err = STRBUF_INIT; + struct object_id oid; memset(&cb, 0, sizeof(cb)); cb.flags = flags; @@ -3293,7 +3239,9 @@ static int files_reflog_expire(struct ref_store *ref_store, } } - (*prepare_fn)(refname, sha1, cb.policy_cb); + hashcpy(oid.hash, sha1); + + (*prepare_fn)(refname, &oid, cb.policy_cb); refs_for_each_reflog_ent(ref_store, refname, expire_reflog_ent, &cb); (*cleanup_fn)(cb.policy_cb); diff --git a/refs/ref-cache.c b/refs/ref-cache.c index 6059362f1d..6b11d9cd12 100644 --- a/refs/ref-cache.c +++ b/refs/ref-cache.c @@ -32,7 +32,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry) } struct ref_entry *create_ref_entry(const char *refname, - const unsigned char *sha1, int flag, + const struct object_id *oid, int flag, int check_name) { struct ref_entry *ref; @@ -41,7 +41,7 @@ struct ref_entry *create_ref_entry(const char *refname, check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) die("Reference has invalid format: '%s'", refname); FLEX_ALLOC_STR(ref, name, refname); - hashcpy(ref->u.value.oid.hash, sha1); + oidcpy(&ref->u.value.oid, oid); oidclr(&ref->u.value.peeled); ref->flag = flag; return ref; diff --git a/refs/ref-cache.h b/refs/ref-cache.h index ffdc54f3f0..1f65e2f9ed 100644 --- a/refs/ref-cache.h +++ b/refs/ref-cache.h @@ -185,7 +185,7 @@ struct ref_entry *create_dir_entry(struct ref_cache *cache, int incomplete); struct ref_entry *create_ref_entry(const char *refname, - const unsigned char *sha1, int flag, + const struct object_id *oid, int flag, int check_name); /* diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 3d46131efb..b6b291cf00 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -130,13 +130,13 @@ struct ref_update { /* * If (flags & REF_HAVE_NEW), set the reference to this value: */ - unsigned char new_sha1[20]; + struct object_id new_oid; /* * If (flags & REF_HAVE_OLD), check that the reference * previously had this value: */ - unsigned char old_sha1[20]; + struct object_id old_oid; /* * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF, @@ -482,6 +482,10 @@ struct ref_store; #define REF_STORE_WRITE (1 << 1) /* can perform update operations */ #define REF_STORE_ODB (1 << 2) /* has access to object database */ #define REF_STORE_MAIN (1 << 3) +#define REF_STORE_ALL_CAPS (REF_STORE_READ | \ + REF_STORE_WRITE | \ + REF_STORE_ODB | \ + REF_STORE_MAIN) /* * Initialize the ref_store for the specified gitdir. These functions diff --git a/remote.c b/remote.c index 801137c72e..fdc52d802c 100644 --- a/remote.c +++ b/remote.c @@ -1191,9 +1191,10 @@ static int match_explicit(struct ref *src, struct ref *dst, else if (is_null_oid(&matched_src->new_oid)) error("unable to delete '%s': remote ref does not exist", dst_value); - else if ((dst_guess = guess_ref(dst_value, matched_src))) + else if ((dst_guess = guess_ref(dst_value, matched_src))) { matched_dst = make_linked_ref(dst_guess, dst_tail); - else + free(dst_guess); + } else error("unable to push to unqualified destination: %s\n" "The destination refspec neither matches an " "existing ref on the remote nor\n" @@ -1296,7 +1297,7 @@ static void add_to_tips(struct tips *tips, const struct object_id *oid) if (is_null_oid(oid)) return; - commit = lookup_commit_reference_gently(oid->hash, 1); + commit = lookup_commit_reference_gently(oid, 1); if (!commit || (commit->object.flags & TMP_MARK)) return; commit->object.flags |= TMP_MARK; @@ -1358,7 +1359,8 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds if (is_null_oid(&ref->new_oid)) continue; - commit = lookup_commit_reference_gently(ref->new_oid.hash, 1); + commit = lookup_commit_reference_gently(&ref->new_oid, + 1); if (!commit) /* not pushing a commit, which is not an error */ continue; @@ -1585,8 +1587,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS; else if (!has_object_file(&ref->old_oid)) reject_reason = REF_STATUS_REJECT_FETCH_FIRST; - else if (!lookup_commit_reference_gently(ref->old_oid.hash, 1) || - !lookup_commit_reference_gently(ref->new_oid.hash, 1)) + else if (!lookup_commit_reference_gently(&ref->old_oid, 1) || + !lookup_commit_reference_gently(&ref->new_oid, 1)) reject_reason = REF_STATUS_REJECT_NEEDS_FORCE; else if (!ref_newer(&ref->new_oid, &ref->old_oid)) reject_reason = REF_STATUS_REJECT_NONFASTFORWARD; @@ -1953,12 +1955,12 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid) * Both new and old must be commit-ish and new is descendant of * old. Otherwise we require --force. */ - o = deref_tag(parse_object(old_oid->hash), NULL, 0); + o = deref_tag(parse_object(old_oid), NULL, 0); if (!o || o->type != OBJ_COMMIT) return 0; old = (struct commit *) o; - o = deref_tag(parse_object(new_oid->hash), NULL, 0); + o = deref_tag(parse_object(new_oid), NULL, 0); if (!o || o->type != OBJ_COMMIT) return 0; new = (struct commit *) o; @@ -2009,13 +2011,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, /* Cannot stat if what we used to build on no longer exists */ if (read_ref(base, oid.hash)) return -1; - theirs = lookup_commit_reference(oid.hash); + theirs = lookup_commit_reference(&oid); if (!theirs) return -1; if (read_ref(branch->refname, oid.hash)) return -1; - ours = lookup_commit_reference(oid.hash); + ours = lookup_commit_reference(&oid); if (!ours) return -1; diff --git a/revision.c b/revision.c index 7ff61ff5f7..b023945309 100644 --- a/revision.c +++ b/revision.c @@ -59,10 +59,10 @@ static void mark_tree_contents_uninteresting(struct tree *tree) while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: - mark_tree_uninteresting(lookup_tree(entry.oid->hash)); + mark_tree_uninteresting(lookup_tree(entry.oid)); break; case OBJ_BLOB: - mark_blob_uninteresting(lookup_blob(entry.oid->hash)); + mark_blob_uninteresting(lookup_blob(entry.oid)); break; default: /* Subproject commit - not in this repository */ @@ -177,23 +177,23 @@ void add_pending_object(struct rev_info *revs, void add_head_to_pending(struct rev_info *revs) { - unsigned char sha1[20]; + struct object_id oid; struct object *obj; - if (get_sha1("HEAD", sha1)) + if (get_oid("HEAD", &oid)) return; - obj = parse_object(sha1); + obj = parse_object(&oid); if (!obj) return; add_pending_object(revs, obj, "HEAD"); } static struct object *get_reference(struct rev_info *revs, const char *name, - const unsigned char *sha1, + const struct object_id *oid, unsigned int flags) { struct object *object; - object = parse_object(sha1); + object = parse_object(oid); if (!object) { if (revs->ignore_missing) return object; @@ -203,10 +203,10 @@ static struct object *get_reference(struct rev_info *revs, const char *name, return object; } -void add_pending_sha1(struct rev_info *revs, const char *name, - const unsigned char *sha1, unsigned int flags) +void add_pending_oid(struct rev_info *revs, const char *name, + const struct object_id *oid, unsigned int flags) { - struct object *object = get_reference(revs, name, sha1, flags); + struct object *object = get_reference(revs, name, oid, flags); add_pending_object(revs, object, name); } @@ -228,9 +228,9 @@ static struct commit *handle_commit(struct rev_info *revs, add_pending_object(revs, object, tag->tag); if (!tag->tagged) die("bad tag"); - object = parse_object(tag->tagged->oid.hash); + object = parse_object(&tag->tagged->oid); if (!object) { - if (flags & UNINTERESTING) + if (revs->ignore_missing_links || (flags & UNINTERESTING)) return NULL; die("bad object %s", oid_to_hex(&tag->tagged->oid)); } @@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) /* How many extra uninteresting commits we want to see.. */ #define SLOP 5 -static int still_interesting(struct commit_list *src, unsigned long date, int slop, +static int still_interesting(struct commit_list *src, timestamp_t date, int slop, struct commit **interesting_cache) { /* @@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs) static int limit_list(struct rev_info *revs) { int slop = SLOP; - unsigned long date = ~0ul; + timestamp_t date = TIME_MAX; struct commit_list *list = revs->commits; struct commit_list *newlist = NULL; struct commit_list **p = &newlist; @@ -1157,9 +1157,9 @@ static int handle_one_ref(const char *path, const struct object_id *oid, if (ref_excluded(cb->all_revs->ref_excludes, path)) return 0; - object = get_reference(cb->all_revs, path, oid->hash, cb->all_flags); + object = get_reference(cb->all_revs, path, oid, cb->all_flags); add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags); - add_pending_sha1(cb->all_revs, path, oid->hash, cb->all_flags); + add_pending_oid(cb->all_revs, path, oid, cb->all_flags); return 0; } @@ -1200,7 +1200,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data) { struct all_refs_cb *cb = cb_data; if (!is_null_oid(oid)) { - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); if (o) { o->flags |= cb->all_flags; /* ??? CMDLINEFLAGS ??? */ @@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data) } static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { handle_one_reflog_commit(ooid, cb_data); @@ -1249,7 +1249,7 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs, int i; if (it->entry_count >= 0) { - struct tree *tree = lookup_tree(it->sha1); + struct tree *tree = lookup_tree(&it->oid); add_pending_object_with_path(revs, &tree->object, "", 040000, path->buf); } @@ -1275,7 +1275,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags) if (S_ISGITLINK(ce->ce_mode)) continue; - blob = lookup_blob(ce->oid.hash); + blob = lookup_blob(&ce->oid); if (!blob) die("unable to add index blob to traversal"); add_pending_object_with_path(revs, &blob->object, "", @@ -1292,7 +1292,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags) static int add_parents_only(struct rev_info *revs, const char *arg_, int flags, int exclude_parent) { - unsigned char sha1[20]; + struct object_id oid; struct object *it; struct commit *commit; struct commit_list *parents; @@ -1303,17 +1303,17 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags, flags ^= UNINTERESTING | BOTTOM; arg++; } - if (get_sha1_committish(arg, sha1)) + if (get_sha1_committish(arg, oid.hash)) return 0; while (1) { - it = get_reference(revs, arg, sha1, 0); + it = get_reference(revs, arg, &oid, 0); if (!it && revs->ignore_missing) return 0; if (it->type != OBJ_TAG) break; if (!((struct tag*)it)->tagged) return 0; - hashcpy(sha1, ((struct tag*)it)->tagged->oid.hash); + oidcpy(&oid, &((struct tag*)it)->tagged->oid); } if (it->type != OBJ_COMMIT) return 0; @@ -1389,16 +1389,16 @@ static void prepare_show_merge(struct rev_info *revs) { struct commit_list *bases; struct commit *head, *other; - unsigned char sha1[20]; + struct object_id oid; const char **prune = NULL; int i, prune_num = 1; /* counting terminating NULL */ - if (get_sha1("HEAD", sha1)) + if (get_oid("HEAD", &oid)) die("--merge without HEAD?"); - head = lookup_commit_or_die(sha1, "HEAD"); - if (get_sha1("MERGE_HEAD", sha1)) + head = lookup_commit_or_die(&oid, "HEAD"); + if (get_oid("MERGE_HEAD", &oid)) die("--merge without MERGE_HEAD?"); - other = lookup_commit_or_die(sha1, "MERGE_HEAD"); + other = lookup_commit_or_die(&oid, "MERGE_HEAD"); add_pending_object(revs, &head->object, "HEAD"); add_pending_object(revs, &other->object, "MERGE_HEAD"); bases = get_merge_bases(head, other); @@ -1434,7 +1434,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi struct object_context oc; char *dotdot; struct object *object; - unsigned char sha1[20]; + struct object_id oid; int local_flags; const char *arg = arg_; int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME; @@ -1444,7 +1444,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi dotdot = strstr(arg, ".."); if (dotdot) { - unsigned char from_sha1[20]; + struct object_id from_oid; const char *next = dotdot + 2; const char *this = arg; int symmetric = *next == '.'; @@ -1470,8 +1470,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi return -1; } } - if (!get_sha1_committish(this, from_sha1) && - !get_sha1_committish(next, sha1)) { + if (!get_sha1_committish(this, from_oid.hash) && + !get_sha1_committish(next, oid.hash)) { struct object *a_obj, *b_obj; if (!cant_be_filename) { @@ -1479,8 +1479,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi verify_non_filename(revs->prefix, arg); } - a_obj = parse_object(from_sha1); - b_obj = parse_object(sha1); + a_obj = parse_object(&from_oid); + b_obj = parse_object(&oid); if (!a_obj || !b_obj) { missing: if (revs->ignore_missing) @@ -1500,10 +1500,10 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi a = (a_obj->type == OBJ_COMMIT ? (struct commit *)a_obj - : lookup_commit_reference(a_obj->oid.hash)); + : lookup_commit_reference(&a_obj->oid)); b = (b_obj->type == OBJ_COMMIT ? (struct commit *)b_obj - : lookup_commit_reference(b_obj->oid.hash)); + : lookup_commit_reference(&b_obj->oid)); if (!a || !b) goto missing; exclude = get_merge_bases(a, b); @@ -1568,11 +1568,11 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi if (revarg_opt & REVARG_COMMITTISH) get_sha1_flags = GET_SHA1_COMMITTISH; - if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc)) + if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc)) return revs->ignore_missing ? 0 : -1; if (!cant_be_filename) verify_non_filename(revs->prefix, arg); - object = get_reference(revs, arg, sha1, flags ^ local_flags); + object = get_reference(revs, arg, &oid, flags ^ local_flags); add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags); add_pending_object_with_mode(revs, object, arg, oc.mode); return 0; @@ -2287,12 +2287,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->show_merge) prepare_show_merge(revs); if (revs->def && !revs->pending.nr && !got_rev_arg) { - unsigned char sha1[20]; + struct object_id oid; struct object *object; struct object_context oc; - if (get_sha1_with_context(revs->def, 0, sha1, &oc)) + if (get_sha1_with_context(revs->def, 0, oid.hash, &oc)) diagnose_missing_default(revs->def); - object = get_reference(revs, revs->def, sha1, 0); + object = get_reference(revs, revs->def, &oid, 0); add_pending_object_with_mode(revs, object, revs->def, oc.mode); } diff --git a/revision.h b/revision.h index 14886ec92b..a91dd3d5d9 100644 --- a/revision.h +++ b/revision.h @@ -181,8 +181,8 @@ struct rev_info { /* special limits */ int skip_count; int max_count; - unsigned long max_age; - unsigned long min_age; + timestamp_t max_age; + timestamp_t min_age; int min_parents; int max_parents; int (*include_check)(struct commit *, void *); @@ -263,9 +263,9 @@ extern void show_object_with_name(FILE *, struct object *, const char *); extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); -extern void add_pending_sha1(struct rev_info *revs, - const char *name, const unsigned char *sha1, - unsigned int flags); +extern void add_pending_oid(struct rev_info *revs, + const char *name, const struct object_id *oid, + unsigned int flags); extern void add_head_to_pending(struct rev_info *); extern void add_reflogs_to_pending(struct rev_info *, unsigned int flags); diff --git a/sequencer.c b/sequencer.c index 10c3b4ff81..a23b948ac1 100644 --- a/sequencer.c +++ b/sequencer.c @@ -344,7 +344,7 @@ static int read_oneliner(struct strbuf *buf, static struct tree *empty_tree(void) { - return lookup_tree(EMPTY_TREE_SHA1_BIN); + return lookup_tree(&empty_tree_oid); } static int error_dirty_index(struct replay_opts *opts) @@ -374,7 +374,7 @@ static void update_abort_safety_file(void) write_file(git_path_abort_safety_file(), "%s", ""); } -static int fast_forward_to(const unsigned char *to, const unsigned char *from, +static int fast_forward_to(const struct object_id *to, const struct object_id *from, int unborn, struct replay_opts *opts) { struct ref_transaction *transaction; @@ -390,7 +390,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from, transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, "HEAD", - to, unborn ? null_sha1 : from, + to->hash, unborn ? null_sha1 : from->hash, 0, sb.buf, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@ -426,7 +426,7 @@ void append_conflicts_hint(struct strbuf *msgbuf) static int do_recursive_merge(struct commit *base, struct commit *next, const char *base_label, const char *next_label, - unsigned char *head, struct strbuf *msgbuf, + struct object_id *head, struct strbuf *msgbuf, struct replay_opts *opts) { struct merge_options o; @@ -482,13 +482,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next, static int is_index_unchanged(void) { - unsigned char head_sha1[20]; + struct object_id head_oid; struct commit *head_commit; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) return error(_("could not resolve HEAD commit\n")); - head_commit = lookup_commit(head_sha1); + head_commit = lookup_commit(&head_oid); /* * If head_commit is NULL, check_commit, called from @@ -508,7 +508,8 @@ static int is_index_unchanged(void) if (cache_tree_update(&the_index, 0)) return error(_("unable to update cache tree\n")); - return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash); + return !oidcmp(&active_cache_tree->oid, + &head_commit->tree->object.oid); } static int write_author_script(const char *message) @@ -834,13 +835,13 @@ static int update_squash_messages(enum todo_command command, strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len); strbuf_release(&header); } else { - unsigned char head[20]; + struct object_id head; struct commit *head_commit; const char *head_message, *body; - if (get_sha1("HEAD", head)) + if (get_oid("HEAD", &head)) return error(_("need a HEAD to fixup")); - if (!(head_commit = lookup_commit_reference(head))) + if (!(head_commit = lookup_commit_reference(&head))) return error(_("could not read HEAD")); if (!(head_message = get_commit_buffer(head_commit, NULL))) return error(_("could not read HEAD's commit message")); @@ -934,7 +935,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, { unsigned int flags = opts->edit ? EDIT_MSG : 0; const char *msg_file = opts->edit ? NULL : git_path_merge_msg(); - unsigned char head[20]; + struct object_id head; struct commit *base, *next, *parent; const char *base_label, *next_label; struct commit_message msg = { NULL, NULL, NULL, NULL }; @@ -948,12 +949,12 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, * that represents the "current" state for merge-recursive * to work on. */ - if (write_cache_as_tree(head, 0, NULL)) + if (write_cache_as_tree(head.hash, 0, NULL)) return error(_("your index file is unmerged.")); } else { - unborn = get_sha1("HEAD", head); + unborn = get_oid("HEAD", &head); if (unborn) - hashcpy(head, EMPTY_TREE_SHA1_BIN); + oidcpy(&head, &empty_tree_oid); if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0, 0)) return error_dirty_index(opts); } @@ -989,11 +990,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, oid_to_hex(&commit->object.oid)); if (opts->allow_ff && !is_fixup(command) && - ((parent && !hashcmp(parent->object.oid.hash, head)) || + ((parent && !oidcmp(&parent->object.oid, &head)) || (!parent && unborn))) { if (is_rebase_i(opts)) write_author_script(msg.message); - res = fast_forward_to(commit->object.oid.hash, head, unborn, + res = fast_forward_to(&commit->object.oid, &head, unborn, opts); if (res || command != TODO_REWORD) goto leave; @@ -1045,6 +1046,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, strbuf_addstr(&msgbuf, p); if (opts->record_origin) { + strbuf_complete_line(&msgbuf); if (!has_conforming_footer(&msgbuf, NULL, 0)) strbuf_addch(&msgbuf, '\n'); strbuf_addstr(&msgbuf, cherry_picked_prefix); @@ -1080,7 +1082,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, res = -1; else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) { res = do_recursive_merge(base, next, base_label, next_label, - head, &msgbuf, opts); + &head, &msgbuf, opts); if (res < 0) return res; res |= write_message(msgbuf.buf, msgbuf.len, @@ -1096,7 +1098,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, commit_list_insert(next, &remotes); res |= try_merge_command(opts->strategy, opts->xopts_nr, (const char **)opts->xopts, - common, sha1_to_hex(head), remotes); + common, oid_to_hex(&head), remotes); free_commit_list(common); free_commit_list(remotes); } @@ -1221,7 +1223,7 @@ static struct todo_item *append_new_todo(struct todo_list *todo_list) static int parse_insn_line(struct todo_item *item, const char *bol, char *eol) { - unsigned char commit_sha1[20]; + struct object_id commit_oid; char *end_of_object_name; int i, saved, status, padding; @@ -1270,7 +1272,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol) end_of_object_name = (char *) bol + strcspn(bol, " \t\n"); saved = *end_of_object_name; *end_of_object_name = '\0'; - status = get_sha1(bol, commit_sha1); + status = get_oid(bol, &commit_oid); *end_of_object_name = saved; item->arg = end_of_object_name + strspn(end_of_object_name, " \t"); @@ -1279,7 +1281,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol) if (status < 0) return -1; - item->commit = lookup_commit_reference(commit_sha1); + item->commit = lookup_commit_reference(&commit_oid); return !item->commit; } @@ -1913,11 +1915,13 @@ static int apply_autostash(struct replay_opts *opts) strbuf_trim(&stash_sha1); child.git_cmd = 1; + child.no_stdout = 1; + child.no_stderr = 1; argv_array_push(&child.args, "stash"); argv_array_push(&child.args, "apply"); argv_array_push(&child.args, stash_sha1.buf); if (!run_command(&child)) - printf(_("Applied autostash.")); + printf(_("Applied autostash.\n")); else { struct child_process store = CHILD_PROCESS_INIT; @@ -2088,6 +2092,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts) res = error(_("could not read orig-head")); goto cleanup_head_ref; } + strbuf_reset(&buf); if (!read_oneliner(&buf, rebase_path_onto(), 0)) { res = error(_("could not read 'onto'")); goto cleanup_head_ref; @@ -2280,7 +2285,7 @@ static int single_pick(struct commit *cmit, struct replay_opts *opts) int sequencer_pick_revisions(struct replay_opts *opts) { struct todo_list todo_list = TODO_LIST_INIT; - unsigned char sha1[20]; + struct object_id oid; int i, res; assert(opts->revs); @@ -2288,16 +2293,16 @@ int sequencer_pick_revisions(struct replay_opts *opts) return -1; for (i = 0; i < opts->revs->pending.nr; i++) { - unsigned char sha1[20]; + struct object_id oid; const char *name = opts->revs->pending.objects[i].name; /* This happens when using --stdin. */ if (!strlen(name)) continue; - if (!get_sha1(name, sha1)) { - if (!lookup_commit_reference_gently(sha1, 1)) { - enum object_type type = sha1_object_info(sha1, NULL); + if (!get_oid(name, &oid)) { + if (!lookup_commit_reference_gently(&oid, 1)) { + enum object_type type = sha1_object_info(oid.hash, NULL); return error(_("%s: can't cherry-pick a %s"), name, typename(type)); } @@ -2334,9 +2339,9 @@ int sequencer_pick_revisions(struct replay_opts *opts) if (walk_revs_populate_todo(&todo_list, opts) || create_seq_dir() < 0) return -1; - if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT)) + if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT)) return error(_("can't revert as initial commit")); - if (save_head(sha1_to_hex(sha1))) + if (save_head(oid_to_hex(&oid))) return -1; if (save_opts(opts)) return -1; @@ -2357,6 +2362,9 @@ void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag) getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); + if (!ignore_footer) + strbuf_complete_line(msgbuf); + /* * If the whole message buffer is equal to the sob, pretend that we * found a conforming footer with a matching sob @@ -2377,13 +2385,6 @@ void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag) * the title and body to be filled in by the user. */ append_newlines = "\n\n"; - } else if (msgbuf->buf[len - 1] != '\n') { - /* - * Incomplete line. Complete the line and add a - * blank one so that there is an empty line between - * the message body and the sob. - */ - append_newlines = "\n\n"; } else if (len == 1) { /* * Buffer contains a single newline. Add another diff --git a/server-info.c b/server-info.c index f6c1a3dfb0..6f865b73a3 100644 --- a/server-info.c +++ b/server-info.c @@ -53,7 +53,7 @@ static int add_info_ref(const char *path, const struct object_id *oid, int flag, void *cb_data) { FILE *fp = cb_data; - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); if (!o) return -1; diff --git a/setup.c b/setup.c index 0309c27821..e3f7699a90 100644 --- a/setup.c +++ b/setup.c @@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir, /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { + char *to_free = NULL; + const char *ret; + if (offset != cwd->len && !is_absolute_path(gitdir)) - gitdir = real_pathdup(gitdir, 1); + gitdir = to_free = real_pathdup(gitdir, 1); if (chdir(cwd->buf)) die_errno("Could not come back to cwd"); - return setup_explicit_git_dir(gitdir, cwd, nongit_ok); + ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok); + free(to_free); + return ret; } /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */ @@ -748,7 +753,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset, /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { - const char *gitdir; + static const char *gitdir; gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset); if (chdir(cwd->buf)) diff --git a/sha1_name.c b/sha1_name.c index 8eec9f7c1b..389276e9d3 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -241,7 +241,7 @@ static int disambiguate_committish_only(const struct object_id *oid, void *cb_da return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(oid->hash), NULL, 0); + obj = deref_tag(parse_object(oid), NULL, 0); if (obj && obj->type == OBJ_COMMIT) return 1; return 0; @@ -265,7 +265,7 @@ static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_ return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(oid->hash), NULL, 0); + obj = deref_tag(parse_object(oid), NULL, 0); if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT)) return 1; return 0; @@ -354,14 +354,14 @@ static int show_ambiguous_object(const struct object_id *oid, void *data) type = sha1_object_info(oid->hash, NULL); if (type == OBJ_COMMIT) { - struct commit *commit = lookup_commit(oid->hash); + struct commit *commit = lookup_commit(oid); if (commit) { struct pretty_print_context pp = {0}; pp.date_mode.type = DATE_SHORT; format_commit_message(commit, " %ad - %s", &desc, &pp); } } else if (type == OBJ_TAG) { - struct tag *tag = lookup_tag(oid->hash); + struct tag *tag = lookup_tag(oid); if (!parse_tag(tag) && tag->tag) strbuf_addf(&desc, " %s", tag->tag); } @@ -660,8 +660,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1, if (reflog_len) { int nth, i; - unsigned long at_time; - unsigned long co_time; + timestamp_t at_time; + timestamp_t co_time; int co_tz, co_cnt; /* Is it asking for N-th entry, or approxidate? */ @@ -722,14 +722,14 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1, static int get_parent(const char *name, int len, unsigned char *result, int idx) { - unsigned char sha1[20]; - int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); + struct object_id oid; + int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH); struct commit *commit; struct commit_list *p; if (ret) return ret; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (parse_commit(commit)) return -1; if (!idx) { @@ -750,14 +750,14 @@ static int get_parent(const char *name, int len, static int get_nth_ancestor(const char *name, int len, unsigned char *result, int generation) { - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; int ret; - ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); + ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH); if (ret) return ret; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (!commit) return -1; @@ -776,7 +776,7 @@ struct object *peel_to_type(const char *name, int namelen, if (name && !namelen) namelen = strlen(name); while (1) { - if (!o || (!o->parsed && !parse_object(o->oid.hash))) + if (!o || (!o->parsed && !parse_object(&o->oid))) return NULL; if (expected_type == OBJ_ANY || o->type == expected_type) return o; @@ -798,7 +798,7 @@ struct object *peel_to_type(const char *name, int namelen, static int peel_onion(const char *name, int len, unsigned char *sha1, unsigned lookup_flags) { - unsigned char outer[20]; + struct object_id outer; const char *sp; unsigned int expected_type = 0; struct object *o; @@ -846,15 +846,15 @@ static int peel_onion(const char *name, int len, unsigned char *sha1, else if (expected_type == OBJ_TREE) lookup_flags |= GET_SHA1_TREEISH; - if (get_sha1_1(name, sp - name - 2, outer, lookup_flags)) + if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags)) return -1; - o = parse_object(outer); + o = parse_object(&outer); if (!o) return -1; if (!expected_type) { o = deref_tag(o, name, sp - name - 2); - if (!o || (!o->parsed && !parse_object(o->oid.hash))) + if (!o || (!o->parsed && !parse_object(&o->oid))) return -1; hashcpy(sha1, o->oid.hash); return 0; @@ -981,7 +981,7 @@ static int handle_one_ref(const char *path, const struct object_id *oid, int flag, void *cb_data) { struct commit_list **list = cb_data; - struct object *object = parse_object(oid->hash); + struct object *object = parse_object(oid); if (!object) return 0; if (object->type == OBJ_TAG) { @@ -1027,7 +1027,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1, int matches; commit = pop_most_recent_commit(&list, ONELINE_SEEN); - if (!parse_object(commit->object.oid.hash)) + if (!parse_object(&commit->object.oid)) continue; buf = get_commit_buffer(commit, NULL); p = strstr(buf, "\n\n"); @@ -1054,7 +1054,7 @@ struct grab_nth_branch_switch_cbdata { }; static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct grab_nth_branch_switch_cbdata *cb = cb_data; @@ -1136,13 +1136,13 @@ int get_oid_mb(const char *name, struct object_id *oid) } if (st) return st; - one = lookup_commit_reference_gently(oid_tmp.hash, 0); + one = lookup_commit_reference_gently(&oid_tmp, 0); if (!one) return -1; if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash)) return -1; - two = lookup_commit_reference_gently(oid_tmp.hash, 0); + two = lookup_commit_reference_gently(&oid_tmp, 0); if (!two) return -1; mbs = get_merge_bases(one, two); diff --git a/shallow.c b/shallow.c index 25b6db989b..ef7ca78993 100644 --- a/shallow.c +++ b/shallow.c @@ -27,13 +27,13 @@ void set_alternate_shallow_file(const char *path, int override) alternate_shallow_file = xstrdup_or_null(path); } -int register_shallow(const unsigned char *sha1) +int register_shallow(const struct object_id *oid) { struct commit_graft *graft = xmalloc(sizeof(struct commit_graft)); - struct commit *commit = lookup_commit(sha1); + struct commit *commit = lookup_commit(oid); - hashcpy(graft->oid.hash, sha1); + oidcpy(&graft->oid, oid); graft->nr_parent = -1; if (commit && commit->object.parsed) commit->parents = NULL; @@ -65,10 +65,10 @@ int is_repository_shallow(void) is_shallow = 1; while (fgets(buf, sizeof(buf), fp)) { - unsigned char sha1[20]; - if (get_sha1_hex(buf, sha1)) + struct object_id oid; + if (get_oid_hex(buf, &oid)) die("bad shallow line: %s", buf); - register_shallow(sha1); + register_shallow(&oid); } fclose(fp); return is_shallow; @@ -241,7 +241,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) if (graft->nr_parent != -1) return 0; if (data->flags & SEEN_ONLY) { - struct commit *c = lookup_commit(graft->oid.hash); + struct commit *c = lookup_commit(&graft->oid); if (!c || !(c->object.flags & SEEN)) { if (data->flags & VERBOSE) printf("Removing %s from .git/shallow\n", @@ -466,18 +466,22 @@ static uint32_t *paint_alloc(struct paint_info *info) * UNINTERESTING or BOTTOM is hit. Set the id-th bit in ref_bitmap for * all walked commits. */ -static void paint_down(struct paint_info *info, const unsigned char *sha1, +static void paint_down(struct paint_info *info, const struct object_id *oid, unsigned int id) { unsigned int i, nr; struct commit_list *head = NULL; int bitmap_nr = (info->nr_bits + 31) / 32; size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr); - uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */ - uint32_t *bitmap = paint_alloc(info); - struct commit *c = lookup_commit_reference_gently(sha1, 1); + struct commit *c = lookup_commit_reference_gently(oid, 1); + uint32_t *tmp; /* to be freed before return */ + uint32_t *bitmap; + if (!c) return; + + tmp = xmalloc(bitmap_size); + bitmap = paint_alloc(info); memset(bitmap, 0, bitmap_size); bitmap[id / 32] |= (1U << (id % 32)); commit_list_insert(c, &head); @@ -531,7 +535,7 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1, static int mark_uninteresting(const char *refname, const struct object_id *oid, int flags, void *cb_data) { - struct commit *commit = lookup_commit_reference_gently(oid->hash, 1); + struct commit *commit = lookup_commit_reference_gently(oid, 1); if (!commit) return 0; commit->object.flags |= UNINTERESTING; @@ -599,18 +603,18 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, /* Mark potential bottoms so we won't go out of bound */ for (i = 0; i < nr_shallow; i++) { - struct commit *c = lookup_commit(oid[shallow[i]].hash); + struct commit *c = lookup_commit(&oid[shallow[i]]); c->object.flags |= BOTTOM; } for (i = 0; i < ref->nr; i++) - paint_down(&pi, ref->oid[i].hash, i); + paint_down(&pi, ref->oid + i, i); if (used) { int bitmap_size = ((pi.nr_bits + 31) / 32) * sizeof(uint32_t); memset(used, 0, sizeof(*used) * info->shallow->nr); for (i = 0; i < nr_shallow; i++) { - const struct commit *c = lookup_commit(oid[shallow[i]].hash); + const struct commit *c = lookup_commit(&oid[shallow[i]]); uint32_t **map = ref_bitmap_at(&pi.ref_bitmap, c); if (*map) used[shallow[i]] = xmemdupz(*map, bitmap_size); @@ -641,7 +645,7 @@ static int add_ref(const char *refname, const struct object_id *oid, { struct commit_array *ca = cb_data; ALLOC_GROW(ca->commits, ca->nr + 1, ca->alloc); - ca->commits[ca->nr] = lookup_commit_reference_gently(oid->hash, 1); + ca->commits[ca->nr] = lookup_commit_reference_gently(oid, 1); if (ca->commits[ca->nr]) ca->nr++; return 0; @@ -679,7 +683,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) info->theirs[dst] = info->theirs[i]; - c = lookup_commit(oid[info->theirs[i]].hash); + c = lookup_commit(&oid[info->theirs[i]]); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -700,7 +704,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_ours; i++) { if (i != dst) info->ours[dst] = info->ours[i]; - c = lookup_commit(oid[info->ours[i]].hash); + c = lookup_commit(&oid[info->ours[i]]); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -722,7 +726,7 @@ static void post_assign_shallow(struct shallow_info *info, int delayed_reachability_test(struct shallow_info *si, int c) { if (si->need_reachability_test[c]) { - struct commit *commit = lookup_commit(si->shallow->oid[c].hash); + struct commit *commit = lookup_commit(&si->shallow->oid[c]); if (!si->commits) { struct commit_array ca; diff --git a/split-index.c b/split-index.c index f519e60f87..49bd197f71 100644 --- a/split-index.c +++ b/split-index.c @@ -73,10 +73,17 @@ void move_cache_to_base_index(struct index_state *istate) int i; /* - * do not delete old si->base, its index entries may be shared - * with istate->cache[]. Accept a bit of leaking here because - * this code is only used by short-lived update-index. + * If "si" is shared with another index_state (e.g. by + * unpack-trees code), we will need to duplicate split_index + * struct. It's not happening now though, luckily. */ + assert(si->refcount <= 1); + + unshare_split_index(istate, 0); + if (si->base) { + discard_index(si->base); + free(si->base); + } si->base = xcalloc(1, sizeof(*si->base)); si->base->version = istate->version; /* zero timestamp disables racy test in ce_write_index() */ @@ -275,11 +282,41 @@ void finish_writing_split_index(struct index_state *istate) istate->cache_nr = si->saved_cache_nr; } +void unshare_split_index(struct index_state *istate, int discard) +{ + struct split_index *si = istate->split_index; + int i; + + if (!si || !si->base) + return; + + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + struct cache_entry *new = NULL; + + if (!ce->index || + ce->index > si->base->cache_nr || + ce != si->base->cache[ce->index - 1]) + continue; + + if (!discard) { + int len = ce_namelen(ce); + new = xcalloc(1, cache_entry_size(len)); + copy_cache_entry(new, ce); + memcpy(new->name, ce->name, len); + new->index = 0; + } + istate->cache[i] = new; + } +} + + void discard_split_index(struct index_state *istate) { struct split_index *si = istate->split_index; if (!si) return; + unshare_split_index(istate, 0); istate->split_index = NULL; si->refcount--; if (si->refcount) @@ -328,14 +365,8 @@ void add_split_index(struct index_state *istate) void remove_split_index(struct index_state *istate) { - if (istate->split_index) { - /* - * can't discard_split_index(&the_index); because that - * will destroy split_index->base->cache[], which may - * be shared with the_index.cache[]. So yeah we're - * leaking a bit here. - */ - istate->split_index = NULL; - istate->cache_changed |= SOMETHING_CHANGED; - } + if (!istate->split_index) + return; + discard_split_index(istate); + istate->cache_changed |= SOMETHING_CHANGED; } diff --git a/split-index.h b/split-index.h index df91c1bda8..65c0f09b2b 100644 --- a/split-index.h +++ b/split-index.h @@ -33,5 +33,6 @@ void finish_writing_split_index(struct index_state *istate); void discard_split_index(struct index_state *istate); void add_split_index(struct index_state *istate); void remove_split_index(struct index_state *istate); +void unshare_split_index(struct index_state *istate, int discard); #endif diff --git a/submodule.c b/submodule.c index 80851d0447..bf5a93d16f 100644 --- a/submodule.c +++ b/submodule.c @@ -20,7 +20,7 @@ static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND; static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int parallel_jobs = 1; -static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP; +static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP; static int initialized_fetch_ref_tips; static struct oid_array ref_tips_before_fetch; static struct oid_array ref_tips_after_fetch; @@ -510,8 +510,8 @@ static void show_submodule_header(FILE *f, const char *path, * Attempt to lookup the commit references, and determine if this is * a fast forward or fast backwards update. */ - *left = lookup_commit_reference(one->hash); - *right = lookup_commit_reference(two->hash); + *left = lookup_commit_reference(one); + *right = lookup_commit_reference(two); /* * Warn about missing commits in the submodule project, but only if @@ -617,7 +617,8 @@ void show_submodule_inline_diff(FILE *f, const char *path, cp.no_stdin = 1; /* TODO: other options may need to be passed here. */ - argv_array_push(&cp.args, "diff"); + argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL); + argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix); if (DIFF_OPT_TST(o, REVERSE_DIFF)) { argv_array_pushf(&cp.args, "--src-prefix=%s%s/", @@ -680,6 +681,94 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce) return submodule_from_path(null_sha1, ce->name); } +static struct oid_array *submodule_commits(struct string_list *submodules, + const char *path) +{ + struct string_list_item *item; + + item = string_list_insert(submodules, path); + if (item->util) + return (struct oid_array *) item->util; + + /* NEEDSWORK: should we have oid_array_init()? */ + item->util = xcalloc(1, sizeof(struct oid_array)); + return (struct oid_array *) item->util; +} + +static void collect_changed_submodules_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) +{ + int i; + struct string_list *changed = data; + + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + struct oid_array *commits; + if (!S_ISGITLINK(p->two->mode)) + continue; + + if (S_ISGITLINK(p->one->mode)) { + /* + * NEEDSWORK: We should honor the name configured in + * the .gitmodules file of the commit we are examining + * here to be able to correctly follow submodules + * being moved around. + */ + commits = submodule_commits(changed, p->two->path); + oid_array_append(commits, &p->two->oid); + } else { + /* Submodule is new or was moved here */ + /* + * NEEDSWORK: When the .git directories of submodules + * live inside the superprojects .git directory some + * day we should fetch new submodules directly into + * that location too when config or options request + * that so they can be checked out from there. + */ + continue; + } + } +} + +/* + * Collect the paths of submodules in 'changed' which have changed based on + * the revisions as specified in 'argv'. Each entry in 'changed' will also + * have a corresponding 'struct oid_array' (in the 'util' field) which lists + * what the submodule pointers were updated to during the change. + */ +static void collect_changed_submodules(struct string_list *changed, + struct argv_array *argv) +{ + struct rev_info rev; + const struct commit *commit; + + init_revisions(&rev, NULL); + setup_revisions(argv->argc, argv->argv, &rev, NULL); + if (prepare_revision_walk(&rev)) + die("revision walk setup failed"); + + while ((commit = get_revision(&rev))) { + struct rev_info diff_rev; + + init_revisions(&diff_rev, NULL); + diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; + diff_rev.diffopt.format_callback = collect_changed_submodules_cb; + diff_rev.diffopt.format_callback_data = changed; + diff_tree_combined_merge(commit, 1, &diff_rev); + } + + reset_revision_walk(); +} + +static void free_submodules_oids(struct string_list *submodules) +{ + struct string_list_item *item; + for_each_string_list_item(item, submodules) + oid_array_clear((struct oid_array *) item->util); + string_list_clear(submodules, 1); +} + static int has_remote(const char *refname, const struct object_id *oid, int flags, void *cb_data) { @@ -697,7 +786,7 @@ static int check_has_commit(const struct object_id *oid, void *data) { int *has_commit = data; - if (!lookup_commit_reference(oid->hash)) + if (!lookup_commit_reference(oid)) *has_commit = 0; return 0; @@ -707,10 +796,44 @@ static int submodule_has_commits(const char *path, struct oid_array *commits) { int has_commit = 1; + /* + * Perform a cheap, but incorrect check for the existance of 'commits'. + * This is done by adding the submodule's object store to the in-core + * object store, and then querying for each commit's existance. If we + * do not have the commit object anywhere, there is no chance we have + * it in the object store of the correct submodule and have it + * reachable from a ref, so we can fail early without spawning rev-list + * which is expensive. + */ if (add_submodule_odb(path)) return 0; oid_array_for_each_unique(commits, check_has_commit, &has_commit); + + if (has_commit) { + /* + * Even if the submodule is checked out and the commit is + * present, make sure it exists in the submodule's object store + * and that it is reachable from a ref. + */ + struct child_process cp = CHILD_PROCESS_INIT; + struct strbuf out = STRBUF_INIT; + + argv_array_pushl(&cp.args, "rev-list", "-n", "1", NULL); + oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args); + argv_array_pushl(&cp.args, "--not", "--all", NULL); + + prepare_submodule_repo_env(&cp.env_array); + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; + + if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len) + has_commit = 0; + + strbuf_release(&out); + } + return has_commit; } @@ -758,91 +881,31 @@ static int submodule_needs_pushing(const char *path, struct oid_array *commits) return 0; } -static struct oid_array *submodule_commits(struct string_list *submodules, - const char *path) -{ - struct string_list_item *item; - - item = string_list_insert(submodules, path); - if (item->util) - return (struct oid_array *) item->util; - - /* NEEDSWORK: should we have oid_array_init()? */ - item->util = xcalloc(1, sizeof(struct oid_array)); - return (struct oid_array *) item->util; -} - -static void collect_submodules_from_diff(struct diff_queue_struct *q, - struct diff_options *options, - void *data) -{ - int i; - struct string_list *submodules = data; - - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - struct oid_array *commits; - if (!S_ISGITLINK(p->two->mode)) - continue; - commits = submodule_commits(submodules, p->two->path); - oid_array_append(commits, &p->two->oid); - } -} - -static void find_unpushed_submodule_commits(struct commit *commit, - struct string_list *needs_pushing) -{ - struct rev_info rev; - - init_revisions(&rev, NULL); - rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = collect_submodules_from_diff; - rev.diffopt.format_callback_data = needs_pushing; - diff_tree_combined_merge(commit, 1, &rev); -} - -static void free_submodules_sha1s(struct string_list *submodules) -{ - struct string_list_item *item; - for_each_string_list_item(item, submodules) - oid_array_clear((struct oid_array *) item->util); - string_list_clear(submodules, 1); -} - int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing) { - struct rev_info rev; - struct commit *commit; struct string_list submodules = STRING_LIST_INIT_DUP; struct string_list_item *submodule; struct argv_array argv = ARGV_ARRAY_INIT; - init_revisions(&rev, NULL); - /* argv.argv[0] will be ignored by setup_revisions */ argv_array_push(&argv, "find_unpushed_submodules"); oid_array_for_each_unique(commits, append_oid_to_argv, &argv); argv_array_push(&argv, "--not"); argv_array_pushf(&argv, "--remotes=%s", remotes_name); - setup_revisions(argv.argc, argv.argv, &rev, NULL); - if (prepare_revision_walk(&rev)) - die("revision walk setup failed"); - - while ((commit = get_revision(&rev)) != NULL) - find_unpushed_submodule_commits(commit, &submodules); - - reset_revision_walk(); - argv_array_clear(&argv); + collect_changed_submodules(&submodules, &argv); for_each_string_list_item(submodule, &submodules) { - struct oid_array *commits = (struct oid_array *) submodule->util; + struct oid_array *commits = submodule->util; + const char *path = submodule->string; - if (submodule_needs_pushing(submodule->string, commits)) - string_list_insert(needs_pushing, submodule->string); + if (submodule_needs_pushing(path, commits)) + string_list_insert(needs_pushing, path); } - free_submodules_sha1s(&submodules); + + free_submodules_oids(&submodules); + argv_array_clear(&argv); return needs_pushing->nr; } @@ -959,125 +1022,56 @@ int push_unpushed_submodules(struct oid_array *commits, return ret; } -static int is_submodule_commit_present(const char *path, unsigned char sha1[20]) -{ - int is_present = 0; - if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) { - /* Even if the submodule is checked out and the commit is - * present, make sure it is reachable from a ref. */ - struct child_process cp = CHILD_PROCESS_INIT; - const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL}; - struct strbuf buf = STRBUF_INIT; - - argv[3] = sha1_to_hex(sha1); - cp.argv = argv; - prepare_submodule_repo_env(&cp.env_array); - cp.git_cmd = 1; - cp.no_stdin = 1; - cp.dir = path; - if (!capture_command(&cp, &buf, 1024) && !buf.len) - is_present = 1; - - strbuf_release(&buf); - } - return is_present; -} - -static void submodule_collect_changed_cb(struct diff_queue_struct *q, - struct diff_options *options, - void *data) -{ - int i; - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - if (!S_ISGITLINK(p->two->mode)) - continue; - - if (S_ISGITLINK(p->one->mode)) { - /* NEEDSWORK: We should honor the name configured in - * the .gitmodules file of the commit we are examining - * here to be able to correctly follow submodules - * being moved around. */ - struct string_list_item *path; - path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path); - if (!path && !is_submodule_commit_present(p->two->path, p->two->oid.hash)) - string_list_append(&changed_submodule_paths, xstrdup(p->two->path)); - } else { - /* Submodule is new or was moved here */ - /* NEEDSWORK: When the .git directories of submodules - * live inside the superprojects .git directory some - * day we should fetch new submodules directly into - * that location too when config or options request - * that so they can be checked out from there. */ - continue; - } - } -} - -static int add_sha1_to_array(const char *ref, const struct object_id *oid, - int flags, void *data) +static int append_oid_to_array(const char *ref, const struct object_id *oid, + int flags, void *data) { - oid_array_append(data, oid); + struct oid_array *array = data; + oid_array_append(array, oid); return 0; } void check_for_new_submodule_commits(struct object_id *oid) { if (!initialized_fetch_ref_tips) { - for_each_ref(add_sha1_to_array, &ref_tips_before_fetch); + for_each_ref(append_oid_to_array, &ref_tips_before_fetch); initialized_fetch_ref_tips = 1; } oid_array_append(&ref_tips_after_fetch, oid); } -static int add_oid_to_argv(const struct object_id *oid, void *data) -{ - argv_array_push(data, oid_to_hex(oid)); - return 0; -} - static void calculate_changed_submodule_paths(void) { - struct rev_info rev; - struct commit *commit; struct argv_array argv = ARGV_ARRAY_INIT; + struct string_list changed_submodules = STRING_LIST_INIT_DUP; + const struct string_list_item *item; /* No need to check if there are no submodules configured */ if (!submodule_from_path(NULL, NULL)) return; - init_revisions(&rev, NULL); argv_array_push(&argv, "--"); /* argv[0] program name */ oid_array_for_each_unique(&ref_tips_after_fetch, - add_oid_to_argv, &argv); + append_oid_to_argv, &argv); argv_array_push(&argv, "--not"); oid_array_for_each_unique(&ref_tips_before_fetch, - add_oid_to_argv, &argv); - setup_revisions(argv.argc, argv.argv, &rev, NULL); - if (prepare_revision_walk(&rev)) - die("revision walk setup failed"); + append_oid_to_argv, &argv); /* * Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_paths". */ - while ((commit = get_revision(&rev))) { - struct commit_list *parent = commit->parents; - while (parent) { - struct diff_options diff_opts; - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.output_format |= DIFF_FORMAT_CALLBACK; - diff_opts.format_callback = submodule_collect_changed_cb; - diff_setup_done(&diff_opts); - diff_tree_sha1(parent->item->object.oid.hash, commit->object.oid.hash, "", &diff_opts); - diffcore_std(&diff_opts); - diff_flush(&diff_opts); - parent = parent->next; - } + collect_changed_submodules(&changed_submodules, &argv); + + for_each_string_list_item(item, &changed_submodules) { + struct oid_array *commits = item->util; + const char *path = item->string; + + if (!submodule_has_commits(path, commits)) + string_list_append(&changed_submodule_paths, path); } + free_submodules_oids(&changed_submodules); argv_array_clear(&argv); oid_array_clear(&ref_tips_before_fetch); oid_array_clear(&ref_tips_after_fetch); @@ -1426,7 +1420,7 @@ static int submodule_has_dirty_index(const struct submodule *sub) { struct child_process cp = CHILD_PROCESS_INIT; - prepare_submodule_repo_env_no_git_dir(&cp.env_array); + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; argv_array_pushl(&cp.args, "diff-index", "--quiet", @@ -1443,7 +1437,7 @@ static int submodule_has_dirty_index(const struct submodule *sub) static void submodule_reset_index(const char *path) { struct child_process cp = CHILD_PROCESS_INIT; - prepare_submodule_repo_env_no_git_dir(&cp.env_array); + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; @@ -1472,6 +1466,23 @@ int submodule_move_head(const char *path, int ret = 0; struct child_process cp = CHILD_PROCESS_INIT; const struct submodule *sub; + int *error_code_ptr, error_code; + + if (!is_submodule_initialized(path)) + return 0; + + if (flags & SUBMODULE_MOVE_HEAD_FORCE) + /* + * Pass non NULL pointer to is_submodule_populated_gently + * to prevent die()-ing. We'll use connect_work_tree_and_git_dir + * to fixup the submodule in the force case later. + */ + error_code_ptr = &error_code; + else + error_code_ptr = NULL; + + if (old && !is_submodule_populated_gently(path, error_code_ptr)) + return 0; sub = submodule_from_path(null_sha1, path); @@ -1490,18 +1501,24 @@ int submodule_move_head(const char *path, absorb_git_dir_into_superproject("", path, ABSORB_GITDIR_RECURSE_SUBMODULES); } else { - struct strbuf sb = STRBUF_INIT; - strbuf_addf(&sb, "%s/modules/%s", + char *gitdir = xstrfmt("%s/modules/%s", get_git_common_dir(), sub->name); - connect_work_tree_and_git_dir(path, sb.buf); - strbuf_release(&sb); + connect_work_tree_and_git_dir(path, gitdir); + free(gitdir); /* make sure the index is clean as well */ submodule_reset_index(path); } + + if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) { + char *gitdir = xstrfmt("%s/modules/%s", + get_git_common_dir(), sub->name); + connect_work_tree_and_git_dir(path, gitdir); + free(gitdir); + } } - prepare_submodule_repo_env_no_git_dir(&cp.env_array); + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; @@ -1509,7 +1526,7 @@ int submodule_move_head(const char *path, argv_array_pushf(&cp.args, "--super-prefix=%s%s/", get_super_prefix_or_empty(), path); - argv_array_pushl(&cp.args, "read-tree", NULL); + argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL); if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN) argv_array_push(&cp.args, "-n"); @@ -1531,15 +1548,16 @@ int submodule_move_head(const char *path, if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) { if (new) { - struct child_process cp1 = CHILD_PROCESS_INIT; + child_process_init(&cp); /* also set the HEAD accordingly */ - cp1.git_cmd = 1; - cp1.no_stdin = 1; - cp1.dir = path; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; - argv_array_pushl(&cp1.args, "update-ref", "HEAD", new, NULL); + prepare_submodule_repo_env(&cp.env_array); + argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL); - if (run_command(&cp1)) { + if (run_command(&cp)) { ret = -1; goto out; } @@ -1629,9 +1647,9 @@ static void print_commit(struct commit *commit) #define MERGE_WARNING(path, msg) \ warning("Failed to merge submodule %s (%s)", path, msg); -int merge_submodule(unsigned char result[20], const char *path, - const unsigned char base[20], const unsigned char a[20], - const unsigned char b[20], int search) +int merge_submodule(struct object_id *result, const char *path, + const struct object_id *base, const struct object_id *a, + const struct object_id *b, int search) { struct commit *commit_base, *commit_a, *commit_b; int parent_count; @@ -1640,14 +1658,14 @@ int merge_submodule(unsigned char result[20], const char *path, int i; /* store a in result in case we fail */ - hashcpy(result, a); + oidcpy(result, a); /* we can not handle deletion conflicts */ - if (is_null_sha1(base)) + if (is_null_oid(base)) return 0; - if (is_null_sha1(a)) + if (is_null_oid(a)) return 0; - if (is_null_sha1(b)) + if (is_null_oid(b)) return 0; if (add_submodule_odb(path)) { @@ -1671,11 +1689,11 @@ int merge_submodule(unsigned char result[20], const char *path, /* Case #1: a is contained in b or vice versa */ if (in_merge_bases(commit_a, commit_b)) { - hashcpy(result, b); + oidcpy(result, b); return 1; } if (in_merge_bases(commit_b, commit_a)) { - hashcpy(result, a); + oidcpy(result, a); return 1; } diff --git a/submodule.h b/submodule.h index 266d81f1c4..8fb0f25498 100644 --- a/submodule.h +++ b/submodule.h @@ -88,10 +88,10 @@ extern int submodule_uses_gitfile(const char *path); #define SUBMODULE_REMOVAL_IGNORE_UNTRACKED (1<<1) #define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<2) extern int bad_to_remove_submodule(const char *path, unsigned flags); -extern int merge_submodule(unsigned char result[20], const char *path, - const unsigned char base[20], - const unsigned char a[20], - const unsigned char b[20], int search); +extern int merge_submodule(struct object_id *result, const char *path, + const struct object_id *base, + const struct object_id *a, + const struct object_id *b, int search); extern int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing); diff --git a/t/.gitattributes b/t/.gitattributes index 2d44088f56..3bd959ae52 100644 --- a/t/.gitattributes +++ b/t/.gitattributes @@ -1,2 +1,22 @@ t[0-9][0-9][0-9][0-9]/* -whitespace -t0110/url-* binary +/diff-lib/* eol=lf +/t0110/url-* binary +/t3900/*.txt eol=lf +/t3901/*.txt eol=lf +/t4034/*/* eol=lf +/t4013/* eol=lf +/t4018/* eol=lf +/t4051/* eol=lf +/t4100/* eol=lf +/t4101/* eol=lf +/t4109/* eol=lf +/t4110/* eol=lf +/t4135/* eol=lf +/t4211/* eol=lf +/t4252/* eol=lf +/t5100/* eol=lf +/t5515/* eol=lf +/t556x_common eol=lf +/t7500/* eol=lf +/t8005/*.txt eol=lf +/t9*/*.dump eol=lf diff --git a/t/helper/test-date.c b/t/helper/test-date.c index 506054bcd5..f414a3ac67 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -4,7 +4,9 @@ static const char *usage_msg = "\n" " test-date relative [time_t]...\n" " test-date show: [time_t]...\n" " test-date parse [date]...\n" -" test-date approxidate [date]...\n"; +" test-date approxidate [date]...\n" +" test-date is64bit\n" +" test-date time_t-is64bit\n"; static void show_relative_dates(const char **argv, struct timeval *now) { @@ -25,14 +27,14 @@ static void show_dates(const char **argv, const char *format) parse_date_format(format, &mode); for (; *argv; argv++) { char *arg; - time_t t; + timestamp_t t; int tz; /* * Do not use our normal timestamp parsing here, as the point * is to test the formatting code in isolation. */ - t = strtol(*argv, &arg, 10); + t = parse_timestamp(*argv, &arg, 10); while (*arg == ' ') arg++; tz = atoi(arg); @@ -46,12 +48,12 @@ static void parse_dates(const char **argv, struct timeval *now) struct strbuf result = STRBUF_INIT; for (; *argv; argv++) { - unsigned long t; + timestamp_t t; int tz; strbuf_reset(&result); parse_date(*argv, &result); - if (sscanf(result.buf, "%lu %d", &t, &tz) == 2) + if (sscanf(result.buf, "%"PRItime" %d", &t, &tz) == 2) printf("%s -> %s\n", *argv, show_date(t, tz, DATE_MODE(ISO8601))); else @@ -63,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now) static void parse_approxidate(const char **argv, struct timeval *now) { for (; *argv; argv++) { - time_t t; + timestamp_t t; t = approxidate_relative(*argv, now); printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601))); } @@ -93,6 +95,10 @@ int cmd_main(int argc, const char **argv) parse_dates(argv+1, &now); else if (!strcmp(*argv, "approxidate")) parse_approxidate(argv+1, &now); + else if (!strcmp(*argv, "is64bit")) + return sizeof(timestamp_t) == 8 ? 0 : 1; + else if (!strcmp(*argv, "time_t-is64bit")) + return sizeof(time_t) == 8 ? 0 : 1; else usage(usage_msg); return 0; diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c index 7af116d49e..ebf3aab22d 100644 --- a/t/helper/test-dump-cache-tree.c +++ b/t/helper/test-dump-cache-tree.c @@ -10,7 +10,7 @@ static void dump_one(struct cache_tree *it, const char *pfx, const char *x) "invalid", x, pfx, it->subtree_nr); else printf("%s %s%s (%d entries, %d subtrees)\n", - sha1_to_hex(it->sha1), x, pfx, + oid_to_hex(&it->oid), x, pfx, it->entry_count, it->subtree_nr); } @@ -32,7 +32,7 @@ static int dump_cache_tree(struct cache_tree *it, } else { dump_one(it, pfx, ""); - if (hashcmp(it->sha1, ref->sha1) || + if (oidcmp(&it->oid, &ref->oid) || ref->entry_count != it->entry_count || ref->subtree_nr != it->subtree_nr) { /* claims to be valid but is lying */ diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c index e939502863..356d8edef1 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -12,10 +12,10 @@ int cmd_main(int ac, const char **av) die("cannot parse %s as an object name", av[1]); if (get_oid(av[2], &hash2)) die("cannot parse %s as an object name", av[2]); - one = parse_tree_indirect(hash1.hash); + one = parse_tree_indirect(&hash1); if (!one) die("not a tree-ish %s", av[1]); - two = parse_tree_indirect(hash2.hash); + two = parse_tree_indirect(&hash2); if (!two) die("not a tree-ish %s", av[2]); diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index a01430c24b..75fe883aac 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -5,7 +5,7 @@ static int boolean = 0; static int integer = 0; static unsigned long magnitude = 0; -static unsigned long timestamp; +static timestamp_t timestamp; static int abbrev = 7; static int verbose = -1; /* unspecified */ static int dry_run = 0, quiet = 0; @@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv) show(&expect, &ret, "boolean: %d", boolean); show(&expect, &ret, "integer: %d", integer); show(&expect, &ret, "magnitude: %lu", magnitude); - show(&expect, &ret, "timestamp: %lu", timestamp); + show(&expect, &ret, "timestamp: %"PRItime, timestamp); show(&expect, &ret, "string: %s", string ? string : "(not set)"); show(&expect, &ret, "abbrev: %d", abbrev); show(&expect, &ret, "verbose: %d", verbose); diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 2d84c45ffe..fba85e7da5 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,5 +1,6 @@ #include "cache.h" #include "refs.h" +#include "worktree.h" static const char *notnull(const char *arg, const char *name) { @@ -32,6 +33,23 @@ static const char **get_store(const char **argv, struct ref_store **refs) strbuf_release(&sb); *refs = get_submodule_ref_store(gitdir); + } else if (skip_prefix(argv[0], "worktree:", &gitdir)) { + struct worktree **p, **worktrees = get_worktrees(0); + + for (p = worktrees; *p; p++) { + struct worktree *wt = *p; + + if (!wt->id) { + /* special case for main worktree */ + if (!strcmp(gitdir, "main")) + break; + } else if (!strcmp(gitdir, wt->id)) + break; + } + if (!*p) + die("no such worktree: %s", gitdir); + + *refs = get_worktree_ref_store(*p); } else die("unknown backend %s", argv[0]); @@ -138,10 +156,10 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv) } static int each_reflog(struct object_id *old_oid, struct object_id *new_oid, - const char *committer, unsigned long timestamp, + const char *committer, timestamp_t timestamp, int tz, const char *msg, void *cb_data) { - printf("%s %s %s %lu %d %s\n", + printf("%s %s %s %"PRItime" %d %s\n", oid_to_hex(old_oid), oid_to_hex(new_oid), committer, timestamp, tz, msg); return 0; diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index fb4f7b014e..58bd4aeb2c 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -73,6 +73,7 @@ create_lib_submodule_repo () { git checkout -b "add_sub1" && git submodule add ../submodule_update_sub1 sub1 && + git submodule add ../submodule_update_sub1 uninitialized_sub && git config -f .gitmodules submodule.sub1.ignore all && git config submodule.sub1.ignore all && git add .gitmodules && @@ -787,11 +788,6 @@ test_submodule_switch_recursing () { then RESULTDS=failure fi - RESULTR=success - if test "$KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED" = 1 - then - RESULTR=failure - fi RESULTOI=success if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1 then @@ -1003,7 +999,7 @@ test_submodule_switch_recursing () { ' # recursing deeper than one level doesn't work yet. - test_expect_$RESULTR "$command: modified submodule updates submodule recursively" ' + test_expect_success "$command: modified submodule updates submodule recursively" ' prolog && reset_work_tree_to_interested add_nested_sub && ( @@ -1212,14 +1208,31 @@ test_submodule_forced_switch_recursing () { ) ' # Updating a submodule from an invalid sha1 updates - test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" ' + test_expect_success "$command: modified submodule does update submodule work tree from invalid commit" ' prolog && reset_work_tree_to_interested invalid_sub1 && ( cd submodule_update && git branch -t valid_sub1 origin/valid_sub1 && - test_must_fail $command valid_sub1 && - test_superproject_content origin/invalid_sub1 + $command valid_sub1 && + test_superproject_content origin/valid_sub1 && + test_submodule_content sub1 origin/valid_sub1 + ) + ' + + # Old versions of Git were buggy writing the .git link file + # (e.g. before f8eaa0ba98b and then moving the superproject repo + # whose submodules contained absolute paths) + test_expect_success "$command: updating submodules fixes .git links" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t modify_sub1 origin/modify_sub1 && + echo "gitdir: bogus/path" >sub1/.git && + $command modify_sub1 && + test_superproject_content origin/modify_sub1 && + test_submodule_content sub1 origin/modify_sub1 ) ' } diff --git a/t/perf/p3400-rebase.sh b/t/perf/p3400-rebase.sh index b3e7d525d2..ce271ca4c1 100755 --- a/t/perf/p3400-rebase.sh +++ b/t/perf/p3400-rebase.sh @@ -5,7 +5,7 @@ test_description='Tests rebase performance' test_perf_default_repo -test_expect_success 'setup' ' +test_expect_success 'setup rebasing on top of a lot of changes' ' git checkout -f -b base && git checkout -b to-rebase && git checkout -b upstream && @@ -33,4 +33,24 @@ test_perf 'rebase on top of a lot of unrelated changes' ' git rebase --onto base HEAD^ ' +test_expect_success 'setup rebasing many changes without split-index' ' + git config core.splitIndex false && + git checkout -b upstream2 to-rebase && + git checkout -b to-rebase2 upstream +' + +test_perf 'rebase a lot of unrelated changes without split-index' ' + git rebase --onto upstream2 base && + git rebase --onto base upstream2 +' + +test_expect_success 'setup rebasing many changes with split-index' ' + git config core.splitIndex true +' + +test_perf 'rebase a lot of unrelated changes with split-index' ' + git rebase --onto upstream2 base && + git rebase --onto base upstream2 +' + test_done diff --git a/t/t0006-date.sh b/t/t0006-date.sh index c0c910867d..42d4ea61ef 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -53,8 +53,8 @@ check_show unix-local "$TIME" '1466000000' # arbitrary time absurdly far in the future FUTURE="5758122296 -0400" -check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" LONG_IS_64BIT -check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" LONG_IS_64BIT +check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" TIME_IS_64BIT,TIME_T_IS_64BIT +check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" TIME_IS_64BIT,TIME_T_IS_64BIT check_parse() { echo "$1 -> $2" >expect diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh deleted file mode 100755 index 89826c568b..0000000000 --- a/t/t0025-crlf-auto.sh +++ /dev/null @@ -1,181 +0,0 @@ -#!/bin/sh - -test_description='CRLF conversion' - -. ./test-lib.sh - -has_cr() { - tr '\015' Q <"$1" | grep Q >/dev/null -} - -test_expect_success setup ' - - git config core.autocrlf false && - - for w in Hello world how are you; do echo $w; done >LFonly && - for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >CRLFonly && - for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >LFwithNUL && - git add . && - - git commit -m initial && - - LFonly=$(git rev-parse HEAD:LFonly) && - CRLFonly=$(git rev-parse HEAD:CRLFonly) && - LFwithNUL=$(git rev-parse HEAD:LFwithNUL) && - - echo happy. -' - -test_expect_success 'default settings cause no changes' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git read-tree --reset -u HEAD && - - ! has_cr LFonly && - has_cr CRLFonly && - LFonlydiff=$(git diff LFonly) && - CRLFonlydiff=$(git diff CRLFonly) && - LFwithNULdiff=$(git diff LFwithNUL) && - test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" -' - -test_expect_success 'crlf=true causes a CRLF file to be normalized' ' - - # Backwards compatibility check - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - echo "CRLFonly crlf" > .gitattributes && - git read-tree --reset -u HEAD && - - # Note, "normalized" means that git will normalize it if added - has_cr CRLFonly && - CRLFonlydiff=$(git diff CRLFonly) && - test -n "$CRLFonlydiff" -' - -test_expect_success 'text=true causes a CRLF file to be normalized' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - echo "CRLFonly text" > .gitattributes && - git read-tree --reset -u HEAD && - - # Note, "normalized" means that git will normalize it if added - has_cr CRLFonly && - CRLFonlydiff=$(git diff CRLFonly) && - test -n "$CRLFonlydiff" -' - -test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git config core.autocrlf false && - echo "LFonly eol=crlf" > .gitattributes && - git read-tree --reset -u HEAD && - - has_cr LFonly && - LFonlydiff=$(git diff LFonly) && - test -z "$LFonlydiff" -' - -test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=input' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git config core.autocrlf input && - echo "LFonly eol=crlf" > .gitattributes && - git read-tree --reset -u HEAD && - - has_cr LFonly && - LFonlydiff=$(git diff LFonly) && - test -z "$LFonlydiff" -' - -test_expect_success 'eol=lf gives a normalized file LFs with autocrlf=true' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git config core.autocrlf true && - echo "LFonly eol=lf" > .gitattributes && - git read-tree --reset -u HEAD && - - ! has_cr LFonly && - LFonlydiff=$(git diff LFonly) && - test -z "$LFonlydiff" -' - -test_expect_success 'autocrlf=true does not normalize CRLF files' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git config core.autocrlf true && - git read-tree --reset -u HEAD && - - has_cr LFonly && - has_cr CRLFonly && - LFonlydiff=$(git diff LFonly) && - CRLFonlydiff=$(git diff CRLFonly) && - LFwithNULdiff=$(git diff LFwithNUL) && - test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" -' - -test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git config core.autocrlf true && - echo "* text=auto" > .gitattributes && - git read-tree --reset -u HEAD && - - has_cr LFonly && - has_cr CRLFonly && - LFonlydiff=$(git diff LFonly) && - CRLFonlydiff=$(git diff CRLFonly) && - LFwithNULdiff=$(git diff LFwithNUL) && - test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" -' - -test_expect_success 'text=auto, autocrlf=true does not normalize binary files' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - git config core.autocrlf true && - echo "* text=auto" > .gitattributes && - git read-tree --reset -u HEAD && - - ! has_cr LFwithNUL && - LFwithNULdiff=$(git diff LFwithNUL) && - test -z "$LFwithNULdiff" -' - -test_expect_success 'eol=crlf _does_ normalize binary files' ' - - rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && - echo "LFwithNUL eol=crlf" > .gitattributes && - git read-tree --reset -u HEAD && - - has_cr LFwithNUL && - LFwithNULdiff=$(git diff LFwithNUL) && - test -z "$LFwithNULdiff" -' - -test_expect_success 'prepare unnormalized' ' - > .gitattributes && - git config core.autocrlf false && - printf "LINEONE\nLINETWO\r\n" >mixed && - git add mixed .gitattributes && - git commit -m "Add mixed" && - git ls-files --eol | egrep "i/crlf" && - git ls-files --eol | egrep "i/mixed" -' - -test_expect_success 'normalize unnormalized' ' - echo "* text=auto" >.gitattributes && - rm .git/index && - git add . && - git commit -m "Introduce end-of-line normalization" && - git ls-files --eol | tr "\\t" " " | sort >act && -cat >exp <"$1".expect && tr '\015\000' QN <"$2" | tr -d 'Z' >"$2".actual && @@ -75,7 +69,7 @@ check_warning () { *) echo >&2 "Illegal 1": "$1" ; return false ;; esac grep "will be replaced by" "$2" | sed -e "s/\(.*\) in [^ ]*$/\1/" | uniq >"$2".actual - test_cmp "$2".expect "$2".actual + test_i18ncmp "$2".expect "$2".actual } commit_check_warn () { diff --git a/t/t0203-gettext-setlocale-sanity.sh b/t/t0203-gettext-setlocale-sanity.sh index a212460081..71b0d74b4d 100755 --- a/t/t0203-gettext-setlocale-sanity.sh +++ b/t/t0203-gettext-setlocale-sanity.sh @@ -8,7 +8,7 @@ test_description="The Git C functions aren't broken by setlocale(3)" . ./lib-gettext.sh test_expect_success 'git show a ISO-8859-1 commit under C locale' ' - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && test_commit "iso-c-commit" iso-under-c && git show >out 2>err && ! test -s err && @@ -16,7 +16,7 @@ test_expect_success 'git show a ISO-8859-1 commit under C locale' ' ' test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 locale' ' - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && test_commit "iso-utf8-commit" iso-under-utf8 && LANGUAGE=is LC_ALL="$is_IS_locale" git show >out 2>err && ! test -s err && diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh index de1ba02dc5..7019d0a04f 100755 --- a/t/t1013-read-tree-submodule.sh +++ b/t/t1013-read-tree-submodule.sh @@ -5,7 +5,6 @@ test_description='read-tree can handle submodules' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh -KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1 KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1 diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index afcca0d52c..13b7851f7c 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -1539,4 +1539,10 @@ test_expect_success !MINGW '--show-origin blob ref' ' test_cmp expect output ' +test_expect_success '--local requires a repo' ' + # we expect 128 to ensure that we do not simply + # fail to find anything and return code "1" + test_expect_code 128 nongit git config --local foo.bar +' + test_done diff --git a/t/t1309-early-config.sh b/t/t1309-early-config.sh index 1af8c454cf..3dda215e8e 100755 --- a/t/t1309-early-config.sh +++ b/t/t1309-early-config.sh @@ -77,7 +77,7 @@ test_with_config () { test_expect_success 'ignore .git/ with incompatible repository version' ' test_with_config "[core]repositoryformatversion = 999999" 2>err && - grep "warning:.* Expected git repo version <= [1-9]" err + test_i18ngrep "warning:.* Expected git repo version <= [1-9]" err ' test_expect_failure 'ignore .git/ with invalid repository version' ' diff --git a/t/t1407-worktree-ref-store.sh b/t/t1407-worktree-ref-store.sh new file mode 100755 index 0000000000..5df06f3556 --- /dev/null +++ b/t/t1407-worktree-ref-store.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='test worktree ref store api' + +. ./test-lib.sh + +RWT="test-ref-store worktree:wt" +RMAIN="test-ref-store worktree:main" + +test_expect_success 'setup' ' + test_commit first && + git worktree add -b wt-master wt && + ( + cd wt && + test_commit second + ) +' + +test_expect_success 'resolve_ref()' ' + SHA1=`git rev-parse master` && + echo "$SHA1 refs/heads/master 0x0" >expected && + $RWT resolve-ref refs/heads/master 0 >actual && + test_cmp expected actual && + $RMAIN resolve-ref refs/heads/master 0 >actual && + test_cmp expected actual +' + +test_expect_success 'resolve_ref()' ' + SHA1=`git -C wt rev-parse HEAD` && + echo "$SHA1 refs/heads/wt-master 0x1" >expected && + $RWT resolve-ref HEAD 0 >actual && + test_cmp expected actual && + + SHA1=`git rev-parse HEAD` && + echo "$SHA1 refs/heads/master 0x1" >expected && + $RMAIN resolve-ref HEAD 0 >actual && + test_cmp expected actual +' + +test_expect_success 'create_symref(FOO, refs/heads/master)' ' + $RWT create-symref FOO refs/heads/master nothing && + echo refs/heads/master >expected && + git -C wt symbolic-ref FOO >actual && + test_cmp expected actual && + + $RMAIN create-symref FOO refs/heads/wt-master nothing && + echo refs/heads/wt-master >expected && + git symbolic-ref FOO >actual && + test_cmp expected actual +' + +test_done diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh index 8937e25e49..e88349c8a0 100755 --- a/t/t1430-bad-ref-name.sh +++ b/t/t1430-bad-ref-name.sh @@ -122,7 +122,7 @@ test_expect_success 'push cannot create a badly named ref' ' ! grep -e "broken\.\.\.ref" output ' -test_expect_failure 'push --mirror can delete badly named ref' ' +test_expect_failure C_LOCALE_OUTPUT 'push --mirror can delete badly named ref' ' top=$(pwd) && git init src && git init dest && diff --git a/t/t1601-index-bogus.sh b/t/t1601-index-bogus.sh new file mode 100755 index 0000000000..73cc9323cd --- /dev/null +++ b/t/t1601-index-bogus.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +test_description='test handling of bogus index entries' +. ./test-lib.sh + +test_expect_success 'create tree with null sha1' ' + tree=$(printf "160000 commit $_z40\\tbroken\\n" | git mktree) +' + +test_expect_success 'read-tree refuses to read null sha1' ' + test_must_fail git read-tree $tree +' + +test_expect_success 'GIT_ALLOW_NULL_SHA1 overrides refusal' ' + GIT_ALLOW_NULL_SHA1=1 git read-tree $tree +' + +test_expect_success 'git write-tree refuses to write null sha1' ' + test_must_fail git write-tree +' + +test_done diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh index e8f70b806f..aa35223369 100755 --- a/t/t2013-checkout-submodule.sh +++ b/t/t2013-checkout-submodule.sh @@ -64,7 +64,6 @@ test_expect_success '"checkout " honors submodule.*.ignore from .git/ ' KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 -KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1 test_submodule_switch_recursing "git checkout --recurse-submodules" test_submodule_forced_switch_recursing "git checkout -f --recurse-submodules" diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 5778c0afe1..a428ae6703 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -236,7 +236,7 @@ test_expect_success 'git branch --format option' ' Refname is refs/heads/ref-to-remote EOF git branch --format="Refname is %(refname)" >actual && - test_cmp expect actual + test_i18ncmp expect actual ' test_done diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 33d392ba11..5bd0275930 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -366,7 +366,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' ' grep "^ file1 | 2 +-$" output ' -test_expect_success 'multi-squash only fires up editor once' ' +test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' ' base=$(git rev-parse HEAD~4) && set_fake_editor && FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \ @@ -376,7 +376,7 @@ test_expect_success 'multi-squash only fires up editor once' ' test 1 = $(git show | grep ONCE | wc -l) ' -test_expect_success 'multi-fixup does not fire up editor' ' +test_expect_success C_LOCALE_OUTPUT 'multi-fixup does not fire up editor' ' git checkout -b multi-fixup E && base=$(git rev-parse HEAD~4) && set_fake_editor && @@ -426,7 +426,7 @@ D ONCE EOF -test_expect_success 'squash and fixup generate correct log messages' ' +test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' ' git checkout -b squash-fixup E && base=$(git rev-parse HEAD~4) && set_fake_editor && @@ -439,7 +439,7 @@ test_expect_success 'squash and fixup generate correct log messages' ' git branch -D squash-fixup ' -test_expect_success 'squash ignores comments' ' +test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' ' git checkout -b skip-comments E && base=$(git rev-parse HEAD~4) && set_fake_editor && @@ -452,7 +452,7 @@ test_expect_success 'squash ignores comments' ' git branch -D skip-comments ' -test_expect_success 'squash ignores blank lines' ' +test_expect_success C_LOCALE_OUTPUT 'squash ignores blank lines' ' git checkout -b skip-blank-lines E && base=$(git rev-parse HEAD~4) && set_fake_editor && @@ -860,7 +860,7 @@ test_expect_success 'rebase -ix with several instances of --exec' ' test_cmp expected actual ' -test_expect_success 'rebase -ix with --autosquash' ' +test_expect_success C_LOCALE_OUTPUT 'rebase -ix with --autosquash' ' git reset --hard execute && git checkout -b autosquash && echo second >second.txt && @@ -943,7 +943,7 @@ test_expect_success 'rebase -i --root fixup root commit' ' test 0 = $(git cat-file commit HEAD | grep -c ^parent\ ) ' -test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' ' +test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' ' git reset --hard && git checkout conflict-branch && set_fake_editor && diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index 48346f1cc0..5848949ec3 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -234,23 +234,23 @@ test_auto_fixup_fixup () { fi } -test_expect_success 'fixup! fixup!' ' +test_expect_success C_LOCALE_OUTPUT 'fixup! fixup!' ' test_auto_fixup_fixup fixup fixup ' -test_expect_success 'fixup! squash!' ' +test_expect_success C_LOCALE_OUTPUT 'fixup! squash!' ' test_auto_fixup_fixup fixup squash ' -test_expect_success 'squash! squash!' ' +test_expect_success C_LOCALE_OUTPUT 'squash! squash!' ' test_auto_fixup_fixup squash squash ' -test_expect_success 'squash! fixup!' ' +test_expect_success C_LOCALE_OUTPUT 'squash! fixup!' ' test_auto_fixup_fixup squash fixup ' -test_expect_success 'autosquash with custom inst format' ' +test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' ' git reset --hard base && git config --add rebase.instructionFormat "[%an @ %ar] %s" && echo 2 >file1 && diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh index bf0a5c9887..9888bf34b9 100755 --- a/t/t3511-cherry-pick-x.sh +++ b/t/t3511-cherry-pick-x.sh @@ -208,6 +208,50 @@ test_expect_success 'cherry-pick -x -s adds sob even when trailing sob exists fo test_cmp expect actual ' +test_expect_success 'cherry-pick -x handles commits with no NL at end of message' ' + pristine_detach initial && + printf "title\n\nSigned-off-by: A " >msg && + sha1=$(git commit-tree -p initial mesg-with-footer^{tree} actual && + + printf "\n(cherry picked from commit %s)\n" $sha1 >>msg && + test_cmp msg actual +' + +test_expect_success 'cherry-pick -x handles commits with no footer and no NL at end of message' ' + pristine_detach initial && + printf "title\n\nnot a footer" >msg && + sha1=$(git commit-tree -p initial mesg-with-footer^{tree} actual && + + printf "\n\n(cherry picked from commit %s)\n" $sha1 >>msg && + test_cmp msg actual +' + +test_expect_success 'cherry-pick -s handles commits with no NL at end of message' ' + pristine_detach initial && + printf "title\n\nSigned-off-by: A " >msg && + sha1=$(git commit-tree -p initial mesg-with-footer^{tree} actual && + + printf "\nSigned-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n" >>msg && + test_cmp msg actual +' + +test_expect_success 'cherry-pick -s handles commits with no footer and no NL at end of message' ' + pristine_detach initial && + printf "title\n\nnot a footer" >msg && + sha1=$(git commit-tree -p initial mesg-with-footer^{tree} actual && + + printf "\n\nSigned-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n" >>msg && + test_cmp msg actual +' + test_expect_success 'cherry-pick -x treats "(cherry picked from..." line as part of footer' ' pristine_detach initial && sha1=$(git rev-parse mesg-with-cherry-footer^0) && diff --git a/t/t3901-8859-1.txt b/t/t3901-8859-1.txt deleted file mode 100755 index 38c21a6a7f..0000000000 --- a/t/t3901-8859-1.txt +++ /dev/null @@ -1,4 +0,0 @@ -: to be sourced in t3901 -- this is latin-1 -GIT_AUTHOR_NAME="Áéí óú" && -GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME && -export GIT_AUTHOR_NAME GIT_COMMITTER_NAME diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index f663d567c8..923eb01f0e 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -31,7 +31,7 @@ test_expect_success setup ' # use UTF-8 in author and committer name to match the # i18n.commitencoding settings - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && test_tick && echo "$GIT_AUTHOR_NAME" >mine && @@ -55,7 +55,7 @@ test_expect_success setup ' # the second one on the side branch is ISO-8859-1 git config i18n.commitencoding ISO8859-1 && # use author and committer name in ISO-8859-1 to match it. - . "$TEST_DIRECTORY"/t3901-8859-1.txt + . "$TEST_DIRECTORY"/t3901/8859-1.txt fi && test_tick && echo Yet another >theirs && @@ -100,7 +100,7 @@ test_expect_success 'rebase (U/U)' ' # The result will be committed by GIT_COMMITTER_NAME -- # we want UTF-8 encoded name. - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git checkout -b test && git rebase master && @@ -110,7 +110,7 @@ test_expect_success 'rebase (U/U)' ' test_expect_success 'rebase (U/L)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard side && git rebase master && @@ -122,7 +122,7 @@ test_expect_success !MINGW 'rebase (L/L)' ' # In this test we want ISO-8859-1 encoded commits as the result git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard side && git rebase master && @@ -135,7 +135,7 @@ test_expect_success !MINGW 'rebase (L/U)' ' # to get ISO-8859-1 results. git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard side && git rebase master && @@ -148,7 +148,7 @@ test_expect_success 'cherry-pick(U/U)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard master && git cherry-pick side^ && @@ -163,7 +163,7 @@ test_expect_success !MINGW 'cherry-pick(L/L)' ' git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard master && git cherry-pick side^ && @@ -178,7 +178,7 @@ test_expect_success 'cherry-pick(U/L)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard master && git cherry-pick side^ && @@ -194,7 +194,7 @@ test_expect_success !MINGW 'cherry-pick(L/U)' ' git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard master && git cherry-pick side^ && @@ -207,7 +207,7 @@ test_expect_success !MINGW 'cherry-pick(L/U)' ' test_expect_success 'rebase --merge (U/U)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard side && git rebase --merge master && @@ -218,7 +218,7 @@ test_expect_success 'rebase --merge (U/U)' ' test_expect_success 'rebase --merge (U/L)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard side && git rebase --merge master && @@ -230,7 +230,7 @@ test_expect_success 'rebase --merge (L/L)' ' # In this test we want ISO-8859-1 encoded commits as the result git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard side && git rebase --merge master && @@ -243,7 +243,7 @@ test_expect_success 'rebase --merge (L/U)' ' # to get ISO-8859-1 results. git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard side && git rebase --merge master && @@ -254,7 +254,7 @@ test_expect_success 'rebase --merge (L/U)' ' test_expect_success 'am (U/U)' ' # Apply UTF-8 patches with UTF-8 commitencoding git config i18n.commitencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard master && git am out-u1 out-u2 && @@ -265,7 +265,7 @@ test_expect_success 'am (U/U)' ' test_expect_success !MINGW 'am (L/L)' ' # Apply ISO-8859-1 patches with ISO-8859-1 commitencoding git config i18n.commitencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard master && git am out-l1 out-l2 && @@ -276,7 +276,7 @@ test_expect_success !MINGW 'am (L/L)' ' test_expect_success 'am (U/L)' ' # Apply ISO-8859-1 patches with UTF-8 commitencoding git config i18n.commitencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard master && # am specifies --utf8 by default. @@ -288,7 +288,7 @@ test_expect_success 'am (U/L)' ' test_expect_success 'am --no-utf8 (U/L)' ' # Apply ISO-8859-1 patches with UTF-8 commitencoding git config i18n.commitencoding UTF-8 && - . "$TEST_DIRECTORY"/t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901/utf8.txt && git reset --hard master && git am --no-utf8 out-l1 out-l2 2>err && @@ -303,7 +303,7 @@ test_expect_success 'am --no-utf8 (U/L)' ' test_expect_success !MINGW 'am (L/U)' ' # Apply UTF-8 patches with ISO-8859-1 commitencoding git config i18n.commitencoding ISO8859-1 && - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && git reset --hard master && # mailinfo will re-code the commit message to the charset specified by diff --git a/t/t3901-utf8.txt b/t/t3901-utf8.txt deleted file mode 100755 index 5f5205cd02..0000000000 --- a/t/t3901-utf8.txt +++ /dev/null @@ -1,4 +0,0 @@ -: to be sourced in t3901 -- this is utf8 -GIT_AUTHOR_NAME="Áéí óú" && -GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME && -export GIT_AUTHOR_NAME GIT_COMMITTER_NAME diff --git a/t/t3901/8859-1.txt b/t/t3901/8859-1.txt new file mode 100755 index 0000000000..38c21a6a7f --- /dev/null +++ b/t/t3901/8859-1.txt @@ -0,0 +1,4 @@ +: to be sourced in t3901 -- this is latin-1 +GIT_AUTHOR_NAME="Áéí óú" && +GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME && +export GIT_AUTHOR_NAME GIT_COMMITTER_NAME diff --git a/t/t3901/utf8.txt b/t/t3901/utf8.txt new file mode 100755 index 0000000000..5f5205cd02 --- /dev/null +++ b/t/t3901/utf8.txt @@ -0,0 +1,4 @@ +: to be sourced in t3901 -- this is utf8 +GIT_AUTHOR_NAME="Áéí óú" && +GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME && +export GIT_AUTHOR_NAME GIT_COMMITTER_NAME diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index b71d1e659e..3b4bed5c9a 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -865,7 +865,7 @@ test_expect_success 'stash push -p with pathspec shows no changes only once' ' git stash push -p foo >actual && echo "No local changes to save" >expect && git reset --hard HEAD~ && - test_cmp expect actual + test_i18ncmp expect actual ' test_expect_success 'stash push with pathspec shows no changes when there are none' ' @@ -875,7 +875,7 @@ test_expect_success 'stash push with pathspec shows no changes when there are no git stash push foo >actual && echo "No local changes to save" >expect && git reset --hard HEAD~ && - test_cmp expect actual + test_i18ncmp expect actual ' test_expect_success 'stash push with pathspec not in the repository errors out' ' diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh index 0b4f7dfdc6..e2824d3437 100755 --- a/t/t4038-diff-combined.sh +++ b/t/t4038-diff-combined.sh @@ -354,7 +354,7 @@ test_expect_failure 'combine diff coalesce three parents' ' ' # Test for a bug reported at -# http://thread.gmane.org/gmane.comp.version-control.git/224410 +# https://public-inbox.org/git/20130515143508.GO25742@login.drsnuggles.stderr.nl/ # where a delete lines were missing from combined diff output when they # occurred exactly before the context lines of a later change. test_expect_success 'combine diff missing delete bug' ' diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh index d4a3ffa69c..33ec26d755 100755 --- a/t/t4060-diff-submodule-option-diff-format.sh +++ b/t/t4060-diff-submodule-option-diff-format.sh @@ -775,4 +775,45 @@ test_expect_success 'diff --submodule=diff with moved nested submodule HEAD' ' test_cmp expected actual ' +test_expect_success 'diff --submodule=diff recurses into nested submodules' ' + cat >expected <<-EOF && + Submodule sm2 contains modified content + Submodule sm2 a5a65c9..280969a: + diff --git a/sm2/.gitmodules b/sm2/.gitmodules + new file mode 100644 + index 0000000..3a816b8 + --- /dev/null + +++ b/sm2/.gitmodules + @@ -0,0 +1,3 @@ + +[submodule "nested"] + + path = nested + + url = ../sm2 + Submodule nested 0000000...b55928c (new submodule) + diff --git a/sm2/nested/file b/sm2/nested/file + new file mode 100644 + index 0000000..ca281f5 + --- /dev/null + +++ b/sm2/nested/file + @@ -0,0 +1 @@ + +nested content + diff --git a/sm2/nested/foo8 b/sm2/nested/foo8 + new file mode 100644 + index 0000000..db9916b + --- /dev/null + +++ b/sm2/nested/foo8 + @@ -0,0 +1 @@ + +foo8 + diff --git a/sm2/nested/foo9 b/sm2/nested/foo9 + new file mode 100644 + index 0000000..9c3b4f6 + --- /dev/null + +++ b/sm2/nested/foo9 + @@ -0,0 +1 @@ + +foo9 + EOF + git diff --submodule=diff >actual 2>err && + test_must_be_empty err && + test_cmp expected actual +' + test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index f577990716..6499cdf6ff 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -399,7 +399,7 @@ cat > expect <<\EOF | | | | Merge branch 'side' | | -| * commit side +| * commit tags/side-2 | | Author: A U Thor | | | | side-2 @@ -577,6 +577,18 @@ test_expect_success 'log.decorate configuration' ' ' +test_expect_success 'log.decorate config parsing' ' + git log --oneline --decorate=full >expect.full && + git log --oneline --decorate=short >expect.short && + + test_config log.decorate full && + test_config log.mailmap true && + git log --oneline >actual && + test_cmp expect.full actual && + git log --oneline --decorate=short >actual && + test_cmp expect.short actual +' + test_expect_success TTY 'log output on a TTY' ' git log --oneline --decorate >expect.short && diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 21eb8c8587..18aa1b5889 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -126,12 +126,12 @@ test_expect_success 'NUL separation with --stat' ' test_i18ncmp expected actual ' -test_expect_failure 'NUL termination with --stat' ' +test_expect_failure C_LOCALE_OUTPUT 'NUL termination with --stat' ' stat0_part=$(git diff --stat HEAD^ HEAD) && stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) && printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n0" >expected && git log -z --stat --pretty="tformat:%s" >actual && - test_i18ncmp expected actual + test_cmp expected actual ' test_expect_success 'setup more commits' ' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 886b6953e4..fe2d4f15a7 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' ' test_cmp expect actual ' -test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' ' +test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' ' rm -f .git/index && echo content >file && git add file && @@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' ' git commit -m "tempori parendum" ' -test_expect_success LONG_IS_64BIT 'generate tar with future mtime' ' +test_expect_success TIME_IS_64BIT 'generate tar with future mtime' ' git archive HEAD >future.tar ' -test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' ' +test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' ' echo 4147 >expect && tar_info future.tar | cut -d" " -f2 >actual && test_cmp expect actual diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index cca23383c5..f6207f42b5 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -27,6 +27,9 @@ check_dir() { test_cmp expect actual } +test_lazy_prereq UNZIP_ZIP64_SUPPORT ' + "$GIT_UNZIP" -v | grep ZIP64_SUPPORT +' # bsdtar/libarchive versions before 3.1.3 consider a tar file with a # global pax header that is not followed by a file record as corrupt. @@ -155,4 +158,51 @@ test_expect_success ZIPINFO 'zip archive with many entries' ' test_cmp expect actual ' +test_expect_success EXPENSIVE,UNZIP,UNZIP_ZIP64_SUPPORT \ + 'zip archive bigger than 4GB' ' + # build string containing 65536 characters + s=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef && + s=$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s && + s=$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s$s && + + # create blob with a length of 65536 + 1 bytes + blob=$(echo $s | git hash-object -w --stdin) && + + # create tree containing 65500 entries of that blob + for i in $(test_seq 1 65500) + do + echo "100644 blob $blob $i" + done >tree && + tree=$(git mktree big.lst && + grep $size big.lst +' + test_done diff --git a/t/t5004/big-pack.zip b/t/t5004/big-pack.zip new file mode 100644 index 0000000000..caaf614eee Binary files /dev/null and b/t/t5004/big-pack.zip differ diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index 424bec7d77..20e2473a03 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -20,11 +20,13 @@ has_any () { } test_expect_success 'setup repo with moderate-sized history' ' - for i in $(test_seq 1 10); do + for i in $(test_seq 1 10) + do test_commit $i done && git checkout -b other HEAD~5 && - for i in $(test_seq 1 10); do + for i in $(test_seq 1 10) + do test_commit side-$i done && git checkout master && @@ -104,7 +106,8 @@ test_expect_success 'clone from bitmapped repository' ' ' test_expect_success 'setup further non-bitmapped commits' ' - for i in $(test_seq 1 10); do + for i in $(test_seq 1 10) + do test_commit further-$i done ' @@ -289,4 +292,43 @@ test_expect_success 'splitting packs does not generate bogus bitmaps' ' git -C no-bitmaps.git fetch .. HEAD ' +test_expect_success 'set up reusable pack' ' + rm -f .git/objects/pack/*.keep && + git repack -adb && + reusable_pack () { + git for-each-ref --format="%(objectname)" | + git pack-objects --delta-base-offset --revs --stdout "$@" + } +' + +test_expect_success 'pack reuse respects --honor-pack-keep' ' + test_when_finished "rm -f .git/objects/pack/*.keep" && + for i in .git/objects/pack/*.pack + do + >${i%.pack}.keep + done && + reusable_pack --honor-pack-keep >empty.pack && + git index-pack empty.pack && + >expect && + git show-index actual && + test_cmp expect actual +' + +test_expect_success 'pack reuse respects --local' ' + mv .git/objects/pack/* alt.git/objects/pack/ && + test_when_finished "mv alt.git/objects/pack/* .git/objects/pack/" && + reusable_pack --local >empty.pack && + git index-pack empty.pack && + >expect && + git show-index actual && + test_cmp expect actual +' + +test_expect_success 'pack reuse respects --incremental' ' + reusable_pack --incremental >empty.pack && + git index-pack empty.pack && + >expect && + git show-index actual && + test_cmp expect actual +' test_done diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh index 37143ea0ac..2ed479b712 100755 --- a/t/t5316-pack-delta-depth.sh +++ b/t/t5316-pack-delta-depth.sh @@ -82,12 +82,16 @@ test_expect_success 'packing produces a long delta' ' # Use --window=0 to make sure we are seeing reused deltas, # not computing a new long chain. pack=$(git pack-objects --all --window=0 expect && + max_chain pack-$pack.pack >actual && + test_i18ncmp expect actual ' test_expect_success '--depth limits depth' ' pack=$(git pack-objects --all --depth=5 expect && + max_chain pack-$pack.pack >actual && + test_i18ncmp expect actual ' test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 3331e0f534..d375d7110d 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -288,7 +288,10 @@ test_expect_success 'receive-pack de-dupes .have lines' ' $shared .have EOF - GIT_TRACE_PACKET=$(pwd)/trace git push fork HEAD:foo && + GIT_TRACE_PACKET=$(pwd)/trace \ + git push \ + --receive-pack="unset GIT_TRACE_PACKET; git-receive-pack" \ + fork HEAD:foo && extract_ref_advertisement refs && test_cmp expect refs ' diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh index ecb8d446a5..5bcb288f5c 100755 --- a/t/t5534-push-signed.sh +++ b/t/t5534-push-signed.sh @@ -124,6 +124,43 @@ test_expect_success GPG 'signed push sends push certificate' ' test_cmp expect dst/push-cert-status ' +test_expect_success GPG 'inconsistent push options in signed push not allowed' ' + # First, invoke receive-pack with dummy input to obtain its preamble. + prepare_dst && + git -C dst config receive.certnonceseed sekrit && + git -C dst config receive.advertisepushoptions 1 && + printf xxxx | test_might_fail git receive-pack dst >preamble && + + # Then, invoke push. Simulate a receive-pack that sends the preamble we + # obtained, followed by a dummy packet. + write_script myscript <<-\EOF && + cat preamble && + printf xxxx && + cat >push + EOF + test_might_fail git push --push-option="foo" --push-option="bar" \ + --receive-pack="\"$(pwd)/myscript\"" --signed dst --delete ff && + + # Replay the push output on a fresh dst, checking that ff is truly + # deleted. + prepare_dst && + git -C dst config receive.certnonceseed sekrit && + git -C dst config receive.advertisepushoptions 1 && + git receive-pack dst push.tweak && + prepare_dst && + git -C dst config receive.certnonceseed sekrit && + git -C dst config receive.advertisepushoptions 1 && + git receive-pack dst out && + git -C dst rev-parse ff && + grep "inconsistent push options" out +' + test_expect_success GPG 'fail without key and heed user.signingkey' ' prepare_dst && mkdir -p dst/.git/hooks && diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh index e4850b778c..39329eb7a8 100755 --- a/t/t5611-clone-config.sh +++ b/t/t5611-clone-config.sh @@ -19,6 +19,14 @@ test_expect_success 'clone -c can set multi-keys' ' test_cmp expect actual ' +test_expect_success 'clone -c can set multi-keys, including some empty' ' + rm -rf child && + git clone -c credential.helper= -c credential.helper=hi . child && + printf "%s\n" "" hi >expect && + git --git-dir=child/.git config --get-all credential.helper >actual && + test_cmp expect actual +' + test_expect_success 'clone -c without a value is boolean true' ' rm -rf child && git clone -c core.foo . child && diff --git a/t/t5612-clone-refspec.sh b/t/t5612-clone-refspec.sh index 7ace2535c8..fac5a73851 100755 --- a/t/t5612-clone-refspec.sh +++ b/t/t5612-clone-refspec.sh @@ -17,13 +17,20 @@ test_expect_success 'setup' ' echo four >file && git commit -a -m four && git checkout master && + git tag five && # default clone git clone . dir_all && + # default clone --no-tags + git clone --no-tags . dir_all_no_tags && + # default --single that follows HEAD=master git clone --single-branch . dir_master && + # default --single that follows HEAD=master with no tags + git clone --single-branch --no-tags . dir_master_no_tags && + # default --single that follows HEAD=side git checkout side && git clone --single-branch . dir_side && @@ -45,6 +52,9 @@ test_expect_success 'setup' ' # explicit --single with tag git clone --single-branch --branch two . dir_tag && + # explicit --single with tag and --no-tags + git clone --single-branch --no-tags --branch two . dir_tag_no_tags && + # advance both "master" and "side" branches git checkout side && echo five >file && @@ -59,7 +69,8 @@ test_expect_success 'setup' ' test_expect_success 'by default all branches will be kept updated' ' ( - cd dir_all && git fetch && + cd dir_all && + git fetch && git for-each-ref refs/remotes/origin | sed -e "/HEAD$/d" \ -e "s|/remotes/origin/|/heads/|" >../actual @@ -71,28 +82,82 @@ test_expect_success 'by default all branches will be kept updated' ' test_expect_success 'by default no tags will be kept updated' ' ( - cd dir_all && git fetch && + cd dir_all && + git fetch && git for-each-ref refs/tags >../actual ) && git for-each-ref refs/tags >expect && - test_must_fail test_cmp expect actual + test_must_fail test_cmp expect actual && + test_line_count = 2 actual +' + +test_expect_success 'clone with --no-tags' ' + ( + cd dir_all_no_tags && + git fetch && + git for-each-ref refs/tags >../actual + ) && + >expect && + test_cmp expect actual ' test_expect_success '--single-branch while HEAD pointing at master' ' ( - cd dir_master && git fetch && + cd dir_master && + git fetch && git for-each-ref refs/remotes/origin | sed -e "/HEAD$/d" \ -e "s|/remotes/origin/|/heads/|" >../actual ) && # only follow master git for-each-ref refs/heads/master >expect && - test_cmp expect actual + # get & check latest tags + test_cmp expect actual && + ( + cd dir_master && + git fetch --tags && + git for-each-ref refs/tags >../actual + ) && + git for-each-ref refs/tags >expect && + test_cmp expect actual && + test_line_count = 2 actual +' + +test_expect_success '--single-branch while HEAD pointing at master and --no-tags' ' + ( + cd dir_master_no_tags && + git fetch && + git for-each-ref refs/remotes/origin | + sed -e "/HEAD$/d" \ + -e "s|/remotes/origin/|/heads/|" >../actual + ) && + # only follow master + git for-each-ref refs/heads/master >expect && + test_cmp expect actual && + # get tags (noop) + ( + cd dir_master_no_tags && + git fetch && + git for-each-ref refs/tags >../actual + ) && + >expect && + test_cmp expect actual && + test_line_count = 0 actual && + # get tags with --tags overrides tagOpt + ( + cd dir_master_no_tags && + git fetch --tags && + git for-each-ref refs/tags >../actual + ) && + git for-each-ref refs/tags >expect && + test_cmp expect actual && + test_line_count = 2 actual ' test_expect_success '--single-branch while HEAD pointing at side' ' ( - cd dir_side && git fetch && + cd dir_side && + git fetch && git for-each-ref refs/remotes/origin | sed -e "/HEAD$/d" \ -e "s|/remotes/origin/|/heads/|" >../actual @@ -104,7 +169,8 @@ test_expect_success '--single-branch while HEAD pointing at side' ' test_expect_success '--single-branch with explicit --branch side' ' ( - cd dir_side2 && git fetch && + cd dir_side2 && + git fetch && git for-each-ref refs/remotes/origin | sed -e "/HEAD$/d" \ -e "s|/remotes/origin/|/heads/|" >../actual @@ -116,16 +182,29 @@ test_expect_success '--single-branch with explicit --branch side' ' test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' ' ( - cd dir_tag && git fetch && + cd dir_tag && + git fetch && git for-each-ref refs/tags >../actual ) && git for-each-ref refs/tags >expect && test_cmp expect actual ' +test_expect_success '--single-branch with explicit --branch with tag fetches updated tag despite --no-tags' ' + ( + cd dir_tag_no_tags && + git fetch && + git for-each-ref refs/tags >../actual + ) && + git for-each-ref refs/tags/two >expect && + test_cmp expect actual && + test_line_count = 1 actual +' + test_expect_success '--single-branch with --mirror' ' ( - cd dir_mirror && git fetch && + cd dir_mirror && + git fetch && git for-each-ref refs > ../actual ) && git for-each-ref refs >expect && @@ -134,7 +213,8 @@ test_expect_success '--single-branch with --mirror' ' test_expect_success '--single-branch with explicit --branch and --mirror' ' ( - cd dir_mirror_side && git fetch && + cd dir_mirror_side && + git fetch && git for-each-ref refs > ../actual ) && git for-each-ref refs >expect && @@ -143,7 +223,8 @@ test_expect_success '--single-branch with explicit --branch and --mirror' ' test_expect_success '--single-branch with detached' ' ( - cd dir_detached && git fetch && + cd dir_detached && + git fetch && git for-each-ref refs/remotes/origin | sed -e "/HEAD$/d" \ -e "s|/remotes/origin/|/heads/|" >../actual diff --git a/t/t5614-clone-submodules-shallow.sh b/t/t5614-clone-submodules-shallow.sh new file mode 100755 index 0000000000..a87d329656 --- /dev/null +++ b/t/t5614-clone-submodules-shallow.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +test_description='Test shallow cloning of repos with submodules' + +. ./test-lib.sh + +pwd=$(pwd) + +test_expect_success 'setup' ' + git checkout -b master && + test_commit commit1 && + test_commit commit2 && + mkdir sub && + ( + cd sub && + git init && + test_commit subcommit1 && + test_commit subcommit2 && + test_commit subcommit3 + ) && + git submodule add "file://$pwd/sub" sub && + git commit -m "add submodule" +' + +test_expect_success 'nonshallow clone implies nonshallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 3 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 3 lines +' + +test_expect_success 'shallow clone with shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --depth 2 --shallow-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 2 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 1 lines +' + +test_expect_success 'shallow clone does not imply shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --depth 2 "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 2 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 3 lines +' + +test_expect_success 'shallow clone with non shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --depth 2 --no-shallow-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 2 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 3 lines +' + +test_expect_success 'non shallow clone with shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --no-local --shallow-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 3 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 1 lines +' + +test_expect_success 'clone follows shallow recommendation' ' + test_when_finished "rm -rf super_clone" && + git config -f .gitmodules submodule.sub.shallow true && + git add .gitmodules && + git commit -m "recommed shallow for sub" && + git clone --recurse-submodules --no-local "file://$pwd/." super_clone && + ( + cd super_clone && + git log --oneline >lines && + test_line_count = 4 lines + ) && + ( + cd super_clone/sub && + git log --oneline >lines && + test_line_count = 1 lines + ) +' + +test_expect_success 'get unshallow recommended shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --no-local "file://$pwd/." super_clone && + ( + cd super_clone && + git submodule update --init --no-recommend-shallow && + git log --oneline >lines && + test_line_count = 4 lines + ) && + ( + cd super_clone/sub && + git log --oneline >lines && + test_line_count = 3 lines + ) +' + +test_expect_success 'clone follows non shallow recommendation' ' + test_when_finished "rm -rf super_clone" && + git config -f .gitmodules submodule.sub.shallow false && + git add .gitmodules && + git commit -m "recommed non shallow for sub" && + git clone --recurse-submodules --no-local "file://$pwd/." super_clone && + ( + cd super_clone && + git log --oneline >lines && + test_line_count = 5 lines + ) && + ( + cd super_clone/sub && + git log --oneline >lines && + test_line_count = 3 lines + ) +' + +test_done diff --git a/t/t5614-clone-submodules.sh b/t/t5614-clone-submodules.sh deleted file mode 100755 index a87d329656..0000000000 --- a/t/t5614-clone-submodules.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/sh - -test_description='Test shallow cloning of repos with submodules' - -. ./test-lib.sh - -pwd=$(pwd) - -test_expect_success 'setup' ' - git checkout -b master && - test_commit commit1 && - test_commit commit2 && - mkdir sub && - ( - cd sub && - git init && - test_commit subcommit1 && - test_commit subcommit2 && - test_commit subcommit3 - ) && - git submodule add "file://$pwd/sub" sub && - git commit -m "add submodule" -' - -test_expect_success 'nonshallow clone implies nonshallow submodule' ' - test_when_finished "rm -rf super_clone" && - git clone --recurse-submodules "file://$pwd/." super_clone && - git -C super_clone log --oneline >lines && - test_line_count = 3 lines && - git -C super_clone/sub log --oneline >lines && - test_line_count = 3 lines -' - -test_expect_success 'shallow clone with shallow submodule' ' - test_when_finished "rm -rf super_clone" && - git clone --recurse-submodules --depth 2 --shallow-submodules "file://$pwd/." super_clone && - git -C super_clone log --oneline >lines && - test_line_count = 2 lines && - git -C super_clone/sub log --oneline >lines && - test_line_count = 1 lines -' - -test_expect_success 'shallow clone does not imply shallow submodule' ' - test_when_finished "rm -rf super_clone" && - git clone --recurse-submodules --depth 2 "file://$pwd/." super_clone && - git -C super_clone log --oneline >lines && - test_line_count = 2 lines && - git -C super_clone/sub log --oneline >lines && - test_line_count = 3 lines -' - -test_expect_success 'shallow clone with non shallow submodule' ' - test_when_finished "rm -rf super_clone" && - git clone --recurse-submodules --depth 2 --no-shallow-submodules "file://$pwd/." super_clone && - git -C super_clone log --oneline >lines && - test_line_count = 2 lines && - git -C super_clone/sub log --oneline >lines && - test_line_count = 3 lines -' - -test_expect_success 'non shallow clone with shallow submodule' ' - test_when_finished "rm -rf super_clone" && - git clone --recurse-submodules --no-local --shallow-submodules "file://$pwd/." super_clone && - git -C super_clone log --oneline >lines && - test_line_count = 3 lines && - git -C super_clone/sub log --oneline >lines && - test_line_count = 1 lines -' - -test_expect_success 'clone follows shallow recommendation' ' - test_when_finished "rm -rf super_clone" && - git config -f .gitmodules submodule.sub.shallow true && - git add .gitmodules && - git commit -m "recommed shallow for sub" && - git clone --recurse-submodules --no-local "file://$pwd/." super_clone && - ( - cd super_clone && - git log --oneline >lines && - test_line_count = 4 lines - ) && - ( - cd super_clone/sub && - git log --oneline >lines && - test_line_count = 1 lines - ) -' - -test_expect_success 'get unshallow recommended shallow submodule' ' - test_when_finished "rm -rf super_clone" && - git clone --no-local "file://$pwd/." super_clone && - ( - cd super_clone && - git submodule update --init --no-recommend-shallow && - git log --oneline >lines && - test_line_count = 4 lines - ) && - ( - cd super_clone/sub && - git log --oneline >lines && - test_line_count = 3 lines - ) -' - -test_expect_success 'clone follows non shallow recommendation' ' - test_when_finished "rm -rf super_clone" && - git config -f .gitmodules submodule.sub.shallow false && - git add .gitmodules && - git commit -m "recommed non shallow for sub" && - git clone --recurse-submodules --no-local "file://$pwd/." super_clone && - ( - cd super_clone && - git log --oneline >lines && - test_line_count = 5 lines - ) && - ( - cd super_clone/sub && - git log --oneline >lines && - test_line_count = 3 lines - ) -' - -test_done diff --git a/t/t6134-pathspec-in-submodule.sh b/t/t6134-pathspec-in-submodule.sh index 0f1cb49ced..c670668409 100755 --- a/t/t6134-pathspec-in-submodule.sh +++ b/t/t6134-pathspec-in-submodule.sh @@ -21,7 +21,7 @@ EOF test_expect_success 'error message for path inside submodule' ' echo a >sub/a && test_must_fail git add sub/a 2>actual && - test_cmp expect actual + test_i18ncmp expect actual ' test_expect_success 'error message for path inside submodule from within submodule' ' diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh index cf076dcd94..394b169ead 100755 --- a/t/t6501-freshen-objects.sh +++ b/t/t6501-freshen-objects.sh @@ -129,7 +129,7 @@ for repack in '' true; do ' done -test_expect_success 'do not complain about existing broken links' ' +test_expect_success 'do not complain about existing broken links (commit)' ' cat >broken-commit <<-\EOF && tree 0000000000000000000000000000000000000001 parent 0000000000000000000000000000000000000002 @@ -144,4 +144,29 @@ test_expect_success 'do not complain about existing broken links' ' test_must_be_empty stderr ' +test_expect_success 'do not complain about existing broken links (tree)' ' + cat >broken-tree <<-\EOF && + 100644 blob 0000000000000000000000000000000000000003 foo + EOF + tree=$(git mktree --missing stderr && + git cat-file -e $tree && + test_must_be_empty stderr +' + +test_expect_success 'do not complain about existing broken links (tag)' ' + cat >broken-tag <<-\EOF && + object 0000000000000000000000000000000000000004 + type commit + tag broken + tagger whatever 1234 -0000 + + this is a broken tag + EOF + tag=$(git hash-object -t tag -w broken-tag) && + git gc 2>stderr && + git cat-file -e $tag && + test_must_be_empty stderr +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index bb2e4d704d..0ef7b94394 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -87,7 +87,7 @@ test_expect_success 'creating a tag with --create-reflog should create reflog' ' git tag --create-reflog tag_with_reflog && git reflog exists refs/tags/tag_with_reflog && sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual && - test_cmp expected actual + test_i18ncmp expected actual ' test_expect_success 'annotated tag with --create-reflog has correct message' ' @@ -98,7 +98,7 @@ test_expect_success 'annotated tag with --create-reflog has correct message' ' git tag -m "annotated tag" --create-reflog tag_with_reflog && git reflog exists refs/tags/tag_with_reflog && sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual && - test_cmp expected actual + test_i18ncmp expected actual ' test_expect_success '--create-reflog does not create reflog on failure' ' diff --git a/t/t7009-filter-branch-null-sha1.sh b/t/t7009-filter-branch-null-sha1.sh index c27f90f285..a8d9ec4987 100755 --- a/t/t7009-filter-branch-null-sha1.sh +++ b/t/t7009-filter-branch-null-sha1.sh @@ -31,6 +31,12 @@ test_expect_success 'setup: bring HEAD and index in sync' ' git commit -a -m "back to normal" ' +test_expect_success 'noop filter-branch complains' ' + test_must_fail git filter-branch \ + --force --prune-empty \ + --index-filter "true" +' + test_expect_success 'filter commands are still checked' ' test_must_fail git filter-branch \ --force --prune-empty \ diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh index 2eda6adeb1..f86ccdf215 100755 --- a/t/t7112-reset-submodule.sh +++ b/t/t7112-reset-submodule.sh @@ -5,6 +5,14 @@ test_description='reset can handle submodules' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh +KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1 +KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 +KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1 + +test_submodule_switch_recursing "git reset --recurse-submodules --keep" + +test_submodule_forced_switch_recursing "git reset --hard --recurse-submodules" + test_submodule_switch "git reset --keep" test_submodule_switch "git reset --merge" diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 1b8f1dbd3a..dcac364c5f 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -281,7 +281,7 @@ test_expect_success 'submodule add with ./, /.. and // in path' ' test_cmp empty untracked ' -test_expect_success 'submodule add with \\ in path' ' +test_expect_success !CYGWIN 'submodule add with \\ in path' ' test_when_finished "rm -rf parent sub\\with\\backslash" && # Initialize a repo with a backslash in its name diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 4ac386d98b..034914a14f 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -447,7 +447,7 @@ test_expect_success 'submodule update - command run for initial population of su EOF rm -rf super/submodule && test_must_fail git -C super submodule update 2>actual && - test_cmp expect actual && + test_i18ncmp expect actual && git -C super submodule update --checkout ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index fb00e6d9b0..79427840a4 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -32,6 +32,17 @@ test_expect_success 'commit -h in broken repository' ' test_i18ngrep "[Uu]sage" broken/usage ' +test_expect_success 'create upstream branch' ' + git checkout -b upstream && + test_commit upstream1 && + test_commit upstream2 && + # leave the first commit on master as root because several + # tests depend on this case; for our upstream we only + # care about commit counts anyway, so a totally divergent + # history is OK + git checkout --orphan master +' + test_expect_success 'setup' ' : >tracked && : >modified && @@ -53,7 +64,9 @@ test_expect_success 'setup' ' echo 1 >dir1/modified && echo 2 >dir2/modified && echo 3 >dir2/added && - git add dir2/added + git add dir2/added && + + git branch --set-upstream-to=upstream ' test_expect_success 'status (1)' ' @@ -75,6 +88,10 @@ EOF test_expect_success 'status --column' ' cat >expect <<\EOF && # On branch master +# Your branch and '\''upstream'\'' have diverged, +# and have 1 and 2 different commits each, respectively. +# (use "git pull" to merge the remote branch into yours) +# # Changes to be committed: # (use "git reset HEAD ..." to unstage) # @@ -105,6 +122,10 @@ test_expect_success 'status --column status.displayCommentPrefix=false' ' cat >expect <<\EOF # On branch master +# Your branch and 'upstream' have diverged, +# and have 1 and 2 different commits each, respectively. +# (use "git pull" to merge the remote branch into yours) +# # Changes to be committed: # (use "git reset HEAD ..." to unstage) # @@ -178,6 +199,9 @@ test_expect_success 'commit ignores status.displayCommentPrefix=false in COMMIT_ cat >expect <<\EOF On branch master +Your branch and 'upstream' have diverged, +and have 1 and 2 different commits each, respectively. + Changes to be committed: new file: dir2/added @@ -248,6 +272,10 @@ test_expect_success 'status with gitignore' ' cat >expect <<\EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 1 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -313,6 +341,10 @@ test_expect_success 'status with gitignore (nothing untracked)' ' cat >expect <<\EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 1 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -348,7 +380,7 @@ output* EOF cat >expect <<\EOF -## master +## master...upstream [ahead 1, behind 2] M dir1/modified A dir2/added ?? dir1/untracked @@ -360,7 +392,7 @@ EOF test_expect_success 'status -s -b' ' git status -s -b >output && - test_cmp expect output + test_i18ncmp expect output ' @@ -370,7 +402,7 @@ test_expect_success 'status -s -z -b' ' git status -s -z -b >output && nul_to_q output.q && mv output.q output && - test_cmp expect output + test_i18ncmp expect output ' test_expect_success 'setup dir3' ' @@ -382,6 +414,10 @@ test_expect_success 'setup dir3' ' test_expect_success 'status -uno' ' cat >expect <..." to unstage) @@ -408,6 +444,9 @@ test_expect_success 'status (status.showUntrackedFiles no)' ' test_expect_success 'status -uno (advice.statusHints false)' ' cat >expect <expect <..." to unstage) @@ -493,6 +536,10 @@ test_expect_success 'status -s (status.showUntrackedFiles normal)' ' test_expect_success 'status -uall' ' cat >expect <..." to unstage) @@ -552,6 +599,10 @@ test_expect_success 'status -s (status.showUntrackedFiles all)' ' test_expect_success 'status with relative paths' ' cat >expect <<\EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 1 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -610,13 +661,19 @@ test_expect_success 'status --porcelain ignores relative paths setting' ' test_expect_success 'setup unique colors' ' git config status.color.untracked blue && - git config status.color.branch green + git config status.color.branch green && + git config status.color.localBranch yellow && + git config status.color.remoteBranch cyan ' test_expect_success 'status with color.ui' ' cat >expect <<\EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 1 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -675,7 +732,7 @@ test_expect_success 'status -s with color.status' ' ' cat >expect <<\EOF -## master +## master...upstream [ahead 1, behind 2] M dir1/modified A dir2/added ?? dir1/untracked @@ -687,7 +744,7 @@ EOF test_expect_success 'status -s -b with color.status' ' git status -s -b | test_decode_color >output && - test_cmp expect output + test_i18ncmp expect output ' @@ -726,7 +783,7 @@ test_expect_success 'status --porcelain respects -b' ' git status --porcelain -b >output && { - echo "## master" && + echo "## master...upstream [ahead 1, behind 2]" && cat expect } >tmp && mv tmp expect && @@ -739,6 +796,10 @@ test_expect_success 'status --porcelain respects -b' ' test_expect_success 'status without relative paths' ' cat >expect <<\EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 1 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -785,6 +846,10 @@ test_expect_success 'status -s without relative paths' ' test_expect_success 'dry-run of partial commit excluding new file in index' ' cat >expect <..." to unstage) @@ -825,6 +890,10 @@ test_expect_success 'setup status submodule summary' ' test_expect_success 'status submodule summary is disabled by default' ' cat >expect <..." to unstage) @@ -881,6 +950,10 @@ head=$(cd sm && git rev-parse --short=7 --verify HEAD) test_expect_success 'status submodule summary' ' cat >expect <..." to unstage) @@ -939,6 +1012,10 @@ test_expect_success 'status -s submodule summary' ' test_expect_success 'status submodule summary (clean submodule): commit' ' cat >expect <..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) @@ -985,6 +1062,10 @@ test_expect_success 'status -z implies porcelain' ' test_expect_success 'commit --dry-run submodule summary (--amend)' ' cat >expect <..." to unstage) @@ -1038,6 +1119,10 @@ touch .gitmodules test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' ' cat > expect << EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 2 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -1146,6 +1231,10 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie test_expect_success "--ignore-submodules=untracked doesn't suppress submodules with modified content" ' cat > expect << EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 2 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -1202,6 +1291,10 @@ head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 -- test_expect_success "--ignore-submodules=untracked doesn't suppress submodule summary" ' cat > expect << EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 2 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -1282,6 +1375,10 @@ test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary cat > expect << EOF ; On branch master +; Your branch and 'upstream' have diverged, +; and have 2 and 2 different commits each, respectively. +; (use "git pull" to merge the remote branch into yours) +; ; Changes to be committed: ; (use "git reset HEAD ..." to unstage) ; @@ -1329,6 +1426,10 @@ test_expect_success "status (core.commentchar with two chars with submodule summ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' cat > expect << EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 2 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) @@ -1353,6 +1454,10 @@ EOF test_expect_success '.gitmodules ignore=all suppresses unstaged submodule summary' ' cat > expect << EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 2 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) @@ -1472,6 +1577,10 @@ test_expect_success 'git commit --dry-run will show a staged but ignored submodu git add sm && cat >expect << EOF && On branch master +Your branch and '\''upstream'\'' have diverged, +and have 2 and 2 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + Changes to be committed: (use "git reset HEAD ..." to unstage) diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh index db9774e345..ddef7ea6b0 100755 --- a/t/t7509-commit.sh +++ b/t/t7509-commit.sh @@ -101,7 +101,7 @@ test_expect_success '--amend option with empty author' ' echo "Empty author test" >>foo && test_tick && test_must_fail git commit -a -m "empty author" --amend 2>err && - grep "empty ident" err + test_i18ngrep "empty ident" err ' test_expect_success '--amend option with missing author' ' @@ -114,7 +114,7 @@ test_expect_success '--amend option with missing author' ' echo "Missing author test" >>foo && test_tick && test_must_fail git commit -a -m "malformed author" --amend 2>err && - grep "empty ident" err + test_i18ngrep "empty ident" err ' test_expect_success '--reset-author makes the commit ours even with --amend option' ' diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index 4dd1d7c520..0c6f91c433 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -1258,4 +1258,21 @@ test_expect_success 'with no command and no key' ' test_cmp expected actual ' +test_expect_success 'with cut line' ' + cat >expected <<-\EOF && + my subject + + review: Brian + sign: A U Thor + # ------------------------ >8 ------------------------ + ignore this + EOF + git interpret-trailers --trailer review:Brian >actual <<-\EOF && + my subject + # ------------------------ >8 ------------------------ + ignore this + EOF + test_cmp expected actual +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 7f09867478..668bbee73c 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -25,14 +25,14 @@ prompt_given () test_expect_success 'basic usage requires no repo' ' test_expect_code 129 git difftool -h >output && - grep ^usage: output && + test_i18ngrep ^usage: output && # create a ceiling directory to prevent Git from finding a repo mkdir -p not/repo && test_when_finished rm -r not && test_expect_code 129 \ env GIT_CEILING_DIRECTORIES="$(pwd)/not" \ git -C not/repo difftool -h >output && - grep ^usage: output + test_i18ngrep ^usage: output ' # Create a file on master and change it on branch diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index b5149fde6e..8dcb05c4a5 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -70,7 +70,7 @@ test_expect_success 'iso-8859-1' ' git config i18n.commitencoding ISO8859-1 && # use author and committer name in ISO-8859-1 to match it. - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901/8859-1.txt && test_tick && echo rosten >file && git commit -s -m den file && diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 6d06ed96cb..cc8d463e01 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -519,7 +519,7 @@ test_expect_success \ test_expect_success \ 'encode(commit): utf8' \ - '. "$TEST_DIRECTORY"/t3901-utf8.txt && + '. "$TEST_DIRECTORY"/t3901/utf8.txt && test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" && test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "UTF-8" >> file && @@ -529,7 +529,7 @@ test_expect_success \ test_expect_success \ 'encode(commit): iso-8859-1' \ - '. "$TEST_DIRECTORY"/t3901-8859-1.txt && + '. "$TEST_DIRECTORY"/t3901/8859-1.txt && test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" && test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "ISO-8859-1" >> file && diff --git a/t/test-lib.sh b/t/test-lib.sh index 13b5696822..26b3edfb2e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -761,10 +761,15 @@ test_done () { say "1..$test_count$skip_all" fi - test -d "$remove_trash" && - cd "$(dirname "$remove_trash")" && - rm -rf "$(basename "$remove_trash")" + if test -z "$debug" + then + test -d "$TRASH_DIRECTORY" || + error "Tests passed but trash directory already removed before test cleanup; aborting" + cd "$TRASH_DIRECTORY/.." && + rm -fr "$TRASH_DIRECTORY" || + error "Tests passed but test cleanup failed; aborting" + fi test_at_end_hook_ exit 0 ;; @@ -919,7 +924,6 @@ case "$TRASH_DIRECTORY" in /*) ;; # absolute path is good *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;; esac -test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY rm -fr "$TRASH_DIRECTORY" || { GIT_EXIT_OK=t echo >&5 "FATAL: Cannot prepare test area" @@ -1164,3 +1168,6 @@ build_option () { test_lazy_prereq LONG_IS_64BIT ' test 8 -le "$(build_option sizeof-long)" ' + +test_lazy_prereq TIME_IS_64BIT 'test-date is64bit' +test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit' diff --git a/tag.c b/tag.c index 243d1fdbbc..47f60ae151 100644 --- a/tag.c +++ b/tag.c @@ -66,7 +66,7 @@ struct object *deref_tag(struct object *o, const char *warn, int warnlen) { while (o && o->type == OBJ_TAG) if (((struct tag *)o)->tagged) - o = parse_object(((struct tag *)o)->tagged->oid.hash); + o = parse_object(&((struct tag *)o)->tagged->oid); else o = NULL; if (!o && warn) { @@ -80,7 +80,7 @@ struct object *deref_tag(struct object *o, const char *warn, int warnlen) struct object *deref_tag_noverify(struct object *o) { while (o && o->type == OBJ_TAG) { - o = parse_object(o->oid.hash); + o = parse_object(&o->oid); if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged) o = ((struct tag *)o)->tagged; else @@ -89,15 +89,15 @@ struct object *deref_tag_noverify(struct object *o) return o; } -struct tag *lookup_tag(const unsigned char *sha1) +struct tag *lookup_tag(const struct object_id *oid) { - struct object *obj = lookup_object(sha1); + struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(sha1, alloc_tag_node()); + return create_object(oid->hash, alloc_tag_node()); return object_as_type(obj, OBJ_TAG, 0); } -static unsigned long parse_tag_date(const char *buf, const char *tail) +static timestamp_t parse_tag_date(const char *buf, const char *tail) { const char *dateptr; @@ -110,13 +110,13 @@ static unsigned long parse_tag_date(const char *buf, const char *tail) /* nada */; if (buf >= tail) return 0; - /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */ - return strtoul(dateptr, NULL, 10); + /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */ + return parse_timestamp(dateptr, NULL, 10); } int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) { - unsigned char sha1[20]; + struct object_id oid; char type[20]; const char *bufptr = data; const char *tail = bufptr + size; @@ -126,11 +126,10 @@ int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) return 0; item->object.parsed = 1; - if (size < 64) + if (size < GIT_SHA1_HEXSZ + 24) return -1; - if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n') + if (memcmp("object ", bufptr, 7) || parse_oid_hex(bufptr + 7, &oid, &bufptr) || *bufptr++ != '\n') return -1; - bufptr += 48; /* "object " + sha1 + "\n" */ if (!starts_with(bufptr, "type ")) return -1; @@ -143,13 +142,13 @@ int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) bufptr = nl + 1; if (!strcmp(type, blob_type)) { - item->tagged = &lookup_blob(sha1)->object; + item->tagged = &lookup_blob(&oid)->object; } else if (!strcmp(type, tree_type)) { - item->tagged = &lookup_tree(sha1)->object; + item->tagged = &lookup_tree(&oid)->object; } else if (!strcmp(type, commit_type)) { - item->tagged = &lookup_commit(sha1)->object; + item->tagged = &lookup_commit(&oid)->object; } else if (!strcmp(type, tag_type)) { - item->tagged = &lookup_tag(sha1)->object; + item->tagged = &lookup_tag(&oid)->object; } else { error("Unknown type %s", type); item->tagged = NULL; diff --git a/tag.h b/tag.h index a5721b6731..fdfcb4a84a 100644 --- a/tag.h +++ b/tag.h @@ -9,10 +9,10 @@ struct tag { struct object object; struct object *tagged; char *tag; - unsigned long date; + timestamp_t date; }; -extern struct tag *lookup_tag(const unsigned char *sha1); +extern struct tag *lookup_tag(const struct object_id *oid); extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size); extern int parse_tag(struct tag *item); extern struct object *deref_tag(struct object *, const char *, int); diff --git a/transport.c b/transport.c index 4d33138a75..9bfcf870f9 100644 --- a/transport.c +++ b/transport.c @@ -87,7 +87,7 @@ static struct ref *get_refs_from_bundle(struct transport *transport, int for_pus for (i = 0; i < data->header.references.nr; i++) { struct ref_list_entry *e = data->header.references.list + i; struct ref *ref = alloc_ref(e->name); - hashcpy(ref->old_oid.hash, e->sha1); + oidcpy(&ref->old_oid, &e->oid); ref->next = result; result = ref; } diff --git a/tree-walk.c b/tree-walk.c index ff77605680..f25a08fddf 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -1075,7 +1075,7 @@ static enum interesting do_match(const struct name_entry *entry, * later on. * max_depth is ignored but we may consider support it * in future, see - * http://thread.gmane.org/gmane.comp.version-control.git/163757/focus=163840 + * https://public-inbox.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/ */ if (ps->recursive && S_ISDIR(entry->mode)) return entry_interesting; diff --git a/tree.c b/tree.c index ce345c5511..603b29ee80 100644 --- a/tree.c +++ b/tree.c @@ -58,7 +58,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base, { struct tree_desc desc; struct name_entry entry; - unsigned char sha1[20]; + struct object_id oid; int len, oldlen = base->len; enum interesting retval = entry_not_interesting; @@ -87,11 +87,11 @@ static int read_tree_1(struct tree *tree, struct strbuf *base, } if (S_ISDIR(entry.mode)) - hashcpy(sha1, entry.oid->hash); + oidcpy(&oid, entry.oid); else if (S_ISGITLINK(entry.mode)) { struct commit *commit; - commit = lookup_commit(entry.oid->hash); + commit = lookup_commit(entry.oid); if (!commit) die("Commit %s in submodule path %s%s not found", oid_to_hex(entry.oid), @@ -102,7 +102,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base, oid_to_hex(entry.oid), base->buf, entry.path); - hashcpy(sha1, commit->tree->object.oid.hash); + oidcpy(&oid, &commit->tree->object.oid); } else continue; @@ -110,7 +110,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base, len = tree_entry_len(&entry); strbuf_add(base, entry.path, len); strbuf_addch(base, '/'); - retval = read_tree_1(lookup_tree(sha1), + retval = read_tree_1(lookup_tree(&oid), base, stage, pathspec, fn, context); strbuf_setlen(base, oldlen); @@ -184,11 +184,11 @@ int read_tree(struct tree *tree, int stage, struct pathspec *match) return 0; } -struct tree *lookup_tree(const unsigned char *sha1) +struct tree *lookup_tree(const struct object_id *oid) { - struct object *obj = lookup_object(sha1); + struct object *obj = lookup_object(oid->hash); if (!obj) - return create_object(sha1, alloc_tree_node()); + return create_object(oid->hash, alloc_tree_node()); return object_as_type(obj, OBJ_TREE, 0); } @@ -232,9 +232,9 @@ void free_tree_buffer(struct tree *tree) tree->object.parsed = 0; } -struct tree *parse_tree_indirect(const unsigned char *sha1) +struct tree *parse_tree_indirect(const struct object_id *oid) { - struct object *obj = parse_object(sha1); + struct object *obj = parse_object(oid); do { if (!obj) return NULL; @@ -247,6 +247,6 @@ struct tree *parse_tree_indirect(const unsigned char *sha1) else return NULL; if (!obj->parsed) - parse_object(obj->oid.hash); + parse_object(&obj->oid); } while (1); } diff --git a/tree.h b/tree.h index d24786cba2..0d4734b94b 100644 --- a/tree.h +++ b/tree.h @@ -12,7 +12,7 @@ struct tree { unsigned long size; }; -struct tree *lookup_tree(const unsigned char *sha1); +struct tree *lookup_tree(const struct object_id *oid); int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size); @@ -24,7 +24,7 @@ static inline int parse_tree(struct tree *tree) void free_tree_buffer(struct tree *tree); /* Parses and returns the tree in the given ent, chasing tags and commits. */ -struct tree *parse_tree_indirect(const unsigned char *sha1); +struct tree *parse_tree_indirect(const struct object_id *oid); #define READ_TREE_RECURSIVE 1 typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *); diff --git a/unpack-trees.c b/unpack-trees.c index aa15111fef..c312c2cd3a 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -252,14 +252,18 @@ static int check_submodule_move_head(const struct cache_entry *ce, const char *new_id, struct unpack_trees_options *o) { + unsigned flags = SUBMODULE_MOVE_HEAD_DRY_RUN; const struct submodule *sub = submodule_from_ce(ce); if (!sub) return 0; + if (o->reset) + flags |= SUBMODULE_MOVE_HEAD_FORCE; + switch (sub->update_strategy.type) { case SM_UPDATE_UNSPECIFIED: case SM_UPDATE_CHECKOUT: - if (submodule_move_head(ce->name, old_id, new_id, SUBMODULE_MOVE_HEAD_DRY_RUN)) + if (submodule_move_head(ce->name, old_id, new_id, flags)) return o->gently ? -1 : add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name); return 0; @@ -308,6 +312,7 @@ static void unlink_entry(const struct cache_entry *ce) case SM_UPDATE_CHECKOUT: case SM_UPDATE_REBASE: case SM_UPDATE_MERGE: + /* state.force is set at the caller. */ submodule_move_head(ce->name, "HEAD", NULL, SUBMODULE_MOVE_HEAD_FORCE); break; @@ -1068,7 +1073,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr, struct cache_entry **cache_end; int dtype = DT_DIR; int ret = is_excluded_from_list(prefix->buf, prefix->len, - basename, &dtype, el); + basename, &dtype, el, &the_index); int rc; strbuf_addch(prefix, '/'); @@ -1171,7 +1176,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, /* Non-directory */ dtype = ce_to_dtype(ce); ret = is_excluded_from_list(ce->name, ce_namelen(ce), - name, &dtype, el); + name, &dtype, el, &the_index); if (ret < 0) ret = defval; if (ret > 0) @@ -1251,7 +1256,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options o->skip_sparse_checkout = 1; if (!o->skip_sparse_checkout) { char *sparse = git_pathdup("info/sparse-checkout"); - if (add_excludes_from_file_to_list(sparse, "", 0, &el, 0) < 0) + if (add_excludes_from_file_to_list(sparse, "", 0, &el, NULL) < 0) o->skip_sparse_checkout = 1; else o->el = ⪙ @@ -1592,7 +1597,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce, memset(&d, 0, sizeof(d)); if (o->dir) d.exclude_per_dir = o->dir->exclude_per_dir; - i = read_directory(&d, pathbuf, namelen+1, NULL); + i = read_directory(&d, &the_index, pathbuf, namelen+1, NULL); if (i) return o->gently ? -1 : add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name); @@ -1634,7 +1639,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype, return 0; if (o->dir && - is_excluded(o->dir, name, &dtype)) + is_excluded(o->dir, &the_index, name, &dtype)) /* * ce->name is explicitly excluded, so it is Ok to * overwrite it. diff --git a/upload-pack.c b/upload-pack.c index ffb028d623..5330c02c14 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = { #define CLIENT_SHALLOW (1u << 18) #define HIDDEN_REF (1u << 19) -static unsigned long oldest_have; +static timestamp_t oldest_have; static int deepen_relative; static int multi_ack; @@ -286,19 +286,19 @@ static void create_pack_file(void) die("git upload-pack: %s", abort_msg); } -static int got_sha1(const char *hex, unsigned char *sha1) +static int got_oid(const char *hex, struct object_id *oid) { struct object *o; int we_knew_they_have = 0; - if (get_sha1_hex(hex, sha1)) + if (get_oid_hex(hex, oid)) die("git upload-pack: expected SHA1 object, got '%s'", hex); - if (!has_sha1_file(sha1)) + if (!has_object_file(oid)) return -1; - o = parse_object(sha1); + o = parse_object(oid); if (!o) - die("oops (%s)", sha1_to_hex(sha1)); + die("oops (%s)", oid_to_hex(oid)); if (o->type == OBJ_COMMIT) { struct commit_list *parents; struct commit *commit = (struct commit *)o; @@ -334,7 +334,7 @@ static int reachable(struct commit *want) break; } if (!commit->object.parsed) - parse_object(commit->object.oid.hash); + parse_object(&commit->object.oid); if (commit->object.flags & REACHABLE) continue; commit->object.flags |= REACHABLE; @@ -382,8 +382,8 @@ static int ok_to_give_up(void) static int get_common_commits(void) { - unsigned char sha1[20]; - char last_hex[41]; + struct object_id oid; + char last_hex[GIT_MAX_HEXSZ + 1]; int got_common = 0; int got_other = 0; int sent_ready = 0; @@ -416,11 +416,11 @@ static int get_common_commits(void) continue; } if (skip_prefix(line, "have ", &arg)) { - switch (got_sha1(arg, sha1)) { + switch (got_oid(arg, &oid)) { case -1: /* they have what we do not */ got_other = 1; if (multi_ack && ok_to_give_up()) { - const char *hex = sha1_to_hex(sha1); + const char *hex = oid_to_hex(&oid); if (multi_ack == 2) { sent_ready = 1; packet_write_fmt(1, "ACK %s ready\n", hex); @@ -430,7 +430,7 @@ static int get_common_commits(void) break; default: got_common = 1; - memcpy(last_hex, sha1_to_hex(sha1), 41); + memcpy(last_hex, oid_to_hex(&oid), 41); if (multi_ack == 2) packet_write_fmt(1, "ACK %s common\n", last_hex); else if (multi_ack) @@ -492,7 +492,7 @@ static int do_reachable_revlist(struct child_process *cmd, goto error; namebuf[0] = '^'; - namebuf[41] = '\n'; + namebuf[GIT_SHA1_HEXSZ + 1] = '\n'; for (i = get_max_object_index(); 0 < i; ) { o = get_indexed_object(--i); if (!o) @@ -502,10 +502,10 @@ static int do_reachable_revlist(struct child_process *cmd, if (!is_our_ref(o)) continue; memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ); - if (write_in_full(cmd->in, namebuf, 42) < 0) + if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 2) < 0) goto error; } - namebuf[40] = '\n'; + namebuf[GIT_SHA1_HEXSZ] = '\n'; for (i = 0; i < src->nr; i++) { o = src->objects[i].item; if (is_our_ref(o)) { @@ -516,7 +516,7 @@ static int do_reachable_revlist(struct child_process *cmd, if (reachable && o->type == OBJ_COMMIT) o->flags |= TMP_MARK; memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ); - if (write_in_full(cmd->in, namebuf, 41) < 0) + if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 1) < 0) goto error; } close(cmd->in); @@ -642,7 +642,7 @@ static void send_shallow(struct commit_list *result) if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write_fmt(1, "shallow %s", oid_to_hex(&object->oid)); - register_shallow(object->oid.hash); + register_shallow(&object->oid); shallow_nr++; } result = result->next; @@ -667,7 +667,7 @@ static void send_unshallow(const struct object_array *shallows) * parse and add the parents to the want list, then * re-register it. */ - unregister_shallow(object->oid.hash); + unregister_shallow(&object->oid); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; @@ -679,7 +679,7 @@ static void send_unshallow(const struct object_array *shallows) add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ - register_shallow(object->oid.hash); + register_shallow(&object->oid); } } @@ -735,14 +735,14 @@ static void receive_needs(void) struct string_list deepen_not = STRING_LIST_INIT_DUP; int depth = 0; int has_non_tip = 0; - unsigned long deepen_since = 0; + timestamp_t deepen_since = 0; int deepen_rev_list = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; - unsigned char sha1_buf[20]; + struct object_id oid_buf; char *line = packet_read_line(0, NULL); const char *arg; @@ -751,15 +751,15 @@ static void receive_needs(void) break; if (skip_prefix(line, "shallow ", &arg)) { - unsigned char sha1[20]; + struct object_id oid; struct object *object; - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die("invalid shallow line: %s", line); - object = parse_object(sha1); + object = parse_object(&oid); if (!object) continue; if (object->type != OBJ_COMMIT) - die("invalid shallow object %s", sha1_to_hex(sha1)); + die("invalid shallow object %s", oid_to_hex(&oid)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); @@ -775,7 +775,7 @@ static void receive_needs(void) } if (skip_prefix(line, "deepen-since ", &arg)) { char *end = NULL; - deepen_since = strtoul(arg, &end, 0); + deepen_since = parse_timestamp(arg, &end, 0); if (!end || *end || !deepen_since || /* revisions.c's max_age -1 is special */ deepen_since == -1) @@ -785,8 +785,8 @@ static void receive_needs(void) } if (skip_prefix(line, "deepen-not ", &arg)) { char *ref = NULL; - unsigned char sha1[20]; - if (expand_ref(arg, strlen(arg), sha1, &ref) != 1) + struct object_id oid; + if (expand_ref(arg, strlen(arg), oid.hash, &ref) != 1) die("git upload-pack: ambiguous deepen-not: %s", line); string_list_append(&deepen_not, ref); free(ref); @@ -794,7 +794,7 @@ static void receive_needs(void) continue; } if (!skip_prefix(line, "want ", &arg) || - get_sha1_hex(arg, sha1_buf)) + get_oid_hex(arg, &oid_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); @@ -821,13 +821,13 @@ static void receive_needs(void) if (parse_feature_request(features, "include-tag")) use_include_tag = 1; - o = parse_object(sha1_buf); + o = parse_object(&oid_buf); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", - sha1_to_hex(sha1_buf)); + oid_to_hex(&oid_buf)); die("git upload-pack: not our ref %s", - sha1_to_hex(sha1_buf)); + oid_to_hex(&oid_buf)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; @@ -863,7 +863,7 @@ static void receive_needs(void) argv_array_push(&av, "rev-list"); if (deepen_since) - argv_array_pushf(&av, "--max-age=%lu", deepen_since); + argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since); if (deepen_not.nr) { argv_array_push(&av, "--not"); for (i = 0; i < deepen_not.nr; i++) { @@ -883,7 +883,7 @@ static void receive_needs(void) if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) - register_shallow(shallows.objects[i].item->oid.hash); + register_shallow(&shallows.objects[i].item->oid); } shallow_nr += shallows.nr; diff --git a/usage.c b/usage.c index ad6d2910fb..1f63e033e9 100644 --- a/usage.c +++ b/usage.c @@ -201,3 +201,35 @@ void warning(const char *warn, ...) warn_routine(warn, params); va_end(params); } + +static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params) +{ + char prefix[256]; + + /* truncation via snprintf is OK here */ + if (file) + snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line); + else + snprintf(prefix, sizeof(prefix), "BUG: "); + + vreportf(prefix, fmt, params); + abort(); +} + +#ifdef HAVE_VARIADIC_MACROS +NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + BUG_vfl(file, line, fmt, ap); + va_end(ap); +} +#else +NORETURN void BUG(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + BUG_vfl(NULL, 0, fmt, ap); + va_end(ap); +} +#endif diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index 97cba39cdf..5a89db30e3 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -68,12 +68,12 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref) } void fast_export_begin_note(uint32_t revision, const char *author, - const char *log, unsigned long timestamp, const char *note_ref) + const char *log, timestamp_t timestamp, const char *note_ref) { static int firstnote = 1; size_t loglen = strlen(log); printf("commit %s\n", note_ref); - printf("committer %s <%s@%s> %lu +0000\n", author, author, "local", timestamp); + printf("committer %s <%s@%s> %"PRItime" +0000\n", author, author, "local", timestamp); printf("data %"PRIuMAX"\n", (uintmax_t)loglen); fwrite(log, loglen, 1, stdout); if (firstnote) { @@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN]; void fast_export_begin_commit(uint32_t revision, const char *author, const struct strbuf *log, const char *uuid, const char *url, - unsigned long timestamp, const char *local_ref) + timestamp_t timestamp, const char *local_ref) { static const struct strbuf empty = STRBUF_INIT; if (!log) @@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author, } printf("commit %s\n", local_ref); printf("mark :%"PRIu32"\n", revision); - printf("committer %s <%s@%s> %lu +0000\n", + printf("committer %s <%s@%s> %"PRItime" +0000\n", *author ? author : "nobody", *author ? author : "nobody", *uuid ? uuid : "local", timestamp); diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h index c8b5adb811..b9a3b71c99 100644 --- a/vcs-svn/fast_export.h +++ b/vcs-svn/fast_export.h @@ -11,10 +11,10 @@ void fast_export_delete(const char *path); void fast_export_modify(const char *path, uint32_t mode, const char *dataref); void fast_export_note(const char *committish, const char *dataref); void fast_export_begin_note(uint32_t revision, const char *author, - const char *log, unsigned long timestamp, const char *note_ref); + const char *log, timestamp_t timestamp, const char *note_ref); void fast_export_begin_commit(uint32_t revision, const char *author, const struct strbuf *log, const char *uuid,const char *url, - unsigned long timestamp, const char *local_ref); + timestamp_t timestamp, const char *local_ref); void fast_export_end_commit(uint32_t revision); void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input); void fast_export_buf_to_data(const struct strbuf *data); diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index e4b395963b..1846685a21 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -47,7 +47,7 @@ static struct { static struct { uint32_t revision; - unsigned long timestamp; + timestamp_t timestamp; struct strbuf log, author, note; } rev_ctx; diff --git a/walker.c b/walker.c index 2c86e406f9..274f1a4935 100644 --- a/walker.c +++ b/walker.c @@ -47,12 +47,12 @@ static int process_tree(struct walker *walker, struct tree *tree) if (S_ISGITLINK(entry.mode)) continue; if (S_ISDIR(entry.mode)) { - struct tree *tree = lookup_tree(entry.oid->hash); + struct tree *tree = lookup_tree(entry.oid); if (tree) obj = &tree->object; } else { - struct blob *blob = lookup_blob(entry.oid->hash); + struct blob *blob = lookup_blob(entry.oid); if (blob) obj = &blob->object; } @@ -180,7 +180,7 @@ static int loop(struct walker *walker) } } if (!obj->type) - parse_object(obj->oid.hash); + parse_object(&obj->oid); if (process_object(walker, obj)) return -1; } @@ -206,7 +206,7 @@ static int interpret_target(struct walker *walker, char *target, unsigned char * static int mark_complete(const char *path, const struct object_id *oid, int flag, void *cb_data) { - struct commit *commit = lookup_commit_reference_gently(oid->hash, 1); + struct commit *commit = lookup_commit_reference_gently(oid, 1); if (commit) { commit->object.flags |= COMPLETE; diff --git a/worktree.c b/worktree.c index bae787cf8d..2801c6d52b 100644 --- a/worktree.c +++ b/worktree.c @@ -19,54 +19,25 @@ void free_worktrees(struct worktree **worktrees) free (worktrees); } -/* - * read 'path_to_ref' into 'ref'. Also if is_detached is not NULL, - * set is_detached to 1 (0) if the ref is detached (is not detached). - * - * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so - * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses - * git_path). Parse the ref ourselves. - * - * return -1 if the ref is not a proper ref, 0 otherwise (success) - */ -static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached) -{ - if (is_detached) - *is_detached = 0; - if (!strbuf_readlink(ref, path_to_ref, 0)) { - /* HEAD is symbolic link */ - if (!starts_with(ref->buf, "refs/") || - check_refname_format(ref->buf, 0)) - return -1; - } else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) { - /* textual symref or detached */ - if (!starts_with(ref->buf, "ref:")) { - if (is_detached) - *is_detached = 1; - } else { - strbuf_remove(ref, 0, strlen("ref:")); - strbuf_trim(ref); - if (check_refname_format(ref->buf, 0)) - return -1; - } - } else - return -1; - return 0; -} - /** - * Add the head_sha1 and head_ref (if not detached) to the given worktree + * Update head_sha1, head_ref and is_detached of the given worktree */ -static void add_head_info(struct strbuf *head_ref, struct worktree *worktree) +static void add_head_info(struct worktree *wt) { - if (head_ref->len) { - if (worktree->is_detached) { - get_sha1_hex(head_ref->buf, worktree->head_sha1); - } else { - resolve_ref_unsafe(head_ref->buf, 0, worktree->head_sha1, NULL); - worktree->head_ref = strbuf_detach(head_ref, NULL); - } - } + int flags; + const char *target; + + target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt), + "HEAD", + RESOLVE_REF_READING, + wt->head_sha1, &flags); + if (!target) + return; + + if (flags & REF_ISSYMREF) + wt->head_ref = xstrdup(target); + else + wt->is_detached = 1; } /** @@ -77,9 +48,7 @@ static struct worktree *get_main_worktree(void) struct worktree *worktree = NULL; struct strbuf path = STRBUF_INIT; struct strbuf worktree_path = STRBUF_INIT; - struct strbuf head_ref = STRBUF_INIT; int is_bare = 0; - int is_detached = 0; strbuf_add_absolute_path(&worktree_path, get_git_common_dir()); is_bare = !strbuf_strip_suffix(&worktree_path, "/.git"); @@ -91,13 +60,10 @@ static struct worktree *get_main_worktree(void) worktree = xcalloc(1, sizeof(*worktree)); worktree->path = strbuf_detach(&worktree_path, NULL); worktree->is_bare = is_bare; - worktree->is_detached = is_detached; - if (!parse_ref(path.buf, &head_ref, &is_detached)) - add_head_info(&head_ref, worktree); + add_head_info(worktree); strbuf_release(&path); strbuf_release(&worktree_path); - strbuf_release(&head_ref); return worktree; } @@ -106,8 +72,6 @@ static struct worktree *get_linked_worktree(const char *id) struct worktree *worktree = NULL; struct strbuf path = STRBUF_INIT; struct strbuf worktree_path = STRBUF_INIT; - struct strbuf head_ref = STRBUF_INIT; - int is_detached = 0; if (!id) die("Missing linked worktree name"); @@ -127,19 +91,14 @@ static struct worktree *get_linked_worktree(const char *id) strbuf_reset(&path); strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id); - if (parse_ref(path.buf, &head_ref, &is_detached) < 0) - goto done; - worktree = xcalloc(1, sizeof(*worktree)); worktree->path = strbuf_detach(&worktree_path, NULL); worktree->id = xstrdup(id); - worktree->is_detached = is_detached; - add_head_info(&head_ref, worktree); + add_head_info(worktree); done: strbuf_release(&path); strbuf_release(&worktree_path); - strbuf_release(&head_ref); return worktree; } @@ -337,8 +296,6 @@ const struct worktree *find_shared_symref(const char *symref, const char *target) { const struct worktree *existing = NULL; - struct strbuf path = STRBUF_INIT; - struct strbuf sb = STRBUF_INIT; static struct worktree **worktrees; int i = 0; @@ -348,6 +305,11 @@ const struct worktree *find_shared_symref(const char *symref, for (i = 0; worktrees[i]; i++) { struct worktree *wt = worktrees[i]; + const char *symref_target; + unsigned char sha1[20]; + struct ref_store *refs; + int flags; + if (wt->is_bare) continue; @@ -362,25 +324,15 @@ const struct worktree *find_shared_symref(const char *symref, } } - strbuf_reset(&path); - strbuf_reset(&sb); - strbuf_addf(&path, "%s/%s", - get_worktree_git_dir(wt), - symref); - - if (parse_ref(path.buf, &sb, NULL)) { - continue; - } - - if (!strcmp(sb.buf, target)) { + refs = get_worktree_ref_store(wt); + symref_target = refs_resolve_ref_unsafe(refs, symref, 0, + sha1, &flags); + if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) { existing = wt; break; } } - strbuf_release(&path); - strbuf_release(&sb); - return existing; } @@ -399,6 +351,7 @@ int submodule_uses_worktrees(const char *path) /* The env would be set for the superproject. */ get_common_dir_noenv(&sb, submodule_gitdir); + free(submodule_gitdir); /* * The check below is only known to be good for repository format @@ -418,7 +371,6 @@ int submodule_uses_worktrees(const char *path) /* See if there is any file inside the worktrees directory. */ dir = opendir(sb.buf); strbuf_release(&sb); - free(submodule_gitdir); if (!dir) return 0; diff --git a/worktree.h b/worktree.h index 6bfb985203..5ea5e503fb 100644 --- a/worktree.h +++ b/worktree.h @@ -4,7 +4,7 @@ struct worktree { char *path; char *id; - char *head_ref; + char *head_ref; /* NULL if HEAD is broken or detached */ char *lock_reason; /* internal use */ unsigned char head_sha1[20]; int is_detached; diff --git a/wt-status.c b/wt-status.c index 0375484962..25aafc35c8 100644 --- a/wt-status.c +++ b/wt-status.c @@ -665,7 +665,7 @@ static void wt_status_collect_untracked(struct wt_status *s) dir.untracked = the_index.untracked; setup_standard_excludes(&dir); - fill_directory(&dir, &s->pathspec); + fill_directory(&dir, &the_index, &s->pathspec); for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; @@ -896,17 +896,18 @@ static void wt_longstatus_print_other(struct wt_status *s, status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); } -void wt_status_truncate_message_at_cut_line(struct strbuf *buf) +size_t wt_status_locate_end(const char *s, size_t len) { const char *p; struct strbuf pattern = STRBUF_INIT; strbuf_addf(&pattern, "\n%c %s", comment_line_char, cut_line); - if (starts_with(buf->buf, pattern.buf + 1)) - strbuf_setlen(buf, 0); - else if ((p = strstr(buf->buf, pattern.buf))) - strbuf_setlen(buf, p - buf->buf + 1); + if (starts_with(s, pattern.buf + 1)) + len = 0; + else if ((p = strstr(s, pattern.buf))) + len = p - s + 1; strbuf_release(&pattern); + return len; } void wt_status_add_cut_line(FILE *fp) @@ -1002,7 +1003,7 @@ static void wt_longstatus_print_tracking(struct wt_status *s) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c", comment_line_char); else - fputs("", s->fp); + fputs("\n", s->fp); } static int has_unmerged(struct wt_status *s) @@ -1082,29 +1083,29 @@ static char *read_line_from_git_path(const char *filename) static int split_commit_in_progress(struct wt_status *s) { int split_in_progress = 0; - char *head = read_line_from_git_path("HEAD"); - char *orig_head = read_line_from_git_path("ORIG_HEAD"); - char *rebase_amend = read_line_from_git_path("rebase-merge/amend"); - char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head"); + char *head, *orig_head, *rebase_amend, *rebase_orig_head; - if (!head || !orig_head || !rebase_amend || !rebase_orig_head || + if ((!s->amend && !s->nowarn && !s->workdir_dirty) || !s->branch || strcmp(s->branch, "HEAD")) - return split_in_progress; + return 0; - if (!strcmp(rebase_amend, rebase_orig_head)) { - if (strcmp(head, rebase_amend)) - split_in_progress = 1; - } else if (strcmp(orig_head, rebase_orig_head)) { - split_in_progress = 1; - } + head = read_line_from_git_path("HEAD"); + orig_head = read_line_from_git_path("ORIG_HEAD"); + rebase_amend = read_line_from_git_path("rebase-merge/amend"); + rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head"); - if (!s->amend && !s->nowarn && !s->workdir_dirty) - split_in_progress = 0; + if (!head || !orig_head || !rebase_amend || !rebase_orig_head) + ; /* fall through, no split in progress */ + else if (!strcmp(rebase_amend, rebase_orig_head)) + split_in_progress = !!strcmp(head, rebase_amend); + else if (strcmp(orig_head, rebase_orig_head)) + split_in_progress = 1; free(head); free(orig_head); free(rebase_amend); free(rebase_orig_head); + return split_in_progress; } @@ -1168,6 +1169,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines) abbrev_sha1_in_line(&line); string_list_append(lines, line.buf); } + fclose(f); return 0; } @@ -1387,7 +1389,7 @@ struct grab_1st_switch_cbdata { }; static int grab_1st_switch(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct grab_1st_switch_cbdata *cb = cb_data; @@ -1428,7 +1430,7 @@ static void wt_status_get_detached_from(struct wt_status_state *state) /* sha1 is a commit? match without further lookup */ (!oidcmp(&cb.noid, &oid) || /* perhaps sha1 is a tag, try to dereference to a commit */ - ((commit = lookup_commit_reference_gently(oid.hash, 1)) != NULL && + ((commit = lookup_commit_reference_gently(&oid, 1)) != NULL && !oidcmp(&cb.noid, &commit->object.oid)))) { const char *from = ref; if (!skip_prefix(from, "refs/tags/", &from)) diff --git a/wt-status.h b/wt-status.h index 6018c627b1..8a3864783b 100644 --- a/wt-status.h +++ b/wt-status.h @@ -112,7 +112,7 @@ struct wt_status_state { unsigned char cherry_pick_head_sha1[20]; }; -void wt_status_truncate_message_at_cut_line(struct strbuf *); +size_t wt_status_locate_end(const char *s, size_t len); void wt_status_add_cut_line(FILE *fp); void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s);