aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/2.2.0.txt43
-rw-r--r--Documentation/config.txt3
-rw-r--r--Documentation/gitattributes.txt4
-rw-r--r--Documentation/technical/api-config.txt13
-rw-r--r--Documentation/technical/api-run-command.txt8
-rw-r--r--Makefile201
-rw-r--r--advice.c3
-rw-r--r--alias.c25
-rw-r--r--archive-tar.c3
-rw-r--r--archive.c12
-rw-r--r--bisect.c7
-rw-r--r--branch.c55
-rw-r--r--builtin/add.c3
-rw-r--r--builtin/apply.c12
-rw-r--r--builtin/checkout.c6
-rw-r--r--builtin/commit.c42
-rw-r--r--builtin/fetch.c10
-rw-r--r--builtin/gc.c51
-rw-r--r--builtin/hash-object.c103
-rw-r--r--builtin/help.c3
-rw-r--r--builtin/merge.c3
-rw-r--r--builtin/mv.c174
-rw-r--r--builtin/notes.c3
-rw-r--r--builtin/receive-pack.c37
-rw-r--r--builtin/remote-ext.c3
-rw-r--r--builtin/repack.c3
-rw-r--r--builtin/replace.c18
-rw-r--r--builtin/tag.c16
-rw-r--r--builtin/update-ref.c52
-rw-r--r--builtin/verify-pack.c3
-rw-r--r--bundle.c6
-rw-r--r--cache-tree.c19
-rw-r--r--cache-tree.h1
-rw-r--r--cache.h34
-rw-r--r--column.c2
-rw-r--r--commit.h16
-rw-r--r--config.c152
-rw-r--r--connect.c8
-rw-r--r--connected.c3
-rw-r--r--contrib/subtree/Makefile5
-rw-r--r--convert.c3
-rw-r--r--credential-cache.c3
-rw-r--r--credential.c3
-rw-r--r--daemon.c34
-rw-r--r--diff.c55
-rw-r--r--diffcore-rename.c6
-rw-r--r--diffcore.h4
-rw-r--r--editor.c3
-rw-r--r--fast-import.c109
-rw-r--r--fetch-pack.c38
-rw-r--r--git-compat-util.h1
-rwxr-xr-xgit-pull.sh2
-rw-r--r--gpg-interface.c6
-rw-r--r--http-backend.c34
-rw-r--r--http.c15
-rw-r--r--imap-send.c79
-rw-r--r--ll-merge.c23
-rw-r--r--log-tree.c25
-rw-r--r--merge-recursive.c22
-rw-r--r--pager.c42
-rw-r--r--prompt.c3
-rw-r--r--read-cache.c14
-rw-r--r--refs.c245
-rw-r--r--refs.h77
-rw-r--r--remote-curl.c3
-rw-r--r--remote-testsvn.c3
-rw-r--r--rerere.c43
-rw-r--r--revision.c2
-rw-r--r--run-command.c37
-rw-r--r--run-command.h3
-rw-r--r--send-pack.c3
-rw-r--r--sequencer.c26
-rw-r--r--sha1_file.c4
-rw-r--r--sha1_name.c3
-rw-r--r--submodule.c21
-rwxr-xr-xt/t0090-cache-tree.sh162
-rwxr-xr-xt/t1050-large.sh20
-rwxr-xr-xt/t1308-config-set.sh21
-rwxr-xr-xt/t3210-pack-refs.sh7
-rwxr-xr-xt/t4055-diff-context.sh2
-rwxr-xr-xt/t7201-co.sh17
-rw-r--r--test-config.c10
-rw-r--r--test-dump-cache-tree.c4
-rw-r--r--test-run-command.c4
-rw-r--r--test-subprocess.c3
-rw-r--r--transport-helper.c5
-rw-r--r--transport.c12
-rw-r--r--unpack-trees.c31
-rw-r--r--upload-pack.c9
-rw-r--r--walker.c86
-rw-r--r--wrapper.c68
-rw-r--r--wt-status.c3
92 files changed, 1453 insertions, 1170 deletions
diff --git a/Documentation/RelNotes/2.2.0.txt b/Documentation/RelNotes/2.2.0.txt
index f771854705..22b73618fc 100644
--- a/Documentation/RelNotes/2.2.0.txt
+++ b/Documentation/RelNotes/2.2.0.txt
@@ -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).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index c55c22ab7b..3b5b24aeb7 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -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
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 643c1ba929..9b45bda748 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -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::
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
index 21f280ca6d..0d8b99b368 100644
--- a/Documentation/technical/api-config.txt
+++ b/Documentation/technical/api-config.txt
@@ -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
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index 69510ae57a..842b8389eb 100644
--- a/Documentation/technical/api-run-command.txt
+++ b/Documentation/technical/api-run-command.txt
@@ -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;
diff --git a/Makefile b/Makefile
index 30cc622f08..e0f15a3df3 100644
--- 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)
diff --git a/advice.c b/advice.c
index 9b42033192..3b8bf3c6da 100644
--- 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 758c867149..6aa164a362 100644
--- 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
diff --git a/archive-tar.c b/archive-tar.c
index 603650fa3c..df2f4c8a64 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -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;
diff --git a/archive.c b/archive.c
index 3fc0fb2928..952a659bcb 100644
--- 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();
diff --git a/bisect.c b/bisect.c
index d6e851d783..df09cbc8ca 100644
--- 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;
}
diff --git a/branch.c b/branch.c
index 46e8aa86df..9a2228ebb4 100644
--- 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);
}
diff --git a/builtin/add.c b/builtin/add.c
index 4baf3a5635..352b85e8db 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -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))
diff --git a/builtin/apply.c b/builtin/apply.c
index 6b7c764918..f204cca5d2 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -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)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f71e74531d..8afdf2b5c4 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -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"));
diff --git a/builtin/commit.c b/builtin/commit.c
index 36e3a2eef2..41f481bd03 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -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;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index e8d0cca3e4..159fb7e916 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index 8d219d8c42..ced1456e1e 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -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();
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index d7fcf4c13c..6158363318 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -10,35 +10,55 @@
#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;
}
diff --git a/builtin/help.c b/builtin/help.c
index 1fdefeb686..8343b4027d 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -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;
diff --git a/builtin/merge.c b/builtin/merge.c
index ce82eb297d..9da9e30d9b 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -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;
diff --git a/builtin/mv.c b/builtin/mv.c
index 6ffe540c20..bf784cb943 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -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;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 820c34135c..c25a412510 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -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;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f93ac454b4..afb8d99264 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -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)
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 692c834d9d..d699d28e98 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -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;
diff --git a/builtin/repack.c b/builtin/repack.c
index a77e743b94..fc088dbe6a 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -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;
diff --git a/builtin/replace.c b/builtin/replace.c
index 294b61b97e..8020db8500 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -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;
diff --git a/builtin/tag.c b/builtin/tag.c
index 19eb747820..a81b9e4174 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -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;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 3067b11310..54a48c0cfa 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -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;
}
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 972579f33c..7747537beb 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -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;
diff --git a/bundle.c b/bundle.c
index b708906cdb..b2b89fe862 100644
--- 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;
diff --git a/cache-tree.c b/cache-tree.c
index c53f7de2b1..75a54fdc72 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -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);
diff --git a/cache-tree.h b/cache-tree.h
index b47ccec7f6..aa7b3e4a0a 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -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 4d5b76c76a..dfa1a5696d 100644
--- 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);
diff --git a/column.c b/column.c
index ca878bcea7..76b615db5f 100644
--- 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)
{
diff --git a/commit.h b/commit.h
index aa8c3ca50a..a401ddfbc4 100644
--- 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,
diff --git a/config.c b/config.c
index 01e0bdbafd..83c913ad09 100644
--- 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,
diff --git a/connect.c b/connect.c
index 5047402a1a..87b5202632 100644
--- 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, ' ');
diff --git a/connected.c b/connected.c
index dae9c9972e..299c56090b 100644
--- a/connected.c
+++ b/connected.c
@@ -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;
diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile
index d9a0ce2c63..c2bd703ee3 100644
--- a/contrib/subtree/Makefile
+++ b/contrib/subtree/Makefile
@@ -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)|' $< >$@
diff --git a/convert.c b/convert.c
index cb5fbb45ea..aa7a139bcf 100644
--- 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;
diff --git a/credential-cache.c b/credential-cache.c
index 9a03792c7d..8689a1519a 100644
--- a/credential-cache.c
+++ b/credential-cache.c
@@ -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;
diff --git a/credential.c b/credential.c
index 4d79d320f8..1886ea50b3 100644
--- a/credential.c
+++ b/credential.c
@@ -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;
diff --git a/daemon.c b/daemon.c
index e6b51ed998..4dcfff9352 100644
--- 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 867f034b8f..d7a5c81bb8 100644
--- 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;
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 2e44a37459..4e132f1fdb 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -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);
diff --git a/diffcore.h b/diffcore.h
index c876dac71a..33ea2de348 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -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 *);
diff --git a/editor.c b/editor.c
index 0abbd8dc3a..01c644cddb 100644
--- 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;
diff --git a/fast-import.c b/fast-import.c
index d73f58cbe3..c071253c90 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -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 @@ found_entry:
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;
diff --git a/fetch-pack.c b/fetch-pack.c
index b8a58fa7a5..7487aa7306 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -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)
diff --git a/git-compat-util.h b/git-compat-util.h
index d675c89603..4e7e3f8726 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -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);
diff --git a/git-pull.sh b/git-pull.sh
index 18a394fcc4..4d4fc77b05 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -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
diff --git a/gpg-interface.c b/gpg-interface.c
index ff07012726..1ef73fb7df 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -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;
diff --git a/http-backend.c b/http-backend.c
index 80790bbaef..404e682593 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -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 c8cd50dd0c..0adcec4683 100644
--- 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;
diff --git a/imap-send.c b/imap-send.c
index 87f9bb18f6..f33e56dba1 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -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;
diff --git a/ll-merge.c b/ll-merge.c
index fb61ea66a1..8ea03e536a 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -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;
}
diff --git a/log-tree.c b/log-tree.c
index 95e9b1da25..bcee7c5966 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -12,17 +12,7 @@
#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 = " (";
diff --git a/merge-recursive.c b/merge-recursive.c
index 1d332b8bbb..8ab944c44c 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -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 8b5cbc56e4..b2b805af98 100644
--- 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;
}
diff --git a/prompt.c b/prompt.c
index d7bb17cb66..e5b4938efc 100644
--- 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;
diff --git a/read-cache.c b/read-cache.c
index 6f0057fe66..b5917e0c07 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -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 27927f2319..2ce5d69090 100644
--- a/refs.c
+++ b/refs.c
@@ -25,6 +25,11 @@ static unsigned char refname_disposition[256] = {
};
/*
+ * 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
* not legal. It is legal if it is something reasonable to have under
@@ -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
@@ -3386,6 +3353,21 @@ struct ref_update {
};
/*
+ * 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
* as atomically as possible. This structure is opaque to callers.
@@ -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 ec46acdde7..68c5770164 100644
--- 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);
diff --git a/remote-curl.c b/remote-curl.c
index 0fcf2ce5ff..017ddd9284 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -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;
diff --git a/remote-testsvn.c b/remote-testsvn.c
index 686e07d317..48bf6eb93b 100644
--- a/remote-testsvn.c
+++ b/remote-testsvn.c
@@ -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");
diff --git a/rerere.c b/rerere.c
index d84b495895..20b18add42 100644
--- 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);
diff --git a/revision.c b/revision.c
index 615535c984..0d3e4171ef 100644
--- a/revision.c
+++ b/revision.c
@@ -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
diff --git a/run-command.c b/run-command.c
index 35a3ebf07b..761f0fde40 100644
--- a/run-command.c
+++ b/run-command.c
@@ -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);
diff --git a/run-command.h b/run-command.h
index ea73de309b..1b135d1c96 100644
--- a/run-command.h
+++ b/run-command.h
@@ -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 *);
diff --git a/send-pack.c b/send-pack.c
index 6129b0fd8e..8b4cbf049c 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -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;
diff --git a/sequencer.c b/sequencer.c
index 3c060e0547..5e8a207474 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -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,
diff --git a/sha1_file.c b/sha1_file.c
index 95afd20910..c08c0cbea8 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -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;
diff --git a/sha1_name.c b/sha1_name.c
index 63ee66fedd..7098b10e3d 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -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 ||
diff --git a/submodule.c b/submodule.c
index c3a61e70f9..0690dc50d0 100644
--- a/submodule.c
+++ b/submodule.c
@@ -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 @@ out:
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;
diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh
index 6c33e28ee8..f9648a8642 100755
--- a/t/t0090-cache-tree.sh
+++ b/t/t0090-cache-tree.sh
@@ -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
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index aea493646e..05a1e1d270 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -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
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index 7fdf840b00..ea0bce2dc6 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -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
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 1a2080e3dc..3a017bf437 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -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
diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh
index cd0454356a..741e0803c1 100755
--- a/t/t4055-diff-context.sh
+++ b/t/t4055-diff-context.sh
@@ -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' '
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 0c9ec0ad44..eae9e5a937 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -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 &&
diff --git a/test-config.c b/test-config.c
index 9dd1b22630..6a77552210 100644
--- a/test-config.c
+++ b/test-config.c
@@ -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;
diff --git a/test-dump-cache-tree.c b/test-dump-cache-tree.c
index 330ba4f4dd..54c0872fcb 100644
--- a/test-dump-cache-tree.c
+++ b/test-dump-cache-tree.c
@@ -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;
}
diff --git a/test-run-command.c b/test-run-command.c
index 37918e15f5..89c7de2c60 100644
--- a/test-run-command.c
+++ b/test-run-command.c
@@ -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;
diff --git a/test-subprocess.c b/test-subprocess.c
index 93525eb7be..56881a0324 100644
--- a/test-subprocess.c
+++ b/test-subprocess.c
@@ -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);
diff --git a/transport-helper.c b/transport-helper.c
index 3d8fe7d801..080a7a6ae2 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -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");
diff --git a/transport.c b/transport.c
index 662421bb5e..7388bb87da 100644
--- a/transport.c
+++ b/transport.c
@@ -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;
diff --git a/unpack-trees.c b/unpack-trees.c
index c6aa8fb993..629c658c46 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1176,7 +1176,8 @@ return_failed:
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) {
diff --git a/upload-pack.c b/upload-pack.c
index 01de944a0a..c789ec0050 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -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;
diff --git a/walker.c b/walker.c
index 014826464e..f8d370913a 100644
--- 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)
diff --git a/wrapper.c b/wrapper.c
index bd24cdabfb..25074d71b6 100644
--- 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);
diff --git a/wt-status.c b/wt-status.c
index 27da5296be..1bf5d72545 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -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;