From: Junio C Hamano Date: Wed, 21 Jun 2017 22:20:44 +0000 (-0700) Subject: Merge branches 'bw/ls-files-sans-the-index' and 'bw/config-h' into bw/repo-object X-Git-Tag: v2.14.0-rc0~38^2~20 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/25bf951381a4880c43a3d1c65e6dce651e61148f?ds=inline;hp=-c Merge branches 'bw/ls-files-sans-the-index' and 'bw/config-h' into bw/repo-object * bw/ls-files-sans-the-index: ls-files: factor out tag calculation ls-files: factor out debug info into a function ls-files: convert show_files to take an index ls-files: convert show_ce_entry to take an index ls-files: convert prune_cache to take an index ls-files: convert ce_excluded to take an index ls-files: convert show_ru_info to take an index ls-files: convert show_other_files to take an index ls-files: convert show_killed_files to take an index ls-files: convert write_eolinfo to take an index ls-files: convert overlay_tree_on_cache to take an index tree: convert read_tree to take an index parameter convert: convert renormalize_buffer to take an index convert: convert convert_to_git to take an index convert: convert convert_to_git_filter_fd to take an index convert: convert crlf_to_git to take an index convert: convert get_cached_convert_stats_ascii to take an index * bw/config-h: config: don't implicitly use gitdir or commondir config: respect commondir setup: teach discover_git_directory to respect the commondir config: don't include config.h by default config: remove git_config_iter config: create config.h alias: use the early config machinery to expand aliases t7006: demonstrate a problem with aliases in subdirectories t1308: relax the test verifying that empty alias values are disallowed help: use early config when autocorrecting aliases config: report correct line number upon error discover_git_directory(): avoid setting invalid git_dir --- 25bf951381a4880c43a3d1c65e6dce651e61148f diff --combined apply.c index 854faa6779,97afb6f60a,5b442860df..65063785c1 --- a/apply.c +++ b/apply.c @@@@ -8,6 -8,6 -8,7 +8,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "blob.h" #include "delta.h" #include "diff.h" @@@@ -2267,7 -2267,7 -2268,7 +2268,7 @@@@ static int read_old_data(struct stat *s case S_IFREG: if (strbuf_read_file(buf, path, st->st_size) != st->st_size) return error(_("unable to open or read %s"), path); - - convert_to_git(path, buf->buf, buf->len, buf, 0); + + convert_to_git(&the_index, path, buf->buf, buf->len, buf, 0); return 0; default: return -1; @@@@ -3741,7 -3741,7 -3742,7 +3742,7 @@@@ static int check_to_create(struct apply return 0; return EXISTS_IN_WORKTREE; -- } else if ((errno != ENOENT) && (errno != ENOTDIR)) { ++ } else if (!is_missing_file_error(errno)) { return error_errno("%s", new_name); } return 0; @@@@ -4091,181 -4091,181 -4092,181 +4092,181 @@@@ static int build_fake_ancestor(struct a res = write_locked_index(&result, &lock, COMMIT_LOCK); discard_index(&result); - if (res) - return error(_("could not write temporary index to %s"), - state->fake_ancestor); + if (res) + return error(_("could not write temporary index to %s"), + state->fake_ancestor); - return 0; - } + return 0; +} - static void stat_patch_list(struct apply_state *state, struct patch *patch) - { - int files, adds, dels; +static void stat_patch_list(struct apply_state *state, struct patch *patch) +{ + int files, adds, dels; - for (files = adds = dels = 0 ; patch ; patch = patch->next) { - files++; - adds += patch->lines_added; - dels += patch->lines_deleted; - show_stats(state, patch); - } + for (files = adds = dels = 0 ; patch ; patch = patch->next) { + files++; + adds += patch->lines_added; + dels += patch->lines_deleted; + show_stats(state, patch); + } - print_stat_summary(stdout, files, adds, dels); - } + print_stat_summary(stdout, files, adds, dels); +} - static void numstat_patch_list(struct apply_state *state, - struct patch *patch) - { - for ( ; patch; patch = patch->next) { - const char *name; - name = patch->new_name ? patch->new_name : patch->old_name; - if (patch->is_binary) - printf("-\t-\t"); - else - printf("%d\t%d\t", patch->lines_added, patch->lines_deleted); - write_name_quoted(name, stdout, state->line_termination); - } - } - - static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name) - { - if (mode) - printf(" %s mode %06o %s\n", newdelete, mode, name); - else - printf(" %s %s\n", newdelete, name); - } - - static void show_mode_change(struct patch *p, int show_name) - { - if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) { - if (show_name) - printf(" mode change %06o => %06o %s\n", - p->old_mode, p->new_mode, p->new_name); - else - printf(" mode change %06o => %06o\n", - p->old_mode, p->new_mode); - } - } - - static void show_rename_copy(struct patch *p) - { - const char *renamecopy = p->is_rename ? "rename" : "copy"; - const char *old, *new; - - /* Find common prefix */ - old = p->old_name; - new = p->new_name; - while (1) { - const char *slash_old, *slash_new; - slash_old = strchr(old, '/'); - slash_new = strchr(new, '/'); - if (!slash_old || - !slash_new || - slash_old - old != slash_new - new || - memcmp(old, new, slash_new - new)) - break; - old = slash_old + 1; - new = slash_new + 1; - } - /* p->old_name thru old is the common prefix, and old and new - * through the end of names are renames - */ - if (old != p->old_name) - printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy, - (int)(old - p->old_name), p->old_name, - old, new, p->score); - else - printf(" %s %s => %s (%d%%)\n", renamecopy, - p->old_name, p->new_name, p->score); - show_mode_change(p, 0); - } - - static void summary_patch_list(struct patch *patch) - { - struct patch *p; - - for (p = patch; p; p = p->next) { - if (p->is_new) - show_file_mode_name("create", p->new_mode, p->new_name); - else if (p->is_delete) - show_file_mode_name("delete", p->old_mode, p->old_name); - else { - if (p->is_rename || p->is_copy) - show_rename_copy(p); - else { - if (p->score) { - printf(" rewrite %s (%d%%)\n", - p->new_name, p->score); - show_mode_change(p, 0); - } - else - show_mode_change(p, 1); - } - } - } - } - - static void patch_stats(struct apply_state *state, struct patch *patch) - { - int lines = patch->lines_added + patch->lines_deleted; - - if (lines > state->max_change) - state->max_change = lines; - if (patch->old_name) { - int len = quote_c_style(patch->old_name, NULL, NULL, 0); - if (!len) - len = strlen(patch->old_name); - if (len > state->max_len) - state->max_len = len; - } - if (patch->new_name) { - int len = quote_c_style(patch->new_name, NULL, NULL, 0); - if (!len) - len = strlen(patch->new_name); - if (len > state->max_len) - state->max_len = len; - } - } - - static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty) - { - if (state->update_index) { - if (remove_file_from_cache(patch->old_name) < 0) - return error(_("unable to remove %s from index"), patch->old_name); - } - if (!state->cached) { - if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) { - remove_path(patch->old_name); - } - } - return 0; - } - - static int add_index_file(struct apply_state *state, - const char *path, - unsigned mode, - void *buf, - unsigned long size) - { - struct stat st; - struct cache_entry *ce; - int namelen = strlen(path); - unsigned ce_size = cache_entry_size(namelen); - - if (!state->update_index) - return 0; - - ce = xcalloc(1, ce_size); - memcpy(ce->name, path, namelen); - ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = create_ce_flags(0); - ce->ce_namelen = namelen; - if (S_ISGITLINK(mode)) { - const char *s; - - if (!skip_prefix(buf, "Subproject commit ", &s) || - get_oid_hex(s, &ce->oid)) { +static void numstat_patch_list(struct apply_state *state, + struct patch *patch) +{ + for ( ; patch; patch = patch->next) { + const char *name; + name = patch->new_name ? patch->new_name : patch->old_name; + if (patch->is_binary) + printf("-\t-\t"); + else + printf("%d\t%d\t", patch->lines_added, patch->lines_deleted); + write_name_quoted(name, stdout, state->line_termination); + } +} + +static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name) +{ + if (mode) + printf(" %s mode %06o %s\n", newdelete, mode, name); + else + printf(" %s %s\n", newdelete, name); +} + +static void show_mode_change(struct patch *p, int show_name) +{ + if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) { + if (show_name) + printf(" mode change %06o => %06o %s\n", + p->old_mode, p->new_mode, p->new_name); + else + printf(" mode change %06o => %06o\n", + p->old_mode, p->new_mode); + } +} + +static void show_rename_copy(struct patch *p) +{ + const char *renamecopy = p->is_rename ? "rename" : "copy"; + const char *old, *new; + + /* Find common prefix */ + old = p->old_name; + new = p->new_name; + while (1) { + const char *slash_old, *slash_new; + slash_old = strchr(old, '/'); + slash_new = strchr(new, '/'); + if (!slash_old || + !slash_new || + slash_old - old != slash_new - new || + memcmp(old, new, slash_new - new)) + break; + old = slash_old + 1; + new = slash_new + 1; + } + /* p->old_name thru old is the common prefix, and old and new + * through the end of names are renames + */ + if (old != p->old_name) + printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy, + (int)(old - p->old_name), p->old_name, + old, new, p->score); + else + printf(" %s %s => %s (%d%%)\n", renamecopy, + p->old_name, p->new_name, p->score); + show_mode_change(p, 0); +} + +static void summary_patch_list(struct patch *patch) +{ + struct patch *p; + + for (p = patch; p; p = p->next) { + if (p->is_new) + show_file_mode_name("create", p->new_mode, p->new_name); + else if (p->is_delete) + show_file_mode_name("delete", p->old_mode, p->old_name); + else { + if (p->is_rename || p->is_copy) + show_rename_copy(p); + else { + if (p->score) { + printf(" rewrite %s (%d%%)\n", + p->new_name, p->score); + show_mode_change(p, 0); + } + else + show_mode_change(p, 1); + } + } + } +} + +static void patch_stats(struct apply_state *state, struct patch *patch) +{ + int lines = patch->lines_added + patch->lines_deleted; + + if (lines > state->max_change) + state->max_change = lines; + if (patch->old_name) { + int len = quote_c_style(patch->old_name, NULL, NULL, 0); + if (!len) + len = strlen(patch->old_name); + if (len > state->max_len) + state->max_len = len; + } + if (patch->new_name) { + int len = quote_c_style(patch->new_name, NULL, NULL, 0); + if (!len) + len = strlen(patch->new_name); + if (len > state->max_len) + state->max_len = len; + } +} + +static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty) +{ + if (state->update_index) { + if (remove_file_from_cache(patch->old_name) < 0) + return error(_("unable to remove %s from index"), patch->old_name); + } + if (!state->cached) { + if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) { + remove_path(patch->old_name); + } + } + return 0; +} + +static int add_index_file(struct apply_state *state, + const char *path, + unsigned mode, + void *buf, + unsigned long size) +{ + struct stat st; + struct cache_entry *ce; + int namelen = strlen(path); + unsigned ce_size = cache_entry_size(namelen); + + if (!state->update_index) + return 0; + + ce = xcalloc(1, ce_size); + memcpy(ce->name, path, namelen); + ce->ce_mode = create_ce_mode(mode); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = namelen; + if (S_ISGITLINK(mode)) { + const char *s; + + if (!skip_prefix(buf, "Subproject commit ", &s) || + get_oid_hex(s, &ce->oid)) { free(ce); - return error(_("corrupt patch for submodule %s"), path); + return error(_("corrupt patch for submodule %s"), path); } } else { if (!state->cached) { diff --combined archive-tar.c index 073e60ebd3,073e60ebd3,d65ac016df..c6ed96ee74 --- a/archive-tar.c +++ b/archive-tar.c @@@@ -2,6 -2,6 -2,7 +2,7 @@@@ * Copyright (c) 2005, 2006 Rene Scharfe */ #include "cache.h" ++ #include "config.h" #include "tar.h" #include "archive.h" #include "streaming.h" @@@@ -27,13 -27,13 -28,10 +28,13 @@@@ static int write_tar_filter_archive(con */ #if ULONG_MAX == 0xFFFFFFFF #define USTAR_MAX_SIZE ULONG_MAX -#define USTAR_MAX_MTIME ULONG_MAX #else #define USTAR_MAX_SIZE 077777777777UL -#define USTAR_MAX_MTIME 077777777777UL +#endif +#if TIME_MAX == 0xFFFFFFFF +#define USTAR_MAX_MTIME TIME_MAX +#else +#define USTAR_MAX_MTIME 077777777777ULL #endif /* writes out the whole block, but only if it is full */ diff --combined archive-zip.c index 27563e9e26,27563e9e26,04fcd86872..e8913e5a26 --- a/archive-zip.c +++ b/archive-zip.c @@@@ -2,6 -2,6 -2,7 +2,7 @@@@ * Copyright (c) 2006 Rene Scharfe */ #include "cache.h" ++ #include "config.h" #include "archive.h" #include "streaming.h" #include "utf8.h" @@@@ -11,14 -11,14 -12,16 +12,14 @@@@ static int zip_date; static int zip_time; -static unsigned char *zip_dir; -static unsigned int zip_dir_size; +/* We only care about the "buf" part here. */ +static struct strbuf zip_dir; -static unsigned int zip_offset; -static unsigned int zip_dir_offset; +static uintmax_t zip_offset; static uint64_t zip_dir_entries; static unsigned int max_creator_version; -#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024) #define ZIP_STREAM (1 << 3) #define ZIP_UTF8 (1 << 11) @@@@ -45,11 -45,11 -48,24 +46,11 @@@@ struct zip_data_desc unsigned char _end[1]; }; -struct zip_dir_header { +struct zip64_data_desc { unsigned char magic[4]; - unsigned char creator_version[2]; - unsigned char version[2]; - unsigned char flags[2]; - unsigned char compression_method[2]; - unsigned char mtime[2]; - unsigned char mdate[2]; unsigned char crc32[4]; - unsigned char compressed_size[4]; - unsigned char size[4]; - unsigned char filename_length[2]; - unsigned char extra_length[2]; - unsigned char comment_length[2]; - unsigned char disk[2]; - unsigned char attr1[2]; - unsigned char attr2[4]; - unsigned char offset[4]; + unsigned char compressed_size[8]; + unsigned char size[8]; unsigned char _end[1]; }; @@@@ -73,14 -73,14 -89,6 +74,14 @@@@ struct zip_extra_mtime unsigned char _end[1]; }; +struct zip64_extra { + unsigned char magic[2]; + unsigned char extra_size[2]; + unsigned char size[8]; + unsigned char compressed_size[8]; + unsigned char _end[1]; +}; + struct zip64_dir_trailer { unsigned char magic[4]; unsigned char record_size[8]; @@@@ -110,15 -110,15 -118,11 +111,15 @@@@ struct zip64_dir_trailer_locator */ #define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) #define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end) +#define ZIP64_DATA_DESC_SIZE offsetof(struct zip64_data_desc, _end) #define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) #define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) #define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end) #define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \ (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags)) +#define ZIP64_EXTRA_SIZE offsetof(struct zip64_extra, _end) +#define ZIP64_EXTRA_PAYLOAD_SIZE \ + (ZIP64_EXTRA_SIZE - offsetof(struct zip64_extra, size)) #define ZIP64_DIR_TRAILER_SIZE offsetof(struct zip64_dir_trailer, _end) #define ZIP64_DIR_TRAILER_RECORD_SIZE \ (ZIP64_DIR_TRAILER_SIZE - \ @@@@ -165,26 -165,26 -169,6 +166,26 @@@@ static void copy_le16_clamp(unsigned ch copy_le16(dest, clamp_max(n, 0xffff, clamped)); } +static void copy_le32_clamp(unsigned char *dest, uint64_t n, int *clamped) +{ + copy_le32(dest, clamp_max(n, 0xffffffff, clamped)); +} + +static int strbuf_add_le(struct strbuf *sb, size_t size, uintmax_t n) +{ + while (size-- > 0) { + strbuf_addch(sb, n & 0xff); + n >>= 8; + } + return -!!n; +} + +static uint32_t clamp32(uintmax_t n) +{ + const uintmax_t max = 0xffffffff; + return (n < max) ? n : max; +} + static void *zlib_deflate_raw(void *data, unsigned long size, int compression_level, unsigned long *compressed_size) @@@@ -222,23 -222,23 -206,23 +223,23 @@@@ static void write_zip_data_desc(unsigne unsigned long compressed_size, unsigned long crc) { - struct zip_data_desc trailer; - - copy_le32(trailer.magic, 0x08074b50); - copy_le32(trailer.crc32, crc); - copy_le32(trailer.compressed_size, compressed_size); - copy_le32(trailer.size, size); - write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE); -} - -static void set_zip_dir_data_desc(struct zip_dir_header *header, - unsigned long size, - unsigned long compressed_size, - unsigned long crc) -{ - copy_le32(header->crc32, crc); - copy_le32(header->compressed_size, compressed_size); - copy_le32(header->size, size); + if (size >= 0xffffffff || compressed_size >= 0xffffffff) { + struct zip64_data_desc trailer; + copy_le32(trailer.magic, 0x08074b50); + copy_le32(trailer.crc32, crc); + copy_le64(trailer.compressed_size, compressed_size); + copy_le64(trailer.size, size); + write_or_die(1, &trailer, ZIP64_DATA_DESC_SIZE); + zip_offset += ZIP64_DATA_DESC_SIZE; + } else { + struct zip_data_desc trailer; + copy_le32(trailer.magic, 0x08074b50); + copy_le32(trailer.crc32, crc); + copy_le32(trailer.compressed_size, compressed_size); + copy_le32(trailer.size, size); + write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE); + zip_offset += ZIP_DATA_DESC_SIZE; + } } static void set_zip_header_data_desc(struct zip_local_header *header, @@@@ -280,14 -280,14 -264,12 +281,14 @@@@ static int write_zip_entry(struct archi unsigned int mode) { struct zip_local_header header; - struct zip_dir_header dirent; + uintmax_t offset = zip_offset; struct zip_extra_mtime extra; + struct zip64_extra extra64; + size_t header_extra_size = ZIP_EXTRA_MTIME_SIZE; + int need_zip64_extra = 0; unsigned long attr2; unsigned long compressed_size; unsigned long crc; - unsigned long direntsize; int method; unsigned char *out; void *deflated = NULL; @@@@ -298,9 -298,9 -280,6 +299,9 @@@@ int is_binary = -1; const char *path_without_prefix = path + args->baselen; unsigned int creator_version = 0; + unsigned int version_needed = 10; + size_t zip_dir_extra_size = ZIP_EXTRA_MTIME_SIZE; + size_t zip64_dir_extra_payload_size = 0; crc = crc32(0, NULL, 0); @@@@ -378,43 -378,43 -357,43 +379,43 @@@@ extra.flags[0] = 1; /* just mtime */ copy_le32(extra.mtime, args->time); - /* make sure we have enough free space in the dictionary */ - direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE; - while (zip_dir_size < zip_dir_offset + direntsize) { - zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; - zip_dir = xrealloc(zip_dir, zip_dir_size); - } + if (size > 0xffffffff || compressed_size > 0xffffffff) + need_zip64_extra = 1; + if (stream && size > 0x7fffffff) + need_zip64_extra = 1; - copy_le32(dirent.magic, 0x02014b50); - copy_le16(dirent.creator_version, creator_version); - copy_le16(dirent.version, 10); - copy_le16(dirent.flags, flags); - copy_le16(dirent.compression_method, method); - copy_le16(dirent.mtime, zip_time); - copy_le16(dirent.mdate, zip_date); - set_zip_dir_data_desc(&dirent, size, compressed_size, crc); - copy_le16(dirent.filename_length, pathlen); - copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE); - copy_le16(dirent.comment_length, 0); - copy_le16(dirent.disk, 0); - copy_le32(dirent.attr2, attr2); - copy_le32(dirent.offset, zip_offset); + if (need_zip64_extra) + version_needed = 45; copy_le32(header.magic, 0x04034b50); - copy_le16(header.version, 10); + copy_le16(header.version, version_needed); copy_le16(header.flags, flags); copy_le16(header.compression_method, method); copy_le16(header.mtime, zip_time); copy_le16(header.mdate, zip_date); - set_zip_header_data_desc(&header, size, compressed_size, crc); + if (need_zip64_extra) { + set_zip_header_data_desc(&header, 0xffffffff, 0xffffffff, crc); + header_extra_size += ZIP64_EXTRA_SIZE; + } else { + set_zip_header_data_desc(&header, size, compressed_size, crc); + } copy_le16(header.filename_length, pathlen); - copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE); + copy_le16(header.extra_length, header_extra_size); write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE); zip_offset += ZIP_EXTRA_MTIME_SIZE; + if (need_zip64_extra) { + copy_le16(extra64.magic, 0x0001); + copy_le16(extra64.extra_size, ZIP64_EXTRA_PAYLOAD_SIZE); + copy_le64(extra64.size, size); + copy_le64(extra64.compressed_size, compressed_size); + write_or_die(1, &extra64, ZIP64_EXTRA_SIZE); + zip_offset += ZIP64_EXTRA_SIZE; + } + if (stream && method == 0) { unsigned char buf[STREAM_BUFFER_SIZE]; ssize_t readlen; @@@@ -437,6 -437,6 -416,9 +438,6 @@@@ zip_offset += compressed_size; write_zip_data_desc(size, compressed_size, crc); - zip_offset += ZIP_DATA_DESC_SIZE; - - set_zip_dir_data_desc(&dirent, size, compressed_size, crc); } else if (stream && method == 8) { unsigned char buf[STREAM_BUFFER_SIZE]; ssize_t readlen; @@@@ -492,6 -492,6 -474,9 +493,6 @@@@ zip_offset += compressed_size; write_zip_data_desc(size, compressed_size, crc); - zip_offset += ZIP_DATA_DESC_SIZE; - - set_zip_dir_data_desc(&dirent, size, compressed_size, crc); } else if (compressed_size > 0) { write_or_die(1, out, compressed_size); zip_offset += compressed_size; @@@@ -500,46 -500,46 -485,14 +501,46 @@@@ free(deflated); free(buffer); - copy_le16(dirent.attr1, !is_binary); + if (compressed_size > 0xffffffff || size > 0xffffffff || + offset > 0xffffffff) { + if (compressed_size >= 0xffffffff) + zip64_dir_extra_payload_size += 8; + if (size >= 0xffffffff) + zip64_dir_extra_payload_size += 8; + if (offset >= 0xffffffff) + zip64_dir_extra_payload_size += 8; + zip_dir_extra_size += 2 + 2 + zip64_dir_extra_payload_size; + } - memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); - zip_dir_offset += ZIP_DIR_HEADER_SIZE; - memcpy(zip_dir + zip_dir_offset, path, pathlen); - zip_dir_offset += pathlen; - memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE); - zip_dir_offset += ZIP_EXTRA_MTIME_SIZE; + strbuf_add_le(&zip_dir, 4, 0x02014b50); /* magic */ + strbuf_add_le(&zip_dir, 2, creator_version); + strbuf_add_le(&zip_dir, 2, version_needed); + strbuf_add_le(&zip_dir, 2, flags); + strbuf_add_le(&zip_dir, 2, method); + strbuf_add_le(&zip_dir, 2, zip_time); + strbuf_add_le(&zip_dir, 2, zip_date); + strbuf_add_le(&zip_dir, 4, crc); + strbuf_add_le(&zip_dir, 4, clamp32(compressed_size)); + strbuf_add_le(&zip_dir, 4, clamp32(size)); + strbuf_add_le(&zip_dir, 2, pathlen); + strbuf_add_le(&zip_dir, 2, zip_dir_extra_size); + strbuf_add_le(&zip_dir, 2, 0); /* comment length */ + strbuf_add_le(&zip_dir, 2, 0); /* disk */ + strbuf_add_le(&zip_dir, 2, !is_binary); + strbuf_add_le(&zip_dir, 4, attr2); + strbuf_add_le(&zip_dir, 4, clamp32(offset)); + strbuf_add(&zip_dir, path, pathlen); + strbuf_add(&zip_dir, &extra, ZIP_EXTRA_MTIME_SIZE); + if (zip64_dir_extra_payload_size) { + strbuf_add_le(&zip_dir, 2, 0x0001); /* magic */ + strbuf_add_le(&zip_dir, 2, zip64_dir_extra_payload_size); + if (size >= 0xffffffff) + strbuf_add_le(&zip_dir, 8, size); + if (compressed_size >= 0xffffffff) + strbuf_add_le(&zip_dir, 8, compressed_size); + if (offset >= 0xffffffff) + strbuf_add_le(&zip_dir, 8, offset); + } zip_dir_entries++; return 0; @@@@ -558,12 -558,12 -511,12 +559,12 @@@@ static void write_zip64_trailer(void copy_le32(trailer64.directory_start_disk, 0); copy_le64(trailer64.entries_on_this_disk, zip_dir_entries); copy_le64(trailer64.entries, zip_dir_entries); - copy_le64(trailer64.size, zip_dir_offset); + copy_le64(trailer64.size, zip_dir.len); copy_le64(trailer64.offset, zip_offset); copy_le32(locator64.magic, 0x07064b50); copy_le32(locator64.disk, 0); - copy_le64(locator64.offset, zip_offset + zip_dir_offset); + copy_le64(locator64.offset, zip_offset + zip_dir.len); copy_le32(locator64.number_of_disks, 1); write_or_die(1, &trailer64, ZIP64_DIR_TRAILER_SIZE); @@@@ -581,11 -581,11 -534,11 +582,11 @@@@ static void write_zip_trailer(const uns copy_le16_clamp(trailer.entries_on_this_disk, zip_dir_entries, &clamped); copy_le16_clamp(trailer.entries, zip_dir_entries, &clamped); - copy_le32(trailer.size, zip_dir_offset); - copy_le32(trailer.offset, zip_offset); + copy_le32(trailer.size, zip_dir.len); + copy_le32_clamp(trailer.offset, zip_offset, &clamped); copy_le16(trailer.comment_length, sha1 ? GIT_SHA1_HEXSZ : 0); - write_or_die(1, zip_dir, zip_dir_offset); + write_or_die(1, zip_dir.buf, zip_dir.len); if (clamped) write_zip64_trailer(); write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); @@@@ -593,17 -593,17 -546,9 +594,17 @@@@ write_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ); } -static void dos_time(time_t *time, int *dos_date, int *dos_time) +static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time) { - struct tm *t = localtime(time); + time_t time; + struct tm *t; + + if (date_overflows(*timestamp)) + die("timestamp too large for this system: %"PRItime, + *timestamp); + time = (time_t)*timestamp; + t = localtime(&time); + *timestamp = time; *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 + (t->tm_year + 1900 - 1980) * 512; @@@@ -624,13 -624,13 -569,14 +625,13 @@@@ static int write_zip_archive(const stru dos_time(&args->time, &zip_date, &zip_time); - zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE); - zip_dir_size = ZIP_DIRECTORY_MIN_SIZE; + strbuf_init(&zip_dir, 0); err = write_archive_entries(args, write_zip_entry); if (!err) write_zip_trailer(args->commit_sha1); - free(zip_dir); + strbuf_release(&zip_dir); return err; } diff --combined archive.c index b15a922dab,b15a922dab,0cba5b4096..60b3035a7a --- a/archive.c +++ b/archive.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "commit.h" #include "tree-walk.h" @@@@ -360,7 -360,7 -361,7 +361,7 @@@@ static void parse_treeish_arg(const cha if (get_sha1(name, oid.hash)) die("Not a valid object name"); - commit = lookup_commit_reference_gently(oid.hash, 1); + commit = lookup_commit_reference_gently(&oid, 1); if (commit) { commit_sha1 = commit->object.oid.hash; archive_time = commit->date; @@@@ -369,7 -369,7 -370,7 +370,7 @@@@ archive_time = time(NULL); } - tree = parse_tree_indirect(oid.hash); + tree = parse_tree_indirect(&oid); if (tree == NULL) die("not a tree object"); @@@@ -383,7 -383,7 -384,7 +384,7 @@@@ if (err || !S_ISDIR(mode)) die("current working directory is untracked"); - tree = parse_tree_indirect(tree_oid.hash); + tree = parse_tree_indirect(&tree_oid); } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; diff --combined attr.c index 821203e2a9,7e2134471c,9f8b029363..6e4b247acd --- a/attr.c +++ b/attr.c @@@@ -9,6 -9,6 -9,7 +9,7 @@@@ #define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" ++ #include "config.h" #include "exec_cmd.h" #include "attr.h" #include "dir.h" @@@@ -720,13 -720,16 -721,16 +721,13 @@@@ void git_attr_set_direction(enum git_at static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) { -- FILE *fp = fopen(path, "r"); ++ FILE *fp = fopen_or_warn(path, "r"); struct attr_stack *res; char buf[2048]; int lineno = 0; -- if (!fp) { -- if (errno != ENOENT && errno != ENOTDIR) -- warn_on_inaccessible(path); ++ if (!fp) return NULL; -- } res = xcalloc(1, sizeof(*res)); while (fgets(buf, sizeof(buf), fp)) { char *bufp = buf; diff --combined bisect.c index 2a2b9b7267,c952df692b,e8f03a08c4..a9fd9fbc61 --- a/bisect.c +++ b/bisect.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "diff.h" #include "revision.h" @@@@ -438,7 -438,10 -439,10 +439,7 @@@@ static void read_bisect_paths(struct ar { struct strbuf str = STRBUF_INIT; const char *filename = git_path_bisect_names(); -- FILE *fp = fopen(filename, "r"); -- -- if (!fp) -- die_errno(_("Could not open file '%s'"), filename); ++ FILE *fp = xfopen(filename, "r"); while (strbuf_getline_lf(&str, fp) != EOF) { strbuf_trim(&str); @@@@ -543,7 -546,7 -547,7 +544,7 @@@@ static unsigned get_prn(unsigned count /* * Custom integer square root from - * http://en.wikipedia.org/wiki/Integer_square_root + * https://en.wikipedia.org/wiki/Integer_square_root */ static int sqrti(int val) { @@@@ -666,7 -669,7 -670,7 +667,7 @@@@ static int is_expected_rev(const struc if (stat(filename, &st) || !S_ISREG(st.st_mode)) return 0; -- fp = fopen(filename, "r"); ++ fp = fopen_or_warn(filename, "r"); if (!fp) return 0; @@@@ -702,7 -705,7 -706,7 +703,7 @@@@ static int bisect_checkout(const unsign static struct commit *get_commit_reference(const struct object_id *oid) { - struct commit *r = lookup_commit_reference(oid->hash); + struct commit *r = lookup_commit_reference(oid); if (!r) die(_("Not a valid commit name %s"), oid_to_hex(oid)); return r; @@@@ -992,10 -995,10 -996,8 +993,10 @@@@ int bisect_next_all(const char *prefix steps_msg = xstrfmt(Q_("(roughly %d step)", "(roughly %d steps)", steps), steps); - /* TRANSLATORS: the last %s will be replaced with - "(roughly %d steps)" translation */ + /* + * TRANSLATORS: the last %s will be replaced with "(roughly %d + * steps)" translation. + */ printf(Q_("Bisecting: %d revision left to test after this %s\n", "Bisecting: %d revisions left to test after this %s\n", nr), nr, steps_msg); diff --combined blame.c index 194b58e960,a6f3d72df8,0000000000..6d57ab9715 mode 100644,100644,000000..100644 --- a/blame.c +++ b/blame.c @@@@ -1,1863 -1,1863 -1,0 +1,1863 @@@@ +#include "cache.h" +#include "refs.h" +#include "cache-tree.h" +#include "mergesort.h" +#include "diff.h" +#include "diffcore.h" +#include "tag.h" +#include "blame.h" + +void blame_origin_decref(struct blame_origin *o) +{ + if (o && --o->refcnt <= 0) { + struct blame_origin *p, *l = NULL; + if (o->previous) + blame_origin_decref(o->previous); + free(o->file.ptr); + /* Should be present exactly once in commit chain */ + for (p = o->commit->util; p; l = p, p = p->next) { + if (p == o) { + if (l) + l->next = p->next; + else + o->commit->util = p->next; + free(o); + return; + } + } + die("internal error in blame_origin_decref"); + } +} + +/* + * Given a commit and a path in it, create a new origin structure. + * The callers that add blame to the scoreboard should use + * get_origin() to obtain shared, refcounted copy instead of calling + * this function directly. + */ +static struct blame_origin *make_origin(struct commit *commit, const char *path) +{ + struct blame_origin *o; + FLEX_ALLOC_STR(o, path, path); + o->commit = commit; + o->refcnt = 1; + o->next = commit->util; + commit->util = o; + return o; +} + +/* + * Locate an existing origin or create a new one. + * This moves the origin to front position in the commit util list. + */ +static struct blame_origin *get_origin(struct commit *commit, const char *path) +{ + struct blame_origin *o, *l; + + for (o = commit->util, l = NULL; o; l = o, o = o->next) { + if (!strcmp(o->path, path)) { + /* bump to front */ + if (l) { + l->next = o->next; + o->next = commit->util; + commit->util = o; + } + return blame_origin_incref(o); + } + } + return make_origin(commit, path); +} + + + +static void verify_working_tree_path(struct commit *work_tree, const char *path) +{ + struct commit_list *parents; + int pos; + + for (parents = work_tree->parents; parents; parents = parents->next) { + const struct object_id *commit_oid = &parents->item->object.oid; + struct object_id blob_oid; + unsigned mode; + + if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) && + sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB) + return; + } + + pos = cache_name_pos(path, strlen(path)); + if (pos >= 0) + ; /* path is in the index */ + else if (-1 - pos < active_nr && + !strcmp(active_cache[-1 - pos]->name, path)) + ; /* path is in the index, unmerged */ + else + die("no such path '%s' in HEAD", path); +} + +static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid) +{ + struct commit *parent; + + parent = lookup_commit_reference(oid); + if (!parent) + die("no such commit %s", oid_to_hex(oid)); + return &commit_list_insert(parent, tail)->next; +} + +static void append_merge_parents(struct commit_list **tail) +{ + int merge_head; + struct strbuf line = STRBUF_INIT; + + merge_head = open(git_path_merge_head(), O_RDONLY); + if (merge_head < 0) { + if (errno == ENOENT) + return; + die("cannot open '%s' for reading", git_path_merge_head()); + } + + while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { + struct object_id oid; + if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid)) + die("unknown line in '%s': %s", git_path_merge_head(), line.buf); + tail = append_parent(tail, &oid); + } + close(merge_head); + strbuf_release(&line); +} + +/* + * This isn't as simple as passing sb->buf and sb->len, because we + * want to transfer ownership of the buffer to the commit (so we + * must use detach). + */ +static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb) +{ + size_t len; + void *buf = strbuf_detach(sb, &len); + set_commit_buffer(c, buf, len); +} + +/* + * Prepare a dummy commit that represents the work tree (or staged) item. + * Note that annotating work tree item never works in the reverse. + */ +static struct commit *fake_working_tree_commit(struct diff_options *opt, + const char *path, + const char *contents_from) +{ + struct commit *commit; + struct blame_origin *origin; + struct commit_list **parent_tail, *parent; + struct object_id head_oid; + struct strbuf buf = STRBUF_INIT; + const char *ident; + time_t now; + int size, len; + struct cache_entry *ce; + unsigned mode; + struct strbuf msg = STRBUF_INIT; + + read_cache(); + time(&now); + commit = alloc_commit_node(); + commit->object.parsed = 1; + commit->date = now; + parent_tail = &commit->parents; + + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + die("no such ref: HEAD"); + + parent_tail = append_parent(parent_tail, &head_oid); + append_merge_parents(parent_tail); + verify_working_tree_path(commit, path); + + origin = make_origin(commit, path); + + ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0); + strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n"); + for (parent = commit->parents; parent; parent = parent->next) + strbuf_addf(&msg, "parent %s\n", + oid_to_hex(&parent->item->object.oid)); + strbuf_addf(&msg, + "author %s\n" + "committer %s\n\n" + "Version of %s from %s\n", + ident, ident, path, + (!contents_from ? path : + (!strcmp(contents_from, "-") ? "standard input" : contents_from))); + set_commit_buffer_from_strbuf(commit, &msg); + + if (!contents_from || strcmp("-", contents_from)) { + struct stat st; + const char *read_from; + char *buf_ptr; + unsigned long buf_len; + + if (contents_from) { + if (stat(contents_from, &st) < 0) + die_errno("Cannot stat '%s'", contents_from); + read_from = contents_from; + } + else { + if (lstat(path, &st) < 0) + die_errno("Cannot lstat '%s'", path); + read_from = path; + } + mode = canon_mode(st.st_mode); + + switch (st.st_mode & S_IFMT) { + case S_IFREG: + if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && + textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len)) + strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1); + else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) + die_errno("cannot open or read '%s'", read_from); + break; + case S_IFLNK: + if (strbuf_readlink(&buf, read_from, st.st_size) < 0) + die_errno("cannot readlink '%s'", read_from); + break; + default: + die("unsupported file type %s", read_from); + } + } + else { + /* Reading from stdin */ + mode = 0; + if (strbuf_read(&buf, 0, 0) < 0) + die_errno("failed to read from stdin"); + } - convert_to_git(path, buf.buf, buf.len, &buf, 0); + + convert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0); + origin->file.ptr = buf.buf; + origin->file.size = buf.len; + pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash); + + /* + * Read the current index, replace the path entry with + * origin->blob_sha1 without mucking with its mode or type + * bits; we are not going to write this index out -- we just + * want to run "diff-index --cached". + */ + discard_cache(); + read_cache(); + + len = strlen(path); + if (!mode) { + int pos = cache_name_pos(path, len); + if (0 <= pos) + mode = active_cache[pos]->ce_mode; + else + /* Let's not bother reading from HEAD tree */ + mode = S_IFREG | 0644; + } + size = cache_entry_size(len); + ce = xcalloc(1, size); + oidcpy(&ce->oid, &origin->blob_oid); + memcpy(ce->name, path, len); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = len; + ce->ce_mode = create_ce_mode(mode); + add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + + cache_tree_invalidate_path(&the_index, path); + + return commit; +} + + + +static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, + xdl_emit_hunk_consume_func_t hunk_func, void *cb_data, int xdl_opts) +{ + xpparam_t xpp = {0}; + xdemitconf_t xecfg = {0}; + xdemitcb_t ecb = {NULL}; + + xpp.flags = xdl_opts; + xecfg.hunk_func = hunk_func; + ecb.priv = cb_data; + return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb); +} + +/* + * Given an origin, prepare mmfile_t structure to be used by the + * diff machinery + */ +static void fill_origin_blob(struct diff_options *opt, + struct blame_origin *o, mmfile_t *file, int *num_read_blob) +{ + if (!o->file.ptr) { + enum object_type type; + unsigned long file_size; + + (*num_read_blob)++; + if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && + textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size)) + ; + else + file->ptr = read_sha1_file(o->blob_oid.hash, &type, + &file_size); + file->size = file_size; + + if (!file->ptr) + die("Cannot read blob %s for path %s", + oid_to_hex(&o->blob_oid), + o->path); + o->file = *file; + } + else + *file = o->file; +} + +static void drop_origin_blob(struct blame_origin *o) +{ + if (o->file.ptr) { + free(o->file.ptr); + o->file.ptr = NULL; + } +} + +/* + * Any merge of blames happens on lists of blames that arrived via + * different parents in a single suspect. In this case, we want to + * sort according to the suspect line numbers as opposed to the final + * image line numbers. The function body is somewhat longish because + * it avoids unnecessary writes. + */ + +static struct blame_entry *blame_merge(struct blame_entry *list1, + struct blame_entry *list2) +{ + struct blame_entry *p1 = list1, *p2 = list2, + **tail = &list1; + + if (!p1) + return p2; + if (!p2) + return p1; + + if (p1->s_lno <= p2->s_lno) { + do { + tail = &p1->next; + if ((p1 = *tail) == NULL) { + *tail = p2; + return list1; + } + } while (p1->s_lno <= p2->s_lno); + } + for (;;) { + *tail = p2; + do { + tail = &p2->next; + if ((p2 = *tail) == NULL) { + *tail = p1; + return list1; + } + } while (p1->s_lno > p2->s_lno); + *tail = p1; + do { + tail = &p1->next; + if ((p1 = *tail) == NULL) { + *tail = p2; + return list1; + } + } while (p1->s_lno <= p2->s_lno); + } +} + +static void *get_next_blame(const void *p) +{ + return ((struct blame_entry *)p)->next; +} + +static void set_next_blame(void *p1, void *p2) +{ + ((struct blame_entry *)p1)->next = p2; +} + +/* + * Final image line numbers are all different, so we don't need a + * three-way comparison here. + */ + +static int compare_blame_final(const void *p1, const void *p2) +{ + return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno + ? 1 : -1; +} + +static int compare_blame_suspect(const void *p1, const void *p2) +{ + const struct blame_entry *s1 = p1, *s2 = p2; + /* + * to allow for collating suspects, we sort according to the + * respective pointer value as the primary sorting criterion. + * The actual relation is pretty unimportant as long as it + * establishes a total order. Comparing as integers gives us + * that. + */ + if (s1->suspect != s2->suspect) + return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1; + if (s1->s_lno == s2->s_lno) + return 0; + return s1->s_lno > s2->s_lno ? 1 : -1; +} + +void blame_sort_final(struct blame_scoreboard *sb) +{ + sb->ent = llist_mergesort(sb->ent, get_next_blame, set_next_blame, + compare_blame_final); +} + +static int compare_commits_by_reverse_commit_date(const void *a, + const void *b, + void *c) +{ + return -compare_commits_by_commit_date(a, b, c); +} + +/* + * For debugging -- origin is refcounted, and this asserts that + * we do not underflow. + */ +static void sanity_check_refcnt(struct blame_scoreboard *sb) +{ + int baa = 0; + struct blame_entry *ent; + + for (ent = sb->ent; ent; ent = ent->next) { + /* Nobody should have zero or negative refcnt */ + if (ent->suspect->refcnt <= 0) { + fprintf(stderr, "%s in %s has negative refcnt %d\n", + ent->suspect->path, + oid_to_hex(&ent->suspect->commit->object.oid), + ent->suspect->refcnt); + baa = 1; + } + } + if (baa) + sb->on_sanity_fail(sb, baa); +} + +/* + * If two blame entries that are next to each other came from + * contiguous lines in the same origin (i.e. pair), + * merge them together. + */ +void blame_coalesce(struct blame_scoreboard *sb) +{ + struct blame_entry *ent, *next; + + for (ent = sb->ent; ent && (next = ent->next); ent = next) { + if (ent->suspect == next->suspect && + ent->s_lno + ent->num_lines == next->s_lno) { + ent->num_lines += next->num_lines; + ent->next = next->next; + blame_origin_decref(next->suspect); + free(next); + ent->score = 0; + next = ent; /* again */ + } + } + + if (sb->debug) /* sanity */ + sanity_check_refcnt(sb); +} + +/* + * Merge the given sorted list of blames into a preexisting origin. + * If there were no previous blames to that commit, it is entered into + * the commit priority queue of the score board. + */ + +static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porigin, + struct blame_entry *sorted) +{ + if (porigin->suspects) + porigin->suspects = blame_merge(porigin->suspects, sorted); + else { + struct blame_origin *o; + for (o = porigin->commit->util; o; o = o->next) { + if (o->suspects) { + porigin->suspects = sorted; + return; + } + } + porigin->suspects = sorted; + prio_queue_put(&sb->commits, porigin->commit); + } +} + +/* + * Fill the blob_sha1 field of an origin if it hasn't, so that later + * call to fill_origin_blob() can use it to locate the data. blob_sha1 + * for an origin is also used to pass the blame for the entire file to + * the parent to detect the case where a child's blob is identical to + * that of its parent's. + * + * This also fills origin->mode for corresponding tree path. + */ +static int fill_blob_sha1_and_mode(struct blame_origin *origin) +{ + if (!is_null_oid(&origin->blob_oid)) + return 0; + if (get_tree_entry(origin->commit->object.oid.hash, + origin->path, + origin->blob_oid.hash, &origin->mode)) + goto error_out; + if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB) + goto error_out; + return 0; + error_out: + oidclr(&origin->blob_oid); + origin->mode = S_IFINVALID; + return -1; +} + +/* + * We have an origin -- check if the same path exists in the + * parent and return an origin structure to represent it. + */ +static struct blame_origin *find_origin(struct commit *parent, + struct blame_origin *origin) +{ + struct blame_origin *porigin; + struct diff_options diff_opts; + const char *paths[2]; + + /* First check any existing origins */ + for (porigin = parent->util; porigin; porigin = porigin->next) + if (!strcmp(porigin->path, origin->path)) { + /* + * The same path between origin and its parent + * without renaming -- the most common case. + */ + return blame_origin_incref (porigin); + } + + /* See if the origin->path is different between parent + * and origin first. Most of the time they are the + * same and diff-tree is fairly efficient about this. + */ + diff_setup(&diff_opts); + DIFF_OPT_SET(&diff_opts, RECURSIVE); + diff_opts.detect_rename = 0; + diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; + paths[0] = origin->path; + paths[1] = NULL; + + parse_pathspec(&diff_opts.pathspec, + PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, + PATHSPEC_LITERAL_PATH, "", paths); + diff_setup_done(&diff_opts); + + if (is_null_oid(&origin->commit->object.oid)) + do_diff_cache(&parent->tree->object.oid, &diff_opts); + else - diff_tree_sha1(parent->tree->object.oid.hash, - origin->commit->tree->object.oid.hash, - "", &diff_opts); ++ diff_tree_oid(&parent->tree->object.oid, ++ &origin->commit->tree->object.oid, ++ "", &diff_opts); + diffcore_std(&diff_opts); + + if (!diff_queued_diff.nr) { + /* The path is the same as parent */ + porigin = get_origin(parent, origin->path); + oidcpy(&porigin->blob_oid, &origin->blob_oid); + porigin->mode = origin->mode; + } else { + /* + * Since origin->path is a pathspec, if the parent + * commit had it as a directory, we will see a whole + * bunch of deletion of files in the directory that we + * do not care about. + */ + int i; + struct diff_filepair *p = NULL; + for (i = 0; i < diff_queued_diff.nr; i++) { + const char *name; + p = diff_queued_diff.queue[i]; + name = p->one->path ? p->one->path : p->two->path; + if (!strcmp(name, origin->path)) + break; + } + if (!p) + die("internal error in blame::find_origin"); + switch (p->status) { + default: + die("internal error in blame::find_origin (%c)", + p->status); + case 'M': + porigin = get_origin(parent, origin->path); + oidcpy(&porigin->blob_oid, &p->one->oid); + porigin->mode = p->one->mode; + break; + case 'A': + case 'T': + /* Did not exist in parent, or type changed */ + break; + } + } + diff_flush(&diff_opts); + clear_pathspec(&diff_opts.pathspec); + return porigin; +} + +/* + * We have an origin -- find the path that corresponds to it in its + * parent and return an origin structure to represent it. + */ +static struct blame_origin *find_rename(struct commit *parent, + struct blame_origin *origin) +{ + struct blame_origin *porigin = NULL; + struct diff_options diff_opts; + int i; + + diff_setup(&diff_opts); + DIFF_OPT_SET(&diff_opts, RECURSIVE); + diff_opts.detect_rename = DIFF_DETECT_RENAME; + diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; + diff_opts.single_follow = origin->path; + diff_setup_done(&diff_opts); + + if (is_null_oid(&origin->commit->object.oid)) + do_diff_cache(&parent->tree->object.oid, &diff_opts); + else - diff_tree_sha1(parent->tree->object.oid.hash, - origin->commit->tree->object.oid.hash, - "", &diff_opts); ++ diff_tree_oid(&parent->tree->object.oid, ++ &origin->commit->tree->object.oid, ++ "", &diff_opts); + diffcore_std(&diff_opts); + + for (i = 0; i < diff_queued_diff.nr; i++) { + struct diff_filepair *p = diff_queued_diff.queue[i]; + if ((p->status == 'R' || p->status == 'C') && + !strcmp(p->two->path, origin->path)) { + porigin = get_origin(parent, p->one->path); + oidcpy(&porigin->blob_oid, &p->one->oid); + porigin->mode = p->one->mode; + break; + } + } + diff_flush(&diff_opts); + clear_pathspec(&diff_opts.pathspec); + return porigin; +} + +/* + * Append a new blame entry to a given output queue. + */ +static void add_blame_entry(struct blame_entry ***queue, + const struct blame_entry *src) +{ + struct blame_entry *e = xmalloc(sizeof(*e)); + memcpy(e, src, sizeof(*e)); + blame_origin_incref(e->suspect); + + e->next = **queue; + **queue = e; + *queue = &e->next; +} + +/* + * src typically is on-stack; we want to copy the information in it to + * a malloced blame_entry that gets added to the given queue. The + * origin of dst loses a refcnt. + */ +static void dup_entry(struct blame_entry ***queue, + struct blame_entry *dst, struct blame_entry *src) +{ + blame_origin_incref(src->suspect); + blame_origin_decref(dst->suspect); + memcpy(dst, src, sizeof(*src)); + dst->next = **queue; + **queue = dst; + *queue = &dst->next; +} + +const char *blame_nth_line(struct blame_scoreboard *sb, long lno) +{ + return sb->final_buf + sb->lineno[lno]; +} + +/* + * It is known that lines between tlno to same came from parent, and e + * has an overlap with that range. it also is known that parent's + * line plno corresponds to e's line tlno. + * + * <---- e -----> + * <------> + * <------------> + * <------------> + * <------------------> + * + * Split e into potentially three parts; before this chunk, the chunk + * to be blamed for the parent, and after that portion. + */ +static void split_overlap(struct blame_entry *split, + struct blame_entry *e, + int tlno, int plno, int same, + struct blame_origin *parent) +{ + int chunk_end_lno; + memset(split, 0, sizeof(struct blame_entry [3])); + + if (e->s_lno < tlno) { + /* there is a pre-chunk part not blamed on parent */ + split[0].suspect = blame_origin_incref(e->suspect); + split[0].lno = e->lno; + split[0].s_lno = e->s_lno; + split[0].num_lines = tlno - e->s_lno; + split[1].lno = e->lno + tlno - e->s_lno; + split[1].s_lno = plno; + } + else { + split[1].lno = e->lno; + split[1].s_lno = plno + (e->s_lno - tlno); + } + + if (same < e->s_lno + e->num_lines) { + /* there is a post-chunk part not blamed on parent */ + split[2].suspect = blame_origin_incref(e->suspect); + split[2].lno = e->lno + (same - e->s_lno); + split[2].s_lno = e->s_lno + (same - e->s_lno); + split[2].num_lines = e->s_lno + e->num_lines - same; + chunk_end_lno = split[2].lno; + } + else + chunk_end_lno = e->lno + e->num_lines; + split[1].num_lines = chunk_end_lno - split[1].lno; + + /* + * if it turns out there is nothing to blame the parent for, + * forget about the splitting. !split[1].suspect signals this. + */ + if (split[1].num_lines < 1) + return; + split[1].suspect = blame_origin_incref(parent); +} + +/* + * split_overlap() divided an existing blame e into up to three parts + * in split. Any assigned blame is moved to queue to + * reflect the split. + */ +static void split_blame(struct blame_entry ***blamed, + struct blame_entry ***unblamed, + struct blame_entry *split, + struct blame_entry *e) +{ + if (split[0].suspect && split[2].suspect) { + /* The first part (reuse storage for the existing entry e) */ + dup_entry(unblamed, e, &split[0]); + + /* The last part -- me */ + add_blame_entry(unblamed, &split[2]); + + /* ... and the middle part -- parent */ + add_blame_entry(blamed, &split[1]); + } + else if (!split[0].suspect && !split[2].suspect) + /* + * The parent covers the entire area; reuse storage for + * e and replace it with the parent. + */ + dup_entry(blamed, e, &split[1]); + else if (split[0].suspect) { + /* me and then parent */ + dup_entry(unblamed, e, &split[0]); + add_blame_entry(blamed, &split[1]); + } + else { + /* parent and then me */ + dup_entry(blamed, e, &split[1]); + add_blame_entry(unblamed, &split[2]); + } +} + +/* + * After splitting the blame, the origins used by the + * on-stack blame_entry should lose one refcnt each. + */ +static void decref_split(struct blame_entry *split) +{ + int i; + + for (i = 0; i < 3; i++) + blame_origin_decref(split[i].suspect); +} + +/* + * reverse_blame reverses the list given in head, appending tail. + * That allows us to build lists in reverse order, then reverse them + * afterwards. This can be faster than building the list in proper + * order right away. The reason is that building in proper order + * requires writing a link in the _previous_ element, while building + * in reverse order just requires placing the list head into the + * _current_ element. + */ + +static struct blame_entry *reverse_blame(struct blame_entry *head, + struct blame_entry *tail) +{ + while (head) { + struct blame_entry *next = head->next; + head->next = tail; + tail = head; + head = next; + } + return tail; +} + +/* + * Process one hunk from the patch between the current suspect for + * blame_entry e and its parent. This first blames any unfinished + * entries before the chunk (which is where target and parent start + * differing) on the parent, and then splits blame entries at the + * start and at the end of the difference region. Since use of -M and + * -C options may lead to overlapping/duplicate source line number + * ranges, all we can rely on from sorting/merging is the order of the + * first suspect line number. + */ +static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq, + int tlno, int offset, int same, + struct blame_origin *parent) +{ + struct blame_entry *e = **srcq; + struct blame_entry *samep = NULL, *diffp = NULL; + + while (e && e->s_lno < tlno) { + struct blame_entry *next = e->next; + /* + * current record starts before differing portion. If + * it reaches into it, we need to split it up and + * examine the second part separately. + */ + if (e->s_lno + e->num_lines > tlno) { + /* Move second half to a new record */ + int len = tlno - e->s_lno; + struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry)); + n->suspect = e->suspect; + n->lno = e->lno + len; + n->s_lno = e->s_lno + len; + n->num_lines = e->num_lines - len; + e->num_lines = len; + e->score = 0; + /* Push new record to diffp */ + n->next = diffp; + diffp = n; + } else + blame_origin_decref(e->suspect); + /* Pass blame for everything before the differing + * chunk to the parent */ + e->suspect = blame_origin_incref(parent); + e->s_lno += offset; + e->next = samep; + samep = e; + e = next; + } + /* + * As we don't know how much of a common stretch after this + * diff will occur, the currently blamed parts are all that we + * can assign to the parent for now. + */ + + if (samep) { + **dstq = reverse_blame(samep, **dstq); + *dstq = &samep->next; + } + /* + * Prepend the split off portions: everything after e starts + * after the blameable portion. + */ + e = reverse_blame(diffp, e); + + /* + * Now retain records on the target while parts are different + * from the parent. + */ + samep = NULL; + diffp = NULL; + while (e && e->s_lno < same) { + struct blame_entry *next = e->next; + + /* + * If current record extends into sameness, need to split. + */ + if (e->s_lno + e->num_lines > same) { + /* + * Move second half to a new record to be + * processed by later chunks + */ + int len = same - e->s_lno; + struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry)); + n->suspect = blame_origin_incref(e->suspect); + n->lno = e->lno + len; + n->s_lno = e->s_lno + len; + n->num_lines = e->num_lines - len; + e->num_lines = len; + e->score = 0; + /* Push new record to samep */ + n->next = samep; + samep = n; + } + e->next = diffp; + diffp = e; + e = next; + } + **srcq = reverse_blame(diffp, reverse_blame(samep, e)); + /* Move across elements that are in the unblamable portion */ + if (diffp) + *srcq = &diffp->next; +} + +struct blame_chunk_cb_data { + struct blame_origin *parent; + long offset; + struct blame_entry **dstq; + struct blame_entry **srcq; +}; + +/* diff chunks are from parent to target */ +static int blame_chunk_cb(long start_a, long count_a, + long start_b, long count_b, void *data) +{ + struct blame_chunk_cb_data *d = data; + if (start_a - start_b != d->offset) + die("internal error in blame::blame_chunk_cb"); + blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b, + start_b + count_b, d->parent); + d->offset = start_a + count_a - (start_b + count_b); + return 0; +} + +/* + * We are looking at the origin 'target' and aiming to pass blame + * for the lines it is suspected to its parent. Run diff to find + * which lines came from parent and pass blame for them. + */ +static void pass_blame_to_parent(struct blame_scoreboard *sb, + struct blame_origin *target, + struct blame_origin *parent) +{ + mmfile_t file_p, file_o; + struct blame_chunk_cb_data d; + struct blame_entry *newdest = NULL; + + if (!target->suspects) + return; /* nothing remains for this target */ + + d.parent = parent; + d.offset = 0; + d.dstq = &newdest; d.srcq = &target->suspects; + + fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob); + fill_origin_blob(&sb->revs->diffopt, target, &file_o, &sb->num_read_blob); + sb->num_get_patch++; + + if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, sb->xdl_opts)) + die("unable to generate diff (%s -> %s)", + oid_to_hex(&parent->commit->object.oid), + oid_to_hex(&target->commit->object.oid)); + /* The rest are the same as the parent */ + blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent); + *d.dstq = NULL; + queue_blames(sb, parent, newdest); + + return; +} + +/* + * The lines in blame_entry after splitting blames many times can become + * very small and trivial, and at some point it becomes pointless to + * blame the parents. E.g. "\t\t}\n\t}\n\n" appears everywhere in any + * ordinary C program, and it is not worth to say it was copied from + * totally unrelated file in the parent. + * + * Compute how trivial the lines in the blame_entry are. + */ +unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e) +{ + unsigned score; + const char *cp, *ep; + + if (e->score) + return e->score; + + score = 1; + cp = blame_nth_line(sb, e->lno); + ep = blame_nth_line(sb, e->lno + e->num_lines); + while (cp < ep) { + unsigned ch = *((unsigned char *)cp); + if (isalnum(ch)) + score++; + cp++; + } + e->score = score; + return score; +} + +/* + * best_so_far[] and this[] are both a split of an existing blame_entry + * that passes blame to the parent. Maintain best_so_far the best split + * so far, by comparing this and best_so_far and copying this into + * bst_so_far as needed. + */ +static void copy_split_if_better(struct blame_scoreboard *sb, + struct blame_entry *best_so_far, + struct blame_entry *this) +{ + int i; + + if (!this[1].suspect) + return; + if (best_so_far[1].suspect) { + if (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1])) + return; + } + + for (i = 0; i < 3; i++) + blame_origin_incref(this[i].suspect); + decref_split(best_so_far); + memcpy(best_so_far, this, sizeof(struct blame_entry [3])); +} + +/* + * We are looking at a part of the final image represented by + * ent (tlno and same are offset by ent->s_lno). + * tlno is where we are looking at in the final image. + * up to (but not including) same match preimage. + * plno is where we are looking at in the preimage. + * + * <-------------- final image ----------------------> + * <------ent------> + * ^tlno ^same + * <---------preimage-----> + * ^plno + * + * All line numbers are 0-based. + */ +static void handle_split(struct blame_scoreboard *sb, + struct blame_entry *ent, + int tlno, int plno, int same, + struct blame_origin *parent, + struct blame_entry *split) +{ + if (ent->num_lines <= tlno) + return; + if (tlno < same) { + struct blame_entry this[3]; + tlno += ent->s_lno; + same += ent->s_lno; + split_overlap(this, ent, tlno, plno, same, parent); + copy_split_if_better(sb, split, this); + decref_split(this); + } +} + +struct handle_split_cb_data { + struct blame_scoreboard *sb; + struct blame_entry *ent; + struct blame_origin *parent; + struct blame_entry *split; + long plno; + long tlno; +}; + +static int handle_split_cb(long start_a, long count_a, + long start_b, long count_b, void *data) +{ + struct handle_split_cb_data *d = data; + handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent, + d->split); + d->plno = start_a + count_a; + d->tlno = start_b + count_b; + return 0; +} + +/* + * Find the lines from parent that are the same as ent so that + * we can pass blames to it. file_p has the blob contents for + * the parent. + */ +static void find_copy_in_blob(struct blame_scoreboard *sb, + struct blame_entry *ent, + struct blame_origin *parent, + struct blame_entry *split, + mmfile_t *file_p) +{ + const char *cp; + mmfile_t file_o; + struct handle_split_cb_data d; + + memset(&d, 0, sizeof(d)); + d.sb = sb; d.ent = ent; d.parent = parent; d.split = split; + /* + * Prepare mmfile that contains only the lines in ent. + */ + cp = blame_nth_line(sb, ent->lno); + file_o.ptr = (char *) cp; + file_o.size = blame_nth_line(sb, ent->lno + ent->num_lines) - cp; + + /* + * file_o is a part of final image we are annotating. + * file_p partially may match that image. + */ + memset(split, 0, sizeof(struct blame_entry [3])); + if (diff_hunks(file_p, &file_o, handle_split_cb, &d, sb->xdl_opts)) + die("unable to generate diff (%s)", + oid_to_hex(&parent->commit->object.oid)); + /* remainder, if any, all match the preimage */ + handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split); +} + +/* Move all blame entries from list *source that have a score smaller + * than score_min to the front of list *small. + * Returns a pointer to the link pointing to the old head of the small list. + */ + +static struct blame_entry **filter_small(struct blame_scoreboard *sb, + struct blame_entry **small, + struct blame_entry **source, + unsigned score_min) +{ + struct blame_entry *p = *source; + struct blame_entry *oldsmall = *small; + while (p) { + if (blame_entry_score(sb, p) <= score_min) { + *small = p; + small = &p->next; + p = *small; + } else { + *source = p; + source = &p->next; + p = *source; + } + } + *small = oldsmall; + *source = NULL; + return small; +} + +/* + * See if lines currently target is suspected for can be attributed to + * parent. + */ +static void find_move_in_parent(struct blame_scoreboard *sb, + struct blame_entry ***blamed, + struct blame_entry **toosmall, + struct blame_origin *target, + struct blame_origin *parent) +{ + struct blame_entry *e, split[3]; + struct blame_entry *unblamed = target->suspects; + struct blame_entry *leftover = NULL; + mmfile_t file_p; + + if (!unblamed) + return; /* nothing remains for this target */ + + fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob); + if (!file_p.ptr) + return; + + /* At each iteration, unblamed has a NULL-terminated list of + * entries that have not yet been tested for blame. leftover + * contains the reversed list of entries that have been tested + * without being assignable to the parent. + */ + do { + struct blame_entry **unblamedtail = &unblamed; + struct blame_entry *next; + for (e = unblamed; e; e = next) { + next = e->next; + find_copy_in_blob(sb, e, parent, split, &file_p); + if (split[1].suspect && + sb->move_score < blame_entry_score(sb, &split[1])) { + split_blame(blamed, &unblamedtail, split, e); + } else { + e->next = leftover; + leftover = e; + } + decref_split(split); + } + *unblamedtail = NULL; + toosmall = filter_small(sb, toosmall, &unblamed, sb->move_score); + } while (unblamed); + target->suspects = reverse_blame(leftover, NULL); +} + +struct blame_list { + struct blame_entry *ent; + struct blame_entry split[3]; +}; + +/* + * Count the number of entries the target is suspected for, + * and prepare a list of entry and the best split. + */ +static struct blame_list *setup_blame_list(struct blame_entry *unblamed, + int *num_ents_p) +{ + struct blame_entry *e; + int num_ents, i; + struct blame_list *blame_list = NULL; + + for (e = unblamed, num_ents = 0; e; e = e->next) + num_ents++; + if (num_ents) { + blame_list = xcalloc(num_ents, sizeof(struct blame_list)); + for (e = unblamed, i = 0; e; e = e->next) + blame_list[i++].ent = e; + } + *num_ents_p = num_ents; + return blame_list; +} + +/* + * For lines target is suspected for, see if we can find code movement + * across file boundary from the parent commit. porigin is the path + * in the parent we already tried. + */ +static void find_copy_in_parent(struct blame_scoreboard *sb, + struct blame_entry ***blamed, + struct blame_entry **toosmall, + struct blame_origin *target, + struct commit *parent, + struct blame_origin *porigin, + int opt) +{ + struct diff_options diff_opts; + int i, j; + struct blame_list *blame_list; + int num_ents; + struct blame_entry *unblamed = target->suspects; + struct blame_entry *leftover = NULL; + + if (!unblamed) + return; /* nothing remains for this target */ + + diff_setup(&diff_opts); + DIFF_OPT_SET(&diff_opts, RECURSIVE); + diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; + + diff_setup_done(&diff_opts); + + /* Try "find copies harder" on new path if requested; + * we do not want to use diffcore_rename() actually to + * match things up; find_copies_harder is set only to - * force diff_tree_sha1() to feed all filepairs to diff_queue, ++ * force diff_tree_oid() to feed all filepairs to diff_queue, + * and this code needs to be after diff_setup_done(), which + * usually makes find-copies-harder imply copy detection. + */ + if ((opt & PICKAXE_BLAME_COPY_HARDEST) + || ((opt & PICKAXE_BLAME_COPY_HARDER) + && (!porigin || strcmp(target->path, porigin->path)))) + DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); + + if (is_null_oid(&target->commit->object.oid)) + do_diff_cache(&parent->tree->object.oid, &diff_opts); + else - diff_tree_sha1(parent->tree->object.oid.hash, - target->commit->tree->object.oid.hash, - "", &diff_opts); ++ diff_tree_oid(&parent->tree->object.oid, ++ &target->commit->tree->object.oid, ++ "", &diff_opts); + + if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER)) + diffcore_std(&diff_opts); + + do { + struct blame_entry **unblamedtail = &unblamed; + blame_list = setup_blame_list(unblamed, &num_ents); + + for (i = 0; i < diff_queued_diff.nr; i++) { + struct diff_filepair *p = diff_queued_diff.queue[i]; + struct blame_origin *norigin; + mmfile_t file_p; + struct blame_entry this[3]; + + if (!DIFF_FILE_VALID(p->one)) + continue; /* does not exist in parent */ + if (S_ISGITLINK(p->one->mode)) + continue; /* ignore git links */ + if (porigin && !strcmp(p->one->path, porigin->path)) + /* find_move already dealt with this path */ + continue; + + norigin = get_origin(parent, p->one->path); + oidcpy(&norigin->blob_oid, &p->one->oid); + norigin->mode = p->one->mode; + fill_origin_blob(&sb->revs->diffopt, norigin, &file_p, &sb->num_read_blob); + if (!file_p.ptr) + continue; + + for (j = 0; j < num_ents; j++) { + find_copy_in_blob(sb, blame_list[j].ent, + norigin, this, &file_p); + copy_split_if_better(sb, blame_list[j].split, + this); + decref_split(this); + } + blame_origin_decref(norigin); + } + + for (j = 0; j < num_ents; j++) { + struct blame_entry *split = blame_list[j].split; + if (split[1].suspect && + sb->copy_score < blame_entry_score(sb, &split[1])) { + split_blame(blamed, &unblamedtail, split, + blame_list[j].ent); + } else { + blame_list[j].ent->next = leftover; + leftover = blame_list[j].ent; + } + decref_split(split); + } + free(blame_list); + *unblamedtail = NULL; + toosmall = filter_small(sb, toosmall, &unblamed, sb->copy_score); + } while (unblamed); + target->suspects = reverse_blame(leftover, NULL); + diff_flush(&diff_opts); + clear_pathspec(&diff_opts.pathspec); +} + +/* + * The blobs of origin and porigin exactly match, so everything + * origin is suspected for can be blamed on the parent. + */ +static void pass_whole_blame(struct blame_scoreboard *sb, + struct blame_origin *origin, struct blame_origin *porigin) +{ + struct blame_entry *e, *suspects; + + if (!porigin->file.ptr && origin->file.ptr) { + /* Steal its file */ + porigin->file = origin->file; + origin->file.ptr = NULL; + } + suspects = origin->suspects; + origin->suspects = NULL; + for (e = suspects; e; e = e->next) { + blame_origin_incref(porigin); + blame_origin_decref(e->suspect); + e->suspect = porigin; + } + queue_blames(sb, porigin, suspects); +} + +/* + * We pass blame from the current commit to its parents. We keep saying + * "parent" (and "porigin"), but what we mean is to find scapegoat to + * exonerate ourselves. + */ +static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit, + int reverse) +{ + if (!reverse) { + if (revs->first_parent_only && + commit->parents && + commit->parents->next) { + free_commit_list(commit->parents->next); + commit->parents->next = NULL; + } + return commit->parents; + } + return lookup_decoration(&revs->children, &commit->object); +} + +static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reverse) +{ + struct commit_list *l = first_scapegoat(revs, commit, reverse); + return commit_list_count(l); +} + +/* Distribute collected unsorted blames to the respected sorted lists + * in the various origins. + */ +static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed) +{ + blamed = llist_mergesort(blamed, get_next_blame, set_next_blame, + compare_blame_suspect); + while (blamed) + { + struct blame_origin *porigin = blamed->suspect; + struct blame_entry *suspects = NULL; + do { + struct blame_entry *next = blamed->next; + blamed->next = suspects; + suspects = blamed; + blamed = next; + } while (blamed && blamed->suspect == porigin); + suspects = reverse_blame(suspects, NULL); + queue_blames(sb, porigin, suspects); + } +} + +#define MAXSG 16 + +static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin, int opt) +{ + struct rev_info *revs = sb->revs; + int i, pass, num_sg; + struct commit *commit = origin->commit; + struct commit_list *sg; + struct blame_origin *sg_buf[MAXSG]; + struct blame_origin *porigin, **sg_origin = sg_buf; + struct blame_entry *toosmall = NULL; + struct blame_entry *blames, **blametail = &blames; + + num_sg = num_scapegoats(revs, commit, sb->reverse); + if (!num_sg) + goto finish; + else if (num_sg < ARRAY_SIZE(sg_buf)) + memset(sg_buf, 0, sizeof(sg_buf)); + else + sg_origin = xcalloc(num_sg, sizeof(*sg_origin)); + + /* + * The first pass looks for unrenamed path to optimize for + * common cases, then we look for renames in the second pass. + */ + for (pass = 0; pass < 2 - sb->no_whole_file_rename; pass++) { + struct blame_origin *(*find)(struct commit *, struct blame_origin *); + find = pass ? find_rename : find_origin; + + for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse); + i < num_sg && sg; + sg = sg->next, i++) { + struct commit *p = sg->item; + int j, same; + + if (sg_origin[i]) + continue; + if (parse_commit(p)) + continue; + porigin = find(p, origin); + if (!porigin) + continue; + if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) { + pass_whole_blame(sb, origin, porigin); + blame_origin_decref(porigin); + goto finish; + } + for (j = same = 0; j < i; j++) + if (sg_origin[j] && + !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) { + same = 1; + break; + } + if (!same) + sg_origin[i] = porigin; + else + blame_origin_decref(porigin); + } + } + + sb->num_commits++; + for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse); + i < num_sg && sg; + sg = sg->next, i++) { + struct blame_origin *porigin = sg_origin[i]; + if (!porigin) + continue; + if (!origin->previous) { + blame_origin_incref(porigin); + origin->previous = porigin; + } + pass_blame_to_parent(sb, origin, porigin); + if (!origin->suspects) + goto finish; + } + + /* + * Optionally find moves in parents' files. + */ + if (opt & PICKAXE_BLAME_MOVE) { + filter_small(sb, &toosmall, &origin->suspects, sb->move_score); + if (origin->suspects) { + for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse); + i < num_sg && sg; + sg = sg->next, i++) { + struct blame_origin *porigin = sg_origin[i]; + if (!porigin) + continue; + find_move_in_parent(sb, &blametail, &toosmall, origin, porigin); + if (!origin->suspects) + break; + } + } + } + + /* + * Optionally find copies from parents' files. + */ + if (opt & PICKAXE_BLAME_COPY) { + if (sb->copy_score > sb->move_score) + filter_small(sb, &toosmall, &origin->suspects, sb->copy_score); + else if (sb->copy_score < sb->move_score) { + origin->suspects = blame_merge(origin->suspects, toosmall); + toosmall = NULL; + filter_small(sb, &toosmall, &origin->suspects, sb->copy_score); + } + if (!origin->suspects) + goto finish; + + for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse); + i < num_sg && sg; + sg = sg->next, i++) { + struct blame_origin *porigin = sg_origin[i]; + find_copy_in_parent(sb, &blametail, &toosmall, + origin, sg->item, porigin, opt); + if (!origin->suspects) + goto finish; + } + } + +finish: + *blametail = NULL; + distribute_blame(sb, blames); + /* + * prepend toosmall to origin->suspects + * + * There is no point in sorting: this ends up on a big + * unsorted list in the caller anyway. + */ + if (toosmall) { + struct blame_entry **tail = &toosmall; + while (*tail) + tail = &(*tail)->next; + *tail = origin->suspects; + origin->suspects = toosmall; + } + for (i = 0; i < num_sg; i++) { + if (sg_origin[i]) { + drop_origin_blob(sg_origin[i]); + blame_origin_decref(sg_origin[i]); + } + } + drop_origin_blob(origin); + if (sg_buf != sg_origin) + free(sg_origin); +} + +/* + * The main loop -- while we have blobs with lines whose true origin + * is still unknown, pick one blob, and allow its lines to pass blames + * to its parents. */ +void assign_blame(struct blame_scoreboard *sb, int opt) +{ + struct rev_info *revs = sb->revs; + struct commit *commit = prio_queue_get(&sb->commits); + + while (commit) { + struct blame_entry *ent; + struct blame_origin *suspect = commit->util; + + /* find one suspect to break down */ + while (suspect && !suspect->suspects) + suspect = suspect->next; + + if (!suspect) { + commit = prio_queue_get(&sb->commits); + continue; + } + + assert(commit == suspect->commit); + + /* + * We will use this suspect later in the loop, + * so hold onto it in the meantime. + */ + blame_origin_incref(suspect); + parse_commit(commit); + if (sb->reverse || + (!(commit->object.flags & UNINTERESTING) && + !(revs->max_age != -1 && commit->date < revs->max_age))) + pass_blame(sb, suspect, opt); + else { + commit->object.flags |= UNINTERESTING; + if (commit->object.parsed) + mark_parents_uninteresting(commit); + } + /* treat root commit as boundary */ + if (!commit->parents && !sb->show_root) + commit->object.flags |= UNINTERESTING; + + /* Take responsibility for the remaining entries */ + ent = suspect->suspects; + if (ent) { + suspect->guilty = 1; + for (;;) { + struct blame_entry *next = ent->next; + if (sb->found_guilty_entry) + sb->found_guilty_entry(ent, sb->found_guilty_entry_data); + if (next) { + ent = next; + continue; + } + ent->next = sb->ent; + sb->ent = suspect->suspects; + suspect->suspects = NULL; + break; + } + } + blame_origin_decref(suspect); + + if (sb->debug) /* sanity */ + sanity_check_refcnt(sb); + } +} + +static const char *get_next_line(const char *start, const char *end) +{ + const char *nl = memchr(start, '\n', end - start); + return nl ? nl + 1 : end; +} + +/* + * To allow quick access to the contents of nth line in the + * final image, prepare an index in the scoreboard. + */ +static int prepare_lines(struct blame_scoreboard *sb) +{ + const char *buf = sb->final_buf; + unsigned long len = sb->final_buf_size; + const char *end = buf + len; + const char *p; + int *lineno; + int num = 0; + + for (p = buf; p < end; p = get_next_line(p, end)) + num++; + + ALLOC_ARRAY(sb->lineno, num + 1); + lineno = sb->lineno; + + for (p = buf; p < end; p = get_next_line(p, end)) + *lineno++ = p - buf; + + *lineno = len; + + sb->num_lines = num; + return sb->num_lines; +} + +static struct commit *find_single_final(struct rev_info *revs, + const char **name_p) +{ + int i; + struct commit *found = NULL; + const char *name = NULL; + + for (i = 0; i < revs->pending.nr; i++) { + struct object *obj = revs->pending.objects[i].item; + if (obj->flags & UNINTERESTING) + continue; + obj = deref_tag(obj, NULL, 0); + if (obj->type != OBJ_COMMIT) + die("Non commit %s?", revs->pending.objects[i].name); + if (found) + die("More than one commit to dig from %s and %s?", + revs->pending.objects[i].name, name); + found = (struct commit *)obj; + name = revs->pending.objects[i].name; + } + if (name_p) + *name_p = name; + return found; +} + +static struct commit *dwim_reverse_initial(struct rev_info *revs, + const char **name_p) +{ + /* + * DWIM "git blame --reverse ONE -- PATH" as + * "git blame --reverse ONE..HEAD -- PATH" but only do so + * when it makes sense. + */ + struct object *obj; + struct commit *head_commit; + struct object_id head_oid; + + if (revs->pending.nr != 1) + return NULL; + + /* Is that sole rev a committish? */ + obj = revs->pending.objects[0].item; + obj = deref_tag(obj, NULL, 0); + if (obj->type != OBJ_COMMIT) + return NULL; + + /* Do we have HEAD? */ + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) + return NULL; + head_commit = lookup_commit_reference_gently(&head_oid, 1); + if (!head_commit) + return NULL; + + /* Turn "ONE" into "ONE..HEAD" then */ + obj->flags |= UNINTERESTING; + add_pending_object(revs, &head_commit->object, "HEAD"); + + if (name_p) + *name_p = revs->pending.objects[0].name; + return (struct commit *)obj; +} + +static struct commit *find_single_initial(struct rev_info *revs, + const char **name_p) +{ + int i; + struct commit *found = NULL; + const char *name = NULL; + + /* + * There must be one and only one negative commit, and it must be + * the boundary. + */ + for (i = 0; i < revs->pending.nr; i++) { + struct object *obj = revs->pending.objects[i].item; + if (!(obj->flags & UNINTERESTING)) + continue; + obj = deref_tag(obj, NULL, 0); + if (obj->type != OBJ_COMMIT) + die("Non commit %s?", revs->pending.objects[i].name); + if (found) + die("More than one commit to dig up from, %s and %s?", + revs->pending.objects[i].name, name); + found = (struct commit *) obj; + name = revs->pending.objects[i].name; + } + + if (!name) + found = dwim_reverse_initial(revs, &name); + if (!name) + die("No commit to dig up from?"); + + if (name_p) + *name_p = name; + return found; +} + +void init_scoreboard(struct blame_scoreboard *sb) +{ + memset(sb, 0, sizeof(struct blame_scoreboard)); + sb->move_score = BLAME_DEFAULT_MOVE_SCORE; + sb->copy_score = BLAME_DEFAULT_COPY_SCORE; +} + +void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig) +{ + const char *final_commit_name = NULL; + struct blame_origin *o; + struct commit *final_commit = NULL; + enum object_type type; + + if (sb->reverse && sb->contents_from) + die(_("--contents and --reverse do not blend well.")); + + if (!sb->reverse) { + sb->final = find_single_final(sb->revs, &final_commit_name); + sb->commits.compare = compare_commits_by_commit_date; + } else { + sb->final = find_single_initial(sb->revs, &final_commit_name); + sb->commits.compare = compare_commits_by_reverse_commit_date; + } + + if (sb->final && sb->contents_from) + die(_("cannot use --contents with final commit object name")); + + if (sb->reverse && sb->revs->first_parent_only) + sb->revs->children.name = NULL; + + if (!sb->final) { + /* + * "--not A B -- path" without anything positive; + * do not default to HEAD, but use the working tree + * or "--contents". + */ + setup_work_tree(); + sb->final = fake_working_tree_commit(&sb->revs->diffopt, + path, sb->contents_from); + add_pending_object(sb->revs, &(sb->final->object), ":"); + } + + if (sb->reverse && sb->revs->first_parent_only) { + final_commit = find_single_final(sb->revs, NULL); + if (!final_commit) + die(_("--reverse and --first-parent together require specified latest commit")); + } + + /* + * If we have bottom, this will mark the ancestors of the + * bottom commits we would reach while traversing as + * uninteresting. + */ + if (prepare_revision_walk(sb->revs)) + die(_("revision walk setup failed")); + + if (sb->reverse && sb->revs->first_parent_only) { + struct commit *c = final_commit; + + sb->revs->children.name = "children"; + while (c->parents && + oidcmp(&c->object.oid, &sb->final->object.oid)) { + struct commit_list *l = xcalloc(1, sizeof(*l)); + + l->item = c; + if (add_decoration(&sb->revs->children, + &c->parents->item->object, l)) + die("BUG: not unique item in first-parent chain"); + c = c->parents->item; + } + + if (oidcmp(&c->object.oid, &sb->final->object.oid)) + die(_("--reverse --first-parent together require range along first-parent chain")); + } + + if (is_null_oid(&sb->final->object.oid)) { + o = sb->final->util; + sb->final_buf = xmemdupz(o->file.ptr, o->file.size); + sb->final_buf_size = o->file.size; + } + else { + o = get_origin(sb->final, path); + if (fill_blob_sha1_and_mode(o)) + die(_("no such path %s in %s"), path, final_commit_name); + + if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) && + textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf, + &sb->final_buf_size)) + ; + else + sb->final_buf = read_sha1_file(o->blob_oid.hash, &type, + &sb->final_buf_size); + + if (!sb->final_buf) + die(_("cannot read blob %s for path %s"), + oid_to_hex(&o->blob_oid), + path); + } + sb->num_read_blob++; + prepare_lines(sb); + + if (orig) + *orig = o; +} + + + +struct blame_entry *blame_entry_prepend(struct blame_entry *head, + long start, long end, + struct blame_origin *o) +{ + struct blame_entry *new_head = xcalloc(1, sizeof(struct blame_entry)); + new_head->lno = start; + new_head->num_lines = end - start; + new_head->suspect = o; + new_head->s_lno = start; + new_head->next = head; + blame_origin_incref(o); + return new_head; +} diff --combined branch.c index 985316eb76,985316eb76,5532b4218f..a8a548ccf2 --- a/branch.c +++ b/branch.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "git-compat-util.h" #include "cache.h" ++ #include "config.h" #include "branch.h" #include "refs.h" #include "remote.h" @@@@ -191,9 -191,9 -192,9 +192,9 @@@@ int validate_new_branchname(const char if (!attr_only) { const char *head; - unsigned char sha1[20]; + struct object_id oid; - head = resolve_ref_unsafe("HEAD", 0, sha1, NULL); + head = resolve_ref_unsafe("HEAD", 0, oid.hash, NULL); if (!is_bare_repository() && head && !strcmp(head, ref->buf)) die(_("Cannot force update the current branch.")); } @@@@ -233,7 -233,7 -234,7 +234,7 @@@@ void create_branch(const char *name, co int quiet, enum branch_track track) { struct commit *commit; - unsigned char sha1[20]; + struct object_id oid; char *real_ref; struct strbuf ref = STRBUF_INIT; int forcing = 0; @@@@ -253,7 -253,7 -254,7 +254,7 @@@@ } real_ref = NULL; - if (get_sha1(start_name, sha1)) { + if (get_oid(start_name, &oid)) { if (explicit_tracking) { if (advice_set_upstream_failure) { error(_(upstream_missing), start_name); @@@@ -265,7 -265,7 -266,7 +266,7 @@@@ die(_("Not a valid object name: '%s'."), start_name); } - switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { + switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) { case 0: /* Not branching from any existing branch */ if (explicit_tracking) @@@@ -286,9 -286,9 -287,9 +287,9 @@@@ break; } - if ((commit = lookup_commit_reference(sha1)) == NULL) + if ((commit = lookup_commit_reference(&oid)) == NULL) die(_("Not a valid branch point: '%s'."), start_name); - hashcpy(sha1, commit->object.oid.hash); + oidcpy(&oid, &commit->object.oid); if (reflog) log_all_ref_updates = LOG_REFS_NORMAL; @@@@ -306,7 -306,7 -307,7 +307,7 @@@@ transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, - sha1, forcing ? NULL : null_sha1, + oid.hash, forcing ? NULL : null_sha1, 0, msg, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); @@@@ -353,18 -353,18 -354,17 +354,18 @@@@ int replace_each_worktree_head_symref(c int i; for (i = 0; worktrees[i]; i++) { + struct ref_store *refs; + if (worktrees[i]->is_detached) continue; - if (strcmp(oldref, worktrees[i]->head_ref)) + if (worktrees[i]->head_ref && + strcmp(oldref, worktrees[i]->head_ref)) continue; - if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]), - newref, logmsg)) { - ret = -1; - error(_("HEAD of working tree %s is not updated"), - worktrees[i]->path); - } + refs = get_worktree_ref_store(worktrees[i]); + if (refs_create_symref(refs, "HEAD", newref, logmsg)) + ret = error(_("HEAD of working tree %s is not updated"), + worktrees[i]->path); } free_worktrees(worktrees); diff --combined builtin/add.c index d9a2491e48,d9a2491e48,55759a6a78..f2415e99f3 --- a/builtin/add.c +++ b/builtin/add.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) 2006 Linus Torvalds */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "lockfile.h" #include "dir.h" @@@@ -17,7 -17,7 -18,6 +18,7 @@@@ #include "revision.h" #include "bulk-checkin.h" #include "argv-array.h" +#include "submodule.h" static const char * const builtin_add_usage[] = { N_("git add [] [--] ..."), @@@@ -136,7 -136,7 -136,7 +137,7 @@@@ static char *prune_directory(struct dir *dst++ = entry; } dir->nr = dst - dir->entries; - add_pathspec_matches_against_index(pathspec, seen); + add_pathspec_matches_against_index(pathspec, &the_index, seen); return seen; } @@@@ -380,19 -380,19 -380,16 +381,19 @@@@ int cmd_add(int argc, const char **argv if (read_cache() < 0) die(_("index file corrupt")); + die_in_unpopulated_submodule(&the_index, prefix); + /* * Check the "pathspec '%s' did not match any files" block * below before enabling new magic. */ parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_FULL | - PATHSPEC_SYMLINK_LEADING_PATH | - PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE, + PATHSPEC_SYMLINK_LEADING_PATH, prefix, argv); + die_path_inside_submodule(&the_index, &pathspec); + if (add_new_files) { int baselen; @@@@ -404,7 -404,7 -401,7 +405,7 @@@@ } /* This picks up the paths that are not tracked */ - baselen = fill_directory(&dir, &pathspec); + baselen = fill_directory(&dir, &the_index, &pathspec); if (pathspec.nr) seen = prune_directory(&dir, &pathspec, baselen); } @@@@ -418,7 -418,7 -415,7 +419,7 @@@@ int i; if (!seen) - seen = find_pathspecs_matching_against_index(&pathspec); + seen = find_pathspecs_matching_against_index(&pathspec, &the_index); /* * file_exists() assumes exact match @@@@ -440,9 -440,9 -437,8 +441,9 @@@@ !file_exists(path))) { if (ignore_missing) { int dtype = DT_UNKNOWN; - if (is_excluded(&dir, path, &dtype)) - dir_add_ignored(&dir, path, pathspec.items[i].len); + if (is_excluded(&dir, &the_index, path, &dtype)) + dir_add_ignored(&dir, &the_index, + path, pathspec.items[i].len); } else die(_("pathspec '%s' did not match any files"), pathspec.items[i].original); diff --combined builtin/am.c index 3985f9a89f,5ee146bfb3,59f46a29ee..7c7b916d23 --- a/builtin/am.c +++ b/builtin/am.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Based on git-am.sh by Junio C Hamano. */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "exec_cmd.h" #include "parse-options.h" @@@@ -563,7 -563,7 -564,7 +564,7 @@@@ static int copy_notes_for_rebase(const goto finish; } -- if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash)) ++ if (copy_note_for_rewrite(c, &from_obj, &to_obj)) ret = error(_("Failed to copy notes from '%s' to '%s'"), oid_to_hex(&from_obj), oid_to_hex(&to_obj)); } @@@@ -879,12 -879,12 -880,12 +880,12 @@@@ static int hg_patch_to_mail(FILE *out, if (skip_prefix(sb.buf, "# User ", &str)) fprintf(out, "From: %s\n", str); else if (skip_prefix(sb.buf, "# Date ", &str)) { - unsigned long timestamp; + timestamp_t timestamp; long tz, tz2; char *end; errno = 0; - timestamp = strtoul(str, &end, 10); + timestamp = parse_timestamp(str, &end, 10); if (errno) return error(_("invalid timestamp")); @@@@ -1145,7 -1145,7 -1146,7 +1146,7 @@@@ static int index_has_changes(struct str DIFF_OPT_SET(&opt, EXIT_WITH_STATUS); if (!sb) DIFF_OPT_SET(&opt, QUICK); - do_diff_cache(head.hash, &opt); + do_diff_cache(&head, &opt); diffcore_std(&opt); for (i = 0; sb && i < diff_queued_diff.nr; i++) { if (i) @@@@ -1275,8 -1275,12 -1276,12 +1276,8 @@@@ static int parse_mail(struct am_state * die("BUG: invalid value for state->scissors"); } -- mi.input = fopen(mail, "r"); -- if (!mi.input) -- die("could not open input"); -- mi.output = fopen(am_path(state, "info"), "w"); -- if (!mi.output) -- die("could not open output 'info'"); ++ mi.input = xfopen(mail, "r"); ++ mi.output = xfopen(am_path(state, "info"), "w"); if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch"))) die("could not parse patch"); @@@@ -1308,7 -1312,7 -1313,7 +1309,7 @@@@ } if (is_empty_file(am_path(state, "patch"))) { - printf_ln(_("Patch is empty. Was it split wrong?")); + printf_ln(_("Patch is empty.")); die_user_resolve(state); } @@@@ -1347,16 -1351,16 -1352,19 +1348,16 @@@@ static int get_mail_commit_oid(struct o struct strbuf sb = STRBUF_INIT; FILE *fp = xfopen(mail, "r"); const char *x; + int ret = 0; - if (strbuf_getline_lf(&sb, fp)) - return -1; - - if (!skip_prefix(sb.buf, "From ", &x)) - return -1; - - if (get_oid_hex(x, commit_id) < 0) - return -1; + if (strbuf_getline_lf(&sb, fp) || + !skip_prefix(sb.buf, "From ", &x) || + get_oid_hex(x, commit_id) < 0) + ret = -1; strbuf_release(&sb); fclose(fp); - return 0; + return ret; } /** @@@@ -1365,33 -1369,33 -1373,40 +1366,33 @@@@ */ static void get_commit_info(struct am_state *state, struct commit *commit) { - const char *buffer, *ident_line, *author_date, *msg; + const char *buffer, *ident_line, *msg; size_t ident_len; - struct ident_split ident_split; - struct strbuf sb = STRBUF_INIT; + struct ident_split id; buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding()); ident_line = find_commit_header(buffer, "author", &ident_len); - if (split_ident_line(&ident_split, ident_line, ident_len) < 0) { - strbuf_add(&sb, ident_line, ident_len); - die(_("invalid ident line: %s"), sb.buf); - } + if (split_ident_line(&id, ident_line, ident_len) < 0) + die(_("invalid ident line: %.*s"), (int)ident_len, ident_line); assert(!state->author_name); - if (ident_split.name_begin) { - strbuf_add(&sb, ident_split.name_begin, - ident_split.name_end - ident_split.name_begin); - state->author_name = strbuf_detach(&sb, NULL); - } else + if (id.name_begin) + state->author_name = + xmemdupz(id.name_begin, id.name_end - id.name_begin); + else state->author_name = xstrdup(""); assert(!state->author_email); - if (ident_split.mail_begin) { - strbuf_add(&sb, ident_split.mail_begin, - ident_split.mail_end - ident_split.mail_begin); - state->author_email = strbuf_detach(&sb, NULL); - } else + if (id.mail_begin) + state->author_email = + xmemdupz(id.mail_begin, id.mail_end - id.mail_begin); + else state->author_email = xstrdup(""); - author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL)); - strbuf_addstr(&sb, author_date); assert(!state->author_date); - state->author_date = strbuf_detach(&sb, NULL); + state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL))); assert(!state->msg); msg = strstr(buffer, "\n\n"); @@@@ -1399,7 -1403,7 -1414,6 +1400,7 @@@@ die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid)); state->msg = xstrdup(msg + 2); state->msg_len = strlen(state->msg); + unuse_commit_buffer(commit, buffer); } /** @@@@ -1440,9 -1444,9 -1454,9 +1441,9 @@@@ static void write_index_patch(const str FILE *fp; if (!get_sha1_tree("HEAD", head.hash)) - tree = lookup_tree(head.hash); + tree = lookup_tree(&head); else - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); fp = xfopen(am_path(state, "patch"), "w"); init_revisions(&rev_info, NULL); @@@@ -1475,7 -1479,7 -1489,7 +1476,7 @@@@ static int parse_mail_rebase(struct am_ if (get_mail_commit_oid(&commit_oid, mail) < 0) die(_("could not parse %s"), mail); - commit = lookup_commit_or_die(commit_oid.hash, mail); + commit = lookup_commit_or_die(&commit_oid, mail); get_commit_info(state, commit); @@@@ -1605,7 -1609,7 -1619,7 +1606,7 @@@@ static int fall_back_threeway(const str init_revisions(&rev_info, NULL); rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS; diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix); - add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0); + add_pending_oid(&rev_info, "HEAD", &our_tree, 0); diff_setup_done(&rev_info.diffopt); run_diff_index(&rev_info, 1); } @@@@ -1670,7 -1674,7 -1684,7 +1671,7 @@@@ static void do_commit(const struct am_s if (!get_sha1_commit("HEAD", parent.hash)) { old_oid = &parent; - commit_list_insert(lookup_commit(parent.hash), &parents); + commit_list_insert(lookup_commit(&parent), &parents); } else { old_oid = NULL; say(state, stderr, _("applying to an empty history")); @@@@ -1927,8 -1931,8 -1941,7 +1928,8 @@@@ static void am_resolve(struct am_state if (unmerged_cache()) { printf_ln(_("You still have unmerged paths in your index.\n" - "Did you forget to use 'git add'?")); + "You should 'git add' each file with resolved conflicts to mark them as such.\n" + "You might run `git rm` on a file to accept \"deleted by them\" for it.")); die_user_resolve(state); } @@@@ -2033,11 -2037,11 -2046,11 +2034,11 @@@@ static int clean_index(const struct obj struct tree *head_tree, *remote_tree, *index_tree; struct object_id index; - head_tree = parse_tree_indirect(head->hash); + head_tree = parse_tree_indirect(head); if (!head_tree) return error(_("Could not parse object '%s'."), oid_to_hex(head)); - remote_tree = parse_tree_indirect(remote->hash); + remote_tree = parse_tree_indirect(remote); if (!remote_tree) return error(_("Could not parse object '%s'."), oid_to_hex(remote)); @@@@ -2049,7 -2053,7 -2062,7 +2050,7 @@@@ if (write_cache_as_tree(index.hash, 0, NULL)) return -1; - index_tree = parse_tree_indirect(index.hash); + index_tree = parse_tree_indirect(&index); if (!index_tree) return error(_("Could not parse object '%s'."), oid_to_hex(&index)); @@@@ -2144,7 -2148,7 -2157,7 +2145,7 @@@@ static void am_abort(struct am_state *s am_rerere_clear(); curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL); - has_curr_head = !is_null_oid(&curr_head); + has_curr_head = curr_branch && !is_null_oid(&curr_head); if (!has_curr_head) hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN); @@@@ -2307,9 -2311,9 -2320,6 +2308,9 @@@@ int cmd_am(int argc, const char **argv OPT_END() }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(usage, options); + git_config(git_am_config, NULL); am_state_init(&state); diff --combined builtin/blame.c index 749ad7f05b,d7a2df3b47,1a7371808a..bda1a78726 --- a/builtin/blame.c +++ b/builtin/blame.c @@@@ -6,13 -6,13 -6,22 +6,14 @@@@ */ #include "cache.h" ++ #include "config.h" -#include "refs.h" #include "builtin.h" -#include "blob.h" #include "commit.h" -#include "tag.h" -#include "tree-walk.h" #include "diff.h" -#include "diffcore.h" #include "revision.h" #include "quote.h" -#include "xdiff-interface.h" -#include "cache-tree.h" #include "string-list.h" #include "mailmap.h" -#include "mergesort.h" #include "parse-options.h" #include "prio-queue.h" #include "utf8.h" @@@@ -21,7 -21,7 -30,6 +22,7 @@@@ #include "line-log.h" #include "dir.h" #include "progress.h" +#include "blame.h" static char blame_usage[] = N_("git blame [] [] [] [--] "); @@@@ -55,21 -55,21 -63,1497 +56,21 @@@@ static struct string_list mailmap = STR #define DEBUG 0 #endif -/* stats */ -static int num_read_blob; -static int num_get_patch; -static int num_commits; - -#define PICKAXE_BLAME_MOVE 01 -#define PICKAXE_BLAME_COPY 02 -#define PICKAXE_BLAME_COPY_HARDER 04 -#define PICKAXE_BLAME_COPY_HARDEST 010 - -/* - * blame for a blame_entry with score lower than these thresholds - * is not passed to the parent using move/copy logic. - */ -static unsigned blame_move_score; -static unsigned blame_copy_score; -#define BLAME_DEFAULT_MOVE_SCORE 20 -#define BLAME_DEFAULT_COPY_SCORE 40 - -/* Remember to update object flag allocation in object.h */ -#define METAINFO_SHOWN (1u<<12) -#define MORE_THAN_ONE_PATH (1u<<13) - -/* - * One blob in a commit that is being suspected - */ -struct origin { - int refcnt; - /* Record preceding blame record for this blob */ - struct origin *previous; - /* origins are put in a list linked via `next' hanging off the - * corresponding commit's util field in order to make finding - * them fast. The presence in this chain does not count - * towards the origin's reference count. It is tempting to - * let it count as long as the commit is pending examination, - * but even under circumstances where the commit will be - * present multiple times in the priority queue of unexamined - * commits, processing the first instance will not leave any - * work requiring the origin data for the second instance. An - * interspersed commit changing that would have to be - * preexisting with a different ancestry and with the same - * commit date in order to wedge itself between two instances - * of the same commit in the priority queue _and_ produce - * blame entries relevant for it. While we don't want to let - * us get tripped up by this case, it certainly does not seem - * worth optimizing for. - */ - struct origin *next; - struct commit *commit; - /* `suspects' contains blame entries that may be attributed to - * this origin's commit or to parent commits. When a commit - * is being processed, all suspects will be moved, either by - * assigning them to an origin in a different commit, or by - * shipping them to the scoreboard's ent list because they - * cannot be attributed to a different commit. - */ - struct blame_entry *suspects; - mmfile_t file; - struct object_id blob_oid; - unsigned mode; - /* guilty gets set when shipping any suspects to the final - * blame list instead of other commits - */ - char guilty; - char path[FLEX_ARRAY]; -}; - -struct progress_info { - struct progress *progress; - int blamed_lines; -}; - -static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, - xdl_emit_hunk_consume_func_t hunk_func, void *cb_data) -{ - xpparam_t xpp = {0}; - xdemitconf_t xecfg = {0}; - xdemitcb_t ecb = {NULL}; - - xpp.flags = xdl_opts; - xecfg.hunk_func = hunk_func; - ecb.priv = cb_data; - return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb); -} - -/* - * Prepare diff_filespec and convert it using diff textconv API - * if the textconv driver exists. - * Return 1 if the conversion succeeds, 0 otherwise. - */ -int textconv_object(const char *path, - unsigned mode, - const struct object_id *oid, - int oid_valid, - char **buf, - unsigned long *buf_size) -{ - struct diff_filespec *df; - struct userdiff_driver *textconv; - - df = alloc_filespec(path); - fill_filespec(df, oid->hash, oid_valid, mode); - textconv = get_textconv(df); - if (!textconv) { - free_filespec(df); - return 0; - } - - *buf_size = fill_textconv(textconv, df, buf); - free_filespec(df); - return 1; -} - -/* - * Given an origin, prepare mmfile_t structure to be used by the - * diff machinery - */ -static void fill_origin_blob(struct diff_options *opt, - struct origin *o, mmfile_t *file) -{ - if (!o->file.ptr) { - enum object_type type; - unsigned long file_size; - - num_read_blob++; - if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && - textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size)) - ; - else - file->ptr = read_sha1_file(o->blob_oid.hash, &type, - &file_size); - file->size = file_size; - - if (!file->ptr) - die("Cannot read blob %s for path %s", - oid_to_hex(&o->blob_oid), - o->path); - o->file = *file; - } - else - *file = o->file; -} - -/* - * Origin is refcounted and usually we keep the blob contents to be - * reused. - */ -static inline struct origin *origin_incref(struct origin *o) -{ - if (o) - o->refcnt++; - return o; -} - -static void origin_decref(struct origin *o) -{ - if (o && --o->refcnt <= 0) { - struct origin *p, *l = NULL; - if (o->previous) - origin_decref(o->previous); - free(o->file.ptr); - /* Should be present exactly once in commit chain */ - for (p = o->commit->util; p; l = p, p = p->next) { - if (p == o) { - if (l) - l->next = p->next; - else - o->commit->util = p->next; - free(o); - return; - } - } - die("internal error in blame::origin_decref"); - } -} - -static void drop_origin_blob(struct origin *o) -{ - if (o->file.ptr) { - free(o->file.ptr); - o->file.ptr = NULL; - } -} - -/* - * Each group of lines is described by a blame_entry; it can be split - * as we pass blame to the parents. They are arranged in linked lists - * kept as `suspects' of some unprocessed origin, or entered (when the - * blame origin has been finalized) into the scoreboard structure. - * While the scoreboard structure is only sorted at the end of - * processing (according to final image line number), the lists - * attached to an origin are sorted by the target line number. - */ -struct blame_entry { - struct blame_entry *next; - - /* the first line of this group in the final image; - * internally all line numbers are 0 based. - */ - int lno; - - /* how many lines this group has */ - int num_lines; - - /* the commit that introduced this group into the final image */ - struct origin *suspect; - - /* the line number of the first line of this group in the - * suspect's file; internally all line numbers are 0 based. - */ - int s_lno; - - /* how significant this entry is -- cached to avoid - * scanning the lines over and over. - */ - unsigned score; -}; - -/* - * Any merge of blames happens on lists of blames that arrived via - * different parents in a single suspect. In this case, we want to - * sort according to the suspect line numbers as opposed to the final - * image line numbers. The function body is somewhat longish because - * it avoids unnecessary writes. - */ - -static struct blame_entry *blame_merge(struct blame_entry *list1, - struct blame_entry *list2) -{ - struct blame_entry *p1 = list1, *p2 = list2, - **tail = &list1; - - if (!p1) - return p2; - if (!p2) - return p1; - - if (p1->s_lno <= p2->s_lno) { - do { - tail = &p1->next; - if ((p1 = *tail) == NULL) { - *tail = p2; - return list1; - } - } while (p1->s_lno <= p2->s_lno); - } - for (;;) { - *tail = p2; - do { - tail = &p2->next; - if ((p2 = *tail) == NULL) { - *tail = p1; - return list1; - } - } while (p1->s_lno > p2->s_lno); - *tail = p1; - do { - tail = &p1->next; - if ((p1 = *tail) == NULL) { - *tail = p2; - return list1; - } - } while (p1->s_lno <= p2->s_lno); - } -} - -static void *get_next_blame(const void *p) -{ - return ((struct blame_entry *)p)->next; -} - -static void set_next_blame(void *p1, void *p2) -{ - ((struct blame_entry *)p1)->next = p2; -} - -/* - * Final image line numbers are all different, so we don't need a - * three-way comparison here. - */ - -static int compare_blame_final(const void *p1, const void *p2) -{ - return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno - ? 1 : -1; -} - -static int compare_blame_suspect(const void *p1, const void *p2) -{ - const struct blame_entry *s1 = p1, *s2 = p2; - /* - * to allow for collating suspects, we sort according to the - * respective pointer value as the primary sorting criterion. - * The actual relation is pretty unimportant as long as it - * establishes a total order. Comparing as integers gives us - * that. - */ - if (s1->suspect != s2->suspect) - return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1; - if (s1->s_lno == s2->s_lno) - return 0; - return s1->s_lno > s2->s_lno ? 1 : -1; -} - -static struct blame_entry *blame_sort(struct blame_entry *head, - int (*compare_fn)(const void *, const void *)) -{ - return llist_mergesort (head, get_next_blame, set_next_blame, compare_fn); -} - -static int compare_commits_by_reverse_commit_date(const void *a, - const void *b, - void *c) -{ - return -compare_commits_by_commit_date(a, b, c); -} - -/* - * The current state of the blame assignment. - */ -struct scoreboard { - /* the final commit (i.e. where we started digging from) */ - struct commit *final; - /* Priority queue for commits with unassigned blame records */ - struct prio_queue commits; - struct rev_info *revs; - const char *path; - - /* - * The contents in the final image. - * Used by many functions to obtain contents of the nth line, - * indexed with scoreboard.lineno[blame_entry.lno]. - */ - const char *final_buf; - unsigned long final_buf_size; - - /* linked list of blames */ - struct blame_entry *ent; - - /* look-up a line in the final buffer */ - int num_lines; - int *lineno; -}; - -static void sanity_check_refcnt(struct scoreboard *); - -/* - * If two blame entries that are next to each other came from - * contiguous lines in the same origin (i.e. pair), - * merge them together. - */ -static void coalesce(struct scoreboard *sb) -{ - struct blame_entry *ent, *next; - - for (ent = sb->ent; ent && (next = ent->next); ent = next) { - if (ent->suspect == next->suspect && - ent->s_lno + ent->num_lines == next->s_lno) { - ent->num_lines += next->num_lines; - ent->next = next->next; - origin_decref(next->suspect); - free(next); - ent->score = 0; - next = ent; /* again */ - } - } - - if (DEBUG) /* sanity */ - sanity_check_refcnt(sb); -} - -/* - * Merge the given sorted list of blames into a preexisting origin. - * If there were no previous blames to that commit, it is entered into - * the commit priority queue of the score board. - */ - -static void queue_blames(struct scoreboard *sb, struct origin *porigin, - struct blame_entry *sorted) -{ - if (porigin->suspects) - porigin->suspects = blame_merge(porigin->suspects, sorted); - else { - struct origin *o; - for (o = porigin->commit->util; o; o = o->next) { - if (o->suspects) { - porigin->suspects = sorted; - return; - } - } - porigin->suspects = sorted; - prio_queue_put(&sb->commits, porigin->commit); - } -} - -/* - * Given a commit and a path in it, create a new origin structure. - * The callers that add blame to the scoreboard should use - * get_origin() to obtain shared, refcounted copy instead of calling - * this function directly. - */ -static struct origin *make_origin(struct commit *commit, const char *path) -{ - struct origin *o; - FLEX_ALLOC_STR(o, path, path); - o->commit = commit; - o->refcnt = 1; - o->next = commit->util; - commit->util = o; - return o; -} - -/* - * Locate an existing origin or create a new one. - * This moves the origin to front position in the commit util list. - */ -static struct origin *get_origin(struct scoreboard *sb, - struct commit *commit, - const char *path) -{ - struct origin *o, *l; - - for (o = commit->util, l = NULL; o; l = o, o = o->next) { - if (!strcmp(o->path, path)) { - /* bump to front */ - if (l) { - l->next = o->next; - o->next = commit->util; - commit->util = o; - } - return origin_incref(o); - } - } - return make_origin(commit, path); -} - -/* - * Fill the blob_sha1 field of an origin if it hasn't, so that later - * call to fill_origin_blob() can use it to locate the data. blob_sha1 - * for an origin is also used to pass the blame for the entire file to - * the parent to detect the case where a child's blob is identical to - * that of its parent's. - * - * This also fills origin->mode for corresponding tree path. - */ -static int fill_blob_sha1_and_mode(struct origin *origin) -{ - if (!is_null_oid(&origin->blob_oid)) - return 0; - if (get_tree_entry(origin->commit->object.oid.hash, - origin->path, - origin->blob_oid.hash, &origin->mode)) - goto error_out; - if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB) - goto error_out; - return 0; - error_out: - oidclr(&origin->blob_oid); - origin->mode = S_IFINVALID; - return -1; -} - -/* - * We have an origin -- check if the same path exists in the - * parent and return an origin structure to represent it. - */ -static struct origin *find_origin(struct scoreboard *sb, - struct commit *parent, - struct origin *origin) -{ - struct origin *porigin; - struct diff_options diff_opts; - const char *paths[2]; - - /* First check any existing origins */ - for (porigin = parent->util; porigin; porigin = porigin->next) - if (!strcmp(porigin->path, origin->path)) { - /* - * The same path between origin and its parent - * without renaming -- the most common case. - */ - return origin_incref (porigin); - } - - /* See if the origin->path is different between parent - * and origin first. Most of the time they are the - * same and diff-tree is fairly efficient about this. - */ - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.detect_rename = 0; - diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - paths[0] = origin->path; - paths[1] = NULL; - - parse_pathspec(&diff_opts.pathspec, - PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, - PATHSPEC_LITERAL_PATH, "", paths); - diff_setup_done(&diff_opts); - - if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(parent->tree->object.oid.hash, &diff_opts); - else - diff_tree_sha1(parent->tree->object.oid.hash, - origin->commit->tree->object.oid.hash, - "", &diff_opts); - diffcore_std(&diff_opts); - - if (!diff_queued_diff.nr) { - /* The path is the same as parent */ - porigin = get_origin(sb, parent, origin->path); - oidcpy(&porigin->blob_oid, &origin->blob_oid); - porigin->mode = origin->mode; - } else { - /* - * Since origin->path is a pathspec, if the parent - * commit had it as a directory, we will see a whole - * bunch of deletion of files in the directory that we - * do not care about. - */ - int i; - struct diff_filepair *p = NULL; - for (i = 0; i < diff_queued_diff.nr; i++) { - const char *name; - p = diff_queued_diff.queue[i]; - name = p->one->path ? p->one->path : p->two->path; - if (!strcmp(name, origin->path)) - break; - } - if (!p) - die("internal error in blame::find_origin"); - switch (p->status) { - default: - die("internal error in blame::find_origin (%c)", - p->status); - case 'M': - porigin = get_origin(sb, parent, origin->path); - oidcpy(&porigin->blob_oid, &p->one->oid); - porigin->mode = p->one->mode; - break; - case 'A': - case 'T': - /* Did not exist in parent, or type changed */ - break; - } - } - diff_flush(&diff_opts); - clear_pathspec(&diff_opts.pathspec); - return porigin; -} - -/* - * We have an origin -- find the path that corresponds to it in its - * parent and return an origin structure to represent it. - */ -static struct origin *find_rename(struct scoreboard *sb, - struct commit *parent, - struct origin *origin) -{ - struct origin *porigin = NULL; - struct diff_options diff_opts; - int i; - - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.detect_rename = DIFF_DETECT_RENAME; - diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_opts.single_follow = origin->path; - diff_setup_done(&diff_opts); - - if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(parent->tree->object.oid.hash, &diff_opts); - else - diff_tree_sha1(parent->tree->object.oid.hash, - origin->commit->tree->object.oid.hash, - "", &diff_opts); - diffcore_std(&diff_opts); - - for (i = 0; i < diff_queued_diff.nr; i++) { - struct diff_filepair *p = diff_queued_diff.queue[i]; - if ((p->status == 'R' || p->status == 'C') && - !strcmp(p->two->path, origin->path)) { - porigin = get_origin(sb, parent, p->one->path); - oidcpy(&porigin->blob_oid, &p->one->oid); - porigin->mode = p->one->mode; - break; - } - } - diff_flush(&diff_opts); - clear_pathspec(&diff_opts.pathspec); - return porigin; -} - -/* - * Append a new blame entry to a given output queue. - */ -static void add_blame_entry(struct blame_entry ***queue, - const struct blame_entry *src) -{ - struct blame_entry *e = xmalloc(sizeof(*e)); - memcpy(e, src, sizeof(*e)); - origin_incref(e->suspect); - - e->next = **queue; - **queue = e; - *queue = &e->next; -} - -/* - * src typically is on-stack; we want to copy the information in it to - * a malloced blame_entry that gets added to the given queue. The - * origin of dst loses a refcnt. - */ -static void dup_entry(struct blame_entry ***queue, - struct blame_entry *dst, struct blame_entry *src) -{ - origin_incref(src->suspect); - origin_decref(dst->suspect); - memcpy(dst, src, sizeof(*src)); - dst->next = **queue; - **queue = dst; - *queue = &dst->next; -} - -static const char *nth_line(struct scoreboard *sb, long lno) -{ - return sb->final_buf + sb->lineno[lno]; -} - -static const char *nth_line_cb(void *data, long lno) -{ - return nth_line((struct scoreboard *)data, lno); -} - -/* - * It is known that lines between tlno to same came from parent, and e - * has an overlap with that range. it also is known that parent's - * line plno corresponds to e's line tlno. - * - * <---- e -----> - * <------> - * <------------> - * <------------> - * <------------------> - * - * Split e into potentially three parts; before this chunk, the chunk - * to be blamed for the parent, and after that portion. - */ -static void split_overlap(struct blame_entry *split, - struct blame_entry *e, - int tlno, int plno, int same, - struct origin *parent) -{ - int chunk_end_lno; - memset(split, 0, sizeof(struct blame_entry [3])); - - if (e->s_lno < tlno) { - /* there is a pre-chunk part not blamed on parent */ - split[0].suspect = origin_incref(e->suspect); - split[0].lno = e->lno; - split[0].s_lno = e->s_lno; - split[0].num_lines = tlno - e->s_lno; - split[1].lno = e->lno + tlno - e->s_lno; - split[1].s_lno = plno; - } - else { - split[1].lno = e->lno; - split[1].s_lno = plno + (e->s_lno - tlno); - } - - if (same < e->s_lno + e->num_lines) { - /* there is a post-chunk part not blamed on parent */ - split[2].suspect = origin_incref(e->suspect); - split[2].lno = e->lno + (same - e->s_lno); - split[2].s_lno = e->s_lno + (same - e->s_lno); - split[2].num_lines = e->s_lno + e->num_lines - same; - chunk_end_lno = split[2].lno; - } - else - chunk_end_lno = e->lno + e->num_lines; - split[1].num_lines = chunk_end_lno - split[1].lno; - - /* - * if it turns out there is nothing to blame the parent for, - * forget about the splitting. !split[1].suspect signals this. - */ - if (split[1].num_lines < 1) - return; - split[1].suspect = origin_incref(parent); -} - -/* - * split_overlap() divided an existing blame e into up to three parts - * in split. Any assigned blame is moved to queue to - * reflect the split. - */ -static void split_blame(struct blame_entry ***blamed, - struct blame_entry ***unblamed, - struct blame_entry *split, - struct blame_entry *e) -{ - if (split[0].suspect && split[2].suspect) { - /* The first part (reuse storage for the existing entry e) */ - dup_entry(unblamed, e, &split[0]); - - /* The last part -- me */ - add_blame_entry(unblamed, &split[2]); - - /* ... and the middle part -- parent */ - add_blame_entry(blamed, &split[1]); - } - else if (!split[0].suspect && !split[2].suspect) - /* - * The parent covers the entire area; reuse storage for - * e and replace it with the parent. - */ - dup_entry(blamed, e, &split[1]); - else if (split[0].suspect) { - /* me and then parent */ - dup_entry(unblamed, e, &split[0]); - add_blame_entry(blamed, &split[1]); - } - else { - /* parent and then me */ - dup_entry(blamed, e, &split[1]); - add_blame_entry(unblamed, &split[2]); - } -} - -/* - * After splitting the blame, the origins used by the - * on-stack blame_entry should lose one refcnt each. - */ -static void decref_split(struct blame_entry *split) -{ - int i; - - for (i = 0; i < 3; i++) - origin_decref(split[i].suspect); -} - -/* - * reverse_blame reverses the list given in head, appending tail. - * That allows us to build lists in reverse order, then reverse them - * afterwards. This can be faster than building the list in proper - * order right away. The reason is that building in proper order - * requires writing a link in the _previous_ element, while building - * in reverse order just requires placing the list head into the - * _current_ element. - */ - -static struct blame_entry *reverse_blame(struct blame_entry *head, - struct blame_entry *tail) -{ - while (head) { - struct blame_entry *next = head->next; - head->next = tail; - tail = head; - head = next; - } - return tail; -} - -/* - * Process one hunk from the patch between the current suspect for - * blame_entry e and its parent. This first blames any unfinished - * entries before the chunk (which is where target and parent start - * differing) on the parent, and then splits blame entries at the - * start and at the end of the difference region. Since use of -M and - * -C options may lead to overlapping/duplicate source line number - * ranges, all we can rely on from sorting/merging is the order of the - * first suspect line number. - */ -static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq, - int tlno, int offset, int same, - struct origin *parent) -{ - struct blame_entry *e = **srcq; - struct blame_entry *samep = NULL, *diffp = NULL; - - while (e && e->s_lno < tlno) { - struct blame_entry *next = e->next; - /* - * current record starts before differing portion. If - * it reaches into it, we need to split it up and - * examine the second part separately. - */ - if (e->s_lno + e->num_lines > tlno) { - /* Move second half to a new record */ - int len = tlno - e->s_lno; - struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry)); - n->suspect = e->suspect; - n->lno = e->lno + len; - n->s_lno = e->s_lno + len; - n->num_lines = e->num_lines - len; - e->num_lines = len; - e->score = 0; - /* Push new record to diffp */ - n->next = diffp; - diffp = n; - } else - origin_decref(e->suspect); - /* Pass blame for everything before the differing - * chunk to the parent */ - e->suspect = origin_incref(parent); - e->s_lno += offset; - e->next = samep; - samep = e; - e = next; - } - /* - * As we don't know how much of a common stretch after this - * diff will occur, the currently blamed parts are all that we - * can assign to the parent for now. - */ - - if (samep) { - **dstq = reverse_blame(samep, **dstq); - *dstq = &samep->next; - } - /* - * Prepend the split off portions: everything after e starts - * after the blameable portion. - */ - e = reverse_blame(diffp, e); - - /* - * Now retain records on the target while parts are different - * from the parent. - */ - samep = NULL; - diffp = NULL; - while (e && e->s_lno < same) { - struct blame_entry *next = e->next; - - /* - * If current record extends into sameness, need to split. - */ - if (e->s_lno + e->num_lines > same) { - /* - * Move second half to a new record to be - * processed by later chunks - */ - int len = same - e->s_lno; - struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry)); - n->suspect = origin_incref(e->suspect); - n->lno = e->lno + len; - n->s_lno = e->s_lno + len; - n->num_lines = e->num_lines - len; - e->num_lines = len; - e->score = 0; - /* Push new record to samep */ - n->next = samep; - samep = n; - } - e->next = diffp; - diffp = e; - e = next; - } - **srcq = reverse_blame(diffp, reverse_blame(samep, e)); - /* Move across elements that are in the unblamable portion */ - if (diffp) - *srcq = &diffp->next; -} - -struct blame_chunk_cb_data { - struct origin *parent; - long offset; - struct blame_entry **dstq; - struct blame_entry **srcq; -}; - -/* diff chunks are from parent to target */ -static int blame_chunk_cb(long start_a, long count_a, - long start_b, long count_b, void *data) -{ - struct blame_chunk_cb_data *d = data; - if (start_a - start_b != d->offset) - die("internal error in blame::blame_chunk_cb"); - blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b, - start_b + count_b, d->parent); - d->offset = start_a + count_a - (start_b + count_b); - return 0; -} - -/* - * We are looking at the origin 'target' and aiming to pass blame - * for the lines it is suspected to its parent. Run diff to find - * which lines came from parent and pass blame for them. - */ -static void pass_blame_to_parent(struct scoreboard *sb, - struct origin *target, - struct origin *parent) -{ - mmfile_t file_p, file_o; - struct blame_chunk_cb_data d; - struct blame_entry *newdest = NULL; - - if (!target->suspects) - return; /* nothing remains for this target */ - - d.parent = parent; - d.offset = 0; - d.dstq = &newdest; d.srcq = &target->suspects; - - fill_origin_blob(&sb->revs->diffopt, parent, &file_p); - fill_origin_blob(&sb->revs->diffopt, target, &file_o); - num_get_patch++; - - if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d)) - die("unable to generate diff (%s -> %s)", - oid_to_hex(&parent->commit->object.oid), - oid_to_hex(&target->commit->object.oid)); - /* The rest are the same as the parent */ - blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent); - *d.dstq = NULL; - queue_blames(sb, parent, newdest); - - return; -} - -/* - * The lines in blame_entry after splitting blames many times can become - * very small and trivial, and at some point it becomes pointless to - * blame the parents. E.g. "\t\t}\n\t}\n\n" appears everywhere in any - * ordinary C program, and it is not worth to say it was copied from - * totally unrelated file in the parent. - * - * Compute how trivial the lines in the blame_entry are. - */ -static unsigned ent_score(struct scoreboard *sb, struct blame_entry *e) -{ - unsigned score; - const char *cp, *ep; - - if (e->score) - return e->score; - - score = 1; - cp = nth_line(sb, e->lno); - ep = nth_line(sb, e->lno + e->num_lines); - while (cp < ep) { - unsigned ch = *((unsigned char *)cp); - if (isalnum(ch)) - score++; - cp++; - } - e->score = score; - return score; -} - -/* - * best_so_far[] and this[] are both a split of an existing blame_entry - * that passes blame to the parent. Maintain best_so_far the best split - * so far, by comparing this and best_so_far and copying this into - * bst_so_far as needed. - */ -static void copy_split_if_better(struct scoreboard *sb, - struct blame_entry *best_so_far, - struct blame_entry *this) -{ - int i; - - if (!this[1].suspect) - return; - if (best_so_far[1].suspect) { - if (ent_score(sb, &this[1]) < ent_score(sb, &best_so_far[1])) - return; - } - - for (i = 0; i < 3; i++) - origin_incref(this[i].suspect); - decref_split(best_so_far); - memcpy(best_so_far, this, sizeof(struct blame_entry [3])); -} - -/* - * We are looking at a part of the final image represented by - * ent (tlno and same are offset by ent->s_lno). - * tlno is where we are looking at in the final image. - * up to (but not including) same match preimage. - * plno is where we are looking at in the preimage. - * - * <-------------- final image ----------------------> - * <------ent------> - * ^tlno ^same - * <---------preimage-----> - * ^plno - * - * All line numbers are 0-based. - */ -static void handle_split(struct scoreboard *sb, - struct blame_entry *ent, - int tlno, int plno, int same, - struct origin *parent, - struct blame_entry *split) -{ - if (ent->num_lines <= tlno) - return; - if (tlno < same) { - struct blame_entry this[3]; - tlno += ent->s_lno; - same += ent->s_lno; - split_overlap(this, ent, tlno, plno, same, parent); - copy_split_if_better(sb, split, this); - decref_split(this); - } -} - -struct handle_split_cb_data { - struct scoreboard *sb; - struct blame_entry *ent; - struct origin *parent; - struct blame_entry *split; - long plno; - long tlno; -}; - -static int handle_split_cb(long start_a, long count_a, - long start_b, long count_b, void *data) -{ - struct handle_split_cb_data *d = data; - handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent, - d->split); - d->plno = start_a + count_a; - d->tlno = start_b + count_b; - return 0; -} - -/* - * Find the lines from parent that are the same as ent so that - * we can pass blames to it. file_p has the blob contents for - * the parent. - */ -static void find_copy_in_blob(struct scoreboard *sb, - struct blame_entry *ent, - struct origin *parent, - struct blame_entry *split, - mmfile_t *file_p) -{ - const char *cp; - mmfile_t file_o; - struct handle_split_cb_data d; - - memset(&d, 0, sizeof(d)); - d.sb = sb; d.ent = ent; d.parent = parent; d.split = split; - /* - * Prepare mmfile that contains only the lines in ent. - */ - cp = nth_line(sb, ent->lno); - file_o.ptr = (char *) cp; - file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp; - - /* - * file_o is a part of final image we are annotating. - * file_p partially may match that image. - */ - memset(split, 0, sizeof(struct blame_entry [3])); - if (diff_hunks(file_p, &file_o, handle_split_cb, &d)) - die("unable to generate diff (%s)", - oid_to_hex(&parent->commit->object.oid)); - /* remainder, if any, all match the preimage */ - handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split); -} - -/* Move all blame entries from list *source that have a score smaller - * than score_min to the front of list *small. - * Returns a pointer to the link pointing to the old head of the small list. - */ - -static struct blame_entry **filter_small(struct scoreboard *sb, - struct blame_entry **small, - struct blame_entry **source, - unsigned score_min) -{ - struct blame_entry *p = *source; - struct blame_entry *oldsmall = *small; - while (p) { - if (ent_score(sb, p) <= score_min) { - *small = p; - small = &p->next; - p = *small; - } else { - *source = p; - source = &p->next; - p = *source; - } - } - *small = oldsmall; - *source = NULL; - return small; -} - -/* - * See if lines currently target is suspected for can be attributed to - * parent. - */ -static void find_move_in_parent(struct scoreboard *sb, - struct blame_entry ***blamed, - struct blame_entry **toosmall, - struct origin *target, - struct origin *parent) -{ - struct blame_entry *e, split[3]; - struct blame_entry *unblamed = target->suspects; - struct blame_entry *leftover = NULL; - mmfile_t file_p; - - if (!unblamed) - return; /* nothing remains for this target */ - - fill_origin_blob(&sb->revs->diffopt, parent, &file_p); - if (!file_p.ptr) - return; +static unsigned blame_move_score; +static unsigned blame_copy_score; - /* At each iteration, unblamed has a NULL-terminated list of - * entries that have not yet been tested for blame. leftover - * contains the reversed list of entries that have been tested - * without being assignable to the parent. - */ - do { - struct blame_entry **unblamedtail = &unblamed; - struct blame_entry *next; - for (e = unblamed; e; e = next) { - next = e->next; - find_copy_in_blob(sb, e, parent, split, &file_p); - if (split[1].suspect && - blame_move_score < ent_score(sb, &split[1])) { - split_blame(blamed, &unblamedtail, split, e); - } else { - e->next = leftover; - leftover = e; - } - decref_split(split); - } - *unblamedtail = NULL; - toosmall = filter_small(sb, toosmall, &unblamed, blame_move_score); - } while (unblamed); - target->suspects = reverse_blame(leftover, NULL); -} +/* Remember to update object flag allocation in object.h */ +#define METAINFO_SHOWN (1u<<12) +#define MORE_THAN_ONE_PATH (1u<<13) -struct blame_list { - struct blame_entry *ent; - struct blame_entry split[3]; +struct progress_info { + struct progress *progress; + int blamed_lines; }; -/* - * Count the number of entries the target is suspected for, - * and prepare a list of entry and the best split. - */ -static struct blame_list *setup_blame_list(struct blame_entry *unblamed, - int *num_ents_p) -{ - struct blame_entry *e; - int num_ents, i; - struct blame_list *blame_list = NULL; - - for (e = unblamed, num_ents = 0; e; e = e->next) - num_ents++; - if (num_ents) { - blame_list = xcalloc(num_ents, sizeof(struct blame_list)); - for (e = unblamed, i = 0; e; e = e->next) - blame_list[i++].ent = e; - } - *num_ents_p = num_ents; - return blame_list; -} - -/* - * For lines target is suspected for, see if we can find code movement - * across file boundary from the parent commit. porigin is the path - * in the parent we already tried. - */ -static void find_copy_in_parent(struct scoreboard *sb, - struct blame_entry ***blamed, - struct blame_entry **toosmall, - struct origin *target, - struct commit *parent, - struct origin *porigin, - int opt) -{ - struct diff_options diff_opts; - int i, j; - struct blame_list *blame_list; - int num_ents; - struct blame_entry *unblamed = target->suspects; - struct blame_entry *leftover = NULL; - - if (!unblamed) - return; /* nothing remains for this target */ - - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - - diff_setup_done(&diff_opts); - - /* Try "find copies harder" on new path if requested; - * we do not want to use diffcore_rename() actually to - * match things up; find_copies_harder is set only to - * force diff_tree_sha1() to feed all filepairs to diff_queue, - * and this code needs to be after diff_setup_done(), which - * usually makes find-copies-harder imply copy detection. - */ - if ((opt & PICKAXE_BLAME_COPY_HARDEST) - || ((opt & PICKAXE_BLAME_COPY_HARDER) - && (!porigin || strcmp(target->path, porigin->path)))) - DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); - - if (is_null_oid(&target->commit->object.oid)) - do_diff_cache(parent->tree->object.oid.hash, &diff_opts); - else - diff_tree_sha1(parent->tree->object.oid.hash, - target->commit->tree->object.oid.hash, - "", &diff_opts); - - if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER)) - diffcore_std(&diff_opts); - - do { - struct blame_entry **unblamedtail = &unblamed; - blame_list = setup_blame_list(unblamed, &num_ents); - - for (i = 0; i < diff_queued_diff.nr; i++) { - struct diff_filepair *p = diff_queued_diff.queue[i]; - struct origin *norigin; - mmfile_t file_p; - struct blame_entry this[3]; - - if (!DIFF_FILE_VALID(p->one)) - continue; /* does not exist in parent */ - if (S_ISGITLINK(p->one->mode)) - continue; /* ignore git links */ - if (porigin && !strcmp(p->one->path, porigin->path)) - /* find_move already dealt with this path */ - continue; - - norigin = get_origin(sb, parent, p->one->path); - oidcpy(&norigin->blob_oid, &p->one->oid); - norigin->mode = p->one->mode; - fill_origin_blob(&sb->revs->diffopt, norigin, &file_p); - if (!file_p.ptr) - continue; - - for (j = 0; j < num_ents; j++) { - find_copy_in_blob(sb, blame_list[j].ent, - norigin, this, &file_p); - copy_split_if_better(sb, blame_list[j].split, - this); - decref_split(this); - } - origin_decref(norigin); - } - - for (j = 0; j < num_ents; j++) { - struct blame_entry *split = blame_list[j].split; - if (split[1].suspect && - blame_copy_score < ent_score(sb, &split[1])) { - split_blame(blamed, &unblamedtail, split, - blame_list[j].ent); - } else { - blame_list[j].ent->next = leftover; - leftover = blame_list[j].ent; - } - decref_split(split); - } - free(blame_list); - *unblamedtail = NULL; - toosmall = filter_small(sb, toosmall, &unblamed, blame_copy_score); - } while (unblamed); - target->suspects = reverse_blame(leftover, NULL); - diff_flush(&diff_opts); - clear_pathspec(&diff_opts.pathspec); -} - -/* - * The blobs of origin and porigin exactly match, so everything - * origin is suspected for can be blamed on the parent. - */ -static void pass_whole_blame(struct scoreboard *sb, - struct origin *origin, struct origin *porigin) -{ - struct blame_entry *e, *suspects; - - if (!porigin->file.ptr && origin->file.ptr) { - /* Steal its file */ - porigin->file = origin->file; - origin->file.ptr = NULL; - } - suspects = origin->suspects; - origin->suspects = NULL; - for (e = suspects; e; e = e->next) { - origin_incref(porigin); - origin_decref(e->suspect); - e->suspect = porigin; - } - queue_blames(sb, porigin, suspects); -} - -/* - * We pass blame from the current commit to its parents. We keep saying - * "parent" (and "porigin"), but what we mean is to find scapegoat to - * exonerate ourselves. - */ -static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit) -{ - if (!reverse) { - if (revs->first_parent_only && - commit->parents && - commit->parents->next) { - free_commit_list(commit->parents->next); - commit->parents->next = NULL; - } - return commit->parents; - } - return lookup_decoration(&revs->children, &commit->object); -} - -static int num_scapegoats(struct rev_info *revs, struct commit *commit) -{ - struct commit_list *l = first_scapegoat(revs, commit); - return commit_list_count(l); -} - -/* Distribute collected unsorted blames to the respected sorted lists - * in the various origins. - */ -static void distribute_blame(struct scoreboard *sb, struct blame_entry *blamed) -{ - blamed = blame_sort(blamed, compare_blame_suspect); - while (blamed) - { - struct origin *porigin = blamed->suspect; - struct blame_entry *suspects = NULL; - do { - struct blame_entry *next = blamed->next; - blamed->next = suspects; - suspects = blamed; - blamed = next; - } while (blamed && blamed->suspect == porigin); - suspects = reverse_blame(suspects, NULL); - queue_blames(sb, porigin, suspects); - } -} - -#define MAXSG 16 - -static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) +static const char *nth_line_cb(void *data, long lno) { - struct rev_info *revs = sb->revs; - int i, pass, num_sg; - struct commit *commit = origin->commit; - struct commit_list *sg; - struct origin *sg_buf[MAXSG]; - struct origin *porigin, **sg_origin = sg_buf; - struct blame_entry *toosmall = NULL; - struct blame_entry *blames, **blametail = &blames; - - num_sg = num_scapegoats(revs, commit); - if (!num_sg) - goto finish; - else if (num_sg < ARRAY_SIZE(sg_buf)) - memset(sg_buf, 0, sizeof(sg_buf)); - else - sg_origin = xcalloc(num_sg, sizeof(*sg_origin)); - - /* - * The first pass looks for unrenamed path to optimize for - * common cases, then we look for renames in the second pass. - */ - for (pass = 0; pass < 2 - no_whole_file_rename; pass++) { - struct origin *(*find)(struct scoreboard *, - struct commit *, struct origin *); - find = pass ? find_rename : find_origin; - - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct commit *p = sg->item; - int j, same; - - if (sg_origin[i]) - continue; - if (parse_commit(p)) - continue; - porigin = find(sb, p, origin); - if (!porigin) - continue; - if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) { - pass_whole_blame(sb, origin, porigin); - origin_decref(porigin); - goto finish; - } - for (j = same = 0; j < i; j++) - if (sg_origin[j] && - !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) { - same = 1; - break; - } - if (!same) - sg_origin[i] = porigin; - else - origin_decref(porigin); - } - } - - num_commits++; - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct origin *porigin = sg_origin[i]; - if (!porigin) - continue; - if (!origin->previous) { - origin_incref(porigin); - origin->previous = porigin; - } - pass_blame_to_parent(sb, origin, porigin); - if (!origin->suspects) - goto finish; - } - - /* - * Optionally find moves in parents' files. - */ - if (opt & PICKAXE_BLAME_MOVE) { - filter_small(sb, &toosmall, &origin->suspects, blame_move_score); - if (origin->suspects) { - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct origin *porigin = sg_origin[i]; - if (!porigin) - continue; - find_move_in_parent(sb, &blametail, &toosmall, origin, porigin); - if (!origin->suspects) - break; - } - } - } - - /* - * Optionally find copies from parents' files. - */ - if (opt & PICKAXE_BLAME_COPY) { - if (blame_copy_score > blame_move_score) - filter_small(sb, &toosmall, &origin->suspects, blame_copy_score); - else if (blame_copy_score < blame_move_score) { - origin->suspects = blame_merge(origin->suspects, toosmall); - toosmall = NULL; - filter_small(sb, &toosmall, &origin->suspects, blame_copy_score); - } - if (!origin->suspects) - goto finish; - - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct origin *porigin = sg_origin[i]; - find_copy_in_parent(sb, &blametail, &toosmall, - origin, sg->item, porigin, opt); - if (!origin->suspects) - goto finish; - } - } - -finish: - *blametail = NULL; - distribute_blame(sb, blames); - /* - * prepend toosmall to origin->suspects - * - * There is no point in sorting: this ends up on a big - * unsorted list in the caller anyway. - */ - if (toosmall) { - struct blame_entry **tail = &toosmall; - while (*tail) - tail = &(*tail)->next; - *tail = origin->suspects; - origin->suspects = toosmall; - } - for (i = 0; i < num_sg; i++) { - if (sg_origin[i]) { - drop_origin_blob(sg_origin[i]); - origin_decref(sg_origin[i]); - } - } - drop_origin_blob(origin); - if (sg_buf != sg_origin) - free(sg_origin); + return blame_nth_line((struct blame_scoreboard *)data, lno); } /* @@@@ -78,13 -78,13 -1562,13 +79,13 @@@@ struct commit_info { struct strbuf author; struct strbuf author_mail; - unsigned long author_time; + timestamp_t author_time; struct strbuf author_tz; /* filled only when asked for details */ struct strbuf committer; struct strbuf committer_mail; - unsigned long committer_time; + timestamp_t committer_time; struct strbuf committer_tz; struct strbuf summary; @@@@ -95,7 -95,7 -1579,7 +96,7 @@@@ */ static void get_ac_line(const char *inbuf, const char *what, struct strbuf *name, struct strbuf *mail, - unsigned long *time, struct strbuf *tz) + timestamp_t *time, struct strbuf *tz) { struct ident_split ident; size_t len, maillen, namelen; @@@@ -216,10 -216,10 -1700,10 +217,10 @@@@ static void get_commit_info(struct comm * To allow LF and other nonportable characters in pathnames, * they are c-style quoted as needed. */ -static void write_filename_info(struct origin *suspect) +static void write_filename_info(struct blame_origin *suspect) { if (suspect->previous) { - struct origin *prev = suspect->previous; + struct blame_origin *prev = suspect->previous; printf("previous %s ", oid_to_hex(&prev->commit->object.oid)); write_name_quoted(prev->path, stdout, '\n'); } @@@@ -233,7 -233,7 -1717,7 +234,7 @@@@ * the first time each commit appears in the output (unless the * user has specifically asked for us to repeat). */ -static int emit_one_suspect_detail(struct origin *suspect, int repeat) +static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat) { struct commit_info ci; @@@@ -244,11 -244,11 -1728,11 +245,11 @@@@ get_commit_info(suspect->commit, &ci, 1); printf("author %s\n", ci.author.buf); printf("author-mail %s\n", ci.author_mail.buf); - printf("author-time %lu\n", ci.author_time); + printf("author-time %"PRItime"\n", ci.author_time); printf("author-tz %s\n", ci.author_tz.buf); printf("committer %s\n", ci.committer.buf); printf("committer-mail %s\n", ci.committer_mail.buf); - printf("committer-time %lu\n", ci.committer_time); + printf("committer-time %"PRItime"\n", ci.committer_time); printf("committer-tz %s\n", ci.committer_tz.buf); printf("summary %s\n", ci.summary.buf); if (suspect->commit->object.flags & UNINTERESTING) @@@@ -263,12 -263,12 -1747,11 +264,12 @@@@ * The blame_entry is found to be guilty for the range. * Show it in incremental output. */ -static void found_guilty_entry(struct blame_entry *ent, - struct progress_info *pi) +static void found_guilty_entry(struct blame_entry *ent, void *data) { + struct progress_info *pi = (struct progress_info *)data; + if (incremental) { - struct origin *suspect = ent->suspect; + struct blame_origin *suspect = ent->suspect; printf("%s %d %d %d\n", oid_to_hex(&suspect->commit->object.oid), @@@@ -281,14 -281,14 -1764,88 +282,14 @@@@ display_progress(pi->progress, pi->blamed_lines); } -/* - * The main loop -- while we have blobs with lines whose true origin - * is still unknown, pick one blob, and allow its lines to pass blames - * to its parents. */ -static void assign_blame(struct scoreboard *sb, int opt) -{ - struct rev_info *revs = sb->revs; - struct commit *commit = prio_queue_get(&sb->commits); - struct progress_info pi = { NULL, 0 }; - - if (show_progress) - pi.progress = start_progress_delay(_("Blaming lines"), - sb->num_lines, 50, 1); - - while (commit) { - struct blame_entry *ent; - struct origin *suspect = commit->util; - - /* find one suspect to break down */ - while (suspect && !suspect->suspects) - suspect = suspect->next; - - if (!suspect) { - commit = prio_queue_get(&sb->commits); - continue; - } - - assert(commit == suspect->commit); - - /* - * We will use this suspect later in the loop, - * so hold onto it in the meantime. - */ - origin_incref(suspect); - parse_commit(commit); - if (reverse || - (!(commit->object.flags & UNINTERESTING) && - !(revs->max_age != -1 && commit->date < revs->max_age))) - pass_blame(sb, suspect, opt); - else { - commit->object.flags |= UNINTERESTING; - if (commit->object.parsed) - mark_parents_uninteresting(commit); - } - /* treat root commit as boundary */ - if (!commit->parents && !show_root) - commit->object.flags |= UNINTERESTING; - - /* Take responsibility for the remaining entries */ - ent = suspect->suspects; - if (ent) { - suspect->guilty = 1; - for (;;) { - struct blame_entry *next = ent->next; - found_guilty_entry(ent, &pi); - if (next) { - ent = next; - continue; - } - ent->next = sb->ent; - sb->ent = suspect->suspects; - suspect->suspects = NULL; - break; - } - } - origin_decref(suspect); - - if (DEBUG) /* sanity */ - sanity_check_refcnt(sb); - } - - stop_progress(&pi.progress); -} - -static const char *format_time(unsigned long time, const char *tz_str, +static const char *format_time(timestamp_t time, const char *tz_str, int show_raw_time) { static struct strbuf time_buf = STRBUF_INIT; strbuf_reset(&time_buf); if (show_raw_time) { - strbuf_addf(&time_buf, "%lu %s", time, tz_str); + strbuf_addf(&time_buf, "%"PRItime" %s", time, tz_str); } else { const char *time_str; @@@@ -320,20 -320,20 -1877,20 +321,20 @@@@ #define OUTPUT_SHOW_EMAIL 0400 #define OUTPUT_LINE_PORCELAIN 01000 -static void emit_porcelain_details(struct origin *suspect, int repeat) +static void emit_porcelain_details(struct blame_origin *suspect, int repeat) { if (emit_one_suspect_detail(suspect, repeat) || (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) write_filename_info(suspect); } -static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, +static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, int opt) { int repeat = opt & OUTPUT_LINE_PORCELAIN; int cnt; const char *cp; - struct origin *suspect = ent->suspect; + struct blame_origin *suspect = ent->suspect; char hex[GIT_MAX_HEXSZ + 1]; oid_to_hex_r(hex, &suspect->commit->object.oid); @@@@ -344,7 -344,7 -1901,7 +345,7 @@@@ ent->num_lines); emit_porcelain_details(suspect, repeat); - cp = nth_line(sb, ent->lno); + cp = blame_nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; if (cnt) { @@@@ -366,11 -366,11 -1923,11 +367,11 @@@@ putchar('\n'); } -static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) +static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt) { int cnt; const char *cp; - struct origin *suspect = ent->suspect; + struct blame_origin *suspect = ent->suspect; struct commit_info ci; char hex[GIT_MAX_HEXSZ + 1]; int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP); @@@@ -378,7 -378,7 -1935,7 +379,7 @@@@ get_commit_info(suspect->commit, &ci, 1); oid_to_hex_r(hex, &suspect->commit->object.oid); - cp = nth_line(sb, ent->lno); + cp = blame_nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev; @@@@ -445,14 -445,14 -2002,14 +446,14 @@@@ commit_info_destroy(&ci); } -static void output(struct scoreboard *sb, int option) +static void output(struct blame_scoreboard *sb, int option) { struct blame_entry *ent; if (option & OUTPUT_PORCELAIN) { for (ent = sb->ent; ent; ent = ent->next) { int count = 0; - struct origin *suspect; + struct blame_origin *suspect; struct commit *commit = ent->suspect->commit; if (commit->object.flags & MORE_THAN_ONE_PATH) continue; @@@@ -474,6 -474,6 -2031,40 +475,6 @@@@ } } -static const char *get_next_line(const char *start, const char *end) -{ - const char *nl = memchr(start, '\n', end - start); - return nl ? nl + 1 : end; -} - -/* - * To allow quick access to the contents of nth line in the - * final image, prepare an index in the scoreboard. - */ -static int prepare_lines(struct scoreboard *sb) -{ - const char *buf = sb->final_buf; - unsigned long len = sb->final_buf_size; - const char *end = buf + len; - const char *p; - int *lineno; - int num = 0; - - for (p = buf; p < end; p = get_next_line(p, end)) - num++; - - ALLOC_ARRAY(sb->lineno, num + 1); - lineno = sb->lineno; - - for (p = buf; p < end; p = get_next_line(p, end)) - *lineno++ = p - buf; - - *lineno = len; - - sb->num_lines = num; - return sb->num_lines; -} - /* * Add phony grafts for use with -S; this is primarily to * support git's cvsserver that wants to give a linear history @@@@ -481,7 -481,7 -2072,7 +482,7 @@@@ */ static int read_ancestry(const char *graft_file) { -- FILE *fp = fopen(graft_file, "r"); ++ FILE *fp = fopen_or_warn(graft_file, "r"); struct strbuf buf = STRBUF_INIT; if (!fp) return -1; @@@@ -496,7 -496,7 -2087,7 +497,7 @@@@ return 0; } -static int update_auto_abbrev(int auto_abbrev, struct origin *suspect) +static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect) { const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash, auto_abbrev); @@@@ -510,7 -510,7 -2101,7 +511,7 @@@@ * How many columns do we need to show line numbers, authors, * and filenames? */ -static void find_alignment(struct scoreboard *sb, int *option) +static void find_alignment(struct blame_scoreboard *sb, int *option) { int longest_src_lines = 0; int longest_dst_lines = 0; @@@@ -520,7 -520,7 -2111,7 +521,7 @@@@ int auto_abbrev = DEFAULT_ABBREV; for (e = sb->ent; e; e = e->next) { - struct origin *suspect = e->suspect; + struct blame_origin *suspect = e->suspect; int num; if (compute_auto_abbrev) @@@@ -548,8 -548,8 -2139,8 +549,8 @@@@ num = e->lno + e->num_lines; if (longest_dst_lines < num) longest_dst_lines = num; - if (largest_score < ent_score(sb, e)) - largest_score = ent_score(sb, e); + if (largest_score < blame_entry_score(sb, e)) + largest_score = blame_entry_score(sb, e); } max_orig_digits = decimal_width(longest_src_lines); max_digits = decimal_width(longest_dst_lines); @@@@ -560,12 -560,12 -2151,31 +561,12 @@@@ abbrev = auto_abbrev + 1; } -/* - * For debugging -- origin is refcounted, and this asserts that - * we do not underflow. - */ -static void sanity_check_refcnt(struct scoreboard *sb) +static void sanity_check_on_fail(struct blame_scoreboard *sb, int baa) { - int baa = 0; - struct blame_entry *ent; - - for (ent = sb->ent; ent; ent = ent->next) { - /* Nobody should have zero or negative refcnt */ - if (ent->suspect->refcnt <= 0) { - fprintf(stderr, "%s in %s has negative refcnt %d\n", - ent->suspect->path, - oid_to_hex(&ent->suspect->commit->object.oid), - ent->suspect->refcnt); - baa = 1; - } - } - if (baa) { - int opt = 0160; - find_alignment(sb, &opt); - output(sb, opt); - die("Baa %d!", baa); - } + int opt = OUTPUT_SHOW_SCORE | OUTPUT_SHOW_NUMBER | OUTPUT_SHOW_NAME; + find_alignment(sb, &opt); + output(sb, opt); + die("Baa %d!", baa); } static unsigned parse_score(const char *arg) @@@@ -615,6 -615,6 -2225,301 +616,6 @@@@ static int git_blame_config(const char return git_default_config(var, value, cb); } -static void verify_working_tree_path(struct commit *work_tree, const char *path) -{ - struct commit_list *parents; - int pos; - - for (parents = work_tree->parents; parents; parents = parents->next) { - const struct object_id *commit_oid = &parents->item->object.oid; - struct object_id blob_oid; - unsigned mode; - - if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) && - sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB) - return; - } - - pos = cache_name_pos(path, strlen(path)); - if (pos >= 0) - ; /* path is in the index */ - else if (-1 - pos < active_nr && - !strcmp(active_cache[-1 - pos]->name, path)) - ; /* path is in the index, unmerged */ - else - die("no such path '%s' in HEAD", path); -} - -static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid) -{ - struct commit *parent; - - parent = lookup_commit_reference(oid->hash); - if (!parent) - die("no such commit %s", oid_to_hex(oid)); - return &commit_list_insert(parent, tail)->next; -} - -static void append_merge_parents(struct commit_list **tail) -{ - int merge_head; - struct strbuf line = STRBUF_INIT; - - merge_head = open(git_path_merge_head(), O_RDONLY); - if (merge_head < 0) { - if (errno == ENOENT) - return; - die("cannot open '%s' for reading", git_path_merge_head()); - } - - while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { - struct object_id oid; - if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid)) - die("unknown line in '%s': %s", git_path_merge_head(), line.buf); - tail = append_parent(tail, &oid); - } - close(merge_head); - strbuf_release(&line); -} - -/* - * This isn't as simple as passing sb->buf and sb->len, because we - * want to transfer ownership of the buffer to the commit (so we - * must use detach). - */ -static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb) -{ - size_t len; - void *buf = strbuf_detach(sb, &len); - set_commit_buffer(c, buf, len); -} - -/* - * Prepare a dummy commit that represents the work tree (or staged) item. - * Note that annotating work tree item never works in the reverse. - */ -static struct commit *fake_working_tree_commit(struct diff_options *opt, - const char *path, - const char *contents_from) -{ - struct commit *commit; - struct origin *origin; - struct commit_list **parent_tail, *parent; - struct object_id head_oid; - struct strbuf buf = STRBUF_INIT; - const char *ident; - time_t now; - int size, len; - struct cache_entry *ce; - unsigned mode; - struct strbuf msg = STRBUF_INIT; - - read_cache(); - time(&now); - commit = alloc_commit_node(); - commit->object.parsed = 1; - commit->date = now; - parent_tail = &commit->parents; - - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) - die("no such ref: HEAD"); - - parent_tail = append_parent(parent_tail, &head_oid); - append_merge_parents(parent_tail); - verify_working_tree_path(commit, path); - - origin = make_origin(commit, path); - - ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0); - strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n"); - for (parent = commit->parents; parent; parent = parent->next) - strbuf_addf(&msg, "parent %s\n", - oid_to_hex(&parent->item->object.oid)); - strbuf_addf(&msg, - "author %s\n" - "committer %s\n\n" - "Version of %s from %s\n", - ident, ident, path, - (!contents_from ? path : - (!strcmp(contents_from, "-") ? "standard input" : contents_from))); - set_commit_buffer_from_strbuf(commit, &msg); - - if (!contents_from || strcmp("-", contents_from)) { - struct stat st; - const char *read_from; - char *buf_ptr; - unsigned long buf_len; - - if (contents_from) { - if (stat(contents_from, &st) < 0) - die_errno("Cannot stat '%s'", contents_from); - read_from = contents_from; - } - else { - if (lstat(path, &st) < 0) - die_errno("Cannot lstat '%s'", path); - read_from = path; - } - mode = canon_mode(st.st_mode); - - switch (st.st_mode & S_IFMT) { - case S_IFREG: - if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && - textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len)) - strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1); - else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) - die_errno("cannot open or read '%s'", read_from); - break; - case S_IFLNK: - if (strbuf_readlink(&buf, read_from, st.st_size) < 0) - die_errno("cannot readlink '%s'", read_from); - break; - default: - die("unsupported file type %s", read_from); - } - } - else { - /* Reading from stdin */ - mode = 0; - if (strbuf_read(&buf, 0, 0) < 0) - die_errno("failed to read from stdin"); - } - convert_to_git(path, buf.buf, buf.len, &buf, 0); - origin->file.ptr = buf.buf; - origin->file.size = buf.len; - pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash); - - /* - * Read the current index, replace the path entry with - * origin->blob_sha1 without mucking with its mode or type - * bits; we are not going to write this index out -- we just - * want to run "diff-index --cached". - */ - discard_cache(); - read_cache(); - - len = strlen(path); - if (!mode) { - int pos = cache_name_pos(path, len); - if (0 <= pos) - mode = active_cache[pos]->ce_mode; - else - /* Let's not bother reading from HEAD tree */ - mode = S_IFREG | 0644; - } - size = cache_entry_size(len); - ce = xcalloc(1, size); - oidcpy(&ce->oid, &origin->blob_oid); - memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(0); - ce->ce_namelen = len; - ce->ce_mode = create_ce_mode(mode); - add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); - - cache_tree_invalidate_path(&the_index, path); - - return commit; -} - -static struct commit *find_single_final(struct rev_info *revs, - const char **name_p) -{ - int i; - struct commit *found = NULL; - const char *name = NULL; - - for (i = 0; i < revs->pending.nr; i++) { - struct object *obj = revs->pending.objects[i].item; - if (obj->flags & UNINTERESTING) - continue; - obj = deref_tag(obj, NULL, 0); - if (obj->type != OBJ_COMMIT) - die("Non commit %s?", revs->pending.objects[i].name); - if (found) - die("More than one commit to dig from %s and %s?", - revs->pending.objects[i].name, name); - found = (struct commit *)obj; - name = revs->pending.objects[i].name; - } - if (name_p) - *name_p = name; - return found; -} - -static char *prepare_final(struct scoreboard *sb) -{ - const char *name; - sb->final = find_single_final(sb->revs, &name); - return xstrdup_or_null(name); -} - -static const char *dwim_reverse_initial(struct scoreboard *sb) -{ - /* - * DWIM "git blame --reverse ONE -- PATH" as - * "git blame --reverse ONE..HEAD -- PATH" but only do so - * when it makes sense. - */ - struct object *obj; - struct commit *head_commit; - unsigned char head_sha1[20]; - - if (sb->revs->pending.nr != 1) - return NULL; - - /* Is that sole rev a committish? */ - obj = sb->revs->pending.objects[0].item; - obj = deref_tag(obj, NULL, 0); - if (obj->type != OBJ_COMMIT) - return NULL; - - /* Do we have HEAD? */ - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) - return NULL; - head_commit = lookup_commit_reference_gently(head_sha1, 1); - if (!head_commit) - return NULL; - - /* Turn "ONE" into "ONE..HEAD" then */ - obj->flags |= UNINTERESTING; - add_pending_object(sb->revs, &head_commit->object, "HEAD"); - - sb->final = (struct commit *)obj; - return sb->revs->pending.objects[0].name; -} - -static char *prepare_initial(struct scoreboard *sb) -{ - int i; - const char *final_commit_name = NULL; - struct rev_info *revs = sb->revs; - - /* - * There must be one and only one negative commit, and it must be - * the boundary. - */ - for (i = 0; i < revs->pending.nr; i++) { - struct object *obj = revs->pending.objects[i].item; - if (!(obj->flags & UNINTERESTING)) - continue; - obj = deref_tag(obj, NULL, 0); - if (obj->type != OBJ_COMMIT) - die("Non commit %s?", revs->pending.objects[i].name); - if (sb->final) - die("More than one commit to dig up from, %s and %s?", - revs->pending.objects[i].name, - final_commit_name); - sb->final = (struct commit *) obj; - final_commit_name = revs->pending.objects[i].name; - } - - if (!final_commit_name) - final_commit_name = dwim_reverse_initial(sb); - if (!final_commit_name) - die("No commit to dig up from?"); - return xstrdup(final_commit_name); -} - static int blame_copy_callback(const struct option *option, const char *arg, int unset) { int *opt = option->value; @@@@ -652,11 -652,11 -2557,13 +653,11 @@@@ int cmd_blame(int argc, const char **ar { struct rev_info revs; const char *path; - struct scoreboard sb; - struct origin *o; + struct blame_scoreboard sb; + struct blame_origin *o; struct blame_entry *ent = NULL; long dashdash_pos, lno; - char *final_commit_name = NULL; - enum object_type type; - struct commit *final_commit = NULL; + struct progress_info pi = { NULL, 0 }; struct string_list range_list = STRING_LIST_INIT_NODUP; int output_option = 0, opt = 0; @@@@ -782,15 -782,15 -2689,12 +783,15 @@@@ parse_done blame_date_width = sizeof("2006-10-19"); break; case DATE_RELATIVE: - /* TRANSLATORS: This string is used to tell us the maximum - display width for a relative timestamp in "git blame" - output. For C locale, "4 years, 11 months ago", which - takes 22 places, is the longest among various forms of - relative timestamps, but your language may need more or - fewer display columns. */ + /* + * TRANSLATORS: This string is used to tell us the + * maximum display width for a relative timestamp in + * "git blame" output. For C locale, "4 years, 11 + * months ago", which takes 22 places, is the longest + * among various forms of relative timestamps, but + * your language may need more or fewer display + * columns. + */ blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */ break; case DATE_NORMAL: @@@@ -806,6 -806,6 -2710,11 +807,6 @@@@ opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE | PICKAXE_BLAME_COPY_HARDER); - if (!blame_move_score) - blame_move_score = BLAME_DEFAULT_MOVE_SCORE; - if (!blame_copy_score) - blame_copy_score = BLAME_DEFAULT_COPY_SCORE; - /* * We have collected options unknown to us in argv[1..unk] * which are to be passed to revision machinery if we are @@@@ -858,13 -858,13 -2767,94 +859,13 @@@@ revs.disable_stdin = 1; setup_revisions(argc, argv, &revs, NULL); - memset(&sb, 0, sizeof(sb)); + init_scoreboard(&sb); sb.revs = &revs; - if (!reverse) { - final_commit_name = prepare_final(&sb); - sb.commits.compare = compare_commits_by_commit_date; - } - else if (contents_from) - die(_("--contents and --reverse do not blend well.")); - else { - final_commit_name = prepare_initial(&sb); - sb.commits.compare = compare_commits_by_reverse_commit_date; - if (revs.first_parent_only) - revs.children.name = NULL; - } - - if (!sb.final) { - /* - * "--not A B -- path" without anything positive; - * do not default to HEAD, but use the working tree - * or "--contents". - */ - setup_work_tree(); - sb.final = fake_working_tree_commit(&sb.revs->diffopt, - path, contents_from); - add_pending_object(&revs, &(sb.final->object), ":"); - } - else if (contents_from) - die(_("cannot use --contents with final commit object name")); - - if (reverse && revs.first_parent_only) { - final_commit = find_single_final(sb.revs, NULL); - if (!final_commit) - die(_("--reverse and --first-parent together require specified latest commit")); - } - - /* - * If we have bottom, this will mark the ancestors of the - * bottom commits we would reach while traversing as - * uninteresting. - */ - if (prepare_revision_walk(&revs)) - die(_("revision walk setup failed")); - - if (reverse && revs.first_parent_only) { - struct commit *c = final_commit; - - sb.revs->children.name = "children"; - while (c->parents && - oidcmp(&c->object.oid, &sb.final->object.oid)) { - struct commit_list *l = xcalloc(1, sizeof(*l)); - - l->item = c; - if (add_decoration(&sb.revs->children, - &c->parents->item->object, l)) - die("BUG: not unique item in first-parent chain"); - c = c->parents->item; - } - - if (oidcmp(&c->object.oid, &sb.final->object.oid)) - die(_("--reverse --first-parent together require range along first-parent chain")); - } - - if (is_null_oid(&sb.final->object.oid)) { - o = sb.final->util; - sb.final_buf = xmemdupz(o->file.ptr, o->file.size); - sb.final_buf_size = o->file.size; - } - else { - o = get_origin(&sb, sb.final, path); - if (fill_blob_sha1_and_mode(o)) - die(_("no such path %s in %s"), path, final_commit_name); - - if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) && - textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb.final_buf, - &sb.final_buf_size)) - ; - else - sb.final_buf = read_sha1_file(o->blob_oid.hash, &type, - &sb.final_buf_size); - - if (!sb.final_buf) - die(_("cannot read blob %s for path %s"), - oid_to_hex(&o->blob_oid), - path); - } - num_read_blob++; - lno = prepare_lines(&sb); + sb.contents_from = contents_from; + sb.reverse = reverse; + setup_scoreboard(&sb, path, &o); + lno = sb.num_lines; if (lno && !range_list.nr) string_list_append(&range_list, "1"); @@@@ -893,13 -893,13 -2883,22 +894,13 @@@@ for (range_i = ranges.nr; range_i > 0; --range_i) { const struct range *r = &ranges.ranges[range_i - 1]; - long bottom = r->start; - long top = r->end; - struct blame_entry *next = ent; - ent = xcalloc(1, sizeof(*ent)); - ent->lno = bottom; - ent->num_lines = top - bottom; - ent->suspect = o; - ent->s_lno = bottom; - ent->next = next; - origin_incref(o); + ent = blame_entry_prepend(ent, r->start, r->end, o); } o->suspects = ent; prio_queue_put(&sb.commits, o->commit); - origin_decref(o); + blame_origin_decref(o); range_set_release(&ranges); string_list_clear(&range_list, 0); @@@@ -907,38 -907,38 -2906,21 +908,38 @@@@ sb.ent = NULL; sb.path = path; + if (blame_move_score) + sb.move_score = blame_move_score; + if (blame_copy_score) + sb.copy_score = blame_copy_score; + + sb.debug = DEBUG; + sb.on_sanity_fail = &sanity_check_on_fail; + + sb.show_root = show_root; + sb.xdl_opts = xdl_opts; + sb.no_whole_file_rename = no_whole_file_rename; + read_mailmap(&mailmap, NULL); + sb.found_guilty_entry = &found_guilty_entry; + sb.found_guilty_entry_data = π + if (show_progress) + pi.progress = start_progress_delay(_("Blaming lines"), + sb.num_lines, 50, 1); + assign_blame(&sb, opt); + stop_progress(&pi.progress); + if (!incremental) setup_pager(); - - free(final_commit_name); - - if (incremental) + else return 0; - sb.ent = blame_sort(sb.ent, compare_blame_final); + blame_sort_final(&sb); - coalesce(&sb); + blame_coalesce(&sb); if (!(output_option & OUTPUT_PORCELAIN)) find_alignment(&sb, &output_option); @@@@ -952,9 -952,9 -2934,9 +953,9 @@@@ } if (show_stats) { - printf("num read blob: %d\n", num_read_blob); - printf("num get patch: %d\n", num_get_patch); - printf("num commits: %d\n", num_commits); + printf("num read blob: %d\n", sb.num_read_blob); + printf("num get patch: %d\n", sb.num_get_patch); + printf("num commits: %d\n", sb.num_commits); } return 0; } diff --combined builtin/branch.c index 83fcda43dc,83fcda43dc,50b59238d4..c958e93257 --- a/builtin/branch.c +++ b/builtin/branch.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "color.h" #include "refs.h" #include "commit.h" @@@@ -124,7 -124,7 -125,7 +125,7 @@@@ static int branch_merged(int kind, cons (reference_name = reference_name_to_free = resolve_refdup(upstream, RESOLVE_REF_READING, oid.hash, NULL)) != NULL) - reference_rev = lookup_commit_reference(oid.hash); + reference_rev = lookup_commit_reference(&oid); } if (!reference_rev) reference_rev = head_rev; @@@@ -157,7 -157,7 -158,7 +158,7 @@@@ static int check_branch_commit(const ch const struct object_id *oid, struct commit *head_rev, int kinds, int force) { - struct commit *rev = lookup_commit_reference(oid->hash); + struct commit *rev = lookup_commit_reference(oid); if (!rev) { error(_("Couldn't look up commit object for '%s'"), refname); return -1; @@@@ -211,7 -211,7 -212,7 +212,7 @@@@ static int delete_branches(int argc, co } if (!force) { - head_rev = lookup_commit_reference(head_oid.hash); + head_rev = lookup_commit_reference(&head_oid); if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } diff --combined builtin/cat-file.c index 4bffd7a2d8,4bffd7a2d8,12451205cf..7efbc4019a --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@@@ -4,8 -4,8 -4,8 +4,9 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "builtin.h" +#include "diff.h" #include "parse-options.h" #include "userdiff.h" #include "streaming.h" @@@@ -62,8 -62,8 -62,7 +63,8 @@@@ static int cat_one_file(int opt, const if (unknown_type) flags |= LOOKUP_UNKNOWN_OBJECT; - if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context)) + if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH, + oid.hash, &obj_context)) die("Not a valid object name %s", obj_name); if (!path) @@@@ -167,8 -167,8 -166,6 +168,8 @@@@ die("git cat-file %s: bad file", obj_name); write_or_die(1, buf, size); + free(buf); + free(obj_context.path); return 0; } diff --combined builtin/check-ignore.c index c7b8c08897,c7b8c08897,a2da09f4ae..3e280b9c7a --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@@@ -1,10 -1,10 -1,10 +1,11 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "dir.h" #include "quote.h" #include "pathspec.h" #include "parse-options.h" +#include "submodule.h" static int quiet, verbose, stdin_paths, show_non_matching, no_index; static const char * const check_ignore_usage[] = { @@@@ -88,23 -88,23 -88,21 +89,23 @@@@ static int check_ignore(struct dir_stru parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP, PATHSPEC_SYMLINK_LEADING_PATH | - PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE | PATHSPEC_KEEP_ORDER, prefix, argv); + die_path_inside_submodule(&the_index, &pathspec); + /* * look for pathspecs matching entries in the index, since these * should not be ignored, in order to be consistent with * 'git status', 'git add' etc. */ - seen = find_pathspecs_matching_against_index(&pathspec); + seen = find_pathspecs_matching_against_index(&pathspec, &the_index); for (i = 0; i < pathspec.nr; i++) { full_path = pathspec.items[i].match; exclude = NULL; if (!seen[i]) { - exclude = last_exclude_matching(dir, full_path, &dtype); + exclude = last_exclude_matching(dir, &the_index, + full_path, &dtype); } if (!quiet && (exclude || show_non_matching)) output_exclude(pathspec.items[i].original, exclude); diff --combined builtin/checkout.c index 1624eed7e7,a6b2af39d3,e0b58ddc0b..9661e1bcba --- a/builtin/checkout.c +++ b/builtin/checkout.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "builtin.h" ++ #include "config.h" #include "lockfile.h" #include "parse-options.h" #include "refs.h" @@@@ -21,12 -21,31 -22,31 +22,12 @@@@ #include "submodule-config.h" #include "submodule.h" --static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; -- static const char * const checkout_usage[] = { N_("git checkout [] "), N_("git checkout [] [] -- ..."), NULL, }; --static int option_parse_recurse_submodules(const struct option *opt, -- const char *arg, int unset) --{ -- if (unset) { -- recurse_submodules = RECURSE_SUBMODULES_OFF; -- return 0; -- } -- if (arg) -- recurse_submodules = -- parse_update_recurse_submodules_arg(opt->long_name, -- arg); -- else -- recurse_submodules = RECURSE_SUBMODULES_ON; -- -- return 0; --} -- struct checkout_opts { int patch_mode; int quiet; @@@@ -216,24 -235,24 -236,22 +217,24 @@@@ static int checkout_merged(int pos, con /* * NEEDSWORK: * There is absolutely no reason to write this as a blob object - * and create a phony cache entry just to leak. This hack is - * primarily to get to the write_entry() machinery that massages - * the contents to work-tree format and writes out which only - * allows it for a cache entry. The code in write_entry() needs - * to be refactored to allow us to feed a - * instead of a cache entry. Such a refactoring would help - * merge_recursive as well (it also writes the merge result to the - * object database even when it may contain conflicts). + * and create a phony cache entry. This hack is primarily to get + * to the write_entry() machinery that massages the contents to + * work-tree format and writes out which only allows it for a + * cache entry. The code in write_entry() needs to be refactored + * to allow us to feed a instead of a cache + * entry. Such a refactoring would help merge_recursive as well + * (it also writes the merge result to the object database even + * when it may contain conflicts). */ if (write_sha1_file(result_buf.ptr, result_buf.size, blob_type, oid.hash)) die(_("Unable to add merge result for '%s'"), path); + free(result_buf.ptr); ce = make_cache_entry(mode, oid.hash, path, 2, 0); if (!ce) die(_("make_cache_entry failed for path '%s'"), path); status = checkout_entry(ce, state, NULL); + free(ce); return status; } @@@@ -376,7 -395,7 -394,7 +377,7 @@@@ static int checkout_paths(const struct die(_("unable to write new index file")); read_ref_full("HEAD", 0, rev.hash, NULL); - head = lookup_commit_reference_gently(rev.hash, 1); + head = lookup_commit_reference_gently(&rev, 1); errs |= post_checkout_hook(head, head, 0); return errs; @@@@ -510,10 -529,10 -528,10 +511,10 @@@@ static int merge_working_tree(const str setup_standard_excludes(topts.dir); } tree = parse_tree_indirect(old->commit ? - old->commit->object.oid.hash : - EMPTY_TREE_SHA1_BIN); + &old->commit->object.oid : + &empty_tree_oid); init_tree_desc(&trees[0], tree->buffer, tree->size); - tree = parse_tree_indirect(new->commit->object.oid.hash); + tree = parse_tree_indirect(&new->commit->object.oid); init_tree_desc(&trees[1], tree->buffer, tree->size); ret = unpack_trees(2, trees, &topts); @@@@ -704,7 -723,7 -722,7 +705,7 @@@@ static int add_pending_uninteresting_re const struct object_id *oid, int flags, void *cb_data) { - add_pending_sha1(cb_data, refname, oid->hash, UNINTERESTING); + add_pending_oid(cb_data, refname, oid, UNINTERESTING); return 0; } @@@@ -790,7 -809,7 -808,7 +791,7 @@@@ static void orphaned_commit_warning(str add_pending_object(&revs, object, oid_to_hex(&object->oid)); for_each_ref(add_pending_uninteresting_ref, &revs); - add_pending_sha1(&revs, "HEAD", new->object.oid.hash, UNINTERESTING); + add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING); refs = revs.pending; revs.leak_pending = 1; @@@@ -816,8 -835,8 -834,7 +817,8 @@@@ static int switch_branches(const struc int flag, writeout_error = 0; memset(&old, 0, sizeof(old)); old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag); - old.commit = lookup_commit_reference_gently(rev.hash, 1); + if (old.path) + old.commit = lookup_commit_reference_gently(&rev, 1); if (!(flag & REF_ISSYMREF)) old.path = NULL; @@@@ -857,7 -876,7 -874,7 +858,7 @@@@ static int git_checkout_config(const ch } if (starts_with(var, "submodule.")) -- return parse_submodule_config_option(var, value); ++ return submodule_config(var, value, NULL); return git_xmerge_config(var, value, NULL); } @@@@ -1031,10 -1050,10 -1048,10 +1032,10 @@@@ static int parse_branchname_arg(int arg else new->path = NULL; /* not an existing branch */ - new->commit = lookup_commit_reference_gently(rev->hash, 1); + new->commit = lookup_commit_reference_gently(rev, 1); if (!new->commit) { /* not a commit */ - *source_tree = parse_tree_indirect(rev->hash); + *source_tree = parse_tree_indirect(rev); } else { parse_commit_or_die(new->commit); *source_tree = new->commit->tree; @@@@ -1165,9 -1184,9 -1182,9 +1166,9 @@@@ int cmd_checkout(int argc, const char * N_("second guess 'git checkout '")), OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees, N_("do not check if another worktree is holding the given ref")), -- { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, ++ { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "checkout", "control recursive updating of submodules", -- PARSE_OPT_OPTARG, option_parse_recurse_submodules }, ++ PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater }, OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")), OPT_END(), }; @@@@ -1198,6 -1217,12 -1215,12 +1199,6 @@@@ git_xmerge_config("merge.conflictstyle", conflict_style, NULL); } -- if (recurse_submodules != RECURSE_SUBMODULES_OFF) { -- git_config(submodule_config, NULL); -- if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) -- set_config_update_recurse_submodules(recurse_submodules); -- } -- if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1) die(_("-b, -B and --orphan are mutually exclusive")); @@@@ -1264,8 -1289,8 -1287,9 +1265,8 @@@@ * new_branch && argc > 1 will be caught later. */ if (opts.new_branch && argc == 1) - die(_("Cannot update paths and switch to branch '%s' at the same time.\n" - "Did you intend to checkout '%s' which can not be resolved as commit?"), - opts.new_branch, argv[0]); + die(_("'%s' is not a commit and a branch '%s' cannot be created from it"), + argv[0], opts.new_branch); if (opts.force_detach) die(_("git checkout: --detach does not take a path argument '%s'"), diff --combined builtin/clean.c index 142bf668cf,142bf668cf,57093db8be..ed954134d2 --- a/builtin/clean.c +++ b/builtin/clean.c @@@@ -8,6 -8,6 -8,7 +8,7 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "dir.h" #include "parse-options.h" #include "string-list.h" @@@@ -683,7 -683,7 -684,7 +684,7 @@@@ static int filter_by_patterns_cmd(void for_each_string_list_item(item, &del_list) { int dtype = DT_UNKNOWN; - if (is_excluded(&dir, item->string, &dtype)) { + if (is_excluded(&dir, &the_index, item->string, &dtype)) { *item->string = '\0'; changed++; } @@@@ -857,38 -857,38 -858,6 +858,38 @@@@ static void interactive_main_loop(void } } +static void correct_untracked_entries(struct dir_struct *dir) +{ + int src, dst, ign; + + for (src = dst = ign = 0; src < dir->nr; src++) { + /* skip paths in ignored[] that cannot be inside entries[src] */ + while (ign < dir->ignored_nr && + 0 <= cmp_dir_entry(&dir->entries[src], &dir->ignored[ign])) + ign++; + + if (ign < dir->ignored_nr && + check_dir_entry_contains(dir->entries[src], dir->ignored[ign])) { + /* entries[src] contains an ignored path, so we drop it */ + free(dir->entries[src]); + } else { + struct dir_entry *ent = dir->entries[src++]; + + /* entries[src] does not contain an ignored path, so we keep it */ + dir->entries[dst++] = ent; + + /* then discard paths in entries[] contained inside entries[src] */ + while (src < dir->nr && + check_dir_entry_contains(ent, dir->entries[src])) + free(dir->entries[src++]); + + /* compensate for the outer loop's loop control */ + src--; + } + } + dir->nr = dst; +} + int cmd_clean(int argc, const char **argv, const char *prefix) { int i, res; @@@@ -948,9 -948,9 -917,6 +949,9 @@@@ dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; + if (remove_directories) + dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS; + if (read_cache() < 0) die(_("index file corrupt")); @@@@ -965,8 -965,8 -931,7 +966,8 @@@@ PATHSPEC_PREFER_CWD, prefix, argv); - fill_directory(&dir, &pathspec); + fill_directory(&dir, &the_index, &pathspec); + correct_untracked_entries(&dir); for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; @@@@ -994,12 -994,12 -959,6 +995,12 @@@@ string_list_append(&del_list, rel); } + for (i = 0; i < dir.nr; i++) + free(dir.entries[i]); + + for (i = 0; i < dir.ignored_nr; i++) + free(dir.ignored[i]); + if (interactive && del_list.nr > 0) interactive_main_loop(); diff --combined builtin/clone.c index a2ea019c59,743f16ae2a,eaacac221b..08b5cc433c --- a/builtin/clone.c +++ b/builtin/clone.c @@@@ -9,6 -9,6 -9,7 +9,7 @@@@ */ #include "builtin.h" ++ #include "config.h" #include "lockfile.h" #include "parse-options.h" #include "fetch-pack.h" @@@@ -40,7 -40,7 -41,6 +41,7 @@@@ static const char * const builtin_clone static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1; static int option_local = -1, option_no_hardlinks, option_shared; +static int option_no_tags; static int option_shallow_submodules; static int deepen; static char *option_template, *option_depth, *option_since; @@@@ -121,8 -121,8 -121,6 +122,8 @@@@ static struct option builtin_clone_opti N_("deepen history of shallow clone, excluding rev")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), + OPT_BOOL(0, "no-tags", &option_no_tags, + N_("don't clone any tags, and make later fetches not to follow them")), OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules, N_("any cloned submodules will be shallow")), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), @@@@ -360,7 -360,7 -358,7 +361,7 @@@@ static void copy_alternates(struct strb * to turn entries with paths relative to the original * absolute, so that they can be used in the new repository. */ -- FILE *in = fopen(src->buf, "r"); ++ FILE *in = xfopen(src->buf, "r"); struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, in) != EOF) { @@@@ -566,7 -566,7 -564,7 +567,7 @@@@ static struct ref *wanted_peer_refs(con } else get_fetch_map(refs, refspec, &tail, 0); - if (!option_mirror && !option_single_branch) + if (!option_mirror && !option_single_branch && !option_no_tags) get_fetch_map(refs, tag_refspec, &tail, 0); return local_refs; @@@@ -655,7 -655,7 -653,7 +656,7 @@@@ static void update_remote_refs(const st if (refs) { write_remote_refs(mapped_refs); - if (option_single_branch) + if (option_single_branch && !option_no_tags) write_followtags(refs, msg); } @@@@ -685,7 -685,7 -683,7 +686,7 @@@@ static void update_head(const struct re install_branch_config(0, head, option_origin, our->name); } } else if (our) { - struct commit *c = lookup_commit_reference(our->old_oid.hash); + struct commit *c = lookup_commit_reference(&our->old_oid); /* --branch specifies a non-branch (i.e. tags), detach HEAD */ update_ref(msg, "HEAD", c->object.oid.hash, NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR); @@@@ -742,7 -742,7 -740,7 +743,7 @@@@ static int checkout(int submodule_progr opts.src_index = &the_index; opts.dst_index = &the_index; - tree = parse_tree_indirect(oid.hash); + tree = parse_tree_indirect(&oid); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts) < 0) @@@@ -776,9 -776,9 -774,7 +777,9 @@@@ static int write_one_config(const char *key, const char *value, void *data) { - return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0); + return git_config_set_multivar_gently(key, + value ? value : "true", + CONFIG_REGEX_NONE, 0); } static void write_config(struct string_list *config) @@@@ -1040,12 -1040,12 -1036,6 +1041,12 @@@@ int cmd_clone(int argc, const char **ar git_config_set(key.buf, repo); strbuf_reset(&key); + if (option_no_tags) { + strbuf_addf(&key, "remote.%s.tagOpt", option_origin); + git_config_set(key.buf, "--no-tags"); + strbuf_reset(&key); + } + if (option_required_reference.nr || option_optional_reference.nr) setup_reference(); diff --combined builtin/commit-tree.c index f39c2b2737,f39c2b2737,e1c17ba64b..a4a923d7c0 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "tree.h" #include "builtin.h" @@@@ -58,7 -58,7 -59,7 +59,7 @@@@ int cmd_commit_tree(int argc, const cha if (get_sha1_commit(argv[i], oid.hash)) die("Not a valid object name %s", argv[i]); assert_sha1_type(oid.hash, OBJ_COMMIT); - new_parent(lookup_commit(oid.hash), &parents); + new_parent(lookup_commit(&oid), &parents); continue; } diff --combined builtin/commit.c index e3c9e190b0,78ef319a24,929a45abed..021070e693 --- a/builtin/commit.c +++ b/builtin/commit.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "cache-tree.h" #include "color.h" @@@@ -253,7 -253,8 -254,7 +254,8 @@@@ static int list_paths(struct string_lis if (with_tree) { char *max_prefix = common_prefix(pattern); - - overlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix); + + overlay_tree_on_index(&the_index, with_tree, + + max_prefix ? max_prefix : prefix); free(max_prefix); } @@@@ -313,7 -314,7 -314,7 +315,7 @@@@ static void create_base_index(const str opts.dst_index = &the_index; opts.fn = oneway_merge; - tree = parse_tree_indirect(current_head->object.oid.hash); + tree = parse_tree_indirect(¤t_head->object.oid); if (!tree) die(_("failed to unpack HEAD tree object")); parse_tree(tree); @@@@ -1263,10 -1264,10 -1264,6 +1265,10 @@@@ static int parse_status_slot(const cha return WT_STATUS_NOBRANCH; if (!strcasecmp(slot, "unmerged")) return WT_STATUS_UNMERGED; + if (!strcasecmp(slot, "localBranch")) + return WT_STATUS_LOCAL_BRANCH; + if (!strcasecmp(slot, "remoteBranch")) + return WT_STATUS_REMOTE_BRANCH; return -1; } @@@@ -1434,7 -1435,7 -1431,7 +1436,7 @@@@ static void print_summary(const char *p struct strbuf author_ident = STRBUF_INIT; struct strbuf committer_ident = STRBUF_INIT; - commit = lookup_commit(oid->hash); + commit = lookup_commit(oid); if (!commit) die(_("couldn't look up newly created commit")); if (parse_commit(commit)) @@@@ -1658,7 -1659,7 -1655,7 +1660,7 @@@@ int cmd_commit(int argc, const char **a if (get_sha1("HEAD", oid.hash)) current_head = NULL; else { - current_head = lookup_commit_or_die(oid.hash, "HEAD"); + current_head = lookup_commit_or_die(&oid, "HEAD"); if (parse_commit(current_head)) die(_("could not parse HEAD commit")); } @@@@ -1699,7 -1700,10 -1696,10 +1701,7 @@@@ if (!reflog_msg) reflog_msg = "commit (merge)"; pptr = commit_list_append(current_head, pptr); -- fp = fopen(git_path_merge_head(), "r"); -- if (fp == NULL) -- die_errno(_("could not open '%s' for reading"), -- git_path_merge_head()); ++ fp = xfopen(git_path_merge_head(), "r"); while (strbuf_getline_lf(&m, fp) != EOF) { struct commit *parent; @@@@ -1736,7 -1740,7 -1736,7 +1738,7 @@@@ if (verbose || /* Truncate the message just before the diff, if any. */ cleanup_mode == CLEANUP_SCISSORS) - wt_status_truncate_message_at_cut_line(&sb); + strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len)); if (cleanup_mode != CLEANUP_NONE) strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL); @@@@ -1759,7 -1763,7 -1759,7 +1761,7 @@@@ append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1, + if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash, parents, oid.hash, author_ident.buf, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); @@@@ -1806,7 -1810,7 -1806,7 +1808,7 @@@@ cfg = init_copy_notes_for_rewrite("amend"); if (cfg) { /* we are amending, so current_head is not NULL */ -- copy_note_for_rewrite(cfg, current_head->object.oid.hash, oid.hash); ++ copy_note_for_rewrite(cfg, ¤t_head->object.oid, &oid); finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'"); } run_rewrite_hook(¤t_head->object.oid, &oid); diff --combined builtin/config.c index 7f6c25d4d9,7f6c25d4d9,1fc6471f37..82db29fae7 --- a/builtin/config.c +++ b/builtin/config.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "color.h" #include "parse-options.h" #include "urlmatch.h" @@@@ -242,8 -242,8 -243,8 +243,8 @@@@ static int get_value(const char *key_, } } -- git_config_with_options(collect_config, &values, -- &given_config_source, &config_options); ++ config_with_options(collect_config, &values, ++ &given_config_source, &config_options); ret = !values.nr; @@@@ -320,8 -320,8 -321,8 +321,8 @@@@ static void get_color(const char *var, get_color_slot = var; get_color_found = 0; parsed_color[0] = '\0'; -- git_config_with_options(git_get_color_config, NULL, -- &given_config_source, &config_options); ++ config_with_options(git_get_color_config, NULL, ++ &given_config_source, &config_options); if (!get_color_found && def_color) { if (color_parse(def_color, parsed_color) < 0) @@@@ -352,8 -352,8 -353,8 +353,8 @@@@ static int get_colorbool(const char *va get_colorbool_found = -1; get_diff_color_found = -1; get_color_ui_found = -1; -- git_config_with_options(git_get_colorbool_config, NULL, -- &given_config_source, &config_options); ++ config_with_options(git_get_colorbool_config, NULL, ++ &given_config_source, &config_options); if (get_colorbool_found < 0) { if (!strcmp(get_colorbool_slot, "color.diff")) @@@@ -441,8 -441,8 -442,8 +442,8 @@@@ static int get_urlmatch(const char *var show_keys = 1; } -- git_config_with_options(urlmatch_config_entry, &config, -- &given_config_source, &config_options); ++ config_with_options(urlmatch_config_entry, &config, ++ &given_config_source, &config_options); ret = !values.nr; @@@@ -496,9 -496,9 -497,6 +497,9 @@@@ int cmd_config(int argc, const char **a usage_with_options(builtin_config_usage, builtin_config_options); } + if (use_local_config && nongit) + die(_("--local can only be used inside a git repository")); + if (given_config_source.file && !strcmp(given_config_source.file, "-")) { given_config_source.file = NULL; @@@@ -538,6 -538,6 -536,10 +539,10 @@@@ config_options.respect_includes = !given_config_source.file; else config_options.respect_includes = respect_includes_opt; ++ if (!nongit) { ++ config_options.commondir = get_git_common_dir(); ++ config_options.git_dir = get_git_dir(); ++ } if (end_null) { term = '\0'; @@@@ -582,9 -582,9 -584,9 +587,9 @@@@ if (actions == ACTION_LIST) { check_argc(argc, 0, 0); -- if (git_config_with_options(show_all_config, NULL, -- &given_config_source, -- &config_options) < 0) { ++ if (config_with_options(show_all_config, NULL, ++ &given_config_source, ++ &config_options) < 0) { if (given_config_source.file) die_errno("unable to read config file '%s'", given_config_source.file); diff --combined builtin/describe.c index 893c8789f4,893c8789f4,3eddfd3706..70eb144608 --- a/builtin/describe.c +++ b/builtin/describe.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "commit.h" #include "tag.h" @@@@ -79,13 -79,13 -80,13 +80,13 @@@@ static int replace_name(struct commit_n struct tag *t; if (!e->tag) { - t = lookup_tag(e->oid.hash); + t = lookup_tag(&e->oid); if (!t || parse_tag(t)) return 1; e->tag = t; } - t = lookup_tag(oid->hash); + t = lookup_tag(oid); if (!t || parse_tag(t)) return 0; *tag = t; @@@@ -245,7 -245,7 -246,7 +246,7 @@@@ static unsigned long finish_depth_compu static void display_name(struct commit_name *n) { if (n->prio == 2 && !n->tag) { - n->tag = lookup_tag(n->oid.hash); + n->tag = lookup_tag(&n->oid); if (!n->tag || parse_tag(n->tag)) die(_("annotated tag %s not available"), n->path); } @@@@ -281,7 -281,7 -282,7 +282,7 @@@@ static void describe(const char *arg, i if (get_oid(arg, &oid)) die(_("Not a valid object name %s"), arg); - cmit = lookup_commit_reference(oid.hash); + cmit = lookup_commit_reference(&oid); if (!cmit) die(_("%s is not a valid '%s' object"), arg, commit_type); @@@@ -309,7 -309,7 -310,7 +310,7 @@@@ struct commit *c; struct commit_name *n = hashmap_iter_first(&names, &iter); for (; n; n = hashmap_iter_next(&iter)) { - c = lookup_commit_reference_gently(n->peeled.hash, 1); + c = lookup_commit_reference_gently(&n->peeled, 1); if (c) c->util = n; } diff --combined builtin/diff-files.c index c97069a714,a572da9d51,29d3e4f416..17bf84d18f --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "diff.h" #include "commit.h" #include "revision.h" @@@@ -20,12 -20,9 -21,9 +21,12 @@@@ int cmd_diff_files(int argc, const cha int result; unsigned options = 0; ++ if (argc == 2 && !strcmp(argv[1], "-h")) ++ usage(diff_files_usage); ++ + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ init_revisions(&rev, prefix); gitmodules_config(); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; precompose_argv(argc, argv); diff --combined builtin/diff-index.c index d59bf6cf5f,f084826a29,e3d418361c..185e6f9b58 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "diff.h" #include "commit.h" #include "revision.h" @@@@ -17,12 -17,9 -18,9 +18,12 @@@@ int cmd_diff_index(int argc, const cha int i; int result; ++ if (argc == 2 && !strcmp(argv[1], "-h")) ++ usage(diff_cache_usage); ++ + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ init_revisions(&rev, prefix); gitmodules_config(); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; precompose_argv(argc, argv); diff --combined builtin/diff-tree.c index 7e15d01f36,e401112045,c81063d534..31d2cb4107 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "diff.h" #include "commit.h" #include "log-tree.h" @@@@ -7,9 -7,9 -8,9 +8,9 @@@@ static struct rev_info log_tree_opt; --static int diff_tree_commit_sha1(const struct object_id *oid) ++static int diff_tree_commit_oid(const struct object_id *oid) { - struct commit *commit = lookup_commit_reference(oid->hash); + struct commit *commit = lookup_commit_reference(oid); if (!commit) return -1; return log_tree_commit(&log_tree_opt, commit); @@@@ -23,7 -23,7 -24,7 +24,7 @@@@ static int stdin_diff_commit(struct com /* Graft the fake parents locally to the commit */ while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) { - struct commit *parent = lookup_commit(oid.hash); + struct commit *parent = lookup_commit(&oid); if (!pptr) { /* Free the real parent list */ free_commit_list(commit->parents); @@@@ -44,13 -44,13 -45,13 +45,13 @@@@ static int stdin_diff_trees(struct tre struct tree *tree2; if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p) return error("Need exactly two trees, separated by a space"); - tree2 = lookup_tree(oid.hash); + tree2 = lookup_tree(&oid); if (!tree2 || parse_tree(tree2)) return -1; printf("%s %s\n", oid_to_hex(&tree1->object.oid), oid_to_hex(&tree2->object.oid)); -- diff_tree_sha1(tree1->object.oid.hash, tree2->object.oid.hash, -- "", &log_tree_opt.diffopt); ++ diff_tree_oid(&tree1->object.oid, &tree2->object.oid, ++ "", &log_tree_opt.diffopt); log_tree_diff_flush(&log_tree_opt); return 0; } @@@@ -67,7 -67,7 -68,7 +68,7 @@@@ static int diff_tree_stdin(char *line line[len-1] = 0; if (parse_oid_hex(line, &oid, &p)) return -1; - obj = parse_object(oid.hash); + obj = parse_object(&oid); if (!obj) return -1; if (obj->type == OBJ_COMMIT) @@@@ -98,18 -98,16 -99,16 +99,18 @@@@ static void diff_tree_tweak_rev(struct int cmd_diff_tree(int argc, const char **argv, const char *prefix) { -- int nr_sha1; char line[1000]; struct object *tree1, *tree2; static struct rev_info *opt = &log_tree_opt; struct setup_revision_opt s_r_opt; int read_stdin = 0; ++ if (argc == 2 && !strcmp(argv[1], "-h")) ++ usage(diff_tree_usage); ++ + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ init_revisions(opt, prefix); gitmodules_config(); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt->abbrev = 0; opt->diff = 1; opt->disable_stdin = 1; @@@@ -130,20 -128,19 -129,19 +131,20 @@@@ } /* -- * NOTE! We expect "a ^b" to be equal to "a..b", so we -- * reverse the order of the objects if the second one -- * is marked UNINTERESTING. ++ * NOTE! We expect "a..b" to expand to "^a b" but it is ++ * perfectly valid for revision range parser to yield "b ^a", ++ * which means the same thing. If we get the latter, i.e. the ++ * second one is marked UNINTERESTING, we recover the original ++ * order the user gave, i.e. "a..b", by swapping the trees. */ -- nr_sha1 = opt->pending.nr; -- switch (nr_sha1) { ++ switch (opt->pending.nr) { case 0: if (!read_stdin) usage(diff_tree_usage); break; case 1: tree1 = opt->pending.objects[0].item; -- diff_tree_commit_sha1(&tree1->oid); ++ diff_tree_commit_oid(&tree1->oid); break; case 2: tree1 = opt->pending.objects[0].item; @@@@ -151,7 -148,9 -149,9 +152,7 @@@@ if (tree2->flags & UNINTERESTING) { SWAP(tree2, tree1); } -- diff_tree_sha1(tree1->oid.hash, -- tree2->oid.hash, -- "", &opt->diffopt); ++ diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt); log_tree_diff_flush(opt); break; } diff --combined builtin/diff.c index d9152c21bf,0c8f86e40d,1ce40c63b2..7cde6abbcf --- a/builtin/diff.c +++ b/builtin/diff.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (c) 2006 Junio C Hamano */ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "color.h" #include "commit.h" @@@@ -20,22 -20,22 -21,23 +21,22 @@@@ #define DIFF_NO_INDEX_EXPLICIT 1 #define DIFF_NO_INDEX_IMPLICIT 2 -struct blobinfo { - struct object_id oid; - const char *name; - unsigned mode; -}; - static const char builtin_diff_usage[] = "git diff [] [ []] [--] [...]"; +static const char *blob_path(struct object_array_entry *entry) +{ + return entry->path ? entry->path : entry->name; +} + static void stuff_change(struct diff_options *opt, unsigned old_mode, unsigned new_mode, const struct object_id *old_oid, const struct object_id *new_oid, int old_oid_valid, int new_oid_valid, - const char *old_name, - const char *new_name) + const char *old_path, + const char *new_path) { struct diff_filespec *one, *two; @@@@ -46,25 -46,25 -48,25 +47,25 @@@@ if (DIFF_OPT_TST(opt, REVERSE_DIFF)) { SWAP(old_mode, new_mode); SWAP(old_oid, new_oid); - SWAP(old_name, new_name); + SWAP(old_path, new_path); } if (opt->prefix && - (strncmp(old_name, opt->prefix, opt->prefix_length) || - strncmp(new_name, opt->prefix, opt->prefix_length))) + (strncmp(old_path, opt->prefix, opt->prefix_length) || + strncmp(new_path, opt->prefix, opt->prefix_length))) return; - one = alloc_filespec(old_name); - two = alloc_filespec(new_name); - fill_filespec(one, old_oid->hash, old_oid_valid, old_mode); - fill_filespec(two, new_oid->hash, new_oid_valid, new_mode); + one = alloc_filespec(old_path); + two = alloc_filespec(new_path); - fill_filespec(one, old_oid->hash, old_oid_valid, old_mode); - fill_filespec(two, new_oid->hash, new_oid_valid, new_mode); ++ fill_filespec(one, old_oid, old_oid_valid, old_mode); ++ fill_filespec(two, new_oid, new_oid_valid, new_mode); diff_queue(&diff_queued_diff, one, two); } static int builtin_diff_b_f(struct rev_info *revs, int argc, const char **argv, - struct blobinfo *blob) + struct object_array_entry **blob) { /* Blob vs file in the working tree*/ struct stat st; @@@@ -83,15 -83,15 -85,14 +84,15 @@@@ diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); - if (blob[0].mode == S_IFINVALID) - blob[0].mode = canon_mode(st.st_mode); + if (blob[0]->mode == S_IFINVALID) + blob[0]->mode = canon_mode(st.st_mode); stuff_change(&revs->diffopt, - blob[0].mode, canon_mode(st.st_mode), - &blob[0].oid, &null_oid, + blob[0]->mode, canon_mode(st.st_mode), + &blob[0]->item->oid, &null_oid, 1, 0, - path, path); + blob[0]->path ? blob[0]->path : path, + path); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@@@ -99,24 -99,24 -100,24 +100,24 @@@@ static int builtin_diff_blobs(struct rev_info *revs, int argc, const char **argv, - struct blobinfo *blob) + struct object_array_entry **blob) { unsigned mode = canon_mode(S_IFREG | 0644); if (argc > 1) usage(builtin_diff_usage); - if (blob[0].mode == S_IFINVALID) - blob[0].mode = mode; + if (blob[0]->mode == S_IFINVALID) + blob[0]->mode = mode; - if (blob[1].mode == S_IFINVALID) - blob[1].mode = mode; + if (blob[1]->mode == S_IFINVALID) + blob[1]->mode = mode; stuff_change(&revs->diffopt, - blob[0].mode, blob[1].mode, - &blob[0].oid, &blob[1].oid, + blob[0]->mode, blob[1]->mode, + &blob[0]->item->oid, &blob[1]->item->oid, 1, 1, - blob[0].name, blob[1].name); + blob_path(blob[0]), blob_path(blob[1])); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@@@ -174,7 -174,7 -175,7 +175,7 @@@@ static int builtin_diff_tree(struct rev swap = 1; oid[swap] = &ent0->item->oid; oid[1 - swap] = &ent1->item->oid; -- diff_tree_sha1(oid[0]->hash, oid[1]->hash, "", &revs->diffopt); ++ diff_tree_oid(oid[0], oid[1], "", &revs->diffopt); log_tree_diff_flush(revs); return 0; } @@@@ -194,7 -194,7 -195,7 +195,7 @@@@ static int builtin_diff_combined(struc revs->dense_combined_merges = revs->combine_merges = 1; for (i = 1; i < ents; i++) oid_array_append(&parents, &ent[i].item->oid); -- diff_tree_combined(ent[0].item->oid.hash, &parents, ++ diff_tree_combined(&ent[0].item->oid, &parents, revs->dense_combined_merges, revs); oid_array_clear(&parents); return 0; @@@@ -259,7 -259,7 -260,7 +260,7 @@@@ int cmd_diff(int argc, const char **arg struct rev_info rev; struct object_array ent = OBJECT_ARRAY_INIT; int blobs = 0, paths = 0; - struct blobinfo blob[2]; + struct object_array_entry *blob[2]; int nongit = 0, no_index = 0; int result = 0; @@@@ -381,7 -381,7 -382,7 +382,7 @@@@ add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); add_pending_object(&rev, &tree->object, "HEAD"); } break; @@@@ -395,7 -395,7 -396,7 +396,7 @@@@ const char *name = entry->name; int flags = (obj->flags & UNINTERESTING); if (!obj->parsed) - obj = parse_object(obj->oid.hash); + obj = parse_object(&obj->oid); obj = deref_tag(obj, NULL, 0); if (!obj) die(_("invalid object '%s' given."), name); @@@@ -408,7 -408,7 -409,9 +409,7 @@@@ } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); - hashcpy(blob[blobs].oid.hash, obj->oid.hash); - blob[blobs].name = name; - blob[blobs].mode = entry->mode; + blob[blobs] = entry; blobs++; } else { diff --combined builtin/difftool.c index b9a892f269,b9a892f269,538b0187fa..9199227f6e --- a/builtin/difftool.c +++ b/builtin/difftool.c @@@@ -12,6 -12,6 -12,7 +12,7 @@@@ * Copyright (C) 2016 Johannes Schindelin */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "run-command.h" #include "exec_cmd.h" @@@@ -226,7 -226,7 -227,6 +227,7 @@@@ static void changed_files(struct hashma hashmap_entry_init(entry, strhash(buf.buf)); hashmap_add(result, entry); } + fclose(fp); if (finish_command(&diff_files)) die("diff-files did not exit properly"); strbuf_release(&index_env); @@@@ -440,10 -440,10 -440,8 +441,10 @@@@ static int run_dir_diff(const char *ext } if (lmode && status != 'C') { - if (checkout_path(lmode, &loid, src_path, &lstate)) - return error("could not write '%s'", src_path); + if (checkout_path(lmode, &loid, src_path, &lstate)) { + ret = error("could not write '%s'", src_path); + goto finish; + } } if (rmode && !S_ISLNK(rmode)) { @@@@ -459,12 -459,12 -457,9 +460,12 @@@@ hashmap_add(&working_tree_dups, entry); if (!use_wt_file(workdir, dst_path, &roid)) { - if (checkout_path(rmode, &roid, dst_path, &rstate)) - return error("could not write '%s'", - dst_path); + if (checkout_path(rmode, &roid, dst_path, + &rstate)) { + ret = error("could not write '%s'", + dst_path); + goto finish; + } } else if (!is_null_oid(&roid)) { /* * Changes in the working tree need special @@@@ -479,12 -479,12 -474,10 +480,12 @@@@ ADD_CACHE_JUST_APPEND); add_path(&rdir, rdir_len, dst_path); - if (ensure_leading_directories(rdir.buf)) - return error("could not create " - "directory for '%s'", - dst_path); + if (ensure_leading_directories(rdir.buf)) { + ret = error("could not create " + "directory for '%s'", + dst_path); + goto finish; + } add_path(&wtdir, wtdir_len, dst_path); if (symlinks) { if (symlink(wtdir.buf, rdir.buf)) { @@@@ -505,15 -505,15 -498,13 +506,15 @@@@ } } + fclose(fp); + fp = NULL; if (finish_command(&child)) { ret = error("error occurred running diff --raw"); goto finish; } if (!i) - return 0; + goto finish; /* * Changes to submodules require special treatment.This loop writes a @@@@ -636,9 -636,9 -627,6 +637,9 @@@@ exit_cleanup(tmpdir, rc); finish: + if (fp) + fclose(fp); + free(lbase_dir); free(rbase_dir); strbuf_release(&ldir); diff --combined builtin/fast-export.c index a932be04f4,24e29ad7ea,e4304e2dd6..12d501bfde --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@@@ -5,6 -5,6 -5,7 +5,7 @@@@ */ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "refs.h" #include "commit.h" #include "object.h" @@@@ -232,7 -232,7 -233,7 +233,7 @@@@ static void export_blob(const struct ob if (anonymize) { buf = anonymize_blob(&size); - object = (struct object *)lookup_blob(oid->hash); + object = (struct object *)lookup_blob(oid); eaten = 0; } else { buf = read_sha1_file(oid->hash, &type, &size); @@@@ -240,7 -240,7 -241,7 +241,7 @@@@ die ("Could not read blob %s", oid_to_hex(oid)); if (check_sha1_signature(oid->hash, buf, size, typename(type)) < 0) die("sha1 mismatch in blob %s", oid_to_hex(oid)); - object = parse_object_buffer(oid->hash, type, size, buf, &eaten); + object = parse_object_buffer(oid, type, size, buf, &eaten); } if (!object) @@@@ -562,12 -562,12 -563,12 +563,12 @@@@ static void handle_commit(struct commi get_object_mark(&commit->parents->item->object) != 0 && !full_tree) { parse_commit_or_die(commit->parents->item); -- diff_tree_sha1(commit->parents->item->tree->object.oid.hash, -- commit->tree->object.oid.hash, "", &rev->diffopt); ++ diff_tree_oid(&commit->parents->item->tree->object.oid, ++ &commit->tree->object.oid, "", &rev->diffopt); } else -- diff_root_tree_sha1(commit->tree->object.oid.hash, -- "", &rev->diffopt); ++ diff_root_tree_oid(&commit->tree->object.oid, ++ "", &rev->diffopt); /* Export the referenced blobs, and remember the marks. */ for (i = 0; i < diff_queued_diff.nr; i++) @@@@ -734,7 -734,7 -735,6 +735,7 @@@@ static void handle_tag(const char *name oid_to_hex(&tag->object.oid)); case DROP: /* Ignore this tag altogether */ + free(buf); return; case REWRITE: if (tagged->type != OBJ_COMMIT) { @@@@ -766,7 -766,7 -766,6 +767,7 @@@@ (int)(tagger_end - tagger), tagger, tagger == tagger_end ? "" : "\n", (int)message_size, (int)message_size, message ? message : ""); + free(buf); } static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name) @@@@ -779,7 -779,7 -778,7 +780,7 @@@@ /* handle nested tags */ while (tag && tag->object.type == OBJ_TAG) { - parse_object(tag->object.oid.hash); + parse_object(&tag->object.oid); string_list_append(&extra_refs, full_name)->util = tag; tag = (struct tag *)tag->tagged; } @@@@ -907,7 -907,9 -906,9 +908,7 @@@@ static void export_marks(char *file static void import_marks(char *input_file) { char line[512]; -- FILE *f = fopen(input_file, "r"); -- if (!f) -- die_errno("cannot read '%s'", input_file); ++ FILE *f = xfopen(input_file, "r"); while (fgets(line, sizeof(line), f)) { uint32_t mark; @@@@ -938,7 -940,7 -939,7 +939,7 @@@@ /* only commits */ continue; - commit = lookup_commit(oid.hash); + commit = lookup_commit(&oid); if (!commit) die("not a commit? can't happen: %s", oid_to_hex(&oid)); diff --combined builtin/fetch.c index 100248c5af,47708451bc,1fe8f62385..16cf8421ce --- a/builtin/fetch.c +++ b/builtin/fetch.c @@@@ -2,6 -2,6 -2,7 +2,7 @@@@ * "git fetch" */ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "commit.h" #include "builtin.h" @@@@ -73,13 -73,6 -74,6 +74,13 @@@@ static int git_fetch_config(const char fetch_prune_config = git_config_bool(k, v); return 0; } ++ ++ if (!strcmp(k, "submodule.recurse")) { ++ int r = git_config_bool(k, v) ? ++ RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF; ++ recurse_submodules = r; ++ } ++ return git_default_config(k, v, cb); } @@@@ -643,8 -636,8 -637,8 +644,8 @@@@ static int update_local_ref(struct ref return r; } - current = lookup_commit_reference_gently(ref->old_oid.hash, 1); - updated = lookup_commit_reference_gently(ref->new_oid.hash, 1); + current = lookup_commit_reference_gently(&ref->old_oid, 1); + updated = lookup_commit_reference_gently(&ref->new_oid, 1); if (!current || !updated) { const char *msg; const char *what; @@@@ -777,8 -770,8 -771,7 +778,8 @@@@ static int store_updated_refs(const cha continue; } - commit = lookup_commit_reference_gently(rm->old_oid.hash, 1); + commit = lookup_commit_reference_gently(&rm->old_oid, + 1); if (!commit) rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE; @@@@ -948,7 -941,7 -941,7 +949,7 @@@@ static int prune_refs(struct refspec *r for (ref = stale_refs; ref; ref = ref->next) string_list_append(&refnames, ref->name); - result = delete_refs(&refnames, 0); + result = delete_refs("fetch: prune", &refnames, 0); string_list_clear(&refnames, 0); } diff --combined builtin/fmt-merge-msg.c index 70137b0b7e,70137b0b7e,2e30b514f2..10cbb43416 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "refs.h" #include "commit.h" #include "diff.h" @@@@ -341,7 -341,7 -342,7 +342,7 @@@@ static void shortlog(const char *name const struct object_id *oid = &origin_data->oid; int limit = opts->shortlog_len; - branch = deref_tag(parse_object(oid->hash), oid_to_hex(oid), GIT_SHA1_HEXSZ); + branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ); if (!branch || branch->type != OBJ_COMMIT) return; @@@@ -559,14 -559,14 -560,14 +560,14 @@@@ static void find_merge_parents(struct m * "name" here and we do not want to contaminate its * util field yet. */ - obj = parse_object(oid.hash); + obj = parse_object(&oid); parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT); if (!parent) continue; commit_list_insert(parent, &parents); add_merge_parent(result, &obj->oid, &parent->object.oid); } - head_commit = lookup_commit(head->hash); + head_commit = lookup_commit(head); if (head_commit) commit_list_insert(head_commit, &parents); parents = reduce_heads(parents); @@@@ -633,7 -633,7 -634,7 +634,7 @@@@ int fmt_merge_msg(struct strbuf *in, st struct commit *head; struct rev_info rev; - head = lookup_commit_or_die(head_oid.hash, "HEAD"); + head = lookup_commit_or_die(&head_oid, "HEAD"); init_revisions(&rev, NULL); rev.commit_format = CMIT_FMT_ONELINE; rev.ignore_merges = 1; diff --combined builtin/fsck.c index 3a2c27f241,cb2ba6cd1b,0c63f6259f..87c6756899 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "commit.h" #include "tree.h" #include "blob.h" @@@@ -280,7 -280,8 -281,8 +281,7 @@@@ static void check_unreachable_object(st free(filename); return; } -- if (!(f = fopen(filename, "w"))) -- die_errno("Could not open '%s'", filename); ++ f = xfopen(filename, "w"); if (obj->type == OBJ_BLOB) { if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1)) die_errno("Could not write '%s'", filename); @@@@ -376,7 -377,7 -378,7 +377,7 @@@@ static int fsck_obj(struct object *obj return 0; } -static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type, +static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten) { /* @@@@ -384,10 -385,10 -386,10 +385,10 @@@@ * verify_packfile(), data_valid variable for details. */ struct object *obj; - obj = parse_object_buffer(sha1, type, size, buffer, eaten); + obj = parse_object_buffer(oid, type, size, buffer, eaten); if (!obj) { errors_found |= ERROR_OBJECT; - return error("%s: object corrupt or missing", sha1_to_hex(sha1)); + return error("%s: object corrupt or missing", oid_to_hex(oid)); } obj->flags = HAS_OBJ; return fsck_obj(obj); @@@@ -396,7 -397,7 -398,7 +397,7 @@@@ static int default_refs; static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, - unsigned long timestamp) + timestamp_t timestamp) { struct object *obj; @@@@ -406,7 -407,7 -408,7 +407,7 @@@@ if (timestamp && name_objects) add_decoration(fsck_walk_options.object_names, obj, - xstrfmt("%s@{%ld}", refname, timestamp)); + xstrfmt("%s@{%"PRItime"}", refname, timestamp)); obj->used = 1; mark_object_reachable(obj); } else { @@@@ -417,7 -418,7 -419,7 +418,7 @@@@ } static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { const char *refname = cb_data; @@@@ -443,7 -444,7 -445,7 +444,7 @@@@ static int fsck_handle_ref(const char * { struct object *obj; - obj = parse_object(oid->hash); + obj = parse_object(oid); if (!obj) { error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid)); errors_found |= ERROR_REACHABLE; @@@@ -505,7 -506,7 -507,7 +506,7 @@@@ static struct object *parse_loose_objec if (!contents && type != OBJ_BLOB) die("BUG: read_loose_object streamed a non-blob"); - obj = parse_object_buffer(oid->hash, type, size, contents, &eaten); + obj = parse_object_buffer(oid, type, size, contents, &eaten); if (!eaten) free(contents); @@@@ -598,10 -599,10 -600,10 +599,10 @@@@ static int fsck_cache_tree(struct cache fprintf(stderr, "Checking cache tree\n"); if (0 <= it->entry_count) { - struct object *obj = parse_object(it->sha1); + struct object *obj = parse_object(&it->oid); if (!obj) { error("%s: invalid sha1 pointer in cache-tree", - sha1_to_hex(it->sha1)); + oid_to_hex(&it->oid)); errors_found |= ERROR_REFS; return 1; } @@@@ -780,7 -781,7 -782,7 +781,7 @@@@ int cmd_fsck(int argc, const char **arg mode = active_cache[i]->ce_mode; if (S_ISGITLINK(mode)) continue; - blob = lookup_blob(active_cache[i]->oid.hash); + blob = lookup_blob(&active_cache[i]->oid); if (!blob) continue; obj = &blob->object; diff --combined builtin/gc.c index f484eda43c,f484eda43c,0a6790d714..bd91f136fe --- a/builtin/gc.c +++ b/builtin/gc.c @@@@ -11,6 -11,6 -11,7 +11,7 @@@@ */ #include "builtin.h" ++ #include "config.h" #include "tempfile.h" #include "lockfile.h" #include "parse-options.h" @@@@ -33,7 -33,7 -34,7 +34,7 @@@@ static int aggressive_window = 250 static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; static int detach_auto = 1; -static unsigned long gc_log_expire_time; +static timestamp_t gc_log_expire_time; static const char *gc_log_expire = "1.day.ago"; static const char *prune_expire = "2.weeks.ago"; static const char *prune_worktrees_expire = "3.months.ago"; diff --combined builtin/grep.c index 3e4b9600e8,7df9c253ee,3df9e08f03..f61a9d938b --- a/builtin/grep.c +++ b/builtin/grep.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (c) 2006 Junio C Hamano */ #include "cache.h" ++ #include "config.h" #include "blob.h" #include "tree.h" #include "commit.h" @@@@ -73,14 -73,14 -74,14 +74,14 @@@@ static pthread_mutex_t grep_mutex static inline void grep_lock(void) { - if (num_threads) - pthread_mutex_lock(&grep_mutex); + assert(num_threads); + pthread_mutex_lock(&grep_mutex); } static inline void grep_unlock(void) { - if (num_threads) - pthread_mutex_unlock(&grep_mutex); + assert(num_threads); + pthread_mutex_unlock(&grep_mutex); } /* Signalled when a new work_item is added to todo. */ @@@@ -224,8 -224,7 -225,7 +225,8 @@@@ static void start_threads(struct grep_o int err; struct grep_opt *o = grep_opt_dup(opt); o->output = strbuf_out; -- o->debug = 0; ++ if (i) ++ o->debug = 0; compile_grep_patterns(o); err = pthread_create(&threads[i], NULL, run, o); @@@@ -290,22 -289,19 -290,8 +291,22 @@@@ static int grep_cmd_config(const char * if (num_threads < 0) die(_("invalid number of threads specified (%d) for %s"), num_threads, var); +#ifdef NO_PTHREADS + else if (num_threads && num_threads != 1) { + /* + * TRANSLATORS: %s is the configuration + * variable for tweaking threads, currently + * grep.threads + */ + warning(_("no threads support, ignoring %s"), var); + num_threads = 0; + } +#endif } ++ if (!strcmp(var, "submodule.recurse")) ++ recurse_submodules = git_config_bool(var, value); ++ return st; } @@@@ -342,7 -338,7 -328,7 +343,7 @@@@ static int grep_oid(struct grep_opt *op #ifndef NO_PTHREADS if (num_threads) { -- add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, oid); ++ add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); return 0; } else @@@@ -351,7 -347,7 -337,7 +352,7 @@@@ struct grep_source gs; int hit; -- grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, oid); ++ grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); hit = grep_source(opt, &gs); @@@@ -510,8 -506,8 -496,6 +511,8 @@@@ static void compile_submodule_options(c break; case GREP_PATTERN_TYPE_UNSPECIFIED: break; + default: + die("BUG: Added a new grep pattern type without updating switch statement"); } for (pattern = opt->pattern_list; pattern != NULL; @@@@ -587,7 -583,7 -571,7 +588,7 @@@@ static int grep_submodule_launch(struc * with the object's name: 'tree-name:filename'. In order to * provide uniformity of output we want to pass the name of the * parent project's object name to the submodule so the submodule can -- * prefix its output with the parent's name and not its own SHA1. ++ * prefix its output with the parent's name and not its own OID. */ if (gs->identifier && end_of_base) argv_array_pushf(&cp.args, "--parent-basename=%.*s", @@@@ -600,12 -596,12 -584,12 +601,12 @@@@ * If there is a tree identifier for the submodule, add the * rev after adding the submodule options but before the * pathspecs. To do this we listen for the '--' and insert the -- * sha1 before pushing the '--' onto the child process argv ++ * oid before pushing the '--' onto the child process argv * array. */ if (gs->identifier && !strcmp("--", submodule_options.argv[i])) { -- argv_array_push(&cp.args, sha1_to_hex(gs->identifier)); ++ argv_array_push(&cp.args, oid_to_hex(gs->identifier)); } argv_array_push(&cp.args, submodule_options.argv[i]); @@@@ -635,11 -631,11 -619,11 +636,11 @@@@ /* * Prep grep structures for a submodule grep -- * sha1: the sha1 of the submodule or NULL if using the working tree ++ * oid: the oid of the submodule or NULL if using the working tree * filename: name of the submodule including tree name of parent * path: location of the submodule */ --static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, ++static int grep_submodule(struct grep_opt *opt, const struct object_id *oid, const char *filename, const char *path) { if (!is_submodule_initialized(path)) @@@@ -649,7 -645,7 -633,7 +650,7 @@@@ * If searching history, check for the presense of the * submodule's gitdir before skipping the submodule. */ -- if (sha1) { ++ if (oid) { const struct submodule *sub = submodule_from_path(null_sha1, path); if (sub) @@@@ -664,7 -660,7 -648,7 +665,7 @@@@ #ifndef NO_PTHREADS if (num_threads) { -- add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, sha1); ++ add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, oid); return 0; } else #endif @@@@ -673,7 -669,7 -657,7 +674,7 @@@@ int hit; grep_source_init(&gs, GREP_SOURCE_SUBMODULE, -- filename, path, sha1); ++ filename, path, oid); hit = grep_submodule_launch(opt, &gs); grep_source_clear(&gs); @@@@ -792,7 -788,7 -776,7 +793,7 @@@@ static int grep_tree(struct grep_opt *o check_attr); free(data); } else if (recurse_submodules && S_ISGITLINK(entry.mode)) { -- hit |= grep_submodule(opt, entry.oid->hash, base->buf, ++ hit |= grep_submodule(opt, entry.oid, base->buf, base->buf + tn_len); } @@@@ -883,7 -879,7 -867,7 +884,7 @@@@ static int grep_directory(struct grep_o if (exc_std) setup_standard_excludes(&dir); - fill_directory(&dir, pathspec); + fill_directory(&dir, &the_index, pathspec); for (i = 0; i < dir.nr; i++) { if (!dir_path_match(dir.entries[i], pathspec, 0, NULL)) continue; @@@@ -1171,6 -1167,8 -1155,8 +1172,6 @@@@ int cmd_grep(int argc, const char **arg if (!opt.fixed && opt.ignore_case) opt.regflags |= REG_ICASE; -- compile_grep_patterns(&opt); -- /* * We have to find "--" in a separate pass, because its presence * influences how we will parse arguments that come before it. @@@@ -1205,18 -1203,18 -1191,16 +1206,18 @@@@ break; } - if (get_sha1_with_context(arg, 0, oid.hash, &oc)) { + if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH, + oid.hash, &oc)) { if (seen_dashdash) die(_("unable to resolve revision: %s"), arg); break; } - object = parse_object_or_die(oid.hash, arg); + object = parse_object_or_die(&oid, arg); if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); + free(oc.path); } /* @@@@ -1243,23 -1241,12 -1227,10 +1244,23 @@@@ num_threads = GREP_NUM_THREADS_DEFAULT; else if (num_threads < 0) die(_("invalid number of threads specified (%d)"), num_threads); ++ if (num_threads == 1) ++ num_threads = 0; #else + if (num_threads) + warning(_("no threads support, ignoring --threads")); num_threads = 0; #endif ++ if (!num_threads) ++ /* ++ * The compiled patterns on the main path are only ++ * used when not using threading. Otherwise ++ * start_threads() below calls compile_grep_patterns() ++ * for each thread. ++ */ ++ compile_grep_patterns(&opt); ++ #ifndef NO_PTHREADS if (num_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) diff --combined builtin/index-pack.c index 04b9dcaf0f,04b9dcaf0f,dfb3d1296a..edc1a91d89 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "builtin.h" ++ #include "config.h" #include "delta.h" #include "pack.h" #include "csum-file.h" @@@@ -747,13 -747,13 -748,13 +748,13 @@@@ static int compare_objects(const unsign ssize_t len = read_istream(data->st, data->buf, size); if (len == 0) die(_("SHA1 COLLISION FOUND WITH %s !"), - sha1_to_hex(data->entry->idx.sha1)); + oid_to_hex(&data->entry->idx.oid)); if (len < 0) die(_("unable to read %s"), - sha1_to_hex(data->entry->idx.sha1)); + oid_to_hex(&data->entry->idx.oid)); if (memcmp(buf, data->buf, len)) die(_("SHA1 COLLISION FOUND WITH %s !"), - sha1_to_hex(data->entry->idx.sha1)); + oid_to_hex(&data->entry->idx.oid)); size -= len; buf += len; } @@@@ -771,12 -771,12 -772,12 +772,12 @@@@ static int check_collison(struct object memset(&data, 0, sizeof(data)); data.entry = entry; - data.st = open_istream(entry->idx.sha1, &type, &size, NULL); + data.st = open_istream(entry->idx.oid.hash, &type, &size, NULL); if (!data.st) return -1; if (size != entry->size || type != entry->type) die(_("SHA1 COLLISION FOUND WITH %s !"), - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); unpack_data(entry, compare_objects, &data); close_istream(data.st); free(data.buf); @@@@ -785,7 -785,7 -786,7 +786,7 @@@@ static void sha1_object(const void *data, struct object_entry *obj_entry, unsigned long size, enum object_type type, - const unsigned char *sha1) + const struct object_id *oid) { void *new_data = NULL; int collision_test_needed = 0; @@@@ -794,7 -794,7 -795,7 +795,7 @@@@ if (startup_info->have_repository) { read_lock(); - collision_test_needed = has_sha1_file_with_flags(sha1, HAS_SHA1_QUICK); + collision_test_needed = has_sha1_file_with_flags(oid->hash, HAS_SHA1_QUICK); read_unlock(); } @@@@ -809,31 -809,31 -810,31 +810,31 @@@@ enum object_type has_type; unsigned long has_size; read_lock(); - has_type = sha1_object_info(sha1, &has_size); + has_type = sha1_object_info(oid->hash, &has_size); if (has_type < 0) - die(_("cannot read existing object info %s"), sha1_to_hex(sha1)); + die(_("cannot read existing object info %s"), oid_to_hex(oid)); if (has_type != type || has_size != size) - die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); - has_data = read_sha1_file(sha1, &has_type, &has_size); + die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid)); + has_data = read_sha1_file(oid->hash, &has_type, &has_size); read_unlock(); if (!data) data = new_data = get_data_from_pack(obj_entry); if (!has_data) - die(_("cannot read existing object %s"), sha1_to_hex(sha1)); + die(_("cannot read existing object %s"), oid_to_hex(oid)); if (size != has_size || type != has_type || memcmp(data, has_data, size) != 0) - die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); + die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid)); free(has_data); } if (strict) { read_lock(); if (type == OBJ_BLOB) { - struct blob *blob = lookup_blob(sha1); + struct blob *blob = lookup_blob(oid); if (blob) blob->object.flags |= FLAG_CHECKED; else - die(_("invalid blob object %s"), sha1_to_hex(sha1)); + die(_("invalid blob object %s"), oid_to_hex(oid)); } else { struct object *obj; int eaten; @@@@ -845,8 -845,8 -846,7 +846,8 @@@@ * we do not need to free the memory here, as the * buf is deleted by the caller. */ - obj = parse_object_buffer(sha1, type, size, buf, &eaten); + obj = parse_object_buffer(oid, type, size, buf, + &eaten); if (!obj) die(_("invalid %s"), typename(type)); if (do_fsck_object && @@@@ -958,10 -958,10 -958,9 +959,10 @@@@ static void resolve_delta(struct object if (!result->data) bad_object(delta_obj->idx.offset, _("failed to apply delta")); hash_sha1_file(result->data, result->size, - typename(delta_obj->real_type), delta_obj->idx.sha1); + typename(delta_obj->real_type), + delta_obj->idx.oid.hash); sha1_object(result->data, NULL, result->size, delta_obj->real_type, - delta_obj->idx.sha1); + &delta_obj->idx.oid); counter_lock(); nr_resolved_deltas++; counter_unlock(); @@@@ -991,7 -991,7 -990,7 +992,7 @@@@ static struct base_data *find_unresolve struct base_data *prev_base) { if (base->ref_last == -1 && base->ofs_last == -1) { - find_ref_delta_children(base->obj->idx.sha1, + find_ref_delta_children(base->obj->idx.oid.hash, &base->ref_first, &base->ref_last, OBJ_REF_DELTA); @@@@ -1132,8 -1132,8 -1131,7 +1133,8 @@@@ static void parse_pack_objects(unsigne for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; void *data = unpack_raw_entry(obj, &ofs_delta->offset, - ref_delta_sha1, obj->idx.sha1); + ref_delta_sha1, + obj->idx.oid.hash); obj->real_type = obj->type; if (obj->type == OBJ_OFS_DELTA) { nr_ofs_deltas++; @@@@ -1149,8 -1149,8 -1147,7 +1150,8 @@@@ obj->real_type = OBJ_BAD; nr_delays++; } else - sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1); + sha1_object(data, NULL, obj->size, obj->type, + &obj->idx.oid); free(data); display_progress(progress, i+1); } @@@@ -1176,8 -1176,8 -1173,7 +1177,8 @@@@ if (obj->real_type != OBJ_BAD) continue; obj->real_type = obj->type; - sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1); + sha1_object(NULL, obj, obj->size, obj->type, + &obj->idx.oid); nr_delays--; } if (nr_delays) @@@@ -1335,7 -1335,7 -1331,7 +1336,7 @@@@ static struct object_entry *append_obj_ obj[1].idx.offset += write_compressed(f, buf, size); obj[0].idx.crc32 = crc32_end(f); sha1flush(f); - hashcpy(obj->idx.sha1, sha1); + hashcpy(obj->idx.oid.hash, sha1); return obj; } @@@@ -1586,14 -1586,14 -1582,13 +1587,14 @@@@ static void show_pack_info(int stat_onl if (stat_only) continue; printf("%s %-6s %lu %lu %"PRIuMAX, - sha1_to_hex(obj->idx.sha1), + oid_to_hex(&obj->idx.oid), typename(obj->real_type), obj->size, (unsigned long)(obj[1].idx.offset - obj->idx.offset), (uintmax_t)obj->idx.offset); if (is_delta_type(obj->type)) { struct object_entry *bobj = &objects[obj_stat[i].base_object_no]; - printf(" %u %s", obj_stat[i].delta_depth, sha1_to_hex(bobj->idx.sha1)); + printf(" %u %s", obj_stat[i].delta_depth, + oid_to_hex(&bobj->idx.oid)); } putchar('\n'); } diff --combined builtin/log.c index 998437b23d,e89ec941ce,b333d4fea2..8ca1de9894 --- a/builtin/log.c +++ b/builtin/log.c @@@@ -5,6 -5,6 -5,7 +5,7 @@@@ * 2006 Junio Hamano */ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "color.h" #include "commit.h" @@@@ -110,8 -110,8 -111,6 +111,8 @@@@ static void init_log_defaults(void { init_grep_defaults(); init_diff_ui_defaults(); + + decoration_style = auto_decoration_style(); } static void cmd_log_init_defaults(struct rev_info *rev) @@@@ -412,6 -412,6 -411,8 +413,6 @@@@ static int git_log_config(const char *v if (decoration_style < 0) decoration_style = 0; /* maybe warn? */ return 0; - } else { - decoration_style = auto_decoration_style(); } if (!strcmp(var, "log.showroot")) { default_show_root = git_config_bool(var, value); @@@@ -483,20 -483,20 -484,16 +484,20 @@@@ static int show_blob_object(const struc !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV)) return stream_blob_to_fd(1, oid, NULL, 0); - if (get_sha1_with_context(obj_name, 0, oidc.hash, &obj_context)) + if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH, + oidc.hash, &obj_context)) die(_("Not a valid object name %s"), obj_name); - if (!obj_context.path[0] || - !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) + if (!obj_context.path || + !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) { + free(obj_context.path); return stream_blob_to_fd(1, oid, NULL, 0); + } if (!buf) die(_("git show %s: bad file"), obj_name); write_or_die(1, buf, size); + free(obj_context.path); return 0; } @@@@ -600,7 -600,7 -597,7 +601,7 @@@@ int cmd_show(int argc, const char **arg rev.shown_one = 1; if (ret) break; - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); if (!o) ret = error(_("Could not read object %s"), oid_to_hex(&t->tagged->oid)); @@@@ -846,10 -846,8 -843,8 +847,10 @@@@ static int open_next_file(struct commi if (output_directory) { strbuf_addstr(&filename, output_directory); if (filename.len >= -- PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) ++ PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) { ++ strbuf_release(&filename); return error(_("name of output directory is too long")); ++ } strbuf_complete(&filename, '/'); } @@@@ -863,11 -861,8 -858,8 +864,11 @@@@ if (!quiet) printf("%s\n", filename.buf + outdir_offset); -- if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) -- return error(_("Cannot open patch file %s"), filename.buf); ++ if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) { ++ error_errno(_("Cannot open patch file %s"), filename.buf); ++ strbuf_release(&filename); ++ return -1; ++ } strbuf_release(&filename); return 0; @@@@ -887,8 -882,8 -879,8 +888,8 @@@@ static void get_patch_ids(struct rev_in o2 = rev->pending.objects[1].item; flags1 = o1->flags; flags2 = o2->flags; - c1 = lookup_commit_reference(o1->oid.hash); - c2 = lookup_commit_reference(o2->oid.hash); + c1 = lookup_commit_reference(&o1->oid); + c2 = lookup_commit_reference(&o2->oid); if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING)) die(_("Not a range.")); @@@@ -919,8 -914,8 -911,8 +920,8 @@@@ static void gen_message_id(struct rev_info *info, char *base) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, "%s.%lu.git.%s", base, - (unsigned long) time(NULL), + strbuf_addf(&buf, "%s.%"PRItime".git.%s", base, + (timestamp_t) time(NULL), git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT)); info->message_id = strbuf_detach(&buf, NULL); } @@@@ -1052,9 -1047,9 -1044,9 +1053,9 @@@@ static void make_cover_letter(struct re diff_setup_done(&opts); -- diff_tree_sha1(origin->tree->object.oid.hash, -- head->tree->object.oid.hash, -- "", &opts); ++ diff_tree_oid(&origin->tree->object.oid, ++ &head->tree->object.oid, ++ "", &opts); diffcore_std(&opts); diff_flush(&opts); @@@@ -1272,7 -1267,7 -1264,7 +1273,7 @@@@ static struct commit *get_base_commit(c if (get_oid(upstream, &oid)) die(_("Failed to resolve '%s' as a valid ref."), upstream); - commit = lookup_commit_or_die(oid.hash, "upstream base"); + commit = lookup_commit_or_die(&oid, "upstream base"); base_list = get_merge_bases_many(commit, total, list); /* There should be one and only one merge base. */ if (!base_list || base_list->next) @@@@ -1363,7 -1358,7 -1355,7 +1364,7 @@@@ static void prepare_bases(struct base_t struct object_id *patch_id; if (commit->util) continue; -- if (commit_patch_id(commit, &diffopt, oid.hash, 0)) ++ if (commit_patch_id(commit, &diffopt, &oid, 0)) die(_("cannot get patch id")); ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id); patch_id = bases->patch_id + bases->nr_patch_id; @@@@ -1828,7 -1823,7 -1820,7 +1829,7 @@@@ static int add_pending_commit(const cha { struct object_id oid; if (get_oid(arg, &oid) == 0) { - struct commit *commit = lookup_commit_reference(oid.hash); + struct commit *commit = lookup_commit_reference(&oid); if (commit) { commit->object.flags |= flags; add_pending_object(revs, &commit->object, arg); diff --combined builtin/ls-files.c index b376afc312,cdc1cfdd26,9751010780..b12d0bb612 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "quote.h" #include "dir.h" #include "builtin.h" @@@@ -53,17 -53,17 -54,17 +54,17 @@@@ static const char *tag_modified = "" static const char *tag_skip_worktree = ""; static const char *tag_resolve_undo = ""; - -static void write_eolinfo(const struct cache_entry *ce, const char *path) + +static void write_eolinfo(const struct index_state *istate, + + const struct cache_entry *ce, const char *path) { - - if (!show_eol) - - return; - - else { + + if (show_eol) { struct stat st; const char *i_txt = ""; const char *w_txt = ""; const char *a_txt = get_convert_attr_ascii(path); if (ce && S_ISREG(ce->ce_mode)) - - i_txt = get_cached_convert_stats_ascii(ce->name); + + i_txt = get_cached_convert_stats_ascii(istate, + + ce->name); if (!lstat(path, &st) && S_ISREG(st.st_mode)) w_txt = get_wt_convert_stats_ascii(path); printf("i/%-5s w/%-5s attr/%-17s\t", i_txt, w_txt, a_txt); @@@@ -93,34 -93,73 -94,34 +94,73 @@@@ static void write_name(const char *name strbuf_release(&full_name); } + +static const char *get_tag(const struct cache_entry *ce, const char *tag) + +{ + + static char alttag[4]; + + + + if (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) { + + memcpy(alttag, tag, 3); + + + + if (isalpha(tag[0])) { + + alttag[0] = tolower(tag[0]); + + } else if (tag[0] == '?') { + + alttag[0] = '!'; + + } else { + + alttag[0] = 'v'; + + alttag[1] = tag[0]; + + alttag[2] = ' '; + + alttag[3] = 0; + + } + + + + tag = alttag; + + } + + + + return tag; + +} + + + +static void print_debug(const struct cache_entry *ce) + +{ + + if (debug_mode) { + + const struct stat_data *sd = &ce->ce_stat_data; + + + + printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); + + printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); + + printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); + + printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); + + printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); + + } + +} + + static void show_dir_entry(const char *tag, struct dir_entry *ent) { int len = max_prefix_len; - if (len >= ent->len) + if (len > ent->len) die("git ls-files: internal error - directory entry not superset of prefix"); if (!dir_path_match(ent, &pathspec, len, ps_matched)) return; fputs(tag, stdout); - - write_eolinfo(NULL, ent->name); + + write_eolinfo(NULL, NULL, ent->name); write_name(ent->name); } - -static void show_other_files(struct dir_struct *dir) + +static void show_other_files(const struct index_state *istate, + + const struct dir_struct *dir) { int i; for (i = 0; i < dir->nr; i++) { struct dir_entry *ent = dir->entries[i]; - - if (!cache_name_is_other(ent->name, ent->len)) + + if (!index_name_is_other(istate, ent->name, ent->len)) continue; show_dir_entry(tag_other, ent); } } - -static void show_killed_files(struct dir_struct *dir) + +static void show_killed_files(const struct index_state *istate, + + const struct dir_struct *dir) { int i; for (i = 0; i < dir->nr; i++) { @@@@ -134,29 -173,29 -135,29 +174,29 @@@@ /* If ent->name is prefix of an entry in the * cache, it will be killed. */ - - pos = cache_name_pos(ent->name, ent->len); + + pos = index_name_pos(istate, ent->name, ent->len); if (0 <= pos) die("BUG: killed-file %.*s not found", ent->len, ent->name); pos = -pos - 1; - - while (pos < active_nr && - - ce_stage(active_cache[pos])) + + while (pos < istate->cache_nr && + + ce_stage(istate->cache[pos])) pos++; /* skip unmerged */ - - if (active_nr <= pos) + + if (istate->cache_nr <= pos) break; /* pos points at a name immediately after * ent->name in the cache. Does it expect * ent->name to be a directory? */ - - len = ce_namelen(active_cache[pos]); + + len = ce_namelen(istate->cache[pos]); if ((ent->len < len) && - - !strncmp(active_cache[pos]->name, + + !strncmp(istate->cache[pos]->name, ent->name, ent->len) && - - active_cache[pos]->name[ent->len] == '/') + + istate->cache[pos]->name[ent->len] == '/') killed = 1; break; } - - if (0 <= cache_name_pos(ent->name, sp - ent->name)) { + + if (0 <= index_name_pos(istate, ent->name, sp - ent->name)) { /* If any of the leading directories in * ent->name is registered in the cache, * ent->name will be killed. @@@@ -230,7 -269,8 -231,7 +270,8 @@@@ static void show_gitlink(const struct c exit(status); } - -static void show_ce_entry(const char *tag, const struct cache_entry *ce) + +static void show_ce_entry(const struct index_state *istate, + + const char *tag, const struct cache_entry *ce) { struct strbuf name = STRBUF_INIT; int len = max_prefix_len; @@@@ -238,7 -278,7 -239,7 +279,7 @@@@ strbuf_addstr(&name, super_prefix); strbuf_addstr(&name, ce->name); - if (len >= ce_namelen(ce)) + if (len > ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && @@@@ -248,22 -288,7 -249,22 +289,7 @@@@ len, ps_matched, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) { - - if (tag && *tag && show_valid_bit && - - (ce->ce_flags & CE_VALID)) { - - static char alttag[4]; - - memcpy(alttag, tag, 3); - - if (isalpha(tag[0])) - - alttag[0] = tolower(tag[0]); - - else if (tag[0] == '?') - - alttag[0] = '!'; - - else { - - alttag[0] = 'v'; - - alttag[1] = tag[0]; - - alttag[2] = ' '; - - alttag[3] = 0; - - } - - tag = alttag; - - } + + tag = get_tag(ce, tag); if (!show_stage) { fputs(tag, stdout); @@@@ -274,30 -299,22 -275,30 +300,22 @@@@ find_unique_abbrev(ce->oid.hash, abbrev), ce_stage(ce)); } - - write_eolinfo(ce, ce->name); + + write_eolinfo(istate, ce, ce->name); write_name(ce->name); - - if (debug_mode) { - - const struct stat_data *sd = &ce->ce_stat_data; - - - - printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); - - printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); - - printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); - - printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); - - printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); - - } + + print_debug(ce); } strbuf_release(&name); } - -static void show_ru_info(void) + +static void show_ru_info(const struct index_state *istate) { struct string_list_item *item; - - if (!the_index.resolve_undo) + + if (!istate->resolve_undo) return; - - for_each_string_list_item(item, the_index.resolve_undo) { + + for_each_string_list_item(item, istate->resolve_undo) { const char *path = item->string; struct resolve_undo_info *ui = item->util; int i, len; @@@@ -319,13 -336,14 -320,13 +337,14 @@@@ } } - -static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce) + +static int ce_excluded(struct dir_struct *dir, struct index_state *istate, + + const struct cache_entry *ce) { int dtype = ce_to_dtype(ce); - return is_excluded(dir, &the_index, ce->name, &dtype); - return is_excluded(dir, ce->name, &dtype); + + return is_excluded(dir, istate, ce->name, &dtype); } - -static void show_files(struct dir_struct *dir) + +static void show_files(struct index_state *istate, struct dir_struct *dir) { int i; @@@@ -333,33 -351,33 -334,33 +352,33 @@@@ if (show_others || show_killed) { if (!show_others) dir->flags |= DIR_COLLECT_KILLED_ONLY; - fill_directory(dir, &the_index, &pathspec); - fill_directory(dir, &pathspec); + + fill_directory(dir, istate, &pathspec); if (show_others) - - show_other_files(dir); + + show_other_files(istate, dir); if (show_killed) - - show_killed_files(dir); + + show_killed_files(istate, dir); } if (show_cached || show_stage) { - - for (i = 0; i < active_nr; i++) { - - const struct cache_entry *ce = active_cache[i]; + + for (i = 0; i < istate->cache_nr; i++) { + + const struct cache_entry *ce = istate->cache[i]; if ((dir->flags & DIR_SHOW_IGNORED) && - - !ce_excluded(dir, ce)) + + !ce_excluded(dir, istate, ce)) continue; if (show_unmerged && !ce_stage(ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; - - show_ce_entry(ce_stage(ce) ? tag_unmerged : + + show_ce_entry(istate, ce_stage(ce) ? tag_unmerged : (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); } } if (show_deleted || show_modified) { - - for (i = 0; i < active_nr; i++) { - - const struct cache_entry *ce = active_cache[i]; + + for (i = 0; i < istate->cache_nr; i++) { + + const struct cache_entry *ce = istate->cache[i]; struct stat st; int err; if ((dir->flags & DIR_SHOW_IGNORED) && - - !ce_excluded(dir, ce)) + + !ce_excluded(dir, istate, ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; @@@@ -367,9 -385,9 -368,9 +386,9 @@@@ continue; err = lstat(ce->name, &st); if (show_deleted && err) - - show_ce_entry(tag_removed, ce); - - if (show_modified && ce_modified(ce, &st, 0)) - - show_ce_entry(tag_modified, ce); + + show_ce_entry(istate, tag_removed, ce); + + if (show_modified && ie_modified(istate, ce, &st, 0)) + + show_ce_entry(istate, tag_modified, ce); } } } @@@@ -377,49 -395,50 -378,30 +396,50 @@@@ /* * Prune the index to only contain stuff starting with "prefix" */ - -static void prune_cache(const char *prefix, size_t prefixlen) + +static void prune_index(struct index_state *istate, + + const char *prefix, size_t prefixlen) { int pos; unsigned int first, last; if (!prefix) return; - - pos = cache_name_pos(prefix, prefixlen); + + pos = index_name_pos(istate, prefix, prefixlen); if (pos < 0) pos = -pos-1; first = pos; - - last = active_nr; + + last = istate->cache_nr; while (last > first) { int next = (last + first) >> 1; - - const struct cache_entry *ce = active_cache[next]; + + const struct cache_entry *ce = istate->cache[next]; if (!strncmp(ce->name, prefix, prefixlen)) { first = next+1; continue; } last = next; } - - memmove(active_cache, active_cache + pos, + + memmove(istate->cache, istate->cache + pos, (last - pos) * sizeof(struct cache_entry *)); - - active_nr = last - pos; + + istate->cache_nr = last - pos; +} + +static int get_common_prefix_len(const char *common_prefix) +{ + int common_prefix_len; + + if (!common_prefix) + return 0; + + common_prefix_len = strlen(common_prefix); + + /* + * If the prefix has a trailing slash, strip it so that submodules wont + * be pruned from the index. + */ + if (common_prefix[common_prefix_len - 1] == '/') + common_prefix_len--; + + return common_prefix_len; } /* @@@@ -430,23 -449,24 -412,23 +450,24 @@@@ * that were given from the command line. We are not * going to write this index out. */ - -void overlay_tree_on_cache(const char *tree_name, const char *prefix) + +void overlay_tree_on_index(struct index_state *istate, + + const char *tree_name, const char *prefix) { struct tree *tree; - unsigned char sha1[20]; + struct object_id oid; struct pathspec pathspec; struct cache_entry *last_stage0 = NULL; int i; - if (get_sha1(tree_name, sha1)) + if (get_oid(tree_name, &oid)) die("tree-ish %s not found.", tree_name); - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(&oid); if (!tree) die("bad tree-ish %s", tree_name); /* Hoist the unmerged entries up to stage #3 to make room */ - - for (i = 0; i < active_nr; i++) { - - struct cache_entry *ce = active_cache[i]; + + for (i = 0; i < istate->cache_nr; i++) { + + struct cache_entry *ce = istate->cache[i]; if (!ce_stage(ce)) continue; ce->ce_flags |= CE_STAGEMASK; @@@@ -459,11 -479,11 -441,11 +480,11 @@@@ PATHSPEC_PREFER_CWD, prefix, matchbuf); } else memset(&pathspec, 0, sizeof(pathspec)); - - if (read_tree(tree, 1, &pathspec)) + + if (read_tree(tree, 1, &pathspec, istate)) die("unable to read tree entries %s", tree_name); - - for (i = 0; i < active_nr; i++) { - - struct cache_entry *ce = active_cache[i]; + + for (i = 0; i < istate->cache_nr; i++) { + + struct cache_entry *ce = istate->cache[i]; switch (ce_stage(ce)) { case 0: last_stage0 = ce; @@@@ -643,7 -663,7 -625,8 +664,7 @@@@ int cmd_ls_files(int argc, const char * "--error-unmatch"); parse_pathspec(&pathspec, 0, - PATHSPEC_PREFER_CWD | - PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, + PATHSPEC_PREFER_CWD, prefix, argv); /* @@@@ -655,9 -675,9 -638,7 +676,9 @@@@ max_prefix = NULL; else max_prefix = common_prefix(&pathspec); - max_prefix_len = max_prefix ? strlen(max_prefix) : 0; + max_prefix_len = get_common_prefix_len(max_prefix); + - prune_cache(max_prefix, max_prefix_len); + + prune_index(&the_index, max_prefix, max_prefix_len); /* Treat unmatching pathspec elements as errors */ if (pathspec.nr && error_unmatch) @@@@ -671,6 -691,6 -652,7 +692,6 @@@@ show_killed || show_modified || show_resolve_undo)) show_cached = 1; - prune_cache(max_prefix, max_prefix_len); if (with_tree) { /* * Basic sanity check; show-stages and show-unmerged @@@@ -678,11 -698,11 -660,11 +699,11 @@@@ */ if (show_stage || show_unmerged) die("ls-files --with-tree is incompatible with -s or -u"); - - overlay_tree_on_cache(with_tree, max_prefix); + + overlay_tree_on_index(&the_index, with_tree, max_prefix); } - - show_files(&dir); + + show_files(&the_index, &dir); if (show_resolve_undo) - - show_ru_info(); + + show_ru_info(&the_index); if (ps_matched) { int bad; diff --combined builtin/ls-tree.c index ee7b293b11,ee7b293b11,4b53a8282b..ef965408e8 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "blob.h" #include "tree.h" #include "commit.h" @@@@ -119,7 -119,7 -120,7 +120,7 @@@@ static int show_tree(const unsigned cha int cmd_ls_tree(int argc, const char **argv, const char *prefix) { - unsigned char sha1[20]; + struct object_id oid; struct tree *tree; int i, full_tree = 0; const struct option ls_tree_options[] = { @@@@ -164,7 -164,7 -165,7 +165,7 @@@@ if (argc < 1) usage_with_options(ls_tree_usage, ls_tree_options); - if (get_sha1(argv[0], sha1)) + if (get_oid(argv[0], &oid)) die("Not a valid object name %s", argv[0]); /* @@@@ -180,7 -180,7 -181,7 +181,7 @@@@ for (i = 0; i < pathspec.nr; i++) pathspec.items[i].nowildcard_len = pathspec.items[i].len; pathspec.has_wildcard = 0; - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(&oid); if (!tree) die("not a tree object"); return !!read_tree_recursive(tree, "", 0, 0, &pathspec, show_tree, NULL); diff --combined builtin/merge-base.c index 0c36a70ad8,0c36a70ad8,9c201cbfc0..6dbd167d3b --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "commit.h" #include "refs.h" #include "diff.h" @@@@ -41,7 -41,7 -42,7 +42,7 @@@@ static struct commit *get_commit_refere if (get_oid(arg, &revkey)) die("Not a valid object name %s", arg); - r = lookup_commit_reference(revkey.hash); + r = lookup_commit_reference(&revkey); if (!r) die("Not a valid commit name %s", arg); @@@@ -120,7 -120,7 -121,7 +121,7 @@@@ static void add_one_commit(struct objec if (is_null_oid(oid)) return; - commit = lookup_commit(oid->hash); + commit = lookup_commit(oid); if (!commit || (commit->object.flags & TMP_MARK) || parse_commit(commit)) @@@@ -132,7 -132,7 -133,7 +133,7 @@@@ } static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *ident, unsigned long timestamp, + const char *ident, timestamp_t timestamp, int tz, const char *message, void *cbdata) { struct rev_collect *revs = cbdata; @@@@ -168,7 -168,7 -169,7 +169,7 @@@@ static int handle_fork_point(int argc, if (get_oid(commitname, &oid)) die("Not a valid object name: '%s'", commitname); - derived = lookup_commit_reference(oid.hash); + derived = lookup_commit_reference(&oid); memset(&revs, 0, sizeof(revs)); revs.initial = 1; for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); diff --combined builtin/merge.c index 84970cd85e,a4a098f40f,9bdd577e09..900bafdb45 --- a/builtin/merge.c +++ b/builtin/merge.c @@@@ -7,6 -7,6 -7,7 +7,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "parse-options.h" #include "builtin.h" #include "lockfile.h" @@@@ -415,7 -415,7 -416,7 +416,7 @@@@ static void finish(struct commit *head_ DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff_setup_done(&opts); -- diff_tree_sha1(head->hash, new_head->hash, "", &opts); ++ diff_tree_oid(head, new_head, "", &opts); diffcore_std(&opts); diff_flush(&opts); } @@@@ -605,13 -605,13 -606,13 +606,13 @@@@ static int read_tree_trivial(struct obj opts.verbose_update = 1; opts.trivial_merges_only = 1; opts.merge = 1; - trees[nr_trees] = parse_tree_indirect(common->hash); + trees[nr_trees] = parse_tree_indirect(common); if (!trees[nr_trees++]) return -1; - trees[nr_trees] = parse_tree_indirect(head->hash); + trees[nr_trees] = parse_tree_indirect(head); if (!trees[nr_trees++]) return -1; - trees[nr_trees] = parse_tree_indirect(one->hash); + trees[nr_trees] = parse_tree_indirect(one); if (!trees[nr_trees++]) return -1; opts.fn = threeway_merge; @@@@ -839,7 -839,9 -840,9 +840,7 @@@@ static int suggest_conflicts(void struct strbuf msgbuf = STRBUF_INIT; filename = git_path_merge_msg(); -- fp = fopen(filename, "a"); -- if (!fp) -- die_errno(_("Could not open '%s' for writing"), filename); ++ fp = xfopen(filename, "a"); append_conflicts_hint(&msgbuf); fputs(msgbuf.buf, fp); @@@@ -1121,7 -1123,7 -1124,7 +1122,7 @@@@ int cmd_merge(int argc, const char **ar if (!branch || is_null_oid(&head_oid)) head_commit = NULL; else - head_commit = lookup_commit_or_die(head_oid.hash, "HEAD"); + head_commit = lookup_commit_or_die(&head_oid, "HEAD"); init_diff_ui_defaults(); git_config(git_merge_config, NULL); @@@@ -1370,8 -1372,8 -1373,8 +1371,8 @@@@ goto done; } - if (checkout_fast_forward(head_commit->object.oid.hash, - commit->object.oid.hash, + if (checkout_fast_forward(&head_commit->object.oid, + &commit->object.oid, overwrite_ignore)) { ret = 1; goto done; diff --combined builtin/name-rev.c index 7fc7e66e85,7fc7e66e85,c222daaa14..e21715f1d0 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "commit.h" #include "tag.h" #include "refs.h" @@@@ -10,64 -10,64 -11,24 +11,64 @@@@ typedef struct rev_name { const char *tip_name; - unsigned long taggerdate; + timestamp_t taggerdate; int generation; int distance; + int from_tag; } rev_name; -static long cutoff = LONG_MAX; +static timestamp_t cutoff = TIME_MAX; /* How many generations are maximally preferred over _one_ merge traversal? */ #define MERGE_TRAVERSAL_WEIGHT 65535 +static int is_better_name(struct rev_name *name, + const char *tip_name, + timestamp_t taggerdate, + int generation, + int distance, + int from_tag) +{ + /* + * When comparing names based on tags, prefer names + * based on the older tag, even if it is farther away. + */ + if (from_tag && name->from_tag) + return (name->taggerdate > taggerdate || + (name->taggerdate == taggerdate && + name->distance > distance)); + + /* + * We know that at least one of them is a non-tag at this point. + * favor a tag over a non-tag. + */ + if (name->from_tag != from_tag) + return from_tag; + + /* + * We are now looking at two non-tags. Tiebreak to favor + * shorter hops. + */ + if (name->distance != distance) + return name->distance > distance; + + /* ... or tiebreak to favor older date */ + if (name->taggerdate != taggerdate) + return name->taggerdate > taggerdate; + + /* keep the current one if we cannot decide */ + return 0; +} + static void name_rev(struct commit *commit, - const char *tip_name, unsigned long taggerdate, - int generation, int distance, + const char *tip_name, timestamp_t taggerdate, + int generation, int distance, int from_tag, int deref) { struct rev_name *name = (struct rev_name *)commit->util; struct commit_list *parents; int parent_number = 1; + char *to_free = NULL; parse_commit(commit); @@@@ -75,7 -75,7 -36,7 +76,7 @@@@ return; if (deref) { - tip_name = xstrfmt("%s^0", tip_name); + tip_name = to_free = xstrfmt("%s^0", tip_name); if (generation) die("generation: %d, but deref?", generation); @@@@ -85,18 -85,18 -46,16 +86,18 @@@@ name = xmalloc(sizeof(rev_name)); commit->util = name; goto copy_data; - } else if (name->taggerdate > taggerdate || - (name->taggerdate == taggerdate && - name->distance > distance)) { + } else if (is_better_name(name, tip_name, taggerdate, + generation, distance, from_tag)) { copy_data: name->tip_name = tip_name; name->taggerdate = taggerdate; name->generation = generation; name->distance = distance; - } else + name->from_tag = from_tag; + } else { + free(to_free); return; + } for (parents = commit->parents; parents; @@@@ -114,12 -114,12 -73,10 +115,12 @@@@ parent_number); name_rev(parents->item, new_name, taggerdate, 0, - distance + MERGE_TRAVERSAL_WEIGHT, 0); + distance + MERGE_TRAVERSAL_WEIGHT, + from_tag, 0); } else { name_rev(parents->item, tip_name, taggerdate, - generation + 1, distance + 1, 0); + generation + 1, distance + 1, + from_tag, 0); } } } @@@@ -158,7 -158,7 -115,7 +159,7 @@@@ struct name_ref_data static struct tip_table { struct tip_table_entry { - unsigned char sha1[20]; + struct object_id oid; const char *refname; } *table; int nr; @@@@ -166,13 -166,13 -123,13 +167,13 @@@@ int sorted; } tip_table; -static void add_to_tip_table(const unsigned char *sha1, const char *refname, +static void add_to_tip_table(const struct object_id *oid, const char *refname, int shorten_unambiguous) { refname = name_ref_abbrev(refname, shorten_unambiguous); ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc); - hashcpy(tip_table.table[tip_table.nr].sha1, sha1); + oidcpy(&tip_table.table[tip_table.nr].oid, oid); tip_table.table[tip_table.nr].refname = xstrdup(refname); tip_table.nr++; tip_table.sorted = 0; @@@@ -181,16 -181,16 -138,16 +182,16 @@@@ static int tipcmp(const void *a_, const void *b_) { const struct tip_table_entry *a = a_, *b = b_; - return hashcmp(a->sha1, b->sha1); + return oidcmp(&a->oid, &b->oid); } static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data) { - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); struct name_ref_data *data = cb_data; int can_abbreviate_output = data->tags_only && data->name_only; int deref = 0; - unsigned long taggerdate = ULONG_MAX; + timestamp_t taggerdate = TIME_MAX; if (data->tags_only && !starts_with(path, "refs/tags/")) return 0; @@@@ -238,25 -238,25 -195,21 +239,25 @@@@ return 0; } - add_to_tip_table(oid->hash, path, can_abbreviate_output); + add_to_tip_table(oid, path, can_abbreviate_output); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); deref = 1; taggerdate = t->date; } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; + int from_tag = starts_with(path, "refs/tags/"); + if (taggerdate == ULONG_MAX) + taggerdate = ((struct commit *)o)->date; path = name_ref_abbrev(path, can_abbreviate_output); - name_rev(commit, xstrdup(path), taggerdate, 0, 0, deref); + name_rev(commit, xstrdup(path), taggerdate, 0, 0, + from_tag, deref); } return 0; } @@@@ -264,7 -264,7 -217,7 +265,7 @@@@ static const unsigned char *nth_tip_table_ent(size_t ix, void *table_) { struct tip_table_entry *table = table_; - return table[ix].sha1; + return table[ix].oid.hash; } static const char *get_exact_ref_match(const struct object *o) @@@@ -349,9 -349,9 -302,9 +350,9 @@@@ static void name_rev_line(char *p, stru #define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f')) if (!ishex(*p)) forty = 0; - else if (++forty == 40 && + else if (++forty == GIT_SHA1_HEXSZ && !ishex(*(p+1))) { - unsigned char sha1[40]; + struct object_id oid; const char *name = NULL; char c = *(p+1); int p_len = p - p_start + 1; @@@@ -359,9 -359,9 -312,9 +360,9 @@@@ forty = 0; *(p+1) = 0; - if (!get_sha1(p - 39, sha1)) { + if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) { struct object *o = - lookup_object(sha1); + lookup_object(oid.hash); if (o) name = get_rev_name(o, &buf); } @@@@ -371,7 -371,7 -324,7 +372,7 @@@@ continue; if (data->name_only) - printf("%.*s%s", p_len - 40, p_start, name); + printf("%.*s%s", p_len - GIT_SHA1_HEXSZ, p_start, name); else printf("%.*s (%s)", p_len, p_start, name); p_start = p + 1; @@@@ -422,18 -422,18 -375,18 +423,18 @@@@ int cmd_name_rev(int argc, const char * cutoff = 0; for (; argc; argc--, argv++) { - unsigned char sha1[20]; + struct object_id oid; struct object *object; struct commit *commit; - if (get_sha1(*argv, sha1)) { + if (get_oid(*argv, &oid)) { fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", *argv); continue; } commit = NULL; - object = parse_object(sha1); + object = parse_object(&oid); if (object) { struct object *peeled = deref_tag(object, *argv, 0); if (peeled && peeled->type == OBJ_COMMIT) diff --combined builtin/notes.c index c939a84b76,7196bff0eb,dceb681bad..77573cf1ea --- a/builtin/notes.c +++ b/builtin/notes.c @@@@ -8,6 -8,6 -8,7 +8,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "notes.h" #include "blob.h" @@@@ -109,11 -109,11 -110,11 +110,11 @@@@ static void free_note_data(struct note_ strbuf_release(&d->buf); } --static int list_each_note(const unsigned char *object_sha1, -- const unsigned char *note_sha1, char *note_path, ++static int list_each_note(const struct object_id *object_oid, ++ const struct object_id *note_oid, char *note_path, void *cb_data) { -- printf("%s %s\n", sha1_to_hex(note_sha1), sha1_to_hex(object_sha1)); ++ printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid)); return 0; } @@@@ -129,10 -129,10 -130,10 +130,10 @@@@ static void copy_obj_to_fd(int fd, cons } } --static void write_commented_object(int fd, const unsigned char *object) ++static void write_commented_object(int fd, const struct object_id *object) { const char *show_args[5] = -- {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL}; ++ {"show", "--stat", "--no-notes", oid_to_hex(object), NULL}; struct child_process show = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; struct strbuf cbuf = STRBUF_INIT; @@@@ -145,7 -145,7 -146,7 +146,7 @@@@ show.git_cmd = 1; if (start_command(&show)) die(_("unable to start 'show' for object '%s'"), -- sha1_to_hex(object)); ++ oid_to_hex(object)); if (strbuf_read(&buf, show.out, 0) < 0) die_errno(_("could not read 'show' output")); @@@@ -157,10 -157,10 -158,10 +158,10 @@@@ if (finish_command(&show)) die(_("failed to finish 'show' for object '%s'"), -- sha1_to_hex(object)); ++ oid_to_hex(object)); } --static void prepare_note_data(const unsigned char *object, struct note_data *d, ++static void prepare_note_data(const struct object_id *object, struct note_data *d, const unsigned char *old_note) { if (d->use_editor || !d->given) { @@@@ -243,16 -243,16 -244,16 +244,16 @@@@ static int parse_reuse_arg(const struc { struct note_data *d = opt->value; char *buf; -- unsigned char object[20]; ++ struct object_id object; enum object_type type; unsigned long len; if (d->buf.len) strbuf_addch(&d->buf, '\n'); -- if (get_sha1(arg, object)) ++ if (get_oid(arg, &object)) die(_("failed to resolve '%s' as a valid ref."), arg); -- if (!(buf = read_sha1_file(object, &type, &len))) { ++ if (!(buf = read_sha1_file(object.hash, &type, &len))) { free(buf); die(_("failed to read object '%s'."), arg); } @@@@ -292,7 -292,7 -293,7 +293,7 @@@@ static int notes_copy_from_stdin(int fo } while (strbuf_getline_lf(&buf, stdin) != EOF) { -- unsigned char from_obj[20], to_obj[20]; ++ struct object_id from_obj, to_obj; struct strbuf **split; int err; @@@@ -301,15 -301,15 -302,15 +302,15 @@@@ die(_("malformed input line: '%s'."), buf.buf); strbuf_rtrim(split[0]); strbuf_rtrim(split[1]); -- if (get_sha1(split[0]->buf, from_obj)) ++ if (get_oid(split[0]->buf, &from_obj)) die(_("failed to resolve '%s' as a valid ref."), split[0]->buf); -- if (get_sha1(split[1]->buf, to_obj)) ++ if (get_oid(split[1]->buf, &to_obj)) die(_("failed to resolve '%s' as a valid ref."), split[1]->buf); if (rewrite_cmd) -- err = copy_note_for_rewrite(c, from_obj, to_obj); ++ err = copy_note_for_rewrite(c, &from_obj, &to_obj); else -- err = copy_note(t, from_obj, to_obj, force, ++ err = copy_note(t, &from_obj, &to_obj, force, combine_notes_overwrite); if (err) { @@@@ -340,10 -340,10 -341,8 +341,10 @@@@ static struct notes_tree *init_notes_ch ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref; if (!starts_with(ref, "refs/notes/")) - /* TRANSLATORS: the first %s will be replaced by a - git notes command: 'add', 'merge', 'remove', etc.*/ + /* + * TRANSLATORS: the first %s will be replaced by a git + * notes command: 'add', 'merge', 'remove', etc. + */ die(_("refusing to %s notes in %s (outside of refs/notes/)"), subcommand, ref); return t; @@@@ -352,8 -352,8 -351,8 +353,8 @@@@ static int list(int argc, const char **argv, const char *prefix) { struct notes_tree *t; -- unsigned char object[20]; -- const unsigned char *note; ++ struct object_id object; ++ const struct object_id *note; int retval = -1; struct option options[] = { OPT_END() @@@@ -370,15 -370,15 -369,15 +371,15 @@@@ t = init_notes_check("list", 0); if (argc) { -- if (get_sha1(argv[0], object)) ++ if (get_oid(argv[0], &object)) die(_("failed to resolve '%s' as a valid ref."), argv[0]); -- note = get_note(t, object); ++ note = get_note(t, &object); if (note) { -- puts(sha1_to_hex(note)); ++ puts(oid_to_hex(note)); retval = 0; } else retval = error(_("no note found for object %s."), -- sha1_to_hex(object)); ++ oid_to_hex(&object)); } else retval = for_each_note(t, 0, list_each_note, NULL); @@@@ -393,8 -393,8 -392,8 +394,8 @@@@ static int add(int argc, const char **a int force = 0, allow_empty = 0; const char *object_ref; struct notes_tree *t; -- unsigned char object[20], new_note[20]; -- const unsigned char *note; ++ struct object_id object, new_note; ++ const struct object_id *note; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &d, N_("message"), @@@@ -425,11 -425,11 -424,11 +426,11 @@@@ object_ref = argc > 1 ? argv[1] : "HEAD"; -- if (get_sha1(object_ref, object)) ++ if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("add", NOTES_INIT_WRITABLE); -- note = get_note(t, object); ++ note = get_note(t, &object); if (note) { if (!force) { @@@@ -439,7 -439,7 -438,7 +440,7 @@@@ return error(_("Cannot add notes. " "Found existing notes for object %s. " "Use '-f' to overwrite existing notes"), -- sha1_to_hex(object)); ++ oid_to_hex(&object)); } /* * Redirect to "edit" subcommand. @@@@ -452,19 -452,19 -451,19 +453,19 @@@@ return append_edit(argc, argv, prefix); } fprintf(stderr, _("Overwriting existing notes for object %s\n"), -- sha1_to_hex(object)); ++ oid_to_hex(&object)); } -- prepare_note_data(object, &d, note); ++ prepare_note_data(&object, &d, note->hash); if (d.buf.len || allow_empty) { -- write_note_data(&d, new_note); -- if (add_note(t, object, new_note, combine_notes_overwrite)) ++ write_note_data(&d, new_note.hash); ++ if (add_note(t, &object, &new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); commit_notes(t, "Notes added by 'git notes add'"); } else { fprintf(stderr, _("Removing note for object %s\n"), -- sha1_to_hex(object)); -- remove_note(t, object); ++ oid_to_hex(&object)); ++ remove_note(t, object.hash); commit_notes(t, "Notes removed by 'git notes add'"); } @@@@ -476,9 -476,9 -475,9 +477,9 @@@@ static int copy(int argc, const char **argv, const char *prefix) { int retval = 0, force = 0, from_stdin = 0; -- const unsigned char *from_note, *note; ++ const struct object_id *from_note, *note; const char *object_ref; -- unsigned char object[20], from_obj[20]; ++ struct object_id object, from_obj; struct notes_tree *t; const char *rewrite_cmd = NULL; struct option options[] = { @@@@ -511,37 -511,37 -510,37 +512,37 @@@@ usage_with_options(git_notes_copy_usage, options); } -- if (get_sha1(argv[0], from_obj)) ++ if (get_oid(argv[0], &from_obj)) die(_("failed to resolve '%s' as a valid ref."), argv[0]); object_ref = 1 < argc ? argv[1] : "HEAD"; -- if (get_sha1(object_ref, object)) ++ if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("copy", NOTES_INIT_WRITABLE); -- note = get_note(t, object); ++ note = get_note(t, &object); if (note) { if (!force) { retval = error(_("Cannot copy notes. Found existing " "notes for object %s. Use '-f' to " "overwrite existing notes"), -- sha1_to_hex(object)); ++ oid_to_hex(&object)); goto out; } fprintf(stderr, _("Overwriting existing notes for object %s\n"), -- sha1_to_hex(object)); ++ oid_to_hex(&object)); } -- from_note = get_note(t, from_obj); ++ from_note = get_note(t, &from_obj); if (!from_note) { retval = error(_("missing notes on source object %s. Cannot " -- "copy."), sha1_to_hex(from_obj)); ++ "copy."), oid_to_hex(&from_obj)); goto out; } -- if (add_note(t, object, from_note, combine_notes_overwrite)) ++ if (add_note(t, &object, from_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); commit_notes(t, "Notes added by 'git notes copy'"); out: @@@@ -554,8 -554,8 -553,8 +555,8 @@@@ static int append_edit(int argc, const int allow_empty = 0; const char *object_ref; struct notes_tree *t; -- unsigned char object[20], new_note[20]; -- const unsigned char *note; ++ struct object_id object, new_note; ++ const struct object_id *note; char *logmsg; const char * const *usage; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; @@@@ -594,19 -594,19 -593,19 +595,19 @@@@ object_ref = 1 < argc ? argv[1] : "HEAD"; -- if (get_sha1(object_ref, object)) ++ if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check(argv[0], NOTES_INIT_WRITABLE); -- note = get_note(t, object); ++ note = get_note(t, &object); -- prepare_note_data(object, &d, edit ? note : NULL); ++ prepare_note_data(&object, &d, edit && note ? note->hash : NULL); if (note && !edit) { /* Append buf to previous note contents */ unsigned long size; enum object_type type; -- char *prev_buf = read_sha1_file(note, &type, &size); ++ char *prev_buf = read_sha1_file(note->hash, &type, &size); strbuf_grow(&d.buf, size + 1); if (d.buf.len && prev_buf && size) @@@@ -617,14 -617,14 -616,14 +618,14 @@@@ } if (d.buf.len || allow_empty) { -- write_note_data(&d, new_note); -- if (add_note(t, object, new_note, combine_notes_overwrite)) ++ write_note_data(&d, new_note.hash); ++ if (add_note(t, &object, &new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]); } else { fprintf(stderr, _("Removing note for object %s\n"), -- sha1_to_hex(object)); -- remove_note(t, object); ++ oid_to_hex(&object)); ++ remove_note(t, object.hash); logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]); } commit_notes(t, logmsg); @@@@ -639,8 -639,8 -638,8 +640,8 @@@@ static int show(int argc, const char ** { const char *object_ref; struct notes_tree *t; -- unsigned char object[20]; -- const unsigned char *note; ++ struct object_id object; ++ const struct object_id *note; int retval; struct option options[] = { OPT_END() @@@@ -656,17 -656,17 -655,17 +657,17 @@@@ object_ref = argc ? argv[0] : "HEAD"; -- if (get_sha1(object_ref, object)) ++ if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("show", 0); -- note = get_note(t, object); ++ note = get_note(t, &object); if (!note) retval = error(_("no note found for object %s."), -- sha1_to_hex(object)); ++ oid_to_hex(&object)); else { -- const char *show_args[3] = {"show", sha1_to_hex(note), NULL}; ++ const char *show_args[3] = {"show", oid_to_hex(note), NULL}; retval = execv_git_cmd(show_args); } free_notes(t); @@@@ -708,7 -708,7 -707,7 +709,7 @@@@ static int merge_commit(struct notes_me if (get_oid("NOTES_MERGE_PARTIAL", &oid)) die(_("failed to read ref NOTES_MERGE_PARTIAL")); - else if (!(partial = lookup_commit_reference(oid.hash))) + else if (!(partial = lookup_commit_reference(&oid))) die(_("could not find commit from NOTES_MERGE_PARTIAL.")); else if (parse_commit(partial)) die(_("could not parse commit from NOTES_MERGE_PARTIAL.")); @@@@ -726,7 -726,7 -725,7 +727,7 @@@@ if (!o->local_ref) die(_("failed to resolve NOTES_MERGE_REF")); -- if (notes_merge_commit(o, t, partial, oid.hash)) ++ if (notes_merge_commit(o, t, partial, &oid)) die(_("failed to finalize notes merge")); /* Reuse existing commit message in reflog message */ @@@@ -762,7 -762,7 -761,7 +763,7 @@@@ static int git_config_get_notes_strateg static int merge(int argc, const char **argv, const char *prefix) { struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT; -- unsigned char result_sha1[20]; ++ struct object_id result_oid; struct notes_tree *t; struct notes_merge_options o; int do_merge = 0, do_commit = 0, do_abort = 0; @@@@ -844,16 -844,16 -843,16 +845,16 @@@@ remote_ref.buf, default_notes_ref()); strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */ -- result = notes_merge(&o, t, result_sha1); ++ result = notes_merge(&o, t, &result_oid); -- if (result >= 0) /* Merge resulted (trivially) in result_sha1 */ ++ if (result >= 0) /* Merge resulted (trivially) in result_oid */ /* Update default notes ref with new commit */ -- update_ref(msg.buf, default_notes_ref(), result_sha1, NULL, ++ update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); else { /* Merge has unresolved conflicts */ const struct worktree *wt; /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */ -- update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL, ++ update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */ wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref()); @@@@ -880,10 -880,10 -879,10 +881,10 @@@@ static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag) { int status; -- unsigned char sha1[20]; -- if (get_sha1(name, sha1)) ++ struct object_id oid; ++ if (get_oid(name, &oid)) return error(_("Failed to resolve '%s' as a valid ref."), name); -- status = remove_note(t, sha1); ++ status = remove_note(t, oid.hash); if (status) fprintf(stderr, _("Object %s has no note\n"), name); else diff --combined builtin/pack-objects.c index f672225def,f672225def,0e17184354..d5e96ed2d0 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "attr.h" #include "object.h" #include "blob.h" @@@@ -44,7 -44,7 -45,7 +45,7 @@@@ static uint32_t nr_result, nr_written static int non_empty; static int reuse_delta = 1, reuse_object = 1; static int keep_unreachable, unpack_unreachable, include_tag; -static unsigned long unpack_unreachable_expiration; +static timestamp_t unpack_unreachable_expiration; static int pack_loose_unreachable; static int local; static int have_non_local_packs; @@@@ -106,14 -106,14 -107,12 +107,14 @@@@ static void *get_delta(struct object_en void *buf, *base_buf, *delta_buf; enum object_type type; - buf = read_sha1_file(entry->idx.sha1, &type, &size); + buf = read_sha1_file(entry->idx.oid.hash, &type, &size); if (!buf) - die("unable to read %s", sha1_to_hex(entry->idx.sha1)); - base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size); + die("unable to read %s", oid_to_hex(&entry->idx.oid)); + base_buf = read_sha1_file(entry->delta->idx.oid.hash, &type, + &base_size); if (!base_buf) - die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1)); + die("unable to read %s", + oid_to_hex(&entry->delta->idx.oid)); delta_buf = diff_delta(base_buf, base_size, buf, size, &delta_size, 0); if (!delta_buf || delta_size != entry->delta_size) @@@@ -251,14 -251,14 -250,12 +252,14 @@@@ static unsigned long write_no_reuse_obj if (!usable_delta) { if (entry->type == OBJ_BLOB && entry->size > big_file_threshold && - (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL) + (st = open_istream(entry->idx.oid.hash, &type, &size, NULL)) != NULL) buf = NULL; else { - buf = read_sha1_file(entry->idx.sha1, &type, &size); + buf = read_sha1_file(entry->idx.oid.hash, &type, + &size); if (!buf) - die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1)); + die(_("unable to read %s"), + oid_to_hex(&entry->idx.oid)); } /* * make sure no cached delta data remains from a @@@@ -326,7 -326,7 -323,7 +327,7 @@@@ return 0; } sha1write(f, header, hdrlen); - sha1write(f, entry->delta->idx.sha1, 20); + sha1write(f, entry->delta->idx.oid.hash, 20); hdrlen += 20; } else { if (limit && hdrlen + datalen + 20 >= limit) { @@@@ -338,7 -338,7 -335,7 +339,7 @@@@ sha1write(f, header, hdrlen); } if (st) { - datalen = write_large_blob_data(st, f, entry->idx.sha1); + datalen = write_large_blob_data(st, f, entry->idx.oid.hash); close_istream(st); } else { sha1write(f, buf, datalen); @@@@ -373,8 -373,8 -370,7 +374,8 @@@@ static off_t write_reuse_object(struct datalen = revidx[1].offset - offset; if (!pack_to_stdout && p->index_version > 1 && check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) { - error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1)); + error("bad packed object CRC for %s", + oid_to_hex(&entry->idx.oid)); unuse_pack(&w_curs); return write_no_reuse_object(f, entry, limit, usable_delta); } @@@@ -384,8 -384,8 -380,7 +385,8 @@@@ if (!pack_to_stdout && p->index_version == 1 && check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) { - error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1)); + error("corrupt packed object for %s", + oid_to_hex(&entry->idx.oid)); unuse_pack(&w_curs); return write_no_reuse_object(f, entry, limit, usable_delta); } @@@@ -410,7 -410,7 -405,7 +411,7 @@@@ return 0; } sha1write(f, header, hdrlen); - sha1write(f, entry->delta->idx.sha1, 20); + sha1write(f, entry->delta->idx.oid.hash, 20); hdrlen += 20; reused_delta++; } else { @@@@ -515,7 -515,7 -510,7 +516,7 @@@@ static enum write_one_status write_one( recursing = (e->idx.offset == 1); if (recursing) { warning("recursive delta detected for object %s", - sha1_to_hex(e->idx.sha1)); + oid_to_hex(&e->idx.oid)); return WRITE_ONE_RECURSIVE; } else if (e->idx.offset || e->preferred_base) { /* offset is non zero if object is written already. */ @@@@ -1438,7 -1438,7 -1433,7 +1439,7 @@@@ static void check_object(struct object_ ofs += 1; if (!ofs || MSB(ofs, 7)) { error("delta base offset overflow in pack for %s", - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); goto give_up; } c = buf[used_0++]; @@@@ -1447,7 -1447,7 -1442,7 +1448,7 @@@@ ofs = entry->in_pack_offset - ofs; if (ofs <= 0 || ofs >= entry->in_pack_offset) { error("delta base offset out of bound for %s", - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); goto give_up; } if (reuse_delta && !entry->preferred_base) { @@@@ -1504,7 -1504,7 -1499,7 +1505,7 @@@@ unuse_pack(&w_curs); } - entry->type = sha1_object_info(entry->idx.sha1, &entry->size); + entry->type = sha1_object_info(entry->idx.oid.hash, &entry->size); /* * The error condition is checked in prepare_pack(). This is * to permit a missing preferred base object to be ignored @@@@ -1520,7 -1520,7 -1515,7 +1521,7 @@@@ static int pack_offset_sort(const void /* avoid filesystem trashing with loose objects */ if (!a->in_pack && !b->in_pack) - return hashcmp(a->idx.sha1, b->idx.sha1); + return oidcmp(&a->idx.oid, &b->idx.oid); if (a->in_pack < b->in_pack) return -1; @@@@ -1566,8 -1566,8 -1561,7 +1567,8 @@@@ static void drop_reused_delta(struct ob * And if that fails, the error will be recorded in entry->type * and dealt with in prepare_pack(). */ - entry->type = sha1_object_info(entry->idx.sha1, &entry->size); + entry->type = sha1_object_info(entry->idx.oid.hash, + &entry->size); } } @@@@ -1859,29 -1859,29 -1853,26 +1860,29 @@@@ static int try_delta(struct unpacked *t /* Load data if not already done */ if (!trg->data) { read_lock(); - trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz); + trg->data = read_sha1_file(trg_entry->idx.oid.hash, &type, + &sz); read_unlock(); if (!trg->data) die("object %s cannot be read", - sha1_to_hex(trg_entry->idx.sha1)); + oid_to_hex(&trg_entry->idx.oid)); if (sz != trg_size) die("object %s inconsistent object length (%lu vs %lu)", - sha1_to_hex(trg_entry->idx.sha1), sz, trg_size); + oid_to_hex(&trg_entry->idx.oid), sz, + trg_size); *mem_usage += sz; } if (!src->data) { read_lock(); - src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz); + src->data = read_sha1_file(src_entry->idx.oid.hash, &type, + &sz); read_unlock(); if (!src->data) { if (src_entry->preferred_base) { static int warned = 0; if (!warned++) warning("object %s cannot be read", - sha1_to_hex(src_entry->idx.sha1)); + oid_to_hex(&src_entry->idx.oid)); /* * Those objects are not included in the * resulting pack. Be resilient and ignore @@@@ -1891,12 -1891,12 -1882,11 +1892,12 @@@@ return 0; } die("object %s cannot be read", - sha1_to_hex(src_entry->idx.sha1)); + oid_to_hex(&src_entry->idx.oid)); } if (sz != src_size) die("object %s inconsistent object length (%lu vs %lu)", - sha1_to_hex(src_entry->idx.sha1), sz, src_size); + oid_to_hex(&src_entry->idx.oid), sz, + src_size); *mem_usage += sz; } if (!src->index) { @@@@ -2348,7 -2348,7 -2338,7 +2349,7 @@@@ static void add_tag_chain(const struct if (packlist_find(&to_pack, oid->hash, NULL)) return; - tag = lookup_tag(oid->hash); + tag = lookup_tag(oid); while (1) { if (!tag || parse_tag(tag) || !tag->tagged) die("unable to pack objects reachable from tag %s", @@@@ -2417,7 -2417,7 -2407,7 +2418,7 @@@@ static void prepare_pack(int window, in nr_deltas++; if (entry->type < 0) die("unable to get type of object %s", - sha1_to_hex(entry->idx.sha1)); + oid_to_hex(&entry->idx.oid)); } else { if (entry->type < 0) { /* @@@@ -2483,10 -2483,10 -2473,8 +2484,10 @@@@ static int git_pack_config(const char * die("invalid number of threads specified (%d)", delta_search_threads); #ifdef NO_PTHREADS - if (delta_search_threads != 1) + if (delta_search_threads != 1) { warning("no threads support, ignoring %s", k); + delta_search_threads = 0; + } #endif return 0; } @@@@ -2688,7 -2688,7 -2676,7 +2689,7 @@@@ static int has_sha1_pack_kept_or_nonloc static struct oid_array recent_objects; static int loosened_object_can_be_discarded(const struct object_id *oid, - unsigned long mtime) + timestamp_t mtime) { if (!unpack_unreachable_expiration) return 0; @@@@ -2730,11 -2730,11 -2718,7 +2731,11 @@@@ static void loosen_unused_packed_object */ static int pack_options_allow_reuse(void) { - return pack_to_stdout && allow_ofs_delta; + return pack_to_stdout && + allow_ofs_delta && + !ignore_packed_keep && + (!local || !have_non_local_packs) && + !incremental; } static int get_object_list_from_bitmap(struct rev_info *revs) @@@@ -2794,10 -2794,10 -2778,10 +2795,10 @@@@ static void get_object_list(int ac, con continue; } if (starts_with(line, "--shallow ")) { - unsigned char sha1[20]; - if (get_sha1_hex(line + 10, sha1)) + struct object_id oid; + if (get_oid_hex(line + 10, &oid)) die("not an SHA-1 '%s'", line + 10); - register_shallow(sha1); + register_shallow(&oid); use_bitmap_index = 0; continue; } diff --combined builtin/pull.c index 69417e4f36,da8b60fc85,3632921f03..2ce311a52e --- a/builtin/pull.c +++ b/builtin/pull.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ * Fetch one or more remote refs and merge it/them into the current HEAD. */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "parse-options.h" #include "exec_cmd.h" @@@@ -337,7 -337,8 -338,8 +338,7 @@@@ static void get_merge_heads(struct oid_ struct strbuf sb = STRBUF_INIT; struct object_id oid; -- if (!(fp = fopen(filename, "r"))) -- die_errno(_("could not open '%s' for reading"), filename); ++ fp = xfopen(filename, "r"); while (strbuf_getline_lf(&sb, fp) != EOF) { if (get_oid_hex(sb.buf, &oid)) continue; /* invalid line: does not start with SHA1 */ @@@@ -522,7 -523,7 -524,7 +523,7 @@@@ static int pull_into_void(const struct * index/worktree changes that the user already made on the unborn * branch. */ - if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0)) + if (checkout_fast_forward(&empty_tree_oid, merge_head, 0)) return 1; if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR)) @@@@ -697,10 -698,10 -699,10 +698,10 @@@@ static int get_octopus_merge_base(struc { struct commit_list *revs = NULL, *result; - commit_list_insert(lookup_commit_reference(curr_head->hash), &revs); - commit_list_insert(lookup_commit_reference(merge_head->hash), &revs); + commit_list_insert(lookup_commit_reference(curr_head), &revs); + commit_list_insert(lookup_commit_reference(merge_head), &revs); if (!is_null_oid(fork_point)) - commit_list_insert(lookup_commit_reference(fork_point->hash), &revs); + commit_list_insert(lookup_commit_reference(fork_point), &revs); result = reduce_heads(get_octopus_merge_bases(revs)); free_commit_list(revs); @@@@ -771,7 -772,7 -773,6 +772,7 @@@@ int cmd_pull(int argc, const char **arg struct oid_array merge_heads = OID_ARRAY_INIT; struct object_id orig_head, curr_head; struct object_id rebase_fork_point; + int autostash; if (!getenv("GIT_REFLOG_ACTION")) set_reflog_message(argc, argv); @@@@ -800,8 -801,8 -801,8 +801,8 @@@@ if (!opt_rebase && opt_autostash != -1) die(_("--[no-]autostash option is only valid with --rebase.")); + autostash = config_autostash; if (opt_rebase) { - int autostash = config_autostash; if (opt_autostash != -1) autostash = opt_autostash; @@@@ -839,7 -840,7 -840,7 +840,7 @@@@ "fast-forwarding your working tree from\n" "commit %s."), oid_to_hex(&orig_head)); - if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0)) + if (checkout_fast_forward(&orig_head, &curr_head, 0)) die(_("Cannot fast-forward your working tree.\n" "After making sure that you saved anything precious from\n" "$ git diff %s\n" @@@@ -862,18 -863,18 -863,16 +863,18 @@@@ die(_("Cannot rebase onto multiple branches.")); if (opt_rebase) { - struct commit_list *list = NULL; - struct commit *merge_head, *head; - - head = lookup_commit_reference(orig_head.hash); - commit_list_insert(head, &list); - merge_head = lookup_commit_reference(merge_heads.oid[0].hash); - if (is_descendant_of(merge_head, list)) { - /* we can fast-forward this without invoking rebase */ - opt_ff = "--ff-only"; - return run_merge(); + if (!autostash) { + struct commit_list *list = NULL; + struct commit *merge_head, *head; + + head = lookup_commit_reference(&orig_head); + commit_list_insert(head, &list); + merge_head = lookup_commit_reference(&merge_heads.oid[0]); + if (is_descendant_of(merge_head, list)) { + /* we can fast-forward this without invoking rebase */ + opt_ff = "--ff-only"; + return run_merge(); + } } return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point); } else { diff --combined builtin/push.c index 258648d5fd,a597759d8f,76aa713d22..03846e8379 --- a/builtin/push.c +++ b/builtin/push.c @@@@ -2,6 -2,6 -2,7 +2,7 @@@@ * "git push" */ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "run-command.h" #include "builtin.h" @@@@ -498,10 -498,6 -499,6 +499,10 @@@@ static int git_push_config(const char * const char *value; if (!git_config_get_value("push.recursesubmodules", &value)) recurse_submodules = parse_push_recurse_submodules_arg(k, value); ++ } else if (!strcmp(k, "submodule.recurse")) { ++ int val = git_config_bool(k, v) ? ++ RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; ++ recurse_submodules = val; } return git_default_config(k, v, NULL); diff --combined builtin/read-tree.c index 5bfd4c9f76,78d3193659,0a85b6d938..d5f618d086 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@@@ -5,6 -5,6 -5,7 +5,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "object.h" #include "tree.h" @@@@ -21,14 -21,15 -22,15 +22,14 @@@@ static int nr_trees; static int read_empty; static struct tree *trees[MAX_UNPACK_TREES]; --static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; -static int list_tree(unsigned char *sha1) +static int list_tree(struct object_id *oid) { struct tree *tree; if (nr_trees >= MAX_UNPACK_TREES) die("I cannot read more than %d trees", MAX_UNPACK_TREES); - tree = parse_tree_indirect(sha1); + tree = parse_tree_indirect(oid); if (!tree) return -1; trees[nr_trees++] = tree; @@@@ -98,12 -99,21 -100,21 +99,12 @@@@ static int debug_merge(const struct cac return 0; } --static int option_parse_recurse_submodules(const struct option *opt, -- const char *arg, int unset) ++static int git_read_tree_config(const char *var, const char *value, void *cb) { -- if (unset) { -- recurse_submodules = RECURSE_SUBMODULES_OFF; -- return 0; -- } -- if (arg) -- recurse_submodules = -- parse_update_recurse_submodules_arg(opt->long_name, -- arg); -- else -- recurse_submodules = RECURSE_SUBMODULES_ON; ++ if (!strcmp(var, "submodule.recurse")) ++ return git_default_submodule_config(var, value, cb); -- return 0; ++ return git_default_config(var, value, cb); } static struct lock_file lock_file; @@@@ -111,7 -121,7 -122,7 +112,7 @@@@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) { int i, stage = 0; - unsigned char sha1[20]; + struct object_id oid; struct tree_desc t[MAX_UNPACK_TREES]; struct unpack_trees_options opts; int prefix_set = 0; @@@@ -147,9 -157,9 -158,9 +148,9 @@@@ N_("skip applying sparse checkout filter")), OPT_BOOL(0, "debug-unpack", &opts.debug_unpack, N_("debug unpack-trees")), -- { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, ++ { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "checkout", "control recursive updating of submodules", -- PARSE_OPT_OPTARG, option_parse_recurse_submodules }, ++ PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater }, OPT_END() }; @@@@ -158,14 -168,18 -169,18 +159,14 @@@@ opts.src_index = &the_index; opts.dst_index = &the_index; -- git_config(git_default_config, NULL); ++ git_config(git_read_tree_config, NULL); argc = parse_options(argc, argv, unused_prefix, read_tree_options, read_tree_usage, 0); -- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); ++ load_submodule_cache(); -- if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) { -- gitmodules_config(); -- git_config(submodule_config, NULL); -- set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON); -- } ++ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) @@@@ -190,13 -204,13 -205,13 +191,13 @@@@ for (i = 0; i < argc; i++) { const char *arg = argv[i]; - if (get_sha1(arg, sha1)) + if (get_oid(arg, &oid)) die("Not a valid object name %s", arg); - if (list_tree(sha1) < 0) + if (list_tree(&oid) < 0) die("failed to unpack tree object %s", arg); stage++; } - if (nr_trees == 0 && !read_empty) + if (!nr_trees && !read_empty && !opts.merge) warning("read-tree: emptying the index with no arguments is deprecated; use --empty"); else if (nr_trees > 0 && read_empty) die("passing trees as arguments contradicts --empty"); @@@@ -212,10 -226,10 -227,9 +213,10 @@@@ setup_work_tree(); if (opts.merge) { - if (stage < 2) - die("just how do you expect me to merge %d trees?", stage-1); switch (stage - 1) { + case 0: + die("you must specify at least one tree to merge"); + break; case 1: opts.fn = opts.prefix ? bind_merge : oneway_merge; break; diff --combined builtin/receive-pack.c index b1706a5731,b1706a5731,01ae7154e6..71c0c768db --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "builtin.h" ++ #include "config.h" #include "lockfile.h" #include "pack.h" #include "refs.h" @@@@ -78,7 -78,7 -79,7 +79,7 @@@@ static const char *NONCE_OK = "OK" static const char *NONCE_SLOP = "SLOP"; static const char *nonce_status; static long nonce_stamp_slop; -static unsigned long nonce_stamp_slop_limit; +static timestamp_t nonce_stamp_slop_limit; static struct ref_transaction *transaction; static enum { @@@@ -454,17 -454,17 -455,17 +455,17 @@@@ static void hmac_sha1(unsigned char *ou git_SHA1_Final(out, &ctx); } -static char *prepare_push_cert_nonce(const char *path, unsigned long stamp) +static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp) { struct strbuf buf = STRBUF_INIT; unsigned char sha1[20]; - strbuf_addf(&buf, "%s:%lu", path, stamp); + strbuf_addf(&buf, "%s:%"PRItime, path, stamp); hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));; strbuf_release(&buf); /* RFC 2104 5. HMAC-SHA1-80 */ - strbuf_addf(&buf, "%lu-%.*s", stamp, 20, sha1_to_hex(sha1)); + strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, 20, sha1_to_hex(sha1)); return strbuf_detach(&buf, NULL); } @@@@ -473,8 -473,8 -474,7 +474,8 @@@@ * after dropping "_commit" from its name and possibly moving it out * of commit.c */ -static char *find_header(const char *msg, size_t len, const char *key) +static char *find_header(const char *msg, size_t len, const char *key, + const char **next_line) { int key_len = strlen(key); const char *line = msg; @@@@ -487,8 -487,8 -487,6 +488,8 @@@@ if (line + key_len < eol && !memcmp(line, key, key_len) && line[key_len] == ' ') { int offset = key_len + 1; + if (next_line) + *next_line = *eol ? eol + 1 : eol; return xmemdupz(line + offset, (eol - line) - offset); } line = *eol ? eol + 1 : NULL; @@@@ -498,8 -498,8 -496,8 +499,8 @@@@ static const char *check_nonce(const char *buf, size_t len) { - char *nonce = find_header(buf, len, "nonce"); - unsigned long stamp, ostamp; + char *nonce = find_header(buf, len, "nonce", NULL); + timestamp_t stamp, ostamp; char *bohmac, *expect = NULL; const char *retval = NONCE_BAD; @@@@ -537,7 -537,7 -535,7 +538,7 @@@@ retval = NONCE_BAD; goto leave; } - stamp = strtoul(nonce, &bohmac, 10); + stamp = parse_timestamp(nonce, &bohmac, 10); if (bohmac == nonce || bohmac[0] != '-') { retval = NONCE_BAD; goto leave; @@@@ -555,7 -555,7 -553,7 +556,7 @@@@ * would mean it was issued by another server with its clock * skewed in the future. */ - ostamp = strtoul(push_cert_nonce, NULL, 10); + ostamp = parse_timestamp(push_cert_nonce, NULL, 10); nonce_stamp_slop = (long)ostamp - (long)stamp; if (nonce_stamp_slop_limit && @@@@ -578,45 -578,45 -576,6 +579,45 @@@@ leave return retval; } +/* + * Return 1 if there is no push_cert or if the push options in push_cert are + * the same as those in the argument; 0 otherwise. + */ +static int check_cert_push_options(const struct string_list *push_options) +{ + const char *buf = push_cert.buf; + int len = push_cert.len; + + char *option; + const char *next_line; + int options_seen = 0; + + int retval = 1; + + if (!len) + return 1; + + while ((option = find_header(buf, len, "push-option", &next_line))) { + len -= (next_line - buf); + buf = next_line; + options_seen++; + if (options_seen > push_options->nr + || strcmp(option, + push_options->items[options_seen - 1].string)) { + retval = 0; + goto leave; + } + free(option); + } + + if (options_seen != push_options->nr) + retval = 0; + +leave: + free(option); + return retval; +} + static void prepare_push_cert_sha1(struct child_process *proc) { static int already_done; @@@@ -900,7 -900,7 -859,7 +901,7 @@@@ static int update_shallow_ref(struct co * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) - register_shallow(extra.oid[i].hash); + register_shallow(&extra.oid[i]); si->shallow_ref[cmd->index] = 0; oid_array_clear(&extra); @@@@ -1028,8 -1028,8 -987,7 +1029,8 @@@@ static const char *update(struct comman { const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; - const char *namespaced_name, *ret; + static char *namespaced_name; + const char *ret; struct object_id *old_oid = &cmd->old_oid; struct object_id *new_oid = &cmd->new_oid; @@@@ -1040,7 -1040,7 -998,6 +1041,7 @@@@ } strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); + free(namespaced_name); namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); if (is_ref_checked_out(namespaced_name)) { @@@@ -1102,8 -1102,8 -1059,8 +1103,8 @@@@ struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - old_object = parse_object(old_oid->hash); - new_object = parse_object(new_oid->hash); + old_object = parse_object(old_oid); + new_object = parse_object(new_oid); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || @@@@ -1126,7 -1126,7 -1083,7 +1127,7 @@@@ if (is_null_oid(new_oid)) { struct strbuf err = STRBUF_INIT; - if (!parse_object(old_oid->hash)) { + if (!parse_object(old_oid)) { old_oid = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); @@@@ -1973,11 -1973,11 -1930,6 +1974,11 @@@@ int cmd_receive_pack(int argc, const ch if (use_push_options) read_push_options(&push_options); + if (!check_cert_push_options(&push_options)) { + struct command *cmd; + for (cmd = commands; cmd; cmd = cmd->next) + cmd->error_string = "inconsistent push options"; + } prepare_shallow_info(&si, &shallow); if (!si.nr_ours && !si.nr_theirs) diff --combined builtin/reflog.c index 920c16dac0,920c16dac0,6e9a8213ea..44cdc2dbd0 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "builtin.h" ++ #include "config.h" #include "lockfile.h" #include "commit.h" #include "refs.h" @@@@ -16,14 -16,14 -17,14 +17,14 @@@@ static const char reflog_delete_usage[ static const char reflog_exists_usage[] = "git reflog exists "; -static unsigned long default_reflog_expire; -static unsigned long default_reflog_expire_unreachable; +static timestamp_t default_reflog_expire; +static timestamp_t default_reflog_expire_unreachable; struct cmd_reflog_expire_cb { struct rev_info revs; int stalefix; - unsigned long expire_total; - unsigned long expire_unreachable; + timestamp_t expire_total; + timestamp_t expire_unreachable; int recno; }; @@@@ -55,14 -55,14 -56,14 +56,14 @@@@ struct collect_reflog_cb #define STUDYING (1u<<11) #define REACHABLE (1u<<12) -static int tree_is_complete(const unsigned char *sha1) +static int tree_is_complete(const struct object_id *oid) { struct tree_desc desc; struct name_entry entry; int complete; struct tree *tree; - tree = lookup_tree(sha1); + tree = lookup_tree(oid); if (!tree) return 0; if (tree->object.flags & SEEN) @@@@ -73,7 -73,7 -74,7 +74,7 @@@@ if (!tree->buffer) { enum object_type type; unsigned long size; - void *data = read_sha1_file(sha1, &type, &size); + void *data = read_sha1_file(oid->hash, &type, &size); if (!data) { tree->object.flags |= INCOMPLETE; return 0; @@@@ -85,7 -85,7 -86,7 +86,7 @@@@ complete = 1; while (tree_entry(&desc, &entry)) { if (!has_sha1_file(entry.oid->hash) || - (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid->hash))) { + (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid))) { tree->object.flags |= INCOMPLETE; complete = 0; } @@@@ -126,7 -126,7 -127,7 +127,7 @@@@ static int commit_is_complete(struct co struct commit_list *parent; c = (struct commit *)study.objects[--study.nr].item; - if (!c->object.parsed && !parse_object(c->object.oid.hash)) + if (!c->object.parsed && !parse_object(&c->object.oid)) c->object.flags |= INCOMPLETE; if (c->object.flags & INCOMPLETE) { @@@@ -152,7 -152,7 -153,7 +153,7 @@@@ for (i = 0; i < found.nr; i++) { struct commit *c = (struct commit *)found.objects[i].item; - if (!tree_is_complete(c->tree->object.oid.hash)) { + if (!tree_is_complete(&c->tree->object.oid)) { is_incomplete = 1; c->object.flags |= INCOMPLETE; } @@@@ -186,13 -186,13 -187,13 +187,13 @@@@ return !is_incomplete; } -static int keep_entry(struct commit **it, unsigned char *sha1) +static int keep_entry(struct commit **it, struct object_id *oid) { struct commit *commit; - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return 1; - commit = lookup_commit_reference_gently(sha1, 1); + commit = lookup_commit_reference_gently(oid, 1); if (!commit) return 0; @@@@ -219,7 -219,7 -220,7 +220,7 @@@@ static void mark_reachable(struct expire_reflog_policy_cb *cb) { struct commit_list *pending; - unsigned long expire_limit = cb->mark_limit; + timestamp_t expire_limit = cb->mark_limit; struct commit_list *leftover = NULL; for (pending = cb->mark_list; pending; pending = pending->next) @@@@ -251,17 -251,17 -252,17 +252,17 @@@@ cb->mark_list = leftover; } -static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1) +static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid) { /* * We may or may not have the commit yet - if not, look it * up using the supplied sha1. */ if (!commit) { - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return 0; - commit = lookup_commit_reference_gently(sha1, 1); + commit = lookup_commit_reference_gently(oid, 1); /* Not a commit -- keep it */ if (!commit) @@@@ -283,8 -283,8 -284,8 +284,8 @@@@ /* * Return true iff the specified reflog entry should be expired. */ -static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, - const char *email, unsigned long timestamp, int tz, +static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; @@@@ -295,13 -295,13 -296,13 +296,13 @@@@ old = new = NULL; if (cb->cmd.stalefix && - (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1))) + (!keep_entry(&old, ooid) || !keep_entry(&new, noid))) return 1; if (timestamp < cb->cmd.expire_unreachable) { if (cb->unreachable_expire_kind == UE_ALWAYS) return 1; - if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1)) + if (unreachable(cb, old, ooid) || unreachable(cb, new, noid)) return 1; } @@@@ -318,7 -318,7 -319,7 +319,7 @@@@ static int push_tip_to_list(const char struct commit *tip_commit; if (flags & REF_ISSYMREF) return 0; - tip_commit = lookup_commit_reference_gently(oid->hash, 1); + tip_commit = lookup_commit_reference_gently(oid, 1); if (!tip_commit) return 0; commit_list_insert(tip_commit, list); @@@@ -326,7 -326,7 -327,7 +327,7 @@@@ } static void reflog_expiry_prepare(const char *refname, - const unsigned char *sha1, + const struct object_id *oid, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; @@@@ -335,7 -335,7 -336,7 +336,7 @@@@ cb->tip_commit = NULL; cb->unreachable_expire_kind = UE_HEAD; } else { - cb->tip_commit = lookup_commit_reference_gently(sha1, 1); + cb->tip_commit = lookup_commit_reference_gently(oid, 1); if (!cb->tip_commit) cb->unreachable_expire_kind = UE_ALWAYS; else @@@@ -392,8 -392,8 -393,8 +393,8 @@@@ static int collect_reflog(const char *r static struct reflog_expire_cfg { struct reflog_expire_cfg *next; - unsigned long expire_total; - unsigned long expire_unreachable; + timestamp_t expire_total; + timestamp_t expire_unreachable; char pattern[FLEX_ARRAY]; } *reflog_expire_cfg, **reflog_expire_cfg_tail; @@@@ -415,7 -415,7 -416,7 +416,7 @@@@ static struct reflog_expire_cfg *find_c return ent; } -static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire) +static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire) { if (!value) return config_error_nonbool(var); @@@@ -433,7 -433,7 -434,7 +434,7 @@@@ static int reflog_expire_config(const c { const char *pattern, *key; int pattern_len; - unsigned long expire; + timestamp_t expire; int slot; struct reflog_expire_cfg *ent; @@@@ -515,7 -515,7 -516,7 +516,7 @@@@ static void set_reflog_expiry_param(str static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) { struct expire_reflog_policy_cb cb; - unsigned long now = time(NULL); + timestamp_t now = time(NULL); int i, status, do_all; int explicit_expiry = 0; unsigned int flags = 0; @@@@ -616,7 -616,7 -617,7 +617,7 @@@@ } static int count_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; diff --combined builtin/remote.c index f1a88fe265,f1a88fe265,a470ed7c62..6273c0c23c --- a/builtin/remote.c +++ b/builtin/remote.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "builtin.h" ++ #include "config.h" #include "parse-options.h" #include "transport.h" #include "remote.h" @@@@ -786,7 -786,7 -787,7 +787,7 @@@@ static int rm(int argc, const char **ar strbuf_release(&buf); if (!result) - result = delete_refs(&branches, REF_NODEREF); + result = delete_refs("remote: remove", &branches, REF_NODEREF); string_list_clear(&branches, 0); if (skipped.nr) { @@@@ -1151,11 -1151,11 -1152,8 +1152,11 @@@@ static int show(int argc, const char ** url_nr = states.remote->url_nr; } for (i = 0; i < url_nr; i++) - /* TRANSLATORS: the colon ':' should align with - the one in " Fetch URL: %s" translation */ + /* + * TRANSLATORS: the colon ':' should align + * with the one in " Fetch URL: %s" + * translation. + */ printf_ln(_(" Push URL: %s"), url[i]); if (!i) printf_ln(_(" Push URL: %s"), _("(no URL)")); @@@@ -1304,7 -1304,7 -1302,7 +1305,7 @@@@ static int prune_remote(const char *rem string_list_sort(&refs_to_prune); if (!dry_run) - result |= delete_refs(&refs_to_prune, 0); + result |= delete_refs("remote: prune", &refs_to_prune, 0); for_each_string_list_item(item, &states.stale) { const char *refname = item->util; diff --combined builtin/repack.c index 38ba4ef825,38ba4ef825,c01ff7c30b..f17a68a17d --- a/builtin/repack.c +++ b/builtin/repack.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "dir.h" #include "parse-options.h" #include "run-command.h" @@@@ -155,7 -155,7 -156,6 +156,7 @@@@ int cmd_repack(int argc, const char **a int keep_unreachable = 0; const char *window = NULL, *window_memory = NULL; const char *depth = NULL; + const char *threads = NULL; const char *max_pack_size = NULL; int no_reuse_delta = 0, no_reuse_object = 0; int no_update_server_info = 0; @@@@ -191,8 -191,8 -191,6 +192,8 @@@@ N_("same as the above, but limit memory size instead of entries count")), OPT_STRING(0, "depth", &depth, N_("n"), N_("limits the maximum delta depth")), + OPT_STRING(0, "threads", &threads, N_("n"), + N_("limits the maximum number of threads")), OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"), N_("maximum size of each packfile")), OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects, @@@@ -237,8 -237,8 -235,6 +238,8 @@@@ argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory); if (depth) argv_array_pushf(&cmd.args, "--depth=%s", depth); + if (threads) + argv_array_pushf(&cmd.args, "--threads=%s", threads); if (max_pack_size) argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size); if (no_reuse_delta) diff --combined builtin/replace.c index c921bc976f,c921bc976f,905b1759a4..80a15cf35f --- a/builtin/replace.c +++ b/builtin/replace.c @@@@ -9,6 -9,6 -9,7 +9,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "refs.h" #include "parse-options.h" @@@@ -328,7 -328,7 -329,7 +329,7 @@@@ static void replace_parents(struct strb struct object_id oid; if (get_oid(argv[i], &oid) < 0) die(_("Not a valid object name: '%s'"), argv[i]); - lookup_commit_or_die(oid.hash, argv[i]); + lookup_commit_or_die(&oid, argv[i]); strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid)); } @@@@ -355,7 -355,7 -356,7 +356,7 @@@@ static void check_one_mergetag(struct c int i; hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash); - tag = lookup_tag(tag_oid.hash); + tag = lookup_tag(&tag_oid); if (!tag) die(_("bad mergetag in commit '%s'"), ref); if (parse_tag_buffer(tag, extra->value, extra->len)) @@@@ -394,7 -394,7 -395,7 +395,7 @@@@ static int create_graft(int argc, cons if (get_oid(old_ref, &old) < 0) die(_("Not a valid object name: '%s'"), old_ref); - commit = lookup_commit_or_die(old.hash, old_ref); + commit = lookup_commit_or_die(&old, old_ref); buffer = get_commit_buffer(commit, &size); strbuf_add(&buf, buffer, size); diff --combined builtin/reset.c index 45001e5200,430602d102,fdd5e5e003..7aeaea2737 --- a/builtin/reset.c +++ b/builtin/reset.c @@@@ -8,6 -8,6 -8,7 +8,7 @@@@ * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano */ #include "builtin.h" ++ #include "config.h" #include "lockfile.h" #include "tag.h" #include "object.h" @@@@ -21,9 -21,28 -22,7 +22,9 @@@@ #include "parse-options.h" #include "unpack-trees.h" #include "cache-tree.h" +#include "submodule.h" +#include "submodule-config.h" - static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; - - static int option_parse_recurse_submodules(const struct option *opt, - const char *arg, int unset) - { - if (unset) { - recurse_submodules = RECURSE_SUBMODULES_OFF; - return 0; - } - if (arg) - recurse_submodules = - parse_update_recurse_submodules_arg(opt->long_name, - arg); - else - recurse_submodules = RECURSE_SUBMODULES_ON; - - return 0; - } - static const char * const git_reset_usage[] = { N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] []"), N_("git reset [-q] [] [--] ..."), @@@@ -86,7 -105,7 -85,7 +87,7 @@@@ static int reset_index(const struct obj return -1; if (reset_type == MIXED || reset_type == HARD) { - tree = parse_tree_indirect(oid->hash); + tree = parse_tree_indirect(oid); prime_cache_tree(&the_index, tree); } @@@@ -156,7 -175,7 -155,7 +157,7 @@@@ static int read_from_tree(const struct opt.format_callback = update_index_from_diff; opt.format_callback_data = &intent_to_add; - if (do_diff_cache(tree_oid->hash, &opt)) + if (do_diff_cache(tree_oid, &opt)) return 1; diffcore_std(&opt); diff_flush(&opt); @@@@ -238,6 -257,6 -237,7 +239,6 @@@@ static void parse_args(struct pathspec parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL | - PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP | (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0), prefix, argv); } @@@@ -265,14 -284,6 -265,6 +266,14 @@@@ static int reset_refs(const char *rev, return update_ref_status; } ++static int git_reset_config(const char *var, const char *value, void *cb) ++{ ++ if (!strcmp(var, "submodule.recurse")) ++ return git_default_submodule_config(var, value, cb); ++ ++ return git_default_config(var, value, cb); ++} ++ int cmd_reset(int argc, const char **argv, const char *prefix) { int reset_type = NONE, update_ref_status = 0, quiet = 0; @@@@ -292,23 -303,27 -284,18 +293,23 @@@@ N_("reset HEAD, index and working tree"), MERGE), OPT_SET_INT(0, "keep", &reset_type, N_("reset HEAD but keep local changes"), KEEP), - { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, ++ { OPTION_CALLBACK, 0, "recurse-submodules", NULL, + "reset", "control recursive updating of submodules", - PARSE_OPT_OPTARG, option_parse_recurse_submodules }, ++ PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater }, OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")), OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that removed paths will be added later")), OPT_END() }; -- git_config(git_default_config, NULL); ++ git_config(git_reset_config, NULL); argc = parse_options(argc, argv, prefix, options, git_reset_usage, PARSE_OPT_KEEP_DASHDASH); parse_args(&pathspec, argv, prefix, patch_mode, &rev); - if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) { - gitmodules_config(); - git_config(submodule_config, NULL); - set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON); - } ++ load_submodule_cache(); + unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash); if (unborn) { /* reset on unborn branch: treat as reset to empty tree */ @@@@ -317,7 -332,7 -304,7 +318,7 @@@@ struct commit *commit; if (get_sha1_committish(rev, oid.hash)) die(_("Failed to resolve '%s' as a valid revision."), rev); - commit = lookup_commit_reference(oid.hash); + commit = lookup_commit_reference(&oid); if (!commit) die(_("Could not parse object '%s'."), rev); oidcpy(&oid, &commit->object.oid); @@@@ -325,7 -340,7 -312,7 +326,7 @@@@ struct tree *tree; if (get_sha1_treeish(rev, oid.hash)) die(_("Failed to resolve '%s' as a valid tree."), rev); - tree = parse_tree_indirect(oid.hash); + tree = parse_tree_indirect(&oid); if (!tree) die(_("Could not parse object '%s'."), rev); oidcpy(&oid, &tree->object.oid); @@@@ -394,7 -409,7 -381,7 +395,7 @@@@ update_ref_status = reset_refs(rev, &oid); if (reset_type == HARD && !update_ref_status && !quiet) - print_new_head_line(lookup_commit_reference(oid.hash)); + print_new_head_line(lookup_commit_reference(&oid)); } if (!pathspec.nr) remove_branch_state(); diff --combined builtin/rev-list.c index b250c515b1,718c6059c9,f9e2caee16..95d84d5cda --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "diff.h" #include "revision.h" @@@@ -80,7 -80,7 -81,7 +81,7 @@@@ static void show_commit(struct commit * } if (info->show_timestamp) - printf("%lu ", commit->date); + printf("%"PRItime" ", commit->date); if (info->header_prefix) fputs(info->header_prefix, stdout); @@@@ -181,7 -181,7 -182,7 +182,7 @@@@ static void finish_object(struct objec if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) die("missing blob object '%s'", oid_to_hex(&obj->oid)); if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) - parse_object(obj->oid.hash); + parse_object(&obj->oid); } static void show_object(struct object *obj, const char *name, void *cb_data) @@@@ -277,9 -277,6 -278,6 +278,9 @@@@ int cmd_rev_list(int argc, const char * int use_bitmap_index = 0; const char *show_progress = NULL; ++ if (argc == 2 && !strcmp(argv[1], "-h")) ++ usage(rev_list_usage); ++ git_config(git_default_config, NULL); init_revisions(&revs, prefix); revs.abbrev = DEFAULT_ABBREV; diff --combined builtin/rev-parse.c index efdc14473b,efdc14473b,9d18bbd648..c78b7b33d6 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "refs.h" #include "quote.h" @@@@ -121,7 -121,7 -122,7 +122,7 @@@@ static void show_with_type(int type, co } /* Output a revision, only if filter allows it */ -static void show_rev(int type, const unsigned char *sha1, const char *name) +static void show_rev(int type, const struct object_id *oid, const char *name) { if (!(filter & DO_REVS)) return; @@@@ -129,10 -129,10 -130,10 +130,10 @@@@ if ((symbolic || abbrev_ref) && name) { if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) { - unsigned char discard[20]; + struct object_id discard; char *full; - switch (dwim_ref(name, strlen(name), discard, &full)) { + switch (dwim_ref(name, strlen(name), discard.hash, &full)) { case 0: /* * Not found -- not a ref. We could @@@@ -158,9 -158,9 -159,9 +159,9 @@@@ } } else if (abbrev) - show_with_type(type, find_unique_abbrev(sha1, abbrev)); + show_with_type(type, find_unique_abbrev(oid->hash, abbrev)); else - show_with_type(type, sha1_to_hex(sha1)); + show_with_type(type, oid_to_hex(oid)); } /* Output a flag, only if filter allows it. */ @@@@ -180,11 -180,11 -181,11 +181,11 @@@@ static int show_default(void const char *s = def; if (s) { - unsigned char sha1[20]; + struct object_id oid; def = NULL; - if (!get_sha1(s, sha1)) { - show_rev(NORMAL, sha1, s); + if (!get_oid(s, &oid)) { + show_rev(NORMAL, &oid, s); return 1; } } @@@@ -195,19 -195,19 -196,19 +196,19 @@@@ static int show_reference(const char *r { if (ref_excluded(ref_excludes, refname)) return 0; - show_rev(NORMAL, oid->hash, refname); + show_rev(NORMAL, oid, refname); return 0; } static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - show_rev(REVERSED, oid->hash, refname); + show_rev(REVERSED, oid, refname); return 0; } static int show_abbrev(const struct object_id *oid, void *cb_data) { - show_rev(NORMAL, oid->hash, NULL); + show_rev(NORMAL, oid, NULL); return 0; } @@@@ -218,7 -218,7 -219,7 +219,7 @@@@ static void show_datestring(const char /* date handling requires both flags and revs */ if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS)) return; - buffer = xstrfmt("%s%lu", flag, approxidate(datestr)); + buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr)); show(buffer); free(buffer); } @@@@ -242,8 -242,8 -243,8 +243,8 @@@@ static int show_file(const char *arg, i static int try_difference(const char *arg) { char *dotdot; - unsigned char sha1[20]; - unsigned char end[20]; + struct object_id oid; + struct object_id end; const char *next; const char *this; int symmetric; @@@@ -273,18 -273,18 -274,18 +274,18 @@@@ return 0; } - if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) { - show_rev(NORMAL, end, next); - show_rev(symmetric ? NORMAL : REVERSED, sha1, this); + if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) { + show_rev(NORMAL, &end, next); + show_rev(symmetric ? NORMAL : REVERSED, &oid, this); if (symmetric) { struct commit_list *exclude; struct commit *a, *b; - a = lookup_commit_reference(sha1); - b = lookup_commit_reference(end); + a = lookup_commit_reference(&oid); + b = lookup_commit_reference(&end); exclude = get_merge_bases(a, b); while (exclude) { struct commit *commit = pop_commit(&exclude); - show_rev(REVERSED, commit->object.oid.hash, NULL); + show_rev(REVERSED, &commit->object.oid, NULL); } } *dotdot = '.'; @@@@ -297,7 -297,7 -298,7 +298,7 @@@@ static int try_parent_shorthands(const char *arg) { char *dotdot; - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; struct commit_list *parents; int parent_number; @@@@ -327,12 -327,12 -328,12 +328,12 @@@@ return 0; *dotdot = 0; - if (get_sha1_committish(arg, sha1)) { + if (get_sha1_committish(arg, oid.hash)) { *dotdot = '^'; return 0; } - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (exclude_parent && exclude_parent > commit_list_count(commit->parents)) { *dotdot = '^'; @@@@ -340,7 -340,7 -341,7 +341,7 @@@@ } if (include_rev) - show_rev(NORMAL, sha1, arg); + show_rev(NORMAL, &oid, arg); for (parents = commit->parents, parent_number = 1; parents; parents = parents->next, parent_number++) { @@@@ -352,7 -352,7 -353,7 +353,7 @@@@ if (symbolic) name = xstrfmt("%s^%d", arg, parent_number); show_rev(include_parents ? NORMAL : REVERSED, - parents->item->object.oid.hash, name); + &parents->item->object.oid, name); free(name); } @@@@ -571,7 -571,7 -572,7 +572,7 @@@@ int cmd_rev_parse(int argc, const char int did_repo_setup = 0; int has_dashdash = 0; int output_prefix = 0; - unsigned char sha1[20]; + struct object_id oid; unsigned int flags = 0; const char *name = NULL; struct object_context unused; @@@@ -910,11 -910,11 -911,11 +911,11 @@@@ name++; type = REVERSED; } - if (!get_sha1_with_context(name, flags, sha1, &unused)) { + if (!get_sha1_with_context(name, flags, oid.hash, &unused)) { if (verify) revs_count++; else - show_rev(type, sha1, name); + show_rev(type, &oid, name); continue; } if (verify) @@@@ -929,7 -929,7 -930,7 +930,7 @@@@ strbuf_release(&buf); if (verify) { if (revs_count == 1) { - show_rev(type, sha1, name); + show_rev(type, &oid, name); return 0; } else if (revs_count == 0 && show_default()) return 0; diff --combined builtin/rm.c index b39f10fcb6,7c323d0123,b1adf1c961..52826d1379 --- a/builtin/rm.c +++ b/builtin/rm.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) Linus Torvalds 2006 */ #include "builtin.h" ++ #include "config.h" #include "lockfile.h" #include "dir.h" #include "cache-tree.h" @@@@ -129,7 -129,7 -130,7 +130,7 @@@@ static int check_local_mod(struct objec ce = active_cache[pos]; if (lstat(ce->name, &st) < 0) { -- if (errno != ENOENT && errno != ENOTDIR) ++ if (!is_missing_file_error(errno)) warning_errno(_("failed to stat '%s'"), ce->name); /* It already vanished from the working tree */ continue; @@@@ -271,7 -271,7 -272,8 +272,7 @@@@ int cmd_rm(int argc, const char **argv die(_("index file corrupt")); parse_pathspec(&pathspec, 0, - PATHSPEC_PREFER_CWD | - PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, + PATHSPEC_PREFER_CWD, prefix, argv); refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL); diff --combined builtin/show-branch.c index 4a6cc6f490,4a6cc6f490,6825439970..e4cf1b5bb2 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "refs.h" #include "builtin.h" @@@@ -358,7 -358,7 -359,7 +359,7 @@@@ static void sort_ref_range(int bottom, static int append_ref(const char *refname, const struct object_id *oid, int allow_dups) { - struct commit *commit = lookup_commit_reference_gently(oid->hash, 1); + struct commit *commit = lookup_commit_reference_gently(oid, 1); int i; if (!commit) @@@@ -735,7 -735,7 -736,7 +736,7 @@@@ int cmd_show_branch(int ac, const char base = strtoul(reflog_base, &ep, 10); if (*ep) { /* Ah, that is a date spec... */ - unsigned long at; + timestamp_t at; at = approxidate(reflog_base); read_ref_at(ref, flags, at, -1, oid.hash, NULL, NULL, NULL, &base); @@@@ -746,7 -746,7 -747,7 +747,7 @@@@ char *logmsg; char *nth_desc; const char *msg; - unsigned long timestamp; + timestamp_t timestamp; int tz; if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg, @@@@ -816,7 -816,7 -817,7 +817,7 @@@@ MAX_REVS), MAX_REVS); if (get_sha1(ref_name[num_rev], revkey.hash)) die(_("'%s' is not a valid ref."), ref_name[num_rev]); - commit = lookup_commit_reference(revkey.hash); + commit = lookup_commit_reference(&revkey); if (!commit) die(_("cannot find commit %s (%s)"), ref_name[num_rev], oid_to_hex(&revkey)); diff --combined builtin/submodule--helper.c index 1b4d2b3467,8cc648d85b,700460c349..8517032b3e --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "parse-options.h" #include "quote.h" #include "pathspec.h" @@@@ -233,7 -233,7 -234,8 +234,7 @@@@ static int module_list_compute(int argc int i, result = 0; char *ps_matched = NULL; parse_pathspec(pathspec, 0, - PATHSPEC_PREFER_FULL | - PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, + PATHSPEC_PREFER_FULL, prefix, argv); if (pathspec->nr) @@@@ -1221,8 -1221,9 -1223,9 +1222,8 @@@@ static struct cmd_struct commands[] = int cmd_submodule__helper(int argc, const char **argv, const char *prefix) { int i; -- if (argc < 2) -- die(_("submodule--helper subcommand must be " -- "called with a subcommand")); ++ if (argc < 2 || !strcmp(argv[1], "-h")) ++ usage("git submodule--helper "); for (i = 0; i < ARRAY_SIZE(commands); i++) { if (!strcmp(argv[1], commands[i].cmd)) { diff --combined builtin/tag.c index 1f74a56db7,1f74a56db7,b85bcf6809..01154ea8dc --- a/builtin/tag.c +++ b/builtin/tag.c @@@@ -7,6 -7,6 -7,7 +7,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "refs.h" #include "tag.h" @@@@ -66,7 -66,7 -67,7 +67,7 @@@@ static int list_tags(struct ref_filter } typedef int (*each_tag_name_fn)(const char *name, const char *ref, - const unsigned char *sha1, const void *cb_data); + const struct object_id *oid, const void *cb_data); static int for_each_tag_name(const char **argv, each_tag_name_fn fn, const void *cb_data) @@@@ -74,17 -74,17 -75,17 +75,17 @@@@ const char **p; struct strbuf ref = STRBUF_INIT; int had_error = 0; - unsigned char sha1[20]; + struct object_id oid; for (p = argv; *p; p++) { strbuf_reset(&ref); strbuf_addf(&ref, "refs/tags/%s", *p); - if (read_ref(ref.buf, sha1)) { + if (read_ref(ref.buf, oid.hash)) { error(_("tag '%s' not found."), *p); had_error = 1; continue; } - if (fn(*p, ref.buf, sha1, cb_data)) + if (fn(*p, ref.buf, &oid, cb_data)) had_error = 1; } strbuf_release(&ref); @@@@ -92,16 -92,16 -93,16 +93,16 @@@@ } static int delete_tag(const char *name, const char *ref, - const unsigned char *sha1, const void *cb_data) + const struct object_id *oid, const void *cb_data) { - if (delete_ref(NULL, ref, sha1, 0)) + if (delete_ref(NULL, ref, oid->hash, 0)) return 1; - printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV)); + printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV)); return 0; } static int verify_tag(const char *name, const char *ref, - const unsigned char *sha1, const void *cb_data) + const struct object_id *oid, const void *cb_data) { int flags; const char *fmt_pretty = cb_data; @@@@ -110,11 -110,11 -111,11 +111,11 @@@@ if (fmt_pretty) flags = GPG_VERIFY_OMIT_STATUS; - if (gpg_verify_tag(sha1, name, flags)) + if (gpg_verify_tag(oid->hash, name, flags)) return -1; if (fmt_pretty) - pretty_print_ref(name, sha1, fmt_pretty); + pretty_print_ref(name, oid->hash, fmt_pretty); return 0; } @@@@ -182,13 -182,13 -183,13 +183,13 @@@@ static int git_tag_config(const char *v return git_default_config(var, value, cb); } -static void write_tag_body(int fd, const unsigned char *sha1) +static void write_tag_body(int fd, const struct object_id *oid) { unsigned long size; enum object_type type; char *buf, *sp; - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); if (!buf) return; /* skip header */ @@@@ -204,11 -204,11 -205,11 +205,11 @@@@ free(buf); } -static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result) +static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result) { if (sign && do_sign(buf) < 0) return error(_("unable to sign the tag")); - if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0) + if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0) return error(_("unable to write tag file")); return 0; } @@@@ -223,15 -223,15 -224,15 +224,15 @@@@ struct create_tag_options } cleanup_mode; }; -static void create_tag(const unsigned char *object, const char *tag, +static void create_tag(const struct object_id *object, const char *tag, struct strbuf *buf, struct create_tag_options *opt, - unsigned char *prev, unsigned char *result) + struct object_id *prev, struct object_id *result) { enum object_type type; struct strbuf header = STRBUF_INIT; char *path = NULL; - type = sha1_object_info(object, NULL); + type = sha1_object_info(object->hash, NULL); if (type <= OBJ_NONE) die(_("bad object type.")); @@@@ -240,7 -240,7 -241,7 +241,7 @@@@ "type %s\n" "tag %s\n" "tagger %s\n\n", - sha1_to_hex(object), + oid_to_hex(object), typename(type), tag, git_committer_info(IDENT_STRICT)); @@@@ -254,7 -254,7 -255,7 +255,7 @@@@ if (fd < 0) die_errno(_("could not create file '%s'"), path); - if (!is_null_sha1(prev)) { + if (!is_null_oid(prev)) { write_tag_body(fd, prev); } else { struct strbuf buf = STRBUF_INIT; @@@@ -296,7 -296,7 -297,7 +297,7 @@@@ } } -static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb) +static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb) { enum object_type type; struct commit *c; @@@@ -310,17 -310,17 -311,17 +311,17 @@@@ strbuf_addstr(sb, rla); } else { strbuf_addstr(sb, "tag: tagging "); - strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV); } strbuf_addstr(sb, " ("); - type = sha1_object_info(sha1, NULL); + type = sha1_object_info(oid->hash, NULL); switch (type) { default: strbuf_addstr(sb, "object of unknown type"); break; case OBJ_COMMIT: - if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) { + if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) { subject_len = find_commit_subject(buf, &subject_start); strbuf_insert(sb, sb->len, subject_start, subject_len); } else { @@@@ -328,7 -328,7 -329,7 +329,7 @@@@ } free(buf); - if ((c = lookup_commit_reference(sha1)) != NULL) + if ((c = lookup_commit_reference(oid)) != NULL) strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT))); break; case OBJ_TREE: @@@@ -378,7 -378,7 -379,7 +379,7 @@@@ int cmd_tag(int argc, const char **argv struct strbuf buf = STRBUF_INIT; struct strbuf ref = STRBUF_INIT; struct strbuf reflog_msg = STRBUF_INIT; - unsigned char object[20], prev[20]; + struct object_id object, prev; const char *object_ref, *tag; struct create_tag_options opt; char *cleanup_arg = NULL; @@@@ -528,14 -528,14 -529,14 +529,14 @@@@ if (argc > 2) die(_("too many params")); - if (get_sha1(object_ref, object)) + if (get_oid(object_ref, &object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); if (strbuf_check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); - if (read_ref(ref.buf, prev)) - hashclr(prev); + if (read_ref(ref.buf, prev.hash)) + oidclr(&prev); else if (!force) die(_("tag '%s' already exists"), tag); @@@@ -550,24 -550,24 -551,24 +551,24 @@@@ else die(_("Invalid cleanup mode %s"), cleanup_arg); - create_reflog_msg(object, &reflog_msg); + create_reflog_msg(&object, &reflog_msg); if (create_tag_object) { if (force_sign_annotate && !annotate) opt.sign = 1; - create_tag(object, tag, &buf, &opt, prev, object); + create_tag(&object, tag, &buf, &opt, &prev, &object); } transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, ref.buf, object, prev, + ref_transaction_update(transaction, ref.buf, object.hash, prev.hash, create_reflog ? REF_FORCE_CREATE_REFLOG : 0, reflog_msg.buf, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); - if (force && !is_null_sha1(prev) && hashcmp(prev, object)) - printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV)); + if (force && !is_null_oid(&prev) && oidcmp(&prev, &object)) + printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV)); strbuf_release(&err); strbuf_release(&buf); diff --combined builtin/unpack-objects.c index 8bc9997767,8bc9997767,9da06548f0..193f8b9d57 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "object.h" #include "delta.h" #include "pack.h" @@@@ -127,7 -127,7 -128,7 +128,7 @@@@ static void *get_data(unsigned long siz } struct delta_info { - unsigned char base_sha1[20]; + struct object_id base_oid; unsigned nr; off_t base_offset; unsigned long size; @@@@ -137,13 -137,13 -138,13 +138,13 @@@@ static struct delta_info *delta_list; -static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1, +static void add_delta_to_list(unsigned nr, const struct object_id *base_oid, off_t base_offset, void *delta, unsigned long size) { struct delta_info *info = xmalloc(sizeof(*info)); - hashcpy(info->base_sha1, base_sha1); + oidcpy(&info->base_oid, base_oid); info->base_offset = base_offset; info->size = size; info->delta = delta; @@@@ -154,7 -154,7 -155,7 +155,7 @@@@ struct obj_info { off_t offset; - unsigned char sha1[20]; + struct object_id oid; struct object *obj; }; @@@@ -170,9 -170,9 -171,9 +171,9 @@@@ static unsigned nr_objects */ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf) { - unsigned char sha1[20]; + struct object_id oid; - if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0) + if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0) die("failed to write object %s", oid_to_hex(&obj->oid)); obj->flags |= FLAG_WRITTEN; } @@@@ -237,19 -237,19 -238,19 +238,19 @@@@ static void write_object(unsigned nr, e void *buf, unsigned long size) { if (!strict) { - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) + if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0) die("failed to write object"); added_object(nr, type, buf, size); free(buf); obj_list[nr].obj = NULL; } else if (type == OBJ_BLOB) { struct blob *blob; - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) + if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0) die("failed to write object"); added_object(nr, type, buf, size); free(buf); - blob = lookup_blob(obj_list[nr].sha1); + blob = lookup_blob(&obj_list[nr].oid); if (blob) blob->object.flags |= FLAG_WRITTEN; else @@@@ -258,10 -258,10 -259,9 +259,10 @@@@ } else { struct object *obj; int eaten; - hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1); + hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash); added_object(nr, type, buf, size); - obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten); + obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf, + &eaten); if (!obj) die("invalid %s", typename(type)); add_object_buffer(obj, buf, size); @@@@ -297,7 -297,7 -297,7 +298,7 @@@@ static void added_object(unsigned nr, e struct delta_info *info; while ((info = *p) != NULL) { - if (!hashcmp(info->base_sha1, obj_list[nr].sha1) || + if (!oidcmp(&info->base_oid, &obj_list[nr].oid) || info->base_offset == obj_list[nr].offset) { *p = info->next; p = &delta_list; @@@@ -321,12 -321,12 -321,12 +322,12 @@@@ static void unpack_non_delta_entry(enu free(buf); } -static int resolve_against_held(unsigned nr, const unsigned char *base, +static int resolve_against_held(unsigned nr, const struct object_id *base, void *delta_data, unsigned long delta_size) { struct object *obj; struct obj_buffer *obj_buffer; - obj = lookup_object(base); + obj = lookup_object(base->hash); if (!obj) return 0; obj_buffer = lookup_object_buffer(obj); @@@@ -342,25 -342,25 -342,25 +343,25 @@@@ static void unpack_delta_entry(enum obj { void *delta_data, *base; unsigned long base_size; - unsigned char base_sha1[20]; + struct object_id base_oid; if (type == OBJ_REF_DELTA) { - hashcpy(base_sha1, fill(20)); - use(20); + hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ)); + use(GIT_SHA1_RAWSZ); delta_data = get_data(delta_size); if (dry_run || !delta_data) { free(delta_data); return; } - if (has_sha1_file(base_sha1)) + if (has_object_file(&base_oid)) ; /* Ok we have this one */ - else if (resolve_against_held(nr, base_sha1, + else if (resolve_against_held(nr, &base_oid, delta_data, delta_size)) return; /* we are done */ else { /* cannot resolve yet --- queue it */ - hashclr(obj_list[nr].sha1); - add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size); + oidclr(&obj_list[nr].oid); + add_delta_to_list(nr, &base_oid, 0, delta_data, delta_size); return; } } else { @@@@ -400,8 -400,8 -400,8 +401,8 @@@@ } else if (base_offset > obj_list[mid].offset) { lo = mid + 1; } else { - hashcpy(base_sha1, obj_list[mid].sha1); - base_found = !is_null_sha1(base_sha1); + oidcpy(&base_oid, &obj_list[mid].oid); + base_found = !is_null_oid(&base_oid); break; } } @@@@ -410,19 -410,19 -410,19 +411,19 @@@@ * The delta base object is itself a delta that * has not been resolved yet. */ - hashclr(obj_list[nr].sha1); - add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size); + oidclr(&obj_list[nr].oid); + add_delta_to_list(nr, &null_oid, base_offset, delta_data, delta_size); return; } } - if (resolve_against_held(nr, base_sha1, delta_data, delta_size)) + if (resolve_against_held(nr, &base_oid, delta_data, delta_size)) return; - base = read_sha1_file(base_sha1, &type, &base_size); + base = read_sha1_file(base_oid.hash, &type, &base_size); if (!base) { error("failed to read delta-pack base object %s", - sha1_to_hex(base_sha1)); + oid_to_hex(&base_oid)); if (!recover) exit(1); has_errors = 1; @@@@ -506,7 -506,7 -506,7 +507,7 @@@@ static void unpack_all(void int cmd_unpack_objects(int argc, const char **argv, const char *prefix) { int i; - unsigned char sha1[20]; + struct object_id oid; check_replace_refs = 0; @@@@ -567,12 -567,12 -567,12 +568,12 @@@@ git_SHA1_Init(&ctx); unpack_all(); git_SHA1_Update(&ctx, buffer, offset); - git_SHA1_Final(sha1, &ctx); + git_SHA1_Final(oid.hash, &ctx); if (strict) write_rest(); - if (hashcmp(fill(20), sha1)) + if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash)) die("final sha1 did not match"); - use(20); + use(GIT_SHA1_RAWSZ); /* Write the last part of the buffer to stdout */ while (len) { diff --combined builtin/update-index.c index f99b1e5790,ebfc09faa0,0a4c236487..56721cf03d --- a/builtin/update-index.c +++ b/builtin/update-index.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "quote.h" #include "cache-tree.h" @@@@ -257,7 -257,7 -258,7 +258,7 @@@@ static int remove_one_path(const char * */ static int process_lstat_error(const char *path, int err) { -- if (err == ENOENT || err == ENOTDIR) ++ if (is_missing_file_error(err)) return remove_one_path(path); return error("lstat(\"%s\"): %s", path, strerror(err)); } diff --combined builtin/verify-commit.c index 05b734e6d1,05b734e6d1,d5e9a17a77..ba38ac9b15 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ * Based on git-verify-tag */ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "commit.h" #include "run-command.h" @@@@ -18,14 -18,14 -19,14 +19,14 @@@@ static const char * const verify_commit NULL }; -static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, unsigned flags) +static int run_gpg_verify(const struct object_id *oid, const char *buf, unsigned long size, unsigned flags) { struct signature_check signature_check; int ret; memset(&signature_check, 0, sizeof(signature_check)); - ret = check_commit_signature(lookup_commit(sha1), &signature_check); + ret = check_commit_signature(lookup_commit(oid), &signature_check); print_signature_buffer(&signature_check, flags); signature_check_clear(&signature_check); @@@@ -35,22 -35,22 -36,22 +36,22 @@@@ static int verify_commit(const char *name, unsigned flags) { enum object_type type; - unsigned char sha1[20]; + struct object_id oid; char *buf; unsigned long size; int ret; - if (get_sha1(name, sha1)) + if (get_oid(name, &oid)) return error("commit '%s' not found.", name); - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid.hash, &type, &size); if (!buf) return error("%s: unable to read file.", name); if (type != OBJ_COMMIT) return error("%s: cannot verify a non-commit object of type %s.", name, typename(type)); - ret = run_gpg_verify(sha1, buf, size, flags); + ret = run_gpg_verify(&oid, buf, size, flags); free(buf); return ret; diff --combined builtin/worktree.c index 793306ea51,793306ea51,d414b6870b..0c5476ee9d --- a/builtin/worktree.c +++ b/builtin/worktree.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "dir.h" #include "parse-options.h" @@@@ -31,7 -31,7 -32,7 +32,7 @@@@ struct add_opts static int show_only; static int verbose; -static unsigned long expire; +static timestamp_t expire; static int prune_worktree(const char *id, struct strbuf *reason) { @@@@ -131,7 -131,7 -132,7 +132,7 @@@@ static int prune(int ac, const char **a OPT_END() }; - expire = ULONG_MAX; + expire = TIME_MAX; ac = parse_options(ac, av, prefix, options, worktree_usage, 0); if (ac) usage_with_options(worktree_usage, options); @@@@ -414,11 -414,11 -415,9 +415,11 @@@@ static void show_worktree(struct worktr find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV)); if (wt->is_detached) strbuf_addstr(&sb, "(detached HEAD)"); - else if (wt->head_ref) - strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0)); - else + else if (wt->head_ref) { + char *ref = shorten_unambiguous_ref(wt->head_ref, 0); + strbuf_addf(&sb, "[%s]", ref); + free(ref); + } else strbuf_addstr(&sb, "(error)"); } printf("%s\n", sb.buf); diff --combined cache.h index d6ba8a2f11,5a0e0a9e5d,82f39f7a9e..96055c2229 --- a/cache.h +++ b/cache.h @@@@ -525,12 -525,12 -525,15 +525,15 @@@@ extern void set_git_work_tree(const cha extern void setup_work_tree(void); /* -- * Find GIT_DIR of the repository that contains the current working directory, -- * without changing the working directory or other global state. The result is -- * appended to gitdir. The return value is either NULL if no repository was -- * found, or pointing to the path inside gitdir's buffer. -- */ -- extern const char *discover_git_directory(struct strbuf *gitdir); ++ * Find the commondir and gitdir of the repository that contains the current ++ * working directory, without changing the working directory or other global ++ * state. The result is appended to commondir and gitdir. If the discovered ++ * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will ++ * both have the same result appended to the buffer. The return value is ++ * either 0 upon success and non-zero if no repository was found. ++ */ ++ extern int discover_git_directory(struct strbuf *commondir, ++ struct strbuf *gitdir); extern const char *setup_git_directory_gently(int *); extern const char *setup_git_directory(void); extern char *prefix_path(const char *prefix, int len, const char *path); @@@@ -597,7 -597,7 -600,6 +600,7 @@@@ extern int read_index_unmerged(struct i #define CLOSE_LOCK (1 << 1) extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags); extern int discard_index(struct index_state *); +extern void move_index_extensions(struct index_state *dst, struct index_state *src); extern int unmerged_index(const struct index_state *); extern int verify_path(const char *path); extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change); @@@@ -1026,13 -1026,6 -1028,6 +1029,13 @@@@ static inline void oidcpy(struct object hashcpy(dst->hash, src->hash); } ++static inline struct object_id *oiddup(const struct object_id *src) ++{ ++ struct object_id *dst = xmalloc(sizeof(struct object_id)); ++ oidcpy(dst, src); ++ return dst; ++} ++ static inline void hashclr(unsigned char *hash) { memset(hash, 0, GIT_SHA1_RAWSZ); @@@@ -1341,18 -1334,18 -1336,13 +1344,18 @@@@ static inline int hex2chr(const char *s struct object_context { unsigned char tree[20]; - char path[PATH_MAX]; unsigned mode; /* * symlink_path is only used by get_tree_entry_follow_symlinks, * and only for symlinks that point outside the repository. */ struct strbuf symlink_path; + /* + * If GET_SHA1_RECORD_PATH is set, this will record path (if any) + * found when resolving the name. The caller is responsible for + * releasing the memory. + */ + char *path; }; #define GET_SHA1_QUIETLY 01 @@@@ -1362,7 -1355,7 -1352,6 +1365,7 @@@@ #define GET_SHA1_TREEISH 020 #define GET_SHA1_BLOB 040 #define GET_SHA1_FOLLOW_SYMLINKS 0100 +#define GET_SHA1_RECORD_PATH 0200 #define GET_SHA1_ONLY_TO_DIE 04000 #define GET_SHA1_DISAMBIGUATORS \ @@@@ -1377,7 -1370,7 -1366,7 +1380,7 @@@@ extern int get_sha1_tree(const char *st extern int get_sha1_treeish(const char *str, unsigned char *sha1); extern int get_sha1_blob(const char *str, unsigned char *sha1); extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix); -extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc); +extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc); extern int get_oid(const char *str, struct object_id *oid); @@@@ -1493,18 -1486,18 -1482,18 +1496,18 @@@@ struct date_mode #define DATE_MODE(t) date_mode_from_type(DATE_##t) struct date_mode *date_mode_from_type(enum date_mode_type type); -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode); -void show_date_relative(unsigned long time, int tz, const struct timeval *now, +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode); +void show_date_relative(timestamp_t time, int tz, const struct timeval *now, struct strbuf *timebuf); int parse_date(const char *date, struct strbuf *out); -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset); -int parse_expiry_date(const char *date, unsigned long *timestamp); +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset); +int parse_expiry_date(const char *date, timestamp_t *timestamp); void datestamp(struct strbuf *out); #define approxidate(s) approxidate_careful((s), NULL) -unsigned long approxidate_careful(const char *, int *); -unsigned long approxidate_relative(const char *date, const struct timeval *now); +timestamp_t approxidate_careful(const char *, int *); +timestamp_t approxidate_relative(const char *date, const struct timeval *now); void parse_date_format(const char *format, struct date_mode *mode); -int date_overflows(unsigned long date); +int date_overflows(timestamp_t date); #define IDENT_STRICT 1 #define IDENT_NO_DATE 2 @@@@ -1879,188 -1872,188 -1868,9 +1882,9 @@@@ extern int packed_object_info(struct pa /* Dumb servers support */ extern int update_server_info(int); -- /* git_config_parse_key() returns these negated: */ -- #define CONFIG_INVALID_KEY 1 -- #define CONFIG_NO_SECTION_OR_NAME 2 -- /* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */ -- #define CONFIG_NO_LOCK -1 -- #define CONFIG_INVALID_FILE 3 -- #define CONFIG_NO_WRITE 4 -- #define CONFIG_NOTHING_SET 5 -- #define CONFIG_INVALID_PATTERN 6 -- #define CONFIG_GENERIC_ERROR 7 -- -- #define CONFIG_REGEX_NONE ((void *)1) -- -- struct git_config_source { -- unsigned int use_stdin:1; -- const char *file; -- const char *blob; -- }; -- -- enum config_origin_type { -- CONFIG_ORIGIN_BLOB, -- CONFIG_ORIGIN_FILE, -- CONFIG_ORIGIN_STDIN, -- CONFIG_ORIGIN_SUBMODULE_BLOB, -- CONFIG_ORIGIN_CMDLINE -- }; -- -- struct config_options { -- unsigned int respect_includes : 1; -- const char *git_dir; -- }; -- -- typedef int (*config_fn_t)(const char *, const char *, void *); -- extern int git_default_config(const char *, const char *, void *); -- extern int git_config_from_file(config_fn_t fn, const char *, void *); -- extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type, -- const char *name, const char *buf, size_t len, void *data); -- extern int git_config_from_blob_sha1(config_fn_t fn, const char *name, -- const unsigned char *sha1, void *data); -- extern void git_config_push_parameter(const char *text); -- extern int git_config_from_parameters(config_fn_t fn, void *data); -- extern void read_early_config(config_fn_t cb, void *data); -- extern void git_config(config_fn_t fn, void *); -- extern int git_config_with_options(config_fn_t fn, void *, -- struct git_config_source *config_source, -- const struct config_options *opts); -- extern int git_parse_ulong(const char *, unsigned long *); -- extern int git_parse_maybe_bool(const char *); -- extern int git_config_int(const char *, const char *); -- extern int64_t git_config_int64(const char *, const char *); -- extern unsigned long git_config_ulong(const char *, const char *); -- extern ssize_t git_config_ssize_t(const char *, const char *); -- extern int git_config_bool_or_int(const char *, const char *, int *); -- extern int git_config_bool(const char *, const char *); -- extern int git_config_maybe_bool(const char *, const char *); -- extern int git_config_string(const char **, const char *, const char *); -- extern int git_config_pathname(const char **, const char *, const char *); -- extern int git_config_set_in_file_gently(const char *, const char *, const char *); -- extern void git_config_set_in_file(const char *, const char *, const char *); -- extern int git_config_set_gently(const char *, const char *); -- extern void git_config_set(const char *, const char *); -- extern int git_config_parse_key(const char *, char **, int *); -- extern int git_config_key_is_valid(const char *key); -- extern int git_config_set_multivar_gently(const char *, const char *, const char *, int); -- extern void git_config_set_multivar(const char *, const char *, const char *, int); -- extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int); -- extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); -- extern int git_config_rename_section(const char *, const char *); -- extern int git_config_rename_section_in_file(const char *, const char *, const char *); -- extern const char *git_etc_gitconfig(void); -- extern int git_env_bool(const char *, int); -- extern unsigned long git_env_ulong(const char *, unsigned long); -- extern int git_config_system(void); -- extern int config_error_nonbool(const char *); -- #if defined(__GNUC__) -- #define config_error_nonbool(s) (config_error_nonbool(s), const_error()) -- #endif extern const char *get_log_output_encoding(void); extern const char *get_commit_output_encoding(void); -- extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data); -- -- enum config_scope { -- CONFIG_SCOPE_UNKNOWN = 0, -- CONFIG_SCOPE_SYSTEM, -- CONFIG_SCOPE_GLOBAL, -- CONFIG_SCOPE_REPO, -- CONFIG_SCOPE_CMDLINE, -- }; -- -- extern enum config_scope current_config_scope(void); -- extern const char *current_config_origin_type(void); -- extern const char *current_config_name(void); -- -- struct config_include_data { -- int depth; -- config_fn_t fn; -- void *data; -- const struct config_options *opts; -- }; -- #define CONFIG_INCLUDE_INIT { 0 } -- extern int git_config_include(const char *name, const char *value, void *data); -- -- /* -- * Match and parse a config key of the form: -- * -- * section.(subsection.)?key -- * -- * (i.e., what gets handed to a config_fn_t). The caller provides the section; -- * we return -1 if it does not match, 0 otherwise. The subsection and key -- * out-parameters are filled by the function (and *subsection is NULL if it is -- * missing). -- * -- * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if -- * there is no subsection at all. -- */ -- extern int parse_config_key(const char *var, -- const char *section, -- const char **subsection, int *subsection_len, -- const char **key); -- -- struct config_set_element { -- struct hashmap_entry ent; -- char *key; -- struct string_list value_list; -- }; -- -- struct configset_list_item { -- struct config_set_element *e; -- int value_index; -- }; -- -- /* -- * the contents of the list are ordered according to their -- * position in the config files and order of parsing the files. -- * (i.e. key-value pair at the last position of .git/config will -- * be at the last item of the list) -- */ -- struct configset_list { -- struct configset_list_item *items; -- unsigned int nr, alloc; -- }; -- -- struct config_set { -- struct hashmap config_hash; -- int hash_initialized; -- struct configset_list list; -- }; -- -- extern void git_configset_init(struct config_set *cs); -- extern int git_configset_add_file(struct config_set *cs, const char *filename); -- extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value); -- extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key); -- extern void git_configset_clear(struct config_set *cs); -- extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest); -- extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest); -- extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest); -- extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest); -- extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest); -- extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest); -- extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest); -- extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest); -- -- extern int git_config_get_value(const char *key, const char **value); -- extern const struct string_list *git_config_get_value_multi(const char *key); -- extern void git_config_clear(void); -- extern void git_config_iter(config_fn_t fn, void *data); -- extern int git_config_get_string_const(const char *key, const char **dest); -- extern int git_config_get_string(const char *key, char **dest); -- extern int git_config_get_int(const char *key, int *dest); -- extern int git_config_get_ulong(const char *key, unsigned long *dest); -- extern int git_config_get_bool(const char *key, int *dest); -- extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); -- extern int git_config_get_maybe_bool(const char *key, int *dest); -- extern int git_config_get_pathname(const char *key, const char **dest); -- extern int git_config_get_untracked_cache(void); -- extern int git_config_get_split_index(void); -- extern int git_config_get_max_percent_split_change(void); -- -- /* This dies if the configured or default date is in the future */ -- extern int git_config_get_expiry(const char *key, const char **output); -- /* * This is a hack for test programs like test-dump-untracked-cache to * ensure that they do not modify the untracked cache when reading it. @@@@ -2068,16 -2061,16 -1878,6 +1892,6 @@@@ */ extern int ignore_untracked_cache_config; -- struct key_value_info { -- const char *filename; -- int linenr; -- enum config_origin_type origin_type; -- enum config_scope scope; -- }; -- -- extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3))); -- extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr); -- extern int committer_ident_sufficiently_given(void); extern int author_ident_sufficiently_given(void); @@@@ -2193,7 -2186,8 -1993,7 +2007,8 @@@@ extern int ws_blank_line(const char *li #define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK) /* ls-files */ - -void overlay_tree_on_cache(const char *tree_name, const char *prefix); + +void overlay_tree_on_index(struct index_state *istate, + + const char *tree_name, const char *prefix); char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); @@@@ -2212,8 -2206,8 -2012,8 +2027,8 @@@@ struct commit_list int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes); -int checkout_fast_forward(const unsigned char *from, - const unsigned char *to, +int checkout_fast_forward(const struct object_id *from, + const struct object_id *to, int overwrite_ignore); diff --combined combine-diff.c index ec9d930440,74f723af3d,2848034fe9..9e163d5ada --- a/combine-diff.c +++ b/combine-diff.c @@@@ -302,7 -302,7 -302,7 +302,7 @@@@ static char *grab_blob(const struct obj return xcalloc(1, 1); } else if (textconv) { struct diff_filespec *df = alloc_filespec(path); -- fill_filespec(df, oid->hash, 1, mode); ++ fill_filespec(df, oid, 1, mode); *size = fill_textconv(textconv, df, &blob); free_filespec(df); } else { @@@@ -1022,7 -1022,7 -1022,7 +1022,7 @@@@ static void show_patch_diff(struct comb &result_size, NULL, NULL); } else if (textconv) { struct diff_filespec *df = alloc_filespec(elem->path); -- fill_filespec(df, null_sha1, 0, st.st_mode); ++ fill_filespec(df, &null_oid, 0, st.st_mode); result_size = fill_textconv(textconv, df, &result); free_filespec(df); } else if (0 <= (fd = open(elem->path, O_RDONLY))) { @@@@ -1053,7 -1053,7 -1053,7 +1053,7 @@@@ if (is_file) { struct strbuf buf = STRBUF_INIT; - - if (convert_to_git(elem->path, result, len, &buf, safe_crlf)) { + + if (convert_to_git(&the_index, elem->path, result, len, &buf, safe_crlf)) { free(result); result = strbuf_detach(&buf, &len); result_size = len; @@@@ -1311,7 -1311,7 -1311,7 +1311,7 @@@@ static const char *path_path(void *obj /* find set of paths that every parent touches */ --static struct combine_diff_path *find_paths_generic(const unsigned char *sha1, ++static struct combine_diff_path *find_paths_generic(const struct object_id *oid, const struct oid_array *parents, struct diff_options *opt) { struct combine_diff_path *paths = NULL; @@@@ -1336,7 -1336,7 -1336,7 +1336,7 @@@@ opt->output_format = stat_opt; else opt->output_format = DIFF_FORMAT_NO_OUTPUT; -- diff_tree_sha1(parents->oid[i].hash, sha1, "", opt); ++ diff_tree_oid(&parents->oid[i], oid, "", opt); diffcore_std(opt); paths = intersect_paths(paths, i, num_parent); @@@@ -1360,31 -1360,31 -1360,31 +1360,31 @@@@ * rename/copy detection, etc, comparing all trees simultaneously (= faster). */ static struct combine_diff_path *find_paths_multitree( -- const unsigned char *sha1, const struct oid_array *parents, ++ const struct object_id *oid, const struct oid_array *parents, struct diff_options *opt) { int i, nparent = parents->nr; -- const unsigned char **parents_sha1; ++ const struct object_id **parents_oid; struct combine_diff_path paths_head; struct strbuf base; -- ALLOC_ARRAY(parents_sha1, nparent); ++ ALLOC_ARRAY(parents_oid, nparent); for (i = 0; i < nparent; i++) -- parents_sha1[i] = parents->oid[i].hash; ++ parents_oid[i] = &parents->oid[i]; /* fake list head, so worker can assume it is non-NULL */ paths_head.next = NULL; strbuf_init(&base, PATH_MAX); -- diff_tree_paths(&paths_head, sha1, parents_sha1, nparent, &base, opt); ++ diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt); strbuf_release(&base); -- free(parents_sha1); ++ free(parents_oid); return paths_head.next; } --void diff_tree_combined(const unsigned char *sha1, ++void diff_tree_combined(const struct object_id *oid, const struct oid_array *parents, int dense, struct rev_info *rev) @@@@ -1448,11 -1448,11 -1448,11 +1448,11 @@@@ * diff(sha1,parent_i) for all i to do the job, specifically * for parent0. */ -- paths = find_paths_generic(sha1, parents, &diffopts); ++ paths = find_paths_generic(oid, parents, &diffopts); } else { int stat_opt; -- paths = find_paths_multitree(sha1, parents, &diffopts); ++ paths = find_paths_multitree(oid, parents, &diffopts); /* * show stat against the first parent even @@@@ -1463,7 -1463,7 -1463,7 +1463,7 @@@@ if (stat_opt) { diffopts.output_format = stat_opt; -- diff_tree_sha1(parents->oid[0].hash, sha1, "", &diffopts); ++ diff_tree_oid(&parents->oid[0], oid, "", &diffopts); diffcore_std(&diffopts); if (opt->orderfile) diffcore_order(opt->orderfile); @@@@ -1539,6 -1539,6 -1539,6 +1539,6 @@@@ void diff_tree_combined_merge(const str oid_array_append(&parents, &parent->item->object.oid); parent = parent->next; } -- diff_tree_combined(commit->object.oid.hash, &parents, dense, rev); ++ diff_tree_combined(&commit->object.oid, &parents, dense, rev); oid_array_clear(&parents); } diff --combined config.c index 34a139c40b,146cb3452a,ca9e9efec1..6f0f8b30f3 --- a/config.c +++ b/config.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ * */ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "exec_cmd.h" #include "strbuf.h" @@@@ -214,12 -214,12 -215,9 +215,10 @@@@ static int include_by_gitdir(const stru struct strbuf pattern = STRBUF_INIT; int ret = 0, prefix; const char *git_dir; + int already_tried_absolute = 0; if (opts->git_dir) git_dir = opts->git_dir; -- else if (have_git_dir()) -- git_dir = get_git_dir(); else goto done; @@@@ -227,7 -227,7 -225,6 +226,7 @@@@ strbuf_add(&pattern, cond, cond_len); prefix = prepare_include_condition_pattern(&pattern); +again: if (prefix < 0) goto done; @@@@ -247,20 -247,20 -244,6 +246,20 @@@@ ret = !wildmatch(pattern.buf + prefix, text.buf + prefix, icase ? WM_CASEFOLD : 0, NULL); + if (!ret && !already_tried_absolute) { + /* + * We've tried e.g. matching gitdir:~/work, but if + * ~/work is a symlink to /mnt/storage/work + * strbuf_realpath() will expand it, so the rule won't + * match. Let's match against a + * strbuf_add_absolute_path() version of the path, + * which'll do the right thing + */ + strbuf_reset(&text); + strbuf_add_absolute_path(&text, git_dir); + already_tried_absolute = 1; + goto again; + } done: strbuf_release(&pattern); strbuf_release(&text); @@@@ -604,7 -604,7 -587,8 +603,8 @@@@ static int get_value(config_fn_t fn, vo */ cf->linenr--; ret = fn(name->buf, value, data); -- cf->linenr++; ++ if (ret >= 0) ++ cf->linenr++; return ret; } @@@@ -1438,7 -1438,7 -1422,7 +1438,7 @@@@ int git_config_from_file(config_fn_t fn int ret = -1; FILE *f; -- f = fopen(filename, "r"); ++ f = fopen_or_warn(filename, "r"); if (f) { flockfile(f); ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data); @@@@ -1545,10 -1545,10 -1529,8 +1545,8 @@@@ static int do_git_config_sequence(cons char *user_config = expand_user_path("~/.gitconfig", 0); char *repo_config; -- if (opts->git_dir) -- repo_config = mkpathdup("%s/config", opts->git_dir); -- else if (have_git_dir()) -- repo_config = git_pathdup("config"); ++ if (opts->commondir) ++ repo_config = mkpathdup("%s/config", opts->commondir); else repo_config = NULL; @@@@ -1579,9 -1579,9 -1561,9 +1577,9 @@@@ return ret; } -- int git_config_with_options(config_fn_t fn, void *data, -- struct git_config_source *config_source, -- const struct config_options *opts) ++ int config_with_options(config_fn_t fn, void *data, ++ struct git_config_source *config_source, ++ const struct config_options *opts) { struct config_include_data inc = CONFIG_INCLUDE_INIT; @@@@ -1612,9 -1612,9 -1594,14 +1610,14 @@@@ static void git_config_raw(config_fn_t struct config_options opts = {0}; opts.respect_includes = 1; -- if (git_config_with_options(fn, data, NULL, &opts) < 0) ++ if (have_git_dir()) { ++ opts.commondir = get_git_common_dir(); ++ opts.git_dir = get_git_dir(); ++ } ++ ++ if (config_with_options(fn, data, NULL, &opts) < 0) /* -- * git_config_with_options() normally returns only ++ * config_with_options() normally returns only * zero, as most errors are fatal, and * non-fatal potential errors are guarded by "if" * statements that are entered only when no error is @@@@ -1653,11 -1653,11 -1640,13 +1656,13 @@@@ static void configset_iter(struct confi void read_early_config(config_fn_t cb, void *data) { struct config_options opts = {0}; -- struct strbuf buf = STRBUF_INIT; ++ struct strbuf commondir = STRBUF_INIT; ++ struct strbuf gitdir = STRBUF_INIT; opts.respect_includes = 1; -- if (have_git_dir()) ++ if (have_git_dir()) { ++ opts.commondir = get_git_common_dir(); opts.git_dir = get_git_dir(); /* * When setup_git_directory() was not yet asked to discover the @@@@ -1667,12 -1667,12 -1656,15 +1672,15 @@@@ * notably, the current working directory is still the same after the * call). */ -- else if (discover_git_directory(&buf)) -- opts.git_dir = buf.buf; ++ } else if (!discover_git_directory(&commondir, &gitdir)) { ++ opts.commondir = commondir.buf; ++ opts.git_dir = gitdir.buf; ++ } -- git_config_with_options(cb, data, NULL, &opts); ++ config_with_options(cb, data, NULL, &opts); -- strbuf_release(&buf); ++ strbuf_release(&commondir); ++ strbuf_release(&gitdir); } static void git_config_check_init(void); @@@@ -1981,7 -1981,7 -1973,7 +1989,7 @@@@ int git_config_get_expiry(const char *k if (ret) return ret; if (strcmp(*output, "now")) { - unsigned long now = approxidate("now"); + timestamp_t now = approxidate("now"); if (approxidate(*output) >= now) git_die_config(key, _("Invalid %s: '%s'"), key, *output); } @@@@ -2637,7 -2637,7 -2629,7 +2645,7 @@@@ int git_config_rename_section_in_file(c struct lock_file *lock; int out_fd; char buf[1024]; - FILE *config_file; + FILE *config_file = NULL; struct stat st; if (new_name && !section_name_is_ok(new_name)) { @@@@ -2656,9 -2656,6 -2648,6 +2664,9 @@@@ } if (!(config_file = fopen(config_filename, "rb"))) { ++ ret = warn_on_fopen_errors(config_filename); ++ if (ret) ++ goto out; /* no config file means nothing to rename, no error */ goto commit_and_out; } @@@@ -2722,14 -2719,14 -2711,11 +2730,14 @@@@ } } fclose(config_file); + config_file = NULL; commit_and_out: if (commit_lock_file(lock) < 0) ret = error_errno("could not write config file %s", config_filename); out: + if (config_file) + fclose(config_file); rollback_lock_file(lock); out_no_rollback: free(filename_buf); diff --combined connect.c index c72b1d1151,c72b1d1151,efddb30ea8..e78d3f43d8 --- a/connect.c +++ b/connect.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #include "git-compat-util.h" #include "cache.h" ++ #include "config.h" #include "pkt-line.h" #include "quote.h" #include "refs.h" @@@@ -71,7 -71,7 -72,7 +72,7 @@@@ static void parse_one_symref_info(struc check_refname_format(target, REFNAME_ALLOW_ONELEVEL)) /* "symref=bogus:pair */ goto reject; - item = string_list_append(symref, sym); + item = string_list_append_nodup(symref, sym); item->util = target; return; reject: diff --combined convert.c index f1e168bc30,4097f521f2,69f23cfcaa..7d2a519daf --- a/convert.c +++ b/convert.c @@@@ -1,10 -1,11 -1,10 +1,12 @@@@ + +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" ++ #include "config.h" #include "attr.h" #include "run-command.h" #include "quote.h" #include "sigchain.h" #include "pkt-line.h" +#include "sub-process.h" /* * convert.c - convert a file when checking it out and checking it in. @@@@ -134,11 -135,12 -134,11 +136,12 @@@@ static const char *gather_convert_stats } } - -const char *get_cached_convert_stats_ascii(const char *path) + +const char *get_cached_convert_stats_ascii(const struct index_state *istate, + + const char *path) { const char *ret; unsigned long sz; - - void *data = read_blob_data_from_cache(path, &sz); + + void *data = read_blob_data_from_index(istate, path, &sz); ret = gather_convert_stats_ascii(data, sz); free(data); return ret; @@@@ -217,13 -219,13 -217,13 +220,13 @@@@ static void check_safe_crlf(const char } } - -static int has_cr_in_index(const char *path) + +static int has_cr_in_index(const struct index_state *istate, const char *path) { unsigned long sz; void *data; int has_cr; - - data = read_blob_data_from_cache(path, &sz); + + data = read_blob_data_from_index(istate, path, &sz); if (!data) return 0; has_cr = memchr(data, '\r', sz) != NULL; @@@@ -253,7 -255,8 -253,7 +256,8 @@@@ static int will_convert_lf_to_crlf(size } - -static int crlf_to_git(const char *path, const char *src, size_t len, + +static int crlf_to_git(const struct index_state *istate, + + const char *path, const char *src, size_t len, struct strbuf *buf, enum crlf_action crlf_action, enum safe_crlf checksafe) { @@@@ -285,7 -288,8 -285,7 +289,8 @@@@ * unless we want to renormalize in a merge or * cherry-pick. */ - - if ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path)) + + if ((checksafe != SAFE_CRLF_RENORMALIZE) && + + has_cr_in_index(istate, path)) convert_crlf_into_lf = 0; } if ((checksafe == SAFE_CRLF_WARN || @@@@ -498,26 -502,26 -498,126 +503,26 @@@@ static int apply_single_file_filter(con #define CAP_SMUDGE (1u<<1) struct cmd2process { - struct hashmap_entry ent; /* must be the first member! */ + struct subprocess_entry subprocess; /* must be the first member! */ unsigned int supported_capabilities; - const char *cmd; - struct child_process process; }; -static int cmd_process_map_initialized; -static struct hashmap cmd_process_map; - -static int cmd2process_cmp(const struct cmd2process *e1, - const struct cmd2process *e2, - const void *unused) -{ - return strcmp(e1->cmd, e2->cmd); -} - -static struct cmd2process *find_multi_file_filter_entry(struct hashmap *hashmap, const char *cmd) -{ - struct cmd2process key; - hashmap_entry_init(&key, strhash(cmd)); - key.cmd = cmd; - return hashmap_get(hashmap, &key, NULL); -} - -static int packet_write_list(int fd, const char *line, ...) -{ - va_list args; - int err; - va_start(args, line); - for (;;) { - if (!line) - break; - if (strlen(line) > LARGE_PACKET_DATA_MAX) - return -1; - err = packet_write_fmt_gently(fd, "%s\n", line); - if (err) - return err; - line = va_arg(args, const char*); - } - va_end(args); - return packet_flush_gently(fd); -} - -static void read_multi_file_filter_status(int fd, struct strbuf *status) -{ - struct strbuf **pair; - char *line; - for (;;) { - line = packet_read_line(fd, NULL); - if (!line) - break; - pair = strbuf_split_str(line, '=', 2); - if (pair[0] && pair[0]->len && pair[1]) { - /* the last "status=" line wins */ - if (!strcmp(pair[0]->buf, "status=")) { - strbuf_reset(status); - strbuf_addbuf(status, pair[1]); - } - } - strbuf_list_free(pair); - } -} - -static void kill_multi_file_filter(struct hashmap *hashmap, struct cmd2process *entry) -{ - if (!entry) - return; - - entry->process.clean_on_exit = 0; - kill(entry->process.pid, SIGTERM); - finish_command(&entry->process); +static int subprocess_map_initialized; +static struct hashmap subprocess_map; - hashmap_remove(hashmap, entry, NULL); - free(entry); -} - -static void stop_multi_file_filter(struct child_process *process) -{ - sigchain_push(SIGPIPE, SIG_IGN); - /* Closing the pipe signals the filter to initiate a shutdown. */ - close(process->in); - close(process->out); - sigchain_pop(SIGPIPE); - /* Finish command will wait until the shutdown is complete. */ - finish_command(process); -} - -static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, const char *cmd) +static int start_multi_file_filter_fn(struct subprocess_entry *subprocess) { int err; - struct cmd2process *entry; - struct child_process *process; - const char *argv[] = { cmd, NULL }; + struct cmd2process *entry = (struct cmd2process *)subprocess; struct string_list cap_list = STRING_LIST_INIT_NODUP; char *cap_buf; const char *cap_name; - - entry = xmalloc(sizeof(*entry)); - entry->cmd = cmd; - entry->supported_capabilities = 0; - process = &entry->process; - - child_process_init(process); - process->argv = argv; - process->use_shell = 1; - process->in = -1; - process->out = -1; - process->clean_on_exit = 1; - process->clean_on_exit_handler = stop_multi_file_filter; - - if (start_command(process)) { - error("cannot fork to run external filter '%s'", cmd); - return NULL; - } - - hashmap_entry_init(entry, strhash(cmd)); + struct child_process *process = &subprocess->process; + const char *cmd = subprocess->cmd; sigchain_push(SIGPIPE, SIG_IGN); - err = packet_write_list(process->in, "git-filter-client", "version=2", NULL); + err = packet_writel(process->in, "git-filter-client", "version=2", NULL); if (err) goto done; @@@@ -533,7 -537,7 -633,7 +538,7 @@@@ if (err) goto done; - err = packet_write_list(process->in, "capability=clean", "capability=smudge", NULL); + err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL); for (;;) { cap_buf = packet_read_line(process->out, NULL); @@@@ -562,7 -566,7 -662,14 +567,7 @@@@ done: sigchain_pop(SIGPIPE); - if (err || errno == EPIPE) { - error("initialization for external filter '%s' failed", cmd); - kill_multi_file_filter(hashmap, entry); - return NULL; - } - - hashmap_add(hashmap, entry); - return entry; + return err; } static int apply_multi_file_filter(const char *path, const char *src, size_t len, @@@@ -576,26 -580,26 -683,22 +581,26 @@@@ struct strbuf filter_status = STRBUF_INIT; const char *filter_type; - if (!cmd_process_map_initialized) { - cmd_process_map_initialized = 1; - hashmap_init(&cmd_process_map, (hashmap_cmp_fn) cmd2process_cmp, 0); + if (!subprocess_map_initialized) { + subprocess_map_initialized = 1; + hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp, 0); entry = NULL; } else { - entry = find_multi_file_filter_entry(&cmd_process_map, cmd); + entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd); } fflush(NULL); if (!entry) { - entry = start_multi_file_filter(&cmd_process_map, cmd); - if (!entry) + entry = xmalloc(sizeof(*entry)); + entry->supported_capabilities = 0; + + if (subprocess_start(&subprocess_map, &entry->subprocess, cmd, start_multi_file_filter_fn)) { + free(entry); return 0; + } } - process = &entry->process; + process = &entry->subprocess.process; if (!(wanted_capability & entry->supported_capabilities)) return 0; @@@@ -635,10 -639,10 -738,7 +640,10 @@@@ if (err) goto done; - read_multi_file_filter_status(process->out, &filter_status); + err = subprocess_read_status(process->out, &filter_status); + if (err) + goto done; + err = strcmp(filter_status.buf, "success"); if (err) goto done; @@@@ -647,16 -651,16 -747,13 +652,16 @@@@ if (err) goto done; - read_multi_file_filter_status(process->out, &filter_status); + err = subprocess_read_status(process->out, &filter_status); + if (err) + goto done; + err = strcmp(filter_status.buf, "success"); done: sigchain_pop(SIGPIPE); - if (err || errno == EPIPE) { + if (err) { if (!strcmp(filter_status.buf, "error")) { /* The filter signaled a problem with the file. */ } else if (!strcmp(filter_status.buf, "abort")) { @@@@ -672,8 -676,8 -769,7 +677,8 @@@@ * Force shutdown and restart if another blob requires filtering. */ error("external filter '%s' failed", cmd); - kill_multi_file_filter(&cmd_process_map, entry); + subprocess_stop(&subprocess_map, &entry->subprocess); + free(entry); } } else { strbuf_swap(dst, &nbuf); @@@@ -1081,7 -1085,8 -1177,7 +1086,8 @@@@ const char *get_convert_attr_ascii(cons return ""; } - -int convert_to_git(const char *path, const char *src, size_t len, + +int convert_to_git(const struct index_state *istate, + + const char *path, const char *src, size_t len, struct strbuf *dst, enum safe_crlf checksafe) { int ret = 0; @@@@ -1097,7 -1102,7 -1193,7 +1103,7 @@@@ src = dst->buf; len = dst->len; } - - ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); + + ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe); if (ret && dst) { src = dst->buf; len = dst->len; @@@@ -1105,7 -1110,8 -1201,7 +1111,8 @@@@ return ret | ident_to_git(path, src, len, dst, ca.ident); } - -void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst, + +void convert_to_git_filter_fd(const struct index_state *istate, + + const char *path, int fd, struct strbuf *dst, enum safe_crlf checksafe) { struct conv_attrs ca; @@@@ -1117,7 -1123,7 -1213,7 +1124,7 @@@@ if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN)) die("%s: clean filter '%s' failed", path, ca.drv->name); - - crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); + + crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); ident_to_git(path, dst->buf, dst->len, dst, ca.ident); } @@@@ -1160,14 -1166,15 -1256,14 +1167,15 @@@@ int convert_to_working_tree(const char return convert_to_working_tree_internal(path, src, len, dst, 0); } - -int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst) + +int renormalize_buffer(const struct index_state *istate, const char *path, + + const char *src, size_t len, struct strbuf *dst) { int ret = convert_to_working_tree_internal(path, src, len, dst, 1); if (ret) { src = dst->buf; len = dst->len; } - - return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE); + + return ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE); } /***************************************************************** diff --combined credential-cache--daemon.c index f3814cc47a,f3814cc47a,2787b29c05..0d5c625094 --- a/credential-cache--daemon.c +++ b/credential-cache--daemon.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "tempfile.h" #include "credential.h" #include "unix-socket.h" @@@@ -8,7 -8,7 -9,7 +9,7 @@@@ static struct tempfile socket_file struct credential_cache_entry { struct credential item; - unsigned long expiration; + timestamp_t expiration; }; static struct credential_cache_entry *entries; static int entries_nr; @@@@ -47,12 -47,12 -48,12 +48,12 @@@@ static void remove_credential(const str e->expiration = 0; } -static int check_expirations(void) +static timestamp_t check_expirations(void) { - static unsigned long wait_for_entry_until; + static timestamp_t wait_for_entry_until; int i = 0; - unsigned long now = time(NULL); - unsigned long next = (unsigned long)-1; + timestamp_t now = time(NULL); + timestamp_t next = TIME_MAX; /* * Initially give the client 30 seconds to actually contact us @@@@ -159,7 -159,7 -160,7 +160,7 @@@@ static void serve_one_client(FILE *in, static int serve_cache_loop(int fd) { struct pollfd pfd; - unsigned long wakeup; + timestamp_t wakeup; wakeup = check_expirations(); if (!wakeup) diff --combined diff.c index acedf86aec,976a6f91b1,4f9b9f8382..41295d4ea9 --- a/diff.c +++ b/diff.c @@@@ -2,6 -2,6 -2,7 +2,7 @@@@ * Copyright (C) 2005 Junio C Hamano */ #include "cache.h" ++ #include "config.h" #include "tempfile.h" #include "quote.h" #include "diff.h" @@@@ -27,7 -27,7 -28,7 +28,7 @@@@ #endif static int diff_detect_rename_default; -static int diff_indent_heuristic; /* experimental */ +static int diff_indent_heuristic = 1; static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; static int diff_use_color_default = -1; @@@@ -290,6 -290,6 -291,9 +291,6 @@@@ int git_diff_ui_config(const char *var return 0; } - if (git_diff_heuristic_config(var, value, cb) < 0) - return -1; - if (!strcmp(var, "diff.wserrorhighlight")) { int val = parse_ws_error_highlight(value); if (val < 0) @@@@ -348,9 -348,9 -352,6 +349,9 @@@@ int git_diff_basic_config(const char *v if (starts_with(var, "submodule.")) return parse_submodule_config_option(var, value); + if (git_diff_heuristic_config(var, value, cb) < 0) + return -1; + return git_default_config(var, value, cb); } @@@@ -2702,13 -2702,13 -2703,13 +2703,13 @@@@ void free_filespec(struct diff_filespe } } --void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1, -- int sha1_valid, unsigned short mode) ++void fill_filespec(struct diff_filespec *spec, const struct object_id *oid, ++ int oid_valid, unsigned short mode) { if (mode) { spec->mode = canon_mode(mode); -- hashcpy(spec->oid.hash, sha1); -- spec->oid_valid = sha1_valid; ++ oidcpy(&spec->oid, oid); ++ spec->oid_valid = oid_valid; } } @@@@ -2717,7 -2717,7 -2718,7 +2718,7 @@@@ * the work tree has that object contents, return true, so that * prepare_temp_file() does not have to inflate and extract. */ --static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file) ++static int reuse_worktree_file(const char *name, const struct object_id *oid, int want_file) { const struct cache_entry *ce; struct stat st; @@@@ -2748,14 -2748,14 -2749,14 +2749,14 @@@@ * objects however would tend to be slower as they need * to be individually opened and inflated. */ -- if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1)) ++ if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(oid->hash)) return 0; /* * Similarly, if we'd have to convert the file contents anyway, that * makes the optimization not worthwhile. */ - - if (!want_file && would_convert_to_git(name)) + + if (!want_file && would_convert_to_git(&the_index, name)) return 0; len = strlen(name); @@@@ -2768,7 -2768,7 -2769,7 +2769,7 @@@@ * This is not the sha1 we are looking for, or * unreusable because it is not a regular file. */ -- if (hashcmp(sha1, ce->oid.hash) || !S_ISREG(ce->ce_mode)) ++ if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode)) return 0; /* @@@@ -2842,7 -2842,7 -2843,7 +2843,7 @@@@ int diff_populate_filespec(struct diff_ return diff_populate_gitlink(s, size_only); if (!s->oid_valid || -- reuse_worktree_file(s->path, s->oid.hash, 0)) { ++ reuse_worktree_file(s->path, &s->oid, 0)) { struct strbuf buf = STRBUF_INIT; struct stat st; int fd; @@@@ -2877,7 -2877,7 -2878,7 +2878,7 @@@@ * point if the path requires us to run the content * conversion. */ - - if (size_only && !would_convert_to_git(s->path)) + + if (size_only && !would_convert_to_git(&the_index, s->path)) return 0; /* @@@@ -2904,7 -2904,7 -2905,7 +2905,7 @@@@ /* * Convert from working tree format to canonical git format */ - - if (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) { + + if (convert_to_git(&the_index, s->path, s->data, s->size, &buf, crlf_warn)) { size_t size = 0; munmap(s->data, s->size); s->should_munmap = 0; @@@@ -3008,7 -3008,7 -3009,7 +3009,7 @@@@ static struct diff_tempfile *prepare_te if (!S_ISGITLINK(one->mode) && (!one->oid_valid || -- reuse_worktree_file(name, one->oid.hash, 1))) { ++ reuse_worktree_file(name, &one->oid, 1))) { struct stat st; if (lstat(name, &st) < 0) { if (errno == ENOENT) @@@@ -3030,13 -3030,13 -3031,13 +3031,13 @@@@ /* we can borrow from the file in the work tree */ temp->name = name; if (!one->oid_valid) -- sha1_to_hex_r(temp->hex, null_sha1); ++ oid_to_hex_r(temp->hex, &null_oid); else oid_to_hex_r(temp->hex, &one->oid); /* Even though we may sometimes borrow the * contents from the work tree, we always want * one->mode. mode is trustworthy even when -- * !(one->sha1_valid), as long as ++ * !(one->oid_valid), as long as * DIFF_FILE_VALID(one). */ xsnprintf(temp->mode, sizeof(temp->mode), "%06o", one->mode); @@@@ -3239,7 -3239,7 -3240,7 +3240,7 @@@@ static void run_diff_cmd(const char *pg fprintf(o->file, "* Unmerged path %s\n", name); } --static void diff_fill_sha1_info(struct diff_filespec *one) ++static void diff_fill_oid_info(struct diff_filespec *one) { if (DIFF_FILE_VALID(one)) { if (!one->oid_valid) { @@@@ -3298,8 -3298,8 -3299,8 +3299,8 @@@@ static void run_diff(struct diff_filepa return; } -- diff_fill_sha1_info(one); -- diff_fill_sha1_info(two); ++ diff_fill_oid_info(one); ++ diff_fill_oid_info(two); if (!pgm && DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && @@@@ -3344,8 -3344,8 -3345,8 +3345,8 @@@@ static void run_diffstat(struct diff_fi if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); -- diff_fill_sha1_info(p->one); -- diff_fill_sha1_info(p->two); ++ diff_fill_oid_info(p->one); ++ diff_fill_oid_info(p->two); builtin_diffstat(name, other, p->one, p->two, diffstat, o, p); } @@@@ -3368,8 -3368,8 -3369,8 +3369,8 @@@@ static void run_checkdiff(struct diff_f if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); -- diff_fill_sha1_info(p->one); -- diff_fill_sha1_info(p->two); ++ diff_fill_oid_info(p->one); ++ diff_fill_oid_info(p->two); builtin_checkdiff(name, other, attr_path, p->one, p->two, o); } @@@@ -4071,7 -4071,9 -4072,9 +4072,7 @@@@ int diff_opt_parse(struct diff_options DIFF_OPT_CLR(options, FUNCCONTEXT); else if ((argcount = parse_long_opt("output", av, &optarg))) { char *path = prefix_filename(prefix, optarg); -- options->file = fopen(path, "w"); -- if (!options->file) -- die_errno("Could not open '%s'", path); ++ options->file = xfopen(path, "w"); options->close_file = 1; if (options->use_color != GIT_COLOR_ALWAYS) options->use_color = GIT_COLOR_NEVER; @@@@ -4582,7 -4584,7 -4585,7 +4583,7 @@@@ static void patch_id_add_mode(git_SHA_C } /* returns 0 upon success, and writes result into sha1 */ --static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only) ++static int diff_get_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only) { struct diff_queue_struct *q = &diff_queued_diff; int i; @@@@ -4614,8 -4616,8 -4617,8 +4615,8 @@@@ if (DIFF_PAIR_UNMERGED(p)) continue; -- diff_fill_sha1_info(p->one); -- diff_fill_sha1_info(p->two); ++ diff_fill_oid_info(p->one); ++ diff_fill_oid_info(p->two); len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); @@@@ -4654,9 -4656,9 -4657,9 +4655,9 @@@@ if (diff_filespec_is_binary(p->one) || diff_filespec_is_binary(p->two)) { git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid), -- 40); ++ GIT_SHA1_HEXSZ); git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid), -- 40); ++ GIT_SHA1_HEXSZ); continue; } @@@@ -4669,15 -4671,15 -4672,15 +4670,15 @@@@ p->one->path); } -- git_SHA1_Final(sha1, &ctx); ++ git_SHA1_Final(oid->hash, &ctx); return 0; } --int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only) ++int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only) { struct diff_queue_struct *q = &diff_queued_diff; int i; -- int result = diff_get_patch_id(options, sha1, diff_header_only); ++ int result = diff_get_patch_id(options, oid, diff_header_only); for (i = 0; i < q->nr; i++) diff_free_filepair(q->queue[i]); @@@@ -4805,7 -4807,9 -4808,9 +4806,7 @@@@ void diff_flush(struct diff_options *op */ if (options->close_file) fclose(options->file); -- options->file = fopen("/dev/null", "w"); -- if (!options->file) -- die_errno("Could not open /dev/null"); ++ options->file = xfopen("/dev/null", "w"); options->close_file = 1; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@@@ -5077,8 -5081,8 -5082,8 +5078,8 @@@@ static int is_submodule_ignored(const c void diff_addremove(struct diff_options *options, int addremove, unsigned mode, -- const unsigned char *sha1, -- int sha1_valid, ++ const struct object_id *oid, ++ int oid_valid, const char *concatpath, unsigned dirty_submodule) { struct diff_filespec *one, *two; @@@@ -5110,9 -5114,9 -5115,9 +5111,9 @@@@ two = alloc_filespec(concatpath); if (addremove != '+') -- fill_filespec(one, sha1, sha1_valid, mode); ++ fill_filespec(one, oid, oid_valid, mode); if (addremove != '-') { -- fill_filespec(two, sha1, sha1_valid, mode); ++ fill_filespec(two, oid, oid_valid, mode); two->dirty_submodule = dirty_submodule; } @@@@ -5123,9 -5127,9 -5128,9 +5124,9 @@@@ void diff_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, -- const unsigned char *old_sha1, -- const unsigned char *new_sha1, -- int old_sha1_valid, int new_sha1_valid, ++ const struct object_id *old_oid, ++ const struct object_id *new_oid, ++ int old_oid_valid, int new_oid_valid, const char *concatpath, unsigned old_dirty_submodule, unsigned new_dirty_submodule) { @@@@ -5138,8 -5142,8 -5143,8 +5139,8 @@@@ if (DIFF_OPT_TST(options, REVERSE_DIFF)) { SWAP(old_mode, new_mode); -- SWAP(old_sha1, new_sha1); -- SWAP(old_sha1_valid, new_sha1_valid); ++ SWAP(old_oid, new_oid); ++ SWAP(old_oid_valid, new_oid_valid); SWAP(old_dirty_submodule, new_dirty_submodule); } @@@@ -5149,8 -5153,8 -5154,8 +5150,8 @@@@ one = alloc_filespec(concatpath); two = alloc_filespec(concatpath); -- fill_filespec(one, old_sha1, old_sha1_valid, old_mode); -- fill_filespec(two, new_sha1, new_sha1_valid, new_mode); ++ fill_filespec(one, old_oid, old_oid_valid, old_mode); ++ fill_filespec(two, new_oid, new_oid_valid, new_mode); one->dirty_submodule = old_dirty_submodule; two->dirty_submodule = new_dirty_submodule; p = diff_queue(&diff_queued_diff, one, two); @@@@ -5240,7 -5244,7 -5245,7 +5241,7 @@@@ size_t fill_textconv(struct userdiff_dr if (driver->textconv_cache && df->oid_valid) { *outbuf = notes_cache_get(driver->textconv_cache, - df->oid.hash, + &df->oid, &size); if (*outbuf) return size; @@@@ -5252,7 -5256,7 -5257,7 +5253,7 @@@@ if (driver->textconv_cache && df->oid_valid) { /* ignore errors, as we might be in a readonly repository */ - notes_cache_put(driver->textconv_cache, df->oid.hash, *outbuf, + notes_cache_put(driver->textconv_cache, &df->oid, *outbuf, size); /* * we could save up changes and flush them all at the end, @@@@ -5266,29 -5270,29 -5271,6 +5267,29 @@@@ return size; } +int textconv_object(const char *path, + unsigned mode, + const struct object_id *oid, + int oid_valid, + char **buf, + unsigned long *buf_size) +{ + struct diff_filespec *df; + struct userdiff_driver *textconv; + + df = alloc_filespec(path); - fill_filespec(df, oid->hash, oid_valid, mode); ++ fill_filespec(df, oid, oid_valid, mode); + textconv = get_textconv(df); + if (!textconv) { + free_filespec(df); + return 0; + } + + *buf_size = fill_textconv(textconv, df, buf); + free_filespec(df); + return 1; +} + void setup_diff_pager(struct diff_options *opt) { /* diff --combined dir.c index 1759063817,f673b86f31,42beb65bea..34445374ba --- a/dir.c +++ b/dir.c @@@@ -7,8 -7,8 -7,8 +7,9 @@@@ * Copyright (C) Linus Torvalds, 2005-2006 * Junio Hamano, 2005-2006 */ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" ++ #include "config.h" #include "dir.h" #include "attr.h" #include "refs.h" @@@@ -46,11 -46,11 -46,9 +47,11 @@@@ struct cached_dir }; static enum path_treatment read_directory_recursive(struct dir_struct *dir, - const char *path, int len, struct untracked_cache_dir *untracked, + struct index_state *istate, const char *path, int len, + struct untracked_cache_dir *untracked, int check_only, const struct pathspec *pathspec); -static int get_dtype(struct dirent *de, const char *path, int len); +static int get_dtype(struct dirent *de, struct index_state *istate, + const char *path, int len); int fspathcmp(const char *a, const char *b) { @@@@ -177,9 -177,9 -175,7 +178,9 @@@@ char *common_prefix(const struct pathsp return len ? xmemdupz(pathspec->items[0].match, len) : NULL; } -int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec) +int fill_directory(struct dir_struct *dir, + struct index_state *istate, + const struct pathspec *pathspec) { const char *prefix; size_t prefix_len; @@@@ -192,7 -192,7 -188,7 +193,7 @@@@ prefix = prefix_len ? pathspec->items[0].match : ""; /* Read the directory and prune it */ - read_directory(dir, prefix, prefix_len, pathspec); + read_directory(dir, istate, prefix, prefix_len, pathspec); return prefix_len; } @@@@ -592,8 -592,8 -588,7 +593,8 @@@@ void add_exclude(const char *string, co x->el = el; } -static void *read_skip_worktree_file_from_index(const char *path, size_t *size, +static void *read_skip_worktree_file_from_index(const struct index_state *istate, + const char *path, size_t *size, struct sha1_stat *sha1_stat) { int pos, len; @@@@ -602,12 -602,12 -597,12 +603,12 @@@@ void *data; len = strlen(path); - pos = cache_name_pos(path, len); + pos = index_name_pos(istate, path, len); if (pos < 0) return NULL; - if (!ce_skip_worktree(active_cache[pos])) + if (!ce_skip_worktree(istate->cache[pos])) return NULL; - data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz); + data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz); if (!data || type != OBJ_BLOB) { free(data); return NULL; @@@@ -615,7 -615,7 -610,7 +616,7 @@@@ *size = xsize_t(sz); if (sha1_stat) { memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat)); - hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash); + hashcpy(sha1_stat->sha1, istate->cache[pos]->oid.hash); } return data; } @@@@ -733,7 -733,7 -728,7 +734,7 @@@@ static void invalidate_directory(struc /* * Given a file with name "fname", read it (either from disk, or from - * the index if "check_index" is non-zero), parse it and store the + * an index if 'istate' is non-null), parse it and store the * exclude rules in "el". * * If "ss" is not NULL, compute SHA-1 of the exclude file and fill @@@@ -741,8 -741,8 -736,7 +742,8 @@@@ * ss_valid is non-zero, "ss" must contain good value as input. */ static int add_excludes(const char *fname, const char *base, int baselen, - struct exclude_list *el, int check_index, + struct exclude_list *el, + struct index_state *istate, struct sha1_stat *sha1_stat) { struct stat st; @@@@ -752,12 -752,12 -746,12 +753,12 @@@@ fd = open(fname, O_RDONLY); if (fd < 0 || fstat(fd, &st) < 0) { -- if (errno != ENOENT) -- warn_on_inaccessible(fname); -- if (0 <= fd) ++ if (fd < 0) ++ warn_on_fopen_errors(fname); ++ else close(fd); - if (!check_index || - (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL) + if (!istate || + (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL) return -1; if (size == 0) { free(buf); @@@@ -789,15 -789,15 -783,15 +790,15 @@@@ if (sha1_stat) { int pos; if (sha1_stat->valid && - !match_stat_data_racy(&the_index, &sha1_stat->stat, &st)) + !match_stat_data_racy(istate, &sha1_stat->stat, &st)) ; /* no content change, ss->sha1 still good */ - else if (check_index && - (pos = cache_name_pos(fname, strlen(fname))) >= 0 && - !ce_stage(active_cache[pos]) && - ce_uptodate(active_cache[pos]) && - !would_convert_to_git(fname)) + else if (istate && + (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 && + !ce_stage(istate->cache[pos]) && + ce_uptodate(istate->cache[pos]) && - !would_convert_to_git(fname)) + + !would_convert_to_git(istate, fname)) hashcpy(sha1_stat->sha1, - active_cache[pos]->oid.hash); + istate->cache[pos]->oid.hash); else hash_sha1_file(buf, size, "blob", sha1_stat->sha1); fill_stat_data(&sha1_stat->stat, &st); @@@@ -828,9 -828,9 -822,9 +829,9 @@@@ int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, struct exclude_list *el, - int check_index) + struct index_state *istate) { - return add_excludes(fname, base, baselen, el, check_index, NULL); + return add_excludes(fname, base, baselen, el, istate, NULL); } struct exclude_list *add_exclude_list(struct dir_struct *dir, @@@@ -862,7 -862,7 -856,7 +863,7 @@@@ static void add_excludes_from_file_1(st if (!dir->untracked) dir->unmanaged_exclude_files++; el = add_exclude_list(dir, EXC_FILE, fname); - if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0) + if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0) die("cannot use %s as an exclude file", fname); } @@@@ -965,8 -965,8 -959,7 +966,8 @@@@ static struct exclude *last_exclude_mat int pathlen, const char *basename, int *dtype, - struct exclude_list *el) + struct exclude_list *el, + struct index_state *istate) { struct exclude *exc = NULL; /* undecided */ int i; @@@@ -981,7 -981,7 -974,7 +982,7 @@@@ if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) - *dtype = get_dtype(NULL, pathname, pathlen); + *dtype = get_dtype(NULL, istate, pathname, pathlen); if (*dtype != DT_DIR) continue; } @@@@ -1014,18 -1014,18 -1007,16 +1015,18 @@@@ */ int is_excluded_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, - struct exclude_list *el) + struct exclude_list *el, struct index_state *istate) { struct exclude *exclude; - exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el); + exclude = last_exclude_matching_from_list(pathname, pathlen, basename, + dtype, el, istate); if (exclude) return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return -1; /* undecided */ } static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir, + struct index_state *istate, const char *pathname, int pathlen, const char *basename, int *dtype_p) { @@@@ -1037,7 -1037,7 -1028,7 +1038,7 @@@@ for (j = group->nr - 1; j >= 0; j--) { exclude = last_exclude_matching_from_list( pathname, pathlen, basename, dtype_p, - &group->el[j]); + &group->el[j], istate); if (exclude) return exclude; } @@@@ -1049,9 -1049,9 -1040,7 +1050,9 @@@@ * Loads the per-directory exclude list for the substring of base * which has a char length of baselen. */ -static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) +static void prep_exclude(struct dir_struct *dir, + struct index_state *istate, + const char *base, int baselen) { struct exclude_list_group *group; struct exclude_list *el; @@@@ -1130,7 -1130,7 -1119,6 +1131,7 @@@@ int dt = DT_DIR; dir->basebuf.buf[stk->baselen - 1] = 0; dir->exclude = last_exclude_matching_from_lists(dir, + istate, dir->basebuf.buf, stk->baselen - 1, dir->basebuf.buf + current, &dt); dir->basebuf.buf[stk->baselen - 1] = '/'; @@@@ -1172,7 -1172,7 -1160,7 +1173,7 @@@@ strbuf_addbuf(&sb, &dir->basebuf); strbuf_addstr(&sb, dir->exclude_per_dir); el->src = strbuf_detach(&sb, NULL); - add_excludes(el->src, el->src, stk->baselen, el, 1, + add_excludes(el->src, el->src, stk->baselen, el, istate, untracked ? &sha1_stat : NULL); } /* @@@@ -1207,20 -1207,20 -1195,19 +1208,20 @@@@ * undecided. */ struct exclude *last_exclude_matching(struct dir_struct *dir, - const char *pathname, - int *dtype_p) + struct index_state *istate, + const char *pathname, + int *dtype_p) { int pathlen = strlen(pathname); const char *basename = strrchr(pathname, '/'); basename = (basename) ? basename+1 : pathname; - prep_exclude(dir, pathname, basename-pathname); + prep_exclude(dir, istate, pathname, basename-pathname); if (dir->exclude) return dir->exclude; - return last_exclude_matching_from_lists(dir, pathname, pathlen, + return last_exclude_matching_from_lists(dir, istate, pathname, pathlen, basename, dtype_p); } @@@@ -1229,11 -1229,11 -1216,10 +1230,11 @@@@ * scans all exclude lists to determine whether pathname is excluded. * Returns 1 if true, otherwise 0. */ -int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +int is_excluded(struct dir_struct *dir, struct index_state *istate, + const char *pathname, int *dtype_p) { struct exclude *exclude = - last_exclude_matching(dir, pathname, dtype_p); + last_exclude_matching(dir, istate, pathname, dtype_p); if (exclude) return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return 0; @@@@ -1248,22 -1248,22 -1234,18 +1249,22 @@@@ static struct dir_entry *dir_entry_new( return ent; } -static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len) +static struct dir_entry *dir_add_name(struct dir_struct *dir, + struct index_state *istate, + const char *pathname, int len) { - if (cache_file_exists(pathname, len, ignore_case)) + if (index_file_exists(istate, pathname, len, ignore_case)) return NULL; ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc); return dir->entries[dir->nr++] = dir_entry_new(pathname, len); } -struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) +struct dir_entry *dir_add_ignored(struct dir_struct *dir, + struct index_state *istate, + const char *pathname, int len) { - if (!cache_name_is_other(pathname, len)) + if (!index_name_is_other(istate, pathname, len)) return NULL; ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc); @@@@ -1281,15 -1281,15 -1263,14 +1282,15 @@@@ enum exist_status * the directory name; instead, use the case insensitive * directory hash. */ -static enum exist_status directory_exists_in_index_icase(const char *dirname, int len) +static enum exist_status directory_exists_in_index_icase(struct index_state *istate, + const char *dirname, int len) { struct cache_entry *ce; - if (cache_dir_exists(dirname, len)) + if (index_dir_exists(istate, dirname, len)) return index_directory; - ce = cache_file_exists(dirname, len, ignore_case); + ce = index_file_exists(istate, dirname, len, ignore_case); if (ce && S_ISGITLINK(ce->ce_mode)) return index_gitdir; @@@@ -1303,19 -1303,19 -1284,18 +1304,19 @@@@ * the files it contains) will sort with the '/' at the * end. */ -static enum exist_status directory_exists_in_index(const char *dirname, int len) +static enum exist_status directory_exists_in_index(struct index_state *istate, + const char *dirname, int len) { int pos; if (ignore_case) - return directory_exists_in_index_icase(dirname, len); + return directory_exists_in_index_icase(istate, dirname, len); - pos = cache_name_pos(dirname, len); + pos = index_name_pos(istate, dirname, len); if (pos < 0) pos = -pos-1; - while (pos < active_nr) { - const struct cache_entry *ce = active_cache[pos++]; + while (pos < istate->cache_nr) { + const struct cache_entry *ce = istate->cache[pos++]; unsigned char endchar; if (strncmp(ce->name, dirname, len)) @@@@ -1365,13 -1365,13 -1345,12 +1366,13 @@@@ * (c) otherwise, we recurse into it. */ static enum path_treatment treat_directory(struct dir_struct *dir, + struct index_state *istate, struct untracked_cache_dir *untracked, const char *dirname, int len, int baselen, int exclude, const struct pathspec *pathspec) { /* The "len-1" is to strip the final '/' */ - switch (directory_exists_in_index(dirname, len-1)) { + switch (directory_exists_in_index(istate, dirname, len-1)) { case index_directory: return path_recurse; @@@@ -1396,7 -1396,7 -1375,7 +1397,7 @@@@ untracked = lookup_untracked(dir->untracked, untracked, dirname + baselen, len - baselen); - return read_directory_recursive(dir, dirname, len, + return read_directory_recursive(dir, istate, dirname, len, untracked, 1, pathspec); } @@@@ -1477,13 -1477,13 -1456,12 +1478,13 @@@@ static int exclude_matches_pathspec(con return 0; } -static int get_index_dtype(const char *path, int len) +static int get_index_dtype(struct index_state *istate, + const char *path, int len) { int pos; const struct cache_entry *ce; - ce = cache_file_exists(path, len, 0); + ce = index_file_exists(istate, path, len, 0); if (ce) { if (!ce_uptodate(ce)) return DT_UNKNOWN; @@@@ -1497,12 -1497,12 -1475,12 +1498,12 @@@@ } /* Try to look it up as a directory */ - pos = cache_name_pos(path, len); + pos = index_name_pos(istate, path, len); if (pos >= 0) return DT_UNKNOWN; pos = -pos-1; - while (pos < active_nr) { - ce = active_cache[pos++]; + while (pos < istate->cache_nr) { + ce = istate->cache[pos++]; if (strncmp(ce->name, path, len)) break; if (ce->name[len] > '/') @@@@ -1516,15 -1516,15 -1494,14 +1517,15 @@@@ return DT_UNKNOWN; } -static int get_dtype(struct dirent *de, const char *path, int len) +static int get_dtype(struct dirent *de, struct index_state *istate, + const char *path, int len) { int dtype = de ? DTYPE(de) : DT_UNKNOWN; struct stat st; if (dtype != DT_UNKNOWN) return dtype; - dtype = get_index_dtype(path, len); + dtype = get_index_dtype(istate, path, len); if (dtype != DT_UNKNOWN) return dtype; if (lstat(path, &st)) @@@@ -1540,17 -1540,17 -1517,16 +1541,17 @@@@ static enum path_treatment treat_one_path(struct dir_struct *dir, struct untracked_cache_dir *untracked, + struct index_state *istate, struct strbuf *path, int baselen, const struct pathspec *pathspec, int dtype, struct dirent *de) { int exclude; - int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case); + int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case); if (dtype == DT_UNKNOWN) - dtype = get_dtype(de, path->buf, path->len); + dtype = get_dtype(de, istate, path->buf, path->len); /* Always exclude indexed files */ if (dtype != DT_DIR && has_path_in_index) @@@@ -1577,10 -1577,10 -1553,10 +1578,10 @@@@ if ((dir->flags & DIR_COLLECT_KILLED_ONLY) && (dtype == DT_DIR) && !has_path_in_index && - (directory_exists_in_index(path->buf, path->len) == index_nonexistent)) + (directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent)) return path_none; - exclude = is_excluded(dir, path->buf, &dtype); + exclude = is_excluded(dir, istate, path->buf, &dtype); /* * Excluded? If we don't explicitly want to show @@@@ -1594,7 -1594,7 -1570,7 +1595,7 @@@@ return path_none; case DT_DIR: strbuf_addch(path, '/'); - return treat_directory(dir, untracked, path->buf, path->len, + return treat_directory(dir, istate, untracked, path->buf, path->len, baselen, exclude, pathspec); case DT_REG: case DT_LNK: @@@@ -1605,7 -1605,7 -1581,6 +1606,7 @@@@ static enum path_treatment treat_path_fast(struct dir_struct *dir, struct untracked_cache_dir *untracked, struct cached_dir *cdir, + struct index_state *istate, struct strbuf *path, int baselen, const struct pathspec *pathspec) @@@@ -1624,7 -1624,7 -1599,7 +1625,7 @@@@ * to its bottom. Verify again the same set of directories * with check_only set. */ - return read_directory_recursive(dir, path->buf, path->len, + return read_directory_recursive(dir, istate, path->buf, path->len, cdir->ucd, 1, pathspec); /* * We get path_recurse in the first run when @@@@ -1638,7 -1638,7 -1613,6 +1639,7 @@@@ static enum path_treatment treat_path(struct dir_struct *dir, struct untracked_cache_dir *untracked, struct cached_dir *cdir, + struct index_state *istate, struct strbuf *path, int baselen, const struct pathspec *pathspec) @@@@ -1647,7 -1647,7 -1621,7 +1648,7 @@@@ struct dirent *de = cdir->de; if (!de) - return treat_path_fast(dir, untracked, cdir, path, + return treat_path_fast(dir, untracked, cdir, istate, path, baselen, pathspec); if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_none; @@@@ -1657,7 -1657,7 -1631,7 +1658,7 @@@@ return path_none; dtype = DTYPE(de); - return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de); + return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de); } static void add_untracked(struct untracked_cache_dir *dir, const char *name) @@@@ -1671,7 -1671,7 -1645,6 +1672,7 @@@@ static int valid_cached_dir(struct dir_struct *dir, struct untracked_cache_dir *untracked, + struct index_state *istate, struct strbuf *path, int check_only) { @@@@ -1686,7 -1686,7 -1659,7 +1687,7 @@@@ return 0; } if (!untracked->valid || - match_stat_data_racy(&the_index, &untracked->stat_data, &st)) { + match_stat_data_racy(istate, &untracked->stat_data, &st)) { if (untracked->valid) invalidate_directory(dir->untracked, untracked); fill_stat_data(&untracked->stat_data, &st); @@@@ -1707,10 -1707,10 -1680,10 +1708,10 @@@@ */ if (path->len && path->buf[path->len - 1] != '/') { strbuf_addch(path, '/'); - prep_exclude(dir, path->buf, path->len); + prep_exclude(dir, istate, path->buf, path->len); strbuf_setlen(path, path->len - 1); } else - prep_exclude(dir, path->buf, path->len); + prep_exclude(dir, istate, path->buf, path->len); /* hopefully prep_exclude() haven't invalidated this entry... */ return untracked->valid; @@@@ -1719,13 -1719,13 -1692,12 +1720,13 @@@@ static int open_cached_dir(struct cached_dir *cdir, struct dir_struct *dir, struct untracked_cache_dir *untracked, + struct index_state *istate, struct strbuf *path, int check_only) { memset(cdir, 0, sizeof(*cdir)); cdir->untracked = untracked; - if (valid_cached_dir(dir, untracked, path, check_only)) + if (valid_cached_dir(dir, untracked, istate, path, check_only)) return 0; cdir->fdir = opendir(path->len ? path->buf : "."); if (dir->untracked) @@@@ -1788,9 -1788,9 -1760,9 +1789,9 @@@@ static void close_cached_dir(struct cac * Returns the most significant path_treatment value encountered in the scan. */ static enum path_treatment read_directory_recursive(struct dir_struct *dir, - const char *base, int baselen, - struct untracked_cache_dir *untracked, int check_only, - const struct pathspec *pathspec) + struct index_state *istate, const char *base, int baselen, + struct untracked_cache_dir *untracked, int check_only, + const struct pathspec *pathspec) { struct cached_dir cdir; enum path_treatment state, subdir_state, dir_state = path_none; @@@@ -1798,7 -1798,7 -1770,7 +1799,7 @@@@ strbuf_add(&path, base, baselen); - if (open_cached_dir(&cdir, dir, untracked, &path, check_only)) + if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only)) goto out; if (untracked) @@@@ -1806,23 -1806,23 -1778,20 +1807,23 @@@@ while (!read_cached_dir(&cdir)) { /* check how the file or directory should be treated */ - state = treat_path(dir, untracked, &cdir, &path, + state = treat_path(dir, untracked, &cdir, istate, &path, baselen, pathspec); if (state > dir_state) dir_state = state; /* recurse into subdir if instructed by treat_path */ - if (state == path_recurse) { + if ((state == path_recurse) || + ((state == path_untracked) && + (dir->flags & DIR_SHOW_IGNORED_TOO) && + (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR))) { struct untracked_cache_dir *ud; ud = lookup_untracked(dir->untracked, untracked, path.buf + baselen, path.len - baselen); subdir_state = - read_directory_recursive(dir, path.buf, + read_directory_recursive(dir, istate, path.buf, path.len, ud, check_only, pathspec); if (subdir_state > dir_state) @@@@ -1844,18 -1844,18 -1813,18 +1845,18 @@@@ switch (state) { case path_excluded: if (dir->flags & DIR_SHOW_IGNORED) - dir_add_name(dir, path.buf, path.len); + dir_add_name(dir, istate, path.buf, path.len); else if ((dir->flags & DIR_SHOW_IGNORED_TOO) || ((dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path.buf, path.len, pathspec))) - dir_add_ignored(dir, path.buf, path.len); + dir_add_ignored(dir, istate, path.buf, path.len); break; case path_untracked: if (dir->flags & DIR_SHOW_IGNORED) break; - dir_add_name(dir, path.buf, path.len); + dir_add_name(dir, istate, path.buf, path.len); if (cdir.fdir) add_untracked(untracked, path.buf + baselen); break; @@@@ -1871,7 -1871,7 -1840,7 +1872,7 @@@@ return dir_state; } -static int cmp_name(const void *p1, const void *p2) +int cmp_dir_entry(const void *p1, const void *p2) { const struct dir_entry *e1 = *(const struct dir_entry **)p1; const struct dir_entry *e2 = *(const struct dir_entry **)p2; @@@@ -1879,16 -1879,16 -1848,7 +1880,16 @@@@ return name_compare(e1->name, e1->len, e2->name, e2->len); } +/* check if *out lexically strictly contains *in */ +int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in) +{ + return (out->len < in->len) && + (out->name[out->len - 1] == '/') && + !memcmp(out->name, in->name, out->len); +} + static int treat_leading_path(struct dir_struct *dir, + struct index_state *istate, const char *path, int len, const struct pathspec *pathspec) { @@@@ -1916,7 -1916,7 -1876,7 +1917,7 @@@@ break; if (simplify_away(sb.buf, sb.len, pathspec)) break; - if (treat_one_path(dir, NULL, &sb, baselen, pathspec, + if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec, DT_DIR, NULL) == path_none) break; /* do not recurse into it */ if (len <= baselen) { @@@@ -2084,8 -2084,8 -2044,8 +2085,8 @@@@ static struct untracked_cache_dir *vali return root; } -int read_directory(struct dir_struct *dir, const char *path, - int len, const struct pathspec *pathspec) +int read_directory(struct dir_struct *dir, struct index_state *istate, + const char *path, int len, const struct pathspec *pathspec) { struct untracked_cache_dir *untracked; @@@@ -2099,34 -2099,34 -2059,10 +2100,34 @@@@ * e.g. prep_exclude() */ dir->untracked = NULL; - if (!len || treat_leading_path(dir, path, len, pathspec)) - read_directory_recursive(dir, path, len, untracked, 0, pathspec); - QSORT(dir->entries, dir->nr, cmp_name); - QSORT(dir->ignored, dir->ignored_nr, cmp_name); + if (!len || treat_leading_path(dir, istate, path, len, pathspec)) + read_directory_recursive(dir, istate, path, len, untracked, 0, pathspec); + QSORT(dir->entries, dir->nr, cmp_dir_entry); + QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry); + + /* + * If DIR_SHOW_IGNORED_TOO is set, read_directory_recursive() will + * also pick up untracked contents of untracked dirs; by default + * we discard these, but given DIR_KEEP_UNTRACKED_CONTENTS we do not. + */ + if ((dir->flags & DIR_SHOW_IGNORED_TOO) && + !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) { + int i, j; + + /* remove from dir->entries untracked contents of untracked dirs */ + for (i = j = 0; j < dir->nr; j++) { + if (i && + check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) { + free(dir->entries[j]); + dir->entries[j] = NULL; + } else { + dir->entries[i++] = dir->entries[j]; + } + } + + dir->nr = i; + } + if (dir->untracked) { static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS); trace_printf_key(&trace_untracked_stats, @@@@ -2138,12 -2138,12 -2074,12 +2139,12 @@@@ dir->untracked->gitignore_invalidated, dir->untracked->dir_invalidated, dir->untracked->dir_opened); - if (dir->untracked == the_index.untracked && + if (dir->untracked == istate->untracked && (dir->untracked->dir_opened || dir->untracked->gitignore_invalidated || dir->untracked->dir_invalidated)) - the_index.cache_changed |= UNTRACKED_CHANGED; - if (dir->untracked != the_index.untracked) { + istate->cache_changed |= UNTRACKED_CHANGED; + if (dir->untracked != istate->untracked) { free(dir->untracked); dir->untracked = NULL; } @@@@ -2337,7 -2337,7 -2273,7 +2338,7 @@@@ int remove_path(const char *name { char *slash; -- if (unlink(name) && errno != ENOENT && errno != ENOTDIR) ++ if (unlink(name) && !is_missing_file_error(errno)) return -1; slash = strrchr(name, '/'); diff --combined environment.c index aa478e71de,aa478e71de,9d9b367925..d40b21fb72 --- a/environment.c +++ b/environment.c @@@@ -8,6 -8,6 -8,7 +8,7 @@@@ * are. */ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "fmt-merge-msg.h" #include "commit.h" @@@@ -169,7 -169,7 -170,7 +170,7 @@@@ static void setup_git_env(void git_dir = getenv(GIT_DIR_ENVIRONMENT); if (!git_dir) { if (!startup_info->have_repository) - die("BUG: setup_git_env called without repository"); + BUG("setup_git_env called without repository"); git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; } gitfile = read_gitfile(git_dir); @@@@ -217,8 -217,8 -218,6 +218,8 @@@@ const char *get_git_dir(void const char *get_git_common_dir(void) { + if (!git_dir) + setup_git_env(); return git_common_dir; } diff --combined fast-import.c index 9a22fc92c0,e69d219682,bbc3e79eaf..94a1b06149 --- a/fast-import.c +++ b/fast-import.c @@@@ -154,6 -154,6 -154,7 +154,7 @@@@ Format of STDIN stream #include "builtin.h" #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "object.h" #include "blob.h" @@@@ -226,7 -226,7 -227,7 +227,7 @@@@ struct tree_entry struct atom_str *name; struct tree_entry_ms { uint16_t mode; - unsigned char sha1[20]; + struct object_id oid; } versions[2]; }; @@@@ -252,19 -252,19 -253,19 +253,19 @@@@ struct branch unsigned active : 1; unsigned delete : 1; unsigned pack_id : PACK_ID_BITS; - unsigned char sha1[20]; + struct object_id oid; }; struct tag { struct tag *next_tag; const char *name; unsigned int pack_id; - unsigned char sha1[20]; + struct object_id oid; }; struct hash_list { struct hash_list *next; - unsigned char sha1[20]; + struct object_id oid; }; typedef enum { @@@@ -386,15 -386,15 -387,13 +387,15 @@@@ static void write_branch_report(FILE *r fputs(" active", rpt); if (b->branch_tree.tree) fputs(" loaded", rpt); - if (is_null_sha1(b->branch_tree.versions[1].sha1)) + if (is_null_oid(&b->branch_tree.versions[1].oid)) fputs(" dirty", rpt); fputc('\n', rpt); - fprintf(rpt, " tip commit : %s\n", sha1_to_hex(b->sha1)); - fprintf(rpt, " old tree : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1)); - fprintf(rpt, " cur tree : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1)); + fprintf(rpt, " tip commit : %s\n", oid_to_hex(&b->oid)); + fprintf(rpt, " old tree : %s\n", + oid_to_hex(&b->branch_tree.versions[0].oid)); + fprintf(rpt, " cur tree : %s\n", + oid_to_hex(&b->branch_tree.versions[1].oid)); fprintf(rpt, " commit clock: %" PRIuMAX "\n", b->last_commit); fputs(" last pack : ", rpt); @@@@ -472,7 -472,7 -471,7 +473,7 @@@@ static void write_crash_report(const ch fputs("Annotated Tags\n", rpt); fputs("--------------\n", rpt); for (tg = first_tag; tg; tg = tg->next_tag) { - fputs(sha1_to_hex(tg->sha1), rpt); + fputs(oid_to_hex(&tg->oid), rpt); fputc(' ', rpt); fputs(tg->name, rpt); fputc('\n', rpt); @@@@ -557,7 -557,7 -556,7 +558,7 @@@@ static void alloc_objects(unsigned int alloc_count += cnt; } -static struct object_entry *new_object(unsigned char *sha1) +static struct object_entry *new_object(struct object_id *oid) { struct object_entry *e; @@@@ -565,32 -565,32 -564,32 +566,32 @@@@ alloc_objects(object_entry_alloc); e = blocks->next_free++; - hashcpy(e->idx.sha1, sha1); + oidcpy(&e->idx.oid, oid); return e; } -static struct object_entry *find_object(unsigned char *sha1) +static struct object_entry *find_object(struct object_id *oid) { - unsigned int h = sha1[0] << 8 | sha1[1]; + unsigned int h = oid->hash[0] << 8 | oid->hash[1]; struct object_entry *e; for (e = object_table[h]; e; e = e->next) - if (!hashcmp(sha1, e->idx.sha1)) + if (!oidcmp(oid, &e->idx.oid)) return e; return NULL; } -static struct object_entry *insert_object(unsigned char *sha1) +static struct object_entry *insert_object(struct object_id *oid) { - unsigned int h = sha1[0] << 8 | sha1[1]; + unsigned int h = oid->hash[0] << 8 | oid->hash[1]; struct object_entry *e = object_table[h]; while (e) { - if (!hashcmp(sha1, e->idx.sha1)) + if (!oidcmp(oid, &e->idx.oid)) return e; e = e->next; } - e = new_object(sha1); + e = new_object(oid); e->next = object_table[h]; e->idx.offset = 0; object_table[h] = e; @@@@ -878,7 -878,7 -877,7 +879,7 @@@@ static struct tree_content *dup_tree_co a = s->entries[i]; b = new_tree_entry(); memcpy(b, a, sizeof(*a)); - if (a->tree && is_null_sha1(b->versions[1].sha1)) + if (a->tree && is_null_oid(&b->versions[1].oid)) b->tree = dup_tree_content(a->tree); else b->tree = NULL; @@@@ -1007,17 -1007,17 -1006,17 +1008,17 @@@@ static void end_packfile(void clear_delta_base_cache(); if (object_count) { struct packed_git *new_p; - unsigned char cur_pack_sha1[20]; + struct object_id cur_pack_oid; char *idx_name; int i; struct branch *b; struct tag *t; close_pack_windows(pack_data); - sha1close(pack_file, cur_pack_sha1, 0); + sha1close(pack_file, cur_pack_oid.hash, 0); fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1, pack_data->pack_name, object_count, - cur_pack_sha1, pack_size); + cur_pack_oid.hash, pack_size); if (object_count <= unpack_limit) { if (!loosen_small_pack(pack_data)) { @@@@ -1043,14 -1043,14 -1042,12 +1044,14 @@@@ for (i = 0; i < branch_table_sz; i++) { for (b = branch_table[i]; b; b = b->table_next_branch) { if (b->pack_id == pack_id) - fprintf(pack_edges, " %s", sha1_to_hex(b->sha1)); + fprintf(pack_edges, " %s", + oid_to_hex(&b->oid)); } } for (t = first_tag; t; t = t->next_tag) { if (t->pack_id == pack_id) - fprintf(pack_edges, " %s", sha1_to_hex(t->sha1)); + fprintf(pack_edges, " %s", + oid_to_hex(&t->oid)); } fputc('\n', pack_edges); fflush(pack_edges); @@@@ -1083,13 -1083,13 -1080,13 +1084,13 @@@@ static int store_object enum object_type type, struct strbuf *dat, struct last_object *last, - unsigned char *sha1out, + struct object_id *oidout, uintmax_t mark) { void *out, *delta; struct object_entry *e; unsigned char hdr[96]; - unsigned char sha1[20]; + struct object_id oid; unsigned long hdrlen, deltalen; git_SHA_CTX c; git_zstream s; @@@@ -1099,17 -1099,17 -1096,17 +1100,17 @@@@ git_SHA1_Init(&c); git_SHA1_Update(&c, hdr, hdrlen); git_SHA1_Update(&c, dat->buf, dat->len); - git_SHA1_Final(sha1, &c); - if (sha1out) - hashcpy(sha1out, sha1); + git_SHA1_Final(oid.hash, &c); + if (oidout) + oidcpy(oidout, &oid); - e = insert_object(sha1); + e = insert_object(&oid); if (mark) insert_mark(mark, e); if (e->idx.offset) { duplicate_count_by_type[type]++; return 1; - } else if (find_sha1_pack(sha1, packed_git)) { + } else if (find_sha1_pack(oid.hash, packed_git)) { e->type = type; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@@@ -1222,13 -1222,13 -1219,13 +1223,13 @@@@ static void truncate_pack(struct sha1fi pack_size = checkpoint->offset; } -static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) +static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) { size_t in_sz = 64 * 1024, out_sz = 64 * 1024; unsigned char *in_buf = xmalloc(in_sz); unsigned char *out_buf = xmalloc(out_sz); struct object_entry *e; - unsigned char sha1[20]; + struct object_id oid; unsigned long hdrlen; off_t offset; git_SHA_CTX c; @@@@ -1291,12 -1291,12 -1288,12 +1292,12 @@@@ } } git_deflate_end(&s); - git_SHA1_Final(sha1, &c); + git_SHA1_Final(oid.hash, &c); - if (sha1out) - hashcpy(sha1out, sha1); + if (oidout) + oidcpy(oidout, &oid); - e = insert_object(sha1); + e = insert_object(&oid); if (mark) insert_mark(mark, e); @@@@ -1305,7 -1305,7 -1302,7 +1306,7 @@@@ duplicate_count_by_type[OBJ_BLOB]++; truncate_pack(&checkpoint); - } else if (find_sha1_pack(sha1, packed_git)) { + } else if (find_sha1_pack(oid.hash, packed_git)) { e->type = OBJ_BLOB; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@@@ -1389,7 -1389,7 -1386,7 +1390,7 @@@@ static const char *get_mode(const char static void load_tree(struct tree_entry *root) { - unsigned char *sha1 = root->versions[1].sha1; + struct object_id *oid = &root->versions[1].oid; struct object_entry *myoe; struct tree_content *t; unsigned long size; @@@@ -1397,22 -1397,22 -1394,22 +1398,22 @@@@ const char *c; root->tree = t = new_tree_content(8); - if (is_null_sha1(sha1)) + if (is_null_oid(oid)) return; - myoe = find_object(sha1); + myoe = find_object(oid); if (myoe && myoe->pack_id != MAX_PACK_ID) { if (myoe->type != OBJ_TREE) - die("Not a tree: %s", sha1_to_hex(sha1)); + die("Not a tree: %s", oid_to_hex(oid)); t->delta_depth = myoe->depth; buf = gfi_unpack_entry(myoe, &size); if (!buf) - die("Can't load tree %s", sha1_to_hex(sha1)); + die("Can't load tree %s", oid_to_hex(oid)); } else { enum object_type type; - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); if (!buf || type != OBJ_TREE) - die("Can't load tree %s", sha1_to_hex(sha1)); + die("Can't load tree %s", oid_to_hex(oid)); } c = buf; @@@@ -1426,13 -1426,13 -1423,13 +1427,13 @@@@ e->tree = NULL; c = get_mode(c, &e->versions[1].mode); if (!c) - die("Corrupt mode in %s", sha1_to_hex(sha1)); + die("Corrupt mode in %s", oid_to_hex(oid)); e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - hashcpy(e->versions[0].sha1, (unsigned char *)c); - hashcpy(e->versions[1].sha1, (unsigned char *)c); - c += 20; + hashcpy(e->versions[0].oid.hash, (unsigned char *)c); + hashcpy(e->versions[1].oid.hash, (unsigned char *)c); + c += GIT_SHA1_RAWSZ; } free(buf); } @@@@ -1479,7 -1479,7 -1476,7 +1480,7 @@@@ static void mktree(struct tree_content strbuf_addf(b, "%o %s%c", (unsigned int)(e->versions[v].mode & ~NO_DELTA), e->name->str_dat, '\0'); - strbuf_add(b, e->versions[v].sha1, 20); + strbuf_add(b, e->versions[v].oid.hash, GIT_SHA1_RAWSZ); } } @@@@ -1490,7 -1490,7 -1487,7 +1491,7 @@@@ static void store_tree(struct tree_entr struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 }; struct object_entry *le = NULL; - if (!is_null_sha1(root->versions[1].sha1)) + if (!is_null_oid(&root->versions[1].oid)) return; if (!root->tree) @@@@ -1503,7 -1503,7 -1500,7 +1504,7 @@@@ } if (!(root->versions[0].mode & NO_DELTA)) - le = find_object(root->versions[0].sha1); + le = find_object(&root->versions[0].oid); if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) { mktree(t, 0, &old_tree); lo.data = old_tree; @@@@ -1512,14 -1512,14 -1509,14 +1513,14 @@@@ } mktree(t, 1, &new_tree); - store_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0); + store_object(OBJ_TREE, &new_tree, &lo, &root->versions[1].oid, 0); t->delta_depth = lo.depth; for (i = 0, j = 0, del = 0; i < t->entry_count; i++) { struct tree_entry *e = t->entries[i]; if (e->versions[1].mode) { e->versions[0].mode = e->versions[1].mode; - hashcpy(e->versions[0].sha1, e->versions[1].sha1); + oidcpy(&e->versions[0].oid, &e->versions[1].oid); t->entries[j++] = e; } else { release_tree_entry(e); @@@@ -1531,14 -1531,14 -1528,14 +1532,14 @@@@ static void tree_content_replace( struct tree_entry *root, - const unsigned char *sha1, + const struct object_id *oid, const uint16_t mode, struct tree_content *newtree) { if (!S_ISDIR(mode)) die("Root cannot be a non-directory"); - hashclr(root->versions[0].sha1); - hashcpy(root->versions[1].sha1, sha1); + oidclr(&root->versions[0].oid); + oidcpy(&root->versions[1].oid, oid); if (root->tree) release_tree_content_recursive(root->tree); root->tree = newtree; @@@@ -1547,7 -1547,7 -1544,7 +1548,7 @@@@ static int tree_content_set( struct tree_entry *root, const char *p, - const unsigned char *sha1, + const struct object_id *oid, const uint16_t mode, struct tree_content *subtree) { @@@@ -1572,10 -1572,10 -1569,10 +1573,10 @@@@ if (!*slash1) { if (!S_ISDIR(mode) && e->versions[1].mode == mode - && !hashcmp(e->versions[1].sha1, sha1)) + && !oidcmp(&e->versions[1].oid, oid)) return 0; e->versions[1].mode = mode; - hashcpy(e->versions[1].sha1, sha1); + oidcpy(&e->versions[1].oid, oid); if (e->tree) release_tree_content_recursive(e->tree); e->tree = subtree; @@@@ -1596,7 -1596,7 -1593,7 +1597,7 @@@@ if (S_ISDIR(e->versions[0].mode)) e->versions[0].mode |= NO_DELTA; - hashclr(root->versions[1].sha1); + oidclr(&root->versions[1].oid); return 1; } if (!S_ISDIR(e->versions[1].mode)) { @@@@ -1605,8 -1605,8 -1602,8 +1606,8 @@@@ } if (!e->tree) load_tree(e); - if (tree_content_set(e, slash1 + 1, sha1, mode, subtree)) { - hashclr(root->versions[1].sha1); + if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) { + oidclr(&root->versions[1].oid); return 1; } return 0; @@@@ -1618,18 -1618,18 -1615,18 +1619,18 @@@@ e = new_tree_entry(); e->name = to_atom(p, n); e->versions[0].mode = 0; - hashclr(e->versions[0].sha1); + oidclr(&e->versions[0].oid); t->entries[t->entry_count++] = e; if (*slash1) { e->tree = new_tree_content(8); e->versions[1].mode = S_IFDIR; - tree_content_set(e, slash1 + 1, sha1, mode, subtree); + tree_content_set(e, slash1 + 1, oid, mode, subtree); } else { e->tree = subtree; e->versions[1].mode = mode; - hashcpy(e->versions[1].sha1, sha1); + oidcpy(&e->versions[1].oid, oid); } - hashclr(root->versions[1].sha1); + oidclr(&root->versions[1].oid); return 1; } @@@@ -1674,7 -1674,7 -1671,7 +1675,7 @@@@ static int tree_content_remove if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) { for (n = 0; n < e->tree->entry_count; n++) { if (e->tree->entries[n]->versions[1].mode) { - hashclr(root->versions[1].sha1); + oidclr(&root->versions[1].oid); return 1; } } @@@@ -1693,8 -1693,8 -1690,8 +1694,8 @@@@ del_entry release_tree_content_recursive(e->tree); e->tree = NULL; e->versions[1].mode = 0; - hashclr(e->versions[1].sha1); - hashclr(root->versions[1].sha1); + oidclr(&e->versions[1].oid); + oidclr(&root->versions[1].oid); return 1; } @@@@ -1739,7 -1739,7 -1736,7 +1740,7 @@@@ static int tree_content_get found_entry: memcpy(leaf, e, sizeof(*leaf)); - if (e->tree && is_null_sha1(e->versions[1].sha1)) + if (e->tree && is_null_oid(&e->versions[1].oid)) leaf->tree = dup_tree_content(e->tree); else leaf->tree = NULL; @@@@ -1750,35 -1750,35 -1747,34 +1751,35 @@@@ static int update_branch(struct branch { static const char *msg = "fast-import"; struct ref_transaction *transaction; - unsigned char old_sha1[20]; + struct object_id old_oid; struct strbuf err = STRBUF_INIT; - if (is_null_sha1(b->sha1)) { + if (is_null_oid(&b->oid)) { if (b->delete) delete_ref(NULL, b->name, NULL, 0); return 0; } - if (read_ref(b->name, old_sha1)) - hashclr(old_sha1); - if (!force_update && !is_null_sha1(old_sha1)) { + if (read_ref(b->name, old_oid.hash)) + oidclr(&old_oid); + if (!force_update && !is_null_oid(&old_oid)) { struct commit *old_cmit, *new_cmit; - old_cmit = lookup_commit_reference_gently(old_sha1, 0); - new_cmit = lookup_commit_reference_gently(b->sha1, 0); + old_cmit = lookup_commit_reference_gently(&old_oid, 0); + new_cmit = lookup_commit_reference_gently(&b->oid, 0); if (!old_cmit || !new_cmit) return error("Branch %s is missing commits.", b->name); if (!in_merge_bases(old_cmit, new_cmit)) { warning("Not updating %s" " (new tip %s does not contain %s)", - b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1)); + b->name, oid_to_hex(&b->oid), + oid_to_hex(&old_oid)); return -1; } } transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, b->name, b->sha1, old_sha1, + ref_transaction_update(transaction, b->name, b->oid.hash, old_oid.hash, 0, msg, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@@@ -1820,7 -1820,7 -1816,7 +1821,7 @@@@ static void dump_tags(void strbuf_addf(&ref_name, "refs/tags/%s", t->name); if (ref_transaction_update(transaction, ref_name.buf, - t->sha1, NULL, 0, msg, &err)) { + t->oid.hash, NULL, 0, msg, &err)) { failure |= error("%s", err.buf); goto cleanup; } @@@@ -1849,7 -1849,7 -1845,7 +1850,7 @@@@ static void dump_marks_helper(FILE *f for (k = 0; k < 1024; k++) { if (m->data.marked[k]) fprintf(f, ":%" PRIuMAX " %s\n", base + k, - sha1_to_hex(m->data.marked[k]->idx.sha1)); + oid_to_hex(&m->data.marked[k]->idx.oid)); } } } @@@@ -1898,7 -1898,7 -1894,7 +1899,7 @@@@ static void read_marks(void while (fgets(line, sizeof(line), f)) { uintmax_t mark; char *end; - unsigned char sha1[20]; + struct object_id oid; struct object_entry *e; end = strchr(line, '\n'); @@@@ -1907,14 -1907,14 -1903,14 +1908,14 @@@@ *end = 0; mark = strtoumax(line + 1, &end, 10); if (!mark || end == line + 1 - || *end != ' ' || get_sha1_hex(end + 1, sha1)) + || *end != ' ' || get_oid_hex(end + 1, &oid)) die("corrupt mark line: %s", line); - e = find_object(sha1); + e = find_object(&oid); if (!e) { - enum object_type type = sha1_object_info(sha1, NULL); + enum object_type type = sha1_object_info(oid.hash, NULL); if (type < 0) - die("object not found: %s", sha1_to_hex(sha1)); - e = insert_object(sha1); + die("object not found: %s", oid_to_hex(&oid)); + e = insert_object(&oid); e->type = type; e->pack_id = MAX_PACK_ID; e->idx.offset = 1; /* just not zero! */ @@@@ -2122,21 -2122,21 -2118,21 +2123,21 @@@@ static char *parse_ident(const char *bu static void parse_and_store_blob( struct last_object *last, - unsigned char *sha1out, + struct object_id *oidout, uintmax_t mark) { static struct strbuf buf = STRBUF_INIT; uintmax_t len; if (parse_data(&buf, big_file_threshold, &len)) - store_object(OBJ_BLOB, &buf, last, sha1out, mark); + store_object(OBJ_BLOB, &buf, last, oidout, mark); else { if (last) { strbuf_release(&last->data); last->offset = 0; last->depth = 0; } - stream_blob(len, sha1out, mark); + stream_blob(len, oidout, mark); skip_optional_lf(); } } @@@@ -2212,21 -2212,21 -2208,21 +2213,21 @@@@ static void construct_path_with_fanout( path[i++] = '/'; fanout--; } - memcpy(path + i, hex_sha1 + j, 40 - j); - path[i + 40 - j] = '\0'; + memcpy(path + i, hex_sha1 + j, GIT_SHA1_HEXSZ - j); + path[i + GIT_SHA1_HEXSZ - j] = '\0'; } static uintmax_t do_change_note_fanout( struct tree_entry *orig_root, struct tree_entry *root, - char *hex_sha1, unsigned int hex_sha1_len, + char *hex_oid, unsigned int hex_oid_len, char *fullpath, unsigned int fullpath_len, unsigned char fanout) { struct tree_content *t; struct tree_entry *e, leaf; - unsigned int i, tmp_hex_sha1_len, tmp_fullpath_len; + unsigned int i, tmp_hex_oid_len, tmp_fullpath_len; uintmax_t num_notes = 0; - unsigned char sha1[20]; + struct object_id oid; char realpath[60]; if (!root->tree) @@@@ -2235,7 -2235,7 -2231,7 +2236,7 @@@@ for (i = 0; t && i < t->entry_count; i++) { e = t->entries[i]; - tmp_hex_sha1_len = hex_sha1_len + e->name->str_len; + tmp_hex_oid_len = hex_oid_len + e->name->str_len; tmp_fullpath_len = fullpath_len; /* @@@@ -2247,12 -2247,12 -2243,12 +2248,12 @@@@ * of 2 chars. */ if (!e->versions[1].mode || - tmp_hex_sha1_len > 40 || + tmp_hex_oid_len > GIT_SHA1_HEXSZ || e->name->str_len % 2) continue; /* This _may_ be a note entry, or a subdir containing notes */ - memcpy(hex_sha1 + hex_sha1_len, e->name->str_dat, + memcpy(hex_oid + hex_oid_len, e->name->str_dat, e->name->str_len); if (tmp_fullpath_len) fullpath[tmp_fullpath_len++] = '/'; @@@@ -2261,14 -2261,14 -2257,14 +2262,14 @@@@ tmp_fullpath_len += e->name->str_len; fullpath[tmp_fullpath_len] = '\0'; - if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) { + if (tmp_hex_oid_len == GIT_SHA1_HEXSZ && !get_oid_hex(hex_oid, &oid)) { /* This is a note entry */ if (fanout == 0xff) { /* Counting mode, no rename */ num_notes++; continue; } - construct_path_with_fanout(hex_sha1, fanout, realpath); + construct_path_with_fanout(hex_oid, fanout, realpath); if (!strcmp(fullpath, realpath)) { /* Note entry is in correct location */ num_notes++; @@@@ -2279,13 -2279,13 -2275,13 +2280,13 @@@@ if (!tree_content_remove(orig_root, fullpath, &leaf, 0)) die("Failed to remove path %s", fullpath); tree_content_set(orig_root, realpath, - leaf.versions[1].sha1, + &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); } else if (S_ISDIR(e->versions[1].mode)) { /* This is a subdir that may contain note entries */ num_notes += do_change_note_fanout(orig_root, e, - hex_sha1, tmp_hex_sha1_len, + hex_oid, tmp_hex_oid_len, fullpath, tmp_fullpath_len, fanout); } @@@@ -2298,14 -2298,14 -2294,8 +2299,14 @@@@ static uintmax_t change_note_fanout(struct tree_entry *root, unsigned char fanout) { - char hex_sha1[40], path[60]; - return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout); + /* + * The size of path is due to one slash between every two hex digits, + * plus the terminating NUL. Note that there is no slash at the end, so + * the number of slashes is one less than half the number of hex + * characters. + */ + char hex_oid[GIT_MAX_HEXSZ], path[GIT_MAX_HEXSZ + (GIT_MAX_HEXSZ / 2) - 1 + 1]; + return do_change_note_fanout(root, root, hex_oid, 0, path, 0, fanout); } /* @@@@ -2366,7 -2366,7 -2356,7 +2367,7 @@@@ static void file_change_m(const char *p static struct strbuf uq = STRBUF_INIT; const char *endp; struct object_entry *oe; - unsigned char sha1[20]; + struct object_id oid; uint16_t mode, inline_data = 0; p = get_mode(p, &mode); @@@@ -2389,14 -2389,14 -2379,15 +2390,14 @@@@ if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); - hashcpy(sha1, oe->idx.sha1); + oidcpy(&oid, &oe->idx.oid); } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ } else { - if (get_sha1_hex(p, sha1)) + if (parse_oid_hex(p, &oid, &p)) die("Invalid dataref: %s", command_buf.buf); - oe = find_object(sha1); - p += 40; + oe = find_object(&oid); if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } @@@@ -2409,7 -2409,7 -2400,7 +2410,7 @@@@ } /* Git does not track empty, non-toplevel directories. */ - if (S_ISDIR(mode) && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN) && *p) { + if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *p) { tree_content_remove(&b->branch_tree, p, NULL, 0); return; } @@@@ -2436,12 -2436,12 -2427,12 +2437,12 @@@@ p = uq.buf; } read_next_command(); - parse_and_store_blob(&last_blob, sha1, 0); + parse_and_store_blob(&last_blob, &oid, 0); } else { enum object_type expected = S_ISDIR(mode) ? OBJ_TREE: OBJ_BLOB; enum object_type type = oe ? oe->type : - sha1_object_info(sha1, NULL); + sha1_object_info(oid.hash, NULL); if (type < 0) die("%s not found: %s", S_ISDIR(mode) ? "Tree" : "Blob", @@@@ -2453,10 -2453,10 -2444,10 +2454,10 @@@@ } if (!*p) { - tree_content_replace(&b->branch_tree, sha1, mode, NULL); + tree_content_replace(&b->branch_tree, &oid, mode, NULL); return; } - tree_content_set(&b->branch_tree, p, sha1, mode, NULL); + tree_content_set(&b->branch_tree, p, &oid, mode, NULL); } static void file_change_d(const char *p, struct branch *b) @@@@ -2514,13 -2514,13 -2505,13 +2515,13 @@@@ static void file_change_cr(const char * die("Path %s not in branch", s); if (!*d) { /* C "path/to/subdir" "" */ tree_content_replace(&b->branch_tree, - leaf.versions[1].sha1, + &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); return; } tree_content_set(&b->branch_tree, d, - leaf.versions[1].sha1, + &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); } @@@@ -2530,7 -2530,7 -2521,7 +2531,7 @@@@ static void note_change_n(const char *p static struct strbuf uq = STRBUF_INIT; struct object_entry *oe; struct branch *s; - unsigned char sha1[20], commit_sha1[20]; + struct object_id oid, commit_oid; char path[60]; uint16_t inline_data = 0; unsigned char new_fanout; @@@@ -2555,14 -2555,14 -2546,15 +2556,14 @@@@ /* or 'inline' */ if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); - hashcpy(sha1, oe->idx.sha1); + oidcpy(&oid, &oe->idx.oid); } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ } else { - if (get_sha1_hex(p, sha1)) + if (parse_oid_hex(p, &oid, &p)) die("Invalid dataref: %s", command_buf.buf); - oe = find_object(sha1); - p += 40; + oe = find_object(&oid); if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } @@@@ -2570,19 -2570,19 -2562,19 +2571,19 @@@@ /* */ s = lookup_branch(p); if (s) { - if (is_null_sha1(s->sha1)) + if (is_null_oid(&s->oid)) die("Can't add a note on empty branch."); - hashcpy(commit_sha1, s->sha1); + oidcpy(&commit_oid, &s->oid); } else if (*p == ':') { uintmax_t commit_mark = parse_mark_ref_eol(p); struct object_entry *commit_oe = find_mark(commit_mark); if (commit_oe->type != OBJ_COMMIT) die("Mark :%" PRIuMAX " not a commit", commit_mark); - hashcpy(commit_sha1, commit_oe->idx.sha1); - } else if (!get_sha1(p, commit_sha1)) { + oidcpy(&commit_oid, &commit_oe->idx.oid); + } else if (!get_oid(p, &commit_oid)) { unsigned long size; - char *buf = read_object_with_reference(commit_sha1, - commit_type, &size, commit_sha1); + char *buf = read_object_with_reference(commit_oid.hash, + commit_type, &size, commit_oid.hash); if (!buf || size < 46) die("Not a valid commit: %s", p); free(buf); @@@@ -2595,13 -2595,13 -2587,13 +2596,13 @@@@ p = uq.buf; } read_next_command(); - parse_and_store_blob(&last_blob, sha1, 0); + parse_and_store_blob(&last_blob, &oid, 0); } else if (oe) { if (oe->type != OBJ_BLOB) die("Not a blob (actually a %s): %s", typename(oe->type), command_buf.buf); - } else if (!is_null_sha1(sha1)) { - enum object_type type = sha1_object_info(sha1, NULL); + } else if (!is_null_oid(&oid)) { + enum object_type type = sha1_object_info(oid.hash, NULL); if (type < 0) die("Blob not found: %s", command_buf.buf); if (type != OBJ_BLOB) @@@@ -2609,51 -2609,51 -2601,50 +2610,51 @@@@ typename(type), command_buf.buf); } - construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path); + construct_path_with_fanout(oid_to_hex(&commit_oid), *old_fanout, path); if (tree_content_remove(&b->branch_tree, path, NULL, 0)) b->num_notes--; - if (is_null_sha1(sha1)) + if (is_null_oid(&oid)) return; /* nothing to insert */ b->num_notes++; new_fanout = convert_num_notes_to_fanout(b->num_notes); - construct_path_with_fanout(sha1_to_hex(commit_sha1), new_fanout, path); - tree_content_set(&b->branch_tree, path, sha1, S_IFREG | 0644, NULL); + construct_path_with_fanout(oid_to_hex(&commit_oid), new_fanout, path); + tree_content_set(&b->branch_tree, path, &oid, S_IFREG | 0644, NULL); } static void file_change_deleteall(struct branch *b) { release_tree_content_recursive(b->branch_tree.tree); - hashclr(b->branch_tree.versions[0].sha1); - hashclr(b->branch_tree.versions[1].sha1); + oidclr(&b->branch_tree.versions[0].oid); + oidclr(&b->branch_tree.versions[1].oid); load_tree(&b->branch_tree); b->num_notes = 0; } static void parse_from_commit(struct branch *b, char *buf, unsigned long size) { - if (!buf || size < 46) - die("Not a valid commit: %s", sha1_to_hex(b->sha1)); + if (!buf || size < GIT_SHA1_HEXSZ + 6) + die("Not a valid commit: %s", oid_to_hex(&b->oid)); if (memcmp("tree ", buf, 5) - || get_sha1_hex(buf + 5, b->branch_tree.versions[1].sha1)) - die("The commit %s is corrupt", sha1_to_hex(b->sha1)); - hashcpy(b->branch_tree.versions[0].sha1, - b->branch_tree.versions[1].sha1); + || get_oid_hex(buf + 5, &b->branch_tree.versions[1].oid)) + die("The commit %s is corrupt", oid_to_hex(&b->oid)); + oidcpy(&b->branch_tree.versions[0].oid, + &b->branch_tree.versions[1].oid); } static void parse_from_existing(struct branch *b) { - if (is_null_sha1(b->sha1)) { - hashclr(b->branch_tree.versions[0].sha1); - hashclr(b->branch_tree.versions[1].sha1); + if (is_null_oid(&b->oid)) { + oidclr(&b->branch_tree.versions[0].oid); + oidclr(&b->branch_tree.versions[1].oid); } else { unsigned long size; char *buf; - buf = read_object_with_reference(b->sha1, - commit_type, &size, b->sha1); + buf = read_object_with_reference(b->oid.hash, + commit_type, &size, + b->oid.hash); parse_from_commit(b, buf, size); free(buf); } @@@@ -2663,28 -2663,28 -2654,28 +2664,28 @@@@ static int parse_from(struct branch *b { const char *from; struct branch *s; - unsigned char sha1[20]; + struct object_id oid; if (!skip_prefix(command_buf.buf, "from ", &from)) return 0; - hashcpy(sha1, b->branch_tree.versions[1].sha1); + oidcpy(&oid, &b->branch_tree.versions[1].oid); s = lookup_branch(from); if (b == s) die("Can't create a branch from itself: %s", b->name); else if (s) { - unsigned char *t = s->branch_tree.versions[1].sha1; - hashcpy(b->sha1, s->sha1); - hashcpy(b->branch_tree.versions[0].sha1, t); - hashcpy(b->branch_tree.versions[1].sha1, t); + struct object_id *t = &s->branch_tree.versions[1].oid; + oidcpy(&b->oid, &s->oid); + oidcpy(&b->branch_tree.versions[0].oid, t); + oidcpy(&b->branch_tree.versions[1].oid, t); } else if (*from == ':') { uintmax_t idnum = parse_mark_ref_eol(from); struct object_entry *oe = find_mark(idnum); if (oe->type != OBJ_COMMIT) die("Mark :%" PRIuMAX " not a commit", idnum); - if (hashcmp(b->sha1, oe->idx.sha1)) { - hashcpy(b->sha1, oe->idx.sha1); + if (oidcmp(&b->oid, &oe->idx.oid)) { + oidcpy(&b->oid, &oe->idx.oid); if (oe->pack_id != MAX_PACK_ID) { unsigned long size; char *buf = gfi_unpack_entry(oe, &size); @@@@ -2693,15 -2693,15 -2684,15 +2694,15 @@@@ } else parse_from_existing(b); } - } else if (!get_sha1(from, b->sha1)) { + } else if (!get_oid(from, &b->oid)) { parse_from_existing(b); - if (is_null_sha1(b->sha1)) + if (is_null_oid(&b->oid)) b->delete = 1; } else die("Invalid ref name or SHA1 expression: %s", from); - if (b->branch_tree.tree && hashcmp(sha1, b->branch_tree.versions[1].sha1)) { + if (b->branch_tree.tree && oidcmp(&oid, &b->branch_tree.versions[1].oid)) { release_tree_content_recursive(b->branch_tree.tree); b->branch_tree.tree = NULL; } @@@@ -2721,17 -2721,17 -2712,17 +2722,17 @@@@ static struct hash_list *parse_merge(un n = xmalloc(sizeof(*n)); s = lookup_branch(from); if (s) - hashcpy(n->sha1, s->sha1); + oidcpy(&n->oid, &s->oid); else if (*from == ':') { uintmax_t idnum = parse_mark_ref_eol(from); struct object_entry *oe = find_mark(idnum); if (oe->type != OBJ_COMMIT) die("Mark :%" PRIuMAX " not a commit", idnum); - hashcpy(n->sha1, oe->idx.sha1); - } else if (!get_sha1(from, n->sha1)) { + oidcpy(&n->oid, &oe->idx.oid); + } else if (!get_oid(from, &n->oid)) { unsigned long size; - char *buf = read_object_with_reference(n->sha1, - commit_type, &size, n->sha1); + char *buf = read_object_with_reference(n->oid.hash, + commit_type, &size, n->oid.hash); if (!buf || size < 46) die("Not a valid commit: %s", from); free(buf); @@@@ -2818,19 -2818,19 -2809,17 +2819,19 @@@@ static void parse_new_commit(const cha /* build the tree and the commit */ store_tree(&b->branch_tree); - hashcpy(b->branch_tree.versions[0].sha1, - b->branch_tree.versions[1].sha1); + oidcpy(&b->branch_tree.versions[0].oid, + &b->branch_tree.versions[1].oid); strbuf_reset(&new_data); strbuf_addf(&new_data, "tree %s\n", - sha1_to_hex(b->branch_tree.versions[1].sha1)); - if (!is_null_sha1(b->sha1)) - strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(b->sha1)); + oid_to_hex(&b->branch_tree.versions[1].oid)); + if (!is_null_oid(&b->oid)) + strbuf_addf(&new_data, "parent %s\n", + oid_to_hex(&b->oid)); while (merge_list) { struct hash_list *next = merge_list->next; - strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(merge_list->sha1)); + strbuf_addf(&new_data, "parent %s\n", + oid_to_hex(&merge_list->oid)); free(merge_list); merge_list = next; } @@@@ -2843,7 -2843,7 -2832,7 +2844,7 @@@@ free(author); free(committer); - if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark)) + if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark)) b->pack_id = pack_id; b->last_commit = object_count_by_type[OBJ_COMMIT]; } @@@@ -2856,7 -2856,7 -2845,7 +2857,7 @@@@ static void parse_new_tag(const char *a struct branch *s; struct tag *t; uintmax_t from_mark = 0; - unsigned char sha1[20]; + struct object_id oid; enum object_type type; const char *v; @@@@ -2875,20 -2875,20 -2864,20 +2876,20 @@@@ die("Expected from command, got %s", command_buf.buf); s = lookup_branch(from); if (s) { - if (is_null_sha1(s->sha1)) + if (is_null_oid(&s->oid)) die("Can't tag an empty branch."); - hashcpy(sha1, s->sha1); + oidcpy(&oid, &s->oid); type = OBJ_COMMIT; } else if (*from == ':') { struct object_entry *oe; from_mark = parse_mark_ref_eol(from); oe = find_mark(from_mark); type = oe->type; - hashcpy(sha1, oe->idx.sha1); - } else if (!get_sha1(from, sha1)) { - struct object_entry *oe = find_object(sha1); + oidcpy(&oid, &oe->idx.oid); + } else if (!get_oid(from, &oid)) { + struct object_entry *oe = find_object(&oid); if (!oe) { - type = sha1_object_info(sha1, NULL); + type = sha1_object_info(oid.hash, NULL); if (type < 0) die("Not a valid object: %s", from); } else @@@@ -2914,7 -2914,7 -2903,7 +2915,7 @@@@ "object %s\n" "type %s\n" "tag %s\n", - sha1_to_hex(sha1), typename(type), t->name); + oid_to_hex(&oid), typename(type), t->name); if (tagger) strbuf_addf(&new_data, "tagger %s\n", tagger); @@@@ -2922,7 -2922,7 -2911,7 +2923,7 @@@@ strbuf_addbuf(&new_data, &msg); free(tagger); - if (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0)) + if (store_object(OBJ_TAG, &new_data, NULL, &t->oid, 0)) t->pack_id = MAX_PACK_ID; else t->pack_id = pack_id; @@@@ -2934,9 -2934,9 -2923,9 +2935,9 @@@@ static void parse_reset_branch(const ch b = lookup_branch(arg); if (b) { - hashclr(b->sha1); - hashclr(b->branch_tree.versions[0].sha1); - hashclr(b->branch_tree.versions[1].sha1); + oidclr(&b->oid); + oidclr(&b->branch_tree.versions[0].oid); + oidclr(&b->branch_tree.versions[1].oid); if (b->branch_tree.tree) { release_tree_content_recursive(b->branch_tree.tree); b->branch_tree.tree = NULL; @@@@ -2956,7 -2956,7 -2945,7 +2957,7 @@@@ static void cat_blob_write(const char * die_errno("Write to frontend failed"); } -static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) +static void cat_blob(struct object_entry *oe, struct object_id *oid) { struct strbuf line = STRBUF_INIT; unsigned long size; @@@@ -2964,7 -2964,7 -2953,7 +2965,7 @@@@ char *buf; if (!oe || oe->pack_id == MAX_PACK_ID) { - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); } else { type = oe->type; buf = gfi_unpack_entry(oe, &size); @@@@ -2975,19 -2975,19 -2964,19 +2976,19 @@@@ */ if (type <= 0) { strbuf_reset(&line); - strbuf_addf(&line, "%s missing\n", sha1_to_hex(sha1)); + strbuf_addf(&line, "%s missing\n", oid_to_hex(oid)); cat_blob_write(line.buf, line.len); strbuf_release(&line); free(buf); return; } if (!buf) - die("Can't read object %s", sha1_to_hex(sha1)); + die("Can't read object %s", oid_to_hex(oid)); if (type != OBJ_BLOB) die("Object %s is a %s but a blob was expected.", - sha1_to_hex(sha1), typename(type)); + oid_to_hex(oid), typename(type)); strbuf_reset(&line); - strbuf_addf(&line, "%s %s %lu\n", sha1_to_hex(sha1), + strbuf_addf(&line, "%s %s %lu\n", oid_to_hex(oid), typename(type), size); cat_blob_write(line.buf, line.len); strbuf_release(&line); @@@@ -3004,7 -3004,7 -2993,7 +3005,7 @@@@ static void parse_get_mark(const char *p) { struct object_entry *oe = oe; - char output[42]; + char output[GIT_MAX_HEXSZ + 2]; /* get-mark SP LF */ if (*p != ':') @@@@ -3014,43 -3014,43 -3003,43 +3015,43 @@@@ if (!oe) die("Unknown mark: %s", command_buf.buf); - xsnprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1)); - cat_blob_write(output, 41); + xsnprintf(output, sizeof(output), "%s\n", oid_to_hex(&oe->idx.oid)); + cat_blob_write(output, GIT_SHA1_HEXSZ + 1); } static void parse_cat_blob(const char *p) { struct object_entry *oe = oe; - unsigned char sha1[20]; + struct object_id oid; /* cat-blob SP LF */ if (*p == ':') { oe = find_mark(parse_mark_ref_eol(p)); if (!oe) die("Unknown mark: %s", command_buf.buf); - hashcpy(sha1, oe->idx.sha1); + oidcpy(&oid, &oe->idx.oid); } else { - if (get_sha1_hex(p, sha1)) + if (parse_oid_hex(p, &oid, &p)) die("Invalid dataref: %s", command_buf.buf); - if (p[40]) + if (*p) die("Garbage after SHA1: %s", command_buf.buf); - oe = find_object(sha1); + oe = find_object(&oid); } - cat_blob(oe, sha1); + cat_blob(oe, &oid); } static struct object_entry *dereference(struct object_entry *oe, - unsigned char sha1[20]) + struct object_id *oid) { unsigned long size; char *buf = NULL; if (!oe) { - enum object_type type = sha1_object_info(sha1, NULL); + enum object_type type = sha1_object_info(oid->hash, NULL); if (type < 0) - die("object not found: %s", sha1_to_hex(sha1)); + die("object not found: %s", oid_to_hex(oid)); /* cache it! */ - oe = insert_object(sha1); + oe = insert_object(oid); oe->type = type; oe->pack_id = MAX_PACK_ID; oe->idx.offset = 1; @@@@ -3069,48 -3069,48 -3058,49 +3070,48 @@@@ buf = gfi_unpack_entry(oe, &size); } else { enum object_type unused; - buf = read_sha1_file(sha1, &unused, &size); + buf = read_sha1_file(oid->hash, &unused, &size); } if (!buf) - die("Can't load object %s", sha1_to_hex(sha1)); + die("Can't load object %s", oid_to_hex(oid)); /* Peel one layer. */ switch (oe->type) { case OBJ_TAG: - if (size < 40 + strlen("object ") || - get_sha1_hex(buf + strlen("object "), sha1)) + if (size < GIT_SHA1_HEXSZ + strlen("object ") || + get_oid_hex(buf + strlen("object "), oid)) die("Invalid SHA1 in tag: %s", command_buf.buf); break; case OBJ_COMMIT: - if (size < 40 + strlen("tree ") || - get_sha1_hex(buf + strlen("tree "), sha1)) + if (size < GIT_SHA1_HEXSZ + strlen("tree ") || + get_oid_hex(buf + strlen("tree "), oid)) die("Invalid SHA1 in commit: %s", command_buf.buf); } free(buf); - return find_object(sha1); + return find_object(oid); } static struct object_entry *parse_treeish_dataref(const char **p) { - unsigned char sha1[20]; + struct object_id oid; struct object_entry *e; if (**p == ':') { /* */ e = find_mark(parse_mark_ref_space(p)); if (!e) die("Unknown mark: %s", command_buf.buf); - hashcpy(sha1, e->idx.sha1); + oidcpy(&oid, &e->idx.oid); } else { /* */ - if (get_sha1_hex(*p, sha1)) + if (parse_oid_hex(*p, &oid, p)) die("Invalid dataref: %s", command_buf.buf); - e = find_object(sha1); - *p += 40; + e = find_object(&oid); if (*(*p)++ != ' ') die("Missing space after tree-ish: %s", command_buf.buf); } while (!e || e->type != OBJ_TREE) - e = dereference(e, sha1); + e = dereference(e, &oid); return e; } @@@@ -3154,8 -3154,8 -3144,8 +3155,8 @@@@ static void parse_ls(const char *p, str } else { struct object_entry *e = parse_treeish_dataref(&p); root = new_tree_entry(); - hashcpy(root->versions[1].sha1, e->idx.sha1); - if (!is_null_sha1(root->versions[1].sha1)) + oidcpy(&root->versions[1].oid, &e->idx.oid); + if (!is_null_oid(&root->versions[1].oid)) root->versions[1].mode = S_IFDIR; load_tree(root); } @@@@ -3177,7 -3177,7 -3167,7 +3178,7 @@@@ if (S_ISDIR(leaf.versions[1].mode)) store_tree(&leaf); - print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p); + print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, p); if (leaf.tree) release_tree_content_recursive(leaf.tree); if (!b || root != &b->branch_tree) @@@@ -3285,7 -3285,9 -3275,9 +3286,7 @@@@ static void option_export_pack_edges(co { if (pack_edges) fclose(pack_edges); -- pack_edges = fopen(edges, "a"); -- if (!pack_edges) -- die_errno("Cannot open '%s'", edges); ++ pack_edges = xfopen(edges, "a"); } static int parse_one_option(const char *option) diff --combined fetch-pack.c index cd86865beb,cd86865beb,963d45db91..fbbc99c888 --- a/fetch-pack.c +++ b/fetch-pack.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "refs.h" #include "pkt-line.h" @@@@ -15,7 -15,7 -16,6 +16,7 @@@@ #include "version.h" #include "prio-queue.h" #include "sha1-array.h" +#include "oidset.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@@@ -79,7 -79,7 -79,7 +80,7 @@@@ static void cache_one_alternate(const c void *vcache) { struct alternate_object_cache *cache = vcache; - struct object *obj = parse_object(oid->hash); + struct object *obj = parse_object(oid); if (!obj || (obj->flags & ALTERNATE)) return; @@@@ -119,9 -119,9 -119,9 +120,9 @@@@ static void rev_list_push(struct commi } } -static int rev_list_insert_ref(const char *refname, const unsigned char *sha1) +static int rev_list_insert_ref(const char *refname, const struct object_id *oid) { - struct object *o = deref_tag(parse_object(sha1), refname, 0); + struct object *o = deref_tag(parse_object(oid), refname, 0); if (o && o->type == OBJ_COMMIT) rev_list_push((struct commit *)o, SEEN); @@@@ -132,13 -132,13 -132,13 +133,13 @@@@ static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - return rev_list_insert_ref(refname, oid->hash); + return rev_list_insert_ref(refname, oid); } static int clear_marks(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - struct object *o = deref_tag(parse_object(oid->hash), refname, 0); + struct object *o = deref_tag(parse_object(oid), refname, 0); if (o && o->type == OBJ_COMMIT) clear_commit_marks((struct commit *)o, @@@@ -184,7 -184,7 -184,7 +185,7 @@@@ static void mark_common(struct commit * Get the next rev to send, ignoring the common. */ -static const unsigned char *get_rev(void) +static const struct object_id *get_rev(void) { struct commit *commit = NULL; @@@@ -223,7 -223,7 -223,7 +224,7 @@@@ } } - return commit->object.oid.hash; + return &commit->object.oid; } enum ack_type { @@@@ -252,7 -252,7 -252,7 +253,7 @@@@ static void consume_shallow_list(struc } } -static enum ack_type get_ack(int fd, unsigned char *result_sha1) +static enum ack_type get_ack(int fd, struct object_id *result_oid) { int len; char *line = packet_read_line(fd, &len); @@@@ -263,7 -263,7 -263,7 +264,7 @@@@ if (!strcmp(line, "NAK")) return NAK; if (skip_prefix(line, "ACK ", &arg)) { - if (!get_sha1_hex(arg, result_sha1)) { + if (!get_oid_hex(arg, result_oid)) { arg += 40; len -= arg - line; if (len < 1) @@@@ -294,7 -294,7 -294,7 +295,7 @@@@ static void send_request(struct fetch_p static void insert_one_alternate_object(struct object *obj) { - rev_list_insert_ref(NULL, obj->oid.hash); + rev_list_insert_ref(NULL, &obj->oid); } #define INITIAL_FLUSH 16 @@@@ -318,12 -318,12 -318,12 +319,12 @@@@ static int next_flush(struct fetch_pack } static int find_common(struct fetch_pack_args *args, - int fd[2], unsigned char *result_sha1, + int fd[2], struct object_id *result_oid, struct ref *refs) { int fetching; int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; - const unsigned char *sha1; + const struct object_id *oid; unsigned in_vain = 0; int got_continue = 0; int got_ready = 0; @@@@ -341,7 -341,7 -341,7 +342,7 @@@@ fetching = 0; for ( ; refs ; refs = refs->next) { - unsigned char *remote = refs->old_oid.hash; + struct object_id *remote = &refs->old_oid; const char *remote_hex; struct object *o; @@@@ -355,12 -355,12 -355,12 +356,12 @@@@ * interested in the case we *know* the object is * reachable and we have already scanned it. */ - if (((o = lookup_object(remote)) != NULL) && + if (((o = lookup_object(remote->hash)) != NULL) && (o->flags & COMPLETE)) { continue; } - remote_hex = sha1_to_hex(remote); + remote_hex = oid_to_hex(remote); if (!fetching) { struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); @@@@ -395,8 -395,8 -395,8 +396,8 @@@@ if (args->depth > 0) packet_buf_write(&req_buf, "deepen %d", args->depth); if (args->deepen_since) { - unsigned long max_age = approxidate(args->deepen_since); - packet_buf_write(&req_buf, "deepen-since %lu", max_age); + timestamp_t max_age = approxidate(args->deepen_since); + packet_buf_write(&req_buf, "deepen-since %"PRItime, max_age); } if (args->deepen_not) { int i; @@@@ -411,25 -411,25 -411,25 +412,25 @@@@ if (args->deepen) { char *line; const char *arg; - unsigned char sha1[20]; + struct object_id oid; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { if (skip_prefix(line, "shallow ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), line); - register_shallow(sha1); + register_shallow(&oid); continue; } if (skip_prefix(line, "unshallow ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die(_("invalid unshallow line: %s"), line); - if (!lookup_object(sha1)) + if (!lookup_object(oid.hash)) die(_("object not found: %s"), line); /* make sure that it is parsed as shallow */ - if (!parse_object(sha1)) + if (!parse_object(&oid)) die(_("error in object: %s"), line); - if (unregister_shallow(sha1)) + if (unregister_shallow(&oid)) die(_("no shallow found: %s"), line); continue; } @@@@ -448,9 -448,9 -448,9 +449,9 @@@@ flushes = 0; retval = -1; - while ((sha1 = get_rev())) { - packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1)); - print_verbose(args, "have %s", sha1_to_hex(sha1)); + while ((oid = get_rev())) { + packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid)); + print_verbose(args, "have %s", oid_to_hex(oid)); in_vain++; if (flush_at <= ++count) { int ack; @@@@ -470,10 -470,10 -470,10 +471,10 @@@@ consume_shallow_list(args, fd[0]); do { - ack = get_ack(fd[0], result_sha1); + ack = get_ack(fd[0], result_oid); if (ack) print_verbose(args, _("got %s %d %s"), "ack", - ack, sha1_to_hex(result_sha1)); + ack, oid_to_hex(result_oid)); switch (ack) { case ACK: flushes = 0; @@@@ -484,9 -484,9 -484,9 +485,9 @@@@ case ACK_ready: case ACK_continue: { struct commit *commit = - lookup_commit(result_sha1); + lookup_commit(result_oid); if (!commit) - die(_("invalid commit %s"), sha1_to_hex(result_sha1)); + die(_("invalid commit %s"), oid_to_hex(result_oid)); if (args->stateless_rpc && ack == ACK_common && !(commit->object.flags & COMMON)) { @@@@ -494,7 -494,7 -494,7 +495,7 @@@@ * on the next RPC request so the peer knows * it is in common with us. */ - const char *hex = sha1_to_hex(result_sha1); + const char *hex = oid_to_hex(result_oid); packet_buf_write(&req_buf, "have %s\n", hex); state_len = req_buf.len; /* @@@@ -539,10 -539,10 -539,10 +540,10 @@@@ done if (!got_ready || !no_done) consume_shallow_list(args, fd[0]); while (flushes || multi_ack) { - int ack = get_ack(fd[0], result_sha1); + int ack = get_ack(fd[0], result_oid); if (ack) { print_verbose(args, _("got %s (%d) %s"), "ack", - ack, sha1_to_hex(result_sha1)); + ack, oid_to_hex(result_oid)); if (ack == ACK) return 0; multi_ack = 1; @@@@ -556,16 -556,16 -556,16 +557,16 @@@@ static struct commit_list *complete; -static int mark_complete(const unsigned char *sha1) +static int mark_complete(const struct object_id *oid) { - struct object *o = parse_object(sha1); + struct object *o = parse_object(oid); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o->flags |= COMPLETE; - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; @@@@ -580,11 -580,11 -580,11 +581,11 @@@@ static int mark_complete_oid(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - return mark_complete(oid->hash); + return mark_complete(oid); } static void mark_recent_complete_commits(struct fetch_pack_args *args, - unsigned long cutoff) + timestamp_t cutoff) { while (complete && cutoff <= complete->item->date) { print_verbose(args, _("Marking %s as complete"), @@@@ -593,38 -593,38 -593,13 +594,38 @@@@ } } +static void add_refs_to_oidset(struct oidset *oids, struct ref *refs) +{ + for (; refs; refs = refs->next) + oidset_insert(oids, &refs->old_oid); +} + +static int tip_oids_contain(struct oidset *tip_oids, + struct ref *unmatched, struct ref *newlist, + const struct object_id *id) +{ + /* + * Note that this only looks at the ref lists the first time it's + * called. This works out in filter_refs() because even though it may + * add to "newlist" between calls, the additions will always be for + * oids that are already in the set. + */ + if (!tip_oids->map.tablesize) { + add_refs_to_oidset(tip_oids, unmatched); + add_refs_to_oidset(tip_oids, newlist); + } + return oidset_contains(tip_oids, id); +} + static void filter_refs(struct fetch_pack_args *args, struct ref **refs, struct ref **sought, int nr_sought) { struct ref *newlist = NULL; struct ref **newtail = &newlist; + struct ref *unmatched = NULL; struct ref *ref, *next; + struct oidset tip_oids = OIDSET_INIT; int i; i = 0; @@@@ -657,28 -657,28 -632,24 +658,28 @@@@ ref->next = NULL; newtail = &ref->next; } else { - free(ref); + ref->next = unmatched; + unmatched = ref; } } /* Append unmatched requests to the list */ for (i = 0; i < nr_sought; i++) { - unsigned char sha1[20]; + struct object_id oid; + const char *p; ref = sought[i]; if (ref->match_status != REF_NOT_MATCHED) continue; - if (get_sha1_hex(ref->name, sha1) || - ref->name[40] != '\0' || - hashcmp(sha1, ref->old_oid.hash)) + if (parse_oid_hex(ref->name, &oid, &p) || + *p != '\0' || + oidcmp(&oid, &ref->old_oid)) continue; if ((allow_unadvertised_object_request & - (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) { + (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) || + tip_oids_contain(&tip_oids, unmatched, newlist, + &ref->old_oid)) { ref->match_status = REF_MATCHED; *newtail = copy_ref(ref); newtail = &(*newtail)->next; @@@@ -686,19 -686,19 -657,12 +687,19 @@@@ ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; } } + + oidset_clear(&tip_oids); + for (ref = unmatched; ref; ref = next) { + next = ref->next; + free(ref); + } + *refs = newlist; } static void mark_alternate_complete(struct object *obj) { - mark_complete(obj->oid.hash); + mark_complete(&obj->oid); } static int everything_local(struct fetch_pack_args *args, @@@@ -707,7 -707,7 -671,7 +708,7 @@@@ { struct ref *ref; int retval; - unsigned long cutoff = 0; + timestamp_t cutoff = 0; save_commit_buffer = 0; @@@@ -717,7 -717,7 -681,7 +718,7 @@@@ if (!has_object_file(&ref->old_oid)) continue; - o = parse_object(ref->old_oid.hash); + o = parse_object(&ref->old_oid); if (!o) continue; @@@@ -761,17 -761,17 -725,17 +762,17 @@@@ filter_refs(args, refs, sought, nr_sought); for (retval = 1, ref = *refs; ref ; ref = ref->next) { - const unsigned char *remote = ref->old_oid.hash; + const struct object_id *remote = &ref->old_oid; struct object *o; - o = lookup_object(remote); + o = lookup_object(remote->hash); if (!o || !(o->flags & COMPLETE)) { retval = 0; - print_verbose(args, "want %s (%s)", sha1_to_hex(remote), + print_verbose(args, "want %s (%s)", oid_to_hex(remote), ref->name); continue; } - print_verbose(args, _("already have %s (%s)"), sha1_to_hex(remote), + print_verbose(args, _("already have %s (%s)"), oid_to_hex(remote), ref->name); } return retval; @@@@ -910,7 -910,7 -874,7 +911,7 @@@@ static struct ref *do_fetch_pack(struc char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); - unsigned char sha1[20]; + struct object_id oid; const char *agent_feature; int agent_len; @@@@ -982,7 -982,7 -946,7 +983,7 @@@@ packet_flush(fd[1]); goto all_done; } - if (find_common(args, fd, sha1, ref) < 0) + if (find_common(args, fd, &oid, ref) < 0) if (!args->keep_pack) /* When cloning, it is not unusual to have * no common commit. diff --combined git.c index 1b8b7f51a6,8ff44f081d,c03de2c090..5be27b07e5 --- a/git.c +++ b/git.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "builtin.h" ++ #include "config.h" #include "exec_cmd.h" #include "help.h" #include "run-command.h" @@@@ -16,53 -16,51 -17,7 +17,9 @@@@ const char git_more_info_string[] "to read about a specific subcommand or concept."); static int use_pager = -1; -- static char *orig_cwd; -- static const char *env_names[] = { -- GIT_DIR_ENVIRONMENT, -- GIT_WORK_TREE_ENVIRONMENT, -- GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, -- GIT_PREFIX_ENVIRONMENT -- }; -- static char *orig_env[4]; -- static int save_restore_env_balance; - - static void save_env_before_alias(void) - { - int i; - - assert(save_restore_env_balance == 0); - save_restore_env_balance = 1; - orig_cwd = xgetcwd(); - for (i = 0; i < ARRAY_SIZE(env_names); i++) { - orig_env[i] = getenv(env_names[i]); - orig_env[i] = xstrdup_or_null(orig_env[i]); - } - } - static void restore_env(int external_alias) - { - int i; - - assert(save_restore_env_balance == 1); - save_restore_env_balance = 0; - if (!external_alias && orig_cwd && chdir(orig_cwd)) - die_errno("could not move to %s", orig_cwd); - free(orig_cwd); - for (i = 0; i < ARRAY_SIZE(env_names); i++) { - if (external_alias && - !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT)) - continue; - if (orig_env[i]) { - setenv(env_names[i], orig_env[i], 1); - free(orig_env[i]); - } else { - unsetenv(env_names[i]); - } - } - } ++static void list_builtins(void); + - static void save_env_before_alias(void) - { - int i; - - assert(save_restore_env_balance == 0); - save_restore_env_balance = 1; - orig_cwd = xgetcwd(); - for (i = 0; i < ARRAY_SIZE(env_names); i++) { - orig_env[i] = getenv(env_names[i]); - orig_env[i] = xstrdup_or_null(orig_env[i]); - } - } - - static void restore_env(int external_alias) - { - int i; - - assert(save_restore_env_balance == 1); - save_restore_env_balance = 0; - if (!external_alias && orig_cwd && chdir(orig_cwd)) - die_errno("could not move to %s", orig_cwd); - free(orig_cwd); - for (i = 0; i < ARRAY_SIZE(env_names); i++) { - if (external_alias && - !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT)) - continue; - if (orig_env[i]) { - setenv(env_names[i], orig_env[i], 1); - free(orig_env[i]); - } else { - unsetenv(env_names[i]); - } - } - } - static void commit_pager_choice(void) { switch (use_pager) { case 0: @@@@ -234,9 -232,6 -189,6 +191,9 @@@@ static int handle_options(const char ** } (*argv)++; (*argc)--; ++ } else if (!strcmp(cmd, "--list-builtins")) { ++ list_builtins(); ++ exit(0); } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(git_usage_string); @@@@ -255,19 -250,19 -207,18 +212,18 @@@@ static int handle_alias(int *argcp, con const char **new_argv; const char *alias_command; char *alias_string; -- int unused_nongit; -- -- save_env_before_alias(); -- setup_git_directory_gently(&unused_nongit); alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { struct child_process child = CHILD_PROCESS_INIT; ++ int nongit_ok; ++ ++ /* Aliases expect GIT_PREFIX, GIT_DIR etc to be set */ ++ setup_git_directory_gently(&nongit_ok); commit_pager_choice(); -- restore_env(1); child.use_shell = 1; argv_array_push(&child.args, alias_string + 1); @@@@ -313,8 -308,8 -264,6 +269,6 @@@@ ret = 1; } -- restore_env(0); -- errno = saved_errno; return ret; @@@@ -534,13 -529,6 -483,6 +488,13 @@@@ int is_builtin(const char *s return !!get_builtin(s); } ++static void list_builtins(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(commands); i++) ++ printf("%s\n", commands[i].cmd); ++} ++ #ifdef STRIP_EXTENSION static void strip_extension(const char **argv) { diff --combined grep.c index d7ef21358e,d03d424e5c,d5211fc5a6..30d317a122 --- a/grep.c +++ b/grep.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "grep.h" #include "userdiff.h" #include "xdiff-interface.h" @@@@ -178,38 -178,23 -179,26 +179,38 @@@@ static void grep_set_pattern_type_optio case GREP_PATTERN_TYPE_BRE: opt->fixed = 0; - opt->pcre = 0; - opt->regflags &= ~REG_EXTENDED; + opt->pcre1 = 0; ++ opt->pcre2 = 0; break; case GREP_PATTERN_TYPE_ERE: opt->fixed = 0; - opt->pcre = 0; + opt->pcre1 = 0; ++ opt->pcre2 = 0; opt->regflags |= REG_EXTENDED; break; case GREP_PATTERN_TYPE_FIXED: opt->fixed = 1; - opt->pcre = 0; - opt->regflags &= ~REG_EXTENDED; + opt->pcre1 = 0; ++ opt->pcre2 = 0; break; case GREP_PATTERN_TYPE_PCRE: opt->fixed = 0; - opt->pcre = 1; - opt->regflags &= ~REG_EXTENDED; ++#ifdef USE_LIBPCRE2 ++ opt->pcre1 = 0; ++ opt->pcre2 = 1; ++#else ++ /* ++ * It's important that pcre1 always be assigned to ++ * even when there's no USE_LIBPCRE* defined. We still ++ * call the PCRE stub function, it just dies with ++ * "cannot use Perl-compatible regexes[...]". ++ */ + opt->pcre1 = 1; ++ opt->pcre2 = 0; ++#endif break; } } @@@@ -336,32 -321,32 -325,8 +337,32 @@@@ static NORETURN void compile_regexp_fai die("%s'%s': %s", where, p->pattern, error); } -#ifdef USE_LIBPCRE -static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt) +static int is_fixed(const char *s, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (is_regex_special(s[i])) + return 0; + } + + return 1; +} + +static int has_null(const char *s, size_t len) +{ + /* + * regcomp cannot accept patterns with NULs so when using it + * we consider any pattern containing a NUL fixed. + */ + if (memchr(s, 0, len)) + return 1; + + return 0; +} + +#ifdef USE_LIBPCRE1 +static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt) { const char *error; int erroffset; @@@@ -369,36 -354,23 -334,23 +370,36 @@@@ if (opt->ignore_case) { if (has_non_ascii(p->pattern)) - p->pcre_tables = pcre_maketables(); + p->pcre1_tables = pcre_maketables(); options |= PCRE_CASELESS; } if (is_utf8_locale() && has_non_ascii(p->pattern)) options |= PCRE_UTF8; - p->pcre_regexp = pcre_compile(p->pattern, options, &error, &erroffset, - p->pcre_tables); - if (!p->pcre_regexp) + p->pcre1_regexp = pcre_compile(p->pattern, options, &error, &erroffset, + p->pcre1_tables); + if (!p->pcre1_regexp) compile_regexp_failed(p, error); - p->pcre1_extra_info = pcre_study(p->pcre1_regexp, 0, &error); - p->pcre_extra_info = pcre_study(p->pcre_regexp, 0, &error); - if (!p->pcre_extra_info && error) ++ p->pcre1_extra_info = pcre_study(p->pcre1_regexp, PCRE_STUDY_JIT_COMPILE, &error); + if (!p->pcre1_extra_info && error) die("%s", error); ++ ++#ifdef GIT_PCRE1_USE_JIT ++ pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on); ++ if (p->pcre1_jit_on == 1) { ++ p->pcre1_jit_stack = pcre_jit_stack_alloc(1, 1024 * 1024); ++ if (!p->pcre1_jit_stack) ++ die("Couldn't allocate PCRE JIT stack"); ++ pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack); ++ } else if (p->pcre1_jit_on != 0) { ++ die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d", ++ p->pcre1_jit_on); ++ } ++#endif } -static int pcrematch(struct grep_pat *p, const char *line, const char *eol, +static int pcre1match(struct grep_pat *p, const char *line, const char *eol, regmatch_t *match, int eflags) { int ovector[30], ret, flags = 0; @@@@ -406,19 -378,8 -358,8 +407,19 @@@@ if (eflags & REG_NOTBOL) flags |= PCRE_NOTBOL; - ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line, eol - line, - ret = pcre_exec(p->pcre_regexp, p->pcre_extra_info, line, eol - line, -- 0, flags, ovector, ARRAY_SIZE(ovector)); ++#ifdef GIT_PCRE1_USE_JIT ++ if (p->pcre1_jit_on) { ++ ret = pcre_jit_exec(p->pcre1_regexp, p->pcre1_extra_info, line, ++ eol - line, 0, flags, ovector, ++ ARRAY_SIZE(ovector), p->pcre1_jit_stack); ++ } else ++#endif ++ { ++ ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line, ++ eol - line, 0, flags, ovector, ++ ARRAY_SIZE(ovector)); ++ } ++ if (ret < 0 && ret != PCRE_ERROR_NOMATCH) die("pcre_exec failed with error code %d", ret); if (ret > 0) { @@@@ -430,165 -391,36 -371,55 +431,165 @@@@ return ret; } -static void free_pcre_regexp(struct grep_pat *p) +static void free_pcre1_regexp(struct grep_pat *p) { - pcre_free(p->pcre_regexp); - pcre_free(p->pcre_extra_info); - pcre_free((void *)p->pcre_tables); + pcre_free(p->pcre1_regexp); - pcre_free(p->pcre1_extra_info); ++#ifdef GIT_PCRE1_USE_JIT ++ if (p->pcre1_jit_on) { ++ pcre_free_study(p->pcre1_extra_info); ++ pcre_jit_stack_free(p->pcre1_jit_stack); ++ } else ++#endif ++ { ++ pcre_free(p->pcre1_extra_info); ++ } + pcre_free((void *)p->pcre1_tables); } -#else /* !USE_LIBPCRE */ -static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt) +#else /* !USE_LIBPCRE1 */ +static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt) { die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE"); } -static int pcrematch(struct grep_pat *p, const char *line, const char *eol, +static int pcre1match(struct grep_pat *p, const char *line, const char *eol, regmatch_t *match, int eflags) { return 1; } -static void free_pcre_regexp(struct grep_pat *p) +static void free_pcre1_regexp(struct grep_pat *p) { } -#endif /* !USE_LIBPCRE */ +#endif /* !USE_LIBPCRE1 */ -static int is_fixed(const char *s, size_t len) ++#ifdef USE_LIBPCRE2 ++static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt) + { - size_t i; ++ int error; ++ PCRE2_UCHAR errbuf[256]; ++ PCRE2_SIZE erroffset; ++ int options = PCRE2_MULTILINE; ++ const uint8_t *character_tables = NULL; ++ int jitret; + - /* regcomp cannot accept patterns with NULs so we - * consider any pattern containing a NUL fixed. - */ - if (memchr(s, 0, len)) - return 1; ++ assert(opt->pcre2); + - for (i = 0; i < len; i++) { - if (is_regex_special(s[i])) - return 0; ++ p->pcre2_compile_context = NULL; ++ ++ if (opt->ignore_case) { ++ if (has_non_ascii(p->pattern)) { ++ character_tables = pcre2_maketables(NULL); ++ p->pcre2_compile_context = pcre2_compile_context_create(NULL); ++ pcre2_set_character_tables(p->pcre2_compile_context, character_tables); ++ } ++ options |= PCRE2_CASELESS; ++ } ++ if (is_utf8_locale() && has_non_ascii(p->pattern)) ++ options |= PCRE2_UTF; ++ ++ p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern, ++ p->patternlen, options, &error, &erroffset, ++ p->pcre2_compile_context); ++ ++ if (p->pcre2_pattern) { ++ p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, NULL); ++ if (!p->pcre2_match_data) ++ die("Couldn't allocate PCRE2 match data"); ++ } else { ++ pcre2_get_error_message(error, errbuf, sizeof(errbuf)); ++ compile_regexp_failed(p, (const char *)&errbuf); ++ } ++ ++ pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on); ++ if (p->pcre2_jit_on == 1) { ++ jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE); ++ if (jitret) ++ die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret); ++ p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL); ++ if (!p->pcre2_jit_stack) ++ die("Couldn't allocate PCRE2 JIT stack"); ++ p->pcre2_match_context = pcre2_match_context_create(NULL); ++ if (!p->pcre2_jit_stack) ++ die("Couldn't allocate PCRE2 match context"); ++ pcre2_jit_stack_assign(p->pcre2_match_context, NULL, p->pcre2_jit_stack); ++ } else if (p->pcre2_jit_on != 0) { ++ die("BUG: The pcre2_jit_on variable should be 0 or 1, not %d", ++ p->pcre1_jit_on); + } ++} ++ ++static int pcre2match(struct grep_pat *p, const char *line, const char *eol, ++ regmatch_t *match, int eflags) ++{ ++ int ret, flags = 0; ++ PCRE2_SIZE *ovector; ++ PCRE2_UCHAR errbuf[256]; ++ ++ if (eflags & REG_NOTBOL) ++ flags |= PCRE2_NOTBOL; + ++ if (p->pcre2_jit_on) ++ ret = pcre2_jit_match(p->pcre2_pattern, (unsigned char *)line, ++ eol - line, 0, flags, p->pcre2_match_data, ++ NULL); ++ else ++ ret = pcre2_match(p->pcre2_pattern, (unsigned char *)line, ++ eol - line, 0, flags, p->pcre2_match_data, ++ NULL); ++ ++ if (ret < 0 && ret != PCRE2_ERROR_NOMATCH) { ++ pcre2_get_error_message(ret, errbuf, sizeof(errbuf)); ++ die("%s failed with error code %d: %s", ++ (p->pcre2_jit_on ? "pcre2_jit_match" : "pcre2_match"), ret, ++ errbuf); ++ } ++ if (ret > 0) { ++ ovector = pcre2_get_ovector_pointer(p->pcre2_match_data); ++ ret = 0; ++ match->rm_so = (int)ovector[0]; ++ match->rm_eo = (int)ovector[1]; ++ } ++ ++ return ret; ++} ++ ++static void free_pcre2_pattern(struct grep_pat *p) ++{ ++ pcre2_compile_context_free(p->pcre2_compile_context); ++ pcre2_code_free(p->pcre2_pattern); ++ pcre2_match_data_free(p->pcre2_match_data); ++ pcre2_jit_stack_free(p->pcre2_jit_stack); ++ pcre2_match_context_free(p->pcre2_match_context); ++} ++#else /* !USE_LIBPCRE2 */ ++static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt) ++{ ++ /* ++ * Unreachable until USE_LIBPCRE2 becomes synonymous with ++ * USE_LIBPCRE. See the sibling comment in ++ * grep_set_pattern_type_option(). ++ */ ++ die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE"); ++} ++ ++static int pcre2match(struct grep_pat *p, const char *line, const char *eol, ++ regmatch_t *match, int eflags) ++{ + return 1; + } + ++static void free_pcre2_pattern(struct grep_pat *p) ++{ ++} ++#endif /* !USE_LIBPCRE2 */ ++ static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt) { struct strbuf sb = STRBUF_INIT; int err; - int regflags; + int regflags = opt->regflags; basic_regex_quote_buf(&sb, p->pattern); - regflags = opt->regflags & ~REG_EXTENDED; if (opt->ignore_case) regflags |= REG_ICASE; err = regcomp(&p->regexp, sb.buf, regflags); @@@@ -625,9 -457,9 -456,7 +626,9 @@@@ static void compile_regexp(struct grep_ * simple string match using kws. p->fixed tells us if we * want to use kws. */ - if (opt->fixed || is_fixed(p->pattern, p->patternlen)) + if (opt->fixed || + has_null(p->pattern, p->patternlen) || + is_fixed(p->pattern, p->patternlen)) p->fixed = !icase || ascii_only; else p->fixed = 0; @@@@ -647,13 -479,8 -476,8 +648,13 @@@@ return; } - if (opt->pcre) { - compile_pcre_regexp(p, opt); ++ if (opt->pcre2) { ++ compile_pcre2_pattern(p, opt); ++ return; ++ } ++ + if (opt->pcre1) { + compile_pcre1_regexp(p, opt); return; } @@@@ -1009,10 -836,8 -833,8 +1010,10 @@@@ void free_grep_patterns(struct grep_op case GREP_PATTERN_BODY: if (p->kws) kwsfree(p->kws); - else if (p->pcre_regexp) - free_pcre_regexp(p); + else if (p->pcre1_regexp) + free_pcre1_regexp(p); ++ else if (p->pcre2_pattern) ++ free_pcre2_pattern(p); else regfree(&p->regexp); free(p->pattern); @@@@ -1091,10 -916,8 -913,8 +1092,10 @@@@ static int patmatch(struct grep_pat *p if (p->fixed) hit = !fixmatch(p, line, eol, match); - else if (p->pcre_regexp) - hit = !pcrematch(p, line, eol, match, eflags); + else if (p->pcre1_regexp) + hit = !pcre1match(p, line, eol, match, eflags); ++ else if (p->pcre2_pattern) ++ hit = !pcre2match(p, line, eol, match, eflags); else hit = !regexec_buf(&p->regexp, line, eol - line, 1, match, eflags); @@@@ -1584,11 -1407,11 -1404,11 +1585,11 @@@@ static int fill_textconv_grep(struct us */ df = alloc_filespec(gs->path); switch (gs->type) { -- case GREP_SOURCE_SHA1: ++ case GREP_SOURCE_OID: fill_filespec(df, gs->identifier, 1, 0100644); break; case GREP_SOURCE_FILE: -- fill_filespec(df, null_sha1, 0, 0100644); ++ fill_filespec(df, &null_oid, 0, 0100644); break; default: die("BUG: attempt to textconv something without a path?"); @@@@ -1928,8 -1751,9 -1748,9 +1929,8 @@@@ void grep_source_init(struct grep_sourc * If the identifier is non-NULL (in the submodule case) it * will be a SHA1 that needs to be copied. */ -- case GREP_SOURCE_SHA1: -- gs->identifier = xmalloc(20); -- hashcpy(gs->identifier, identifier); ++ case GREP_SOURCE_OID: ++ gs->identifier = oiddup(identifier); break; case GREP_SOURCE_BUF: gs->identifier = NULL; @@@@ -1952,7 -1776,7 -1773,7 +1953,7 @@@@ void grep_source_clear_data(struct grep { switch (gs->type) { case GREP_SOURCE_FILE: -- case GREP_SOURCE_SHA1: ++ case GREP_SOURCE_OID: case GREP_SOURCE_SUBMODULE: free(gs->buf); gs->buf = NULL; @@@@ -1964,7 -1788,7 -1785,7 +1965,7 @@@@ } } --static int grep_source_load_sha1(struct grep_source *gs) ++static int grep_source_load_oid(struct grep_source *gs) { enum object_type type; @@@@ -1975,7 -1799,7 -1796,7 +1976,7 @@@@ if (!gs->buf) return error(_("'%s': unable to read %s"), gs->name, -- sha1_to_hex(gs->identifier)); ++ oid_to_hex(gs->identifier)); return 0; } @@@@ -2021,8 -1845,8 -1842,8 +2022,8 @@@@ static int grep_source_load(struct grep switch (gs->type) { case GREP_SOURCE_FILE: return grep_source_load_file(gs); -- case GREP_SOURCE_SHA1: -- return grep_source_load_sha1(gs); ++ case GREP_SOURCE_OID: ++ return grep_source_load_oid(gs); case GREP_SOURCE_BUF: return gs->buf ? 0 : -1; case GREP_SOURCE_SUBMODULE: diff --combined help.c index f637fc8006,db7f3d79a0,b8f3a98e4c..8ba0777410 --- a/help.c +++ b/help.c @@@@ -1,7 -1,7 -1,7 +1,8 @@@@ #include "cache.h" ++ #include "config.h" #include "builtin.h" #include "exec_cmd.h" +#include "run-command.h" #include "levenshtein.h" #include "help.h" #include "common-cmds.h" @@@@ -9,7 -9,6 -9,6 +10,7 @@@@ #include "column.h" #include "version.h" #include "refs.h" ++#include "parse-options.h" void add_cmdname(struct cmdnames *cmds, const char *name, int len) { @@@@ -98,6 -97,6 -97,48 +99,6 @@@@ static void pretty_print_cmdnames(struc string_list_clear(&list, 0); } -static int is_executable(const char *name) -{ - struct stat st; - - if (stat(name, &st) || /* stat, not lstat */ - !S_ISREG(st.st_mode)) - return 0; - -#if defined(GIT_WINDOWS_NATIVE) - /* - * On Windows there is no executable bit. The file extension - * indicates whether it can be run as an executable, and Git - * has special-handling to detect scripts and launch them - * through the indicated script interpreter. We test for the - * file extension first because virus scanners may make - * it quite expensive to open many files. - */ - if (ends_with(name, ".exe")) - return S_IXUSR; - -{ - /* - * Now that we know it does not have an executable extension, - * peek into the file instead. - */ - char buf[3] = { 0 }; - int n; - int fd = open(name, O_RDONLY); - st.st_mode &= ~S_IXUSR; - if (fd >= 0) { - n = read(fd, buf, 2); - if (n == 2) - /* look for a she-bang */ - if (!strcmp(buf, "#!")) - st.st_mode |= S_IXUSR; - close(fd); - } -} -#endif - return st.st_mode & S_IXUSR; -} - static void list_commands_in_dir(struct cmdnames *cmds, const char *path, const char *prefix) @@@@ -290,7 -289,7 -331,7 +291,7 @@@@ const char *help_unknown_cmd(const cha memset(&other_cmds, 0, sizeof(other_cmds)); memset(&aliases, 0, sizeof(aliases)); -- git_config(git_unknown_cmd_config, NULL); ++ read_early_config(git_unknown_cmd_config, NULL); load_command_list("git-", &main_cmds, &other_cmds); @@@@ -371,8 -370,8 -412,8 +372,8 @@@@ if (SIMILAR_ENOUGH(best_similarity)) { fprintf_ln(stderr, - Q_("\nDid you mean this?", - "\nDid you mean one of these?", + Q_("\nThe most similar command is", + "\nThe most similar commands are", n)); for (i = 0; i < n; i++) @@@@ -384,30 -383,16 -425,16 +385,30 @@@@ int cmd_version(int argc, const char **argv, const char *prefix) { ++ int build_options = 0; ++ const char * const usage[] = { ++ N_("git version []"), ++ NULL ++ }; ++ struct option options[] = { ++ OPT_BOOL(0, "build-options", &build_options, ++ "also print build options"), ++ OPT_END() ++ }; ++ ++ argc = parse_options(argc, argv, prefix, options, usage, 0); ++ /* * The format of this string should be kept stable for compatibility * with external projects that rely on the output of "git version". ++ * ++ * Always show the version, even if other options are given. */ printf("git version %s\n", git_version_string); -- while (*++argv) { -- if (!strcmp(*argv, "--build-options")) { -- printf("sizeof-long: %d\n", (int)sizeof(long)); -- /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ -- } ++ ++ if (build_options) { ++ printf("sizeof-long: %d\n", (int)sizeof(long)); ++ /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ } return 0; } diff --combined http-backend.c index ba5ff1aa29,ba5ff1aa29,109df44e31..519025d2c3 --- a/http-backend.c +++ b/http-backend.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "pkt-line.h" #include "object.h" @@@@ -90,7 -90,7 -91,7 +91,7 @@@@ static void hdr_int(struct strbuf *hdr strbuf_addf(hdr, "%s: %" PRIuMAX "\r\n", name, value); } -static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when) +static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when) { const char *value = show_date(when, 0, DATE_MODE(RFC2822)); hdr_str(hdr, name, value); @@@@ -105,7 -105,7 -106,7 +106,7 @@@@ static void hdr_nocache(struct strbuf * static void hdr_cache_forever(struct strbuf *hdr) { - unsigned long now = time(NULL); + timestamp_t now = time(NULL); hdr_date(hdr, "Date", now); hdr_date(hdr, "Expires", now + 31536000); hdr_str(hdr, "Cache-Control", "public, max-age=31536000"); @@@@ -431,7 -431,7 -432,7 +432,7 @@@@ static int show_text_ref(const char *na { const char *name_nons = strip_namespace(name); struct strbuf *buf = cb_data; - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); if (!o) return 0; diff --combined ident.c index 91c7609055,bea871c8e0,d41fc91192..327abe557f --- a/ident.c +++ b/ident.c @@@@ -6,6 -6,6 -6,7 +6,7 @@@@ * Copyright (C) 2005 Linus Torvalds */ #include "cache.h" ++ #include "config.h" static struct strbuf git_default_name = STRBUF_INIT; static struct strbuf git_default_email = STRBUF_INIT; @@@@ -72,10 -72,12 -73,12 +73,10 @@@@ static int add_mailname_host(struct str FILE *mailname; struct strbuf mailnamebuf = STRBUF_INIT; -- mailname = fopen("/etc/mailname", "r"); -- if (!mailname) { -- if (errno != ENOENT) -- warning_errno("cannot open /etc/mailname"); ++ mailname = fopen_or_warn("/etc/mailname", "r"); ++ if (!mailname) return -1; -- } ++ if (strbuf_getline(&mailnamebuf, mailname) == EOF) { if (ferror(mailname)) warning_errno("cannot read /etc/mailname"); diff --combined ll-merge.c index ac0d4a5d78,d7eafb61a6,24ff94e1dd..b9576efe97 --- a/ll-merge.c +++ b/ll-merge.c @@@@ -5,6 -5,6 -5,7 +5,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "attr.h" #include "xdiff-interface.h" #include "run-command.h" @@@@ -339,7 -339,7 -340,7 +340,7 @@@@ static const struct ll_merge_driver *fi static void normalize_file(mmfile_t *mm, const char *path) { struct strbuf strbuf = STRBUF_INIT; - - if (renormalize_buffer(path, mm->ptr, mm->size, &strbuf)) { + + if (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) { free(mm->ptr); mm->size = strbuf.len; mm->ptr = strbuf_detach(&strbuf, NULL); diff --combined log-tree.c index 2903874ecf,a4ec11c2bf,282510b105..410ab4f02d --- a/log-tree.c +++ b/log-tree.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "diff.h" #include "commit.h" #include "tag.h" @@@@ -105,13 -105,13 -106,13 +106,13 @@@@ static int add_ref_decoration(const cha warning("invalid replace ref %s", refname); return 0; } - obj = parse_object(original_oid.hash); + obj = parse_object(&original_oid); if (obj) add_name_decoration(DECORATION_GRAFTED, "replaced", obj); return 0; } - obj = parse_object(oid->hash); + obj = parse_object(oid); if (!obj) return 0; @@@@ -132,7 -132,7 -133,7 +133,7 @@@@ if (!obj) break; if (!obj->parsed) - parse_object(obj->oid.hash); + parse_object(&obj->oid); add_name_decoration(DECORATION_REF_TAG, refname, obj); } return 0; @@@@ -140,7 -140,7 -141,7 +141,7 @@@@ static int add_graft_decoration(const struct commit_graft *graft, void *cb_data) { - struct commit *commit = lookup_commit(graft->oid.hash); + struct commit *commit = lookup_commit(&graft->oid); if (!commit) return 0; add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object); @@@@ -184,7 -184,7 -185,7 +185,7 @@@@ static const struct name_decoration *cu { const struct name_decoration *list, *head = NULL; const char *branch_name = NULL; - unsigned char unused[20]; + struct object_id unused; int rru_flags; /* First find HEAD */ @@@@ -197,7 -197,7 -198,7 +198,7 @@@@ return NULL; /* Now resolve and find the matching current branch */ - branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags); + branch_name = resolve_ref_unsafe("HEAD", 0, unused.hash, &rru_flags); if (!(rru_flags & REF_ISSYMREF)) return NULL; @@@@ -456,13 -456,13 -457,13 +457,13 @@@@ static void show_signature(struct rev_i strbuf_release(&signature); } -static int which_parent(const unsigned char *sha1, const struct commit *commit) +static int which_parent(const struct object_id *oid, const struct commit *commit) { int nth; const struct commit_list *parent; for (nth = 0, parent = commit->parents; parent; parent = parent->next) { - if (!hashcmp(parent->item->object.oid.hash, sha1)) + if (!oidcmp(&parent->item->object.oid, oid)) return nth; nth++; } @@@@ -481,14 -481,14 -482,14 +482,14 @@@@ static void show_one_mergetag(struct co void *data) { struct rev_info *opt = (struct rev_info *)data; - unsigned char sha1[20]; + struct object_id oid; struct tag *tag; struct strbuf verify_message; int status, nth; size_t payload_size, gpg_message_offset; - hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1); - tag = lookup_tag(sha1); + hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), oid.hash); + tag = lookup_tag(&oid); if (!tag) return; /* error message already given */ @@@@ -500,7 -500,7 -501,7 +501,7 @@@@ &commit->parents->next->item->object.oid)) strbuf_addf(&verify_message, "merged tag '%s'\n", tag->tag); - else if ((nth = which_parent(tag->tagged->oid.hash, commit)) < 0) + else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0) strbuf_addf(&verify_message, "tag %s names a non-parent %s\n", tag->tag, tag->tagged->oid.hash); else @@@@ -536,7 -536,7 -537,7 +537,7 @@@@ void show_log(struct rev_info *opt struct strbuf msgbuf = STRBUF_INIT; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; - int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; + int abbrev_commit = opt->abbrev_commit ? opt->abbrev : GIT_SHA1_HEXSZ; const char *extra_headers = opt->extra_headers; struct pretty_print_context ctx = {0}; @@@@ -655,7 -655,7 -656,7 +656,7 @@@@ struct strbuf notebuf = STRBUF_INIT; raw = (opt->commit_format == CMIT_FMT_USERFORMAT); -- format_display_notes(commit->object.oid.hash, ¬ebuf, ++ format_display_notes(&commit->object.oid, ¬ebuf, get_log_output_encoding(), raw); ctx.notes_message = notebuf.len ? strbuf_detach(¬ebuf, NULL) @@@@ -803,7 -803,7 -804,7 +804,7 @@@@ static int log_tree_diff(struct rev_inf parents = get_saved_parents(opt, commit); if (!parents) { if (opt->show_root_diff) { -- diff_root_tree_sha1(oid->hash, "", &opt->diffopt); ++ diff_root_tree_oid(oid, "", &opt->diffopt); log_tree_diff_flush(opt); } return !opt->loginfo; @@@@ -822,8 -822,8 -823,8 +823,8 @@@@ * we merged _in_. */ parse_commit_or_die(parents->item); -- diff_tree_sha1(parents->item->tree->object.oid.hash, -- oid->hash, "", &opt->diffopt); ++ diff_tree_oid(&parents->item->tree->object.oid, ++ oid, "", &opt->diffopt); log_tree_diff_flush(opt); return !opt->loginfo; } @@@@ -837,8 -837,8 -838,8 +838,8 @@@@ struct commit *parent = parents->item; parse_commit_or_die(parent); -- diff_tree_sha1(parent->tree->object.oid.hash, -- oid->hash, "", &opt->diffopt); ++ diff_tree_oid(&parent->tree->object.oid, ++ oid, "", &opt->diffopt); log_tree_diff_flush(opt); showed_log |= !opt->loginfo; diff --combined mailinfo.c index f92cb9f729,f92cb9f729,aaed3870a4..f59162453e --- a/mailinfo.c +++ b/mailinfo.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "utf8.h" #include "strbuf.h" #include "mailinfo.h" @@@@ -882,10 -882,10 -883,7 +883,10 @@@@ static int read_one_header_line(struct for (;;) { int peek; - peek = fgetc(in); ungetc(peek, in); + peek = fgetc(in); + if (peek == EOF) + break; + ungetc(peek, in); if (peek != ' ' && peek != '\t') break; if (strbuf_getline_lf(&continuation, in)) @@@@ -1102,10 -1102,10 -1100,6 +1103,10 @@@@ int mailinfo(struct mailinfo *mi, cons do { peek = fgetc(mi->input); + if (peek == EOF) { + fclose(cmitmsg); + return error("empty patch: '%s'", patch); + } } while (isspace(peek)); ungetc(peek, mi->input); diff --combined merge-recursive.c index 5cc86df2d1,eac12d4888,a85144c23a..59e5ee41a8 --- a/merge-recursive.c +++ b/merge-recursive.c @@@@ -4,6 -4,6 -4,7 +4,7 @@@@ * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006 */ #include "cache.h" ++ #include "config.h" #include "advice.h" #include "lockfile.h" #include "cache-tree.h" @@@@ -67,7 -67,7 -68,7 +68,7 @@@@ static struct tree *shift_tree_object(s } if (!oidcmp(&two->object.oid, &shifted)) return two; - return lookup_tree(shifted.hash); + return lookup_tree(&shifted); } static struct commit *make_virtual_commit(struct tree *tree, const char *comment) @@@@ -304,7 -304,7 -305,7 +305,7 @@@@ struct tree *write_tree_from_memory(str return NULL; } - result = lookup_tree(active_cache_tree->sha1); + result = lookup_tree(&active_cache_tree->oid); return result; } @@@@ -528,7 -528,7 -529,7 +529,7 @@@@ static struct string_list *get_renames( opts.show_rename_progress = o->show_rename_progress; opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_setup_done(&opts); -- diff_tree_sha1(o_tree->object.oid.hash, tree->object.oid.hash, "", &opts); ++ diff_tree_oid(&o_tree->object.oid, &tree->object.oid, "", &opts); diffcore_std(&opts); if (opts.needed_rename_limit > o->needed_rename_limit) o->needed_rename_limit = opts.needed_rename_limit; @@@@ -994,11 -994,11 -995,11 +995,11 @@@@ static int merge_file_1(struct merge_op return ret; result->clean = (merge_status == 0); } else if (S_ISGITLINK(a->mode)) { - result->clean = merge_submodule(result->oid.hash, + result->clean = merge_submodule(&result->oid, one->path, - one->oid.hash, - a->oid.hash, - b->oid.hash, + &one->oid, + &a->oid, + &b->oid, !o->call_depth); } else if (S_ISLNK(a->mode)) { oidcpy(&result->oid, &a->oid); @@@@ -1639,8 -1639,8 -1640,8 +1640,8 @@@@ static int blob_unchanged(struct merge_ * performed. Comparison can be skipped if both files are * unchanged since their sha1s have already been compared. */ - - if (renormalize_buffer(path, o.buf, o.len, &o) | - - renormalize_buffer(path, a.buf, a.len, &a)) + + if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) | + + renormalize_buffer(&the_index, path, a.buf, a.len, &a)) ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len)); error_return: @@@@ -2042,7 -2042,7 -2043,7 +2043,7 @@@@ int merge_recursive(struct merge_option /* if there is no common ancestor, use an empty tree */ struct tree *tree; - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } @@@@ -2103,7 -2103,7 -2104,7 +2104,7 @@@@ static struct commit *get_ref(const str { struct object *object; - object = deref_tag(parse_object(oid->hash), name, strlen(name)); + object = deref_tag(parse_object(oid), name, strlen(name)); if (!object) return NULL; if (object->type == OBJ_TREE) diff --combined notes-utils.c index 9ebf841956,031503d7b2,9d7fdd6354..9765deb41a --- a/notes-utils.c +++ b/notes-utils.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "refs.h" #include "notes-utils.h" @@@@ -7,18 -7,18 -8,18 +8,18 @@@@ void create_notes_commit(struct notes_t const char *msg, size_t msg_len, unsigned char *result_sha1) { - unsigned char tree_sha1[20]; + struct object_id tree_oid; assert(t->initialized); - if (write_notes_tree(t, tree_sha1)) + if (write_notes_tree(t, tree_oid.hash)) die("Failed to write notes tree to database"); if (!parents) { /* Deduce parent commit from t->ref */ - unsigned char parent_sha1[20]; - if (!read_ref(t->ref, parent_sha1)) { - struct commit *parent = lookup_commit(parent_sha1); + struct object_id parent_oid; + if (!read_ref(t->ref, parent_oid.hash)) { + struct commit *parent = lookup_commit(&parent_oid); if (parse_commit(parent)) die("Failed to find/parse commit %s", t->ref); commit_list_insert(parent, &parents); @@@@ -26,14 -26,14 -27,14 +27,14 @@@@ /* else: t->ref points to nothing, assume root/orphan commit */ } - if (commit_tree(msg, msg_len, tree_sha1, parents, result_sha1, NULL, NULL)) + if (commit_tree(msg, msg_len, tree_oid.hash, parents, result_sha1, NULL, NULL)) die("Failed to commit notes tree to database"); } void commit_notes(struct notes_tree *t, const char *msg) { struct strbuf buf = STRBUF_INIT; - unsigned char commit_sha1[20]; + struct object_id commit_oid; if (!t) t = &default_notes_tree; @@@@ -46,9 -46,9 -47,9 +47,9 @@@@ strbuf_addstr(&buf, msg); strbuf_complete_line(&buf); - create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1); + create_notes_commit(t, NULL, buf.buf, buf.len, commit_oid.hash); strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ - update_ref(buf.buf, t->update_ref, commit_sha1, NULL, 0, + update_ref(buf.buf, t->update_ref, commit_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); strbuf_release(&buf); @@@@ -132,11 -132,11 -133,8 +133,11 @@@@ struct notes_rewrite_cfg *init_copy_not c->mode_from_env = 1; c->combine = parse_combine_notes_fn(rewrite_mode_env); if (!c->combine) - /* TRANSLATORS: The first %s is the name of the - environment variable, the second %s is its value */ + /* + * TRANSLATORS: The first %s is the name of + * the environment variable, the second %s is + * its value. + */ error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT, rewrite_mode_env); } @@@@ -158,7 -158,7 -156,7 +159,7 @@@@ } int copy_note_for_rewrite(struct notes_rewrite_cfg *c, -- const unsigned char *from_obj, const unsigned char *to_obj) ++ const struct object_id *from_obj, const struct object_id *to_obj) { int ret = 0; int i; diff --combined notes.c index 4b3a1adda5,542563b280,dbcfef4d7a..8f47c202c5 --- a/notes.c +++ b/notes.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "notes.h" #include "blob.h" #include "tree.h" @@@@ -35,8 -35,8 -36,8 +36,8 @@@@ struct int_node * subtree. */ struct leaf_node { -- unsigned char key_sha1[20]; -- unsigned char val_sha1[20]; ++ struct object_id key_oid; ++ struct object_id val_oid; }; /* @@@@ -51,7 -51,7 -52,7 +52,7 @@@@ struct non_note struct non_note *next; /* grounded (last->next == NULL) */ char *path; unsigned int mode; -- unsigned char sha1[20]; ++ struct object_id oid; }; #define PTR_TYPE_NULL 0 @@@@ -65,10 -65,8 -66,8 +66,10 @@@@ #define GET_NIBBLE(n, sha1) (((sha1[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f) ++#define KEY_INDEX (GIT_SHA1_RAWSZ - 1) ++#define FANOUT_PATH_SEPARATORS ((GIT_SHA1_HEXSZ / 2) - 1) #define SUBTREE_SHA1_PREFIXCMP(key_sha1, subtree_sha1) \ -- (memcmp(key_sha1, subtree_sha1, subtree_sha1[19])) ++ (memcmp(key_sha1, subtree_sha1, subtree_sha1[KEY_INDEX])) struct notes_tree default_notes_tree; @@@@ -102,7 -100,7 -101,7 +103,7 @@@@ static void **note_tree_search(struct n if (GET_PTR_TYPE(p) == PTR_TYPE_SUBTREE) { l = (struct leaf_node *) CLR_PTR_TYPE(p); -- if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) { ++ if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_oid.hash)) { /* unpack tree and resume search */ (*tree)->a[0] = NULL; load_subtree(t, l, *tree, *n); @@@@ -120,7 -118,7 -119,7 +121,7 @@@@ return note_tree_search(t, tree, n, key_sha1); case PTR_TYPE_SUBTREE: l = (struct leaf_node *) CLR_PTR_TYPE(p); -- if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) { ++ if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_oid.hash)) { /* unpack tree and resume search */ (*tree)->a[i] = NULL; load_subtree(t, l, *tree, *n); @@@@ -145,7 -143,7 -144,7 +146,7 @@@@ static struct leaf_node *note_tree_find void **p = note_tree_search(t, &tree, &n, key_sha1); if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) { struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p); -- if (!hashcmp(key_sha1, l->key_sha1)) ++ if (!hashcmp(key_sha1, l->key_oid.hash)) return l; } return NULL; @@@@ -196,19 -194,19 -195,19 +197,19 @@@@ static void note_tree_remove(struct not struct leaf_node *entry) { struct leaf_node *l; -- struct int_node *parent_stack[20]; ++ struct int_node *parent_stack[GIT_SHA1_RAWSZ]; unsigned char i, j; -- void **p = note_tree_search(t, &tree, &n, entry->key_sha1); ++ void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash); assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */ if (GET_PTR_TYPE(*p) != PTR_TYPE_NOTE) return; /* type mismatch, nothing to remove */ l = (struct leaf_node *) CLR_PTR_TYPE(*p); -- if (hashcmp(l->key_sha1, entry->key_sha1)) ++ if (oidcmp(&l->key_oid, &entry->key_oid)) return; /* key mismatch, nothing to remove */ /* we have found a matching entry */ -- hashcpy(entry->val_sha1, l->val_sha1); ++ oidcpy(&entry->val_oid, &l->val_oid); free(l); *p = SET_PTR_TYPE(NULL, PTR_TYPE_NULL); @@@@ -218,14 -216,14 -217,14 +219,14 @@@@ /* first, build stack of ancestors between root and current node */ parent_stack[0] = t->root; for (i = 0; i < n; i++) { -- j = GET_NIBBLE(i, entry->key_sha1); ++ j = GET_NIBBLE(i, entry->key_oid.hash); parent_stack[i + 1] = CLR_PTR_TYPE(parent_stack[i]->a[j]); } assert(i == n && parent_stack[i] == tree); /* next, unwind stack until note_tree_consolidate() is done */ while (i > 0 && !note_tree_consolidate(parent_stack[i], parent_stack[i - 1], -- GET_NIBBLE(i - 1, entry->key_sha1))) ++ GET_NIBBLE(i - 1, entry->key_oid.hash))) i--; } @@@@ -248,7 -246,7 -247,7 +249,7 @@@@ static int note_tree_insert(struct note { struct int_node *new_node; struct leaf_node *l; -- void **p = note_tree_search(t, &tree, &n, entry->key_sha1); ++ void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash); int ret = 0; assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */ @@@@ -256,7 -254,7 -255,7 +257,7 @@@@ switch (GET_PTR_TYPE(*p)) { case PTR_TYPE_NULL: assert(!*p); -- if (is_null_sha1(entry->val_sha1)) ++ if (is_null_oid(&entry->val_oid)) free(entry); else *p = SET_PTR_TYPE(entry, type); @@@@ -264,22 -262,22 -263,22 +265,22 @@@@ case PTR_TYPE_NOTE: switch (type) { case PTR_TYPE_NOTE: -- if (!hashcmp(l->key_sha1, entry->key_sha1)) { ++ if (!oidcmp(&l->key_oid, &entry->key_oid)) { /* skip concatenation if l == entry */ -- if (!hashcmp(l->val_sha1, entry->val_sha1)) ++ if (!oidcmp(&l->val_oid, &entry->val_oid)) return 0; -- ret = combine_notes(l->val_sha1, -- entry->val_sha1); -- if (!ret && is_null_sha1(l->val_sha1)) ++ ret = combine_notes(l->val_oid.hash, ++ entry->val_oid.hash); ++ if (!ret && is_null_oid(&l->val_oid)) note_tree_remove(t, tree, n, entry); free(entry); return ret; } break; case PTR_TYPE_SUBTREE: -- if (!SUBTREE_SHA1_PREFIXCMP(l->key_sha1, -- entry->key_sha1)) { ++ if (!SUBTREE_SHA1_PREFIXCMP(l->key_oid.hash, ++ entry->key_oid.hash)) { /* unpack 'entry' */ load_subtree(t, entry, tree, n); free(entry); @@@@ -289,7 -287,7 -288,7 +290,7 @@@@ } break; case PTR_TYPE_SUBTREE: -- if (!SUBTREE_SHA1_PREFIXCMP(entry->key_sha1, l->key_sha1)) { ++ if (!SUBTREE_SHA1_PREFIXCMP(entry->key_oid.hash, l->key_oid.hash)) { /* unpack 'l' and restart insert */ *p = NULL; load_subtree(t, l, tree, n); @@@@ -303,7 -301,7 -302,7 +304,7 @@@@ /* non-matching leaf_node */ assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE || GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE); -- if (is_null_sha1(entry->val_sha1)) { /* skip insertion of empty note */ ++ if (is_null_oid(&entry->val_oid)) { /* skip insertion of empty note */ free(entry); return 0; } @@@@ -343,21 -341,21 -342,21 +344,21 @@@@ static void note_tree_free(struct int_n * Otherwise, returns number of bytes written to sha1 (i.e. hex_len / 2). * Pads sha1 with NULs up to sha1_len (not included in returned length). */ --static int get_sha1_hex_segment(const char *hex, unsigned int hex_len, -- unsigned char *sha1, unsigned int sha1_len) ++static int get_oid_hex_segment(const char *hex, unsigned int hex_len, ++ unsigned char *oid, unsigned int oid_len) { unsigned int i, len = hex_len >> 1; -- if (hex_len % 2 != 0 || len > sha1_len) ++ if (hex_len % 2 != 0 || len > oid_len) return -1; for (i = 0; i < len; i++) { unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]); if (val & ~0xff) return -1; -- *sha1++ = val; ++ *oid++ = val; hex += 2; } -- for (; i < sha1_len; i++) -- *sha1++ = 0; ++ for (; i < oid_len; i++) ++ *oid++ = 0; return len; } @@@@ -375,7 -373,7 -374,7 +376,7 @@@@ static void add_non_note(struct notes_t n->next = NULL; n->path = path; n->mode = mode; -- hashcpy(n->sha1, sha1); ++ hashcpy(n->oid.hash, sha1); t->prev_non_note = n; if (!t->first_non_note) { @@@@ -401,7 -399,7 -400,7 +402,7 @@@@ if (non_note_cmp(p, n) == 0) { /* n ~= p; overwrite p with n */ assert(strcmp(p->path, n->path) == 0); p->mode = n->mode; -- hashcpy(p->sha1, n->sha1); ++ oidcpy(&p->oid, &n->oid); free(n); t->prev_non_note = p; return; @@@@ -415,7 -413,7 -414,7 +416,7 @@@@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree, struct int_node *node, unsigned int n) { -- unsigned char object_sha1[20]; ++ struct object_id object_oid; unsigned int prefix_len; void *buf; struct tree_desc desc; @@@@ -424,18 -422,18 -423,18 +425,18 @@@@ unsigned char type; struct leaf_node *l; -- buf = fill_tree_descriptor(&desc, subtree->val_sha1); ++ buf = fill_tree_descriptor(&desc, subtree->val_oid.hash); if (!buf) die("Could not read %s for notes-index", -- sha1_to_hex(subtree->val_sha1)); ++ oid_to_hex(&subtree->val_oid)); -- prefix_len = subtree->key_sha1[19]; ++ prefix_len = subtree->key_oid.hash[KEY_INDEX]; assert(prefix_len * 2 >= n); -- memcpy(object_sha1, subtree->key_sha1, prefix_len); ++ memcpy(object_oid.hash, subtree->key_oid.hash, prefix_len); while (tree_entry(&desc, &entry)) { path_len = strlen(entry.path); -- len = get_sha1_hex_segment(entry.path, path_len, -- object_sha1 + prefix_len, 20 - prefix_len); ++ len = get_oid_hex_segment(entry.path, path_len, ++ object_oid.hash + prefix_len, GIT_SHA1_RAWSZ - prefix_len); if (len < 0) goto handle_non_note; /* entry.path is not a SHA1 */ len += prefix_len; @@@@ -445,16 -443,16 -444,16 +446,16 @@@@ * If object SHA1 is incomplete (len < 20), and current * component consists of 2 hex chars, assume note subtree */ -- if (len <= 20) { ++ if (len <= GIT_SHA1_RAWSZ) { type = PTR_TYPE_NOTE; l = (struct leaf_node *) xcalloc(1, sizeof(struct leaf_node)); -- hashcpy(l->key_sha1, object_sha1); -- hashcpy(l->val_sha1, entry.oid->hash); -- if (len < 20) { ++ oidcpy(&l->key_oid, &object_oid); ++ oidcpy(&l->val_oid, entry.oid); ++ if (len < GIT_SHA1_RAWSZ) { if (!S_ISDIR(entry.mode) || path_len != 2) goto handle_non_note; /* not subtree */ -- l->key_sha1[19] = (unsigned char) len; ++ l->key_oid.hash[KEY_INDEX] = (unsigned char) len; type = PTR_TYPE_SUBTREE; } if (note_tree_insert(t, node, n, l, type, @@@@ -462,7 -460,7 -461,7 +463,7 @@@@ die("Failed to load %s %s into notes tree " "from %s", type == PTR_TYPE_NOTE ? "note" : "subtree", -- sha1_to_hex(l->key_sha1), t->ref); ++ oid_to_hex(&l->key_oid), t->ref); } continue; @@@@ -488,7 -486,7 -487,7 +489,7 @@@@ handle_non_note */ { struct strbuf non_note_path = STRBUF_INIT; -- const char *q = sha1_to_hex(subtree->key_sha1); ++ const char *q = oid_to_hex(&subtree->key_oid); int i; for (i = 0; i < prefix_len; i++) { strbuf_addch(&non_note_path, *q++); @@@@ -544,14 -542,14 -543,14 +545,14 @@@@ static unsigned char determine_fanout(s } /* hex SHA1 + 19 * '/' + NUL */ --#define FANOUT_PATH_MAX 40 + 19 + 1 ++#define FANOUT_PATH_MAX GIT_SHA1_HEXSZ + FANOUT_PATH_SEPARATORS + 1 static void construct_path_with_fanout(const unsigned char *sha1, unsigned char fanout, char *path) { unsigned int i = 0, j = 0; const char *hex_sha1 = sha1_to_hex(sha1); -- assert(fanout < 20); ++ assert(fanout < GIT_SHA1_RAWSZ); while (fanout) { path[i++] = hex_sha1[j++]; path[i++] = hex_sha1[j++]; @@@@ -601,17 -599,15 -600,15 +602,17 @@@@ redo flags & FOR_EACH_NOTE_YIELD_SUBTREES) { /* invoke callback with subtree */ unsigned int path_len = -- l->key_sha1[19] * 2 + fanout; ++ l->key_oid.hash[KEY_INDEX] * 2 + fanout; assert(path_len < FANOUT_PATH_MAX - 1); -- construct_path_with_fanout(l->key_sha1, fanout, ++ construct_path_with_fanout(l->key_oid.hash, ++ fanout, path); /* Create trailing slash, if needed */ if (path[path_len - 1] != '/') path[path_len++] = '/'; path[path_len] = '\0'; -- ret = fn(l->key_sha1, l->val_sha1, path, ++ ret = fn(&l->key_oid, &l->val_oid, ++ path, cb_data); } if (n > fanout * 2 || @@@@ -625,10 -621,8 -622,8 +626,10 @@@@ break; case PTR_TYPE_NOTE: l = (struct leaf_node *) CLR_PTR_TYPE(p); -- construct_path_with_fanout(l->key_sha1, fanout, path); -- ret = fn(l->key_sha1, l->val_sha1, path, cb_data); ++ construct_path_with_fanout(l->key_oid.hash, fanout, ++ path); ++ ret = fn(&l->key_oid, &l->val_oid, path, ++ cb_data); break; } if (ret) @@@@ -656,7 -650,7 -651,7 +657,7 @@@@ static void write_tree_entry(struct str unsigned char *sha1) { strbuf_addf(buf, "%o %.*s%c", mode, path_len, path, '\0'); -- strbuf_add(buf, sha1, 20); ++ strbuf_add(buf, sha1, GIT_SHA1_RAWSZ); } static void tree_write_stack_init_subtree(struct tree_write_stack *tws, @@@@ -668,7 -662,7 -663,7 +669,7 @@@@ n = (struct tree_write_stack *) xmalloc(sizeof(struct tree_write_stack)); n->next = NULL; -- strbuf_init(&n->buf, 256 * (32 + 40)); /* assume 256 entries per tree */ ++ strbuf_init(&n->buf, 256 * (32 + GIT_SHA1_HEXSZ)); /* assume 256 entries per tree */ n->path[0] = n->path[1] = '\0'; tws->next = n; tws->path[0] = path[0]; @@@@ -679,18 -673,18 -674,18 +680,18 @@@@ static int tree_write_stack_finish_subt { int ret; struct tree_write_stack *n = tws->next; -- unsigned char s[20]; ++ struct object_id s; if (n) { ret = tree_write_stack_finish_subtree(n); if (ret) return ret; -- ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s); ++ ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s.hash); if (ret) return ret; strbuf_release(&n->buf); free(n); tws->next = NULL; -- write_tree_entry(&tws->buf, 040000, tws->path, 2, s); ++ write_tree_entry(&tws->buf, 040000, tws->path, 2, s.hash); tws->path[0] = tws->path[1] = '\0'; } return 0; @@@@ -698,7 -692,7 -693,7 +699,7 @@@@ static int write_each_note_helper(struct tree_write_stack *tws, const char *path, unsigned int mode, -- const unsigned char *sha1) ++ const struct object_id *oid) { size_t path_len = strlen(path); unsigned int n = 0; @@@@ -728,7 -722,7 -723,7 +729,7 @@@@ /* Finally add given entry to the current tree object */ write_tree_entry(&tws->buf, mode, path + 3 * n, path_len - (3 * n), -- sha1); ++ oid->hash); return 0; } @@@@ -748,7 -742,7 -743,7 +749,7 @@@@ static int write_each_non_note_until(co ; /* do nothing, prefer note to non-note */ else { ret = write_each_note_helper(d->root, n->path, n->mode, -- n->sha1); ++ &n->oid); if (ret) return ret; } @@@@ -758,8 -752,8 -753,8 +759,8 @@@@ return 0; } --static int write_each_note(const unsigned char *object_sha1, -- const unsigned char *note_sha1, char *note_path, ++static int write_each_note(const struct object_id *object_oid, ++ const struct object_id *note_oid, char *note_path, void *cb_data) { struct write_each_note_data *d = @@@@ -773,11 -767,11 -768,11 +774,11 @@@@ note_path[note_path_len] = '\0'; mode = 040000; } -- assert(note_path_len <= 40 + 19); ++ assert(note_path_len <= GIT_SHA1_HEXSZ + FANOUT_PATH_SEPARATORS); /* Weave non-note entries into note entries */ return write_each_non_note_until(note_path, d) || -- write_each_note_helper(d->root, note_path, mode, note_sha1); ++ write_each_note_helper(d->root, note_path, mode, note_oid); } struct note_delete_list { @@@@ -785,20 -779,20 -780,20 +786,20 @@@@ const unsigned char *sha1; }; --static int prune_notes_helper(const unsigned char *object_sha1, -- const unsigned char *note_sha1, char *note_path, ++static int prune_notes_helper(const struct object_id *object_oid, ++ const struct object_id *note_oid, char *note_path, void *cb_data) { struct note_delete_list **l = (struct note_delete_list **) cb_data; struct note_delete_list *n; -- if (has_sha1_file(object_sha1)) ++ if (has_object_file(object_oid)) return 0; /* nothing to do for this note */ /* failed to find object => prune this note */ n = (struct note_delete_list *) xmalloc(sizeof(*n)); n->next = *l; -- n->sha1 = object_sha1; ++ n->sha1 = object_oid->hash; *l = n; return 0; } @@@@ -948,8 -942,8 -943,8 +949,8 @@@@ void string_list_add_refs_by_glob(struc if (has_glob_specials(glob)) { for_each_glob_ref(string_list_add_one_ref, glob, list); } else { -- unsigned char sha1[20]; -- if (get_sha1(glob, sha1)) ++ struct object_id oid; ++ if (get_oid(glob, &oid)) warning("notes ref %s is invalid", glob); if (!unsorted_string_list_has_string(list, glob)) string_list_append(list, glob); @@@@ -1033,8 -1027,8 -1028,8 +1034,8 @@@@ void init_notes(struct notes_tree *t, c die("Failed to read notes tree referenced by %s (%s)", notes_ref, oid_to_hex(&object_oid)); -- hashclr(root_tree.key_sha1); -- hashcpy(root_tree.val_sha1, oid.hash); ++ oidclr(&root_tree.key_oid); ++ oidcpy(&root_tree.val_oid, &oid); load_subtree(t, &root_tree, t->root, 0); } @@@@ -1086,8 -1080,8 -1081,8 +1087,8 @@@@ void init_display_notes(struct display_ string_list_clear(&display_notes_refs, 0); } --int add_note(struct notes_tree *t, const unsigned char *object_sha1, -- const unsigned char *note_sha1, combine_notes_fn combine_notes) ++int add_note(struct notes_tree *t, const struct object_id *object_oid, ++ const struct object_id *note_oid, combine_notes_fn combine_notes) { struct leaf_node *l; @@@@ -1098,8 -1092,8 -1093,8 +1099,8 @@@@ if (!combine_notes) combine_notes = t->combine_notes; l = (struct leaf_node *) xmalloc(sizeof(struct leaf_node)); -- hashcpy(l->key_sha1, object_sha1); -- hashcpy(l->val_sha1, note_sha1); ++ oidcpy(&l->key_oid, object_oid); ++ oidcpy(&l->val_oid, note_oid); return note_tree_insert(t, t->root, 0, l, PTR_TYPE_NOTE, combine_notes); } @@@@ -1110,25 -1104,25 -1105,25 +1111,25 @@@@ int remove_note(struct notes_tree *t, c if (!t) t = &default_notes_tree; assert(t->initialized); -- hashcpy(l.key_sha1, object_sha1); -- hashclr(l.val_sha1); ++ hashcpy(l.key_oid.hash, object_sha1); ++ oidclr(&l.val_oid); note_tree_remove(t, t->root, 0, &l); -- if (is_null_sha1(l.val_sha1)) /* no note was removed */ ++ if (is_null_oid(&l.val_oid)) /* no note was removed */ return 1; t->dirty = 1; return 0; } --const unsigned char *get_note(struct notes_tree *t, -- const unsigned char *object_sha1) ++const struct object_id *get_note(struct notes_tree *t, ++ const struct object_id *oid) { struct leaf_node *found; if (!t) t = &default_notes_tree; assert(t->initialized); -- found = note_tree_find(t, t->root, 0, object_sha1); -- return found ? found->val_sha1 : NULL; ++ found = note_tree_find(t, t->root, 0, oid->hash); ++ return found ? &found->val_oid : NULL; } int for_each_note(struct notes_tree *t, int flags, each_note_fn fn, @@@@ -1152,7 -1146,7 -1147,7 +1153,7 @@@@ int write_notes_tree(struct notes_tree /* Prepare for traversal of current notes tree */ root.next = NULL; /* last forward entry in list is grounded */ -- strbuf_init(&root.buf, 256 * (32 + 40)); /* assume 256 entries */ ++ strbuf_init(&root.buf, 256 * (32 + GIT_SHA1_HEXSZ)); /* assume 256 entries */ root.path[0] = root.path[1] = '\0'; cb_data.root = &root; cb_data.next_non_note = t->first_non_note; @@@@ -1215,11 -1209,11 -1210,11 +1216,11 @@@@ void free_notes(struct notes_tree *t * (raw != 0) gives the %N userformat; otherwise, the note message is given * for human consumption. */ --static void format_note(struct notes_tree *t, const unsigned char *object_sha1, ++static void format_note(struct notes_tree *t, const struct object_id *object_oid, struct strbuf *sb, const char *output_encoding, int raw) { static const char utf8[] = "utf-8"; -- const unsigned char *sha1; ++ const struct object_id *oid; char *msg, *msg_p; unsigned long linelen, msglen; enum object_type type; @@@@ -1229,11 -1223,11 -1224,11 +1230,11 @@@@ if (!t->initialized) init_notes(t, NULL, NULL, 0); -- sha1 = get_note(t, object_sha1); -- if (!sha1) ++ oid = get_note(t, object_oid); ++ if (!oid) return; -- if (!(msg = read_sha1_file(sha1, &type, &msglen)) || type != OBJ_BLOB) { ++ if (!(msg = read_sha1_file(oid->hash, &type, &msglen)) || type != OBJ_BLOB) { free(msg); return; } @@@@ -1277,22 -1271,22 -1272,22 +1278,22 @@@@ free(msg); } --void format_display_notes(const unsigned char *object_sha1, ++void format_display_notes(const struct object_id *object_oid, struct strbuf *sb, const char *output_encoding, int raw) { int i; assert(display_notes_trees); for (i = 0; display_notes_trees[i]; i++) -- format_note(display_notes_trees[i], object_sha1, sb, ++ format_note(display_notes_trees[i], object_oid, sb, output_encoding, raw); } int copy_note(struct notes_tree *t, -- const unsigned char *from_obj, const unsigned char *to_obj, ++ const struct object_id *from_obj, const struct object_id *to_obj, int force, combine_notes_fn combine_notes) { -- const unsigned char *note = get_note(t, from_obj); -- const unsigned char *existing_note = get_note(t, to_obj); ++ const struct object_id *note = get_note(t, from_obj); ++ const struct object_id *existing_note = get_note(t, to_obj); if (!force && existing_note) return 1; @@@@ -1300,7 -1294,7 -1295,7 +1301,7 @@@@ if (note) return add_note(t, to_obj, note, combine_notes); else if (existing_note) -- return add_note(t, to_obj, null_sha1, combine_notes); ++ return add_note(t, to_obj, &null_oid, combine_notes); return 0; } @@@@ -1317,9 -1311,9 -1312,9 +1318,9 @@@@ void expand_notes_ref(struct strbuf *sb void expand_loose_notes_ref(struct strbuf *sb) { -- unsigned char object[20]; ++ struct object_id object; -- if (get_sha1(sb->buf, object)) { ++ if (get_oid(sb->buf, &object)) { /* fallback to expand_notes_ref */ expand_notes_ref(sb); } diff --combined parse-options.c index e5ad34a2c3,e5ad34a2c3,cbf84a6048..0dd9fc6a0d --- a/parse-options.c +++ b/parse-options.c @@@@ -1,6 -1,6 -1,7 +1,7 @@@@ #include "git-compat-util.h" #include "parse-options.h" #include "cache.h" ++ #include "config.h" #include "commit.h" #include "color.h" #include "utf8.h" @@@@ -589,10 -589,10 -590,8 +590,10 @@@@ static int usage_with_options_internal( fprintf_ln(outfile, _("usage: %s"), _(*usagestr++)); while (*usagestr && **usagestr) - /* TRANSLATORS: the colon here should align with the - one in "usage: %s" translation */ + /* + * TRANSLATORS: the colon here should align with the + * one in "usage: %s" translation. + */ fprintf_ln(outfile, _(" or: %s"), _(*usagestr++)); while (*usagestr) { if (**usagestr) diff --combined pathspec.c index 828405021f,828405021f,e4659b1440..ecc5331c23 --- a/pathspec.c +++ b/pathspec.c @@@@ -1,5 -1,5 -1,5 +1,6 @@@@ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" ++ #include "config.h" #include "dir.h" #include "pathspec.h" #include "attr.h" @@@@ -18,7 -18,7 -18,6 +19,7 @@@@ * to use find_pathspecs_matching_against_index() instead. */ void add_pathspec_matches_against_index(const struct pathspec *pathspec, + const struct index_state *istate, char *seen) { int num_unmatched = 0, i; @@@@ -34,8 -34,8 -33,8 +35,8 @@@@ num_unmatched++; if (!num_unmatched) return; - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; + for (i = 0; i < istate->cache_nr; i++) { + const struct cache_entry *ce = istate->cache[i]; ce_path_match(ce, pathspec, seen); } } @@@@ -48,11 -48,11 -47,10 +49,11 @@@@ * nature of the "closest" (i.e. most specific) matches which each of the * given pathspecs achieves against all items in the index. */ -char *find_pathspecs_matching_against_index(const struct pathspec *pathspec) +char *find_pathspecs_matching_against_index(const struct pathspec *pathspec, + const struct index_state *istate) { char *seen = xcalloc(pathspec->nr, 1); - add_pathspec_matches_against_index(pathspec, seen); + add_pathspec_matches_against_index(pathspec, istate, seen); return seen; } @@@@ -389,6 -389,6 -387,65 +390,6 @@@@ static const char *parse_element_magic( return parse_short_magic(magic, elem); } -static void strip_submodule_slash_cheap(struct pathspec_item *item) -{ - if (item->len >= 1 && item->match[item->len - 1] == '/') { - int i = cache_name_pos(item->match, item->len - 1); - - if (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) { - item->len--; - item->match[item->len] = '\0'; - } - } -} - -static void strip_submodule_slash_expensive(struct pathspec_item *item) -{ - int i; - - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - int ce_len = ce_namelen(ce); - - if (!S_ISGITLINK(ce->ce_mode)) - continue; - - if (item->len <= ce_len || item->match[ce_len] != '/' || - memcmp(ce->name, item->match, ce_len)) - continue; - - if (item->len == ce_len + 1) { - /* strip trailing slash */ - item->len--; - item->match[item->len] = '\0'; - } else { - die(_("Pathspec '%s' is in submodule '%.*s'"), - item->original, ce_len, ce->name); - } - } -} - -static void die_inside_submodule_path(struct pathspec_item *item) -{ - int i; - - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - int ce_len = ce_namelen(ce); - - if (!S_ISGITLINK(ce->ce_mode)) - continue; - - if (item->len < ce_len || - !(item->match[ce_len] == '/' || item->match[ce_len] == '\0') || - memcmp(ce->name, item->match, ce_len)) - continue; - - die(_("Pathspec '%s' is in submodule '%.*s'"), - item->original, ce_len, ce->name); - } -} - /* * Perform the initialization of a pathspec_item based on a pathspec element. */ @@@@ -461,6 -461,6 -518,12 +462,6 @@@@ static void init_pathspec_item(struct p item->original = xstrdup(elt); } - if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) - strip_submodule_slash_cheap(item); - - if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE) - strip_submodule_slash_expensive(item); - if (magic & PATHSPEC_LITERAL) { item->nowildcard_len = item->len; } else { @@@@ -485,7 -485,7 -548,15 +486,7 @@@@ /* sanity checks, pathspec matchers assume these are sane */ if (item->nowildcard_len > item->len || item->prefix > item->len) { - /* - * This case can be triggered by the user pointing us to a - * pathspec inside a submodule, which is an input error. - * Detect that here and complain, but fallback in the - * non-submodule case to a BUG, as we have no idea what - * would trigger that. - */ - die_inside_submodule_path(item); - die ("BUG: item->nowildcard_len > item->len || item->prefix > item->len)"); + die ("BUG: error initializing pathspec_item"); } } diff --combined pretty.c index 09701bd2ff,09701bd2ff,06a1f13c60..9c9f81b5b0 --- a/pretty.c +++ b/pretty.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "commit.h" #include "utf8.h" #include "diff.h" @@@@ -405,11 -405,11 -406,11 +406,11 @@@@ static void add_rfc2047(struct strbuf * const char *show_ident_date(const struct ident_split *ident, const struct date_mode *mode) { - unsigned long date = 0; + timestamp_t date = 0; long tz = 0; if (ident->date_begin && ident->date_end) - date = strtoul(ident->date_begin, NULL, 10); + date = parse_timestamp(ident->date_begin, NULL, 10); if (date_overflows(date)) date = 0; else { @@@@ -1137,7 -1137,7 -1138,7 +1138,7 @@@@ static size_t format_commit_one(struct /* these depend on the commit */ if (!commit->object.parsed) - parse_object(commit->object.oid.hash); + parse_object(&commit->object.oid); switch (placeholder[0]) { case 'H': /* commit hash */ diff --combined read-cache.c index bc156a133e,bc156a133e,e623e075de..c8c766dab0 --- a/read-cache.c +++ b/read-cache.c @@@@ -5,6 -5,6 -5,7 +5,7 @@@@ */ #define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" ++ #include "config.h" #include "tempfile.h" #include "lockfile.h" #include "cache-tree.h" @@@@ -1877,9 -1877,9 -1878,15 +1878,9 @@@@ int discard_index(struct index_state *i { int i; - for (i = 0; i < istate->cache_nr; i++) { - if (istate->cache[i]->index && - istate->split_index && - istate->split_index->base && - istate->cache[i]->index <= istate->split_index->base->cache_nr && - istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1]) - continue; + unshare_split_index(istate, 1); + for (i = 0; i < istate->cache_nr; i++) free(istate->cache[i]); - } resolve_undo_clear_index(istate); istate->cache_nr = 0; istate->cache_changed = 0; @@@@ -2181,10 -2181,10 -2188,9 +2182,10 @@@@ void update_index_if_able(struct index_ rollback_lock_file(lockfile); } -static int do_write_index(struct index_state *istate, int newfd, +static int do_write_index(struct index_state *istate, struct tempfile *tempfile, int strip_extensions) { + int newfd = tempfile->fd; git_SHA_CTX c; struct cache_header hdr; int i, err, removed, extended, hdr_version; @@@@ -2192,7 -2192,7 -2198,6 +2193,7 @@@@ int entries = istate->cache_nr; struct stat st; struct strbuf previous_name_buf = STRBUF_INIT, *previous_name; + int drop_cache_tree = 0; for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) @@@@ -2243,8 -2243,8 -2248,6 +2244,8 @@@@ warning(msg, ce->name); else return error(msg, ce->name); + + drop_cache_tree = 1; } if (ce_write_entry(&c, newfd, ce, previous_name) < 0) return -1; @@@@ -2263,7 -2263,7 -2266,7 +2264,7 @@@@ if (err) return -1; } - if (!strip_extensions && istate->cache_tree) { + if (!strip_extensions && !drop_cache_tree && istate->cache_tree) { struct strbuf sb = STRBUF_INIT; cache_tree_write(&sb, istate->cache_tree); @@@@ -2296,11 -2296,11 -2299,7 +2297,11 @@@@ return -1; } - if (ce_flush(&c, newfd, istate->sha1) || fstat(newfd, &st)) + if (ce_flush(&c, newfd, istate->sha1)) + return -1; + if (close_tempfile(tempfile)) + return error(_("could not close '%s'"), tempfile->filename.buf); + if (stat(tempfile->filename.buf, &st)) return -1; istate->timestamp.sec = (unsigned int)st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); @@@@ -2323,7 -2323,7 -2322,7 +2324,7 @@@@ static int commit_locked_index(struct l static int do_write_locked_index(struct index_state *istate, struct lock_file *lock, unsigned flags) { - int ret = do_write_index(istate, get_lock_file_fd(lock), 0); + int ret = do_write_index(istate, &lock->tempfile, 0); if (ret) return ret; assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) != @@@@ -2420,7 -2420,7 -2419,7 +2421,7 @@@@ static int write_shared_index(struct in return do_write_locked_index(istate, lock, flags); } move_cache_to_base_index(istate); - ret = do_write_index(si->base, fd, 1); + ret = do_write_index(si->base, &temporary_sharedindex, 1); if (ret) { delete_tempfile(&temporary_sharedindex); return ret; @@@@ -2630,9 -2630,9 -2629,3 +2631,9 @@@@ void stat_validity_update(struct stat_v fill_stat_data(sv->sd, &st); } } + +void move_index_extensions(struct index_state *dst, struct index_state *src) +{ + dst->untracked = src->untracked; + src->untracked = NULL; +} diff --combined refs.c index f0685c9251,f0685c9251,c0cd259141..84112c88ee --- a/refs.c +++ b/refs.c @@@@ -3,6 -3,6 -3,7 +3,7 @@@@ */ #include "cache.h" ++ #include "config.h" #include "hashmap.h" #include "lockfile.h" #include "iterator.h" @@@@ -11,7 -11,7 -12,6 +12,7 @@@@ #include "object.h" #include "tag.h" #include "submodule.h" +#include "worktree.h" /* * List of all available backends @@@@ -714,7 -714,7 -714,7 +715,7 @@@@ int is_branch(const char *refname struct read_ref_at_cb { const char *refname; - unsigned long at_time; + timestamp_t at_time; int cnt; int reccnt; unsigned char *sha1; @@@@ -723,15 -723,15 -723,15 +724,15 @@@@ unsigned char osha1[20]; unsigned char nsha1[20]; int tz; - unsigned long date; + timestamp_t date; char **msg; - unsigned long *cutoff_time; + timestamp_t *cutoff_time; int *cutoff_tz; int *cutoff_cnt; }; static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct read_ref_at_cb *cb = cb_data; @@@@ -778,7 -778,7 -778,7 +779,7 @@@@ } static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct read_ref_at_cb *cb = cb_data; @@@@ -798,9 -798,9 -798,9 +799,9 @@@@ return 1; } -int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt, +int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt, unsigned char *sha1, char **msg, - unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt) + timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt) { struct read_ref_at_cb cb; @@@@ -848,24 -848,24 -848,11 +849,24 @@@@ struct ref_transaction *ref_transaction void ref_transaction_free(struct ref_transaction *transaction) { - int i; + size_t i; if (!transaction) return; + switch (transaction->state) { + case REF_TRANSACTION_OPEN: + case REF_TRANSACTION_CLOSED: + /* OK */ + break; + case REF_TRANSACTION_PREPARED: + die("BUG: free called on a prepared reference transaction"); + break; + default: + die("BUG: unexpected reference transaction state"); + break; + } + for (i = 0; i < transaction->nr; i++) { free(transaction->updates[i]->msg); free(transaction->updates[i]); @@@@ -896,9 -896,9 -883,9 +897,9 @@@@ struct ref_update *ref_transaction_add_ update->flags = flags; if (flags & REF_HAVE_NEW) - hashcpy(update->new_sha1, new_sha1); + hashcpy(update->new_oid.hash, new_sha1); if (flags & REF_HAVE_OLD) - hashcpy(update->old_sha1, old_sha1); + hashcpy(update->old_oid.hash, old_sha1); update->msg = xstrdup_or_null(msg); return update; } @@@@ -1259,19 -1259,19 -1246,8 +1260,19 @@@@ struct ref_iterator *refs_ref_iterator_ { struct ref_iterator *iter; + if (ref_paranoia < 0) + ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0); + if (ref_paranoia) + flags |= DO_FOR_EACH_INCLUDE_BROKEN; + iter = refs->be->iterator_begin(refs, prefix, flags); - iter = prefix_ref_iterator_begin(iter, prefix, trim); + + /* + * `iterator_begin()` already takes care of prefix, but we + * might need to do some trimming: + */ + if (trim) + iter = prefix_ref_iterator_begin(iter, "", trim); return iter; } @@@@ -1502,32 -1502,32 -1478,32 +1503,32 @@@@ int resolve_gitlink_ref(const char *sub return 0; } -struct submodule_hash_entry +struct ref_store_hash_entry { struct hashmap_entry ent; /* must be the first member! */ struct ref_store *refs; - /* NUL-terminated name of submodule: */ - char submodule[FLEX_ARRAY]; + /* NUL-terminated identifier of the ref store: */ + char name[FLEX_ARRAY]; }; -static int submodule_hash_cmp(const void *entry, const void *entry_or_key, +static int ref_store_hash_cmp(const void *entry, const void *entry_or_key, const void *keydata) { - const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key; - const char *submodule = keydata ? keydata : e2->submodule; + const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key; + const char *name = keydata ? keydata : e2->name; - return strcmp(e1->submodule, submodule); + return strcmp(e1->name, name); } -static struct submodule_hash_entry *alloc_submodule_hash_entry( - const char *submodule, struct ref_store *refs) +static struct ref_store_hash_entry *alloc_ref_store_hash_entry( + const char *name, struct ref_store *refs) { - struct submodule_hash_entry *entry; + struct ref_store_hash_entry *entry; - FLEX_ALLOC_STR(entry, submodule, submodule); - hashmap_entry_init(entry, strhash(submodule)); + FLEX_ALLOC_STR(entry, name, name); + hashmap_entry_init(entry, strhash(name)); entry->refs = refs; return entry; } @@@@ -1538,23 -1538,23 -1514,20 +1539,23 @@@@ static struct ref_store *main_ref_store /* A hashmap of ref_stores, stored by submodule name: */ static struct hashmap submodule_ref_stores; +/* A hashmap of ref_stores, stored by worktree id: */ +static struct hashmap worktree_ref_stores; + /* - * Return the ref_store instance for the specified submodule. If that - * ref_store hasn't been initialized yet, return NULL. + * Look up a ref store by name. If that ref_store hasn't been + * registered yet, return NULL. */ -static struct ref_store *lookup_submodule_ref_store(const char *submodule) +static struct ref_store *lookup_ref_store_map(struct hashmap *map, + const char *name) { - struct submodule_hash_entry *entry; + struct ref_store_hash_entry *entry; - if (!submodule_ref_stores.tablesize) + if (!map->tablesize) /* It's initialized on demand in register_ref_store(). */ return NULL; - entry = hashmap_get_from_hash(&submodule_ref_stores, - strhash(submodule), submodule); + entry = hashmap_get_from_hash(map, strhash(name), name); return entry ? entry->refs : NULL; } @@@@ -1581,24 -1581,24 -1554,29 +1582,24 @@@@ struct ref_store *get_main_ref_store(vo if (main_ref_store) return main_ref_store; - main_ref_store = ref_store_init(get_git_dir(), - (REF_STORE_READ | - REF_STORE_WRITE | - REF_STORE_ODB | - REF_STORE_MAIN)); + main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS); return main_ref_store; } /* - * Register the specified ref_store to be the one that should be used - * for submodule. It is a fatal error to call this function twice for - * the same submodule. + * Associate a ref store with a name. It is a fatal error to call this + * function twice for the same name. */ -static void register_submodule_ref_store(struct ref_store *refs, - const char *submodule) +static void register_ref_store_map(struct hashmap *map, + const char *type, + struct ref_store *refs, + const char *name) { - if (!submodule_ref_stores.tablesize) - hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0); + if (!map->tablesize) + hashmap_init(map, ref_store_hash_cmp, 0); - if (hashmap_put(&submodule_ref_stores, - alloc_submodule_hash_entry(submodule, refs))) - die("BUG: ref_store for submodule '%s' initialized twice", - submodule); + if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs))) + die("BUG: %s ref_store '%s' initialized twice", type, name); } struct ref_store *get_submodule_ref_store(const char *submodule) @@@@ -1615,7 -1615,7 -1593,7 +1616,7 @@@@ return get_main_ref_store(); } - refs = lookup_submodule_ref_store(submodule); + refs = lookup_ref_store_map(&submodule_ref_stores, submodule); if (refs) return refs; @@@@ -1634,39 -1634,39 -1612,12 +1635,39 @@@@ /* assume that add_submodule_odb() has been called */ refs = ref_store_init(submodule_sb.buf, REF_STORE_READ | REF_STORE_ODB); - register_submodule_ref_store(refs, submodule); + register_ref_store_map(&submodule_ref_stores, "submodule", + refs, submodule); strbuf_release(&submodule_sb); return refs; } +struct ref_store *get_worktree_ref_store(const struct worktree *wt) +{ + struct ref_store *refs; + const char *id; + + if (wt->is_current) + return get_main_ref_store(); + + id = wt->id ? wt->id : "/"; + refs = lookup_ref_store_map(&worktree_ref_stores, id); + if (refs) + return refs; + + if (wt->id) + refs = ref_store_init(git_common_path("worktrees/%s", wt->id), + REF_STORE_ALL_CAPS); + else + refs = ref_store_init(get_git_common_dir(), + REF_STORE_ALL_CAPS); + + if (refs) + register_ref_store_map(&worktree_ref_stores, "worktree", + refs, id); + return refs; +} + void base_ref_store_init(struct ref_store *refs, const struct ref_storage_be *be) { @@@@ -1707,108 -1707,108 -1658,18 +1708,108 @@@@ int create_symref(const char *ref_targe refs_heads_master, logmsg); } -int ref_transaction_commit(struct ref_transaction *transaction, - struct strbuf *err) +int ref_update_reject_duplicates(struct string_list *refnames, + struct strbuf *err) +{ + size_t i, n = refnames->nr; + + assert(err); + + for (i = 1; i < n; i++) { + int cmp = strcmp(refnames->items[i - 1].string, + refnames->items[i].string); + + if (!cmp) { + strbuf_addf(err, + "multiple updates for ref '%s' not allowed.", + refnames->items[i].string); + return 1; + } else if (cmp > 0) { + die("BUG: ref_update_reject_duplicates() received unsorted list"); + } + } + return 0; +} + +int ref_transaction_prepare(struct ref_transaction *transaction, + struct strbuf *err) { struct ref_store *refs = transaction->ref_store; + switch (transaction->state) { + case REF_TRANSACTION_OPEN: + /* Good. */ + break; + case REF_TRANSACTION_PREPARED: + die("BUG: prepare called twice on reference transaction"); + break; + case REF_TRANSACTION_CLOSED: + die("BUG: prepare called on a closed reference transaction"); + break; + default: + die("BUG: unexpected reference transaction state"); + break; + } + if (getenv(GIT_QUARANTINE_ENVIRONMENT)) { strbuf_addstr(err, _("ref updates forbidden inside quarantine environment")); return -1; } - return refs->be->transaction_commit(refs, transaction, err); + return refs->be->transaction_prepare(refs, transaction, err); +} + +int ref_transaction_abort(struct ref_transaction *transaction, + struct strbuf *err) +{ + struct ref_store *refs = transaction->ref_store; + int ret = 0; + + switch (transaction->state) { + case REF_TRANSACTION_OPEN: + /* No need to abort explicitly. */ + break; + case REF_TRANSACTION_PREPARED: + ret = refs->be->transaction_abort(refs, transaction, err); + break; + case REF_TRANSACTION_CLOSED: + die("BUG: abort called on a closed reference transaction"); + break; + default: + die("BUG: unexpected reference transaction state"); + break; + } + + ref_transaction_free(transaction); + return ret; +} + +int ref_transaction_commit(struct ref_transaction *transaction, + struct strbuf *err) +{ + struct ref_store *refs = transaction->ref_store; + int ret; + + switch (transaction->state) { + case REF_TRANSACTION_OPEN: + /* Need to prepare first. */ + ret = ref_transaction_prepare(transaction, err); + if (ret) + return ret; + break; + case REF_TRANSACTION_PREPARED: + /* Fall through to finish. */ + break; + case REF_TRANSACTION_CLOSED: + die("BUG: commit called on a closed reference transaction"); + break; + default: + die("BUG: unexpected reference transaction state"); + break; + } + + return refs->be->transaction_finish(refs, transaction, err); } int refs_verify_refname_available(struct ref_store *refs, @@@@ -2010,16 -2010,16 -1871,15 +2011,16 @@@@ int initial_ref_transaction_commit(stru return refs->be->initial_transaction_commit(refs, transaction, err); } -int refs_delete_refs(struct ref_store *refs, struct string_list *refnames, - unsigned int flags) +int refs_delete_refs(struct ref_store *refs, const char *msg, + struct string_list *refnames, unsigned int flags) { - return refs->be->delete_refs(refs, refnames, flags); + return refs->be->delete_refs(refs, msg, refnames, flags); } -int delete_refs(struct string_list *refnames, unsigned int flags) +int delete_refs(const char *msg, struct string_list *refnames, + unsigned int flags) { - return refs_delete_refs(get_main_ref_store(), refnames, flags); + return refs_delete_refs(get_main_ref_store(), msg, refnames, flags); } int refs_rename_ref(struct ref_store *refs, const char *oldref, diff --combined refs/files-backend.c index d8b3f73147,d8b3f73147,1d530f6020..621a4086c3 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "../cache.h" ++ #include "../config.h" #include "../refs.h" #include "refs-internal.h" #include "ref-cache.h" @@@@ -43,6 -43,6 -44,15 +44,6 @@@@ struct packed_ref_cache */ unsigned int referrers; - /* - * Iff the packed-refs file associated with this instance is - * currently locked for writing, this points at the associated - * lock (which is owned by somebody else). The referrer count - * is also incremented when the file is locked and decremented - * when it is unlocked. - */ - struct lock_file *lock; - /* The metadata from when this packed-refs cache was read */ struct stat_validity validity; }; @@@@ -61,13 -61,13 -71,10 +62,13 @@@@ struct files_ref_store struct ref_cache *loose; struct packed_ref_cache *packed; -}; -/* Lock used for the main packed-refs file: */ -static struct lock_file packlock; + /* + * Lock used for the "packed-refs" file. Note that this (and + * thus the enclosing `files_ref_store`) must not be freed. + */ + struct lock_file packed_refs_lock; +}; /* * Increment the reference count of *packed_refs. @@@@ -98,8 -98,8 -105,8 +99,8 @@@@ static void clear_packed_ref_cache(stru if (refs->packed) { struct packed_ref_cache *packed_refs = refs->packed; - if (packed_refs->lock) - die("internal error: packed-ref cache cleared while locked"); + if (is_lock_file_locked(&refs->packed_refs_lock)) + die("BUG: packed-ref cache cleared while locked"); refs->packed = NULL; release_packed_ref_cache(packed_refs); } @@@@ -189,15 -189,15 -196,27 +190,15 @@@@ static const char PACKED_REFS_HEADER[] * Return a pointer to the refname within the line (null-terminated), * or NULL if there was a problem. */ -static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1) +static const char *parse_ref_line(struct strbuf *line, struct object_id *oid) { const char *ref; - /* - * 42: the answer to everything. - * - * In this case, it happens to be the answer to - * 40 (length of sha1 hex representation) - * +1 (space in between hex and name) - * +1 (newline at the end of the line) - */ - if (line->len <= 42) + if (parse_oid_hex(line->buf, oid, &ref) < 0) return NULL; - - if (get_sha1_hex(line->buf, sha1) < 0) - return NULL; - if (!isspace(line->buf[40])) + if (!isspace(*ref++)) return NULL; - ref = line->buf + 41; if (isspace(*ref)) return NULL; @@@@ -209,9 -209,9 -228,7 +210,9 @@@@ } /* - * Read f, which is a packed-refs file, into dir. + * Read from `packed_refs_file` into a newly-allocated + * `packed_ref_cache` and return it. The return value will already + * have its reference count incremented. * * A comment line of the form "# pack-refs with: " may contain zero or * more traits. We interpret the traits as follows: @@@@ -237,38 -237,38 -254,14 +238,38 @@@@ * compatibility with older clients, but we do not require it * (i.e., "peeled" is a no-op if "fully-peeled" is set). */ -static void read_packed_refs(FILE *f, struct ref_dir *dir) +static struct packed_ref_cache *read_packed_refs(const char *packed_refs_file) { + FILE *f; + struct packed_ref_cache *packed_refs = xcalloc(1, sizeof(*packed_refs)); struct ref_entry *last = NULL; struct strbuf line = STRBUF_INIT; enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE; + struct ref_dir *dir; + + acquire_packed_ref_cache(packed_refs); + packed_refs->cache = create_ref_cache(NULL, NULL); + packed_refs->cache->root->flag &= ~REF_INCOMPLETE; + + f = fopen(packed_refs_file, "r"); + if (!f) { + if (errno == ENOENT) { + /* + * This is OK; it just means that no + * "packed-refs" file has been written yet, + * which is equivalent to it being empty. + */ + return packed_refs; + } else { + die_errno("couldn't read %s", packed_refs_file); + } + } + + stat_validity_update(&packed_refs->validity, fileno(f)); + dir = get_ref_dir(packed_refs->cache->root); while (strbuf_getwholeline(&line, f, '\n') != EOF) { - unsigned char sha1[20]; + struct object_id oid; const char *refname; const char *traits; @@@@ -281,17 -281,17 -274,17 +282,17 @@@@ continue; } - refname = parse_ref_line(&line, sha1); + refname = parse_ref_line(&line, &oid); if (refname) { int flag = REF_ISPACKED; if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(refname)) die("packed refname is dangerous: %s", refname); - hashclr(sha1); + oidclr(&oid); flag |= REF_BAD_NAME | REF_ISBROKEN; } - last = create_ref_entry(refname, sha1, flag, 0); + last = create_ref_entry(refname, &oid, flag); if (peeled == PEELED_FULLY || (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/"))) last->flag |= REF_KNOWS_PEELED; @@@@ -302,8 -302,8 -295,8 +303,8 @@@@ line.buf[0] == '^' && line.len == PEELED_LINE_LENGTH && line.buf[PEELED_LINE_LENGTH - 1] == '\n' && - !get_sha1_hex(line.buf + 1, sha1)) { - hashcpy(last->u.value.peeled.hash, sha1); + !get_oid_hex(line.buf + 1, &oid)) { + oidcpy(&last->u.value.peeled, &oid); /* * Regardless of what the file header said, * we definitely know the value of *this* @@@@ -313,10 -313,10 -306,7 +314,10 @@@@ } } + fclose(f); strbuf_release(&line); + + return packed_refs; } static const char *files_packed_refs_path(struct files_ref_store *refs) @@@@ -371,24 -371,24 -361,30 +372,24 @@@@ static void files_ref_path(struct files /* * Get the packed_ref_cache for the specified files_ref_store, - * creating it if necessary. + * creating and populating it if it hasn't been read before or if the + * file has been changed (according to its `validity` field) since it + * was last read. On the other hand, if we hold the lock, then assume + * that the file hasn't been changed out from under us, so skip the + * extra `stat()` call in `stat_validity_check()`. */ static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *refs) { const char *packed_refs_file = files_packed_refs_path(refs); if (refs->packed && + !is_lock_file_locked(&refs->packed_refs_lock) && !stat_validity_check(&refs->packed->validity, packed_refs_file)) clear_packed_ref_cache(refs); - if (!refs->packed) { - FILE *f; - - refs->packed = xcalloc(1, sizeof(*refs->packed)); - acquire_packed_ref_cache(refs->packed); - refs->packed->cache = create_ref_cache(&refs->base, NULL); - refs->packed->cache->root->flag &= ~REF_INCOMPLETE; - f = fopen(packed_refs_file, "r"); - if (f) { - stat_validity_update(&refs->packed->validity, fileno(f)); - read_packed_refs(f, get_ref_dir(refs->packed->cache->root)); - fclose(f); - } - } + if (!refs->packed) + refs->packed = read_packed_refs(packed_refs_file); + return refs->packed; } @@@@ -409,18 -409,18 -405,14 +410,18 @@@@ static struct ref_dir *get_packed_refs( * commit_packed_refs(). */ static void add_packed_ref(struct files_ref_store *refs, - const char *refname, const unsigned char *sha1) + const char *refname, const struct object_id *oid) { struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs); - if (!packed_ref_cache->lock) - die("internal error: packed refs not locked"); + if (!is_lock_file_locked(&refs->packed_refs_lock)) + die("BUG: packed refs not locked"); + + if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) + die("Reference has invalid format: '%s'", refname); + add_ref_entry(get_packed_ref_dir(packed_ref_cache), - create_ref_entry(refname, sha1, REF_ISPACKED, 1)); + create_ref_entry(refname, oid, REF_ISPACKED)); } /* @@@@ -453,7 -453,7 -445,7 +454,7 @@@@ static void loose_fill_ref_dir(struct r strbuf_add(&refname, dirname, dirnamelen); while ((de = readdir(d)) != NULL) { - unsigned char sha1[20]; + struct object_id oid; struct stat st; int flag; @@@@ -474,10 -474,10 -466,10 +475,10 @@@@ if (!refs_resolve_ref_unsafe(&refs->base, refname.buf, RESOLVE_REF_READING, - sha1, &flag)) { - hashclr(sha1); + oid.hash, &flag)) { + oidclr(&oid); flag |= REF_ISBROKEN; - } else if (is_null_sha1(sha1)) { + } else if (is_null_oid(&oid)) { /* * It is so astronomically unlikely * that NULL_SHA1 is the SHA-1 of an @@@@ -493,11 -493,11 -485,11 +494,11 @@@@ REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(refname.buf)) die("loose refname is dangerous: %s", refname.buf); - hashclr(sha1); + oidclr(&oid); flag |= REF_BAD_NAME | REF_ISBROKEN; } add_entry_to_dir(dir, - create_ref_entry(refname.buf, sha1, flag, 0)); + create_ref_entry(refname.buf, &oid, flag)); } strbuf_setlen(&refname, dirnamelen); strbuf_setlen(&path, path_baselen); @@@@ -1078,12 -1078,12 -1070,15 +1079,12 @@@@ static struct ref_iterator *files_ref_i struct ref_iterator *loose_iter, *packed_iter; struct files_ref_iterator *iter; struct ref_iterator *ref_iterator; + unsigned int required_flags = REF_STORE_READ; - if (ref_paranoia < 0) - ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0); - if (ref_paranoia) - flags |= DO_FOR_EACH_INCLUDE_BROKEN; + if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) + required_flags |= REF_STORE_ODB; - refs = files_downcast(ref_store, - REF_STORE_READ | (ref_paranoia ? 0 : REF_STORE_ODB), - "ref_iterator_begin"); + refs = files_downcast(ref_store, required_flags, "ref_iterator_begin"); iter = xcalloc(1, sizeof(*iter)); ref_iterator = &iter->base; @@@@ -1308,17 -1308,17 -1303,17 +1309,17 @@@@ static int lock_packed_refs(struct file } if (hold_lock_file_for_update_timeout( - &packlock, files_packed_refs_path(refs), + &refs->packed_refs_lock, files_packed_refs_path(refs), flags, timeout_value) < 0) return -1; /* - * Get the current packed-refs while holding the lock. If the - * packed-refs file has been modified since we last read it, - * this will automatically invalidate the cache and re-read - * the packed-refs file. + * Get the current packed-refs while holding the lock. It is + * important that we call `get_packed_ref_cache()` before + * setting `packed_ref_cache->lock`, because otherwise the + * former will see that the file is locked and assume that the + * cache can't be stale. */ packed_ref_cache = get_packed_ref_cache(refs); - packed_ref_cache->lock = &packlock; /* Increment the reference count to prevent it from being freed: */ acquire_packed_ref_cache(packed_ref_cache); return 0; @@@@ -1341,10 -1341,10 -1336,10 +1342,10 @@@@ static int commit_packed_refs(struct fi files_assert_main_repository(refs, "commit_packed_refs"); - if (!packed_ref_cache->lock) - die("internal error: packed-refs not locked"); + if (!is_lock_file_locked(&refs->packed_refs_lock)) + die("BUG: packed-refs not locked"); - out = fdopen_lock_file(packed_ref_cache->lock, "w"); + out = fdopen_lock_file(&refs->packed_refs_lock, "w"); if (!out) die_errno("unable to fdopen packed-refs descriptor"); @@@@ -1362,10 -1362,10 -1357,11 +1363,10 @@@@ if (ok != ITER_DONE) die("error while iterating over references"); - if (commit_lock_file(packed_ref_cache->lock)) { + if (commit_lock_file(&refs->packed_refs_lock)) { save_errno = errno; error = -1; } - packed_ref_cache->lock = NULL; release_packed_ref_cache(packed_ref_cache); errno = save_errno; return error; @@@@ -1383,9 -1383,9 -1379,10 +1384,9 @@@@ static void rollback_packed_refs(struc files_assert_main_repository(refs, "rollback_packed_refs"); - if (!packed_ref_cache->lock) - die("internal error: packed-refs not locked"); - rollback_lock_file(packed_ref_cache->lock); - packed_ref_cache->lock = NULL; + if (!is_lock_file_locked(&refs->packed_refs_lock)) + die("BUG: packed-refs not locked"); + rollback_lock_file(&refs->packed_refs_lock); release_packed_ref_cache(packed_ref_cache); clear_packed_ref_cache(refs); } @@@@ -1480,32 -1480,32 -1477,6 +1481,32 @@@@ static void prune_refs(struct files_ref } } +/* + * Return true if the specified reference should be packed. + */ +static int should_pack_ref(const char *refname, + const struct object_id *oid, unsigned int ref_flags, + unsigned int pack_flags) +{ + /* Do not pack per-worktree refs: */ + if (ref_type(refname) != REF_TYPE_NORMAL) + return 0; + + /* Do not pack non-tags unless PACK_REFS_ALL is set: */ + if (!(pack_flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/")) + return 0; + + /* Do not pack symbolic refs: */ + if (ref_flags & REF_ISSYMREF) + return 0; + + /* Do not pack broken refs: */ + if (!ref_resolves_to_object(refname, oid, ref_flags)) + return 0; + + return 1; +} + static int files_pack_refs(struct ref_store *ref_store, unsigned int flags) { struct files_ref_store *refs = @@@@ -1527,9 -1527,9 -1498,21 +1528,9 @@@@ * pruned, also add it to refs_to_prune. */ struct ref_entry *packed_entry; - int is_tag_ref = starts_with(iter->refname, "refs/tags/"); - - /* Do not pack per-worktree refs: */ - if (ref_type(iter->refname) != REF_TYPE_NORMAL) - continue; - /* ALWAYS pack tags */ - if (!(flags & PACK_REFS_ALL) && !is_tag_ref) - continue; - - /* Do not pack symbolic or broken refs: */ - if (iter->flags & REF_ISSYMREF) - continue; - - if (!ref_resolves_to_object(iter->refname, iter->oid, iter->flags)) + if (!should_pack_ref(iter->refname, iter->oid, iter->flags, + flags)) continue; /* @@@@ -1544,8 -1544,8 -1527,8 +1545,8 @@@@ packed_entry->flag = REF_ISPACKED; oidcpy(&packed_entry->u.value.oid, iter->oid); } else { - packed_entry = create_ref_entry(iter->refname, iter->oid->hash, - REF_ISPACKED, 0); + packed_entry = create_ref_entry(iter->refname, iter->oid, + REF_ISPACKED); add_ref_entry(packed_refs, packed_entry); } oidclr(&packed_entry->u.value.peeled); @@@@ -1625,7 -1625,7 -1608,7 +1626,7 @@@@ static int repack_without_refs(struct f return ret; } -static int files_delete_refs(struct ref_store *ref_store, +static int files_delete_refs(struct ref_store *ref_store, const char *msg, struct string_list *refnames, unsigned int flags) { struct files_ref_store *refs = @@@@ -1657,7 -1657,7 -1640,7 +1658,7 @@@@ for (i = 0; i < refnames->nr; i++) { const char *refname = refnames->items[i].string; - if (refs_delete_ref(&refs->base, NULL, refname, NULL, flags)) + if (refs_delete_ref(&refs->base, msg, refname, NULL, flags)) result |= error(_("could not remove reference %s"), refname); } @@@@ -1727,10 -1727,10 -1710,10 +1728,10 @@@@ static int rename_tmp_log(struct files_ } static int write_ref_to_lockfile(struct ref_lock *lock, - const unsigned char *sha1, struct strbuf *err); + const struct object_id *oid, struct strbuf *err); static int commit_ref_update(struct files_ref_store *refs, struct ref_lock *lock, - const unsigned char *sha1, const char *logmsg, + const struct object_id *oid, const char *logmsg, struct strbuf *err); static int files_rename_ref(struct ref_store *ref_store, @@@@ -1739,7 -1739,7 -1722,7 +1740,7 @@@@ { struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_WRITE, "rename_ref"); - unsigned char sha1[20], orig_sha1[20]; + struct object_id oid, orig_oid; int flag = 0, logmoved = 0; struct ref_lock *lock; struct stat loginfo; @@@@ -1761,7 -1761,7 -1744,7 +1762,7 @@@@ if (!refs_resolve_ref_unsafe(&refs->base, oldrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - orig_sha1, &flag)) { + orig_oid.hash, &flag)) { ret = error("refname %s not found", oldrefname); goto out; } @@@@ -1783,21 -1783,21 -1766,21 +1784,21 @@@@ } if (refs_delete_ref(&refs->base, logmsg, oldrefname, - orig_sha1, REF_NODEREF)) { + orig_oid.hash, REF_NODEREF)) { error("unable to delete old %s", oldrefname); goto rollback; } /* - * Since we are doing a shallow lookup, sha1 is not the - * correct value to pass to delete_ref as old_sha1. But that - * doesn't matter, because an old_sha1 check wouldn't add to + * Since we are doing a shallow lookup, oid is not the + * correct value to pass to delete_ref as old_oid. But that + * doesn't matter, because an old_oid check wouldn't add to * the safety anyway; we want to delete the reference whatever * its current value. */ if (!refs_read_ref_full(&refs->base, newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, - sha1, NULL) && + oid.hash, NULL) && refs_delete_ref(&refs->base, NULL, newrefname, NULL, REF_NODEREF)) { if (errno == EISDIR) { @@@@ -1830,10 -1830,10 -1813,10 +1831,10 @@@@ strbuf_release(&err); goto rollback; } - hashcpy(lock->old_oid.hash, orig_sha1); + oidcpy(&lock->old_oid, &orig_oid); - if (write_ref_to_lockfile(lock, orig_sha1, &err) || - commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) { + if (write_ref_to_lockfile(lock, &orig_oid, &err) || + commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) { error("unable to write current sha1 into %s: %s", newrefname, err.buf); strbuf_release(&err); goto rollback; @@@@ -1853,8 -1853,8 -1836,8 +1854,8 @@@@ flag = log_all_ref_updates; log_all_ref_updates = LOG_REFS_NONE; - if (write_ref_to_lockfile(lock, orig_sha1, &err) || - commit_ref_update(refs, lock, orig_sha1, NULL, &err)) { + if (write_ref_to_lockfile(lock, &orig_oid, &err) || + commit_ref_update(refs, lock, &orig_oid, NULL, &err)) { error("unable to write current sha1 into %s: %s", oldrefname, err.buf); strbuf_release(&err); } @@@@ -2004,8 -2004,8 -1987,8 +2005,8 @@@@ static int files_create_reflog(struct r return 0; } -static int log_ref_write_fd(int fd, const unsigned char *old_sha1, - const unsigned char *new_sha1, +static int log_ref_write_fd(int fd, const struct object_id *old_oid, + const struct object_id *new_oid, const char *committer, const char *msg) { int msglen, written; @@@@ -2016,8 -2016,8 -1999,8 +2017,8 @@@@ maxlen = strlen(committer) + msglen + 100; logrec = xmalloc(maxlen); len = xsnprintf(logrec, maxlen, "%s %s %s\n", - sha1_to_hex(old_sha1), - sha1_to_hex(new_sha1), + oid_to_hex(old_oid), + oid_to_hex(new_oid), committer); if (msglen) len += copy_reflog_msg(logrec + len - 1, msg) - 1; @@@@ -2031,8 -2031,8 -2014,8 +2032,8 @@@@ } static int files_log_ref_write(struct files_ref_store *refs, - const char *refname, const unsigned char *old_sha1, - const unsigned char *new_sha1, const char *msg, + const char *refname, const struct object_id *old_oid, + const struct object_id *new_oid, const char *msg, int flags, struct strbuf *err) { int logfd, result; @@@@ -2049,7 -2049,7 -2032,7 +2050,7 @@@@ if (logfd < 0) return 0; - result = log_ref_write_fd(logfd, old_sha1, new_sha1, + result = log_ref_write_fd(logfd, old_oid, new_oid, git_committer_info(0), msg); if (result) { struct strbuf sb = STRBUF_INIT; @@@@ -2081,29 -2081,29 -2064,29 +2082,29 @@@@ * return -1. */ static int write_ref_to_lockfile(struct ref_lock *lock, - const unsigned char *sha1, struct strbuf *err) + const struct object_id *oid, struct strbuf *err) { static char term = '\n'; struct object *o; int fd; - o = parse_object(sha1); + o = parse_object(oid); if (!o) { strbuf_addf(err, "trying to write ref '%s' with nonexistent object %s", - lock->ref_name, sha1_to_hex(sha1)); + lock->ref_name, oid_to_hex(oid)); unlock_ref(lock); return -1; } if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) { strbuf_addf(err, "trying to write non-commit object %s to branch '%s'", - sha1_to_hex(sha1), lock->ref_name); + oid_to_hex(oid), lock->ref_name); unlock_ref(lock); return -1; } fd = get_lock_file_fd(lock->lk); - if (write_in_full(fd, sha1_to_hex(sha1), 40) != 40 || + if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ || write_in_full(fd, &term, 1) != 1 || close_ref(lock) < 0) { strbuf_addf(err, @@@@ -2121,14 -2121,14 -2104,14 +2122,14 @@@@ */ static int commit_ref_update(struct files_ref_store *refs, struct ref_lock *lock, - const unsigned char *sha1, const char *logmsg, + const struct object_id *oid, const char *logmsg, struct strbuf *err) { files_assert_main_repository(refs, "commit_ref_update"); clear_loose_ref_cache(refs); if (files_log_ref_write(refs, lock->ref_name, - lock->old_oid.hash, sha1, + &lock->old_oid, oid, logmsg, 0, err)) { char *old_msg = strbuf_detach(err, NULL); strbuf_addf(err, "cannot update the ref '%s': %s", @@@@ -2151,18 -2151,18 -2134,18 +2152,18 @@@@ * check with HEAD only which should cover 99% of all usage * scenarios (even 100% of the default ones). */ - unsigned char head_sha1[20]; + struct object_id head_oid; int head_flag; const char *head_ref; head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD", RESOLVE_REF_READING, - head_sha1, &head_flag); + head_oid.hash, &head_flag); if (head_ref && (head_flag & REF_ISSYMREF) && !strcmp(head_ref, lock->ref_name)) { struct strbuf log_err = STRBUF_INIT; if (files_log_ref_write(refs, "HEAD", - lock->old_oid.hash, sha1, + &lock->old_oid, oid, logmsg, 0, &log_err)) { error("%s", log_err.buf); strbuf_release(&log_err); @@@@ -2200,12 -2200,12 -2183,12 +2201,12 @@@@ static void update_symref_reflog(struc const char *target, const char *logmsg) { struct strbuf err = STRBUF_INIT; - unsigned char new_sha1[20]; + struct object_id new_oid; if (logmsg && !refs_read_ref_full(&refs->base, target, - RESOLVE_REF_READING, new_sha1, NULL) && - files_log_ref_write(refs, refname, lock->old_oid.hash, - new_sha1, logmsg, 0, &err)) { + RESOLVE_REF_READING, new_oid.hash, NULL) && + files_log_ref_write(refs, refname, &lock->old_oid, + &new_oid, logmsg, 0, &err)) { error("%s", err.buf); strbuf_release(&err); } @@@@ -2258,6 -2258,6 -2241,50 +2259,6 @@@@ static int files_create_symref(struct r return ret; } -int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg) -{ - /* - * FIXME: this obviously will not work well for future refs - * backends. This function needs to die. - */ - struct files_ref_store *refs = - files_downcast(get_main_ref_store(), - REF_STORE_WRITE, - "set_head_symref"); - - static struct lock_file head_lock; - struct ref_lock *lock; - struct strbuf head_path = STRBUF_INIT; - const char *head_rel; - int ret; - - strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir)); - if (hold_lock_file_for_update(&head_lock, head_path.buf, - LOCK_NO_DEREF) < 0) { - struct strbuf err = STRBUF_INIT; - unable_to_lock_message(head_path.buf, errno, &err); - error("%s", err.buf); - strbuf_release(&err); - strbuf_release(&head_path); - return -1; - } - - /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for - linked trees */ - head_rel = remove_leading_path(head_path.buf, - absolute_path(get_git_common_dir())); - /* to make use of create_symref_locked(), initialize ref_lock */ - lock = xcalloc(1, sizeof(struct ref_lock)); - lock->lk = &head_lock; - lock->ref_name = xstrdup(head_rel); - - ret = create_symref_locked(refs, lock, head_rel, target, logmsg); - - unlock_ref(lock); /* will free lock */ - strbuf_release(&head_path); - return ret; -} - static int files_reflog_exists(struct ref_store *ref_store, const char *refname) { @@@@ -2291,7 -2291,7 -2318,7 +2292,7 @@@@ static int show_one_reflog_ent(struct s { struct object_id ooid, noid; char *email_end, *message; - unsigned long timestamp; + timestamp_t timestamp; int tz; const char *p = sb->buf; @@@@ -2301,7 -2301,7 -2328,7 +2302,7 @@@@ parse_oid_hex(p, &noid, &p) || *p++ != ' ' || !(email_end = strchr(p, '>')) || email_end[1] != ' ' || - !(timestamp = strtoul(email_end + 2, &message, 10)) || + !(timestamp = parse_timestamp(email_end + 2, &message, 10)) || !message || message[0] != ' ' || (message[1] != '+' && message[1] != '-') || !isdigit(message[2]) || !isdigit(message[3]) || @@@@ -2551,6 -2551,6 -2578,23 +2552,6 @@@@ static struct ref_iterator *files_reflo return ref_iterator; } -static int ref_update_reject_duplicates(struct string_list *refnames, - struct strbuf *err) -{ - int i, n = refnames->nr; - - assert(err); - - for (i = 1; i < n; i++) - if (!strcmp(refnames->items[i - 1].string, refnames->items[i].string)) { - strbuf_addf(err, - "multiple updates for ref '%s' not allowed.", - refnames->items[i].string); - return 1; - } - return 0; -} - /* * If update is a direct update of head_ref (the reference pointed to * by HEAD), then add an extra REF_LOG_ONLY update for HEAD. @@@@ -2590,7 -2590,7 -2634,7 +2591,7 @@@@ static int split_head_update(struct ref new_update = ref_transaction_add_update( transaction, "HEAD", update->flags | REF_LOG_ONLY | REF_NODEREF, - update->new_sha1, update->old_sha1, + update->new_oid.hash, update->old_oid.hash, update->msg); item->util = new_update; @@@@ -2647,7 -2647,7 -2691,7 +2648,7 @@@@ static int split_symref_update(struct f new_update = ref_transaction_add_update( transaction, referent, new_flags, - update->new_sha1, update->old_sha1, + update->new_oid.hash, update->old_oid.hash, update->msg); new_update->parent_update = update; @@@@ -2686,10 -2686,10 -2730,10 +2687,10 @@@@ static int check_old_oid(struct ref_upd struct strbuf *err) { if (!(update->flags & REF_HAVE_OLD) || - !hashcmp(oid->hash, update->old_sha1)) + !oidcmp(oid, &update->old_oid)) return 0; - if (is_null_sha1(update->old_sha1)) + if (is_null_oid(&update->old_oid)) strbuf_addf(err, "cannot lock ref '%s': " "reference already exists", original_update_refname(update)); @@@@ -2697,13 -2697,13 -2741,13 +2698,13 @@@@ strbuf_addf(err, "cannot lock ref '%s': " "reference is missing but expected %s", original_update_refname(update), - sha1_to_hex(update->old_sha1)); + oid_to_hex(&update->old_oid)); else strbuf_addf(err, "cannot lock ref '%s': " "is at %s but expected %s", original_update_refname(update), oid_to_hex(oid), - sha1_to_hex(update->old_sha1)); + oid_to_hex(&update->old_oid)); return -1; } @@@@ -2730,13 -2730,13 -2774,13 +2731,13 @@@@ static int lock_ref_for_update(struct f { struct strbuf referent = STRBUF_INIT; int mustexist = (update->flags & REF_HAVE_OLD) && - !is_null_sha1(update->old_sha1); + !is_null_oid(&update->old_oid); int ret; struct ref_lock *lock; files_assert_main_repository(refs, "lock_ref_for_update"); - if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) + if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid)) update->flags |= REF_DELETING; if (head_ref) { @@@@ -2818,12 -2818,12 -2862,12 +2819,12 @@@@ !(update->flags & REF_DELETING) && !(update->flags & REF_LOG_ONLY)) { if (!(update->type & REF_ISSYMREF) && - !hashcmp(lock->old_oid.hash, update->new_sha1)) { + !oidcmp(&lock->old_oid, &update->new_oid)) { /* * The reference already has the desired * value, so we don't need to write it. */ - } else if (write_ref_to_lockfile(lock, update->new_sha1, + } else if (write_ref_to_lockfile(lock, &update->new_oid, err)) { char *write_err = strbuf_detach(err, NULL); @@@@ -2856,45 -2856,45 -2900,31 +2857,45 @@@@ return 0; } -static int files_transaction_commit(struct ref_store *ref_store, - struct ref_transaction *transaction, - struct strbuf *err) +/* + * Unlock any references in `transaction` that are still locked, and + * mark the transaction closed. + */ +static void files_transaction_cleanup(struct ref_transaction *transaction) +{ + size_t i; + + for (i = 0; i < transaction->nr; i++) { + struct ref_update *update = transaction->updates[i]; + struct ref_lock *lock = update->backend_data; + + if (lock) { + unlock_ref(lock); + update->backend_data = NULL; + } + } + + transaction->state = REF_TRANSACTION_CLOSED; +} + +static int files_transaction_prepare(struct ref_store *ref_store, + struct ref_transaction *transaction, + struct strbuf *err) { struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_WRITE, - "ref_transaction_commit"); - int ret = 0, i; - struct string_list refs_to_delete = STRING_LIST_INIT_NODUP; - struct string_list_item *ref_to_delete; + "ref_transaction_prepare"); + size_t i; + int ret = 0; struct string_list affected_refnames = STRING_LIST_INIT_NODUP; char *head_ref = NULL; int head_type; struct object_id head_oid; - struct strbuf sb = STRBUF_INIT; assert(err); - if (transaction->state != REF_TRANSACTION_OPEN) - die("BUG: commit called for transaction that is not open"); - - if (!transaction->nr) { - transaction->state = REF_TRANSACTION_CLOSED; - return 0; - } + if (!transaction->nr) + goto cleanup; /* * Fail if a refname appears more than once in the @@@@ -2953,8 -2953,8 -2983,6 +2954,8 @@@@ * that new values are valid, and write new values to the * lockfiles, ready to be activated. Only keep one lockfile * open at a time to avoid running out of file descriptors. + * Note that lock_ref_for_update() might append more updates + * to the transaction. */ for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; @@@@ -2962,38 -2962,38 -2990,7 +2963,38 @@@@ ret = lock_ref_for_update(refs, update, transaction, head_ref, &affected_refnames, err); if (ret) - goto cleanup; + break; + } + +cleanup: + free(head_ref); + string_list_clear(&affected_refnames, 0); + + if (ret) + files_transaction_cleanup(transaction); + else + transaction->state = REF_TRANSACTION_PREPARED; + + return ret; +} + +static int files_transaction_finish(struct ref_store *ref_store, + struct ref_transaction *transaction, + struct strbuf *err) +{ + struct files_ref_store *refs = + files_downcast(ref_store, 0, "ref_transaction_finish"); + size_t i; + int ret = 0; + struct string_list refs_to_delete = STRING_LIST_INIT_NODUP; + struct string_list_item *ref_to_delete; + struct strbuf sb = STRBUF_INIT; + + assert(err); + + if (!transaction->nr) { + transaction->state = REF_TRANSACTION_CLOSED; + return 0; } /* Perform updates first so live commits remain referenced */ @@@@ -3005,8 -3005,8 -3002,8 +3006,8 @@@@ update->flags & REF_LOG_ONLY) { if (files_log_ref_write(refs, lock->ref_name, - lock->old_oid.hash, - update->new_sha1, + &lock->old_oid, + &update->new_oid, update->msg, update->flags, err)) { char *old_msg = strbuf_detach(err, NULL); @@@@ -3073,10 -3073,10 -3070,15 +3074,10 @@@@ clear_loose_ref_cache(refs); cleanup: - strbuf_release(&sb); - transaction->state = REF_TRANSACTION_CLOSED; + files_transaction_cleanup(transaction); for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; - struct ref_lock *lock = update->backend_data; - - if (lock) - unlock_ref(lock); if (update->flags & REF_DELETED_LOOSE) { /* @@@@ -3090,19 -3090,19 -3092,13 +3091,19 @@@@ } } + strbuf_release(&sb); string_list_clear(&refs_to_delete, 0); - free(head_ref); - string_list_clear(&affected_refnames, 0); - return ret; } +static int files_transaction_abort(struct ref_store *ref_store, + struct ref_transaction *transaction, + struct strbuf *err) +{ + files_transaction_cleanup(transaction); + return 0; +} + static int ref_present(const char *refname, const struct object_id *oid, int flags, void *cb_data) { @@@@ -3118,8 -3118,8 -3114,7 +3119,8 @@@@ static int files_initial_transaction_co struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_WRITE, "initial_ref_transaction_commit"); - int ret = 0, i; + size_t i; + int ret = 0; struct string_list affected_refnames = STRING_LIST_INIT_NODUP; assert(err); @@@@ -3157,7 -3157,7 -3152,7 +3158,7 @@@@ struct ref_update *update = transaction->updates[i]; if ((update->flags & REF_HAVE_OLD) && - !is_null_sha1(update->old_sha1)) + !is_null_oid(&update->old_oid)) die("BUG: initial ref transaction with old_sha1 set"); if (refs_verify_refname_available(&refs->base, update->refname, &affected_refnames, NULL, @@@@ -3178,9 -3178,9 -3173,8 +3179,9 @@@@ struct ref_update *update = transaction->updates[i]; if ((update->flags & REF_HAVE_NEW) && - !is_null_sha1(update->new_sha1)) - add_packed_ref(refs, update->refname, update->new_sha1); + !is_null_oid(&update->new_oid)) + add_packed_ref(refs, update->refname, + &update->new_oid); } if (commit_packed_refs(refs)) { @@@@ -3205,7 -3205,7 -3199,7 +3206,7 @@@@ struct expire_reflog_cb }; static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct expire_reflog_cb *cb = cb_data; @@@@ -3214,7 -3214,7 -3208,7 +3215,7 @@@@ if (cb->flags & EXPIRE_REFLOGS_REWRITE) ooid = &cb->last_kept_oid; - if ((*cb->should_prune_fn)(ooid->hash, noid->hash, email, timestamp, tz, + if ((*cb->should_prune_fn)(ooid, noid, email, timestamp, tz, message, policy_cb)) { if (!cb->newlog) printf("would prune %s", message); @@@@ -3222,7 -3222,7 -3216,7 +3223,7 @@@@ printf("prune %s", message); } else { if (cb->newlog) { - fprintf(cb->newlog, "%s %s %s %lu %+05d\t%s", + fprintf(cb->newlog, "%s %s %s %"PRItime" %+05d\t%s", oid_to_hex(ooid), oid_to_hex(noid), email, timestamp, tz, message); oidcpy(&cb->last_kept_oid, noid); @@@@ -3251,7 -3251,7 -3245,6 +3252,7 @@@@ static int files_reflog_expire(struct r int status = 0; int type; struct strbuf err = STRBUF_INIT; + struct object_id oid; memset(&cb, 0, sizeof(cb)); cb.flags = flags; @@@@ -3301,9 -3301,9 -3294,7 +3302,9 @@@@ } } - (*prepare_fn)(refname, sha1, cb.policy_cb); + hashcpy(oid.hash, sha1); + + (*prepare_fn)(refname, &oid, cb.policy_cb); refs_for_each_reflog_ent(ref_store, refname, expire_reflog_ent, &cb); (*cleanup_fn)(cb.policy_cb); @@@@ -3373,9 -3373,9 -3364,7 +3374,9 @@@@ struct ref_storage_be refs_be_files = "files", files_ref_store_create, files_init_db, - files_transaction_commit, + files_transaction_prepare, + files_transaction_finish, + files_transaction_abort, files_initial_transaction_commit, files_pack_refs, diff --combined remote.c index f998f989e9,3649d60cdc,6ef03bb730..d87482573d --- a/remote.c +++ b/remote.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "remote.h" #include "refs.h" #include "commit.h" @@@@ -251,7 -251,7 -252,7 +252,7 @@@@ static const char *skip_spaces(const ch static void read_remotes_file(struct remote *remote) { struct strbuf buf = STRBUF_INIT; -- FILE *f = fopen(git_path("remotes/%s", remote->name), "r"); ++ FILE *f = fopen_or_warn(git_path("remotes/%s", remote->name), "r"); if (!f) return; @@@@ -277,7 -277,7 -278,7 +278,7 @@@@ static void read_branches_file(struct r { char *frag; struct strbuf buf = STRBUF_INIT; -- FILE *f = fopen(git_path("branches/%s", remote->name), "r"); ++ FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r"); if (!f) return; @@@@ -477,6 -477,6 -478,26 +478,6 @@@@ static void read_config(void alias_all_urls(); } -/* - * This function frees a refspec array. - * Warning: code paths should be checked to ensure that the src - * and dst pointers are always freeable pointers as well - * as the refspec pointer itself. - */ -static void free_refspecs(struct refspec *refspec, int nr_refspec) -{ - int i; - - if (!refspec) - return; - - for (i = 0; i < nr_refspec; i++) { - free(refspec[i].src); - free(refspec[i].dst); - } - free(refspec); -} - static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) { int i; @@@@ -590,7 -590,7 -611,7 +591,7 @@@@ * since it is only possible to reach this point from within * the for loop above. */ - free_refspecs(rs, i+1); + free_refspec(i+1, rs); return NULL; } die("Invalid refspec '%s'", refspec[i]); @@@@ -601,7 -601,7 -622,7 +602,7 @@@@ int valid_fetch_refspec(const char *fet struct refspec *refspec; refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1); - free_refspecs(refspec, 1); + free_refspec(1, refspec); return !!refspec; } @@@@ -618,10 -618,10 -639,6 +619,10 @@@@ struct refspec *parse_push_refspec(int void free_refspec(int nr_refspec, struct refspec *refspec) { int i; + + if (!refspec) + return; + for (i = 0; i < nr_refspec; i++) { free(refspec[i].src); free(refspec[i].dst); @@@@ -633,12 -633,12 -650,7 +634,12 @@@@ static int valid_remote_nick(const cha { if (!name[0] || is_dot_or_dotdot(name)) return 0; - return !strchr(name, '/'); /* no slash */ + + /* remote nicknames cannot contain slashes */ + while (*name) + if (is_dir_sep(*name++)) + return 0; + return 1; } const char *remote_for_branch(struct branch *branch, int *explicit) @@@@ -1180,10 -1180,10 -1192,9 +1181,10 @@@@ static int match_explicit(struct ref *s else if (is_null_oid(&matched_src->new_oid)) error("unable to delete '%s': remote ref does not exist", dst_value); - else if ((dst_guess = guess_ref(dst_value, matched_src))) + else if ((dst_guess = guess_ref(dst_value, matched_src))) { matched_dst = make_linked_ref(dst_guess, dst_tail); - else + free(dst_guess); + } else error("unable to push to unqualified destination: %s\n" "The destination refspec neither matches an " "existing ref on the remote nor\n" @@@@ -1286,7 -1286,7 -1297,7 +1287,7 @@@@ static void add_to_tips(struct tips *ti if (is_null_oid(oid)) return; - commit = lookup_commit_reference_gently(oid->hash, 1); + commit = lookup_commit_reference_gently(oid, 1); if (!commit || (commit->object.flags & TMP_MARK)) return; commit->object.flags |= TMP_MARK; @@@@ -1348,8 -1348,8 -1359,7 +1349,8 @@@@ static void add_missing_tags(struct re if (is_null_oid(&ref->new_oid)) continue; - commit = lookup_commit_reference_gently(ref->new_oid.hash, 1); + commit = lookup_commit_reference_gently(&ref->new_oid, + 1); if (!commit) /* not pushing a commit, which is not an error */ continue; @@@@ -1576,8 -1576,8 -1586,8 +1577,8 @@@@ void set_ref_status_for_push(struct re reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS; else if (!has_object_file(&ref->old_oid)) reject_reason = REF_STATUS_REJECT_FETCH_FIRST; - else if (!lookup_commit_reference_gently(ref->old_oid.hash, 1) || - !lookup_commit_reference_gently(ref->new_oid.hash, 1)) + else if (!lookup_commit_reference_gently(&ref->old_oid, 1) || + !lookup_commit_reference_gently(&ref->new_oid, 1)) reject_reason = REF_STATUS_REJECT_NEEDS_FORCE; else if (!ref_newer(&ref->new_oid, &ref->old_oid)) reject_reason = REF_STATUS_REJECT_NONFASTFORWARD; @@@@ -1944,12 -1944,12 -1954,12 +1945,12 @@@@ int ref_newer(const struct object_id *n * Both new and old must be commit-ish and new is descendant of * old. Otherwise we require --force. */ - o = deref_tag(parse_object(old_oid->hash), NULL, 0); + o = deref_tag(parse_object(old_oid), NULL, 0); if (!o || o->type != OBJ_COMMIT) return 0; old = (struct commit *) o; - o = deref_tag(parse_object(new_oid->hash), NULL, 0); + o = deref_tag(parse_object(new_oid), NULL, 0); if (!o || o->type != OBJ_COMMIT) return 0; new = (struct commit *) o; @@@@ -2000,13 -2000,13 -2010,13 +2001,13 @@@@ int stat_tracking_info(struct branch *b /* Cannot stat if what we used to build on no longer exists */ if (read_ref(base, oid.hash)) return -1; - theirs = lookup_commit_reference(oid.hash); + theirs = lookup_commit_reference(&oid); if (!theirs) return -1; if (read_ref(branch->refname, oid.hash)) return -1; - ours = lookup_commit_reference(oid.hash); + ours = lookup_commit_reference(&oid); if (!ours) return -1; diff --combined rerere.c index c26c29f87a,3bd55caf3b,344d6aa818..829b3b0f08 --- a/rerere.c +++ b/rerere.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "string-list.h" #include "rerere.h" @@@@ -200,7 -200,7 -201,7 +201,7 @@@@ static struct rerere_id *new_rerere_id( static void read_rr(struct string_list *rr) { struct strbuf buf = STRBUF_INIT; -- FILE *in = fopen(git_path_merge_rr(), "r"); ++ FILE *in = fopen_or_warn(git_path_merge_rr(), "r"); if (!in) return; @@@@ -484,14 -484,13 -485,13 +485,14 @@@@ static int handle_file(const char *path io.input = fopen(path, "r"); io.io.wrerror = 0; if (!io.input) -- return error("Could not open %s", path); ++ return error_errno("Could not open %s", path); if (output) { io.io.output = fopen(output, "w"); if (!io.io.output) { ++ error_errno("Could not write %s", output); fclose(io.input); -- return error("Could not write %s", output); ++ return -1; } } diff --combined sequencer.c index d63099d50f,924fb1d0c3,7356a93562..224afe79b9 --- a/sequencer.c +++ b/sequencer.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "lockfile.h" #include "sequencer.h" #include "dir.h" @@@@ -344,7 -344,7 -345,7 +345,7 @@@@ static int read_oneliner(struct strbuf static struct tree *empty_tree(void) { - return lookup_tree(EMPTY_TREE_SHA1_BIN); + return lookup_tree(&empty_tree_oid); } static int error_dirty_index(struct replay_opts *opts) @@@@ -374,7 -374,7 -375,7 +375,7 @@@@ static void update_abort_safety_file(vo write_file(git_path_abort_safety_file(), "%s", ""); } -static int fast_forward_to(const unsigned char *to, const unsigned char *from, +static int fast_forward_to(const struct object_id *to, const struct object_id *from, int unborn, struct replay_opts *opts) { struct ref_transaction *transaction; @@@@ -390,7 -390,7 -391,7 +391,7 @@@@ transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, "HEAD", - to, unborn ? null_sha1 : from, + to->hash, unborn ? null_sha1 : from->hash, 0, sb.buf, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); @@@@ -426,7 -426,7 -427,7 +427,7 @@@@ void append_conflicts_hint(struct strbu static int do_recursive_merge(struct commit *base, struct commit *next, const char *base_label, const char *next_label, - unsigned char *head, struct strbuf *msgbuf, + struct object_id *head, struct strbuf *msgbuf, struct replay_opts *opts) { struct merge_options o; @@@@ -464,8 -464,8 -465,7 +465,8 @@@@ if (active_cache_changed && write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) - /* TRANSLATORS: %s will be "revert", "cherry-pick" or + /* + * TRANSLATORS: %s will be "revert", "cherry-pick" or * "rebase -i". */ return error(_("%s: Unable to write new index file"), @@@@ -483,13 -483,13 -483,13 +484,13 @@@@ static int is_index_unchanged(void) { - unsigned char head_sha1[20]; + struct object_id head_oid; struct commit *head_commit; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) return error(_("could not resolve HEAD commit\n")); - head_commit = lookup_commit(head_sha1); + head_commit = lookup_commit(&head_oid); /* * If head_commit is NULL, check_commit, called from @@@@ -509,8 -509,8 -509,7 +510,8 @@@@ if (cache_tree_update(&the_index, 0)) return error(_("unable to update cache tree\n")); - return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash); + return !oidcmp(&active_cache_tree->oid, + &head_commit->tree->object.oid); } static int write_author_script(const char *message) @@@@ -836,13 -836,13 -835,13 +837,13 @@@@ static int update_squash_messages(enum strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len); strbuf_release(&header); } else { - unsigned char head[20]; + struct object_id head; struct commit *head_commit; const char *head_message, *body; - if (get_sha1("HEAD", head)) + if (get_oid("HEAD", &head)) return error(_("need a HEAD to fixup")); - if (!(head_commit = lookup_commit_reference(head))) + if (!(head_commit = lookup_commit_reference(&head))) return error(_("could not read HEAD")); if (!(head_message = get_commit_buffer(head_commit, NULL))) return error(_("could not read HEAD's commit message")); @@@@ -899,8 -899,8 -898,8 +900,8 @@@@ static void flush_rewritten_pending(voi FILE *out; if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), 82) > 0 && -- !get_sha1("HEAD", newsha1) && -- (out = fopen(rebase_path_rewritten_list(), "a"))) { ++ !get_sha1("HEAD", newsha1) && ++ (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) { char *bol = buf.buf, *eol; while (*bol) { @@@@ -919,7 -919,7 -918,7 +920,7 @@@@ static void record_in_rewritten(struct object_id *oid, enum todo_command next_command) { -- FILE *out = fopen(rebase_path_rewritten_pending(), "a"); ++ FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a"); if (!out) return; @@@@ -936,7 -936,7 -935,7 +937,7 @@@@ static int do_pick_commit(enum todo_com { unsigned int flags = opts->edit ? EDIT_MSG : 0; const char *msg_file = opts->edit ? NULL : git_path_merge_msg(); - unsigned char head[20]; + struct object_id head; struct commit *base, *next, *parent; const char *base_label, *next_label; struct commit_message msg = { NULL, NULL, NULL, NULL }; @@@@ -950,12 -950,12 -949,12 +951,12 @@@@ * that represents the "current" state for merge-recursive * to work on. */ - if (write_cache_as_tree(head, 0, NULL)) + if (write_cache_as_tree(head.hash, 0, NULL)) return error(_("your index file is unmerged.")); } else { - unborn = get_sha1("HEAD", head); + unborn = get_oid("HEAD", &head); if (unborn) - hashcpy(head, EMPTY_TREE_SHA1_BIN); + oidcpy(&head, &empty_tree_oid); if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0, 0)) return error_dirty_index(opts); } @@@@ -991,11 -991,11 -990,11 +992,11 @@@@ oid_to_hex(&commit->object.oid)); if (opts->allow_ff && !is_fixup(command) && - ((parent && !hashcmp(parent->object.oid.hash, head)) || + ((parent && !oidcmp(&parent->object.oid, &head)) || (!parent && unborn))) { if (is_rebase_i(opts)) write_author_script(msg.message); - res = fast_forward_to(commit->object.oid.hash, head, unborn, + res = fast_forward_to(&commit->object.oid, &head, unborn, opts); if (res || command != TODO_REWORD) goto leave; @@@@ -1047,7 -1047,7 -1046,6 +1048,7 @@@@ strbuf_addstr(&msgbuf, p); if (opts->record_origin) { + strbuf_complete_line(&msgbuf); if (!has_conforming_footer(&msgbuf, NULL, 0)) strbuf_addch(&msgbuf, '\n'); strbuf_addstr(&msgbuf, cherry_picked_prefix); @@@@ -1083,7 -1083,7 -1081,7 +1084,7 @@@@ res = -1; else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) { res = do_recursive_merge(base, next, base_label, next_label, - head, &msgbuf, opts); + &head, &msgbuf, opts); if (res < 0) return res; res |= write_message(msgbuf.buf, msgbuf.len, @@@@ -1099,7 -1099,7 -1097,7 +1100,7 @@@@ commit_list_insert(next, &remotes); res |= try_merge_command(opts->strategy, opts->xopts_nr, (const char **)opts->xopts, - common, sha1_to_hex(head), remotes); + common, oid_to_hex(&head), remotes); free_commit_list(common); free_commit_list(remotes); } @@@@ -1224,7 -1224,7 -1222,7 +1225,7 @@@@ static struct todo_item *append_new_tod static int parse_insn_line(struct todo_item *item, const char *bol, char *eol) { - unsigned char commit_sha1[20]; + struct object_id commit_oid; char *end_of_object_name; int i, saved, status, padding; @@@@ -1273,7 -1273,7 -1271,7 +1274,7 @@@@ end_of_object_name = (char *) bol + strcspn(bol, " \t\n"); saved = *end_of_object_name; *end_of_object_name = '\0'; - status = get_sha1(bol, commit_sha1); + status = get_oid(bol, &commit_oid); *end_of_object_name = saved; item->arg = end_of_object_name + strspn(end_of_object_name, " \t"); @@@@ -1282,7 -1282,7 -1280,7 +1283,7 @@@@ if (status < 0) return -1; - item->commit = lookup_commit_reference(commit_sha1); + item->commit = lookup_commit_reference(&commit_oid); return !item->commit; } @@@@ -1381,7 -1381,7 -1379,7 +1382,7 @@@@ static int read_populate_todo(struct to if (is_rebase_i(opts)) { struct todo_list done = TODO_LIST_INIT; -- FILE *f = fopen(rebase_path_msgtotal(), "w"); ++ FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w"); if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 && !parse_insn_buffer(done.buf.buf, &done)) @@@@ -1916,13 -1916,13 -1914,11 +1917,13 @@@@ static int apply_autostash(struct repla strbuf_trim(&stash_sha1); child.git_cmd = 1; + child.no_stdout = 1; + child.no_stderr = 1; argv_array_push(&child.args, "stash"); argv_array_push(&child.args, "apply"); argv_array_push(&child.args, stash_sha1.buf); if (!run_command(&child)) - printf(_("Applied autostash.")); + printf(_("Applied autostash.\n")); else { struct child_process store = CHILD_PROCESS_INIT; @@@@ -2093,7 -2093,7 -2089,6 +2094,7 @@@@ cleanup_head_ref res = error(_("could not read orig-head")); goto cleanup_head_ref; } + strbuf_reset(&buf); if (!read_oneliner(&buf, rebase_path_onto(), 0)) { res = error(_("could not read 'onto'")); goto cleanup_head_ref; @@@@ -2130,8 -2130,8 -2125,8 +2131,8 @@@@ if (read_oneliner(&buf, rebase_path_orig_head(), 0) && !get_sha1(buf.buf, orig.hash) && !get_sha1("HEAD", head.hash)) { -- diff_tree_sha1(orig.hash, head.hash, -- "", &log_tree_opt.diffopt); ++ diff_tree_oid(&orig, &head, "", ++ &log_tree_opt.diffopt); log_tree_diff_flush(&log_tree_opt); } } @@@@ -2286,7 -2286,7 -2281,7 +2287,7 @@@@ static int single_pick(struct commit *c int sequencer_pick_revisions(struct replay_opts *opts) { struct todo_list todo_list = TODO_LIST_INIT; - unsigned char sha1[20]; + struct object_id oid; int i, res; assert(opts->revs); @@@@ -2294,16 -2294,16 -2289,16 +2295,16 @@@@ return -1; for (i = 0; i < opts->revs->pending.nr; i++) { - unsigned char sha1[20]; + struct object_id oid; const char *name = opts->revs->pending.objects[i].name; /* This happens when using --stdin. */ if (!strlen(name)) continue; - if (!get_sha1(name, sha1)) { - if (!lookup_commit_reference_gently(sha1, 1)) { - enum object_type type = sha1_object_info(sha1, NULL); + if (!get_oid(name, &oid)) { + if (!lookup_commit_reference_gently(&oid, 1)) { + enum object_type type = sha1_object_info(oid.hash, NULL); return error(_("%s: can't cherry-pick a %s"), name, typename(type)); } @@@@ -2340,9 -2340,9 -2335,9 +2341,9 @@@@ if (walk_revs_populate_todo(&todo_list, opts) || create_seq_dir() < 0) return -1; - if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT)) + if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT)) return error(_("can't revert as initial commit")); - if (save_head(sha1_to_hex(sha1))) + if (save_head(oid_to_hex(&oid))) return -1; if (save_opts(opts)) return -1; @@@@ -2363,9 -2363,9 -2358,6 +2364,9 @@@@ void append_signoff(struct strbuf *msgb getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); + if (!ignore_footer) + strbuf_complete_line(msgbuf); + /* * If the whole message buffer is equal to the sob, pretend that we * found a conforming footer with a matching sob @@@@ -2386,6 -2386,6 -2378,13 +2387,6 @@@@ * the title and body to be filled in by the user. */ append_newlines = "\n\n"; - } else if (msgbuf->buf[len - 1] != '\n') { - /* - * Incomplete line. Complete the line and add a - * blank one so that there is an empty line between - * the message body and the sob. - */ - append_newlines = "\n\n"; } else if (len == 1) { /* * Buffer contains a single newline. Add another diff --combined setup.c index 751d02b9be,e3f7699a90,4e38cf2a4f..358fbc2e53 --- a/setup.c +++ b/setup.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "dir.h" #include "string-list.h" @@@@ -134,27 -134,23 -135,23 +135,27 @@@@ int path_inside_repo(const char *prefix int check_filename(const char *prefix, const char *arg) { -- const char *name; char *to_free = NULL; struct stat st; -- if (starts_with(arg, ":/")) { -- if (arg[2] == '\0') /* ":/" is root dir, always exists */ ++ if (skip_prefix(arg, ":/", &arg)) { ++ if (!*arg) /* ":/" is root dir, always exists */ return 1; -- name = arg + 2; -- } else if (prefix) -- name = to_free = prefix_filename(prefix, arg); -- else -- name = arg; -- if (!lstat(name, &st)) { ++ prefix = NULL; ++ } else if (skip_prefix(arg, ":!", &arg) || ++ skip_prefix(arg, ":^", &arg)) { ++ if (!*arg) /* excluding everything is silly, but allowed */ ++ return 1; ++ } ++ ++ if (prefix) ++ arg = to_free = prefix_filename(prefix, arg); ++ ++ if (!lstat(arg, &st)) { free(to_free); return 1; /* file exists */ } -- if (errno == ENOENT || errno == ENOTDIR) { ++ if (is_missing_file_error(errno)) { free(to_free); return 0; /* file does not exist */ } @@@@ -185,24 -181,6 -182,6 +186,24 @@@@ static void NORETURN die_verify_filenam } ++/* ++ * Check for arguments that don't resolve as actual files, ++ * but which look sufficiently like pathspecs that we'll consider ++ * them such for the purposes of rev/pathspec DWIM parsing. ++ */ ++static int looks_like_pathspec(const char *arg) ++{ ++ /* anything with a wildcard character */ ++ if (!no_wildcard(arg)) ++ return 1; ++ ++ /* long-form pathspec magic */ ++ if (starts_with(arg, ":(")) ++ return 1; ++ ++ return 0; ++} ++ /* * Verify a filename that we got as an argument for a pathspec * entry. Note that a filename that begins with "-" never verifies @@@@ -229,7 -207,7 -208,7 +230,7 @@@@ void verify_filename(const char *prefix { if (*arg == '-') die("bad flag '%s' used after filename", arg); -- if (check_filename(prefix, arg) || !no_wildcard(arg)) ++ if (looks_like_pathspec(arg) || check_filename(prefix, arg)) return; die_verify_filename(prefix, arg, diagnose_misspelt_rev); } @@@@ -725,16 -703,16 -704,11 +726,16 @@@@ static const char *setup_discovered_git /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { + char *to_free = NULL; + const char *ret; + if (offset != cwd->len && !is_absolute_path(gitdir)) - gitdir = real_pathdup(gitdir, 1); + gitdir = to_free = real_pathdup(gitdir, 1); if (chdir(cwd->buf)) die_errno("Could not come back to cwd"); - return setup_explicit_git_dir(gitdir, cwd, nongit_ok); + ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok); + free(to_free); + return ret; } /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */ @@@@ -775,7 -753,7 -749,7 +776,7 @@@@ static const char *setup_bare_git_dir(s /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { - const char *gitdir; + static const char *gitdir; gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset); if (chdir(cwd->buf)) @@@@ -967,19 -945,19 -941,21 +968,21 @@@@ static enum discovery_result setup_git_ } } -- const char *discover_git_directory(struct strbuf *gitdir) ++ int discover_git_directory(struct strbuf *commondir, ++ struct strbuf *gitdir) { struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT; size_t gitdir_offset = gitdir->len, cwd_len; ++ size_t commondir_offset = commondir->len; struct repository_format candidate; if (strbuf_getcwd(&dir)) -- return NULL; ++ return -1; cwd_len = dir.len; if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) { strbuf_release(&dir); -- return NULL; ++ return -1; } /* @@@@ -995,8 -973,8 -971,10 +998,10 @@@@ strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len); } ++ get_common_dir(commondir, gitdir->buf + gitdir_offset); ++ strbuf_reset(&dir); -- strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset); ++ strbuf_addf(&dir, "%s/config", commondir->buf + commondir_offset); read_repository_format(&candidate, dir.buf); strbuf_release(&dir); @@@@ -1004,10 -982,10 -982,12 +1009,12 @@@@ warning("ignoring git dir '%s': %s", gitdir->buf + gitdir_offset, err.buf); strbuf_release(&err); -- return NULL; ++ strbuf_setlen(commondir, commondir_offset); ++ strbuf_setlen(gitdir, gitdir_offset); ++ return -1; } -- return gitdir->buf + gitdir_offset; ++ return 0; } const char *setup_git_directory_gently(int *nongit_ok) diff --combined sha1_file.c index 59a4ed2ed3,feb227a837,44561e0b92..a900b28042 --- a/sha1_file.c +++ b/sha1_file.c @@@@ -7,6 -7,6 -7,7 +7,7 @@@@ * creation etc. */ #include "cache.h" ++ #include "config.h" #include "string-list.h" #include "lockfile.h" #include "delta.h" @@@@ -3546,7 -3546,7 -3547,7 +3547,7 @@@@ static int index_mem(unsigned char *sha */ if ((type == OBJ_BLOB) && path) { struct strbuf nbuf = STRBUF_INIT; - - if (convert_to_git(path, buf, size, &nbuf, + + if (convert_to_git(&the_index, path, buf, size, &nbuf, write_object ? safe_crlf : SAFE_CRLF_FALSE)) { buf = strbuf_detach(&nbuf, &size); re_allocated = 1; @@@@ -3580,7 -3580,7 -3581,7 +3581,7 @@@@ static int index_stream_convert_blob(un assert(path); assert(would_convert_to_git_filter_fd(path)); - - convert_to_git_filter_fd(path, fd, &sbuf, + + convert_to_git_filter_fd(&the_index, path, fd, &sbuf, write_object ? safe_crlf : SAFE_CRLF_FALSE); if (write_object) @@@@ -3668,7 -3668,7 -3669,7 +3669,7 @@@@ int index_fd(unsigned char *sha1, int f else if (!S_ISREG(st->st_mode)) ret = index_pipe(sha1, fd, type, path, flags); else if (st->st_size <= big_file_threshold || type != OBJ_BLOB || - - (path && would_convert_to_git(path))) + + (path && would_convert_to_git(&the_index, path))) ret = index_core(sha1, fd, xsize_t(st->st_size), type, path, flags); else diff --combined sha1_name.c index 5126853bb5,e9ffe685d5,7e1e86c97a..d2d732c19b --- a/sha1_name.c +++ b/sha1_name.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "tag.h" #include "commit.h" #include "tree.h" @@@@ -241,7 -241,7 -242,7 +242,7 @@@@ static int disambiguate_committish_only return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(oid->hash), NULL, 0); + obj = deref_tag(parse_object(oid), NULL, 0); if (obj && obj->type == OBJ_COMMIT) return 1; return 0; @@@@ -265,7 -265,7 -266,7 +266,7 @@@@ static int disambiguate_treeish_only(co return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(oid->hash), NULL, 0); + obj = deref_tag(parse_object(oid), NULL, 0); if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT)) return 1; return 0; @@@@ -354,14 -354,14 -355,14 +355,14 @@@@ static int show_ambiguous_object(const type = sha1_object_info(oid->hash, NULL); if (type == OBJ_COMMIT) { - struct commit *commit = lookup_commit(oid->hash); + struct commit *commit = lookup_commit(oid); if (commit) { struct pretty_print_context pp = {0}; pp.date_mode.type = DATE_SHORT; format_commit_message(commit, " %ad - %s", &desc, &pp); } } else if (type == OBJ_TAG) { - struct tag *tag = lookup_tag(oid->hash); + struct tag *tag = lookup_tag(oid); if (!parse_tag(tag) && tag->tag) strbuf_addf(&desc, " %s", tag->tag); } @@@@ -660,8 -660,8 -661,8 +661,8 @@@@ static int get_sha1_basic(const char *s if (reflog_len) { int nth, i; - unsigned long at_time; - unsigned long co_time; + timestamp_t at_time; + timestamp_t co_time; int co_tz, co_cnt; /* Is it asking for N-th entry, or approxidate? */ @@@@ -722,14 -722,14 -723,14 +723,14 @@@@ static int get_parent(const char *name, int len, unsigned char *result, int idx) { - unsigned char sha1[20]; - int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); + struct object_id oid; + int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH); struct commit *commit; struct commit_list *p; if (ret) return ret; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (parse_commit(commit)) return -1; if (!idx) { @@@@ -750,14 -750,14 -751,14 +751,14 @@@@ static int get_nth_ancestor(const char *name, int len, unsigned char *result, int generation) { - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; int ret; - ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); + ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH); if (ret) return ret; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (!commit) return -1; @@@@ -776,7 -776,7 -777,7 +777,7 @@@@ struct object *peel_to_type(const char if (name && !namelen) namelen = strlen(name); while (1) { - if (!o || (!o->parsed && !parse_object(o->oid.hash))) + if (!o || (!o->parsed && !parse_object(&o->oid))) return NULL; if (expected_type == OBJ_ANY || o->type == expected_type) return o; @@@@ -798,7 -798,7 -799,7 +799,7 @@@@ static int peel_onion(const char *name, int len, unsigned char *sha1, unsigned lookup_flags) { - unsigned char outer[20]; + struct object_id outer; const char *sp; unsigned int expected_type = 0; struct object *o; @@@@ -846,15 -846,15 -847,15 +847,15 @@@@ else if (expected_type == OBJ_TREE) lookup_flags |= GET_SHA1_TREEISH; - if (get_sha1_1(name, sp - name - 2, outer, lookup_flags)) + if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags)) return -1; - o = parse_object(outer); + o = parse_object(&outer); if (!o) return -1; if (!expected_type) { o = deref_tag(o, name, sp - name - 2); - if (!o || (!o->parsed && !parse_object(o->oid.hash))) + if (!o || (!o->parsed && !parse_object(&o->oid))) return -1; hashcpy(sha1, o->oid.hash); return 0; @@@@ -981,7 -981,7 -982,7 +982,7 @@@@ static int handle_one_ref(const char *p int flag, void *cb_data) { struct commit_list **list = cb_data; - struct object *object = parse_object(oid->hash); + struct object *object = parse_object(oid); if (!object) return 0; if (object->type == OBJ_TAG) { @@@@ -1027,7 -1027,7 -1028,7 +1028,7 @@@@ static int get_sha1_oneline(const char int matches; commit = pop_most_recent_commit(&list, ONELINE_SEEN); - if (!parse_object(commit->object.oid.hash)) + if (!parse_object(&commit->object.oid)) continue; buf = get_commit_buffer(commit, NULL); p = strstr(buf, "\n\n"); @@@@ -1054,7 -1054,7 -1055,7 +1055,7 @@@@ struct grab_nth_branch_switch_cbdata }; static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct grab_nth_branch_switch_cbdata *cb = cb_data; @@@@ -1136,13 -1136,13 -1137,13 +1137,13 @@@@ int get_oid_mb(const char *name, struc } if (st) return st; - one = lookup_commit_reference_gently(oid_tmp.hash, 0); + one = lookup_commit_reference_gently(&oid_tmp, 0); if (!one) return -1; if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash)) return -1; - two = lookup_commit_reference_gently(oid_tmp.hash, 0); + two = lookup_commit_reference_gently(&oid_tmp, 0); if (!two) return -1; mbs = get_merge_bases(one, two); @@@@ -1408,7 -1408,7 -1409,7 +1409,7 @@@@ static void diagnose_invalid_sha1_path( if (file_exists(filename)) die("Path '%s' exists on disk, but not in '%.*s'.", filename, object_name_len, object_name); -- if (errno == ENOENT || errno == ENOTDIR) { ++ if (is_missing_file_error(errno)) { char *fullname = xstrfmt("%s%s", prefix, filename); if (!get_tree_entry(tree_sha1, fullname, @@@@ -1473,7 -1473,7 -1474,7 +1474,7 @@@@ static void diagnose_invalid_index_path if (file_exists(filename)) die("Path '%s' exists on disk, but not in the index.", filename); -- if (errno == ENOENT || errno == ENOTDIR) ++ if (is_missing_file_error(errno)) die("Path '%s' does not exist (neither on disk nor in the index).", filename); @@@@ -1511,7 -1511,7 -1512,6 +1512,7 @@@@ static int get_sha1_with_context_1(cons memset(oc, 0, sizeof(*oc)); oc->mode = S_IFINVALID; + strbuf_init(&oc->symlink_path, 0); ret = get_sha1_1(name, namelen, sha1, flags); if (!ret) return ret; @@@@ -1550,8 -1550,8 -1550,7 +1551,8 @@@@ namelen = strlen(cp); } - strlcpy(oc->path, cp, sizeof(oc->path)); + if (flags & GET_SHA1_RECORD_PATH) + oc->path = xstrdup(cp); if (!active_cache) read_cache(); @@@@ -1614,8 -1614,8 -1613,7 +1615,8 @@@@ } } hashcpy(oc->tree, tree_sha1); - strlcpy(oc->path, filename, sizeof(oc->path)); + if (flags & GET_SHA1_RECORD_PATH) + oc->path = xstrdup(filename); free(new_filename); return ret; @@@@ -1641,9 -1641,9 -1639,9 +1642,9 @@@@ void maybe_die_on_misspelt_object_name( get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc); } -int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc) +int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc) { if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE) die("BUG: incompatible flags for get_sha1_with_context"); - return get_sha1_with_context_1(str, flags, NULL, sha1, orc); + return get_sha1_with_context_1(str, flags, NULL, sha1, oc); } diff --combined submodule.c index 1b8a3b575d,bf5a93d16f,8cfcb3bedd..da0b805493 --- a/submodule.c +++ b/submodule.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "submodule-config.h" #include "submodule.h" #include "dir.h" @@@@ -16,12 -16,11 -17,11 +17,12 @@@@ #include "quote.h" #include "remote.h" #include "worktree.h" ++#include "parse-options.h" static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND; --static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT; ++static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF; static int parallel_jobs = 1; -static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP; +static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP; static int initialized_fetch_ref_tips; static struct oid_array ref_tips_before_fetch; static struct oid_array ref_tips_after_fetch; @@@@ -154,8 -153,7 -154,7 +155,8 @@@@ void set_diffopt_flags_from_submodule_c } } --int submodule_config(const char *var, const char *value, void *cb) ++/* For loading from the .gitmodules file. */ ++static int git_modules_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "submodule.fetchjobs")) { parallel_jobs = git_config_int(var, value); @@@@ -171,56 -169,6 -170,6 +172,56 @@@@ return 0; } ++/* Loads all submodule settings from the config. */ ++int submodule_config(const char *var, const char *value, void *cb) ++{ ++ if (!strcmp(var, "submodule.recurse")) { ++ int v = git_config_bool(var, value) ? ++ RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF; ++ config_update_recurse_submodules = v; ++ return 0; ++ } else { ++ return git_modules_config(var, value, cb); ++ } ++} ++ ++/* Cheap function that only determines if we're interested in submodules at all */ ++int git_default_submodule_config(const char *var, const char *value, void *cb) ++{ ++ if (!strcmp(var, "submodule.recurse")) { ++ int v = git_config_bool(var, value) ? ++ RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF; ++ config_update_recurse_submodules = v; ++ } ++ return 0; ++} ++ ++int option_parse_recurse_submodules_worktree_updater(const struct option *opt, ++ const char *arg, int unset) ++{ ++ if (unset) { ++ config_update_recurse_submodules = RECURSE_SUBMODULES_OFF; ++ return 0; ++ } ++ if (arg) ++ config_update_recurse_submodules = ++ parse_update_recurse_submodules_arg(opt->long_name, ++ arg); ++ else ++ config_update_recurse_submodules = RECURSE_SUBMODULES_ON; ++ ++ return 0; ++} ++ ++void load_submodule_cache(void) ++{ ++ if (config_update_recurse_submodules == RECURSE_SUBMODULES_OFF) ++ return; ++ ++ gitmodules_config(); ++ git_config(submodule_config, NULL); ++} ++ void gitmodules_config(void) { const char *work_tree = get_git_work_tree(); @@@@ -248,8 -196,7 -197,7 +249,8 @@@@ } if (!gitmodules_is_unmerged) -- git_config_from_file(submodule_config, gitmodules_path.buf, NULL); ++ git_config_from_file(git_modules_config, ++ gitmodules_path.buf, NULL); strbuf_release(&gitmodules_path); } } @@@@ -260,7 -207,7 -208,7 +261,7 @@@@ void gitmodules_config_sha1(const unsig unsigned char sha1[20]; if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) { -- git_config_from_blob_sha1(submodule_config, rev.buf, ++ git_config_from_blob_sha1(git_modules_config, rev.buf, sha1, NULL); } strbuf_release(&rev); @@@@ -335,69 -282,69 -283,6 +336,69 @@@@ int is_submodule_populated_gently(cons return ret; } +/* + * Dies if the provided 'prefix' corresponds to an unpopulated submodule + */ +void die_in_unpopulated_submodule(const struct index_state *istate, + const char *prefix) +{ + int i, prefixlen; + + if (!prefix) + return; + + prefixlen = strlen(prefix); + + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + int ce_len = ce_namelen(ce); + + if (!S_ISGITLINK(ce->ce_mode)) + continue; + if (prefixlen <= ce_len) + continue; + if (strncmp(ce->name, prefix, ce_len)) + continue; + if (prefix[ce_len] != '/') + continue; + + die(_("in unpopulated submodule '%s'"), ce->name); + } +} + +/* + * Dies if any paths in the provided pathspec descends into a submodule + */ +void die_path_inside_submodule(const struct index_state *istate, + const struct pathspec *ps) +{ + int i, j; + + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + int ce_len = ce_namelen(ce); + + if (!S_ISGITLINK(ce->ce_mode)) + continue; + + for (j = 0; j < ps->nr ; j++) { + const struct pathspec_item *item = &ps->items[j]; + + if (item->len <= ce_len) + continue; + if (item->match[ce_len] != '/') + continue; + if (strncmp(ce->name, item->match, ce_len)) + continue; + if (item->len == ce_len + 1) + continue; + + die(_("Pathspec '%s' is in submodule '%.*s'"), + item->original, ce_len, ce->name); + } + } +} + int parse_submodule_update_strategy(const char *value, struct submodule_update_strategy *dst) { @@@@ -563,8 -510,8 -448,8 +564,8 @@@@ static void show_submodule_header(FILE * Attempt to lookup the commit references, and determine if this is * a fast forward or fast backwards update. */ - *left = lookup_commit_reference(one->hash); - *right = lookup_commit_reference(two->hash); + *left = lookup_commit_reference(one); + *right = lookup_commit_reference(two); /* * Warn about missing commits in the submodule project, but only if @@@@ -670,8 -617,8 -555,7 +671,8 @@@@ void show_submodule_inline_diff(FILE *f cp.no_stdin = 1; /* TODO: other options may need to be passed here. */ - argv_array_push(&cp.args, "diff"); + argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL); + argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix); if (DIFF_OPT_TST(o, REVERSE_DIFF)) { argv_array_pushf(&cp.args, "--src-prefix=%s%s/", @@@@ -713,6 -660,11 -597,11 +714,6 @@@@ void set_config_fetch_recurse_submodule config_fetch_recurse_submodules = value; } --void set_config_update_recurse_submodules(int value) --{ -- config_update_recurse_submodules = value; --} -- int should_update_submodules(void) { return config_update_recurse_submodules == RECURSE_SUBMODULES_ON; @@@@ -729,94 -681,94 -618,6 +730,94 @@@@ const struct submodule *submodule_from_ return submodule_from_path(null_sha1, ce->name); } +static struct oid_array *submodule_commits(struct string_list *submodules, + const char *path) +{ + struct string_list_item *item; + + item = string_list_insert(submodules, path); + if (item->util) + return (struct oid_array *) item->util; + + /* NEEDSWORK: should we have oid_array_init()? */ + item->util = xcalloc(1, sizeof(struct oid_array)); + return (struct oid_array *) item->util; +} + +static void collect_changed_submodules_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) +{ + int i; + struct string_list *changed = data; + + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + struct oid_array *commits; + if (!S_ISGITLINK(p->two->mode)) + continue; + + if (S_ISGITLINK(p->one->mode)) { + /* + * NEEDSWORK: We should honor the name configured in + * the .gitmodules file of the commit we are examining + * here to be able to correctly follow submodules + * being moved around. + */ + commits = submodule_commits(changed, p->two->path); + oid_array_append(commits, &p->two->oid); + } else { + /* Submodule is new or was moved here */ + /* + * NEEDSWORK: When the .git directories of submodules + * live inside the superprojects .git directory some + * day we should fetch new submodules directly into + * that location too when config or options request + * that so they can be checked out from there. + */ + continue; + } + } +} + +/* + * Collect the paths of submodules in 'changed' which have changed based on + * the revisions as specified in 'argv'. Each entry in 'changed' will also + * have a corresponding 'struct oid_array' (in the 'util' field) which lists + * what the submodule pointers were updated to during the change. + */ +static void collect_changed_submodules(struct string_list *changed, + struct argv_array *argv) +{ + struct rev_info rev; + const struct commit *commit; + + init_revisions(&rev, NULL); + setup_revisions(argv->argc, argv->argv, &rev, NULL); + if (prepare_revision_walk(&rev)) + die("revision walk setup failed"); + + while ((commit = get_revision(&rev))) { + struct rev_info diff_rev; + + init_revisions(&diff_rev, NULL); + diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; + diff_rev.diffopt.format_callback = collect_changed_submodules_cb; + diff_rev.diffopt.format_callback_data = changed; + diff_tree_combined_merge(commit, 1, &diff_rev); + } + + reset_revision_walk(); +} + +static void free_submodules_oids(struct string_list *submodules) +{ + struct string_list_item *item; + for_each_string_list_item(item, submodules) + oid_array_clear((struct oid_array *) item->util); + string_list_clear(submodules, 1); +} + static int has_remote(const char *refname, const struct object_id *oid, int flags, void *cb_data) { @@@@ -834,7 -786,7 -635,7 +835,7 @@@@ static int check_has_commit(const struc { int *has_commit = data; - if (!lookup_commit_reference(oid->hash)) + if (!lookup_commit_reference(oid)) *has_commit = 0; return 0; @@@@ -844,44 -796,44 -645,10 +845,44 @@@@ static int submodule_has_commits(const { int has_commit = 1; + /* + * Perform a cheap, but incorrect check for the existance of 'commits'. + * This is done by adding the submodule's object store to the in-core + * object store, and then querying for each commit's existance. If we + * do not have the commit object anywhere, there is no chance we have + * it in the object store of the correct submodule and have it + * reachable from a ref, so we can fail early without spawning rev-list + * which is expensive. + */ if (add_submodule_odb(path)) return 0; oid_array_for_each_unique(commits, check_has_commit, &has_commit); + + if (has_commit) { + /* + * Even if the submodule is checked out and the commit is + * present, make sure it exists in the submodule's object store + * and that it is reachable from a ref. + */ + struct child_process cp = CHILD_PROCESS_INIT; + struct strbuf out = STRBUF_INIT; + + argv_array_pushl(&cp.args, "rev-list", "-n", "1", NULL); + oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args); + argv_array_pushl(&cp.args, "--not", "--all", NULL); + + prepare_submodule_repo_env(&cp.env_array); + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; + + if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len) + has_commit = 0; + + strbuf_release(&out); + } + return has_commit; } @@@@ -929,31 -881,31 -696,91 +930,31 @@@@ static int submodule_needs_pushing(cons return 0; } -static struct oid_array *submodule_commits(struct string_list *submodules, - const char *path) -{ - struct string_list_item *item; - - item = string_list_insert(submodules, path); - if (item->util) - return (struct oid_array *) item->util; - - /* NEEDSWORK: should we have oid_array_init()? */ - item->util = xcalloc(1, sizeof(struct oid_array)); - return (struct oid_array *) item->util; -} - -static void collect_submodules_from_diff(struct diff_queue_struct *q, - struct diff_options *options, - void *data) -{ - int i; - struct string_list *submodules = data; - - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - struct oid_array *commits; - if (!S_ISGITLINK(p->two->mode)) - continue; - commits = submodule_commits(submodules, p->two->path); - oid_array_append(commits, &p->two->oid); - } -} - -static void find_unpushed_submodule_commits(struct commit *commit, - struct string_list *needs_pushing) -{ - struct rev_info rev; - - init_revisions(&rev, NULL); - rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = collect_submodules_from_diff; - rev.diffopt.format_callback_data = needs_pushing; - diff_tree_combined_merge(commit, 1, &rev); -} - -static void free_submodules_sha1s(struct string_list *submodules) -{ - struct string_list_item *item; - for_each_string_list_item(item, submodules) - oid_array_clear((struct oid_array *) item->util); - string_list_clear(submodules, 1); -} - int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing) { - struct rev_info rev; - struct commit *commit; struct string_list submodules = STRING_LIST_INIT_DUP; struct string_list_item *submodule; struct argv_array argv = ARGV_ARRAY_INIT; - init_revisions(&rev, NULL); - /* argv.argv[0] will be ignored by setup_revisions */ argv_array_push(&argv, "find_unpushed_submodules"); oid_array_for_each_unique(commits, append_oid_to_argv, &argv); argv_array_push(&argv, "--not"); argv_array_pushf(&argv, "--remotes=%s", remotes_name); - setup_revisions(argv.argc, argv.argv, &rev, NULL); - if (prepare_revision_walk(&rev)) - die("revision walk setup failed"); - - while ((commit = get_revision(&rev)) != NULL) - find_unpushed_submodule_commits(commit, &submodules); - - reset_revision_walk(); - argv_array_clear(&argv); + collect_changed_submodules(&submodules, &argv); for_each_string_list_item(submodule, &submodules) { - struct oid_array *commits = (struct oid_array *) submodule->util; + struct oid_array *commits = submodule->util; + const char *path = submodule->string; - if (submodule_needs_pushing(submodule->string, commits)) - string_list_insert(needs_pushing, submodule->string); + if (submodule_needs_pushing(path, commits)) + string_list_insert(needs_pushing, path); } - free_submodules_sha1s(&submodules); + + free_submodules_oids(&submodules); + argv_array_clear(&argv); return needs_pushing->nr; } @@@@ -1070,56 -1022,56 -897,125 +1071,56 @@@@ int push_unpushed_submodules(struct oid return ret; } -static int is_submodule_commit_present(const char *path, unsigned char sha1[20]) -{ - int is_present = 0; - if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) { - /* Even if the submodule is checked out and the commit is - * present, make sure it is reachable from a ref. */ - struct child_process cp = CHILD_PROCESS_INIT; - const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL}; - struct strbuf buf = STRBUF_INIT; - - argv[3] = sha1_to_hex(sha1); - cp.argv = argv; - prepare_submodule_repo_env(&cp.env_array); - cp.git_cmd = 1; - cp.no_stdin = 1; - cp.dir = path; - if (!capture_command(&cp, &buf, 1024) && !buf.len) - is_present = 1; - - strbuf_release(&buf); - } - return is_present; -} - -static void submodule_collect_changed_cb(struct diff_queue_struct *q, - struct diff_options *options, - void *data) -{ - int i; - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - if (!S_ISGITLINK(p->two->mode)) - continue; - - if (S_ISGITLINK(p->one->mode)) { - /* NEEDSWORK: We should honor the name configured in - * the .gitmodules file of the commit we are examining - * here to be able to correctly follow submodules - * being moved around. */ - struct string_list_item *path; - path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path); - if (!path && !is_submodule_commit_present(p->two->path, p->two->oid.hash)) - string_list_append(&changed_submodule_paths, xstrdup(p->two->path)); - } else { - /* Submodule is new or was moved here */ - /* NEEDSWORK: When the .git directories of submodules - * live inside the superprojects .git directory some - * day we should fetch new submodules directly into - * that location too when config or options request - * that so they can be checked out from there. */ - continue; - } - } -} - -static int add_sha1_to_array(const char *ref, const struct object_id *oid, - int flags, void *data) +static int append_oid_to_array(const char *ref, const struct object_id *oid, + int flags, void *data) { - oid_array_append(data, oid); + struct oid_array *array = data; + oid_array_append(array, oid); return 0; } void check_for_new_submodule_commits(struct object_id *oid) { if (!initialized_fetch_ref_tips) { - for_each_ref(add_sha1_to_array, &ref_tips_before_fetch); + for_each_ref(append_oid_to_array, &ref_tips_before_fetch); initialized_fetch_ref_tips = 1; } oid_array_append(&ref_tips_after_fetch, oid); } -static int add_oid_to_argv(const struct object_id *oid, void *data) -{ - argv_array_push(data, oid_to_hex(oid)); - return 0; -} - static void calculate_changed_submodule_paths(void) { - struct rev_info rev; - struct commit *commit; struct argv_array argv = ARGV_ARRAY_INIT; + struct string_list changed_submodules = STRING_LIST_INIT_DUP; + const struct string_list_item *item; /* No need to check if there are no submodules configured */ if (!submodule_from_path(NULL, NULL)) return; - init_revisions(&rev, NULL); argv_array_push(&argv, "--"); /* argv[0] program name */ oid_array_for_each_unique(&ref_tips_after_fetch, - add_oid_to_argv, &argv); + append_oid_to_argv, &argv); argv_array_push(&argv, "--not"); oid_array_for_each_unique(&ref_tips_before_fetch, - add_oid_to_argv, &argv); - setup_revisions(argv.argc, argv.argv, &rev, NULL); - if (prepare_revision_walk(&rev)) - die("revision walk setup failed"); + append_oid_to_argv, &argv); /* * Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_paths". */ - while ((commit = get_revision(&rev))) { - struct commit_list *parent = commit->parents; - while (parent) { - struct diff_options diff_opts; - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.output_format |= DIFF_FORMAT_CALLBACK; - diff_opts.format_callback = submodule_collect_changed_cb; - diff_setup_done(&diff_opts); - diff_tree_sha1(parent->item->object.oid.hash, commit->object.oid.hash, "", &diff_opts); - diffcore_std(&diff_opts); - diff_flush(&diff_opts); - parent = parent->next; - } + collect_changed_submodules(&changed_submodules, &argv); + + for_each_string_list_item(item, &changed_submodules) { + struct oid_array *commits = item->util; + const char *path = item->string; + + if (!submodule_has_commits(path, commits)) + string_list_append(&changed_submodule_paths, path); } + free_submodules_oids(&changed_submodules); argv_array_clear(&argv); oid_array_clear(&ref_tips_before_fetch); oid_array_clear(&ref_tips_after_fetch); @@@@ -1468,7 -1420,7 -1364,7 +1469,7 @@@@ static int submodule_has_dirty_index(co { struct child_process cp = CHILD_PROCESS_INIT; - prepare_submodule_repo_env_no_git_dir(&cp.env_array); + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; argv_array_pushl(&cp.args, "diff-index", "--quiet", @@@@ -1485,7 -1437,7 -1381,7 +1486,7 @@@@ static void submodule_reset_index(const char *path) { struct child_process cp = CHILD_PROCESS_INIT; - prepare_submodule_repo_env_no_git_dir(&cp.env_array); + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; @@@@ -1514,23 -1466,23 -1410,6 +1515,23 @@@@ int submodule_move_head(const char *pat int ret = 0; struct child_process cp = CHILD_PROCESS_INIT; const struct submodule *sub; + int *error_code_ptr, error_code; + + if (!is_submodule_initialized(path)) + return 0; + + if (flags & SUBMODULE_MOVE_HEAD_FORCE) + /* + * Pass non NULL pointer to is_submodule_populated_gently + * to prevent die()-ing. We'll use connect_work_tree_and_git_dir + * to fixup the submodule in the force case later. + */ + error_code_ptr = &error_code; + else + error_code_ptr = NULL; + + if (old && !is_submodule_populated_gently(path, error_code_ptr)) + return 0; sub = submodule_from_path(null_sha1, path); @@@@ -1549,24 -1501,24 -1428,18 +1550,24 @@@@ absorb_git_dir_into_superproject("", path, ABSORB_GITDIR_RECURSE_SUBMODULES); } else { - struct strbuf sb = STRBUF_INIT; - strbuf_addf(&sb, "%s/modules/%s", + char *gitdir = xstrfmt("%s/modules/%s", get_git_common_dir(), sub->name); - connect_work_tree_and_git_dir(path, sb.buf); - strbuf_release(&sb); + connect_work_tree_and_git_dir(path, gitdir); + free(gitdir); /* make sure the index is clean as well */ submodule_reset_index(path); } + + if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) { + char *gitdir = xstrfmt("%s/modules/%s", + get_git_common_dir(), sub->name); + connect_work_tree_and_git_dir(path, gitdir); + free(gitdir); + } } - prepare_submodule_repo_env_no_git_dir(&cp.env_array); + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; @@@@ -1574,7 -1526,7 -1447,7 +1575,7 @@@@ argv_array_pushf(&cp.args, "--super-prefix=%s%s/", get_super_prefix_or_empty(), path); - argv_array_pushl(&cp.args, "read-tree", NULL); + argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL); if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN) argv_array_push(&cp.args, "-n"); @@@@ -1596,16 -1548,16 -1469,15 +1597,16 @@@@ if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) { if (new) { - struct child_process cp1 = CHILD_PROCESS_INIT; + child_process_init(&cp); /* also set the HEAD accordingly */ - cp1.git_cmd = 1; - cp1.no_stdin = 1; - cp1.dir = path; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; - argv_array_pushl(&cp1.args, "update-ref", "HEAD", new, NULL); + prepare_submodule_repo_env(&cp.env_array); + argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL); - if (run_command(&cp1)) { + if (run_command(&cp)) { ret = -1; goto out; } @@@@ -1695,9 -1647,9 -1567,9 +1696,9 @@@@ static void print_commit(struct commit #define MERGE_WARNING(path, msg) \ warning("Failed to merge submodule %s (%s)", path, msg); -int merge_submodule(unsigned char result[20], const char *path, - const unsigned char base[20], const unsigned char a[20], - const unsigned char b[20], int search) +int merge_submodule(struct object_id *result, const char *path, + const struct object_id *base, const struct object_id *a, + const struct object_id *b, int search) { struct commit *commit_base, *commit_a, *commit_b; int parent_count; @@@@ -1706,14 -1658,14 -1578,14 +1707,14 @@@@ int i; /* store a in result in case we fail */ - hashcpy(result, a); + oidcpy(result, a); /* we can not handle deletion conflicts */ - if (is_null_sha1(base)) + if (is_null_oid(base)) return 0; - if (is_null_sha1(a)) + if (is_null_oid(a)) return 0; - if (is_null_sha1(b)) + if (is_null_oid(b)) return 0; if (add_submodule_odb(path)) { @@@@ -1737,11 -1689,11 -1609,11 +1738,11 @@@@ /* Case #1: a is contained in b or vice versa */ if (in_merge_bases(commit_a, commit_b)) { - hashcpy(result, b); + oidcpy(result, b); return 1; } if (in_merge_bases(commit_b, commit_a)) { - hashcpy(result, a); + oidcpy(result, a); return 1; } diff --combined t/t1300-repo-config.sh index 13b7851f7c,13b7851f7c,f664bfc671..a37ef04222 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@@@ -703,6 -703,6 -703,12 +703,12 @@@@ test_expect_success 'invalid unit' test_i18ngrep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual ' ++ test_expect_success 'line number is reported correctly' ' ++ printf "[bool]\n\tvar\n" >invalid && ++ test_must_fail git config -f invalid --path bool.var 2>actual && ++ test_i18ngrep "line 2" actual ++ ' ++ test_expect_success 'invalid stdin config' ' echo "[broken" | test_must_fail git config --list --file - >output 2>&1 && test_i18ngrep "bad config line 1 in standard input" output @@@@ -1539,10 -1539,10 -1545,4 +1545,10 @@@@ test_expect_success !MINGW '--show-orig test_cmp expect output ' +test_expect_success '--local requires a repo' ' + # we expect 128 to ensure that we do not simply + # fail to find anything and return code "1" + test_expect_code 128 nongit git config --local foo.bar +' + test_done diff --combined t/t1308-config-set.sh index e495a61616,ff50960cca,69a0aa56d6..bafed5c9b8 --- a/t/t1308-config-set.sh +++ b/t/t1308-config-set.sh @@@@ -183,22 -183,11 -183,11 +183,22 @@@@ test_expect_success 'proper error on no test_cmp expect actual ' ++test_expect_success 'proper error on directory "files"' ' ++ echo "Error (-1) reading configuration file a-directory." >expect && ++ mkdir a-directory && ++ test_expect_code 2 test-config configset_get_value foo.bar a-directory 2>output && ++ grep "^warning:" output && ++ grep "^Error" output >actual && ++ test_cmp expect actual ++' ++ test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' ' chmod -r .git/config && test_when_finished "chmod +r .git/config" && echo "Error (-1) reading configuration file .git/config." >expect && -- test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>actual && ++ test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>output && ++ grep "^warning:" output && ++ grep "^Error" output >actual && test_cmp expect actual ' @@@@ -226,7 -215,7 -215,9 +226,9 @@@@ test_expect_success 'check line errors br EOF test_expect_code 128 git br 2>result && -- test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result ++ test_i18ngrep "missing value for .alias\.br" result && ++ test_i18ngrep "fatal: .*\.git/config" result && ++ test_i18ngrep "fatal: .*line 2" result ' test_expect_success 'error on modifying repo config without repo' ' diff --combined transport.c index 9bfcf870f9,9bfcf870f9,6096f82586..b9995306f2 --- a/transport.c +++ b/transport.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "transport.h" #include "run-command.h" #include "pkt-line.h" @@@@ -87,7 -87,7 -88,7 +88,7 @@@@ static struct ref *get_refs_from_bundle for (i = 0; i < data->header.references.nr; i++) { struct ref_list_entry *e = data->header.references.list + i; struct ref *ref = alloc_ref(e->name); - hashcpy(ref->old_oid.hash, e->sha1); + oidcpy(&ref->old_oid, &e->oid); ref->next = result; result = ref; } diff --combined unpack-trees.c index d38c37e38c,d38c37e38c,e7b5a21ef7..dd535bc849 --- a/unpack-trees.c +++ b/unpack-trees.c @@@@ -1,5 -1,5 -1,6 +1,6 @@@@ #define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" ++ #include "config.h" #include "dir.h" #include "tree.h" #include "tree-walk.h" @@@@ -252,18 -252,18 -253,14 +253,18 @@@@ static int check_submodule_move_head(co const char *new_id, struct unpack_trees_options *o) { + unsigned flags = SUBMODULE_MOVE_HEAD_DRY_RUN; const struct submodule *sub = submodule_from_ce(ce); if (!sub) return 0; + if (o->reset) + flags |= SUBMODULE_MOVE_HEAD_FORCE; + switch (sub->update_strategy.type) { case SM_UPDATE_UNSPECIFIED: case SM_UPDATE_CHECKOUT: - if (submodule_move_head(ce->name, old_id, new_id, SUBMODULE_MOVE_HEAD_DRY_RUN)) + if (submodule_move_head(ce->name, old_id, new_id, flags)) return o->gently ? -1 : add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name); return 0; @@@@ -312,7 -312,7 -309,6 +313,7 @@@@ static void unlink_entry(const struct c case SM_UPDATE_CHECKOUT: case SM_UPDATE_REBASE: case SM_UPDATE_MERGE: + /* state.force is set at the caller. */ submodule_move_head(ce->name, "HEAD", NULL, SUBMODULE_MOVE_HEAD_FORCE); break; @@@@ -1073,7 -1073,7 -1069,7 +1074,7 @@@@ static int clear_ce_flags_dir(struct ca struct cache_entry **cache_end; int dtype = DT_DIR; int ret = is_excluded_from_list(prefix->buf, prefix->len, - basename, &dtype, el); + basename, &dtype, el, &the_index); int rc; strbuf_addch(prefix, '/'); @@@@ -1176,7 -1176,7 -1172,7 +1177,7 @@@@ static int clear_ce_flags_1(struct cach /* Non-directory */ dtype = ce_to_dtype(ce); ret = is_excluded_from_list(ce->name, ce_namelen(ce), - name, &dtype, el); + name, &dtype, el, &the_index); if (ret < 0) ret = defval; if (ret > 0) @@@@ -1256,7 -1256,7 -1252,7 +1257,7 @@@@ int unpack_trees(unsigned len, struct t o->skip_sparse_checkout = 1; if (!o->skip_sparse_checkout) { char *sparse = git_pathdup("info/sparse-checkout"); - if (add_excludes_from_file_to_list(sparse, "", 0, &el, 0) < 0) + if (add_excludes_from_file_to_list(sparse, "", 0, &el, NULL) < 0) o->skip_sparse_checkout = 1; else o->el = ⪙ @@@@ -1396,7 -1396,7 -1392,6 +1397,7 @@@@ WRITE_TREE_SILENT | WRITE_TREE_REPAIR); } + move_index_extensions(&o->result, o->dst_index); discard_index(o->dst_index); *o->dst_index = o->result; } else { @@@@ -1598,7 -1598,7 -1593,7 +1599,7 @@@@ static int verify_clean_subdirectory(co memset(&d, 0, sizeof(d)); if (o->dir) d.exclude_per_dir = o->dir->exclude_per_dir; - i = read_directory(&d, pathbuf, namelen+1, NULL); + i = read_directory(&d, &the_index, pathbuf, namelen+1, NULL); if (i) return o->gently ? -1 : add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name); @@@@ -1640,7 -1640,7 -1635,7 +1641,7 @@@@ static int check_ok_to_remove(const cha return 0; if (o->dir && - is_excluded(o->dir, name, &dtype)) + is_excluded(o->dir, &the_index, name, &dtype)) /* * ce->name is explicitly excluded, so it is Ok to * overwrite it. diff --combined upload-pack.c index 5330c02c14,5330c02c14,7581a51960..7efff2fbfd --- a/upload-pack.c +++ b/upload-pack.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "refs.h" #include "pkt-line.h" #include "sideband.h" @@@@ -35,7 -35,7 -36,7 +36,7 @@@@ static const char * const upload_pack_u #define CLIENT_SHALLOW (1u << 18) #define HIDDEN_REF (1u << 19) -static unsigned long oldest_have; +static timestamp_t oldest_have; static int deepen_relative; static int multi_ack; @@@@ -286,19 -286,19 -287,19 +287,19 @@@@ static void create_pack_file(void die("git upload-pack: %s", abort_msg); } -static int got_sha1(const char *hex, unsigned char *sha1) +static int got_oid(const char *hex, struct object_id *oid) { struct object *o; int we_knew_they_have = 0; - if (get_sha1_hex(hex, sha1)) + if (get_oid_hex(hex, oid)) die("git upload-pack: expected SHA1 object, got '%s'", hex); - if (!has_sha1_file(sha1)) + if (!has_object_file(oid)) return -1; - o = parse_object(sha1); + o = parse_object(oid); if (!o) - die("oops (%s)", sha1_to_hex(sha1)); + die("oops (%s)", oid_to_hex(oid)); if (o->type == OBJ_COMMIT) { struct commit_list *parents; struct commit *commit = (struct commit *)o; @@@@ -334,7 -334,7 -335,7 +335,7 @@@@ static int reachable(struct commit *wan break; } if (!commit->object.parsed) - parse_object(commit->object.oid.hash); + parse_object(&commit->object.oid); if (commit->object.flags & REACHABLE) continue; commit->object.flags |= REACHABLE; @@@@ -382,8 -382,8 -383,8 +383,8 @@@@ static int ok_to_give_up(void static int get_common_commits(void) { - unsigned char sha1[20]; - char last_hex[41]; + struct object_id oid; + char last_hex[GIT_MAX_HEXSZ + 1]; int got_common = 0; int got_other = 0; int sent_ready = 0; @@@@ -416,11 -416,11 -417,11 +417,11 @@@@ continue; } if (skip_prefix(line, "have ", &arg)) { - switch (got_sha1(arg, sha1)) { + switch (got_oid(arg, &oid)) { case -1: /* they have what we do not */ got_other = 1; if (multi_ack && ok_to_give_up()) { - const char *hex = sha1_to_hex(sha1); + const char *hex = oid_to_hex(&oid); if (multi_ack == 2) { sent_ready = 1; packet_write_fmt(1, "ACK %s ready\n", hex); @@@@ -430,7 -430,7 -431,7 +431,7 @@@@ break; default: got_common = 1; - memcpy(last_hex, sha1_to_hex(sha1), 41); + memcpy(last_hex, oid_to_hex(&oid), 41); if (multi_ack == 2) packet_write_fmt(1, "ACK %s common\n", last_hex); else if (multi_ack) @@@@ -492,7 -492,7 -493,7 +493,7 @@@@ static int do_reachable_revlist(struct goto error; namebuf[0] = '^'; - namebuf[41] = '\n'; + namebuf[GIT_SHA1_HEXSZ + 1] = '\n'; for (i = get_max_object_index(); 0 < i; ) { o = get_indexed_object(--i); if (!o) @@@@ -502,10 -502,10 -503,10 +503,10 @@@@ if (!is_our_ref(o)) continue; memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ); - if (write_in_full(cmd->in, namebuf, 42) < 0) + if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 2) < 0) goto error; } - namebuf[40] = '\n'; + namebuf[GIT_SHA1_HEXSZ] = '\n'; for (i = 0; i < src->nr; i++) { o = src->objects[i].item; if (is_our_ref(o)) { @@@@ -516,7 -516,7 -517,7 +517,7 @@@@ if (reachable && o->type == OBJ_COMMIT) o->flags |= TMP_MARK; memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ); - if (write_in_full(cmd->in, namebuf, 41) < 0) + if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 1) < 0) goto error; } close(cmd->in); @@@@ -642,7 -642,7 -643,7 +643,7 @@@@ static void send_shallow(struct commit_ if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write_fmt(1, "shallow %s", oid_to_hex(&object->oid)); - register_shallow(object->oid.hash); + register_shallow(&object->oid); shallow_nr++; } result = result->next; @@@@ -667,7 -667,7 -668,7 +668,7 @@@@ static void send_unshallow(const struc * parse and add the parents to the want list, then * re-register it. */ - unregister_shallow(object->oid.hash); + unregister_shallow(&object->oid); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; @@@@ -679,7 -679,7 -680,7 +680,7 @@@@ add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ - register_shallow(object->oid.hash); + register_shallow(&object->oid); } } @@@@ -735,14 -735,14 -736,14 +736,14 @@@@ static void receive_needs(void struct string_list deepen_not = STRING_LIST_INIT_DUP; int depth = 0; int has_non_tip = 0; - unsigned long deepen_since = 0; + timestamp_t deepen_since = 0; int deepen_rev_list = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; - unsigned char sha1_buf[20]; + struct object_id oid_buf; char *line = packet_read_line(0, NULL); const char *arg; @@@@ -751,15 -751,15 -752,15 +752,15 @@@@ break; if (skip_prefix(line, "shallow ", &arg)) { - unsigned char sha1[20]; + struct object_id oid; struct object *object; - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die("invalid shallow line: %s", line); - object = parse_object(sha1); + object = parse_object(&oid); if (!object) continue; if (object->type != OBJ_COMMIT) - die("invalid shallow object %s", sha1_to_hex(sha1)); + die("invalid shallow object %s", oid_to_hex(&oid)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); @@@@ -775,7 -775,7 -776,7 +776,7 @@@@ } if (skip_prefix(line, "deepen-since ", &arg)) { char *end = NULL; - deepen_since = strtoul(arg, &end, 0); + deepen_since = parse_timestamp(arg, &end, 0); if (!end || *end || !deepen_since || /* revisions.c's max_age -1 is special */ deepen_since == -1) @@@@ -785,8 -785,8 -786,8 +786,8 @@@@ } if (skip_prefix(line, "deepen-not ", &arg)) { char *ref = NULL; - unsigned char sha1[20]; - if (expand_ref(arg, strlen(arg), sha1, &ref) != 1) + struct object_id oid; + if (expand_ref(arg, strlen(arg), oid.hash, &ref) != 1) die("git upload-pack: ambiguous deepen-not: %s", line); string_list_append(&deepen_not, ref); free(ref); @@@@ -794,7 -794,7 -795,7 +795,7 @@@@ continue; } if (!skip_prefix(line, "want ", &arg) || - get_sha1_hex(arg, sha1_buf)) + get_oid_hex(arg, &oid_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); @@@@ -821,13 -821,13 -822,13 +822,13 @@@@ if (parse_feature_request(features, "include-tag")) use_include_tag = 1; - o = parse_object(sha1_buf); + o = parse_object(&oid_buf); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", - sha1_to_hex(sha1_buf)); + oid_to_hex(&oid_buf)); die("git upload-pack: not our ref %s", - sha1_to_hex(sha1_buf)); + oid_to_hex(&oid_buf)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; @@@@ -863,7 -863,7 -864,7 +864,7 @@@@ argv_array_push(&av, "rev-list"); if (deepen_since) - argv_array_pushf(&av, "--max-age=%lu", deepen_since); + argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since); if (deepen_not.nr) { argv_array_push(&av, "--not"); for (i = 0; i < deepen_not.nr; i++) { @@@@ -883,7 -883,7 -884,7 +884,7 @@@@ if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) - register_shallow(shallows.objects[i].item->oid.hash); + register_shallow(&shallows.objects[i].item->oid); } shallow_nr += shallows.nr; diff --combined wrapper.c index 4632c7d4c0,d837417709,487a9f7532..36630e5d18 --- a/wrapper.c +++ b/wrapper.c @@@@ -2,6 -2,6 -2,7 +2,7 @@@@ * Various trivial helper wrappers around standard functions */ #include "cache.h" ++ #include "config.h" static void do_nothing(size_t size) { @@@@ -418,32 -418,6 -419,6 +419,32 @@@@ FILE *fopen_for_writing(const char *pat return ret; } ++static void warn_on_inaccessible(const char *path) ++{ ++ warning_errno(_("unable to access '%s'"), path); ++} ++ ++int warn_on_fopen_errors(const char *path) ++{ ++ if (errno != ENOENT && errno != ENOTDIR) { ++ warn_on_inaccessible(path); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++FILE *fopen_or_warn(const char *path, const char *mode) ++{ ++ FILE *fp = fopen(path, mode); ++ ++ if (fp) ++ return fp; ++ ++ warn_on_fopen_errors(path); ++ return NULL; ++} ++ int xmkstemp(char *template) { int fd; @@@@ -602,10 -576,15 -577,15 +603,10 @@@@ int remove_or_warn(unsigned int mode, c return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file); } --void warn_on_inaccessible(const char *path) --{ -- warning_errno(_("unable to access '%s'"), path); --} -- static int access_error_is_ok(int err, unsigned flag) { -- return err == ENOENT || err == ENOTDIR || -- ((flag & ACCESS_EACCES_OK) && err == EACCES); ++ return (is_missing_file_error(err) || ++ ((flag & ACCESS_EACCES_OK) && err == EACCES)); } int access_or_warn(const char *path, int mode, unsigned flag) diff --combined xdiff-interface.c index d3f78ca2a7,060038c2d6,5ac07d7348..018e033089 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@@@ -1,4 -1,4 -1,5 +1,5 @@@@ #include "cache.h" ++ #include "config.h" #include "xdiff-interface.h" #include "xdiff/xtypes.h" #include "xdiff/xdiffi.h" @@@@ -164,9 -164,9 -165,9 +165,9 @@@@ int read_mmfile(mmfile_t *ptr, const ch size_t sz; if (stat(filename, &st)) -- return error("Could not stat %s", filename); ++ return error_errno("Could not stat %s", filename); if ((f = fopen(filename, "rb")) == NULL) -- return error("Could not open %s", filename); ++ return error_errno("Could not open %s", filename); sz = xsize_t(st.st_size); ptr->ptr = xmalloc(sz ? sz : 1); if (sz && fread(ptr->ptr, sz, 1, f) != 1) {