From: Shawn O. Pearce Date: Tue, 16 Oct 2007 02:31:47 +0000 (-0400) Subject: Merge branch 'maint' X-Git-Tag: v1.5.4-rc0~360 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/d55e7c3acf72413563e695a19f7f66efac442064?ds=inline;hp=-c Merge branch 'maint' * maint: Whip post 1.5.3.4 maintenance series into shape. rebase -i: use diff plumbing instead of porcelain Do not remove distributed configure script git-archive: document --exec git-reflog: document --verbose git-config: handle --file option with relative pathname properly clear_commit_marks(): avoid deep recursion git add -i: Remove unused variables git add -i: Fix parsing of abbreviated hunk headers git-config: don't silently ignore options after --list Clean up "git log" format with DIFF_FORMAT_NO_OUTPUT Fix embarrassing "git log --follow" bug Conflicts: RelNotes git-rebase--interactive.sh --- d55e7c3acf72413563e695a19f7f66efac442064 diff --combined Makefile index 55fbcb73e1,c63d656f5d..d74ac93c11 --- a/Makefile +++ b/Makefile @@@ -28,8 -28,6 +28,8 @@@ all: # # Define NO_STRCASESTR if you don't have strcasestr. # +# Define NO_MEMMEM if you don't have memmem. +# # Define NO_STRLCPY if you don't have strlcpy. # # Define NO_STRTOUMAX if you don't have strtoumax in the C library. @@@ -124,9 -122,6 +124,9 @@@ # If not set it defaults to the bare 'wish'. If it is set to the empty # string then NO_TCLTK will be forced (this is used by configure script). # +# Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit +# parallel delta searching when packing objects. +# GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@@ -211,7 -206,7 +211,7 @@@ SCRIPT_SH = git-ls-remote.sh \ git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \ git-pull.sh git-rebase.sh git-rebase--interactive.sh \ - git-repack.sh git-request-pull.sh git-reset.sh \ + git-repack.sh git-request-pull.sh \ git-sh-setup.sh \ git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ @@@ -233,7 -228,7 +233,7 @@@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ - git-convert-objects$X git-fetch-pack$X \ + git-fetch-pack$X \ git-hash-object$X git-index-pack$X git-local-fetch$X \ git-fast-import$X \ git-daemon$X \ @@@ -358,7 -353,6 +358,7 @@@ BUILTIN_OBJS = builtin-reflog.o \ builtin-config.o \ builtin-rerere.o \ + builtin-reset.o \ builtin-rev-list.o \ builtin-rev-parse.o \ builtin-revert.o \ @@@ -402,14 -396,12 +402,14 @@@ ifeq ($(uname_S),Darwin NEEDS_LIBICONV = YesPlease OLD_ICONV = UnfortunatelyYes NO_STRLCPY = YesPlease + NO_MEMMEM = YesPlease endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease NEEDS_NSL = YesPlease SHELL_PATH = /bin/bash NO_STRCASESTR = YesPlease + NO_MEMMEM = YesPlease NO_HSTRERROR = YesPlease ifeq ($(uname_R),5.8) NEEDS_LIBICONV = YesPlease @@@ -432,7 -424,6 +432,7 @@@ ifeq ($(uname_O),Cygwin NO_D_TYPE_IN_DIRENT = YesPlease NO_D_INO_IN_DIRENT = YesPlease NO_STRCASESTR = YesPlease + NO_MEMMEM = YesPlease NO_SYMLINK_HEAD = YesPlease NEEDS_LIBICONV = YesPlease NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes @@@ -446,13 -437,11 +446,13 @@@ endif ifeq ($(uname_S),FreeBSD) NEEDS_LIBICONV = YesPlease + NO_MEMMEM = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease + NO_MEMMEM = YesPlease NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib @@@ -467,7 -456,6 +467,7 @@@ ifeq ($(uname_S),NetBSD endif ifeq ($(uname_S),AIX) NO_STRCASESTR=YesPlease + NO_MEMMEM = YesPlease NO_STRLCPY = YesPlease NEEDS_LIBICONV=YesPlease endif @@@ -479,7 -467,6 +479,7 @@@ ifeq ($(uname_S),IRIX64 NO_IPV6=YesPlease NO_SETENV=YesPlease NO_STRCASESTR=YesPlease + NO_MEMMEM = YesPlease NO_STRLCPY = YesPlease NO_SOCKADDR_STORAGE=YesPlease SHELL_PATH=/usr/gnu/bin/bash @@@ -674,15 -661,6 +674,15 @@@ ifdef NO_HSTRERRO COMPAT_CFLAGS += -DNO_HSTRERROR COMPAT_OBJS += compat/hstrerror.o endif +ifdef NO_MEMMEM + COMPAT_CFLAGS += -DNO_MEMMEM + COMPAT_OBJS += compat/memmem.o +endif + +ifdef THREADED_DELTA_SEARCH + BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH + EXTLIBS += -lpthread +endif ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks @@@ -947,10 -925,6 +947,10 @@@ tags $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +cscope: + $(RM) cscope* + $(FIND) . -name '*.[hcS]' -print | xargs cscope -b + ### Detect prefix changes TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) @@@ -1092,14 -1066,17 +1092,17 @@@ dist-doc ### Cleaning rules + distclean: clean + $(RM) configure + clean: $(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \ $(LIB_FILE) $(XDIFF_LIB) $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X $(RM) $(TEST_PROGRAMS) - $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags + $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* $(RM) -r autom4te.cache - $(RM) configure config.log config.mak.autogen config.mak.append config.status config.cache + $(RM) config.log config.mak.autogen config.mak.append config.status config.cache $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz @@@ -1115,7 -1092,7 +1118,7 @@@ endi $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS .PHONY: all install clean strip -.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags .FORCE-GIT-CFLAGS +.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS ### Check documentation # diff --combined commit.c index 20fb2209cb,1fbdd2d51b..ac24266e93 --- a/commit.c +++ b/commit.c @@@ -441,28 -441,33 +441,33 @@@ struct commit *pop_most_recent_commit(s void clear_commit_marks(struct commit *commit, unsigned int mark) { - struct commit_list *parents; + while (commit) { + struct commit_list *parents; - commit->object.flags &= ~mark; - parents = commit->parents; - while (parents) { - struct commit *parent = parents->item; + if (!(mark & commit->object.flags)) + return; - /* Have we already cleared this? */ - if (mark & parent->object.flags) - clear_commit_marks(parent, mark); - parents = parents->next; + commit->object.flags &= ~mark; + + parents = commit->parents; + if (!parents) + return; + + while ((parents = parents->next)) + clear_commit_marks(parents->item, mark); + + commit = commit->parents->item; } } /* * Generic support for pretty-printing the header */ -static int get_one_line(const char *msg, unsigned long len) +static int get_one_line(const char *msg) { int ret = 0; - while (len--) { + for (;;) { char c = *msg++; if (!c) break; @@@ -485,25 -490,31 +490,25 @@@ static int is_rfc2047_special(char ch return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); } -static int add_rfc2047(char *buf, const char *line, int len, +static void add_rfc2047(struct strbuf *sb, const char *line, int len, const char *encoding) { - char *bp = buf; - int i, needquote; - char q_encoding[128]; - const char *q_encoding_fmt = "=?%s?q?"; + int i, last; - for (i = needquote = 0; !needquote && i < len; i++) { + for (i = 0; i < len; i++) { int ch = line[i]; if (non_ascii(ch)) - needquote++; - if ((i + 1 < len) && - (ch == '=' && line[i+1] == '?')) - needquote++; + goto needquote; + if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) + goto needquote; } - if (!needquote) - return sprintf(buf, "%.*s", len, line); - - i = snprintf(q_encoding, sizeof(q_encoding), q_encoding_fmt, encoding); - if (sizeof(q_encoding) < i) - die("Insanely long encoding name %s", encoding); - memcpy(bp, q_encoding, i); - bp += i; - for (i = 0; i < len; i++) { + strbuf_add(sb, line, len); + return; + +needquote: + strbuf_grow(sb, len * 3 + strlen(encoding) + 100); + strbuf_addf(sb, "=?%s?q?", encoding); + for (i = last = 0; i < len; i++) { unsigned ch = line[i] & 0xFF; /* * We encode ' ' using '=20' even though rfc2047 @@@ -512,30 -523,40 +517,30 @@@ * leave the underscore in place. */ if (is_rfc2047_special(ch) || ch == ' ') { - sprintf(bp, "=%02X", ch); - bp += 3; + strbuf_add(sb, line + last, i - last); + strbuf_addf(sb, "=%02X", ch); + last = i + 1; } - else - *bp++ = ch; } - memcpy(bp, "?=", 2); - bp += 2; - return bp - buf; -} - -static unsigned long bound_rfc2047(unsigned long len, const char *encoding) -{ - /* upper bound of q encoded string of length 'len' */ - unsigned long elen = strlen(encoding); - - return len * 3 + elen + 100; + strbuf_add(sb, line + last, len - last); + strbuf_addstr(sb, "?="); } -static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, +static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, const char *line, enum date_mode dmode, const char *encoding) { char *date; int namelen; unsigned long time; - int tz, ret; + int tz; const char *filler = " "; if (fmt == CMIT_FMT_ONELINE) - return 0; + return; date = strchr(line, '>'); if (!date) - return 0; + return; namelen = ++date - line; time = strtoul(date, &date, 10); tz = strtol(date, NULL, 10); @@@ -544,34 -565,42 +549,34 @@@ char *name_tail = strchr(line, '<'); int display_name_length; if (!name_tail) - return 0; + return; while (line < name_tail && isspace(name_tail[-1])) name_tail--; display_name_length = name_tail - line; filler = ""; - strcpy(buf, "From: "); - ret = strlen(buf); - ret += add_rfc2047(buf + ret, line, display_name_length, - encoding); - memcpy(buf + ret, name_tail, namelen - display_name_length); - ret += namelen - display_name_length; - buf[ret++] = '\n'; - } - else { - ret = sprintf(buf, "%s: %.*s%.*s\n", what, + strbuf_addstr(sb, "From: "); + add_rfc2047(sb, line, display_name_length, encoding); + strbuf_add(sb, name_tail, namelen - display_name_length); + strbuf_addch(sb, '\n'); + } else { + strbuf_addf(sb, "%s: %.*s%.*s\n", what, (fmt == CMIT_FMT_FULLER) ? 4 : 0, filler, namelen, line); } switch (fmt) { case CMIT_FMT_MEDIUM: - ret += sprintf(buf + ret, "Date: %s\n", - show_date(time, tz, dmode)); + strbuf_addf(sb, "Date: %s\n", show_date(time, tz, dmode)); break; case CMIT_FMT_EMAIL: - ret += sprintf(buf + ret, "Date: %s\n", - show_date(time, tz, DATE_RFC2822)); + strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822)); break; case CMIT_FMT_FULLER: - ret += sprintf(buf + ret, "%sDate: %s\n", what, - show_date(time, tz, dmode)); + strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode)); break; default: /* notin' */ break; } - return ret; } static int is_empty_line(const char *line, int *len_p) @@@ -583,16 -612,16 +588,16 @@@ return !len; } -static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *commit, int abbrev) +static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb, + const struct commit *commit, int abbrev) { struct commit_list *parent = commit->parents; - int offset; if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) || !parent || !parent->next) - return 0; + return; - offset = sprintf(buf, "Merge:"); + strbuf_addstr(sb, "Merge:"); while (parent) { struct commit *p = parent->item; @@@ -605,9 -634,10 +610,9 @@@ dots = (abbrev && strlen(hex) != 40) ? "..." : ""; parent = parent->next; - offset += sprintf(buf + offset, " %s%s", hex, dots); + strbuf_addf(sb, " %s%s", hex, dots); } - buf[offset++] = '\n'; - return offset; + strbuf_addch(sb, '\n'); } static char *get_header(const struct commit *commit, const char *key) @@@ -628,7 -658,11 +633,7 @@@ if (eol - line > key_len && !strncmp(line, key, key_len) && line[key_len] == ' ') { - int len = eol - line - key_len; - char *ret = xmalloc(len); - memcpy(ret, line + key_len + 1, len - 1); - ret[len - 1] = '\0'; - return ret; + return xmemdupz(line + key_len + 1, eol - line - key_len - 1); } line = next; } @@@ -636,34 -670,47 +641,34 @@@ static char *replace_encoding_header(char *buf, const char *encoding) { - char *encoding_header = strstr(buf, "\nencoding "); - char *header_end = strstr(buf, "\n\n"); - char *end_of_encoding_header; - int encoding_header_pos; - int encoding_header_len; - int new_len; - int need_len; - int buflen = strlen(buf) + 1; - - if (!header_end) - header_end = buf + buflen; - if (!encoding_header || encoding_header >= header_end) - return buf; - encoding_header++; - end_of_encoding_header = strchr(encoding_header, '\n'); - if (!end_of_encoding_header) + struct strbuf tmp; + size_t start, len; + char *cp = buf; + + /* guess if there is an encoding header before a \n\n */ + while (strncmp(cp, "encoding ", strlen("encoding "))) { + cp = strchr(cp, '\n'); + if (!cp || *++cp == '\n') + return buf; + } + start = cp - buf; + cp = strchr(cp, '\n'); + if (!cp) return buf; /* should not happen but be defensive */ - end_of_encoding_header++; - - encoding_header_len = end_of_encoding_header - encoding_header; - encoding_header_pos = encoding_header - buf; + len = cp + 1 - (buf + start); + strbuf_init(&tmp, 0); + strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); if (is_encoding_utf8(encoding)) { /* we have re-coded to UTF-8; drop the header */ - memmove(encoding_header, end_of_encoding_header, - buflen - (encoding_header_pos + encoding_header_len)); - return buf; - } - new_len = strlen(encoding); - need_len = new_len + strlen("encoding \n"); - if (encoding_header_len < need_len) { - buf = xrealloc(buf, buflen + (need_len - encoding_header_len)); - encoding_header = buf + encoding_header_pos; - end_of_encoding_header = encoding_header + encoding_header_len; + strbuf_remove(&tmp, start, len); + } else { + /* just replaces XXXX in 'encoding XXXX\n' */ + strbuf_splice(&tmp, start + strlen("encoding "), + len - strlen("encoding \n"), + encoding, strlen(encoding)); } - memmove(end_of_encoding_header + (need_len - encoding_header_len), - end_of_encoding_header, - buflen - (encoding_header_pos + encoding_header_len)); - memcpy(encoding_header + 9, encoding, strlen(encoding)); - encoding_header[9 + new_len] = '\n'; - return buf; + return strbuf_detach(&tmp, NULL); } static char *logmsg_reencode(const struct commit *commit, @@@ -705,7 -752,7 +710,7 @@@ static void fill_person(struct interp * start = end + 1; while (end > 0 && isspace(msg[end - 1])) end--; - table[0].value = xstrndup(msg, end); + table[0].value = xmemdupz(msg, end); if (start >= len) return; @@@ -717,7 -764,7 +722,7 @@@ if (end >= len) return; - table[1].value = xstrndup(msg + start, end - start); + table[1].value = xmemdupz(msg + start, end - start); /* parse date */ for (start = end + 1; start < len && isspace(msg[start]); start++) @@@ -728,7 -775,7 +733,7 @@@ if (msg + start == ep) return; - table[5].value = xstrndup(msg + start, ep - (msg + start)); + table[5].value = xmemdupz(msg + start, ep - (msg + start)); /* parse tz */ for (start = ep - msg + 1; start < len && isspace(msg[start]); start++) @@@ -745,8 -792,8 +750,8 @@@ interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601)); } -static long format_commit_message(const struct commit *commit, - const char *msg, char **buf_p, unsigned long *space_p) +void format_commit_message(const struct commit *commit, + const void *format, struct strbuf *sb) { struct interp table[] = { { "%H" }, /* commit hash */ @@@ -799,10 -846,8 +804,10 @@@ }; struct commit_list *p; char parents[1024]; + unsigned long len; int i; enum { HEADER, SUBJECT, BODY } state; + const char *msg = commit->buffer; if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table)) die("invalid interp table!"); @@@ -855,7 -900,7 +860,7 @@@ ; /* do nothing */ if (state == SUBJECT) { - table[ISUBJECT].value = xstrndup(msg + i, eol - i); + table[ISUBJECT].value = xmemdupz(msg + i, eol - i); i = eol; } if (i == eol) { @@@ -871,21 -916,30 +876,21 @@@ msg + i + 10, eol - i - 10); else if (!prefixcmp(msg + i, "encoding ")) table[IENCODING].value = - xstrndup(msg + i + 9, eol - i - 9); + xmemdupz(msg + i + 9, eol - i - 9); i = eol; } if (msg[i]) table[IBODY].value = xstrdup(msg + i); - for (i = 0; i < ARRAY_SIZE(table); i++) - if (!table[i].value) - interp_set_entry(table, i, ""); - - do { - char *buf = *buf_p; - unsigned long space = *space_p; - space = interpolate(buf, space, user_format, - table, ARRAY_SIZE(table)); - if (!space) - break; - buf = xrealloc(buf, space); - *buf_p = buf; - *space_p = space; - } while (1); + len = interpolate(sb->buf + sb->len, strbuf_avail(sb), + format, table, ARRAY_SIZE(table)); + if (len > strbuf_avail(sb)) { + strbuf_grow(sb, len); + interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1, + format, table, ARRAY_SIZE(table)); + } + strbuf_setlen(sb, sb->len + len); interp_clear_table(table, ARRAY_SIZE(table)); - - return strlen(*buf_p); } static void pp_header(enum cmit_fmt fmt, @@@ -894,24 -948,34 +899,24 @@@ const char *encoding, const struct commit *commit, const char **msg_p, - unsigned long *len_p, - unsigned long *ofs_p, - char **buf_p, - unsigned long *space_p) + struct strbuf *sb) { int parents_shown = 0; for (;;) { const char *line = *msg_p; - char *dst; - int linelen = get_one_line(*msg_p, *len_p); - unsigned long len; + int linelen = get_one_line(*msg_p); if (!linelen) return; *msg_p += linelen; - *len_p -= linelen; if (linelen == 1) /* End of header */ return; - ALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p); - dst = *buf_p + *ofs_p; - if (fmt == CMIT_FMT_RAW) { - memcpy(dst, line, linelen); - *ofs_p += linelen; + strbuf_add(sb, line, linelen); continue; } @@@ -929,8 -993,10 +934,8 @@@ parent = parent->next, num++) ; /* with enough slop */ - num = *ofs_p + num * 50 + 20; - ALLOC_GROW(*buf_p, num, *space_p); - dst = *buf_p + *ofs_p; - *ofs_p += add_merge_info(fmt, dst, commit, abbrev); + strbuf_grow(sb, num * 50 + 20); + add_merge_info(fmt, sb, commit, abbrev); parents_shown = 1; } @@@ -940,82 -1006,129 +945,82 @@@ * FULLER shows both authors and dates. */ if (!memcmp(line, "author ", 7)) { - len = linelen; - if (fmt == CMIT_FMT_EMAIL) - len = bound_rfc2047(linelen, encoding); - ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p); - dst = *buf_p + *ofs_p; - *ofs_p += add_user_info("Author", fmt, dst, - line + 7, dmode, encoding); + strbuf_grow(sb, linelen + 80); + add_user_info("Author", fmt, sb, line + 7, dmode, encoding); } - if (!memcmp(line, "committer ", 10) && (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) { - len = linelen; - if (fmt == CMIT_FMT_EMAIL) - len = bound_rfc2047(linelen, encoding); - ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p); - dst = *buf_p + *ofs_p; - *ofs_p += add_user_info("Commit", fmt, dst, - line + 10, dmode, encoding); + strbuf_grow(sb, linelen + 80); + add_user_info("Commit", fmt, sb, line + 10, dmode, encoding); } } } static void pp_title_line(enum cmit_fmt fmt, const char **msg_p, - unsigned long *len_p, - unsigned long *ofs_p, - char **buf_p, - unsigned long *space_p, - int indent, + struct strbuf *sb, const char *subject, const char *after_subject, const char *encoding, int plain_non_ascii) { - char *title; - unsigned long title_alloc, title_len; - unsigned long len; + struct strbuf title; + + strbuf_init(&title, 80); - title_len = 0; - title_alloc = 80; - title = xmalloc(title_alloc); for (;;) { const char *line = *msg_p; - int linelen = get_one_line(line, *len_p); - *msg_p += linelen; - *len_p -= linelen; + int linelen = get_one_line(line); + *msg_p += linelen; if (!linelen || is_empty_line(line, &linelen)) break; - if (title_alloc <= title_len + linelen + 2) { - title_alloc = title_len + linelen + 80; - title = xrealloc(title, title_alloc); - } - len = 0; - if (title_len) { + strbuf_grow(&title, linelen + 2); + if (title.len) { if (fmt == CMIT_FMT_EMAIL) { - len++; - title[title_len++] = '\n'; + strbuf_addch(&title, '\n'); } - len++; - title[title_len++] = ' '; + strbuf_addch(&title, ' '); } - memcpy(title + title_len, line, linelen); - title_len += linelen; + strbuf_add(&title, line, linelen); } - /* Enough slop for the MIME header and rfc2047 */ - len = bound_rfc2047(title_len, encoding)+ 1000; - if (subject) - len += strlen(subject); - if (after_subject) - len += strlen(after_subject); - if (encoding) - len += strlen(encoding); - ALLOC_GROW(*buf_p, title_len + *ofs_p + len, *space_p); - + strbuf_grow(sb, title.len + 1024); if (subject) { - len = strlen(subject); - memcpy(*buf_p + *ofs_p, subject, len); - *ofs_p += len; - *ofs_p += add_rfc2047(*buf_p + *ofs_p, - title, title_len, encoding); + strbuf_addstr(sb, subject); + add_rfc2047(sb, title.buf, title.len, encoding); } else { - memcpy(*buf_p + *ofs_p, title, title_len); - *ofs_p += title_len; + strbuf_addbuf(sb, &title); } - (*buf_p)[(*ofs_p)++] = '\n'; + strbuf_addch(sb, '\n'); + if (plain_non_ascii) { const char *header_fmt = "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=%s\n" "Content-Transfer-Encoding: 8bit\n"; - *ofs_p += snprintf(*buf_p + *ofs_p, - *space_p - *ofs_p, - header_fmt, encoding); + strbuf_addf(sb, header_fmt, encoding); } if (after_subject) { - len = strlen(after_subject); - memcpy(*buf_p + *ofs_p, after_subject, len); - *ofs_p += len; + strbuf_addstr(sb, after_subject); } - free(title); if (fmt == CMIT_FMT_EMAIL) { - ALLOC_GROW(*buf_p, *ofs_p + 20, *space_p); - (*buf_p)[(*ofs_p)++] = '\n'; + strbuf_addch(sb, '\n'); } + strbuf_release(&title); } static void pp_remainder(enum cmit_fmt fmt, const char **msg_p, - unsigned long *len_p, - unsigned long *ofs_p, - char **buf_p, - unsigned long *space_p, + struct strbuf *sb, int indent) { int first = 1; for (;;) { const char *line = *msg_p; - int linelen = get_one_line(line, *len_p); + int linelen = get_one_line(line); *msg_p += linelen; - *len_p -= linelen; if (!linelen) break; @@@ -1028,32 -1141,36 +1033,32 @@@ } first = 0; - ALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p); + strbuf_grow(sb, linelen + indent + 20); if (indent) { - memset(*buf_p + *ofs_p, ' ', indent); - *ofs_p += indent; + memset(sb->buf + sb->len, ' ', indent); + strbuf_setlen(sb, sb->len + indent); } - memcpy(*buf_p + *ofs_p, line, linelen); - *ofs_p += linelen; - (*buf_p)[(*ofs_p)++] = '\n'; + strbuf_add(sb, line, linelen); + strbuf_addch(sb, '\n'); } } -unsigned long pretty_print_commit(enum cmit_fmt fmt, - const struct commit *commit, - unsigned long len, - char **buf_p, unsigned long *space_p, - int abbrev, const char *subject, - const char *after_subject, +void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, + struct strbuf *sb, int abbrev, + const char *subject, const char *after_subject, enum date_mode dmode) { - unsigned long offset = 0; unsigned long beginning_of_body; int indent = 4; const char *msg = commit->buffer; int plain_non_ascii = 0; char *reencoded; const char *encoding; - char *buf; - if (fmt == CMIT_FMT_USERFORMAT) - return format_commit_message(commit, msg, buf_p, space_p); + if (fmt == CMIT_FMT_USERFORMAT) { + format_commit_message(commit, user_format, sb); + return; + } encoding = (git_log_output_encoding ? git_log_output_encoding @@@ -1063,6 -1180,7 +1068,6 @@@ reencoded = logmsg_reencode(commit, encoding); if (reencoded) { msg = reencoded; - len = strlen(reencoded); } if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) @@@ -1077,13 -1195,14 +1082,13 @@@ if (fmt == CMIT_FMT_EMAIL && !after_subject) { int i, ch, in_body; - for (in_body = i = 0; (ch = msg[i]) && i < len; i++) { + for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ - if (ch == '\n' && - i + 1 < len && msg[i+1] == '\n') + if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { @@@ -1093,44 -1212,59 +1098,44 @@@ } } - pp_header(fmt, abbrev, dmode, encoding, - commit, &msg, &len, - &offset, buf_p, space_p); + pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb); if (fmt != CMIT_FMT_ONELINE && !subject) { - ALLOC_GROW(*buf_p, offset + 20, *space_p); - (*buf_p)[offset++] = '\n'; + strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ for (;;) { - int linelen = get_one_line(msg, len); + int linelen = get_one_line(msg); int ll = linelen; if (!linelen) break; if (!is_empty_line(msg, &ll)) break; msg += linelen; - len -= linelen; } /* These formats treat the title line specially. */ - if (fmt == CMIT_FMT_ONELINE - || fmt == CMIT_FMT_EMAIL) - pp_title_line(fmt, &msg, &len, &offset, - buf_p, space_p, indent, - subject, after_subject, encoding, - plain_non_ascii); - - beginning_of_body = offset; - if (fmt != CMIT_FMT_ONELINE) - pp_remainder(fmt, &msg, &len, &offset, - buf_p, space_p, indent); - - while (offset && isspace((*buf_p)[offset-1])) - offset--; + if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) + pp_title_line(fmt, &msg, sb, subject, + after_subject, encoding, plain_non_ascii); - ALLOC_GROW(*buf_p, offset + 20, *space_p); - buf = *buf_p; + beginning_of_body = sb->len; + if (fmt != CMIT_FMT_ONELINE) + pp_remainder(fmt, &msg, sb, indent); + strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) - buf[offset++] = '\n'; + strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ - if (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body) - buf[offset++] = '\n'; - buf[offset] = '\0'; + if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) + strbuf_addch(sb, '\n'); free(reencoded); - return offset; } struct commit *pop_commit(struct commit_list **stack) @@@ -1209,12 -1343,12 +1214,12 @@@ void sort_in_topological_order_fn(struc next=next->next; } /* - * find the tips - * - * tips are nodes not reachable from any other node in the list - * - * the tips serve as a starting set for the work queue. - */ + * find the tips + * + * tips are nodes not reachable from any other node in the list + * + * the tips serve as a starting set for the work queue. + */ next=*list; insert = &work; while (next) { @@@ -1241,9 -1375,9 +1246,9 @@@ if (pn) { /* * parents are only enqueued for emission - * when all their children have been emitted thereby - * guaranteeing topological order. - */ + * when all their children have been emitted thereby + * guaranteeing topological order. + */ pn->indegree--; if (!pn->indegree) { if (!lifo) @@@ -1255,9 -1389,9 +1260,9 @@@ parents=parents->next; } /* - * work_item is a commit all of whose children - * have already been emitted. we can emit it now. - */ + * work_item is a commit all of whose children + * have already been emitted. we can emit it now. + */ *pptr = work_node->list_item; pptr = &(*pptr)->next; *pptr = NULL; @@@ -1353,7 -1487,8 +1358,7 @@@ static struct commit_list *merge_bases( } struct commit_list *get_merge_bases(struct commit *one, - struct commit *two, - int cleanup) + struct commit *two, int cleanup) { struct commit_list *list; struct commit **rslt; diff --combined git-rebase--interactive.sh index 050140d666,50b79ff8ff..df4cedb859 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@@ -36,14 -36,14 +36,14 @@@ warn () output () { case "$VERBOSE" in '') - "$@" > "$DOTEST"/output 2>&1 + output=$("$@" 2>&1 ) status=$? - test $status != 0 && - cat "$DOTEST"/output + test $status != 0 && printf "%s\n" "$output" return $status - ;; + ;; *) "$@" + ;; esac } @@@ -63,7 -63,6 +63,7 @@@ comment_for_reflog () ''|rebase*) GIT_REFLOG_ACTION="rebase -i ($1)" export GIT_REFLOG_ACTION + ;; esac } @@@ -71,23 -70,22 +71,23 @@@ mark_action_done () sed -e 1q < "$TODO" >> "$DONE" sed -e 1d < "$TODO" >> "$TODO".new mv -f "$TODO".new "$TODO" - count=$(($(wc -l < "$DONE"))) - total=$(($count+$(wc -l < "$TODO"))) + count=$(($(grep -ve '^$' -e '^#' < "$DONE" | wc -l))) + total=$(($count+$(grep -ve '^$' -e '^#' < "$TODO" | wc -l))) printf "Rebasing (%d/%d)\r" $count $total test -z "$VERBOSE" || echo } make_patch () { - parent_sha1=$(git rev-parse --verify "$1"^ 2> /dev/null) + parent_sha1=$(git rev-parse --verify "$1"^) || + die "Cannot get patch for $1^" - git diff "$parent_sha1".."$1" > "$DOTEST"/patch + git diff-tree -p "$parent_sha1".."$1" > "$DOTEST"/patch + test -f "$DOTEST"/message || + git cat-file commit "$1" | sed "1,/^$/d" > "$DOTEST"/message + test -f "$DOTEST"/author-script || + get_author_ident_from_commit "$1" > "$DOTEST"/author-script } die_with_patch () { - test -f "$DOTEST"/message || - git cat-file commit $sha1 | sed "1,/^$/d" > "$DOTEST"/message - test -f "$DOTEST"/author-script || - get_author_ident_from_commit $sha1 > "$DOTEST"/author-script make_patch "$1" die "$2" } @@@ -97,18 -95,13 +97,18 @@@ die_abort () die "$1" } +has_action () { + grep -vqe '^$' -e '^#' "$1" +} + pick_one () { no_ff= case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1" test -d "$REWRITTEN" && pick_one_preserving_merges "$@" && return - parent_sha1=$(git rev-parse --verify $sha1^ 2>/dev/null) + parent_sha1=$(git rev-parse --verify $sha1^) || + die "Could not get the parent of $sha1" current_sha1=$(git rev-parse --verify HEAD) if test $no_ff$current_sha1 = $parent_sha1; then output git reset --hard $sha1 @@@ -136,7 -129,7 +136,7 @@@ pick_one_preserving_merges () fast_forward=t preserve=t new_parents= - for p in $(git rev-list --parents -1 $sha1 | cut -d\ -f2-) + for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-) do if test -f "$REWRITTEN"/$p then @@@ -148,47 -141,41 +148,47 @@@ ;; # do nothing; that parent is already there *) new_parents="$new_parents $new_p" + ;; esac fi done case $fast_forward in t) output warn "Fast forward to $sha1" - test $preserve=f && echo $sha1 > "$REWRITTEN"/$sha1 + test $preserve = f || echo $sha1 > "$REWRITTEN"/$sha1 ;; f) test "a$1" = a-n && die "Refusing to squash a merge: $sha1" - first_parent=$(expr "$new_parents" : " \([^ ]*\)") + first_parent=$(expr "$new_parents" : ' \([^ ]*\)') # detach HEAD to current parent output git checkout $first_parent 2> /dev/null || die "Cannot move HEAD to $first_parent" echo $sha1 > "$DOTEST"/current-commit case "$new_parents" in - \ *\ *) + ' '*' '*) # redo merge author_script=$(get_author_ident_from_commit $sha1) eval "$author_script" - msg="$(git cat-file commit $sha1 | \ - sed -e '1,/^$/d' -e "s/[\"\\]/\\\\&/g")" + msg="$(git cat-file commit $sha1 | sed -e '1,/^$/d')" # NEEDSWORK: give rerere a chance - if ! output git merge $STRATEGY -m "$msg" $new_parents + if ! GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \ + GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \ + GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \ + output git merge $STRATEGY -m "$msg" \ + $new_parents then - echo "$msg" > "$GIT_DIR"/MERGE_MSG + printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG die Error redoing merge $sha1 fi ;; *) output git cherry-pick $STRATEGY "$@" || die_with_patch $sha1 "Could not pick $sha1" + ;; esac + ;; esac } @@@ -225,28 -212,27 +225,28 @@@ peek_next_command () } do_next () { - test -f "$DOTEST"/message && rm "$DOTEST"/message - test -f "$DOTEST"/author-script && rm "$DOTEST"/author-script + rm -f "$DOTEST"/message "$DOTEST"/author-script \ + "$DOTEST"/amend || exit read command sha1 rest < "$TODO" case "$command" in - \#|'') + '#'*|'') mark_action_done ;; - pick) + pick|p) comment_for_reflog pick mark_action_done pick_one $sha1 || die_with_patch $sha1 "Could not apply $sha1... $rest" ;; - edit) + edit|e) comment_for_reflog edit mark_action_done pick_one $sha1 || die_with_patch $sha1 "Could not apply $sha1... $rest" make_patch $sha1 + : > "$DOTEST"/amend warn warn "You can amend the commit now, with" warn @@@ -254,25 -240,24 +254,25 @@@ warn exit 0 ;; - squash) + squash|s) comment_for_reflog squash - test -z "$(grep -ve '^$' -e '^#' < $DONE)" && + has_action "$DONE" || die "Cannot 'squash' without a previous commit" mark_action_done make_squash_message $sha1 > "$MSG" case "$(peek_next_command)" in - squash) + squash|s) EDIT_COMMIT= USE_OUTPUT=output cp "$MSG" "$SQUASH_MSG" - ;; + ;; *) EDIT_COMMIT=-e USE_OUTPUT= - test -f "$SQUASH_MSG" && rm "$SQUASH_MSG" + rm -f "$SQUASH_MSG" || exit + ;; esac failed=f @@@ -284,9 -269,7 +284,9 @@@ f) # This is like --amend, but with a different message eval "$author_script" - export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE + GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \ + GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \ + GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \ $USE_OUTPUT git commit -F "$MSG" $EDIT_COMMIT ;; t) @@@ -294,13 -277,11 +294,13 @@@ warn warn "Could not apply $sha1... $rest" die_with_patch $sha1 "" + ;; esac ;; *) warn "Unknown command: $command $sha1 $rest" die_with_patch $sha1 "Please fix this in the file $TODO." + ;; esac test -s "$TODO" && return @@@ -317,18 -298,13 +317,18 @@@ else NEWHEAD=$(git rev-parse HEAD) fi && - message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO)" && - git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD && - git symbolic-ref HEAD $HEADNAME && { + case $HEADNAME in + refs/*) + message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO)" && + git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD && + git symbolic-ref HEAD $HEADNAME + ;; + esac && { test ! -f "$DOTEST"/verbose || - git diff --stat $(cat "$DOTEST"/head)..HEAD + git diff-tree --stat $(cat "$DOTEST"/head)..HEAD } && rm -rf "$DOTEST" && + git gc --auto && warn "Successfully rebased and updated $HEADNAME." exit @@@ -354,9 -330,7 +354,9 @@@ d git update-index --refresh && git diff-files --quiet && ! git diff-index --cached --quiet HEAD && - . "$DOTEST"/author-script && + . "$DOTEST"/author-script && { + test ! -f "$DOTEST"/amend || git reset --soft HEAD^ + } && export GIT_AUTHOR_NAME GIT_AUTHOR_NAME GIT_AUTHOR_DATE && git commit -F "$DOTEST"/message -e @@@ -370,11 -344,7 +370,11 @@@ HEADNAME=$(cat "$DOTEST"/head-name) HEAD=$(cat "$DOTEST"/head) - git symbolic-ref HEAD $HEADNAME && + case $HEADNAME in + refs/*) + git symbolic-ref HEAD $HEADNAME + ;; + esac && output git reset --hard $HEAD && rm -rf "$DOTEST" exit @@@ -436,6 -406,7 +436,6 @@@ require_clean_work_tree - mkdir "$DOTEST" || die "Could not create temporary $DOTEST" if test ! -z "$2" then output git show-ref --verify --quiet "refs/heads/$2" || @@@ -447,13 -418,11 +447,13 @@@ HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?" UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base" + mkdir "$DOTEST" || die "Could not create temporary $DOTEST" + test -z "$ONTO" && ONTO=$UPSTREAM : > "$DOTEST"/interactive || die "Could not mark as interactive" - git symbolic-ref HEAD > "$DOTEST"/head-name || - die "Could not get HEAD" + git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null || + echo "detached HEAD" > "$DOTEST"/head-name echo $HEAD > "$DOTEST"/head echo $UPSTREAM > "$DOTEST"/upstream @@@ -499,18 -468,17 +499,18 @@@ EO $UPSTREAM...$HEAD | \ sed -n "s/^>/pick /p" >> "$TODO" - test -z "$(grep -ve '^$' -e '^#' < $TODO)" && + has_action "$TODO" || die_abort "Nothing to do" cp "$TODO" "$TODO".backup git_editor "$TODO" || die "Could not execute editor" - test -z "$(grep -ve '^$' -e '^#' < $TODO)" && + has_action "$TODO" || die_abort "Nothing to do" output git checkout $ONTO && do_rest + ;; esac shift done diff --combined log-tree.c index 23191543d5,b509c0c7ec..62edd34455 --- a/log-tree.c +++ b/log-tree.c @@@ -79,14 -79,25 +79,14 @@@ static int detect_any_signoff(char *let return seen_head && seen_name; } -static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p, - unsigned long at, const char *signoff) +static void append_signoff(struct strbuf *sb, const char *signoff) { static const char signed_off_by[] = "Signed-off-by: "; size_t signoff_len = strlen(signoff); int has_signoff = 0; char *cp; - char *buf; - unsigned long buf_sz; - buf = *buf_p; - buf_sz = *buf_sz_p; - if (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) { - buf_sz += strlen(signed_off_by) + signoff_len + 3; - buf = xrealloc(buf, buf_sz); - *buf_p = buf; - *buf_sz_p = buf_sz; - } - cp = buf; + cp = sb->buf; /* First see if we already have the sign-off by the signer */ while ((cp = strstr(cp, signed_off_by))) { @@@ -94,25 -105,29 +94,25 @@@ has_signoff = 1; cp += strlen(signed_off_by); - if (cp + signoff_len >= buf + at) + if (cp + signoff_len >= sb->buf + sb->len) break; if (strncmp(cp, signoff, signoff_len)) continue; if (!isspace(cp[signoff_len])) continue; /* we already have him */ - return at; + return; } if (!has_signoff) - has_signoff = detect_any_signoff(buf, at); + has_signoff = detect_any_signoff(sb->buf, sb->len); if (!has_signoff) - buf[at++] = '\n'; + strbuf_addch(sb, '\n'); - strcpy(buf + at, signed_off_by); - at += strlen(signed_off_by); - strcpy(buf + at, signoff); - at += signoff_len; - buf[at++] = '\n'; - buf[at] = 0; - return at; + strbuf_addstr(sb, signed_off_by); + strbuf_add(sb, signoff, signoff_len); + strbuf_addch(sb, '\n'); } static unsigned int digits_in_number(unsigned int number) @@@ -127,12 -142,14 +127,12 @@@ void show_log(struct rev_info *opt, const char *sep) { - char *msgbuf = NULL; - unsigned long msgbuf_len = 0; + struct strbuf msgbuf; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; int abbrev = opt->diffopt.abbrev; int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; const char *extra; - int len; const char *subject = NULL, *extra_headers = opt->extra_headers; opt->loginfo = NULL; @@@ -271,18 -288,18 +271,18 @@@ /* * And then the pretty-printed message itself */ - len = pretty_print_commit(opt->commit_format, commit, ~0u, - &msgbuf, &msgbuf_len, abbrev, subject, - extra_headers, opt->date_mode); + strbuf_init(&msgbuf, 0); + pretty_print_commit(opt->commit_format, commit, &msgbuf, + abbrev, subject, extra_headers, opt->date_mode); if (opt->add_signoff) - len = append_signoff(&msgbuf, &msgbuf_len, len, - opt->add_signoff); + append_signoff(&msgbuf, opt->add_signoff); if (opt->show_log_size) - printf("log size %i\n", len); + printf("log size %i\n", (int)msgbuf.len); - printf("%s%s%s", msgbuf, extra, sep); - free(msgbuf); + if (msgbuf.len) + printf("%s%s%s", msgbuf.buf, extra, sep); + strbuf_release(&msgbuf); } int log_tree_diff_flush(struct rev_info *opt) @@@ -304,7 -321,8 +304,8 @@@ * output for readability. */ show_log(opt, opt->diffopt.msg_sep); - if (opt->verbose_header && + if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && + opt->verbose_header && opt->commit_format != CMIT_FMT_ONELINE) { int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; if ((pch & opt->diffopt.output_format) == pch) diff --combined revision.c index 5d294be308,48756b5d44..e76da0d448 --- a/revision.c +++ b/revision.c @@@ -1134,7 -1134,22 +1134,7 @@@ int setup_revisions(int argc, const cha continue; } if (!strncmp(arg, "--date=", 7)) { - if (!strcmp(arg + 7, "relative")) - revs->date_mode = DATE_RELATIVE; - else if (!strcmp(arg + 7, "iso8601") || - !strcmp(arg + 7, "iso")) - revs->date_mode = DATE_ISO8601; - else if (!strcmp(arg + 7, "rfc2822") || - !strcmp(arg + 7, "rfc")) - revs->date_mode = DATE_RFC2822; - else if (!strcmp(arg + 7, "short")) - revs->date_mode = DATE_SHORT; - 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); + revs->date_mode = parse_date_format(arg + 7); continue; } if (!strcmp(arg, "--log-size")) { @@@ -1241,8 -1256,8 +1241,8 @@@ if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) revs->diff = 1; - /* Pickaxe needs diffs */ - if (revs->diffopt.pickaxe) + /* Pickaxe and rename following needs diffs */ + if (revs->diffopt.pickaxe || revs->diffopt.follow_renames) revs->diff = 1; if (revs->topo_order)