diff options
49 files changed, 640 insertions, 781 deletions
diff --git a/.gitignore b/.gitignore index 31c03f468b..0fd59b9ff2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ git-applypatch git-archimport git-bisect git-branch -git-build-rev-cache git-cat-file git-checkout git-checkout-index @@ -73,13 +72,15 @@ git-rev-list git-rev-parse git-rev-tree git-revert +git-send-email git-send-pack git-sh-setup git-shortlog git-show-branch git-show-index -git-show-rev-cache git-ssh-fetch +git-ssh-pull +git-ssh-push git-ssh-upload git-status git-stripspace diff --git a/Documentation/Makefile b/Documentation/Makefile index b81a6a2c72..37b7fcb97d 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -45,7 +45,7 @@ man1: $(DOC_MAN1) man7: $(DOC_MAN7) install: - $(INSTALL) -m755 -d $(DESTDIR)/$(man1) $(DESTDIR)/$(man7) + $(INSTALL) -d -m755 $(DESTDIR)/$(man1) $(DESTDIR)/$(man7) $(INSTALL) $(DOC_MAN1) $(DESTDIR)/$(man1) $(INSTALL) $(DOC_MAN7) $(DESTDIR)/$(man7) diff --git a/Documentation/git-build-rev-cache.txt b/Documentation/git-build-rev-cache.txt deleted file mode 100644 index 1dbad7763f..0000000000 --- a/Documentation/git-build-rev-cache.txt +++ /dev/null @@ -1,38 +0,0 @@ -git-build-rev-cache(1) -====================== - -NAME ----- -git-build-rev-cache - Create or update a rev-cache file. - -SYNOPSIS --------- -'git-build-rev-cache' [-v] <rev-cache-file> < list-of-heads - -DESCRIPTION ------------ -Creates or updates a file that describes the commit ancestry reachable -from the list-of-head read from stdin. This file is in an append-only -binary format to make the server side friendly to rsync mirroring -scheme, and can be read by the git-show-rev-cache command. - -OPTIONS -------- --v:: - Verbose. - -<rev-cache-file>:: - The rev-cache to operate on. - -Author ------- -Written by Junio C Hamano <junkio@cox.net> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - -GIT ---- -Part of the link:git.html[git] suite - diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index 017f646601..8c1cc07048 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -26,6 +26,12 @@ OPTIONS ------- include::pull-fetch-param.txt[] +-u, \--update-head-ok:: + By default 'git-fetch' refuses to update the head which + corresponds to the current branch. This flag disables the + check. Note that fetching into the current branch will not + update the index and working directory, so use it with care. + Author ------ diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 35fecf3f83..32c06a1662 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -32,8 +32,11 @@ I have the commit object 'bar', but not 'foo'". The *--bisect* flag limits output to the one commit object which is roughly halfway between the included and excluded commits. Thus, -if "git-rev-list --bisect foo ^bar ^baz" outputs 'midpoint', the output -of "git-rev-list foo ^midpoint" and "git-rev-list midpoint ^bar ^baz" +if 'git-rev-list --bisect foo ^bar +^baz' outputs 'midpoint', the output +of 'git-rev-list foo ^midpoint' and 'git-rev-list midpoint +^bar +^baz' would be of roughly the same length. Finding the change which introduces a regression is thus reduced to a binary search: repeatedly generate and test new 'midpoint's until the commit chain is of length one. diff --git a/Documentation/git-show-rev-cache.txt b/Documentation/git-show-rev-cache.txt deleted file mode 100644 index 104ecb7b0f..0000000000 --- a/Documentation/git-show-rev-cache.txt +++ /dev/null @@ -1,37 +0,0 @@ -git-show-rev-cache(1) -===================== - -NAME ----- -git-show-rev-cache - Show the contents of a rev-cache file. - -SYNOPSIS --------- -'git-show-rev-cache' <rev-cache-file> - -DESCRIPTION ------------ -Show the contents of <rev-cache-file>. - -A rev-cache file describes the commit ancestry reachable from references -supplied as input to get-build-rev-cache. This file is in an -append-only binary format to make the server side friendly to rsync -mirroring scheme. - -OPTIONS -------- -<rev-cache-file>:: - Rev-cache file to display. - -Author ------- -Written by Junio C Hamano <junkio@cox.net> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - -GIT ---- -Part of the link:git.html[git] suite - diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt index 74c4364ad8..39222c3b4c 100644 --- a/Documentation/git-update-server-info.txt +++ b/Documentation/git-update-server-info.txt @@ -38,8 +38,6 @@ of what they are for: * info/refs -* info/rev-cache - BUGS ---- diff --git a/Documentation/git.txt b/Documentation/git.txt index 31dd4749e6..bec562e30e 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -359,9 +359,6 @@ link:git-tag.html[git-tag]:: Interrogators: -link:git-build-rev-cache.html[git-build-rev-cache]:: - Create or update a rev-cache file. - link:git-cherry.html[git-cherry]:: Find commits not merged upstream. @@ -402,9 +399,6 @@ link:git-send-email.html[git-send-email]:: Send patch e-mails out of "format-patch --mbox" output. Previously this command was known as git-send-email-script. -link:git-show-rev-cache.html[git-show-rev-cache]:: - Show the contents of a rev-cache file. - link:git-stripspace.html[git-stripspace]:: Filter out empty lines. diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt index 8f6b68cb55..8642182c89 100644 --- a/Documentation/pull-fetch-param.txt +++ b/Documentation/pull-fetch-param.txt @@ -80,3 +80,14 @@ <ref>: when pulling/fetching, and <ref>:<ref> when pushing. That is, do not store it locally if fetching, and update the same name if pushing. + +-a, \--append:: + Append ref names and object names of fetched refs to the + existing contents of $GIT_DIR/FETCH_HEAD. Without this + option old data in $GIT_DIR/FETCH_HEAD will be overwritten. + +-f, \--force:: + Usually, the command refuses to update a local ref that is + not an ancestor of the remote ref used to overwrite it. + This flag disables the check. What this means is that the + local repository can lose commits; use it with care. diff --git a/Documentation/repository-layout.txt b/Documentation/repository-layout.txt index 499b070598..d20fa80d87 100644 --- a/Documentation/repository-layout.txt +++ b/Documentation/repository-layout.txt @@ -117,13 +117,6 @@ info/grafts:: listing their 40-byte hexadecimal object names separated by a space and terminated by a newline. -info/rev-cache:: - No higher-level tool currently takes advantage of this - file, but it is generated when `git update-server-info` - is run. It records the commit ancestry information of - the commits in this repository in a concise binary - format, and can be read with `git-show-rev-cache`. - info/exclude:: This file, by convention among Porcelains, stores the exclude pattern list. `git status` looks at it, but @@ -92,7 +92,7 @@ SIMPLE_PROGRAMS = \ # ... and all the rest PROGRAMS = \ - git-apply git-build-rev-cache git-cat-file \ + git-apply git-cat-file \ git-checkout-index git-clone-pack git-commit-tree \ git-convert-objects git-diff-files \ git-diff-helper git-diff-index git-diff-stages \ @@ -103,12 +103,15 @@ PROGRAMS = \ git-peek-remote git-prune-packed git-read-tree \ git-receive-pack git-rev-list git-rev-parse \ git-rev-tree git-send-pack git-show-branch \ - git-show-index git-show-rev-cache git-ssh-fetch \ + git-show-index git-ssh-fetch \ git-ssh-upload git-tar-tree git-unpack-file \ git-unpack-objects git-update-index git-update-server-info \ git-upload-pack git-verify-pack git-write-tree \ $(SIMPLE_PROGRAMS) +# Backward compatibility -- to be removed in 0.99.8 +PROGRAMS += git-ssh-pull git-ssh-push + PYMODULES = \ gitMergeCommon.py @@ -125,7 +128,7 @@ LIB_FILE=libgit.a LIB_H = \ blob.h cache.h commit.h count-delta.h csum-file.h delta.h \ diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \ - rev-cache.h run-command.h strbuf.h tag.h tree.h + run-command.h strbuf.h tag.h tree.h DIFF_OBJS = \ diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \ @@ -135,7 +138,7 @@ LIB_OBJS = \ blob.o commit.o connect.o count-delta.o csum-file.o \ date.o diff-delta.o entry.o ident.o index.o \ object.o pack-check.o patch-delta.o path.o pkt-line.o \ - quote.o read-cache.o refs.o rev-cache.o run-command.o \ + quote.o read-cache.o refs.o run-command.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o $(DIFF_OBJS) @@ -148,7 +151,8 @@ ifeq ($(shell uname -s),Darwin) endif ifeq ($(shell uname -s),SunOS) NEEDS_SOCKET = YesPlease - PLATFORM_DEFINES += -DNO_GETDOMAINNAME=1 + NEEDS_NSL = YesPlease + PLATFORM_DEFINES += -D__EXTENSIONS__ endif ifndef SHELL_PATH @@ -195,6 +199,10 @@ ifdef NEEDS_SOCKET LIBS += -lsocket SIMPLE_LIB += -lsocket endif +ifdef NEEDS_NSL + LIBS += -lnsl + SIMPLE_LIB += -lnsl +endif DEFINES += '-DSHA1_HEADER=$(SHA1_HEADER)' @@ -250,6 +258,8 @@ git-http-fetch: fetch.o git-local-fetch: fetch.o git-ssh-fetch: rsh.o fetch.o git-ssh-upload: rsh.o +git-ssh-pull: rsh.o fetch.o +git-ssh-push: rsh.o git-http-fetch: LIBS += -lcurl git-rev-list: LIBS += $(OPENSSL_LIBSSL) @@ -288,12 +298,12 @@ check: ### Installation rules install: $(PROGRAMS) $(SCRIPTS) - $(INSTALL) -m755 -d $(DESTDIR)$(bindir) + $(INSTALL) -d -m755 $(DESTDIR)$(bindir) $(INSTALL) $(PROGRAMS) $(SCRIPTS) $(DESTDIR)$(bindir) $(INSTALL) git-revert $(DESTDIR)$(bindir)/git-cherry-pick sh ./cmd-rename.sh $(DESTDIR)$(bindir) $(MAKE) -C templates install - $(INSTALL) -m755 -d $(DESTDIR)$(GIT_PYTHON_DIR) + $(INSTALL) -d -m755 $(DESTDIR)$(GIT_PYTHON_DIR) $(INSTALL) $(PYMODULES) $(DESTDIR)$(GIT_PYTHON_DIR) install-doc: diff --git a/build-rev-cache.c b/build-rev-cache.c deleted file mode 100644 index 948898beb4..0000000000 --- a/build-rev-cache.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "refs.h" -#include "cache.h" -#include "commit.h" -#include "rev-cache.h" - -static void process_head_list(int verbose) -{ - char buf[512]; - - while (fgets(buf, sizeof(buf), stdin)) { - unsigned char sha1[20]; - struct commit *commit; - - if (get_sha1_hex(buf, sha1)) { - error("ignoring: %s", buf); - continue; - } - if (!(commit = lookup_commit_reference(sha1))) { - error("not a commit: %s", sha1_to_hex(sha1)); - continue; - } - record_rev_cache(commit->object.sha1, verbose ? stderr : NULL); - } -} - - -static const char *build_rev_cache_usage = -"git-build-rev-cache <rev-cache-file> < list-of-heads"; - -int main(int ac, char **av) -{ - int verbose = 0; - const char *path; - - while (1 < ac && av[1][0] == '-') { - if (!strcmp(av[1], "-v")) - verbose = 1; - else - usage(build_rev_cache_usage); - ac--; av++; - } - - if (ac != 2) - usage(build_rev_cache_usage); - - path = av[1]; - - /* read existing rev-cache */ - read_rev_cache(path, NULL, 0); - - process_head_list(verbose); - - /* update the rev-cache database by appending newly found one to it */ - write_rev_cache(path, path); - return 0; -} diff --git a/cmd-rename.sh b/cmd-rename.sh index 1edb037bea..ada33fb51d 100755 --- a/cmd-rename.sh +++ b/cmd-rename.sh @@ -42,12 +42,14 @@ git-tag-script git-tag git-verify-tag-script git-verify-tag git-http-pull git-http-fetch git-local-pull git-local-fetch -git-ssh-pull git-ssh-fetch git-checkout-cache git-checkout-index git-diff-cache git-diff-index git-merge-cache git-merge-index git-update-cache git-update-index -git-ssh-push git-ssh-upload git-convert-cache git-convert-objects git-fsck-cache git-fsck-objects EOF + +# These two are a bit more than symlinks now. +# git-ssh-push git-ssh-upload +# git-ssh-pull git-ssh-fetch @@ -3,6 +3,8 @@ #include "commit.h" #include "cache.h" +int save_commit_buffer = 1; + struct sort_node { /* @@ -264,7 +266,7 @@ int parse_commit(struct commit *item) sha1_to_hex(item->object.sha1)); } ret = parse_commit_buffer(item, buffer, size); - if (!ret) { + if (save_commit_buffer && !ret) { item->buffer = buffer; return 0; } @@ -17,6 +17,7 @@ struct commit { char *buffer; }; +extern int save_commit_buffer; extern const char *commit_type; struct commit *lookup_commit(const unsigned char *sha1); diff --git a/convert-objects.c b/convert-objects.c index 073cab592f..9ad0c77678 100644 --- a/convert-objects.c +++ b/convert-objects.c @@ -1,5 +1,4 @@ #define _XOPEN_SOURCE /* glibc2 needs this */ -#define __EXTENSIONS__ /* solaris needs this */ #include <time.h> #include <ctype.h> #include "cache.h" diff --git a/debian/control b/debian/control index 33a8f852b9..5d75c325e2 100644 --- a/debian/control +++ b/debian/control @@ -2,13 +2,13 @@ Source: git-core Section: devel Priority: optional Maintainer: Junio C Hamano <junkio@cox.net> -Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0) +Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0), bc Standards-Version: 3.6.1 Package: git-core Architecture: any Depends: ${shlibs:Depends}, ${perl:Depends}, ${misc:Depends}, patch, rcs -Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0) +Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0), less Suggests: cogito Conflicts: git, cogito (<< 0.13) Description: The git content addressable filesystem diff --git a/debian/rules b/debian/rules index 1a53ca2398..568d430932 100755 --- a/debian/rules +++ b/debian/rules @@ -41,7 +41,7 @@ MAN_DESTDIR := $(DESTDIR)/$(MANDIR) build: debian/build-stamp debian/build-stamp: dh_testdir - $(MAKE) prefix=$(PREFIX) PYTHON_PATH=/usr/bin/python2.4 all doc + $(MAKE) prefix=$(PREFIX) PYTHON_PATH=/usr/bin/python2.4 all doc test touch debian/build-stamp debian-clean: diff --git a/diff-tree.c b/diff-tree.c index fc87902a3d..e8f5d1b126 100644 --- a/diff-tree.c +++ b/diff-tree.c @@ -370,6 +370,7 @@ static int diff_tree_commit(const unsigned char *commit, const char *name) } offset += 48; } + free(buf); return 0; } @@ -214,14 +214,10 @@ struct diff_filespec *alloc_filespec(const char *path) { int namelen = strlen(path); struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1); + + memset(spec, 0, sizeof(*spec)); spec->path = (char *)(spec + 1); - strcpy(spec->path, path); - spec->should_free = spec->should_munmap = 0; - spec->xfrm_flags = 0; - spec->size = 0; - spec->data = NULL; - spec->mode = 0; - memset(spec->sha1, 0, 20); + memcpy(spec->path, path, namelen+1); return spec; } @@ -406,13 +402,14 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) return 0; } -void diff_free_filespec(struct diff_filespec *s) +void diff_free_filespec_data(struct diff_filespec *s) { if (s->should_free) free(s->data); else if (s->should_munmap) munmap(s->data, s->size); - free(s); + s->should_free = s->should_munmap = 0; + s->data = NULL; } static void prep_temp_blob(struct diff_tempfile *temp, @@ -765,14 +762,17 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue, dp->status = 0; dp->source_stays = 0; dp->broken_pair = 0; - diff_q(queue, dp); + if (queue) + diff_q(queue, dp); return dp; } void diff_free_filepair(struct diff_filepair *p) { - diff_free_filespec(p->one); - diff_free_filespec(p->two); + diff_free_filespec_data(p->one); + diff_free_filespec_data(p->two); + free(p->one); + free(p->two); free(p); } diff --git a/diffcore-break.c b/diffcore-break.c index b0c8461e12..06f9a7f0ee 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -231,8 +231,8 @@ static void merge_broken(struct diff_filepair *p, dp = diff_queue(outq, d->one, c->two); dp->score = p->score; - diff_free_filespec(d->two); - diff_free_filespec(c->one); + diff_free_filespec_data(d->two); + diff_free_filespec_data(c->one); free(d); free(c); } diff --git a/diffcore-rename.c b/diffcore-rename.c index dbc8522132..092cf68de6 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -47,7 +47,8 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two, if (first < rename_dst_nr) memmove(rename_dst + first + 1, rename_dst + first, (rename_dst_nr - first - 1) * sizeof(*rename_dst)); - rename_dst[first].two = two; + rename_dst[first].two = alloc_filespec(two->path); + fill_filespec(rename_dst[first].two, two->sha1, two->mode); rename_dst[first].pair = NULL; return &(rename_dst[first]); } @@ -201,8 +202,7 @@ static int estimate_similarity(struct diff_filespec *src, return score; } -static void record_rename_pair(struct diff_queue_struct *renq, - int dst_index, int src_index, int score) +static void record_rename_pair(int dst_index, int src_index, int score) { struct diff_filespec *one, *two, *src, *dst; struct diff_filepair *dp; @@ -218,7 +218,7 @@ static void record_rename_pair(struct diff_queue_struct *renq, two = alloc_filespec(dst->path); fill_filespec(two, dst->sha1, dst->mode); - dp = diff_queue(renq, one, two); + dp = diff_queue(NULL, one, two); dp->score = score; dp->source_stays = rename_src[src_index].src_path_left; rename_dst[dst_index].pair = dp; @@ -252,15 +252,14 @@ static int compute_stays(struct diff_queue_struct *q, void diffcore_rename(int detect_rename, int minimum_score) { struct diff_queue_struct *q = &diff_queued_diff; - struct diff_queue_struct renq, outq; + struct diff_queue_struct outq; struct diff_score *mx; - int i, j; + int i, j, rename_count; int num_create, num_src, dst_cnt; if (!minimum_score) minimum_score = DEFAULT_RENAME_SCORE; - renq.queue = NULL; - renq.nr = renq.alloc = 0; + rename_count = 0; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@ -292,19 +291,19 @@ void diffcore_rename(int detect_rename, int minimum_score) struct diff_filespec *one = rename_src[j].one; if (!is_exact_match(one, two)) continue; - record_rename_pair(&renq, i, j, MAX_SCORE); + record_rename_pair(i, j, MAX_SCORE); + rename_count++; break; /* we are done with this entry */ } } - diff_debug_queue("done detecting exact", &renq); /* Have we run out the created file pool? If so we can avoid * doing the delta matrix altogether. */ - if (renq.nr == rename_dst_nr) + if (rename_count == rename_dst_nr) goto cleanup; - num_create = (rename_dst_nr - renq.nr); + num_create = (rename_dst_nr - rename_count); num_src = rename_src_nr; mx = xmalloc(sizeof(*mx) * num_create * num_src); for (dst_cnt = i = 0; i < rename_dst_nr; i++) { @@ -330,14 +329,14 @@ void diffcore_rename(int detect_rename, int minimum_score) continue; /* already done, either exact or fuzzy. */ if (mx[i].score < minimum_score) break; /* there is no more usable pair. */ - record_rename_pair(&renq, mx[i].dst, mx[i].src, mx[i].score); + record_rename_pair(mx[i].dst, mx[i].src, mx[i].score); + rename_count++; } free(mx); - diff_debug_queue("done detecting fuzzy", &renq); cleanup: /* At this point, we have found some renames and copies and they - * are kept in renq. The original list is still in *q. + * are recorded in rename_dst. The original list is still in *q. */ outq.queue = NULL; outq.nr = outq.alloc = 0; @@ -372,9 +371,9 @@ void diffcore_rename(int detect_rename, int minimum_score) * * (1) this is a broken delete and the counterpart * broken create remains in the output; or - * (2) this is not a broken delete, and renq does - * not have a rename/copy to move p->one->path - * out. + * (2) this is not a broken delete, and rename_dst + * does not have a rename/copy to move p->one->path + * out of existence. * * Otherwise, the counterpart broken create * has been turned into a rename-edit; or @@ -390,11 +389,16 @@ void diffcore_rename(int detect_rename, int minimum_score) pair_to_free = p; } else { - for (j = 0; j < renq.nr; j++) - if (!strcmp(renq.queue[j]->one->path, - p->one->path)) - break; - if (j < renq.nr) + for (j = 0; j < rename_dst_nr; j++) { + if (!rename_dst[j].pair) + continue; + if (strcmp(rename_dst[j].pair-> + one->path, + p->one->path)) + continue; + break; + } + if (j < rename_dst_nr) /* this path remains */ pair_to_free = p; } @@ -416,7 +420,6 @@ void diffcore_rename(int detect_rename, int minimum_score) } diff_debug_queue("done copying original", &outq); - free(renq.queue); free(q->queue); *q = outq; diff_debug_queue("done collapsing", q); @@ -438,6 +441,11 @@ void diffcore_rename(int detect_rename, int minimum_score) } } + for (i = 0; i < rename_dst_nr; i++) { + diff_free_filespec_data(rename_dst[i].two); + free(rename_dst[i].two); + } + free(rename_dst); rename_dst = NULL; rename_dst_nr = rename_dst_alloc = 0; diff --git a/diffcore.h b/diffcore.h index 633d1ae5cf..f1b5ca748c 100644 --- a/diffcore.h +++ b/diffcore.h @@ -43,7 +43,7 @@ extern void fill_filespec(struct diff_filespec *, const unsigned char *, unsigned short); extern int diff_populate_filespec(struct diff_filespec *, int); -extern void diff_free_filespec(struct diff_filespec *); +extern void diff_free_filespec_data(struct diff_filespec *); struct diff_filepair { struct diff_filespec *one; @@ -33,42 +33,51 @@ static void report_missing(const char *what, const unsigned char *missing) what, missing_hex, sha1_to_hex(current_commit_sha1)); } -static int make_sure_we_have_it(const char *what, unsigned char *sha1) -{ - int status = 0; - - if (!has_sha1_file(sha1)) { - status = fetch(sha1); - if (status && what) - report_missing(what, sha1); - } - return status; -} - static int process(unsigned char *sha1, const char *type); static int process_tree(struct tree *tree) { - struct tree_entry_list *entries; + struct tree_entry_list *entry; if (parse_tree(tree)) return -1; - for (entries = tree->entries; entries; entries = entries->next) { - if (process(entries->item.any->sha1, - entries->directory ? tree_type : blob_type)) + entry = tree->entries; + tree->entries = NULL; + while (entry) { + struct tree_entry_list *next = entry->next; + if (process(entry->item.any->sha1, + entry->directory ? tree_type : blob_type)) return -1; + free(entry); + entry = next; } return 0; } +#define COMPLETE 1U +#define TO_FETCH 2U +#define TO_SCAN 4U +#define SCANNED 8U + +static struct commit_list *complete = NULL; + static int process_commit(struct commit *commit) { if (parse_commit(commit)) return -1; + while (complete && complete->item->date >= commit->date) { + pop_most_recent_commit(&complete, COMPLETE); + } + + if (commit->object.flags & COMPLETE) + return 0; + memcpy(current_commit_sha1, commit->object.sha1, 20); + pull_say("walk %s\n", sha1_to_hex(commit->object.sha1)); + if (get_tree) { if (process(commit->tree->object.sha1, tree_type)) return -1; @@ -78,10 +87,7 @@ static int process_commit(struct commit *commit) if (get_history) { struct commit_list *parents = commit->parents; for (; parents; parents = parents->next) { - if (has_sha1_file(parents->item->object.sha1)) - continue; - if (process(parents->item->object.sha1, - commit_type)) + if (process(parents->item->object.sha1, commit_type)) return -1; } } @@ -100,6 +106,10 @@ static struct object_list **process_queue_end = &process_queue; static int process_object(struct object *obj) { + if (obj->flags & SCANNED) + return 0; + obj->flags |= SCANNED; + if (obj->type == commit_type) { if (process_commit((struct commit *)obj)) return -1; @@ -126,17 +136,23 @@ static int process_object(struct object *obj) static int process(unsigned char *sha1, const char *type) { struct object *obj = lookup_object_type(sha1, type); + if (has_sha1_file(sha1)) { parse_object(sha1); /* We already have it, so we should scan it now. */ - return process_object(obj); + if (obj->flags & (SCANNED | TO_SCAN)) + return 0; + object_list_insert(obj, process_queue_end); + process_queue_end = &(*process_queue_end)->next; + obj->flags |= TO_SCAN; + return 0; } - if (object_list_contains(process_queue, obj)) + if (obj->flags & (COMPLETE | TO_FETCH)) return 0; object_list_insert(obj, process_queue_end); process_queue_end = &(*process_queue_end)->next; + obj->flags |= TO_FETCH; - //fprintf(stderr, "prefetch %s\n", sha1_to_hex(sha1)); prefetch(sha1); return 0; @@ -144,21 +160,27 @@ static int process(unsigned char *sha1, const char *type) static int loop(void) { + struct object_list *elem; + while (process_queue) { struct object *obj = process_queue->item; - /* - fprintf(stderr, "%d objects to pull\n", - object_list_length(process_queue)); - */ - process_queue = process_queue->next; + elem = process_queue; + process_queue = elem->next; + free(elem); if (!process_queue) process_queue_end = &process_queue; - //fprintf(stderr, "fetch %s\n", sha1_to_hex(obj->sha1)); - - if (make_sure_we_have_it(obj->type ? obj->type : "object", - obj->sha1)) - return -1; + /* If we are not scanning this object, we placed it in + * the queue because we needed to fetch it first. + */ + if (! (obj->flags & TO_SCAN)) { + if (fetch(obj->sha1)) { + report_missing(obj->type + ? obj->type + : "object", obj->sha1); + return -1; + } + } if (!obj->type) parse_object(obj->sha1); if (process_object(obj)) @@ -179,18 +201,30 @@ static int interpret_target(char *target, unsigned char *sha1) return -1; } +static int mark_complete(const char *path, const unsigned char *sha1) +{ + struct commit *commit = lookup_commit_reference_gently(sha1, 1); + if (commit) { + commit->object.flags |= COMPLETE; + insert_by_date(commit, &complete); + } + return 0; +} int pull(char *target) { unsigned char sha1[20]; int fd = -1; + save_commit_buffer = 0; if (write_ref && current_ref) { fd = lock_ref_sha1(write_ref, current_ref); if (fd < 0) return -1; } + for_each_ref(mark_complete); + if (interpret_target(target, sha1)) return error("Could not interpret %s as something to pull", target); diff --git a/git-bisect.sh b/git-bisect.sh index a5be3a7293..8dc77c991c 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -110,7 +110,7 @@ bisect_next_check() { } bisect_auto_next() { - bisect_next_check && bisect_next + bisect_next_check && bisect_next || : } bisect_next() { diff --git a/git-branch.sh b/git-branch.sh index 81b9e6cce1..dcec2a9f2f 100755 --- a/git-branch.sh +++ b/git-branch.sh @@ -3,7 +3,7 @@ . git-sh-setup || die "Not a git archive" usage () { - echo >&2 "usage: $(basename $0)"' [<branchname> [start-point]] + echo >&2 "usage: $(basename $0)"' [-d <branch>] | [<branch> [start-point]] If no arguments, show available branches and mark current branch with a star. If one argument, create a new branch <branchname> based off of current HEAD. @@ -12,6 +12,59 @@ If two arguments, create a new branch <branchname> based off of <start-point>. exit 1 } +delete_branch () { + option="$1" branch_name="$2" + headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||') + case ",$headref," in + ",$branch_name,") + die "Cannot delete the branch you are on." ;; + ,,) + die "What branch are you on anyway?" ;; + esac + branch=$(cat "$GIT_DIR/refs/heads/$branch_name") && + branch=$(git-rev-parse --verify "$branch^0") || + die "Seriously, what branch are you talking about?" + case "$option" in + -D) + ;; + *) + mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ') + case " $mbs " in + *' '$branch' '*) + # the merge base of branch and HEAD contains branch -- + # which means that the HEAD contains everything in the HEAD. + ;; + *) + echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD. +If you are sure you want to delete it, run 'git branch -D $branch_name'." + exit 1 + ;; + esac + ;; + esac + rm -f "$GIT_DIR/refs/heads/$branch_name" + echo "Deleted branch $branch_name." + exit 0 +} + +while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac +do + case "$1" in + -d | -D) + delete_branch "$1" "$2" + exit + ;; + --) + shift + break + ;; + -*) + usage + ;; + esac + shift +done + case "$#" in 0) headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||') @@ -36,11 +89,6 @@ case "$#" in esac branchname="$1" -case "$branchname" in --*) - usage;; -esac - rev=$(git-rev-parse --verify "$head") || exit [ -e "$GIT_DIR/refs/heads/$branchname" ] && die "$branchname already exists" diff --git a/git-checkout.sh b/git-checkout.sh index 4a605cd9c6..e02c7afbae 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -22,7 +22,8 @@ while [ "$#" != "0" ]; do force=1 ;; *) - rev=$(git-rev-parse --verify "$arg^0") || exit + rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) || + die "hey dummy, branch '$arg' doesn't exist." if [ -z "$rev" ]; then echo "unknown flag $arg" exit 1 diff --git a/git-clone.sh b/git-clone.sh index a21f13af2a..bfb8fd6285 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -144,8 +144,32 @@ yes,yes) *) case "$repo" in rsync://*) - rsync $quiet -avz --ignore-existing "$repo/objects/" "$D/.git/objects/" && - rsync $quiet -avz --ignore-existing "$repo/refs/" "$D/.git/refs/" + rsync $quiet -av --ignore-existing \ + --exclude info "$repo/objects/" "$D/.git/objects/" && + rsync $quiet -av --ignore-existing \ + --exclude info "$repo/refs/" "$D/.git/refs/" || exit + + # Look at objects/info/alternates for rsync -- http will + # support it natively and git native ones will do it on the + # remote end. Not having that file is not a crime. + rsync -q "$repo/objects/info/alternates" "$D/.git/TMP_ALT" || + rm -f "$D/.git/TMP_ALT" + if test -f "$D/.git/TMP_ALT" + then + ( cd $D && + . git-parse-remote && + resolve_alternates "$repo" <"./.git/TMP_ALT" ) | + while read alt + do + case "$alt" in 'bad alternate: '*) die "$alt";; esac + case "$quiet" in + '') echo >&2 "Getting alternate: $alt" ;; + esac + rsync $quiet -av --ignore-existing \ + --exclude info "$alt" "$D/.git/objects" || exit + done + rm -f "$D/.git/TMP_ALT" + fi ;; http://*) clone_dumb_http "$repo" "$D" diff --git a/git-core.spec.in b/git-core.spec.in index f98f8db7c7..6c17d523f9 100644 --- a/git-core.spec.in +++ b/git-core.spec.in @@ -1,16 +1,15 @@ # Pass --without docs to rpmbuild if you don't want the documetnation Name: git-core Version: @@VERSION@@ -Release: 1 -Vendor: Junio C Hamano <junkio@cox.net> +Release: 1%{?dist} Summary: Git core and tools License: GPL Group: Development/Tools URL: http://kernel.org/pub/software/scm/git/ Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz BuildRequires: zlib-devel, openssl-devel, curl-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3} -BuildRoot: %{_tmppath}/%{name}-%{version}-root -Requires: sh-utils, curl, diffutils, rsync, rcs, openssh-clients, perl, python >= 2.4, tk +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Requires: rsync, rcs, curl, less, openssh-clients, python >= 2.4, tk %description This is a stupid (but extremely fast) directory content manager. It @@ -24,7 +23,7 @@ elsewhere for tools for ordinary humans layered on top of this. %setup -q %build -make prefix=%{_prefix} all %{!?_without_docs: doc} +make COPTS="$RPM_OPT_FLAGS" prefix=%{_prefix} all %{!?_without_docs: doc} %install rm -rf $RPM_BUILD_ROOT @@ -37,17 +36,35 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/* -%{_datadir}/git-core/templates/* +%{_datadir}/git-core/ %doc README COPYING Documentation/*.txt %{!?_without_docs: %doc Documentation/*.html } %{!?_without_docs: %{_mandir}/man1/*.1*} %{!?_without_docs: %{_mandir}/man7/*.7*} %changelog +* Fri Sep 16 2005 Chris Wright <chrisw@osdl.org> 0.99.6-1 +- update to 0.99.6 + +* Fri Sep 16 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl> +- Linus noticed that less is required, added to the dependencies + * Sun Sep 11 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl> - Updated dependencies - Don't assume manpages are gzipped +* Thu Aug 18 2005 Chris Wright <chrisw@osdl.org> 0.99.4-4 +- drop sh_utils, sh-utils, diffutils, mktemp, and openssl Requires +- use RPM_OPT_FLAGS in spec file, drop patch0 + +* Wed Aug 17 2005 Tom "spot" Callaway <tcallawa@redhat.com> 0.99.4-3 +- use dist tag to differentiate between branches +- use rpm optflags by default (patch0) +- own %{_datadir}/git-core/ + +* Mon Aug 15 2005 Chris Wright <chrisw@osdl.org> +- update spec file to fix Buildroot, Requires, and drop Vendor + * Sun Aug 07 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl> - Redid the description - Cut overlong make line, loosened changelog a bit diff --git a/git-fetch.sh b/git-fetch.sh index 2273944038..72f17ab6c9 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -183,12 +183,30 @@ do ;; rsync://*) TMP_HEAD="$GIT_DIR/TMP_HEAD" - rsync -L "$remote/$remote_name" "$TMP_HEAD" || exit 1 + rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1 head=$(git-rev-parse TMP_HEAD) rm -f "$TMP_HEAD" test "$rsync_slurped_objects" || { - rsync -avz --ignore-existing "$remote/objects/" \ - "$GIT_OBJECT_DIRECTORY/" || exit + rsync -av --ignore-existing --exclude info \ + "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit + + # Look at objects/info/alternates for rsync -- http will + # support it natively and git native ones will do it on the remote + # end. Not having that file is not a crime. + rsync -q "$remote/objects/info/alternates" "$GIT_DIR/TMP_ALT" || + rm -f "$GIT_DIR/TMP_ALT" + if test -f "$GIT_DIR/TMP_ALT" + then + resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" | + while read alt + do + case "$alt" in 'bad alternate: '*) die "$alt";; esac + echo >&2 "Getting alternate: $alt" + rsync -av --ignore-existing --exclude info \ + "$alt" "$GIT_OBJECT_DIRECTORY/" || exit + done + rm -f "$GIT_DIR/TMP_ALT" + fi rsync_slurped_objects=t } ;; diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 3c5d94b344..a9db0cd825 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -153,3 +153,24 @@ get_remote_refs_for_fetch () { ;; esac } + +resolve_alternates () { + # original URL (xxx.git) + top_=`expr "$1" : '\([^:]*:/*[^/]*\)/'` + while read path + do + case "$path" in + \#* | '') + continue ;; + /*) + echo "$top_$path/" ;; + ../*) + # relative -- ugly but seems to work. + echo "$1/objects/$path/" ;; + *) + # exit code may not be caught by the reader. + echo "bad alternate: $path" + exit 1 ;; + esac + done +} diff --git a/git-pull.sh b/git-pull.sh index c1b4474495..8cf39e7f64 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -25,8 +25,10 @@ then fi merge_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ') -merge_name=$(sed -e 's/^[0-9a-f]* //' "$GIT_DIR"/FETCH_HEAD | - tr '\012' ' ') +merge_name=$( + perl -e 'print join("; ", map { chomp; s/^[0-9a-f]* //; $_ } <>)' \ + "$GIT_DIR"/FETCH_HEAD +) case "$merge_head" in '') diff --git a/git-repack.sh b/git-repack.sh index 064c85cbb6..b395d0ef34 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -58,7 +58,15 @@ then # all-into-one is used. if test "$all_into_one" != '' && test "$existing" != '' then - ( cd "$PACKDIR" && rm -f $existing ) + ( cd "$PACKDIR" && + for e in $existing + do + case "$e" in + ./pack-$name.pack | ./pack-$name.idx) ;; + *) rm -f $e ;; + esac + done + ) fi fi diff --git a/git-shortlog.perl b/git-shortlog.perl index 107c895df3..8f0984be02 100755 --- a/git-shortlog.perl +++ b/git-shortlog.perl @@ -108,7 +108,7 @@ sub changelog_input { if ($pstate == 1) { my ($email); - next unless /^Author: (.*)<(.*)>.*$/; + next unless /^[Aa]uthor:? (.*)<(.*)>.*$/; $n_records++; diff --git a/http-fetch.c b/http-fetch.c index 4e564fc453..17051fe43a 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -14,8 +14,19 @@ #endif static CURL *curl; +static struct curl_slist *no_pragma_header; -static char *base; +static char *initial_base; + +struct alt_base +{ + char *base; + int got_indices; + struct packed_git *packs; + struct alt_base *next; +}; + +struct alt_base *alt = NULL; static SHA_CTX c; static z_stream stream; @@ -71,11 +82,9 @@ void prefetch(unsigned char *sha1) { } -static int got_indices = 0; - -static struct packed_git *packs = NULL; +static int got_alternates = 0; -static int fetch_index(unsigned char *sha1) +static int fetch_index(struct alt_base *repo, unsigned char *sha1) { char *filename; char *url; @@ -89,9 +98,9 @@ static int fetch_index(unsigned char *sha1) fprintf(stderr, "Getting index for pack %s\n", sha1_to_hex(sha1)); - url = xmalloc(strlen(base) + 64); + url = xmalloc(strlen(repo->base) + 64); sprintf(url, "%s/objects/pack/pack-%s.idx", - base, sha1_to_hex(sha1)); + repo->base, sha1_to_hex(sha1)); filename = sha1_pack_index_name(sha1); indexfile = fopen(filename, "w"); @@ -102,6 +111,7 @@ static int fetch_index(unsigned char *sha1) curl_easy_setopt(curl, CURLOPT_FILE, indexfile); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header); if (curl_easy_perform(curl)) { fclose(indexfile); @@ -112,22 +122,92 @@ static int fetch_index(unsigned char *sha1) return 0; } -static int setup_index(unsigned char *sha1) +static int setup_index(struct alt_base *repo, unsigned char *sha1) { struct packed_git *new_pack; if (has_pack_file(sha1)) return 0; // don't list this as something we can get - if (fetch_index(sha1)) + if (fetch_index(repo, sha1)) return -1; new_pack = parse_pack_index(sha1); - new_pack->next = packs; - packs = new_pack; + new_pack->next = repo->packs; + repo->packs = new_pack; return 0; } -static int fetch_indices(void) +static int fetch_alternates(char *base) +{ + int ret = 0; + struct buffer buffer; + char *url; + char *data; + int i = 0; + if (got_alternates) + return 0; + data = xmalloc(4096); + buffer.size = 4096; + buffer.posn = 0; + buffer.buffer = data; + + if (get_verbosely) + fprintf(stderr, "Getting alternates list\n"); + + url = xmalloc(strlen(base) + 31); + sprintf(url, "%s/objects/info/http-alternates", base); + + curl_easy_setopt(curl, CURLOPT_FILE, &buffer); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(curl, CURLOPT_URL, url); + + if (curl_easy_perform(curl) || !buffer.posn) { + sprintf(url, "%s/objects/info/alternates", base); + + curl_easy_setopt(curl, CURLOPT_FILE, &buffer); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(curl, CURLOPT_URL, url); + + if (curl_easy_perform(curl)) { + return 0; + } + } + + while (i < buffer.posn) { + int posn = i; + while (posn < buffer.posn && data[posn] != '\n') + posn++; + if (data[posn] == '\n') { + if (data[i] == '/') { + int serverlen = strchr(base + 8, '/') - base; + // skip 'objects' at end + char *target = + xmalloc(serverlen + posn - i - 6); + struct alt_base *newalt; + strncpy(target, base, serverlen); + strncpy(target + serverlen, data + i, + posn - i - 7); + target[serverlen + posn - i - 7] = '\0'; + if (get_verbosely) + fprintf(stderr, + "Also look at %s\n", target); + newalt = xmalloc(sizeof(*newalt)); + newalt->next = alt; + newalt->base = target; + newalt->got_indices = 0; + newalt->packs = NULL; + alt = newalt; + ret++; + } + } + i = posn + 1; + } + got_alternates = 1; + + return ret; +} + +static int fetch_indices(struct alt_base *repo) { unsigned char sha1[20]; char *url; @@ -135,7 +215,7 @@ static int fetch_indices(void) char *data; int i = 0; - if (got_indices) + if (repo->got_indices) return 0; data = xmalloc(4096); @@ -146,18 +226,19 @@ static int fetch_indices(void) if (get_verbosely) fprintf(stderr, "Getting pack list\n"); - url = xmalloc(strlen(base) + 21); - sprintf(url, "%s/objects/info/packs", base); + url = xmalloc(strlen(repo->base) + 21); + sprintf(url, "%s/objects/info/packs", repo->base); curl_easy_setopt(curl, CURLOPT_FILE, &buffer); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); if (curl_easy_perform(curl)) { return error("Unable to get pack index %s", url); } - do { + while (i < buffer.posn) { switch (data[i]) { case 'P': i++; @@ -165,7 +246,7 @@ static int fetch_indices(void) !strncmp(data + i, " pack-", 6) && !strncmp(data + i + 46, ".pack\n", 6)) { get_sha1_hex(data + i + 6, sha1); - setup_index(sha1); + setup_index(repo, sha1); i += 51; break; } @@ -174,13 +255,13 @@ static int fetch_indices(void) i++; } i++; - } while (i < buffer.posn); + } - got_indices = 1; + repo->got_indices = 1; return 0; } -static int fetch_pack(unsigned char *sha1) +static int fetch_pack(struct alt_base *repo, unsigned char *sha1) { char *url; struct packed_git *target; @@ -188,12 +269,11 @@ static int fetch_pack(unsigned char *sha1) FILE *packfile; char *filename; - if (fetch_indices()) + if (fetch_indices(repo)) return -1; - target = find_sha1_pack(sha1, packs); + target = find_sha1_pack(sha1, repo->packs); if (!target) - return error("Couldn't get %s: not separate or in any pack", - sha1_to_hex(sha1)); + return -1; if (get_verbosely) { fprintf(stderr, "Getting pack %s\n", @@ -202,9 +282,9 @@ static int fetch_pack(unsigned char *sha1) sha1_to_hex(sha1)); } - url = xmalloc(strlen(base) + 65); + url = xmalloc(strlen(repo->base) + 65); sprintf(url, "%s/objects/pack/pack-%s.pack", - base, sha1_to_hex(target->sha1)); + repo->base, sha1_to_hex(target->sha1)); filename = sha1_pack_name(target->sha1); packfile = fopen(filename, "w"); @@ -215,6 +295,7 @@ static int fetch_pack(unsigned char *sha1) curl_easy_setopt(curl, CURLOPT_FILE, packfile); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header); if (curl_easy_perform(curl)) { fclose(packfile); @@ -223,7 +304,7 @@ static int fetch_pack(unsigned char *sha1) fclose(packfile); - lst = &packs; + lst = &repo->packs; while (*lst != target) lst = &((*lst)->next); *lst = (*lst)->next; @@ -233,7 +314,7 @@ static int fetch_pack(unsigned char *sha1) return 0; } -int fetch(unsigned char *sha1) +int fetch_object(struct alt_base *repo, unsigned char *sha1) { char *hex = sha1_to_hex(sha1); char *filename = sha1_file_name(sha1); @@ -255,10 +336,11 @@ int fetch(unsigned char *sha1) curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt(curl, CURLOPT_FILE, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header); - url = xmalloc(strlen(base) + 50); - strcpy(url, base); - posn = url + strlen(base); + url = xmalloc(strlen(repo->base) + 50); + strcpy(url, repo->base); + posn = url + strlen(repo->base); strcpy(posn, "objects/"); posn += 8; memcpy(posn, hex, 2); @@ -270,9 +352,7 @@ int fetch(unsigned char *sha1) if (curl_easy_perform(curl)) { unlink(filename); - if (fetch_pack(sha1)) - return error("Tried %s", url); - return 0; + return -1; } close(local); @@ -291,11 +371,30 @@ int fetch(unsigned char *sha1) return 0; } +int fetch(unsigned char *sha1) +{ + struct alt_base *altbase = alt; + while (altbase) { + if (!fetch_object(altbase, sha1)) + return 0; + if (!fetch_pack(altbase, sha1)) + return 0; + if (fetch_alternates(altbase->base) > 0) { + altbase = alt; + continue; + } + altbase = altbase->next; + } + return error("Unable to find %s under %s\n", sha1_to_hex(sha1), + initial_base); +} + int fetch_ref(char *ref, unsigned char *sha1) { char *url, *posn; char hex[42]; struct buffer buffer; + char *base = initial_base; buffer.size = 41; buffer.posn = 0; buffer.buffer = hex; @@ -303,6 +402,7 @@ int fetch_ref(char *ref, unsigned char *sha1) curl_easy_setopt(curl, CURLOPT_FILE, &buffer); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); url = xmalloc(strlen(base) + 6 + strlen(ref)); strcpy(url, base); @@ -354,6 +454,7 @@ int main(int argc, char **argv) curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); + no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); curl_ssl_verify = getenv("GIT_SSL_NO_VERIFY") ? 0 : 1; curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify); @@ -361,11 +462,17 @@ int main(int argc, char **argv) curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif - base = url; + alt = xmalloc(sizeof(*alt)); + alt->base = url; + alt->got_indices = 0; + alt->packs = NULL; + alt->next = NULL; + initial_base = url; if (pull(commit_id)) return 1; + curl_slist_free_all(no_pragma_header); curl_global_cleanup(); return 0; } @@ -36,13 +36,11 @@ int setup_ident(void) memcpy(real_email, pw->pw_name, len); real_email[len++] = '@'; gethostname(real_email + len, sizeof(real_email) - len); -#ifndef NO_GETDOMAINNAME if (!strchr(real_email+len, '.')) { len = strlen(real_email); real_email[len++] = '.'; getdomainname(real_email+len, sizeof(real_email)-len); } -#endif /* And set the default date */ datestamp(real_date, sizeof(real_date)); return 0; @@ -9,6 +9,8 @@ struct object **objs; int nr_objs; static int obj_allocs; +int track_object_refs = 1; + static int find_object(const unsigned char *sha1) { int first = 0, last = nr_objs; @@ -67,9 +69,12 @@ void created_object(const unsigned char *sha1, struct object *obj) void add_ref(struct object *refer, struct object *target) { - struct object_list **pp = &refer->refs; - struct object_list *p; - + struct object_list **pp, *p; + + if (!track_object_refs) + return; + + pp = &refer->refs; while ((p = *pp) != NULL) { if (p->item == target) return; @@ -87,6 +92,8 @@ void mark_reachable(struct object *obj, unsigned int mask) { struct object_list *p = obj->refs; + if (!track_object_refs) + die("cannot do reachability with object refs turned off"); /* If we've been here already, don't bother */ if (obj->flags & mask) return; @@ -17,6 +17,7 @@ struct object { void *util; }; +extern int track_object_refs; extern int nr_objs; extern struct object **objs; diff --git a/rev-cache.c b/rev-cache.c deleted file mode 100644 index 6344d62247..0000000000 --- a/rev-cache.c +++ /dev/null @@ -1,318 +0,0 @@ -#include "refs.h" -#include "cache.h" -#include "rev-cache.h" - -struct rev_cache **rev_cache; -int nr_revs, alloc_revs; - -static struct rev_list_elem *rle_free; - -#define BATCH_SIZE 512 - -int find_rev_cache(const unsigned char *sha1) -{ - int lo = 0, hi = nr_revs; - while (lo < hi) { - int mi = (lo + hi) / 2; - struct rev_cache *ri = rev_cache[mi]; - int cmp = memcmp(sha1, ri->sha1, 20); - if (!cmp) - return mi; - if (cmp < 0) - hi = mi; - else - lo = mi + 1; - } - return -lo - 1; -} - -static struct rev_list_elem *alloc_list_elem(void) -{ - struct rev_list_elem *rle; - if (!rle_free) { - int i; - - rle = xmalloc(sizeof(*rle) * BATCH_SIZE); - for (i = 0; i < BATCH_SIZE - 1; i++) { - rle[i].ri = NULL; - rle[i].next = &rle[i + 1]; - } - rle[BATCH_SIZE - 1].ri = NULL; - rle[BATCH_SIZE - 1].next = NULL; - rle_free = rle; - } - rle = rle_free; - rle_free = rle->next; - return rle; -} - -static struct rev_cache *create_rev_cache(const unsigned char *sha1) -{ - struct rev_cache *ri; - int pos = find_rev_cache(sha1); - - if (0 <= pos) - return rev_cache[pos]; - pos = -pos - 1; - if (alloc_revs <= ++nr_revs) { - alloc_revs = alloc_nr(alloc_revs); - rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs); - } - if (pos < nr_revs) - memmove(rev_cache + pos + 1, rev_cache + pos, - (nr_revs - pos - 1) * sizeof(ri)); - ri = xcalloc(1, sizeof(*ri)); - memcpy(ri->sha1, sha1, 20); - rev_cache[pos] = ri; - return ri; -} - -static unsigned char last_sha1[20]; - -static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri) -{ - unsigned char flag; - struct rev_list_elem *rle; - - if (ri->written) - return; - - if (ri->parsed) { - /* We use last_sha1 compression only for the first parent; - * otherwise the resulting rev-cache would lose the parent - * order information. - */ - if (ri->parents && - !memcmp(ri->parents->ri->sha1, last_sha1, 20)) - flag = (ri->num_parents - 1) | 0x80; - else - flag = ri->num_parents; - - fwrite(ri->sha1, 20, 1, rev_cache_file); - fwrite(&flag, 1, 1, rev_cache_file); - for (rle = ri->parents; rle; rle = rle->next) { - if (flag & 0x80 && rle == ri->parents) - continue; - fwrite(rle->ri->sha1, 20, 1, rev_cache_file); - } - memcpy(last_sha1, ri->sha1, 20); - ri->written = 1; - } - /* recursively write children depth first */ - for (rle = ri->children; rle; rle = rle->next) - write_one_rev_cache(rev_cache_file, rle->ri); -} - -void write_rev_cache(const char *newpath, const char *oldpath) -{ - /* write the following commit ancestry information in - * $GIT_DIR/info/rev-cache. - * - * The format is: - * 20-byte SHA1 (commit ID) - * 1-byte flag: - * - bit 0-6 records "number of parent commit SHA1s to - * follow" (i.e. up to 127 children can be listed). - * - when the bit 7 is on, then "the entry immediately - * before this entry is one of the parents of this - * commit". - * N x 20-byte SHA1 (parent commit IDs) - */ - FILE *rev_cache_file; - int i; - struct rev_cache *ri; - - if (!strcmp(newpath, oldpath)) { - /* If we are doing it in place */ - rev_cache_file = fopen(newpath, "a"); - } - else { - char buf[8096]; - size_t sz; - FILE *oldfp = fopen(oldpath, "r"); - rev_cache_file = fopen(newpath, "w"); - if (oldfp) { - while (1) { - sz = fread(buf, 1, sizeof(buf), oldfp); - if (sz == 0) - break; - fwrite(buf, 1, sz, rev_cache_file); - } - fclose(oldfp); - } - } - - memset(last_sha1, 0, 20); - - /* Go through available rev_cache structures, starting from - * parentless ones first, so that we would get most out of - * last_sha1 optimization by the depth first behaviour of - * write_one_rev_cache(). - */ - for (i = 0; i < nr_revs; i++) { - ri = rev_cache[i]; - if (ri->num_parents) - continue; - write_one_rev_cache(rev_cache_file, ri); - } - /* Then the rest */ - for (i = 0; i < nr_revs; i++) { - ri = rev_cache[i]; - write_one_rev_cache(rev_cache_file, ri); - } - fclose(rev_cache_file); -} - -static void add_parent(struct rev_cache *child, - const unsigned char *parent_sha1) -{ - struct rev_cache *parent = create_rev_cache(parent_sha1); - struct rev_list_elem *e = alloc_list_elem(); - - /* Keep the parent list ordered in the same way the commit - * object records them. - */ - e->ri = parent; - e->next = NULL; - if (!child->parents_tail) - child->parents = e; - else - child->parents_tail->next = e; - child->parents_tail = e; - child->num_parents++; - - /* There is no inherent order of the children so we just - * LIFO them together. - */ - e = alloc_list_elem(); - e->next = parent->children; - parent->children = e; - e->ri = child; - parent->num_children++; -} - -int read_rev_cache(const char *path, FILE *dumpfile, int dry_run) -{ - unsigned char *map; - int fd; - struct stat st; - unsigned long ofs, len; - struct rev_cache *ri = NULL; - - fd = open(path, O_RDONLY); - if (fd < 0) { - if (dry_run) - return error("cannot open %s", path); - if (errno == ENOENT) - return 0; - return -1; - } - if (fstat(fd, &st)) { - close(fd); - return -1; - } - map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (map == MAP_FAILED) - return -1; - - memset(last_sha1, 0, 20); - ofs = 0; - len = st.st_size; - while (ofs < len) { - unsigned char sha1[20]; - int flag, cnt, i; - if (len < ofs + 21) - die("rev-cache too short"); - memcpy(sha1, map + ofs, 20); - flag = map[ofs + 20]; - ofs += 21; - cnt = (flag & 0x7f) + ((flag & 0x80) != 0); - if (len < ofs + (flag & 0x7f) * 20) - die("rev-cache too short to have %d more parents", - (flag & 0x7f)); - if (dumpfile) - fprintf(dumpfile, "%s", sha1_to_hex(sha1)); - if (!dry_run) { - ri = create_rev_cache(sha1); - if (!ri) - die("cannot create rev-cache for %s", - sha1_to_hex(sha1)); - ri->written = ri->parsed = 1; - } - i = 0; - if (flag & 0x80) { - if (!dry_run) - add_parent(ri, last_sha1); - if (dumpfile) - fprintf(dumpfile, " %s", - sha1_to_hex(last_sha1)); - i++; - } - while (i++ < cnt) { - if (!dry_run) - add_parent(ri, map + ofs); - if (dumpfile) - fprintf(dumpfile, " %s", - sha1_to_hex(last_sha1)); - ofs += 20; - } - if (dumpfile) - fprintf(dumpfile, "\n"); - memcpy(last_sha1, sha1, 20); - } - if (ofs != len) - die("rev-cache truncated?"); - munmap(map, len); - return 0; -} - -int record_rev_cache(const unsigned char *sha1, FILE *dumpfile) -{ - unsigned char parent[20]; - char type[20]; - unsigned long size, ofs; - unsigned int cnt, i; - void *buf; - struct rev_cache *ri; - - buf = read_sha1_file(sha1, type, &size); - if (!buf) - return error("%s: not found", sha1_to_hex(sha1)); - if (strcmp(type, "commit")) { - free(buf); - return error("%s: not a commit but a %s", - sha1_to_hex(sha1), type); - } - ri = create_rev_cache(sha1); - if (ri->parsed) - return 0; - if (dumpfile) - fprintf(dumpfile, "commit %s\n", sha1_to_hex(sha1)); - - cnt = 0; - ofs = 46; /* "tree " + hex-sha1 + "\n" */ - while (!memcmp(buf + ofs, "parent ", 7) && - !get_sha1_hex(buf + ofs + 7, parent)) { - ofs += 48; - cnt++; - } - if (cnt * 48 + 46 != ofs) { - free(buf); - die("internal error in record_rev_cache"); - } - - ri = create_rev_cache(sha1); - ri->parsed = 1; - - for (i = 0; i < cnt; i++) { - unsigned char parent_sha1[20]; - - ofs = 46 + i * 48 + 7; - get_sha1_hex(buf + ofs, parent_sha1); - add_parent(ri, parent_sha1); - record_rev_cache(parent_sha1, dumpfile); - } - free(buf); - return 0; -} diff --git a/rev-cache.h b/rev-cache.h deleted file mode 100644 index b238ac640c..0000000000 --- a/rev-cache.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef REV_CACHE_H -#define REV_CACHE_H - -extern struct rev_cache { - struct rev_cache *head_list; - struct rev_list_elem *children; - struct rev_list_elem *parents; - struct rev_list_elem *parents_tail; - unsigned short num_parents; - unsigned short num_children; - unsigned int written : 1; - unsigned int parsed : 1; - unsigned int work : 30; - void *work_ptr; - unsigned char sha1[20]; -} **rev_cache; -extern int nr_revs, alloc_revs; - -struct rev_list_elem { - struct rev_list_elem *next; - struct rev_cache *ri; -}; - -extern int find_rev_cache(const unsigned char *); -extern int read_rev_cache(const char *, FILE *, int); -extern int record_rev_cache(const unsigned char *, FILE *); -extern void write_rev_cache(const char *new, const char *old); - -#endif diff --git a/rev-list.c b/rev-list.c index 2d97cdb64b..e41d5a045c 100644 --- a/rev-list.c +++ b/rev-list.c @@ -147,11 +147,16 @@ static struct object_list **process_tree(struct tree *tree, struct object_list * die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; p = add_object(obj, p, name); - for (entry = tree->entries ; entry ; entry = entry->next) { + entry = tree->entries; + tree->entries = NULL; + while (entry) { + struct tree_entry_list *next = entry->next; if (entry->directory) p = process_tree(entry->item.tree, p, entry->name); else p = process_blob(entry->item.blob, p, entry->name); + free(entry); + entry = next; } return p; } @@ -218,12 +223,15 @@ static void mark_tree_uninteresting(struct tree *tree) if (parse_tree(tree) < 0) die("bad tree %s", sha1_to_hex(obj->sha1)); entry = tree->entries; + tree->entries = NULL; while (entry) { + struct tree_entry_list *next = entry->next; if (entry->directory) mark_tree_uninteresting(entry->item.tree); else mark_blob_uninteresting(entry->item.blob); - entry = entry->next; + free(entry); + entry = next; } } @@ -231,8 +239,6 @@ static void mark_parents_uninteresting(struct commit *commit) { struct commit_list *parents = commit->parents; - if (tree_objects) - mark_tree_uninteresting(commit->tree); while (parents) { struct commit *commit = parents->item; commit->object.flags |= UNINTERESTING; @@ -272,29 +278,6 @@ static int everybody_uninteresting(struct commit_list *orig) continue; return 0; } - - /* - * Ok, go back and mark all the edge trees uninteresting, - * since otherwise we can have situations where a parent - * that was marked uninteresting (and we never even had - * to look at) had lots of objects that we don't want to - * include. - * - * NOTE! This still doesn't mean that the object list is - * "correct", since we may end up listing objects that - * even older commits (that we don't list) do actually - * reference, but it gets us to a minimal list (or very - * close) in practice. - */ - if (!tree_objects) - return 1; - - while (orig) { - struct commit *commit = orig->item; - if (!parse_commit(commit) && commit->tree) - mark_tree_uninteresting(commit->tree); - orig = orig->next; - } return 1; } @@ -370,6 +353,19 @@ static struct commit_list *find_bisection(struct commit_list *list) return best; } +static void mark_edges_uninteresting(struct commit_list *list) +{ + for ( ; list; list = list->next) { + struct commit_list *parents = list->item->parents; + + for ( ; parents; parents = parents->next) { + struct commit *commit = parents->item; + if (commit->object.flags & UNINTERESTING) + mark_tree_uninteresting(commit->tree); + } + } +} + static struct commit_list *limit_list(struct commit_list *list) { struct commit_list *newlist = NULL; @@ -388,6 +384,8 @@ static struct commit_list *limit_list(struct commit_list *list) } p = &commit_list_insert(commit, p)->next; } + if (tree_objects) + mark_edges_uninteresting(newlist); if (bisect_list) newlist = find_bisection(newlist); return newlist; @@ -563,6 +561,8 @@ int main(int argc, char **argv) struct commit *exclude = NULL; struct commit *include = NULL; *dotdot = 0; + if (!*next) + next = "HEAD"; exclude = get_commit_reference(arg, UNINTERESTING); include = get_commit_reference(next, 0); if (exclude && include) { @@ -571,7 +571,7 @@ int main(int argc, char **argv) handle_one_commit(include, &list); continue; } - *next = '.'; + *dotdot = '.'; } if (*arg == '^') { flags = UNINTERESTING; @@ -582,6 +582,9 @@ int main(int argc, char **argv) handle_one_commit(commit, &list); } + save_commit_buffer = verbose_header; + track_object_refs = 0; + if (!merge_order) { sort_by_date(&list); if (limited) @@ -8,6 +8,71 @@ #define COMMAND_SIZE 4096 +/* + * Write a shell-quoted version of a string into a buffer, and + * return bytes that ought to be output excluding final null. + */ +static int shell_quote(char *buf, int nmax, const char *str) +{ + char ch; + int nq; + int oc = 0; + + while ( (ch = *str++) ) { + nq = 0; + if ( strchr(" !\"#$%&\'()*;<=>?[\\]^`{|}", ch) ) + nq = 1; + + if ( nq ) { + if ( nmax > 1 ) { + *buf++ = '\\'; + nmax--; + } + oc++; + } + + if ( nmax > 1 ) { + *buf++ = ch; + nmax--; + } + oc++; + } + + if ( nmax ) + *buf = '\0'; + + return oc; +} + +/* + * Append a string to a string buffer, with or without quoting. Return true + * if the buffer overflowed. + */ +static int add_to_string(char **ptrp, int *sizep, const char *str, int quote) +{ + char *p = *ptrp; + int size = *sizep; + int oc; + + if ( quote ) { + oc = shell_quote(p, size, str); + } else { + oc = strlen(str); + memcpy(p, str, (oc >= size) ? size-1 : oc); + } + + if ( oc >= size ) { + p[size-1] = '\0'; + *ptrp += size-1; + *sizep = 1; + return 1; /* Overflow, string unusable */ + } + + *ptrp += oc; + *sizep -= oc; + return 0; +} + int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, char *url, int rmt_argc, char **rmt_argv) { @@ -16,6 +81,8 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, int sv[2]; char command[COMMAND_SIZE]; char *posn; + int sizen; + int of; int i; if (!strcmp(url, "-")) { @@ -37,24 +104,30 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, if (!path) { return error("Bad URL: %s", url); } - /* ssh <host> 'cd <path>; stdio-pull <arg...> <commit-id>' */ - snprintf(command, COMMAND_SIZE, - "%s='%s' %s", - GIT_DIR_ENVIRONMENT, path, remote_prog); - *path = '\0'; - posn = command + strlen(command); - for (i = 0; i < rmt_argc; i++) { - *(posn++) = ' '; - strncpy(posn, rmt_argv[i], COMMAND_SIZE - (posn - command)); - posn += strlen(rmt_argv[i]); - if (posn - command + 4 >= COMMAND_SIZE) { - return error("Command line too long"); - } + /* $GIT_RSH <host> "env GIR_DIR=<path> <remote_prog> <args...>" */ + sizen = COMMAND_SIZE; + posn = command; + of = 0; + of |= add_to_string(&posn, &sizen, "env ", 0); + of |= add_to_string(&posn, &sizen, GIT_DIR_ENVIRONMENT, 0); + of |= add_to_string(&posn, &sizen, "=", 0); + of |= add_to_string(&posn, &sizen, path, 1); + of |= add_to_string(&posn, &sizen, " ", 0); + of |= add_to_string(&posn, &sizen, remote_prog, 1); + + for ( i = 0 ; i < rmt_argc ; i++ ) { + of |= add_to_string(&posn, &sizen, " ", 0); + of |= add_to_string(&posn, &sizen, rmt_argv[i], 1); } - strcpy(posn, " -"); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) { + + of |= add_to_string(&posn, &sizen, " -", 0); + + if ( of ) + return error("Command line too long"); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) return error("Couldn't create socket"); - } + if (!fork()) { const char *ssh, *ssh_basename; ssh = getenv("GIT_SSH"); diff --git a/server-info.c b/server-info.c index 2b3aecab4a..a9e5607f2f 100644 --- a/server-info.c +++ b/server-info.c @@ -3,20 +3,9 @@ #include "object.h" #include "commit.h" #include "tag.h" -#include "rev-cache.h" /* refs */ static FILE *info_ref_fp; -static unsigned long info_ref_time; -static int info_ref_is_stale = 0; - -static int stat_ref(const char *path, const unsigned char *sha1) -{ - struct stat st; - if (!stat(path, &st) && info_ref_time < st.st_mtime) - info_ref_is_stale = 1; - return 0; -} static int add_info_ref(const char *path, const unsigned char *sha1) { @@ -26,7 +15,6 @@ static int add_info_ref(const char *path, const unsigned char *sha1) static int update_info_refs(int force) { - struct stat st; char *path0 = strdup(git_path("info/refs")); int len = strlen(path0); char *path1 = xmalloc(len + 2); @@ -34,21 +22,6 @@ static int update_info_refs(int force) strcpy(path1, path0); strcpy(path1 + len, "+"); - if (!force) { - if (stat(path0, &st)) { - if (errno == ENOENT) - info_ref_is_stale = 1; - else - return error("cannot stat %s", path0); - } - else { - info_ref_time = st.st_mtime; - for_each_ref(stat_ref); - } - if (!info_ref_is_stale) - return 0; - } - safe_create_leading_directories(path0); info_ref_fp = fopen(path1, "w"); if (!info_ref_fp) @@ -516,45 +489,6 @@ static int update_info_packs(int force) return 0; } -/* rev-cache */ -static int record_rev_cache_ref(const char *path, const unsigned char *sha1) -{ - struct object *obj = parse_object(sha1); - - if (!obj) - return error("ref %s has bad sha %s", path, sha1_to_hex(sha1)); - while (obj && obj->type == tag_type) - obj = parse_object(((struct tag *)obj)->tagged->sha1); - if (!obj || obj->type != commit_type) - /* tag pointing at a non-commit */ - return 0; - return record_rev_cache(obj->sha1, NULL); -} - -static int update_info_revs(int force) -{ - char *path0 = strdup(git_path("info/rev-cache")); - int len = strlen(path0); - char *path1 = xmalloc(len + 2); - - strcpy(path1, path0); - strcpy(path1 + len, "+"); - - /* read existing rev-cache */ - if (!force) - read_rev_cache(path0, NULL, 0); - safe_create_leading_directories(path0); - - for_each_ref(record_rev_cache_ref); - - /* update the rev-cache database */ - write_rev_cache(path1, force ? "/dev/null" : path0); - rename(path1, path0); - free(path1); - free(path0); - return 0; -} - /* public */ int update_server_info(int force) { @@ -566,7 +500,6 @@ int update_server_info(int force) errs = errs | update_info_refs(force); errs = errs | update_info_packs(force); - errs = errs | update_info_revs(force); return errs; } diff --git a/show-rev-cache.c b/show-rev-cache.c deleted file mode 100644 index fa92b87abc..0000000000 --- a/show-rev-cache.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "cache.h" -#include "rev-cache.h" - -static char *show_rev_cache_usage = -"git-show-rev-cache <rev-cache-file>"; - -int main(int ac, char **av) -{ - while (1 < ac && av[0][1] == '-') { - /* do flags here */ - break; - ac--; av++; - } - if (ac != 2) - usage(show_rev_cache_usage); - - return read_rev_cache(av[1], stdout, 1); -} diff --git a/ssh-fetch.c b/ssh-fetch.c index d8f4368bc5..683a1e4a01 100644 --- a/ssh-fetch.c +++ b/ssh-fetch.c @@ -1,3 +1,13 @@ +#ifndef COUNTERPART_ENV_NAME +#define COUNTERPART_ENV_NAME "GIT_SSH_UPLOAD" +#endif +#ifndef COUNTERPART_PROGRAM_NAME +#define COUNTERPART_PROGRAM_NAME "git-ssh-upload" +#endif +#ifndef MY_PROGRAM_NAME +#define MY_PROGRAM_NAME "git-ssh-fetch" +#endif + #include "cache.h" #include "commit.h" #include "rsh.h" @@ -82,6 +92,9 @@ int fetch_ref(char *ref, unsigned char *sha1) return 0; } +static const char ssh_fetch_usage[] = + MY_PROGRAM_NAME + " [-c] [-t] [-a] [-v] [-d] [--recover] [-w ref] commit-id url"; int main(int argc, char **argv) { char *commit_id; @@ -110,7 +123,7 @@ int main(int argc, char **argv) arg++; } if (argc < arg + 2) { - usage("git-ssh-fetch [-c] [-t] [-a] [-v] [-d] [--recover] [-w ref] commit-id url"); + usage(ssh_fetch_usage); return 1; } commit_id = argv[arg]; diff --git a/ssh-pull.c b/ssh-pull.c new file mode 100644 index 0000000000..868ce4d41f --- /dev/null +++ b/ssh-pull.c @@ -0,0 +1,4 @@ +#define COUNTERPART_ENV_NAME "GIT_SSH_PUSH" +#define COUNTERPART_PROGRAM_NAME "git-ssh-push" +#define MY_PROGRAM_NAME "git-ssh-pull" +#include "ssh-fetch.c" diff --git a/ssh-push.c b/ssh-push.c new file mode 100644 index 0000000000..a562df1b31 --- /dev/null +++ b/ssh-push.c @@ -0,0 +1,4 @@ +#define COUNTERPART_ENV_NAME "GIT_SSH_PULL" +#define COUNTERPART_PROGRAM_NAME "git-ssh-pull" +#define MY_PROGRAM_NAME "git-ssh-push" +#include "ssh-upload.c" diff --git a/ssh-upload.c b/ssh-upload.c index 10a3687339..603abcc8c3 100644 --- a/ssh-upload.c +++ b/ssh-upload.c @@ -1,3 +1,13 @@ +#ifndef COUNTERPART_ENV_NAME +#define COUNTERPART_ENV_NAME "GIT_SSH_FETCH" +#endif +#ifndef COUNTERPART_PROGRAM_NAME +#define COUNTERPART_PROGRAM_NAME "git-ssh-fetch" +#endif +#ifndef MY_PROGRAM_NAME +#define MY_PROGRAM_NAME "git-ssh-upload" +#endif + #include "cache.h" #include "rsh.h" #include "refs.h" @@ -97,7 +107,7 @@ static void service(int fd_in, int fd_out) { } static const char ssh_push_usage[] = - "git-ssh-upload [-c] [-t] [-a] [-w ref] commit-id url"; + MY_PROGRAM_NAME " [-c] [-t] [-a] [-w ref] commit-id url"; int main(int argc, char **argv) { @@ -109,8 +119,8 @@ int main(int argc, char **argv) unsigned char sha1[20]; char hex[41]; - prog = getenv("GIT_SSH_PULL"); - if (!prog) prog = "git-ssh-fetch"; + prog = getenv(COUNTERPART_ENV_NAME); + if (!prog) prog = COUNTERPART_PROGRAM_NAME; while (arg < argc && argv[arg][0] == '-') { if (argv[arg][1] == 'w') arg++; diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh index 5b69681c52..d0ed24275e 100755 --- a/t/t1001-read-tree-m-2way.sh +++ b/t/t1001-read-tree-m-2way.sh @@ -11,7 +11,7 @@ There is the head (called H) and another commit (called M), which is simply ahead of H. The index and the work tree contains a state that is derived from H, but may also have local changes. This test checks all the combinations described in the two-tree merge "carry forward" -rules, found in <Documentation/git-rev-tree.txt>. +rules, found in <Documentation/git-read-tree.txt>. In the test, these paths are used: bozbar - in H, stays in M, modified from bozbar to gnusto |