Merge branch 'js/fsck-tag-validation' into HEAD
authorJunio C Hamano <gitster@pobox.com>
Fri, 12 Sep 2014 18:05:08 +0000 (11:05 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Sep 2014 18:05:08 +0000 (11:05 -0700)
* js/fsck-tag-validation:
Make sure that index-pack --strict checks tag objects
Add regression tests for stricter tag fsck'ing
fsck: check tag objects' headers
Make sure fsck_commit_buffer() does not run out of the buffer
fsck_object(): allow passing object data separately from the object itself
Refactor type_from_string() to allow continuing after detecting an error

92 files changed:
Documentation/RelNotes/2.2.0.txt
Documentation/config.txt
Documentation/gitattributes.txt
Documentation/technical/api-config.txt
Documentation/technical/api-run-command.txt
Makefile
advice.c
alias.c
archive-tar.c
archive.c
bisect.c
branch.c
builtin/add.c
builtin/apply.c
builtin/checkout.c
builtin/commit.c
builtin/fetch.c
builtin/gc.c
builtin/hash-object.c
builtin/help.c
builtin/merge.c
builtin/mv.c
builtin/notes.c
builtin/receive-pack.c
builtin/remote-ext.c
builtin/repack.c
builtin/replace.c
builtin/tag.c
builtin/update-ref.c
builtin/verify-pack.c
bundle.c
cache-tree.c
cache-tree.h
cache.h
column.c
commit.h
config.c
connect.c
connected.c
contrib/subtree/Makefile
convert.c
credential-cache.c
credential.c
daemon.c
diff.c
diffcore-rename.c
diffcore.h
editor.c
fast-import.c
fetch-pack.c
git-compat-util.h
git-pull.sh
gpg-interface.c
http-backend.c
http.c
imap-send.c
ll-merge.c
log-tree.c
merge-recursive.c
pager.c
prompt.c
read-cache.c
refs.c
refs.h
remote-curl.c
remote-testsvn.c
rerere.c
revision.c
run-command.c
run-command.h
send-pack.c
sequencer.c
sha1_file.c
sha1_name.c
submodule.c
t/t0090-cache-tree.sh
t/t1050-large.sh
t/t1308-config-set.sh
t/t3210-pack-refs.sh
t/t4055-diff-context.sh
t/t7201-co.sh
test-config.c
test-dump-cache-tree.c
test-run-command.c
test-subprocess.c
transport-helper.c
transport.c
unpack-trees.c
upload-pack.c
walker.c
wrapper.c
wt-status.c
index f77185470553ebf0c3aa1817efff9b5614819a4e..22b73618fc55a475b3e4c21cc0b62170f3e0b4cf 100644 (file)
@@ -25,6 +25,15 @@ UI, Workflows & Features
 
 Performance, Internal Implementation, etc.
 
+ * The API to manipulate the "refs" is currently undergoing a revamp
+   to make it more transactional, with the eventual goal to allow
+   all-or-none atomic updates and migrating the storage to something
+   other than the traditional filesystem based one (e.g. databases).
+
+ * We no longer attempt to keep track of individual dependencies to
+   the header files in the build procedure, relying on automated
+   dependency generation support from modern compilers.
+
  * In tests, we have been using NOT_{MINGW,CYGWIN} test prerequisites
    long before negated prerequisites e.g. !MINGW were invented.
    The former has been converted to the latter to avoid confusion.
@@ -37,12 +46,25 @@ Performance, Internal Implementation, etc.
    to update the file again while still holding the lock, but the
    lockfile API lacked support for such an access pattern.
 
+ * The API to allocate the structure to keep track of commit
+   decoration has been updated to make it less cumbersome to use.
+
  * An in-core caching layer to let us avoid reading the same
-   configuration files number of times has been added.
+   configuration files number of times has been added.  A few commands
+   have been converted to use this subsystem.
 
  * Various code paths have been cleaned up and simplified by using
    "strbuf", "starts_with()", and "skip_prefix()" APIs more.
 
+ * A few codepaths that died when large blobs that would not fit in
+   core are involved in their operation have been taught to punt
+   instead, by e.g. marking too large a blob as not to be diffed.
+
+ * A few more code paths in "commit" and "checkout" have been taught
+   to repopulate the cache-tree in the index, to help speed up later
+   "write-tree" (used in "commit") and "diff-index --cached" (used in
+   "status").
+
 
 Also contains various documentation updates and code clean-ups.
 
@@ -89,3 +111,22 @@ notes for details).
 
  * Pack-protocol documentation had a minor typo.
    (merge 5d146f7 sp/pack-protocol-doc-on-shallow later to maint).
+
+ * "git checkout -m" did not switch to another branch while carrying
+   the local changes forward when a path was deleted from the index.
+   (merge 6a143aa jn/unpack-trees-checkout-m-carry-deletion later to maint).
+
+ * With sufficiently long refnames, "git fast-import" could have
+   overflown an on-stack buffer.
+   (merge c252785 jk/fast-import-fixes later to maint).
+
+ * After "pack-refs --prune" packed refs at the top-level, it failed
+   to prune them.
+   (merge afd11d3 jk/prune-top-level-refs-after-packing later to maint).
+
+ * Progress output from "git gc --auto" was visible in "git fetch -q".
+   (merge 6fceed3 nd/fetch-pass-quiet-to-gc-child-process later to maint).
+
+ * We used to pass -1000 to poll(2), expecting it to also mean "no
+   timeout", which should be spelled as -1.
+   (merge 6c71f8b et/spell-poll-infinite-with-minus-one-only later to maint).
index c55c22ab7be94e798164a48622aca21dd4daa44f..3b5b24aeb7f16c03e06bd6f38fd89e9080011ce7 100644 (file)
@@ -499,7 +499,8 @@ core.bigFileThreshold::
        Files larger than this size are stored deflated, without
        attempting delta compression.  Storing large files without
        delta compression avoids excessive memory usage, at the
-       slight expense of increased disk usage.
+       slight expense of increased disk usage. Additionally files
+       larger than this size are always treated as binary.
 +
 Default is 512 MiB on all platforms.  This should be reasonable
 for most projects as source code and other text files can still
index 643c1ba9290ff10813eab57b95f7c26d8c43c7e2..9b45bda7485c7e4742b13cdf19272968592b640a 100644 (file)
@@ -440,8 +440,8 @@ Unspecified::
 
        A path to which the `diff` attribute is unspecified
        first gets its contents inspected, and if it looks like
-       text, it is treated as text.  Otherwise it would
-       generate `Binary files differ`.
+       text and is smaller than core.bigFileThreshold, it is treated
+       as text. Otherwise it would generate `Binary files differ`.
 
 String::
 
index 21f280ca6dbd85a1f4d1d599db1393077fc93bdf..0d8b99b368aea13a322382314d88229acda0b1db 100644 (file)
@@ -155,6 +155,19 @@ as well as retrieval for the queried variable, including:
        Similar to `git_config_get_string`, but expands `~` or `~user` into
        the user's home directory when found at the beginning of the path.
 
+`git_die_config(const char *key, const char *err, ...)`::
+
+       First prints the error message specified by the caller in `err` and then
+       dies printing the line number and the file name of the highest priority
+       value for the configuration variable `key`.
+
+`void git_die_config_linenr(const char *key, const char *filename, int linenr)`::
+
+       Helper function which formats the die error message according to the
+       parameters entered. Used by `git_die_config()`. It can be used by callers
+       handling `git_config_get_value_multi()` to print the correct error message
+       for the desired value.
+
 See test-config.c for usage examples.
 
 Value Parsing Helpers
index 69510ae57afcedbe13334160c6a26c52c42e8d54..842b8389eb867b6db654cf7fe29e8f10b92b259e 100644 (file)
@@ -13,6 +13,10 @@ produces in the caller in order to process it.
 Functions
 ---------
 
+`child_process_init`
+
+       Initialize a struct child_process variable.
+
 `start_command`::
 
        Start a sub-process. Takes a pointer to a `struct child_process`
@@ -96,8 +100,8 @@ command to run in a sub-process.
 
 The caller:
 
-1. allocates and clears (memset(&chld, 0, sizeof(chld));) a
-   struct child_process variable;
+1. allocates and clears (using child_process_init() or
+   CHILD_PROCESS_INIT) a struct child_process variable;
 2. initializes the members;
 3. calls start_command();
 4. processes the data;
index 30cc622f08ba9ba69b727c1b6a4933d2d9158de4..e0f15a3df3ae441d33b9d0a0ddadc729ec4773b3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -317,9 +317,6 @@ all::
 # dependency rules.  The default is "auto", which means to use computed header
 # dependencies if your compiler is detected to support it.
 #
-# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
-# dependency rules.
-#
 # Define NATIVE_CRLF if your platform uses CRLF for line endings.
 #
 # Define XDL_FAST_HASH to use an alternative line-hashing method in
@@ -432,7 +429,6 @@ XDIFF_OBJS =
 VCSSVN_OBJS =
 GENERATED_H =
 EXTRA_CPPFLAGS =
-LIB_H =
 LIB_OBJS =
 PROGRAM_OBJS =
 PROGRAMS =
@@ -632,131 +628,11 @@ VCSSVN_LIB = vcs-svn/lib.a
 
 GENERATED_H += common-cmds.h
 
-LIB_H += advice.h
-LIB_H += archive.h
-LIB_H += argv-array.h
-LIB_H += attr.h
-LIB_H += bisect.h
-LIB_H += blob.h
-LIB_H += branch.h
-LIB_H += builtin.h
-LIB_H += bulk-checkin.h
-LIB_H += bundle.h
-LIB_H += cache-tree.h
-LIB_H += cache.h
-LIB_H += color.h
-LIB_H += column.h
-LIB_H += commit.h
-LIB_H += compat/bswap.h
-LIB_H += compat/mingw.h
-LIB_H += compat/obstack.h
-LIB_H += compat/poll/poll.h
-LIB_H += compat/precompose_utf8.h
-LIB_H += compat/terminal.h
-LIB_H += compat/win32/dirent.h
-LIB_H += compat/win32/pthread.h
-LIB_H += compat/win32/syslog.h
-LIB_H += connected.h
-LIB_H += convert.h
-LIB_H += credential.h
-LIB_H += csum-file.h
-LIB_H += decorate.h
-LIB_H += delta.h
-LIB_H += diff.h
-LIB_H += diffcore.h
-LIB_H += dir.h
-LIB_H += exec_cmd.h
-LIB_H += ewah/ewok.h
-LIB_H += ewah/ewok_rlw.h
-LIB_H += fetch-pack.h
-LIB_H += fmt-merge-msg.h
-LIB_H += fsck.h
-LIB_H += gettext.h
-LIB_H += git-compat-util.h
-LIB_H += gpg-interface.h
-LIB_H += graph.h
-LIB_H += grep.h
-LIB_H += hashmap.h
-LIB_H += help.h
-LIB_H += http.h
-LIB_H += kwset.h
-LIB_H += levenshtein.h
-LIB_H += line-log.h
-LIB_H += line-range.h
-LIB_H += list-objects.h
-LIB_H += ll-merge.h
-LIB_H += log-tree.h
-LIB_H += mailmap.h
-LIB_H += merge-blobs.h
-LIB_H += merge-recursive.h
-LIB_H += mergesort.h
-LIB_H += notes-cache.h
-LIB_H += notes-merge.h
-LIB_H += notes-utils.h
-LIB_H += notes.h
-LIB_H += object.h
-LIB_H += pack-objects.h
-LIB_H += pack-revindex.h
-LIB_H += pack.h
-LIB_H += pack-bitmap.h
-LIB_H += parse-options.h
-LIB_H += patch-ids.h
-LIB_H += pathspec.h
-LIB_H += pkt-line.h
-LIB_H += prio-queue.h
-LIB_H += progress.h
-LIB_H += prompt.h
-LIB_H += quote.h
-LIB_H += reachable.h
-LIB_H += reflog-walk.h
-LIB_H += refs.h
-LIB_H += remote.h
-LIB_H += rerere.h
-LIB_H += resolve-undo.h
-LIB_H += revision.h
-LIB_H += run-command.h
-LIB_H += send-pack.h
-LIB_H += sequencer.h
-LIB_H += sha1-array.h
-LIB_H += sha1-lookup.h
-LIB_H += shortlog.h
-LIB_H += sideband.h
-LIB_H += sigchain.h
-LIB_H += strbuf.h
-LIB_H += streaming.h
-LIB_H += string-list.h
-LIB_H += submodule.h
-LIB_H += tag.h
-LIB_H += tar.h
-LIB_H += thread-utils.h
-LIB_H += transport.h
-LIB_H += tree-walk.h
-LIB_H += tree.h
-LIB_H += unpack-trees.h
-LIB_H += unicode_width.h
-LIB_H += url.h
-LIB_H += urlmatch.h
-LIB_H += userdiff.h
-LIB_H += utf8.h
-LIB_H += varint.h
-LIB_H += vcs-svn/fast_export.h
-LIB_H += vcs-svn/line_buffer.h
-LIB_H += vcs-svn/repo_tree.h
-LIB_H += vcs-svn/sliding_window.h
-LIB_H += vcs-svn/svndiff.h
-LIB_H += vcs-svn/svndump.h
-LIB_H += walker.h
-LIB_H += wildmatch.h
-LIB_H += wt-status.h
-LIB_H += xdiff-interface.h
-LIB_H += xdiff/xdiff.h
-LIB_H += xdiff/xdiffi.h
-LIB_H += xdiff/xemit.h
-LIB_H += xdiff/xinclude.h
-LIB_H += xdiff/xmacros.h
-LIB_H += xdiff/xprepare.h
-LIB_H += xdiff/xtypes.h
-LIB_H += xdiff/xutils.h
+LIB_H = $(shell $(FIND) . \
+       -name .git -prune -o \
+       -name t -prune -o \
+       -name Documentation -prune -o \
+       -name '*.h' -print)
 
 LIB_OBJS += abspath.o
 LIB_OBJS += advice.o
@@ -1026,11 +902,6 @@ sysconfdir = etc
 endif
 endif
 
-ifdef CHECK_HEADER_DEPENDENCIES
-COMPUTE_HEADER_DEPENDENCIES = no
-USE_COMPUTED_HEADER_DEPENDENCIES =
-endif
-
 ifndef COMPUTE_HEADER_DEPENDENCIES
 COMPUTE_HEADER_DEPENDENCIES = auto
 endif
@@ -1382,7 +1253,6 @@ ifdef NO_INET_PTON
 endif
 ifndef NO_UNIX_SOCKETS
        LIB_OBJS += unix-socket.o
-       LIB_H += unix-socket.h
        PROGRAM_OBJS += credential-cache.o
        PROGRAM_OBJS += credential-cache--daemon.o
 endif
@@ -1406,12 +1276,10 @@ endif
 ifdef BLK_SHA1
        SHA1_HEADER = "block-sha1/sha1.h"
        LIB_OBJS += block-sha1/sha1.o
-       LIB_H += block-sha1/sha1.h
 else
 ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
        LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
-       LIB_H += ppc/sha1.h
 else
 ifdef APPLE_COMMON_CRYPTO
        COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
@@ -1938,29 +1806,13 @@ $(dep_dirs):
 missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
 dep_file = $(dir $@).depend/$(notdir $@).d
 dep_args = -MF $(dep_file) -MQ $@ -MMD -MP
-ifdef CHECK_HEADER_DEPENDENCIES
-$(error cannot compute header dependencies outside a normal build. \
-Please unset CHECK_HEADER_DEPENDENCIES and try again)
-endif
 endif
 
 ifneq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
-ifndef CHECK_HEADER_DEPENDENCIES
 dep_dirs =
 missing_dep_dirs =
 dep_args =
 endif
-endif
-
-ifdef CHECK_HEADER_DEPENDENCIES
-ifndef PRINT_HEADER_DEPENDENCIES
-missing_deps = $(filter-out $(notdir $^), \
-       $(notdir $(shell $(MAKE) -s $@ \
-               CHECK_HEADER_DEPENDENCIES=YesPlease \
-               USE_COMPUTED_HEADER_DEPENDENCIES=YesPlease \
-               PRINT_HEADER_DEPENDENCIES=YesPlease)))
-endif
-endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
@@ -1968,45 +1820,10 @@ C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
 
 .SUFFIXES:
 
-ifdef PRINT_HEADER_DEPENDENCIES
-$(C_OBJ): %.o: %.c FORCE
-       echo $^
-$(ASM_OBJ): %.o: %.S FORCE
-       echo $^
-
-ifndef CHECK_HEADER_DEPENDENCIES
-$(error cannot print header dependencies during a normal build. \
-Please set CHECK_HEADER_DEPENDENCIES and try again)
-endif
-endif
-
-ifndef PRINT_HEADER_DEPENDENCIES
-ifdef CHECK_HEADER_DEPENDENCIES
-$(C_OBJ): %.o: %.c $(dep_files) FORCE
-       @set -e; echo CHECK $@; \
-       missing_deps="$(missing_deps)"; \
-       if test "$$missing_deps"; \
-       then \
-               echo missing dependencies: $$missing_deps; \
-               false; \
-       fi
-$(ASM_OBJ): %.o: %.S $(dep_files) FORCE
-       @set -e; echo CHECK $@; \
-       missing_deps="$(missing_deps)"; \
-       if test "$$missing_deps"; \
-       then \
-               echo missing dependencies: $$missing_deps; \
-               false; \
-       fi
-endif
-endif
-
-ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
        $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
        $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
-endif
 
 %.s: %.c GIT-CFLAGS FORCE
        $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
@@ -2133,9 +1950,9 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
 XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
        --keyword=gettextln --keyword=eval_gettextln
 XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
-LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
-LOCALIZED_SH := $(SCRIPT_SH)
-LOCALIZED_PERL := $(SCRIPT_PERL)
+LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
+LOCALIZED_SH = $(SCRIPT_SH)
+LOCALIZED_PERL = $(SCRIPT_PERL)
 
 ifdef XGETTEXT_INCLUDE_TESTS
 LOCALIZED_C += t/t0200/test.c
@@ -2143,7 +1960,7 @@ LOCALIZED_SH += t/t0200/test.sh
 LOCALIZED_PERL += t/t0200/test.perl
 endif
 
-po/git.pot: $(LOCALIZED_C)
+po/git.pot: $(GENERATED_H) FORCE
        $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C)
        $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_SH) \
                $(LOCALIZED_SH)
index 9b420331926c6bf1aa371f973d6a96886f419b06..3b8bf3c6da6afdd5ef4cfcc77131690ccbbf3757 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -86,8 +86,7 @@ int error_resolve_conflict(const char *me)
                 * other commands doing a merge do.
                 */
                advise(_("Fix them up in the work tree, and then use 'git add/rm <file>'\n"
-                        "as appropriate to mark resolution and make a commit, or use\n"
-                        "'git commit -a'."));
+                        "as appropriate to mark resolution and make a commit."));
        return -1;
 }
 
diff --git a/alias.c b/alias.c
index 758c8671494ad003a6e7e33f8a14b5450311bf54..6aa164a362427ffa5dc8616bcb01aec3f15b462b 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -1,26 +1,13 @@
 #include "cache.h"
 
-static const char *alias_key;
-static char *alias_val;
-
-static int alias_lookup_cb(const char *k, const char *v, void *cb)
-{
-       const char *name;
-       if (skip_prefix(k, "alias.", &name) && !strcmp(name, alias_key)) {
-               if (!v)
-                       return config_error_nonbool(k);
-               alias_val = xstrdup(v);
-               return 0;
-       }
-       return 0;
-}
-
 char *alias_lookup(const char *alias)
 {
-       alias_key = alias;
-       alias_val = NULL;
-       git_config(alias_lookup_cb, NULL);
-       return alias_val;
+       char *v = NULL;
+       struct strbuf key = STRBUF_INIT;
+       strbuf_addf(&key, "alias.%s", alias);
+       git_config_get_string(key.buf, &v);
+       strbuf_release(&key);
+       return v;
 }
 
 #define SPLIT_CMDLINE_BAD_ENDING 1
index 603650fa3cc83e844cd6b0e61f145ed99a67158c..df2f4c8a643796ee96a31185f2a49fa7e00ca991 100644 (file)
@@ -395,7 +395,7 @@ static int write_tar_filter_archive(const struct archiver *ar,
                                    struct archiver_args *args)
 {
        struct strbuf cmd = STRBUF_INIT;
-       struct child_process filter;
+       struct child_process filter = CHILD_PROCESS_INIT;
        const char *argv[2];
        int r;
 
@@ -406,7 +406,6 @@ static int write_tar_filter_archive(const struct archiver *ar,
        if (args->compression_level >= 0)
                strbuf_addf(&cmd, " -%d", args->compression_level);
 
-       memset(&filter, 0, sizeof(filter));
        argv[0] = cmd.buf;
        argv[1] = NULL;
        filter.argv = argv;
index 3fc0fb2928f1007ec5d8763d9d3a9b88152059ad..952a659bcb59ea8b476d6677f2a04d717c6c7dd2 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -402,14 +402,6 @@ static int parse_archive_args(int argc, const char **argv,
        return argc;
 }
 
-static int git_default_archive_config(const char *var, const char *value,
-                                     void *cb)
-{
-       if (!strcmp(var, "uploadarchive.allowunreachable"))
-               remote_allow_unreachable = git_config_bool(var, value);
-       return git_default_config(var, value, cb);
-}
-
 int write_archive(int argc, const char **argv, const char *prefix,
                  int setup_prefix, const char *name_hint, int remote)
 {
@@ -420,7 +412,9 @@ int write_archive(int argc, const char **argv, const char *prefix,
        if (setup_prefix && prefix == NULL)
                prefix = setup_git_directory_gently(&nongit);
 
-       git_config(git_default_archive_config, NULL);
+       git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
+       git_config(git_default_config, NULL);
+
        init_tar_archiver();
        init_zip_archiver();
 
index d6e851d783c3541eb21edd47170ce7a32e082e61..df09cbc8cabe9dcb87a0023445babcf14c3d7691 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -215,11 +215,12 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
        }
        qsort(array, cnt, sizeof(*array), compare_commit_dist);
        for (p = list, i = 0; i < cnt; i++) {
-               struct name_decoration *r = xmalloc(sizeof(*r) + 100);
+               char buf[100]; /* enough for dist=%d */
                struct object *obj = &(array[i].commit->object);
 
-               sprintf(r->name, "dist=%d", array[i].distance);
-               r->next = add_decoration(&name_decoration, obj, r);
+               snprintf(buf, sizeof(buf), "dist=%d", array[i].distance);
+               add_name_decoration(DECORATION_NONE, buf, obj);
+
                p->item = array[i].commit;
                p = p->next;
        }
index 46e8aa86df1811ff19899869a33ecb48cacb107f..9a2228ebb46df721741db2249ab25cce5dfb4282 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -140,33 +140,17 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
        return 0;
 }
 
-struct branch_desc_cb {
-       const char *config_name;
-       const char *value;
-};
-
-static int read_branch_desc_cb(const char *var, const char *value, void *cb)
-{
-       struct branch_desc_cb *desc = cb;
-       if (strcmp(desc->config_name, var))
-               return 0;
-       free((char *)desc->value);
-       return git_config_string(&desc->value, var, value);
-}
-
 int read_branch_desc(struct strbuf *buf, const char *branch_name)
 {
-       struct branch_desc_cb cb;
+       char *v = NULL;
        struct strbuf name = STRBUF_INIT;
        strbuf_addf(&name, "branch.%s.description", branch_name);
-       cb.config_name = name.buf;
-       cb.value = NULL;
-       if (git_config(read_branch_desc_cb, &cb) < 0) {
+       if (git_config_get_string(name.buf, &v)) {
                strbuf_release(&name);
                return -1;
        }
-       if (cb.value)
-               strbuf_addstr(buf, cb.value);
+       strbuf_addstr(buf, v);
+       free(v);
        strbuf_release(&name);
        return 0;
 }
@@ -226,7 +210,6 @@ void create_branch(const char *head,
                   int force, int reflog, int clobber_head,
                   int quiet, enum branch_track track)
 {
-       struct ref_lock *lock = NULL;
        struct commit *commit;
        unsigned char sha1[20];
        char *real_ref, msg[PATH_MAX + 20];
@@ -285,15 +268,6 @@ void create_branch(const char *head,
                die(_("Not a valid branch point: '%s'."), start_name);
        hashcpy(sha1, commit->object.sha1);
 
-       if (!dont_change_ref) {
-               lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
-               if (!lock)
-                       die_errno(_("Failed to lock ref for update"));
-       }
-
-       if (reflog)
-               log_all_ref_updates = 1;
-
        if (forcing)
                snprintf(msg, sizeof msg, "branch: Reset to %s",
                         start_name);
@@ -301,13 +275,26 @@ void create_branch(const char *head,
                snprintf(msg, sizeof msg, "branch: Created from %s",
                         start_name);
 
+       if (reflog)
+               log_all_ref_updates = 1;
+
+       if (!dont_change_ref) {
+               struct ref_transaction *transaction;
+               struct strbuf err = STRBUF_INIT;
+
+               transaction = ref_transaction_begin(&err);
+               if (!transaction ||
+                   ref_transaction_update(transaction, ref.buf, sha1,
+                                          null_sha1, 0, !forcing, &err) ||
+                   ref_transaction_commit(transaction, msg, &err))
+                       die("%s", err.buf);
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
+       }
+
        if (real_ref && track)
                setup_tracking(ref.buf + 11, real_ref, track, quiet);
 
-       if (!dont_change_ref)
-               if (write_ref_sha1(lock, sha1, msg) < 0)
-                       die_errno(_("Failed to write ref"));
-
        strbuf_release(&ref);
        free(real_ref);
 }
index 4baf3a563510b10e592ff06ae62df2f405413f6c..352b85e8db19e1b4fa05ca37804f0c625e582912 100644 (file)
@@ -180,7 +180,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        char *file = git_pathdup("ADD_EDIT.patch");
        const char *apply_argv[] = { "apply", "--recount", "--cached",
                NULL, NULL };
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct rev_info rev;
        int out;
        struct stat st;
@@ -214,7 +214,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        if (!st.st_size)
                die(_("Empty patch. Aborted."));
 
-       memset(&child, 0, sizeof(child));
        child.git_cmd = 1;
        child.argv = apply_argv;
        if (run_command(&child))
index 6b7c764918cff18957f67a2e345c0610e459859d..f204cca5d2df50d8ecb01944927fb756ac387b5e 100644 (file)
@@ -4274,13 +4274,11 @@ static int apply_patch(int fd, const char *filename, int options)
        return 0;
 }
 
-static int git_apply_config(const char *var, const char *value, void *cb)
+static void git_apply_config(void)
 {
-       if (!strcmp(var, "apply.whitespace"))
-               return git_config_string(&apply_default_whitespace, var, value);
-       else if (!strcmp(var, "apply.ignorewhitespace"))
-               return git_config_string(&apply_default_ignorewhitespace, var, value);
-       return git_default_config(var, value, cb);
+       git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
+       git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+       git_config(git_default_config, NULL);
 }
 
 static int option_parse_exclude(const struct option *opt,
@@ -4428,7 +4426,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
 
        prefix = prefix_;
        prefix_length = prefix ? strlen(prefix) : 0;
-       git_config(git_apply_config, NULL);
+       git_apply_config();
        if (apply_default_whitespace)
                parse_whitespace_option(apply_default_whitespace);
        if (apply_default_ignorewhitespace)
index f71e74531d2a7d195ff2987f6dca3c69c636aa7c..8afdf2b5c4bfbd53e7315afe9d8ae3d88f93dd57 100644 (file)
@@ -552,6 +552,12 @@ static int merge_working_tree(const struct checkout_opts *opts,
                }
        }
 
+       if (!active_cache_tree)
+               active_cache_tree = cache_tree();
+
+       if (!cache_tree_fully_valid(active_cache_tree))
+               cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+
        if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
index 36e3a2eef2b65e1e9977fd66e5bd514e492c3e56..41f481bd030ba96f8883e64517eda95931344545 100644 (file)
@@ -353,6 +353,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
 
                discard_cache();
                read_cache_from(index_lock.filename);
+               if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
+                       if (reopen_lock_file(&index_lock) < 0)
+                               die(_("unable to write index file"));
+                       if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+                               die(_("unable to update temporary index"));
+               } else
+                       warning(_("Failed to update main cache tree"));
 
                commit_style = COMMIT_NORMAL;
                return index_lock.filename;
@@ -393,8 +400,12 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
        if (!only && !pathspec.nr) {
                hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
-               if (active_cache_changed) {
+               if (active_cache_changed
+                   || !cache_tree_fully_valid(active_cache_tree)) {
                        update_main_cache_tree(WRITE_TREE_SILENT);
+                       active_cache_changed = 1;
+               }
+               if (active_cache_changed) {
                        if (write_locked_index(&the_index, &index_lock,
                                               COMMIT_LOCK))
                                die(_("unable to write new_index file"));
@@ -444,6 +455,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
        hold_locked_index(&index_lock, 1);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
+       update_main_cache_tree(WRITE_TREE_SILENT);
        if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                die(_("unable to write new_index file"));
 
@@ -1540,7 +1552,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
 {
        /* oldsha1 SP newsha1 LF NUL */
        static char buf[2*40 + 3];
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        const char *argv[3];
        int code;
        size_t n;
@@ -1552,7 +1564,6 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
        argv[1] = "amend";
        argv[2] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.argv = argv;
        proc.in = -1;
        proc.stdout_to_stderr = 1;
@@ -1652,11 +1663,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        const char *index_file, *reflog_msg;
        char *nl;
        unsigned char sha1[20];
-       struct ref_lock *ref_lock;
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_commit_usage, builtin_commit_options);
@@ -1778,16 +1790,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        strbuf_release(&author_ident);
        free_commit_extra_headers(extra);
 
-       ref_lock = lock_any_ref_for_update("HEAD",
-                                          !current_head
-                                          ? NULL
-                                          : current_head->object.sha1,
-                                          0, NULL);
-       if (!ref_lock) {
-               rollback_index_files();
-               die(_("cannot lock HEAD ref"));
-       }
-
        nl = strchr(sb.buf, '\n');
        if (nl)
                strbuf_setlen(&sb, nl + 1 - sb.buf);
@@ -1796,10 +1798,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
        strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
 
-       if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, "HEAD", sha1,
+                                  current_head
+                                  ? current_head->object.sha1 : NULL,
+                                  0, !!current_head, &err) ||
+           ref_transaction_commit(transaction, sb.buf, &err)) {
                rollback_index_files();
-               die(_("cannot update HEAD ref"));
+               die("%s", err.buf);
        }
+       ref_transaction_free(transaction);
 
        unlink(git_path("CHERRY_PICK_HEAD"));
        unlink(git_path("REVERT_HEAD"));
@@ -1828,5 +1837,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (!quiet)
                print_summary(prefix, sha1, !current_head);
 
+       strbuf_release(&err);
        return 0;
 }
index e8d0cca3e4110e1ae6db82f21c899c44460cb849..159fb7e91614253cf7820b0c4cd7d07407c76762 100644 (file)
@@ -1110,9 +1110,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        struct string_list list = STRING_LIST_INIT_NODUP;
        struct remote *remote;
        int result = 0;
-       static const char *argv_gc_auto[] = {
-               "gc", "--auto", NULL,
-       };
+       struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
 
        packet_trace_identity("fetch");
 
@@ -1198,7 +1196,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        list.strdup_strings = 1;
        string_list_clear(&list, 0);
 
-       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+       argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
+       if (verbosity < 0)
+               argv_array_push(&argv_gc_auto, "--quiet");
+       run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);
+       argv_array_clear(&argv_gc_auto);
 
        return result;
 }
index 8d219d8c42cb4dfb64468f9b4d82648bff646685..ced1456e1e3b71af05e382fcd505cc269391bb88 100644 (file)
@@ -55,44 +55,33 @@ static void remove_pidfile_on_signal(int signo)
        raise(signo);
 }
 
-static int gc_config(const char *var, const char *value, void *cb)
+static void gc_config(void)
 {
-       if (!strcmp(var, "gc.packrefs")) {
+       const char *value;
+
+       if (!git_config_get_value("gc.packrefs", &value)) {
                if (value && !strcmp(value, "notbare"))
                        pack_refs = -1;
                else
-                       pack_refs = git_config_bool(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.aggressivewindow")) {
-               aggressive_window = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.aggressivedepth")) {
-               aggressive_depth = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.auto")) {
-               gc_auto_threshold = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.autopacklimit")) {
-               gc_auto_pack_limit = git_config_int(var, value);
-               return 0;
+                       pack_refs = git_config_bool("gc.packrefs", value);
        }
-       if (!strcmp(var, "gc.autodetach")) {
-               detach_auto = git_config_bool(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.pruneexpire")) {
-               if (value && strcmp(value, "now")) {
+
+       git_config_get_int("gc.aggressivewindow", &aggressive_window);
+       git_config_get_int("gc.aggressivedepth", &aggressive_depth);
+       git_config_get_int("gc.auto", &gc_auto_threshold);
+       git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
+       git_config_get_bool("gc.autodetach", &detach_auto);
+
+       if (!git_config_get_string_const("gc.pruneexpire", &prune_expire)) {
+               if (strcmp(prune_expire, "now")) {
                        unsigned long now = approxidate("now");
-                       if (approxidate(value) >= now)
-                               return error(_("Invalid %s: '%s'"), var, value);
+                       if (approxidate(prune_expire) >= now) {
+                               git_die_config("gc.pruneexpire", _("Invalid gc.pruneexpire: '%s'"),
+                                               prune_expire);
+                       }
                }
-               return git_config_string(&prune_expire, var, value);
        }
-       return git_default_config(var, value, cb);
+       git_config(git_default_config, NULL);
 }
 
 static int too_many_loose_objects(void)
@@ -301,7 +290,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        argv_array_pushl(&prune, "prune", "--expire", NULL );
        argv_array_pushl(&rerere, "rerere", "gc", NULL);
 
-       git_config(gc_config, NULL);
+       gc_config();
 
        if (pack_refs < 0)
                pack_refs = !is_bare_repository();
index d7fcf4c13c7e0f0855fba51c6b58d2b06c99984e..61583633182da359556fc65795a8eb740167675c 100644 (file)
 #include "parse-options.h"
 #include "exec_cmd.h"
 
-static void hash_fd(int fd, const char *type, int write_object, const char *path)
+/*
+ * This is to create corrupt objects for debugging and as such it
+ * needs to bypass the data conversion performed by, and the type
+ * limitation imposed by, index_fd() and its callees.
+ */
+static int hash_literally(unsigned char *sha1, int fd, const char *type, unsigned flags)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int ret;
+
+       if (strbuf_read(&buf, fd, 4096) < 0)
+               ret = -1;
+       else if (flags & HASH_WRITE_OBJECT)
+               ret = write_sha1_file(buf.buf, buf.len, type, sha1);
+       else
+               ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
+       strbuf_release(&buf);
+       return ret;
+}
+
+static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
+                   int literally)
 {
        struct stat st;
        unsigned char sha1[20];
-       unsigned flags = (HASH_FORMAT_CHECK |
-                         (write_object ? HASH_WRITE_OBJECT : 0));
 
        if (fstat(fd, &st) < 0 ||
-           index_fd(sha1, fd, &st, type_from_string(type), path, flags))
-               die(write_object
+           (literally
+            ? hash_literally(sha1, fd, type, flags)
+            : index_fd(sha1, fd, &st, type_from_string(type), path, flags)))
+               die((flags & HASH_WRITE_OBJECT)
                    ? "Unable to add %s to database"
                    : "Unable to hash %s", path);
        printf("%s\n", sha1_to_hex(sha1));
        maybe_flush_or_die(stdout, "hash to stdout");
 }
 
-static void hash_object(const char *path, const char *type, int write_object,
-                       const char *vpath)
+static void hash_object(const char *path, const char *type, const char *vpath,
+                       unsigned flags, int literally)
 {
        int fd;
        fd = open(path, O_RDONLY);
        if (fd < 0)
                die_errno("Cannot open '%s'", path);
-       hash_fd(fd, type, write_object, vpath);
+       hash_fd(fd, type, vpath, flags, literally);
 }
 
-static int no_filters;
-
-static void hash_stdin_paths(const char *type, int write_objects)
+static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
+                            int literally)
 {
        struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
 
@@ -49,47 +69,46 @@ static void hash_stdin_paths(const char *type, int write_objects)
                                die("line is badly quoted");
                        strbuf_swap(&buf, &nbuf);
                }
-               hash_object(buf.buf, type, write_objects,
-                   no_filters ? NULL : buf.buf);
+               hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,
+                           literally);
        }
        strbuf_release(&buf);
        strbuf_release(&nbuf);
 }
 
-static const char * const hash_object_usage[] = {
-       N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
-       N_("git hash-object  --stdin-paths < <list-of-paths>"),
-       NULL
-};
-
-static const char *type;
-static int write_object;
-static int hashstdin;
-static int stdin_paths;
-static const char *vpath;
-
-static const struct option hash_object_options[] = {
-       OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
-       OPT_BOOL('w', NULL, &write_object, N_("write the object into the object database")),
-       OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
-       OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
-       OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
-       OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
-       OPT_END()
-};
-
 int cmd_hash_object(int argc, const char **argv, const char *prefix)
 {
+       static const char * const hash_object_usage[] = {
+               N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+               N_("git hash-object  --stdin-paths < <list-of-paths>"),
+               NULL
+       };
+       const char *type = blob_type;
+       int hashstdin = 0;
+       int stdin_paths = 0;
+       int no_filters = 0;
+       int literally = 0;
+       unsigned flags = HASH_FORMAT_CHECK;
+       const char *vpath = NULL;
+       const struct option hash_object_options[] = {
+               OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
+               OPT_BIT('w', NULL, &flags, N_("write the object into the object database"),
+                       HASH_WRITE_OBJECT),
+               OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+               OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+               OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
+               OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")),
+               OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
+               OPT_END()
+       };
        int i;
        int prefix_length = -1;
        const char *errstr = NULL;
 
-       type = blob_type;
-
        argc = parse_options(argc, argv, NULL, hash_object_options,
                             hash_object_usage, 0);
 
-       if (write_object) {
+       if (flags & HASH_WRITE_OBJECT) {
                prefix = setup_git_directory();
                prefix_length = prefix ? strlen(prefix) : 0;
                if (vpath && prefix)
@@ -119,19 +138,19 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
        }
 
        if (hashstdin)
-               hash_fd(0, type, write_object, vpath);
+               hash_fd(0, type, vpath, flags, literally);
 
        for (i = 0 ; i < argc; i++) {
                const char *arg = argv[i];
 
                if (0 <= prefix_length)
                        arg = prefix_filename(prefix, prefix_length, arg);
-               hash_object(arg, type, write_object,
-                           no_filters ? NULL : vpath ? vpath : arg);
+               hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
+                           flags, literally);
        }
 
        if (stdin_paths)
-               hash_stdin_paths(type, write_object);
+               hash_stdin_paths(type, no_filters, flags, literally);
 
        return 0;
 }
index 1fdefeb6867cdd37beaf41c5fa9e113576b19f17..8343b4027d458d77a720f79d64c9a4c116208f84 100644 (file)
@@ -79,12 +79,11 @@ static const char *get_man_viewer_info(const char *name)
 static int check_emacsclient_version(void)
 {
        struct strbuf buffer = STRBUF_INIT;
-       struct child_process ec_process;
+       struct child_process ec_process = CHILD_PROCESS_INIT;
        const char *argv_ec[] = { "emacsclient", "--version", NULL };
        int version;
 
        /* emacsclient prints its version number on stderr */
-       memset(&ec_process, 0, sizeof(ec_process));
        ec_process.argv = argv_ec;
        ec_process.err = -1;
        ec_process.stdout_to_stderr = 1;
index ce82eb297db3d03394f4e73a9b07574661db7090..9da9e30d9be46a5ed2de06e8545fe61537ba3676 100644 (file)
@@ -237,11 +237,10 @@ static void drop_save(void)
 static int save_state(unsigned char *stash)
 {
        int len;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf buffer = STRBUF_INIT;
        const char *argv[] = {"stash", "create", NULL};
 
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.out = -1;
        cp.git_cmd = 1;
index 6ffe540c202f69a41fcf40d443f73073d3ba08bd..bf784cb94361f8db5ea17906d0199284a04be99a 100644 (file)
@@ -61,6 +61,46 @@ static const char *add_slash(const char *path)
 static struct lock_file lock_file;
 #define SUBMODULE_WITH_GITDIR ((const char *)1)
 
+static void prepare_move_submodule(const char *src, int first,
+                                  const char **submodule_gitfile)
+{
+       struct strbuf submodule_dotgit = STRBUF_INIT;
+       if (!S_ISGITLINK(active_cache[first]->ce_mode))
+               die(_("Directory %s is in index and no submodule?"), src);
+       if (!is_staging_gitmodules_ok())
+               die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+       strbuf_addf(&submodule_dotgit, "%s/.git", src);
+       *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
+       if (*submodule_gitfile)
+               *submodule_gitfile = xstrdup(*submodule_gitfile);
+       else
+               *submodule_gitfile = SUBMODULE_WITH_GITDIR;
+       strbuf_release(&submodule_dotgit);
+}
+
+static int index_range_of_same_dir(const char *src, int length,
+                                  int *first_p, int *last_p)
+{
+       const char *src_w_slash = add_slash(src);
+       int first, last, len_w_slash = length + 1;
+
+       first = cache_name_pos(src_w_slash, len_w_slash);
+       if (first >= 0)
+               die(_("%.*s is in index"), len_w_slash, src_w_slash);
+
+       first = -1 - first;
+       for (last = first; last < active_nr; last++) {
+               const char *path = active_cache[last]->name;
+               if (strncmp(path, src_w_slash, len_w_slash))
+                       break;
+       }
+       if (src_w_slash != src)
+               free((char *)src_w_slash);
+       *first_p = first;
+       *last_p = last;
+       return last - first;
+}
+
 int cmd_mv(int argc, const char **argv, const char *prefix)
 {
        int i, gitmodules_modified = 0;
@@ -108,7 +148,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
        } else {
                if (argc != 1)
-                       die("destination '%s' is not a directory", dest_path[0]);
+                       die(_("destination '%s' is not a directory"), dest_path[0]);
                destination = dest_path;
        }
 
@@ -131,75 +171,36 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                                && lstat(dst, &st) == 0)
                        bad = _("cannot move directory over file");
                else if (src_is_dir) {
-                       int first = cache_name_pos(src, length);
-                       if (first >= 0) {
-                               struct strbuf submodule_dotgit = STRBUF_INIT;
-                               if (!S_ISGITLINK(active_cache[first]->ce_mode))
-                                       die (_("Huh? Directory %s is in index and no submodule?"), src);
-                               if (!is_staging_gitmodules_ok())
-                                       die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
-                               strbuf_addf(&submodule_dotgit, "%s/.git", src);
-                               submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
-                               if (submodule_gitfile[i])
-                                       submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
-                               else
-                                       submodule_gitfile[i] = SUBMODULE_WITH_GITDIR;
-                               strbuf_release(&submodule_dotgit);
-                       } else {
-                               const char *src_w_slash = add_slash(src);
-                               int last, len_w_slash = length + 1;
+                       int first = cache_name_pos(src, length), last;
 
-                               modes[i] = WORKING_DIRECTORY;
+                       if (first >= 0)
+                               prepare_move_submodule(src, first,
+                                                      submodule_gitfile + i);
+                       else if (index_range_of_same_dir(src, length,
+                                                        &first, &last) < 1)
+                               bad = _("source directory is empty");
+                       else { /* last - first >= 1 */
+                               int j, dst_len, n;
 
-                               first = cache_name_pos(src_w_slash, len_w_slash);
-                               if (first >= 0)
-                                       die (_("Huh? %.*s is in index?"),
-                                                       len_w_slash, src_w_slash);
-
-                               first = -1 - first;
-                               for (last = first; last < active_nr; last++) {
-                                       const char *path = active_cache[last]->name;
-                                       if (strncmp(path, src_w_slash, len_w_slash))
-                                               break;
-                               }
-                               if (src_w_slash != src)
-                                       free((char *)src_w_slash);
-
-                               if (last - first < 1)
-                                       bad = _("source directory is empty");
-                               else {
-                                       int j, dst_len;
-
-                                       if (last - first > 0) {
-                                               source = xrealloc(source,
-                                                               (argc + last - first)
-                                                               * sizeof(char *));
-                                               destination = xrealloc(destination,
-                                                               (argc + last - first)
-                                                               * sizeof(char *));
-                                               modes = xrealloc(modes,
-                                                               (argc + last - first)
-                                                               * sizeof(enum update_mode));
-                                               submodule_gitfile = xrealloc(submodule_gitfile,
-                                                               (argc + last - first)
-                                                               * sizeof(char *));
-                                       }
+                               modes[i] = WORKING_DIRECTORY;
+                               n = argc + last - first;
+                               source = xrealloc(source, n * sizeof(char *));
+                               destination = xrealloc(destination, n * sizeof(char *));
+                               modes = xrealloc(modes, n * sizeof(enum update_mode));
+                               submodule_gitfile = xrealloc(submodule_gitfile, n * sizeof(char *));
 
-                                       dst = add_slash(dst);
-                                       dst_len = strlen(dst);
+                               dst = add_slash(dst);
+                               dst_len = strlen(dst);
 
-                                       for (j = 0; j < last - first; j++) {
-                                               const char *path =
-                                                       active_cache[first + j]->name;
-                                               source[argc + j] = path;
-                                               destination[argc + j] =
-                                                       prefix_path(dst, dst_len,
-                                                               path + length + 1);
-                                               modes[argc + j] = INDEX;
-                                               submodule_gitfile[argc + j] = NULL;
-                                       }
-                                       argc += last - first;
+                               for (j = 0; j < last - first; j++) {
+                                       const char *path = active_cache[first + j]->name;
+                                       source[argc + j] = path;
+                                       destination[argc + j] =
+                                               prefix_path(dst, dst_len, path + length + 1);
+                                       modes[argc + j] = INDEX;
+                                       submodule_gitfile[argc + j] = NULL;
                                }
+                               argc += last - first;
                        }
                } else if (cache_name_pos(src, length) < 0)
                        bad = _("not under version control");
@@ -225,24 +226,22 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                else
                        string_list_insert(&src_for_dst, dst);
 
-               if (bad) {
-                       if (ignore_errors) {
-                               if (--argc > 0) {
-                                       memmove(source + i, source + i + 1,
-                                               (argc - i) * sizeof(char *));
-                                       memmove(destination + i,
-                                               destination + i + 1,
-                                               (argc - i) * sizeof(char *));
-                                       memmove(modes + i, modes + i + 1,
-                                               (argc - i) * sizeof(enum update_mode));
-                                       memmove(submodule_gitfile + i,
-                                               submodule_gitfile + i + 1,
-                                               (argc - i) * sizeof(char *));
-                                       i--;
-                               }
-                       } else
-                               die (_("%s, source=%s, destination=%s"),
-                                    bad, src, dst);
+               if (!bad)
+                       continue;
+               if (!ignore_errors)
+                       die(_("%s, source=%s, destination=%s"),
+                            bad, src, dst);
+               if (--argc > 0) {
+                       int n = argc - i;
+                       memmove(source + i, source + i + 1,
+                               n * sizeof(char *));
+                       memmove(destination + i, destination + i + 1,
+                               n * sizeof(char *));
+                       memmove(modes + i, modes + i + 1,
+                               n * sizeof(enum update_mode));
+                       memmove(submodule_gitfile + i, submodule_gitfile + i + 1,
+                               n * sizeof(char *));
+                       i--;
                }
        }
 
@@ -254,7 +253,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                        printf(_("Renaming %s to %s\n"), src, dst);
                if (!show_only && mode != INDEX) {
                        if (rename(src, dst) < 0 && !ignore_errors)
-                               die_errno (_("renaming '%s' failed"), src);
+                               die_errno(_("renaming '%s' failed"), src);
                        if (submodule_gitfile[i]) {
                                if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
                                        connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
@@ -275,10 +274,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        if (gitmodules_modified)
                stage_updated_gitmodules();
 
-       if (active_cache_changed) {
-               if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
-                       die(_("Unable to write new index file"));
-       }
+       if (active_cache_changed &&
+           write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+               die(_("Unable to write new index file"));
 
        return 0;
 }
index 820c34135cab439e2168dd08947bd79d7ed7ae71..c25a4125103b5bb1c8571864a974105decc1a181 100644 (file)
@@ -122,12 +122,11 @@ static void write_commented_object(int fd, const unsigned char *object)
 {
        const char *show_args[5] =
                {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
-       struct child_process show;
+       struct child_process show = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf cbuf = STRBUF_INIT;
 
        /* Invoke "git show --stat --no-notes $object" */
-       memset(&show, 0, sizeof(show));
        show.argv = show_args;
        show.no_stdin = 1;
        show.out = -1;
index f93ac454b4133f5c1e7cb1675a618b4c0b3174cd..afb8d9926496de2bed8bcab793dd79562e575e18 100644 (file)
@@ -255,7 +255,7 @@ static int copy_to_sideband(int in, int out, void *arg)
 typedef int (*feed_fn)(void *, const char **, size_t *);
 static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
 {
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        struct async muxer;
        const char *argv[2];
        int code;
@@ -266,7 +266,6 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
 
        argv[1] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.argv = argv;
        proc.in = -1;
        proc.stdout_to_stderr = 1;
@@ -350,7 +349,7 @@ static int run_receive_hook(struct command *commands, const char *hook_name,
 static int run_update_hook(struct command *cmd)
 {
        const char *argv[5];
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        int code;
 
        argv[0] = find_hook("update");
@@ -362,7 +361,6 @@ static int run_update_hook(struct command *cmd)
        argv[3] = sha1_to_hex(cmd->new_sha1);
        argv[4] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.no_stdin = 1;
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
@@ -475,7 +473,6 @@ static const char *update(struct command *cmd, struct shallow_info *si)
        const char *namespaced_name;
        unsigned char *old_sha1 = cmd->old_sha1;
        unsigned char *new_sha1 = cmd->new_sha1;
-       struct ref_lock *lock;
 
        /* only refs/... are allowed */
        if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -576,19 +573,27 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                return NULL; /* good */
        }
        else {
+               struct strbuf err = STRBUF_INIT;
+               struct ref_transaction *transaction;
+
                if (shallow_update && si->shallow_ref[cmd->index] &&
                    update_shallow_ref(cmd, si))
                        return "shallow error";
 
-               lock = lock_any_ref_for_update(namespaced_name, old_sha1,
-                                              0, NULL);
-               if (!lock) {
-                       rp_error("failed to lock %s", name);
-                       return "failed to lock";
-               }
-               if (write_ref_sha1(lock, new_sha1, "push")) {
-                       return "failed to write"; /* error() already called */
+               transaction = ref_transaction_begin(&err);
+               if (!transaction ||
+                   ref_transaction_update(transaction, namespaced_name,
+                                          new_sha1, old_sha1, 0, 1, &err) ||
+                   ref_transaction_commit(transaction, "push", &err)) {
+                       ref_transaction_free(transaction);
+
+                       rp_error("%s", err.buf);
+                       strbuf_release(&err);
+                       return "failed to update ref";
                }
+
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
                return NULL; /* good */
        }
 }
@@ -598,7 +603,7 @@ static void run_update_post_hook(struct command *commands)
        struct command *cmd;
        int argc;
        const char **argv;
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        char *hook;
 
        hook = find_hook("post-update");
@@ -621,7 +626,6 @@ static void run_update_post_hook(struct command *commands)
        }
        argv[argc] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.no_stdin = 1;
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
@@ -911,7 +915,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
        const char *hdr_err;
        int status;
        char hdr_arg[38];
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        int fsck_objects = (receive_fsck_objects >= 0
                            ? receive_fsck_objects
                            : transfer_fsck_objects >= 0
@@ -933,7 +937,6 @@ static const char *unpack(int err_fd, struct shallow_info *si)
                argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL);
        }
 
-       memset(&child, 0, sizeof(child));
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
                argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL);
                if (quiet)
index 692c834d9dd48615e42b67e3924c64e3397ad903..d699d28e98c7e76e3c0a4943b58a8c88acede988 100644 (file)
@@ -179,9 +179,8 @@ static void send_git_request(int stdin_fd, const char *serv, const char *repo,
 static int run_child(const char *arg, const char *service)
 {
        int r;
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
 
-       memset(&child, 0, sizeof(child));
        child.in = -1;
        child.out = -1;
        child.err = 0;
index a77e743b94036b2d856e6b3f74999170e39b5f17..fc088dbe6aec8b7a8fd23c924d8bc10c426b78ec 100644 (file)
@@ -133,7 +133,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                {".idx"},
                {".bitmap", 1},
        };
-       struct child_process cmd;
+       struct child_process cmd = CHILD_PROCESS_INIT;
        struct string_list_item *item;
        struct argv_array cmd_args = ARGV_ARRAY_INIT;
        struct string_list names = STRING_LIST_INIT_DUP;
@@ -250,7 +250,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
        argv_array_push(&cmd_args, packtmp);
 
-       memset(&cmd, 0, sizeof(cmd));
        cmd.argv = cmd_args.argv;
        cmd.git_cmd = 1;
        cmd.out = -1;
index 294b61b97e20ac9b5684bd6a180da37ebef43db9..8020db850092691f55df3815173a6eefce0ca6a0 100644 (file)
@@ -155,7 +155,8 @@ static int replace_object_sha1(const char *object_ref,
        unsigned char prev[20];
        enum object_type obj_type, repl_type;
        char ref[PATH_MAX];
-       struct ref_lock *lock;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
        obj_type = sha1_object_info(object, NULL);
        repl_type = sha1_object_info(repl, NULL);
@@ -168,12 +169,13 @@ static int replace_object_sha1(const char *object_ref,
 
        check_ref_valid(object, prev, ref, sizeof(ref), force);
 
-       lock = lock_any_ref_for_update(ref, prev, 0, NULL);
-       if (!lock)
-               die("%s: cannot lock the ref", ref);
-       if (write_ref_sha1(lock, repl, NULL) < 0)
-               die("%s: cannot update the ref", ref);
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err))
+               die("%s", err.buf);
 
+       ref_transaction_free(transaction);
        return 0;
 }
 
@@ -197,7 +199,7 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
 static void export_object(const unsigned char *sha1, enum object_type type,
                          int raw, const char *filename)
 {
-       struct child_process cmd = { NULL };
+       struct child_process cmd = CHILD_PROCESS_INIT;
        int fd;
 
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -234,7 +236,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
 
        if (!raw && type == OBJ_TREE) {
                const char *argv[] = { "mktree", NULL };
-               struct child_process cmd = { argv };
+               struct child_process cmd = CHILD_PROCESS_INIT;
                struct strbuf result = STRBUF_INIT;
 
                cmd.argv = argv;
index 19eb7478208d7e9c88ced92f2620572d2b234974..a81b9e4174c77fc10d9f0a37c547723505208c3c 100644 (file)
@@ -576,7 +576,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct strbuf ref = STRBUF_INIT;
        unsigned char object[20], prev[20];
        const char *object_ref, *tag;
-       struct ref_lock *lock;
        struct create_tag_options opt;
        char *cleanup_arg = NULL;
        int annotate = 0, force = 0, lines = -1;
@@ -584,6 +583,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        const char *msgfile = NULL, *keyid = NULL;
        struct msg_arg msg = { 0, STRBUF_INIT };
        struct commit_list *with_commit = NULL;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
        struct option options[] = {
                OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
                { OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
@@ -729,14 +730,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (annotate)
                create_tag(object, tag, &buf, &opt, prev, object);
 
-       lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
-       if (!lock)
-               die(_("%s: cannot lock the ref"), ref.buf);
-       if (write_ref_sha1(lock, object, NULL) < 0)
-               die(_("%s: cannot update the ref"), ref.buf);
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, ref.buf, object, prev,
+                                  0, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err))
+               die("%s", err.buf);
+       ref_transaction_free(transaction);
        if (force && !is_null_sha1(prev) && hashcmp(prev, object))
                printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
 
+       strbuf_release(&err);
        strbuf_release(&buf);
        strbuf_release(&ref);
        return 0;
index 3067b11310fb01e9e05a1988898566f211601e07..54a48c0cfaab57122fc7ce57c525638c2c95408c 100644 (file)
@@ -12,11 +12,8 @@ static const char * const git_update_ref_usage[] = {
        NULL
 };
 
-static struct ref_transaction *transaction;
-
 static char line_termination = '\n';
 static int update_flags;
-static struct strbuf err = STRBUF_INIT;
 
 /*
  * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
@@ -177,8 +174,10 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
  * depending on how line_termination is set.
  */
 
-static const char *parse_cmd_update(struct strbuf *input, const char *next)
+static const char *parse_cmd_update(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char new_sha1[20];
        unsigned char old_sha1[20];
@@ -204,12 +203,15 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next)
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
 
-static const char *parse_cmd_create(struct strbuf *input, const char *next)
+static const char *parse_cmd_create(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char new_sha1[20];
 
@@ -226,16 +228,21 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next)
        if (*next != line_termination)
                die("create %s: extra input: %s", refname, next);
 
-       ref_transaction_create(transaction, refname, new_sha1, update_flags);
+       if (ref_transaction_create(transaction, refname, new_sha1,
+                                  update_flags, &err))
+               die("%s", err.buf);
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
 
-static const char *parse_cmd_delete(struct strbuf *input, const char *next)
+static const char *parse_cmd_delete(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char old_sha1[20];
        int have_old;
@@ -256,17 +263,21 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next)
        if (*next != line_termination)
                die("delete %s: extra input: %s", refname, next);
 
-       ref_transaction_delete(transaction, refname, old_sha1,
-                              update_flags, have_old);
+       if (ref_transaction_delete(transaction, refname, old_sha1,
+                                  update_flags, have_old, &err))
+               die("%s", err.buf);
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
 
-static const char *parse_cmd_verify(struct strbuf *input, const char *next)
+static const char *parse_cmd_verify(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char new_sha1[20];
        unsigned char old_sha1[20];
@@ -294,6 +305,7 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next)
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
@@ -307,7 +319,7 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next)
        return next + 8;
 }
 
-static void update_refs_stdin(void)
+static void update_refs_stdin(struct ref_transaction *transaction)
 {
        struct strbuf input = STRBUF_INIT;
        const char *next;
@@ -322,13 +334,13 @@ static void update_refs_stdin(void)
                else if (isspace(*next))
                        die("whitespace before command: %s", next);
                else if (starts_with(next, "update "))
-                       next = parse_cmd_update(&input, next + 7);
+                       next = parse_cmd_update(transaction, &input, next + 7);
                else if (starts_with(next, "create "))
-                       next = parse_cmd_create(&input, next + 7);
+                       next = parse_cmd_create(transaction, &input, next + 7);
                else if (starts_with(next, "delete "))
-                       next = parse_cmd_delete(&input, next + 7);
+                       next = parse_cmd_delete(transaction, &input, next + 7);
                else if (starts_with(next, "verify "))
-                       next = parse_cmd_verify(&input, next + 7);
+                       next = parse_cmd_verify(transaction, &input, next + 7);
                else if (starts_with(next, "option "))
                        next = parse_cmd_option(&input, next + 7);
                else
@@ -362,15 +374,21 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                die("Refusing to perform update with empty message.");
 
        if (read_stdin) {
-               transaction = ref_transaction_begin();
+               struct strbuf err = STRBUF_INIT;
+               struct ref_transaction *transaction;
+
+               transaction = ref_transaction_begin(&err);
+               if (!transaction)
+                       die("%s", err.buf);
                if (delete || no_deref || argc > 0)
                        usage_with_options(git_update_ref_usage, options);
                if (end_null)
                        line_termination = '\0';
-               update_refs_stdin();
+               update_refs_stdin(transaction);
                if (ref_transaction_commit(transaction, msg, &err))
                        die("%s", err.buf);
                ref_transaction_free(transaction);
+               strbuf_release(&err);
                return 0;
        }
 
index 972579f33c4b0adfb2240ef90b22980dc042c70a..7747537beb72aba52377a13b9b3d61829f3a2fa8 100644 (file)
@@ -8,7 +8,7 @@
 
 static int verify_one_pack(const char *path, unsigned int flags)
 {
-       struct child_process index_pack;
+       struct child_process index_pack = CHILD_PROCESS_INIT;
        const char *argv[] = {"index-pack", NULL, NULL, NULL };
        struct strbuf arg = STRBUF_INIT;
        int verbose = flags & VERIFY_PACK_VERBOSE;
@@ -32,7 +32,6 @@ static int verify_one_pack(const char *path, unsigned int flags)
                strbuf_addstr(&arg, ".pack");
        argv[2] = arg.buf;
 
-       memset(&index_pack, 0, sizeof(index_pack));
        index_pack.argv = argv;
        index_pack.git_cmd = 1;
 
index b708906cdbd2a14d0e5bcd1e1288c78777cf6a5e..b2b89fe8628eb29b613754ee8e837fd56de185da 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -240,7 +240,7 @@ int create_bundle(struct bundle_header *header, const char *path,
        int i, ref_count = 0;
        struct strbuf buf = STRBUF_INIT;
        struct rev_info revs;
-       struct child_process rls;
+       struct child_process rls = CHILD_PROCESS_INIT;
        FILE *rls_fout;
 
        bundle_to_stdout = !strcmp(path, "-");
@@ -258,7 +258,6 @@ int create_bundle(struct bundle_header *header, const char *path,
        init_revisions(&revs, NULL);
 
        /* write prerequisites */
-       memset(&rls, 0, sizeof(rls));
        argv_array_pushl(&rls.args,
                         "rev-list", "--boundary", "--pretty=oneline",
                         NULL);
@@ -417,14 +416,13 @@ int unbundle(struct bundle_header *header, int bundle_fd, int flags)
 {
        const char *argv_index_pack[] = {"index-pack",
                                         "--fix-thin", "--stdin", NULL, NULL};
-       struct child_process ip;
+       struct child_process ip = CHILD_PROCESS_INIT;
 
        if (flags & BUNDLE_VERBOSE)
                argv_index_pack[3] = "-v";
 
        if (verify_bundle(header, 0))
                return -1;
-       memset(&ip, 0, sizeof(ip));
        ip.argv = argv_index_pack;
        ip.in = bundle_fd;
        ip.no_stdout = 1;
index c53f7de2b13acfc1b97c60b04552e57791377442..75a54fdc7232e5693b042aa06540d51a99f01551 100644 (file)
@@ -246,9 +246,12 @@ static int update_one(struct cache_tree *it,
        struct strbuf buffer;
        int missing_ok = flags & WRITE_TREE_MISSING_OK;
        int dryrun = flags & WRITE_TREE_DRY_RUN;
+       int repair = flags & WRITE_TREE_REPAIR;
        int to_invalidate = 0;
        int i;
 
+       assert(!(dryrun && repair));
+
        *skip_count = 0;
 
        if (0 <= it->entry_count && has_sha1_file(it->sha1))
@@ -320,6 +323,7 @@ static int update_one(struct cache_tree *it,
                int pathlen, entlen;
                const unsigned char *sha1;
                unsigned mode;
+               int expected_missing = 0;
 
                path = ce->name;
                pathlen = ce_namelen(ce);
@@ -336,8 +340,10 @@ static int update_one(struct cache_tree *it,
                        i += sub->count;
                        sha1 = sub->cache_tree->sha1;
                        mode = S_IFDIR;
-                       if (sub->cache_tree->entry_count < 0)
+                       if (sub->cache_tree->entry_count < 0) {
                                to_invalidate = 1;
+                               expected_missing = 1;
+                       }
                }
                else {
                        sha1 = ce->sha1;
@@ -347,6 +353,8 @@ static int update_one(struct cache_tree *it,
                }
                if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
                        strbuf_release(&buffer);
+                       if (expected_missing)
+                               return -1;
                        return error("invalid object %06o %s for '%.*s'",
                                mode, sha1_to_hex(sha1), entlen+baselen, path);
                }
@@ -381,7 +389,14 @@ static int update_one(struct cache_tree *it,
 #endif
        }
 
-       if (dryrun)
+       if (repair) {
+               unsigned char sha1[20];
+               hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
+               if (has_sha1_file(sha1))
+                       hashcpy(it->sha1, sha1);
+               else
+                       to_invalidate = 1;
+       } else if (dryrun)
                hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
        else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) {
                strbuf_release(&buffer);
index b47ccec7f626d7cda34ed17661c1dc3e4f035d6a..aa7b3e4a0a9d4bbb29574d71e23c05349be4c6fc 100644 (file)
@@ -39,6 +39,7 @@ int update_main_cache_tree(int);
 #define WRITE_TREE_IGNORE_CACHE_TREE 2
 #define WRITE_TREE_DRY_RUN 4
 #define WRITE_TREE_SILENT 8
+#define WRITE_TREE_REPAIR 16
 
 /* error return codes */
 #define WRITE_TREE_UNREADABLE_INDEX (-1)
diff --git a/cache.h b/cache.h
index 4d5b76c76ab2275f51c504cac62cda7e563e1d1d..dfa1a5696d448b407644276df58fb24e25c57113 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -8,6 +8,7 @@
 #include "gettext.h"
 #include "convert.h"
 #include "trace.h"
+#include "string-list.h"
 
 #include SHA1_HEADER
 #ifndef git_SHA_CTX
@@ -1296,7 +1297,7 @@ extern int git_config_from_buf(config_fn_t fn, const char *name,
                               const char *buf, size_t len, void *data);
 extern void git_config_push_parameter(const char *text);
 extern int git_config_from_parameters(config_fn_t fn, void *data);
-extern int git_config(config_fn_t fn, void *);
+extern void git_config(config_fn_t fn, void *);
 extern int git_config_with_options(config_fn_t fn, void *,
                                   struct git_config_source *config_source,
                                   int respect_includes);
@@ -1353,9 +1354,32 @@ extern int parse_config_key(const char *var,
                            const char **subsection, int *subsection_len,
                            const char **key);
 
+struct config_set_element {
+       struct hashmap_entry ent;
+       char *key;
+       struct string_list value_list;
+};
+
+struct configset_list_item {
+       struct config_set_element *e;
+       int value_index;
+};
+
+/*
+ * the contents of the list are ordered according to their
+ * position in the config files and order of parsing the files.
+ * (i.e. key-value pair at the last position of .git/config will
+ * be at the last item of the list)
+ */
+struct configset_list {
+       struct configset_list_item *items;
+       unsigned int nr, alloc;
+};
+
 struct config_set {
        struct hashmap config_hash;
        int hash_initialized;
+       struct configset_list list;
 };
 
 extern void git_configset_init(struct config_set *cs);
@@ -1385,6 +1409,14 @@ extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
 extern int git_config_get_maybe_bool(const char *key, int *dest);
 extern int git_config_get_pathname(const char *key, const char **dest);
 
+struct key_value_info {
+       const char *filename;
+       int linenr;
+};
+
+extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
+
 extern int committer_ident_sufficiently_given(void);
 extern int author_ident_sufficiently_given(void);
 
index ca878bcea7a42476a7c2b03e74897a2af87bec3f..76b615db5f2a4ff7567a7d1d9d6514f838f15321 100644 (file)
--- a/column.c
+++ b/column.c
@@ -367,7 +367,7 @@ int parseopt_column_callback(const struct option *opt,
 }
 
 static int fd_out = -1;
-static struct child_process column_process;
+static struct child_process column_process = CHILD_PROCESS_INIT;
 
 int run_column_filter(int colopts, const struct column_options *opts)
 {
index aa8c3ca50af42375caf954e309d76731b4a9295e..a401ddfbc4e5c2e5e4a9d7aeedebc34e6103c9fa 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -26,13 +26,25 @@ extern int save_commit_buffer;
 extern const char *commit_type;
 
 /* While we can decorate any object with a name, it's only used for commits.. */
-extern struct decoration name_decoration;
 struct name_decoration {
        struct name_decoration *next;
        int type;
-       char name[1];
+       char name[FLEX_ARRAY];
 };
 
+enum decoration_type {
+       DECORATION_NONE = 0,
+       DECORATION_REF_LOCAL,
+       DECORATION_REF_REMOTE,
+       DECORATION_REF_TAG,
+       DECORATION_REF_STASH,
+       DECORATION_REF_HEAD,
+       DECORATION_GRAFTED,
+};
+
+void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);
+const struct name_decoration *get_name_decoration(const struct object *obj);
+
 struct commit *lookup_commit(const unsigned char *sha1);
 struct commit *lookup_commit_reference(const unsigned char *sha1);
 struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
index 01e0bdbafd4d43a7fb983449c78d711d22dd2375..83c913ad0928aba882a86f361170cd256adbd445 100644 (file)
--- a/config.c
+++ b/config.c
@@ -35,12 +35,6 @@ struct config_source {
        long (*do_ftell)(struct config_source *c);
 };
 
-struct config_set_element {
-       struct hashmap_entry ent;
-       char *key;
-       struct string_list value_list;
-};
-
 static struct config_source *cf;
 
 static int zlib_compression_seen;
@@ -252,6 +246,7 @@ static int get_next_char(void)
                cf->linenr++;
        if (c == EOF) {
                cf->eof = 1;
+               cf->linenr++;
                c = '\n';
        }
        return c;
@@ -327,6 +322,7 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
 {
        int c;
        char *value;
+       int ret;
 
        /* Get the full name */
        for (;;) {
@@ -349,7 +345,15 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
                if (!value)
                        return -1;
        }
-       return fn(name->buf, value, data);
+       /*
+        * We already consumed the \n, but we need linenr to point to
+        * the line we just parsed during the call to fn to get
+        * accurate line number in error messages.
+        */
+       cf->linenr--;
+       ret = fn(name->buf, value, data);
+       cf->linenr++;
+       return ret;
 }
 
 static int get_extended_base_var(struct strbuf *name, int c)
@@ -465,9 +469,9 @@ static int git_parse_source(config_fn_t fn, void *data)
                        break;
        }
        if (cf->die_on_error)
-               die("bad config file line %d in %s", cf->linenr, cf->name);
+               die(_("bad config file line %d in %s"), cf->linenr, cf->name);
        else
-               return error("bad config file line %d in %s", cf->linenr, cf->name);
+               return error(_("bad config file line %d in %s"), cf->linenr, cf->name);
 }
 
 static int parse_unit_factor(const char *end, uintmax_t *val)
@@ -583,9 +587,9 @@ static void die_bad_number(const char *name, const char *value)
                value = "";
 
        if (cf && cf->name)
-               die("bad numeric config value '%s' for '%s' in %s: %s",
+               die(_("bad numeric config value '%s' for '%s' in %s: %s"),
                    value, name, cf->name, reason);
-       die("bad numeric config value '%s' for '%s': %s", value, name, reason);
+       die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason);
 }
 
 int git_config_int(const char *name, const char *value)
@@ -670,7 +674,7 @@ int git_config_pathname(const char **dest, const char *var, const char *value)
                return config_error_nonbool(var);
        *dest = expand_user_path(value);
        if (!*dest)
-               die("Failed to expand user dir in: '%s'", value);
+               die(_("failed to expand user dir in: '%s'"), value);
        return 0;
 }
 
@@ -748,7 +752,7 @@ static int git_default_core_config(const char *var, const char *value)
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
-                       die("bad zlib compression level %d", level);
+                       die(_("bad zlib compression level %d"), level);
                zlib_compression_level = level;
                zlib_compression_seen = 1;
                return 0;
@@ -759,7 +763,7 @@ static int git_default_core_config(const char *var, const char *value)
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
-                       die("bad zlib compression level %d", level);
+                       die(_("bad zlib compression level %d"), level);
                core_compression_level = level;
                core_compression_seen = 1;
                if (!zlib_compression_seen)
@@ -881,7 +885,7 @@ static int git_default_core_config(const char *var, const char *value)
                else if (!strcmp(value, "link"))
                        object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
                else
-                       die("Invalid mode for object creation: %s", value);
+                       die(_("invalid mode for object creation: %s"), value);
                return 0;
        }
 
@@ -1181,7 +1185,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
        switch (git_config_from_parameters(fn, data)) {
        case -1: /* error */
-               die("unable to parse command-line config");
+               die(_("unable to parse command-line config"));
                break;
        case 0: /* found nothing */
                break;
@@ -1228,9 +1232,48 @@ int git_config_with_options(config_fn_t fn, void *data,
        return ret;
 }
 
-int git_config(config_fn_t fn, void *data)
+static void git_config_raw(config_fn_t fn, void *data)
+{
+       if (git_config_with_options(fn, data, NULL, 1) < 0)
+               /*
+                * git_config_with_options() normally returns only
+                * positive values, as most errors are fatal, and
+                * non-fatal potential errors are guarded by "if"
+                * statements that are entered only when no error is
+                * possible.
+                *
+                * If we ever encounter a non-fatal error, it means
+                * something went really wrong and we should stop
+                * immediately.
+                */
+               die(_("unknown error occured while reading the configuration files"));
+}
+
+static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
 {
-       return git_config_with_options(fn, data, NULL, 1);
+       int i, value_index;
+       struct string_list *values;
+       struct config_set_element *entry;
+       struct configset_list *list = &cs->list;
+       struct key_value_info *kv_info;
+
+       for (i = 0; i < list->nr; i++) {
+               entry = list->items[i].e;
+               value_index = list->items[i].value_index;
+               values = &entry->value_list;
+               if (fn(entry->key, values->items[value_index].string, data) < 0) {
+                       kv_info = values->items[value_index].util;
+                       git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
+               }
+       }
+}
+
+static void git_config_check_init(void);
+
+void git_config(config_fn_t fn, void *data)
+{
+       git_config_check_init();
+       configset_iter(&the_config_set, fn, data);
 }
 
 static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
@@ -1258,6 +1301,10 @@ static struct config_set_element *configset_find_element(struct config_set *cs,
 static int configset_add_value(struct config_set *cs, const char *key, const char *value)
 {
        struct config_set_element *e;
+       struct string_list_item *si;
+       struct configset_list_item *l_item;
+       struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
+
        e = configset_find_element(cs, key);
        /*
         * Since the keys are being fed by git_config*() callback mechanism, they
@@ -1270,7 +1317,22 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
                string_list_init(&e->value_list, 1);
                hashmap_add(&cs->config_hash, e);
        }
-       string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+       si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+
+       ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
+       l_item = &cs->list.items[cs->list.nr++];
+       l_item->e = e;
+       l_item->value_index = e->value_list.nr - 1;
+
+       if (cf) {
+               kv_info->filename = strintern(cf->name);
+               kv_info->linenr = cf->linenr;
+       } else {
+               /* for values read from `git_config_from_parameters()` */
+               kv_info->filename = NULL;
+               kv_info->linenr = -1;
+       }
+       si->util = kv_info;
 
        return 0;
 }
@@ -1285,6 +1347,9 @@ void git_configset_init(struct config_set *cs)
 {
        hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
        cs->hash_initialized = 1;
+       cs->list.nr = 0;
+       cs->list.alloc = 0;
+       cs->list.items = NULL;
 }
 
 void git_configset_clear(struct config_set *cs)
@@ -1297,10 +1362,14 @@ void git_configset_clear(struct config_set *cs)
        hashmap_iter_init(&cs->config_hash, &iter);
        while ((entry = hashmap_iter_next(&iter))) {
                free(entry->key);
-               string_list_clear(&entry->value_list, 0);
+               string_list_clear(&entry->value_list, 1);
        }
        hashmap_free(&cs->config_hash, 1);
        cs->hash_initialized = 0;
+       free(cs->list.items);
+       cs->list.nr = 0;
+       cs->list.alloc = 0;
+       cs->list.items = NULL;
 }
 
 static int config_set_callback(const char *key, const char *value, void *cb)
@@ -1419,7 +1488,7 @@ static void git_config_check_init(void)
        if (the_config_set.hash_initialized)
                return;
        git_configset_init(&the_config_set);
-       git_config(config_set_callback, &the_config_set);
+       git_config_raw(config_set_callback, &the_config_set);
 }
 
 void git_config_clear(void)
@@ -1443,8 +1512,12 @@ const struct string_list *git_config_get_value_multi(const char *key)
 
 int git_config_get_string_const(const char *key, const char **dest)
 {
+       int ret;
        git_config_check_init();
-       return git_configset_get_string_const(&the_config_set, key, dest);
+       ret = git_configset_get_string_const(&the_config_set, key, dest);
+       if (ret < 0)
+               git_die_config(key, NULL);
+       return ret;
 }
 
 int git_config_get_string(const char *key, char **dest)
@@ -1485,8 +1558,39 @@ int git_config_get_maybe_bool(const char *key, int *dest)
 
 int git_config_get_pathname(const char *key, const char **dest)
 {
+       int ret;
        git_config_check_init();
-       return git_configset_get_pathname(&the_config_set, key, dest);
+       ret = git_configset_get_pathname(&the_config_set, key, dest);
+       if (ret < 0)
+               git_die_config(key, NULL);
+       return ret;
+}
+
+NORETURN
+void git_die_config_linenr(const char *key, const char *filename, int linenr)
+{
+       if (!filename)
+               die(_("unable to parse '%s' from command-line config"), key);
+       else
+               die(_("bad config variable '%s' in file '%s' at line %d"),
+                   key, filename, linenr);
+}
+
+NORETURN __attribute__((format(printf, 2, 3)))
+void git_die_config(const char *key, const char *err, ...)
+{
+       const struct string_list *values;
+       struct key_value_info *kv_info;
+
+       if (err) {
+               va_list params;
+               va_start(params, err);
+               vreportf("error: ", err, params);
+               va_end(params);
+       }
+       values = git_config_get_value_multi(key);
+       kv_info = values->items[values->nr - 1].util;
+       git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
 }
 
 /*
@@ -1522,7 +1626,7 @@ static int store_aux(const char *key, const char *value, void *cb)
        case KEY_SEEN:
                if (matches(key, value)) {
                        if (store.seen == 1 && store.multi_replace == 0) {
-                               warning("%s has multiple values", key);
+                               warning(_("%s has multiple values"), key);
                        }
 
                        ALLOC_GROW(store.offset, store.seen + 1,
index 5047402a1aade7a443f55999550ae4542189ef01..87b52026326e8c0f0296e80d64c784888f719a8e 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -537,7 +537,8 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
 
        get_host_and_port(&host, &port);
 
-       proxy = xcalloc(1, sizeof(*proxy));
+       proxy = xmalloc(sizeof(*proxy));
+       child_process_init(proxy);
        argv_array_push(&proxy->args, git_proxy_command);
        argv_array_push(&proxy->args, host);
        argv_array_push(&proxy->args, port);
@@ -639,7 +640,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
        return protocol;
 }
 
-static struct child_process no_fork;
+static struct child_process no_fork = CHILD_PROCESS_INIT;
 
 /*
  * This returns a dummy child_process if the transport protocol does not
@@ -694,7 +695,8 @@ struct child_process *git_connect(int fd[2], const char *url,
                             target_host, 0);
                free(target_host);
        } else {
-               conn = xcalloc(1, sizeof(*conn));
+               conn = xmalloc(sizeof(*conn));
+               child_process_init(conn);
 
                strbuf_addstr(&cmd, prog);
                strbuf_addch(&cmd, ' ');
index dae9c9972eb3485bd20494efd78d09f1189667cb..299c56090bc38b1572b0ac03ec48532f40de605f 100644 (file)
@@ -25,7 +25,7 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
                                           struct transport *transport,
                                           const char *shallow_file)
 {
-       struct child_process rev_list;
+       struct child_process rev_list = CHILD_PROCESS_INIT;
        const char *argv[9];
        char commit[41];
        unsigned char sha1[20];
@@ -60,7 +60,6 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
                argv[ac++] = "--quiet";
        argv[ac] = NULL;
 
-       memset(&rev_list, 0, sizeof(rev_list));
        rev_list.argv = argv;
        rev_list.git_cmd = 1;
        rev_list.in = -1;
index d9a0ce2c6337b906617306f466139b5f486a753d..c2bd703ee3aa0fd734c71dc50c01085455d33773 100644 (file)
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 -include ../../config.mak.autogen
 -include ../../config.mak
 
@@ -34,7 +37,7 @@ GIT_SUBTREE_XML := git-subtree.xml
 GIT_SUBTREE_TXT := git-subtree.txt
 GIT_SUBTREE_HTML := git-subtree.html
 
-all: $(GIT_SUBTREE)
+all:: $(GIT_SUBTREE)
 
 $(GIT_SUBTREE): $(GIT_SUBTREE_SH)
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' $< >$@
index cb5fbb45ea04cead65316ecf6b44730b17108122..aa7a139bcf7f3d33511e106545e6d8989a0ffe35 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -321,7 +321,7 @@ static int filter_buffer(int in, int out, void *data)
        /*
         * Spawn cmd and feed the buffer contents through its stdin.
         */
-       struct child_process child_process;
+       struct child_process child_process = CHILD_PROCESS_INIT;
        struct filter_params *params = (struct filter_params *)data;
        int write_err, status;
        const char *argv[] = { NULL, NULL };
@@ -344,7 +344,6 @@ static int filter_buffer(int in, int out, void *data)
 
        argv[0] = cmd.buf;
 
-       memset(&child_process, 0, sizeof(child_process));
        child_process.argv = argv;
        child_process.use_shell = 1;
        child_process.in = -1;
index 9a03792c7de109e957a1f01924c4f66ba87b5c87..8689a1519a5635a1d92e9e4106936b4159d2e106 100644 (file)
@@ -37,12 +37,11 @@ static int send_request(const char *socket, const struct strbuf *out)
 
 static void spawn_daemon(const char *socket)
 {
-       struct child_process daemon;
+       struct child_process daemon = CHILD_PROCESS_INIT;
        const char *argv[] = { NULL, NULL, NULL };
        char buf[128];
        int r;
 
-       memset(&daemon, 0, sizeof(daemon));
        argv[0] = "git-credential-cache--daemon";
        argv[1] = socket;
        daemon.argv = argv;
index 4d79d320f89e956aa9233a170120f05b2473ca59..1886ea50b3b3c2a213e34876de691fa3d0a83b6c 100644 (file)
@@ -205,11 +205,10 @@ static int run_credential_helper(struct credential *c,
                                 const char *cmd,
                                 int want_output)
 {
-       struct child_process helper;
+       struct child_process helper = CHILD_PROCESS_INIT;
        const char *argv[] = { NULL, NULL };
        FILE *fp;
 
-       memset(&helper, 0, sizeof(helper));
        argv[0] = cmd;
        helper.argv = argv;
        helper.use_shell = 1;
index e6b51ed9981f2e4084504a2a092a3f28fc7d4c8a..4dcfff9352c8d034bfaec4efa0c36df41e7813a7 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -230,23 +230,6 @@ struct daemon_service {
        int overridable;
 };
 
-static struct daemon_service *service_looking_at;
-static int service_enabled;
-
-static int git_daemon_config(const char *var, const char *value, void *cb)
-{
-       const char *service;
-
-       if (skip_prefix(var, "daemon.", &service) &&
-           !strcmp(service, service_looking_at->config_name)) {
-               service_enabled = git_config_bool(var, value);
-               return 0;
-       }
-
-       /* we are not interested in parsing any other configuration here */
-       return 0;
-}
-
 static int daemon_error(const char *dir, const char *msg)
 {
        if (!informative_errors)
@@ -259,7 +242,7 @@ static const char *access_hook;
 
 static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
 {
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        const char *argv[8];
        const char **arg = argv;
@@ -277,7 +260,6 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        *arg = NULL;
 #undef STRARG
 
-       memset(&child, 0, sizeof(child));
        child.use_shell = 1;
        child.argv = argv;
        child.no_stdin = 1;
@@ -324,6 +306,7 @@ static int run_service(const char *dir, struct daemon_service *service)
 {
        const char *path;
        int enabled = service->enabled;
+       struct strbuf var = STRBUF_INIT;
 
        loginfo("Request %s for '%s'", service->name, dir);
 
@@ -354,11 +337,9 @@ static int run_service(const char *dir, struct daemon_service *service)
        }
 
        if (service->overridable) {
-               service_looking_at = service;
-               service_enabled = -1;
-               git_config(git_daemon_config, NULL);
-               if (0 <= service_enabled)
-                       enabled = service_enabled;
+               strbuf_addf(&var, "daemon.%s", service->config_name);
+               git_config_get_bool(var.buf, &enabled);
+               strbuf_release(&var);
        }
        if (!enabled) {
                logerror("'%s': service not enabled for '%s'",
@@ -406,9 +387,8 @@ static void copy_to_log(int fd)
 
 static int run_service_command(const char **argv)
 {
-       struct child_process cld;
+       struct child_process cld = CHILD_PROCESS_INIT;
 
-       memset(&cld, 0, sizeof(cld));
        cld.argv = argv;
        cld.git_cmd = 1;
        cld.err = -1;
@@ -733,7 +713,7 @@ static void check_dead_children(void)
 static char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
-       struct child_process cld = { NULL };
+       struct child_process cld = CHILD_PROCESS_INIT;
        char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
        char *env[] = { addrbuf, portbuf, NULL };
 
diff --git a/diff.c b/diff.c
index 867f034b8ffc052d28f28a86fd9f52a5aa5b2c82..d7a5c81bb8545584ce5fe652dc42f2ee8bc1e2fd 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -376,7 +376,7 @@ static unsigned long diff_filespec_size(struct diff_filespec *one)
 {
        if (!DIFF_FILE_VALID(one))
                return 0;
-       diff_populate_filespec(one, 1);
+       diff_populate_filespec(one, CHECK_SIZE_ONLY);
        return one->size;
 }
 
@@ -1910,11 +1910,11 @@ static void show_dirstat(struct diff_options *options)
                        diff_free_filespec_data(p->one);
                        diff_free_filespec_data(p->two);
                } else if (DIFF_FILE_VALID(p->one)) {
-                       diff_populate_filespec(p->one, 1);
+                       diff_populate_filespec(p->one, CHECK_SIZE_ONLY);
                        copied = added = 0;
                        diff_free_filespec_data(p->one);
                } else if (DIFF_FILE_VALID(p->two)) {
-                       diff_populate_filespec(p->two, 1);
+                       diff_populate_filespec(p->two, CHECK_SIZE_ONLY);
                        copied = 0;
                        added = p->two->size;
                        diff_free_filespec_data(p->two);
@@ -2188,8 +2188,8 @@ int diff_filespec_is_binary(struct diff_filespec *one)
                        one->is_binary = one->driver->binary;
                else {
                        if (!one->data && DIFF_FILE_VALID(one))
-                               diff_populate_filespec(one, 0);
-                       if (one->data)
+                               diff_populate_filespec(one, CHECK_BINARY);
+                       if (one->is_binary == -1 && one->data)
                                one->is_binary = buffer_is_binary(one->data,
                                                one->size);
                        if (one->is_binary == -1)
@@ -2324,6 +2324,19 @@ static void builtin_diff(const char *name_a,
        } else if (!DIFF_OPT_TST(o, TEXT) &&
            ( (!textconv_one && diff_filespec_is_binary(one)) ||
              (!textconv_two && diff_filespec_is_binary(two)) )) {
+               if (!one->data && !two->data &&
+                   S_ISREG(one->mode) && S_ISREG(two->mode) &&
+                   !DIFF_OPT_TST(o, BINARY)) {
+                       if (!hashcmp(one->sha1, two->sha1)) {
+                               if (must_show_header)
+                                       fprintf(o->file, "%s", header.buf);
+                               goto free_ab_and_return;
+                       }
+                       fprintf(o->file, "%s", header.buf);
+                       fprintf(o->file, "%sBinary files %s and %s differ\n",
+                               line_prefix, lbl[0], lbl[1]);
+                       goto free_ab_and_return;
+               }
                if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                        die("unable to read files to diff");
                /* Quite common confusing case */
@@ -2668,8 +2681,9 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
  * grab the data for the blob (or file) for our own in-core comparison.
  * diff_filespec has data and size fields for this purpose.
  */
-int diff_populate_filespec(struct diff_filespec *s, int size_only)
+int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
 {
+       int size_only = flags & CHECK_SIZE_ONLY;
        int err = 0;
        /*
         * demote FAIL to WARN to allow inspecting the situation
@@ -2724,6 +2738,11 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                }
                if (size_only)
                        return 0;
+               if ((flags & CHECK_BINARY) &&
+                   s->size > big_file_threshold && s->is_binary == -1) {
+                       s->is_binary = 1;
+                       return 0;
+               }
                fd = open(s->path, O_RDONLY);
                if (fd < 0)
                        goto err_empty;
@@ -2745,16 +2764,21 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        }
        else {
                enum object_type type;
-               if (size_only) {
+               if (size_only || (flags & CHECK_BINARY)) {
                        type = sha1_object_info(s->sha1, &s->size);
                        if (type < 0)
                                die("unable to read %s", sha1_to_hex(s->sha1));
-               } else {
-                       s->data = read_sha1_file(s->sha1, &type, &s->size);
-                       if (!s->data)
-                               die("unable to read %s", sha1_to_hex(s->sha1));
-                       s->should_free = 1;
+                       if (size_only)
+                               return 0;
+                       if (s->size > big_file_threshold && s->is_binary == -1) {
+                               s->is_binary = 1;
+                               return 0;
+                       }
                }
+               s->data = read_sha1_file(s->sha1, &type, &s->size);
+               if (!s->data)
+                       die("unable to read %s", sha1_to_hex(s->sha1));
+               s->should_free = 1;
        }
        return 0;
 }
@@ -4688,8 +4712,8 @@ static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
            !DIFF_FILE_VALID(p->two) ||
            (p->one->sha1_valid && p->two->sha1_valid) ||
            (p->one->mode != p->two->mode) ||
-           diff_populate_filespec(p->one, 1) ||
-           diff_populate_filespec(p->two, 1) ||
+           diff_populate_filespec(p->one, CHECK_SIZE_ONLY) ||
+           diff_populate_filespec(p->two, CHECK_SIZE_ONLY) ||
            (p->one->size != p->two->size) ||
            !diff_filespec_is_identical(p->one, p->two)) /* (2) */
                p->skip_stat_unmatch_result = 1;
@@ -4931,7 +4955,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        struct diff_tempfile *temp;
        const char *argv[3];
        const char **arg = argv;
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        int err = 0;
 
@@ -4940,7 +4964,6 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        *arg++ = temp->name;
        *arg = NULL;
 
-       memset(&child, 0, sizeof(child));
        child.use_shell = 1;
        child.argv = argv;
        child.out = -1;
index 2e44a3745939bb75841730ba0cff78ea872df8d9..4e132f1fdb68ed3c930ca8224a5403c9b406cc3b 100644 (file)
@@ -147,9 +147,11 @@ static int estimate_similarity(struct diff_filespec *src,
         * is a possible size - we really should have a flag to
         * say whether the size is valid or not!)
         */
-       if (!src->cnt_data && diff_populate_filespec(src, 1))
+       if (!src->cnt_data &&
+           diff_populate_filespec(src, CHECK_SIZE_ONLY))
                return 0;
-       if (!dst->cnt_data && diff_populate_filespec(dst, 1))
+       if (!dst->cnt_data &&
+           diff_populate_filespec(dst, CHECK_SIZE_ONLY))
                return 0;
 
        max_size = ((src->size > dst->size) ? src->size : dst->size);
index c876dac71a585abb1e138444eb28258e3bf6d7e8..33ea2de348803b29a08a6713ae4cab1345f874d9 100644 (file)
@@ -55,7 +55,9 @@ extern void free_filespec(struct diff_filespec *);
 extern void fill_filespec(struct diff_filespec *, const unsigned char *,
                          int, unsigned short);
 
-extern int diff_populate_filespec(struct diff_filespec *, int);
+#define CHECK_SIZE_ONLY 1
+#define CHECK_BINARY    2
+extern int diff_populate_filespec(struct diff_filespec *, unsigned int);
 extern void diff_free_filespec_data(struct diff_filespec *);
 extern void diff_free_filespec_blob(struct diff_filespec *);
 extern int diff_filespec_is_binary(struct diff_filespec *);
index 0abbd8dc3a0ec91acd0c143b6d9b5ad41ac90417..01c644cddbe8e57e31cc711aa0ca3838cf23c64d 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -38,10 +38,9 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en
 
        if (strcmp(editor, ":")) {
                const char *args[] = { editor, real_path(path), NULL };
-               struct child_process p;
+               struct child_process p = CHILD_PROCESS_INIT;
                int ret, sig;
 
-               memset(&p, 0, sizeof(p));
                p.argv = args;
                p.env = env;
                p.use_shell = 1;
index d73f58cbe3fe4522fa24d47f9086d927b3296c8b..c071253c90807b6fa98771e9fd046fed12bb7b4b 100644 (file)
@@ -946,10 +946,12 @@ static void unkeep_all_packs(void)
 
 static void end_packfile(void)
 {
-       struct packed_git *old_p = pack_data, *new_p;
+       if (!pack_data)
+               return;
 
        clear_delta_base_cache();
        if (object_count) {
+               struct packed_git *new_p;
                unsigned char cur_pack_sha1[20];
                char *idx_name;
                int i;
@@ -991,10 +993,11 @@ static void end_packfile(void)
                pack_id++;
        }
        else {
-               close(old_p->pack_fd);
-               unlink_or_warn(old_p->pack_name);
+               close(pack_data->pack_fd);
+               unlink_or_warn(pack_data->pack_name);
        }
-       free(old_p);
+       free(pack_data);
+       pack_data = NULL;
 
        /* We can't carry a delta across packfiles. */
        strbuf_release(&last_blob.data);
@@ -1679,8 +1682,9 @@ static int tree_content_get(
 static int update_branch(struct branch *b)
 {
        static const char *msg = "fast-import";
-       struct ref_lock *lock;
+       struct ref_transaction *transaction;
        unsigned char old_sha1[20];
+       struct strbuf err = STRBUF_INIT;
 
        if (read_ref(b->name, old_sha1))
                hashclr(old_sha1);
@@ -1689,29 +1693,33 @@ static int update_branch(struct branch *b)
                        delete_ref(b->name, old_sha1, 0);
                return 0;
        }
-       lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL);
-       if (!lock)
-               return error("Unable to lock %s", b->name);
        if (!force_update && !is_null_sha1(old_sha1)) {
                struct commit *old_cmit, *new_cmit;
 
                old_cmit = lookup_commit_reference_gently(old_sha1, 0);
                new_cmit = lookup_commit_reference_gently(b->sha1, 0);
-               if (!old_cmit || !new_cmit) {
-                       unlock_ref(lock);
+               if (!old_cmit || !new_cmit)
                        return error("Branch %s is missing commits.", b->name);
-               }
 
                if (!in_merge_bases(old_cmit, new_cmit)) {
-                       unlock_ref(lock);
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
                                b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1));
                        return -1;
                }
        }
-       if (write_ref_sha1(lock, b->sha1, msg) < 0)
-               return error("Unable to update %s", b->name);
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
+                                  0, 1, &err) ||
+           ref_transaction_commit(transaction, msg, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&err);
+               return -1;
+       }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
        return 0;
 }
 
@@ -1730,15 +1738,32 @@ static void dump_tags(void)
 {
        static const char *msg = "fast-import";
        struct tag *t;
-       struct ref_lock *lock;
-       char ref_name[PATH_MAX];
+       struct strbuf ref_name = STRBUF_INIT;
+       struct strbuf err = STRBUF_INIT;
+       struct ref_transaction *transaction;
 
+       transaction = ref_transaction_begin(&err);
+       if (!transaction) {
+               failure |= error("%s", err.buf);
+               goto cleanup;
+       }
        for (t = first_tag; t; t = t->next_tag) {
-               sprintf(ref_name, "tags/%s", t->name);
-               lock = lock_ref_sha1(ref_name, NULL);
-               if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0)
-                       failure |= error("Unable to update %s", ref_name);
+               strbuf_reset(&ref_name);
+               strbuf_addf(&ref_name, "refs/tags/%s", t->name);
+
+               if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
+                                          NULL, 0, 0, &err)) {
+                       failure |= error("%s", err.buf);
+                       goto cleanup;
+               }
        }
+       if (ref_transaction_commit(transaction, msg, &err))
+               failure |= error("%s", err.buf);
+
+ cleanup:
+       ref_transaction_free(transaction);
+       strbuf_release(&ref_name);
+       strbuf_release(&err);
 }
 
 static void dump_marks_helper(FILE *f,
@@ -3274,36 +3299,34 @@ static void parse_option(const char *option)
        die("This version of fast-import does not support option: %s", option);
 }
 
-static int git_pack_config(const char *k, const char *v, void *cb)
+static void git_pack_config(void)
 {
-       if (!strcmp(k, "pack.depth")) {
-               max_depth = git_config_int(k, v);
+       int indexversion_value;
+       unsigned long packsizelimit_value;
+
+       if (!git_config_get_ulong("pack.depth", &max_depth)) {
                if (max_depth > MAX_DEPTH)
                        max_depth = MAX_DEPTH;
-               return 0;
        }
-       if (!strcmp(k, "pack.compression")) {
-               int level = git_config_int(k, v);
-               if (level == -1)
-                       level = Z_DEFAULT_COMPRESSION;
-               else if (level < 0 || level > Z_BEST_COMPRESSION)
-                       die("bad pack compression level %d", level);
-               pack_compression_level = level;
+       if (!git_config_get_int("pack.compression", &pack_compression_level)) {
+               if (pack_compression_level == -1)
+                       pack_compression_level = Z_DEFAULT_COMPRESSION;
+               else if (pack_compression_level < 0 ||
+                        pack_compression_level > Z_BEST_COMPRESSION)
+                       git_die_config("pack.compression",
+                                       "bad pack compression level %d", pack_compression_level);
                pack_compression_seen = 1;
-               return 0;
        }
-       if (!strcmp(k, "pack.indexversion")) {
-               pack_idx_opts.version = git_config_int(k, v);
+       if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
+               pack_idx_opts.version = indexversion_value;
                if (pack_idx_opts.version > 2)
-                       die("bad pack.indexversion=%"PRIu32,
-                           pack_idx_opts.version);
-               return 0;
-       }
-       if (!strcmp(k, "pack.packsizelimit")) {
-               max_packsize = git_config_ulong(k, v);
-               return 0;
+                       git_die_config("pack.indexversion",
+                                       "bad pack.indexversion=%"PRIu32, pack_idx_opts.version);
        }
-       return git_default_config(k, v, cb);
+       if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
+               max_packsize = packsizelimit_value;
+
+       git_config(git_default_config, NULL);
 }
 
 static const char fast_import_usage[] =
@@ -3356,7 +3379,7 @@ int main(int argc, char **argv)
 
        setup_git_directory();
        reset_pack_idx_option(&pack_idx_opts);
-       git_config(git_pack_config, NULL);
+       git_pack_config();
        if (!pack_compression_seen && core_compression_seen)
                pack_compression_level = core_compression_level;
 
index b8a58fa7a542fe166ad71c9b17a4908c81d24a4f..7487aa730630e8b45874e3487db8e71c05e1968c 100644 (file)
@@ -666,7 +666,7 @@ static int get_pack(struct fetch_pack_args *args,
        char hdr_arg[256];
        const char **av, *cmd_name;
        int do_keep = args->keep_pack;
-       struct child_process cmd;
+       struct child_process cmd = CHILD_PROCESS_INIT;
        int ret;
 
        memset(&demux, 0, sizeof(demux));
@@ -685,7 +685,6 @@ static int get_pack(struct fetch_pack_args *args,
        else
                demux.out = xd[0];
 
-       memset(&cmd, 0, sizeof(cmd));
        cmd.argv = argv;
        av = argv;
        *hdr_arg = 0;
@@ -869,34 +868,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        return ref;
 }
 
-static int fetch_pack_config(const char *var, const char *value, void *cb)
+static void fetch_pack_config(void)
 {
-       if (strcmp(var, "fetch.unpacklimit") == 0) {
-               fetch_unpack_limit = git_config_int(var, value);
-               return 0;
-       }
-
-       if (strcmp(var, "transfer.unpacklimit") == 0) {
-               transfer_unpack_limit = git_config_int(var, value);
-               return 0;
-       }
-
-       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
-               prefer_ofs_delta = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "fetch.fsckobjects")) {
-               fetch_fsck_objects = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "transfer.fsckobjects")) {
-               transfer_fsck_objects = git_config_bool(var, value);
-               return 0;
-       }
+       git_config_get_int("fetch.unpacklimit", &fetch_unpack_limit);
+       git_config_get_int("transfer.unpacklimit", &transfer_unpack_limit);
+       git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
+       git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
+       git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
 
-       return git_default_config(var, value, cb);
+       git_config(git_default_config, NULL);
 }
 
 static void fetch_pack_setup(void)
@@ -904,7 +884,7 @@ static void fetch_pack_setup(void)
        static int did_setup;
        if (did_setup)
                return;
-       git_config(fetch_pack_config, NULL);
+       fetch_pack_config();
        if (0 <= transfer_unpack_limit)
                unpack_limit = transfer_unpack_limit;
        else if (0 <= fetch_unpack_limit)
index d675c89603eaf6135354c120f06289bd90a3f3d3..4e7e3f8726a26a1f7dfbb889fe3531d01d4419b9 100644 (file)
@@ -609,6 +609,7 @@ extern try_to_free_t set_try_to_free_routine(try_to_free_t);
 extern char *xstrdup(const char *str);
 extern void *xmalloc(size_t size);
 extern void *xmallocz(size_t size);
+extern void *xmallocz_gently(size_t size);
 extern void *xmemdupz(const void *data, size_t len);
 extern char *xstrndup(const char *str, size_t len);
 extern void *xrealloc(void *ptr, size_t size);
index 18a394fcc4e704621c8b5e8bc92b7cbee2fd21fe..4d4fc77b05648c7d2d76ae932b7d68cdf411d364 100755 (executable)
@@ -20,7 +20,7 @@ die_conflict () {
     if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
        die "$(gettext "Pull is not possible because you have unmerged files.
 Please, fix them up in the work tree, and then use 'git add/rm <file>'
-as appropriate to mark resolution, or use 'git commit -a'.")"
+as appropriate to mark resolution and make a commit.")"
     else
        die "$(gettext "Pull is not possible because you have unmerged files.")"
     fi
index ff07012726ea28daa2551966d0555d2e8efa2375..1ef73fb7dfedd8cd5d3444433218ff177a63111b 100644 (file)
@@ -55,12 +55,11 @@ const char *get_signing_key(void)
  */
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
 {
-       struct child_process gpg;
+       struct child_process gpg = CHILD_PROCESS_INIT;
        const char *args[4];
        ssize_t len;
        size_t i, j, bottom;
 
-       memset(&gpg, 0, sizeof(gpg));
        gpg.argv = args;
        gpg.in = -1;
        gpg.out = -1;
@@ -116,7 +115,7 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
                         const char *signature, size_t signature_size,
                         struct strbuf *gpg_output, struct strbuf *gpg_status)
 {
-       struct child_process gpg;
+       struct child_process gpg = CHILD_PROCESS_INIT;
        const char *args_gpg[] = {NULL, "--status-fd=1", "--verify", "FILE", "-", NULL};
        char path[PATH_MAX];
        int fd, ret;
@@ -133,7 +132,6 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
                             path, strerror(errno));
        close(fd);
 
-       memset(&gpg, 0, sizeof(gpg));
        gpg.argv = args_gpg;
        gpg.in = -1;
        gpg.out = -1;
index 80790bbaef95a56ac737c7763e48035e3e0754ee..404e682593ecfca218d0aee0634f5c21356ef69c 100644 (file)
@@ -219,29 +219,22 @@ static void get_idx_file(char *name)
        send_local_file("application/x-git-packed-objects-toc", name);
 }
 
-static int http_config(const char *var, const char *value, void *cb)
+static void http_config(void)
 {
-       const char *p;
+       int i, value = 0;
+       struct strbuf var = STRBUF_INIT;
 
-       if (!strcmp(var, "http.getanyfile")) {
-               getanyfile = git_config_bool(var, value);
-               return 0;
-       }
+       git_config_get_bool("http.getanyfile", &getanyfile);
 
-       if (skip_prefix(var, "http.", &p)) {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
-                       struct rpc_service *svc = &rpc_service[i];
-                       if (!strcmp(p, svc->config_name)) {
-                               svc->enabled = git_config_bool(var, value);
-                               return 0;
-                       }
-               }
+       for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
+               struct rpc_service *svc = &rpc_service[i];
+               strbuf_addf(&var, "http.%s", svc->config_name);
+               if (!git_config_get_bool(var.buf, &value))
+                       svc->enabled = value;
+               strbuf_reset(&var);
        }
 
-       /* we are not interested in parsing any other configuration here */
-       return 0;
+       strbuf_release(&var);
 }
 
 static struct rpc_service *select_service(const char *name)
@@ -323,7 +316,7 @@ static void run_service(const char **argv)
        const char *host = getenv("REMOTE_ADDR");
        struct argv_array env = ARGV_ARRAY_INIT;
        int gzipped_request = 0;
-       struct child_process cld;
+       struct child_process cld = CHILD_PROCESS_INIT;
 
        if (encoding && !strcmp(encoding, "gzip"))
                gzipped_request = 1;
@@ -341,7 +334,6 @@ static void run_service(const char **argv)
                argv_array_pushf(&env, "GIT_COMMITTER_EMAIL=%s@http.%s",
                                 user, host);
 
-       memset(&cld, 0, sizeof(cld));
        cld.argv = argv;
        cld.env = env.argv;
        if (gzipped_request)
@@ -627,7 +619,7 @@ int main(int argc, char **argv)
            access("git-daemon-export-ok", F_OK) )
                not_found("Repository not exported: '%s'", dir);
 
-       git_config(http_config, NULL);
+       http_config();
        cmd->imp(cmd_arg);
        return 0;
 }
diff --git a/http.c b/http.c
index c8cd50dd0c2b2213a86957cd4b24c03c0d85717d..0adcec4683f997044807a772713d476dd77cf105 100644 (file)
--- a/http.c
+++ b/http.c
@@ -300,6 +300,9 @@ static CURL *get_curl_handle(void)
 {
        CURL *result = curl_easy_init();
 
+       if (!result)
+               die("curl_easy_init failed");
+
        if (!curl_ssl_verify) {
                curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
                curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0);
@@ -399,7 +402,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        git_config(urlmatch_config_entry, &config);
        free(normalized_url);
 
-       curl_global_init(CURL_GLOBAL_ALL);
+       if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
+               die("curl_global_init failed");
 
        http_proactive_auth = proactive_auth;
 
@@ -417,10 +421,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        }
 
        curlm = curl_multi_init();
-       if (curlm == NULL) {
-               fprintf(stderr, "Error creating curl multi handle.\n");
-               exit(1);
-       }
+       if (!curlm)
+               die("curl_multi_init failed");
 #endif
 
        if (getenv("GIT_SSL_NO_VERIFY"))
@@ -1332,7 +1334,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
        struct packed_git **lst;
        struct packed_git *p = preq->target;
        char *tmp_idx;
-       struct child_process ip;
+       struct child_process ip = CHILD_PROCESS_INIT;
        const char *ip_argv[8];
 
        close_pack_index(p);
@@ -1355,7 +1357,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
        ip_argv[3] = preq->tmpfile;
        ip_argv[4] = NULL;
 
-       memset(&ip, 0, sizeof(ip));
        ip.argv = ip_argv;
        ip.git_cmd = 1;
        ip.no_stdin = 1;
index 87f9bb18f6983a99499f170cef1f319f6c63d6f1..f33e56dba1e06cd61448069e3d300e3650477320 100644 (file)
@@ -69,6 +69,7 @@ struct imap_server_conf {
        char *tunnel;
        char *host;
        int port;
+       char *folder;
        char *user;
        char *pass;
        int use_ssl;
@@ -82,6 +83,7 @@ static struct imap_server_conf server = {
        NULL,   /* tunnel */
        NULL,   /* host */
        0,      /* port */
+       NULL,   /* folder */
        NULL,   /* user */
        NULL,   /* pass */
        0,      /* use_ssl */
@@ -523,7 +525,7 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
        if (Verbose) {
                if (imap->num_in_progress)
                        printf("(%d in progress) ", imap->num_in_progress);
-               if (memcmp(cmd->cmd, "LOGIN", 5))
+               if (!starts_with(cmd->cmd, "LOGIN"))
                        printf(">>> %s", buf);
                else
                        printf(">>> %d LOGIN <user> <pass>\n", cmd->tag);
@@ -791,7 +793,7 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
                                else /*if (!strcmp("BAD", arg))*/
                                        resp = RESP_BAD;
                                fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n",
-                                        memcmp(cmdp->cmd, "LOGIN", 5) ?
+                                       !starts_with(cmdp->cmd, "LOGIN") ?
                                                        cmdp->cmd : "LOGIN <user> <pass>",
                                                        arg, cmd ? cmd : "");
                        }
@@ -924,17 +926,16 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f
        /* open connection to IMAP server */
 
        if (srvc->tunnel) {
-               const char *argv[] = { srvc->tunnel, NULL };
-               struct child_process tunnel = {NULL};
+               struct child_process tunnel = CHILD_PROCESS_INIT;
 
                imap_info("Starting tunnel '%s'... ", srvc->tunnel);
 
-               tunnel.argv = argv;
+               argv_array_push(&tunnel.args, srvc->tunnel);
                tunnel.use_shell = 1;
                tunnel.in = -1;
                tunnel.out = -1;
                if (start_command(&tunnel))
-                       die("cannot start proxy %s", argv[0]);
+                       die("cannot start proxy %s", srvc->tunnel);
 
                imap->buf.sock.fd[0] = tunnel.out;
                imap->buf.sock.fd[1] = tunnel.in;
@@ -1306,45 +1307,35 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
        return 1;
 }
 
-static char *imap_folder;
-
-static int git_imap_config(const char *key, const char *val, void *cb)
+static void git_imap_config(void)
 {
-       if (!skip_prefix(key, "imap.", &key))
-               return 0;
+       const char *val = NULL;
 
-       /* check booleans first, and barf on others */
-       if (!strcmp("sslverify", key))
-               server.ssl_verify = git_config_bool(key, val);
-       else if (!strcmp("preformattedhtml", key))
-               server.use_html = git_config_bool(key, val);
-       else if (!val)
-               return config_error_nonbool(key);
-
-       if (!strcmp("folder", key)) {
-               imap_folder = xstrdup(val);
-       } else if (!strcmp("host", key)) {
-               if (starts_with(val, "imap:"))
-                       val += 5;
-               else if (starts_with(val, "imaps:")) {
-                       val += 6;
-                       server.use_ssl = 1;
+       git_config_get_bool("imap.sslverify", &server.ssl_verify);
+       git_config_get_bool("imap.preformattedhtml", &server.use_html);
+       git_config_get_string("imap.folder", &server.folder);
+
+       if (!git_config_get_value("imap.host", &val)) {
+               if (!val) {
+                       git_die_config("imap.host", "Missing value for 'imap.host'");
+               } else {
+                       if (starts_with(val, "imap:"))
+                               val += 5;
+                       else if (starts_with(val, "imaps:")) {
+                               val += 6;
+                               server.use_ssl = 1;
+                       }
+                       if (starts_with(val, "//"))
+                               val += 2;
+                       server.host = xstrdup(val);
                }
-               if (starts_with(val, "//"))
-                       val += 2;
-               server.host = xstrdup(val);
-       } else if (!strcmp("user", key))
-               server.user = xstrdup(val);
-       else if (!strcmp("pass", key))
-               server.pass = xstrdup(val);
-       else if (!strcmp("port", key))
-               server.port = git_config_int(key, val);
-       else if (!strcmp("tunnel", key))
-               server.tunnel = xstrdup(val);
-       else if (!strcmp("authmethod", key))
-               server.auth_method = xstrdup(val);
+       }
 
-       return 0;
+       git_config_get_string("imap.user", &server.user);
+       git_config_get_string("imap.pass", &server.pass);
+       git_config_get_int("imap.port", &server.port);
+       git_config_get_string("imap.tunnel", &server.tunnel);
+       git_config_get_string("imap.authmethod", &server.auth_method);
 }
 
 int main(int argc, char **argv)
@@ -1365,12 +1356,12 @@ int main(int argc, char **argv)
                usage(imap_send_usage);
 
        setup_git_directory_gently(&nongit_ok);
-       git_config(git_imap_config, NULL);
+       git_imap_config();
 
        if (!server.port)
                server.port = server.use_ssl ? 993 : 143;
 
-       if (!imap_folder) {
+       if (!server.folder) {
                fprintf(stderr, "no imap store specified\n");
                return 1;
        }
@@ -1400,7 +1391,7 @@ int main(int argc, char **argv)
        }
 
        /* write it to the imap server */
-       ctx = imap_open_store(&server, imap_folder);
+       ctx = imap_open_store(&server, server.folder);
        if (!ctx) {
                fprintf(stderr, "failed to open store\n");
                return 1;
index fb61ea66a13eba3a8e91a05dbe1c37de98cec853..8ea03e536a56655ff48f4fa8a3050c0225d52f38 100644 (file)
@@ -225,11 +225,8 @@ static int read_merge_config(const char *var, const char *value, void *cb)
        const char *key, *name;
        int namelen;
 
-       if (!strcmp(var, "merge.default")) {
-               if (value)
-                       default_ll_merge = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp(var, "merge.default"))
+               return git_config_string(&default_ll_merge, var, value);
 
        /*
         * We are not interested in anything but "merge.<name>.variable";
@@ -254,12 +251,8 @@ static int read_merge_config(const char *var, const char *value, void *cb)
                ll_user_merge_tail = &(fn->next);
        }
 
-       if (!strcmp("name", key)) {
-               if (!value)
-                       return error("%s: lacks value", var);
-               fn->description = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp("name", key))
+               return git_config_string(&fn->description, var, value);
 
        if (!strcmp("driver", key)) {
                if (!value)
@@ -285,12 +278,8 @@ static int read_merge_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (!strcmp("recursive", key)) {
-               if (!value)
-                       return error("%s: lacks value", var);
-               fn->recursive = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp("recursive", key))
+               return git_config_string(&fn->recursive, var, value);
 
        return 0;
 }
index 95e9b1da259ef33a1c5bc7f7d07e853ebc5dbcec..bcee7c596696eb1da109b3ff375e09453045a60f 100644 (file)
 #include "sequencer.h"
 #include "line-log.h"
 
-struct decoration name_decoration = { "object names" };
-
-enum decoration_type {
-       DECORATION_NONE = 0,
-       DECORATION_REF_LOCAL,
-       DECORATION_REF_REMOTE,
-       DECORATION_REF_TAG,
-       DECORATION_REF_STASH,
-       DECORATION_REF_HEAD,
-       DECORATION_GRAFTED,
-};
+static struct decoration name_decoration = { "object names" };
 
 static char decoration_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RESET,
@@ -84,15 +74,20 @@ int parse_decorate_color_config(const char *var, const int ofs, const char *valu
 #define decorate_get_color_opt(o, ix) \
        decorate_get_color((o)->use_color, ix)
 
-static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
+void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
 {
        int nlen = strlen(name);
-       struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen);
+       struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);
        memcpy(res->name, name, nlen + 1);
        res->type = type;
        res->next = add_decoration(&name_decoration, obj, res);
 }
 
+const struct name_decoration *get_name_decoration(const struct object *obj)
+{
+       return lookup_decoration(&name_decoration, obj);
+}
+
 static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
 {
        struct object *obj;
@@ -187,13 +182,13 @@ void format_decorations(struct strbuf *sb,
                        int use_color)
 {
        const char *prefix;
-       struct name_decoration *decoration;
+       const struct name_decoration *decoration;
        const char *color_commit =
                diff_get_color(use_color, DIFF_COMMIT);
        const char *color_reset =
                decorate_get_color(use_color, DECORATION_NONE);
 
-       decoration = lookup_decoration(&name_decoration, &commit->object);
+       decoration = get_name_decoration(&commit->object);
        if (!decoration)
                return;
        prefix = " (";
index 1d332b8bbbf076b819e2052c84874fb0728dae02..8ab944c44cf1afd516505fe9bb80dbc06708d1af 100644 (file)
@@ -2026,22 +2026,12 @@ int merge_recursive_generic(struct merge_options *o,
        return clean ? 0 : 1;
 }
 
-static int merge_recursive_config(const char *var, const char *value, void *cb)
+static void merge_recursive_config(struct merge_options *o)
 {
-       struct merge_options *o = cb;
-       if (!strcmp(var, "merge.verbosity")) {
-               o->verbosity = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "diff.renamelimit")) {
-               o->diff_rename_limit = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "merge.renamelimit")) {
-               o->merge_rename_limit = git_config_int(var, value);
-               return 0;
-       }
-       return git_xmerge_config(var, value, cb);
+       git_config_get_int("merge.verbosity", &o->verbosity);
+       git_config_get_int("diff.renamelimit", &o->diff_rename_limit);
+       git_config_get_int("merge.renamelimit", &o->merge_rename_limit);
+       git_config(git_xmerge_config, NULL);
 }
 
 void init_merge_options(struct merge_options *o)
@@ -2052,7 +2042,7 @@ void init_merge_options(struct merge_options *o)
        o->diff_rename_limit = -1;
        o->merge_rename_limit = -1;
        o->renormalize = 0;
-       git_config(merge_recursive_config, o);
+       merge_recursive_config(o);
        if (getenv("GIT_MERGE_VERBOSITY"))
                o->verbosity =
                        strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
diff --git a/pager.c b/pager.c
index 8b5cbc56e4fd57a1b9d2cad3e668df4c508a7b17..b2b805af98552061a723f3b8e2ac3093d0b897f7 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -6,19 +6,13 @@
 #define DEFAULT_PAGER "less"
 #endif
 
-struct pager_config {
-       const char *cmd;
-       int want;
-       char *value;
-};
-
 /*
  * This is split up from the rest of git so that we can do
  * something different on Windows.
  */
 
 static const char *pager_argv[] = { NULL, NULL };
-static struct child_process pager_process;
+static struct child_process pager_process = CHILD_PROCESS_INIT;
 
 static void wait_for_pager(void)
 {
@@ -155,30 +149,22 @@ int decimal_width(int number)
        return width;
 }
 
-static int pager_command_config(const char *var, const char *value, void *data)
+/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
+int check_pager_config(const char *cmd)
 {
-       struct pager_config *c = data;
-       if (starts_with(var, "pager.") && !strcmp(var + 6, c->cmd)) {
-               int b = git_config_maybe_bool(var, value);
+       int want = -1;
+       struct strbuf key = STRBUF_INIT;
+       const char *value = NULL;
+       strbuf_addf(&key, "pager.%s", cmd);
+       if (!git_config_get_value(key.buf, &value)) {
+               int b = git_config_maybe_bool(key.buf, value);
                if (b >= 0)
-                       c->want = b;
+                       want = b;
                else {
-                       c->want = 1;
-                       c->value = xstrdup(value);
+                       want = 1;
+                       pager_program = xstrdup(value);
                }
        }
-       return 0;
-}
-
-/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
-int check_pager_config(const char *cmd)
-{
-       struct pager_config c;
-       c.cmd = cmd;
-       c.want = -1;
-       c.value = NULL;
-       git_config(pager_command_config, &c);
-       if (c.value)
-               pager_program = c.value;
-       return c.want;
+       strbuf_release(&key);
+       return want;
 }
index d7bb17cb663c2f47ad59d34ecea17c6cc977e815..e5b4938efcf329eb4f25b6f90231c35abeacbbd3 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -6,7 +6,7 @@
 
 static char *do_askpass(const char *cmd, const char *prompt)
 {
-       struct child_process pass;
+       struct child_process pass = CHILD_PROCESS_INIT;
        const char *args[3];
        static struct strbuf buffer = STRBUF_INIT;
        int err = 0;
@@ -15,7 +15,6 @@ static char *do_askpass(const char *cmd, const char *prompt)
        args[1] = prompt;
        args[2] = NULL;
 
-       memset(&pass, 0, sizeof(pass));
        pass.argv = args;
        pass.out = -1;
 
index 6f0057fe66a59e1239703ee4458de200304f727a..b5917e0c0743af3c831f9571e19e269e8a1f6014 100644 (file)
@@ -1246,24 +1246,16 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
 
 #define INDEX_FORMAT_DEFAULT 3
 
-static int index_format_config(const char *var, const char *value, void *cb)
-{
-       unsigned int *version = cb;
-       if (!strcmp(var, "index.version")) {
-               *version = git_config_int(var, value);
-               return 0;
-       }
-       return 1;
-}
-
 static unsigned int get_index_format_default(void)
 {
        char *envversion = getenv("GIT_INDEX_VERSION");
        char *endp;
+       int value;
        unsigned int version = INDEX_FORMAT_DEFAULT;
 
        if (!envversion) {
-               git_config(index_format_config, &version);
+               if (!git_config_get_int("index.version", &value))
+                       version = value;
                if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
                        warning(_("index.version set, but the value is invalid.\n"
                                  "Using version %i"), INDEX_FORMAT_DEFAULT);
diff --git a/refs.c b/refs.c
index 27927f2319130cc0575817542dfd47c37cc5149b..2ce5d690907d33bda557f66150ef1317f39b4f93 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -24,6 +24,11 @@ static unsigned char refname_disposition[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
 };
 
+/*
+ * Used as a flag to ref_transaction_delete when a loose ref is being
+ * pruned.
+ */
+#define REF_ISPRUNING  0x0100
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -2068,7 +2073,10 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
        return logs_found;
 }
 
-/* This function should make sure errno is meaningful on error */
+/*
+ * Locks a "refs/" ref returning the lock on success and NULL on failure.
+ * On failure errno is set to something meaningful.
+ */
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                                            const unsigned char *old_sha1,
                                            int flags, int *type_p)
@@ -2169,15 +2177,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        return NULL;
 }
 
-struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1)
-{
-       char refpath[PATH_MAX];
-       if (check_refname_format(refname, 0))
-               return NULL;
-       strcpy(refpath, mkpath("refs/%s", refname));
-       return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
-}
-
 struct ref_lock *lock_any_ref_for_update(const char *refname,
                                         const unsigned char *old_sha1,
                                         int flags, int *type_p)
@@ -2387,13 +2386,25 @@ static void try_remove_empty_parents(char *name)
 /* make sure nobody touched the ref, and unlink */
 static void prune_ref(struct ref_to_prune *r)
 {
-       struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
-       if (lock) {
-               unlink_or_warn(git_path("%s", r->name));
-               unlock_ref(lock);
-               try_remove_empty_parents(r->name);
+       if (check_refname_format(r->name, 0))
+               return;
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_delete(transaction, r->name, r->sha1,
+                                  REF_ISPRUNING, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&err);
+               return;
        }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+       try_remove_empty_parents(r->name);
 }
 
 static void prune_refs(struct ref_to_prune *r)
@@ -2536,11 +2547,6 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
        return ret;
 }
 
-static int repack_without_ref(const char *refname)
-{
-       return repack_without_refs(&refname, 1, NULL);
-}
-
 static int delete_ref_loose(struct ref_lock *lock, int flag)
 {
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
@@ -2558,24 +2564,22 @@ static int delete_ref_loose(struct ref_lock *lock, int flag)
 
 int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
 {
-       struct ref_lock *lock;
-       int ret = 0, flag = 0;
-
-       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
-       if (!lock)
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_delete(transaction, refname, sha1, delopt,
+                                  sha1 && !is_null_sha1(sha1), &err) ||
+           ref_transaction_commit(transaction, NULL, &err)) {
+               error("%s", err.buf);
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
                return 1;
-       ret |= delete_ref_loose(lock, flag);
-
-       /* removing the loose one could have resurrected an earlier
-        * packed one.  Also, if it was not loose we need to repack
-        * without it.
-        */
-       ret |= repack_without_ref(lock->ref_name);
-
-       unlink_or_warn(git_path("logs/%s", lock->ref_name));
-       clear_loose_ref_cache(&ref_cache);
-       unlock_ref(lock);
-       return ret;
+       }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+       return 0;
 }
 
 /*
@@ -3332,43 +3336,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
        return retval;
 }
 
-static struct ref_lock *update_ref_lock(const char *refname,
-                                       const unsigned char *oldval,
-                                       int flags, int *type_p,
-                                       enum action_on_err onerr)
-{
-       struct ref_lock *lock;
-       lock = lock_any_ref_for_update(refname, oldval, flags, type_p);
-       if (!lock) {
-               const char *str = "Cannot lock the ref '%s'.";
-               switch (onerr) {
-               case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
-               case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
-               case UPDATE_REFS_QUIET_ON_ERR: break;
-               }
-       }
-       return lock;
-}
-
-static int update_ref_write(const char *action, const char *refname,
-                           const unsigned char *sha1, struct ref_lock *lock,
-                           struct strbuf *err, enum action_on_err onerr)
-{
-       if (write_ref_sha1(lock, sha1, action) < 0) {
-               const char *str = "Cannot update the ref '%s'.";
-               if (err)
-                       strbuf_addf(err, str, refname);
-
-               switch (onerr) {
-               case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
-               case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
-               case UPDATE_REFS_QUIET_ON_ERR: break;
-               }
-               return 1;
-       }
-       return 0;
-}
-
 /**
  * Information needed for a single ref update.  Set new_sha1 to the
  * new value or to zero to delete the ref.  To check the old value
@@ -3385,6 +3352,21 @@ struct ref_update {
        const char refname[FLEX_ARRAY];
 };
 
+/*
+ * Transaction states.
+ * OPEN:   The transaction is in a valid state and can accept new updates.
+ *         An OPEN transaction can be committed.
+ * CLOSED: A closed transaction is no longer active and no other operations
+ *         than free can be used on it in this state.
+ *         A transaction can either become closed by successfully committing
+ *         an active transaction or if there is a failure while building
+ *         the transaction thus rendering it failed/inactive.
+ */
+enum ref_transaction_state {
+       REF_TRANSACTION_OPEN   = 0,
+       REF_TRANSACTION_CLOSED = 1
+};
+
 /*
  * Data structure for holding a reference transaction, which can
  * consist of checks and updates to multiple references, carried out
@@ -3394,9 +3376,10 @@ struct ref_transaction {
        struct ref_update **updates;
        size_t alloc;
        size_t nr;
+       enum ref_transaction_state state;
 };
 
-struct ref_transaction *ref_transaction_begin(void)
+struct ref_transaction *ref_transaction_begin(struct strbuf *err)
 {
        return xcalloc(1, sizeof(struct ref_transaction));
 }
@@ -3436,6 +3419,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
 {
        struct ref_update *update;
 
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: update called for transaction that is not open");
+
        if (have_old && !old_sha1)
                die("BUG: have_old is true but old_sha1 is NULL");
 
@@ -3448,44 +3434,84 @@ int ref_transaction_update(struct ref_transaction *transaction,
        return 0;
 }
 
-void ref_transaction_create(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *new_sha1,
-                           int flags)
+int ref_transaction_create(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *new_sha1,
+                          int flags,
+                          struct strbuf *err)
 {
-       struct ref_update *update = add_update(transaction, refname);
+       struct ref_update *update;
+
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: create called for transaction that is not open");
+
+       if (!new_sha1 || is_null_sha1(new_sha1))
+               die("BUG: create ref with null new_sha1");
+
+       update = add_update(transaction, refname);
 
-       assert(!is_null_sha1(new_sha1));
        hashcpy(update->new_sha1, new_sha1);
        hashclr(update->old_sha1);
        update->flags = flags;
        update->have_old = 1;
+       return 0;
 }
 
-void ref_transaction_delete(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *old_sha1,
-                           int flags, int have_old)
+int ref_transaction_delete(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          int flags, int have_old,
+                          struct strbuf *err)
 {
-       struct ref_update *update = add_update(transaction, refname);
+       struct ref_update *update;
 
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: delete called for transaction that is not open");
+
+       if (have_old && !old_sha1)
+               die("BUG: have_old is true but old_sha1 is NULL");
+
+       update = add_update(transaction, refname);
        update->flags = flags;
        update->have_old = have_old;
        if (have_old) {
                assert(!is_null_sha1(old_sha1));
                hashcpy(update->old_sha1, old_sha1);
        }
+       return 0;
 }
 
 int update_ref(const char *action, const char *refname,
               const unsigned char *sha1, const unsigned char *oldval,
               int flags, enum action_on_err onerr)
 {
-       struct ref_lock *lock;
-       lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
-       if (!lock)
+       struct ref_transaction *t;
+       struct strbuf err = STRBUF_INIT;
+
+       t = ref_transaction_begin(&err);
+       if (!t ||
+           ref_transaction_update(t, refname, sha1, oldval, flags,
+                                  !!oldval, &err) ||
+           ref_transaction_commit(t, action, &err)) {
+               const char *str = "update_ref failed for ref '%s': %s";
+
+               ref_transaction_free(t);
+               switch (onerr) {
+               case UPDATE_REFS_MSG_ON_ERR:
+                       error(str, refname, err.buf);
+                       break;
+               case UPDATE_REFS_DIE_ON_ERR:
+                       die(str, refname, err.buf);
+                       break;
+               case UPDATE_REFS_QUIET_ON_ERR:
+                       break;
+               }
+               strbuf_release(&err);
                return 1;
-       return update_ref_write(action, refname, sha1, lock, NULL, onerr);
+       }
+       strbuf_release(&err);
+       ref_transaction_free(t);
+       return 0;
 }
 
 static int ref_update_compare(const void *r1, const void *r2)
@@ -3519,8 +3545,13 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        int n = transaction->nr;
        struct ref_update **updates = transaction->updates;
 
-       if (!n)
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: commit called for transaction that is not open");
+
+       if (!n) {
+               transaction->state = REF_TRANSACTION_CLOSED;
                return 0;
+       }
 
        /* Allocate work space */
        delnames = xmalloc(sizeof(*delnames) * n);
@@ -3535,12 +3566,12 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
 
-               update->lock = update_ref_lock(update->refname,
-                                              (update->have_old ?
-                                               update->old_sha1 : NULL),
-                                              update->flags,
-                                              &update->type,
-                                              UPDATE_REFS_QUIET_ON_ERR);
+               update->lock = lock_any_ref_for_update(update->refname,
+                                                      (update->have_old ?
+                                                       update->old_sha1 :
+                                                       NULL),
+                                                      update->flags,
+                                                      &update->type);
                if (!update->lock) {
                        if (err)
                                strbuf_addf(err, "Cannot lock the ref '%s'.",
@@ -3555,14 +3586,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                struct ref_update *update = updates[i];
 
                if (!is_null_sha1(update->new_sha1)) {
-                       ret = update_ref_write(msg,
-                                              update->refname,
-                                              update->new_sha1,
-                                              update->lock, err,
-                                              UPDATE_REFS_QUIET_ON_ERR);
-                       update->lock = NULL; /* freed by update_ref_write */
-                       if (ret)
+                       ret = write_ref_sha1(update->lock, update->new_sha1,
+                                            msg);
+                       update->lock = NULL; /* freed by write_ref_sha1 */
+                       if (ret) {
+                               if (err)
+                                       strbuf_addf(err, "Cannot update the ref '%s'.",
+                                                   update->refname);
                                goto cleanup;
+                       }
                }
        }
 
@@ -3571,8 +3603,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                struct ref_update *update = updates[i];
 
                if (update->lock) {
-                       delnames[delnum++] = update->lock->ref_name;
                        ret |= delete_ref_loose(update->lock, update->type);
+                       if (!(update->flags & REF_ISPRUNING))
+                               delnames[delnum++] = update->lock->ref_name;
                }
        }
 
@@ -3582,6 +3615,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        clear_loose_ref_cache(&ref_cache);
 
 cleanup:
+       transaction->state = REF_TRANSACTION_CLOSED;
+
        for (i = 0; i < n; i++)
                if (updates[i]->lock)
                        unlock_ref(updates[i]->lock);
diff --git a/refs.h b/refs.h
index ec46acdde7b67d3531a4c0e18d33901d2a4f307a..68c57701646f05a44dd0da95d981787653ae032d 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -10,6 +10,38 @@ struct ref_lock {
        int force_write;
 };
 
+/*
+ * A ref_transaction represents a collection of ref updates
+ * that should succeed or fail together.
+ *
+ * Calling sequence
+ * ----------------
+ * - Allocate and initialize a `struct ref_transaction` by calling
+ *   `ref_transaction_begin()`.
+ *
+ * - List intended ref updates by calling functions like
+ *   `ref_transaction_update()` and `ref_transaction_create()`.
+ *
+ * - Call `ref_transaction_commit()` to execute the transaction.
+ *   If this succeeds, the ref updates will have taken place and
+ *   the transaction cannot be rolled back.
+ *
+ * - At any time call `ref_transaction_free()` to discard the
+ *   transaction and free associated resources.  In particular,
+ *   this rolls back the transaction if it has not been
+ *   successfully committed.
+ *
+ * Error handling
+ * --------------
+ *
+ * On error, transaction functions append a message about what
+ * went wrong to the 'err' argument.  The message mentions what
+ * ref was being updated (if any) when the error occurred so it
+ * can be passed to 'die' or 'error' as-is.
+ *
+ * The message is appended to err without first clearing err.
+ * err will not be '\n' terminated.
+ */
 struct ref_transaction;
 
 /*
@@ -141,14 +173,17 @@ extern int is_branch(const char *refname);
 extern int peel_ref(const char *refname, unsigned char *sha1);
 
 /*
- * Locks a "refs/" ref returning the lock on success and NULL on failure.
- * On failure errno is set to something meaningful.
+ * Flags controlling lock_any_ref_for_update(), ref_transaction_update(),
+ * ref_transaction_create(), etc.
+ * REF_NODEREF: act on the ref directly, instead of dereferencing
+ *              symbolic references.
+ *
+ * Flags >= 0x100 are reserved for internal use.
  */
-extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1);
-
-/** Locks any ref (for 'HEAD' type refs). */
 #define REF_NODEREF    0x01
-/* errno is set to something meaningful on failure */
+/*
+ * This function sets errno to something meaningful on failure.
+ */
 extern struct ref_lock *lock_any_ref_for_update(const char *refname,
                                                const unsigned char *old_sha1,
                                                int flags, int *type_p);
@@ -232,7 +267,7 @@ enum action_on_err {
  * Begin a reference transaction.  The reference transaction must
  * be freed by calling ref_transaction_free().
  */
-struct ref_transaction *ref_transaction_begin(void);
+struct ref_transaction *ref_transaction_begin(struct strbuf *err);
 
 /*
  * The following functions add a reference check or update to a
@@ -250,7 +285,7 @@ struct ref_transaction *ref_transaction_begin(void);
  * it must not have existed beforehand.
  * Function returns 0 on success and non-zero on failure. A failure to update
  * means that the transaction as a whole has failed and will need to be
- * rolled back. On failure the err buffer will be updated.
+ * rolled back.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
@@ -264,28 +299,34 @@ int ref_transaction_update(struct ref_transaction *transaction,
  * that the reference should have after the update; it must not be the
  * null SHA-1.  It is verified that the reference does not exist
  * already.
+ * Function returns 0 on success and non-zero on failure. A failure to create
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
-void ref_transaction_create(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *new_sha1,
-                           int flags);
+int ref_transaction_create(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *new_sha1,
+                          int flags,
+                          struct strbuf *err);
 
 /*
  * Add a reference deletion to transaction.  If have_old is true, then
  * old_sha1 holds the value that the reference should have had before
  * the update (which must not be the null SHA-1).
+ * Function returns 0 on success and non-zero on failure. A failure to delete
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
-void ref_transaction_delete(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *old_sha1,
-                           int flags, int have_old);
+int ref_transaction_delete(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          int flags, int have_old,
+                          struct strbuf *err);
 
 /*
  * Commit all of the changes that have been queued in transaction, as
  * atomically as possible.  Return a nonzero value if there is a
  * problem.
- * If err is non-NULL we will add an error string to it to explain why
- * the transaction failed. The string does not end in newline.
  */
 int ref_transaction_commit(struct ref_transaction *transaction,
                           const char *msg, struct strbuf *err);
index 0fcf2ce5ff20cc7c6f1bdf6257c94cf8fa21b35a..017ddd9284d77e65f0d005649adbcc8a38e3a538 100644 (file)
@@ -623,10 +623,9 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
        const char *svc = rpc->service_name;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf *preamble = rpc->stdin_preamble;
-       struct child_process client;
+       struct child_process client = CHILD_PROCESS_INIT;
        int err = 0;
 
-       memset(&client, 0, sizeof(client));
        client.in = -1;
        client.out = -1;
        client.git_cmd = 1;
index 686e07d317bf157461f0ce680958a466675c80bc..48bf6eb93b361a736d96e701749c16bae8d169a8 100644 (file)
@@ -175,7 +175,7 @@ static int cmd_import(const char *line)
        char *note_msg;
        unsigned char head_sha1[20];
        unsigned int startrev;
-       struct child_process svndump_proc;
+       struct child_process svndump_proc = CHILD_PROCESS_INIT;
        const char *command = "svnrdump";
 
        if (read_ref(private_ref, head_sha1))
@@ -200,7 +200,6 @@ static int cmd_import(const char *line)
                if(dumpin_fd < 0)
                        die_errno("Couldn't open svn dump file %s.", url);
        } else {
-               memset(&svndump_proc, 0, sizeof(struct child_process));
                svndump_proc.out = -1;
                argv_array_push(&svndump_proc.args, command);
                argv_array_push(&svndump_proc.args, "dump");
index d84b495895bc6d42980c388ed03c560174604f92..20b18add42d2551a227eaac8125fe806006d2856 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -573,15 +573,11 @@ static int do_plain_rerere(struct string_list *rr, int fd)
        return write_rr(rr, fd);
 }
 
-static int git_rerere_config(const char *var, const char *value, void *cb)
+static void git_rerere_config(void)
 {
-       if (!strcmp(var, "rerere.enabled"))
-               rerere_enabled = git_config_bool(var, value);
-       else if (!strcmp(var, "rerere.autoupdate"))
-               rerere_autoupdate = git_config_bool(var, value);
-       else
-               return git_default_config(var, value, cb);
-       return 0;
+       git_config_get_bool("rerere.enabled", &rerere_enabled);
+       git_config_get_bool("rerere.autoupdate", &rerere_autoupdate);
+       git_config(git_default_config, NULL);
 }
 
 static int is_rerere_enabled(void)
@@ -606,7 +602,7 @@ int setup_rerere(struct string_list *merge_rr, int flags)
 {
        int fd;
 
-       git_config(git_rerere_config, NULL);
+       git_rerere_config();
        if (!is_rerere_enabled())
                return -1;
 
@@ -699,24 +695,6 @@ static void unlink_rr_item(const char *name)
        rmdir(git_path("rr-cache/%s", name));
 }
 
-struct rerere_gc_config_cb {
-       int cutoff_noresolve;
-       int cutoff_resolve;
-};
-
-static int git_rerere_gc_config(const char *var, const char *value, void *cb)
-{
-       struct rerere_gc_config_cb *cf = cb;
-
-       if (!strcmp(var, "gc.rerereresolved"))
-               cf->cutoff_resolve = git_config_int(var, value);
-       else if (!strcmp(var, "gc.rerereunresolved"))
-               cf->cutoff_noresolve = git_config_int(var, value);
-       else
-               return git_default_config(var, value, cb);
-       return 0;
-}
-
 void rerere_gc(struct string_list *rr)
 {
        struct string_list to_remove = STRING_LIST_INIT_DUP;
@@ -724,9 +702,12 @@ void rerere_gc(struct string_list *rr)
        struct dirent *e;
        int i, cutoff;
        time_t now = time(NULL), then;
-       struct rerere_gc_config_cb cf = { 15, 60 };
+       int cutoff_noresolve = 15;
+       int cutoff_resolve = 60;
 
-       git_config(git_rerere_gc_config, &cf);
+       git_config_get_int("gc.rerereresolved", &cutoff_resolve);
+       git_config_get_int("gc.rerereunresolved", &cutoff_noresolve);
+       git_config(git_default_config, NULL);
        dir = opendir(git_path("rr-cache"));
        if (!dir)
                die_errno("unable to open rr-cache directory");
@@ -736,12 +717,12 @@ void rerere_gc(struct string_list *rr)
 
                then = rerere_last_used_at(e->d_name);
                if (then) {
-                       cutoff = cf.cutoff_resolve;
+                       cutoff = cutoff_resolve;
                } else {
                        then = rerere_created_at(e->d_name);
                        if (!then)
                                continue;
-                       cutoff = cf.cutoff_noresolve;
+                       cutoff = cutoff_noresolve;
                }
                if (then < now - cutoff * 86400)
                        string_list_append(&to_remove, e->d_name);
index 615535c98453336323a437530132f27824b51ac2..0d3e4171ef73f0cfb58a4f396e17717f3b0bb5a3 100644 (file)
@@ -473,7 +473,7 @@ static int rev_compare_tree(struct rev_info *revs,
                 * If we are simplifying by decoration, then the commit
                 * is worth showing if it has a tag pointing at it.
                 */
-               if (lookup_decoration(&name_decoration, &commit->object))
+               if (get_name_decoration(&commit->object))
                        return REV_TREE_DIFFERENT;
                /*
                 * A commit that is not pointed by a tag is uninteresting
index 35a3ebf07b1792ac7b0ecef30781223591413093..761f0fde40c91a3cc910c092c5aa9ad56f2f0042 100644 (file)
@@ -8,6 +8,12 @@
 # define SHELL_PATH "/bin/sh"
 #endif
 
+void child_process_init(struct child_process *child)
+{
+       memset(child, 0, sizeof(*child));
+       argv_array_init(&child->args);
+}
+
 struct child_to_clean {
        pid_t pid;
        struct child_to_clean *next;
@@ -555,31 +561,21 @@ int run_command(struct child_process *cmd)
        return finish_command(cmd);
 }
 
-static void prepare_run_command_v_opt(struct child_process *cmd,
-                                     const char **argv,
-                                     int opt)
-{
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->argv = argv;
-       cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
-       cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
-       cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
-       cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
-       cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
-       cmd->clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0;
-}
-
 int run_command_v_opt(const char **argv, int opt)
 {
-       struct child_process cmd;
-       prepare_run_command_v_opt(&cmd, argv, opt);
-       return run_command(&cmd);
+       return run_command_v_opt_cd_env(argv, opt, NULL, NULL);
 }
 
 int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
 {
-       struct child_process cmd;
-       prepare_run_command_v_opt(&cmd, argv, opt);
+       struct child_process cmd = CHILD_PROCESS_INIT;
+       cmd.argv = argv;
+       cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
+       cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
+       cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+       cmd.silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
+       cmd.use_shell = opt & RUN_USING_SHELL ? 1 : 0;
+       cmd.clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0;
        cmd.dir = dir;
        cmd.env = env;
        return run_command(&cmd);
@@ -763,14 +759,13 @@ char *find_hook(const char *name)
 
 int run_hook_ve(const char *const *env, const char *name, va_list args)
 {
-       struct child_process hook;
+       struct child_process hook = CHILD_PROCESS_INIT;
        const char *p;
 
        p = find_hook(name);
        if (!p)
                return 0;
 
-       memset(&hook, 0, sizeof(hook));
        argv_array_push(&hook.args, p);
        while ((p = va_arg(args, const char *)))
                argv_array_push(&hook.args, p);
index ea73de309bc65c3d00bb34ad84824ba72d85cbfe..1b135d1c960aa58e2fa4ad44ecc195835daac69a 100644 (file)
@@ -44,6 +44,9 @@ struct child_process {
        unsigned clean_on_exit:1;
 };
 
+#define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT }
+void child_process_init(struct child_process *);
+
 int start_command(struct child_process *);
 int finish_command(struct child_process *);
 int run_command(struct child_process *);
index 6129b0fd8e8e1961ab4c74de4f421c41c7786b42..8b4cbf049c243b8cdc1add94ddf1bf50bcbd8df9 100644 (file)
@@ -47,7 +47,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
                NULL,
                NULL,
        };
-       struct child_process po;
+       struct child_process po = CHILD_PROCESS_INIT;
        int i;
 
        i = 4;
@@ -59,7 +59,6 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
                argv[i++] = "-q";
        if (args->progress)
                argv[i++] = "--progress";
-       memset(&po, 0, sizeof(po));
        po.argv = argv;
        po.in = -1;
        po.out = args->stateless_rpc ? -1 : fd;
index 3c060e054720b7b17f9a868cabb1a0ef62aa1b50..5e8a207474bc6971a0de4f9ff6160a5681ac7b6d 100644 (file)
@@ -237,23 +237,33 @@ static int error_dirty_index(struct replay_opts *opts)
 static int fast_forward_to(const unsigned char *to, const unsigned char *from,
                        int unborn, struct replay_opts *opts)
 {
-       struct ref_lock *ref_lock;
+       struct ref_transaction *transaction;
        struct strbuf sb = STRBUF_INIT;
-       int ret;
+       struct strbuf err = STRBUF_INIT;
 
        read_cache();
        if (checkout_fast_forward(from, to, 1))
                exit(128); /* the callee should have complained already */
-       ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
-                                          0, NULL);
-       if (!ref_lock)
-               return error(_("Failed to lock HEAD during fast_forward_to"));
 
        strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
-       ret = write_ref_sha1(ref_lock, to, sb.buf);
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, "HEAD",
+                                  to, unborn ? null_sha1 : from,
+                                  0, 1, &err) ||
+           ref_transaction_commit(transaction, sb.buf, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&sb);
+               strbuf_release(&err);
+               return -1;
+       }
 
        strbuf_release(&sb);
-       return ret;
+       strbuf_release(&err);
+       ref_transaction_free(transaction);
+       return 0;
 }
 
 static int do_recursive_merge(struct commit *base, struct commit *next,
index 95afd209107277da3154226dd08bd8040a9097b5..c08c0cbea805b38104504b9b51266949affb6991 100644 (file)
@@ -1923,7 +1923,9 @@ static void *unpack_compressed_entry(struct packed_git *p,
        git_zstream stream;
        unsigned char *buffer, *in;
 
-       buffer = xmallocz(size);
+       buffer = xmallocz_gently(size);
+       if (!buffer)
+               return NULL;
        memset(&stream, 0, sizeof(stream));
        stream.next_out = buffer;
        stream.avail_out = size + 1;
index 63ee66fedd617e2cacfae7a763f43ee600d15273..7098b10e3db0caef02ae2daef8f0624e641aada4 100644 (file)
@@ -839,7 +839,7 @@ static int handle_one_ref(const char *path,
        }
        if (object->type != OBJ_COMMIT)
                return 0;
-       commit_list_insert_by_date((struct commit *)object, list);
+       commit_list_insert((struct commit *)object, list);
        return 0;
 }
 
@@ -1366,6 +1366,7 @@ static int get_sha1_with_context_1(const char *name,
                if (!only_to_die && namelen > 2 && name[1] == '/') {
                        struct commit_list *list = NULL;
                        for_each_ref(handle_one_ref, &list);
+                       commit_list_sort_by_date(&list);
                        return get_sha1_oneline(name + 2, sha1, list);
                }
                if (namelen < 3 ||
index c3a61e70f9f72eced2530d425717972881b947c8..0690dc50d07e9fd30242e41afe149476a34fc105 100644 (file)
@@ -433,13 +433,12 @@ static int submodule_needs_pushing(const char *path, const unsigned char sha1[20
                return 0;
 
        if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
-               struct child_process cp;
+               struct child_process cp = CHILD_PROCESS_INIT;
                const char *argv[] = {"rev-list", NULL, "--not", "--remotes", "-n", "1" , NULL};
                struct strbuf buf = STRBUF_INIT;
                int needs_pushing = 0;
 
                argv[1] = sha1_to_hex(sha1);
-               memset(&cp, 0, sizeof(cp));
                cp.argv = argv;
                cp.env = local_repo_env;
                cp.git_cmd = 1;
@@ -524,10 +523,9 @@ static int push_submodule(const char *path)
                return 1;
 
        if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
-               struct child_process cp;
+               struct child_process cp = CHILD_PROCESS_INIT;
                const char *argv[] = {"push", NULL};
 
-               memset(&cp, 0, sizeof(cp));
                cp.argv = argv;
                cp.env = local_repo_env;
                cp.git_cmd = 1;
@@ -569,12 +567,11 @@ static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
        if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) {
                /* Even if the submodule is checked out and the commit is
                 * present, make sure it is reachable from a ref. */
-               struct child_process cp;
+               struct child_process cp = CHILD_PROCESS_INIT;
                const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
                struct strbuf buf = STRBUF_INIT;
 
                argv[3] = sha1_to_hex(sha1);
-               memset(&cp, 0, sizeof(cp));
                cp.argv = argv;
                cp.env = local_repo_env;
                cp.git_cmd = 1;
@@ -695,7 +692,7 @@ int fetch_populated_submodules(const struct argv_array *options,
                               int quiet)
 {
        int i, result = 0;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct string_list_item *name_for_path;
        const char *work_tree = get_git_work_tree();
@@ -711,7 +708,6 @@ int fetch_populated_submodules(const struct argv_array *options,
        argv_array_push(&argv, "--recurse-submodules-default");
        /* default value, "--submodule-prefix" and its value are added later */
 
-       memset(&cp, 0, sizeof(cp));
        cp.env = local_repo_env;
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@ -794,7 +790,7 @@ int fetch_populated_submodules(const struct argv_array *options,
 unsigned is_submodule_modified(const char *path, int ignore_untracked)
 {
        ssize_t len;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        const char *argv[] = {
                "status",
                "--porcelain",
@@ -821,7 +817,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        if (ignore_untracked)
                argv[2] = "-uno";
 
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
@@ -862,7 +857,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
 
 int submodule_uses_gitfile(const char *path)
 {
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        const char *argv[] = {
                "submodule",
                "foreach",
@@ -883,7 +878,6 @@ int submodule_uses_gitfile(const char *path)
        strbuf_release(&buf);
 
        /* Now test that all nested submodules use a gitfile too */
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
@@ -901,7 +895,7 @@ int ok_to_remove_submodule(const char *path)
 {
        struct stat st;
        ssize_t len;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        const char *argv[] = {
                "status",
                "--porcelain",
@@ -918,7 +912,6 @@ int ok_to_remove_submodule(const char *path)
        if (!submodule_uses_gitfile(path))
                return 0;
 
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
index 6c33e28ee8df4d239dd6d1c1d98c324b01c70ed3..f9648a86426470785159b5132305a256c80b5ca4 100755 (executable)
@@ -8,7 +8,7 @@ cache-tree extension.
  . ./test-lib.sh
 
 cmp_cache_tree () {
-       test-dump-cache-tree >actual &&
+       test-dump-cache-tree | sed -e '/#(ref)/d' >actual &&
        sed "s/$_x40/SHA/" <actual >filtered &&
        test_cmp "$1" filtered
 }
@@ -16,15 +16,40 @@ cmp_cache_tree () {
 # We don't bother with actually checking the SHA1:
 # test-dump-cache-tree already verifies that all existing data is
 # correct.
-test_shallow_cache_tree () {
-       printf "SHA  (%d entries, 0 subtrees)\n" $(git ls-files|wc -l) >expect &&
+generate_expected_cache_tree_rec () {
+       dir="$1${1:+/}" &&
+       parent="$2" &&
+       # ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux
+       # We want to count only foo because it's the only direct child
+       subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) &&
+       subtree_count=$(echo "$subtrees"|awk '$1 {++c} END {print c}') &&
+       entries=$(git ls-files|wc -l) &&
+       printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" &&
+       for subtree in $subtrees
+       do
+               cd "$subtree"
+               generate_expected_cache_tree_rec "$dir$subtree" "$dir" || return 1
+               cd ..
+       done &&
+       dir=$parent
+}
+
+generate_expected_cache_tree () {
+       (
+               generate_expected_cache_tree_rec
+       )
+}
+
+test_cache_tree () {
+       generate_expected_cache_tree >expect &&
        cmp_cache_tree expect
 }
 
 test_invalid_cache_tree () {
-       echo "invalid                                   (0 subtrees)" >expect &&
-       printf "SHA #(ref)  (%d entries, 0 subtrees)\n" $(git ls-files|wc -l) >>expect &&
-       cmp_cache_tree expect
+       printf "invalid                                  %s ()\n" "" "$@" >expect &&
+       test-dump-cache-tree |
+       sed -n -e "s/[0-9]* subtrees//" -e '/#(ref)/d' -e '/^invalid /p' >actual &&
+       test_cmp expect actual
 }
 
 test_no_cache_tree () {
@@ -32,26 +57,59 @@ test_no_cache_tree () {
        cmp_cache_tree expect
 }
 
-test_expect_failure 'initial commit has cache-tree' '
+test_expect_success 'initial commit has cache-tree' '
        test_commit foo &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'read-tree HEAD establishes cache-tree' '
        git read-tree HEAD &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'git-add invalidates cache-tree' '
        test_when_finished "git reset --hard; git read-tree HEAD" &&
-       echo "I changed this file" > foo &&
+       echo "I changed this file" >foo &&
        git add foo &&
        test_invalid_cache_tree
 '
 
+test_expect_success 'git-add in subdir invalidates cache-tree' '
+       test_when_finished "git reset --hard; git read-tree HEAD" &&
+       mkdir dirx &&
+       echo "I changed this file" >dirx/foo &&
+       git add dirx/foo &&
+       test_invalid_cache_tree
+'
+
+cat >before <<\EOF
+SHA  (3 entries, 2 subtrees)
+SHA dir1/ (1 entries, 0 subtrees)
+SHA dir2/ (1 entries, 0 subtrees)
+EOF
+
+cat >expect <<\EOF
+invalid                                   (2 subtrees)
+invalid                                  dir1/ (0 subtrees)
+SHA dir2/ (1 entries, 0 subtrees)
+EOF
+
+test_expect_success 'git-add in subdir does not invalidate sibling cache-tree' '
+       git tag no-children &&
+       test_when_finished "git reset --hard no-children; git read-tree HEAD" &&
+       mkdir dir1 dir2 &&
+       test_commit dir1/a &&
+       test_commit dir2/b &&
+       echo "I changed this file" >dir1/a &&
+       cmp_cache_tree before &&
+       echo "I changed this file" >dir1/a &&
+       git add dir1/a &&
+       cmp_cache_tree expect
+'
+
 test_expect_success 'update-index invalidates cache-tree' '
        test_when_finished "git reset --hard; git read-tree HEAD" &&
-       echo "I changed this file" > foo &&
+       echo "I changed this file" >foo &&
        git update-index --add foo &&
        test_invalid_cache_tree
 '
@@ -59,7 +117,7 @@ test_expect_success 'update-index invalidates cache-tree' '
 test_expect_success 'write-tree establishes cache-tree' '
        test-scrap-cache-tree &&
        git write-tree &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'test-scrap-cache-tree works' '
@@ -70,24 +128,94 @@ test_expect_success 'test-scrap-cache-tree works' '
 
 test_expect_success 'second commit has cache-tree' '
        test_commit bar &&
-       test_shallow_cache_tree
+       test_cache_tree
+'
+
+test_expect_success 'commit --interactive gives cache-tree on partial commit' '
+       cat <<-\EOT >foo.c &&
+       int foo()
+       {
+               return 42;
+       }
+       int bar()
+       {
+               return 42;
+       }
+       EOT
+       git add foo.c &&
+       test_invalid_cache_tree &&
+       git commit -m "add a file" &&
+       test_cache_tree &&
+       cat <<-\EOT >foo.c &&
+       int foo()
+       {
+               return 43;
+       }
+       int bar()
+       {
+               return 44;
+       }
+       EOT
+       (echo p; echo 1; echo; echo s; echo n; echo y; echo q) |
+       git commit --interactive -m foo &&
+       test_cache_tree
+'
+
+test_expect_success 'commit in child dir has cache-tree' '
+       mkdir dir &&
+       >dir/child.t &&
+       git add dir/child.t &&
+       git commit -m dir/child.t &&
+       test_cache_tree
 '
 
 test_expect_success 'reset --hard gives cache-tree' '
        test-scrap-cache-tree &&
        git reset --hard &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'reset --hard without index gives cache-tree' '
        rm -f .git/index &&
        git reset --hard &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
-test_expect_failure 'checkout gives cache-tree' '
+test_expect_success 'checkout gives cache-tree' '
+       git tag current &&
        git checkout HEAD^ &&
-       test_shallow_cache_tree
+       test_cache_tree
+'
+
+test_expect_success 'checkout -b gives cache-tree' '
+       git checkout current &&
+       git checkout -b prev HEAD^ &&
+       test_cache_tree
+'
+
+test_expect_success 'checkout -B gives cache-tree' '
+       git checkout current &&
+       git checkout -B prev HEAD^ &&
+       test_cache_tree
+'
+
+test_expect_success 'partial commit gives cache-tree' '
+       git checkout -b partial no-children &&
+       test_commit one &&
+       test_commit two &&
+       echo "some change" >one.t &&
+       git add one.t &&
+       echo "some other change" >two.t &&
+       git commit two.t -m partial &&
+       test_cache_tree
+'
+
+test_expect_success 'no phantom error when switching trees' '
+       mkdir newdir &&
+       >newdir/one &&
+       git add newdir/one &&
+       git checkout 2>errors &&
+       ! test -s errors
 '
 
 test_done
index aea493646e4400e733749768e48f2a3d1a470299..05a1e1d270d2f6254658607541f1b114299533e5 100755 (executable)
@@ -112,6 +112,20 @@ test_expect_success 'diff --raw' '
        git diff --raw HEAD^
 '
 
+test_expect_success 'diff --stat' '
+       git diff --stat HEAD^ HEAD
+'
+
+test_expect_success 'diff' '
+       git diff HEAD^ HEAD >actual &&
+       grep "Binary files.*differ" actual
+'
+
+test_expect_success 'diff --cached' '
+       git diff --cached HEAD^ >actual &&
+       grep "Binary files.*differ" actual
+'
+
 test_expect_success 'hash-object' '
        git hash-object large1
 '
@@ -163,4 +177,10 @@ test_expect_success 'zip achiving, deflate' '
        git archive --format=zip HEAD >/dev/null
 '
 
+test_expect_success 'fsck' '
+       test_must_fail git fsck 2>err &&
+       n=$(grep "error: attempting to allocate .* over limit" err | wc -l) &&
+       test "$n" -gt 1
+'
+
 test_done
index 7fdf840b0020fb626118d056693b0e6be92bc1ac..ea0bce2dc64b6fe3cac3e00f48b7a17a341af647 100755 (executable)
@@ -119,6 +119,16 @@ test_expect_success 'find integer value for a key' '
        check_config get_int lamb.chop 65
 '
 
+test_expect_success 'find string value for a key' '
+       check_config get_string case.baz hask &&
+       check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\""
+'
+
+test_expect_success 'check line error when NULL string is queried' '
+       test_expect_code 128 test-config get_string case.foo 2>result &&
+       test_i18ngrep "fatal: .*case\.foo.*\.git/config.*line 7" result
+'
+
 test_expect_success 'find integer if value is non parse-able' '
        check_config expect_code 128 get_int lamb.head
 '
@@ -197,4 +207,15 @@ test_expect_success 'proper error on error in custom config files' '
        test_cmp expect actual
 '
 
+test_expect_success 'check line errors for malformed values' '
+       mv .git/config .git/config.old &&
+       test_when_finished "mv .git/config.old .git/config" &&
+       cat >.git/config <<-\EOF &&
+       [alias]
+               br
+       EOF
+       test_expect_code 128 git br 2>result &&
+       test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result
+'
+
 test_done
index 1a2080e3dca272b6ed40739a7539f01f4f6ae65c..3a017bf437395526cf54403d4ea1db36a3cff0b3 100755 (executable)
@@ -151,4 +151,11 @@ test_expect_success 'delete ref while another dangling packed ref' '
        test_cmp /dev/null result
 '
 
+test_expect_success 'pack ref directly below refs/' '
+       git update-ref refs/top HEAD &&
+       git pack-refs --all --prune &&
+       grep refs/top .git/packed-refs &&
+       test_path_is_missing .git/refs/top
+'
+
 test_done
index cd0454356a6ea26c630f76748dd2c4f73bed8526..741e0803c1ac0a418c98c7eee9cb449a7c60da06 100755 (executable)
@@ -79,7 +79,7 @@ test_expect_success 'non-integer config parsing' '
 test_expect_success 'negative integer config parsing' '
        git config diff.context -1 &&
        test_must_fail git diff 2>output &&
-       test_i18ngrep "bad config file" output
+       test_i18ngrep "bad config variable" output
 '
 
 test_expect_success '-U0 is valid, so is diff.context=0' '
index 0c9ec0ad44ef4e3239e67a0c9e9ecc1340dcee8a..eae9e5a937150d60002620c8b29293f4d7ed122f 100755 (executable)
@@ -223,6 +223,23 @@ test_expect_success 'checkout --merge --conflict=diff3 <branch>' '
        test_cmp two expect
 '
 
+test_expect_success 'switch to another branch while carrying a deletion' '
+
+       git checkout -f master && git reset --hard && git clean -f &&
+       git rm two &&
+
+       test_must_fail git checkout simple 2>errs &&
+       test_i18ngrep overwritten errs &&
+
+       git checkout --merge simple 2>errs &&
+       test_i18ngrep ! overwritten errs &&
+       git ls-files -u &&
+       test_must_fail git cat-file -t :0:two &&
+       test "$(git cat-file -t :1:two)" = blob &&
+       test "$(git cat-file -t :2:two)" = blob &&
+       test_must_fail git cat-file -t :3:two
+'
+
 test_expect_success 'checkout to detach HEAD (with advice declined)' '
 
        git config advice.detachedHead false &&
index 9dd1b22630948b63d971a8ef5ff363db2d80fd9a..6a775522105d9bfc5c1c60f36944bc43e64badef 100644 (file)
@@ -16,6 +16,8 @@
  *
  * get_bool -> print bool value for the entered key or die
  *
+ * get_string -> print string value for the entered key or die
+ *
  * configset_get_value -> returns value with the highest priority for the entered key
  *                     from a config_set constructed from files entered as arguments.
  *
@@ -84,6 +86,14 @@ int main(int argc, char **argv)
                        printf("Value not found for \"%s\"\n", argv[2]);
                        goto exit1;
                }
+       } else if (argc == 3 && !strcmp(argv[1], "get_string")) {
+               if (!git_config_get_string_const(argv[2], &v)) {
+                       printf("%s\n", v);
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
        } else if (!strcmp(argv[1], "configset_get_value")) {
                for (i = 3; i < argc; i++) {
                        int err;
index 330ba4f4dd23e2cf21acbe8a7023eaca4ec09afe..54c0872fcb18edb4ca28a63fdfd4be3a17df388e 100644 (file)
@@ -26,16 +26,16 @@ static int dump_cache_tree(struct cache_tree *it,
                return 0;
 
        if (it->entry_count < 0) {
+               /* invalid */
                dump_one(it, pfx, "");
                dump_one(ref, pfx, "#(ref) ");
-               if (it->subtree_nr != ref->subtree_nr)
-                       errs = 1;
        }
        else {
                dump_one(it, pfx, "");
                if (hashcmp(it->sha1, ref->sha1) ||
                    ref->entry_count != it->entry_count ||
                    ref->subtree_nr != it->subtree_nr) {
+                       /* claims to be valid but is lying */
                        dump_one(ref, pfx, "#(ref) ");
                        errs = 1;
                }
index 37918e15f5ce06d0079ce09ae1a7be7b14533c48..89c7de2c600ce2781ce666324e703d555937740a 100644 (file)
@@ -15,9 +15,7 @@
 
 int main(int argc, char **argv)
 {
-       struct child_process proc;
-
-       memset(&proc, 0, sizeof(proc));
+       struct child_process proc = CHILD_PROCESS_INIT;
 
        if (argc < 3)
                return 1;
index 93525eb7be48eb11c242200827a7f6f0706ee241..56881a032471752ca16880d98ea1510e16d38eed 100644 (file)
@@ -3,7 +3,7 @@
 
 int main(int argc, char **argv)
 {
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        int nogit = 0;
 
        setup_git_directory_gently(&nogit);
@@ -13,7 +13,6 @@ int main(int argc, char **argv)
                setup_work_tree();
                argv++;
        }
-       memset(&cp, 0, sizeof(cp));
        cp.git_cmd = 1;
        cp.argv = (const char **)argv + 1;
        return run_command(&cp);
index 3d8fe7d801293a338f13dfd01ba352e84c658813..080a7a6ae23e6915c425a3e471fd641aabafba90 100644 (file)
@@ -118,7 +118,8 @@ static struct child_process *get_helper(struct transport *transport)
        if (data->helper)
                return data->helper;
 
-       helper = xcalloc(1, sizeof(*helper));
+       helper = xmalloc(sizeof(*helper));
+       child_process_init(helper);
        helper->in = -1;
        helper->out = -1;
        helper->err = 0;
@@ -395,7 +396,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti
        struct child_process *helper = get_helper(transport);
        struct helper_data *data = transport->data;
        int cat_blob_fd, code;
-       memset(fastimport, 0, sizeof(*fastimport));
+       child_process_init(fastimport);
        fastimport->in = helper->out;
        argv_array_push(&fastimport->args, "fast-import");
        argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet");
index 662421bb5e076177f0fc320330287d3da50303a5..7388bb87dae96514801bcd604b74d31f54955f9a 100644 (file)
@@ -201,7 +201,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
        struct ref dummy = {NULL}, *tail = &dummy;
-       struct child_process rsync;
+       struct child_process rsync = CHILD_PROCESS_INIT;
        const char *args[5];
        int temp_dir_len;
 
@@ -218,7 +218,6 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
        strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addstr(&buf, "/refs");
 
-       memset(&rsync, 0, sizeof(rsync));
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
        args[0] = "rsync";
@@ -263,9 +262,8 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
 static int fetch_objs_via_rsync(struct transport *transport,
                                int nr_objs, struct ref **to_fetch)
 {
-       struct child_process rsync;
+       struct child_process rsync = CHILD_PROCESS_INIT;
 
-       memset(&rsync, 0, sizeof(rsync));
        rsync.stdout_to_stderr = 1;
        argv_array_push(&rsync.args, "rsync");
        argv_array_push(&rsync.args, (transport->verbose > 1) ? "-rv" : "-r");
@@ -327,7 +325,7 @@ static int rsync_transport_push(struct transport *transport,
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
        int result = 0, i;
-       struct child_process rsync;
+       struct child_process rsync = CHILD_PROCESS_INIT;
        const char *args[10];
 
        if (flags & TRANSPORT_PUSH_MIRROR)
@@ -338,7 +336,6 @@ static int rsync_transport_push(struct transport *transport,
        strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addch(&buf, '/');
 
-       memset(&rsync, 0, sizeof(rsync));
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
        i = 0;
@@ -1056,7 +1053,7 @@ static int run_pre_push_hook(struct transport *transport,
 {
        int ret = 0, x;
        struct ref *r;
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        struct strbuf buf;
        const char *argv[4];
 
@@ -1067,7 +1064,6 @@ static int run_pre_push_hook(struct transport *transport,
        argv[2] = transport->url;
        argv[3] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.argv = argv;
        proc.in = -1;
 
index c6aa8fb993aa4bd92e4269d7a85c6b45fe9801e8..629c658c46a1b4f4bcd8bbe9770d7fd767ae2216 100644 (file)
@@ -1176,7 +1176,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 static int reject_merge(const struct cache_entry *ce,
                        struct unpack_trees_options *o)
 {
-       return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
+       return o->gently ? -1 :
+               add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
 }
 
 static int same(const struct cache_entry *a, const struct cache_entry *b)
@@ -1631,7 +1632,7 @@ int threeway_merge(const struct cache_entry * const *stages,
        /* #14, #14ALT, #2ALT */
        if (remote && !df_conflict_head && head_match && !remote_match) {
                if (index && !same(index, remote) && !same(index, head))
-                       return o->gently ? -1 : reject_merge(index, o);
+                       return reject_merge(index, o);
                return merged_entry(remote, index, o);
        }
        /*
@@ -1639,7 +1640,7 @@ int threeway_merge(const struct cache_entry * const *stages,
         * make sure that it matches head.
         */
        if (index && !same(index, head))
-               return o->gently ? -1 : reject_merge(index, o);
+               return reject_merge(index, o);
 
        if (head) {
                /* #5ALT, #15 */
@@ -1768,9 +1769,8 @@ int twoway_merge(const struct cache_entry * const *src,
                                else
                                        return merged_entry(newtree, current, o);
                        }
-                       return o->gently ? -1 : reject_merge(current, o);
-               }
-               else if ((!oldtree && !newtree) || /* 4 and 5 */
+                       return reject_merge(current, o);
+               } else if ((!oldtree && !newtree) || /* 4 and 5 */
                         (!oldtree && newtree &&
                          same(current, newtree)) || /* 6 and 7 */
                         (oldtree && newtree &&
@@ -1779,26 +1779,15 @@ int twoway_merge(const struct cache_entry * const *src,
                          !same(oldtree, newtree) && /* 18 and 19 */
                          same(current, newtree))) {
                        return keep_entry(current, o);
-               }
-               else if (oldtree && !newtree && same(current, oldtree)) {
+               } else if (oldtree && !newtree && same(current, oldtree)) {
                        /* 10 or 11 */
                        return deleted_entry(oldtree, current, o);
-               }
-               else if (oldtree && newtree &&
+               } else if (oldtree && newtree &&
                         same(current, oldtree) && !same(current, newtree)) {
                        /* 20 or 21 */
                        return merged_entry(newtree, current, o);
-               }
-               else {
-                       /* all other failures */
-                       if (oldtree)
-                               return o->gently ? -1 : reject_merge(oldtree, o);
-                       if (current)
-                               return o->gently ? -1 : reject_merge(current, o);
-                       if (newtree)
-                               return o->gently ? -1 : reject_merge(newtree, o);
-                       return -1;
-               }
+               } else
+                       return reject_merge(current, o);
        }
        else if (newtree) {
                if (oldtree && !o->initial_checkout) {
index 01de944a0a23f752364de51d7f5a5be6480575e8..c789ec00507696b4e52b081b66cc0e7c8cba42f9 100644 (file)
@@ -80,7 +80,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
 
 static void create_pack_file(void)
 {
-       struct child_process pack_objects;
+       struct child_process pack_objects = CHILD_PROCESS_INIT;
        char data[8193], progress[128];
        char abort_msg[] = "aborting due to possible repository "
                "corruption on the remote side.";
@@ -108,7 +108,6 @@ static void create_pack_file(void)
                argv[arg++] = "--include-tag";
        argv[arg++] = NULL;
 
-       memset(&pack_objects, 0, sizeof(pack_objects));
        pack_objects.in = -1;
        pack_objects.out = -1;
        pack_objects.err = -1;
@@ -167,7 +166,9 @@ static void create_pack_file(void)
                if (!pollsize)
                        break;
 
-               ret = poll(pfd, pollsize, 1000 * keepalive);
+               ret = poll(pfd, pollsize,
+                       keepalive < 0 ? -1 : 1000 * keepalive);
+
                if (ret < 0) {
                        if (errno != EINTR) {
                                error("poll failed, resuming: %s",
@@ -448,7 +449,7 @@ static void check_non_tip(void)
        static const char *argv[] = {
                "rev-list", "--stdin", NULL,
        };
-       static struct child_process cmd;
+       static struct child_process cmd = CHILD_PROCESS_INIT;
        struct object *o;
        char namebuf[42]; /* ^ + SHA-1 + LF */
        int i;
index 014826464e07c93374868c61673cfe308961dfb7..f8d370913a8dcfb87d62ab994b4823dc84157f8b 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -205,7 +205,7 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag,
        struct commit *commit = lookup_commit_reference_gently(sha1, 1);
        if (commit) {
                commit->object.flags |= COMPLETE;
-               commit_list_insert_by_date(commit, &complete);
+               commit_list_insert(commit, &complete);
        }
        return 0;
 }
@@ -251,64 +251,76 @@ void walker_targets_free(int targets, char **target, const char **write_ref)
 int walker_fetch(struct walker *walker, int targets, char **target,
                 const char **write_ref, const char *write_ref_log_details)
 {
-       struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
+       struct strbuf refname = STRBUF_INIT;
+       struct strbuf err = STRBUF_INIT;
+       struct ref_transaction *transaction = NULL;
        unsigned char *sha1 = xmalloc(targets * 20);
-       const char *msg;
-       char *to_free = NULL;
-       int ret;
-       int i;
+       char *msg = NULL;
+       int i, ret = -1;
 
        save_commit_buffer = 0;
 
-       for (i = 0; i < targets; i++) {
-               if (!write_ref || !write_ref[i])
-                       continue;
-
-               lock[i] = lock_ref_sha1(write_ref[i], NULL);
-               if (!lock[i]) {
-                       error("Can't lock ref %s", write_ref[i]);
-                       goto unlock_and_fail;
+       if (write_ref) {
+               transaction = ref_transaction_begin(&err);
+               if (!transaction) {
+                       error("%s", err.buf);
+                       goto done;
                }
        }
 
-       if (!walker->get_recover)
+       if (!walker->get_recover) {
                for_each_ref(mark_complete, NULL);
+               commit_list_sort_by_date(&complete);
+       }
 
        for (i = 0; i < targets; i++) {
                if (interpret_target(walker, target[i], &sha1[20 * i])) {
                        error("Could not interpret response from server '%s' as something to pull", target[i]);
-                       goto unlock_and_fail;
+                       goto done;
                }
                if (process(walker, lookup_unknown_object(&sha1[20 * i])))
-                       goto unlock_and_fail;
+                       goto done;
        }
 
        if (loop(walker))
-               goto unlock_and_fail;
-
-       if (write_ref_log_details)
-               msg = to_free = xstrfmt("fetch from %s", write_ref_log_details);
-       else
-               msg = "fetch (unknown)";
+               goto done;
+       if (!write_ref) {
+               ret = 0;
+               goto done;
+       }
+       if (write_ref_log_details) {
+               msg = xstrfmt("fetch from %s", write_ref_log_details);
+       } else {
+               msg = NULL;
+       }
        for (i = 0; i < targets; i++) {
-               if (!write_ref || !write_ref[i])
+               if (!write_ref[i])
                        continue;
-               ret = write_ref_sha1(lock[i], &sha1[20 * i], msg);
-               lock[i] = NULL;
-               if (ret)
-                       goto unlock_and_fail;
+               strbuf_reset(&refname);
+               strbuf_addf(&refname, "refs/%s", write_ref[i]);
+               if (ref_transaction_update(transaction, refname.buf,
+                                          &sha1[20 * i], NULL, 0, 0,
+                                          &err)) {
+                       error("%s", err.buf);
+                       goto done;
+               }
+       }
+       if (ref_transaction_commit(transaction,
+                                  msg ? msg : "fetch (unknown)",
+                                  &err)) {
+               error("%s", err.buf);
+               goto done;
        }
-       free(to_free);
-
-       return 0;
 
-unlock_and_fail:
-       for (i = 0; i < targets; i++)
-               if (lock[i])
-                       unlock_ref(lock[i]);
-       free(to_free);
+       ret = 0;
 
-       return -1;
+done:
+       ref_transaction_free(transaction);
+       free(msg);
+       free(sha1);
+       strbuf_release(&err);
+       strbuf_release(&refname);
+       return ret;
 }
 
 void walker_free(struct walker *walker)
index bd24cdabfb818d4eddde4f08819f5a0166283a6a..25074d71b6ce72066efc02abda74ddfb10f71d6c 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -9,16 +9,23 @@ static void do_nothing(size_t size)
 
 static void (*try_to_free_routine)(size_t size) = do_nothing;
 
-static void memory_limit_check(size_t size)
+static int memory_limit_check(size_t size, int gentle)
 {
        static int limit = -1;
        if (limit == -1) {
                const char *env = getenv("GIT_ALLOC_LIMIT");
                limit = env ? atoi(env) * 1024 : 0;
        }
-       if (limit && size > limit)
-               die("attempting to allocate %"PRIuMAX" over limit %d",
-                   (intmax_t)size, limit);
+       if (limit && size > limit) {
+               if (gentle) {
+                       error("attempting to allocate %"PRIuMAX" over limit %d",
+                             (intmax_t)size, limit);
+                       return -1;
+               } else
+                       die("attempting to allocate %"PRIuMAX" over limit %d",
+                           (intmax_t)size, limit);
+       }
+       return 0;
 }
 
 try_to_free_t set_try_to_free_routine(try_to_free_t routine)
@@ -42,11 +49,12 @@ char *xstrdup(const char *str)
        return ret;
 }
 
-void *xmalloc(size_t size)
+static void *do_xmalloc(size_t size, int gentle)
 {
        void *ret;
 
-       memory_limit_check(size);
+       if (memory_limit_check(size, gentle))
+               return NULL;
        ret = malloc(size);
        if (!ret && !size)
                ret = malloc(1);
@@ -55,9 +63,16 @@ void *xmalloc(size_t size)
                ret = malloc(size);
                if (!ret && !size)
                        ret = malloc(1);
-               if (!ret)
-                       die("Out of memory, malloc failed (tried to allocate %lu bytes)",
-                           (unsigned long)size);
+               if (!ret) {
+                       if (!gentle)
+                               die("Out of memory, malloc failed (tried to allocate %lu bytes)",
+                                   (unsigned long)size);
+                       else {
+                               error("Out of memory, malloc failed (tried to allocate %lu bytes)",
+                                     (unsigned long)size);
+                               return NULL;
+                       }
+               }
        }
 #ifdef XMALLOC_POISON
        memset(ret, 0xA5, size);
@@ -65,16 +80,37 @@ void *xmalloc(size_t size)
        return ret;
 }
 
-void *xmallocz(size_t size)
+void *xmalloc(size_t size)
+{
+       return do_xmalloc(size, 0);
+}
+
+static void *do_xmallocz(size_t size, int gentle)
 {
        void *ret;
-       if (unsigned_add_overflows(size, 1))
-               die("Data too large to fit into virtual memory space.");
-       ret = xmalloc(size + 1);
-       ((char*)ret)[size] = 0;
+       if (unsigned_add_overflows(size, 1)) {
+               if (gentle) {
+                       error("Data too large to fit into virtual memory space.");
+                       return NULL;
+               } else
+                       die("Data too large to fit into virtual memory space.");
+       }
+       ret = do_xmalloc(size + 1, gentle);
+       if (ret)
+               ((char*)ret)[size] = 0;
        return ret;
 }
 
+void *xmallocz(size_t size)
+{
+       return do_xmallocz(size, 0);
+}
+
+void *xmallocz_gently(size_t size)
+{
+       return do_xmallocz(size, 1);
+}
+
 /*
  * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
  * "data" to the allocated memory, zero terminates the allocated memory,
@@ -96,7 +132,7 @@ void *xrealloc(void *ptr, size_t size)
 {
        void *ret;
 
-       memory_limit_check(size);
+       memory_limit_check(size, 0);
        ret = realloc(ptr, size);
        if (!ret && !size)
                ret = realloc(ptr, 1);
@@ -115,7 +151,7 @@ void *xcalloc(size_t nmemb, size_t size)
 {
        void *ret;
 
-       memory_limit_check(size * nmemb);
+       memory_limit_check(size * nmemb, 0);
        ret = calloc(nmemb, size);
        if (!ret && (!nmemb || !size))
                ret = calloc(1, 1);
index 27da5296be253844e0f2bc8d5996faf343192828..1bf5d725453f726f6a6179f9706a50f3c8c9dbb5 100644 (file)
@@ -725,7 +725,7 @@ static void wt_status_print_changed(struct wt_status *s)
 
 static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
 {
-       struct child_process sm_summary;
+       struct child_process sm_summary = CHILD_PROCESS_INIT;
        struct argv_array env = ARGV_ARRAY_INIT;
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct strbuf cmd_stdout = STRBUF_INIT;
@@ -744,7 +744,6 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt
        if (!uncommitted)
                argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
 
-       memset(&sm_summary, 0, sizeof(sm_summary));
        sm_summary.argv = argv.argv;
        sm_summary.env = env.argv;
        sm_summary.git_cmd = 1;