From a5c1780a0355a71b9fb70f1f1977ce726ee5b8d8 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 20 Apr 2007 11:23:45 -0400 Subject: [PATCH 01/80] Don't repack existing objects in fast-import Some users of fast-import have been trying to use it to rewrite commits and trees, an activity where the all of the relevant blobs are already available from the existing packfiles. In such a case we don't want to repack a blob, even if the frontend application has supplied us the raw data rather than a mark or a SHA-1 name. I'm intentionally only checking the packfiles that existed when fast-import started and am always ignoring all loose object files. We ignore loose objects because fast-import tends to operate on a very large number of objects in a very short timespan, and it is usually creating new objects, not reusing existing ones. In such a situtation the majority of the objects will not be found in the existing packfiles, nor will they be loose object files. If the frontend application really wants us to look at loose object files, then they can just repack the repository before running fast-import. Signed-off-by: Shawn O. Pearce --- fast-import.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fast-import.c b/fast-import.c index cdd629d6bc..e3290df3d4 100644 --- a/fast-import.c +++ b/fast-import.c @@ -904,6 +904,12 @@ static int store_object( if (e->offset) { duplicate_count_by_type[type]++; return 1; + } else if (find_sha1_pack(sha1, packed_git)) { + e->type = type; + e->pack_id = MAX_PACK_ID; + e->offset = 1; /* just not zero! */ + duplicate_count_by_type[type]++; + return 1; } if (last && last->data && last->depth < max_depth) { @@ -2021,6 +2027,7 @@ static void import_marks(const char *input_file) e = insert_object(sha1); e->type = type; e->pack_id = MAX_PACK_ID; + e->offset = 1; /* just not zero! */ } insert_mark(mark, e); } @@ -2086,6 +2093,7 @@ int main(int argc, const char **argv) if (i != argc) usage(fast_import_usage); + prepare_packed_git(); start_packfile(); for (;;) { read_next_command(); From 228e94f93570b580da388069900c56b813c91953 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 1 Apr 2007 18:14:06 -0700 Subject: [PATCH 02/80] Move index-related variables into a structure. This defines a index_state structure and moves index-related global variables into it. Currently there is one instance of it, the_index, and everybody accesses it, so there is no code change. Signed-off-by: Junio C Hamano --- cache.h | 19 ++++++++++++++++--- read-cache.c | 12 ++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/cache.h b/cache.h index 89aaf0022d..4841c9a161 100644 --- a/cache.h +++ b/cache.h @@ -143,9 +143,22 @@ static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned in #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7) -extern struct cache_entry **active_cache; -extern unsigned int active_nr, active_alloc, active_cache_changed; -extern struct cache_tree *active_cache_tree; +struct index_state { + struct cache_entry **cache; + unsigned int cache_nr, cache_alloc, cache_changed; + struct cache_tree *cache_tree; + time_t timestamp; + void *mmap; + size_t mmap_size; +}; + +extern struct index_state the_index; + +#define active_cache (the_index.cache) +#define active_nr (the_index.cache_nr) +#define active_alloc (the_index.cache_alloc) +#define active_cache_changed (the_index.cache_changed) +#define active_cache_tree (the_index.cache_tree) enum object_type { OBJ_BAD = -1, diff --git a/read-cache.c b/read-cache.c index d2f332a622..9b4385ea5c 100644 --- a/read-cache.c +++ b/read-cache.c @@ -19,14 +19,10 @@ #define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) ) #define CACHE_EXT_TREE 0x54524545 /* "TREE" */ -struct cache_entry **active_cache; -static time_t index_file_timestamp; -unsigned int active_nr, active_alloc, active_cache_changed; - -struct cache_tree *active_cache_tree; - -static void *cache_mmap; -static size_t cache_mmap_size; +struct index_state the_index; +#define index_file_timestamp (the_index.timestamp) +#define cache_mmap (the_index.mmap) +#define cache_mmap_size (the_index.mmap_size) /* * This only updates the "non-critical" parts of the directory From 4aab5b46f44a7ba860e07a52be506b7b57b2bd5f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 1 Apr 2007 23:26:07 -0700 Subject: [PATCH 03/80] Make read-cache.c "the_index" free. This makes all low-level functions defined in read-cache.c to take an explicit index_state structure as their first parameter, to specify which index to work on. These functions traditionally operated on "the_index" and were named foo_cache(); the counterparts this patch introduces are called foo_index(). The traditional foo_cache() functions are made into macros that give "the_index" to their corresponding foo_index() functions. Signed-off-by: Junio C Hamano --- cache.h | 39 ++++++--- read-cache.c | 237 ++++++++++++++++++++++++++++----------------------- 2 files changed, 155 insertions(+), 121 deletions(-) diff --git a/cache.h b/cache.h index 4841c9a161..74e47dffa2 100644 --- a/cache.h +++ b/cache.h @@ -154,12 +154,27 @@ struct index_state { extern struct index_state the_index; +#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS #define active_cache (the_index.cache) #define active_nr (the_index.cache_nr) #define active_alloc (the_index.cache_alloc) #define active_cache_changed (the_index.cache_changed) #define active_cache_tree (the_index.cache_tree) +#define read_cache() read_index(&the_index) +#define read_cache_from(path) read_index_from(&the_index, (path)) +#define write_cache(newfd, cache, entries) write_index(&the_index, (newfd)) +#define discard_cache() discard_index(&the_index) +#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen)) +#define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option)) +#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos)) +#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path)) +#define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose)) +#define refresh_cache(flags) refresh_index(&the_index, flags) +#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really)) +#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really)) +#endif + enum object_type { OBJ_BAD = -1, OBJ_NONE = 0, @@ -208,23 +223,23 @@ extern void verify_non_filename(const char *prefix, const char *name); #define alloc_nr(x) (((x)+16)*3/2) /* Initialize and use the cache information */ -extern int read_cache(void); -extern int read_cache_from(const char *path); -extern int write_cache(int newfd, struct cache_entry **cache, int entries); -extern int discard_cache(void); +extern int read_index(struct index_state *); +extern int read_index_from(struct index_state *, const char *path); +extern int write_index(struct index_state *, int newfd); +extern int discard_index(struct index_state *); extern int verify_path(const char *path); -extern int cache_name_pos(const char *name, int namelen); +extern int index_name_pos(struct index_state *, const char *name, int namelen); #define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */ #define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */ #define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */ -extern int add_cache_entry(struct cache_entry *ce, int option); +extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option); extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); -extern int remove_cache_entry_at(int pos); -extern int remove_file_from_cache(const char *path); -extern int add_file_to_cache(const char *path, int verbose); +extern int remove_index_entry_at(struct index_state *, int pos); +extern int remove_file_from_index(struct index_state *, const char *path); +extern int add_file_to_index(struct index_state *, const char *path, int verbose); extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); -extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int); -extern int ce_modified(struct cache_entry *ce, struct stat *st, int); +extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int); +extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int); extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); extern int read_pipe(int fd, char** return_buf, unsigned long* return_size); @@ -236,7 +251,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_UNMERGED 0x0002 /* allow unmerged */ #define REFRESH_QUIET 0x0004 /* be quiet about it */ #define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */ -extern int refresh_cache(unsigned int flags); +extern int refresh_index(struct index_state *, unsigned int flags); struct lock_file { struct lock_file *next; diff --git a/read-cache.c b/read-cache.c index 9b4385ea5c..e04e99112d 100644 --- a/read-cache.c +++ b/read-cache.c @@ -3,6 +3,7 @@ * * Copyright (C) Linus Torvalds, 2005 */ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "cache-tree.h" #include "refs.h" @@ -20,9 +21,6 @@ #define CACHE_EXT_TREE 0x54524545 /* "TREE" */ struct index_state the_index; -#define index_file_timestamp (the_index.timestamp) -#define cache_mmap (the_index.mmap) -#define cache_mmap_size (the_index.mmap_size) /* * This only updates the "non-critical" parts of the directory @@ -192,7 +190,8 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) return changed; } -int ce_match_stat(struct cache_entry *ce, struct stat *st, int options) +int ie_match_stat(struct index_state *istate, + struct cache_entry *ce, struct stat *st, int options) { unsigned int changed; int ignore_valid = options & 01; @@ -224,8 +223,8 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st, int options) * carefully than others. */ if (!changed && - index_file_timestamp && - index_file_timestamp <= ntohl(ce->ce_mtime.sec)) { + istate->timestamp && + istate->timestamp <= ntohl(ce->ce_mtime.sec)) { if (assume_racy_is_modified) changed |= DATA_CHANGED; else @@ -235,10 +234,11 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st, int options) return changed; } -int ce_modified(struct cache_entry *ce, struct stat *st, int really) +int ie_modified(struct index_state *istate, + struct cache_entry *ce, struct stat *st, int really) { int changed, changed_fs; - changed = ce_match_stat(ce, st, really); + changed = ie_match_stat(istate, ce, st, really); if (!changed) return 0; /* @@ -306,15 +306,15 @@ int cache_name_compare(const char *name1, int flags1, const char *name2, int fla return 0; } -int cache_name_pos(const char *name, int namelen) +int index_name_pos(struct index_state *istate, const char *name, int namelen) { int first, last; first = 0; - last = active_nr; + last = istate->cache_nr; while (last > first) { int next = (last + first) >> 1; - struct cache_entry *ce = active_cache[next]; + struct cache_entry *ce = istate->cache[next]; int cmp = cache_name_compare(name, namelen, ce->name, ntohs(ce->ce_flags)); if (!cmp) return next; @@ -328,27 +328,29 @@ int cache_name_pos(const char *name, int namelen) } /* Remove entry, return true if there are more entries to go.. */ -int remove_cache_entry_at(int pos) +int remove_index_entry_at(struct index_state *istate, int pos) { - active_cache_changed = 1; - active_nr--; - if (pos >= active_nr) + istate->cache_changed = 1; + istate->cache_nr--; + if (pos >= istate->cache_nr) return 0; - memmove(active_cache + pos, active_cache + pos + 1, (active_nr - pos) * sizeof(struct cache_entry *)); + memmove(istate->cache + pos, + istate->cache + pos + 1, + (istate->cache_nr - pos) * sizeof(struct cache_entry *)); return 1; } -int remove_file_from_cache(const char *path) +int remove_file_from_index(struct index_state *istate, const char *path) { - int pos = cache_name_pos(path, strlen(path)); + int pos = index_name_pos(istate, path, strlen(path)); if (pos < 0) pos = -pos-1; - while (pos < active_nr && !strcmp(active_cache[pos]->name, path)) - remove_cache_entry_at(pos); + while (pos < istate->cache_nr && !strcmp(istate->cache[pos]->name, path)) + remove_index_entry_at(istate, pos); return 0; } -int add_file_to_cache(const char *path, int verbose) +int add_file_to_index(struct index_state *istate, const char *path, int verbose) { int size, namelen; struct stat st; @@ -378,19 +380,19 @@ int add_file_to_cache(const char *path, int verbose) * from it, otherwise assume unexecutable regular file. */ struct cache_entry *ent; - int pos = cache_name_pos(path, namelen); + int pos = index_name_pos(istate, path, namelen); - ent = (0 <= pos) ? active_cache[pos] : NULL; + ent = (0 <= pos) ? istate->cache[pos] : NULL; ce->ce_mode = ce_mode_from_stat(ent, st.st_mode); } if (index_path(ce->sha1, path, &st, 1)) die("unable to index file %s", path); - if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE)) + if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE)) die("unable to add %s to index",path); if (verbose) printf("add '%s'\n", path); - cache_tree_invalidate_path(active_cache_tree, path); + cache_tree_invalidate_path(istate->cache_tree, path); return 0; } @@ -494,15 +496,16 @@ inside: * Do we have another file that has the beginning components being a * proper superset of the name we're trying to add? */ -static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replace) +static int has_file_name(struct index_state *istate, + const struct cache_entry *ce, int pos, int ok_to_replace) { int retval = 0; int len = ce_namelen(ce); int stage = ce_stage(ce); const char *name = ce->name; - while (pos < active_nr) { - struct cache_entry *p = active_cache[pos++]; + while (pos < istate->cache_nr) { + struct cache_entry *p = istate->cache[pos++]; if (len >= ce_namelen(p)) break; @@ -517,7 +520,7 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac retval = -1; if (!ok_to_replace) break; - remove_cache_entry_at(--pos); + remove_index_entry_at(istate, --pos); } return retval; } @@ -526,7 +529,8 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac * Do we have another file with a pathname that is a proper * subset of the name we're trying to add? */ -static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace) +static int has_dir_name(struct index_state *istate, + const struct cache_entry *ce, int pos, int ok_to_replace) { int retval = 0; int stage = ce_stage(ce); @@ -544,7 +548,7 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace } len = slash - name; - pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage))); + pos = index_name_pos(istate, name, ntohs(create_ce_flags(len, stage))); if (pos >= 0) { /* * Found one, but not so fast. This could @@ -554,11 +558,11 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace * it is Ok to have a directory at the same * path. */ - if (stage || active_cache[pos]->ce_mode) { + if (stage || istate->cache[pos]->ce_mode) { retval = -1; if (!ok_to_replace) break; - remove_cache_entry_at(pos); + remove_index_entry_at(istate, pos); continue; } } @@ -570,8 +574,8 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace * already matches the sub-directory, then we know * we're ok, and we can exit. */ - while (pos < active_nr) { - struct cache_entry *p = active_cache[pos]; + while (pos < istate->cache_nr) { + struct cache_entry *p = istate->cache[pos]; if ((ce_namelen(p) <= len) || (p->name[len] != '/') || memcmp(p->name, name, len)) @@ -598,7 +602,9 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace * from the cache so the caller should recompute the insert position. * When this happens, we return non-zero. */ -static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace) +static int check_file_directory_conflict(struct index_state *istate, + const struct cache_entry *ce, + int pos, int ok_to_replace) { int retval; @@ -613,28 +619,28 @@ static int check_file_directory_conflict(const struct cache_entry *ce, int pos, * first, since removing those will not change the position * in the array. */ - retval = has_file_name(ce, pos, ok_to_replace); + retval = has_file_name(istate, ce, pos, ok_to_replace); /* * Then check if the path might have a clashing sub-directory * before it. */ - return retval + has_dir_name(ce, pos, ok_to_replace); + return retval + has_dir_name(istate, ce, pos, ok_to_replace); } -int add_cache_entry(struct cache_entry *ce, int option) +int add_index_entry(struct index_state *istate, struct cache_entry *ce, int option) { int pos; int ok_to_add = option & ADD_CACHE_OK_TO_ADD; int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE; int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK; - pos = cache_name_pos(ce->name, ntohs(ce->ce_flags)); + pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags)); /* existing match? Just replace it. */ if (pos >= 0) { - active_cache_changed = 1; - active_cache[pos] = ce; + istate->cache_changed = 1; + istate->cache[pos] = ce; return 0; } pos = -pos-1; @@ -643,10 +649,10 @@ int add_cache_entry(struct cache_entry *ce, int option) * Inserting a merged entry ("stage 0") into the index * will always replace all non-merged entries.. */ - if (pos < active_nr && ce_stage(ce) == 0) { - while (ce_same_name(active_cache[pos], ce)) { + if (pos < istate->cache_nr && ce_stage(ce) == 0) { + while (ce_same_name(istate->cache[pos], ce)) { ok_to_add = 1; - if (!remove_cache_entry_at(pos)) + if (!remove_index_entry_at(istate, pos)) break; } } @@ -657,25 +663,29 @@ int add_cache_entry(struct cache_entry *ce, int option) return -1; if (!skip_df_check && - check_file_directory_conflict(ce, pos, ok_to_replace)) { + check_file_directory_conflict(istate, ce, pos, ok_to_replace)) { if (!ok_to_replace) - return error("'%s' appears as both a file and as a directory", ce->name); - pos = cache_name_pos(ce->name, ntohs(ce->ce_flags)); + return error("'%s' appears as both a file and as a directory", + ce->name); + pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags)); pos = -pos-1; } /* Make sure the array is big enough .. */ - if (active_nr == active_alloc) { - active_alloc = alloc_nr(active_alloc); - active_cache = xrealloc(active_cache, active_alloc * sizeof(struct cache_entry *)); + if (istate->cache_nr == istate->cache_alloc) { + istate->cache_alloc = alloc_nr(istate->cache_alloc); + istate->cache = xrealloc(istate->cache, + istate->cache_alloc * sizeof(struct cache_entry *)); } /* Add it in.. */ - active_nr++; - if (active_nr > pos) - memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce)); - active_cache[pos] = ce; - active_cache_changed = 1; + istate->cache_nr++; + if (istate->cache_nr > pos) + memmove(istate->cache + pos + 1, + istate->cache + pos, + (istate->cache_nr - pos - 1) * sizeof(ce)); + istate->cache[pos] = ce; + istate->cache_changed = 1; return 0; } @@ -690,7 +700,8 @@ int add_cache_entry(struct cache_entry *ce, int option) * For example, you'd want to do this after doing a "git-read-tree", * to link up the stat cache details with the proper files. */ -static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, int *err) +static struct cache_entry *refresh_cache_ent(struct index_state *istate, + struct cache_entry *ce, int really, int *err) { struct stat st; struct cache_entry *updated; @@ -702,7 +713,7 @@ static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, return NULL; } - changed = ce_match_stat(ce, &st, really); + changed = ie_match_stat(istate, ce, &st, really); if (!changed) { if (really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID))) @@ -711,7 +722,7 @@ static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, return ce; } - if (ce_modified(ce, &st, really)) { + if (ie_modified(istate, ce, &st, really)) { if (err) *err = EINVAL; return NULL; @@ -734,7 +745,7 @@ static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, return updated; } -int refresh_cache(unsigned int flags) +int refresh_index(struct index_state *istate, unsigned int flags) { int i; int has_errors = 0; @@ -743,14 +754,14 @@ int refresh_cache(unsigned int flags) int quiet = (flags & REFRESH_QUIET) != 0; int not_new = (flags & REFRESH_IGNORE_MISSING) != 0; - for (i = 0; i < active_nr; i++) { + for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce, *new; int cache_errno = 0; - ce = active_cache[i]; + ce = istate->cache[i]; if (ce_stage(ce)) { - while ((i < active_nr) && - ! strcmp(active_cache[i]->name, ce->name)) + while ((i < istate->cache_nr) && + ! strcmp(istate->cache[i]->name, ce->name)) i++; i--; if (allow_unmerged) @@ -760,7 +771,7 @@ int refresh_cache(unsigned int flags) continue; } - new = refresh_cache_ent(ce, really, &cache_errno); + new = refresh_cache_ent(istate, ce, really, &cache_errno); if (new == ce) continue; if (!new) { @@ -771,7 +782,7 @@ int refresh_cache(unsigned int flags) * means the index is not valid anymore. */ ce->ce_flags &= ~htons(CE_VALID); - active_cache_changed = 1; + istate->cache_changed = 1; } if (quiet) continue; @@ -779,18 +790,18 @@ int refresh_cache(unsigned int flags) has_errors = 1; continue; } - active_cache_changed = 1; - /* You can NOT just free active_cache[i] here, since it + istate->cache_changed = 1; + /* You can NOT just free istate->cache[i] here, since it * might not be necessarily malloc()ed but can also come * from mmap(). */ - active_cache[i] = new; + istate->cache[i] = new; } return has_errors; } struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) { - return refresh_cache_ent(ce, really, NULL); + return refresh_cache_ent(&the_index, ce, really, NULL); } static int verify_hdr(struct cache_header *hdr, unsigned long size) @@ -810,11 +821,12 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size) return 0; } -static int read_index_extension(const char *ext, void *data, unsigned long sz) +static int read_index_extension(struct index_state *istate, + const char *ext, void *data, unsigned long sz) { switch (CACHE_EXT(ext)) { case CACHE_EXT_TREE: - active_cache_tree = cache_tree_read(data, sz); + istate->cache_tree = cache_tree_read(data, sz); break; default: if (*ext < 'A' || 'Z' < *ext) @@ -826,13 +838,13 @@ static int read_index_extension(const char *ext, void *data, unsigned long sz) return 0; } -int read_cache(void) +int read_index(struct index_state *istate) { - return read_cache_from(get_index_file()); + return read_index_from(istate, get_index_file()); } /* remember to discard_cache() before reading a different cache! */ -int read_cache_from(const char *path) +int read_index_from(struct index_state *istate, const char *path) { int fd, i; struct stat st; @@ -840,11 +852,11 @@ int read_cache_from(const char *path) struct cache_header *hdr; errno = EBUSY; - if (cache_mmap) - return active_nr; + if (istate->mmap) + return istate->cache_nr; errno = ENOENT; - index_file_timestamp = 0; + istate->timestamp = 0; fd = open(path, O_RDONLY); if (fd < 0) { if (errno == ENOENT) @@ -853,32 +865,35 @@ int read_cache_from(const char *path) } if (!fstat(fd, &st)) { - cache_mmap_size = xsize_t(st.st_size); + istate->mmap_size = xsize_t(st.st_size); errno = EINVAL; - if (cache_mmap_size >= sizeof(struct cache_header) + 20) - cache_mmap = xmmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (istate->mmap_size >= sizeof(struct cache_header) + 20) + istate->mmap = xmmap(NULL, istate->mmap_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); else die("index file smaller than expected"); } else die("cannot stat the open index (%s)", strerror(errno)); close(fd); - hdr = cache_mmap; - if (verify_hdr(hdr, cache_mmap_size) < 0) + hdr = istate->mmap; + if (verify_hdr(hdr, istate->mmap_size) < 0) goto unmap; - active_nr = ntohl(hdr->hdr_entries); - active_alloc = alloc_nr(active_nr); - active_cache = xcalloc(active_alloc, sizeof(struct cache_entry *)); + istate->cache_nr = ntohl(hdr->hdr_entries); + istate->cache_alloc = alloc_nr(istate->cache_nr); + istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *)); offset = sizeof(*hdr); - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = (struct cache_entry *) ((char *) cache_mmap + offset); + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce; + + ce = (struct cache_entry *)((char *)(istate->mmap) + offset); offset = offset + ce_size(ce); - active_cache[i] = ce; + istate->cache[i] = ce; } - index_file_timestamp = st.st_mtime; - while (offset <= cache_mmap_size - 20 - 8) { + istate->timestamp = st.st_mtime; + while (offset <= istate->mmap_size - 20 - 8) { /* After an array of active_nr index entries, * there can be arbitrary number of extended * sections, each of which is prefixed with @@ -886,35 +901,37 @@ int read_cache_from(const char *path) * in 4-byte network byte order. */ unsigned long extsize; - memcpy(&extsize, (char *) cache_mmap + offset + 4, 4); + memcpy(&extsize, (char *)(istate->mmap) + offset + 4, 4); extsize = ntohl(extsize); - if (read_index_extension(((const char *) cache_mmap) + offset, - (char *) cache_mmap + offset + 8, + if (read_index_extension(istate, + ((const char *) (istate->mmap)) + offset, + (char *) (istate->mmap) + offset + 8, extsize) < 0) goto unmap; offset += 8; offset += extsize; } - return active_nr; + return istate->cache_nr; unmap: - munmap(cache_mmap, cache_mmap_size); + munmap(istate->mmap, istate->mmap_size); errno = EINVAL; die("index file corrupt"); } -int discard_cache(void) +int discard_index(struct index_state *istate) { int ret; - active_nr = active_cache_changed = 0; - index_file_timestamp = 0; - cache_tree_free(&active_cache_tree); - if (cache_mmap == NULL) + istate->cache_nr = 0; + istate->cache_changed = 0; + istate->timestamp = 0; + cache_tree_free(&(istate->cache_tree)); + if (istate->mmap == NULL) return 0; - ret = munmap(cache_mmap, cache_mmap_size); - cache_mmap = NULL; - cache_mmap_size = 0; + ret = munmap(istate->mmap, istate->mmap_size); + istate->mmap = NULL; + istate->mmap_size = 0; /* no need to throw away allocated active_cache */ return ret; @@ -1033,11 +1050,13 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) } } -int write_cache(int newfd, struct cache_entry **cache, int entries) +int write_index(struct index_state *istate, int newfd) { SHA_CTX c; struct cache_header hdr; int i, removed; + struct cache_entry **cache = istate->cache; + int entries = istate->cache_nr; for (i = removed = 0; i < entries; i++) if (!cache[i]->ce_mode) @@ -1055,17 +1074,17 @@ int write_cache(int newfd, struct cache_entry **cache, int entries) struct cache_entry *ce = cache[i]; if (!ce->ce_mode) continue; - if (index_file_timestamp && - index_file_timestamp <= ntohl(ce->ce_mtime.sec)) + if (istate->timestamp && + istate->timestamp <= ntohl(ce->ce_mtime.sec)) ce_smudge_racily_clean_entry(ce); if (ce_write(&c, newfd, ce, ce_size(ce)) < 0) return -1; } /* Write extension data here */ - if (active_cache_tree) { + if (istate->cache_tree) { unsigned long sz; - void *data = cache_tree_write(active_cache_tree, &sz); + void *data = cache_tree_write(istate->cache_tree, &sz); if (data && !write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) && !ce_write(&c, newfd, data, sz)) From 40689ae1ef9a05503c75298ec50b194ca9d15522 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Sun, 22 Apr 2007 18:43:56 +0200 Subject: [PATCH 04/80] Add S_IFINVALID mode S_IFINVALID is used to signal, that no mode information is available. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- cache.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cache.h b/cache.h index 89aaf0022d..b1adbe7b6e 100644 --- a/cache.h +++ b/cache.h @@ -24,6 +24,9 @@ #define DTYPE(de) DT_UNKNOWN #endif +/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */ +#define S_IFINVALID 0030000 + /* * A "directory link" is a link to another git directory. * From a0cd87a57044efa8aef39b476fd9240af57a1853 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 23 Apr 2007 22:55:05 +0200 Subject: [PATCH 05/80] add get_sha1_with_mode get_sha1_with_mode basically behaves as get_sha1. It has an additional parameter for storing the mode of the object. If the mode can not be determined, it stores S_IFINVALID. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- cache.h | 1 + sha1_name.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index b1adbe7b6e..23e8f24d5c 100644 --- a/cache.h +++ b/cache.h @@ -342,6 +342,7 @@ static inline unsigned int hexval(unsigned int c) #define DEFAULT_ABBREV 7 extern int get_sha1(const char *str, unsigned char *sha1); +extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode); extern int get_sha1_hex(const char *hex, unsigned char *sha1); extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */ extern int read_ref(const char *filename, unsigned char *sha1); diff --git a/sha1_name.c b/sha1_name.c index b0b12bbe9d..55f25a2d3b 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -643,11 +643,17 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1) */ int get_sha1(const char *name, unsigned char *sha1) { - int ret, bracket_depth; unsigned unused; + return get_sha1_with_mode(name, sha1, &unused); +} + +int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode) +{ + int ret, bracket_depth; int namelen = strlen(name); const char *cp; + *mode = S_IFINVALID; prepare_alt_odb(); ret = get_sha1_1(name, namelen, sha1); if (!ret) @@ -685,6 +691,7 @@ int get_sha1(const char *name, unsigned char *sha1) break; if (ce_stage(ce) == stage) { hashcpy(sha1, ce->sha1); + *mode = ntohl(ce->ce_mode); return 0; } pos++; @@ -703,7 +710,7 @@ int get_sha1(const char *name, unsigned char *sha1) unsigned char tree_sha1[20]; if (!get_sha1_1(name, cp-name, tree_sha1)) return get_tree_entry(tree_sha1, cp+1, sha1, - &unused); + mode); } return ret; } From e5709a4a6809e45bf59b851debf24a813e1c6b58 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Sun, 22 Apr 2007 18:43:58 +0200 Subject: [PATCH 06/80] add add_object_array_with_mode Each object in struct object_array is extended with the mode. If not specified, S_IFINVALID is used. An object with an mode value can be added with add_object_array_with_mode. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- object.c | 6 ++++++ object.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/object.c b/object.c index 7bd3fec556..37d1363359 100644 --- a/object.c +++ b/object.c @@ -230,6 +230,11 @@ int object_list_contains(struct object_list *list, struct object *obj) } void add_object_array(struct object *obj, const char *name, struct object_array *array) +{ + add_object_array_with_mode(obj, name, array, S_IFINVALID); +} + +void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode) { unsigned nr = array->nr; unsigned alloc = array->alloc; @@ -243,5 +248,6 @@ void add_object_array(struct object *obj, const char *name, struct object_array } objects[nr].item = obj; objects[nr].name = name; + objects[nr].mode = mode; array->nr = ++nr; } diff --git a/object.h b/object.h index 3e26a0e8b9..94f19eed86 100644 --- a/object.h +++ b/object.h @@ -17,6 +17,7 @@ struct object_array { struct object_array_entry { struct object *item; const char *name; + unsigned mode; } *objects; }; @@ -77,5 +78,6 @@ int object_list_contains(struct object_list *list, struct object *obj); /* Object array handling .. */ void add_object_array(struct object *obj, const char *name, struct object_array *array); +void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode); #endif /* OBJECT_H */ From bb6c2fba4103948445304493b6211998a02810ce Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Sun, 22 Apr 2007 18:43:59 +0200 Subject: [PATCH 07/80] store mode in rev_list, if : syntax is used Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- revision.c | 17 ++++++++++++----- revision.h | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/revision.c b/revision.c index ce70f48ce0..49bd29225b 100644 --- a/revision.c +++ b/revision.c @@ -115,10 +115,15 @@ void mark_parents_uninteresting(struct commit *commit) } void add_pending_object(struct rev_info *revs, struct object *obj, const char *name) +{ + add_pending_object_with_mode(revs, obj, name, S_IFINVALID); +} + +void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode) { if (revs->no_walk && (obj->flags & UNINTERESTING)) die("object ranges do not make sense when not walking revisions"); - add_object_array(obj, name, &revs->pending); + add_object_array_with_mode(obj, name, &revs->pending, mode); if (revs->reflog_info && obj->type == OBJ_COMMIT) add_reflog_for_walk(revs->reflog_info, (struct commit *)obj, name); @@ -723,6 +728,7 @@ int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, int cant_be_filename) { + unsigned mode; char *dotdot; struct object *object; unsigned char sha1[20]; @@ -796,12 +802,12 @@ int handle_revision_arg(const char *arg, struct rev_info *revs, local_flags = UNINTERESTING; arg++; } - if (get_sha1(arg, sha1)) + if (get_sha1_with_mode(arg, sha1, &mode)) return -1; if (!cant_be_filename) verify_non_filename(revs->prefix, arg); object = get_reference(revs, arg, sha1, flags ^ local_flags); - add_pending_object(revs, object, arg); + add_pending_object_with_mode(revs, object, arg, mode); return 0; } @@ -1177,10 +1183,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (def && !revs->pending.nr) { unsigned char sha1[20]; struct object *object; - if (get_sha1(def, sha1)) + unsigned mode; + if (get_sha1_with_mode(def, sha1, &mode)) die("bad default revision '%s'", def); object = get_reference(revs, def, sha1, 0); - add_pending_object(revs, object, def); + add_pending_object_with_mode(revs, object, def, mode); } if (revs->topo_order) diff --git a/revision.h b/revision.h index 8a02618428..5b41e2da20 100644 --- a/revision.h +++ b/revision.h @@ -131,5 +131,6 @@ extern void add_object(struct object *obj, const char *name); extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); +extern void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode); #endif From 01618a3ab131548582f4e2371b9b5e7328f61e4a Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Sun, 22 Apr 2007 18:44:00 +0200 Subject: [PATCH 08/80] use mode of the tree in git-diff, if : syntax is used Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-diff.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/builtin-diff.c b/builtin-diff.c index 2ae60097b8..4ba4d18f87 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -13,13 +13,10 @@ #include "log-tree.h" #include "builtin.h" -/* NEEDSWORK: struct object has place for name but we _do_ - * know mode when we extracted the blob out of a tree, which - * we currently lose. - */ struct blobinfo { unsigned char sha1[20]; const char *name; + unsigned mode; }; static const char builtin_diff_usage[] = @@ -70,8 +67,12 @@ static int builtin_diff_b_f(struct rev_info *revs, die("'%s': %s", path, strerror(errno)); if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) die("'%s': not a regular file or symlink", path); + + if (blob[0].mode == S_IFINVALID) + blob[0].mode = canon_mode(st.st_mode); + stuff_change(&revs->diffopt, - canon_mode(st.st_mode), canon_mode(st.st_mode), + blob[0].mode, canon_mode(st.st_mode), blob[0].sha1, null_sha1, path, path); diffcore_std(&revs->diffopt); @@ -88,8 +89,14 @@ static int builtin_diff_blobs(struct rev_info *revs, if (argc > 1) usage(builtin_diff_usage); + if (blob[0].mode == S_IFINVALID) + blob[0].mode = mode; + + if (blob[1].mode == S_IFINVALID) + blob[1].mode = mode; + stuff_change(&revs->diffopt, - mode, mode, + blob[0].mode, blob[1].mode, blob[0].sha1, blob[1].sha1, blob[0].name, blob[1].name); diffcore_std(&revs->diffopt); @@ -272,6 +279,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) die("more than two blobs given: '%s'", name); hashcpy(blob[blobs].sha1, obj->sha1); blob[blobs].name = name; + blob[blobs].mode = list->mode; blobs++; continue; From 43342941dd736fe06fe607a1594422cc8ba461a1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 22 Apr 2007 23:56:22 -0700 Subject: [PATCH 09/80] Diff between two blobs should take mode changes into account now. Signed-off-by: Junio C Hamano --- builtin-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-diff.c b/builtin-diff.c index 4ba4d18f87..7f367b6b9d 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -32,7 +32,7 @@ static void stuff_change(struct diff_options *opt, struct diff_filespec *one, *two; if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) && - !hashcmp(old_sha1, new_sha1)) + !hashcmp(old_sha1, new_sha1) && (old_mode == new_mode)) return; if (opt->reverse_diff) { From b51b8bbf146d17556226bff14f97957e84aa0207 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 24 Apr 2007 00:51:35 -0700 Subject: [PATCH 10/80] Create a sysconfdir variable, and use it for ETC_GITCONFIG ETC_GITCONFIG defaults to $(prefix)/etc/gitconfig, so if you just set prefix=/usr, you end up with a git that looks in /usr/etc/gitconfig, rather than /etc/gitconfig as specified by the FHS. Furthermore, setting ETC_GITCONFIG does not fix the paths to any future system-wide configuration files. Factor out the path to the system-wide configuration directory into a variable sysconfdir, normally set to $(prefix)/etc, but set to /etc when prefix=/usr . This fixes the prefix=/usr problem for ETC_GITCONFIG, and allows centralized configuration of any future system-wide configuration files without requiring further action from package maintainers or other people building and installing git. Signed-off-by: Josh Triplett Signed-off-by: Junio C Hamano --- Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index dcdaa02e47..b61c5d4cd2 100644 --- a/Makefile +++ b/Makefile @@ -133,7 +133,12 @@ prefix = $(HOME) bindir = $(prefix)/bin gitexecdir = $(bindir) template_dir = $(prefix)/share/git-core/templates/ -ETC_GITCONFIG = $(prefix)/etc/gitconfig +ifeq ($(prefix),/usr) +sysconfdir = /etc +else +sysconfdir = $(prefix)/etc +endif +ETC_GITCONFIG = $(sysconfdir)/gitconfig # DESTDIR= # default configuration for gitweb @@ -152,7 +157,7 @@ GITWEB_FAVICON = git-favicon.png GITWEB_SITE_HEADER = GITWEB_SITE_FOOTER = -export prefix bindir gitexecdir template_dir +export prefix bindir gitexecdir template_dir sysconfdir CC = gcc AR = ar From 46f6178a3f4e7a5bf8b47da0f3cc5c998d907ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 24 Apr 2007 13:51:04 +0200 Subject: [PATCH 11/80] fix importing of subversion tars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add a / between the prefix and name fields of the tar archive if prefix is non-empty. Signed-off-by: Uwe Kleine-König Signed-off-by: Shawn O. Pearce --- contrib/fast-import/import-tars.perl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index 5585a8b2c5..184214689d 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -64,7 +64,12 @@ foreach my $tar_file (@ARGV) } print FI "\n"; - my $path = "$prefix$name"; + my $path; + if ($prefix) { + $path = "$prefix/$name"; + } else { + $path = "$name"; + } $files{$path} = [$next_mark++, $mode]; $commit_time = $mtime if $mtime > $commit_time; From 886a39074be34d21afc6c1b8af1f7f4b3ef54dc5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 24 Apr 2007 11:21:47 -0700 Subject: [PATCH 12/80] t/test-lib.sh: Protect ourselves from common misconfiguration that exports CDPATH to the environment Signed-off-by: Junio C Hamano --- t/test-lib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index c0754747fb..f2c6bd3b01 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -36,6 +36,10 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR VISUAL +# Protect ourselves from common misconfiguration to export +# CDPATH into the environment +unset CDPATH + case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in 1|2|true) echo "* warning: Some tests will not work if GIT_TRACE" \ From 00be8dcc1aca3c1c1a94b39f0563d30d1fa89290 Mon Sep 17 00:00:00 2001 From: Sami Farin Date: Tue, 24 Apr 2007 22:56:02 +0300 Subject: [PATCH 13/80] fast-import: size_t vs ssize_t size_t is unsigned, so (n < 0) is never true. Signed-off-by: Shawn O. Pearce --- fast-import.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast-import.c b/fast-import.c index e3290df3d4..c4c8cb905e 100644 --- a/fast-import.c +++ b/fast-import.c @@ -673,7 +673,7 @@ static void fixup_header_footer(void) buf = xmalloc(buf_sz); for (;;) { - size_t n = xread(pack_fd, buf, buf_sz); + ssize_t n = xread(pack_fd, buf, buf_sz); if (!n) break; if (n < 0) From b9d14ffbf1f42eb80231d0378dd2f019a162c054 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 24 Apr 2007 13:46:02 -0700 Subject: [PATCH 14/80] gitattributes documentation: clarify overriding Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index d2edb9b14a..857d55a409 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -49,10 +49,12 @@ Set to a value:: Unspecified:: No glob pattern matches the path, and nothing says if - the path has or does not have the attribute. + the path has or does not have the attribute, the + attribute for the path is said to be Unspecified. When more than one glob pattern matches the path, a later line -overrides an earlier line. +overrides an earlier line. This overriding is done per +attribute. When deciding what attributes are assigned to a path, git consults `$GIT_DIR/info/attributes` file (which has the highest @@ -215,7 +217,7 @@ String:: merge driver. The built-in 3-way merge driver can be explicitly specified by asking for "text" driver; the built-in "take the current branch" driver can be - requested by "binary". + requested with "binary". Defining a custom merge driver From 7d4f4a2f0dd440ce6116ed318440c2474afdd843 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 24 Apr 2007 14:27:00 -0700 Subject: [PATCH 15/80] applymbox & quiltimport: typofix. 6777c380 fixed only one of three typos introduced in an earlier patch 87ab7992. This fixes the other two. Signed-off-by: Junio C Hamano --- git-applymbox.sh | 2 +- git-quiltimport.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/git-applymbox.sh b/git-applymbox.sh index 3efd6a7464..c18e80ff8c 100755 --- a/git-applymbox.sh +++ b/git-applymbox.sh @@ -78,7 +78,7 @@ do git-mailinfo $keep_subject $utf8 \ .dotest/msg .dotest/patch <$i >.dotest/info || exit 1 test -s .dotest/patch || { - echo "Patch is empty. Was is split wrong?" + echo "Patch is empty. Was it split wrong?" exit 1 } git-stripspace < .dotest/msg > .dotest/msg-clean diff --git a/git-quiltimport.sh b/git-quiltimport.sh index 018cc75bd0..a7a6757dd8 100755 --- a/git-quiltimport.sh +++ b/git-quiltimport.sh @@ -74,7 +74,7 @@ for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do echo $patch_name (cat $QUILT_PATCHES/$patch_name | git-mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3 test -s .dotest/patch || { - echo "Patch is empty. Was is split wrong?" + echo "Patch is empty. Was it split wrong?" exit 1 } From ce11873921e19be44082660882e07b205082643b Mon Sep 17 00:00:00 2001 From: Adam Roben Date: Tue, 24 Apr 2007 18:02:07 -0700 Subject: [PATCH 16/80] Remove usernames from all commit messages, not just when using svmprops Signed-off-by: Sam Vilain Signed-off-by: Adam Roben Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index efc4c88a4e..077d6b3a13 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1866,11 +1866,14 @@ sub make_log_entry { } elsif ($self->use_svnsync_props) { my $full_url = $self->svnsync->{url}; $full_url .= "/$self->{path}" if length $self->{path}; + remove_username($full_url); my $uuid = $self->svnsync->{uuid}; $log_entry{metadata} = "$full_url\@$rev $uuid"; $email ||= "$author\@$uuid" } else { - $log_entry{metadata} = $self->metadata_url. "\@$rev " . + my $url = $self->metadata_url; + remove_username($url); + $log_entry{metadata} = "$url\@$rev " . $self->ra->get_uuid; $email ||= "$author\@" . $self->ra->get_uuid; } From 3fed15f568c24ec00ef78fddc6cbb881fbbb0277 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 21 Apr 2007 19:09:02 -0700 Subject: [PATCH 17/80] Add 'ident' conversion. The 'ident' attribute set to path squashes "$ident:$" to "$ident$" upon checkin, and expands it to "$ident: $" upon checkout. As we have two conversions that affect checkin/checkout paths, clarify how they interact with each other. Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 31 ++++- convert.c | 194 ++++++++++++++++++++++++++++++-- t/t0021-conversion.sh | 39 +++++++ 3 files changed, 252 insertions(+), 12 deletions(-) create mode 100755 t/t0021-conversion.sh diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 857d55a409..b6f90f6f37 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -78,12 +78,17 @@ are attributes-aware. Checking-out and checking-in ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The attribute `crlf` affects how the contents stored in the +These attributes affect how the contents stored in the repository are copied to the working tree files when commands -such as `git checkout` and `git merge` run. It also affects how +such as `git checkout` and `git merge` run. They also affect how git stores the contents you prepare in the working tree in the repository upon `git add` and `git commit`. +`crlf` +^^^^^^ + +This attribute controls the line-ending convention. + Set:: Setting the `crlf` attribute on a path is meant to mark @@ -129,6 +134,28 @@ converted to LF upon checkin, but there is no conversion done upon checkout. +`ident` +^^^^^^^ + +When the attribute `ident` is set to a path, git replaces +`$ident$` in the blob object with `$ident:`, followed by +40-character hexadecimal blob object name, followed by a dollar +sign `$` upon checkout. Any byte sequence that begins with +`$ident:` and ends with `$` in the worktree file is replaced +with `$ident$` upon check-in. + + +Interaction between checkin/checkout attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the check-in codepath, the worktree file is first converted +with `ident` (if specified), and then with `crlf` (again, if +specified and applicable). + +In the check-out codepath, the blob content is first converted +with `crlf`, and then `ident`. + + Generating diff text ~~~~~~~~~~~~~~~~~~~~ diff --git a/convert.c b/convert.c index ad106ef35f..5fdaee7571 100644 --- a/convert.c +++ b/convert.c @@ -1,5 +1,6 @@ #include "cache.h" #include "attr.h" +#include "run-command.h" /* * convert.c - convert a file when checking it out and checking it in. @@ -203,10 +204,152 @@ static char *crlf_to_worktree(const char *path, const char *src, unsigned long * static void setup_convert_check(struct git_attr_check *check) { static struct git_attr *attr_crlf; + static struct git_attr *attr_ident; - if (!attr_crlf) + if (!attr_crlf) { attr_crlf = git_attr("crlf", 4); - check->attr = attr_crlf; + attr_ident = git_attr("ident", 5); + } + check[0].attr = attr_crlf; + check[1].attr = attr_ident; +} + +static int count_ident(const char *cp, unsigned long size) +{ + /* + * "$ident: 0000000000000000000000000000000000000000 $" <=> "$ident$" + */ + int cnt = 0; + char ch; + + while (size) { + ch = *cp++; + size--; + if (ch != '$') + continue; + if (size < 6) + break; + if (memcmp("ident", cp, 5)) + continue; + ch = cp[5]; + cp += 6; + size -= 6; + if (ch == '$') + cnt++; /* $ident$ */ + if (ch != ':') + continue; + + /* + * "$ident: ... "; scan up to the closing dollar sign and discard. + */ + while (size) { + ch = *cp++; + size--; + if (ch == '$') { + cnt++; + break; + } + } + } + return cnt; +} + +static char *ident_to_git(const char *path, const char *src, unsigned long *sizep, int ident) +{ + int cnt; + unsigned long size; + char *dst, *buf; + + if (!ident) + return NULL; + size = *sizep; + cnt = count_ident(src, size); + if (!cnt) + return NULL; + buf = xmalloc(size); + + for (dst = buf; size; size--) { + char ch = *src++; + *dst++ = ch; + if ((ch == '$') && (6 <= size) && + !memcmp("ident:", src, 6)) { + unsigned long rem = size - 6; + const char *cp = src + 6; + do { + ch = *cp++; + if (ch == '$') + break; + rem--; + } while (rem); + if (!rem) + continue; + memcpy(dst, "ident$", 6); + dst += 6; + size -= (cp - src); + src = cp; + } + } + + *sizep = dst - buf; + return buf; +} + +static char *ident_to_worktree(const char *path, const char *src, unsigned long *sizep, int ident) +{ + int cnt; + unsigned long size; + char *dst, *buf; + unsigned char sha1[20]; + + if (!ident) + return NULL; + + size = *sizep; + cnt = count_ident(src, size); + if (!cnt) + return NULL; + + hash_sha1_file(src, size, "blob", sha1); + buf = xmalloc(size + cnt * 43); + + for (dst = buf; size; size--) { + const char *cp; + char ch = *src++; + *dst++ = ch; + if ((ch != '$') || (size < 6) || memcmp("ident", src, 5)) + continue; + + if (src[5] == ':') { + /* discard up to but not including the closing $ */ + unsigned long rem = size - 6; + cp = src + 6; + do { + ch = *cp++; + if (ch == '$') + break; + rem--; + } while (rem); + if (!rem) + continue; + size -= (cp - src); + } else if (src[5] == '$') + cp = src + 5; + else + continue; + + memcpy(dst, "ident: ", 7); + dst += 7; + memcpy(dst, sha1_to_hex(sha1), 40); + dst += 40; + *dst++ = ' '; + size -= (cp - src); + src = cp; + *dst++ = *src++; + size--; + } + + *sizep = dst - buf; + return buf; } static int git_path_check_crlf(const char *path, struct git_attr_check *check) @@ -224,26 +367,57 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check) return CRLF_GUESS; } +static int git_path_check_ident(const char *path, struct git_attr_check *check) +{ + const char *value = check->value; + + return !!ATTR_TRUE(value); +} + char *convert_to_git(const char *path, const char *src, unsigned long *sizep) { - struct git_attr_check check[1]; + struct git_attr_check check[2]; int crlf = CRLF_GUESS; + int ident = 0; + char *buf, *buf2; setup_convert_check(check); - if (!git_checkattr(path, 1, check)) { - crlf = git_path_check_crlf(path, check); + if (!git_checkattr(path, ARRAY_SIZE(check), check)) { + crlf = git_path_check_crlf(path, check + 0); + ident = git_path_check_ident(path, check + 1); } - return crlf_to_git(path, src, sizep, crlf); + + buf = crlf_to_git(path, src, sizep, crlf); + + buf2 = ident_to_git(path, buf ? buf : src, sizep, ident); + if (buf2) { + free(buf); + buf = buf2; + } + + return buf; } char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep) { - struct git_attr_check check[1]; + struct git_attr_check check[2]; int crlf = CRLF_GUESS; + int ident = 0; + char *buf, *buf2; setup_convert_check(check); - if (!git_checkattr(path, 1, check)) { - crlf = git_path_check_crlf(path, check); + if (!git_checkattr(path, ARRAY_SIZE(check), check)) { + crlf = git_path_check_crlf(path, check + 0); + ident = git_path_check_ident(path, check + 1); } - return crlf_to_worktree(path, src, sizep, crlf); + + buf = ident_to_worktree(path, src, sizep, ident); + + buf2 = crlf_to_worktree(path, buf ? buf : src, sizep, crlf); + if (buf2) { + free(buf); + buf = buf2; + } + + return buf; } diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh new file mode 100755 index 0000000000..ad952c9ce2 --- /dev/null +++ b/t/t0021-conversion.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +test_description='blob conversion via gitattributes' + +. ./test-lib.sh + +test_expect_success setup ' + { + echo "*.i ident" + } >.gitattributes && + + { + echo a b c d e f g h i j k l m + echo n o p q r s t u v w x y z + echo '\''$ident$'\'' + } >test && + cat test >test.t && + cat test >test.o && + cat test >test.i && + git add test test.t test.i && + rm -f test test.t test.i && + git checkout -- test test.t test.i +' + +script='s/^\$ident: \([0-9a-f]*\) \$/\1/p' + +test_expect_success check ' + + cmp test.o test && + cmp test.o test.t && + + # ident should be stripped in the repository + git diff --raw --exit-code :test :test.i && + id=$(git rev-parse --verify :test) && + embedded=$(sed -ne "$script" test.i) && + test "z$id" = "z$embedded" +' + +test_done From aa4ed402c9721170fde2e9e43c3825562070e65e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 21 Apr 2007 03:14:13 -0700 Subject: [PATCH 18/80] Add 'filter' attribute and external filter driver definition. The interface is similar to the custom low-level merge drivers. First you configure your filter driver by defining 'filter..*' variables in the configuration. filter..clean filter command to run upon checkin filter..smudge filter command to run upon checkout Then you assign filter attribute to each path, whose name matches the custom filter driver's name. Example: (in .gitattributes) *.c filter=indent (in config) [filter "indent"] clean = indent smudge = cat Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 39 ++++++ convert.c | 237 +++++++++++++++++++++++++++++++- t/t0021-conversion.sh | 9 ++ 3 files changed, 282 insertions(+), 3 deletions(-) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index b6f90f6f37..87723105d1 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -156,6 +156,45 @@ In the check-out codepath, the blob content is first converted with `crlf`, and then `ident`. +`filter` +^^^^^^^^ + +A `filter` attribute can be set to a string value. This names +filter driver specified in the configuration. + +A filter driver consists of `clean` command and `smudge` +command, either of which can be left unspecified. Upon +checkout, when `smudge` command is specified, the command is fed +the blob object from its standard input, and its standard output +is used to update the worktree file. Similarly, `clean` command +is used to convert the contents of worktree file upon checkin. + +Missing filter driver definition in the config is not an error +but makes the filter a no-op passthru. + +The content filtering is done to massage the content into a +shape that is more convenient for the platform, filesystem, and +the user to use. The keyword here is "more convenient" and not +"turning something unusable into usable". In other words, it is +"hanging yourself because we gave you a long rope" if your +project uses filtering mechanism in such a way that it makes +your project unusable unless the checkout is done with a +specific filter in effect. + + +Interaction between checkin/checkout attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the check-in codepath, the worktree file is first converted +with `filter` driver (if specified and corresponding driver +defined), then the result is processed with `ident` (if +specified), and then finally with `crlf` (again, if specified +and applicable). + +In the check-out codepath, the blob content is first converted +with `crlf`, and then `ident` and fed to `filter`. + + Generating diff text ~~~~~~~~~~~~~~~~~~~~ diff --git a/convert.c b/convert.c index 5fdaee7571..9ee31b0ee0 100644 --- a/convert.c +++ b/convert.c @@ -201,17 +201,212 @@ static char *crlf_to_worktree(const char *path, const char *src, unsigned long * return buffer; } +static int filter_buffer(const char *path, const char *src, + unsigned long size, const char *cmd) +{ + /* + * Spawn cmd and feed the buffer contents through its stdin. + */ + struct child_process child_process; + int pipe_feed[2]; + int write_err, status; + + memset(&child_process, 0, sizeof(child_process)); + + if (pipe(pipe_feed) < 0) { + error("cannot create pipe to run external filter %s", cmd); + return 1; + } + + child_process.pid = fork(); + if (child_process.pid < 0) { + error("cannot fork to run external filter %s", cmd); + close(pipe_feed[0]); + close(pipe_feed[1]); + return 1; + } + if (!child_process.pid) { + dup2(pipe_feed[0], 0); + close(pipe_feed[0]); + close(pipe_feed[1]); + execlp("sh", "sh", "-c", cmd, NULL); + return 1; + } + close(pipe_feed[0]); + + write_err = (write_in_full(pipe_feed[1], src, size) < 0); + if (close(pipe_feed[1])) + write_err = 1; + if (write_err) + error("cannot feed the input to external filter %s", cmd); + + status = finish_command(&child_process); + if (status) + error("external filter %s failed %d", cmd, -status); + return (write_err || status); +} + +static char *apply_filter(const char *path, const char *src, + unsigned long *sizep, const char *cmd) +{ + /* + * Create a pipeline to have the command filter the buffer's + * contents. + * + * (child --> cmd) --> us + */ + const int SLOP = 4096; + int pipe_feed[2]; + int status; + char *dst; + unsigned long dstsize, dstalloc; + struct child_process child_process; + + if (!cmd) + return NULL; + + memset(&child_process, 0, sizeof(child_process)); + + if (pipe(pipe_feed) < 0) { + error("cannot create pipe to run external filter %s", cmd); + return NULL; + } + + fflush(NULL); + child_process.pid = fork(); + if (child_process.pid < 0) { + error("cannot fork to run external filter %s", cmd); + close(pipe_feed[0]); + close(pipe_feed[1]); + return NULL; + } + if (!child_process.pid) { + dup2(pipe_feed[1], 1); + close(pipe_feed[0]); + close(pipe_feed[1]); + exit(filter_buffer(path, src, *sizep, cmd)); + } + close(pipe_feed[1]); + + dstalloc = *sizep; + dst = xmalloc(dstalloc); + dstsize = 0; + + while (1) { + ssize_t numread = xread(pipe_feed[0], dst + dstsize, + dstalloc - dstsize); + + if (numread <= 0) { + if (!numread) + break; + error("read from external filter %s failed", cmd); + free(dst); + dst = NULL; + break; + } + dstsize += numread; + if (dstalloc <= dstsize + SLOP) { + dstalloc = dstsize + SLOP; + dst = xrealloc(dst, dstalloc); + } + } + if (close(pipe_feed[0])) { + error("read from external filter %s failed", cmd); + free(dst); + dst = NULL; + } + + status = finish_command(&child_process); + if (status) { + error("external filter %s failed %d", cmd, -status); + free(dst); + dst = NULL; + } + + if (dst) + *sizep = dstsize; + return dst; +} + +static struct convert_driver { + const char *name; + struct convert_driver *next; + char *smudge; + char *clean; +} *user_convert, **user_convert_tail; + +static int read_convert_config(const char *var, const char *value) +{ + const char *ep, *name; + int namelen; + struct convert_driver *drv; + + /* + * External conversion drivers are configured using + * "filter..variable". + */ + if (prefixcmp(var, "filter.") || (ep = strrchr(var, '.')) == var + 6) + return 0; + name = var + 7; + namelen = ep - name; + for (drv = user_convert; drv; drv = drv->next) + if (!strncmp(drv->name, name, namelen) && !drv->name[namelen]) + break; + if (!drv) { + char *namebuf; + drv = xcalloc(1, sizeof(struct convert_driver)); + namebuf = xmalloc(namelen + 1); + memcpy(namebuf, name, namelen); + namebuf[namelen] = 0; + drv->name = namebuf; + drv->next = NULL; + *user_convert_tail = drv; + user_convert_tail = &(drv->next); + } + + ep++; + + /* + * filter..smudge and filter..clean specifies + * the command line: + * + * command-line + * + * The command-line will not be interpolated in any way. + */ + + if (!strcmp("smudge", ep)) { + if (!value) + return error("%s: lacks value", var); + drv->smudge = strdup(value); + return 0; + } + + if (!strcmp("clean", ep)) { + if (!value) + return error("%s: lacks value", var); + drv->clean = strdup(value); + return 0; + } + return 0; +} + static void setup_convert_check(struct git_attr_check *check) { static struct git_attr *attr_crlf; static struct git_attr *attr_ident; + static struct git_attr *attr_filter; if (!attr_crlf) { attr_crlf = git_attr("crlf", 4); attr_ident = git_attr("ident", 5); + attr_filter = git_attr("filter", 6); + user_convert_tail = &user_convert; + git_config(read_convert_config); } check[0].attr = attr_crlf; check[1].attr = attr_ident; + check[2].attr = attr_filter; } static int count_ident(const char *cp, unsigned long size) @@ -367,6 +562,20 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check) return CRLF_GUESS; } +static struct convert_driver *git_path_check_convert(const char *path, + struct git_attr_check *check) +{ + const char *value = check->value; + struct convert_driver *drv; + + if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value)) + return NULL; + for (drv = user_convert; drv; drv = drv->next) + if (!strcmp(value, drv->name)) + return drv; + return NULL; +} + static int git_path_check_ident(const char *path, struct git_attr_check *check) { const char *value = check->value; @@ -376,18 +585,29 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check) char *convert_to_git(const char *path, const char *src, unsigned long *sizep) { - struct git_attr_check check[2]; + struct git_attr_check check[3]; int crlf = CRLF_GUESS; int ident = 0; + char *filter = NULL; char *buf, *buf2; setup_convert_check(check); if (!git_checkattr(path, ARRAY_SIZE(check), check)) { + struct convert_driver *drv; crlf = git_path_check_crlf(path, check + 0); ident = git_path_check_ident(path, check + 1); + drv = git_path_check_convert(path, check + 2); + if (drv && drv->clean) + filter = drv->clean; } - buf = crlf_to_git(path, src, sizep, crlf); + buf = apply_filter(path, src, sizep, filter); + + buf2 = crlf_to_git(path, buf ? buf : src, sizep, crlf); + if (buf2) { + free(buf); + buf = buf2; + } buf2 = ident_to_git(path, buf ? buf : src, sizep, ident); if (buf2) { @@ -400,15 +620,20 @@ char *convert_to_git(const char *path, const char *src, unsigned long *sizep) char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep) { - struct git_attr_check check[2]; + struct git_attr_check check[3]; int crlf = CRLF_GUESS; int ident = 0; + char *filter = NULL; char *buf, *buf2; setup_convert_check(check); if (!git_checkattr(path, ARRAY_SIZE(check), check)) { + struct convert_driver *drv; crlf = git_path_check_crlf(path, check + 0); ident = git_path_check_ident(path, check + 1); + drv = git_path_check_convert(path, check + 2); + if (drv && drv->smudge) + filter = drv->smudge; } buf = ident_to_worktree(path, src, sizep, ident); @@ -419,5 +644,11 @@ char *convert_to_working_tree(const char *path, const char *src, unsigned long * buf = buf2; } + buf2 = apply_filter(path, buf ? buf : src, sizep, filter); + if (buf2) { + free(buf); + buf = buf2; + } + return buf; } diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index ad952c9ce2..bab9ecc34e 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -4,8 +4,17 @@ test_description='blob conversion via gitattributes' . ./test-lib.sh +cat <<\EOF >rot13.sh +tr '[a-zA-Z]' '[n-za-mN-ZA-M]' +EOF +chmod +x rot13.sh + test_expect_success setup ' + git config filter.rot13.smudge ./rot13.sh && + git config filter.rot13.clean ./rot13.sh && + { + echo "*.t filter=rot13" echo "*.i ident" } >.gitattributes && From cc2903fc70ea9e1bb7788a6f5f46b5d3dd1b6fe4 Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 25 Apr 2007 11:17:56 -0300 Subject: [PATCH 19/80] remove_subtree(): Use strerror() when possible Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Junio C Hamano --- entry.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/entry.c b/entry.c index 84f78025ff..b51addbf8d 100644 --- a/entry.c +++ b/entry.c @@ -33,7 +33,7 @@ static void remove_subtree(const char *path) char *name; if (!dir) - die("cannot opendir %s", path); + die("cannot opendir %s (%s)", path, strerror(errno)); strcpy(pathbuf, path); name = pathbuf + strlen(path); *name++ = '/'; @@ -45,15 +45,15 @@ static void remove_subtree(const char *path) continue; strcpy(name, de->d_name); if (lstat(pathbuf, &st)) - die("cannot lstat %s", pathbuf); + die("cannot lstat %s (%s)", pathbuf, strerror(errno)); if (S_ISDIR(st.st_mode)) remove_subtree(pathbuf); else if (unlink(pathbuf)) - die("cannot unlink %s", pathbuf); + die("cannot unlink %s (%s)", pathbuf, strerror(errno)); } closedir(dir); if (rmdir(path)) - die("cannot rmdir %s", path); + die("cannot rmdir %s (%s)", path, strerror(errno)); } static int create_file(const char *path, unsigned int mode) From efbc5831264fbe3696e6fc264bba9319265d7344 Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 25 Apr 2007 11:18:08 -0300 Subject: [PATCH 20/80] entry.c: Use const qualifier for 'struct checkout' parameters Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Junio C Hamano --- cache.h | 2 +- entry.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cache.h b/cache.h index f05b67ad45..38a0cbd580 100644 --- a/cache.h +++ b/cache.h @@ -409,7 +409,7 @@ struct checkout { refresh_cache:1; }; -extern int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath); +extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); extern struct alternate_object_database { struct alternate_object_database *next; diff --git a/entry.c b/entry.c index b51addbf8d..82bf7259a7 100644 --- a/entry.c +++ b/entry.c @@ -1,7 +1,7 @@ #include "cache.h" #include "blob.h" -static void create_directories(const char *path, struct checkout *state) +static void create_directories(const char *path, const struct checkout *state) { int len = strlen(path); char *buf = xmalloc(len + 1); @@ -75,7 +75,7 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned return NULL; } -static int write_entry(struct cache_entry *ce, char *path, struct checkout *state, int to_tempfile) +static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile) { int fd; long wrote; @@ -163,7 +163,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat return 0; } -int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath) +int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath) { static char path[PATH_MAX + 1]; struct stat st; From 3511a3774e60783d979ebc2ef7b04371a23602bb Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 25 Apr 2007 11:18:17 -0300 Subject: [PATCH 21/80] read_cache_from(): small simplification This change 'opens' the code block which maps the index file into memory, making the code clearer and easier to read. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Junio C Hamano --- read-cache.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/read-cache.c b/read-cache.c index e04e99112d..d9f46da5cc 100644 --- a/read-cache.c +++ b/read-cache.c @@ -864,16 +864,15 @@ int read_index_from(struct index_state *istate, const char *path) die("index file open failed (%s)", strerror(errno)); } - if (!fstat(fd, &st)) { - istate->mmap_size = xsize_t(st.st_size); - errno = EINVAL; - if (istate->mmap_size >= sizeof(struct cache_header) + 20) - istate->mmap = xmmap(NULL, istate->mmap_size, - PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - else - die("index file smaller than expected"); - } else + if (fstat(fd, &st)) die("cannot stat the open index (%s)", strerror(errno)); + + errno = EINVAL; + istate->mmap_size = xsize_t(st.st_size); + if (istate->mmap_size < sizeof(struct cache_header) + 20) + die("index file smaller than expected"); + + istate->mmap = xmmap(NULL, istate->mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); close(fd); hdr = istate->mmap; From 79dbbedd78ae064be6bb8a0f61fd4872222e47dd Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 25 Apr 2007 11:18:28 -0300 Subject: [PATCH 22/80] core-tutorial: minor fixes - Do not break the line when it's not needed - s/Your/You Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Junio C Hamano --- Documentation/core-tutorial.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/core-tutorial.txt b/Documentation/core-tutorial.txt index 97cdb90cb4..6b9b9ad7d1 100644 --- a/Documentation/core-tutorial.txt +++ b/Documentation/core-tutorial.txt @@ -319,10 +319,9 @@ argument to `git-commit-tree`. `git-commit-tree` normally takes several arguments -- it wants to know what the 'parent' of a commit was, but since this is the first commit ever in this new repository, and it has no parents, we only need to pass in -the object name of the tree. However, `git-commit-tree` -also wants to get a commit message -on its standard input, and it will write out the resulting object name for the -commit to its standard output. +the object name of the tree. However, `git-commit-tree` also wants to get a +commit message on its standard input, and it will write out the resulting +object name for the commit to its standard output. And this is where we create the `.git/refs/heads/master` file which is pointed at by `HEAD`. This file is supposed to contain @@ -1304,7 +1303,7 @@ So, we can use somebody else's work from a remote repository, but how can *you* prepare a repository to let other people pull from it? -Your do your real work in your working tree that has your +You do your real work in your working tree that has your primary repository hanging under it as its `.git` subdirectory. You *could* make that repository accessible remotely and ask people to pull from it, but in practice that is not the way From 3e0a93a5bf9fe10453599a94af8191f421ee3b16 Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 25 Apr 2007 11:18:41 -0300 Subject: [PATCH 23/80] init_buffer(): Kill buf pointer We don't need it, it's possible to assign the block of memory to bufp Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Junio C Hamano --- builtin-commit-tree.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 4a8d8d8b67..ccbcbe30da 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -16,9 +16,8 @@ */ static void init_buffer(char **bufp, unsigned int *sizep) { - char *buf = xmalloc(BLOCKING); + *bufp = xmalloc(BLOCKING); *sizep = 0; - *bufp = buf; } static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...) From d1efefa46fda6bb68bcd73a5e532eef98ef28a1d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 25 Apr 2007 04:02:27 -0400 Subject: [PATCH 24/80] Actually handle some-low memory conditions Tim Ansell discovered his Debian server didn't permit git-daemon to use as much memory as it needed to handle cloning a project with a 128 MiB packfile. Filtering the strace provided by Tim of the rev-list child showed this gem of a sequence: open("./objects/pack/pack-*.pack", O_RDONLY|O_LARGEFILE <... open resumed> ) = 5 OK, so the packfile is fd 5... mmap2(NULL, 33554432, PROT_READ, MAP_PRIVATE, 5, 0 <... mmap2 resumed> ) = 0xb5e2d000 and we mapped one 32 MiB window from it at position 0... mmap2(NULL, 31020635, PROT_READ, MAP_PRIVATE, 5, 0x6000 <... mmap2 resumed> ) = -1 ENOMEM (Cannot allocate memory) And we asked for another window further into the file. But got denied. In Tim's case this was due to a resource limit on the git-daemon process, and its children. Now where are we in the code? We're down inside use_pack(), after we have called unuse_one_window() enough times to make sure we stay within our allowed maximum window size. However since we didn't unmap the prior window at 0xb5e2d000 we aren't exceeding the current limit (which probably was just the defaults). But we're actually down inside xmmap()... So we release the window we do have (by calling release_pack_memory), assuming there is some memory pressure... munmap(0xb5e2d000, 33554432 <... munmap resumed> ) = 0 close(5 <... close resumed> ) = 0 And that was the last window in this packfile. So we closed it. Way to go us. Our xmmap did not expect release_pack_memory to close the fd its about to map... mmap2(NULL, 31020635, PROT_READ, MAP_PRIVATE, 5, 0x6000 <... mmap2 resumed> ) = -1 EBADF (Bad file descriptor) And so the Linux kernel happily tells us f' off. write(2, "fatal: ", 7 <... write resumed> ) = 7 write(2, "Out of memory? mmap failed: Bad "..., 47 <... write resumed> ) = 47 And we report the bad file descriptor error, and not the ENOMEM, and die, claiming we are out of memory. But actually that mmap should have succeeded, as we had enough memory for that window, seeing as how we released the prior one. Originally when I developed the sliding window mmap feature I had this exact same bug in fast-import, and I dealt with it by handing in the struct packed_git* we want to open the new window for, as the caller wasn't prepared to reopen the packfile if unuse_one_window closed it. The same is true here from xmmap, but the caller doesn't have the struct packed_git* handy. So I'm using the file descriptor instead to perform the same test. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-compat-util.h | 12 ++++++------ sha1_file.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 5f6a281b78..e3cf3703bb 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -156,13 +156,13 @@ extern size_t gitstrlcpy(char *, const char *, size_t); extern uintmax_t gitstrtoumax(const char *, char **, int); #endif -extern void release_pack_memory(size_t); +extern void release_pack_memory(size_t, int); static inline char* xstrdup(const char *str) { char *ret = strdup(str); if (!ret) { - release_pack_memory(strlen(str) + 1); + release_pack_memory(strlen(str) + 1, -1); ret = strdup(str); if (!ret) die("Out of memory, strdup failed"); @@ -176,7 +176,7 @@ static inline void *xmalloc(size_t size) if (!ret && !size) ret = malloc(1); if (!ret) { - release_pack_memory(size); + release_pack_memory(size, -1); ret = malloc(size); if (!ret && !size) ret = malloc(1); @@ -195,7 +195,7 @@ static inline void *xrealloc(void *ptr, size_t size) if (!ret && !size) ret = realloc(ptr, 1); if (!ret) { - release_pack_memory(size); + release_pack_memory(size, -1); ret = realloc(ptr, size); if (!ret && !size) ret = realloc(ptr, 1); @@ -211,7 +211,7 @@ static inline void *xcalloc(size_t nmemb, size_t size) if (!ret && (!nmemb || !size)) ret = calloc(1, 1); if (!ret) { - release_pack_memory(nmemb * size); + release_pack_memory(nmemb * size, -1); ret = calloc(nmemb, size); if (!ret && (!nmemb || !size)) ret = calloc(1, 1); @@ -228,7 +228,7 @@ static inline void *xmmap(void *start, size_t length, if (ret == MAP_FAILED) { if (!length) return NULL; - release_pack_memory(length); + release_pack_memory(length, fd); ret = mmap(start, length, prot, flags, fd, offset); if (ret == MAP_FAILED) die("Out of memory? mmap failed: %s", strerror(errno)); diff --git a/sha1_file.c b/sha1_file.c index 9c26038420..523417027a 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -516,7 +516,7 @@ static void scan_windows(struct packed_git *p, } } -static int unuse_one_window(struct packed_git *current) +static int unuse_one_window(struct packed_git *current, int keep_fd) { struct packed_git *p, *lru_p = NULL; struct pack_window *lru_w = NULL, *lru_l = NULL; @@ -532,7 +532,7 @@ static int unuse_one_window(struct packed_git *current) lru_l->next = lru_w->next; else { lru_p->windows = lru_w->next; - if (!lru_p->windows && lru_p != current) { + if (!lru_p->windows && lru_p->pack_fd != keep_fd) { close(lru_p->pack_fd); lru_p->pack_fd = -1; } @@ -544,10 +544,10 @@ static int unuse_one_window(struct packed_git *current) return 0; } -void release_pack_memory(size_t need) +void release_pack_memory(size_t need, int fd) { size_t cur = pack_mapped; - while (need >= (cur - pack_mapped) && unuse_one_window(NULL)) + while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd)) ; /* nothing */ } @@ -680,7 +680,7 @@ unsigned char* use_pack(struct packed_git *p, win->len = (size_t)len; pack_mapped += win->len; while (packed_git_limit < pack_mapped - && unuse_one_window(p)) + && unuse_one_window(p, p->pack_fd)) ; /* nothing */ win->base = xmmap(NULL, win->len, PROT_READ, MAP_PRIVATE, From c21aa54e190e6527f05a2a943b343032e9dac90b Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Thu, 26 Apr 2007 00:28:17 +0200 Subject: [PATCH 25/80] Fix handle leak in write_tree This is a quick and dirty fix for the broken "git cherry-pick -n" on some broken OS, which does not remove the directory entry after unlink succeeded(!) if the file is still open somewher. The entry is left but "protected": no open, no unlink, no stat. Very annoying. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-write-tree.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/builtin-write-tree.c b/builtin-write-tree.c index 90fc1cfcf4..a1894814f7 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -36,8 +36,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix) die("git-write-tree: error building trees"); if (0 <= newfd) { if (!write_cache(newfd, active_cache, active_nr) - && !close(newfd)) + && !close(newfd)) { commit_lock_file(lock_file); + newfd = -1; + } } /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller @@ -55,6 +57,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix) else hashcpy(sha1, active_cache_tree->sha1); + if (0 <= newfd) + close(newfd); rollback_lock_file(lock_file); return 0; From b03c7a63a0fae58a576749d7a6b0507edde12584 Mon Sep 17 00:00:00 2001 From: Adam Roben Date: Wed, 25 Apr 2007 11:50:32 -0700 Subject: [PATCH 26/80] git-svn: Don't rely on $_ after making a function call Many functions and operators in perl set $_, so its value cannot be relied upon after calling arbitrary functions. The solution is simply to copy the value of $_ into a local variable that will not get overwritten. Signed-off-by: Adam Roben Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 077d6b3a13..90f3bc18b9 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -771,19 +771,19 @@ sub cmt_metadata { sub working_head_info { my ($head, $refs) = @_; my ($fh, $ctx) = command_output_pipe('rev-list', $head); - while (<$fh>) { - chomp; - my ($url, $rev, $uuid) = cmt_metadata($_); + while (my $hash = <$fh>) { + chomp($hash); + my ($url, $rev, $uuid) = cmt_metadata($hash); if (defined $url && defined $rev) { if (my $gs = Git::SVN->find_by_url($url)) { my $c = $gs->rev_db_get($rev); - if ($c && $c eq $_) { + if ($c && $c eq $hash) { close $fh; # break the pipe return ($url, $rev, $uuid, $gs); } } } - unshift @$refs, $_ if $refs; + unshift @$refs, $hash if $refs; } command_close_pipe($fh, $ctx); (undef, undef, undef, undef); From 238cc6352eabe3f87f13093bc4015162bf424509 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:15 -0700 Subject: [PATCH 27/80] Document --dry-run parameter to send-email. Looks like --dry-run was added to the code, but never to the --help output. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/git-send-email.perl b/git-send-email.perl index 1278fcba46..5e38a97cb6 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -77,6 +77,8 @@ Options: --quiet Make git-send-email less verbose. One line per email should be all that is output. + --dry-run Do everything except actually send the emails. + EOT exit(1); } From 71c7da94218fbe36e64a326825ff30ef811b2a88 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:16 -0700 Subject: [PATCH 28/80] Prefix Dry- to the message status to denote dry-runs. While doing testing, it's useful to see that a dry run was actually done, instead of a real one. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index 5e38a97cb6..50d45fe005 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -488,9 +488,9 @@ X-Mailer: git-send-email $gitversion $smtp->ok or die "Failed to send $subject\n".$smtp->message; } if ($quiet) { - printf "Sent %s\n", $subject; + printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { - print "OK. Log says:\nDate: $date\n"; + print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n"); if ($smtp) { print "Server: $smtp_server\n"; } else { From 8e3d436b0b5148bac11259bac55621e285eeb6c4 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:17 -0700 Subject: [PATCH 29/80] Debugging cleanup improvements The debug output is much more helpful if it has the parameters that were used. Pull the sendmail parameters into a seperate array for that, and also include similar data during the Net::SMTP case. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index 50d45fe005..36795c8bdd 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -465,15 +465,15 @@ X-Mailer: git-send-email $gitversion $header .= join("\n", @xh) . "\n"; } + my @sendmail_parameters = ('-i', map { extract_valid_address($_) } @recipients); + if ($dry_run) { # We don't want to send the email. } elsif ($smtp_server =~ m#^/#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { - exec($smtp_server,'-i', - map { extract_valid_address($_) } - @recipients) or die $!; + exec($smtp_server, @sendmail_parameters) or die $!; } print $sm "$header\n$message"; close $sm or die $?; @@ -493,8 +493,10 @@ X-Mailer: git-send-email $gitversion print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n"); if ($smtp) { print "Server: $smtp_server\n"; + print "MAIL FROM: $from\n"; + print "RCPT TO: ".join(',',@recipients)."\n"; } else { - print "Sendmail: $smtp_server\n"; + print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n"; } print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n"; if ($smtp) { From af068d274245be9aedc58e6835c2e43329639974 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:18 -0700 Subject: [PATCH 30/80] Change the scope of the $cc variable as it is not needed outside of send_message. $cc is only used inside the send_message scope, so lets clean it out of the global scope. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index 36795c8bdd..ad83009e23 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -379,7 +379,7 @@ if (@files) { } # Variables we set as part of the loop over files -our ($message_id, $cc, %mail, $subject, $reply_to, $references, $message); +our ($message_id, %mail, $subject, $reply_to, $references, $message); sub extract_valid_address { my $address = shift; @@ -420,7 +420,6 @@ sub make_message_id -$cc = ""; $time = time - scalar $#files; sub unquote_rfc2047 { @@ -443,7 +442,8 @@ sub send_message $gitversion = Git::version(); } - my ($author_name) = ($from =~ /^(.*?)\s+ Date: Wed, 25 Apr 2007 19:37:19 -0700 Subject: [PATCH 31/80] Perform correct quoting of recipient names. Always perform quoting of the recipient names if they contain periods, previously only the author's address was treated this way. This stops sendmail binaries from exploding the name into bad addresses. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index ad83009e23..e4fe8965bb 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -431,9 +431,22 @@ sub unquote_rfc2047 { return "$_"; } +# If an address contains a . in the name portion, the name must be quoted. +sub sanitize_address_rfc822 +{ + my ($recipient) = @_; + my ($recipient_name) = ($recipient =~ /^(.*?)\s+ Date: Wed, 25 Apr 2007 19:37:20 -0700 Subject: [PATCH 32/80] Validate @recipients before using it for sendmail and Net::SMTP. Ensure that @recipients is only raw addresses when it is handed to the sendmail binary OR Net::SMTP, otherwise BCC cases might get an extra <, or wierd stuff might be passed to the exec. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index e4fe8965bb..b602292904 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -449,6 +449,7 @@ sub send_message @cc = (map { sanitize_address_rfc822($_) } @cc); my $to = join (",\n\t", @recipients); @recipients = unique_email_list(@recipients,@cc,@bcclist); + @recipients = (map { extract_valid_address($_) } @recipients); my $date = format_2822_time($time++); my $gitversion = '@@GIT_VERSION@@'; if ($gitversion =~ m/..GIT_VERSION../) { @@ -474,7 +475,7 @@ X-Mailer: git-send-email $gitversion $header .= join("\n", @xh) . "\n"; } - my @sendmail_parameters = ('-i', map { extract_valid_address($_) } @recipients); + my @sendmail_parameters = ('-i', @recipients); if ($dry_run) { # We don't want to send the email. From 2b69bfc23d89d2ec5507bc6906b533e8429b313d Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:21 -0700 Subject: [PATCH 33/80] Ensure clean addresses are always used with Net::SMTP Always pass in clean addresses to Net::SMTP for the MAIL FROM, and use them on the SMTP non-quiet output as well. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index b602292904..35c4722a15 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -476,6 +476,7 @@ X-Mailer: git-send-email $gitversion } my @sendmail_parameters = ('-i', @recipients); + my $raw_from = extract_valid_address($from); if ($dry_run) { # We don't want to send the email. @@ -490,7 +491,7 @@ X-Mailer: git-send-email $gitversion } else { require Net::SMTP; $smtp ||= Net::SMTP->new( $smtp_server ); - $smtp->mail( $from ) or die $smtp->message; + $smtp->mail( $raw_from ) or die $smtp->message; $smtp->to( @recipients ) or die $smtp->message; $smtp->data or die $smtp->message; $smtp->datasend("$header\n$message") or die $smtp->message; @@ -501,10 +502,10 @@ X-Mailer: git-send-email $gitversion printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n"); - if ($smtp) { + if ($smtp_server !~ m#^/#) { print "Server: $smtp_server\n"; - print "MAIL FROM: $from\n"; - print "RCPT TO: ".join(',',@recipients)."\n"; + print "MAIL FROM:<$raw_from>\n"; + print "RCPT TO:".join(',',(map { "<$_>" } @recipients))."\n"; } else { print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n"; } From f073a592d6400b3aa653ce02943535bf917078b5 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:22 -0700 Subject: [PATCH 34/80] Allow users to optionally specify their envelope sender. If your normal user is not the same user you are subscribed to a list with, then the default envelope sender used will cause your messages to bounce or silently vanish into the ether. This patch provides an optional parameter to set the envelope sender. To use it with the sendmail binary, you must have privileges to use the -f parameter! Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 35c4722a15..56c2936f27 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -79,6 +79,8 @@ Options: --dry-run Do everything except actually send the emails. + --envelope-sender Specify the envelope sender used to send the emails. + EOT exit(1); } @@ -139,6 +141,7 @@ my (@to,@cc,@initial_cc,@bcclist,@xh, my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc, $dry_run) = (1, 0, 0, 0, 0); my $smtp_server; +my $envelope_sender; # Example reply to: #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>'; @@ -177,6 +180,7 @@ my $rc = GetOptions("from=s" => \$from, "suppress-from" => \$suppress_from, "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc, "dry-run" => \$dry_run, + "envelope-sender=s" => \$envelope_sender, ); unless ($rc) { @@ -476,7 +480,11 @@ X-Mailer: git-send-email $gitversion } my @sendmail_parameters = ('-i', @recipients); - my $raw_from = extract_valid_address($from); + my $raw_from = $from; + $raw_from = $envelope_sender if (defined $envelope_sender); + $raw_from = extract_valid_address($raw_from); + unshift (@sendmail_parameters, + '-f', $raw_from) if(defined $envelope_sender); if ($dry_run) { # We don't want to send the email. From 03044a9854b006a64c5117d971b01c1d1586edd9 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 19:37:23 -0700 Subject: [PATCH 35/80] Document --dry-run and envelope-sender for git-send-email. Catch the documentation up with the rest of this patchset. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- Documentation/git-send-email.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 682313e95d..795db873fc 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -85,6 +85,15 @@ The --cc option must be repeated for each user you want on the cc list. Do not add the From: address to the cc: list, if it shows up in a From: line. +--dry-run:: + Do everything except actually send the emails. + +--envelope-sender:: + Specify the envelope sender used to send the emails. + This is useful if your default address is not the address that is + subscribed to a list. If you use the sendmail binary, you must have + suitable privileges for the -f parameter. + --to:: Specify the primary recipient of the emails generated. Generally, this will be the upstream maintainer of the From a7b02ccf9a682fa0c2b28df6ca20f9199cdca4de Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 24 Apr 2007 23:36:22 -0700 Subject: [PATCH 36/80] Add --date={local,relative,default} This adds --date={local,relative,default} option to log family of commands, to allow displaying timestamps in user's local timezone, relative time, or the default format. Existing --relative-date option is a synonym of --date=relative; we could probably deprecate it in the long run. Signed-off-by: Junio C Hamano --- Documentation/git-rev-list.txt | 14 +++++++++++++- builtin-rev-list.c | 2 +- cache.h | 2 +- commit.c | 12 ++++++------ commit.h | 2 +- date.c | 35 ++++++++++++++++++++++++++++++++-- log-tree.c | 4 ++-- revision.c | 13 ++++++++++++- revision.h | 4 ++-- 9 files changed, 71 insertions(+), 17 deletions(-) diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 77e068b15f..1b12b4f2a4 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -25,6 +25,7 @@ SYNOPSIS [ \--cherry-pick ] [ \--encoding[=] ] [ \--(author|committer|grep)= ] + [ \--date={local|relative|default} ] [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] [ \--bisect ] @@ -90,9 +91,20 @@ include::pretty-formats.txt[] --relative-date:: - Show dates relative to the current time, e.g. "2 hours ago". + Synonym for `--date=relative`. + +--date={relative,local,default}:: + Only takes effect for dates shown in human-readable format, such as when using "--pretty". ++ +`--date=relative` shows dates relative to the current time, +e.g. "2 hours ago". ++ +`--date=local` shows timestamps in user's local timezone. ++ +`--date=default` shows timestamps in the original timezone +(either committer's or author's). --header:: diff --git a/builtin-rev-list.c b/builtin-rev-list.c index c0329dcecd..ebf53f5944 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -95,7 +95,7 @@ static void show_commit(struct commit *commit) static char pretty_header[16384]; pretty_print_commit(revs.commit_format, commit, ~0, pretty_header, sizeof(pretty_header), - revs.abbrev, NULL, NULL, revs.relative_date); + revs.abbrev, NULL, NULL, revs.date_mode); printf("%s%c", pretty_header, hdr_termination); } fflush(stdout); diff --git a/cache.h b/cache.h index 38a0cbd580..8e76152645 100644 --- a/cache.h +++ b/cache.h @@ -389,7 +389,7 @@ extern void *read_object_with_reference(const unsigned char *sha1, unsigned long *size, unsigned char *sha1_ret); -enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT }; +enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT, DATE_LOCAL }; const char *show_date(unsigned long time, int timezone, enum date_mode mode); const char *show_rfc2822_date(unsigned long time, int timezone); int parse_date(const char *date, char *buf, int bufsize); diff --git a/commit.c b/commit.c index 10466c4ae0..f1ba972d9a 100644 --- a/commit.c +++ b/commit.c @@ -526,7 +526,7 @@ static int add_rfc2047(char *buf, const char *line, int len, } static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, - const char *line, int relative_date, + const char *line, enum date_mode dmode, const char *encoding) { char *date; @@ -569,7 +569,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, switch (fmt) { case CMIT_FMT_MEDIUM: ret += sprintf(buf + ret, "Date: %s\n", - show_date(time, tz, relative_date)); + show_date(time, tz, dmode)); break; case CMIT_FMT_EMAIL: ret += sprintf(buf + ret, "Date: %s\n", @@ -577,7 +577,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, break; case CMIT_FMT_FULLER: ret += sprintf(buf + ret, "%sDate: %s\n", what, - show_date(time, tz, relative_date)); + show_date(time, tz, dmode)); break; default: /* notin' */ @@ -919,7 +919,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, - int relative_date) + enum date_mode dmode) { int hdr = 1, body = 0, seen_title = 0; unsigned long offset = 0; @@ -1023,14 +1023,14 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, offset += add_user_info("Author", fmt, buf + offset, line + 7, - relative_date, + dmode, encoding); if (!memcmp(line, "committer ", 10) && (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) offset += add_user_info("Commit", fmt, buf + offset, line + 10, - relative_date, + dmode, encoding); continue; } diff --git a/commit.h b/commit.h index 59de17eff8..86e8dca0c9 100644 --- a/commit.h +++ b/commit.h @@ -61,7 +61,7 @@ enum cmit_fmt { }; extern enum cmit_fmt get_commit_format(const char *arg); -extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, int relative_date); +extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode); /** Removes the first commit from a list sorted by date, and adds all * of its parents. diff --git a/date.c b/date.c index 0ceccbe034..a9b59a289e 100644 --- a/date.c +++ b/date.c @@ -55,6 +55,32 @@ static struct tm *time_to_tm(unsigned long time, int tz) return gmtime(&t); } +/* + * What value of "tz" was in effect back then at "time" in the + * local timezone? + */ +static int local_tzoffset(unsigned long time) +{ + time_t t, t_local; + struct tm tm; + int offset, eastwest; + + t = time; + localtime_r(&t, &tm); + t_local = my_mktime(&tm); + + if (t_local < t) { + eastwest = -1; + offset = t - t_local; + } else { + eastwest = 1; + offset = t_local - t; + } + offset /= 60; /* in minutes */ + offset = (offset % 60) + ((offset / 60) * 100); + return offset * eastwest; +} + const char *show_date(unsigned long time, int tz, enum date_mode mode) { struct tm *tm; @@ -102,6 +128,9 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) /* Else fall back on absolute format.. */ } + if (mode == DATE_LOCAL) + tz = local_tzoffset(time); + tm = time_to_tm(time, tz); if (!tm) return NULL; @@ -109,12 +138,14 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) sprintf(timebuf, "%04d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); else - sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d %+05d", + sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d", weekday_names[tm->tm_wday], month_names[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_year + 1900, tz); + tm->tm_year + 1900, + (mode == DATE_LOCAL) ? 0 : ' ', + tz); return timebuf; } diff --git a/log-tree.c b/log-tree.c index 300b733560..c679324c07 100644 --- a/log-tree.c +++ b/log-tree.c @@ -267,7 +267,7 @@ void show_log(struct rev_info *opt, const char *sep) if (opt->reflog_info) { show_reflog_message(opt->reflog_info, opt->commit_format == CMIT_FMT_ONELINE, - opt->relative_date); + opt->date_mode); if (opt->commit_format == CMIT_FMT_ONELINE) { printf("%s", sep); return; @@ -280,7 +280,7 @@ void show_log(struct rev_info *opt, const char *sep) */ len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev, subject, - extra_headers, opt->relative_date); + extra_headers, opt->date_mode); if (opt->add_signoff) len = append_signoff(this_header, sizeof(this_header), len, diff --git a/revision.c b/revision.c index 49bd29225b..e60a26c6bb 100644 --- a/revision.c +++ b/revision.c @@ -1111,7 +1111,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch continue; } if (!strcmp(arg, "--relative-date")) { - revs->relative_date = 1; + revs->date_mode = DATE_RELATIVE; + continue; + } + if (!strncmp(arg, "--date=", 7)) { + if (!strcmp(arg + 7, "relative")) + revs->date_mode = DATE_RELATIVE; + else if (!strcmp(arg + 7, "local")) + revs->date_mode = DATE_LOCAL; + else if (!strcmp(arg + 7, "default")) + revs->date_mode = DATE_NORMAL; + else + die("unknown date format %s", arg); continue; } diff --git a/revision.h b/revision.h index 5b41e2da20..cdf94ad695 100644 --- a/revision.h +++ b/revision.h @@ -63,8 +63,8 @@ struct rev_info { /* Format info */ unsigned int shown_one:1, - abbrev_commit:1, - relative_date:1; + abbrev_commit:1; + enum date_mode date_mode; const char **ignore_packed; /* pretend objects in these are unpacked */ int num_ignore_packed; From 56973d20c181abdc5cc13eab976733feec0c590b Mon Sep 17 00:00:00 2001 From: Adam Roben Date: Wed, 25 Apr 2007 12:42:58 -0700 Subject: [PATCH 37/80] git-svn: Ignore usernames in URLs in find_by_url Usernames don't matter for the purposes of find_by_url, so always remove them before doing any comparisons. Signed-off-by: Adam Roben Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-svn.perl b/git-svn.perl index 90f3bc18b9..7b5f8ab3be 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1064,7 +1064,10 @@ sub init_remote_config { sub find_by_url { # repos_root and, path are optional my ($class, $full_url, $repos_root, $path) = @_; + return undef unless defined $full_url; + remove_username($full_url); + remove_username($repos_root) if defined $repos_root; my $remotes = read_all_remotes(); if (defined $full_url && defined $repos_root && !defined $path) { $path = $full_url; @@ -1072,6 +1075,7 @@ sub find_by_url { # repos_root and, path are optional } foreach my $repo_id (keys %$remotes) { my $u = $remotes->{$repo_id}->{url} or next; + remove_username($u); next if defined $repos_root && $repos_root ne $u; my $fetch = $remotes->{$repo_id}->{fetch} || {}; From bf7af1167411cbdd5ade7587a64b18d1b7b2ea69 Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Wed, 25 Apr 2007 21:53:22 -0700 Subject: [PATCH 38/80] Sanitize @to recipients. We need to sanitize @to as well to ensure that names are properly quoted. Signed-off-by: Robin H. Johnson Signed-off-by: Junio C Hamano --- git-send-email.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-send-email.perl b/git-send-email.perl index 56c2936f27..12ced28885 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -274,6 +274,7 @@ sub expand_aliases { } @to = expand_aliases(@to); +@to = (map { sanitize_address_rfc822($_) } @to); @initial_cc = expand_aliases(@initial_cc); @bcclist = expand_aliases(@bcclist); From 8abe88a29c0789276c6d028b76b1190630b101c6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 25 Apr 2007 23:27:07 -0700 Subject: [PATCH 39/80] Start preparing for 1.5.1.3 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.1.3.txt | 38 ++++++++++++++++++++++++++++++ RelNotes | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Documentation/RelNotes-1.5.1.3.txt diff --git a/Documentation/RelNotes-1.5.1.3.txt b/Documentation/RelNotes-1.5.1.3.txt new file mode 100644 index 0000000000..9a4b069ccc --- /dev/null +++ b/Documentation/RelNotes-1.5.1.3.txt @@ -0,0 +1,38 @@ +GIT v1.5.1.3 Release Notes (draft) +========================== + +Fixes since v1.5.1.2 +-------------------- + +* Bugfixes + + - git-add tried to optimize by finding common leading + directories across its arguments but botched, causing very + confused behaviour. + + - unofficial rpm.spec file shipped with git was letting + ETC_GITCONFIG set to /usr/etc/gitconfig. Tweak the official + Makefile to make it harder for distro people to make the + same mistake, by setting the variable to /etc/gitconfig if + prefix is set to /usr. + + - git-svn inconsistently stripped away username from the URL + only when svnsync_props was in use. + + - git-send-email was not quoting recipient names that have + period '.' in them. Also it did not allow overriding + envelope sender, which made it impossible to send patches to + certain subscriber-only lists. + + - built-in write_tree() routine had a sequence that renamed a + file that is still open, which some systems did not like. + + - when memory is very tight, sliding mmap code to read + packfiles incorrectly closed the fd that was still being + used to read the pack. + +--- +exec >/var/tmp/1 +O=v1.5.1.2-23-gbf7af11 +echo O=`git describe refs/heads/maint` +git shortlog --no-merges $O..refs/heads/maint diff --git a/RelNotes b/RelNotes index 09f5a7413c..b630faa0c0 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes-1.5.1.2.txt \ No newline at end of file +Documentation/RelNotes-1.5.1.3.txt \ No newline at end of file From c135ee88f8584996ead993c76015d2c03798ab9e Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 25 Apr 2007 22:06:59 +0200 Subject: [PATCH 40/80] Avoid excessive rewrites in merge-recursive If a file is changed in one branch, and renamed and changed to the same content in another branch than we can skip the rewrite of this file in the working directory, as the content does not change. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- merge-recursive.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 403a4c8bca..37f1ba93fe 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1342,20 +1342,26 @@ static int process_renames(struct path_list *a_renames, mfi = merge_file(o, a, b, a_branch, b_branch); - if (mfi.merge || !mfi.clean) - output(1, "Renamed %s => %s", ren1_src, ren1_dst); - if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); - if (!mfi.clean) { - output(1, "CONFLICT (rename/modify): Merge conflict in %s", - ren1_dst); - clean_merge = 0; + if (mfi.merge && mfi.clean && + sha_eq(mfi.sha, ren1->pair->two->sha1) && + mfi.mode == ren1->pair->two->mode) + output(3, "Skipped %s (merged same as existing)", ren1_dst); + else { + if (mfi.merge || !mfi.clean) + output(1, "Renamed %s => %s", ren1_src, ren1_dst); + if (mfi.merge) + output(2, "Auto-merged %s", ren1_dst); + if (!mfi.clean) { + output(1, "CONFLICT (rename/modify): Merge conflict in %s", + ren1_dst); + clean_merge = 0; - if (!index_only) - update_stages(ren1_dst, - o, a, b, 1); + if (!index_only) + update_stages(ren1_dst, + o, a, b, 1); + } + update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); } - update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } } From 8a359819273a4460d5806d2d5e76cd7993a84843 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 25 Apr 2007 22:07:45 +0200 Subject: [PATCH 41/80] Add a test for merging changed and rename-changed branches Also leave a warning for future merge-recursive explorers. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- merge-recursive.c | 5 +++++ t/t6022-merge-rename.sh | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/merge-recursive.c b/merge-recursive.c index 37f1ba93fe..094ac59e69 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1345,6 +1345,11 @@ static int process_renames(struct path_list *a_renames, if (mfi.merge && mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) + /* + * This messaged is part of + * t6022 test. If you change + * it update the test too. + */ output(3, "Skipped %s (merged same as existing)", ren1_dst); else { if (mfi.merge || !mfi.clean) diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index b608e202c1..e3f7ae8120 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -47,6 +47,8 @@ git branch white && git branch red && git branch blue && git branch yellow && +git branch change && +git branch change+rename && sed -e "/^g /s/.*/g : master changes a line/" A+ && mv A+ A && @@ -77,6 +79,17 @@ rm -f A M && git update-index --add --remove A C M N && git commit -m "blue renames A->C, M->N" && +git checkout change && +sed -e "/^g /s/.*/g : changed line/" A+ && +mv A+ A && +git commit -q -a -m "changed" && + +git checkout change+rename && +sed -e "/^g /s/.*/g : changed line/" B && +rm A && +git update-index --add B && +git commit -q -a -m "changed and renamed" && + git checkout master' test_expect_success 'pull renaming branch into unrenaming one' \ @@ -318,4 +331,14 @@ test_expect_success 'interference with untracked working tree file' ' git reset --hard anchor ' +test_expect_success 'merge of identical changes in a renamed file' ' + rm -f A M N + git reset --hard && + git checkout change+rename && + GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" && + git reset --hard HEAD^ && + git checkout change && + GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B" +' + test_done From 0d5e6c9781aae33795243452fd50663d17ec2b9d Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Thu, 26 Apr 2007 21:13:49 +0200 Subject: [PATCH 42/80] Ignore merged status of the file-level merge as it is not relevant for whether the result should be written. Even if no real merge happened, there might be _no_ reason to rewrite the working tree file. Maybe even more so. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- merge-recursive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/merge-recursive.c b/merge-recursive.c index 094ac59e69..8f72b2c079 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1342,7 +1342,7 @@ static int process_renames(struct path_list *a_renames, mfi = merge_file(o, a, b, a_branch, b_branch); - if (mfi.merge && mfi.clean && + if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) /* From 8e404f82abdfd912ad43c6fae7c218ff75a5d122 Mon Sep 17 00:00:00 2001 From: Andy Parkins Date: Thu, 26 Apr 2007 22:35:39 +0100 Subject: [PATCH 43/80] post-receive-email example hook: fastforward should have been fast_forward Signed-off-by: Andy Parkins Signed-off-by: Junio C Hamano --- contrib/hooks/post-receive-email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index 65160153ee..edb30f6f0f 100644 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -302,7 +302,7 @@ generate_update_branch_email() # List all of the revisions that were removed by this update, in a fast forward # update, this list will be empty, because rev-list O ^N is empty. For a non # fast forward, O ^N is the list of removed revisions - fastforward="" + fast_forward="" rev="" for rev in $(git rev-list $newrev..$oldrev) do From 024e5b31af6f06d39542ab1a44de358d7734388b Mon Sep 17 00:00:00 2001 From: Andy Parkins Date: Thu, 26 Apr 2007 22:36:24 +0100 Subject: [PATCH 44/80] post-receive-email example hook: detect rewind-only updates and output sensible message Sometimes a non-fast-forward update doesn't add new commits, it merely removes old commits. This patch adds support for detecting that and outputting a more correct message. Signed-off-by: Andy Parkins Signed-off-by: Junio C Hamano --- contrib/hooks/post-receive-email | 77 ++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index edb30f6f0f..e175b426a4 100644 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -327,36 +327,67 @@ generate_update_branch_email() if [ -z "$fastforward" ]; then echo " from $oldrev ($oldrev_type)" else + # 1. Existing revisions were removed. In this case newrev is a + # subset of oldrev - this is the reverse of a fast-forward, + # a rewind + # 2. New revisions were added on top of an old revision, this is + # a rewind and addition. + + # (1) certainly happened, (2) possibly. When (2) hasn't happened, + # we set a flag to indicate that no log printout is required. + echo "" - echo "This update added new revisions after undoing old revisions. That is to" - echo "say, the old revision is not a strict subset of the new revision. This" - echo "situation occurs when you --force push a change and generate a" - echo "repository containing something like this:" - echo "" - echo " * -- * -- B -- O -- O -- O ($oldrev)" - echo " \\" - echo " N -- N -- N ($newrev)" - echo "" - echo "When this happens we assume that you've already had alert emails for all" - echo "of the O revisions, and so we here report only the revisions in the N" - echo "branch from the common base, B." + + # Find the common ancestor of the old and new revisions and compare + # it with newrev + baserev=$(git merge-base $oldrev $newrev) + rewind_only="" + if [ "$baserev" = "$newrev" ]; then + echo "This update discarded existing revisions and left the branch pointing at" + echo "a previous point in the repository history." + echo "" + echo " * -- * -- N ($newrev)" + echo " \\" + echo " O -- O -- O ($oldrev)" + echo "" + echo "The removed revisions are not necessarilly gone - if another reference" + echo "still refers to them they will stay in the repository." + rewind_only=1 + else + echo "This update added new revisions after undoing existing revisions. That is" + echo "to say, the old revision is not a strict subset of the new revision. This" + echo "situation occurs when you --force push a change and generate a repository" + echo "containing something like this:" + echo "" + echo " * -- * -- B -- O -- O -- O ($oldrev)" + echo " \\" + echo " N -- N -- N ($newrev)" + echo "" + echo "When this happens we assume that you've already had alert emails for all" + echo "of the O revisions, and so we here report only the revisions in the N" + echo "branch from the common base, B." + fi fi echo "" - echo "Those revisions listed above that are new to this repository have" - echo "not appeared on any other notification email; so we list those" - echo "revisions in full, below." + if [ -z "$rewind_only" ]; then + echo "Those revisions listed above that are new to this repository have" + echo "not appeared on any other notification email; so we list those" + echo "revisions in full, below." - echo "" - echo $LOGBEGIN - git rev-parse --not --branches | grep -v $(git rev-parse $refname) | - git rev-list --pretty --stdin $oldrev..$newrev + echo "" + echo $LOGBEGIN + git rev-parse --not --branches | grep -v $(git rev-parse $refname) | + git rev-list --pretty --stdin $oldrev..$newrev - # XXX: Need a way of detecting whether git rev-list actually outputted - # anything, so that we can issue a "no new revisions added by this - # update" message + # XXX: Need a way of detecting whether git rev-list actually outputted + # anything, so that we can issue a "no new revisions added by this + # update" message - echo $LOGEND + echo $LOGEND + else + echo "No new revisions were added by this update." + fi # The diffstat is shown from the old revision to the new revision. This # is to show the truth of what happened in this change. There's no point From c855195cd014f8b5a32a32b36cb77319654583a3 Mon Sep 17 00:00:00 2001 From: Andy Parkins Date: Thu, 26 Apr 2007 22:37:16 +0100 Subject: [PATCH 45/80] post-receive-email example hook: sed command for getting description was wrong The sed command that extracted the first line of the project description didn't include the -n switch and hence the project name was being printed twice. This was ruining the email header generation because it was assumed that the description was only one line and was included in the subject. This turned the subject into a two line item and prematurely finished the header. Signed-off-by: Andy Parkins Signed-off-by: Junio C Hamano --- contrib/hooks/post-receive-email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index e175b426a4..d1bef9125b 100644 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -587,7 +587,7 @@ if [ -z "$GIT_DIR" ]; then exit 1 fi -projectdesc=$(sed -e '1p' "$GIT_DIR/description") +projectdesc=$(sed -ne '1p' "$GIT_DIR/description") # Check if the description is unchanged from it's default, and shorten it to a # more manageable length if it is if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null From 4551d05fe44c6d87ff8a24cfba7a79bba0179d5e Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:58:55 -0500 Subject: [PATCH 46/80] Removing -n option from git-diff-files documentation -n is not a short form of --no-index as the documentation suggests. Removing it from the documentation and command usage string. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-diff-files.txt | 4 ++-- builtin-diff-files.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt index b78c4c64f1..2e1e29ef5a 100644 --- a/Documentation/git-diff-files.txt +++ b/Documentation/git-diff-files.txt @@ -8,7 +8,7 @@ git-diff-files - Compares files in the working tree and the index SYNOPSIS -------- -'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|-n|--no-index] [] [...] +'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|--no-index] [] [...] DESCRIPTION ----------- @@ -36,7 +36,7 @@ omit diff output for unmerged entries and just show "Unmerged". diff, similar to the way 'diff-tree' shows a merge commit with these flags. -\-n,\--no-index:: +--no-index:: Compare the two given files / directories. -q:: diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 6ba5077a2b..6cb30c8e12 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -10,7 +10,7 @@ #include "builtin.h" static const char diff_files_usage[] = -"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|-n|--no-index] [] [...]" +"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|--no-index] [] [...]" COMMON_DIFF_OPTIONS_HELP; int cmd_diff_files(int argc, const char **argv, const char *prefix) From 42905294de0c1885f5636319c4790f184d767875 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:58:56 -0500 Subject: [PATCH 47/80] Document additional options for git-fetch Document --quiet/-q and --verbose/-v Add -n as an alternate for --no-tags Fix some whitespace issues Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/fetch-options.txt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 5b4d184a73..bdc7332c7b 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -1,13 +1,20 @@ +-q, \--quiet:: + Pass --quiet to git-fetch-pack and silence any other internally + used programs. + +-v, \--verbose:: + Be verbose. + -a, \--append:: Append ref names and object names of fetched refs to the existing contents of `.git/FETCH_HEAD`. Without this option old data in `.git/FETCH_HEAD` will be overwritten. \--upload-pack :: - When given, and the repository to fetch from is handled - by 'git-fetch-pack', '--exec=' is passed to - the command to specify non-default path for the command - run on the other end. + When given, and the repository to fetch from is handled + by 'git-fetch-pack', '--exec=' is passed to + the command to specify non-default path for the command + run on the other end. -f, \--force:: When `git-fetch` is used with `:` @@ -16,7 +23,7 @@ fetches is a descendant of ``. This option overrides that check. -\--no-tags:: +-n, \--no-tags:: By default, `git-fetch` fetches tags that point at objects that are downloaded from the remote repository and stores them locally. This option disables this From 2bc060cc6fce9f51240bf35803a5690dd1813c7c Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:58:57 -0500 Subject: [PATCH 48/80] Update git-fmt-merge documentation Documentation/git-fmt-merge-msg.txt: --summary to list commit summaries on merge --no-summary --file to take merged objects from a file. Configuration option merge.summary Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-fmt-merge-msg.txt | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt index a70eb3994a..e560b30c57 100644 --- a/Documentation/git-fmt-merge-msg.txt +++ b/Documentation/git-fmt-merge-msg.txt @@ -8,7 +8,8 @@ git-fmt-merge-msg - Produce a merge commit message SYNOPSIS -------- -'git-fmt-merge-msg' <$GIT_DIR/FETCH_HEAD +git-fmt-merge-msg [--summary | --no-summary] <$GIT_DIR/FETCH_HEAD +git-fmt-merge-msg [--summary | --no-summray] -F DESCRIPTION ----------- @@ -19,6 +20,28 @@ passed as the '' argument of `git-merge`. This script is intended mostly for internal use by scripts automatically invoking `git-merge`. +OPTIONS +------- + +--summary:: + In addition to branch names, populate the log message with + one-line descriptions from the actual commits that are being + merged. + +--no-summary:: + Do not list one-line descriptions from the actual commits being + merged. + +--file , -F :: + Take the list of merged objects from instead of + stdin. + +CONFIGURATION +------------- + +merge.summary:: + Whether to include summaries of merged commits in newly + merge commit messages. False by default. SEE ALSO -------- From cf0d720b7f861e90b9cadfc989d5b57c4b1ff531 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:58:58 -0500 Subject: [PATCH 49/80] Update git-grep documentation Documentation/git-grep.txt: Document -F/--fixed-strings to search for non-regexp patterns. Document -I to not search binary files. Document - as a shortcut for -C. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-grep.txt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 0140c8e358..c5a5dad1ce 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -12,12 +12,13 @@ SYNOPSIS 'git-grep' [--cached] [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp] [-v | --invert-match] [-h|-H] [--full-name] - [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] - [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-E | --extended-regexp] [-G | --basic-regexp] + [-F | --fixed-strings] [-n] + [-l | --files-with-matches] [-L | --files-without-match] [-c | --count] [--all-match] [-A ] [-B ] [-C ] - [-f ] [-e] [--and|--or|--not|(|)|-e ...] - [...] + [-f ] [-e] + [--and|--or|--not|(|)|-e ...] [...] [--] [...] DESCRIPTION @@ -39,6 +40,9 @@ OPTIONS Ignore case differences between the patterns and the files. +-I:: + Don't match the pattern in binary files. + -w | --word-regexp:: Match the pattern only at word boundary (either begin at the beginning of a line, or preceded by a non-word character; end at @@ -64,6 +68,10 @@ OPTIONS Use POSIX extended/basic regexp for patterns. Default is to use basic regexp. +-F | --fixed-strings:: + Use fixed strings for patterns (don't interpret pattern + as a regex). + -n:: Prefix the line number to matching lines. @@ -81,6 +89,9 @@ OPTIONS line containing `--` between contiguous groups of matches. +-:: + A shortcut for specifying -C. + -f :: Read patterns from , one per line. From a44f88e251a82c32dcc4715f063e3e3e39562a8d Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:58:59 -0500 Subject: [PATCH 50/80] Update -L documentation for git-blame/git-annotate Documenting alternate ways to use -L: -L /regex/,end -L start,+offset Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/blame-options.txt | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 331f161c77..a46bf6ce70 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -9,8 +9,28 @@ --show-stats:: Include additional statistics at the end of blame output. --L n,m:: - Annotate only the specified line range (lines count from 1). +-L ,:: + Annotate only the given line range. and can take + one of these forms: + + - number ++ +If or is a number, it specifies an +absolute line number (lines count from 1). ++ + +- /regex/ ++ +This form will use the first line matching the given +POSIX regex. If is a regex, it will search +starting at the line given by . ++ + +- +offset or -offset ++ +This is only valid for and will specify a number +of lines before or after the line given by . ++ -l:: Show long rev (Default: off). From d8190a8ec86bc9c75cd85352b0a186991c70a5bb Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:59:00 -0500 Subject: [PATCH 51/80] Update git-http-push documentation Documentation/git-http-push.txt: Changing --complete to --all. Added documentation for -d and -D to remote remote refs. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-http-push.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt index 4b4a46169c..a15cf5b2a3 100644 --- a/Documentation/git-http-push.txt +++ b/Documentation/git-http-push.txt @@ -8,7 +8,7 @@ git-http-push - Push objects over HTTP/DAV to another repository SYNOPSIS -------- -'git-http-push' [--complete] [--force] [--verbose] [...] +'git-http-push' [--all] [--force] [--verbose] [...] DESCRIPTION ----------- @@ -18,7 +18,7 @@ remote branch. OPTIONS ------- ---complete:: +--all:: Do not assume that the remote repository is complete in its current state, and verify all objects in the entire local ref's history exist in the remote repository. @@ -34,6 +34,15 @@ OPTIONS Report the list of objects being walked locally and the list of objects successfully sent to the remote repository. +-d, -D:: + Remove from remote repository. The specified branch + cannot be the remote HEAD. If -d is specified the following + other conditions must also be met: + + - Remote HEAD must resolve to an object that exists locally + - Specified branch resolves to an object that exists locally + - Specified branch is an ancestor of the remote HEAD + ...:: The remote refs to update. From f5158a07d26b957f700dc6cc4fdb5a693a1314b3 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:59:01 -0500 Subject: [PATCH 52/80] Update git-local-fetch documentation Documentation/git-local-fetch.txt: -s to use symbolic links instead of file-to-file copy, -l to use hardlinks, -n to never use file-to-file copies, --recover to resume a failed fetch. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-local-fetch.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/git-local-fetch.txt b/Documentation/git-local-fetch.txt index 22048d82bd..dd9e2387fc 100644 --- a/Documentation/git-local-fetch.txt +++ b/Documentation/git-local-fetch.txt @@ -24,6 +24,16 @@ OPTIONS Get all the objects. -v:: Report what is downloaded. +-s:: + Instead of regular file-to-file copying use symbolic links to the objects + in the remote repository. +-l:: + Before attempting symlinks (if -s is specified) or file-to-file copying the + remote objects, try to hardlink the remote objects into the local + repository. +-n:: + Never attempt to file-to-file copy remote objects. Only useful with + -s or -l command-line options. -w :: Writes the commit-id into the filename under $GIT_DIR/refs/ on @@ -35,6 +45,10 @@ OPTIONS ['\t'] +--recover:: + Verify that everything reachable from target is fetched. Used after + an earlier fetch is interrupted. + Author ------ Written by Junio C Hamano From 71e2e5993b6f2afdfda0cc92e0d55e84c9f876b0 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Thu, 26 Apr 2007 23:59:02 -0500 Subject: [PATCH 53/80] Update git-http-fetch documentation Documentation/git-http-fetch.txt: --recover to resume a failed fetch operation. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-http-fetch.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt index 7dc2df3044..4deabc376c 100644 --- a/Documentation/git-http-fetch.txt +++ b/Documentation/git-http-fetch.txt @@ -39,6 +39,10 @@ commit-id:: ['\t'] +--recover:: + Verify that everything reachable from target is fetched. Used after + an earlier fetch is interrupted. + Author ------ Written by Linus Torvalds From bb924cb331c143eaf92ba8d86b65caff15252543 Mon Sep 17 00:00:00 2001 From: Michele Ballabio Date: Fri, 27 Apr 2007 21:56:47 +0200 Subject: [PATCH 54/80] git shortlog documentation: add long options and fix a typo Signed-off-by: Michele Ballabio Signed-off-by: Junio C Hamano --- Documentation/git-shortlog.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index 1c8c55ef6e..15cc6f77c1 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] -git-shortlog [-n|--number] [-s|--summary] [...] +git-shortlog [-n|--numbered] [-s|--summary] [...] DESCRIPTION ----------- @@ -22,14 +22,14 @@ Additionally, "[PATCH]" will be stripped from the commit description. OPTIONS ------- --h:: +-h, \--help:: Print a short usage message and exit. --n:: +-n, \--numbered:: Sort output according to the number of commits per author instead of author alphabetic order. --s:: +-s, \--summary:: Suppress commit description and provide a commit count summary only. FILES From 26e60160a074747fbe8866ddac4e0c7660c17ff6 Mon Sep 17 00:00:00 2001 From: Adam Roben Date: Fri, 27 Apr 2007 11:57:53 -0700 Subject: [PATCH 55/80] git-svn: Added 'find-rev' command This patch adds a new 'find-rev' command to git-svn that lets you easily translate between SVN revision numbers and git tree-ish. Signed-off-by: Adam Roben Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- Documentation/git-svn.txt | 5 +++++ git-svn.perl | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index a0d34e0058..a35b9de3bf 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -159,6 +159,11 @@ New features: Any other arguments are passed directly to `git log' -- +'find-rev':: + When given an SVN revision number of the form 'rN', returns the + corresponding git commit hash. When given a tree-ish, returns the + corresponding SVN revision number. + 'set-tree':: You should consider using 'dcommit' instead of this command. Commit specified commit or tree objects to SVN. This relies on diff --git a/git-svn.perl b/git-svn.perl index 7b5f8ab3be..4be8576894 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -141,6 +141,8 @@ my %cmd = ( 'color' => \$Git::SVN::Log::color, 'pager=s' => \$Git::SVN::Log::pager, } ], + 'find-rev' => [ \&cmd_find_rev, "Translate between SVN revision numbers and tree-ish", + { } ], 'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory", { 'merge|m|M' => \$_merge, 'verbose|v' => \$_verbose, @@ -428,6 +430,28 @@ sub cmd_dcommit { command_noisy(@finish, $gs->refname); } +sub cmd_find_rev { + my $revision_or_hash = shift; + my $result; + if ($revision_or_hash =~ /^r\d+$/) { + my $desired_revision = substr($revision_or_hash, 1); + my ($fh, $ctx) = command_output_pipe('rev-list', 'HEAD'); + while (my $hash = <$fh>) { + chomp($hash); + my (undef, $rev, undef) = cmt_metadata($hash); + if ($rev && $rev eq $desired_revision) { + $result = $hash; + last; + } + } + command_close_pipe($fh, $ctx); + } else { + my (undef, $rev, undef) = cmt_metadata($revision_or_hash); + $result = $rev; + } + print "$result\n" if $result; +} + sub cmd_rebase { command_noisy(qw/update-index --refresh/); my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); From 87859f34434dda61cabb03447efd1dd2fe7ebac7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 29 Apr 2007 01:59:47 +0200 Subject: [PATCH 56/80] import-tars: be nice to wrong directory modes Some tars seem to have modes 0755 for directories, not 01000755. Do not generate an empty object for them, but ignore them. Noticed by riddochc on IRC. Signed-off-by: Johannes Schindelin Signed-off-by: Shawn O. Pearce --- contrib/fast-import/import-tars.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index 5585a8b2c5..e84647770a 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -52,6 +52,7 @@ foreach my $tar_file (@ARGV) Z8 Z1 Z100 Z6 Z2 Z32 Z32 Z8 Z8 Z*', $_; last unless $name; + next if $name =~ '/$'; $mode = oct $mode; $size = oct $size; $mtime = oct $mtime; From 475d1b333a03b0c13cbbc4ebf395fe11c989f931 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 28 Apr 2007 20:01:27 -0400 Subject: [PATCH 57/80] Don't allow empty pathnames in fast-import riddochc on #git noticed corruption caused by import-tars. This was fixed in the prior commit by Dscho, but fast-import was wrong to have allowed a tree to be created with an empty string as the filename. No operating system allows this, and Git itself doesn't accept this into the index. Signed-off-by: Shawn O. Pearce --- fast-import.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fast-import.c b/fast-import.c index cdd629d6bc..6c43a0d37f 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1193,6 +1193,8 @@ static int tree_content_set( n = slash1 - p; else n = strlen(p); + if (!n) + die("Empty path component found in input"); for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; From cb2cada6da9d71604fd09efbff47cddbea453e1e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 28 Apr 2007 20:29:23 -0400 Subject: [PATCH 58/80] Catch empty pathnames in trees during fsck Released versions of fast-import have been able to create a tree that contains files or subtrees that contain no name. Unfortunately these trees aren't valid, but people may have actually tried to create them due to bugs in import-tars.perl or their own fast-import frontend. We now look for this unusual condition and warn the user if at least one of their tree objects contains the problem. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fsck.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builtin-fsck.c b/builtin-fsck.c index 7c3b0a535f..75e10e25ec 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -218,6 +218,7 @@ static int fsck_tree(struct tree *item) { int retval; int has_full_path = 0; + int has_empty_name = 0; int has_zero_pad = 0; int has_bad_modes = 0; int has_dup_entries = 0; @@ -241,6 +242,8 @@ static int fsck_tree(struct tree *item) if (strchr(name, '/')) has_full_path = 1; + if (!*name) + has_empty_name = 1; has_zero_pad |= *(char *)desc.buffer == '0'; update_tree_entry(&desc); @@ -289,6 +292,9 @@ static int fsck_tree(struct tree *item) if (has_full_path) { objwarning(&item->object, "contains full pathnames"); } + if (has_empty_name) { + objwarning(&item->object, "contains empty pathname"); + } if (has_zero_pad) { objwarning(&item->object, "contains zero-padded file modes"); } From 4e6380e5c3af2d8cea8ffac2a7759b4f4e62089b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 28 Apr 2007 00:15:48 -0700 Subject: [PATCH 59/80] Do not barf on too long action description Reflog message is primarily about easier identification, and leaving truncated entry is much better than dying. Signed-off-by: Junio C Hamano --- builtin-fetch--tool.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c index e9d6764550..2ad45dcd44 100644 --- a/builtin-fetch--tool.c +++ b/builtin-fetch--tool.c @@ -35,16 +35,13 @@ static int update_ref(const char *action, unsigned char *sha1, unsigned char *oldval) { - int len; char msg[1024]; char *rla = getenv("GIT_REFLOG_ACTION"); static struct ref_lock *lock; if (!rla) rla = "(reflog update)"; - len = snprintf(msg, sizeof(msg), "%s: %s", rla, action); - if (sizeof(msg) <= len) - die("insanely long action"); + snprintf(msg, sizeof(msg), "%s: %s", rla, action); lock = lock_any_ref_for_update(refname, oldval); if (!lock) return 1; From 2342c4ee1437277a36c07246ab577a520dab588b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 29 Apr 2007 00:22:00 -0700 Subject: [PATCH 60/80] Update .mailmap with "Michael" Signed-off-by: Junio C Hamano --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 3a624eabc3..17e89af118 100644 --- a/.mailmap +++ b/.mailmap @@ -23,6 +23,7 @@ Lars Doelle Lars Doelle Lukas Sandström Martin Langhoff +Michele Ballabio Nguyễn Thái Ngọc Duy Ramsay Allan Jones René Scharfe From d0c32b63394992f8dd083a4f2f380ab190dbb2ca Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 29 Apr 2007 00:31:14 -0700 Subject: [PATCH 61/80] Fix import-tars fix. This heeds advice from our resident Perl expert to make sure the script is not confused with a string that ends with /\n Signed-off-by: Junio C Hamano --- contrib/fast-import/import-tars.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index e84647770a..82a90429c8 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -52,7 +52,7 @@ foreach my $tar_file (@ARGV) Z8 Z1 Z100 Z6 Z2 Z32 Z32 Z8 Z8 Z*', $_; last unless $name; - next if $name =~ '/$'; + next if $name =~ m{/\z}; $mode = oct $mode; $size = oct $size; $mtime = oct $mtime; From 4e58bf970bfddb8106541d98c3321fdf2a6ba23b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 28 Apr 2007 18:40:12 -0700 Subject: [PATCH 62/80] Add missing reference to GIT_COMMITTER_DATE in git-commit-tree documentation Signed-off-by: Josh Triplett Signed-off-by: Junio C Hamano --- Documentation/git-commit-tree.txt | 1 + Documentation/git.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index cf25507f8f..1571dbbb74 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -60,6 +60,7 @@ either `.git/config` file, or using the following environment variables. GIT_AUTHOR_DATE GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL + GIT_COMMITTER_DATE (nb "<", ">" and "\n"s are stripped) diff --git a/Documentation/git.txt b/Documentation/git.txt index 9defc33273..c81162eba5 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -340,6 +340,7 @@ git Commits 'GIT_AUTHOR_DATE':: 'GIT_COMMITTER_NAME':: 'GIT_COMMITTER_EMAIL':: +'GIT_COMMITTER_DATE':: see gitlink:git-commit-tree[1] git Diffs From e9d54bd18bcf5dc9eb68eb1cba9a6a7ba3f71fd6 Mon Sep 17 00:00:00 2001 From: Julian Phillips Date: Sun, 29 Apr 2007 03:46:42 +0100 Subject: [PATCH 63/80] http.c: Fix problem with repeated calls of http_init Calling http_init after calling http_cleanup causes a segfault. This is due to the pragma_header curl_slist being freed but not being set to NULL. The subsequent call to http_init tries to setup the slist again, but it now points to an invalid memory location. Signed-off-by: Julian Phillips Signed-off-by: Junio C Hamano --- http.c | 1 + 1 file changed, 1 insertion(+) diff --git a/http.c b/http.c index 576740feff..ae27e0c940 100644 --- a/http.c +++ b/http.c @@ -300,6 +300,7 @@ void http_cleanup(void) curl_global_cleanup(); curl_slist_free_all(pragma_header); + pragma_header = NULL; } struct active_request_slot *get_active_slot(void) From 28a94f885a735e7474357698ec384de24d526620 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 28 Apr 2007 18:40:28 -0700 Subject: [PATCH 64/80] Fall back to $EMAIL for missing GIT_AUTHOR_EMAIL and GIT_COMMITTER_EMAIL Some other programs get the user's email address from $EMAIL, so fall back to that if we don't have a Git-specific email address. Signed-off-by: Josh Triplett Signed-off-by: Junio C Hamano --- Documentation/config.txt | 4 ++-- Documentation/git-commit-tree.txt | 1 + Documentation/git.txt | 1 + ident.c | 2 ++ t/test-lib.sh | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index e0aff5369f..c257cdf525 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -610,8 +610,8 @@ tar.umask:: user.email:: Your email address to be recorded in any newly created commits. - Can be overridden by the 'GIT_AUTHOR_EMAIL' and 'GIT_COMMITTER_EMAIL' - environment variables. See gitlink:git-commit-tree[1]. + Can be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and + 'EMAIL' environment variables. See gitlink:git-commit-tree[1]. user.name:: Your full name to be recorded in any newly created commits. diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index 1571dbbb74..504a3aa1b4 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -61,6 +61,7 @@ either `.git/config` file, or using the following environment variables. GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE + EMAIL (nb "<", ">" and "\n"s are stripped) diff --git a/Documentation/git.txt b/Documentation/git.txt index 08ba53ae01..c5d02dacde 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -345,6 +345,7 @@ git Commits 'GIT_COMMITTER_NAME':: 'GIT_COMMITTER_EMAIL':: 'GIT_COMMITTER_DATE':: +'EMAIL':: see gitlink:git-commit-tree[1] git Diffs diff --git a/ident.c b/ident.c index 88e7f74e88..69a04b827d 100644 --- a/ident.c +++ b/ident.c @@ -195,6 +195,8 @@ const char *fmt_ident(const char *name, const char *email, setup_ident(); if (!name) name = git_default_name; + if (!email) + email = getenv("EMAIL"); if (!email) email = git_default_email; diff --git a/t/test-lib.sh b/t/test-lib.sh index f2c6bd3b01..dee3ad7621 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -16,6 +16,7 @@ unset AUTHOR_EMAIL unset AUTHOR_NAME unset COMMIT_AUTHOR_EMAIL unset COMMIT_AUTHOR_NAME +unset EMAIL unset GIT_ALTERNATE_OBJECT_DIRECTORIES unset GIT_AUTHOR_DATE GIT_AUTHOR_EMAIL=author@example.com From 093dc5bee61c47f5b0f3bea04339c9bf8839ca47 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 12 Apr 2007 15:50:45 -0700 Subject: [PATCH 65/80] blame -s: suppress author name and time. With this "git blame -b -s HEAD~n..HEAD" becomes a nicer way to review the result of recent changes in context. Signed-off-by: Junio C Hamano --- Documentation/git-blame.txt | 5 ++++- builtin-blame.c | 19 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index 8f9439a6dd..44678b0c36 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -8,7 +8,7 @@ git-blame - Show what revision and author last modified each line of a file SYNOPSIS -------- [verse] -'git-blame' [-c] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m] +'git-blame' [-c] [-b] [--root] [-s] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m] [-S ] [-M] [-C] [-C] [--since=] [ | --contents ] [--] @@ -60,6 +60,9 @@ include::blame-options.txt[] -n, --show-number:: Show line number in the original commit (Default: off). +-s:: + Suppress author name and timestamp from the output. + THE PORCELAIN FORMAT -------------------- diff --git a/builtin-blame.c b/builtin-blame.c index 8919b028e6..de80311036 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -18,7 +18,7 @@ #include "cache-tree.h" static char blame_usage[] = -"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" +"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" " -c Use the same output mode as git-annotate (Default: off)\n" " -b Show blank SHA-1 for boundary commits (Default: off)\n" " -l Show long commit SHA1 (Default: off)\n" @@ -26,6 +26,7 @@ static char blame_usage[] = " -t Show raw timestamp (Default: off)\n" " -f, --show-name Show original filename (Default: auto)\n" " -n, --show-number Show original linenumber (Default: off)\n" +" -s Suppress author name and timestamp (Default: off)\n" " -p, --porcelain Show in a format designed for machine consumption\n" " -L n,m Process only line range n,m, counting from 1\n" " -M, -C Find line movements within and across files\n" @@ -1483,6 +1484,7 @@ static const char *format_time(unsigned long time, const char *tz_str, #define OUTPUT_SHOW_NAME 020 #define OUTPUT_SHOW_NUMBER 040 #define OUTPUT_SHOW_SCORE 0100 +#define OUTPUT_NO_AUTHOR 0200 static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) { @@ -1577,10 +1579,15 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) if (opt & OUTPUT_SHOW_NUMBER) printf(" %*d", max_orig_digits, ent->s_lno + 1 + cnt); - printf(" (%-*.*s %10s %*d) ", - longest_author, longest_author, ci.author, - format_time(ci.author_time, ci.author_tz, - show_raw_time), + + if (!(opt & OUTPUT_NO_AUTHOR)) + printf(" (%-*.*s %10s", + longest_author, longest_author, + ci.author, + format_time(ci.author_time, + ci.author_tz, + show_raw_time)); + printf(" %*d) ", max_digits, ent->lno + 1 + cnt); } do { @@ -2092,6 +2099,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix) output_option |= OUTPUT_RAW_TIMESTAMP; else if (!strcmp("-l", arg)) output_option |= OUTPUT_LONG_OBJECT_NAME; + else if (!strcmp("-s", arg)) + output_option |= OUTPUT_NO_AUTHOR; else if (!strcmp("-S", arg) && ++i < argc) revs_file = argv[i]; else if (!prefixcmp(arg, "-M")) { From 7c1c6782e0b88c9366c575fd47e48050070afdd3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 27 Apr 2007 00:41:15 -0700 Subject: [PATCH 66/80] Split out mailmap handling out of shortlog This splits out a few functions to deal with mailmap from shortlog and makes it a bit more usable from other programs. Most notably, it does not clobber input e-mail address anymore. Signed-off-by: Junio C Hamano --- Makefile | 4 +-- builtin-shortlog.c | 84 +++---------------------------------------- mailmap.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ mailmap.h | 7 ++++ 4 files changed, 101 insertions(+), 82 deletions(-) create mode 100644 mailmap.c create mode 100644 mailmap.h diff --git a/Makefile b/Makefile index 60c41fd0d8..85c0a75426 100644 --- a/Makefile +++ b/Makefile @@ -288,7 +288,7 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h + utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@ -310,7 +310,7 @@ LIB_OBJS = \ write_or_die.o trace.o list-objects.o grep.o match-trees.o \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \ - convert.o attr.o decorate.o progress.o + convert.o attr.o decorate.o progress.o mailmap.o BUILTIN_OBJS = \ builtin-add.o \ diff --git a/builtin-shortlog.c b/builtin-shortlog.c index 3f93498bb7..b57a88a6b0 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -5,6 +5,7 @@ #include "path-list.h" #include "revision.h" #include "utf8.h" +#include "mailmap.h" static const char shortlog_usage[] = "git-shortlog [-n] [-s] [... ]"; @@ -26,83 +27,6 @@ static int compare_by_number(const void *a1, const void *a2) static struct path_list mailmap = {NULL, 0, 0, 0}; -static int read_mailmap(const char *filename) -{ - char buffer[1024]; - FILE *f = fopen(filename, "r"); - - if (f == NULL) - return 1; - while (fgets(buffer, sizeof(buffer), f) != NULL) { - char *end_of_name, *left_bracket, *right_bracket; - char *name, *email; - int i; - if (buffer[0] == '#') { - static const char abbrev[] = "# repo-abbrev:"; - int abblen = sizeof(abbrev) - 1; - int len = strlen(buffer); - - if (len && buffer[len - 1] == '\n') - buffer[--len] = 0; - if (!strncmp(buffer, abbrev, abblen)) { - char *cp; - - if (common_repo_prefix) - free(common_repo_prefix); - common_repo_prefix = xmalloc(len); - - for (cp = buffer + abblen; isspace(*cp); cp++) - ; /* nothing */ - strcpy(common_repo_prefix, cp); - } - continue; - } - if ((left_bracket = strchr(buffer, '<')) == NULL) - continue; - if ((right_bracket = strchr(left_bracket + 1, '>')) == NULL) - continue; - if (right_bracket == left_bracket + 1) - continue; - for (end_of_name = left_bracket; end_of_name != buffer - && isspace(end_of_name[-1]); end_of_name--) - /* keep on looking */ - if (end_of_name == buffer) - continue; - name = xmalloc(end_of_name - buffer + 1); - strlcpy(name, buffer, end_of_name - buffer + 1); - email = xmalloc(right_bracket - left_bracket); - for (i = 0; i < right_bracket - left_bracket - 1; i++) - email[i] = tolower(left_bracket[i + 1]); - email[right_bracket - left_bracket - 1] = '\0'; - path_list_insert(email, &mailmap)->util = name; - } - fclose(f); - return 0; -} - -static int map_email(char *email, char *name, int maxlen) -{ - char *p; - struct path_list_item *item; - - /* autocomplete common developers */ - p = strchr(email, '>'); - if (!p) - return 0; - - *p = '\0'; - /* downcase the email address */ - for (p = email; *p; p++) - *p = tolower(*p); - item = path_list_lookup(email, &mailmap); - if (item != NULL) { - const char *realname = (const char *)item->util; - strncpy(name, realname, maxlen); - return 1; - } - return 0; -} - static void insert_author_oneline(struct path_list *list, const char *author, int authorlen, const char *oneline, int onelinelen) @@ -184,7 +108,7 @@ static void read_from_stdin(struct path_list *list) (bob = strchr(buffer + 7, '<')) != NULL) { char buffer2[1024], offset = 0; - if (map_email(bob + 1, buffer, sizeof(buffer))) + if (map_email(&mailmap, bob + 1, buffer, sizeof(buffer))) bob = buffer + strlen(buffer); else { offset = 8; @@ -238,7 +162,7 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list) die("Invalid commit buffer: %s", sha1_to_hex(commit->object.sha1)); - if (map_email(bracket + 1, scratch, + if (map_email(&mailmap, bracket + 1, scratch, sizeof(scratch))) { author = scratch; authorlen = strlen(scratch); @@ -360,7 +284,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) die ("unrecognized argument: %s", argv[1]); if (!access(".mailmap", R_OK)) - read_mailmap(".mailmap"); + read_mailmap(&mailmap, ".mailmap", &common_repo_prefix); if (rev.pending.nr == 0) { if (isatty(0)) diff --git a/mailmap.c b/mailmap.c new file mode 100644 index 0000000000..af187a3826 --- /dev/null +++ b/mailmap.c @@ -0,0 +1,88 @@ +#include "cache.h" +#include "path-list.h" + +int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev) +{ + char buffer[1024]; + FILE *f = fopen(filename, "r"); + + if (f == NULL) + return 1; + while (fgets(buffer, sizeof(buffer), f) != NULL) { + char *end_of_name, *left_bracket, *right_bracket; + char *name, *email; + int i; + if (buffer[0] == '#') { + static const char abbrev[] = "# repo-abbrev:"; + int abblen = sizeof(abbrev) - 1; + int len = strlen(buffer); + + if (len && buffer[len - 1] == '\n') + buffer[--len] = 0; + if (!strncmp(buffer, abbrev, abblen)) { + char *cp; + + if (repo_abbrev) + free(*repo_abbrev); + *repo_abbrev = xmalloc(len); + + for (cp = buffer + abblen; isspace(*cp); cp++) + ; /* nothing */ + strcpy(*repo_abbrev, cp); + } + continue; + } + if ((left_bracket = strchr(buffer, '<')) == NULL) + continue; + if ((right_bracket = strchr(left_bracket + 1, '>')) == NULL) + continue; + if (right_bracket == left_bracket + 1) + continue; + for (end_of_name = left_bracket; end_of_name != buffer + && isspace(end_of_name[-1]); end_of_name--) + /* keep on looking */ + if (end_of_name == buffer) + continue; + name = xmalloc(end_of_name - buffer + 1); + strlcpy(name, buffer, end_of_name - buffer + 1); + email = xmalloc(right_bracket - left_bracket); + for (i = 0; i < right_bracket - left_bracket - 1; i++) + email[i] = tolower(left_bracket[i + 1]); + email[right_bracket - left_bracket - 1] = '\0'; + path_list_insert(email, map)->util = name; + } + fclose(f); + return 0; +} + +int map_email(struct path_list *map, const char *email, char *name, int maxlen) +{ + char *p; + struct path_list_item *item; + char buf[1024], *mailbuf; + int i; + + /* autocomplete common developers */ + p = strchr(email, '>'); + if (!p) + return 0; + if (p - email + 1 < sizeof(buf)) + mailbuf = buf; + else + mailbuf = xmalloc(p - email + 1); + + /* downcase the email address */ + for (i = 0; i < p - email; i++) + mailbuf[i] = tolower(email[i]); + mailbuf[i] = 0; + item = path_list_lookup(mailbuf, map); + if (mailbuf != buf) + free(mailbuf); + if (item != NULL) { + const char *realname = (const char *)item->util; + strncpy(name, realname, maxlen); + return 1; + } + return 0; +} + diff --git a/mailmap.h b/mailmap.h new file mode 100644 index 0000000000..3503fd2727 --- /dev/null +++ b/mailmap.h @@ -0,0 +1,7 @@ +#ifndef MAILMAP_H +#define MAILMAP_H + +int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev); +int map_email(struct path_list *mailmap, const char *email, char *name, int maxlen); + +#endif From f95673849c99baf3b10756e944d6ebe22394a2c0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 27 Apr 2007 00:42:15 -0700 Subject: [PATCH 67/80] Apply mailmap in git-blame output. This makes git-blame to use the same mailmap used by git-shortlog. Signed-off-by: Junio C Hamano --- builtin-blame.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index de80311036..682edba9e5 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -16,14 +16,17 @@ #include "quote.h" #include "xdiff-interface.h" #include "cache-tree.h" +#include "path-list.h" +#include "mailmap.h" static char blame_usage[] = -"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" +"git-blame [-c] [-b] [-l] [--root] [-x] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" " -c Use the same output mode as git-annotate (Default: off)\n" " -b Show blank SHA-1 for boundary commits (Default: off)\n" " -l Show long commit SHA1 (Default: off)\n" " --root Do not treat root commits as boundaries (Default: off)\n" " -t Show raw timestamp (Default: off)\n" +" -x Do not use .mailmap file\n" " -f, --show-name Show original filename (Default: auto)\n" " -n, --show-number Show original linenumber (Default: off)\n" " -s Suppress author name and timestamp (Default: off)\n" @@ -43,6 +46,8 @@ static int show_root; static int blank_boundary; static int incremental; static int cmd_is_annotate; +static int no_mailmap; +static struct path_list mailmap; #ifndef DEBUG #define DEBUG 0 @@ -1265,8 +1270,8 @@ static void get_ac_line(const char *inbuf, const char *what, int bufsz, char *person, const char **mail, unsigned long *time, const char **tz) { - int len; - char *tmp, *endp; + int len, tzlen, maillen; + char *tmp, *endp, *timepos; tmp = strstr(inbuf, what); if (!tmp) @@ -1292,17 +1297,42 @@ static void get_ac_line(const char *inbuf, const char *what, while (*tmp != ' ') tmp--; *tz = tmp+1; + tzlen = (person+len)-(tmp+1); *tmp = 0; while (*tmp != ' ') tmp--; *time = strtoul(tmp, NULL, 10); + timepos = tmp; *tmp = 0; while (*tmp != ' ') tmp--; *mail = tmp + 1; *tmp = 0; + maillen = timepos - tmp; + + if (!mailmap.nr) + return; + + /* + * mailmap expansion may make the name longer. + * make room by pushing stuff down. + */ + tmp = person + bufsz - (tzlen + 1); + memmove(tmp, *tz, tzlen); + tmp[tzlen] = 0; + *tz = tmp; + + tmp = tmp - (maillen + 1); + memmove(tmp, *mail, maillen); + tmp[maillen] = 0; + *mail = tmp; + + /* + * Now, convert e-mail using mailmap + */ + map_email(&mailmap, tmp + 1, person, tmp-person-1); } static void get_commit_info(struct commit *commit, @@ -2143,6 +2173,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix) else if (!strcmp("-p", arg) || !strcmp("--porcelain", arg)) output_option |= OUTPUT_PORCELAIN; + else if (!strcmp("-x", arg) || + !strcmp("--no-mailmap", arg)) + no_mailmap = 1; else if (!strcmp("--", arg)) { seen_dashdash = 1; i++; @@ -2342,6 +2375,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix) die("reading graft file %s failed: %s", revs_file, strerror(errno)); + if (!no_mailmap && !access(".mailmap", R_OK)) + read_mailmap(&mailmap, ".mailmap", NULL); + assign_blame(&sb, &revs, opt); if (incremental) From e0173ad9fcabfcabe54d65be2c8b6602f61079e6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 28 Apr 2007 23:38:52 -0700 Subject: [PATCH 68/80] Make macros to prevent double-inclusion in headers consistent. Signed-off-by: Junio C Hamano --- diffcore.h | 4 ++-- exec_cmd.h | 6 +++--- path-list.h | 6 +++--- progress.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/diffcore.h b/diffcore.h index 1ea80671e3..7b9294eab2 100644 --- a/diffcore.h +++ b/diffcore.h @@ -1,8 +1,8 @@ /* * Copyright (C) 2005 Junio C Hamano */ -#ifndef _DIFFCORE_H_ -#define _DIFFCORE_H_ +#ifndef DIFFCORE_H +#define DIFFCORE_H /* This header file is internal between diff.c and its diff transformers * (e.g. diffcore-rename, diffcore-pickaxe). Never include this header diff --git a/exec_cmd.h b/exec_cmd.h index 989621ff4e..849a8395a0 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -1,5 +1,5 @@ -#ifndef __GIT_EXEC_CMD_H_ -#define __GIT_EXEC_CMD_H_ +#ifndef GIT_EXEC_CMD_H +#define GIT_EXEC_CMD_H extern void git_set_exec_path(const char *exec_path); extern const char* git_exec_path(void); @@ -7,4 +7,4 @@ extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); -#endif /* __GIT_EXEC_CMD_H_ */ +#endif /* GIT_EXEC_CMD_H */ diff --git a/path-list.h b/path-list.h index d6401eaa35..ce5ffabcce 100644 --- a/path-list.h +++ b/path-list.h @@ -1,5 +1,5 @@ -#ifndef _PATH_LIST_H_ -#define _PATH_LIST_H_ +#ifndef PATH_LIST_H +#define PATH_LIST_H struct path_list_item { char *path; @@ -19,4 +19,4 @@ void path_list_clear(struct path_list *list, int free_items); struct path_list_item *path_list_insert(const char *path, struct path_list *list); struct path_list_item *path_list_lookup(const char *path, struct path_list *list); -#endif /* _PATH_LIST_H_ */ +#endif /* PATH_LIST_H */ diff --git a/progress.h b/progress.h index 4ee851acfb..5ae1a89e5a 100644 --- a/progress.h +++ b/progress.h @@ -1,5 +1,5 @@ -#ifndef __progress_h__ -#define __progress_h__ +#ifndef PROGRESS_H +#define PROGRESS_H struct progress { const char *prefix; From 96651ef50837e1c121def715dcf7416e9bcb1d0b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 28 Apr 2007 15:32:49 -0700 Subject: [PATCH 69/80] Make sure test-genrandom and test-chmtime are builtas part of the main build. Signed-off-by: Junio C Hamano --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 85c0a75426..2fea115919 100644 --- a/Makefile +++ b/Makefile @@ -933,13 +933,17 @@ endif ### Testing rules +TEST_PROGRAMS = test-chmtime$X test-genrandom$X + +all:: $(TEST_PROGRAMS) + # GNU make supports exporting all variables by "export" without parameters. # However, the environment gets quite big, and some programs have problems # with that. export NO_SVN_TESTS -test: all test-chmtime$X test-genrandom$X +test: all $(MAKE) -C t/ all test-date$X: test-date.c date.o ctype.o From bcd8ee5b4368594f2fe646c97d75a8bcdfb1d4e7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 29 Apr 2007 14:05:54 -0700 Subject: [PATCH 70/80] Fix symlink handling in git-svn, related to PerlIO After reading the leading contents from a symlink data obtained from subversion, which we expect to begin with 'link ', the code forked to hash the remainder (which should match readlink() result) using git-hash-objects, by redirecting its STDIN from the filehandle we read that 'link ' from. This was Ok with Perl on modern Linux, but on Mac OS, the read in the parent process slurped more than we asked for in stdio buffer, and the child did not correctly see the "remainder". This attempts to fix the issue by using lower level sysseek and sysread instead of seek and read to bypass the stdio buffer. Signed-off-by: Junio C Hamano Acked-by: Eric Wong Acked-by: Seth Falcon --- git-svn.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 4be8576894..6f509f85e4 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2470,9 +2470,9 @@ sub close_file { my $got = $md5->hexdigest; die "Checksum mismatch: $path\n", "expected: $exp\n got: $got\n" if ($got ne $exp); - seek($fh, 0, 0) or croak $!; + sysseek($fh, 0, 0) or croak $!; if ($fb->{mode_b} == 120000) { - read($fh, my $buf, 5) == 5 or croak $!; + sysread($fh, my $buf, 5) == 5 or croak $!; $buf eq 'link ' or die "$path has mode 120000", "but is not a link\n"; } From b3cb7e4582410c7fcaa531a2283b43499eb8fb22 Mon Sep 17 00:00:00 2001 From: Adam Roben Date: Sun, 29 Apr 2007 01:35:27 -0700 Subject: [PATCH 71/80] git-svn: Add 'find-rev' command This patch adds a new 'find-rev' command to git-svn that lets you easily translate between SVN revision numbers and git tree-ish. Signed-off-by: Adam Roben Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- Documentation/git-svn.txt | 5 +++-- git-svn.perl | 19 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index a35b9de3bf..62d7ef8be4 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -161,8 +161,9 @@ Any other arguments are passed directly to `git log' -- 'find-rev':: When given an SVN revision number of the form 'rN', returns the - corresponding git commit hash. When given a tree-ish, returns the - corresponding SVN revision number. + corresponding git commit hash (this can optionally be followed by a + tree-ish to specify which branch should be searched). When given a + tree-ish, returns the corresponding SVN revision number. 'set-tree':: You should consider using 'dcommit' instead of this command. diff --git a/git-svn.perl b/git-svn.perl index 6f509f85e4..6657e100fb 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -434,17 +434,16 @@ sub cmd_find_rev { my $revision_or_hash = shift; my $result; if ($revision_or_hash =~ /^r\d+$/) { - my $desired_revision = substr($revision_or_hash, 1); - my ($fh, $ctx) = command_output_pipe('rev-list', 'HEAD'); - while (my $hash = <$fh>) { - chomp($hash); - my (undef, $rev, undef) = cmt_metadata($hash); - if ($rev && $rev eq $desired_revision) { - $result = $hash; - last; - } + my $head = shift; + $head ||= 'HEAD'; + my @refs; + my (undef, undef, undef, $gs) = working_head_info($head, \@refs); + unless ($gs) { + die "Unable to determine upstream SVN information from ", + "$head history\n"; } - command_close_pipe($fh, $ctx); + my $desired_revision = substr($revision_or_hash, 1); + $result = $gs->rev_db_get($desired_revision); } else { my (undef, $rev, undef) = cmt_metadata($revision_or_hash); $result = $rev; From a7af09d2dbf39bae4c12c7d1c8829f8598011257 Mon Sep 17 00:00:00 2001 From: Jari Aalto Date: Mon, 30 Apr 2007 19:04:25 +0300 Subject: [PATCH 72/80] Clarify SubmittingPatches Checklist Separate things to be checked when making commits, and things to be checked when sending patches. Signed-off-by: Jari Aalto Signed-off-by: Junio C Hamano --- Documentation/SubmittingPatches | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 131bcff9b2..8cf5093dd9 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -1,5 +1,7 @@ Checklist (and a short version for the impatient): + Commits: + - make commits of logical units - check for unnecessary whitespace with "git diff --check" before committing @@ -12,8 +14,14 @@ Checklist (and a short version for the impatient): commit message (or just use the option "-s" when committing) to confirm that you agree to the Developer's Certificate of Origin - - do not PGP sign your patch + + Patch: + - use "git format-patch -M" to create the patch + - send your patch to . If you use + git-send-email(1), please test it first by sending + email to yourself. + - do not PGP sign your patch - do not attach your patch, but read in the mail body, unless you cannot teach your mailer to leave the formatting of the patch alone. From 34b604af293ec288ed11cbb5cac90a2ddb87e159 Mon Sep 17 00:00:00 2001 From: Jari Aalto Date: Mon, 30 Apr 2007 14:21:38 +0300 Subject: [PATCH 73/80] git.7: Mention preformatted html doc location Signed-off-by: Jari Aalto Signed-off-by: Junio C Hamano --- Documentation/git.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/git.txt b/Documentation/git.txt index c81162eba5..aa65802c86 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -29,6 +29,10 @@ in a coherent way to git enlightenment ;-). The COMMAND is either a name of a Git command (see below) or an alias as defined in the configuration file (see gitlink:git-config[1]). +Formatted and hyperlinked version of the latest git +documentation can be viewed at +`http://www.kernel.org/pub/software/scm/git/docs/`. + ifdef::stalenotes[] [NOTE] ============ From 928a559000e1c9ba0d570c5d3d4e11155b4d1ffd Mon Sep 17 00:00:00 2001 From: Jari Aalto Date: Mon, 30 Apr 2007 15:37:28 +0300 Subject: [PATCH 74/80] send-email documentation: clarify --smtp-server It can be either hostname/address, or a full path to a local executable. Signed-off-by: Jari Aalto Signed-off-by: Junio C Hamano --- Documentation/git-send-email.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 795db873fc..7ae39fd5a2 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -54,7 +54,7 @@ The --cc option must be repeated for each user you want on the cc list. --in-reply-to:: Specify the contents of the first In-Reply-To header. - Subsequent emails will refer to the previous email + Subsequent emails will refer to the previous email instead of this if --chain-reply-to is set (the default) Only necessary if --compose is also set. If --compose is not set, this will be prompted for. @@ -68,8 +68,9 @@ The --cc option must be repeated for each user you want on the cc list. all that is output. --smtp-server:: - If set, specifies the outgoing SMTP server to use. A full - pathname of a sendmail-like program can be specified instead; + If set, specifies the outgoing SMTP server to use (e.g. + `smtp.example.com` or a raw IP address). Alternatively it can + specify a full pathname of a sendmail-like program instead; the program must support the `-i` option. Default value can be specified by the 'sendemail.smtpserver' configuration option; the built-in default is `/usr/sbin/sendmail` or From 600682aaa12c56d55bd24233828205c43ece2ded Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Tue, 1 May 2007 00:22:53 +0200 Subject: [PATCH 75/80] Use strlcpy instead of strncpy in mailmap.c strncpy does not NUL-terminate output in case of output buffer too short, and map_email prototype (and usage) does not allow for figuring out what the length of the name is. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- mailmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailmap.c b/mailmap.c index af187a3826..c29e4e5349 100644 --- a/mailmap.c +++ b/mailmap.c @@ -80,7 +80,7 @@ int map_email(struct path_list *map, const char *email, char *name, int maxlen) free(mailbuf); if (item != NULL) { const char *realname = (const char *)item->util; - strncpy(name, realname, maxlen); + strlcpy(name, realname, maxlen); return 1; } return 0; From 8503ee4394dd47af136019bd8da53e5adec17e5d Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Tue, 1 May 2007 00:26:36 +0200 Subject: [PATCH 76/80] Fix read_mailmap to handle a caller uninterested in repo abbreviation The only such a caller builtin-blame.c would pass NULL as the place where to store the abbreviation. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- mailmap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mailmap.c b/mailmap.c index c29e4e5349..38359a23b0 100644 --- a/mailmap.c +++ b/mailmap.c @@ -17,6 +17,9 @@ int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev int abblen = sizeof(abbrev) - 1; int len = strlen(buffer); + if (!repo_abbrev) + continue; + if (len && buffer[len - 1] == '\n') buffer[--len] = 0; if (!strncmp(buffer, abbrev, abblen)) { From e44b5d106c2934b93cfba2ea7fb2ed1e32edaae2 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Tue, 1 May 2007 00:27:05 +0200 Subject: [PATCH 77/80] Remove pointless calls to access(2) when checking for .mailmap read_mailmap already returns not 0 in case of error, and nothing seem to be interested in it. It also is silent about the fact (read_mailmap being to chatty would justify the call to access, but there is no point for it to be and it isn't). Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-blame.c | 2 +- builtin-shortlog.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index 682edba9e5..3442d282aa 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2375,7 +2375,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) die("reading graft file %s failed: %s", revs_file, strerror(errno)); - if (!no_mailmap && !access(".mailmap", R_OK)) + if (!no_mailmap) read_mailmap(&mailmap, ".mailmap", NULL); assign_blame(&sb, &revs, opt); diff --git a/builtin-shortlog.c b/builtin-shortlog.c index b57a88a6b0..8d3f742d43 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -283,8 +283,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) if (argc > 1) die ("unrecognized argument: %s", argv[1]); - if (!access(".mailmap", R_OK)) - read_mailmap(&mailmap, ".mailmap", &common_repo_prefix); + read_mailmap(&mailmap, ".mailmap", &common_repo_prefix); if (rev.pending.nr == 0) { if (isatty(0)) From fe5d30b6302369990499c428b28921b903153b81 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Tue, 1 May 2007 00:31:52 +0200 Subject: [PATCH 78/80] Include mailmap.h in mailmap.c to catch mailmap interface changes Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- mailmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mailmap.c b/mailmap.c index 38359a23b0..cb567a2832 100644 --- a/mailmap.c +++ b/mailmap.c @@ -1,5 +1,6 @@ #include "cache.h" #include "path-list.h" +#include "mailmap.h" int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev) { From b5cc62f701abf8b903387a5d7c77a59f347d66fd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 30 Apr 2007 17:09:48 -0700 Subject: [PATCH 79/80] GIT v1.5.1.3 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.1.3.txt | 20 ++++++++++++++------ GIT-VERSION-GEN | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Documentation/RelNotes-1.5.1.3.txt b/Documentation/RelNotes-1.5.1.3.txt index 9a4b069ccc..2ddeabd029 100644 --- a/Documentation/RelNotes-1.5.1.3.txt +++ b/Documentation/RelNotes-1.5.1.3.txt @@ -1,4 +1,4 @@ -GIT v1.5.1.3 Release Notes (draft) +GIT v1.5.1.3 Release Notes ========================== Fixes since v1.5.1.2 @@ -19,6 +19,8 @@ Fixes since v1.5.1.2 - git-svn inconsistently stripped away username from the URL only when svnsync_props was in use. + - git-svn got confused when handling symlinks on Mac OS. + - git-send-email was not quoting recipient names that have period '.' in them. Also it did not allow overriding envelope sender, which made it impossible to send patches to @@ -31,8 +33,14 @@ Fixes since v1.5.1.2 packfiles incorrectly closed the fd that was still being used to read the pack. ---- -exec >/var/tmp/1 -O=v1.5.1.2-23-gbf7af11 -echo O=`git describe refs/heads/maint` -git shortlog --no-merges $O..refs/heads/maint + - import-tars contributed front-end for fastimport was passing + wrong directory modes without checking. + + - git-fastimport trusted its input too much and allowed to + create corrupt tree objects with entries without a name. + + - git-fetch needlessly barfed when too long reflog action + description was given by the caller. + +Also contains various documentation updates. + diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 41ee8b4ea2..cd9e0500e0 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.1.2.GIT +DEF_VER=v1.5.1.3.GIT LF=' ' From 4c1611249432733818e724fe04a3e9b04848cdab Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 30 Apr 2007 17:30:02 -0700 Subject: [PATCH 80/80] GIT v1.5.2-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.2.txt | 42 ++++++++++++++++++++++++++++---- GIT-VERSION-GEN | 2 +- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Documentation/RelNotes-1.5.2.txt b/Documentation/RelNotes-1.5.2.txt index abecac6de9..712ebb0b78 100644 --- a/Documentation/RelNotes-1.5.2.txt +++ b/Documentation/RelNotes-1.5.2.txt @@ -26,8 +26,14 @@ Updates since v1.5.1 considered a binary or text (the former would be treated by 'git diff' not to produce textual output; the latter can go through the line endings conversion process in repositories - with core.autocrlf set), and specify a custom 3-way merge - driver. + with core.autocrlf set), expand and unexpand '$ident$' keyword + with blob object name, specify a custom 3-way merge driver, + and specify a custom diff driver. You can also apply + arbitrary filter to contents on check-in/check-out codepath + but this feature is an extremely sharp-edged razor and needs + to be handled with caution (do not use it unless you + understand the earlier mailing list discussion on keyward + expansion). * The packfile format now optionally suports 64-bit index. @@ -53,8 +59,21 @@ Updates since v1.5.1 commit -a" (i.e. update the index to match the working tree); it obviously does not make a commit. + - "git clean" honors a new configuration, "clean.requireforce". When + set to true, this makes "git clean" a no-op, preventing you + from losing files by typing "git clean" when you meant to + say "make clean". You can still say "git clean -f" to + override this. + + - "git log" family of commands learned --date={local,relative,default} + option. --date=relative is synonym to the --relative-date. + --date=local gives the timestamp in local timezone. + * Updated behavior of existing commands. + - When $GIT_COMMITTER_EMAIL or $GIT_AUTHOR_EMAIL is not set + but $EMAIL is set, the latter is used as a substitute. + - "git diff --stat" shows size of preimage and postimage blobs for binary contents. Earlier it only said "Bin". @@ -82,11 +101,17 @@ Updates since v1.5.1 - "gitview" (in contrib/ section) learned to better support "git-annotate". + - "git diff $commit1:$path2 $commit2:$path2" can now report + mode changes between the two blobs. + - Local "git fetch" from a repository whose object store is one of the alternates (e.g. fetching from the origin in a repository created with "git clone -l -s") avoids downloading objects unnecessary. + - "git blame" uses .mailmap to canonicalize the author name + just like "git shortlog" does. + * Builds - git-p4import has never been installed; now there is an @@ -102,11 +127,15 @@ Updates since v1.5.1 * Performance Tweaks - - optimized "git-rev-list --bisect" (hence "git-bisect"). + - Optimized "git-rev-list --bisect" (hence "git-bisect"). - - optimized "git-add $path" in a large directory, most of + - Optimized "git-add $path" in a large directory, most of whose contents are ignored. + - The recursive merge strategy updated a worktree file that + was changed identically in two branches, when one of them + renamed it. We do not do that when there is no rename, so + match that behaviour. Fixes since v1.5.1 ------------------ @@ -133,12 +162,15 @@ this release, unless otherwise noted. will not be backported to 1.5.1.x series, as it is rather an intrusive change. + - git-fetch had trouble with a remote with insanely large number + of refs. + * Documentation updates * Performance Tweaks -- exec >/var/tmp/1 -O=v1.5.1.2-242-g2d76548 +O=v1.5.2-rc0-106-g07c785d echo O=`git describe refs/heads/master` git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index cd9e0500e0..0a6ea68dec 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.1.3.GIT +DEF_VER=v1.5.2-rc1.GIT LF=' '