Merge branch 'jk/no-system-includes-in-dot-c' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 9 Aug 2019 22:18:18 +0000 (15:18 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Aug 2019 22:18:19 +0000 (15:18 -0700)
Compilation fix.

* jk/no-system-includes-in-dot-c:
wt-status.h: drop stdio.h include
verify-tag: drop signal.h include

125 files changed:
.clang-format
Documentation/CodingGuidelines
Documentation/RelNotes/2.22.1.txt [new file with mode: 0644]
Documentation/config/alias.txt
Documentation/config/gpg.txt
Documentation/git-branch.txt
Documentation/git-clone.txt
Documentation/git-fsck.txt
Documentation/git-hash-object.txt
Documentation/git-send-email.txt
Documentation/git.txt
Documentation/gitignore.txt
Documentation/gitweb.txt
Documentation/merge-options.txt
Documentation/technical/api-trace2.txt
Documentation/technical/commit-graph.txt
README.md
RelNotes
apply.c
builtin/am.c
builtin/bisect--helper.c
builtin/branch.c
builtin/clean.c
builtin/clone.c
builtin/commit-graph.c
builtin/commit.c
builtin/fetch.c
builtin/gc.c
builtin/index-pack.c
builtin/init-db.c
builtin/interpret-trailers.c
builtin/ls-files.c
builtin/merge.c
builtin/pack-objects.c
builtin/rebase.c
builtin/receive-pack.c
builtin/repack.c
builtin/rm.c
builtin/stash.c
builtin/submodule--helper.c
builtin/update-index.c
bundle.c
cache.h
ci/install-dependencies.sh
ci/lib.sh
commit-graph.c
commit-graph.h
commit.c
compat/mingw.c
compat/poll/poll.c
compat/winansi.c
config.c
contrib/coccinelle/array.cocci
contrib/completion/git-completion.bash
delta-islands.c
delta-islands.h
diff-lib.c
diff.c
diffcore-rename.c
dir.c
editor.c
entry.c
fast-import.c
fsmonitor.c
fsmonitor.h
git-add--interactive.perl
git-p4.py
git-request-pull.sh
gpg-interface.c
grep.c
kwset.c
list-objects-filter.c
ls-refs.c
name-hash.c
object-store.h
object.c
packfile.c
packfile.h
pager.c
preload-index.c
pretty.c
progress.c
read-cache.c
sequencer.c
server-info.c
sh-i18n--envsubst.c
sha1-file.c
t/t0001-init.sh
t/t0061-run-command.sh
t/t1301-shared-repo.sh
t/t2400-worktree-add.sh
t/t3404-rebase-interactive.sh
t/t3418-rebase-continue.sh
t/t3420-rebase-autostash.sh
t/t3430-rebase-merges.sh
t/t3600-rm.sh
t/t3701-add-interactive.sh
t/t3903-stash.sh
t/t4015-diff-whitespace.sh
t/t4257-am-interactive.sh [new file with mode: 0755]
t/t5150-request-pull.sh
t/t5318-commit-graph.sh
t/t5509-fetch-push-namespaces.sh
t/t5541-http-push-smart.sh
t/t5551-http-fetch-smart.sh
t/t5601-clone.sh
t/t5607-clone-bundle.sh
t/t5616-partial-clone.sh
t/t5801-remote-helpers.sh
t/t5801/git-remote-testgit
t/t6500-gc.sh
t/t7300-clean.sh
t/t7407-submodule-foreach.sh
t/t7513-interpret-trailers.sh
t/t7600-merge.sh
t/t9832-unshelve.sh
t/test-lib-functions.sh
transport-helper.c
transport.c
unicode-width.h
upload-pack.c
url.c
worktree.c
wrapper.c
xdiff/xemit.c
index 41d4cd23fd97f599053a19555a173894da71e560..c592dda681fecfaa6bf64fb3f539eafaf4123ed8 100644 (file)
@@ -148,8 +148,21 @@ SpacesInSquareBrackets: false
 Cpp11BracedListStyle: false
 
 # A list of macros that should be interpreted as foreach loops instead of as
-# function calls.
-ForEachMacros: ['for_each_string_list_item', 'for_each_wanted_builtin', 'for_each_builtin', 'for_each_ut']
+# function calls. Taken from:
+#   git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' \
+#   | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$,  - '\1'," \
+#   | sort | uniq
+ForEachMacros:
+  - 'for_each_abbrev'
+  - 'for_each_builtin'
+  - 'for_each_string_list_item'
+  - 'for_each_ut'
+  - 'for_each_wanted_builtin'
+  - 'list_for_each'
+  - 'list_for_each_dir'
+  - 'list_for_each_prev'
+  - 'list_for_each_prev_safe'
+  - 'list_for_each_safe'
 
 # The maximum number of consecutive empty lines to keep.
 MaxEmptyLinesToKeep: 1
index 32210a4386c32972b7c4dbfa36b0cf977dd85de2..f45db5b72740b692a87a050271f5930743e4c4aa 100644 (file)
@@ -195,10 +195,30 @@ For C programs:
    by e.g. "echo DEVELOPER=1 >>config.mak".
 
  - We try to support a wide range of C compilers to compile Git with,
-   including old ones. That means that you should not use C99
-   initializers, even if a lot of compilers grok it.
+   including old ones.  You should not use features from newer C
+   standard, even if your compiler groks them.
 
- - Variables have to be declared at the beginning of the block.
+   There are a few exceptions to this guideline:
+
+   . since early 2012 with e1327023ea, we have been using an enum
+     definition whose last element is followed by a comma.  This, like
+     an array initializer that ends with a trailing comma, can be used
+     to reduce the patch noise when adding a new identifer at the end.
+
+   . since mid 2017 with cbc0f81d, we have been using designated
+     initializers for struct (e.g. "struct t v = { .val = 'a' };").
+
+   . since mid 2017 with 512f41cf, we have been using designated
+     initializers for array (e.g. "int array[10] = { [5] = 2 }").
+
+   These used to be forbidden, but we have not heard any breakage
+   report, and they are assumed to be safe.
+
+ - Variables have to be declared at the beginning of the block, before
+   the first statement (i.e. -Wdeclaration-after-statement).
+
+ - Declaring a variable in the for loop "for (int i = 0; i < 10; i++)"
+   is still not allowed in this codebase.
 
  - NULL pointers shall be written as NULL, not as 0.
 
@@ -412,6 +432,12 @@ For C programs:
    must be declared with "extern" in header files. However, function
    declarations should not use "extern", as that is already the default.
 
+ - You can launch gdb around your program using the shorthand GIT_DEBUGGER.
+   Run `GIT_DEBUGGER=1 ./bin-wrappers/git foo` to simply use gdb as is, or
+   run `GIT_DEBUGGER="<debugger> <debugger-args>" ./bin-wrappers/git foo` to
+   use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb"
+   ./bin-wrappers/git log` (See `wrap-for-bin.sh`.)
+
 For Perl programs:
 
  - Most of the C guidelines above apply.
diff --git a/Documentation/RelNotes/2.22.1.txt b/Documentation/RelNotes/2.22.1.txt
new file mode 100644 (file)
index 0000000..76dd8fb
--- /dev/null
@@ -0,0 +1,147 @@
+Git 2.22.1 Release Notes
+========================
+
+Fixes since v2.22
+-----------------
+
+ * A relative pathname given to "git init --template=<path> <repo>"
+   ought to be relative to the directory "git init" gets invoked in,
+   but it instead was made relative to the repository, which has been
+   corrected.
+
+ * "git worktree add" used to fail when another worktree connected to
+   the same repository was corrupt, which has been corrected.
+
+ * The ownership rule for the file descriptor to fast-import remote
+   backend was mixed up, leading to unrelated file descriptor getting
+   closed, which has been fixed.
+
+ * "git update-server-info" used to leave stale packfiles in its
+   output, which has been corrected.
+
+ * The server side support for "git fetch" used to show incorrect
+   value for the HEAD symbolic ref when the namespace feature is in
+   use, which has been corrected.
+
+ * "git am -i --resolved" segfaulted after trying to see a commit as
+   if it were a tree, which has been corrected.
+
+ * "git bundle verify" needs to see if prerequisite objects exist in
+   the receiving repository, but the command did not check if we are
+   in a repository upfront, which has been corrected.
+
+ * "git merge --squash" is designed to update the working tree and the
+   index without creating the commit, and this cannot be countermanded
+   by adding the "--commit" option; the command now refuses to work
+   when both options are given.
+
+ * The data collected by fsmonitor was not properly written back to
+   the on-disk index file, breaking t7519 tests occasionally, which
+   has been corrected.
+
+ * Update to Unicode 12.1 width table.
+
+ * The command line to invoke a "git cat-file" command from inside
+   "git p4" was not properly quoted to protect a caret and running a
+   broken command on Windows, which has been corrected.
+
+ * "git request-pull" learned to warn when the ref we ask them to pull
+   from in the local repository and in the published repository are
+   different.
+
+ * When creating a partial clone, the object filtering criteria is
+   recorded for the origin of the clone, but this incorrectly used a
+   hardcoded name "origin" to name that remote; it has been corrected
+   to honor the "--origin <name>" option.
+
+ * "git fetch" into a lazy clone forgot to fetch base objects that are
+   necessary to complete delta in a thin packfile, which has been
+   corrected.
+
+ * The filter_data used in the list-objects-filter (which manages a
+   lazily sparse clone repository) did not use the dynamic array API
+   correctly---'nr' is supposed to point at one past the last element
+   of the array in use.  This has been corrected.
+
+ * The description about slashes in gitignore patterns (used to
+   indicate things like "anchored to this level only" and "only
+   matches directories") has been revamped.
+
+ * The URL decoding code has been updated to avoid going past the end
+   of the string while parsing %-<hex>-<hex> sequence.
+
+ * The list of for-each like macros used by clang-format has been
+   updated.
+
+ * "git push --atomic" that goes over the transport-helper (namely,
+   the smart http transport) failed to prevent refs to be pushed when
+   it can locally tell that one of the ref update will fail without
+   having to consult the other end, which has been corrected.
+
+ * "git clean" silently skipped a path when it cannot lstat() it; now
+   it gives a warning.
+
+ * A codepath that reads from GPG for signed object verification read
+   past the end of allocated buffer, which has been fixed.
+
+ * "git rm" to resolve a conflicted path leaked an internal message
+   "needs merge" before actually removing the path, which was
+   confusing.  This has been corrected.
+
+ * The "git clone" documentation refers to command line options in its
+   description in the short form; they have been replaced with long
+   forms to make them more recognisable.
+
+ * The configuration variable rebase.rescheduleFailedExec should be
+   effective only while running an interactive rebase and should not
+   affect anything when running a non-interactive one, which was not
+   the case.  This has been corrected.
+
+ * "git submodule foreach" did not protect command line options passed
+   to the command to be run in each submodule correctly, when the
+   "--recursive" option was in use.
+
+ * Use "Erase in Line" CSI sequence that is already used in the editor
+   support to clear cruft in the progress output.
+
+ * The codepath to compute delta islands used to spew progress output
+   without giving the callers any way to squelch it, which has been
+   fixed.
+
+ * The code to parse scaled numbers out of configuration files has
+   been made more robust and also easier to follow.
+
+ * An incorrect list of options was cached after command line
+   completion failed (e.g. trying to complete a command that requires
+   a repository outside one), which has been corrected.
+
+ * "git rebase --abort" used to leave refs/rewritten/ when concluding
+   "git rebase -r", which has been corrected.
+
+ * "git stash show 23" used to work, but no more after getting
+   rewritten in C; this regression has been corrected.
+
+ * "git interpret-trailers" always treated '#' as the comment
+   character, regardless of core.commentChar setting, which has been
+   corrected.
+
+ * Code clean-up to avoid signed integer overlaps during binary search.
+
+ * "git checkout -p" needs to selectively apply a patch in reverse,
+   which did not work well.
+
+ * The commit-graph file is now part of the "files that the runtime
+   may keep open file descriptors on, all of which would need to be
+   closed when done with the object store", and the file descriptor to
+   an existing commit-graph file now is closed before "gc" finalizes a
+   new instance to replace it.
+
+ * Code restructuring during 2.20 period broke fetching tags via
+   "import" based transports.
+
+ * We have been trying out a few language features outside c89; the
+   coding guidelines document did not talk about them and instead had
+   a blanket ban against them.
+
+
+Also contains various documentation updates, code clean-ups and minor fixups.
index 0b14178314251a9b43c62bc5f85a4c1cc445fd1a..f1ca739d574293fd001322a2cc272e2cc0510344 100644 (file)
@@ -1,18 +1,28 @@
 alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
-       after defining "alias.last = cat-file commit HEAD", the invocation
-       "git last" is equivalent to "git cat-file commit HEAD". To avoid
+       after defining `alias.last = cat-file commit HEAD`, the invocation
+       `git last` is equivalent to `git cat-file commit HEAD`. To avoid
        confusion and troubles with script usage, aliases that
        hide existing Git commands are ignored. Arguments are split by
        spaces, the usual shell quoting and escaping is supported.
        A quote pair or a backslash can be used to quote them.
 +
+Note that the first word of an alias does not necessarily have to be a
+command. It can be a command-line option that will be passed into the
+invocation of `git`. In particular, this is useful when used with `-c`
+to pass in one-time configurations or `-p` to force pagination. For example,
+`loud-rebase = -c commit.verbose=true rebase` can be defined such that
+running `git loud-rebase` would be equivalent to
+`git -c commit.verbose=true rebase`. Also, `ps = -p status` would be a
+helpful alias since `git ps` would paginate the output of `git status`
+where the original command does not.
++
 If the alias expansion is prefixed with an exclamation point,
 it will be treated as a shell command.  For example, defining
-"alias.new = !gitk --all --not ORIG_HEAD", the invocation
-"git new" is equivalent to running the shell command
-"gitk --all --not ORIG_HEAD".  Note that shell commands will be
+`alias.new = !gitk --all --not ORIG_HEAD`, the invocation
+`git new` is equivalent to running the shell command
+`gitk --all --not ORIG_HEAD`.  Note that shell commands will be
 executed from the top-level directory of a repository, which may
 not necessarily be the current directory.
-`GIT_PREFIX` is set as returned by running 'git rev-parse --show-prefix'
+`GIT_PREFIX` is set as returned by running `git rev-parse --show-prefix`
 from the original current directory. See linkgit:git-rev-parse[1].
index f999f8ea491d0238abaca2037535c0374f28bc01..cce2c8924598c240fcebfadea8be5b4b28ce378e 100644 (file)
@@ -2,7 +2,7 @@ gpg.program::
        Use this custom program instead of "`gpg`" found on `$PATH` when
        making or verifying a PGP signature. The program must support the
        same command-line interface as GPG, namely, to verify a detached
-       signature, "`gpg --verify $file - <$signature`" is run, and the
+       signature, "`gpg --verify $signature - <$file`" is run, and the
        program is expected to signal a good signature by exiting with
        code 0, and to generate an ASCII-armored detached signature, the
        standard input of "`gpg -bsau $key`" is fed with the contents to be
index 6ebd512b4f3344c2f166f5bb09f0b5c6eb96ab03..d9325e2145441520c706c8d0a369d559e841eb19 100644 (file)
@@ -8,12 +8,15 @@ git-branch - List, create, or delete branches
 SYNOPSIS
 --------
 [verse]
-'git branch' [--color[=<when>] | --no-color] [-r | -a]
-       [--list] [--show-current] [-v [--abbrev=<length> | --no-abbrev]]
+'git branch' [--color[=<when>] | --no-color]
+       [-v [--abbrev=<length> | --no-abbrev]]
+       [--show-current]
        [--column[=<options>] | --no-column] [--sort=<key>]
        [(--merged | --no-merged) [<commit>]]
        [--contains [<commit]] [--no-contains [<commit>]]
-       [--points-at <object>] [--format=<format>] [<pattern>...]
+       [--points-at <object>] [--format=<format>]
+       [(-r | --remotes) | (-a | --all)]
+       [--list] [<pattern>...]
 'git branch' [--track | --no-track] [-f] <branchname> [<start-point>]
 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
 'git branch' --unset-upstream [<branchname>]
@@ -28,11 +31,15 @@ DESCRIPTION
 If `--list` is given, or if there are no non-option arguments, existing
 branches are listed; the current branch will be highlighted with an
 asterisk.  Option `-r` causes the remote-tracking branches to be listed,
-and option `-a` shows both local and remote branches. If a `<pattern>`
+and option `-a` shows both local and remote branches.
+
+If a `<pattern>`
 is given, it is used as a shell wildcard to restrict the output to
 matching branches. If multiple patterns are given, a branch is shown if
-it matches any of the patterns.  Note that when providing a
-`<pattern>`, you must use `--list`; otherwise the command is interpreted
+it matches any of the patterns.
+
+Note that when providing a
+`<pattern>`, you must use `--list`; otherwise the command may be interpreted
 as branch creation.
 
 With `--contains`, shows only the branches that contain the named commit
@@ -153,10 +160,12 @@ This option is only applicable in non-verbose mode.
 -r::
 --remotes::
        List or delete (if used with -d) the remote-tracking branches.
+       Combine with `--list` to match the optional pattern(s).
 
 -a::
 --all::
        List both remote-tracking branches and local branches.
+       Combine with `--list` to match optional pattern(s).
 
 -l::
 --list::
@@ -322,6 +331,18 @@ $ git branch -D test                                    <2>
 <2> Delete the "test" branch even if the "master" branch (or whichever branch
     is currently checked out) does not have all commits from the test branch.
 
+Listing branches from a specific remote::
++
+------------
+$ git branch -r -l '<remote>/<pattern>'                 <1>
+$ git for-each-ref 'refs/remotes/<remote>/<pattern>'    <2>
+------------
++
+<1> Using `-a` would conflate <remote> with any local branches you happen to
+    have been prefixed with the same <remote> pattern.
+<2> `for-each-ref` can take a wide range of options. See linkgit:git-for-each-ref[1]
+
+Patterns will normally need quoting.
 
 NOTES
 -----
index a0f14b51f2654ced2fb7f76078d95050d2730a7d..ca8871c165bffa25e5d7500918ef15415f0c3e41 100644 (file)
@@ -22,7 +22,7 @@ DESCRIPTION
 
 Clones a repository into a newly created directory, creates
 remote-tracking branches for each branch in the cloned repository
-(visible using `git branch -r`), and creates and checks out an
+(visible using `git branch --remotes`), and creates and checks out an
 initial branch that is forked from the cloned repository's
 currently active branch.
 
@@ -40,8 +40,8 @@ configuration variables.
 
 OPTIONS
 -------
---local::
 -l::
+--local::
        When the repository to clone from is on a local machine,
        this flag bypasses the normal "Git aware" transport
        mechanism and clones the repository by making a copy of
@@ -62,8 +62,8 @@ Git transport instead.
        directory instead of using hardlinks. This may be desirable
        if you are trying to make a back-up of your repository.
 
---shared::
 -s::
+--shared::
        When the repository to clone is on the local machine,
        instead of using hard links, automatically setup
        `.git/objects/info/alternates` to share the objects
@@ -80,13 +80,13 @@ which automatically call `git gc --auto`. (See linkgit:git-gc[1].)
 If these objects are removed and were referenced by the cloned repository,
 then the cloned repository will become corrupt.
 +
-Note that running `git repack` without the `-l` option in a repository
-cloned with `-s` will copy objects from the source repository into a pack
-in the cloned repository, removing the disk space savings of `clone -s`.
-It is safe, however, to run `git gc`, which uses the `-l` option by
+Note that running `git repack` without the `--local` option in a repository
+cloned with `--shared` will copy objects from the source repository into a pack
+in the cloned repository, removing the disk space savings of `clone --shared`.
+It is safe, however, to run `git gc`, which uses the `--local` option by
 default.
 +
-If you want to break the dependency of a repository cloned with `-s` on
+If you want to break the dependency of a repository cloned with `--shared` on
 its source repository, you can simply run `git repack -a` to copy all
 objects from the source repository into a pack in the cloned repository.
 
@@ -115,19 +115,19 @@ objects from the source repository into a pack in the cloned repository.
        same repository, and this option can be used to stop the
        borrowing.
 
---quiet::
 -q::
+--quiet::
        Operate quietly.  Progress is not reported to the standard
        error stream.
 
---verbose::
 -v::
+--verbose::
        Run verbosely. Does not affect the reporting of progress status
        to the standard error stream.
 
 --progress::
        Progress status is reported on the standard error stream
-       by default when it is attached to a terminal, unless -q
+       by default when it is attached to a terminal, unless `--quiet`
        is specified. This flag forces progress status even if the
        standard error stream is not directed to a terminal.
 
@@ -139,15 +139,15 @@ objects from the source repository into a pack in the cloned repository.
        When multiple `--server-option=<option>` are given, they are all
        sent to the other side in the order listed on the command line.
 
---no-checkout::
 -n::
+--no-checkout::
        No checkout of HEAD is performed after the clone is complete.
 
 --bare::
        Make a 'bare' Git repository.  That is, instead of
        creating `<directory>` and placing the administrative
        files in `<directory>/.git`, make the `<directory>`
-       itself the `$GIT_DIR`. This obviously implies the `-n`
+       itself the `$GIT_DIR`. This obviously implies the `--no-checkout`
        because there is nowhere to check out the working tree.
        Also the branch heads at the remote are copied directly
        to corresponding local branch heads, without mapping
@@ -163,13 +163,13 @@ objects from the source repository into a pack in the cloned repository.
        that all these refs are overwritten by a `git remote update` in the
        target repository.
 
---origin <name>::
 -o <name>::
+--origin <name>::
        Instead of using the remote name `origin` to keep track
        of the upstream repository, use `<name>`.
 
---branch <name>::
 -b <name>::
+--branch <name>::
        Instead of pointing the newly created HEAD to the branch pointed
        to by the cloned repository's HEAD, point to `<name>` branch
        instead. In a non-bare repository, this is the branch that will
@@ -177,8 +177,8 @@ objects from the source repository into a pack in the cloned repository.
        `--branch` can also take tags and detaches the HEAD at that commit
        in the resulting repository.
 
---upload-pack <upload-pack>::
 -u <upload-pack>::
+--upload-pack <upload-pack>::
        When given, and the repository to clone from is accessed
        via ssh, this specifies a non-default path for the command
        run on the other end.
@@ -187,8 +187,8 @@ objects from the source repository into a pack in the cloned repository.
        Specify the directory from which templates will be used;
        (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
 
---config <key>=<value>::
 -c <key>=<value>::
+--config <key>=<value>::
        Set a configuration variable in the newly-created repository;
        this takes effect immediately after the repository is
        initialized, but before the remote history is fetched or any
index e0eae642c10f75cff57c0a9d07420e3218235423..d72d15be5babb2a108cf37e8ae396ae587baf1cf 100644 (file)
@@ -104,6 +104,11 @@ care about this output and want to speed it up further.
        progress status even if the standard error stream is not
        directed to a terminal.
 
+CONFIGURATION
+-------------
+
+include::config/fsck.txt[]
+
 DISCUSSION
 ----------
 
index 814e74406ae4fb6ac68213df1f7e8e0192d1dbaf..df9e2c58bdbc5f31edaf25577df744868e16f3de 100644 (file)
@@ -18,9 +18,7 @@ Computes the object ID value for an object with specified type
 with the contents of the named file (which can be outside of the
 work tree), and optionally writes the resulting object into the
 object database.  Reports its object ID to its standard output.
-This is used by 'git cvsimport' to update the index
-without modifying files in the work tree.  When <type> is not
-specified, it defaults to "blob".
+When <type> is not specified, it defaults to "blob".
 
 OPTIONS
 -------
index 1afe9fc858ea7dcd05ae5f77c994af8f17f5bf52..504ae7fe76e0f608934095d074100e561409a5b3 100644 (file)
@@ -500,8 +500,12 @@ app-specific or your regular password as appropriate.  If you have credential
 helper configured (see linkgit:git-credential[1]), the password will be saved in
 the credential store so you won't have to type it the next time.
 
-Note: the following perl modules are required
-      Net::SMTP::SSL, MIME::Base64 and Authen::SASL
+Note: the following core Perl modules that may be installed with your
+distribution of Perl are required:
+MIME::Base64, MIME::QuotedPrint, Net::Domain and Net::SMTP.
+These additional Perl modules are also required:
+Authen::SASL and Mail::Address.
+
 
 SEE ALSO
 --------
index 6ddc1e2ca6830ac165543dad4a57afd6d4b50c49..81f7ecd52c959f74f5b78b45d34ea0c9b041a966 100644 (file)
@@ -56,7 +56,8 @@ help ...`.
        Run as if git was started in '<path>' instead of the current working
        directory.  When multiple `-C` options are given, each subsequent
        non-absolute `-C <path>` is interpreted relative to the preceding `-C
-       <path>`.
+       <path>`.  If '<path>' is present but empty, e.g. `-C ""`, then the
+       current working directory is left unchanged.
 +
 This option affects options that expect path name like `--git-dir` and
 `--work-tree` in that their interpretations of the path names would be
index b5bc9dbff05b293caae7c42e865b19bc067c4d82..d47b1ae29637269859bc7f41d0fc49732c8f39aa 100644 (file)
@@ -89,28 +89,28 @@ PATTERN FORMAT
    Put a backslash ("`\`") in front of the first "`!`" for patterns
    that begin with a literal "`!`", for example, "`\!important!.txt`".
 
- - If the pattern ends with a slash, it is removed for the
-   purpose of the following description, but it would only find
-   a match with a directory.  In other words, `foo/` will match a
-   directory `foo` and paths underneath it, but will not match a
-   regular file or a symbolic link `foo` (this is consistent
-   with the way how pathspec works in general in Git).
-
- - If the pattern does not contain a slash '/', Git treats it as
-   a shell glob pattern and checks for a match against the
-   pathname relative to the location of the `.gitignore` file
-   (relative to the toplevel of the work tree if not from a
-   `.gitignore` file).
-
- - Otherwise, Git treats the pattern as a shell glob: "`*`" matches
-   anything except "`/`", "`?`" matches any one character except "`/`"
-   and "`[]`" matches one character in a selected range. See
-   fnmatch(3) and the FNM_PATHNAME flag for a more detailed
  description.
-
- - A leading slash matches the beginning of the pathname.
-   For example, "/{asterisk}.c" matches "cat-file.c" but not
-   "mozilla-sha1/sha1.c".
+ - The slash '/' is used as the directory separator. Separators may
+   occur at the beginning, middle or end of the `.gitignore` search pattern.
+
+ - If there is a separator at the beginning or middle (or both) of the
+   pattern, then the pattern is relative to the directory level of the
+   particular `.gitignore` file itself. Otherwise the pattern may also
+   match at any level below the `.gitignore` level.
+
+ - If there is a separator at the end of the pattern then the pattern
+   will only match directories, otherwise the pattern can match both
+   files and directories.
+
+ - For example, a pattern `doc/frotz/` matches `doc/frotz` directory,
+   but not `a/doc/frotz` directory; however `frotz/` matches `frotz`
+   and `a/frotz` that is a directory (all paths are relative from
+   the `.gitignore` file).
+
- An asterisk "`*`" matches anything except a slash.
+   The character "`?`" matches any one character except "`/`".
+   The range notation, e.g. `[a-zA-Z]`, can be used to match
+   one of the characters in a range. See fnmatch(3) and the
+   FNM_PATHNAME flag for a more detailed description.
 
 Two consecutive asterisks ("`**`") in patterns matched against
 full pathname may have special meaning:
@@ -152,6 +152,28 @@ To stop tracking a file that is currently tracked, use
 EXAMPLES
 --------
 
+ - The pattern `hello.*` matches any file or folder
+   whose name begins with `hello`. If one wants to restrict
+   this only to the directory and not in its subdirectories,
+   one can prepend the pattern with a slash, i.e. `/hello.*`;
+   the pattern now matches `hello.txt`, `hello.c` but not
+   `a/hello.java`.
+
+ - The pattern `foo/` will match a directory `foo` and
+   paths underneath it, but will not match a regular file
+   or a symbolic link `foo` (this is consistent with the
+   way how pathspec works in general in Git)
+
+ - The pattern `doc/frotz` and `/doc/frotz` have the same effect
+   in any `.gitignore` file. In other words, a leading slash
+   is not relevant  if there is already a middle slash in
+   the pattern.
+
+ - The pattern "foo/*", matches "foo/test.json"
+   (a regular file), "foo/bar" (a directory), but it does not match
+   "foo/bar/hello.c" (a regular file), as the asterisk in the
+   pattern does not match "bar/hello.c" which has a slash in it.
+
 --------------------------------------------------------------
     $ git status
     [...]
index c7436098c9596f221fc9553c1af7f8a599c6301c..3cc9b034c435a555f96eb7943932045ec2b9bcc8 100644 (file)
@@ -28,8 +28,7 @@ Gitweb provides a web interface to Git repositories.  Its features include:
   revisions one at a time, viewing the history of the repository.
 * Finding commits which commit messages matches given search term.
 
-See http://git.kernel.org/?p=git/git.git;a=tree;f=gitweb[] or
-http://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
+See http://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
 browsed using gitweb itself.
 
 
index 61876dbc335e240b8842aba3dd4e3fd8a54e574a..79a00d2a4abd6f7191f2639185e199fa85f6289b 100644 (file)
@@ -102,6 +102,8 @@ merge.
 +
 With --no-squash perform the merge and commit the result. This
 option can be used to override --squash.
++
+With --squash, --commit is not allowed, and will fail.
 
 -s <strategy>::
 --strategy=<strategy>::
index 23c3cc7a3727ed88513c1e735a41654a75334363..fd1e6289447050c39dcc993c552196c24c21b6e9 100644 (file)
@@ -668,7 +668,7 @@ completed.)
        "event":"signal",
        ...
        "t_abs":0.001227,  # elapsed time in seconds
-       "signal":13        # SIGTERM, SIGINT, etc.
+       "signo":13         # SIGTERM, SIGINT, etc.
 }
 ------------
 
index 7805b0968c828fda1601fe00c2b5b9d9359b38e2..fb53341d5ee3116361d599b5aca2e5ea3a228589 100644 (file)
@@ -127,23 +127,6 @@ Design Details
   helpful for these clones, anyway. The commit-graph will not be read or
   written when shallow commits are present.
 
-Future Work
------------
-
-- After computing and storing generation numbers, we must make graph
-  walks aware of generation numbers to gain the performance benefits they
-  enable. This will mostly be accomplished by swapping a commit-date-ordered
-  priority queue with one ordered by generation number. The following
-  operations are important candidates:
-
-    - 'log --topo-order'
-    - 'tag --merged'
-
-- A server could provide a commit-graph file as part of the network protocol
-  to avoid extra calculations by clients. This feature is only of benefit if
-  the user is willing to trust the file, because verifying the file is correct
-  is as hard as computing it from scratch.
-
 Related Links
 -------------
 [0] https://bugs.chromium.org/p/git/issues/detail?id=8
index 88f126184c52bfe4859ec189d018872902e02a84..e1d2b82209bb6d9aab0c86ca89d486c48bfc71f5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ including full documentation and Git related tools.
 
 See [Documentation/gittutorial.txt][] to get started, then see
 [Documentation/giteveryday.txt][] for a useful minimum set of commands, and
-Documentation/git-<commandname>.txt for documentation of each command.
+`Documentation/git-<commandname>.txt` for documentation of each command.
 If git has been correctly installed, then the tutorial can also be
 read with `man gittutorial` or `git help tutorial`, and the
 documentation of each command with `man git-<commandname>` or `git help
index 0b6d9fdbcf0cc440914446e494fde666c893562f..30cbde7a54991c577d1cfc35ad53faf549b32397 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.22.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.22.1.txt
\ No newline at end of file
diff --git a/apply.c b/apply.c
index f15afa9f6af98ae41af60eb2296ee35d38ccc7fd..4992eca416c9c2b5d21de42460cafa839df25f4e 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -4310,7 +4310,7 @@ static int add_index_file(struct apply_state *state,
                                                     "created file '%s'"),
                                                   path);
                        }
-                       fill_stat_cache_info(ce, &st);
+                       fill_stat_cache_info(state->repo->index, ce, &st);
                }
                if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
                        discard_cache_entry(ce);
index 912d9821b18acfa0a4c1e3bed8e6c9e7b43dcdf8..252e37ddf08e45eceb98628fe598df3ebcafb1fd 100644 (file)
@@ -1339,9 +1339,10 @@ static void write_index_patch(const struct am_state *state)
        struct rev_info rev_info;
        FILE *fp;
 
-       if (!get_oid_tree("HEAD", &head))
-               tree = lookup_tree(the_repository, &head);
-       else
+       if (!get_oid("HEAD", &head)) {
+               struct commit *commit = lookup_commit_or_die(&head, "HEAD");
+               tree = get_commit_tree(commit);
+       } else
                tree = lookup_tree(the_repository,
                                   the_repository->hash_algo->empty_tree);
 
@@ -1643,11 +1644,8 @@ static int do_interactive(struct am_state *state)
 {
        assert(state->msg);
 
-       if (!isatty(0))
-               die(_("cannot be interactive without stdin connected to a terminal."));
-
        for (;;) {
-               const char *reply;
+               char reply[64];
 
                puts(_("Commit Body is:"));
                puts("--------------------------");
@@ -1659,11 +1657,11 @@ static int do_interactive(struct am_state *state)
                 * in your translation. The program will only accept English
                 * input at this point.
                 */
-               reply = git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);
+               printf(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "));
+               if (!fgets(reply, sizeof(reply), stdin))
+                       die("unable to read from stdin; aborting");
 
-               if (!reply) {
-                       continue;
-               } else if (*reply == 'y' || *reply == 'Y') {
+               if (*reply == 'y' || *reply == 'Y') {
                        return 0;
                } else if (*reply == 'a' || *reply == 'A') {
                        state->interactive = 0;
@@ -1803,7 +1801,7 @@ static void am_run(struct am_state *state, int resume)
         */
        if (!state->rebasing) {
                am_destroy(state);
-               close_all_packs(the_repository->objects);
+               close_object_store(the_repository->objects);
                run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        }
 }
@@ -2334,6 +2332,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                                argv_array_push(&paths, mkpath("%s/%s", prefix, argv[i]));
                }
 
+               if (state.interactive && !paths.argc)
+                       die(_("interactive mode requires patches on the command line"));
+
                am_setup(&state, patch_format, paths.argv, keep_cr);
 
                argv_array_clear(&paths);
index e7325fe37f6148fd1ccd6fc5842bbc8f5022c306..1fbe156e67a4c75694de7e606a21cf959dd19f51 100644 (file)
@@ -570,7 +570,10 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
        write_file(git_path_bisect_start(), "%s\n", start_head.buf);
 
        if (no_checkout) {
-               get_oid(start_head.buf, &oid);
+               if (get_oid(start_head.buf, &oid) < 0) {
+                       retval = error(_("invalid ref: '%s'"), start_head.buf);
+                       goto finish;
+               }
                if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
                               UPDATE_REFS_MSG_ON_ERR)) {
                        retval = -1;
index d4359b33ac0fb27b6b8be7109a2a862bc9cd2d77..8e243cf8c2fe094ec332150761f7434287d6e96b 100644 (file)
@@ -830,7 +830,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                strbuf_release(&buf);
        } else if (argc > 0 && argc <= 2) {
                if (filter.kind != FILTER_REFS_BRANCHES)
-                       die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
+                       die(_("The -a, and -r, options to 'git branch' do not take a branch name.\n"
+                                 "Did you mean to use: -a|-r --list <pattern>?"));
 
                if (track == BRANCH_TRACK_OVERRIDE)
                        die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
index aaba4af3c26de2150ad655a0b162fc85a69a466d..d5579da716e06f372132f827852b0f49f1e4af1d 100644 (file)
@@ -34,6 +34,7 @@ static const char *msg_would_remove = N_("Would remove %s\n");
 static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 static const char *msg_warn_remove_failed = N_("failed to remove %s");
+static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
 
 enum color_clean {
        CLEAN_COLOR_RESET = 0,
@@ -194,7 +195,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
                strbuf_setlen(path, len);
                strbuf_addstr(path, e->d_name);
                if (lstat(path->buf, &st))
-                       ; /* fall thru */
+                       warning_errno(_(msg_warn_lstat_failed), path->buf);
                else if (S_ISDIR(st.st_mode)) {
                        if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
                                ret = 1;
index 85b0d3155de0d9ee9257ac44acc699c004022836..3623f040d4086458b8e36e5e701d892c1d426078 100644 (file)
@@ -1220,7 +1220,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                        remote_head_points_at, &branch_top);
 
        if (filter_options.choice)
-               partial_clone_register("origin", &filter_options);
+               partial_clone_register(option_origin, &filter_options);
 
        if (is_local)
                clone_local(path, git_dir);
@@ -1245,7 +1245,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        transport_disconnect(transport);
 
        if (option_dissociate) {
-               close_all_packs(the_repository->objects);
+               close_object_store(the_repository->objects);
                dissociate_from_references();
        }
 
index 537fdfd0f0759e8cce2303af5a197ae77b2b879b..d8efa5bab276a816bef48e9cb3891ccc0cb81aad 100644 (file)
@@ -141,6 +141,8 @@ static int graph_write(int argc, const char **argv)
        struct string_list *pack_indexes = NULL;
        struct string_list *commit_hex = NULL;
        struct string_list lines;
+       int result = 0;
+       unsigned int flags = COMMIT_GRAPH_PROGRESS;
 
        static struct option builtin_commit_graph_write_options[] = {
                OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -165,13 +167,13 @@ static int graph_write(int argc, const char **argv)
                die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
        if (!opts.obj_dir)
                opts.obj_dir = get_object_directory();
+       if (opts.append)
+               flags |= COMMIT_GRAPH_APPEND;
 
        read_replace_refs = 0;
 
-       if (opts.reachable) {
-               write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
-               return 0;
-       }
+       if (opts.reachable)
+               return write_commit_graph_reachable(opts.obj_dir, flags);
 
        string_list_init(&lines, 0);
        if (opts.stdin_packs || opts.stdin_commits) {
@@ -188,14 +190,14 @@ static int graph_write(int argc, const char **argv)
                UNLEAK(buf);
        }
 
-       write_commit_graph(opts.obj_dir,
-                          pack_indexes,
-                          commit_hex,
-                          opts.append,
-                          1);
+       if (write_commit_graph(opts.obj_dir,
+                              pack_indexes,
+                              commit_hex,
+                              flags))
+               result = 1;
 
        UNLEAK(lines);
-       return 0;
+       return result;
 }
 
 int cmd_commit_graph(int argc, const char **argv, const char *prefix)
index 1c9e8e2228c7ce58375bc247c4ad5850a1bd7d2d..192140111747cc0683c1ae19a785000110808ff3 100644 (file)
@@ -1669,8 +1669,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                      "new_index file. Check that disk is not full and quota is\n"
                      "not exceeded, and then \"git reset HEAD\" to recover."));
 
-       if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
-               write_commit_graph_reachable(get_object_directory(), 0, 0);
+       if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
+           write_commit_graph_reachable(get_object_directory(), 0))
+               return 1;
 
        repo_rerere(the_repository, 0);
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
index 4ba63d5ac642844832a5c832cea93ddf99507764..c9b92b1e52448bb1537a229b3ed7d1587db28ecf 100644 (file)
@@ -239,6 +239,7 @@ static int will_fetch(struct ref **head, const unsigned char *sha1)
 struct refname_hash_entry {
        struct hashmap_entry ent; /* must be the first member */
        struct object_id oid;
+       int ignore;
        char refname[FLEX_ARRAY];
 };
 
@@ -287,6 +288,11 @@ static int refname_hash_exists(struct hashmap *map, const char *refname)
        return !!hashmap_get_from_hash(map, strhash(refname), refname);
 }
 
+static void clear_item(struct refname_hash_entry *item)
+{
+       item->ignore = 1;
+}
+
 static void find_non_local_tags(const struct ref *refs,
                                struct ref **head,
                                struct ref ***tail)
@@ -319,7 +325,7 @@ static void find_non_local_tags(const struct ref *refs,
                            !will_fetch(head, ref->old_oid.hash) &&
                            !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
                            !will_fetch(head, item->oid.hash))
-                               oidclr(&item->oid);
+                               clear_item(item);
                        item = NULL;
                        continue;
                }
@@ -333,7 +339,7 @@ static void find_non_local_tags(const struct ref *refs,
                if (item &&
                    !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
                    !will_fetch(head, item->oid.hash))
-                       oidclr(&item->oid);
+                       clear_item(item);
 
                item = NULL;
 
@@ -354,7 +360,7 @@ static void find_non_local_tags(const struct ref *refs,
        if (item &&
            !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
            !will_fetch(head, item->oid.hash))
-               oidclr(&item->oid);
+               clear_item(item);
 
        /*
         * For all the tags in the remote_refs_list,
@@ -362,19 +368,21 @@ static void find_non_local_tags(const struct ref *refs,
         */
        for_each_string_list_item(remote_ref_item, &remote_refs_list) {
                const char *refname = remote_ref_item->string;
+               struct ref *rm;
 
                item = hashmap_get_from_hash(&remote_refs, strhash(refname), refname);
                if (!item)
                        BUG("unseen remote ref?");
 
                /* Unless we have already decided to ignore this item... */
-               if (!is_null_oid(&item->oid)) {
-                       struct ref *rm = alloc_ref(item->refname);
-                       rm->peer_ref = alloc_ref(item->refname);
-                       oidcpy(&rm->old_oid, &item->oid);
-                       **tail = rm;
-                       *tail = &rm->next;
-               }
+               if (item->ignore)
+                       continue;
+
+               rm = alloc_ref(item->refname);
+               rm->peer_ref = alloc_ref(item->refname);
+               oidcpy(&rm->old_oid, &item->oid);
+               **tail = rm;
+               *tail = &rm->next;
        }
        hashmap_free(&remote_refs, 1);
        string_list_clear(&remote_refs_list, 0);
@@ -1672,7 +1680,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 
        string_list_clear(&list, 0);
 
-       close_all_packs(the_repository->objects);
+       close_object_store(the_repository->objects);
 
        argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
        if (verbosity < 0)
index 8943bcc300d4a2ce6786857908e189c374373906..be8e0bfcbe0a428f72c5762ff8a066baaefd2533 100644 (file)
@@ -653,7 +653,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        gc_before_repack();
 
        if (!repository_format_precious_objects) {
-               close_all_packs(the_repository->objects);
+               close_object_store(the_repository->objects);
                if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
                        die(FAILED_RUN, repack.argv[0]);
 
@@ -681,13 +681,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        report_garbage = report_pack_garbage;
        reprepare_packed_git(the_repository);
        if (pack_garbage.nr > 0) {
-               close_all_packs(the_repository->objects);
+               close_object_store(the_repository->objects);
                clean_pack_garbage();
        }
 
-       if (gc_write_commit_graph)
-               write_commit_graph_reachable(get_object_directory(), 0,
-                                            !quiet && !daemonized);
+       if (gc_write_commit_graph &&
+           write_commit_graph_reachable(get_object_directory(),
+                                        !quiet && !daemonized ? COMMIT_GRAPH_PROGRESS : 0))
+               return 1;
 
        if (auto_gc && too_many_loose_objects())
                warning(_("There are too many unreachable loose objects; "
index ccf4eb7e9b3361ee7eb209180d98ce8df757d92d..0d55f73b0b443b60dccc31096675d40691b3eb56 100644 (file)
@@ -14,6 +14,7 @@
 #include "thread-utils.h"
 #include "packfile.h"
 #include "object-store.h"
+#include "fetch-object.h"
 
 static const char index_pack_usage[] =
 "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -1351,6 +1352,25 @@ static void fix_unresolved_deltas(struct hashfile *f)
                sorted_by_pos[i] = &ref_deltas[i];
        QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
 
+       if (repository_format_partial_clone) {
+               /*
+                * Prefetch the delta bases.
+                */
+               struct oid_array to_fetch = OID_ARRAY_INIT;
+               for (i = 0; i < nr_ref_deltas; i++) {
+                       struct ref_delta_entry *d = sorted_by_pos[i];
+                       if (!oid_object_info_extended(the_repository, &d->oid,
+                                                     NULL,
+                                                     OBJECT_INFO_FOR_PREFETCH))
+                               continue;
+                       oid_array_append(&to_fetch, &d->oid);
+               }
+               if (to_fetch.nr)
+                       fetch_objects(repository_format_partial_clone,
+                                     to_fetch.oid, to_fetch.nr);
+               oid_array_clear(&to_fetch);
+       }
+
        for (i = 0; i < nr_ref_deltas; i++) {
                struct ref_delta_entry *d = sorted_by_pos[i];
                enum object_type type;
@@ -1650,8 +1670,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        int report_end_of_input = 0;
 
        /*
-        * index-pack never needs to fetch missing objects, since it only
-        * accesses the repo to do hash collision checks
+        * index-pack never needs to fetch missing objects except when
+        * REF_DELTA bases are missing (which are explicitly handled). It only
+        * accesses the repo to do hash collision checks and to check which
+        * REF_DELTA bases need to be fetched.
         */
        fetch_if_missing = 0;
 
index 6ca002893f47516ee8963db09d60b3716b60a205..944ec77fe1032775ff595f0b1eb99a1fb22d059f 100644 (file)
@@ -502,6 +502,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        if (real_git_dir && !is_absolute_path(real_git_dir))
                real_git_dir = real_pathdup(real_git_dir, 1);
 
+       if (template_dir && *template_dir && !is_absolute_path(template_dir))
+               template_dir = absolute_pathdup(template_dir);
+
        if (argc == 1) {
                int mkdir_tried = 0;
        retry:
index 8ae40dec4746571cf80d2f76bbad067c33a972fa..f101d092b883e6554cce193c66626b5707252c3f 100644 (file)
@@ -10,6 +10,7 @@
 #include "parse-options.h"
 #include "string-list.h"
 #include "trailer.h"
+#include "config.h"
 
 static const char * const git_interpret_trailers_usage[] = {
        N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
@@ -112,6 +113,8 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
+       git_config(git_default_config, NULL);
+
        argc = parse_options(argc, argv, prefix, options,
                             git_interpret_trailers_usage, 0);
 
index 7f83c9a6f26bd92e5e3832a8ea8d6ec44d5a5f5a..670e8fb93c9320686410cabb8938a106be8e8158 100644 (file)
@@ -373,7 +373,7 @@ static void prune_index(struct index_state *istate,
        first = pos;
        last = istate->cache_nr;
        while (last > first) {
-               int next = (last + first) >> 1;
+               int next = first + ((last - first) >> 1);
                const struct cache_entry *ce = istate->cache[next];
                if (!strncmp(ce->name, prefix, prefixlen)) {
                        first = next+1;
index e96f72af8044769df6b4ef42f0525b572b0c39e2..29988e54c5be5ecb3afa2382ba73a965e1d2b511 100644 (file)
@@ -58,7 +58,7 @@ static const char * const builtin_merge_usage[] = {
 };
 
 static int show_diffstat = 1, shortlog_len = -1, squash;
-static int option_commit = 1;
+static int option_commit = -1;
 static int option_edit = -1;
 static int allow_trivial = 1, have_message, verify_signatures;
 static int overwrite_ignore = 1;
@@ -457,7 +457,7 @@ static void finish(struct commit *head_commit,
                         * We ignore errors in 'gc --auto', since the
                         * user should see them.
                         */
-                       close_all_packs(the_repository->objects);
+                       close_object_store(the_repository->objects);
                        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
                }
        }
@@ -1339,9 +1339,19 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (squash) {
                if (fast_forward == FF_NO)
                        die(_("You cannot combine --squash with --no-ff."));
+               if (option_commit > 0)
+                       die(_("You cannot combine --squash with --commit."));
+               /*
+                * squash can now silently disable option_commit - this is not
+                * a problem as it is only overriding the default, not a user
+                * supplied option.
+                */
                option_commit = 0;
        }
 
+       if (option_commit < 0)
+               option_commit = 1;
+
        if (!argc) {
                if (default_to_upstream)
                        argc = setup_with_upstream(&argv);
index 41d7fc59830c090d8b0422980528e4ea429c9e6b..787ae1028844c9be009feaf487c7bc9ce5f46cee 100644 (file)
@@ -3134,7 +3134,7 @@ static void get_object_list(int ac, const char **av)
                return;
 
        if (use_delta_islands)
-               load_delta_islands(the_repository);
+               load_delta_islands(the_repository, progress);
 
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
index db6ca9bd7d4c4e9cdf58eb47fbfce2dda5b58497..2748fa6f2e91d2b788d5b54edfb15de29d8aa833 100644 (file)
@@ -738,20 +738,30 @@ static int finish_rebase(struct rebase_options *opts)
 {
        struct strbuf dir = STRBUF_INIT;
        const char *argv_gc_auto[] = { "gc", "--auto", NULL };
+       int ret = 0;
 
        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
        apply_autostash(opts);
-       close_all_packs(the_repository->objects);
+       close_object_store(the_repository->objects);
        /*
         * We ignore errors in 'gc --auto', since the
         * user should see them.
         */
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
-       strbuf_addstr(&dir, opts->state_dir);
-       remove_dir_recursively(&dir, 0);
-       strbuf_release(&dir);
+       if (opts->type == REBASE_INTERACTIVE) {
+               struct replay_opts replay = REPLAY_OPTS_INIT;
 
-       return 0;
+               replay.action = REPLAY_INTERACTIVE_REBASE;
+               ret = sequencer_remove_state(&replay);
+       } else {
+               strbuf_addstr(&dir, opts->state_dir);
+               if (remove_dir_recursively(&dir, 0))
+                       ret = error(_("could not remove '%s'"),
+                                   opts->state_dir);
+               strbuf_release(&dir);
+       }
+
+       return ret;
 }
 
 static struct commit *peel_committish(const char *name)
@@ -1384,6 +1394,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        struct string_list strategy_options = STRING_LIST_INIT_NODUP;
        struct object_id squash_onto;
        char *squash_onto_name = NULL;
+       int reschedule_failed_exec = -1;
        struct option builtin_rebase_options[] = {
                OPT_STRING(0, "onto", &options.onto_name,
                           N_("revision"),
@@ -1476,7 +1487,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "root", &options.root,
                         N_("rebase all reachable commits up to the root(s)")),
                OPT_BOOL(0, "reschedule-failed-exec",
-                        &options.reschedule_failed_exec,
+                        &reschedule_failed_exec,
                         N_("automatically re-schedule any `exec` that fails")),
                OPT_END(),
        };
@@ -1626,15 +1637,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        die(_("could not move back to %s"),
                            oid_to_hex(&options.orig_head));
                remove_branch_state(the_repository);
-               ret = finish_rebase(&options);
+               ret = !!finish_rebase(&options);
                goto cleanup;
        }
        case ACTION_QUIT: {
-               strbuf_reset(&buf);
-               strbuf_addstr(&buf, options.state_dir);
-               ret = !!remove_dir_recursively(&buf, 0);
-               if (ret)
-                       die(_("could not remove '%s'"), options.state_dir);
+               if (options.type == REBASE_INTERACTIVE) {
+                       struct replay_opts replay = REPLAY_OPTS_INIT;
+
+                       replay.action = REPLAY_INTERACTIVE_REBASE;
+                       ret = !!sequencer_remove_state(&replay);
+               } else {
+                       strbuf_reset(&buf);
+                       strbuf_addstr(&buf, options.state_dir);
+                       ret = !!remove_dir_recursively(&buf, 0);
+                       if (ret)
+                               error(_("could not remove '%s'"),
+                                      options.state_dir);
+               }
                goto cleanup;
        }
        case ACTION_EDIT_TODO:
@@ -1783,8 +1802,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                break;
        }
 
-       if (options.reschedule_failed_exec && !is_interactive(&options))
-               die(_("%s requires an interactive rebase"), "--reschedule-failed-exec");
+       if (reschedule_failed_exec > 0 && !is_interactive(&options))
+               die(_("--reschedule-failed-exec requires "
+                     "--exec or --interactive"));
+       if (reschedule_failed_exec >= 0)
+               options.reschedule_failed_exec = reschedule_failed_exec;
 
        if (options.git_am_opts.argc) {
                /* all am options except -q are compatible only with --am */
@@ -2146,6 +2168,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        ret = !!run_specific_rebase(&options, action);
 
 cleanup:
+       strbuf_release(&buf);
        strbuf_release(&revisions);
        free(options.head_name);
        free(options.gpg_sign_opt);
index 29f165d8bd3513a6f85667b070e8f157994364bb..c5f5da940b0dee3fd2df55e11514ee9553926e30 100644 (file)
@@ -2043,7 +2043,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                        proc.git_cmd = 1;
                        proc.argv = argv_gc_auto;
 
-                       close_all_packs(the_repository->objects);
+                       close_object_store(the_repository->objects);
                        if (!start_command(&proc)) {
                                if (use_sideband)
                                        copy_to_sideband(proc.err, -1, NULL);
index caca11392713eb92816d1e503f286bfe0d9be78a..f834b5551b1ffe003b943c18cd35397e9196e730 100644 (file)
@@ -422,7 +422,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (!names.nr && !po_args.quiet)
                printf_ln(_("Nothing new to pack."));
 
-       close_all_packs(the_repository->objects);
+       close_object_store(the_repository->objects);
 
        /*
         * Ok we have prepared all new packfiles.
index 90cbe896c99188130a36a18aa18a57cd080be591..bf4a443e1369c2ef6131e5ac34be30c5a5d5b19f 100644 (file)
@@ -273,7 +273,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        parse_pathspec(&pathspec, 0,
                       PATHSPEC_PREFER_CWD,
                       prefix, argv);
-       refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
+       refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
 
        seen = xcalloc(pathspec.nr, 1);
 
index 2a8e6d09b406345519201ef64f572197a409e7a4..fde6397caa16326912087215383506026d00ab79 100644 (file)
@@ -713,11 +713,11 @@ static int git_stash_config(const char *var, const char *value, void *cb)
 static int show_stash(int argc, const char **argv, const char *prefix)
 {
        int i;
-       int opts = 0;
        int ret = 0;
        struct stash_info info;
        struct rev_info rev;
        struct argv_array stash_args = ARGV_ARRAY_INIT;
+       struct argv_array revision_args = ARGV_ARRAY_INIT;
        struct option options[] = {
                OPT_END()
        };
@@ -726,11 +726,12 @@ static int show_stash(int argc, const char **argv, const char *prefix)
        git_config(git_diff_ui_config, NULL);
        init_revisions(&rev, prefix);
 
+       argv_array_push(&revision_args, argv[0]);
        for (i = 1; i < argc; i++) {
                if (argv[i][0] != '-')
                        argv_array_push(&stash_args, argv[i]);
                else
-                       opts++;
+                       argv_array_push(&revision_args, argv[i]);
        }
 
        ret = get_stash_info(&info, stash_args.argc, stash_args.argv);
@@ -742,7 +743,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
         * The config settings are applied only if there are not passed
         * any options.
         */
-       if (!opts) {
+       if (revision_args.argc == 1) {
                git_config(git_stash_config, NULL);
                if (show_stat)
                        rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
@@ -756,7 +757,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
                }
        }
 
-       argc = setup_revisions(argc, argv, &rev, NULL);
+       argc = setup_revisions(revision_args.argc, revision_args.argv, &rev, NULL);
        if (argc > 1) {
                free_stash_info(&info);
                usage_with_options(git_stash_show_usage, options);
index 0bf4aa088e0ca4bf6378d121cfc23e0f42ac3af4..afaf0819c981ff896bf6f0b843b594a660d85a97 100644 (file)
@@ -540,6 +540,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
                if (info->quiet)
                        argv_array_push(&cpr.args, "--quiet");
 
+               argv_array_push(&cpr.args, "--");
                argv_array_pushv(&cpr.args, info->argv);
 
                if (run_command(&cpr))
index 27db0928bf052b0c518bee57ffa7cdd6c03d5d85..3f8cc6ccb47c2f8927e91076a8844d2cfd8a0bb2 100644 (file)
@@ -280,7 +280,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = len;
-       fill_stat_cache_info(ce, st);
+       fill_stat_cache_info(&the_index, ce, st);
        ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
 
        if (index_path(&the_index, &ce->oid, path, st,
index b45666c49b1c19a63d816527a761d0177d9633ce..b5d21cd80f1cd009a8113ceb34c9a834ddbdbe3a 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -142,6 +142,9 @@ int verify_bundle(struct repository *r,
        int i, ret = 0, req_nr;
        const char *message = _("Repository lacks these prerequisite commits:");
 
+       if (!r || !r->objects || !r->objects->odb)
+               return error(_("need a repository to verify a bundle"));
+
        repo_init_revisions(r, &revs, NULL);
        for (i = 0; i < p->nr; i++) {
                struct ref_list_entry *e = p->list + i;
diff --git a/cache.h b/cache.h
index b4bb2e2c11adff0061065fa975874c7c4a2a318b..3e7cd0b4bc5528d00f3ec01d46db9e8a16d770e3 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -826,7 +826,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st);
 int match_stat_data_racy(const struct index_state *istate,
                         const struct stat_data *sd, struct stat *st);
 
-void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
+void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st);
 
 #define REFRESH_REALLY         0x0001  /* ignore_valid */
 #define REFRESH_UNMERGED       0x0002  /* allow unmerged */
@@ -1759,6 +1759,7 @@ void setup_pager(void);
 int pager_in_use(void);
 extern int pager_use_color;
 int term_columns(void);
+void term_clear_line(void);
 int decimal_width(uintmax_t);
 int check_pager_config(const char *cmd);
 void prepare_pager_args(struct child_process *, const char *pager);
index 7f6acdd803c33bc43200804ecec5d99f6d404224..8cc72503cb768573bc6d284eb57910ba6ca5a5cb 100755 (executable)
@@ -34,7 +34,7 @@ linux-clang|linux-gcc)
        popd
        ;;
 osx-clang|osx-gcc)
-       brew update >/dev/null
+       export HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1
        # Uncomment this if you want to run perf tests:
        # brew install gnu-time
        test -z "$BREW_INSTALL_PACKAGES" ||
index 288a5b3884ad825c99601ba5dc62ee81c62d7d64..0c7171a17354fd6dba5017e443b3d1b936f73e34 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -163,8 +163,10 @@ linux-clang|linux-gcc)
        export GIT_TEST_HTTPD=YesPlease
 
        # The Linux build installs the defined dependency versions below.
-       # The OS X build installs the latest available versions. Keep that
-       # in mind when you encounter a broken OS X build!
+       # The OS X build installs much more recent versions, whichever
+       # were recorded in the Homebrew database upon creating the OS X
+       # image.
+       # Keep that in mind when you encounter a broken OS X build!
        export LINUX_P4_VERSION="16.2"
        export LINUX_GIT_LFS_VERSION="1.5.2"
 
index 7c5e54875fdacdf77235a077c9928f7d3bf0d001..1752341098c328da1e9f6bce230e6b04730ffa11 100644 (file)
@@ -361,10 +361,10 @@ int generation_numbers_enabled(struct repository *r)
        return !!first_generation;
 }
 
-void close_commit_graph(struct repository *r)
+void close_commit_graph(struct raw_object_store *o)
 {
-       free_commit_graph(r->objects->commit_graph);
-       r->objects->commit_graph = NULL;
+       free_commit_graph(o->commit_graph);
+       o->commit_graph = NULL;
 }
 
 static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@ -525,14 +525,38 @@ struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit
        return get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);
 }
 
+struct packed_commit_list {
+       struct commit **list;
+       int nr;
+       int alloc;
+};
+
+struct packed_oid_list {
+       struct object_id *list;
+       int nr;
+       int alloc;
+};
+
+struct write_commit_graph_context {
+       struct repository *r;
+       const char *obj_dir;
+       char *graph_name;
+       struct packed_oid_list oids;
+       struct packed_commit_list commits;
+       int num_extra_edges;
+       unsigned long approx_nr_objects;
+       struct progress *progress;
+       int progress_done;
+       uint64_t progress_cnt;
+       unsigned append:1,
+                report_progress:1;
+};
+
 static void write_graph_chunk_fanout(struct hashfile *f,
-                                    struct commit **commits,
-                                    int nr_commits,
-                                    struct progress *progress,
-                                    uint64_t *progress_cnt)
+                                    struct write_commit_graph_context *ctx)
 {
        int i, count = 0;
-       struct commit **list = commits;
+       struct commit **list = ctx->commits.list;
 
        /*
         * Write the first-level table (the list is sorted,
@@ -540,10 +564,10 @@ static void write_graph_chunk_fanout(struct hashfile *f,
         * having to do eight extra binary search iterations).
         */
        for (i = 0; i < 256; i++) {
-               while (count < nr_commits) {
+               while (count < ctx->commits.nr) {
                        if ((*list)->object.oid.hash[0] != i)
                                break;
-                       display_progress(progress, ++*progress_cnt);
+                       display_progress(ctx->progress, ++ctx->progress_cnt);
                        count++;
                        list++;
                }
@@ -553,14 +577,12 @@ static void write_graph_chunk_fanout(struct hashfile *f,
 }
 
 static void write_graph_chunk_oids(struct hashfile *f, int hash_len,
-                                  struct commit **commits, int nr_commits,
-                                  struct progress *progress,
-                                  uint64_t *progress_cnt)
+                                  struct write_commit_graph_context *ctx)
 {
-       struct commit **list = commits;
+       struct commit **list = ctx->commits.list;
        int count;
-       for (count = 0; count < nr_commits; count++, list++) {
-               display_progress(progress, ++*progress_cnt);
+       for (count = 0; count < ctx->commits.nr; count++, list++) {
+               display_progress(ctx->progress, ++ctx->progress_cnt);
                hashwrite(f, (*list)->object.oid.hash, (int)hash_len);
        }
 }
@@ -572,19 +594,17 @@ static const unsigned char *commit_to_sha1(size_t index, void *table)
 }
 
 static void write_graph_chunk_data(struct hashfile *f, int hash_len,
-                                  struct commit **commits, int nr_commits,
-                                  struct progress *progress,
-                                  uint64_t *progress_cnt)
+                                  struct write_commit_graph_context *ctx)
 {
-       struct commit **list = commits;
-       struct commit **last = commits + nr_commits;
+       struct commit **list = ctx->commits.list;
+       struct commit **last = ctx->commits.list + ctx->commits.nr;
        uint32_t num_extra_edges = 0;
 
        while (list < last) {
                struct commit_list *parent;
                int edge_value;
                uint32_t packedDate[2];
-               display_progress(progress, ++*progress_cnt);
+               display_progress(ctx->progress, ++ctx->progress_cnt);
 
                parse_commit_no_graph(*list);
                hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len);
@@ -595,8 +615,8 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                        edge_value = GRAPH_PARENT_NONE;
                else {
                        edge_value = sha1_pos(parent->item->object.oid.hash,
-                                             commits,
-                                             nr_commits,
+                                             ctx->commits.list,
+                                             ctx->commits.nr,
                                              commit_to_sha1);
 
                        if (edge_value < 0)
@@ -616,8 +636,8 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                        edge_value = GRAPH_EXTRA_EDGES_NEEDED | num_extra_edges;
                else {
                        edge_value = sha1_pos(parent->item->object.oid.hash,
-                                             commits,
-                                             nr_commits,
+                                             ctx->commits.list,
+                                             ctx->commits.nr,
                                              commit_to_sha1);
                        if (edge_value < 0)
                                BUG("missing parent %s for commit %s",
@@ -649,19 +669,16 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
 }
 
 static void write_graph_chunk_extra_edges(struct hashfile *f,
-                                         struct commit **commits,
-                                         int nr_commits,
-                                         struct progress *progress,
-                                         uint64_t *progress_cnt)
+                                         struct write_commit_graph_context *ctx)
 {
-       struct commit **list = commits;
-       struct commit **last = commits + nr_commits;
+       struct commit **list = ctx->commits.list;
+       struct commit **last = ctx->commits.list + ctx->commits.nr;
        struct commit_list *parent;
 
        while (list < last) {
                int num_parents = 0;
 
-               display_progress(progress, ++*progress_cnt);
+               display_progress(ctx->progress, ++ctx->progress_cnt);
 
                for (parent = (*list)->parents; num_parents < 3 && parent;
                     parent = parent->next)
@@ -675,8 +692,8 @@ static void write_graph_chunk_extra_edges(struct hashfile *f,
                /* Since num_parents > 2, this initializer is safe. */
                for (parent = (*list)->parents->next; parent; parent = parent->next) {
                        int edge_value = sha1_pos(parent->item->object.oid.hash,
-                                                 commits,
-                                                 nr_commits,
+                                                 ctx->commits.list,
+                                                 ctx->commits.nr,
                                                  commit_to_sha1);
 
                        if (edge_value < 0)
@@ -700,125 +717,111 @@ static int commit_compare(const void *_a, const void *_b)
        return oidcmp(a, b);
 }
 
-struct packed_commit_list {
-       struct commit **list;
-       int nr;
-       int alloc;
-};
-
-struct packed_oid_list {
-       struct object_id *list;
-       int nr;
-       int alloc;
-       struct progress *progress;
-       int progress_done;
-};
-
 static int add_packed_commits(const struct object_id *oid,
                              struct packed_git *pack,
                              uint32_t pos,
                              void *data)
 {
-       struct packed_oid_list *list = (struct packed_oid_list*)data;
+       struct write_commit_graph_context *ctx = (struct write_commit_graph_context*)data;
        enum object_type type;
        off_t offset = nth_packed_object_offset(pack, pos);
        struct object_info oi = OBJECT_INFO_INIT;
 
-       if (list->progress)
-               display_progress(list->progress, ++list->progress_done);
+       if (ctx->progress)
+               display_progress(ctx->progress, ++ctx->progress_done);
 
        oi.typep = &type;
-       if (packed_object_info(the_repository, pack, offset, &oi) < 0)
+       if (packed_object_info(ctx->r, pack, offset, &oi) < 0)
                die(_("unable to get type of object %s"), oid_to_hex(oid));
 
        if (type != OBJ_COMMIT)
                return 0;
 
-       ALLOC_GROW(list->list, list->nr + 1, list->alloc);
-       oidcpy(&(list->list[list->nr]), oid);
-       list->nr++;
+       ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
+       oidcpy(&(ctx->oids.list[ctx->oids.nr]), oid);
+       ctx->oids.nr++;
 
        return 0;
 }
 
-static void add_missing_parents(struct packed_oid_list *oids, struct commit *commit)
+static void add_missing_parents(struct write_commit_graph_context *ctx, struct commit *commit)
 {
        struct commit_list *parent;
        for (parent = commit->parents; parent; parent = parent->next) {
                if (!(parent->item->object.flags & UNINTERESTING)) {
-                       ALLOC_GROW(oids->list, oids->nr + 1, oids->alloc);
-                       oidcpy(&oids->list[oids->nr], &(parent->item->object.oid));
-                       oids->nr++;
+                       ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
+                       oidcpy(&ctx->oids.list[ctx->oids.nr], &(parent->item->object.oid));
+                       ctx->oids.nr++;
                        parent->item->object.flags |= UNINTERESTING;
                }
        }
 }
 
-static void close_reachable(struct packed_oid_list *oids, int report_progress)
+static void close_reachable(struct write_commit_graph_context *ctx)
 {
        int i;
        struct commit *commit;
-       struct progress *progress = NULL;
 
-       if (report_progress)
-               progress = start_delayed_progress(
-                       _("Loading known commits in commit graph"), oids->nr);
-       for (i = 0; i < oids->nr; i++) {
-               display_progress(progress, i + 1);
-               commit = lookup_commit(the_repository, &oids->list[i]);
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
+                                       _("Loading known commits in commit graph"),
+                                       ctx->oids.nr);
+       for (i = 0; i < ctx->oids.nr; i++) {
+               display_progress(ctx->progress, i + 1);
+               commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
                if (commit)
                        commit->object.flags |= UNINTERESTING;
        }
-       stop_progress(&progress);
+       stop_progress(&ctx->progress);
 
        /*
-        * As this loop runs, oids->nr may grow, but not more
+        * As this loop runs, ctx->oids.nr may grow, but not more
         * than the number of missing commits in the reachable
         * closure.
         */
-       if (report_progress)
-               progress = start_delayed_progress(
-                       _("Expanding reachable commits in commit graph"), oids->nr);
-       for (i = 0; i < oids->nr; i++) {
-               display_progress(progress, i + 1);
-               commit = lookup_commit(the_repository, &oids->list[i]);
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
+                                       _("Expanding reachable commits in commit graph"),
+                                       ctx->oids.nr);
+       for (i = 0; i < ctx->oids.nr; i++) {
+               display_progress(ctx->progress, i + 1);
+               commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
 
                if (commit && !parse_commit_no_graph(commit))
-                       add_missing_parents(oids, commit);
+                       add_missing_parents(ctx, commit);
        }
-       stop_progress(&progress);
+       stop_progress(&ctx->progress);
 
-       if (report_progress)
-               progress = start_delayed_progress(
-                       _("Clearing commit marks in commit graph"), oids->nr);
-       for (i = 0; i < oids->nr; i++) {
-               display_progress(progress, i + 1);
-               commit = lookup_commit(the_repository, &oids->list[i]);
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
+                                       _("Clearing commit marks in commit graph"),
+                                       ctx->oids.nr);
+       for (i = 0; i < ctx->oids.nr; i++) {
+               display_progress(ctx->progress, i + 1);
+               commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
 
                if (commit)
                        commit->object.flags &= ~UNINTERESTING;
        }
-       stop_progress(&progress);
+       stop_progress(&ctx->progress);
 }
 
-static void compute_generation_numbers(struct packed_commit_list* commits,
-                                      int report_progress)
+static void compute_generation_numbers(struct write_commit_graph_context *ctx)
 {
        int i;
        struct commit_list *list = NULL;
-       struct progress *progress = NULL;
 
-       if (report_progress)
-               progress = start_progress(
-                       _("Computing commit graph generation numbers"),
-                       commits->nr);
-       for (i = 0; i < commits->nr; i++) {
-               display_progress(progress, i + 1);
-               if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY &&
-                   commits->list[i]->generation != GENERATION_NUMBER_ZERO)
+       if (ctx->report_progress)
+               ctx->progress = start_progress(
+                                       _("Computing commit graph generation numbers"),
+                                       ctx->commits.nr);
+       for (i = 0; i < ctx->commits.nr; i++) {
+               display_progress(ctx->progress, i + 1);
+               if (ctx->commits.list[i]->generation != GENERATION_NUMBER_INFINITY &&
+                   ctx->commits.list[i]->generation != GENERATION_NUMBER_ZERO)
                        continue;
 
-               commit_list_insert(commits->list[i], &list);
+               commit_list_insert(ctx->commits.list[i], &list);
                while (list) {
                        struct commit *current = list->item;
                        struct commit_list *parent;
@@ -845,7 +848,7 @@ static void compute_generation_numbers(struct packed_commit_list* commits,
                        }
                }
        }
-       stop_progress(&progress);
+       stop_progress(&ctx->progress);
 }
 
 static int add_ref_to_list(const char *refname,
@@ -858,207 +861,187 @@ static int add_ref_to_list(const char *refname,
        return 0;
 }
 
-void write_commit_graph_reachable(const char *obj_dir, int append,
-                                 int report_progress)
+int write_commit_graph_reachable(const char *obj_dir, unsigned int flags)
 {
        struct string_list list = STRING_LIST_INIT_DUP;
+       int result;
 
        for_each_ref(add_ref_to_list, &list);
-       write_commit_graph(obj_dir, NULL, &list, append, report_progress);
+       result = write_commit_graph(obj_dir, NULL, &list,
+                                   flags);
 
        string_list_clear(&list, 0);
+       return result;
 }
 
-void write_commit_graph(const char *obj_dir,
-                       struct string_list *pack_indexes,
-                       struct string_list *commit_hex,
-                       int append, int report_progress)
+static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
+                               struct string_list *pack_indexes)
 {
-       struct packed_oid_list oids;
-       struct packed_commit_list commits;
-       struct hashfile *f;
-       uint32_t i, count_distinct = 0;
-       char *graph_name;
-       struct lock_file lk = LOCK_INIT;
-       uint32_t chunk_ids[5];
-       uint64_t chunk_offsets[5];
-       int num_chunks;
-       int num_extra_edges;
-       struct commit_list *parent;
-       struct progress *progress = NULL;
-       const unsigned hashsz = the_hash_algo->rawsz;
-       uint64_t progress_cnt = 0;
+       uint32_t i;
        struct strbuf progress_title = STRBUF_INIT;
-       unsigned long approx_nr_objects;
-
-       if (!commit_graph_compatible(the_repository))
-               return;
-
-       oids.nr = 0;
-       approx_nr_objects = approximate_object_count();
-       oids.alloc = approx_nr_objects / 32;
-       oids.progress = NULL;
-       oids.progress_done = 0;
+       struct strbuf packname = STRBUF_INIT;
+       int dirlen;
 
-       if (append) {
-               prepare_commit_graph_one(the_repository, obj_dir);
-               if (the_repository->objects->commit_graph)
-                       oids.alloc += the_repository->objects->commit_graph->num_commits;
+       strbuf_addf(&packname, "%s/pack/", ctx->obj_dir);
+       dirlen = packname.len;
+       if (ctx->report_progress) {
+               strbuf_addf(&progress_title,
+                           Q_("Finding commits for commit graph in %d pack",
+                              "Finding commits for commit graph in %d packs",
+                              pack_indexes->nr),
+                           pack_indexes->nr);
+               ctx->progress = start_delayed_progress(progress_title.buf, 0);
+               ctx->progress_done = 0;
        }
-
-       if (oids.alloc < 1024)
-               oids.alloc = 1024;
-       ALLOC_ARRAY(oids.list, oids.alloc);
-
-       if (append && the_repository->objects->commit_graph) {
-               struct commit_graph *commit_graph =
-                       the_repository->objects->commit_graph;
-               for (i = 0; i < commit_graph->num_commits; i++) {
-                       const unsigned char *hash = commit_graph->chunk_oid_lookup +
-                               commit_graph->hash_len * i;
-                       hashcpy(oids.list[oids.nr++].hash, hash);
+       for (i = 0; i < pack_indexes->nr; i++) {
+               struct packed_git *p;
+               strbuf_setlen(&packname, dirlen);
+               strbuf_addstr(&packname, pack_indexes->items[i].string);
+               p = add_packed_git(packname.buf, packname.len, 1);
+               if (!p) {
+                       error(_("error adding pack %s"), packname.buf);
+                       return -1;
+               }
+               if (open_pack_index(p)) {
+                       error(_("error opening index for %s"), packname.buf);
+                       return -1;
                }
+               for_each_object_in_pack(p, add_packed_commits, ctx,
+                                       FOR_EACH_OBJECT_PACK_ORDER);
+               close_pack(p);
+               free(p);
        }
 
-       if (pack_indexes) {
-               struct strbuf packname = STRBUF_INIT;
-               int dirlen;
-               strbuf_addf(&packname, "%s/pack/", obj_dir);
-               dirlen = packname.len;
-               if (report_progress) {
-                       strbuf_addf(&progress_title,
-                                   Q_("Finding commits for commit graph in %d pack",
-                                      "Finding commits for commit graph in %d packs",
-                                      pack_indexes->nr),
-                                   pack_indexes->nr);
-                       oids.progress = start_delayed_progress(progress_title.buf, 0);
-                       oids.progress_done = 0;
-               }
-               for (i = 0; i < pack_indexes->nr; i++) {
-                       struct packed_git *p;
-                       strbuf_setlen(&packname, dirlen);
-                       strbuf_addstr(&packname, pack_indexes->items[i].string);
-                       p = add_packed_git(packname.buf, packname.len, 1);
-                       if (!p)
-                               die(_("error adding pack %s"), packname.buf);
-                       if (open_pack_index(p))
-                               die(_("error opening index for %s"), packname.buf);
-                       for_each_object_in_pack(p, add_packed_commits, &oids,
-                                               FOR_EACH_OBJECT_PACK_ORDER);
-                       close_pack(p);
-                       free(p);
-               }
-               stop_progress(&oids.progress);
-               strbuf_reset(&progress_title);
-               strbuf_release(&packname);
+       stop_progress(&ctx->progress);
+       strbuf_reset(&progress_title);
+       strbuf_release(&packname);
+
+       return 0;
+}
+
+static void fill_oids_from_commit_hex(struct write_commit_graph_context *ctx,
+                                     struct string_list *commit_hex)
+{
+       uint32_t i;
+       struct strbuf progress_title = STRBUF_INIT;
+
+       if (ctx->report_progress) {
+               strbuf_addf(&progress_title,
+                           Q_("Finding commits for commit graph from %d ref",
+                              "Finding commits for commit graph from %d refs",
+                              commit_hex->nr),
+                           commit_hex->nr);
+               ctx->progress = start_delayed_progress(
+                                       progress_title.buf,
+                                       commit_hex->nr);
        }
+       for (i = 0; i < commit_hex->nr; i++) {
+               const char *end;
+               struct object_id oid;
+               struct commit *result;
+
+               display_progress(ctx->progress, i + 1);
+               if (commit_hex->items[i].string &&
+                   parse_oid_hex(commit_hex->items[i].string, &oid, &end))
+                       continue;
 
-       if (commit_hex) {
-               if (report_progress) {
-                       strbuf_addf(&progress_title,
-                                   Q_("Finding commits for commit graph from %d ref",
-                                      "Finding commits for commit graph from %d refs",
-                                      commit_hex->nr),
-                                   commit_hex->nr);
-                       progress = start_delayed_progress(progress_title.buf,
-                                                         commit_hex->nr);
-               }
-               for (i = 0; i < commit_hex->nr; i++) {
-                       const char *end;
-                       struct object_id oid;
-                       struct commit *result;
-
-                       display_progress(progress, i + 1);
-                       if (commit_hex->items[i].string &&
-                           parse_oid_hex(commit_hex->items[i].string, &oid, &end))
-                               continue;
-
-                       result = lookup_commit_reference_gently(the_repository, &oid, 1);
-
-                       if (result) {
-                               ALLOC_GROW(oids.list, oids.nr + 1, oids.alloc);
-                               oidcpy(&oids.list[oids.nr], &(result->object.oid));
-                               oids.nr++;
-                       }
+               result = lookup_commit_reference_gently(ctx->r, &oid, 1);
+
+               if (result) {
+                       ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
+                       oidcpy(&ctx->oids.list[ctx->oids.nr], &(result->object.oid));
+                       ctx->oids.nr++;
                }
-               stop_progress(&progress);
-               strbuf_reset(&progress_title);
        }
+       stop_progress(&ctx->progress);
+       strbuf_release(&progress_title);
+}
 
-       if (!pack_indexes && !commit_hex) {
-               if (report_progress)
-                       oids.progress = start_delayed_progress(
-                               _("Finding commits for commit graph among packed objects"),
-                               approx_nr_objects);
-               for_each_packed_object(add_packed_commits, &oids,
-                                      FOR_EACH_OBJECT_PACK_ORDER);
-               if (oids.progress_done < approx_nr_objects)
-                       display_progress(oids.progress, approx_nr_objects);
-               stop_progress(&oids.progress);
-       }
+static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
+{
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
+                       _("Finding commits for commit graph among packed objects"),
+                       ctx->approx_nr_objects);
+       for_each_packed_object(add_packed_commits, ctx,
+                              FOR_EACH_OBJECT_PACK_ORDER);
+       if (ctx->progress_done < ctx->approx_nr_objects)
+               display_progress(ctx->progress, ctx->approx_nr_objects);
+       stop_progress(&ctx->progress);
+}
 
-       close_reachable(&oids, report_progress);
+static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
+{
+       uint32_t i, count_distinct = 1;
 
-       if (report_progress)
-               progress = start_delayed_progress(
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
                        _("Counting distinct commits in commit graph"),
-                       oids.nr);
-       display_progress(progress, 0); /* TODO: Measure QSORT() progress */
-       QSORT(oids.list, oids.nr, commit_compare);
-       count_distinct = 1;
-       for (i = 1; i < oids.nr; i++) {
-               display_progress(progress, i + 1);
-               if (!oideq(&oids.list[i - 1], &oids.list[i]))
+                       ctx->oids.nr);
+       display_progress(ctx->progress, 0); /* TODO: Measure QSORT() progress */
+       QSORT(ctx->oids.list, ctx->oids.nr, commit_compare);
+
+       for (i = 1; i < ctx->oids.nr; i++) {
+               display_progress(ctx->progress, i + 1);
+               if (!oideq(&ctx->oids.list[i - 1], &ctx->oids.list[i]))
                        count_distinct++;
        }
-       stop_progress(&progress);
+       stop_progress(&ctx->progress);
 
-       if (count_distinct >= GRAPH_EDGE_LAST_MASK)
-               die(_("the commit graph format cannot write %d commits"), count_distinct);
+       return count_distinct;
+}
 
-       commits.nr = 0;
-       commits.alloc = count_distinct;
-       ALLOC_ARRAY(commits.list, commits.alloc);
+static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
+{
+       uint32_t i;
+       struct commit_list *parent;
 
-       num_extra_edges = 0;
-       if (report_progress)
-               progress = start_delayed_progress(
+       ctx->num_extra_edges = 0;
+       if (ctx->report_progress)
+               ctx->progress = start_delayed_progress(
                        _("Finding extra edges in commit graph"),
-                       oids.nr);
-       for (i = 0; i < oids.nr; i++) {
+                       ctx->oids.nr);
+       for (i = 0; i < ctx->oids.nr; i++) {
                int num_parents = 0;
-               display_progress(progress, i + 1);
-               if (i > 0 && oideq(&oids.list[i - 1], &oids.list[i]))
+               display_progress(ctx->progress, i + 1);
+               if (i > 0 && oideq(&ctx->oids.list[i - 1], &ctx->oids.list[i]))
                        continue;
 
-               commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
-               parse_commit_no_graph(commits.list[commits.nr]);
+               ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.list[i]);
+               parse_commit_no_graph(ctx->commits.list[ctx->commits.nr]);
 
-               for (parent = commits.list[commits.nr]->parents;
+               for (parent = ctx->commits.list[ctx->commits.nr]->parents;
                     parent; parent = parent->next)
                        num_parents++;
 
                if (num_parents > 2)
-                       num_extra_edges += num_parents - 1;
+                       ctx->num_extra_edges += num_parents - 1;
 
-               commits.nr++;
+               ctx->commits.nr++;
        }
-       num_chunks = num_extra_edges ? 4 : 3;
-       stop_progress(&progress);
-
-       if (commits.nr >= GRAPH_EDGE_LAST_MASK)
-               die(_("too many commits to write graph"));
-
-       compute_generation_numbers(&commits, report_progress);
+       stop_progress(&ctx->progress);
+}
 
-       graph_name = get_commit_graph_filename(obj_dir);
-       if (safe_create_leading_directories(graph_name)) {
-               UNLEAK(graph_name);
-               die_errno(_("unable to create leading directories of %s"),
-                         graph_name);
+static int write_commit_graph_file(struct write_commit_graph_context *ctx)
+{
+       uint32_t i;
+       struct hashfile *f;
+       struct lock_file lk = LOCK_INIT;
+       uint32_t chunk_ids[5];
+       uint64_t chunk_offsets[5];
+       const unsigned hashsz = the_hash_algo->rawsz;
+       struct strbuf progress_title = STRBUF_INIT;
+       int num_chunks = ctx->num_extra_edges ? 4 : 3;
+
+       ctx->graph_name = get_commit_graph_filename(ctx->obj_dir);
+       if (safe_create_leading_directories(ctx->graph_name)) {
+               UNLEAK(ctx->graph_name);
+               error(_("unable to create leading directories of %s"),
+                       ctx->graph_name);
+               return -1;
        }
 
-       hold_lock_file_for_update(&lk, graph_name, LOCK_DIE_ON_ERROR);
+       hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR);
        f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
 
        hashwrite_be32(f, GRAPH_SIGNATURE);
@@ -1071,7 +1054,7 @@ void write_commit_graph(const char *obj_dir,
        chunk_ids[0] = GRAPH_CHUNKID_OIDFANOUT;
        chunk_ids[1] = GRAPH_CHUNKID_OIDLOOKUP;
        chunk_ids[2] = GRAPH_CHUNKID_DATA;
-       if (num_extra_edges)
+       if (ctx->num_extra_edges)
                chunk_ids[3] = GRAPH_CHUNKID_EXTRAEDGES;
        else
                chunk_ids[3] = 0;
@@ -1079,9 +1062,9 @@ void write_commit_graph(const char *obj_dir,
 
        chunk_offsets[0] = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
        chunk_offsets[1] = chunk_offsets[0] + GRAPH_FANOUT_SIZE;
-       chunk_offsets[2] = chunk_offsets[1] + hashsz * commits.nr;
-       chunk_offsets[3] = chunk_offsets[2] + (hashsz + 16) * commits.nr;
-       chunk_offsets[4] = chunk_offsets[3] + 4 * num_extra_edges;
+       chunk_offsets[2] = chunk_offsets[1] + hashsz * ctx->commits.nr;
+       chunk_offsets[3] = chunk_offsets[2] + (hashsz + 16) * ctx->commits.nr;
+       chunk_offsets[4] = chunk_offsets[3] + 4 * ctx->num_extra_edges;
 
        for (i = 0; i <= num_chunks; i++) {
                uint32_t chunk_write[3];
@@ -1092,31 +1075,113 @@ void write_commit_graph(const char *obj_dir,
                hashwrite(f, chunk_write, 12);
        }
 
-       if (report_progress) {
+       if (ctx->report_progress) {
                strbuf_addf(&progress_title,
                            Q_("Writing out commit graph in %d pass",
                               "Writing out commit graph in %d passes",
                               num_chunks),
                            num_chunks);
-               progress = start_delayed_progress(
+               ctx->progress = start_delayed_progress(
                        progress_title.buf,
-                       num_chunks * commits.nr);
+                       num_chunks * ctx->commits.nr);
        }
-       write_graph_chunk_fanout(f, commits.list, commits.nr, progress, &progress_cnt);
-       write_graph_chunk_oids(f, hashsz, commits.list, commits.nr, progress, &progress_cnt);
-       write_graph_chunk_data(f, hashsz, commits.list, commits.nr, progress, &progress_cnt);
-       if (num_extra_edges)
-               write_graph_chunk_extra_edges(f, commits.list, commits.nr, progress, &progress_cnt);
-       stop_progress(&progress);
+       write_graph_chunk_fanout(f, ctx);
+       write_graph_chunk_oids(f, hashsz, ctx);
+       write_graph_chunk_data(f, hashsz, ctx);
+       if (ctx->num_extra_edges)
+               write_graph_chunk_extra_edges(f, ctx);
+       stop_progress(&ctx->progress);
        strbuf_release(&progress_title);
 
-       close_commit_graph(the_repository);
+       close_commit_graph(ctx->r->objects);
        finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
        commit_lock_file(&lk);
 
-       free(graph_name);
-       free(commits.list);
-       free(oids.list);
+       return 0;
+}
+
+int write_commit_graph(const char *obj_dir,
+                      struct string_list *pack_indexes,
+                      struct string_list *commit_hex,
+                      unsigned int flags)
+{
+       struct write_commit_graph_context *ctx;
+       uint32_t i, count_distinct = 0;
+       int res = 0;
+
+       if (!commit_graph_compatible(the_repository))
+               return 0;
+
+       ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
+       ctx->r = the_repository;
+       ctx->obj_dir = obj_dir;
+       ctx->append = flags & COMMIT_GRAPH_APPEND ? 1 : 0;
+       ctx->report_progress = flags & COMMIT_GRAPH_PROGRESS ? 1 : 0;
+
+       ctx->approx_nr_objects = approximate_object_count();
+       ctx->oids.alloc = ctx->approx_nr_objects / 32;
+
+       if (ctx->append) {
+               prepare_commit_graph_one(ctx->r, ctx->obj_dir);
+               if (ctx->r->objects->commit_graph)
+                       ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
+       }
+
+       if (ctx->oids.alloc < 1024)
+               ctx->oids.alloc = 1024;
+       ALLOC_ARRAY(ctx->oids.list, ctx->oids.alloc);
+
+       if (ctx->append && ctx->r->objects->commit_graph) {
+               struct commit_graph *g = ctx->r->objects->commit_graph;
+               for (i = 0; i < g->num_commits; i++) {
+                       const unsigned char *hash = g->chunk_oid_lookup + g->hash_len * i;
+                       hashcpy(ctx->oids.list[ctx->oids.nr++].hash, hash);
+               }
+       }
+
+       if (pack_indexes) {
+               if ((res = fill_oids_from_packs(ctx, pack_indexes)))
+                       goto cleanup;
+       }
+
+       if (commit_hex)
+               fill_oids_from_commit_hex(ctx, commit_hex);
+
+       if (!pack_indexes && !commit_hex)
+               fill_oids_from_all_packs(ctx);
+
+       close_reachable(ctx);
+
+       count_distinct = count_distinct_commits(ctx);
+
+       if (count_distinct >= GRAPH_EDGE_LAST_MASK) {
+               error(_("the commit graph format cannot write %d commits"), count_distinct);
+               res = -1;
+               goto cleanup;
+       }
+
+       ctx->commits.alloc = count_distinct;
+       ALLOC_ARRAY(ctx->commits.list, ctx->commits.alloc);
+
+       copy_oids_to_commits(ctx);
+
+       if (ctx->commits.nr >= GRAPH_EDGE_LAST_MASK) {
+               error(_("too many commits to write graph"));
+               res = -1;
+               goto cleanup;
+       }
+
+       compute_generation_numbers(ctx);
+
+       res = write_commit_graph_file(ctx);
+
+cleanup:
+       free(ctx->graph_name);
+       free(ctx->commits.list);
+       free(ctx->oids.list);
+       free(ctx);
+
+       return res;
 }
 
 #define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
index 7dfb8c896fc35f633c73221ec639ca9c425338ab..390c7f696104fbe772151b91cb04889d0f682401 100644 (file)
@@ -65,16 +65,24 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
  */
 int generation_numbers_enabled(struct repository *r);
 
-void write_commit_graph_reachable(const char *obj_dir, int append,
-                                 int report_progress);
-void write_commit_graph(const char *obj_dir,
-                       struct string_list *pack_indexes,
-                       struct string_list *commit_hex,
-                       int append, int report_progress);
+#define COMMIT_GRAPH_APPEND     (1 << 0)
+#define COMMIT_GRAPH_PROGRESS   (1 << 1)
+
+/*
+ * The write_commit_graph* methods return zero on success
+ * and a negative value on failure. Note that if the repository
+ * is not compatible with the commit-graph feature, then the
+ * methods will return 0 without writing a commit-graph.
+ */
+int write_commit_graph_reachable(const char *obj_dir, unsigned int flags);
+int write_commit_graph(const char *obj_dir,
+                      struct string_list *pack_indexes,
+                      struct string_list *commit_hex,
+                      unsigned int flags);
 
 int verify_commit_graph(struct repository *r, struct commit_graph *g);
 
-void close_commit_graph(struct repository *);
+void close_commit_graph(struct raw_object_store *);
 void free_commit_graph(struct commit_graph *);
 
 #endif
index 8fa1883c61c580578a755cdf2da009203d8d386e..26ce0770f688eb94d5be5975d756752dbc0337a8 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -449,7 +449,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
        item->date = parse_commit_date(bufptr, tail);
 
        if (check_graph)
-               load_commit_graph_info(the_repository, item);
+               load_commit_graph_info(r, item);
 
        return 0;
 }
index 9b6d2400e1107fa2a65f6ecd7d067809115930b9..6d7fc07a487a0ffb023db5b45ba9eaa0b3c36bc9 100644 (file)
@@ -1437,7 +1437,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        si.hStdOutput = winansi_get_osfhandle(fhout);
        si.hStdError = winansi_get_osfhandle(fherr);
 
-       if (xutftowcs_path(wcmd, cmd) < 0)
+       if (*argv && !strcmp(cmd, *argv))
+               wcmd[0] = L'\0';
+       else if (xutftowcs_path(wcmd, cmd) < 0)
                return -1;
        if (dir && xutftowcs_path(wdir, dir) < 0)
                return -1;
@@ -1466,8 +1468,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        wenvblk = make_environment_block(deltaenv);
 
        memset(&pi, 0, sizeof(pi));
-       ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-               wenvblk, dir ? wdir : NULL, &si, &pi);
+       ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
+               flags, wenvblk, dir ? wdir : NULL, &si, &pi);
 
        free(wenvblk);
        free(wargs);
index 4459408c7d0ba762b1dd4184a4c970778ba097a5..8b07edb0feca434cce2ff7766c30d7529febf996 100644 (file)
@@ -149,7 +149,7 @@ win32_compute_revents (HANDLE h, int *p_sought)
     case FILE_TYPE_PIPE:
       if (!once_only)
        {
-         NtQueryInformationFile = (PNtQueryInformationFile)
+         NtQueryInformationFile = (PNtQueryInformationFile)(void (*)(void))
            GetProcAddress (GetModuleHandle ("ntdll.dll"),
                            "NtQueryInformationFile");
          once_only = TRUE;
index f4f08237f9ed513e0dd3b3bfd9494f19944e3239..a29d34ef44864f02bd89c8490d38bca0efe2a8e6 100644 (file)
@@ -7,6 +7,7 @@
 #include <wingdi.h>
 #include <winreg.h>
 #include "win32.h"
+#include "win32/lazyload.h"
 
 static int fd_is_interactive[3] = { 0, 0, 0 };
 #define FD_CONSOLE 0x1
@@ -41,26 +42,21 @@ typedef struct _CONSOLE_FONT_INFOEX {
 #endif
 #endif
 
-typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
-               PCONSOLE_FONT_INFOEX);
-
 static void warn_if_raster_font(void)
 {
        DWORD fontFamily = 0;
-       PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+       DECLARE_PROC_ADDR(kernel32.dll, BOOL, GetCurrentConsoleFontEx,
+                       HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
 
        /* don't bother if output was ascii only */
        if (!non_ascii_used)
                return;
 
        /* GetCurrentConsoleFontEx is available since Vista */
-       pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
-                       GetModuleHandle("kernel32.dll"),
-                       "GetCurrentConsoleFontEx");
-       if (pGetCurrentConsoleFontEx) {
+       if (INIT_PROC_ADDR(GetCurrentConsoleFontEx)) {
                CONSOLE_FONT_INFOEX cfi;
                cfi.cbSize = sizeof(cfi);
-               if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+               if (GetCurrentConsoleFontEx(console, 0, &cfi))
                        fontFamily = cfi.FontFamily;
        } else {
                /* pre-Vista: check default console font in registry */
index 296a6d9cc4110bd7fcef542ac9cc9cfe04d4f4d4..26196bdccfbc268d7ee669546d39a15e14703494 100644 (file)
--- a/config.c
+++ b/config.c
@@ -834,22 +834,16 @@ static int git_parse_source(config_fn_t fn, void *data,
        return error_return;
 }
 
-static int parse_unit_factor(const char *end, uintmax_t *val)
+static uintmax_t get_unit_factor(const char *end)
 {
        if (!*end)
                return 1;
-       else if (!strcasecmp(end, "k")) {
-               *val *= 1024;
-               return 1;
-       }
-       else if (!strcasecmp(end, "m")) {
-               *val *= 1024 * 1024;
-               return 1;
-       }
-       else if (!strcasecmp(end, "g")) {
-               *val *= 1024 * 1024 * 1024;
-               return 1;
-       }
+       else if (!strcasecmp(end, "k"))
+               return 1024;
+       else if (!strcasecmp(end, "m"))
+               return 1024 * 1024;
+       else if (!strcasecmp(end, "g"))
+               return 1024 * 1024 * 1024;
        return 0;
 }
 
@@ -859,19 +853,20 @@ static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
                char *end;
                intmax_t val;
                uintmax_t uval;
-               uintmax_t factor = 1;
+               uintmax_t factor;
 
                errno = 0;
                val = strtoimax(value, &end, 0);
                if (errno == ERANGE)
                        return 0;
-               if (!parse_unit_factor(end, &factor)) {
+               factor = get_unit_factor(end);
+               if (!factor) {
                        errno = EINVAL;
                        return 0;
                }
-               uval = labs(val);
-               uval *= factor;
-               if (uval > max || labs(val) > uval) {
+               uval = val < 0 ? -val : val;
+               if (unsigned_mult_overflows(factor, uval) ||
+                   factor * uval > max) {
                        errno = ERANGE;
                        return 0;
                }
@@ -888,21 +883,23 @@ static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
        if (value && *value) {
                char *end;
                uintmax_t val;
-               uintmax_t oldval;
+               uintmax_t factor;
 
                errno = 0;
                val = strtoumax(value, &end, 0);
                if (errno == ERANGE)
                        return 0;
-               oldval = val;
-               if (!parse_unit_factor(end, &val)) {
+               factor = get_unit_factor(end);
+               if (!factor) {
                        errno = EINVAL;
                        return 0;
                }
-               if (val > max || oldval > val) {
+               if (unsigned_mult_overflows(factor, val) ||
+                   factor * val > max) {
                        errno = ERANGE;
                        return 0;
                }
+               val *= factor;
                *ret = val;
                return 1;
        }
index 01586821dc7c15be2a94c30bfbf4f3b4c94ac5f3..46b8d2ee11151b97e4e0cfd56afcf059247d1c54 100644 (file)
@@ -1,29 +1,60 @@
 @@
-type T;
-T *dst;
-T *src;
-expression n;
+expression dst, src, n, E;
 @@
-- memcpy(dst, src, (n) * sizeof(*dst));
-+ COPY_ARRAY(dst, src, n);
+  memcpy(dst, src, n * sizeof(
+- E[...]
++ *(E)
+  ))
 
 @@
 type T;
-T *dst;
-T *src;
-expression n;
+T *ptr;
+T[] arr;
+expression E, n;
 @@
-- memcpy(dst, src, (n) * sizeof(*src));
-+ COPY_ARRAY(dst, src, n);
+(
+  memcpy(ptr, E,
+- n * sizeof(*(ptr))
++ n * sizeof(T)
+  )
+|
+  memcpy(arr, E,
+- n * sizeof(*(arr))
++ n * sizeof(T)
+  )
+|
+  memcpy(E, ptr,
+- n * sizeof(*(ptr))
++ n * sizeof(T)
+  )
+|
+  memcpy(E, arr,
+- n * sizeof(*(arr))
++ n * sizeof(T)
+  )
+)
 
 @@
 type T;
-T *dst;
-T *src;
+T *dst_ptr;
+T *src_ptr;
+T[] dst_arr;
+T[] src_arr;
 expression n;
 @@
-- memcpy(dst, src, (n) * sizeof(T));
-+ COPY_ARRAY(dst, src, n);
+(
+- memcpy(dst_ptr, src_ptr, (n) * sizeof(T))
++ COPY_ARRAY(dst_ptr, src_ptr, n)
+|
+- memcpy(dst_ptr, src_arr, (n) * sizeof(T))
++ COPY_ARRAY(dst_ptr, src_arr, n)
+|
+- memcpy(dst_arr, src_ptr, (n) * sizeof(T))
++ COPY_ARRAY(dst_arr, src_ptr, n)
+|
+- memcpy(dst_arr, src_arr, (n) * sizeof(T))
++ COPY_ARRAY(dst_arr, src_arr, n)
+)
 
 @@
 type T;
index 9f71bcde967bc50915b90eaef72061f8c6a56315..8c6b610a2447cd1ec7c2dff0f9dbd09f6a024f57 100644 (file)
@@ -400,7 +400,8 @@ __gitcomp_builtin ()
        if [ -z "$options" ]; then
                # leading and trailing spaces are significant to make
                # option removal work correctly.
-               options=" $incl $(__git ${cmd/_/ } --git-completion-helper) "
+               options=" $incl $(__git ${cmd/_/ } --git-completion-helper) " || return
+
                for i in $excl; do
                        options="${options/ $i / }"
                done
index 2186bd0738ed2fcbe216cf24a6c99ed4dc4ccd9b..b959f6c380a6f42849db570cf0a51fed23f2b2a8 100644 (file)
@@ -454,7 +454,7 @@ static void deduplicate_islands(struct repository *r)
        free(list);
 }
 
-void load_delta_islands(struct repository *r)
+void load_delta_islands(struct repository *r, int progress)
 {
        island_marks = kh_init_sha1();
        remote_islands = kh_init_str();
@@ -463,7 +463,8 @@ void load_delta_islands(struct repository *r)
        for_each_ref(find_island_for_ref, NULL);
        deduplicate_islands(r);
 
-       fprintf(stderr, _("Marked %d islands, done.\n"), island_counter);
+       if (progress)
+               fprintf(stderr, _("Marked %d islands, done.\n"), island_counter);
 }
 
 void propagate_island_marks(struct commit *commit)
index 3ac8045d8c528be81ac1cbefe9942c534e3c498a..eb0f952629fc0a6cdcc113e19a04ddaa54bb32dd 100644 (file)
@@ -11,7 +11,7 @@ int in_same_island(const struct object_id *, const struct object_id *);
 void resolve_tree_islands(struct repository *r,
                          int progress,
                          struct packing_data *to_pack);
-void load_delta_islands(struct repository *r);
+void load_delta_islands(struct repository *r, int progress);
 void propagate_island_marks(struct commit *commit);
 int compute_pack_layers(struct packing_data *to_pack);
 
index a838c219ec044b9fb78b4bda058d078e66d7aaf8..61812f48c2737a4702e604962e97f5c00d394b16 100644 (file)
@@ -232,7 +232,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 
                if (!changed && !dirty_submodule) {
                        ce_mark_uptodate(ce);
-                       mark_fsmonitor_valid(ce);
+                       mark_fsmonitor_valid(istate, ce);
                        if (!revs->diffopt.flags.find_copies_harder)
                                continue;
                }
diff --git a/diff.c b/diff.c
index a654d46f6a93de96d85706c7373ef0d617081a21..1ccd96bbfde23a0f6d42104e81f78e0953c1bc93 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4206,6 +4206,8 @@ static void run_external_diff(const char *pgm,
        argv_array_pushf(&env, "GIT_DIFF_PATH_COUNTER=%d", ++o->diff_path_counter);
        argv_array_pushf(&env, "GIT_DIFF_PATH_TOTAL=%d", q->nr);
 
+       diff_free_filespec_data(one);
+       diff_free_filespec_data(two);
        if (run_command_v_opt_cd_env(argv.argv, RUN_USING_SHELL, NULL, env.argv))
                die(_("external diff died, stopping at %s"), name);
 
index 07bd34b63145e1dc179afebcc7af351c34c2ab07..6af92d5eba6584416d331c2f6e63bd7d403ca773 100644 (file)
@@ -23,7 +23,7 @@ static int find_rename_dst(struct diff_filespec *two)
        first = 0;
        last = rename_dst_nr;
        while (last > first) {
-               int next = (last + first) >> 1;
+               int next = first + ((last - first) >> 1);
                struct diff_rename_dst *dst = &(rename_dst[next]);
                int cmp = strcmp(two->path, dst->two->path);
                if (!cmp)
@@ -83,7 +83,7 @@ static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
        first = 0;
        last = rename_src_nr;
        while (last > first) {
-               int next = (last + first) >> 1;
+               int next = first + ((last - first) >> 1);
                struct diff_rename_src *src = &(rename_src[next]);
                int cmp = strcmp(one->path, src->p->one->path);
                if (!cmp)
diff --git a/dir.c b/dir.c
index ba4a51c296efcad9861ebfb4b318fbd5cb3025a4..d021c908e5d162cfd4d961ab11d16b1b9eb7124a 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -701,7 +701,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,
        first = 0;
        last = dir->dirs_nr;
        while (last > first) {
-               int cmp, next = (last + first) >> 1;
+               int cmp, next = first + ((last - first) >> 1);
                d = dir->dirs[next];
                cmp = strncmp(name, d->name, len);
                if (!cmp && strlen(d->name) > len)
index 71547674ab4e885bd06560a547e78fddb0849158..f079abbf1102686fdb8e64258f456877f976dd03 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -96,10 +96,10 @@ static int launch_specified_editor(const char *editor, const char *path,
 
                if (print_waiting_for_editor && !is_terminal_dumb())
                        /*
-                        * Go back to the beginning and erase the entire line to
-                        * avoid wasting the vertical space.
+                        * Erase the entire line to avoid wasting the
+                        * vertical space.
                         */
-                       fputs("\r\033[K", stderr);
+                       term_clear_line();
        }
 
        if (!buffer)
diff --git a/entry.c b/entry.c
index 0e4f2f29101f913d0db2c401851f279eac496f02..53380bb614c19e82edfb45049f1703b4a3b9c8a3 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -373,7 +373,7 @@ static int write_entry(struct cache_entry *ce,
                        if (lstat(ce->name, &st) < 0)
                                return error_errno("unable to stat just-written file %s",
                                                   ce->name);
-               fill_stat_cache_info(ce, &st);
+               fill_stat_cache_info(state->istate, ce, &st);
                ce->ce_flags |= CE_UPDATE_IN_BASE;
                mark_fsmonitor_invalid(state->istate, ce);
                state->istate->cache_changed |= CE_ENTRY_CHANGED;
index f38d04fa58510bb7ab35caf4c43d5b2d954cc292..606d44278d88b3ae23dac934dc1e77eb0b138c31 100644 (file)
@@ -644,7 +644,7 @@ static struct tree_content *grow_tree_content(
        struct tree_content *r = new_tree_content(t->entry_count + amt);
        r->entry_count = t->entry_count;
        r->delta_depth = t->delta_depth;
-       memcpy(r->entries,t->entries,t->entry_count*sizeof(t->entries[0]));
+       COPY_ARRAY(r->entries, t->entries, t->entry_count);
        release_tree_content(t);
        return r;
 }
index 1dee0aded1c433c7cfb90195328f270559c9b421..231e83a94db58e4efb2f4d7a1dbe90220bd2f317 100644 (file)
@@ -56,7 +56,7 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data,
 
 void fill_fsmonitor_bitmap(struct index_state *istate)
 {
-       int i;
+       unsigned int i;
        istate->fsmonitor_dirty = ewah_new();
        for (i = 0; i < istate->cache_nr; i++)
                if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
@@ -134,7 +134,7 @@ void refresh_fsmonitor(struct index_state *istate)
        size_t bol; /* beginning of line */
        uint64_t last_update;
        char *buf;
-       int i;
+       unsigned int i;
 
        if (!core_fsmonitor || istate->fsmonitor_has_run_once)
                return;
@@ -192,7 +192,7 @@ void refresh_fsmonitor(struct index_state *istate)
 
 void add_fsmonitor(struct index_state *istate)
 {
-       int i;
+       unsigned int i;
 
        if (!istate->fsmonitor_last_update) {
                trace_printf_key(&trace_fsmonitor, "add fsmonitor");
@@ -225,7 +225,7 @@ void remove_fsmonitor(struct index_state *istate)
 
 void tweak_fsmonitor(struct index_state *istate)
 {
-       int i;
+       unsigned int i;
        int fsmonitor_enabled = git_config_get_fsmonitor();
 
        if (istate->fsmonitor_dirty) {
index 8489fa3244976bb3e489c030e726cf06f0e4e9b3..739318ab6d1060e3f5ef9eba0ab93aa560c1d246 100644 (file)
@@ -49,9 +49,10 @@ void refresh_fsmonitor(struct index_state *istate);
  * called any time the cache entry has been updated to reflect the
  * current state of the file on disk.
  */
-static inline void mark_fsmonitor_valid(struct cache_entry *ce)
+static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache_entry *ce)
 {
-       if (core_fsmonitor) {
+       if (core_fsmonitor && !(ce->ce_flags & CE_FSMONITOR_VALID)) {
+               istate->cache_changed = 1;
                ce->ce_flags |= CE_FSMONITOR_VALID;
                trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_clean '%s'", ce->name);
        }
index 20eb81cc92f947d872b31a179d43d97772ff25e4..da5b4ec4bc50e4e3adaba0f25820262b6a7436a0 100755 (executable)
@@ -972,7 +972,11 @@ sub coalesce_overlapping_hunks {
                        next;
                }
                if ($ofs_delta) {
-                       $n_ofs += $ofs_delta;
+                       if ($patch_mode_flavour{IS_REVERSE}) {
+                               $o_ofs -= $ofs_delta;
+                       } else {
+                               $n_ofs += $ofs_delta;
+                       }
                        $_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
                                                             $n_ofs, $n_cnt);
                }
index 5b79920f46a972437ff05966d042a84d44f050d9..c71a6832e2fa0a632dc93155d0fa2b727c659f5e 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -737,7 +737,7 @@ def extractLogMessageFromGitCommit(commit):
 
     ## fixme: title is first line of commit, not 1st paragraph.
     foundTitle = False
-    for log in read_pipe_lines("git cat-file commit %s" % commit):
+    for log in read_pipe_lines(["git", "cat-file", "commit", commit]):
        if not foundTitle:
            if len(log) == 1:
                foundTitle = True
@@ -1309,7 +1309,7 @@ def processContent(self, git_mode, relPath, contents):
 
 class Command:
     delete_actions = ( "delete", "move/delete", "purge" )
-    add_actions = ( "add", "move/add" )
+    add_actions = ( "add", "branch", "move/add" )
 
     def __init__(self):
         self.usage = "usage: %prog [options]"
index 13c172bd94fc5d4a9658b27fae9733f73a272376..2d0e44656cc6ca4cc0cd8b579a1ebd8798e90b5f 100755 (executable)
@@ -65,6 +65,8 @@ test -z "$head" && die "fatal: Not a valid revision: $local"
 headrev=$(git rev-parse --verify --quiet "$head"^0)
 test -z "$headrev" && die "fatal: Ambiguous revision: $local"
 
+local_sha1=$(git rev-parse --verify --quiet "$head")
+
 # Was it a branch with a description?
 branch_name=${head#refs/heads/}
 if test "z$branch_name" = "z$headref" ||
@@ -77,43 +79,53 @@ merge_base=$(git merge-base $baserev $headrev) ||
 die "fatal: No commits in common between $base and $head"
 
 # $head is the refname from the command line.
-# If a ref with the same name as $head exists at the remote
-# and their values match, use that.
-#
-# Otherwise find a random ref that matches $headrev.
+# Find a ref with the same name as $head that exists at the remote
+# and points to the same commit as the local object.
 find_matching_ref='
        my ($head,$headrev) = (@ARGV);
-       my ($found);
+       my $pattern = qr{/\Q$head\E$};
+       my ($remote_sha1, $found);
 
        while (<STDIN>) {
                chomp;
                my ($sha1, $ref, $deref) = /^(\S+)\s+([^^]+)(\S*)$/;
-               my ($pattern);
-               next unless ($sha1 eq $headrev);
 
-               $pattern="/$head\$";
-               if ($ref eq $head) {
-                       $found = $ref;
-               }
-               if ($ref =~ /$pattern/) {
-                       $found = $ref;
-               }
                if ($sha1 eq $head) {
-                       $found = $sha1;
+                       $found = $remote_sha1 = $sha1;
+                       break;
+               }
+
+               if ($ref eq $head || $ref =~ $pattern) {
+                       if ($deref eq "") {
+                               # Remember the matching object on the remote side
+                               $remote_sha1 = $sha1;
+                       }
+                       if ($sha1 eq $headrev) {
+                               $found = $ref;
+                               break;
+                       }
                }
        }
        if ($found) {
-               print "$found\n";
+               $remote_sha1 = $headrev if ! defined $remote_sha1;
+               print "$remote_sha1 $found\n";
        }
 '
 
-ref=$(git ls-remote "$url" | @@PERL@@ -e "$find_matching_ref" "${remote:-HEAD}" "$headrev")
+set fnord $(git ls-remote "$url" | @@PERL@@ -e "$find_matching_ref" "${remote:-HEAD}" "$headrev")
+remote_sha1=$2
+ref=$3
 
 if test -z "$ref"
 then
        echo "warn: No match for commit $headrev found at $url" >&2
        echo "warn: Are you sure you pushed '${remote:-HEAD}' there?" >&2
        status=1
+elif test "$local_sha1" != "$remote_sha1"
+then
+       echo "warn: $head found at $url but points to a different object" >&2
+       echo "warn: Are you sure you pushed '${remote:-HEAD}' there?" >&2
+       status=1
 fi
 
 # Special case: turn "for_linus" to "tags/for_linus" when it is correct
index 8ed274533f87198a74a3660809c25932fa43124a..d60115ca404edfedc492c55e5bc0f22fe0eaa5a2 100644 (file)
@@ -116,6 +116,9 @@ static void parse_gpg_output(struct signature_check *sigc)
        for (line = buf; *line; line = strchrnul(line+1, '\n')) {
                while (*line == '\n')
                        line++;
+               if (!*line)
+                       break;
+
                /* Skip lines that don't start with GNUPG status */
                if (!skip_prefix(line, "[GNUPG:] ", &line))
                        continue;
diff --git a/grep.c b/grep.c
index 0d50598acda6f1c41951d1d656ea701114473239..f7c3a5803e8ea0bf2c609e9eeec6764217641cfc 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1780,6 +1780,10 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
        enum grep_context ctx = GREP_CONTEXT_HEAD;
        xdemitconf_t xecfg;
 
+       if (!opt->status_only && gs->name == NULL)
+               BUG("grep call which could print a name requires "
+                   "grep_source.name be non-NULL");
+
        if (!opt->output)
                opt->output = std_output;
 
diff --git a/kwset.c b/kwset.c
index 4fb6455acaf1293c4f47f27eb6e47be4d39633e2..fc439e0667f137f3449635a37a32f8418d5041f0 100644 (file)
--- a/kwset.c
+++ b/kwset.c
 #include "compat/obstack.h"
 
 #define NCHAR (UCHAR_MAX + 1)
-#define obstack_chunk_alloc xmalloc
+/* adapter for `xmalloc()`, which takes `size_t`, not `long` */
+static void *obstack_chunk_alloc(long size)
+{
+       if (size < 0)
+               BUG("Cannot allocate a negative amount: %ld", size);
+       return xmalloc(size);
+}
 #define obstack_chunk_free free
 
 #define U(c) ((unsigned char) (c))
@@ -475,7 +481,7 @@ kwsprep (kwset_t kws)
        for (i = 0; i < NCHAR; ++i)
          kwset->next[i] = next[U(trans[i])];
       else
-       memcpy(kwset->next, next, NCHAR * sizeof(struct trie *));
+       COPY_ARRAY(kwset->next, next, NCHAR);
     }
 
   /* Fix things up for any translation table. */
index 53f90442c5da992808f09f6d764fcefc44d70ee0..36e1f774bcfc50d0475ad835464cec092314eb79 100644 (file)
@@ -356,13 +356,13 @@ static enum list_objects_filter_result filter_sparse(
                                            filename, &dtype, &filter_data->el,
                                            r->index);
                if (val < 0)
-                       val = filter_data->array_frame[filter_data->nr].defval;
+                       val = filter_data->array_frame[filter_data->nr - 1].defval;
 
                ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1,
                           filter_data->alloc);
-               filter_data->nr++;
                filter_data->array_frame[filter_data->nr].defval = val;
                filter_data->array_frame[filter_data->nr].child_prov_omit = 0;
+               filter_data->nr++;
 
                /*
                 * A directory with this tree OID may appear in multiple
@@ -387,16 +387,15 @@ static enum list_objects_filter_result filter_sparse(
 
        case LOFS_END_TREE:
                assert(obj->type == OBJ_TREE);
-               assert(filter_data->nr > 0);
+               assert(filter_data->nr > 1);
 
-               frame = &filter_data->array_frame[filter_data->nr];
-               filter_data->nr--;
+               frame = &filter_data->array_frame[--filter_data->nr];
 
                /*
                 * Tell our parent directory if any of our children were
                 * provisionally omitted.
                 */
-               filter_data->array_frame[filter_data->nr].child_prov_omit |=
+               filter_data->array_frame[filter_data->nr - 1].child_prov_omit |=
                        frame->child_prov_omit;
 
                /*
@@ -412,7 +411,7 @@ static enum list_objects_filter_result filter_sparse(
                assert(obj->type == OBJ_BLOB);
                assert((obj->flags & SEEN) == 0);
 
-               frame = &filter_data->array_frame[filter_data->nr];
+               frame = &filter_data->array_frame[filter_data->nr - 1];
 
                dtype = DT_REG;
                val = is_excluded_from_list(pathname, strlen(pathname),
@@ -453,7 +452,7 @@ static enum list_objects_filter_result filter_sparse(
 static void filter_sparse_free(void *filter_data)
 {
        struct filter_sparse_data *d = filter_data;
-       /* TODO free contents of 'd' */
+       free(d->array_frame);
        free(d);
 }
 
@@ -472,6 +471,7 @@ static void *filter_sparse_oid__init(
        ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
        d->array_frame[d->nr].defval = 0; /* default to include */
        d->array_frame[d->nr].child_prov_omit = 0;
+       d->nr++;
 
        *filter_fn = filter_sparse;
        *filter_free_fn = filter_sparse_free;
index 0a7dbc6442fad37fd9e2ce72866b04b134818181..818aef70a09e7cedc2f241f235302e69969b2e3b 100644 (file)
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -57,7 +57,8 @@ static int send_ref(const char *refname, const struct object_id *oid,
                if (!symref_target)
                        die("'%s' is a symref but it is not?", refname);
 
-               strbuf_addf(&refline, " symref-target:%s", symref_target);
+               strbuf_addf(&refline, " symref-target:%s",
+                           strip_namespace(symref_target));
        }
 
        if (data->peel) {
index b4861bc7b02a93bd5f3659098764f535bb1f51c1..695908609f40f9cbb3960162a311af5d452610e2 100644 (file)
@@ -345,8 +345,9 @@ static int handle_range_dir(
        else {
                int begin = k_start;
                int end = k_end;
+               assert(begin >= 0);
                while (begin < end) {
-                       int mid = (begin + end) >> 1;
+                       int mid = begin + ((end - begin) >> 1);
                        int cmp = strncmp(istate->cache[mid]->name, prefix->buf, prefix->len);
                        if (cmp == 0) /* mid has same prefix; look in second part */
                                begin = mid + 1;
index 272e01e452b97bd8598a76d6facc5a6f803b579a..49f56ab8d9608919808ecebe71b9deb30c53980b 100644 (file)
@@ -277,10 +277,14 @@ struct object_info {
 #define OBJECT_INFO_IGNORE_LOOSE 16
 /*
  * Do not attempt to fetch the object if missing (even if fetch_is_missing is
- * nonzero). This is meant for bulk prefetching of missing blobs in a partial
- * clone. Implies OBJECT_INFO_QUICK.
+ * nonzero).
  */
-#define OBJECT_INFO_FOR_PREFETCH (32 + OBJECT_INFO_QUICK)
+#define OBJECT_INFO_SKIP_FETCH_OBJECT 32
+/*
+ * This is meant for bulk prefetching of missing blobs in a partial
+ * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
+ */
+#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
 
 int oid_object_info_extended(struct repository *r,
                             const struct object_id *,
index e81d47a79cd6eb42fae7c104be0e9ac1e5173e79..cf1a2b708612a0e335893fadee0952e620400c5f 100644 (file)
--- a/object.c
+++ b/object.c
@@ -517,7 +517,7 @@ void raw_object_store_clear(struct raw_object_store *o)
        o->loaded_alternates = 0;
 
        INIT_LIST_HEAD(&o->packed_git_mru);
-       close_all_packs(o);
+       close_object_store(o);
        o->packed_git = NULL;
 }
 
index 49c8544ff4591e71e1845cd1b275d5fdb898b400..c0d83fdfed973de8574224e46fb0afd4be0a98c9 100644 (file)
@@ -16,6 +16,7 @@
 #include "tree.h"
 #include "object-store.h"
 #include "midx.h"
+#include "commit-graph.h"
 
 char *odb_pack_name(struct strbuf *buf,
                    const unsigned char *sha1,
@@ -336,7 +337,7 @@ void close_pack(struct packed_git *p)
        close_pack_index(p);
 }
 
-void close_all_packs(struct raw_object_store *o)
+void close_object_store(struct raw_object_store *o)
 {
        struct packed_git *p;
 
@@ -350,6 +351,8 @@ void close_all_packs(struct raw_object_store *o)
                close_midx(o->multi_pack_index);
                o->multi_pack_index = NULL;
        }
+
+       close_commit_graph(o);
 }
 
 /*
@@ -640,7 +643,7 @@ unsigned char *use_pack(struct packed_git *p,
                        while (packed_git_limit < pack_mapped
                                && unuse_one_window(p))
                                ; /* nothing */
-                       win->base = xmmap(NULL, win->len,
+                       win->base = xmmap_gently(NULL, win->len,
                                PROT_READ, MAP_PRIVATE,
                                p->pack_fd, win->offset);
                        if (win->base == MAP_FAILED)
@@ -1269,7 +1272,7 @@ static enum object_type packed_to_object_type(struct repository *r,
                if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {
                        poi_stack_alloc = alloc_nr(poi_stack_nr);
                        ALLOC_ARRAY(poi_stack, poi_stack_alloc);
-                       memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);
+                       COPY_ARRAY(poi_stack, small_poi_stack, poi_stack_nr);
                } else {
                        ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);
                }
@@ -1679,8 +1682,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
                    && delta_stack == small_delta_stack) {
                        delta_stack_alloc = alloc_nr(delta_stack_nr);
                        ALLOC_ARRAY(delta_stack, delta_stack_alloc);
-                       memcpy(delta_stack, small_delta_stack,
-                              sizeof(*delta_stack)*delta_stack_nr);
+                       COPY_ARRAY(delta_stack, small_delta_stack,
+                                  delta_stack_nr);
                } else {
                        ALLOC_GROW(delta_stack, delta_stack_nr+1, delta_stack_alloc);
                }
index b678d35c0b6df11623f2d29f7b7ea7dfe0e1bea1..81e868d55a9b1f1aeaafa4925a72ae5c53af86e9 100644 (file)
@@ -90,7 +90,7 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value);
 unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
 void close_pack_windows(struct packed_git *);
 void close_pack(struct packed_git *);
-void close_all_packs(struct raw_object_store *o);
+void close_object_store(struct raw_object_store *o);
 void unuse_pack(struct pack_window **);
 void clear_delta_base_cache(void);
 struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
diff --git a/pager.c b/pager.c
index 4168460ae92ceb18b4a31c4d0524b411231cf137..41446d4f0543df18fb2430188d886ed1975a55d9 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -177,6 +177,26 @@ int term_columns(void)
        return term_columns_at_startup;
 }
 
+/*
+ * Clear the entire line, leave cursor in first column.
+ */
+void term_clear_line(void)
+{
+       if (is_terminal_dumb())
+               /*
+                * Fall back to print a terminal width worth of space
+                * characters (hoping that the terminal is still as wide
+                * as it was upon the first call to term_columns()).
+                */
+               fprintf(stderr, "\r%*s\r", term_columns(), "");
+       else
+               /*
+                * On non-dumb terminals use an escape sequence to clear
+                * the whole line, no matter how wide the terminal.
+                */
+               fputs("\r\033[K", stderr);
+}
+
 /*
  * How many columns do we need to show this number in decimal?
  */
index e73600ee7841a299e060369ca9eecf46d5a7fb0f..ed6eaa47388af8d33398e7c9652c622030e75147 100644 (file)
@@ -78,7 +78,7 @@ static void *preload_thread(void *_data)
                if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY|CE_MATCH_IGNORE_FSMONITOR))
                        continue;
                ce_mark_uptodate(ce);
-               mark_fsmonitor_valid(ce);
+               mark_fsmonitor_valid(index, ce);
        } while (--nr > 0);
        if (p->progress) {
                struct progress_data *pd = p->progress;
index ced0485257d3190f0c3ad8b89f15fa47c8660fad..e4ed14effe1aabdef50155b932a96e6648ff4707 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -106,8 +106,8 @@ static void setup_commit_formats(void)
        commit_formats_len = ARRAY_SIZE(builtin_formats);
        builtin_formats_len = commit_formats_len;
        ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
-       memcpy(commit_formats, builtin_formats,
-              sizeof(*builtin_formats)*ARRAY_SIZE(builtin_formats));
+       COPY_ARRAY(commit_formats, builtin_formats,
+                  ARRAY_SIZE(builtin_formats));
 
        git_config(git_pretty_formats_config, NULL);
 }
index a2e8cf64a8d1aa2f94c745bbb5098b9c771f3a05..095dcd0ddff2132a4dcfd59486ee4a5ddfa4684f 100644 (file)
@@ -88,7 +88,6 @@ static void display(struct progress *progress, uint64_t n, const char *done)
        const char *tp;
        struct strbuf *counters_sb = &progress->counters_sb;
        int show_update = 0;
-       int last_count_len = counters_sb->len;
 
        if (progress->delay && (!progress_update || --progress->delay))
                return;
@@ -116,26 +115,21 @@ static void display(struct progress *progress, uint64_t n, const char *done)
        if (show_update) {
                if (is_foreground_fd(fileno(stderr)) || done) {
                        const char *eol = done ? done : "\r";
-                       size_t clear_len = counters_sb->len < last_count_len ?
-                                       last_count_len - counters_sb->len + 1 :
-                                       0;
-                       size_t progress_line_len = progress->title_len +
-                                               counters_sb->len + 2;
-                       int cols = term_columns();
 
+                       term_clear_line();
                        if (progress->split) {
-                               fprintf(stderr, "  %s%*s", counters_sb->buf,
-                                       (int) clear_len, eol);
-                       } else if (!done && cols < progress_line_len) {
-                               clear_len = progress->title_len + 1 < cols ?
-                                           cols - progress->title_len - 1 : 0;
-                               fprintf(stderr, "%s:%*s\n  %s%s",
-                                       progress->title, (int) clear_len, "",
-                                       counters_sb->buf, eol);
+                               fprintf(stderr, "  %s%s", counters_sb->buf,
+                                       eol);
+                       } else if (!done &&
+                                  /* The "+ 2" accounts for the ": ". */
+                                  term_columns() < progress->title_len +
+                                                   counters_sb->len + 2) {
+                               fprintf(stderr, "%s:\n  %s%s",
+                                       progress->title, counters_sb->buf, eol);
                                progress->split = 1;
                        } else {
-                               fprintf(stderr, "%s: %s%*s", progress->title,
-                                       counters_sb->buf, (int) clear_len, eol);
+                               fprintf(stderr, "%s: %s%s", progress->title,
+                                       counters_sb->buf, eol);
                        }
                        fflush(stderr);
                }
index 22e7b9944e35d257b144fe06dce2073c91d4819f..93a897f240696c82d45e4189266fe187c58f0b1b 100644 (file)
@@ -195,7 +195,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
  * cache, ie the parts that aren't tracked by GIT, and only used
  * to validate the cache.
  */
-void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
+void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st)
 {
        fill_stat_data(&ce->ce_stat_data, st);
 
@@ -204,7 +204,7 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 
        if (S_ISREG(st->st_mode)) {
                ce_mark_uptodate(ce);
-               mark_fsmonitor_valid(ce);
+               mark_fsmonitor_valid(istate, ce);
        }
 }
 
@@ -549,7 +549,7 @@ static int index_name_stage_pos(const struct index_state *istate, const char *na
        first = 0;
        last = istate->cache_nr;
        while (last > first) {
-               int next = (last + first) >> 1;
+               int next = first + ((last - first) >> 1);
                struct cache_entry *ce = istate->cache[next];
                int cmp = cache_name_stage_compare(name, namelen, stage, ce->name, ce_namelen(ce), ce_stage(ce));
                if (!cmp)
@@ -728,7 +728,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        memcpy(ce->name, path, namelen);
        ce->ce_namelen = namelen;
        if (!intent_only)
-               fill_stat_cache_info(ce, st);
+               fill_stat_cache_info(istate, ce, st);
        else
                ce->ce_flags |= CE_INTENT_TO_ADD;
 
@@ -1432,7 +1432,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                         */
                        if (!S_ISGITLINK(ce->ce_mode)) {
                                ce_mark_uptodate(ce);
-                               mark_fsmonitor_valid(ce);
+                               mark_fsmonitor_valid(istate, ce);
                        }
                        return ce;
                }
@@ -1447,7 +1447,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        updated = make_empty_cache_entry(istate, ce_namelen(ce));
        copy_cache_entry(updated, ce);
        memcpy(updated->name, ce->name, ce->ce_namelen + 1);
-       fill_stat_cache_info(updated, &st);
+       fill_stat_cache_info(istate, updated, &st);
        /*
         * If ignore_valid is not set, we should leave CE_VALID bit
         * alone.  Otherwise, paths marked with --no-assume-unchanged
@@ -2140,7 +2140,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                die(_("%s: index file smaller than expected"), path);
 
-       mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       mmap = xmmap_gently(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
        if (mmap == MAP_FAILED)
                die_errno(_("%s: unable to map index file"), path);
        close(fd);
index f88a97fb10a322c21062ec8c102482677cfd0feb..1d206fd22456cce12f7496321df8a47fcb94db9e 100644 (file)
@@ -279,7 +279,7 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
 int sequencer_remove_state(struct replay_opts *opts)
 {
        struct strbuf buf = STRBUF_INIT;
-       int i;
+       int i, ret = 0;
 
        if (is_rebase_i(opts) &&
            strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
@@ -288,8 +288,10 @@ int sequencer_remove_state(struct replay_opts *opts)
                        char *eol = strchr(p, '\n');
                        if (eol)
                                *eol = '\0';
-                       if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0)
+                       if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0) {
                                warning(_("could not delete '%s'"), p);
+                               ret = -1;
+                       }
                        if (!eol)
                                break;
                        p = eol + 1;
@@ -305,10 +307,11 @@ int sequencer_remove_state(struct replay_opts *opts)
 
        strbuf_reset(&buf);
        strbuf_addstr(&buf, get_dir(opts));
-       remove_dir_recursively(&buf, 0);
+       if (remove_dir_recursively(&buf, 0))
+               ret = error(_("could not remove '%s'"), buf.buf);
        strbuf_release(&buf);
 
-       return 0;
+       return ret;
 }
 
 static const char *action_name(const struct replay_opts *opts)
@@ -3731,8 +3734,11 @@ static int pick_commits(struct repository *r,
                        unlink(git_path_merge_head(the_repository));
                        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
 
-                       if (item->command == TODO_BREAK)
+                       if (item->command == TODO_BREAK) {
+                               if (!opts->verbose)
+                                       term_clear_line();
                                return stopped_at_head(r);
+                       }
                }
                if (item->command <= TODO_SQUASH) {
                        if (is_rebase_i(opts))
@@ -3754,11 +3760,14 @@ static int pick_commits(struct repository *r,
                        }
                        if (item->command == TODO_EDIT) {
                                struct commit *commit = item->commit;
-                               if (!res)
+                               if (!res) {
+                                       if (!opts->verbose)
+                                               term_clear_line();
                                        fprintf(stderr,
                                                _("Stopped at %s...  %.*s\n"),
                                                short_commit_name(commit),
                                                item->arg_len, arg);
+                               }
                                return error_with_patch(r, commit,
                                        arg, item->arg_len, opts, res, !res);
                        }
@@ -3796,6 +3805,8 @@ static int pick_commits(struct repository *r,
                        int saved = *end_of_arg;
                        struct stat st;
 
+                       if (!opts->verbose)
+                               term_clear_line();
                        *end_of_arg = '\0';
                        res = do_exec(r, arg);
                        *end_of_arg = saved;
@@ -3954,10 +3965,13 @@ static int pick_commits(struct repository *r,
                }
                apply_autostash(opts);
 
-               if (!opts->quiet)
+               if (!opts->quiet) {
+                       if (!opts->verbose)
+                               term_clear_line();
                        fprintf(stderr,
                                "Successfully rebased and updated %s.\n",
                                head_ref.buf);
+               }
 
                strbuf_release(&buf);
                strbuf_release(&head_ref);
index 41274d098bc3b07b7f0130e7b9efcc20873cf46d..92187c70db650ee0e4d5ea4bf3435e84a51c44b2 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "dir.h"
 #include "repository.h"
 #include "refs.h"
 #include "object.h"
@@ -191,26 +192,21 @@ static void init_pack_info(const char *infofile, int force)
 {
        struct packed_git *p;
        int stale;
-       int i = 0;
+       int i;
+       size_t alloc = 0;
 
        for (p = get_all_packs(the_repository); p; p = p->next) {
                /* we ignore things on alternate path since they are
                 * not available to the pullers in general.
                 */
-               if (!p->pack_local)
-                       continue;
-               i++;
-       }
-       num_pack = i;
-       info = xcalloc(num_pack, sizeof(struct pack_info *));
-       for (i = 0, p = get_all_packs(the_repository); p; p = p->next) {
-               if (!p->pack_local)
+               if (!p->pack_local || !file_exists(p->pack_name))
                        continue;
-               assert(i < num_pack);
+
+               i = num_pack++;
+               ALLOC_GROW(info, num_pack, alloc);
                info[i] = xcalloc(1, sizeof(struct pack_info));
                info[i]->p = p;
                info[i]->old_num = -1;
-               i++;
        }
 
        if (infofile && !force)
index cecfdd36c7e696dce6188aea3398fbe8857d798b..e7430b9aa8ecf136a7d625ee059822e1e1a74b26 100644 (file)
@@ -249,7 +249,7 @@ sorted_string_list_member (const string_list_ty *slp, const char *s)
        {
          /* Here we know that if s is in the list, it is at an index j
             with j1 <= j < j2.  */
-         size_t j = (j1 + j2) >> 1;
+         size_t j = j1 + ((j2 - j1) >> 1);
          int result = strcmp (slp->item[j], s);
 
          if (result > 0)
index ed5c50dac427f2f3aa2b9b7b203bf2355049b163..888b6024d5de050753765e37b65ea0521d91f9fd 100644 (file)
@@ -1379,7 +1379,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
                /* Check if it is a missing object */
                if (fetch_if_missing && repository_format_partial_clone &&
                    !already_retried && r == the_repository &&
-                   !(flags & OBJECT_INFO_FOR_PREFETCH)) {
+                   !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
                        /*
                         * TODO Investigate having fetch_object() return
                         * TODO error/success and stopping the music here.
index 77a224aafb8c63a237f868bff23e6d3cd418bb44..77c5ed6a18e7849c4b823f9056dfb34cca951e15 100755 (executable)
@@ -175,7 +175,7 @@ test_expect_success 'reinit' '
 test_expect_success 'init with --template' '
        mkdir template-source &&
        echo content >template-source/file &&
-       git init --template=../template-source template-custom &&
+       git init --template=template-source template-custom &&
        test_cmp template-source/file template-custom/.git/file
 '
 
@@ -311,8 +311,8 @@ test_expect_success 'init prefers command line to GIT_DIR' '
 test_expect_success 'init with separate gitdir' '
        rm -rf newdir &&
        git init --separate-git-dir realgitdir newdir &&
-       echo "gitdir: $(pwd)/realgitdir" >expected &&
-       test_cmp expected newdir/.git &&
+       newdir_git="$(cat newdir/.git)" &&
+       test_cmp_fspath "$(pwd)/realgitdir" "${newdir_git#gitdir: }" &&
        test_path_is_dir realgitdir/refs
 '
 
@@ -361,12 +361,9 @@ test_expect_success 're-init on .git file' '
 '
 
 test_expect_success 're-init to update git link' '
-       (
-       cd newdir &&
-       git init --separate-git-dir ../surrealgitdir
-       ) &&
-       echo "gitdir: $(pwd)/surrealgitdir" >expected &&
-       test_cmp expected newdir/.git &&
+       git -C newdir init --separate-git-dir ../surrealgitdir &&
+       newdir_git="$(cat newdir/.git)" &&
+       test_cmp_fspath "$(pwd)/surrealgitdir" "${newdir_git#gitdir: }" &&
        test_path_is_dir surrealgitdir/refs &&
        test_path_is_missing realgitdir/refs
 '
@@ -374,12 +371,9 @@ test_expect_success 're-init to update git link' '
 test_expect_success 're-init to move gitdir' '
        rm -rf newdir realgitdir surrealgitdir &&
        git init newdir &&
-       (
-       cd newdir &&
-       git init --separate-git-dir ../realgitdir
-       ) &&
-       echo "gitdir: $(pwd)/realgitdir" >expected &&
-       test_cmp expected newdir/.git &&
+       git -C newdir init --separate-git-dir ../realgitdir &&
+       newdir_git="$(cat newdir/.git)" &&
+       test_cmp_fspath "$(pwd)/realgitdir" "${newdir_git#gitdir: }" &&
        test_path_is_dir realgitdir/refs
 '
 
index ebc49561acc08e916b2ab78cd84e6729c65f5803..015fac8b5d077165c7f9ac8090fd4e2ac12a7cb3 100755 (executable)
@@ -210,4 +210,10 @@ test_expect_success MINGW 'verify curlies are quoted properly' '
        test_cmp expect actual
 '
 
+test_expect_success MINGW 'can spawn with argv[0] containing spaces' '
+       cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" ./ &&
+       test_must_fail "$PWD/test-fake-ssh$X" 2>err &&
+       grep TRASH_DIRECTORY err
+'
+
 test_done
index dfece751b572821464c390ee68f26d91624e2a33..2dc853d1be5f0fe012d40b5d020fcbfd7638ccb7 100755 (executable)
@@ -136,7 +136,7 @@ test_expect_success POSIXPERM 'forced modes' '
        (
                cd new &&
                umask 002 &&
-               git init --shared=0660 --template=../templates &&
+               git init --shared=0660 --template=templates &&
                >frotz &&
                git add frotz &&
                git commit -a -m initial &&
@@ -192,7 +192,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)'
        umask 0022 &&
        git init --bare --shared=0666 child.git &&
        test_path_is_missing child.git/foo &&
-       git init --bare --template=../templates child.git &&
+       git init --bare --template=templates child.git &&
        echo "-rw-rw-rw-" >expect &&
        test_modebits child.git/foo >actual &&
        test_cmp expect actual
@@ -203,7 +203,7 @@ test_expect_success POSIXPERM 'template can set core.sharedrepository' '
        umask 0022 &&
        git config core.sharedrepository 0666 &&
        cp .git/config templates/config &&
-       git init --bare --template=../templates child.git &&
+       git init --bare --template=templates child.git &&
        echo "-rw-rw-rw-" >expect &&
        test_modebits child.git/HEAD >actual &&
        test_cmp expect actual
index 286bba35d8ae06f97cbf59263cd472975036deaa..d83a9f0fdc0faaef9756166f7b6223212514a7d6 100755 (executable)
@@ -570,4 +570,16 @@ test_expect_success '"add" an existing locked but missing worktree' '
        git worktree add --force --force --detach gnoo
 '
 
+test_expect_success '"add" should not fail because of another bad worktree' '
+       git init add-fail &&
+       (
+               cd add-fail &&
+               test_commit first &&
+               mkdir sub &&
+               git worktree add sub/to-be-deleted &&
+               rm -rf sub &&
+               git worktree add second
+       )
+'
+
 test_done
index 1723e1a858585d9e83d7662326a6f337db7e1fa6..461dd539ffd4803c62d54e22e8921fbefa2c0786 100755 (executable)
@@ -75,11 +75,10 @@ test_expect_success 'rebase --keep-empty' '
        test_line_count = 6 actual
 '
 
-cat > expect <<EOF
-error: nothing to do
-EOF
-
 test_expect_success 'rebase -i with empty HEAD' '
+       cat >expect <<-\EOF &&
+       error: nothing to do
+       EOF
        set_fake_editor &&
        test_must_fail env FAKE_LINES="1 exec_true" git rebase -i HEAD^ >actual 2>&1 &&
        test_i18ncmp expect actual
@@ -237,25 +236,23 @@ test_expect_success 'exchange two commits' '
        test G = $(git cat-file commit HEAD | sed -ne \$p)
 '
 
-cat > expect << EOF
-diff --git a/file1 b/file1
-index f70f10e..fd79235 100644
---- a/file1
-+++ b/file1
-@@ -1 +1 @@
--A
-+G
-EOF
-
-cat > expect2 << EOF
-<<<<<<< HEAD
-D
-=======
-G
->>>>>>> 5d18e54... G
-EOF
-
 test_expect_success 'stop on conflicting pick' '
+       cat >expect <<-\EOF &&
+       diff --git a/file1 b/file1
+       index f70f10e..fd79235 100644
+       --- a/file1
+       +++ b/file1
+       @@ -1 +1 @@
+       -A
+       +G
+       EOF
+       cat >expect2 <<-\EOF &&
+       <<<<<<< HEAD
+       D
+       =======
+       G
+       >>>>>>> 5d18e54... G
+       EOF
        git tag new-branch1 &&
        set_fake_editor &&
        test_must_fail git rebase -i master &&
@@ -495,15 +492,14 @@ test_expect_success 'commit message retained after conflict' '
        git branch -D conflict-squash
 '
 
-cat > expect-squash-fixup << EOF
-B
-
-D
+test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' '
+       cat >expect-squash-fixup <<-\EOF &&
+       B
 
-ONCE
-EOF
+       D
 
-test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' '
+       ONCE
+       EOF
        git checkout -b squash-fixup E &&
        base=$(git rev-parse HEAD~4) &&
        set_fake_editor &&
@@ -799,13 +795,12 @@ test_expect_success 'rebase -i can copy notes' '
        test "a note" = "$(git notes show HEAD)"
 '
 
-cat >expect <<EOF
-an earlier note
-
-a note
-EOF
-
 test_expect_success 'rebase -i can copy notes over a fixup' '
+       cat >expect <<-\EOF &&
+       an earlier note
+
+       a note
+       EOF
        git reset --hard n3 &&
        git notes add -m"an earlier note" n2 &&
        set_fake_editor &&
@@ -1031,7 +1026,7 @@ test_expect_success 'rebase -i --root reword root commit' '
        test -z "$(git show -s --format=%p HEAD^)"
 '
 
-test_expect_success 'rebase -i --root when root has untracked file confilct' '
+test_expect_success 'rebase -i --root when root has untracked file conflict' '
        test_when_finished "reset_rebase" &&
        git checkout -b failing-root-pick A &&
        echo x >file2 &&
@@ -1304,52 +1299,37 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' '
                actual
 '
 
-cat >expect <<EOF
-Warning: some commits may have been dropped accidentally.
-Dropped commits (newer to older):
- - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
-To avoid this message, use "drop" to explicitly remove a commit.
-
-Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
-The possible behaviours are: ignore, warn, error.
-
-Rebasing (1/4)
-Rebasing (2/4)
-Rebasing (3/4)
-Rebasing (4/4)
-Successfully rebased and updated refs/heads/missing-commit.
-EOF
-
-cr_to_nl () {
-       tr '\015' '\012'
-}
-
 test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' '
+       cat >expect <<-EOF &&
+       Warning: some commits may have been dropped accidentally.
+       Dropped commits (newer to older):
+        - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
+       To avoid this message, use "drop" to explicitly remove a commit.
+       EOF
        test_config rebase.missingCommitsCheck warn &&
        rebase_setup_and_clean missing-commit &&
        set_fake_editor &&
        FAKE_LINES="1 2 3 4" \
                git rebase -i --root 2>actual.2 &&
-       cr_to_nl <actual.2 >actual &&
+       head -n4 actual.2 >actual &&
        test_i18ncmp expect actual &&
        test D = $(git cat-file commit HEAD | sed -ne \$p)
 '
 
-cat >expect <<EOF
-Warning: some commits may have been dropped accidentally.
-Dropped commits (newer to older):
- - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
- - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2)
-To avoid this message, use "drop" to explicitly remove a commit.
-
-Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
-The possible behaviours are: ignore, warn, error.
-
-You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
-Or you can abort the rebase with 'git rebase --abort'.
-EOF
-
 test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
+       cat >expect <<-EOF &&
+       Warning: some commits may have been dropped accidentally.
+       Dropped commits (newer to older):
+        - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
+        - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2)
+       To avoid this message, use "drop" to explicitly remove a commit.
+
+       Use '\''git config rebase.missingCommitsCheck'\'' to change the level of warnings.
+       The possible behaviours are: ignore, warn, error.
+
+       You can fix this with '\''git rebase --edit-todo'\'' and then run '\''git rebase --continue'\''.
+       Or you can abort the rebase with '\''git rebase --abort'\''.
+       EOF
        test_config rebase.missingCommitsCheck error &&
        rebase_setup_and_clean missing-commit &&
        set_fake_editor &&
index bdaa511bb0ae1082568e83781252f667b39cda8a..4eff14dae53223fb432ff5d9147543850a2c9ad5 100755 (executable)
@@ -265,4 +265,12 @@ test_expect_success '--reschedule-failed-exec' '
        test_i18ngrep "has been rescheduled" err
 '
 
+test_expect_success 'rebase.reschedulefailedexec only affects `rebase -i`' '
+       test_config rebase.reschedulefailedexec true &&
+       test_must_fail git rebase -x false HEAD^ &&
+       grep "^exec false" .git/rebase-merge/git-rebase-todo &&
+       git rebase --abort &&
+       git rebase HEAD^
+'
+
 test_done
index 2d1094e4831a88205133558d2ca6ac5ac07209d1..9186e90127712feaf92fe94e5bdfce02528fcf5f 100755 (executable)
@@ -49,7 +49,7 @@ create_expected_success_interactive () {
        $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
        HEAD is now at $(git rev-parse --short feature-branch) third commit
        Rebasing (1/2)QRebasing (2/2)QApplied autostash.
-       Successfully rebased and updated refs/heads/rebased-feature-branch.
+       Q                                                                                QSuccessfully rebased and updated refs/heads/rebased-feature-branch.
        EOF
 }
 
@@ -73,7 +73,7 @@ create_expected_failure_interactive () {
        Rebasing (1/2)QRebasing (2/2)QApplying autostash resulted in conflicts.
        Your changes are safe in the stash.
        You can run "git stash pop" or "git stash drop" at any time.
-       Successfully rebased and updated refs/heads/rebased-feature-branch.
+       Q                                                                                QSuccessfully rebased and updated refs/heads/rebased-feature-branch.
        EOF
 }
 
index 42ba5b9f0981b2b7ce98e1c5c55012ef61757bab..f0814d5280c6755ad1f9f8378a6a32d32ffaee1d 100755 (executable)
@@ -224,8 +224,24 @@ test_expect_success 'refs/rewritten/* is worktree-local' '
        test_cmp_rev HEAD "$(cat wt/b)"
 '
 
+test_expect_success '--abort cleans up refs/rewritten' '
+       git checkout -b abort-cleans-refs-rewritten H &&
+       GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ &&
+       git rev-parse --verify refs/rewritten/onto &&
+       git rebase --abort &&
+       test_must_fail git rev-parse --verify refs/rewritten/onto
+'
+
+test_expect_success '--quit cleans up refs/rewritten' '
+       git checkout -b quit-cleans-refs-rewritten H &&
+       GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ &&
+       git rev-parse --verify refs/rewritten/onto &&
+       git rebase --quit &&
+       test_must_fail git rev-parse --verify refs/rewritten/onto
+'
+
 test_expect_success 'post-rewrite hook and fixups work for merges' '
-       git checkout -b post-rewrite &&
+       git checkout -b post-rewrite &&
        test_commit same1 &&
        git reset --hard HEAD^ &&
        test_commit same2 &&
index 85ae7dc1e4618275413a8b498f43d43f3e0ead92..66282a720ee853e7442334c889e199978aac9260 100755 (executable)
@@ -252,6 +252,19 @@ test_expect_success 'choking "git rm" should not let it die with cruft' '
        test_path_is_missing .git/index.lock
 '
 
+test_expect_success 'Resolving by removal is not a warning-worthy event' '
+       git reset -q --hard &&
+       test_when_finished "rm -f .git/index.lock msg && git reset -q --hard" &&
+       blob=$(echo blob | git hash-object -w --stdin) &&
+       for stage in 1 2 3
+       do
+               echo "100644 $blob $stage       blob"
+       done | git update-index --index-info &&
+       git rm blob >msg 2>&1 &&
+       test_i18ngrep ! "needs merge" msg &&
+       test_must_fail git ls-files -s --error-unmatch blob
+'
+
 test_expect_success 'rm removes subdirectories recursively' '
        mkdir -p dir/subdir/subsubdir &&
        echo content >dir/subdir/subsubdir/file &&
index 65dfbc033a027df1a590cbfaf75ae47f4ed9c547..69991a3168f354b8bfefcd396a968e653bb352bd 100755 (executable)
@@ -639,4 +639,12 @@ test_expect_success 'add -p patch editing works with pathological context lines'
        test_cmp expected-2 actual
 '
 
+test_expect_success 'checkout -p works with pathological context lines' '
+       test_write_lines a a a a a a >a &&
+       git add a &&
+       test_write_lines a b a b a b a b a b a > a&&
+       test_write_lines s n n y q | git checkout -p &&
+       test_write_lines a b a b a a b a b a >expect &&
+       test_cmp expect a
+'
 test_done
index ea30d5f6a0f228971d29e257a89fca6ea594cecb..b22e671608119d37dd73bf6b0df41ce62e1a26f9 100755 (executable)
@@ -708,6 +708,24 @@ test_expect_success 'invalid ref of the form "n", n >= N' '
        git stash drop
 '
 
+test_expect_success 'valid ref of the form "n", n < N' '
+       git stash clear &&
+       echo bar5 >file &&
+       echo bar6 >file2 &&
+       git add file2 &&
+       git stash &&
+       git stash show 0 &&
+       git stash branch tmp 0 &&
+       git checkout master &&
+       git stash &&
+       git stash apply 0 &&
+       git reset --hard &&
+       git stash pop 0 &&
+       git stash &&
+       git stash drop 0 &&
+       test_must_fail git stash drop
+'
+
 test_expect_success 'branch: do not drop the stash if the branch exists' '
        git stash clear &&
        echo foo >file &&
index ab4670d23653eca46292b13ef1559584aae5c3a6..6b087df3dcbd01df9c7e533f9e039518beaa773a 100755 (executable)
@@ -2008,4 +2008,26 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
        test_cmp expected actual
 '
 
+# Note that the "6" in the expected hunk header below is funny, since we only
+# show 5 lines (the missing one was blank and thus ignored). This is how
+# --ignore-blank-lines behaves even without --function-context, and this test
+# is just checking the interaction of the two features. Don't take it as an
+# endorsement of that output.
+test_expect_success 'combine --ignore-blank-lines with --function-context' '
+       test_write_lines 1 "" 2 3 4 5 >a &&
+       test_write_lines 1    2 3 4   >b &&
+       test_must_fail git diff --no-index \
+               --ignore-blank-lines --function-context a b >actual.raw &&
+       sed -n "/@@/,\$p" <actual.raw >actual &&
+       cat <<-\EOF >expect &&
+       @@ -1,6 +1,4 @@
+        1
+        2
+        3
+        4
+       -5
+       EOF
+       test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4257-am-interactive.sh b/t/t4257-am-interactive.sh
new file mode 100755 (executable)
index 0000000..5344bd2
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='am --interactive tests'
+. ./test-lib.sh
+
+test_expect_success 'set up patches to apply' '
+       test_commit unrelated &&
+       test_commit no-conflict &&
+       test_commit conflict-patch file patch &&
+       git format-patch --stdout -2 >mbox &&
+
+       git reset --hard unrelated &&
+       test_commit conflict-master file master base
+'
+
+# Sanity check our setup.
+test_expect_success 'applying all patches generates conflict' '
+       test_must_fail git am mbox &&
+       echo resolved >file &&
+       git add -u &&
+       git am --resolved
+'
+
+test_expect_success 'interactive am can apply a single patch' '
+       git reset --hard base &&
+       # apply the first, but not the second
+       test_write_lines y n | git am -i mbox &&
+
+       echo no-conflict >expect &&
+       git log -1 --format=%s >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'interactive am can resolve conflict' '
+       git reset --hard base &&
+       # apply both; the second one will conflict
+       test_write_lines y y | test_must_fail git am -i mbox &&
+       echo resolved >file &&
+       git add -u &&
+       # interactive "--resolved" will ask us if we want to apply the result
+       echo y | git am -i --resolved &&
+
+       echo conflict-patch >expect &&
+       git log -1 --format=%s >actual &&
+       test_cmp expect actual &&
+
+       echo resolved >expect &&
+       git cat-file blob HEAD:file >actual &&
+       test_cmp expect actual
+'
+
+test_done
index fca001eb9bb5767b1aff6439dbc98e49ed3aaef8..852dcd913f1e746ba4a65763ae31ee96064f3fd2 100755 (executable)
@@ -246,4 +246,57 @@ test_expect_success 'request-pull ignores OPTIONS_KEEPDASHDASH poison' '
 
 '
 
+test_expect_success 'request-pull quotes regex metacharacters properly' '
+
+       rm -fr downstream.git &&
+       git init --bare downstream.git &&
+       (
+               cd local &&
+               git checkout initial &&
+               git merge --ff-only master &&
+               git tag -mrelease v2.0 &&
+               git push origin refs/tags/v2.0:refs/tags/v2-0 &&
+               test_must_fail git request-pull initial "$downstream_url" tags/v2.0 \
+                       2>../err
+       ) &&
+       grep "No match for commit .*" err &&
+       grep "Are you sure you pushed" err
+
+'
+
+test_expect_success 'pull request with mismatched object' '
+
+       rm -fr downstream.git &&
+       git init --bare downstream.git &&
+       (
+               cd local &&
+               git checkout initial &&
+               git merge --ff-only master &&
+               git push origin HEAD:refs/tags/full &&
+               test_must_fail git request-pull initial "$downstream_url" tags/full \
+                       2>../err
+       ) &&
+       grep "points to a different object" err &&
+       grep "Are you sure you pushed" err
+
+'
+
+test_expect_success 'pull request with stale object' '
+
+       rm -fr downstream.git &&
+       git init --bare downstream.git &&
+       (
+               cd local &&
+               git checkout initial &&
+               git merge --ff-only master &&
+               git push origin refs/tags/full &&
+               git tag -f -m"Thirty-one days" full &&
+               test_must_fail git request-pull initial "$downstream_url" tags/full \
+                       2>../err
+       ) &&
+       grep "points to a different object" err &&
+       grep "Are you sure you pushed" err
+
+'
+
 test_done
index 840ad4d8accbfef59e2c9ade82105cc717f6866c..5267c4be20e709bb1632c5b9786ffdb418bcb5c9 100755 (executable)
@@ -23,6 +23,14 @@ test_expect_success 'write graph with no packs' '
        test_path_is_file info/commit-graph
 '
 
+test_expect_success 'close with correct error on bad input' '
+       cd "$TRASH_DIRECTORY/full" &&
+       echo doesnotexist >in &&
+       { git commit-graph write --stdin-packs <in 2>stderr; ret=$?; } &&
+       test "$ret" = 1 &&
+       test_i18ngrep "error adding pack" stderr
+'
+
 test_expect_success 'create commits and repack' '
        cd "$TRASH_DIRECTORY/full" &&
        for i in $(test_seq 3)
index c88df78c0bffaae8f09fc2db79427d85a6f8ff48..75cbfcc392c8cd71e20d901a7a28bf7f6f73451a 100755 (executable)
@@ -124,4 +124,32 @@ test_expect_success 'try to update a hidden full ref' '
        test_must_fail git -C original push pushee-namespaced master
 '
 
+test_expect_success 'set up ambiguous HEAD' '
+       git init ambiguous &&
+       (
+               cd ambiguous &&
+               git commit --allow-empty -m foo &&
+               git update-ref refs/namespaces/ns/refs/heads/one HEAD &&
+               git update-ref refs/namespaces/ns/refs/heads/two HEAD &&
+               git symbolic-ref refs/namespaces/ns/HEAD \
+                       refs/namespaces/ns/refs/heads/two
+       )
+'
+
+test_expect_success 'clone chooses correct HEAD (v0)' '
+       GIT_NAMESPACE=ns git -c protocol.version=0 \
+               clone ambiguous ambiguous-v0 &&
+       echo refs/heads/two >expect &&
+       git -C ambiguous-v0 symbolic-ref HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'clone chooses correct HEAD (v2)' '
+       GIT_NAMESPACE=ns git -c protocol.version=2 \
+               clone ambiguous ambiguous-v2 &&
+       echo refs/heads/two >expect &&
+       git -C ambiguous-v2 symbolic-ref HEAD >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 8ef8763e063cf30da8af4a80079458cf8e18c56d..b86ddb60f2ea6ec1c177b8be5d056d064a1d7697 100755 (executable)
@@ -177,6 +177,55 @@ test_expect_success 'push (chunked)' '
         test $HEAD = $(git rev-parse --verify HEAD))
 '
 
+test_expect_success 'push --atomic also prevents branch creation, reports collateral' '
+       # Setup upstream repo - empty for now
+       d=$HTTPD_DOCUMENT_ROOT_PATH/atomic-branches.git &&
+       git init --bare "$d" &&
+       test_config -C "$d" http.receivepack true &&
+       up="$HTTPD_URL"/smart/atomic-branches.git &&
+
+       # Tell "$up" about two branches for now
+       test_commit atomic1 &&
+       test_commit atomic2 &&
+       git branch collateral &&
+       git push "$up" master collateral &&
+
+       # collateral is a valid push, but should be failed by atomic push
+       git checkout collateral &&
+       test_commit collateral1 &&
+
+       # Make master incompatible with upstream to provoke atomic
+       git checkout master &&
+       git reset --hard HEAD^ &&
+
+       # Add a new branch which should be failed by atomic push. This is a
+       # regression case.
+       git branch atomic &&
+
+       # --atomic should cause entire push to be rejected
+       test_must_fail git push --atomic "$up" master atomic collateral 2>output &&
+
+       # the new branch should not have been created upstream
+       test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
+
+       # upstream should still reflect atomic2, the last thing we pushed
+       # successfully
+       git rev-parse atomic2 >expected &&
+       # on master...
+       git -C "$d" rev-parse refs/heads/master >actual &&
+       test_cmp expected actual &&
+       # ...and collateral.
+       git -C "$d" rev-parse refs/heads/collateral >actual &&
+       test_cmp expected actual &&
+
+       # the failed refs should be indicated to the user
+       grep "^ ! .*rejected.* master -> master" output &&
+
+       # the collateral failure refs should be indicated to the user
+       grep "^ ! .*rejected.* atomic -> atomic .*atomic push failed" output &&
+       grep "^ ! .*rejected.* collateral -> collateral .*atomic push failed" output
+'
+
 test_expect_success 'push --all can push to empty repo' '
        d=$HTTPD_DOCUMENT_ROOT_PATH/empty-all.git &&
        git init --bare "$d" &&
@@ -213,7 +262,7 @@ test_expect_success TTY 'push shows progress when stderr is a tty' '
        cd "$ROOT_PATH"/test_repo_clone &&
        test_commit noisy &&
        test_terminal git push >output 2>&1 &&
-       test_i18ngrep "^Writing objects" output
+       test_i18ngrep "Writing objects" output
 '
 
 test_expect_success TTY 'push --quiet silences status and progress' '
@@ -228,7 +277,7 @@ test_expect_success TTY 'push --no-progress silences progress but not status' '
        test_commit no-progress &&
        test_terminal git push --no-progress >output 2>&1 &&
        test_i18ngrep "^To http" output &&
-       test_i18ngrep ! "^Writing objects" output
+       test_i18ngrep ! "Writing objects" output
 '
 
 test_expect_success 'push --progress shows progress to non-tty' '
@@ -236,7 +285,7 @@ test_expect_success 'push --progress shows progress to non-tty' '
        test_commit progress &&
        git push --progress >output 2>&1 &&
        test_i18ngrep "^To http" output &&
-       test_i18ngrep "^Writing objects" output
+       test_i18ngrep "Writing objects" output
 '
 
 test_expect_success 'http push gives sane defaults to reflog' '
index ac74626a7b667c3723569cfbca9c77bc264c6728..e38e54386795a0e05003e803dc79301ed1cd52d9 100755 (executable)
@@ -199,7 +199,7 @@ test_expect_success 'GIT_SMART_HTTP can disable smart http' '
 
 test_expect_success 'invalid Content-Type rejected' '
        test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual &&
-       grep "not valid:" actual
+       test_i18ngrep "not valid:" actual
 '
 
 test_expect_success 'create namespaced refs' '
@@ -301,11 +301,10 @@ test_expect_success CMDLINE_LIMIT \
        )
 '
 
-test_expect_success 'large fetch-pack requests can be split across POSTs' '
+test_expect_success 'large fetch-pack requests can be sent using chunked encoding' '
        GIT_TRACE_CURL=true git -c http.postbuffer=65536 \
                clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err &&
-       grep "^=> Send header: POST" err >posts &&
-       test_line_count = 2 posts
+       grep "^=> Send header: Transfer-Encoding: chunked" err
 '
 
 test_expect_success 'test allowreachablesha1inwant' '
@@ -466,7 +465,7 @@ test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '
 
 test_expect_success 'server-side error detected' '
        test_must_fail git clone $HTTPD_URL/error_smart/repo.git 2>actual &&
-       grep "server-side error" actual
+       test_i18ngrep "server-side error" actual
 '
 
 test_done
index de9d99cf88a5b72a3aa6e190124dff36e67818b6..37d76808d4a74b101f0606fc7a114fed6a8afa91 100755 (executable)
@@ -630,9 +630,8 @@ test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
        test_i18ngrep "the following paths have collided" icasefs/warning
 '
 
-partial_clone () {
+partial_clone_server () {
               SERVER="$1" &&
-              URL="$2" &&
 
        rm -rf "$SERVER" client &&
        test_create_repo "$SERVER" &&
@@ -642,8 +641,14 @@ partial_clone () {
        test_commit -C "$SERVER" two &&
        HASH2=$(git hash-object "$SERVER/two.t") &&
        test_config -C "$SERVER" uploadpack.allowfilter 1 &&
-       test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 &&
+       test_config -C "$SERVER" uploadpack.allowanysha1inwant 1
+}
 
+partial_clone () {
+              SERVER="$1" &&
+              URL="$2" &&
+
+       partial_clone_server "${SERVER}" &&
        git clone --filter=blob:limit=0 "$URL" client &&
 
        git -C client fsck &&
@@ -660,6 +665,11 @@ test_expect_success 'partial clone' '
        partial_clone server "file://$(pwd)/server"
 '
 
+test_expect_success 'partial clone with -o' '
+       partial_clone_server server &&
+       git clone -o blah --filter=blob:limit=0 "file://$(pwd)/server" client
+'
+
 test_expect_success 'partial clone: warn if server does not support object filtering' '
        rm -rf server client &&
        test_create_repo server &&
index cf39e9e2437f06b4725b61ad2194dd65b4857f82..2a0fb15cf175251df0a140aa4f5c56fd7885292d 100755 (executable)
@@ -14,6 +14,12 @@ test_expect_success 'setup' '
        git tag -d third
 '
 
+test_expect_success '"verify" needs a worktree' '
+       git bundle create tip.bundle -1 master &&
+       test_must_fail nongit git bundle verify ../tip.bundle 2>err &&
+       test_i18ngrep "need a repository" err
+'
+
 test_expect_success 'annotated tags can be excluded by rev-list options' '
        git bundle create bundle --all --since=7.Apr.2005.15:14:00.-0700 &&
        git ls-remote bundle > output &&
index 9a8f9886b3e2d82b5c10bf749d485f05bd364db6..b91ef548f86b0e250b8fdcd1b8b764c780218931 100755 (executable)
@@ -244,11 +244,25 @@ test_expect_success 'fetch what is specified on CLI even if already promised' '
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
-# Converts bytes into a form suitable for inclusion in a sed command. For
-# example, "printf 'ab\r\n' | hex_unpack" results in '\x61\x62\x0d\x0a'.
-sed_escape () {
-       perl -e '$/ = undef; $input = <>; print unpack("H2" x length($input), $input)' |
-               sed 's/\(..\)/\\x\1/g'
+# Converts bytes into their hexadecimal representation. For example,
+# "printf 'ab\r\n' | hex_unpack" results in '61620d0a'.
+hex_unpack () {
+       perl -e '$/ = undef; $input = <>; print unpack("H2" x length($input), $input)'
+}
+
+# Inserts $1 at the start of the string and every 2 characters thereafter.
+intersperse () {
+       sed 's/\(..\)/'$1'\1/g'
+}
+
+# Create a one-time-sed command to replace the existing packfile with $1.
+replace_packfile () {
+       # The protocol requires that the packfile be sent in sideband 1, hence
+       # the extra \x01 byte at the beginning.
+       printf "1,/packfile/!c %04x\\\\x01%s0000" \
+               "$(($(wc -c <$1) + 5))" \
+               "$(hex_unpack <$1 | intersperse '\\x')" \
+               >"$HTTPD_ROOT_PATH/one-time-sed"
 }
 
 test_expect_success 'upon cloning, check that all refs point to objects' '
@@ -270,10 +284,7 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
        # Replace the existing packfile with the crafted one. The protocol
        # requires that the packfile be sent in sideband 1, hence the extra
        # \x01 byte at the beginning.
-       printf "1,/packfile/!c %04x\\\\x01%s0000" \
-               "$(($(wc -c <incomplete.pack) + 5))" \
-               "$(sed_escape <incomplete.pack)" \
-               >"$HTTPD_ROOT_PATH/one-time-sed" &&
+       replace_packfile incomplete.pack &&
 
        # Use protocol v2 because the sed command looks for the "packfile"
        # section header.
@@ -313,10 +324,7 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
        # Replace the existing packfile with the crafted one. The protocol
        # requires that the packfile be sent in sideband 1, hence the extra
        # \x01 byte at the beginning.
-       printf "1,/packfile/!c %04x\\\\x01%s0000" \
-               "$(($(wc -c <incomplete.pack) + 5))" \
-               "$(sed_escape <incomplete.pack)" \
-               >"$HTTPD_ROOT_PATH/one-time-sed" &&
+       replace_packfile incomplete.pack &&
 
        # Use protocol v2 because the sed command looks for the "packfile"
        # section header.
@@ -331,4 +339,82 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
        ! test -e "$HTTPD_ROOT_PATH/one-time-sed"
 '
 
+test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '
+       SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
+       rm -rf "$SERVER" repo &&
+       test_create_repo "$SERVER" &&
+       test_config -C "$SERVER" uploadpack.allowfilter 1 &&
+       test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 &&
+
+       # Create a commit with 2 blobs to be used as delta bases.
+       for i in $(test_seq 10)
+       do
+               echo "this is a line" >>"$SERVER/foo.txt" &&
+               echo "this is another line" >>"$SERVER/have.txt"
+       done &&
+       git -C "$SERVER" add foo.txt have.txt &&
+       git -C "$SERVER" commit -m bar &&
+       git -C "$SERVER" rev-parse HEAD:foo.txt >deltabase_missing &&
+       git -C "$SERVER" rev-parse HEAD:have.txt >deltabase_have &&
+
+       # Clone. The client has deltabase_have but not deltabase_missing.
+       git -c protocol.version=2 clone --no-checkout \
+               --filter=blob:none $HTTPD_URL/one_time_sed/server repo &&
+       git -C repo hash-object -w -- "$SERVER/have.txt" &&
+
+       # Sanity check to ensure that the client does not have
+       # deltabase_missing.
+       git -C repo rev-list --objects --ignore-missing \
+               -- $(cat deltabase_missing) >objlist &&
+       test_line_count = 0 objlist &&
+
+       # Another commit. This commit will be fetched by the client.
+       echo "abcdefghijklmnopqrstuvwxyz" >>"$SERVER/foo.txt" &&
+       echo "abcdefghijklmnopqrstuvwxyz" >>"$SERVER/have.txt" &&
+       git -C "$SERVER" add foo.txt have.txt &&
+       git -C "$SERVER" commit -m baz &&
+
+       # Pack a thin pack containing, among other things, HEAD:foo.txt
+       # delta-ed against HEAD^:foo.txt and HEAD:have.txt delta-ed against
+       # HEAD^:have.txt.
+       printf "%s\n--not\n%s\n" \
+               $(git -C "$SERVER" rev-parse HEAD) \
+               $(git -C "$SERVER" rev-parse HEAD^) |
+               git -C "$SERVER" pack-objects --thin --stdout >thin.pack &&
+
+       # Ensure that the pack contains one delta against HEAD^:foo.txt. Since
+       # the delta contains at least 26 novel characters, the size cannot be
+       # contained in 4 bits, so the object header will take up 2 bytes. The
+       # most significant nybble of the first byte is 0b1111 (0b1 to indicate
+       # that the header continues, and 0b111 to indicate REF_DELTA), followed
+       # by any 3 nybbles, then the OID of the delta base.
+       printf "f.,..%s" $(intersperse "," <deltabase_missing) >want &&
+       hex_unpack <thin.pack | intersperse "," >have &&
+       grep $(cat want) have &&
+
+       # Ensure that the pack contains one delta against HEAD^:have.txt,
+       # similar to the above.
+       printf "f.,..%s" $(intersperse "," <deltabase_have) >want &&
+       hex_unpack <thin.pack | intersperse "," >have &&
+       grep $(cat want) have &&
+
+       replace_packfile thin.pack &&
+
+       # Use protocol v2 because the sed command looks for the "packfile"
+       # section header.
+       test_config -C "$SERVER" protocol.version 2 &&
+
+       # Fetch the thin pack and ensure that index-pack is able to handle the
+       # REF_DELTA object with a missing promisor delta base.
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C repo -c protocol.version=2 fetch &&
+
+       # Ensure that the missing delta base was directly fetched, but not the
+       # one that the client has.
+       grep "want $(cat deltabase_missing)" trace &&
+       ! grep "want $(cat deltabase_have)" trace &&
+
+       # Ensure that the one-time-sed script was used.
+       ! test -e "$HTTPD_ROOT_PATH/one-time-sed"
+'
+
 test_done
index d04f8007e0e34fa938bf4fccb91eff384743e616..2d6c4a281edb3f0678a600fd3e780825536da437 100755 (executable)
@@ -126,7 +126,7 @@ test_expect_success 'forced push' '
 '
 
 test_expect_success 'cloning without refspec' '
-       GIT_REMOTE_TESTGIT_REFSPEC="" \
+       GIT_REMOTE_TESTGIT_NOREFSPEC=1 \
        git clone "testgit::${PWD}/server" local2 2>error &&
        test_i18ngrep "this remote helper should implement refspec capability" error &&
        compare_refs local2 HEAD server HEAD
@@ -135,7 +135,7 @@ test_expect_success 'cloning without refspec' '
 test_expect_success 'pulling without refspecs' '
        (cd local2 &&
        git reset --hard &&
-       GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) &&
+       GIT_REMOTE_TESTGIT_NOREFSPEC=1 git pull 2>../error) &&
        test_i18ngrep "this remote helper should implement refspec capability" error &&
        compare_refs local2 HEAD server HEAD
 '
@@ -145,8 +145,8 @@ test_expect_success 'pushing without refspecs' '
        (cd local2 &&
        echo content >>file &&
        git commit -a -m ten &&
-       GIT_REMOTE_TESTGIT_REFSPEC="" &&
-       export GIT_REMOTE_TESTGIT_REFSPEC &&
+       GIT_REMOTE_TESTGIT_NOREFSPEC=1 &&
+       export GIT_REMOTE_TESTGIT_NOREFSPEC &&
        test_must_fail git push 2>../error) &&
        test_i18ngrep "remote-helper doesn.t support push; refspec needed" error
 '
@@ -303,4 +303,14 @@ test_expect_success 'fetch url' '
        compare_refs server HEAD local FETCH_HEAD
 '
 
+test_expect_success 'fetch tag' '
+       (cd server &&
+        git tag v1.0
+       ) &&
+       (cd local &&
+        git fetch
+       ) &&
+       compare_refs local v1.0 server v1.0
+'
+
 test_done
index 752c763eb666e197304efbc7ea006325a36ff870..6b9f0b5dc79cf0239daf4f6a210baaccf8612d74 100755 (executable)
@@ -11,13 +11,15 @@ fi
 url=$2
 
 dir="$GIT_DIR/testgit/$alias"
-prefix="refs/testgit/$alias"
 
-default_refspec="refs/heads/*:${prefix}/heads/*"
+h_refspec="refs/heads/*:refs/testgit/$alias/heads/*"
+t_refspec="refs/tags/*:refs/testgit/$alias/tags/*"
 
-refspec="${GIT_REMOTE_TESTGIT_REFSPEC-$default_refspec}"
-
-test -z "$refspec" && prefix="refs"
+if test -n "$GIT_REMOTE_TESTGIT_NOREFSPEC"
+then
+       h_refspec=""
+       t_refspec=""
+fi
 
 GIT_DIR="$url/.git"
 export GIT_DIR
@@ -40,7 +42,8 @@ do
        capabilities)
                echo 'import'
                echo 'export'
-               test -n "$refspec" && echo "refspec $refspec"
+               test -n "$h_refspec" && echo "refspec $h_refspec"
+               test -n "$t_refspec" && echo "refspec $t_refspec"
                if test -n "$gitmarks"
                then
                        echo "*import-marks $gitmarks"
@@ -52,7 +55,7 @@ do
                echo
                ;;
        list)
-               git for-each-ref --format='? %(refname)' 'refs/heads/'
+               git for-each-ref --format='? %(refname)' 'refs/heads/' 'refs/tags/'
                head=$(git symbolic-ref HEAD)
                echo "@$head HEAD"
                echo
@@ -81,10 +84,11 @@ do
 
                echo "feature done"
                git fast-export \
+                       ${h_refspec:+"--refspec=$h_refspec"} \
+                       ${t_refspec:+"--refspec=$t_refspec"} \
                        ${testgitmarks:+"--import-marks=$testgitmarks"} \
                        ${testgitmarks:+"--export-marks=$testgitmarks"} \
-                       $refs |
-               sed -e "s#refs/heads/#${prefix}/heads/#g"
+                       $refs
                echo "done"
                ;;
        export)
index 515c6735e9cb076c9f4b5a252c48216765b5076a..c0f04dc6b0e149173691e13c0194ffbd53be6ef8 100755 (executable)
@@ -71,6 +71,8 @@ test_expect_success 'gc --keep-largest-pack' '
                git gc --keep-largest-pack &&
                ( cd .git/objects/pack && ls *.pack ) >pack-list &&
                test_line_count = 2 pack-list &&
+               awk "/^P /{print \$2}" <.git/objects/info/packs >pack-info &&
+               test_line_count = 2 pack-info &&
                test_path_is_file $BASE_PACK &&
                git fsck
        )
index 7b36954d63d70e79149cf1558a93586e1b39c867..a2c45d1902ac5df8c67b16eb8a9a8dd99839eac1 100755 (executable)
@@ -669,4 +669,16 @@ test_expect_success 'git clean -d skips untracked dirs containing ignored files'
        test_path_is_missing foo/b/bb
 '
 
+test_expect_success MINGW 'handle clean & core.longpaths = false nicely' '
+       test_config core.longpaths false &&
+       a50=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+       mkdir -p $a50$a50/$a50$a50/$a50$a50 &&
+       : >"$a50$a50/test.txt" 2>"$a50$a50/$a50$a50/$a50$a50/test.txt" &&
+       # create a temporary outside the working tree to hide from "git clean"
+       test_must_fail git clean -xdf 2>.git/err &&
+       # grepping for a strerror string is unportable but it is OK here with
+       # MINGW prereq
+       test_i18ngrep "too long" .git/err
+'
+
 test_done
index 706ae762e0ec2fd0103f7f6788eff13ec86ebd67..6b2aa917e11871eb403c8c79725b1e1944f8d29f 100755 (executable)
@@ -421,4 +421,11 @@ test_expect_success 'option-like arguments passed to foreach commands are not lo
        test_cmp expected actual
 '
 
+test_expect_success 'option-like arguments passed to foreach recurse correctly' '
+       git -C clone2 submodule foreach --recursive "echo be --an-option" >expect &&
+       git -C clone2 submodule foreach --recursive echo be --an-option >actual &&
+       grep -e "--an-option" expect &&
+       test_cmp expect actual
+'
+
 test_done
index c44186133147838d7f17c4d42f8cb96a5df73b28..f19202b509899481d4a098de049f1e2c9cae9915 100755 (executable)
@@ -538,33 +538,50 @@ test_expect_success 'with 2 files arguments' '
        test_cmp expected actual
 '
 
-test_expect_success 'with message that has comments' '
-       cat basic_message >message_with_comments &&
-       sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
-               # comment
-
-               # other comment
-               Cc: Z
-               # yet another comment
-               Reviewed-by: Johan
-               Reviewed-by: Z
-               # last comment
-
-       EOF
-       cat basic_patch >>message_with_comments &&
-       cat basic_message >expected &&
-       cat >>expected <<-\EOF &&
-               # comment
-
-               Reviewed-by: Johan
-               Cc: Peff
-               # last comment
-
-       EOF
-       cat basic_patch >>expected &&
-       git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
-       test_cmp expected actual
-'
+# Cover multiple comment characters with the same test input.
+for char in "#" ";"
+do
+       case "$char" in
+       "#")
+               # This is the default, so let's explicitly _not_
+               # set any config to make sure it behaves as we expect.
+               ;;
+       *)
+               config="-c core.commentChar=$char"
+               ;;
+       esac
+
+       test_expect_success "with message that has comments ($char)" '
+               cat basic_message >message_with_comments &&
+               sed -e "s/ Z\$/ /" \
+                   -e "s/#/$char/g" >>message_with_comments <<-EOF &&
+                       # comment
+
+                       # other comment
+                       Cc: Z
+                       # yet another comment
+                       Reviewed-by: Johan
+                       Reviewed-by: Z
+                       # last comment
+
+               EOF
+               cat basic_patch >>message_with_comments &&
+               cat basic_message >expected &&
+               sed -e "s/#/$char/g" >>expected <<-\EOF &&
+                       # comment
+
+                       Reviewed-by: Johan
+                       Cc: Peff
+                       # last comment
+
+               EOF
+               cat basic_patch >>expected &&
+               git $config interpret-trailers \
+                       --trim-empty --trailer "Cc: Peff" \
+                       message_with_comments >actual &&
+               test_cmp expected actual
+       '
+done
 
 test_expect_success 'with message that has an old style conflict block' '
        cat basic_message >message_with_comments &&
index 7f9c68cbe75a688357e6c71486c3897861421681..4ec5d9ec790a0d54f4883fc118b5df25c94f43f4 100755 (executable)
@@ -570,6 +570,12 @@ test_expect_success 'combining --squash and --no-ff is refused' '
        test_must_fail git merge --no-ff --squash c1
 '
 
+test_expect_success 'combining --squash and --commit is refused' '
+       git reset --hard c0 &&
+       test_must_fail git merge --squash --commit c1 &&
+       test_must_fail git merge --commit --squash c1
+'
+
 test_expect_success 'option --ff-only overwrites --no-ff' '
        git merge --no-ff --ff-only c1 &&
        test_must_fail git merge --no-ff --ff-only c2
index 1286a5b824b77d71061fb890d9f528b46ecc087d..e9276c48f4a2e795899a03681a737c70635ab39c 100755 (executable)
@@ -22,7 +22,10 @@ test_expect_success 'init depot' '
                : >file_to_move &&
                p4 add file_to_delete &&
                p4 add file_to_move &&
-               p4 submit -d "add files to delete"
+               p4 submit -d "add files to delete" &&
+               echo file_to_integrate >file_to_integrate &&
+               p4 add file_to_integrate &&
+               p4 submit -d "add file to integrate"
        )
 '
 
@@ -40,6 +43,7 @@ test_expect_success 'create shelved changelist' '
                p4 delete file_to_delete &&
                p4 edit file_to_move &&
                p4 move file_to_move moved_file &&
+               p4 integrate file_to_integrate integrated_file &&
                p4 opened &&
                p4 shelve -i <<EOF
 Change: new
@@ -53,6 +57,7 @@ Files:
        //depot/file_to_delete
        //depot/file_to_move
        //depot/moved_file
+       //depot/integrated_file
 EOF
 
        ) &&
@@ -65,6 +70,7 @@ EOF
                test_path_is_file file2 &&
                test_cmp file1 "$cli"/file1 &&
                test_cmp file2 "$cli"/file2 &&
+               test_cmp file_to_integrate "$cli"/integrated_file &&
                test_path_is_missing file_to_delete &&
                test_path_is_missing file_to_move &&
                test_path_is_file moved_file
index 8270de74beafb931f09f296557406c0d158d48de..f233522f43ab39728e3c454258920283f5d9cab3 100644 (file)
@@ -888,6 +888,21 @@ test_cmp_rev () {
        fi
 }
 
+# Compare paths respecting core.ignoreCase
+test_cmp_fspath () {
+       if test "x$1" = "x$2"
+       then
+               return 0
+       fi
+
+       if test true != "$(git config --get --type=bool core.ignorecase)"
+       then
+               return 1
+       fi
+
+       test "x$(echo "$1" | tr A-Z a-z)" =  "x$(echo "$2" | tr A-Z a-z)"
+}
+
 # Print a sequence of integers in increasing order, either with
 # two arguments (start and end):
 #
index cec83bd663d0f27589bd09176e38b084270f56c4..6b05a88faf59ee74840b0f9fa340a5d9397a0f5d 100644 (file)
@@ -423,7 +423,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti
        struct helper_data *data = transport->data;
        int cat_blob_fd, code;
        child_process_init(fastimport);
-       fastimport->in = helper->out;
+       fastimport->in = xdup(helper->out);
        argv_array_push(&fastimport->args, "fast-import");
        argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet");
 
@@ -853,6 +853,7 @@ static int push_refs_with_push(struct transport *transport,
 {
        int force_all = flags & TRANSPORT_PUSH_FORCE;
        int mirror = flags & TRANSPORT_PUSH_MIRROR;
+       int atomic = flags & TRANSPORT_PUSH_ATOMIC;
        struct helper_data *data = transport->data;
        struct strbuf buf = STRBUF_INIT;
        struct ref *ref;
@@ -872,6 +873,11 @@ static int push_refs_with_push(struct transport *transport,
                case REF_STATUS_REJECT_NONFASTFORWARD:
                case REF_STATUS_REJECT_STALE:
                case REF_STATUS_REJECT_ALREADY_EXISTS:
+                       if (atomic) {
+                               string_list_clear(&cas_options, 0);
+                               return 0;
+                       } else
+                               continue;
                case REF_STATUS_UPTODATE:
                        continue;
                default:
index f1fcd2c4b006dc2ece2019ac91f73a2f42bbf6bd..453de8f7041b966a9bd0eaee20ef8f5758cec2f1 100644 (file)
@@ -1226,6 +1226,20 @@ int transport_push(struct repository *r,
                err = push_had_errors(remote_refs);
                ret = push_ret | err;
 
+               if ((flags & TRANSPORT_PUSH_ATOMIC) && err) {
+                       struct ref *it;
+                       for (it = remote_refs; it; it = it->next)
+                               switch (it->status) {
+                               case REF_STATUS_NONE:
+                               case REF_STATUS_UPTODATE:
+                               case REF_STATUS_OK:
+                                       it->status = REF_STATUS_ATOMIC_PUSH_FAILED;
+                                       break;
+                               default:
+                                       break;
+                               }
+               }
+
                if (!quiet || err)
                        transport_print_push_status(transport->url, remote_refs,
                                        verbose | porcelain, porcelain,
index 93a48f3bf8429ebb9b40f6a079e6ef0c6d0edcd8..c9d027625d1f671a0807930480c9a3e4ddd1040d 100644 (file)
@@ -380,8 +380,7 @@ static const struct interval double_width[] = {
 { 0x31C0, 0x31E3 },
 { 0x31F0, 0x321E },
 { 0x3220, 0x3247 },
-{ 0x3250, 0x32FE },
-{ 0x3300, 0x4DBF },
+{ 0x3250, 0x4DBF },
 { 0x4E00, 0xA48C },
 { 0xA490, 0xA4C6 },
 { 0xA960, 0xA97C },
index 24298913c0d7932e20f4677d3b8a4ea62ed69f8d..b2a9f368ecd6ab159cae99deac0b9a9b5ee08f6a 100644 (file)
@@ -722,7 +722,7 @@ static void deepen_by_rev_list(struct packet_writer *writer, int ac,
 {
        struct commit_list *result;
 
-       close_commit_graph(the_repository);
+       close_commit_graph(the_repository->objects);
        result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);
        send_shallow(writer, result);
        free_commit_list(result);
@@ -1037,8 +1037,8 @@ static int find_symref(const char *refname, const struct object_id *oid,
        symref_target = resolve_ref_unsafe(refname, 0, NULL, &flag);
        if (!symref_target || (flag & REF_ISSYMREF) == 0)
                die("'%s' is a symref but it is not?", refname);
-       item = string_list_append(cb_data, refname);
-       item->util = xstrdup(symref_target);
+       item = string_list_append(cb_data, strip_namespace(refname));
+       item->util = xstrdup(strip_namespace(symref_target));
        return 0;
 }
 
diff --git a/url.c b/url.c
index 25576c390baa79cb0a203d7f682e8f3442f91a60..1b8ef78ceab03784ad48f8411b20669e2ea1ea1f 100644 (file)
--- a/url.c
+++ b/url.c
@@ -46,9 +46,9 @@ static char *url_decode_internal(const char **query, int len,
                        break;
                }
 
-               if (c == '%') {
+               if (c == '%' && (len < 0 || len >= 3)) {
                        int val = hex2chr(q + 1);
-                       if (0 <= val) {
+                       if (0 < val) {
                                strbuf_addch(out, val);
                                q += 3;
                                len -= 3;
index 4f66cd9ce178d855245712b42d681ff8bcda0636..5b4793caa34e3ab981268662efdc1d840ac53390 100644 (file)
@@ -228,9 +228,12 @@ struct worktree *find_worktree(struct worktree **list,
                free(to_free);
                return NULL;
        }
-       for (; *list; list++)
-               if (!fspathcmp(path, real_path((*list)->path)))
+       for (; *list; list++) {
+               const char *wt_path = real_path_if_valid((*list)->path);
+
+               if (wt_path && !fspathcmp(path, wt_path))
                        break;
+       }
        free(path);
        free(to_free);
        return *list;
index ea3cf64d4c399ae84c156b850002459a8ffde72c..1e45ab7b92749b653484f522701f5d86521b03c7 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -502,7 +502,7 @@ int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
         * Try TMP_MAX different filenames.
         */
        gettimeofday(&tv, NULL);
-       value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
+       value = ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
        filename_template = &pattern[len - 6 - suffix_len];
        for (count = 0; count < TMP_MAX; ++count) {
                uint64_t v = value;
index 7778dc2b190f84fe2ab1e1539756a7e1f4254c3b..30713ae9a98ecfc9f764120d3a1d18b5a8ee11bf 100644 (file)
@@ -210,7 +210,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                        if (fs1 < 0)
                                fs1 = 0;
                        if (fs1 < s1) {
-                               s2 -= s1 - fs1;
+                               s2 = XDL_MAX(s2 - (s1 - fs1), 0);
                                s1 = fs1;
                        }
                }
@@ -232,7 +232,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                        if (fe1 < 0)
                                fe1 = xe->xdf1.nrec;
                        if (fe1 > e1) {
-                               e2 += fe1 - e1;
+                               e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec);
                                e1 = fe1;
                        }