From c80522e30fdc190f8c8c7fc983bbe040a1b03e93 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Sep 2005 23:49:55 -0700 Subject: Make merge comment git-pull makes for an octopus a bit prettier. Signed-off-by: Junio C Hamano diff --git a/git-pull.sh b/git-pull.sh index c1b4474..dd36c61 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -24,9 +24,11 @@ then die "You need to first update your working tree." 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_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD) +merge_name=$( + perl -e 'print join("; ", map { chomp; s/^[0-9a-f]* //; $_ } <>)' \ + "$GIT_DIR"/FETCH_HEAD +) case "$merge_head" in '') -- cgit v0.10.2-6-g49f6 From 705a7148ba1bb9597b1837b7f64a0dcb67f1ad0c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 14 Sep 2005 13:41:24 -0700 Subject: [PATCH] Fix alloc_filespec() initialization This simplifies and fixes the initialization of a "diff_filespec" when allocated. The old code would not initialize "sha1_valid". Noticed by valgrind. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index f8e3cbf..1059049 100644 --- a/diff.c +++ b/diff.c @@ -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; } -- cgit v0.10.2-6-g49f6 From 19397b4521bcc27eb224413fb71519223b94290f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 14 Sep 2005 14:06:50 -0700 Subject: Revert "[PATCH] plug memory leak in diff.c::diff_free_filepair()" This reverts 068eac91ce04b9aca163acb1927c3878c45d1a07 commit. diff --git a/diff.c b/diff.c index 1059049..05a0663 100644 --- a/diff.c +++ b/diff.c @@ -402,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, @@ -767,8 +768,8 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue, 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); } diff --git a/diffcore-break.c b/diffcore-break.c index b0c8461..06f9a7f 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.h b/diffcore.h index 633d1ae..f1b5ca7 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; -- cgit v0.10.2-6-g49f6 From ba65af9c1f67461c0dfa6582c911d6a893d80284 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 14 Sep 2005 01:43:53 -0700 Subject: git-branch -d : delete unused branch. The new flag '-d' lets you delete a branch. For safety, it does not lets you delete the branch you are currently on, nor a branch that has been fully merged into your current branch. The credit for the safety check idea goes to Daniel Barkalow. Signed-off-by: Junio C Hamano diff --git a/git-branch.sh b/git-branch.sh index 81b9e6c..dcec2a9 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)"' [ [start-point]] + echo >&2 "usage: $(basename $0)"' [-d ] | [ [start-point]] If no arguments, show available branches and mark current branch with a star. If one argument, create a new branch based off of current HEAD. @@ -12,6 +12,59 @@ If two arguments, create a new branch based off of . 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" -- cgit v0.10.2-6-g49f6 From 1db69b571c9eaab73a7b21303bfedda5fb5f31ce Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Tue, 13 Sep 2005 19:38:58 +0400 Subject: [PATCH] git-http-fetch: Allow caching of retrieved objects by proxy servers By default the curl library adds "Pragma: no-cache" header to all requests, which disables caching by proxy servers. However, most files in a GIT repository are immutable, and caching them is safe and could be useful. This patch removes the "Pragma: no-cache" header from requests for all files except the pack list (objects/info/packs) and references (refs/*), which are really mutable and should not be cached. Signed-off-by: Sergey Vlasov Signed-off-by: Junio C Hamano (cherry picked from 3b2a4c46fd5093ec79fb60e1b14b8d4a58c74612 commit) diff --git a/http-fetch.c b/http-fetch.c index 4e564fc..1a433a9 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -14,6 +14,7 @@ #endif static CURL *curl; +static struct curl_slist *no_pragma_header; static char *base; @@ -102,6 +103,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); @@ -152,6 +154,7 @@ static int fetch_indices(void) 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); @@ -215,6 +218,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); @@ -255,6 +259,7 @@ 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); @@ -303,6 +308,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 +360,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); @@ -366,6 +373,7 @@ int main(int argc, char **argv) if (pull(commit_id)) return 1; + curl_slist_free_all(no_pragma_header); curl_global_cleanup(); return 0; } -- cgit v0.10.2-6-g49f6 From 53764ee43defda7109fe547f471eac54c4e8b3d6 Mon Sep 17 00:00:00 2001 From: Peter Eriksen Date: Wed, 14 Sep 2005 12:41:52 +0200 Subject: [PATCH] Use '-d' as the first flag to 'install' ... in order to please Solaris 'install'. GNU install is not harmed with this. [jc: Documentation/Makefile also fixed.] Signed-off-by: Junio C Hamano diff --git a/Documentation/Makefile b/Documentation/Makefile index b81a6a2..37b7fcb 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/Makefile b/Makefile index a851f56..88189fb 100644 --- a/Makefile +++ b/Makefile @@ -288,12 +288,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: -- cgit v0.10.2-6-g49f6 From 0f56479d7325083953be36b8c8ee90380ff27f92 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 14 Sep 2005 13:08:55 -0700 Subject: Retire info/rev-cache It was one of those things that were well intentioned but did not turn out to be useful in practice. Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 31c03f4..9fde27f 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 @@ -78,7 +77,6 @@ git-sh-setup git-shortlog git-show-branch git-show-index -git-show-rev-cache git-ssh-fetch git-ssh-upload git-status diff --git a/Documentation/git-build-rev-cache.txt b/Documentation/git-build-rev-cache.txt deleted file mode 100644 index 1dbad77..0000000 --- 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] < 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. - -:: - The rev-cache to operate on. - -Author ------- -Written by Junio C Hamano - -Documentation --------------- -Documentation by Junio C Hamano and the git-list . - -GIT ---- -Part of the link:git.html[git] suite - diff --git a/Documentation/git-show-rev-cache.txt b/Documentation/git-show-rev-cache.txt deleted file mode 100644 index 104ecb7..0000000 --- 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' - -DESCRIPTION ------------ -Show the contents of . - -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 to display. - -Author ------- -Written by Junio C Hamano - -Documentation --------------- -Documentation by Junio C Hamano and the git-list . - -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 74c4364..39222c3 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 31dd474..bec562e 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/repository-layout.txt b/Documentation/repository-layout.txt index 499b070..d20fa80 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 diff --git a/Makefile b/Makefile index 88189fb..e8421cc 100644 --- a/Makefile +++ b/Makefile @@ -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,7 +103,7 @@ 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 \ @@ -125,7 +125,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 +135,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) diff --git a/build-rev-cache.c b/build-rev-cache.c deleted file mode 100644 index 948898b..0000000 --- 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 < 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/rev-cache.c b/rev-cache.c deleted file mode 100644 index 6344d62..0000000 --- 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 b238ac6..0000000 --- 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/server-info.c b/server-info.c index 2b3aeca..3263035 100644 --- a/server-info.c +++ b/server-info.c @@ -3,7 +3,6 @@ #include "object.h" #include "commit.h" #include "tag.h" -#include "rev-cache.h" /* refs */ static FILE *info_ref_fp; @@ -516,45 +515,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 +526,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 fa92b87..0000000 --- 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 "; - -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); -} -- cgit v0.10.2-6-g49f6 From 60d0526aaa5d29589420bfadd0623ec878c5edf3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 14 Sep 2005 13:15:53 -0700 Subject: Unoptimize info/refs creation. The code did not catch the case where you removed an existing ref without changing anything else. We are not talking about hundreds of refs anyway, so remove that optimization. Signed-off-by: Junio C Hamano diff --git a/server-info.c b/server-info.c index 3263035..a9e5607 100644 --- a/server-info.c +++ b/server-info.c @@ -6,16 +6,6 @@ /* 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) { @@ -25,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); @@ -33,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) -- cgit v0.10.2-6-g49f6 From 61420a2cb45c01e55d5bfc6abc632b9a41bb73a7 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Wed, 14 Sep 2005 16:48:05 +0400 Subject: [PATCH] Document git-fetch options Add documentation for git-fetch options Signed-off-by: Junio C Hamano diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index 017f646..8c1cc07 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/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt index 8f6b68c..8642182 100644 --- a/Documentation/pull-fetch-param.txt +++ b/Documentation/pull-fetch-param.txt @@ -80,3 +80,14 @@ : when pulling/fetching, and : 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. -- cgit v0.10.2-6-g49f6 From 22c6e1d0f76f58a425065d3e8e447b6366ccd98c Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 14 Sep 2005 21:31:42 -0400 Subject: [PATCH] Fix fetch completeness assumptions Don't assume that any commit we have is complete; assume that any ref we have is complete. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/fetch.c b/fetch.c index e874538..7db35f0 100644 --- a/fetch.c +++ b/fetch.c @@ -62,11 +62,21 @@ static int process_tree(struct tree *tree) return 0; } +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, 1); + } + + + if (commit->object.flags & 1) + return 0; + memcpy(current_commit_sha1, commit->object.sha1, 20); if (get_tree) { @@ -78,8 +88,6 @@ 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)) return -1; @@ -126,6 +134,7 @@ 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. */ @@ -179,6 +188,19 @@ static int interpret_target(char *target, unsigned char *sha1) return -1; } +static int mark_complete(const char *path, const unsigned char *sha1) +{ + struct object *obj = parse_object(sha1); + while (obj->type == tag_type) { + obj = ((struct tag *) obj)->tagged; + parse_object(obj->sha1); + } + if (obj->type == commit_type) { + obj->flags |= 1; + insert_by_date((struct commit *) obj, &complete); + } + return 0; +} int pull(char *target) { @@ -191,6 +213,8 @@ int pull(char *target) return -1; } + for_each_ref(mark_complete); + if (interpret_target(target, sha1)) return error("Could not interpret %s as something to pull", target); -- cgit v0.10.2-6-g49f6 From 0de68d28d34f915951324b9f387e6e67172e9951 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 15 Sep 2005 12:33:14 -0700 Subject: [PATCH] rsh.c env and quoting cleanup, take 2 This patch does proper quoting, and uses "env" to be compatible with tcsh. As a side benefit, I believe the code is a lot cleaner to read. [jc: I am accepting this not because I necessarily agree with the quoting approach taken by it, but because (1) the code is only used by ssh-fetch/ssh-upload pair which I do not care much about (if you have ssh account on the remote end you should be using git-send-pack git-fetch-pack pair over ssh anyway), and (2) HPA is one of the more important customers belonging to the Linux kernel community and I want to help his workflow -- which includes not wasting his time by asking him to switch to git-send-pack/git-fetch-pack pair, nor to use a better shell ;-). I might not have taken this patch if it mucked with git_connect in connect.c in its current form.] Signed-off-by: H. Peter Anvin Signed-off-by: Junio C Hamano diff --git a/rsh.c b/rsh.c index 04cbdf7..1c63686 100644 --- a/rsh.c +++ b/rsh.c @@ -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 'cd ; stdio-pull ' */ - 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 "env GIR_DIR= " */ + 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"); -- cgit v0.10.2-6-g49f6 From f71a69ab055c47056d0270b29b8f7455278c2422 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 15 Sep 2005 14:56:37 -0700 Subject: Be more backward compatible with git-ssh-{push,pull}. HPA reminded me that these programs knows about the name of the counterpart on the other end and simply symlinking the old name to new name locally would not be enough. Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 9fde27f..1d4a411 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,8 @@ git-shortlog git-show-branch git-show-index git-ssh-fetch +git-ssh-pull +git-ssh-push git-ssh-upload git-status git-stripspace diff --git a/Makefile b/Makefile index e8421cc..b48fe44 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,9 @@ PROGRAMS = \ 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 @@ -250,6 +253,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) diff --git a/cmd-rename.sh b/cmd-rename.sh index 1edb037..ada33fb 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 diff --git a/ssh-fetch.c b/ssh-fetch.c index d8f4368..683a1e4 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 0000000..868ce4d --- /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 0000000..a562df1 --- /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 10a3687..603abcc 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++; -- cgit v0.10.2-6-g49f6 From 60ab26de9970ce829c95eb11ebb407fe95780148 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 15 Sep 2005 14:43:17 -0700 Subject: [PATCH] Avoid wasting memory in git-rev-list As pointed out on the list, git-rev-list can use a lot of memory. One low-hanging fruit is to free the commit buffer for commits that we parse. By default, parse_commit() will save away the buffer, since a lot of cases do want it, and re-reading it continually would be unnecessary. However, in many cases the buffer isn't actually necessary and saving it just wastes memory. We could just free the buffer ourselves, but especially in git-rev-list, we actually end up using the helper functions that automatically add parent commits to the commit lists, so we don't actually control the commit parsing directly. Instead, just make this behaviour of "parse_commit()" a global flag. Maybe this is a bit tasteless, but it's very simple, and it makes a noticable difference in memory usage. Before the change: [torvalds@g5 linux]$ /usr/bin/time git-rev-list v2.6.12..HEAD > /dev/null 0.26user 0.02system 0:00.28elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+3714minor)pagefaults 0swaps after the change: [torvalds@g5 linux]$ /usr/bin/time git-rev-list v2.6.12..HEAD > /dev/null 0.26user 0.00system 0:00.27elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+2433minor)pagefaults 0swaps note how the minor faults have decreased from 3714 pages to 2433 pages. That's all due to the fewer anonymous pages allocated to hold the comment buffers and their metadata. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/commit.c b/commit.c index 2f73cf3..f735f98 100644 --- a/commit.c +++ b/commit.c @@ -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; } diff --git a/commit.h b/commit.h index 9dda2f0..30702ca 100644 --- a/commit.h +++ b/commit.h @@ -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/rev-list.c b/rev-list.c index 2d97cdb..96aa342 100644 --- a/rev-list.c +++ b/rev-list.c @@ -582,6 +582,8 @@ int main(int argc, char **argv) handle_one_commit(commit, &list); } + save_commit_buffer = verbose_header; + if (!merge_order) { sort_by_date(&list); if (limited) -- cgit v0.10.2-6-g49f6 From 98533b90cb8e88484cb381334b19cbf4f7cf92b1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 15 Sep 2005 15:06:39 -0700 Subject: Avoid wasting memory while keeping track of what we have during fetch. Signed-off-by: Junio C Hamano diff --git a/fetch.c b/fetch.c index 7db35f0..71c4f41 100644 --- a/fetch.c +++ b/fetch.c @@ -207,6 +207,7 @@ 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) -- cgit v0.10.2-6-g49f6 From 5098bafb756de69d03882707a3382899c0cb7dd1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 15 Sep 2005 16:13:43 -0700 Subject: Plug diff leaks. It is a bit embarrassing that it took this long for a fix since the problem was first reported on Aug 13th. Message-ID: <87y876gl1r.wl@mail2.atmark-techno.com> From: Yasushi SHOJI Newsgroups: gmane.comp.version-control.git Subject: [patch] possible memory leak in diff.c::diff_free_filepair() Date: Sat, 13 Aug 2005 19:58:56 +0900 This time I used valgrind to make sure that it does not overeagerly discard memory that is still being used. Signed-off-by: Junio C Hamano diff --git a/diff-tree.c b/diff-tree.c index fc87902..e8f5d1b 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; } diff --git a/diff.c b/diff.c index 05a0663..d8d20c2 100644 --- a/diff.c +++ b/diff.c @@ -762,7 +762,8 @@ 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; } @@ -770,6 +771,8 @@ void diff_free_filepair(struct diff_filepair *p) { diff_free_filespec_data(p->one); diff_free_filespec_data(p->two); + free(p->one); + free(p->two); free(p); } diff --git a/diffcore-rename.c b/diffcore-rename.c index dbc8522..092cf68 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; -- cgit v0.10.2-6-g49f6 From 5bdbaaa4e9dd901dd2907b53bbecfdf3eac9276b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 15 Sep 2005 15:14:29 -0700 Subject: [PATCH] Re-organize "git-rev-list --objects" logic The logic to calculate the full object list used to be very inter-twined with the logic that looked up the commits. For no good reason - it's actually a lot simpler to just do that logic as a separate pass. This improves performance a bit, and uses slightly less memory in my tests, but more importantly it makes the code simpler to work with and follow what it does. The performance win is less than I had hoped for, but I get: Before: [torvalds@g5 linux]$ /usr/bin/time git-rev-list --objects v2.6.12..HEAD | wc -l 13.64user 0.42system 0:14.13elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+47947minor)pagefaults 0swaps 58945 After: [torvalds@g5 linux]$ /usr/bin/time git-rev-list --objects v2.6.12..HEAD | wc -l 11.80user 0.36system 0:12.16elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+42684minor)pagefaults 0swaps 58945 ie it improved by 2 seconds, and took a 5000+ fewer pages (hey, that's 20MB out of 174MB to go). And got the same number of objects (in theory, the more expensive one might find some more shared objects to avoid. In practice it obviously doesn't). I know how to make it use _lots_ less memory, which will probably speed it up. But that's for another time, and I'd prefer to see this go in first. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/rev-list.c b/rev-list.c index 96aa342..c410bc3 100644 --- a/rev-list.c +++ b/rev-list.c @@ -231,8 +231,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 +270,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 +345,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 +376,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; -- cgit v0.10.2-6-g49f6 From 316eee8fe0282a6f14441b0045a32871bdf90d36 Mon Sep 17 00:00:00 2001 From: "jdl@freescale.com" Date: Thu, 15 Sep 2005 17:40:13 -0500 Subject: [PATCH] Documentation/git-rev-list.txt typo fix Fix the "superscript" problem on the git-rev-list doc page. Signed-off-by: Jon Loeliger Signed-off-by: Junio C Hamano diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 35fecf3..8bf5d61 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -32,8 +32,8 @@ 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. -- cgit v0.10.2-6-g49f6 From b4416b432bde78fac057224d14c7e9c85097a152 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 15 Sep 2005 17:38:26 -0700 Subject: Revert breakage introduced by c80522e30fdc190f8c8c7fc983bbe040a1b03e93. Signed-off-by: Junio C Hamano diff --git a/git-pull.sh b/git-pull.sh index dd36c61..8cf39e7 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -24,7 +24,7 @@ then die "You need to first update your working tree." fi -merge_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD) +merge_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ') merge_name=$( perl -e 'print join("; ", map { chomp; s/^[0-9a-f]* //; $_ } <>)' \ "$GIT_DIR"/FETCH_HEAD -- cgit v0.10.2-6-g49f6 From c6ae61590f79cb7ff848ef0f2c33396507e60442 Mon Sep 17 00:00:00 2001 From: Horst von Brand Date: Fri, 16 Sep 2005 00:08:24 -0400 Subject: [PATCH] Require less in RPM spec ... and the next one will be the one to do Debian, naturally. Signed-off-by: Junio C Hamano diff --git a/git-core.spec.in b/git-core.spec.in index f98f8db..677e44f 100644 --- a/git-core.spec.in +++ b/git-core.spec.in @@ -10,7 +10,7 @@ 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 +Requires: sh-utils, curl, diffutils, less, rsync, rcs, openssh-clients, perl, python >= 2.4, tk %description This is a stupid (but extremely fast) directory content manager. It @@ -44,6 +44,9 @@ rm -rf $RPM_BUILD_ROOT %{!?_without_docs: %{_mandir}/man7/*.7*} %changelog +* Fri Sep 16 2005 Horst H. von Brand +- Linus noticed that less is required, added to the dependencies + * Sun Sep 11 2005 Horst H. von Brand - Updated dependencies - Don't assume manpages are gzipped -- cgit v0.10.2-6-g49f6 From b93aa3ec9506618e9a22c04d775b35f31e7e068f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 15 Sep 2005 23:33:03 -0700 Subject: Recommend 'less' for Debian. Signed-off-by: Junio C Hamano diff --git a/debian/control b/debian/control index 33a8f85..845a08c 100644 --- a/debian/control +++ b/debian/control @@ -8,7 +8,7 @@ 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 -- cgit v0.10.2-6-g49f6 From ed0a84883ec33cd2d4ee7f66204de7dab13353d8 Mon Sep 17 00:00:00 2001 From: Peter Hagervall Date: Fri, 16 Sep 2005 16:24:12 +0200 Subject: [PATCH] PATCH Documentation/git-rev-list.txt typo fix An earlier commit causes a mismatch in and tags, one way of fixing it is having no more than one caret symbol per line, which is the only solution I found in the asciidoc documentation. Ugly, but it works. [jc: ugly indeed but that is not Peter's fault.] Signed-off-by: Peter Hagervall Signed-off-by: Junio C Hamano diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 8bf5d61..32c06a1 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. -- cgit v0.10.2-6-g49f6 From 0e60471c2a30882b9b44ebfd699d2414a0a348cc Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 16 Sep 2005 13:38:49 -0700 Subject: [PATCH] Update git-core.spec.in Update git-core spec file based on feedback from Fedora Extras review. - update BuildRoot to be more specific - eliminate Requires that must be satisfied for base system install - drop Vendor - use dist tag to differentiate between branches - own %{_datadir}/git-core/ - use RPM_OPT_FLAGS in spec file Signed-off-by: Chris Wright Signed-off-by: Junio C Hamano diff --git a/git-core.spec.in b/git-core.spec.in index 677e44f..6c17d52 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 +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, less, 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,13 +36,16 @@ 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 0.99.6-1 +- update to 0.99.6 + * Fri Sep 16 2005 Horst H. von Brand - Linus noticed that less is required, added to the dependencies @@ -51,6 +53,18 @@ rm -rf $RPM_BUILD_ROOT - Updated dependencies - Don't assume manpages are gzipped +* Thu Aug 18 2005 Chris Wright 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 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 +- update spec file to fix Buildroot, Requires, and drop Vendor + * Sun Aug 07 2005 Horst H. von Brand - Redid the description - Cut overlong make line, loosened changelog a bit -- cgit v0.10.2-6-g49f6 From 6b82d16bfcfffebbb5790b114063e1617d17338a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 16 Sep 2005 12:30:46 -0700 Subject: [PATCH] Make git-checkout failure message more friendly. ... or less so, perhaps ;-). Suggested by Jeff Garzik. Signed-off-by: Junio C Hamano diff --git a/git-checkout.sh b/git-checkout.sh index 4a605cd..e02c7af 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 -- cgit v0.10.2-6-g49f6 From 28423758591577828672219c1031d463701a11cc Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Fri, 16 Sep 2005 13:54:10 +0200 Subject: [PATCH] Debian: build-depend on "bc" Build systems should run tests. This patch adds the necessary debian/control and debian/rules bits ("bc" was missing, t/t4002-diff-basic.sh wants it). Signed-off-by: Matthias Urlichs Signed-off-by: Junio C Hamano diff --git a/debian/control b/debian/control index 845a08c..5d75c32 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: git-core Section: devel Priority: optional Maintainer: Junio C Hamano -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 diff --git a/debian/rules b/debian/rules index 1a53ca2..568d430 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: -- cgit v0.10.2-6-g49f6 From d0ac30f20ca1dd1d28a1b84bf13687f09cf535ae Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 16 Sep 2005 14:30:29 -0700 Subject: [PATCH] fetch.c: cleanups Clean-ups suggested by Sergey Vlasov and acked by Daniel Barkalow. Signed-off-by: Junio C Hamano diff --git a/fetch.c b/fetch.c index 71c4f41..6ee6161 100644 --- a/fetch.c +++ b/fetch.c @@ -62,7 +62,8 @@ static int process_tree(struct tree *tree) return 0; } -struct commit_list *complete = NULL; +#define COMPLETE 1U +static struct commit_list *complete = NULL; static int process_commit(struct commit *commit) { @@ -70,11 +71,11 @@ static int process_commit(struct commit *commit) return -1; while (complete && complete->item->date >= commit->date) { - pop_most_recent_commit(&complete, 1); + pop_most_recent_commit(&complete, COMPLETE); } - if (commit->object.flags & 1) + if (commit->object.flags & COMPLETE) return 0; memcpy(current_commit_sha1, commit->object.sha1, 20); @@ -190,14 +191,10 @@ static int interpret_target(char *target, unsigned char *sha1) static int mark_complete(const char *path, const unsigned char *sha1) { - struct object *obj = parse_object(sha1); - while (obj->type == tag_type) { - obj = ((struct tag *) obj)->tagged; - parse_object(obj->sha1); - } - if (obj->type == commit_type) { - obj->flags |= 1; - insert_by_date((struct commit *) obj, &complete); + struct commit *commit = lookup_commit_reference_gently(sha1, 1); + if (commit) { + commit->object.flags |= COMPLETE; + insert_by_date(commit, &complete); } return 0; } -- cgit v0.10.2-6-g49f6 From b0d8923ec01fd91b75ab079034f89ced91500157 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 16 Sep 2005 14:32:48 -0700 Subject: [PATCH] Improve git-rev-list memory usage further This avoids keeping tree entries around, and free's them as it traverses the list. This avoids building up a huge memory footprint just for these small but very common allocations. Before: $ /usr/bin/time git-rev-list --objects v2.6.12..HEAD | wc -l 11.65user 0.38system 0:12.65elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+42934minor)pagefaults 0swaps 59124 After: $ /usr/bin/time git-rev-list --objects v2.6.12..HEAD | wc -l 12.28user 0.29system 0:12.57elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+26718minor)pagefaults 0swaps 59124 Note how the minor fault numbers - which ends up being how many pages we needed to map - go down from 42934 (167 MB) to 26718 (104 MB). That is: Before: 42934 minor pagefaults After: 26718 minor pagefaults This is all in _addition_ to the previous fixes. It used to be ~48,000 pagefaults. That's still a honking big memory footprint, but it's about half of what it was just a day or two ago (and this is the object list for a pretty big update - almost 60,000 objects. Smaller updates need less memory). Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/rev-list.c b/rev-list.c index c410bc3..91534dd 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; } } -- cgit v0.10.2-6-g49f6 From 8805ccac40348094d26b3b892c6ca3d08dc12ae0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 16 Sep 2005 14:55:33 -0700 Subject: [PATCH] Avoid building object ref lists when not needed The object parsing code builds a generic "this object references that object" because doing a full connectivity check for fsck requires it. However, nothing else really needs it, and it's quite expensive for git-rev-list that can have tons of objects in flight. So, exactly like the commit buffer save thing, add a global flag to disable it, and use it in git-rev-list. Before: $ /usr/bin/time git-rev-list --objects v2.6.12..HEAD | wc -l 12.28user 0.29system 0:12.57elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+26718minor)pagefaults 0swaps 59124 After this change: $ /usr/bin/time git-rev-list --objects v2.6.12..HEAD | wc -l 10.33user 0.18system 0:10.54elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+18509minor)pagefaults 0swaps 59124 and note how the number of pages touched by git-rev-list for this particular object list has shrunk from 26,718 (104 MB) to 18,509 (72 MB). Calculating the total object difference between two git revisions is still clearly the most expensive git operation (both in memory and CPU time), but it's now less than 40% of what it used to be. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/object.c b/object.c index 63e6e78..1fdebe0 100644 --- a/object.c +++ b/object.c @@ -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; diff --git a/object.h b/object.h index bf74449..6accda3 100644 --- a/object.h +++ b/object.h @@ -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-list.c b/rev-list.c index 91534dd..c55e912 100644 --- a/rev-list.c +++ b/rev-list.c @@ -581,6 +581,7 @@ int main(int argc, char **argv) } save_commit_buffer = verbose_header; + track_object_refs = 0; if (!merge_order) { sort_by_date(&list); -- cgit v0.10.2-6-g49f6 From 4447badcd22a889d656192803eff1003602839c5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 17 Sep 2005 11:56:41 -0700 Subject: Teach rsync transport about alternates. For local operations and downloading and uploading via git aware protocols, use of $GIT_OBJECT_DIRECTORY/info/alternates is recommended on the server side for big projects that are derived from another one (like Linux kernel). However, dumb protocols and rsync transport needs to resolve this on the client end, which we did not bother doing until this week. I noticed we use "rsync -z" but most of our payload is already compressed, which was not quite right. This commit also fixes it. Signed-off-by: Junio C Hamano diff --git a/git-clone.sh b/git-clone.sh index a21f13a..bfb8fd6 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-fetch.sh b/git-fetch.sh index 2273944..72f17ab 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 3c5d94b..a9db0cd 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 +} -- cgit v0.10.2-6-g49f6 From a09af243fbffeb5ddc5dbc94a4bdf9201c346030 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 16 Sep 2005 20:40:12 -0700 Subject: Add git-send-email to .gitignore Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 1d4a411..0fd59b9 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ git-rev-list git-rev-parse git-rev-tree git-revert +git-send-email git-send-pack git-sh-setup git-shortlog -- cgit v0.10.2-6-g49f6 From 2a7055ae982fd66b078ac84cbb2b1f9408b67295 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 16 Sep 2005 17:53:19 -0700 Subject: [PATCH] Fix "git-rev-list" revision range parsing There were two bugs in there: - if the range didn't end up working, we restored the '.' character in the wrong place. - an empty end-of-range should be interpreted as HEAD. See rev-parse.c for the reference implementation of this. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/rev-list.c b/rev-list.c index c55e912..e41d5a0 100644 --- a/rev-list.c +++ b/rev-list.c @@ -561,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) { @@ -569,7 +571,7 @@ int main(int argc, char **argv) handle_one_commit(include, &list); continue; } - *next = '.'; + *dotdot = '.'; } if (*arg == '^') { flags = UNINTERESTING; -- cgit v0.10.2-6-g49f6 From aa894d8887c96a8b72adf94c2b52c519f7b47174 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 16 Sep 2005 18:02:46 -0700 Subject: [PATCH] Make "git shortlog" understand raw logs This is a nicer fix for git-shortlog being unable to handle the raw log format. Just use a more permissive regexp instead of doing two nearly identical ones. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano diff --git a/git-shortlog.perl b/git-shortlog.perl index 107c895..8f0984b 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++; -- cgit v0.10.2-6-g49f6 From 5a90d4ac1ab4d7700595e415e3a2062ecb378523 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 11 Sep 2005 22:25:49 -0700 Subject: [PATCH] getdomainname should be usable on SunOS with -lnsl Jason Riedy suggests that we should be able to use getdomainname if we properly specify which libraries to link. Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index b48fe44..0e9f2ec 100644 --- a/Makefile +++ b/Makefile @@ -151,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 @@ -198,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)' diff --git a/convert-objects.c b/convert-objects.c index 073cab5..9ad0c77 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 #include #include "cache.h" diff --git a/ident.c b/ident.c index 0df2d97..a2d241f 100644 --- a/ident.c +++ b/ident.c @@ -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; -- cgit v0.10.2-6-g49f6 From 50d69ef4f59756195172721e5f25a9dc28e891ca Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 16 Sep 2005 23:27:52 -0700 Subject: Fix typo in test comment. I do not know why it was spelled git-rev-tree when I meant to say git-read-tree, but the typo was left since day one. Signed-off-by: Junio C Hamano diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh index 5b69681..d0ed242 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 . +rules, found in . In the test, these paths are used: bozbar - in H, stays in M, modified from bozbar to gnusto -- cgit v0.10.2-6-g49f6 From b3661567cfa604abfa6a67d8e7bbd6db018c3fe6 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 14 Sep 2005 23:26:08 -0400 Subject: [PATCH] Add support for alternates in HTTP This tries .../objects/info/http-alternates and then .../objects/info/alternates, looking for a file which specifies where else to download objects and packs from. It currently only supports absolute paths, and doesn't support full URLs. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano diff --git a/http-fetch.c b/http-fetch.c index 1a433a9..17051fe 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -16,7 +16,17 @@ 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; @@ -72,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; @@ -90,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"); @@ -114,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; @@ -137,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); @@ -148,8 +226,8 @@ 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); @@ -160,7 +238,7 @@ static int fetch_indices(void) return error("Unable to get pack index %s", url); } - do { + while (i < buffer.posn) { switch (data[i]) { case 'P': i++; @@ -168,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; } @@ -177,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; @@ -191,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", @@ -205,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"); @@ -227,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; @@ -237,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); @@ -261,9 +338,9 @@ int fetch(unsigned char *sha1) 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); @@ -275,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); @@ -296,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; @@ -368,7 +462,12 @@ 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; -- cgit v0.10.2-6-g49f6 From 434d036fe4b8f1b7571eb912957590a483944b26 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 17 Sep 2005 13:51:03 -0700 Subject: Do not fail after calling bisect_auto_next() As a convenience measure, 'bisect bad' or 'bisect good' automatically does 'bisect next' when it knows it can, but the result of that test to see if it can was leaking through as the exit code from the whole thing, which was bad. Noticed by Anton Blanchard. Signed-off-by: Junio C Hamano diff --git a/git-bisect.sh b/git-bisect.sh index a5be3a7..8dc77c9 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() { -- cgit v0.10.2-6-g49f6 From 490e23d22afad5734daa447f1a991eeff3a669bb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 17 Sep 2005 23:35:49 -0700 Subject: Archive-destroying "git repack -a -d" bug. Using "git repack -a -d" can destroy your git archive if you use it twice in succession, because the new pack can be called the same as the old pack. Found by Linus. Signed-off-by: Junio C Hamano diff --git a/git-repack.sh b/git-repack.sh index 064c85c..b395d0e 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 -- cgit v0.10.2-6-g49f6 From 85d106c267ec26f398e0aaf352d8011f661c459a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 18 Sep 2005 01:01:07 -0700 Subject: Improve the safety check used in fetch.c The recent safety check to trust only the commits we have made things impossibly slow and turn out to waste a lot of memory. This commit fixes it with the following improvements: - mark already scanned objects and avoid rescanning the same object again; - free the tree entries when we have scanned the tree entries; this is the same as b0d8923ec01fd91b75ab079034f89ced91500157 which reduced memory usage by rev-list; - plug memory leak from the object_list dequeuing code; - use the process_queue not just for fetching but for scanning, to make things tail recursive to avoid deep recursion; the deep recursion was especially prominent when we cloned a big pack. - avoid has_sha1_file() call when we already know we do not have that object. Signed-off-by: Junio C Hamano diff --git a/fetch.c b/fetch.c index 6ee6161..1d95ce0 100644 --- a/fetch.c +++ b/fetch.c @@ -33,36 +33,33 @@ 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) @@ -73,13 +70,14 @@ static int process_commit(struct commit *commit) 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; @@ -89,8 +87,7 @@ static int process_commit(struct commit *commit) if (get_history) { struct commit_list *parents = commit->parents; for (; parents; parents = parents->next) { - if (process(parents->item->object.sha1, - commit_type)) + if (process(parents->item->object.sha1, commit_type)) return -1; } } @@ -109,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; @@ -139,14 +140,19 @@ static int process(unsigned char *sha1, const char *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; @@ -154,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)) -- cgit v0.10.2-6-g49f6