diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Documentation/git-clone-pack.txt | 64 | ||||
-rw-r--r-- | Documentation/git-clone.txt | 4 | ||||
-rw-r--r-- | Documentation/git-rebase.txt | 20 | ||||
-rw-r--r-- | Documentation/git-receive-pack.txt | 3 | ||||
-rw-r--r-- | Documentation/git-repo-config.txt | 12 | ||||
-rw-r--r-- | Documentation/git-upload-pack.txt | 2 | ||||
-rw-r--r-- | Documentation/git.txt | 6 | ||||
-rw-r--r-- | INSTALL | 2 | ||||
-rw-r--r-- | Makefile | 44 | ||||
-rw-r--r-- | alloc.c | 51 | ||||
-rw-r--r-- | blame.c | 4 | ||||
-rw-r--r-- | blob.c | 2 | ||||
-rw-r--r-- | builtin-apply.c | 6 | ||||
-rw-r--r-- | builtin-diff-files.c | 2 | ||||
-rw-r--r-- | builtin-diff-index.c | 2 | ||||
-rw-r--r-- | builtin-diff-tree.c | 42 | ||||
-rw-r--r-- | builtin-diff.c | 26 | ||||
-rw-r--r-- | builtin-grep.c | 25 | ||||
-rw-r--r-- | builtin-log.c | 4 | ||||
-rw-r--r-- | builtin-mailinfo.c (renamed from mailinfo.c) | 85 | ||||
-rw-r--r-- | builtin-mailsplit.c (renamed from mailsplit.c) | 71 | ||||
-rw-r--r-- | builtin-read-tree.c | 3 | ||||
-rw-r--r-- | builtin-rev-list.c | 64 | ||||
-rw-r--r-- | builtin-stripspace.c (renamed from stripspace.c) | 16 | ||||
-rw-r--r-- | builtin-update-index.c (renamed from update-index.c) | 19 | ||||
-rw-r--r-- | builtin-update-ref.c (renamed from update-ref.c) | 5 | ||||
-rw-r--r-- | builtin-write-tree.c (renamed from write-tree.c) | 68 | ||||
-rw-r--r-- | builtin.h | 15 | ||||
-rw-r--r-- | cache.h | 15 | ||||
-rw-r--r-- | clone-pack.c | 186 | ||||
-rw-r--r-- | commit.c | 23 | ||||
-rw-r--r-- | config.c | 43 | ||||
-rw-r--r-- | connect.c | 5 | ||||
-rw-r--r-- | contrib/git-svn/Makefile | 3 | ||||
-rwxr-xr-x | contrib/git-svn/git-svn.perl | 15 | ||||
-rw-r--r-- | contrib/git-svn/t/t0002-deep-rmdir.sh | 29 | ||||
-rw-r--r-- | convert-objects.c | 22 | ||||
-rw-r--r-- | csum-file.c | 4 | ||||
-rw-r--r-- | daemon.c | 63 | ||||
-rw-r--r-- | diff-delta.c | 5 | ||||
-rw-r--r-- | diff-lib.c | 45 | ||||
-rw-r--r-- | diff.c | 81 | ||||
-rw-r--r-- | diff.h | 3 | ||||
-rw-r--r-- | diffcore-order.c | 2 | ||||
-rw-r--r-- | fetch-clone.c | 71 | ||||
-rw-r--r-- | fetch-pack.c | 22 | ||||
-rwxr-xr-x | git-checkout.sh | 3 | ||||
-rwxr-xr-x | git-rebase.sh | 201 | ||||
-rw-r--r-- | git.c | 8 | ||||
-rw-r--r-- | http-fetch.c | 15 | ||||
-rw-r--r-- | http-push.c | 43 | ||||
-rw-r--r-- | http.c | 4 | ||||
-rw-r--r-- | imap-send.c | 2 | ||||
-rw-r--r-- | merge-index.c | 5 | ||||
-rw-r--r-- | name-rev.c | 19 | ||||
-rw-r--r-- | object-refs.c | 3 | ||||
-rw-r--r-- | object.c | 17 | ||||
-rw-r--r-- | object.h | 13 | ||||
-rw-r--r-- | pack-check.c | 6 | ||||
-rw-r--r-- | pack-objects.c | 8 | ||||
-rw-r--r-- | pack-redundant.c | 18 | ||||
-rw-r--r-- | pager.c | 2 | ||||
-rw-r--r-- | patch-delta.c | 4 | ||||
-rw-r--r-- | pkt-line.c | 8 | ||||
-rw-r--r-- | pkt-line.h | 1 | ||||
-rw-r--r-- | quote.c | 9 | ||||
-rw-r--r-- | read-cache.c | 13 | ||||
-rw-r--r-- | repo-config.c | 37 | ||||
-rw-r--r-- | revision.c | 33 | ||||
-rw-r--r-- | revision.h | 12 | ||||
-rw-r--r-- | sha1_file.c | 29 | ||||
-rw-r--r-- | ssh-fetch.c | 2 | ||||
-rw-r--r-- | t/Makefile | 2 | ||||
-rw-r--r-- | t/annotate-tests.sh | 2 | ||||
-rwxr-xr-x | t/t1300-repo-config.sh | 24 | ||||
-rwxr-xr-x | t/t3402-rebase-merge.sh | 112 | ||||
-rw-r--r-- | tag.c | 6 | ||||
-rw-r--r-- | tree-walk.c | 11 | ||||
-rw-r--r-- | tree.c | 2 | ||||
-rw-r--r-- | upload-pack.c | 253 | ||||
-rw-r--r-- | xdiff/xutils.c | 11 | ||||
-rw-r--r-- | xdiff/xutils.h | 1 |
83 files changed, 1502 insertions, 742 deletions
diff --git a/.gitignore b/.gitignore index afd0876218..65aa939f6b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ git-cherry git-cherry-pick git-clean git-clone -git-clone-pack git-commit git-commit-tree git-convert-objects diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt deleted file mode 100644 index 09f43eefe4..0000000000 --- a/Documentation/git-clone-pack.txt +++ /dev/null @@ -1,64 +0,0 @@ -git-clone-pack(1) -================= - -NAME ----- -git-clone-pack - Clones a repository by receiving packed objects - - -SYNOPSIS --------- -'git-clone-pack' [--exec=<git-upload-pack>] [<host>:]<directory> [<head>...] - -DESCRIPTION ------------ -Clones a repository into the current repository by invoking -'git-upload-pack', possibly on the remote host via ssh, in -the named repository, and stores the sent pack in the local -repository. - -OPTIONS -------- ---exec=<git-upload-pack>:: - Use this to specify the path to 'git-upload-pack' on the - remote side, if it is not found on your $PATH. - Installations of sshd ignore the user's environment - setup scripts for login shells (e.g. .bash_profile) and - your privately installed git may not be found on the system - default $PATH. Another workaround suggested is to set - up your $PATH in ".bashrc", but this flag is for people - who do not want to pay the overhead for non-interactive - shells by having a lean .bashrc file (they set most of - the things up in .bash_profile). - -<host>:: - A remote host that houses the repository. When this - part is specified, 'git-upload-pack' is invoked via - ssh. - -<directory>:: - The repository to sync from. - -<head>...:: - The heads to update. This is relative to $GIT_DIR - (e.g. "HEAD", "refs/heads/master"). When unspecified, - all heads are updated to match the remote repository. -+ -Usually all the refs from existing repository are stored -under the same name in the new repository. Giving explicit -<head> arguments instead writes the object names and refs to -the standard output, just like get-fetch-pack does. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano. - - -GIT ---- -Part of the gitlink:git[7] suite - diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index a90521e513..f973c64313 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -62,7 +62,7 @@ OPTIONS --quiet:: -q:: Operate quietly. This flag is passed to "rsync" and - "git-clone-pack" commands when given. + "git-fetch-pack" commands when given. -n:: No checkout of HEAD is performed after the clone is complete. @@ -85,7 +85,7 @@ OPTIONS --upload-pack <upload-pack>:: -u <upload-pack>:: When given, and the repository to clone from is handled - by 'git-clone-pack', '--exec=<upload-pack>' is passed to + by 'git-fetch-pack', '--exec=<upload-pack>' is passed to the command to specify non-default path for the command run on the other end. diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 08ee4aabaf..c339c4525c 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -7,7 +7,7 @@ git-rebase - Rebase local commits to a new head SYNOPSIS -------- -'git-rebase' [--onto <newbase>] <upstream> [<branch>] +'git-rebase' [--merge] [--onto <newbase>] <upstream> [<branch>] 'git-rebase' --continue | --skip | --abort @@ -106,6 +106,24 @@ OPTIONS --abort:: Restore the original branch and abort the rebase operation. +--skip:: + Restart the rebasing process by skipping the current patch. + This does not work with the --merge option. + +--merge:: + Use merging strategies to rebase. When the recursive (default) merge + strategy is used, this allows rebase to be aware of renames on the + upstream side. + +-s <strategy>, \--strategy=<strategy>:: + Use the given merge strategy; can be supplied more than + once to specify them in the order they should be tried. + If there is no `-s` option, a built-in list of strategies + is used instead (`git-merge-recursive` when merging a single + head, `git-merge-octopus` otherwise). This implies --merge. + +include::merge-strategies.txt[] + NOTES ----- When you rebase a branch, you are changing its history in a way that diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt index 60debca487..f9457d45ed 100644 --- a/Documentation/git-receive-pack.txt +++ b/Documentation/git-receive-pack.txt @@ -18,8 +18,7 @@ information fed from the remote end. This command is usually not invoked directly by the end user. The UI for the protocol is on the 'git-send-pack' side, and the program pair is meant to be used to push updates to remote -repository. For pull operations, see 'git-fetch-pack' and -'git-clone-pack'. +repository. For pull operations, see 'git-fetch-pack'. The command allows for creation and fast forwarding of sha1 refs (heads/tags) on the remote end (strictly speaking, it is the diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index d5142e0dcd..803c0d5cae 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -73,6 +73,18 @@ OPTIONS List all variables set in .git/config. +ENVIRONMENT +----------- + +GIT_CONFIG:: + Take the configuration from the given file instead of .git/config. + +GIT_CONFIG_LOCAL:: + Currently the same as $GIT_CONFIG; when Git will support global + configuration files, this will cause it to take the configuration + from the global configuration file in addition to the given file. + + EXAMPLE ------- diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt index 4795e98754..b2c9307661 100644 --- a/Documentation/git-upload-pack.txt +++ b/Documentation/git-upload-pack.txt @@ -12,7 +12,7 @@ SYNOPSIS DESCRIPTION ----------- -Invoked by 'git-clone-pack' and/or 'git-fetch-pack', learns what +Invoked by 'git-fetch-pack', learns what objects the other side is missing, and sends them after packing. This command is usually not invoked directly by the end user. diff --git a/Documentation/git.txt b/Documentation/git.txt index d4472b56d1..51f20c6e67 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -192,10 +192,6 @@ the working tree. Synching repositories ~~~~~~~~~~~~~~~~~~~~~ -gitlink:git-clone-pack[1]:: - Clones a repository into the current repository (engine - for ssh and local transport). - gitlink:git-fetch-pack[1]:: Updates from a remote repository (engine for ssh and local transport). @@ -237,7 +233,7 @@ gitlink:git-update-server-info[1]:: clients discover references and packs on it. gitlink:git-upload-pack[1]:: - Invoked by 'git-clone-pack' and 'git-fetch-pack' to push + Invoked by 'git-fetch-pack' to push what are asked for. gitlink:git-upload-tar[1]:: @@ -96,7 +96,7 @@ Issues of note: $ mkdir manual && cd manual $ git init-db - $ git clone-pack git://git.kernel.org/pub/scm/git/git.git man html | + $ git fetch-pack git://git.kernel.org/pub/scm/git/git.git man html | while read a b do echo $a >.git/$b @@ -144,34 +144,33 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ # The ones that do not have to link with lcrypto, lz nor xdiff. SIMPLE_PROGRAMS = \ - git-mailsplit$X \ - git-stripspace$X git-daemon$X + git-daemon$X # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ - git-checkout-index$X git-clone-pack$X \ + git-checkout-index$X \ git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \ git-hash-object$X git-index-pack$X git-local-fetch$X \ - git-mailinfo$X git-merge-base$X \ + git-merge-base$X \ git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \ git-peek-remote$X git-prune-packed$X git-receive-pack$X \ git-send-pack$X git-shell$X \ git-show-index$X git-ssh-fetch$X \ git-ssh-upload$X git-unpack-file$X \ - git-unpack-objects$X git-update-index$X git-update-server-info$X \ - git-upload-pack$X git-verify-pack$X git-write-tree$X \ - git-update-ref$X git-symbolic-ref$X \ + git-unpack-objects$X git-update-server-info$X \ + git-upload-pack$X git-verify-pack$X \ + git-symbolic-ref$X \ git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ git-describe$X git-merge-tree$X git-blame$X git-imap-send$X -BUILT_INS = git-log$X git-whatchanged$X git-show$X \ - git-count-objects$X git-diff$X git-push$X \ - git-grep$X git-add$X git-rm$X git-rev-list$X \ - git-check-ref-format$X git-rev-parse$X \ +BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \ + git-count-objects$X git-diff$X git-push$X git-mailsplit$X \ + git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \ + git-check-ref-format$X git-rev-parse$X git-mailinfo$X \ git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \ git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \ - git-read-tree$X git-commit-tree$X \ - git-apply$X git-show-branch$X git-diff-files$X \ + git-read-tree$X git-commit-tree$X git-write-tree$X \ + git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \ git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X # what 'all' will build and 'install' will install, in gitexecdir @@ -216,18 +215,19 @@ LIB_OBJS = \ 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 \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ - $(DIFF_OBJS) + alloc.o $(DIFF_OBJS) BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \ builtin-rm.o builtin-init-db.o builtin-rev-parse.o \ - builtin-tar-tree.o builtin-upload-tar.o \ - builtin-ls-files.o builtin-ls-tree.o \ - builtin-read-tree.o builtin-commit-tree.o \ + builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \ + builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \ + builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \ builtin-apply.o builtin-show-branch.o builtin-diff-files.o \ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \ - builtin-cat-file.o + builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \ + builtin-update-ref.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@ -380,9 +380,7 @@ ifdef NEEDS_LIBICONV else ICONV_LINK = endif - LIB_4_ICONV = $(ICONV_LINK) -liconv -else - LIB_4_ICONV = + LIBS += $(ICONV_LINK) -liconv endif ifdef NEEDS_SOCKET LIBS += -lsocket @@ -565,10 +563,6 @@ $(SIMPLE_PROGRAMS) : git-%$X : %.o $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIB_FILE) $(SIMPLE_LIB) -git-mailinfo$X: mailinfo.o $(LIB_FILE) - $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ - $(LIB_FILE) $(SIMPLE_LIB) $(LIB_4_ICONV) - git-local-fetch$X: fetch.o git-ssh-fetch$X: rsh.o fetch.o git-ssh-upload$X: rsh.o diff --git a/alloc.c b/alloc.c new file mode 100644 index 0000000000..e3b22f4322 --- /dev/null +++ b/alloc.c @@ -0,0 +1,51 @@ +/* + * alloc.c - specialized allocator for internal objects + * + * Copyright (C) 2006 Linus Torvalds + * + * The standard malloc/free wastes too much space for objects, partly because + * it maintains all the allocation infrastructure (which isn't needed, since + * we never free an object descriptor anyway), but even more because it ends + * up with maximal alignment because it doesn't know what the object alignment + * for the new allocation is. + */ +#include "cache.h" +#include "object.h" +#include "blob.h" +#include "tree.h" +#include "commit.h" +#include "tag.h" + +#define BLOCKING 1024 + +#define DEFINE_ALLOCATOR(name) \ +static unsigned int name##_allocs; \ +struct name *alloc_##name##_node(void) \ +{ \ + static int nr; \ + static struct name *block; \ + \ + if (!nr) { \ + nr = BLOCKING; \ + block = xcalloc(BLOCKING, sizeof(struct name)); \ + } \ + nr--; \ + name##_allocs++; \ + return block++; \ +} + +DEFINE_ALLOCATOR(blob) +DEFINE_ALLOCATOR(tree) +DEFINE_ALLOCATOR(commit) +DEFINE_ALLOCATOR(tag) + +#define REPORT(name) \ + fprintf(stderr, "%10s: %8u (%zu kB)\n", #name, name##_allocs, name##_allocs*sizeof(struct name) >> 10) + +void alloc_report(void) +{ + REPORT(blob); + REPORT(tree); + REPORT(commit); + REPORT(tag); +} @@ -301,9 +301,9 @@ static void fill_line_map(struct commit *commit, struct commit *other, if (DEBUG) printf("map: i1: %d %d %p i2: %d %d %p\n", i1, map[i1], - i1 != -1 ? blame_lines[map[i1]] : NULL, + (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL), i2, map2[i2], - i2 != -1 ? blame_lines[map2[i2]] : NULL); + (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL)); if (map2[i2] != -1 && blame_lines[map[i1]] && !blame_lines[map2[i2]]) @@ -8,7 +8,7 @@ struct blob *lookup_blob(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) { - struct blob *ret = xcalloc(1, sizeof(struct blob)); + struct blob *ret = alloc_blob_node(); created_object(sha1, &ret->object); ret->object.type = TYPE_BLOB; return ret; diff --git a/builtin-apply.c b/builtin-apply.c index e113c74dd8..6dd0472ae0 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -148,7 +148,7 @@ static void *read_patch_file(int fd, unsigned long *sizep) buffer = xrealloc(buffer, alloc); nr = alloc - size; } - nr = xread(fd, buffer + size, nr); + nr = xread(fd, (char *) buffer + size, nr); if (!nr) break; if (nr < 0) @@ -164,7 +164,7 @@ static void *read_patch_file(int fd, unsigned long *sizep) */ if (alloc < size + SLOP) buffer = xrealloc(buffer, size + SLOP); - memset(buffer + size, 0, SLOP); + memset((char *) buffer + size, 0, SLOP); return buffer; } @@ -1194,7 +1194,7 @@ static int read_old_data(struct stat *st, const char *path, void *buf, unsigned return error("unable to open %s", path); got = 0; for (;;) { - int ret = xread(fd, buf + got, size - got); + int ret = xread(fd, (char *) buf + got, size - got); if (ret <= 0) break; got += ret; diff --git a/builtin-diff-files.c b/builtin-diff-files.c index cebda828ee..5afc1d7208 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -41,7 +41,7 @@ int cmd_diff_files(int argc, const char **argv, char **envp) * rev.max_count is reasonable (0 <= n <= 3), * there is no other revision filtering parameters. */ - if (rev.pending_objects || + if (rev.pending.nr || rev.min_age != -1 || rev.max_age != -1) usage(diff_files_usage); /* diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 1958580d82..c42ef9a7a7 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -32,7 +32,7 @@ int cmd_diff_index(int argc, const char **argv, char **envp) * Make sure there is one revision (i.e. pending object), * and there is no revision filtering parameters. */ - if (!rev.pending_objects || rev.pending_objects->next || + if (rev.pending.nr != 1 || rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1) usage(diff_cache_usage); return run_diff_index(&rev, cached); diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 58cf65856d..3409a39a9f 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -65,7 +65,6 @@ int cmd_diff_tree(int argc, const char **argv, char **envp) char line[1000]; struct object *tree1, *tree2; static struct rev_info *opt = &log_tree_opt; - struct object_list *list; int read_stdin = 0; git_config(git_diff_config); @@ -86,45 +85,28 @@ int cmd_diff_tree(int argc, const char **argv, char **envp) } /* - * NOTE! "setup_revisions()" will have inserted the revisions - * it parsed in reverse order. So if you do - * - * git-diff-tree a b - * - * the commit list will be "b" -> "a" -> NULL, so we reverse - * the order of the objects if the first one is not marked - * UNINTERESTING. + * NOTE! We expect "a ^b" to be equal to "a..b", so we + * reverse the order of the objects if the second one + * is marked UNINTERESTING. */ - nr_sha1 = 0; - list = opt->pending_objects; - if (list) { - nr_sha1++; - tree1 = list->item; - list = list->next; - if (list) { - nr_sha1++; - tree2 = tree1; - tree1 = list->item; - if (list->next) - usage(diff_tree_usage); - /* Switch them around if the second one was uninteresting.. */ - if (tree2->flags & UNINTERESTING) { - struct object *tmp = tree2; - tree2 = tree1; - tree1 = tmp; - } - } - } - + nr_sha1 = opt->pending.nr; switch (nr_sha1) { case 0: if (!read_stdin) usage(diff_tree_usage); break; case 1: + tree1 = opt->pending.objects[0].item; diff_tree_commit_sha1(tree1->sha1); break; case 2: + tree1 = opt->pending.objects[0].item; + tree2 = opt->pending.objects[1].item; + if (tree2->flags & UNINTERESTING) { + struct object *tmp = tree2; + tree2 = tree1; + tree1 = tmp; + } diff_tree_sha1(tree1->sha1, tree2->sha1, "", &opt->diffopt); diff --git a/builtin-diff.c b/builtin-diff.c index 6ac3d4b8ca..99a2f76605 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -50,7 +50,7 @@ static int builtin_diff_files(struct rev_info *revs, * specified rev.max_count is reasonable (0 <= n <= 3), and * there is no other revision filtering parameter. */ - if (revs->pending_objects || + if (revs->pending.nr || revs->min_age != -1 || revs->max_age != -1 || 3 < revs->max_count) @@ -172,7 +172,7 @@ static int builtin_diff_index(struct rev_info *revs, * Make sure there is one revision (i.e. pending object), * and there is no revision filtering parameters. */ - if (!revs->pending_objects || revs->pending_objects->next || + if (revs->pending.nr != 1 || revs->max_count != -1 || revs->min_age != -1 || revs->max_age != -1) usage(builtin_diff_usage); @@ -181,10 +181,10 @@ static int builtin_diff_index(struct rev_info *revs, static int builtin_diff_tree(struct rev_info *revs, int argc, const char **argv, - struct object_list *ent) + struct object_array_entry *ent) { const unsigned char *(sha1[2]); - int swap = 1; + int swap = 0; while (1 < argc) { const char *arg = argv[1]; if (!strcmp(arg, "--raw")) @@ -195,10 +195,10 @@ static int builtin_diff_tree(struct rev_info *revs, } /* We saw two trees, ent[0] and ent[1]. - * unless ent[0] is unintesting, they are swapped + * if ent[1] is unintesting, they are swapped */ - if (ent[0].item->flags & UNINTERESTING) - swap = 0; + if (ent[1].item->flags & UNINTERESTING) + swap = 1; sha1[swap] = ent[0].item->sha1; sha1[1-swap] = ent[1].item->sha1; diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt); @@ -208,7 +208,7 @@ static int builtin_diff_tree(struct rev_info *revs, static int builtin_diff_combined(struct rev_info *revs, int argc, const char **argv, - struct object_list *ent, + struct object_array_entry *ent, int ents) { const unsigned char (*parent)[20]; @@ -242,13 +242,14 @@ void add_head(struct rev_info *revs) obj = parse_object(sha1); if (!obj) return; - add_object(obj, &revs->pending_objects, NULL, "HEAD"); + add_pending_object(revs, obj, "HEAD"); } int cmd_diff(int argc, const char **argv, char **envp) { + int i; struct rev_info rev; - struct object_list *list, ent[100]; + struct object_array_entry ent[100]; int ents = 0, blobs = 0, paths = 0; const char *path = NULL; struct blobinfo blob[2]; @@ -281,7 +282,7 @@ int cmd_diff(int argc, const char **argv, char **envp) /* Do we have --cached and not have a pending object, then * default to HEAD by hand. Eek. */ - if (!rev.pending_objects) { + if (!rev.pending.nr) { int i; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -294,7 +295,8 @@ int cmd_diff(int argc, const char **argv, char **envp) } } - for (list = rev.pending_objects; list; list = list->next) { + for (i = 0; i < rev.pending.nr; i++) { + struct object_array_entry *list = rev.pending.objects+i; struct object *obj = list->item; const char *name = list->name; int flags = (obj->flags & UNINTERESTING); diff --git a/builtin-grep.c b/builtin-grep.c index 9806499263..2e7986cece 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -29,10 +29,11 @@ static int pathspec_matches(const char **paths, const char *name) int matchlen = strlen(match); const char *cp, *meta; - if ((matchlen <= namelen) && - !strncmp(name, match, matchlen) && - (match[matchlen-1] == '/' || - name[matchlen] == '\0' || name[matchlen] == '/')) + if (!matchlen || + ((matchlen <= namelen) && + !strncmp(name, match, matchlen) && + (match[matchlen-1] == '/' || + name[matchlen] == '\0' || name[matchlen] == '/'))) return 1; if (!fnmatch(match, name, 0)) return 1; @@ -657,7 +658,7 @@ int cmd_grep(int argc, const char **argv, char **envp) int cached = 0; int seen_dashdash = 0; struct grep_opt opt; - struct object_list *list, **tail, *object_list = NULL; + struct object_array list = { 0, 0, NULL }; const char *prefix = setup_git_directory(); const char **paths = NULL; int i; @@ -677,7 +678,6 @@ int cmd_grep(int argc, const char **argv, char **envp) * that continues up to the -- (if exists), and then paths. */ - tail = &object_list; while (1 < argc) { const char *arg = argv[1]; argc--; argv++; @@ -851,12 +851,9 @@ int cmd_grep(int argc, const char **argv, char **envp) /* Is it a rev? */ if (!get_sha1(arg, sha1)) { struct object *object = parse_object(sha1); - struct object_list *elem; if (!object) die("bad object %s", arg); - elem = object_list_insert(object, tail); - elem->name = arg; - tail = &elem->next; + add_object_array(object, arg, &list); continue; } if (!strcmp(arg, "--")) { @@ -881,16 +878,16 @@ int cmd_grep(int argc, const char **argv, char **envp) paths[1] = NULL; } - if (!object_list) + if (!list.nr) return !grep_cache(&opt, paths, cached); if (cached) die("both --cached and trees are given."); - for (list = object_list; list; list = list->next) { + for (i = 0; i < list.nr; i++) { struct object *real_obj; - real_obj = deref_tag(list->item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list->name)) + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, list.objects[i].name)) hit = 1; } return !hit; diff --git a/builtin-log.c b/builtin-log.c index 9187fd337b..5a8a50b81d 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -257,8 +257,8 @@ int cmd_format_patch(int argc, const char **argv, char **envp) output_directory); } - if (rev.pending_objects && rev.pending_objects->next == NULL) { - rev.pending_objects->item->flags |= UNINTERESTING; + if (rev.pending.nr == 1) { + rev.pending.objects[0].item->flags |= UNINTERESTING; add_head(&rev); } diff --git a/mailinfo.c b/builtin-mailinfo.c index d9b74f30de..821642a7af 100644 --- a/mailinfo.c +++ b/builtin-mailinfo.c @@ -12,11 +12,12 @@ #endif #include "git-compat-util.h" #include "cache.h" +#include "builtin.h" -static FILE *cmitmsg, *patchfile; +static FILE *cmitmsg, *patchfile, *fin, *fout; static int keep_subject = 0; -static char *metainfo_charset = NULL; +static const char *metainfo_charset = NULL; static char line[1000]; static char date[1000]; static char name[1000]; @@ -49,7 +50,7 @@ static int bogus_from(char *line) /* This is fallback, so do not bother if we already have an * e-mail address. - */ + */ if (*email) return 0; @@ -322,13 +323,13 @@ static char *cleanup_subject(char *subject) if (remove <= len *2) { subject = p+1; continue; - } + } break; } eatspace(subject); return subject; } -} +} static void cleanup_space(char *buf) { @@ -648,7 +649,7 @@ static void handle_info(void) cleanup_space(email); cleanup_space(sub); - printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", + fprintf(fout, "Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n", name, email, sub, date); } @@ -685,7 +686,7 @@ static int handle_commit_msg(int *seen) continue; fputs(line, cmitmsg); - } while (fgets(line, sizeof(line), stdin) != NULL); + } while (fgets(line, sizeof(line), fin) != NULL); fclose(cmitmsg); cmitmsg = NULL; return 0; @@ -706,7 +707,7 @@ static void handle_patch(void) decode_transfer_encoding(line); fputs(line, patchfile); patch_lines++; - } while (fgets(line, sizeof(line), stdin) != NULL); + } while (fgets(line, sizeof(line), fin) != NULL); } /* multipart boundary and transfer encoding are set up for us, and we @@ -719,7 +720,7 @@ static int handle_multipart_one_part(int *seen) { int n = 0; - while (fgets(line, sizeof(line), stdin) != NULL) { + while (fgets(line, sizeof(line), fin) != NULL) { again: n++; if (is_multipart_boundary(line)) @@ -740,7 +741,7 @@ static void handle_multipart_body(void) int part_num = 0; /* Skip up to the first boundary */ - while (fgets(line, sizeof(line), stdin) != NULL) + while (fgets(line, sizeof(line), fin) != NULL) if (is_multipart_boundary(line)) { part_num = 1; break; @@ -749,7 +750,7 @@ static void handle_multipart_body(void) return; /* We are on boundary line. Start slurping the subhead. */ while (1) { - int hdr = read_one_header_line(line, sizeof(line), stdin); + int hdr = read_one_header_line(line, sizeof(line), fin); if (!hdr) { if (handle_multipart_one_part(&seen) < 0) return; @@ -781,10 +782,45 @@ static void handle_body(void) } } +int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, + const char *msg, const char *patch) +{ + keep_subject = ks; + metainfo_charset = encoding; + fin = in; + fout = out; + + cmitmsg = fopen(msg, "w"); + if (!cmitmsg) { + perror(msg); + return -1; + } + patchfile = fopen(patch, "w"); + if (!patchfile) { + perror(patch); + fclose(cmitmsg); + return -1; + } + while (1) { + int hdr = read_one_header_line(line, sizeof(line), fin); + if (!hdr) { + if (multipart_boundary[0]) + handle_multipart_body(); + else + handle_body(); + handle_info(); + break; + } + check_header_line(line); + } + + return 0; +} + static const char mailinfo_usage[] = "git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info"; -int main(int argc, char **argv) +int cmd_mailinfo(int argc, const char **argv, char **envp) { /* NEEDSWORK: might want to do the optional .git/ directory * discovery @@ -805,27 +841,6 @@ int main(int argc, char **argv) if (argc != 3) usage(mailinfo_usage); - cmitmsg = fopen(argv[1], "w"); - if (!cmitmsg) { - perror(argv[1]); - exit(1); - } - patchfile = fopen(argv[2], "w"); - if (!patchfile) { - perror(argv[2]); - exit(1); - } - while (1) { - int hdr = read_one_header_line(line, sizeof(line), stdin); - if (!hdr) { - if (multipart_boundary[0]) - handle_multipart_body(); - else - handle_body(); - handle_info(); - break; - } - check_header_line(line); - } - return 0; + + return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]); } diff --git a/mailsplit.c b/builtin-mailsplit.c index 70a569c12a..e2a0058435 100644 --- a/mailsplit.c +++ b/builtin-mailsplit.c @@ -12,6 +12,7 @@ #include <string.h> #include <stdio.h> #include "cache.h" +#include "builtin.h" static const char git_mailsplit_usage[] = "git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>..."; @@ -102,14 +103,48 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) exit(1); } -int main(int argc, const char **argv) +int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip) { - int nr = 0, nr_prec = 4; + char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip)); + int ret = -1; + + while (*mbox) { + const char *file = *mbox++; + FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r"); + int file_done = 0; + + if ( !f ) { + error("cannot open mbox %s", file); + goto out; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + if (f == stdin) + break; /* empty stdin is OK */ + error("cannot read mbox %s", file); + goto out; + } + + while (!file_done) { + sprintf(name, "%s/%0*d", dir, nr_prec, ++skip); + file_done = split_one(f, name, allow_bare); + } + + if (f != stdin) + fclose(f); + } + ret = skip; +out: + free(name); + return ret; +} +int cmd_mailsplit(int argc, const char **argv, char **envp) +{ + int nr = 0, nr_prec = 4, ret; int allow_bare = 0; const char *dir = NULL; const char **argp; static const char *stdin_only[] = { "-", NULL }; - char *name; for (argp = argv+1; *argp; argp++) { const char *arg = *argp; @@ -158,31 +193,9 @@ int main(int argc, const char **argv) argp = stdin_only; } - name = xmalloc(strlen(dir) + 2 + 3 * sizeof(nr)); - - while (*argp) { - const char *file = *argp++; - FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r"); - int file_done = 0; - - if ( !f ) - die ("cannot open mbox %s", file); - - if (fgets(buf, sizeof(buf), f) == NULL) { - if (f == stdin) - break; /* empty stdin is OK */ - die("cannot read mbox %s", file); - } - - while (!file_done) { - sprintf(name, "%s/%0*d", dir, nr_prec, ++nr); - file_done = split_one(f, name, allow_bare); - } - - if (f != stdin) - fclose(f); - } + ret = split_mbox(argp, dir, allow_bare, nr_prec, nr); + if (ret != -1) + printf("%d\n", ret); - printf("%d\n", nr); - return 0; + return ret == -1; } diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 04506da892..9a2099d730 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -31,8 +31,7 @@ static int merge_size = 0; static struct object_list *trees = NULL; -static struct cache_entry df_conflict_entry = { -}; +static struct cache_entry df_conflict_entry; struct tree_entry_list { struct tree_entry_list *next; diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 71353eb19d..63bad0e96a 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -99,26 +99,26 @@ static void show_commit(struct commit *commit) } } -static struct object_list **process_blob(struct blob *blob, - struct object_list **p, - struct name_path *path, - const char *name) +static void process_blob(struct blob *blob, + struct object_array *p, + struct name_path *path, + const char *name) { struct object *obj = &blob->object; if (!revs.blob_objects) - return p; + return; if (obj->flags & (UNINTERESTING | SEEN)) - return p; + return; obj->flags |= SEEN; name = strdup(name); - return add_object(obj, p, path, name); + add_object(obj, p, path, name); } -static struct object_list **process_tree(struct tree *tree, - struct object_list **p, - struct name_path *path, - const char *name) +static void process_tree(struct tree *tree, + struct object_array *p, + struct name_path *path, + const char *name) { struct object *obj = &tree->object; struct tree_desc desc; @@ -126,14 +126,14 @@ static struct object_list **process_tree(struct tree *tree, struct name_path me; if (!revs.tree_objects) - return p; + return; if (obj->flags & (UNINTERESTING | SEEN)) - return p; + return; if (parse_tree(tree) < 0) die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; name = strdup(name); - p = add_object(obj, p, path, name); + add_object(obj, p, path, name); me.up = path; me.elem = name; me.elem_len = strlen(name); @@ -143,57 +143,59 @@ static struct object_list **process_tree(struct tree *tree, while (tree_entry(&desc, &entry)) { if (S_ISDIR(entry.mode)) - p = process_tree(lookup_tree(entry.sha1), p, &me, entry.path); + process_tree(lookup_tree(entry.sha1), p, &me, entry.path); else - p = process_blob(lookup_blob(entry.sha1), p, &me, entry.path); + process_blob(lookup_blob(entry.sha1), p, &me, entry.path); } free(tree->buffer); tree->buffer = NULL; - return p; } static void show_commit_list(struct rev_info *revs) { + int i; struct commit *commit; - struct object_list *objects = NULL, **p = &objects, *pending; + struct object_array objects = { 0, 0, NULL }; while ((commit = get_revision(revs)) != NULL) { - p = process_tree(commit->tree, p, NULL, ""); + process_tree(commit->tree, &objects, NULL, ""); show_commit(commit); } - for (pending = revs->pending_objects; pending; pending = pending->next) { + for (i = 0; i < revs->pending.nr; i++) { + struct object_array_entry *pending = revs->pending.objects + i; struct object *obj = pending->item; const char *name = pending->name; if (obj->flags & (UNINTERESTING | SEEN)) continue; if (obj->type == TYPE_TAG) { obj->flags |= SEEN; - p = add_object(obj, p, NULL, name); + add_object_array(obj, name, &objects); continue; } if (obj->type == TYPE_TREE) { - p = process_tree((struct tree *)obj, p, NULL, name); + process_tree((struct tree *)obj, &objects, NULL, name); continue; } if (obj->type == TYPE_BLOB) { - p = process_blob((struct blob *)obj, p, NULL, name); + process_blob((struct blob *)obj, &objects, NULL, name); continue; } die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); } - while (objects) { + for (i = 0; i < objects.nr; i++) { + struct object_array_entry *p = objects.objects + i; + /* An object with name "foo\n0000000..." can be used to * confuse downstream git-pack-objects very badly. */ - const char *ep = strchr(objects->name, '\n'); + const char *ep = strchr(p->name, '\n'); if (ep) { - printf("%s %.*s\n", sha1_to_hex(objects->item->sha1), - (int) (ep - objects->name), - objects->name); + printf("%s %.*s\n", sha1_to_hex(p->item->sha1), + (int) (ep - p->name), + p->name); } else - printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name); - objects = objects->next; + printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name); } } @@ -348,7 +350,7 @@ int cmd_rev_list(int argc, const char **argv, char **envp) if ((!list && (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && - !revs.pending_objects)) || + !revs.pending.nr)) || revs.diff) usage(rev_list_usage); diff --git a/stripspace.c b/builtin-stripspace.c index 65a6346452..2ce1264f7b 100644 --- a/stripspace.c +++ b/builtin-stripspace.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <string.h> #include <ctype.h> +#include "builtin.h" /* * Remove empty lines from the beginning and end. @@ -28,21 +29,21 @@ static int cleanup(char *line) return 1; } -int main(int argc, char **argv) +void stripspace(FILE *in, FILE *out) { int empties = -1; int incomplete = 0; char line[1024]; - while (fgets(line, sizeof(line), stdin)) { + while (fgets(line, sizeof(line), in)) { incomplete = cleanup(line); /* Not just an empty line? */ if (line[0] != '\n') { if (empties > 0) - putchar('\n'); + fputc('\n', out); empties = 0; - fputs(line, stdout); + fputs(line, out); continue; } if (empties < 0) @@ -50,6 +51,11 @@ int main(int argc, char **argv) empties++; } if (incomplete) - putchar('\n'); + fputc('\n', out); +} + +int cmd_stripspace(int argc, const char **argv, char **envp) +{ + stripspace(stdin, stdout); return 0; } diff --git a/update-index.c b/builtin-update-index.c index fbccc4a67b..ef50243452 100644 --- a/update-index.c +++ b/builtin-update-index.c @@ -8,6 +8,7 @@ #include "quote.h" #include "cache-tree.h" #include "tree-walk.h" +#include "builtin.h" /* * Default to not allowing changes to the list of files. The @@ -186,8 +187,6 @@ static void chmod_path(int flip, const char *path) die("git-update-index: cannot chmod %cx '%s'", flip, path); } -static struct lock_file lock_file; - static void update_one(const char *path, const char *prefix, int prefix_length) { const char *p = prefix_path(prefix, prefix_length, path); @@ -238,7 +237,7 @@ static void read_index_info(int line_termination) * (2) mode SP type SP sha1 TAB path * The second format is to stuff git-ls-tree output * into the index file. - * + * * (3) mode SP sha1 SP stage TAB path * This format is to put higher order stages into the * index file and matches git-ls-files --stage output. @@ -477,7 +476,7 @@ static int do_reupdate(int ac, const char **av, return 0; } -int main(int argc, const char **argv) +int cmd_update_index(int argc, const char **argv, char **envp) { int i, newfd, entries, has_errors = 0, line_termination = '\n'; int allow_options = 1; @@ -486,12 +485,16 @@ int main(int argc, const char **argv) int prefix_length = prefix ? strlen(prefix) : 0; char set_executable_bit = 0; unsigned int refresh_flags = 0; + struct lock_file *lock_file; git_config(git_default_config); - newfd = hold_lock_file_for_update(&lock_file, get_index_file()); + /* We can't free this memory, it becomes part of a linked list parsed atexit() */ + lock_file = xcalloc(1, sizeof(struct lock_file)); + + newfd = hold_lock_file_for_update(lock_file, get_index_file()); if (newfd < 0) - die("unable to create new index file"); + die("unable to create new cachefile"); entries = read_cache(); if (entries < 0) @@ -645,9 +648,11 @@ int main(int argc, const char **argv) finish: if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - commit_lock_file(&lock_file)) + commit_lock_file(lock_file)) die("Unable to write new index file"); } + rollback_lock_file(lock_file); + return has_errors ? 1 : 0; } diff --git a/update-ref.c b/builtin-update-ref.c index a1e6bb90fe..00333c7e7c 100644 --- a/update-ref.c +++ b/builtin-update-ref.c @@ -1,10 +1,11 @@ #include "cache.h" #include "refs.h" +#include "builtin.h" static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>] [-m <reason>]"; -int main(int argc, char **argv) +int cmd_update_ref(int argc, const char **argv, char **envp) { const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL; struct ref_lock *lock; @@ -52,5 +53,7 @@ int main(int argc, char **argv) return 1; if (write_ref_sha1(lock, sha1, msg) < 0) return 1; + + /* write_ref_sha1 always unlocks the ref, no need to do it explicitly */ return 0; } diff --git a/write-tree.c b/builtin-write-tree.c index bd07da6183..70e9b6fcc6 100644 --- a/write-tree.c +++ b/builtin-write-tree.c @@ -3,41 +3,24 @@ * * Copyright (C) Linus Torvalds, 2005 */ +#include "builtin.h" #include "cache.h" #include "tree.h" #include "cache-tree.h" -static int missing_ok = 0; -static char *prefix = NULL; - static const char write_tree_usage[] = "git-write-tree [--missing-ok] [--prefix=<prefix>/]"; -static struct lock_file lock_file; - -int main(int argc, char **argv) +int write_tree(unsigned char *sha1, int missing_ok, const char *prefix) { int entries, was_valid, newfd; - setup_git_directory(); + /* We can't free this memory, it becomes part of a linked list parsed atexit() */ + struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - newfd = hold_lock_file_for_update(&lock_file, get_index_file()); - entries = read_cache(); - - while (1 < argc) { - char *arg = argv[1]; - if (!strcmp(arg, "--missing-ok")) - missing_ok = 1; - else if (!strncmp(arg, "--prefix=", 9)) - prefix = arg + 9; - else - die(write_tree_usage); - argc--; argv++; - } - - if (argc > 2) - die("too many options"); + newfd = hold_lock_file_for_update(lock_file, get_index_file()); + entries = read_cache(); if (entries < 0) die("git-write-tree: error reading cache"); @@ -45,6 +28,7 @@ int main(int argc, char **argv) active_cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(active_cache_tree); + if (!was_valid) { if (cache_tree_update(active_cache_tree, active_cache, active_nr, @@ -52,7 +36,7 @@ int main(int argc, char **argv) die("git-write-tree: error building trees"); if (0 <= newfd) { if (!write_cache(newfd, active_cache, active_nr)) - commit_lock_file(&lock_file); + commit_lock_file(lock_file); } /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller @@ -61,12 +45,44 @@ int main(int argc, char **argv) * performance penalty and not a big deal. */ } + if (prefix) { struct cache_tree *subtree = cache_tree_find(active_cache_tree, prefix); - printf("%s\n", sha1_to_hex(subtree->sha1)); + memcpy(sha1, subtree->sha1, 20); } else - printf("%s\n", sha1_to_hex(active_cache_tree->sha1)); + memcpy(sha1, active_cache_tree->sha1, 20); + + rollback_lock_file(lock_file); + return 0; } + +int cmd_write_tree(int argc, const char **argv, char **envp) +{ + int missing_ok = 0, ret; + const char *prefix = NULL; + unsigned char sha1[20]; + + setup_git_directory(); + + while (1 < argc) { + const char *arg = argv[1]; + if (!strcmp(arg, "--missing-ok")) + missing_ok = 1; + else if (!strncmp(arg, "--prefix=", 9)) + prefix = arg + 9; + else + die(write_tree_usage); + argc--; argv++; + } + + if (argc > 2) + die("too many options"); + + ret = write_tree(sha1, missing_ok, prefix); + printf("%s\n", sha1_to_hex(sha1)); + + return ret; +} @@ -1,6 +1,8 @@ #ifndef BUILTIN_H #define BUILTIN_H +#include <stdio.h> + #ifndef PATH_MAX # define PATH_MAX 4096 #endif @@ -45,5 +47,18 @@ extern int cmd_diff_stages(int argc, const char **argv, char **envp); extern int cmd_diff_tree(int argc, const char **argv, char **envp); extern int cmd_cat_file(int argc, const char **argv, char **envp); extern int cmd_rev_parse(int argc, const char **argv, char **envp); +extern int cmd_update_index(int argc, const char **argv, char **envp); +extern int cmd_update_ref(int argc, const char **argv, char **envp); + +extern int cmd_write_tree(int argc, const char **argv, char **envp); +extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix); + +extern int cmd_mailsplit(int argc, const char **argv, char **envp); +extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip); + +extern int cmd_mailinfo(int argc, const char **argv, char **envp); +extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch); +extern int cmd_stripspace(int argc, const char **argv, char **envp); +extern void stripspace(FILE *in, FILE *out); #endif @@ -374,8 +374,8 @@ extern char git_commit_encoding[MAX_ENCODING_LENGTH]; extern int copy_fd(int ifd, int ofd); /* Finish off pack transfer receiving end */ -extern int receive_unpack_pack(int fd[2], const char *me, int quiet); -extern int receive_keep_pack(int fd[2], const char *me, int quiet); +extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int); +extern int receive_keep_pack(int fd[2], const char *me, int quiet, int); /* pager.c */ extern void setup_pager(void); @@ -384,4 +384,15 @@ extern void setup_pager(void); int decode_85(char *dst, char *line, int linelen); void encode_85(char *buf, unsigned char *data, int bytes); +/* alloc.c */ +struct blob; +struct tree; +struct commit; +struct tag; +extern struct blob *alloc_blob_node(void); +extern struct tree *alloc_tree_node(void); +extern struct commit *alloc_commit_node(void); +extern struct tag *alloc_tag_node(void); +extern void alloc_report(void); + #endif /* CACHE_H */ diff --git a/clone-pack.c b/clone-pack.c deleted file mode 100644 index a4370f595f..0000000000 --- a/clone-pack.c +++ /dev/null @@ -1,186 +0,0 @@ -#include "cache.h" -#include "refs.h" -#include "pkt-line.h" - -static const char clone_pack_usage[] = -"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*"; -static const char *exec = "git-upload-pack"; - -static int quiet = 0; - -static void clone_handshake(int fd[2], struct ref *ref) -{ - unsigned char sha1[20]; - - while (ref) { - packet_write(fd[1], "want %s\n", sha1_to_hex(ref->old_sha1)); - ref = ref->next; - } - packet_flush(fd[1]); - - /* We don't have nuttin' */ - packet_write(fd[1], "done\n"); - if (get_ack(fd[0], sha1)) - error("Huh! git-clone-pack got positive ack for %s", sha1_to_hex(sha1)); -} - -static int is_master(struct ref *ref) -{ - return !strcmp(ref->name, "refs/heads/master"); -} - -static void write_one_ref(struct ref *ref) -{ - char *path = git_path("%s", ref->name); - int fd; - char *hex; - - if (!strncmp(ref->name, "refs/", 5) && - check_ref_format(ref->name + 5)) { - error("refusing to create funny ref '%s' locally", ref->name); - return; - } - - if (safe_create_leading_directories(path)) - die("unable to create leading directory for %s", ref->name); - fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666); - if (fd < 0) - die("unable to create ref %s", ref->name); - hex = sha1_to_hex(ref->old_sha1); - hex[40] = '\n'; - if (write(fd, hex, 41) != 41) - die("unable to write ref %s", ref->name); - close(fd); -} - -static void write_refs(struct ref *ref) -{ - struct ref *head = NULL, *head_ptr, *master_ref; - char *head_path; - - /* Upload-pack must report HEAD first */ - if (!strcmp(ref->name, "HEAD")) { - head = ref; - ref = ref->next; - } - head_ptr = NULL; - master_ref = NULL; - while (ref) { - if (is_master(ref)) - master_ref = ref; - if (head && - !memcmp(ref->old_sha1, head->old_sha1, 20) && - !strncmp(ref->name, "refs/heads/",11) && - (!head_ptr || ref == master_ref)) - head_ptr = ref; - - write_one_ref(ref); - ref = ref->next; - } - if (!head) { - fprintf(stderr, "No HEAD in remote.\n"); - return; - } - - head_path = strdup(git_path("HEAD")); - if (!head_ptr) { - /* - * If we had a master ref, and it wasn't HEAD, we need to undo the - * symlink, and write a standalone HEAD. Give a warning, because that's - * really really wrong. - */ - if (master_ref) { - error("HEAD doesn't point to any refs! Making standalone HEAD"); - unlink(head_path); - } - write_one_ref(head); - free(head_path); - return; - } - - /* We reset to the master branch if it's available */ - if (master_ref) - return; - - fprintf(stderr, "Setting HEAD to %s\n", head_ptr->name); - - /* - * Uhhuh. Other end didn't have master. We start HEAD off with - * the first branch with the same value. - */ - if (create_symref(head_path, head_ptr->name) < 0) - die("unable to link HEAD to %s", head_ptr->name); - free(head_path); -} - -static int clone_pack(int fd[2], int nr_match, char **match) -{ - struct ref *refs; - int status; - - get_remote_heads(fd[0], &refs, nr_match, match, 1); - if (!refs) { - packet_flush(fd[1]); - die("no matching remote head"); - } - clone_handshake(fd, refs); - - status = receive_keep_pack(fd, "git-clone-pack", quiet); - if (!quiet) - fprintf(stderr, "\n"); - - if (!status) { - if (nr_match == 0) - write_refs(refs); - else - while (refs) { - printf("%s %s\n", - sha1_to_hex(refs->old_sha1), - refs->name); - refs = refs->next; - } - } - return status; -} - -int main(int argc, char **argv) -{ - int i, ret, nr_heads; - char *dest = NULL, **heads; - int fd[2]; - pid_t pid; - - setup_git_directory(); - - nr_heads = 0; - heads = NULL; - for (i = 1; i < argc; i++) { - char *arg = argv[i]; - - if (*arg == '-') { - if (!strcmp("-q", arg)) { - quiet = 1; - continue; - } - if (!strncmp("--exec=", arg, 7)) { - exec = arg + 7; - continue; - } - usage(clone_pack_usage); - } - dest = arg; - heads = argv + i + 1; - nr_heads = argc - i - 1; - break; - } - if (!dest) - usage(clone_pack_usage); - pid = git_connect(fd, dest, exec); - if (pid < 0) - return 1; - ret = clone_pack(fd, nr_heads, heads); - close(fd[0]); - close(fd[1]); - finish_connect(pid); - return ret; -} @@ -84,7 +84,7 @@ struct commit *lookup_commit(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) { - struct commit *ret = xcalloc(1, sizeof(struct commit)); + struct commit *ret = alloc_commit_node(); created_object(sha1, &ret->object); ret->object.type = TYPE_COMMIT; return ret; @@ -447,7 +447,7 @@ static int add_rfc2047(char *buf, const char *line, int len) memcpy(bp, q_utf8, sizeof(q_utf8)-1); bp += sizeof(q_utf8)-1; for (i = 0; i < len; i++) { - unsigned ch = line[i]; + unsigned ch = line[i] & 0xFF; if (is_rfc2047_special(ch)) { sprintf(bp, "=%02X", ch); bp += 3; @@ -571,10 +571,23 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit * to say this is not a 7-bit ASCII. */ if (fmt == CMIT_FMT_EMAIL && !after_subject) { - int i; - for (i = 0; !plain_non_ascii && msg[i] && i < len; i++) - if (msg[i] & 0x80) + int i, ch, in_body; + + for (in_body = i = 0; (ch = msg[i]) && i < len; i++) { + if (!in_body) { + /* author could be non 7-bit ASCII but + * the log may so; skip over the + * header part first. + */ + if (ch == '\n' && + i + 1 < len && msg[i+1] == '\n') + in_body = 1; + } + else if (ch & 0x80) { plain_non_ascii = 1; + break; + } + } } for (;;) { @@ -317,7 +317,33 @@ int git_config_from_file(config_fn_t fn, const char *filename) int git_config(config_fn_t fn) { - return git_config_from_file(fn, git_path("config")); + int ret = 0; + char *repo_config = NULL; + const char *home = NULL, *filename; + + /* $GIT_CONFIG makes git read _only_ the given config file, + * $GIT_CONFIG_LOCAL will make it process it in addition to the + * global config file, the same way it would the per-repository + * config file otherwise. */ + filename = getenv("GIT_CONFIG"); + if (!filename) { + home = getenv("HOME"); + filename = getenv("GIT_CONFIG_LOCAL"); + if (!filename) + filename = repo_config = strdup(git_path("config")); + } + + if (home) { + char *user_config = strdup(mkpath("%s/.gitconfig", home)); + if (!access(user_config, R_OK)) + ret = git_config_from_file(fn, user_config); + free(user_config); + } + + ret += git_config_from_file(fn, filename); + if (repo_config) + free(repo_config); + return ret; } /* @@ -490,10 +516,19 @@ int git_config_set_multivar(const char* key, const char* value, int i, dot; int fd = -1, in_fd; int ret; - char* config_filename = strdup(git_path("config")); - char* lock_file = strdup(git_path("config.lock")); + char* config_filename; + char* lock_file; const char* last_dot = strrchr(key, '.'); + config_filename = getenv("GIT_CONFIG"); + if (!config_filename) { + config_filename = getenv("GIT_CONFIG_LOCAL"); + if (!config_filename) + config_filename = git_path("config"); + } + config_filename = strdup(config_filename); + lock_file = strdup(mkpath("%s.lock", config_filename)); + /* * Since "key" actually contains the section name and the real * key name separated by a dot, we have to know where the dot is. @@ -600,7 +635,7 @@ int git_config_set_multivar(const char* key, const char* value, * As a side effect, we make sure to transform only a valid * existing config file. */ - if (git_config(store_aux)) { + if (git_config_from_file(store_aux, config_filename)) { fprintf(stderr, "invalid config file\n"); free(store.key); if (store.value_regex != NULL) { @@ -581,6 +581,11 @@ int git_connect(int fd[2], char *url, const char *prog) enum protocol protocol = PROTO_LOCAL; int free_path = 0; + /* Without this we cannot rely on waitpid() to tell + * what happened to our children. + */ + signal(SIGCHLD, SIG_DFL); + host = strstr(url, "://"); if(host) { *host = '\0'; diff --git a/contrib/git-svn/Makefile b/contrib/git-svn/Makefile index 6aedb10f12..7c20946943 100644 --- a/contrib/git-svn/Makefile +++ b/contrib/git-svn/Makefile @@ -29,8 +29,7 @@ git-svn.html : git-svn.txt asciidoc -b xhtml11 -d manpage \ -f ../../Documentation/asciidoc.conf $< test: git-svn - cd t && $(SHELL) ./t0000-contrib-git-svn.sh $(TEST_FLAGS) - cd t && $(SHELL) ./t0001-contrib-git-svn-props.sh $(TEST_FLAGS) + cd t && for i in t????-*.sh; do $(SHELL) ./$$i $(TEST_FLAGS); done # we can test NO_OPTIMIZE_COMMITS independently of LC_ALL full-test: diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl index da0ff9ad8a..7e7f2f0cd9 100755 --- a/contrib/git-svn/git-svn.perl +++ b/contrib/git-svn/git-svn.perl @@ -2841,13 +2841,20 @@ sub rmdirs { exec qw/git-ls-tree --name-only -r -z/, $self->{c} or croak $!; } local $/ = "\0"; + my @svn_path = split m#/#, $self->{svn_path}; while (<$fh>) { chomp; - $_ = $self->{svn_path} . '/' . $_; - my ($dn) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#); - delete $rm->{$dn}; - last unless %$rm; + my @dn = (@svn_path, (split m#/#, $_)); + while (pop @dn) { + delete $rm->{join '/', @dn}; + } + unless (%$rm) { + close $fh; + return; + } } + close $fh; + my ($r, $p, $bat) = ($self->{r}, $self->{pool}, $self->{bat}); foreach my $d (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$rm) { $self->close_directory($bat->{$d}, $p); diff --git a/contrib/git-svn/t/t0002-deep-rmdir.sh b/contrib/git-svn/t/t0002-deep-rmdir.sh new file mode 100644 index 0000000000..d693d183c8 --- /dev/null +++ b/contrib/git-svn/t/t0002-deep-rmdir.sh @@ -0,0 +1,29 @@ +test_description='git-svn rmdir' +. ./lib-git-svn.sh + +test_expect_success 'initialize repo' " + mkdir import && + cd import && + mkdir -p deeply/nested/directory/number/1 && + mkdir -p deeply/nested/directory/number/2 && + echo foo > deeply/nested/directory/number/1/file && + echo foo > deeply/nested/directory/number/2/another && + svn import -m 'import for git-svn' . $svnrepo && + cd .. + " + +test_expect_success 'mirror via git-svn' " + git-svn init $svnrepo && + git-svn fetch && + git checkout -f -b test-rmdir remotes/git-svn + " + +test_expect_success 'Try a commit on rmdir' " + git rm -f deeply/nested/directory/number/2/another && + git commit -a -m 'remove another' && + git-svn commit --rmdir HEAD && + svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1 + " + + +test_done diff --git a/convert-objects.c b/convert-objects.c index a67d6b479e..0fabd8981c 100644 --- a/convert-objects.c +++ b/convert-objects.c @@ -103,12 +103,12 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base if (!slash) { newlen += sprintf(new + newlen, "%o %s", mode, path); new[newlen++] = '\0'; - memcpy(new + newlen, buffer + len - 20, 20); + memcpy(new + newlen, (char *) buffer + len - 20, 20); newlen += 20; used += len; size -= len; - buffer += len; + buffer = (char *) buffer + len; continue; } @@ -121,7 +121,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base used += len; size -= len; - buffer += len; + buffer = (char *) buffer + len; } write_sha1_file(new, newlen, tree_type, result_sha1); @@ -137,13 +137,13 @@ static void convert_tree(void *buffer, unsigned long size, unsigned char *result while (size) { int len = 1+strlen(buffer); - convert_binary_sha1(buffer + len); + convert_binary_sha1((char *) buffer + len); len += 20; if (len > size) die("corrupt tree object"); size -= len; - buffer += len; + buffer = (char *) buffer + len; } write_subdirectory(orig_buffer, orig_size, "", 0, result_sha1); @@ -244,14 +244,14 @@ static void convert_date(void *buffer, unsigned long size, unsigned char *result // "tree <sha1>\n" memcpy(new + newlen, buffer, 46); newlen += 46; - buffer += 46; + buffer = (char *) buffer + 46; size -= 46; // "parent <sha1>\n" while (!memcmp(buffer, "parent ", 7)) { memcpy(new + newlen, buffer, 48); newlen += 48; - buffer += 48; + buffer = (char *) buffer + 48; size -= 48; } @@ -275,11 +275,11 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu if (memcmp(buffer, "tree ", 5)) die("Bad commit '%s'", (char*) buffer); - convert_ascii_sha1(buffer+5); - buffer += 46; /* "tree " + "hex sha1" + "\n" */ + convert_ascii_sha1((char *) buffer + 5); + buffer = (char *) buffer + 46; /* "tree " + "hex sha1" + "\n" */ while (!memcmp(buffer, "parent ", 7)) { - convert_ascii_sha1(buffer+7); - buffer += 48; + convert_ascii_sha1((char *) buffer + 7); + buffer = (char *) buffer + 48; } convert_date(orig_buffer, orig_size, result_sha1); } diff --git a/csum-file.c b/csum-file.c index 5f9249aeed..ebaad0397f 100644 --- a/csum-file.c +++ b/csum-file.c @@ -17,7 +17,7 @@ static int sha1flush(struct sha1file *f, unsigned int count) for (;;) { int ret = xwrite(f->fd, buf, count); if (ret > 0) { - buf += ret; + buf = (char *) buf + ret; count -= ret; if (count) continue; @@ -57,7 +57,7 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count) memcpy(f->buffer + offset, buf, nr); count -= nr; offset += nr; - buf += nr; + buf = (char *) buf + nr; left -= nr; if (!left) { SHA1_Update(&f->ctx, f->buffer, offset); @@ -264,11 +264,34 @@ static int upload(char *dir) return -1; } -static int execute(void) +static int execute(struct sockaddr *addr) { static char line[1000]; int pktlen, len; + if (addr) { + char addrbuf[256] = ""; + int port = -1; + + if (addr->sa_family == AF_INET) { + struct sockaddr_in *sin_addr = (void *) addr; + inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf)); + port = sin_addr->sin_port; +#ifndef NO_IPV6 + } else if (addr && addr->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6_addr = (void *) addr; + + char *buf = addrbuf; + *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */ + inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1); + strcat(buf, "]"); + + port = sin6_addr->sin6_port; +#endif + } + loginfo("Connection from %s:%d", addrbuf, port); + } + alarm(init_timeout ? init_timeout : timeout); pktlen = packet_read_line(0, line, sizeof(line)); alarm(0); @@ -414,8 +437,6 @@ static void check_max_connections(void) static void handle(int incoming, struct sockaddr *addr, int addrlen) { pid_t pid = fork(); - char addrbuf[256] = ""; - int port = -1; if (pid) { unsigned idx; @@ -436,26 +457,7 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen) dup2(incoming, 1); close(incoming); - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin_addr = (void *) addr; - inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf)); - port = sin_addr->sin_port; - -#ifndef NO_IPV6 - } else if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6_addr = (void *) addr; - - char *buf = addrbuf; - *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */ - inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1); - strcat(buf, "]"); - - port = sin6_addr->sin6_port; -#endif - } - loginfo("Connection from %s:%d", addrbuf, port); - - exit(execute()); + exit(execute(addr)); } static void child_handler(int signo) @@ -671,6 +673,11 @@ int main(int argc, char **argv) int inetd_mode = 0; int i; + /* Without this we cannot rely on waitpid() to tell + * what happened to our children. + */ + signal(SIGCHLD, SIG_DFL); + for (i = 1; i < argc; i++) { char *arg = argv[i]; @@ -751,8 +758,16 @@ int main(int argc, char **argv) } if (inetd_mode) { + struct sockaddr_storage ss; + struct sockaddr *peer = (struct sockaddr *)&ss; + socklen_t slen = sizeof(ss); + fclose(stderr); //FIXME: workaround - return execute(); + + if (getpeername(0, peer, &slen)) + peer = NULL; + + return execute(peer); } return serve(port); diff --git a/diff-delta.c b/diff-delta.c index 25a798d050..8b9172aa2e 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -22,6 +22,7 @@ #include <string.h> #include "delta.h" +#include "git-compat-util.h" /* maximum hash entry list for the same hash bucket */ #define HASH_LIMIT 64 @@ -131,7 +132,7 @@ struct delta_index { const void *src_buf; unsigned long src_size; unsigned int hash_mask; - struct index_entry *hash[0]; + struct index_entry *hash[FLEX_ARRAY]; }; struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) @@ -283,7 +284,7 @@ create_delta(const struct delta_index *index, ref_data = index->src_buf; ref_top = ref_data + index->src_size; data = trg_buf; - top = trg_buf + trg_size; + top = (const unsigned char *) trg_buf + trg_size; outpos++; val = 0; diff --git a/diff-lib.c b/diff-lib.c index 2183b41b03..116b5a9d68 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -34,21 +34,23 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) continue; if (ce_stage(ce)) { - struct { - struct combine_diff_path p; - struct combine_diff_parent filler[5]; - } combine; + struct combine_diff_path *dpath; int num_compare_stages = 0; + size_t path_len; - combine.p.next = NULL; - combine.p.len = ce_namelen(ce); - combine.p.path = xmalloc(combine.p.len + 1); - memcpy(combine.p.path, ce->name, combine.p.len); - combine.p.path[combine.p.len] = 0; - combine.p.mode = 0; - memset(combine.p.sha1, 0, 20); - memset(&combine.p.parent[0], 0, - sizeof(combine.filler)); + path_len = ce_namelen(ce); + + dpath = xmalloc (combine_diff_path_size (5, path_len)); + dpath->path = (char *) &(dpath->parent[5]); + + dpath->next = NULL; + dpath->len = path_len; + memcpy(dpath->path, ce->name, path_len); + dpath->path[path_len] = '\0'; + dpath->mode = 0; + memset(dpath->sha1, 0, 20); + memset(&(dpath->parent[0]), 0, + sizeof(struct combine_diff_parent)*5); while (i < entries) { struct cache_entry *nce = active_cache[i]; @@ -64,11 +66,11 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) if (2 <= stage) { int mode = ntohl(nce->ce_mode); num_compare_stages++; - memcpy(combine.p.parent[stage-2].sha1, + memcpy(dpath->parent[stage-2].sha1, nce->sha1, 20); - combine.p.parent[stage-2].mode = + dpath->parent[stage-2].mode = canon_mode(mode); - combine.p.parent[stage-2].status = + dpath->parent[stage-2].status = DIFF_STATUS_MODIFIED; } @@ -83,13 +85,14 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) i--; if (revs->combine_merges && num_compare_stages == 2) { - show_combined_diff(&combine.p, 2, + show_combined_diff(dpath, 2, revs->dense_combined_merges, revs); - free(combine.p.path); + free(dpath); continue; } - free(combine.p.path); + free(dpath); + dpath = NULL; /* * Show the diff for the 'ce' if we found the one @@ -329,8 +332,8 @@ int run_diff_index(struct rev_info *revs, int cached) } mark_merge_entries(); - ent = revs->pending_objects->item; - tree_name = revs->pending_objects->name; + ent = revs->pending.objects[0].item; + tree_name = revs->pending.objects[0].name; tree = parse_tree_indirect(ent->sha1); if (!tree) return error("bad tree object %s", tree_name); @@ -25,6 +25,20 @@ int git_diff_config(const char *var, const char *value) return git_default_config(var, value); } +enum color_diff { + DIFF_PLAIN = 0, + DIFF_METAINFO = 1, + DIFF_FILE_OLD = 2, + DIFF_FILE_NEW = 3, +}; + +static const char *diff_colors[] = { + "\033[0;0m", + "\033[1;35m", + "\033[1;31m", + "\033[1;34m", +}; + static char *quote_one(const char *str) { int needlen; @@ -177,23 +191,54 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) } struct emit_callback { + struct xdiff_emit_state xm; + int nparents, color_diff; const char **label_path; }; -static int fn_out(void *priv, mmbuffer_t *mb, int nbuf) +static inline void color_diff(int diff_use_color, enum color_diff ix) +{ + if (diff_use_color) + fputs(diff_colors[ix], stdout); +} + +static void fn_out_consume(void *priv, char *line, unsigned long len) { int i; struct emit_callback *ecbdata = priv; if (ecbdata->label_path[0]) { + color_diff(ecbdata->color_diff, DIFF_METAINFO); printf("--- %s\n", ecbdata->label_path[0]); + color_diff(ecbdata->color_diff, DIFF_METAINFO); printf("+++ %s\n", ecbdata->label_path[1]); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } - for (i = 0; i < nbuf; i++) - if (!fwrite(mb[i].ptr, mb[i].size, 1, stdout)) - return -1; - return 0; + + /* This is not really necessary for now because + * this codepath only deals with two-way diffs. + */ + for (i = 0; i < len && line[i] == '@'; i++) + ; + if (2 <= i && i < len && line[i] == ' ') { + ecbdata->nparents = i - 1; + color_diff(ecbdata->color_diff, DIFF_METAINFO); + } + else if (len < ecbdata->nparents) + color_diff(ecbdata->color_diff, DIFF_PLAIN); + else { + int nparents = ecbdata->nparents; + int color = DIFF_PLAIN; + for (i = 0; i < nparents && len; i++) { + if (line[i] == '-') + color = DIFF_FILE_OLD; + else if (line[i] == '+') + color = DIFF_FILE_NEW; + } + color_diff(ecbdata->color_diff, color); + } + fwrite(line, len, 1, stdout); + color_diff(ecbdata->color_diff, DIFF_PLAIN); } static char *pprint_rename(const char *a, const char *b) @@ -515,7 +560,7 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two) else line[0] = bytes - 26 + 'a' - 1; encode_85(line + 1, cp, bytes); - cp += bytes; + cp = (char *) cp + bytes; puts(line); } printf("\n"); @@ -549,25 +594,35 @@ static void builtin_diff(const char *name_a, b_two = quote_two("b/", name_b); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; + color_diff(o->color_diff, DIFF_METAINFO); printf("diff --git %s %s\n", a_one, b_two); if (lbl[0][0] == '/') { /* /dev/null */ + color_diff(o->color_diff, DIFF_METAINFO); printf("new file mode %06o\n", two->mode); - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } } else if (lbl[1][0] == '/') { printf("deleted file mode %06o\n", one->mode); - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } } else { if (one->mode != two->mode) { + color_diff(o->color_diff, DIFF_METAINFO); printf("old mode %06o\n", one->mode); + color_diff(o->color_diff, DIFF_METAINFO); printf("new mode %06o\n", two->mode); } - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } /* * we do not run diff between different kind * of objects. @@ -575,6 +630,7 @@ static void builtin_diff(const char *name_a, if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite) { + color_diff(o->color_diff, DIFF_PLAIN); emit_rewrite_diff(name_a, name_b, one, two); goto free_ab_and_return; } @@ -602,7 +658,9 @@ static void builtin_diff(const char *name_a, xdemitcb_t ecb; struct emit_callback ecbdata; + memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.label_path = lbl; + ecbdata.color_diff = o->color_diff; xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; @@ -612,8 +670,9 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!strncmp(diffopts, "-u", 2)) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecb.outf = fn_out; + ecb.outf = xdiff_outf; ecb.priv = &ecbdata; + ecbdata.xm.consume = fn_out_consume; xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } @@ -1456,6 +1515,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (40 < options->abbrev) options->abbrev = 40; } + else if (!strcmp(arg, "--color")) + options->color_diff = 1; else return 0; return 1; @@ -32,7 +32,8 @@ struct diff_options { full_index:1, silent_on_remove:1, find_copies_harder:1, - summary:1; + summary:1, + color_diff:1; int context; int break_opt; int detect_rename; diff --git a/diffcore-order.c b/diffcore-order.c index 0bc2b22f84..aef6da6044 100644 --- a/diffcore-order.c +++ b/diffcore-order.c @@ -30,7 +30,7 @@ static void prepare_order(const char *orderfile) close(fd); if (map == MAP_FAILED) return; - endp = map + st.st_size; + endp = (char *) map + st.st_size; for (pass = 0; pass < 2; pass++) { cnt = 0; cp = map; diff --git a/fetch-clone.c b/fetch-clone.c index da1b3ffbaa..c16b0c481b 100644 --- a/fetch-clone.c +++ b/fetch-clone.c @@ -1,5 +1,6 @@ #include "cache.h" #include "exec_cmd.h" +#include "pkt-line.h" #include <sys/wait.h> #include <sys/time.h> @@ -23,7 +24,7 @@ static int finish_pack(const char *pack_tmp_name, const char *me) pid = fork(); if (pid < 0) - die("git-clone-pack: unable to fork off git-index-pack"); + die("%s: unable to fork off git-index-pack", me); if (!pid) { close(0); dup2(pipe_fd[1], 1); @@ -94,11 +95,69 @@ static int finish_pack(const char *pack_tmp_name, const char *me) exit(1); } -int receive_unpack_pack(int fd[2], const char *me, int quiet) +static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2]) +{ + pid_t side_pid; + + if (!sideband) { + fd[0] = xd[0]; + fd[1] = xd[1]; + return 0; + } + /* xd[] is talking with upload-pack; subprocess reads from + * xd[0], spits out band#2 to stderr, and feeds us band#1 + * through our fd[0]. + */ + if (pipe(fd) < 0) + die("%s: unable to set up pipe", me); + side_pid = fork(); + if (side_pid < 0) + die("%s: unable to fork off sideband demultiplexer", me); + if (!side_pid) { + /* subprocess */ + close(fd[0]); + if (xd[0] != xd[1]) + close(xd[1]); + while (1) { + char buf[1024]; + int len = packet_read_line(xd[0], buf, sizeof(buf)); + if (len == 0) + break; + if (len < 1) + die("%s: protocol error: no band designator", + me); + len--; + switch (buf[0] & 0xFF) { + case 3: + safe_write(2, buf+1, len); + fprintf(stderr, "\n"); + exit(1); + case 2: + safe_write(2, buf+1, len); + continue; + case 1: + safe_write(fd[1], buf+1, len); + continue; + default: + die("%s: protocol error: bad band #%d", + me, (buf[0] & 0xFF)); + } + } + exit(0); + } + close(xd[0]); + close(fd[1]); + fd[1] = xd[1]; + return side_pid; +} + +int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband) { int status; - pid_t pid; + pid_t pid, side_pid; + int fd[2]; + side_pid = setup_sideband(sideband, me, fd, xd); pid = fork(); if (pid < 0) die("%s: unable to fork off git-unpack-objects", me); @@ -147,10 +206,10 @@ int receive_unpack_pack(int fd[2], const char *me, int quiet) */ #define usec_to_binarymsec(x) ((int)(x) / (1000512 >> 10)) -int receive_keep_pack(int fd[2], const char *me, int quiet) +int receive_keep_pack(int xd[2], const char *me, int quiet, int sideband) { char tmpfile[PATH_MAX]; - int ofd, ifd; + int ofd, ifd, fd[2]; unsigned long total; static struct timeval prev_tv; struct average { @@ -160,6 +219,8 @@ int receive_keep_pack(int fd[2], const char *me, int quiet) unsigned long avg_bytes, avg_time; int idx = 0; + setup_sideband(sideband, me, fd, xd); + ifd = fd[0]; snprintf(tmpfile, sizeof(tmpfile), "%s/pack/tmp-XXXXXX", get_object_directory()); diff --git a/fetch-pack.c b/fetch-pack.c index 7d23a8071a..f2c51ebe4b 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -25,7 +25,7 @@ static const char *exec = "git-upload-pack"; #define MAX_IN_VAIN 256 static struct commit_list *rev_list = NULL; -static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0; +static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0, use_sideband; static void rev_list_push(struct commit *commit, int mark) { @@ -165,9 +165,14 @@ static int find_common(int fd[2], unsigned char *result_sha1, continue; } - packet_write(fd[1], "want %s%s%s\n", sha1_to_hex(remote), - (multi_ack ? " multi_ack" : ""), - (use_thin_pack ? " thin-pack" : "")); + if (!fetching) + packet_write(fd[1], "want %s%s%s%s\n", + sha1_to_hex(remote), + (multi_ack ? " multi_ack" : ""), + (use_sideband ? " side-band" : ""), + (use_thin_pack ? " thin-pack" : "")); + else + packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); fetching++; } packet_flush(fd[1]); @@ -421,6 +426,11 @@ static int fetch_pack(int fd[2], int nr_match, char **match) fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } + if (server_supports("side-band")) { + if (verbose) + fprintf(stderr, "Server supports side-band\n"); + use_sideband = 1; + } if (!ref) { packet_flush(fd[1]); die("no matching remote head"); @@ -437,9 +447,9 @@ static int fetch_pack(int fd[2], int nr_match, char **match) fprintf(stderr, "warning: no common commits\n"); if (keep_pack) - status = receive_keep_pack(fd, "git-fetch-pack", quiet); + status = receive_keep_pack(fd, "git-fetch-pack", quiet, use_sideband); else - status = receive_unpack_pack(fd, "git-fetch-pack", quiet); + status = receive_unpack_pack(fd, "git-fetch-pack", quiet, use_sideband); if (status) die("git-fetch-pack: fetch failed."); diff --git a/git-checkout.sh b/git-checkout.sh index 564117f006..77c2593809 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -137,8 +137,7 @@ fi if [ "$force" ] then - git-read-tree --reset $new && - git-checkout-index -q -f -u -a + git-read-tree --reset -u $new else git-update-index --refresh >/dev/null merge_error=$(git-read-tree -m -u $old $new 2>&1) || ( diff --git a/git-rebase.sh b/git-rebase.sh index e6b57b8ab9..b9ce1125d8 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -34,7 +34,96 @@ When you have resolved this problem run \"git rebase --continue\". If you would prefer to skip this patch, instead run \"git rebase --skip\". To restore the original branch and stop rebasing run \"git rebase --abort\". " + +MRESOLVEMSG=" +When you have resolved this problem run \"git rebase --continue\". +To restore the original branch and stop rebasing run \"git rebase --abort\". +" unset newbase +strategy=recursive +do_merge= +dotest=$GIT_DIR/.dotest-merge +prec=4 + +continue_merge () { + test -n "$prev_head" || die "prev_head must be defined" + test -d "$dotest" || die "$dotest directory does not exist" + + unmerged=$(git-ls-files -u) + if test -n "$unmerged" + then + echo "You still have unmerged paths in your index" + echo "did you forget update-index?" + die "$MRESOLVEMSG" + fi + + if test -n "`git-diff-index HEAD`" + then + git-commit -C "`cat $dotest/current`" + else + echo "Previous merge succeeded automatically" + fi + + prev_head=`git-rev-parse HEAD^0` + + # save the resulting commit so we can read-tree on it later + echo "$prev_head" > "$dotest/`printf %0${prec}d $msgnum`.result" + echo "$prev_head" > "$dotest/prev_head" + + # onto the next patch: + msgnum=$(($msgnum + 1)) + printf "%0${prec}d" "$msgnum" > "$dotest/msgnum" +} + +call_merge () { + cmt="$(cat $dotest/`printf %0${prec}d $1`)" + echo "$cmt" > "$dotest/current" + git-merge-$strategy "$cmt^" -- HEAD "$cmt" + rv=$? + case "$rv" in + 0) + git-commit -C "$cmt" || die "commit failed: $MRESOLVEMSG" + ;; + 1) + test -d "$GIT_DIR/rr-cache" && git-rerere + die "$MRESOLVEMSG" + ;; + 2) + echo "Strategy: $rv $strategy failed, try another" 1>&2 + die "$MRESOLVEMSG" + ;; + *) + die "Unknown exit code ($rv) from command:" \ + "git-merge-$strategy $cmt^ -- HEAD $cmt" + ;; + esac +} + +finish_rb_merge () { + set -e + + msgnum=1 + echo "Finalizing rebased commits..." + git-reset --hard "`cat $dotest/onto`" + end="`cat $dotest/end`" + while test "$msgnum" -le "$end" + do + msgnum=`printf "%0${prec}d" "$msgnum"` + printf "%0${prec}d" "$msgnum" > "$dotest/msgnum" + + git-read-tree `cat "$dotest/$msgnum.result"` + git-checkout-index -q -f -u -a + git-commit -C "`cat $dotest/$msgnum`" + + echo "Committed $msgnum" + echo ' '`git-rev-list --pretty=oneline -1 HEAD | \ + sed 's/^[a-f0-9]\+ //'` + msgnum=$(($msgnum + 1)) + done + rm -r "$dotest" + echo "All done." +} + while case "$#" in 0) break ;; esac do case "$1" in @@ -46,17 +135,43 @@ do exit 1 ;; esac + if test -d "$dotest" + then + prev_head="`cat $dotest/prev_head`" + end="`cat $dotest/end`" + msgnum="`cat $dotest/msgnum`" + onto="`cat $dotest/onto`" + continue_merge + while test "$msgnum" -le "$end" + do + call_merge "$msgnum" + continue_merge + done + finish_rb_merge + exit + fi git am --resolved --3way --resolvemsg="$RESOLVEMSG" exit ;; --skip) + if test -d "$dotest" + then + die "--skip is not supported when using --merge" + fi git am -3 --skip --resolvemsg="$RESOLVEMSG" exit ;; --abort) - [ -d .dotest ] || die "No rebase in progress?" + if test -d "$dotest" + then + rm -r "$dotest" + elif test -d .dotest + then + rm -r .dotest + else + die "No rebase in progress?" + fi git reset --hard ORIG_HEAD - rm -r .dotest exit ;; --onto) @@ -64,6 +179,23 @@ do newbase="$2" shift ;; + -M|-m|--m|--me|--mer|--merg|--merge) + do_merge=t + ;; + -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ + --strateg=*|--strategy=*|\ + -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) + case "$#,$1" in + *,*=*) + strategy=`expr "$1" : '-[^=]*=\(.*\)'` ;; + 1,*) + usage ;; + *) + strategy="$2" + shift ;; + esac + do_merge=t + ;; -*) usage ;; @@ -75,16 +207,25 @@ do done # Make sure we do not have .dotest -if mkdir .dotest +if test -z "$do_merge" then - rmdir .dotest -else - echo >&2 ' + if mkdir .dotest + then + rmdir .dotest + else + echo >&2 ' It seems that I cannot create a .dotest directory, and I wonder if you are in the middle of patch application or another rebase. If that is not the case, please rm -fr .dotest and run me again. I am stopping in case you still have something valuable there.' - exit 1 + exit 1 + fi +else + if test -d "$dotest" + then + die "previous dotest directory $dotest still exists." \ + 'try git-rebase < --continue | --abort >' + fi fi # The tree must be really really clean. @@ -152,6 +293,48 @@ then exit 0 fi -git-format-patch -k --stdout --full-index "$upstream"..ORIG_HEAD | -git am --binary -3 -k --resolvemsg="$RESOLVEMSG" +if test -z "$do_merge" +then + git-format-patch -k --stdout --full-index "$upstream"..ORIG_HEAD | + git am --binary -3 -k --resolvemsg="$RESOLVEMSG" + exit $? +fi + +if test "@@NO_PYTHON@@" && test "$strategy" = "recursive" +then + die 'The recursive merge strategy currently relies on Python, +which this installation of git was not configured with. Please consider +a different merge strategy (e.g. octopus, resolve, stupid, ours) +or install Python and git with Python support.' + +fi + +# start doing a rebase with git-merge +# this is rename-aware if the recursive (default) strategy is used + +mkdir -p "$dotest" +echo "$onto" > "$dotest/onto" +prev_head=`git-rev-parse HEAD^0` +echo "$prev_head" > "$dotest/prev_head" + +msgnum=0 +for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \ + | perl -e 'print reverse <>'` +do + msgnum=$(($msgnum + 1)) + echo "$cmt" > "$dotest/`printf "%0${prec}d" $msgnum`" +done + +printf "%0${prec}d" 1 > "$dotest/msgnum" +printf "%0${prec}d" "$msgnum" > "$dotest/end" + +end=$msgnum +msgnum=1 + +while test "$msgnum" -le "$end" +do + call_merge "$msgnum" + continue_merge +done +finish_rb_merge @@ -178,7 +178,13 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "diff-stages", cmd_diff_stages }, { "diff-tree", cmd_diff_tree }, { "cat-file", cmd_cat_file }, - { "rev-parse", cmd_rev_parse } + { "rev-parse", cmd_rev_parse }, + { "write-tree", cmd_write_tree }, + { "mailsplit", cmd_mailsplit }, + { "mailinfo", cmd_mailinfo }, + { "stripspace", cmd_stripspace }, + { "update-index", cmd_update_index }, + { "update-ref", cmd_update_ref } }; int i; diff --git a/http-fetch.c b/http-fetch.c index da1a7f5416..2b63d89501 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -123,7 +123,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, struct object_request *obj_req = (struct object_request *)data; do { ssize_t retval = write(obj_req->local, - ptr + posn, size - posn); + (char *) ptr + posn, size - posn); if (retval < 0) return posn; posn += retval; @@ -1136,13 +1136,14 @@ int fetch(unsigned char *sha1) static inline int needs_quote(int ch) { - switch (ch) { - case '/': case '-': case '.': - case 'A'...'Z': case 'a'...'z': case '0'...'9': + if (((ch >= 'A') && (ch <= 'Z')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= '0') && (ch <= '9')) + || (ch == '/') + || (ch == '-') + || (ch == '.')) return 0; - default: - return 1; - } + return 1; } static inline int hex(int v) diff --git a/http-push.c b/http-push.c index ba64f8fff5..8d472f0202 100644 --- a/http-push.c +++ b/http-push.c @@ -196,7 +196,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, struct transfer_request *request = (struct transfer_request *)data; do { ssize_t retval = write(request->local_fileno, - ptr + posn, size - posn); + (char *) ptr + posn, size - posn); if (retval < 0) return posn; posn += retval; @@ -1077,13 +1077,14 @@ static int fetch_indices(void) static inline int needs_quote(int ch) { - switch (ch) { - case '/': case '-': case '.': - case 'A'...'Z': case 'a'...'z': case '0'...'9': + if (((ch >= 'A') && (ch <= 'Z')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= '0') && (ch <= '9')) + || (ch == '/') + || (ch == '-') + || (ch == '.')) return 0; - default: - return 1; - } + return 1; } static inline int hex(int v) @@ -1171,7 +1172,7 @@ static void one_remote_object(const char *hex) obj->flags |= REMOTE; if (!object_list_contains(objects, obj)) - add_object(obj, &objects, NULL, ""); + object_list_insert(obj, &objects); } static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed) @@ -1699,6 +1700,15 @@ static int locking_available(void) return lock_flags; } +struct object_list **add_one_object(struct object *obj, struct object_list **p) +{ + struct object_list *entry = xmalloc(sizeof(struct object_list)); + entry->item = obj; + entry->next = *p; + *p = entry; + return &entry->next; +} + static struct object_list **process_blob(struct blob *blob, struct object_list **p, struct name_path *path, @@ -1712,8 +1722,7 @@ static struct object_list **process_blob(struct blob *blob, return p; obj->flags |= SEEN; - name = strdup(name); - return add_object(obj, p, path, name); + return add_one_object(obj, p); } static struct object_list **process_tree(struct tree *tree, @@ -1735,7 +1744,7 @@ static struct object_list **process_tree(struct tree *tree, obj->flags |= SEEN; name = strdup(name); - p = add_object(obj, p, NULL, name); + p = add_one_object(obj, p); me.up = path; me.elem = name; me.elem_len = strlen(name); @@ -1756,8 +1765,9 @@ static struct object_list **process_tree(struct tree *tree, static int get_delta(struct rev_info *revs, struct remote_lock *lock) { + int i; struct commit *commit; - struct object_list **p = &objects, *pending; + struct object_list **p = &objects; int count = 0; while ((commit = get_revision(revs)) != NULL) { @@ -1767,15 +1777,16 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock) count += add_send_request(&commit->object, lock); } - for (pending = revs->pending_objects; pending; pending = pending->next) { - struct object *obj = pending->item; - const char *name = pending->name; + for (i = 0; i < revs->pending.nr; i++) { + struct object_array_entry *entry = revs->pending.objects + i; + struct object *obj = entry->item; + const char *name = entry->name; if (obj->flags & (UNINTERESTING | SEEN)) continue; if (obj->type == TYPE_TAG) { obj->flags |= SEEN; - p = add_object(obj, p, NULL, name); + p = add_one_object(obj, p); continue; } if (obj->type == TYPE_TREE) { @@ -34,7 +34,7 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, size_t size = eltsize * nmemb; if (size > buffer->size - buffer->posn) size = buffer->size - buffer->posn; - memcpy(ptr, buffer->buffer + buffer->posn, size); + memcpy(ptr, (char *) buffer->buffer + buffer->posn, size); buffer->posn += size; return size; } @@ -49,7 +49,7 @@ size_t fwrite_buffer(const void *ptr, size_t eltsize, buffer->size = buffer->posn + size; buffer->buffer = xrealloc(buffer->buffer, buffer->size); } - memcpy(buffer->buffer + buffer->posn, ptr, size); + memcpy((char *) buffer->buffer + buffer->posn, ptr, size); buffer->posn += size; data_received++; return size; diff --git a/imap-send.c b/imap-send.c index 285ad29afb..94e39cd94c 100644 --- a/imap-send.c +++ b/imap-send.c @@ -93,7 +93,7 @@ typedef struct { char *data; int len; unsigned char flags; - unsigned char crlf:1; + unsigned int crlf:1; } msg_data_t; #define DRV_OK 0 diff --git a/merge-index.c b/merge-index.c index 024196e7ac..190e12fb7c 100644 --- a/merge-index.c +++ b/merge-index.c @@ -99,6 +99,11 @@ int main(int argc, char **argv) { int i, force_file = 0; + /* Without this we cannot rely on waitpid() to tell + * what happened to our children. + */ + signal(SIGCHLD, SIG_DFL); + if (argc < 3) usage("git-merge-index [-o] [-q] <merge-program> (-a | <filename>*)"); diff --git a/name-rev.c b/name-rev.c index c29b93ea71..3a5ac35d16 100644 --- a/name-rev.c +++ b/name-rev.c @@ -125,11 +125,10 @@ static const char* get_rev_name(struct object *o) return buffer; } - + int main(int argc, char **argv) { - struct object_list *revs = NULL; - struct object_list **walker = &revs; + struct object_array revs = { 0, 0, NULL }; int as_is = 0, all = 0, transform_stdin = 0; setup_git_directory(); @@ -184,9 +183,7 @@ int main(int argc, char **argv) if (cutoff > commit->date) cutoff = commit->date; - object_list_append((struct object *)commit, walker); - (*walker)->name = *argv; - walker = &((*walker)->next); + add_object_array((struct object *)commit, *argv, &revs); } for_each_ref(name_ref); @@ -243,9 +240,13 @@ int main(int argc, char **argv) if (objs[i]) printf("%s %s\n", sha1_to_hex(objs[i]->sha1), get_rev_name(objs[i])); - } else - for ( ; revs; revs = revs->next) - printf("%s %s\n", revs->name, get_rev_name(revs->item)); + } else { + int i; + for (i = 0; i < revs.nr; i++) + printf("%s %s\n", + revs.objects[i].name, + get_rev_name(revs.objects[i].item)); + } return 0; } diff --git a/object-refs.c b/object-refs.c index 8afa2276fb..a7d49c60d7 100644 --- a/object-refs.c +++ b/object-refs.c @@ -127,6 +127,9 @@ void mark_reachable(struct object *obj, unsigned int mask) if (!track_object_refs) die("cannot do reachability with object refs turned off"); + /* nothing to lookup */ + if (!refs_hash_size) + return; /* If we've been here already, don't bother */ if (obj->flags & mask) return; @@ -200,3 +200,20 @@ int object_list_contains(struct object_list *list, struct object *obj) } return 0; } + +void add_object_array(struct object *obj, const char *name, struct object_array *array) +{ + unsigned nr = array->nr; + unsigned alloc = array->alloc; + struct object_array_entry *objects = array->objects; + + if (nr >= alloc) { + alloc = (alloc + 32) * 2; + objects = xrealloc(objects, alloc * sizeof(*objects)); + array->alloc = alloc; + array->objects = objects; + } + objects[nr].item = obj; + objects[nr].name = name; + array->nr = ++nr; +} @@ -4,7 +4,6 @@ struct object_list { struct object *item; struct object_list *next; - const char *name; }; struct object_refs { @@ -13,6 +12,15 @@ struct object_refs { struct object *ref[FLEX_ARRAY]; /* more */ }; +struct object_array { + unsigned int nr; + unsigned int alloc; + struct object_array_entry { + struct object *item; + const char *name; + } *objects; +}; + #define TYPE_BITS 3 #define FLAG_BITS 27 @@ -72,4 +80,7 @@ unsigned object_list_length(struct object_list *list); int object_list_contains(struct object_list *list, struct object *obj); +/* Object array handling .. */ +void add_object_array(struct object *obj, const char *name, struct object_array *array); + #endif /* OBJECT_H */ diff --git a/pack-check.c b/pack-check.c index e57587909e..3a62e1b7e4 100644 --- a/pack-check.c +++ b/pack-check.c @@ -29,10 +29,10 @@ static int verify_packfile(struct packed_git *p) pack_base = p->pack_base; SHA1_Update(&ctx, pack_base, pack_size - 20); SHA1_Final(sha1, &ctx); - if (memcmp(sha1, pack_base + pack_size - 20, 20)) + if (memcmp(sha1, (char *) pack_base + pack_size - 20, 20)) return error("Packfile %s SHA1 mismatch with itself", p->pack_name); - if (memcmp(sha1, index_base + index_size - 40, 20)) + if (memcmp(sha1, (char *) index_base + index_size - 40, 20)) return error("Packfile %s SHA1 mismatch with idx", p->pack_name); @@ -135,7 +135,7 @@ int verify_pack(struct packed_git *p, int verbose) SHA1_Init(&ctx); SHA1_Update(&ctx, index_base, index_size - 20); SHA1_Final(sha1, &ctx); - if (memcmp(sha1, index_base + index_size - 20, 20)) + if (memcmp(sha1, (char *) index_base + index_size - 20, 20)) ret = error("Packfile index for %s SHA1 mismatch", p->pack_name); diff --git a/pack-objects.c b/pack-objects.c index 179560f2bd..bed2497b79 100644 --- a/pack-objects.c +++ b/pack-objects.c @@ -156,7 +156,7 @@ static void prepare_pack_revindex(struct pack_revindex *rix) rix->revindex = xmalloc(sizeof(unsigned long) * (num_ent + 1)); for (i = 0; i < num_ent; i++) { - unsigned int hl = *((unsigned int *)(index + 24 * i)); + unsigned int hl = *((unsigned int *)((char *) index + 24*i)); rix->revindex[i] = ntohl(hl); } /* This knows the pack format -- the 20-byte trailer @@ -300,7 +300,7 @@ static unsigned long write_object(struct sha1file *f, use_packed_git(p); datalen = find_packed_object_size(p, entry->in_pack_offset); - buf = p->pack_base + entry->in_pack_offset; + buf = (char *) p->pack_base + entry->in_pack_offset; sha1write(f, buf, datalen); unuse_packed_git(p); hdrlen = 0; /* not really */ @@ -1221,6 +1221,10 @@ int main(int argc, char **argv) local = 1; continue; } + if (!strcmp("--progress", arg)) { + progress = 1; + continue; + } if (!strcmp("--incremental", arg)) { incremental = 1; continue; diff --git a/pack-redundant.c b/pack-redundant.c index cd81f5a66e..41fb960569 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -246,12 +246,12 @@ static struct pack_list * pack_list_difference(const struct pack_list *A, static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2) { int p1_off, p2_off; - void *p1_base, *p2_base; + unsigned char *p1_base, *p2_base; struct llist_item *p1_hint = NULL, *p2_hint = NULL; - + p1_off = p2_off = 256 * 4 + 4; - p1_base = (void *)p1->pack->index_base; - p2_base = (void *)p2->pack->index_base; + p1_base = (unsigned char *) p1->pack->index_base; + p2_base = (unsigned char *) p2->pack->index_base; while (p1_off <= p1->pack->index_size - 3 * 20 && p2_off <= p2->pack->index_size - 3 * 20) @@ -351,11 +351,11 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2) { size_t ret = 0; int p1_off, p2_off; - void *p1_base, *p2_base; + char *p1_base, *p2_base; p1_off = p2_off = 256 * 4 + 4; - p1_base = (void *)p1->index_base; - p2_base = (void *)p2->index_base; + p1_base = (char *)p1->index_base; + p2_base = (char *)p2->index_base; while (p1_off <= p1->index_size - 3 * 20 && p2_off <= p2->index_size - 3 * 20) @@ -534,7 +534,7 @@ static struct pack_list * add_pack(struct packed_git *p) { struct pack_list l; size_t off; - void *base; + unsigned char *base; if (!p->pack_local && !(alt_odb || verbose)) return NULL; @@ -543,7 +543,7 @@ static struct pack_list * add_pack(struct packed_git *p) llist_init(&l.all_objects); off = 256 * 4 + 4; - base = (void *)p->index_base; + base = (unsigned char *)p->index_base; while (off <= p->index_size - 3 * 20) { llist_insert_back(l.all_objects, base + off); off += 24; @@ -46,7 +46,7 @@ void setup_pager(void) close(fd[0]); close(fd[1]); - setenv("LESS", "-S", 0); + setenv("LESS", "-RS", 0); run_pager(pager); die("unable to execute pager '%s'", pager); exit(255); diff --git a/patch-delta.c b/patch-delta.c index 8f318ed8aa..e3a1d425ee 100644 --- a/patch-delta.c +++ b/patch-delta.c @@ -25,7 +25,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size, return NULL; data = delta_buf; - top = delta_buf + delta_size; + top = (const unsigned char *) delta_buf + delta_size; /* make sure the orig file size matches what we expect */ size = get_delta_hdr_size(&data, top); @@ -56,7 +56,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size, cp_off + cp_size > src_size || cp_size > size) goto bad; - memcpy(out, src_buf + cp_off, cp_size); + memcpy(out, (char *) src_buf + cp_off, cp_size); out += cp_size; size -= cp_size; } else if (cmd) { diff --git a/pkt-line.c b/pkt-line.c index bb3bab05cd..c1e81f976f 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -16,12 +16,13 @@ * The writing side could use stdio, but since the reading * side can't, we stay with pure read/write interfaces. */ -static void safe_write(int fd, const void *buf, unsigned n) +ssize_t safe_write(int fd, const void *buf, ssize_t n) { + ssize_t nn = n; while (n) { int ret = xwrite(fd, buf, n); if (ret > 0) { - buf += ret; + buf = (char *) buf + ret; n -= ret; continue; } @@ -29,6 +30,7 @@ static void safe_write(int fd, const void *buf, unsigned n) die("write error (disk full?)"); die("write error (%s)", strerror(errno)); } + return nn; } /* @@ -66,7 +68,7 @@ static void safe_read(int fd, void *buffer, unsigned size) int n = 0; while (n < size) { - int ret = xread(fd, buffer + n, size - n); + int ret = xread(fd, (char *) buffer + n, size - n); if (ret < 0) die("read error (%s)", strerror(errno)); if (!ret) diff --git a/pkt-line.h b/pkt-line.h index 51d0cbe219..9abef24de3 100644 --- a/pkt-line.h +++ b/pkt-line.h @@ -8,5 +8,6 @@ void packet_flush(int fd); void packet_write(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3))); int packet_read_line(int fd, char *buffer, unsigned size); +ssize_t safe_write(int, const void *, ssize_t); #endif @@ -206,7 +206,14 @@ char *unquote_c_style(const char *quoted, const char **endp) case '\\': case '"': break; /* verbatim */ - case '0'...'7': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': /* octal */ ac = ((ch - '0') << 6); if ((ch = *sp++) < '0' || '7' < ch) diff --git a/read-cache.c b/read-cache.c index c499c51856..3c32aae7e8 100644 --- a/read-cache.c +++ b/read-cache.c @@ -706,7 +706,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size) SHA1_Init(&c); SHA1_Update(&c, hdr, size - 20); SHA1_Final(sha1, &c); - if (memcmp(sha1, (void *)hdr + size - 20, 20)) + if (memcmp(sha1, (char *) hdr + size - 20, 20)) return error("bad index file sha1 signature"); return 0; } @@ -770,7 +770,7 @@ int read_cache(void) offset = sizeof(*hdr); for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = map + offset; + struct cache_entry *ce = (struct cache_entry *) ((char *) map + offset); offset = offset + ce_size(ce); active_cache[i] = ce; } @@ -783,10 +783,11 @@ int read_cache(void) * in 4-byte network byte order. */ unsigned long extsize; - memcpy(&extsize, map + offset + 4, 4); + memcpy(&extsize, (char *) map + offset + 4, 4); extsize = ntohl(extsize); - if (read_index_extension(map + offset, - map + offset + 8, extsize) < 0) + if (read_index_extension(((const char *) map) + offset, + (char *) map + offset + 8, + extsize) < 0) goto unmap; offset += 8; offset += extsize; @@ -820,7 +821,7 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len) } write_buffer_len = buffered; len -= partial; - data += partial; + data = (char *) data + partial; } return 0; } diff --git a/repo-config.c b/repo-config.c index 08fc4cc57d..ab8f1afeea 100644 --- a/repo-config.c +++ b/repo-config.c @@ -64,7 +64,20 @@ static int show_config(const char* key_, const char* value_) static int get_value(const char* key_, const char* regex_) { + int ret = -1; char *tl; + char *global = NULL, *repo_config = NULL; + const char *local; + + local = getenv("GIT_CONFIG"); + if (!local) { + const char *home = getenv("HOME"); + local = getenv("GIT_CONFIG_LOCAL"); + if (!local) + local = repo_config = strdup(git_path("config")); + if (home) + global = strdup(mkpath("%s/.gitconfig", home)); + } key = strdup(key_); for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl) @@ -76,7 +89,7 @@ static int get_value(const char* key_, const char* regex_) key_regexp = (regex_t*)malloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { fprintf(stderr, "Invalid key pattern: %s\n", key_); - return -1; + goto free_strings; } } @@ -89,11 +102,16 @@ static int get_value(const char* key_, const char* regex_) regexp = (regex_t*)malloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { fprintf(stderr, "Invalid pattern: %s\n", regex_); - return -1; + goto free_strings; } } - git_config(show_config); + if (do_all && global) + git_config_from_file(show_config, global); + git_config_from_file(show_config, local); + if (!do_all && !seen && global) + git_config_from_file(show_config, global); + free(key); if (regexp) { regfree(regexp); @@ -101,9 +119,16 @@ static int get_value(const char* key_, const char* regex_) } if (do_all) - return !seen; - - return (seen == 1) ? 0 : 1; + ret = !seen; + else + ret = (seen == 1) ? 0 : 1; + +free_strings: + if (repo_config) + free(repo_config); + if (global) + free(global); + return ret; } int main(int argc, const char **argv) diff --git a/revision.c b/revision.c index 7bff2a10b1..b963f2adfd 100644 --- a/revision.c +++ b/revision.c @@ -31,17 +31,12 @@ static char *path_name(struct name_path *path, const char *name) return n; } -struct object_list **add_object(struct object *obj, - struct object_list **p, - struct name_path *path, - const char *name) +void add_object(struct object *obj, + struct object_array *p, + struct name_path *path, + const char *name) { - struct object_list *entry = xmalloc(sizeof(*entry)); - entry->item = obj; - entry->next = *p; - entry->name = path_name(path, name); - *p = entry; - return &entry->next; + add_object_array(obj, path_name(path, name), p); } static void mark_blob_uninteresting(struct blob *blob) @@ -117,9 +112,9 @@ void mark_parents_uninteresting(struct commit *commit) } } -static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name) +void add_pending_object(struct rev_info *revs, struct object *obj, const char *name) { - add_object(obj, &revs->pending_objects, NULL, name); + add_object_array(obj, name, &revs->pending); } static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags) @@ -836,7 +831,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch object = get_reference(revs, arg, sha1, flags ^ local_flags); add_pending_object(revs, object, arg); } - if (def && !revs->pending_objects) { + if (def && !revs->pending.nr) { unsigned char sha1[20]; struct object *object; if (get_sha1(def, sha1)) @@ -868,11 +863,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch void prepare_revision_walk(struct rev_info *revs) { - struct object_list *list; + int nr = revs->pending.nr; + struct object_array_entry *list = revs->pending.objects; - list = revs->pending_objects; - revs->pending_objects = NULL; - while (list) { + revs->pending.nr = 0; + revs->pending.alloc = 0; + revs->pending.objects = NULL; + while (--nr >= 0) { struct commit *commit = handle_commit(revs, list->item, list->name); if (commit) { if (!(commit->object.flags & SEEN)) { @@ -880,7 +877,7 @@ void prepare_revision_walk(struct rev_info *revs) insert_by_date(commit, &revs->commits); } } - list = list->next; + list++; } if (revs->no_walk) diff --git a/revision.h b/revision.h index 4020e25c33..c010a08116 100644 --- a/revision.h +++ b/revision.h @@ -18,7 +18,7 @@ typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit); struct rev_info { /* Starting list */ struct commit_list *commits; - struct object_list *pending_objects; + struct object_array pending; /* Basic information */ const char *prefix; @@ -99,9 +99,11 @@ struct name_path { const char *elem; }; -extern struct object_list **add_object(struct object *obj, - struct object_list **p, - struct name_path *path, - const char *name); +extern void add_object(struct object *obj, + struct object_array *p, + struct name_path *path, + const char *name); + +extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); #endif diff --git a/sha1_file.c b/sha1_file.c index b4ff233bad..c80528b506 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -486,8 +486,9 @@ int use_packed_git(struct packed_git *p) * this is cheap. */ if (memcmp((char*)(p->index_base) + p->index_size - 40, - p->pack_base + p->pack_size - 20, 20)) { - + (char *) p->pack_base + p->pack_size - 20, + 20)) { + die("packfile %s does not match index.", p->pack_name); } } @@ -701,7 +702,7 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size int bytes = strlen(buffer) + 1; unsigned char *buf = xmalloc(1+size); - memcpy(buf, buffer + bytes, stream->total_out - bytes); + memcpy(buf, (char *) buffer + bytes, stream->total_out - bytes); bytes = stream->total_out - bytes; if (bytes < size) { stream->next_out = buf + bytes; @@ -853,7 +854,7 @@ static unsigned long unpack_object_header(struct packed_git *p, unsigned long of if (offset >= p->pack_size) die("object offset outside of pack file"); - pack = p->pack_base + offset; + pack = (unsigned char *) p->pack_base + offset; c = *pack++; offset++; *type = (c >> 4) & 7; @@ -883,7 +884,7 @@ int check_reuse_pack_delta(struct packed_git *p, unsigned long offset, ptr = unpack_object_header(p, ptr, kindp, sizep); if (*kindp != OBJ_DELTA) goto done; - memcpy(base, p->pack_base + ptr, 20); + memcpy(base, (char *) p->pack_base + ptr, 20); status = 0; done: unuse_packed_git(p); @@ -903,7 +904,7 @@ void packed_object_info_detail(struct pack_entry *e, enum object_type kind; offset = unpack_object_header(p, e->offset, &kind, size); - pack = p->pack_base + offset; + pack = (unsigned char *) p->pack_base + offset; if (kind != OBJ_DELTA) *delta_chain_length = 0; else { @@ -919,7 +920,7 @@ void packed_object_info_detail(struct pack_entry *e, find_pack_entry_one(pack, &base_ent, p); offset = unpack_object_header(p, base_ent.offset, &kind, &junk); - pack = p->pack_base + offset; + pack = (unsigned char *) p->pack_base + offset; chain_length++; } while (kind == OBJ_DELTA); *delta_chain_length = chain_length; @@ -957,7 +958,7 @@ static int packed_object_info(struct pack_entry *entry, die("cannot map packed file"); offset = unpack_object_header(p, entry->offset, &kind, &size); - pack = p->pack_base + offset; + pack = (unsigned char *) p->pack_base + offset; left = p->pack_size - offset; switch (kind) { @@ -1096,7 +1097,7 @@ void *unpack_entry_gently(struct pack_entry *entry, void *retval; offset = unpack_object_header(p, entry->offset, &kind, &size); - pack = p->pack_base + offset; + pack = (unsigned char *) p->pack_base + offset; left = p->pack_size - offset; switch (kind) { case OBJ_DELTA: @@ -1134,7 +1135,7 @@ int nth_packed_object_sha1(const struct packed_git *p, int n, void *index = p->index_base + 256; if (n < 0 || num_packed_objects(p) <= n) return -1; - memcpy(sha1, (index + 24 * n + 4), 20); + memcpy(sha1, (char *) index + (24 * n) + 4, 20); return 0; } @@ -1148,9 +1149,9 @@ int find_pack_entry_one(const unsigned char *sha1, do { int mi = (lo + hi) / 2; - int cmp = memcmp(index + 24 * mi + 4, sha1, 20); + int cmp = memcmp((char *) index + (24 * mi) + 4, sha1, 20); if (!cmp) { - e->offset = ntohl(*((unsigned int *)(index + 24 * mi))); + e->offset = ntohl(*((unsigned int *) ((char *) index + (24 * mi)))); memcpy(e->sha1, sha1, 20); e->p = p; return 1; @@ -1290,7 +1291,7 @@ void *read_object_with_reference(const unsigned char *sha1, ref_length = strlen(ref_type); if (memcmp(buffer, ref_type, ref_length) || - get_sha1_hex(buffer + ref_length, actual_sha1)) { + get_sha1_hex((char *) buffer + ref_length, actual_sha1)) { free(buffer); return NULL; } @@ -1408,7 +1409,7 @@ static int write_buffer(int fd, const void *buf, size_t len) return error("file write error (%s)", strerror(errno)); } len -= size; - buf += size; + buf = (char *) buf + size; } return 0; } diff --git a/ssh-fetch.c b/ssh-fetch.c index e3067b878e..1e59cd2008 100644 --- a/ssh-fetch.c +++ b/ssh-fetch.c @@ -24,7 +24,7 @@ static ssize_t force_write(int fd, void *buffer, size_t length) { ssize_t ret = 0; while (ret < length) { - ssize_t size = write(fd, buffer + ret, length - ret); + ssize_t size = write(fd, (char *) buffer + ret, length - ret); if (size < 0) { return size; } diff --git a/t/Makefile b/t/Makefile index 549598575b..632c55f6d5 100644 --- a/t/Makefile +++ b/t/Makefile @@ -19,7 +19,7 @@ endif all: $(T) clean $(T): - @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) + @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) clean: rm -fr trash diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index c04f0e1540..1148b0257d 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -111,7 +111,7 @@ test_expect_success \ test_expect_success \ 'some edit' \ - 'perl -pi -e "s/^1A.*\n$//; s/^3A/99/" file && + 'perl -p -i.orig -e "s/^1A.*\n$//; s/^3A/99/" file && GIT_AUTHOR_NAME="D" git commit -a -m "edit"' test_expect_success \ diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 8260d57b63..0de2497746 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -309,5 +309,29 @@ EOF test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect' +cat > other-config << EOF +[ein] + bahn = strasse +EOF + +cat > expect << EOF +ein.bahn=strasse +EOF + +GIT_CONFIG=other-config git-repo-config -l > output + +test_expect_success 'alternative GIT_CONFIG' 'cmp output expect' + +GIT_CONFIG=other-config git-repo-config anwohner.park ausweis + +cat > expect << EOF +[ein] + bahn = strasse +[anwohner] + park = ausweis +EOF + +test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect' + test_done diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh new file mode 100755 index 0000000000..d34c6cf6f3 --- /dev/null +++ b/t/t3402-rebase-merge.sh @@ -0,0 +1,112 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='git rebase --merge test' + +. ./test-lib.sh + +if test "$no_python"; then + echo "Skipping: no python => no recursive merge" + test_done + exit 0 +fi + +T="A quick brown fox +jumps over the lazy dog." +for i in 1 2 3 4 5 6 7 8 9 10 +do + echo "$i $T" +done >original + +test_expect_success setup ' + git add original && + git commit -m"initial" && + git branch side && + echo "11 $T" >>original && + git commit -a -m"master updates a bit." && + + echo "12 $T" >>original && + git commit -a -m"master updates a bit more." && + + git checkout side && + (echo "0 $T" ; cat original) >renamed && + git add renamed && + git update-index --force-remove original && + git commit -a -m"side renames and edits." && + + tr "[a-z]" "[A-Z]" <original >newfile && + git add newfile && + git commit -a -m"side edits further." && + + tr "[a-m]" "[A-M]" <original >newfile && + rm -f original && + git commit -a -m"side edits once again." && + + git branch test-rebase side && + git branch test-rebase-pick side && + git branch test-reference-pick side && + git checkout -b test-merge side +' + +test_expect_success 'reference merge' ' + git merge -s recursive "reference merge" HEAD master +' + +test_expect_success rebase ' + git checkout test-rebase && + git rebase --merge master +' + +test_expect_success 'merge and rebase should match' ' + git diff-tree -r test-rebase test-merge >difference && + if test -s difference + then + cat difference + (exit 1) + else + echo happy + fi +' + +test_expect_success 'rebase the other way' ' + git reset --hard master && + git rebase --merge side +' + +test_expect_success 'merge and rebase should match' ' + git diff-tree -r test-rebase test-merge >difference && + if test -s difference + then + cat difference + (exit 1) + else + echo happy + fi +' + +test_expect_success 'picking rebase' ' + git reset --hard side && + git rebase --merge --onto master side^^ && + mb=$(git merge-base master HEAD) && + if test "$mb" = "$(git rev-parse master)" + then + echo happy + else + git show-branch + (exit 1) + fi && + f=$(git diff-tree --name-only HEAD^ HEAD) && + g=$(git diff-tree --name-only HEAD^^ HEAD^) && + case "$f,$g" in + newfile,newfile) + echo happy ;; + *) + echo "$f" + echo "$g" + (exit 1) + esac +' + +test_done @@ -19,7 +19,7 @@ struct tag *lookup_tag(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) { - struct tag *ret = xcalloc(1, sizeof(struct tag)); + struct tag *ret = alloc_tag_node(); created_object(sha1, &ret->object); ret->object.type = TYPE_TAG; return ret; @@ -47,10 +47,10 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size) if (size < 64) return -1; - if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object)) + if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, object)) return -1; - type_line = data + 48; + type_line = (char *) data + 48; if (memcmp("\ntype ", type_line-1, 6)) return -1; diff --git a/tree-walk.c b/tree-walk.c index 297c6972b9..3f83e98f3a 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -43,7 +43,7 @@ void update_tree_entry(struct tree_desc *desc) if (size < len) die("corrupt tree file"); - desc->buf = buf + len; + desc->buf = (char *) buf + len; desc->size = size - len; } @@ -66,7 +66,7 @@ const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pat const void *tree = desc->buf; unsigned long size = desc->size; int len = strlen(tree)+1; - const unsigned char *sha1 = tree + len; + const unsigned char *sha1 = (unsigned char *) tree + len; const char *path; unsigned int mode; @@ -80,7 +80,8 @@ const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pat int tree_entry(struct tree_desc *desc, struct name_entry *entry) { - const void *tree = desc->buf, *path; + const void *tree = desc->buf; + const char *path; unsigned long len, size = desc->size; if (!size) @@ -95,10 +96,10 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry) entry->pathlen = len; path += len + 1; - entry->sha1 = path; + entry->sha1 = (const unsigned char *) path; path += 20; - len = path - tree; + len = path - (char *) tree; if (len > size) die("corrupt tree file"); @@ -129,7 +129,7 @@ struct tree *lookup_tree(const unsigned char *sha1) { struct object *obj = lookup_object(sha1); if (!obj) { - struct tree *ret = xcalloc(1, sizeof(struct tree)); + struct tree *ret = alloc_tree_node(); created_object(sha1, &ret->object); ret->object.type = TYPE_TREE; return ret; diff --git a/upload-pack.c b/upload-pack.c index 979e58306e..7b86f6965b 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -5,6 +5,9 @@ #include "object.h" #include "commit.h" #include "exec_cmd.h" +#include <signal.h> +#include <sys/poll.h> +#include <sys/wait.h> static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>"; @@ -18,6 +21,7 @@ static int use_thin_pack = 0; static unsigned char has_sha1[MAX_HAS][20]; static unsigned char needs_sha1[MAX_NEEDS][20]; static unsigned int timeout = 0; +static int use_sideband = 0; static void reset_timeout(void) { @@ -31,19 +35,63 @@ static int strip(char *line, int len) return len; } +#define PACKET_MAX 1000 +static ssize_t send_client_data(int fd, const char *data, ssize_t sz) +{ + ssize_t ssz; + const char *p; + + if (!data) { + if (!use_sideband) + return 0; + packet_flush(1); + } + + if (!use_sideband) { + if (fd == 3) + /* emergency quit */ + fd = 2; + return safe_write(fd, data, sz); + } + p = data; + ssz = sz; + while (sz) { + unsigned n; + char hdr[5]; + + n = sz; + if (PACKET_MAX - 5 < n) + n = PACKET_MAX - 5; + sprintf(hdr, "%04x", n + 5); + hdr[4] = fd; + safe_write(1, hdr, 5); + safe_write(1, p, n); + p += n; + sz -= n; + } + return ssz; +} + static void create_pack_file(void) { - int fd[2]; - pid_t pid; + /* Pipes between rev-list to pack-objects, pack-objects to us + * and pack-objects error stream for progress bar. + */ + int lp_pipe[2], pu_pipe[2], pe_pipe[2]; + pid_t pid_rev_list, pid_pack_objects; int create_full_pack = (nr_our_refs == nr_needs && !nr_has); + char data[8193], progress[128]; + char abort_msg[] = "aborting due to possible repository " + "corruption on the remote side."; + int buffered = -1; - if (pipe(fd) < 0) + if (pipe(lp_pipe) < 0) die("git-upload-pack: unable to create pipe"); - pid = fork(); - if (pid < 0) + pid_rev_list = fork(); + if (pid_rev_list < 0) die("git-upload-pack: unable to fork git-rev-list"); - if (!pid) { + if (!pid_rev_list) { int i; int args; const char **argv; @@ -60,10 +108,10 @@ static void create_pack_file(void) argv = (const char **) p; buf = xmalloc(args * 45); - dup2(fd[1], 1); + dup2(lp_pipe[1], 1); close(0); - close(fd[0]); - close(fd[1]); + close(lp_pipe[0]); + close(lp_pipe[1]); *p++ = "rev-list"; *p++ = use_thin_pack ? "--objects-edge" : "--objects"; if (create_full_pack || MAX_NEEDS <= nr_needs) @@ -86,11 +134,184 @@ static void create_pack_file(void) execv_git_cmd(argv); die("git-upload-pack: unable to exec git-rev-list"); } - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - execl_git_cmd("pack-objects", "--stdout", NULL); - die("git-upload-pack: unable to exec git-pack-objects"); + + if (pipe(pu_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + if (pipe(pe_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + pid_pack_objects = fork(); + if (pid_pack_objects < 0) { + /* daemon sets things up to ignore TERM */ + kill(pid_rev_list, SIGKILL); + die("git-upload-pack: unable to fork git-pack-objects"); + } + if (!pid_pack_objects) { + dup2(lp_pipe[0], 0); + dup2(pu_pipe[1], 1); + dup2(pe_pipe[1], 2); + + close(lp_pipe[0]); + close(lp_pipe[1]); + close(pu_pipe[0]); + close(pu_pipe[1]); + close(pe_pipe[0]); + close(pe_pipe[1]); + execl_git_cmd("pack-objects", "--stdout", "--progress", NULL); + kill(pid_rev_list, SIGKILL); + die("git-upload-pack: unable to exec git-pack-objects"); + } + + close(lp_pipe[0]); + close(lp_pipe[1]); + + /* We read from pe_pipe[0] to capture stderr output for + * progress bar, and pu_pipe[0] to capture the pack data. + */ + close(pe_pipe[1]); + close(pu_pipe[1]); + + while (1) { + const char *who; + struct pollfd pfd[2]; + pid_t pid; + int status; + ssize_t sz; + int pe, pu, pollsize; + + pollsize = 0; + pe = pu = -1; + + if (0 <= pu_pipe[0]) { + pfd[pollsize].fd = pu_pipe[0]; + pfd[pollsize].events = POLLIN; + pu = pollsize; + pollsize++; + } + if (0 <= pe_pipe[0]) { + pfd[pollsize].fd = pe_pipe[0]; + pfd[pollsize].events = POLLIN; + pe = pollsize; + pollsize++; + } + + if (pollsize) { + if (poll(pfd, pollsize, -1) < 0) { + if (errno != EINTR) { + error("poll failed, resuming: %s", + strerror(errno)); + sleep(1); + } + continue; + } + if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) { + /* Data ready; we keep the last byte + * to ourselves in case we detect + * broken rev-list, so that we can + * leave the stream corrupted. This + * is unfortunate -- unpack-objects + * would happily accept a valid pack + * data with trailing garbage, so + * appending garbage after we pass all + * the pack data is not good enough to + * signal breakage to downstream. + */ + char *cp = data; + ssize_t outsz = 0; + if (0 <= buffered) { + *cp++ = buffered; + outsz++; + } + sz = read(pu_pipe[0], cp, + sizeof(data) - outsz); + if (0 < sz) + ; + else if (sz == 0) { + close(pu_pipe[0]); + pu_pipe[0] = -1; + } + else + goto fail; + sz += outsz; + if (1 < sz) { + buffered = data[sz-1] & 0xFF; + sz--; + } + else + buffered = -1; + sz = send_client_data(1, data, sz); + if (sz < 0) + goto fail; + } + if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) { + /* Status ready; we ship that in the side-band + * or dump to the standard error. + */ + sz = read(pe_pipe[0], progress, + sizeof(progress)); + if (0 < sz) + send_client_data(2, progress, sz); + else if (sz == 0) { + close(pe_pipe[0]); + pe_pipe[0] = -1; + } + else + goto fail; + } + } + + /* See if the children are still there */ + if (pid_rev_list || pid_pack_objects) { + pid = waitpid(-1, &status, WNOHANG); + if (!pid) + continue; + who = ((pid == pid_rev_list) ? "git-rev-list" : + (pid == pid_pack_objects) ? "git-pack-objects" : + NULL); + if (!who) { + if (pid < 0) { + error("git-upload-pack: %s", + strerror(errno)); + goto fail; + } + error("git-upload-pack: we weren't " + "waiting for %d", pid); + continue; + } + if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) { + error("git-upload-pack: %s died with error.", + who); + goto fail; + } + if (pid == pid_rev_list) + pid_rev_list = 0; + if (pid == pid_pack_objects) + pid_pack_objects = 0; + if (pid_rev_list || pid_pack_objects) + continue; + } + + /* both died happily */ + if (pollsize) + continue; + + /* flush the data */ + if (0 <= buffered) { + data[0] = buffered; + sz = send_client_data(1, data, 1); + if (sz < 0) + goto fail; + fprintf(stderr, "flushed.\n"); + } + send_client_data(1, NULL, 0); + return; + } + fail: + if (pid_pack_objects) + kill(pid_pack_objects, SIGKILL); + if (pid_rev_list) + kill(pid_rev_list, SIGKILL); + send_client_data(3, abort_msg, sizeof(abort_msg)); + die("git-upload-pack: %s", abort_msg); } static int got_sha1(char *hex, unsigned char *sha1) @@ -197,6 +418,8 @@ static int receive_needs(void) multi_ack = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; + if (strstr(line+45, "side-band")) + use_sideband = 1; /* We have sent all our refs already, and the other end * should have chosen out of them; otherwise they are @@ -218,7 +441,7 @@ static int receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1) { - static char *capabilities = "multi_ack thin-pack"; + static char *capabilities = "multi_ack thin-pack side-band"; struct object *o = parse_object(sha1); if (!o) diff --git a/xdiff/xutils.c b/xdiff/xutils.c index 21ab8e7e26..f91b403475 100644 --- a/xdiff/xutils.c +++ b/xdiff/xutils.c @@ -44,21 +44,18 @@ long xdl_bogosqrt(long n) { int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, xdemitcb_t *ecb) { + int i = 2; mmbuffer_t mb[3]; - int i; mb[0].ptr = (char *) pre; mb[0].size = psize; mb[1].ptr = (char *) rec; mb[1].size = size; - i = 2; - - if (!size || rec[size-1] != '\n') { - mb[2].ptr = "\n\\ No newline at end of file\n"; + if (size > 0 && rec[size - 1] != '\n') { + mb[2].ptr = (char *) "\n\\ No newline at end of file\n"; mb[2].size = strlen(mb[2].ptr); - i = 3; + i++; } - if (ecb->outf(ecb->priv, mb, i) < 0) { return -1; diff --git a/xdiff/xutils.h b/xdiff/xutils.h index ea38ee903f..08691a2447 100644 --- a/xdiff/xutils.h +++ b/xdiff/xutils.h @@ -24,6 +24,7 @@ #define XUTILS_H + long xdl_bogosqrt(long n); int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, xdemitcb_t *ecb); |