diff options
-rw-r--r-- | Documentation/RelNotes-1.5.0.5.txt | 28 | ||||
-rw-r--r-- | Documentation/config.txt | 4 | ||||
-rw-r--r-- | builtin-branch.c | 39 | ||||
-rw-r--r-- | builtin-pack-objects.c | 14 | ||||
-rw-r--r-- | cache.h | 9 | ||||
-rw-r--r-- | config.c | 4 | ||||
-rwxr-xr-x | git-applymbox.sh | 4 | ||||
-rwxr-xr-x | git-checkout.sh | 2 | ||||
-rwxr-xr-x | git-fetch.sh | 12 | ||||
-rwxr-xr-x | git-merge.sh | 4 | ||||
-rwxr-xr-x | git-parse-remote.sh | 14 | ||||
-rw-r--r-- | local-fetch.c | 33 | ||||
-rw-r--r-- | pack-check.c | 8 | ||||
-rw-r--r-- | pack-redundant.c | 30 | ||||
-rw-r--r-- | pack.h | 30 | ||||
-rw-r--r-- | sha1_file.c | 151 | ||||
-rwxr-xr-x | t/t3200-branch.sh | 6 | ||||
-rwxr-xr-x | t/t5300-pack-object.sh | 73 | ||||
-rwxr-xr-x | t/t5520-pull.sh | 24 | ||||
-rw-r--r-- | tree-diff.c | 56 | ||||
-rw-r--r-- | tree-walk.c | 4 | ||||
-rw-r--r-- | tree-walk.h | 5 |
22 files changed, 380 insertions, 174 deletions
diff --git a/Documentation/RelNotes-1.5.0.5.txt b/Documentation/RelNotes-1.5.0.5.txt new file mode 100644 index 0000000..aa86149 --- /dev/null +++ b/Documentation/RelNotes-1.5.0.5.txt @@ -0,0 +1,28 @@ +GIT v1.5.0.5 Release Notes +========================== + +Fixes since v1.5.0.3 +-------------------- + +* Bugfixes + + - git-merge (hence git-pull) did not refuse fast-forwarding + when the working tree had local changes that would have + conflicted with it. + + - git.el does not add duplicate sign-off lines. + + - git-commit shows the full stat of the resulting commit, not + just about the files in the current directory, when run from + a subdirectory. + + - "git-checkout -m '@{8 hours ago}'" had a funny failure from + eval; fixed. + + - git-gui updates. + +* Documentation updates + +* User manual updates + + diff --git a/Documentation/config.txt b/Documentation/config.txt index aaae9ac..953acae 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -272,6 +272,10 @@ branch.<name>.merge:: `git fetch`) to lookup the default branch for merging. Without this option, `git pull` defaults to merge the first refspec fetched. Specify multiple values to get an octopus merge. + If you wish to setup `git pull` so that it merges into <name> from + another branch in the local repository, you can point + branch.<name>.merge to the desired branch, and use the special setting + `.` (a period) for branch.<name>.remote. color.branch:: A boolean to enable/disable color in the output of diff --git a/builtin-branch.c b/builtin-branch.c index 42b1ff1..a4494ee 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -372,9 +372,26 @@ static int get_remote_config(const char *key, const char *value) return 0; } -static void set_branch_defaults(const char *name, const char *real_ref) +static void set_branch_merge(const char *name, const char *config_remote, + const char *config_repo) { char key[1024]; + if (sizeof(key) <= + snprintf(key, sizeof(key), "branch.%s.remote", name)) + die("what a long branch name you have!"); + git_config_set(key, config_remote); + + /* + * We do not have to check if we have enough space for + * the 'merge' key, since it's shorter than the + * previous 'remote' key, which we already checked. + */ + snprintf(key, sizeof(key), "branch.%s.merge", name); + git_config_set(key, config_repo); +} + +static void set_branch_defaults(const char *name, const char *real_ref) +{ const char *slash = strrchr(real_ref, '/'); if (!slash) @@ -384,21 +401,15 @@ static void set_branch_defaults(const char *name, const char *real_ref) start_len = strlen(real_ref); base_len = slash - real_ref; git_config(get_remote_config); + if (!config_repo && !config_remote && + !prefixcmp(real_ref, "refs/heads/")) { + set_branch_merge(name, ".", real_ref); + printf("Branch %s set up to track local branch %s.\n", + name, real_ref); + } if (config_repo && config_remote) { - if (sizeof(key) <= - snprintf(key, sizeof(key), "branch.%s.remote", name)) - die("what a long branch name you have!"); - git_config_set(key, config_remote); - - /* - * We do not have to check if we have enough space for - * the 'merge' key, since it's shorter than the - * previous 'remote' key, which we already checked. - */ - snprintf(key, sizeof(key), "branch.%s.merge", name); - git_config_set(key, config_repo); - + set_branch_merge(name, config_remote, config_repo); printf("Branch %s set up to track remote branch %s.\n", name, real_ref); } diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index f8ebad0..73d448b 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -166,11 +166,12 @@ static void prepare_pack_revindex(struct pack_revindex *rix) struct packed_git *p = rix->p; int num_ent = num_packed_objects(p); int i; - void *index = p->index_base + 256; + const char *index = p->index_data; + index += 4 * 256; rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1)); for (i = 0; i < num_ent; i++) { - unsigned int hl = *((unsigned int *)((char *) index + 24*i)); + uint32_t hl = *((uint32_t *)(index + 24 * i)); rix->revindex[i].offset = ntohl(hl); rix->revindex[i].nr = i; } @@ -217,11 +218,11 @@ static off_t find_packed_object_size(struct packed_git *p, off_t ofs) return entry[1].offset - ofs; } -static unsigned char *find_packed_object_name(struct packed_git *p, - off_t ofs) +static const unsigned char *find_packed_object_name(struct packed_git *p, + off_t ofs) { struct revindex_entry *entry = find_packed_object(p, ofs); - return (unsigned char *)(p->index_base + 256) + 24 * entry->nr + 4; + return ((unsigned char *)p->index_data) + 4 * 256 + 24 * entry->nr + 4; } static void *delta_against(void *buf, unsigned long size, struct object_entry *entry) @@ -996,7 +997,8 @@ static void check_object(struct object_entry *entry) * delta. */ if (!no_reuse_delta) { - unsigned char c, *base_name; + unsigned char c; + const unsigned char *base_name; off_t ofs; unsigned long used_0; /* there is at least 20 bytes left in the pack */ @@ -371,10 +371,11 @@ struct pack_window { extern struct packed_git { struct packed_git *next; struct pack_window *windows; - uint32_t *index_base; - time_t mtime; + const void *index_data; off_t index_size; off_t pack_size; + time_t mtime; + int index_version; int pack_fd; int pack_local; unsigned char sha1[20]; @@ -412,7 +413,7 @@ extern int server_supports(const char *feature); extern struct packed_git *parse_pack_index(unsigned char *sha1); extern struct packed_git *parse_pack_index_file(const unsigned char *sha1, - char *idx_path); + const char *idx_path); extern void prepare_packed_git(void); extern void reprepare_packed_git(void); @@ -424,7 +425,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1, extern void pack_report(void); extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); extern void unuse_pack(struct pack_window **); -extern struct packed_git *add_packed_git(char *, int, int); +extern struct packed_git *add_packed_git(const char *, int, int); extern uint32_t num_packed_objects(const struct packed_git *p); extern int nth_packed_object_sha1(const struct packed_git *, uint32_t, unsigned char*); extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *); @@ -351,12 +351,12 @@ int git_default_config(const char *var, const char *value) } if (!strcmp(var, "i18n.commitencoding")) { - git_commit_encoding = strdup(value); + git_commit_encoding = xstrdup(value); return 0; } if (!strcmp(var, "i18n.logoutputencoding")) { - git_log_output_encoding = strdup(value); + git_log_output_encoding = xstrdup(value); return 0; } diff --git a/git-applymbox.sh b/git-applymbox.sh index 2cbdc7e..3efd6a7 100755 --- a/git-applymbox.sh +++ b/git-applymbox.sh @@ -77,9 +77,9 @@ do *) git-mailinfo $keep_subject $utf8 \ .dotest/msg .dotest/patch <$i >.dotest/info || exit 1 - test -s $dotest/patch || { + test -s .dotest/patch || { echo "Patch is empty. Was is split wrong?" - stop_here $this + exit 1 } git-stripspace < .dotest/msg > .dotest/msg-clean ;; diff --git a/git-checkout.sh b/git-checkout.sh index fcadf20..39ffa8b 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -89,7 +89,7 @@ while [ "$#" != "0" ]; do esac done -case "$new_branch,$track" in +case "$newbranch,$track" in ,--*) die "git checkout: --track and --no-track require -b" esac diff --git a/git-fetch.sh b/git-fetch.sh index 9d45dd2..e218042 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -157,7 +157,7 @@ then fi fi -fetch_native () { +fetch_all_at_once () { eval=$(echo "$1" | git-fetch--tool parse-reflist "-") eval "$eval" @@ -165,7 +165,9 @@ fetch_native () { ( : subshell because we muck with IFS IFS=" $LF" ( - if test -f "$remote" ; then + if test "$remote" = . ; then + git-show-ref $rref || echo failed "$remote" + elif test -f "$remote" ; then test -n "$shallow_depth" && die "shallow clone with bundle is not supported" git-bundle unbundle "$remote" $rref || @@ -188,7 +190,7 @@ fetch_native () { } -fetch_dumb () { +fetch_per_ref () { reflist="$1" refs= rref= @@ -292,10 +294,10 @@ fetch_dumb () { fetch_main () { case "$remote" in http://* | https://* | ftp://* | rsync://* ) - fetch_dumb "$@" + fetch_per_ref "$@" ;; *) - fetch_native "$@" + fetch_all_at_once "$@" ;; esac } diff --git a/git-merge.sh b/git-merge.sh index 6ce62c8..8759c5a 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -292,13 +292,13 @@ f,*) # Again the most common case of merging one remote. echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)" git-update-index --refresh 2>/dev/null - new_head=$(git-rev-parse --verify "$1^0") && - git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && msg="Fast forward" if test -n "$have_message" then msg="$msg (no commit created; -m option ignored)" fi + new_head=$(git-rev-parse --verify "$1^0") && + git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && finish "$new_head" "$msg" || exit dropsave exit 0 diff --git a/git-parse-remote.sh b/git-parse-remote.sh index c46131f..437b0c3 100755 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -9,6 +9,9 @@ get_data_source () { */*) echo '' ;; + .) + echo self + ;; *) if test "$(git-config --get "remote.$1.url")" then @@ -31,6 +34,9 @@ get_remote_url () { '') echo "$1" ;; + self) + echo "$1" + ;; config) git-config --get "remote.$1.url" ;; @@ -57,7 +63,7 @@ get_default_remote () { get_remote_default_refs_for_push () { data_source=$(get_data_source "$1") case "$data_source" in - '' | branches) + '' | branches | self) ;; # no default push mapping, just send matching refs. config) git-config --get-all "remote.$1.push" ;; @@ -163,6 +169,10 @@ get_remote_default_refs_for_fetch () { case "$data_source" in '') echo "HEAD:" ;; + self) + canon_refs_list_for_fetch -d "$1" \ + $(git-for-each-ref --format='%(refname):') + ;; config) canon_refs_list_for_fetch -d "$1" \ $(git-config --get-all "remote.$1.fetch") ;; @@ -177,7 +187,7 @@ get_remote_default_refs_for_fetch () { }' "$GIT_DIR/remotes/$1") ;; *) - die "internal error: get-remote-default-ref-for-push $1" ;; + die "internal error: get-remote-default-ref-for-fetch $1" ;; esac } diff --git a/local-fetch.c b/local-fetch.c index 7cfe8b3..4b650ef 100644 --- a/local-fetch.c +++ b/local-fetch.c @@ -64,9 +64,9 @@ static int copy_file(const char *source, char *dest, const char *hex, } /* If we got ENOENT there is no point continuing. */ if (errno == ENOENT) { - if (warn_if_not_exists) - fprintf(stderr, "does not exist %s\n", source); - return -1; + if (!warn_if_not_exists) + return -1; + return error("does not exist %s", source); } } if (use_symlink) { @@ -74,9 +74,8 @@ static int copy_file(const char *source, char *dest, const char *hex, if (stat(source, &st)) { if (!warn_if_not_exists && errno == ENOENT) return -1; - fprintf(stderr, "cannot stat %s: %s\n", source, - strerror(errno)); - return -1; + return error("cannot stat %s: %s", source, + strerror(errno)); } if (!symlink(source, dest)) { pull_say("symlink %s\n", hex); @@ -90,25 +89,21 @@ static int copy_file(const char *source, char *dest, const char *hex, if (ifd < 0) { if (!warn_if_not_exists && errno == ENOENT) return -1; - fprintf(stderr, "cannot open %s\n", source); - return -1; + return error("cannot open %s", source); } ofd = open(dest, O_WRONLY | O_CREAT | O_EXCL, 0666); if (ofd < 0) { - fprintf(stderr, "cannot open %s\n", dest); close(ifd); - return -1; + return error("cannot open %s", dest); } status = copy_fd(ifd, ofd); close(ofd); if (status) - fprintf(stderr, "cannot write %s\n", dest); - else - pull_say("copy %s\n", hex); - return status; + return error("cannot write %s", dest); + pull_say("copy %s\n", hex); + return 0; } - fprintf(stderr, "failed to copy %s with given copy methods.\n", hex); - return -1; + return error("failed to copy %s with given copy methods.", hex); } static int fetch_pack(const unsigned char *sha1) @@ -181,13 +176,11 @@ int fetch_ref(char *ref, unsigned char *sha1) ifd = open(filename, O_RDONLY); if (ifd < 0) { close(ifd); - fprintf(stderr, "cannot open %s\n", filename); - return -1; + return error("cannot open %s", filename); } if (read_in_full(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) { close(ifd); - fprintf(stderr, "cannot read from %s\n", filename); - return -1; + return error("cannot read from %s", filename); } close(ifd); pull_say("ref %s\n", sha1_to_hex(sha1)); diff --git a/pack-check.c b/pack-check.c index 299c514..d988322 100644 --- a/pack-check.c +++ b/pack-check.c @@ -5,7 +5,7 @@ static int verify_packfile(struct packed_git *p, struct pack_window **w_curs) { off_t index_size = p->index_size; - void *index_base = p->index_base; + const unsigned char *index_base = p->index_data; SHA_CTX ctx; unsigned char sha1[20]; off_t offset = 0, pack_sig = p->pack_size - 20; @@ -31,7 +31,7 @@ static int verify_packfile(struct packed_git *p, if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL))) return error("Packfile %s SHA1 mismatch with itself", p->pack_name); - if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40)) + if (hashcmp(sha1, index_base + index_size - 40)) return error("Packfile %s SHA1 mismatch with idx", p->pack_name); unuse_pack(w_curs); @@ -127,7 +127,7 @@ static void show_pack_info(struct packed_git *p) int verify_pack(struct packed_git *p, int verbose) { off_t index_size = p->index_size; - void *index_base = p->index_base; + const unsigned char *index_base = p->index_data; SHA_CTX ctx; unsigned char sha1[20]; int ret; @@ -137,7 +137,7 @@ int verify_pack(struct packed_git *p, int verbose) SHA1_Init(&ctx); SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20)); SHA1_Final(sha1, &ctx); - if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20)) + if (hashcmp(sha1, index_base + index_size - 20)) ret = error("Packfile index for %s SHA1 mismatch", p->pack_name); diff --git a/pack-redundant.c b/pack-redundant.c index c8f7d9a..40e579b 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -17,7 +17,7 @@ static int load_all_packs, verbose, alt_odb; struct llist_item { struct llist_item *next; - unsigned char *sha1; + const unsigned char *sha1; }; static struct llist { struct llist_item *front; @@ -104,9 +104,9 @@ static struct llist * llist_copy(struct llist *list) return ret; } -static inline struct llist_item * llist_insert(struct llist *list, - struct llist_item *after, - unsigned char *sha1) +static inline struct llist_item *llist_insert(struct llist *list, + struct llist_item *after, + const unsigned char *sha1) { struct llist_item *new = llist_item_get(); new->sha1 = sha1; @@ -128,12 +128,14 @@ static inline struct llist_item * llist_insert(struct llist *list, return new; } -static inline struct llist_item *llist_insert_back(struct llist *list, unsigned char *sha1) +static inline struct llist_item *llist_insert_back(struct llist *list, + const unsigned char *sha1) { return llist_insert(list, list->back, sha1); } -static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, unsigned char *sha1, struct llist_item *hint) +static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, + const unsigned char *sha1, struct llist_item *hint) { struct llist_item *prev = NULL, *l; @@ -246,12 +248,12 @@ static struct pack_list * pack_list_difference(const struct pack_list *A, static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2) { int p1_off, p2_off; - unsigned char *p1_base, *p2_base; + const unsigned char *p1_base, *p2_base; struct llist_item *p1_hint = NULL, *p2_hint = NULL; p1_off = p2_off = 256 * 4 + 4; - p1_base = (unsigned char *) p1->pack->index_base; - p2_base = (unsigned char *) p2->pack->index_base; + p1_base = p1->pack->index_data; + p2_base = p2->pack->index_data; while (p1_off <= p1->pack->index_size - 3 * 20 && p2_off <= p2->pack->index_size - 3 * 20) @@ -351,11 +353,11 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2) { size_t ret = 0; int p1_off, p2_off; - unsigned char *p1_base, *p2_base; + const unsigned char *p1_base, *p2_base; p1_off = p2_off = 256 * 4 + 4; - p1_base = (unsigned char *)p1->index_base; - p2_base = (unsigned char *)p2->index_base; + p1_base = p1->index_data; + p2_base = p2->index_data; while (p1_off <= p1->index_size - 3 * 20 && p2_off <= p2->index_size - 3 * 20) @@ -534,7 +536,7 @@ static struct pack_list * add_pack(struct packed_git *p) { struct pack_list l; size_t off; - unsigned char *base; + const unsigned char *base; if (!p->pack_local && !(alt_odb || verbose)) return NULL; @@ -543,7 +545,7 @@ static struct pack_list * add_pack(struct packed_git *p) llist_init(&l.all_objects); off = 256 * 4 + 4; - base = (unsigned char *)p->index_base; + base = p->index_data; while (off <= p->index_size - 3 * 20) { llist_insert_back(l.all_objects, base + off); off += 24; @@ -16,24 +16,15 @@ struct pack_header { }; /* - * Packed object index header - * - * struct pack_idx_header { - * uint32_t idx_signature; - * uint32_t idx_version; - * }; - * - * Note: this header isn't active yet. In future versions of git - * we may change the index file format. At that time we would start - * the first four bytes of the new index format with this signature, - * as all older git binaries would find this value illegal and abort - * reading the file. + * The first four bytes of index formats later than version 1 should + * start with this signature, as all older git binaries would find this + * value illegal and abort reading the file. * * This is the case because the number of objects in a packfile * cannot exceed 1,431,660,000 as every object would need at least - * 3 bytes of data and the overall packfile cannot exceed 4 GiB due - * to the 32 bit offsets used by the index. Clearly the signature - * exceeds this maximum. + * 3 bytes of data and the overall packfile cannot exceed 4 GiB with + * version 1 of the index file due to the offsets limited to 32 bits. + * Clearly the signature exceeds this maximum. * * Very old git binaries will also compare the first 4 bytes to the * next 4 bytes in the index and abort with a "non-monotonic index" @@ -43,6 +34,15 @@ struct pack_header { */ #define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */ +/* + * Packed object index header + */ +struct pack_idx_header { + uint32_t idx_signature; + uint32_t idx_version; +}; + + extern int verify_pack(struct packed_git *, int); #define PH_ERROR_EOF (-1) diff --git a/sha1_file.c b/sha1_file.c index 5691448..ee64865 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -432,16 +432,15 @@ void pack_report() pack_mapped, peak_pack_mapped); } -static int check_packed_git_idx(const char *path, - unsigned long *idx_size_, - void **idx_map_) +static int check_packed_git_idx(const char *path, struct packed_git *p) { void *idx_map; - uint32_t *index; + struct pack_idx_header *hdr; size_t idx_size; - uint32_t nr, i; + uint32_t nr, i, *index; int fd = open(path, O_RDONLY); struct stat st; + if (fd < 0) return -1; if (fstat(fd, &st)) { @@ -456,15 +455,12 @@ static int check_packed_git_idx(const char *path, idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - index = idx_map; - *idx_map_ = idx_map; - *idx_size_ = idx_size; - /* a future index format would start with this, as older git * binaries would fail the non-monotonic index check below. * give a nicer warning to the user if we can. */ - if (index[0] == htonl(PACK_IDX_SIGNATURE)) { + hdr = idx_map; + if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) { munmap(idx_map, idx_size); return error("index file %s is a newer version" " and is not supported by this binary" @@ -473,6 +469,7 @@ static int check_packed_git_idx(const char *path, } nr = 0; + index = idx_map; for (i = 0; i < 256; i++) { uint32_t n = ntohl(index[i]); if (n < nr) { @@ -494,6 +491,9 @@ static int check_packed_git_idx(const char *path, return error("wrong index file size in %s", path); } + p->index_version = 1; + p->index_data = idx_map; + p->index_size = idx_size; return 0; } @@ -614,7 +614,7 @@ static int open_packed_git_1(struct packed_git *p) return error("end of packfile %s is unavailable", p->pack_name); if (read_in_full(p->pack_fd, sha1, sizeof(sha1)) != sizeof(sha1)) return error("packfile %s signature is unavailable", p->pack_name); - idx_sha1 = ((unsigned char *)p->index_base) + p->index_size - 40; + idx_sha1 = ((unsigned char *)p->index_data) + p->index_size - 40; if (hashcmp(sha1, idx_sha1)) return error("packfile %s does not match index", p->pack_name); return 0; @@ -710,38 +710,37 @@ unsigned char* use_pack(struct packed_git *p, return win->base + offset; } -struct packed_git *add_packed_git(char *path, int path_len, int local) +struct packed_git *add_packed_git(const char *path, int path_len, int local) { struct stat st; - struct packed_git *p; - unsigned long idx_size; - void *idx_map; - unsigned char sha1[20]; + struct packed_git *p = xmalloc(sizeof(*p) + path_len + 2); - if (check_packed_git_idx(path, &idx_size, &idx_map)) + /* + * Make sure a corresponding .pack file exists and that + * the index looks sane. + */ + path_len -= strlen(".idx"); + if (path_len < 1) return NULL; - - /* do we have a corresponding .pack file? */ - strcpy(path + path_len - 4, ".pack"); - if (stat(path, &st) || !S_ISREG(st.st_mode)) { - munmap(idx_map, idx_size); + memcpy(p->pack_name, path, path_len); + strcpy(p->pack_name + path_len, ".pack"); + if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) || + check_packed_git_idx(path, p)) { + free(p); return NULL; } + /* ok, it looks sane as far as we can check without * actually mapping the pack file. */ - p = xmalloc(sizeof(*p) + path_len + 2); - strcpy(p->pack_name, path); - p->index_size = idx_size; p->pack_size = st.st_size; - p->index_base = idx_map; p->next = NULL; p->windows = NULL; p->pack_fd = -1; p->pack_local = local; p->mtime = st.st_mtime; - if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1)) - hashcpy(p->sha1, sha1); + if (path_len < 40 || get_sha1_hex(path + path_len - 40, p->sha1)) + hashclr(p->sha1); return p; } @@ -751,23 +750,19 @@ struct packed_git *parse_pack_index(unsigned char *sha1) return parse_pack_index_file(sha1, path); } -struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_path) +struct packed_git *parse_pack_index_file(const unsigned char *sha1, + const char *idx_path) { - struct packed_git *p; - unsigned long idx_size; - void *idx_map; - char *path; + const char *path = sha1_pack_name(sha1); + struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2); - if (check_packed_git_idx(idx_path, &idx_size, &idx_map)) + if (check_packed_git_idx(idx_path, p)) { + free(p); return NULL; + } - path = sha1_pack_name(sha1); - - p = xmalloc(sizeof(*p) + strlen(path) + 2); strcpy(p->pack_name, path); - p->index_size = idx_size; p->pack_size = 0; - p->index_base = idx_map; p->next = NULL; p->windows = NULL; p->pack_fd = -1; @@ -1357,6 +1352,65 @@ static void *unpack_compressed_entry(struct packed_git *p, return buffer; } +#define MAX_DELTA_CACHE (256) + +static struct delta_base_cache_entry { + struct packed_git *p; + off_t base_offset; + unsigned long size; + void *data; + enum object_type type; +} delta_base_cache[MAX_DELTA_CACHE]; + +static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset) +{ + unsigned long hash; + + hash = (unsigned long)p + (unsigned long)base_offset; + hash += (hash >> 8) + (hash >> 16); + return hash & 0xff; +} + +static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset, + unsigned long *base_size, enum object_type *type, int keep_cache) +{ + void *ret; + unsigned long hash = pack_entry_hash(p, base_offset); + struct delta_base_cache_entry *ent = delta_base_cache + hash; + + ret = ent->data; + if (ret && ent->p == p && ent->base_offset == base_offset) + goto found_cache_entry; + return unpack_entry(p, base_offset, type, base_size); + +found_cache_entry: + if (!keep_cache) + ent->data = NULL; + else { + ret = xmalloc(ent->size + 1); + memcpy(ret, ent->data, ent->size); + ((char *)ret)[ent->size] = 0; + } + *type = ent->type; + *base_size = ent->size; + return ret; +} + +static void add_delta_base_cache(struct packed_git *p, off_t base_offset, + void *base, unsigned long base_size, enum object_type type) +{ + unsigned long hash = pack_entry_hash(p, base_offset); + struct delta_base_cache_entry *ent = delta_base_cache + hash; + + if (ent->data) + free(ent->data); + ent->p = p; + ent->base_offset = base_offset; + ent->type = type; + ent->data = base; + ent->size = base_size; +} + static void *unpack_delta_entry(struct packed_git *p, struct pack_window **w_curs, off_t curpos, @@ -1370,7 +1424,7 @@ static void *unpack_delta_entry(struct packed_git *p, off_t base_offset; base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset); - base = unpack_entry(p, base_offset, type, &base_size); + base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0); if (!base) die("failed to read delta base object" " at %"PRIuMAX" from %s", @@ -1383,7 +1437,7 @@ static void *unpack_delta_entry(struct packed_git *p, if (!result) die("failed to apply delta"); free(delta_data); - free(base); + add_delta_base_cache(p, base_offset, base, base_size, *type); return result; } @@ -1423,24 +1477,27 @@ uint32_t num_packed_objects(const struct packed_git *p) int nth_packed_object_sha1(const struct packed_git *p, uint32_t n, unsigned char* sha1) { - void *index = p->index_base + 256; + const unsigned char *index = p->index_data; + index += 4 * 256; if (num_packed_objects(p) <= n) return -1; - hashcpy(sha1, (unsigned char *) index + (24 * n) + 4); + hashcpy(sha1, index + 24 * n + 4); return 0; } off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *p) { - uint32_t *level1_ofs = p->index_base; + const uint32_t *level1_ofs = p->index_data; int hi = ntohl(level1_ofs[*sha1]); int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1])); - void *index = p->index_base + 256; + const unsigned char *index = p->index_data; + + index += 4 * 256; do { int mi = (lo + hi) / 2; - int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1); + int cmp = hashcmp(index + 24 * mi + 4, sha1); if (!cmp) return ntohl(*((uint32_t *)((char *)index + (24 * mi)))); if (cmp > 0) @@ -1564,7 +1621,7 @@ static void *read_packed_sha1(const unsigned char *sha1, if (!find_pack_entry(sha1, &e, NULL)) return NULL; else - return unpack_entry(e.p, e.offset, type, size); + return cache_or_unpack_entry(e.p, e.offset, size, type, 1); } /* diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 75c000a..9558bdb 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -145,9 +145,15 @@ test_expect_success 'test overriding tracking setup via --no-track' \ git-config remote.local.fetch refs/heads/*:refs/remotes/local/* && (git-show-ref -q refs/remotes/local/master || git-fetch local) && git-branch --no-track my2 local/master && + git-config branch.autosetupmerge false && ! test $(git-config branch.my2.remote) = local && ! test $(git-config branch.my2.merge) = refs/heads/master' +test_expect_success 'test local tracking setup' \ + 'git branch --track my6 s && + test $(git-config branch.my6.remote) = . && + test $(git-config branch.my6.merge) = refs/heads/s' + # Keep this test last, as it changes the current branch cat >expect <<EOF 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index f511547..eacb1e9 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -64,7 +64,7 @@ test_expect_success \ cd "$TRASH" test_expect_success \ - 'pack with delta' \ + 'pack with REF_DELTA' \ 'pwd && packname_2=$(git-pack-objects test-2 <obj-list)' @@ -72,7 +72,7 @@ rm -fr .git2 mkdir .git2 test_expect_success \ - 'unpack with delta' \ + 'unpack with REF_DELTA' \ 'GIT_OBJECT_DIRECTORY=.git2/objects && export GIT_OBJECT_DIRECTORY && git-init && @@ -82,7 +82,7 @@ test_expect_success \ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ - 'check unpack with delta' \ + 'check unpack with REF_DELTA' \ '(cd ../.git && find objects -type f -print) | while read path do @@ -93,6 +93,42 @@ test_expect_success \ done' cd "$TRASH" +test_expect_success \ + 'pack with OFS_DELTA' \ + 'pwd && + packname_3=$(git-pack-objects --delta-base-offset test-3 <obj-list)' + +rm -fr .git2 +mkdir .git2 + +test_expect_success \ + 'unpack with OFS_DELTA' \ + 'GIT_OBJECT_DIRECTORY=.git2/objects && + export GIT_OBJECT_DIRECTORY && + git-init && + git-unpack-objects -n <test-3-${packname_3}.pack && + git-unpack-objects <test-3-${packname_3}.pack' + +unset GIT_OBJECT_DIRECTORY +cd "$TRASH/.git2" +test_expect_success \ + 'check unpack with OFS_DELTA' \ + '(cd ../.git && find objects -type f -print) | + while read path + do + cmp $path ../.git/$path || { + echo $path differs. + return 1 + } + done' +cd "$TRASH" + +test_expect_success \ + 'compare delta flavors' \ + 'size_2=`stat -c "%s" test-2-${packname_2}.pack` && + size_3=`stat -c "%s" test-3-${packname_3}.pack` && + test $size_2 -gt $size_3' + rm -fr .git2 mkdir .git2 @@ -111,12 +147,11 @@ test_expect_success \ } >current && diff expect current' - test_expect_success \ - 'use packed deltified objects' \ + 'use packed deltified (REF_DELTA) objects' \ 'GIT_OBJECT_DIRECTORY=.git2/objects && export GIT_OBJECT_DIRECTORY && - rm -f .git2/objects/pack/test-?.idx && + rm .git2/objects/pack/test-* && cp test-2-${packname_2}.pack test-2-${packname_2}.idx .git2/objects/pack && { git-diff-tree --root -p $commit && while read object @@ -127,11 +162,28 @@ test_expect_success \ } >current && diff expect current' +test_expect_success \ + 'use packed deltified (OFS_DELTA) objects' \ + 'GIT_OBJECT_DIRECTORY=.git2/objects && + export GIT_OBJECT_DIRECTORY && + rm .git2/objects/pack/test-* && + cp test-3-${packname_3}.pack test-3-${packname_3}.idx .git2/objects/pack && { + git-diff-tree --root -p $commit && + while read object + do + t=`git-cat-file -t $object` && + git-cat-file $t $object || return 1 + done <obj-list + } >current && + diff expect current' + unset GIT_OBJECT_DIRECTORY test_expect_success \ 'verify pack' \ - 'git-verify-pack test-1-${packname_1}.idx test-2-${packname_2}.idx' + 'git-verify-pack test-1-${packname_1}.idx \ + test-2-${packname_2}.idx \ + test-3-${packname_3}.idx' test_expect_success \ 'corrupt a pack and see if verify catches' \ @@ -194,6 +246,13 @@ test_expect_success \ git-index-pack test-3.pack && cmp test-3.idx test-2-${packname_2}.idx && + cp test-3-${packname_3}.pack test-3.pack && + git-index-pack -o tmp.idx test-3-${packname_3}.pack && + cmp tmp.idx test-3-${packname_3}.idx && + + git-index-pack test-3.pack && + cmp test-3.idx test-3-${packname_3}.idx && + :' test_done diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 7eb3783..243212d 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -29,5 +29,29 @@ test_expect_success 'checking the results' ' diff file cloned/file ' +test_expect_success 'test . as a remote' ' + + git branch copy master && + git config branch.copy.remote . && + git config branch.copy.merge refs/heads/master && + echo updated >file && + git commit -a -m updated && + git checkout copy && + test `cat file` = file && + git pull && + test `cat file` = updated +' + +test_expect_success 'the default remote . should not break explicit pull' ' + git checkout -b second master^ && + echo modified >file && + git commit -a -m modified && + git checkout copy && + git reset --hard HEAD^ && + test `cat file` = file && + git pull . second && + test `cat file` = modified +' + test_done diff --git a/tree-diff.c b/tree-diff.c index 44cde74..3940962 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -5,9 +5,8 @@ #include "diff.h" #include "tree.h" -static char *malloc_base(const char *base, const char *path, int pathlen) +static char *malloc_base(const char *base, int baselen, const char *path, int pathlen) { - int baselen = strlen(base); char *newbase = xmalloc(baselen + pathlen + 2); memcpy(newbase, base, baselen); memcpy(newbase + baselen, path, pathlen); @@ -16,9 +15,9 @@ static char *malloc_base(const char *base, const char *path, int pathlen) } static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base); + const char *base, int baselen); -static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) +static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; @@ -28,15 +27,15 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); - pathlen1 = strlen(path1); - pathlen2 = strlen(path2); + pathlen1 = tree_entry_len(path1, sha1); + pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { - show_entry(opt, "-", t1, base); + show_entry(opt, "-", t1, base, baselen); return -1; } if (cmp > 0) { - show_entry(opt, "+", t2, base); + show_entry(opt, "+", t2, base, baselen); return 1; } if (!opt->find_copies_harder && !hashcmp(sha1, sha2) && mode1 == mode2) @@ -47,14 +46,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { - show_entry(opt, "-", t1, base); - show_entry(opt, "+", t2, base); + show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "+", t2, base, baselen); return 0; } if (opt->recursive && S_ISDIR(mode1)) { int retval; - char *newbase = malloc_base(base, path1, pathlen1); + char *newbase = malloc_base(base, baselen, path1, pathlen1); if (opt->tree_in_recursive) opt->change(opt, mode1, mode2, sha1, sha2, base, path1); @@ -67,20 +66,20 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const return 0; } -static int interesting(struct tree_desc *desc, const char *base, struct diff_options *opt) +static int interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt) { const char *path; + const unsigned char *sha1; unsigned mode; int i; - int baselen, pathlen; + int pathlen; if (!opt->nr_paths) return 1; - (void)tree_entry_extract(desc, &path, &mode); + sha1 = tree_entry_extract(desc, &path, &mode); - pathlen = strlen(path); - baselen = strlen(base); + pathlen = tree_entry_len(path, sha1); for (i=0; i < opt->nr_paths; i++) { const char *match = opt->paths[i]; @@ -121,18 +120,18 @@ static int interesting(struct tree_desc *desc, const char *base, struct diff_opt } /* A whole sub-tree went away or appeared */ -static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base) +static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) { while (desc->size) { - if (interesting(desc, base, opt)) - show_entry(opt, prefix, desc, base); + if (interesting(desc, base, baselen, opt)) + show_entry(opt, prefix, desc, base, baselen); update_tree_entry(desc); } } /* A file entry went away or appeared */ static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base) + const char *base, int baselen) { unsigned mode; const char *path; @@ -140,7 +139,8 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (opt->recursive && S_ISDIR(mode)) { enum object_type type; - char *newbase = malloc_base(base, path, strlen(path)); + int pathlen = tree_entry_len(path, sha1); + char *newbase = malloc_base(base, baselen, path, pathlen); struct tree_desc inner; void *tree; @@ -149,7 +149,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree die("corrupt tree sha %s", sha1_to_hex(sha1)); inner.buf = tree; - show_tree(opt, prefix, &inner, newbase); + show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen); free(tree); free(newbase); @@ -160,28 +160,30 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) { + int baselen = strlen(base); + while (t1->size | t2->size) { if (opt->quiet && opt->has_changes) break; - if (opt->nr_paths && t1->size && !interesting(t1, base, opt)) { + if (opt->nr_paths && t1->size && !interesting(t1, base, baselen, opt)) { update_tree_entry(t1); continue; } - if (opt->nr_paths && t2->size && !interesting(t2, base, opt)) { + if (opt->nr_paths && t2->size && !interesting(t2, base, baselen, opt)) { update_tree_entry(t2); continue; } if (!t1->size) { - show_entry(opt, "+", t2, base); + show_entry(opt, "+", t2, base, baselen); update_tree_entry(t2); continue; } if (!t2->size) { - show_entry(opt, "-", t1, base); + show_entry(opt, "-", t1, base, baselen); update_tree_entry(t1); continue; } - switch (compare_tree_entry(t1, t2, base, opt)) { + switch (compare_tree_entry(t1, t2, base, baselen, opt)) { case -1: update_tree_entry(t1); continue; diff --git a/tree-walk.c b/tree-walk.c index 70f8999..a4a4e2a 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -32,7 +32,7 @@ static void entry_clear(struct name_entry *a) static void entry_extract(struct tree_desc *t, struct name_entry *a) { a->sha1 = tree_entry_extract(t, &a->path, &a->mode); - a->pathlen = strlen(a->path); + a->pathlen = tree_entry_len(a->path, a->sha1); } void update_tree_entry(struct tree_desc *desc) @@ -169,7 +169,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char sha1 = tree_entry_extract(t, &entry, mode); update_tree_entry(t); - entrylen = strlen(entry); + entrylen = tree_entry_len(entry, sha1); if (entrylen > namelen) continue; cmp = memcmp(name, entry, entrylen); diff --git a/tree-walk.h b/tree-walk.h index e57befa..a0d7afd 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -13,6 +13,11 @@ struct name_entry { int pathlen; }; +static inline int tree_entry_len(const char *name, const unsigned char *sha1) +{ + return (char *)sha1 - (char *)name - 1; +} + void update_tree_entry(struct tree_desc *); const unsigned char *tree_entry_extract(struct tree_desc *, const char **, unsigned int *); |