"text" (i.e. be subjected to the autocrlf mechanism) is
decided purely based on the contents.
+core.safecrlf::
+ If true, makes git check if converting `CRLF` as controlled by
+ `core.autocrlf` is reversible. Git will verify if a command
+ modifies a file in the work tree either directly or indirectly.
+ For example, committing a file followed by checking out the
+ same file should yield the original file in the work tree. If
+ this is not the case for the current setting of
+ `core.autocrlf`, git will reject the file. The variable can
+ be set to "warn", in which case git will only warn about an
+ irreversible conversion but continue the operation.
++
+CRLF conversion bears a slight chance of corrupting data.
+autocrlf=true will convert CRLF to LF during commit and LF to
+CRLF during checkout. A file that contains a mixture of LF and
+CRLF before the commit cannot be recreated by git. For text
+files this is the right thing to do: it corrects line endings
+such that we have only LF line endings in the repository.
+But for binary files that are accidentally classified as text the
+conversion can corrupt data.
++
+If you recognize such corruption early you can easily fix it by
+setting the conversion type explicitly in .gitattributes. Right
+after committing you still have the original file in your work
+tree and this file is not yet corrupted. You can explicitly tell
+git that this file is binary and git will handle the file
+appropriately.
++
+Unfortunately, the desired effect of cleaning up text files with
+mixed line endings and the undesired effect of corrupting binary
+files cannot be distinguished. In both cases CRLFs are removed
+in an irreversible way. For text files this is the right thing
+to do because CRLFs are line endings, while for binary files
+converting CRLFs corrupts data.
++
+Note, this safety check does not mean that a checkout will generate a
+file identical to the original file for a different setting of
+`core.autocrlf`, but only for the current one. For example, a text
+file with `LF` would be accepted with `core.autocrlf=input` and could
+later be checked out with `core.autocrlf=true`, in which case the
+resulting file would contain `CRLF`, although the original file
+contained `LF`. However, in both work trees the line endings would be
+consistent, that is either all `LF` or all `CRLF`, but never mixed. A
+file with mixed line endings would be reported by the `core.safecrlf`
+mechanism.
+
core.symlinks::
If false, symbolic links are checked out as small plain files that
contain the link text. linkgit:git-update-index[1] and
error (enabled by default).
* `indent-with-non-tab` treats a line that is indented with 8 or more
space characters as an error (not enabled by default).
+* `cr-at-eol` treats a carriage-return at the end of line as
+ part of the line terminator, i.e. with it, `trailing-space`
+ does not trigger if the character before such a carriage-return
+ is not a whitespace (not enabled by default).
alias.*::
Command aliases for the linkgit:git[1] command wrapper - e.g.
branch.autosetupmerge::
Tells `git-branch` and `git-checkout` to setup new branches
- so that linkgit:git-pull[1] will appropriately merge from that
- remote branch. Note that even if this option is not set,
+ so that linkgit:git-pull[1] will appropriately merge from the
+ starting point branch. Note that even if this option is not set,
this behavior can be chosen per-branch using the `--track`
- and `--no-track` options. This option defaults to true.
+ and `--no-track` options. The valid settings are: `false` -- no
+ automatic setup is done; `true` -- automatic setup is done when the
+ starting point is a remote branch; `always` -- automatic setup is
+ done when the starting point is either a local branch or remote
+ branch. This option defaults to true.
branch.<name>.remote::
When in branch <name>, it tells `git fetch` which remote to fetch.
commit.template::
Specify a file to use as the template for new commit messages.
+color.ui::
+ When set to `always`, always use colors in all git commands which
+ are capable of colored output. When false (or `never`), never. When
+ set to `true` or `auto`, use colors only when the output is to the
+ terminal. When more specific variables of color.* are set, they always
+ take precedence over this setting. Defaults to false.
+
diff.autorefreshindex::
When using `git diff` to compare with work tree
files, do not consider stat-only change as changed.
warning. This is meant to reduce packing time on multiprocessor
machines. The required amount of memory for the delta search window
is however multiplied by the number of threads.
+ Specifying 0 will cause git to auto-detect the number of CPU's
+ and set the number of threads accordingly.
pack.indexVersion::
Specify the default pack index version. Valid values are 1 for
whenever the corresponding pack is larger than 2 GB. Otherwise
the default is 1.
+pack.packSizeLimit:
+ The default maximum size of a pack. This setting only affects
+ packing to a file, i.e. the git:// protocol is unaffected. It
+ can be overridden by the `\--max-pack-size` option of
+ linkgit:git-repack[1].
+
pull.octopus::
The default merge strategy to use when pulling multiple branches
at once.
archiving user's umask will be used instead. See umask(2) and
linkgit:git-archive[1].
+url.<base>.insteadOf::
+ Any URL that starts with this value will be rewritten to
+ start, instead, with <base>. In cases where some site serves a
+ large number of repositories, and serves them with multiple
+ access methods, and some users need to use different access
+ methods, this feature allows people to specify any of the
+ equivalent URLs and have git automatically rewrite the URL to
+ the best alternative for the particular user, even for a
+ never-before-seen repository on the site. When more than one
+ insteadOf strings match a given URL, the longest match is used.
+
user.email::
Your email address to be recorded in any newly created commits.
Can be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and
The configuration variables in the 'imap' section are described
in linkgit:git-imap-send[1].
+ receive.fsckObjects::
+ If it is set to true, git-receive-pack will check all received
+ objects. It will abort in the case of a malformed object or a
+ broken link. The result of an abort are only dangling objects.
+ The default value is true.
+
receive.unpackLimit::
If the number of objects received in a push is below this
limit then the objects will be unpacked into loose object
# Define V=1 to have a more verbose compile.
#
+# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
+# when attempting to read from an fopen'ed directory.
+#
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
# This also implies MOZILLA_SHA1.
#
# Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit
# parallel delta searching when packing objects.
#
+# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
+# is a simplified version of the merge sort used in glibc. This is
+# recommended if Git triggers O(n^2) behavior in your platform's qsort().
+#
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
BASIC_LDFLAGS =
SCRIPT_SH = \
- git-bisect.sh git-checkout.sh \
+ git-bisect.sh \
git-clone.sh \
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
git-filter-branch.sh \
git-stash.sh \
- git-help--browse.sh
+ git-web--browse.sh
SCRIPT_PERL = \
git-add--interactive.perl \
git-upload-pack$X \
git-pack-redundant$X git-var$X \
git-merge-tree$X git-imap-send$X \
- git-merge-recursive$X \
$(EXTRA_PROGRAMS)
# Empty...
EXTRA_PROGRAMS =
+# List built-in command $C whose implementation cmd_$C() is not in
+# builtin-$C.o but is linked in as part of some other command.
BUILT_INS = \
git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
git-get-tar-commit-id$X git-init$X git-repo-config$X \
git-fsck-objects$X git-cherry-pick$X git-peek-remote$X git-status$X \
+ git-merge-subtree$X \
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
-ALL_PROGRAMS += git-merge-subtree$X
-
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X gitweb/gitweb.cgi
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
- mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h
+ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h fsck.h
DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
patch-ids.o \
object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
sideband.o reachable.o reflog-walk.o \
- quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
+ quote.o read-cache.o refs.o run-command.o dir.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
revision.o pager.o tree-walk.o xdiff-interface.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
- transport.o bundle.o walker.o parse-options.o ws.o archive.o fsck.o
+ transport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o \
- alias.o
++ alias.o fsck.o
BUILTIN_OBJS = \
builtin-add.o \
builtin-bundle.o \
builtin-cat-file.o \
builtin-check-attr.o \
+ builtin-checkout.o \
builtin-checkout-index.o \
builtin-check-ref-format.o \
builtin-clean.o \
builtin-merge-base.o \
builtin-merge-file.o \
builtin-merge-ours.o \
+ builtin-merge-recursive.o \
builtin-mv.o \
builtin-name-rev.o \
builtin-pack-objects.o \
ifdef NO_C99_FORMAT
BASIC_CFLAGS += -DNO_C99_FORMAT
endif
+ifdef FREAD_READS_DIRECTORIES
+ COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
+ COMPAT_OBJS += compat/fopen.o
+endif
ifdef NO_SYMLINK_HEAD
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
endif
COMPAT_CFLAGS += -DNO_MEMMEM
COMPAT_OBJS += compat/memmem.o
endif
+ifdef INTERNAL_QSORT
+ COMPAT_CFLAGS += -DINTERNAL_QSORT
+ COMPAT_OBJS += compat/qsort.o
+endif
ifdef THREADED_DELTA_SEARCH
BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
EXTLIBS += -lpthread
+ LIB_OBJS += thread-utils.o
endif
ifeq ($(TCLTK_PATH),)
### Build rules
-all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS)
+all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
ifneq (,$X)
$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';)
endif
help.o: help.c common-cmds.h GIT-CFLAGS
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
+ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
'-DGIT_INFO_PATH="$(infodir_SQ)"' $<
-git-merge-subtree$X: git-merge-recursive$X
- $(QUIET_BUILT_IN)$(RM) $@ && ln git-merge-recursive$X $@
-
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && ln git$X $@
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
- -e 's|@@HTMLDIR@@|$(htmldir_SQ)|g' \
$@.sh >$@+ && \
chmod +x $@+ && \
mv $@+ $@
echo "$$FLAGS" >GIT-CFLAGS; \
fi
+GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
+ @echo SHELL_PATH=\''$(SHELL_PATH_SQ)'\' >$@
+
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)')
mv $@+ $@
GIT_TARNAME=git-$(GIT_VERSION)
-dist: git.spec git-archive configure
+dist: git.spec git-archive$(X) configure
./git-archive --format=tar \
--prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
@mkdir -p $(GIT_TARNAME)
$(MAKE) -C gitk-git clean
$(MAKE) -C git-gui clean
endif
- $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
+ $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
.PHONY: all install clean strip
.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
+.PHONY: .FORCE-GIT-BUILD-OPTIONS
### Check documentation
#
#include "pack.h"
#include "sideband.h"
#include "fetch-pack.h"
+#include "remote.h"
#include "run-command.h"
static int transfer_unpack_limit = -1;
int retval;
unsigned long cutoff = 0;
- track_object_refs = 0;
save_commit_buffer = 0;
for (ref = *refs; ref; ref = ref->next) {
cmd.git_cmd = 1;
if (start_command(&cmd))
die("fetch-pack: unable to fork off %s", argv[0]);
- if (do_keep && pack_lockfile)
+ if (do_keep && pack_lockfile) {
*pack_lockfile = index_pack_lockfile(cmd.out);
+ close(cmd.out);
+ }
if (finish_command(&cmd))
die("%s failed", argv[0]);
}
static struct ref *do_fetch_pack(int fd[2],
+ const struct ref *orig_ref,
int nr_match,
char **match,
char **pack_lockfile)
{
- struct ref *ref;
+ struct ref *ref = copy_ref_list(orig_ref);
unsigned char sha1[20];
- get_remote_heads(fd[0], &ref, 0, NULL, 0);
if (is_repository_shallow() && !server_supports("shallow"))
die("Server does not support shallow clients");
if (server_supports("multi_ack")) {
fprintf(stderr, "Server supports side-band\n");
use_sideband = 1;
}
- if (!ref) {
- packet_flush(fd[1]);
- die("no matching remote head");
- }
if (everything_local(&ref, nr_match, match)) {
packet_flush(fd[1]);
goto all_done;
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
int i, ret, nr_heads;
- struct ref *ref;
+ struct ref *ref = NULL;
char *dest = NULL, **heads;
+ int fd[2];
+ struct child_process *conn;
nr_heads = 0;
heads = NULL;
if (!dest)
usage(fetch_pack_usage);
- ref = fetch_pack(&args, dest, nr_heads, heads, NULL);
+ conn = git_connect(fd, (char *)dest, args.uploadpack,
+ args.verbose ? CONNECT_VERBOSE : 0);
+ if (conn) {
+ get_remote_heads(fd[0], &ref, 0, NULL, 0);
+
+ ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
+ close(fd[0]);
+ close(fd[1]);
+ if (finish_connect(conn))
+ ref = NULL;
+ } else {
+ ref = NULL;
+ }
ret = !ref;
+ if (!ret && nr_heads) {
+ /* If the heads to pull were given, we should have
+ * consumed all of them by matching the remote.
+ * Otherwise, 'git-fetch remote no-such-ref' would
+ * silently succeed without issuing an error.
+ */
+ for (i = 0; i < nr_heads; i++)
+ if (heads[i] && heads[i][0]) {
+ error("no such remote ref %s", heads[i]);
+ ret = 1;
+ }
+ }
while (ref) {
printf("%s %s\n",
sha1_to_hex(ref->old_sha1), ref->name);
}
struct ref *fetch_pack(struct fetch_pack_args *my_args,
+ int fd[], struct child_process *conn,
+ const struct ref *ref,
const char *dest,
int nr_heads,
char **heads,
char **pack_lockfile)
{
- int i, ret;
- int fd[2];
- struct child_process *conn;
- struct ref *ref;
struct stat st;
+ struct ref *ref_cpy;
fetch_pack_setup();
memcpy(&args, my_args, sizeof(args));
st.st_mtime = 0;
}
- conn = git_connect(fd, (char *)dest, args.uploadpack,
- args.verbose ? CONNECT_VERBOSE : 0);
if (heads && nr_heads)
nr_heads = remove_duplicates(nr_heads, heads);
- ref = do_fetch_pack(fd, nr_heads, heads, pack_lockfile);
- close(fd[0]);
- close(fd[1]);
- ret = finish_connect(conn);
-
- if (!ret && nr_heads) {
- /* If the heads to pull were given, we should have
- * consumed all of them by matching the remote.
- * Otherwise, 'git-fetch remote no-such-ref' would
- * silently succeed without issuing an error.
- */
- for (i = 0; i < nr_heads; i++)
- if (heads[i] && heads[i][0]) {
- error("no such remote ref %s", heads[i]);
- ret = 1;
- }
+ if (!ref) {
+ packet_flush(fd[1]);
+ die("no matching remote head");
}
+ ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile);
- if (!ret && args.depth > 0) {
+ if (args.depth > 0) {
struct cache_time mtime;
char *shallow = git_path("shallow");
int fd;
}
}
- if (ret)
- ref = NULL;
-
- return ref;
+ return ref_cpy;
}
#include "pack.h"
#include "cache-tree.h"
#include "tree-walk.h"
+ #include "fsck.h"
#include "parse-options.h"
#define REACHABLE 0x0001
return -1;
}
- static int objwarning(struct object *obj, const char *err, ...)
+ static int fsck_error_func(struct object *obj, int type, const char *err, ...)
{
va_list params;
va_start(params, err);
- objreport(obj, "warning", err, params);
+ objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params);
va_end(params);
- return -1;
+ return (type == FSCK_WARN) ? 0 : 1;
+ }
+
+ static int mark_object(struct object *obj, int type, void *data)
+ {
+ struct tree *tree = NULL;
+ struct object *parent = data;
+ int result;
+
+ if (!obj) {
+ printf("broken link from %7s %s\n",
+ typename(parent->type), sha1_to_hex(parent->sha1));
+ printf("broken link from %7s %s\n",
+ (type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
+ errors_found |= ERROR_REACHABLE;
+ return 1;
+ }
+
+ if (type != OBJ_ANY && obj->type != type)
+ objerror(parent, "wrong object type in link");
+
+ if (obj->flags & REACHABLE)
+ return 0;
+ obj->flags |= REACHABLE;
+ if (!obj->parsed) {
+ if (parent && !has_sha1_file(obj->sha1)) {
+ printf("broken link from %7s %s\n",
+ typename(parent->type), sha1_to_hex(parent->sha1));
+ printf(" to %7s %s\n",
+ typename(obj->type), sha1_to_hex(obj->sha1));
+ errors_found |= ERROR_REACHABLE;
+ }
+ return 1;
+ }
+
+ if (obj->type == OBJ_TREE) {
+ obj->parsed = 0;
+ tree = (struct tree *)obj;
+ if (parse_tree(tree) < 0)
+ return 1; /* error already displayed */
+ }
+ result = fsck_walk(obj, mark_object, obj);
+ if (tree) {
+ free(tree->buffer);
+ tree->buffer = NULL;
+ }
+ if (result < 0)
+ result = 1;
+
+ return result;
+ }
+
+ static void mark_object_reachable(struct object *obj)
+ {
+ mark_object(obj, OBJ_ANY, 0);
+ }
+
+ static int mark_used(struct object *obj, int type, void *data)
+ {
+ if (!obj)
+ return 1;
+ obj->used = 1;
+ return 0;
}
/*
*/
static void check_reachable_object(struct object *obj)
{
- const struct object_refs *refs;
-
/*
* We obviously want the object to be parsed,
* except if it was in a pack-file and we didn't
errors_found |= ERROR_REACHABLE;
return;
}
-
- /*
- * Check that everything that we try to reference is also good.
- */
- refs = lookup_object_refs(obj);
- if (refs) {
- unsigned j;
- for (j = 0; j < refs->count; j++) {
- struct object *ref = refs->ref[j];
- if (ref->parsed ||
- (has_sha1_file(ref->sha1)))
- continue;
- printf("broken link from %7s %s\n",
- typename(obj->type), sha1_to_hex(obj->sha1));
- printf(" to %7s %s\n",
- typename(ref->type), sha1_to_hex(ref->sha1));
- errors_found |= ERROR_REACHABLE;
- }
- }
}
/*
}
}
- /*
- * The entries in a tree are ordered in the _path_ order,
- * which means that a directory entry is ordered by adding
- * a slash to the end of it.
- *
- * So a directory called "a" is ordered _after_ a file
- * called "a.c", because "a/" sorts after "a.c".
- */
- #define TREE_UNORDERED (-1)
- #define TREE_HAS_DUPS (-2)
-
- static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
+ static int fsck_sha1(const unsigned char *sha1)
{
- int len1 = strlen(name1);
- int len2 = strlen(name2);
- int len = len1 < len2 ? len1 : len2;
- unsigned char c1, c2;
- int cmp;
-
- cmp = memcmp(name1, name2, len);
- if (cmp < 0)
+ struct object *obj = parse_object(sha1);
+ if (!obj) {
+ errors_found |= ERROR_OBJECT;
+ return error("%s: object corrupt or missing",
+ sha1_to_hex(sha1));
+ }
+ if (obj->flags & SEEN)
return 0;
- if (cmp > 0)
- return TREE_UNORDERED;
-
- /*
- * Ok, the first <len> characters are the same.
- * Now we need to order the next one, but turn
- * a '\0' into a '/' for a directory entry.
- */
- c1 = name1[len];
- c2 = name2[len];
- if (!c1 && !c2)
- /*
- * git-write-tree used to write out a nonsense tree that has
- * entries with the same name, one blob and one tree. Make
- * sure we do not have duplicate entries.
- */
- return TREE_HAS_DUPS;
- if (!c1 && S_ISDIR(mode1))
- c1 = '/';
- if (!c2 && S_ISDIR(mode2))
- c2 = '/';
- return c1 < c2 ? 0 : TREE_UNORDERED;
- }
-
- static int fsck_tree(struct tree *item)
- {
- int retval;
- int has_full_path = 0;
- int has_empty_name = 0;
- int has_zero_pad = 0;
- int has_bad_modes = 0;
- int has_dup_entries = 0;
- int not_properly_sorted = 0;
- struct tree_desc desc;
- unsigned o_mode;
- const char *o_name;
- const unsigned char *o_sha1;
+ obj->flags |= SEEN;
if (verbose)
- fprintf(stderr, "Checking tree %s\n",
- sha1_to_hex(item->object.sha1));
-
- init_tree_desc(&desc, item->buffer, item->size);
-
- o_mode = 0;
- o_name = NULL;
- o_sha1 = NULL;
- while (desc.size) {
- unsigned mode;
- const char *name;
- const unsigned char *sha1;
-
- sha1 = tree_entry_extract(&desc, &name, &mode);
-
- if (strchr(name, '/'))
- has_full_path = 1;
- if (!*name)
- has_empty_name = 1;
- has_zero_pad |= *(char *)desc.buffer == '0';
- update_tree_entry(&desc);
-
- switch (mode) {
- /*
- * Standard modes..
- */
- case S_IFREG | 0755:
- case S_IFREG | 0644:
- case S_IFLNK:
- case S_IFDIR:
- case S_IFGITLINK:
- break;
- /*
- * This is nonstandard, but we had a few of these
- * early on when we honored the full set of mode
- * bits..
- */
- case S_IFREG | 0664:
- if (!check_strict)
- break;
- default:
- has_bad_modes = 1;
- }
+ fprintf(stderr, "Checking %s %s\n",
+ typename(obj->type), sha1_to_hex(obj->sha1));
- if (o_name) {
- switch (verify_ordered(o_mode, o_name, mode, name)) {
- case TREE_UNORDERED:
- not_properly_sorted = 1;
- break;
- case TREE_HAS_DUPS:
- has_dup_entries = 1;
- break;
- default:
- break;
- }
- }
+ if (fsck_walk(obj, mark_used, 0))
+ objerror(obj, "broken links");
+ if (fsck_object(obj, check_strict, fsck_error_func))
+ return -1;
- o_mode = mode;
- o_name = name;
- o_sha1 = sha1;
- }
- free(item->buffer);
- item->buffer = NULL;
+ if (obj->type == OBJ_TREE) {
+ struct tree *item = (struct tree *) obj;
- retval = 0;
- if (has_full_path) {
- objwarning(&item->object, "contains full pathnames");
+ free(item->buffer);
+ item->buffer = NULL;
}
- if (has_empty_name) {
- objwarning(&item->object, "contains empty pathname");
- }
- if (has_zero_pad) {
- objwarning(&item->object, "contains zero-padded file modes");
- }
- if (has_bad_modes) {
- objwarning(&item->object, "contains bad file modes");
- }
- if (has_dup_entries) {
- retval = objerror(&item->object, "contains duplicate file entries");
- }
- if (not_properly_sorted) {
- retval = objerror(&item->object, "not properly sorted");
- }
- return retval;
- }
- static int fsck_commit(struct commit *commit)
- {
- char *buffer = commit->buffer;
- unsigned char tree_sha1[20], sha1[20];
+ if (obj->type == OBJ_COMMIT) {
+ struct commit *commit = (struct commit *) obj;
- if (verbose)
- fprintf(stderr, "Checking commit %s\n",
- sha1_to_hex(commit->object.sha1));
-
- if (!commit->date)
- return objerror(&commit->object, "invalid author/committer line");
-
- if (memcmp(buffer, "tree ", 5))
- return objerror(&commit->object, "invalid format - expected 'tree' line");
- if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
- return objerror(&commit->object, "invalid 'tree' line format - bad sha1");
- buffer += 46;
- while (!memcmp(buffer, "parent ", 7)) {
- if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
- return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
- buffer += 48;
- }
- if (memcmp(buffer, "author ", 7))
- return objerror(&commit->object, "invalid format - expected 'author' line");
- free(commit->buffer);
- commit->buffer = NULL;
- if (!commit->tree)
- return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
- if (!commit->parents && show_root)
- printf("root %s\n", sha1_to_hex(commit->object.sha1));
- return 0;
- }
+ free(commit->buffer);
+ commit->buffer = NULL;
- static int fsck_tag(struct tag *tag)
- {
- struct object *tagged = tag->tagged;
+ if (!commit->parents && show_root)
+ printf("root %s\n", sha1_to_hex(commit->object.sha1));
+ }
- if (verbose)
- fprintf(stderr, "Checking tag %s\n",
- sha1_to_hex(tag->object.sha1));
+ if (obj->type == OBJ_TAG) {
+ struct tag *tag = (struct tag *) obj;
- if (!tagged) {
- return objerror(&tag->object, "could not load tagged object");
+ if (show_tags && tag->tagged) {
+ printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1));
+ printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
+ }
}
- if (!show_tags)
- return 0;
- printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
- printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
return 0;
}
- static int fsck_sha1(const unsigned char *sha1)
- {
- struct object *obj = parse_object(sha1);
- if (!obj) {
- errors_found |= ERROR_OBJECT;
- return error("%s: object corrupt or missing",
- sha1_to_hex(sha1));
- }
- if (obj->flags & SEEN)
- return 0;
- obj->flags |= SEEN;
- if (obj->type == OBJ_BLOB)
- return 0;
- if (obj->type == OBJ_TREE)
- return fsck_tree((struct tree *) obj);
- if (obj->type == OBJ_COMMIT)
- return fsck_commit((struct commit *) obj);
- if (obj->type == OBJ_TAG)
- return fsck_tag((struct tag *) obj);
-
- /* By now, parse_object() would've returned NULL instead. */
- return objerror(obj, "unknown type '%d' (internal fsck error)",
- obj->type);
- }
-
/*
* This is the sorting chunk size: make it reasonably
* big so that we can sort well..
obj = lookup_object(osha1);
if (obj) {
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
}
}
obj = lookup_object(nsha1);
if (obj) {
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
}
return 0;
}
error("%s: not a commit", refname);
default_refs++;
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
return 0;
}
sha1_to_hex(it->sha1));
return 1;
}
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
obj->used = 1;
if (obj->type != OBJ_TREE)
err |= objerror(obj, "non-tree in cache-tree");
{
int i, heads;
- track_object_refs = 1;
errors_found = 0;
argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0);
continue;
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
heads++;
continue;
}
struct blob *blob;
struct object *obj;
- mode = ntohl(active_cache[i]->ce_mode);
+ mode = active_cache[i]->ce_mode;
if (S_ISGITLINK(mode))
continue;
blob = lookup_blob(active_cache[i]->sha1);
continue;
obj = &blob->object;
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
}
if (active_cache_tree)
fsck_cache_tree(active_cache_tree);
#include "progress.h"
#ifdef THREADED_DELTA_SEARCH
+#include "thread-utils.h"
#include <pthread.h>
#endif
static const char *base_name;
static int progress = 1;
static int window = 10;
-static uint32_t pack_size_limit;
+static uint32_t pack_size_limit, pack_size_limit_cfg;
static int depth = 50;
static int delta_search_threads = 1;
static int pack_to_stdout;
* accounting lock. Compiler will optimize the strangeness
* away when THREADED_DELTA_SEARCH is not defined.
*/
- if (trg_entry->delta_data)
- free(trg_entry->delta_data);
+ free(trg_entry->delta_data);
cache_lock();
if (trg_entry->delta_data) {
delta_cache_size -= trg_entry->delta_size;
}
if (!strcmp(k, "pack.threads")) {
delta_search_threads = git_config_int(k, v);
- if (delta_search_threads < 1)
+ if (delta_search_threads < 0)
die("invalid number of threads specified (%d)",
delta_search_threads);
#ifndef THREADED_DELTA_SEARCH
- if (delta_search_threads > 1)
+ if (delta_search_threads != 1)
warning("no threads support, ignoring %s", k);
#endif
return 0;
die("bad pack.indexversion=%d", pack_idx_default_version);
return 0;
}
+ if (!strcmp(k, "pack.packsizelimit")) {
+ pack_size_limit_cfg = git_config_ulong(k, v);
+ return 0;
+ }
return git_default_config(k, v);
}
init_revisions(&revs, NULL);
save_commit_buffer = 0;
- track_object_refs = 0;
setup_revisions(ac, av, &revs, NULL);
while (fgets(line, sizeof(line), stdin) != NULL) {
die("bad revision '%s'", line);
}
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
}
if (!prefixcmp(arg, "--max-pack-size=")) {
char *end;
+ pack_size_limit_cfg = 0;
pack_size_limit = strtoul(arg+16, &end, 0) * 1024 * 1024;
if (!arg[16] || *end)
usage(pack_usage);
if (!prefixcmp(arg, "--threads=")) {
char *end;
delta_search_threads = strtoul(arg+10, &end, 0);
- if (!arg[10] || *end || delta_search_threads < 1)
+ if (!arg[10] || *end || delta_search_threads < 0)
usage(pack_usage);
#ifndef THREADED_DELTA_SEARCH
- if (delta_search_threads > 1)
+ if (delta_search_threads != 1)
warning("no threads support, "
"ignoring %s", arg);
#endif
if (pack_to_stdout != !base_name)
usage(pack_usage);
+ if (!pack_to_stdout && !pack_size_limit)
+ pack_size_limit = pack_size_limit_cfg;
+
if (pack_to_stdout && pack_size_limit)
die("--max-pack-size cannot be used to build a pack for transfer.");
if (!pack_to_stdout && thin)
die("--thin cannot be used to build an indexable pack.");
+#ifdef THREADED_DELTA_SEARCH
+ if (!delta_search_threads) /* --threads=0 means autodetect */
+ delta_search_threads = online_cpus();
+#endif
+
prepare_packed_git();
if (progress)
" --no-merges\n"
" --remove-empty\n"
" --all\n"
+" --branches\n"
+" --tags\n"
+" --remotes\n"
" --stdin\n"
" --quiet\n"
" ordering output:\n"
fputs(header_prefix, stdout);
if (commit->object.flags & BOUNDARY)
putchar('-');
+ else if (commit->object.flags & UNINTERESTING)
+ putchar('^');
else if (revs.left_right) {
if (commit->object.flags & SYMMETRIC_LEFT)
putchar('<');
else
putchar('\n');
- if (revs.verbose_header) {
+ if (revs.verbose_header && commit->buffer) {
struct strbuf buf;
strbuf_init(&buf, 0);
pretty_print_commit(revs.commit_format, commit,
usage(rev_list_usage);
save_commit_buffer = revs.verbose_header || revs.grep_filter;
- track_object_refs = 0;
if (bisect_list)
revs.limited = 1;
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
if (revs.tree_objects)
mark_edges_uninteresting(revs.commits, &revs, show_edge);
#include "git-compat-util.h"
#include "strbuf.h"
+#include "hash.h"
#include SHA1_HEADER
#include <zlib.h>
* We save the fields in big-endian order to allow using the
* index file over NFS transparently.
*/
+struct ondisk_cache_entry {
+ struct cache_time ctime;
+ struct cache_time mtime;
+ unsigned int dev;
+ unsigned int ino;
+ unsigned int mode;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int size;
+ unsigned char sha1[20];
+ unsigned short flags;
+ char name[FLEX_ARRAY]; /* more */
+};
+
struct cache_entry {
- struct cache_time ce_ctime;
- struct cache_time ce_mtime;
+ unsigned int ce_ctime;
+ unsigned int ce_mtime;
unsigned int ce_dev;
unsigned int ce_ino;
unsigned int ce_mode;
unsigned int ce_uid;
unsigned int ce_gid;
unsigned int ce_size;
+ unsigned int ce_flags;
unsigned char sha1[20];
- unsigned short ce_flags;
+ struct cache_entry *next;
char name[FLEX_ARRAY]; /* more */
};
#define CE_NAMEMASK (0x0fff)
#define CE_STAGEMASK (0x3000)
-#define CE_UPDATE (0x4000)
#define CE_VALID (0x8000)
#define CE_STAGESHIFT 12
-#define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT))
-#define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags))
+/* In-memory only */
+#define CE_UPDATE (0x10000)
+#define CE_REMOVE (0x20000)
+#define CE_UPTODATE (0x40000)
+
+#define CE_HASHED (0x100000)
+#define CE_UNHASHED (0x200000)
+
+/*
+ * Copy the sha1 and stat state of a cache entry from one to
+ * another. But we never change the name, or the hash state!
+ */
+#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
+static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry *src)
+{
+ unsigned int state = dst->ce_flags & CE_STATE_MASK;
+
+ /* Don't copy hash chain and name */
+ memcpy(dst, src, offsetof(struct cache_entry, next));
+
+ /* Restore the hash state */
+ dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
+}
+
+/*
+ * We don't actually *remove* it, we can just mark it invalid so that
+ * we won't find it in lookups.
+ *
+ * Not only would we have to search the lists (simple enough), but
+ * we'd also have to rehash other hash buckets in case this makes the
+ * hash bucket empty (common). So it's much better to just mark
+ * it.
+ */
+static inline void remove_index_entry(struct cache_entry *ce)
+{
+ ce->ce_flags |= CE_UNHASHED;
+}
+
+static inline unsigned create_ce_flags(size_t len, unsigned stage)
+{
+ if (len >= CE_NAMEMASK)
+ len = CE_NAMEMASK;
+ return (len | (stage << CE_STAGESHIFT));
+}
+
+static inline size_t ce_namelen(const struct cache_entry *ce)
+{
+ size_t len = ce->ce_flags & CE_NAMEMASK;
+ if (len < CE_NAMEMASK)
+ return len;
+ return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
+}
+
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
-#define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT)
+#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
+#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
+#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
static inline unsigned int create_ce_mode(unsigned int mode)
{
if (S_ISLNK(mode))
- return htonl(S_IFLNK);
+ return S_IFLNK;
if (S_ISDIR(mode) || S_ISGITLINK(mode))
- return htonl(S_IFGITLINK);
- return htonl(S_IFREG | ce_permissions(mode));
+ return S_IFGITLINK;
+ return S_IFREG | ce_permissions(mode);
}
static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
{
extern int trust_executable_bit, has_symlinks;
if (!has_symlinks && S_ISREG(mode) &&
- ce && S_ISLNK(ntohl(ce->ce_mode)))
+ ce && S_ISLNK(ce->ce_mode))
return ce->ce_mode;
if (!trust_executable_bit && S_ISREG(mode)) {
- if (ce && S_ISREG(ntohl(ce->ce_mode)))
+ if (ce && S_ISREG(ce->ce_mode))
return ce->ce_mode;
return create_ce_mode(0666);
}
return create_ce_mode(mode);
}
+static inline int ce_to_dtype(const struct cache_entry *ce)
+{
+ unsigned ce_mode = ntohl(ce->ce_mode);
+ if (S_ISREG(ce_mode))
+ return DT_REG;
+ else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
+ return DT_DIR;
+ else if (S_ISLNK(ce_mode))
+ return DT_LNK;
+ else
+ return DT_UNKNOWN;
+}
#define canon_mode(mode) \
(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
+#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7)
struct index_state {
struct cache_entry **cache;
unsigned int cache_nr, cache_alloc, cache_changed;
struct cache_tree *cache_tree;
time_t timestamp;
- void *mmap;
- size_t mmap_size;
+ void *alloc;
+ unsigned name_hash_initialized : 1;
+ struct hash_table name_hash;
};
extern struct index_state the_index;
#define read_cache_from(path) read_index_from(&the_index, (path))
#define write_cache(newfd, cache, entries) write_index(&the_index, (newfd))
#define discard_cache() discard_index(&the_index)
+#define unmerged_cache() unmerged_index(&the_index)
#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
#define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))
#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
+#define cache_name_exists(name, namelen) index_name_exists(&the_index, (name), (namelen))
#endif
enum object_type {
/* 5 for future expansion */
OBJ_OFS_DELTA = 6,
OBJ_REF_DELTA = 7,
+ OBJ_ANY,
OBJ_MAX,
};
extern int read_index_from(struct index_state *, const char *path);
extern int write_index(struct index_state *, int newfd);
extern int discard_index(struct index_state *);
+extern int unmerged_index(struct index_state *);
extern int verify_path(const char *path);
+extern int index_name_exists(struct index_state *istate, const char *name, int namelen);
extern int index_name_pos(struct index_state *, const char *name, int namelen);
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
extern size_t delta_base_cache_limit;
extern int auto_crlf;
+enum safe_crlf {
+ SAFE_CRLF_FALSE = 0,
+ SAFE_CRLF_FAIL = 1,
+ SAFE_CRLF_WARN = 2,
+};
+
+extern enum safe_crlf safe_crlf;
+
+enum branch_track {
+ BRANCH_TRACK_NEVER = 0,
+ BRANCH_TRACK_REMOTE,
+ BRANCH_TRACK_ALWAYS,
+ BRANCH_TRACK_EXPLICIT,
+};
+
+extern enum branch_track git_branch_track;
+
#define GIT_REPO_VERSION 0
extern int repository_format_version;
extern int check_repository_format(void);
extern int git_config_rename_section(const char *, const char *);
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value);
+extern int git_env_bool(const char *, int);
+extern int git_config_system(void);
+extern int git_config_global(void);
extern int config_error_nonbool(const char *);
#define MAX_GITNAME (1000)
/* IO helper functions */
extern void maybe_flush_or_die(FILE *, const char *);
extern int copy_fd(int ifd, int ofd);
+extern int copy_file(const char *dst, const char *src, int mode);
extern int read_in_full(int fd, void *buf, size_t count);
extern int write_in_full(int fd, const void *buf, size_t count);
extern void write_or_die(int fd, const void *buf, size_t count);
/* convert.c */
/* returns 1 if *dst was used */
-extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
+extern int convert_to_git(const char *path, const char *src, size_t len,
+ struct strbuf *dst, enum safe_crlf checksafe);
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
/* add */
#define WS_TRAILING_SPACE 01
#define WS_SPACE_BEFORE_TAB 02
#define WS_INDENT_WITH_NON_TAB 04
+#define WS_CR_AT_EOL 010
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
extern unsigned whitespace_rule_cfg;
extern unsigned whitespace_rule(const char *);
FILE *stream, const char *set,
const char *reset, const char *ws);
extern char *whitespace_error_string(unsigned ws);
+extern int ws_fix_copy(char *, const char *, int, unsigned, int *);
/* ls-files */
int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);
int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset);
void overlay_tree_on_cache(const char *tree_name, const char *prefix);
+char *alias_lookup(const char *alias);
+
#endif /* CACHE_H */
int abbrev, const char *subject,
const char *after_subject, enum date_mode,
int non_ascii_present);
+void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
+ const char *line, enum date_mode dmode,
+ const char *encoding);
+void pp_title_line(enum cmit_fmt fmt,
+ const char **msg_p,
+ struct strbuf *sb,
+ const char *subject,
+ const char *after_subject,
+ const char *encoding,
+ int plain_non_ascii);
+void pp_remainder(enum cmit_fmt fmt,
+ const char **msg_p,
+ struct strbuf *sb,
+ int indent);
+
/** Removes the first commit from a list sorted by date, and adds all
* of its parents.
struct commit_graft *read_graft_line(char *buf, int len);
int register_commit_graft(struct commit_graft *, int);
int read_graft_file(const char *graft_file);
+ struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
static int deny_non_fast_forwards = 0;
+ static int receive_fsck_objects = 1;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
return 0;
}
+ if (strcmp(var, "receive.fsckobjects") == 0) {
+ receive_fsck_objects = git_config_bool(var, value);
+ return 0;
+ }
+
return git_default_config(var, value);
}
break;
}
}
+ close(proc.in);
return hook_status(finish_command(&proc), hook_name);
}
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
if (ntohl(hdr.hdr_entries) < unpack_limit) {
- int code;
- const char *unpacker[3];
- unpacker[0] = "unpack-objects";
- unpacker[1] = hdr_arg;
- unpacker[2] = NULL;
+ int code, i = 0;
+ const char *unpacker[4];
+ unpacker[i++] = "unpack-objects";
+ if (receive_fsck_objects)
+ unpacker[i++] = "--strict";
+ unpacker[i++] = hdr_arg;
+ unpacker[i++] = NULL;
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
switch (code) {
case 0:
return "unpacker exited with error code";
}
} else {
- const char *keeper[6];
- int s, status;
+ const char *keeper[7];
+ int s, status, i = 0;
char keep_arg[256];
struct child_process ip;
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
strcpy(keep_arg + s, "localhost");
- keeper[0] = "index-pack";
- keeper[1] = "--stdin";
- keeper[2] = "--fix-thin";
- keeper[3] = hdr_arg;
- keeper[4] = keep_arg;
- keeper[5] = NULL;
+ keeper[i++] = "index-pack";
+ keeper[i++] = "--stdin";
+ if (receive_fsck_objects)
+ keeper[i++] = "--strict";
+ keeper[i++] = "--fix-thin";
+ keeper[i++] = hdr_arg;
+ keeper[i++] = keep_arg;
+ keeper[i++] = NULL;
memset(&ip, 0, sizeof(ip));
ip.argv = keeper;
ip.out = -1;
if (start_command(&ip))
return "index-pack fork failed";
pack_lockfile = index_pack_lockfile(ip.out);
+ close(ip.out);
status = finish_command(&ip);
if (!status) {
reprepare_packed_git();
struct object *deref_tag(struct object *o, const char *warn, int warnlen)
{
while (o && o->type == OBJ_TAG)
- o = parse_object(((struct tag *)o)->tagged->sha1);
+ if (((struct tag *)o)->tagged)
+ o = parse_object(((struct tag *)o)->tagged->sha1);
+ else
+ o = NULL;
if (!o && warn) {
if (!warnlen)
warnlen = strlen(warn);
item->tagged = NULL;
}
- if (item->tagged && track_object_refs) {
- struct object_refs *refs = alloc_object_refs(1);
- refs->ref[0] = item->tagged;
- set_object_refs(&item->object, refs);
- }
-
return 0;
}
ce1 = *((const struct cache_entry **)a_);
ce2 = *((const struct cache_entry **)b_);
- return cache_name_compare(ce1->name, ntohs(ce1->ce_flags),
- ce2->name, ntohs(ce2->ce_flags));
+ return cache_name_compare(ce1->name, ce1->ce_flags,
+ ce2->name, ce2->ce_flags);
}
int read_tree(struct tree *tree, int stage, const char **match)
return (struct tree *) obj;
}
- /*
- * NOTE! Tree refs to external git repositories
- * (ie gitlinks) do not count as real references.
- *
- * You don't have to have those repositories
- * available at all, much less have the objects
- * accessible from the current repository.
- */
- static void track_tree_refs(struct tree *item)
- {
- int n_refs = 0, i;
- struct object_refs *refs;
- struct tree_desc desc;
- struct name_entry entry;
-
- /* Count how many entries there are.. */
- init_tree_desc(&desc, item->buffer, item->size);
- while (tree_entry(&desc, &entry)) {
- if (S_ISGITLINK(entry.mode))
- continue;
- n_refs++;
- }
-
- /* Allocate object refs and walk it again.. */
- i = 0;
- refs = alloc_object_refs(n_refs);
- init_tree_desc(&desc, item->buffer, item->size);
- while (tree_entry(&desc, &entry)) {
- struct object *obj;
-
- if (S_ISGITLINK(entry.mode))
- continue;
- if (S_ISDIR(entry.mode))
- obj = &lookup_tree(entry.sha1)->object;
- else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
- obj = &lookup_blob(entry.sha1)->object;
- else {
- warning("in tree %s: entry %s has bad mode %.6o\n",
- sha1_to_hex(item->object.sha1), entry.path, entry.mode);
- obj = lookup_unknown_object(entry.sha1);
- }
- refs->ref[i++] = obj;
- }
- set_object_refs(&item->object, refs);
- }
-
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
{
if (item->object.parsed)
item->buffer = buffer;
item->size = size;
- if (track_object_refs)
- track_tree_refs(item);
return 0;
}
}
setup_revisions(0, NULL, &revs, NULL);
}
- prepare_revision_walk(&revs);
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
return 0;
char hex[41], last_hex[41];
int len;
- track_object_refs = 0;
save_commit_buffer = 0;
for(;;) {
}
if (o->type == OBJ_TAG) {
o = deref_tag(o, refname, 0);
- packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
+ if (o)
+ packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
}
return 0;
}