From: Junio C Hamano Date: Wed, 16 Apr 2008 07:37:33 +0000 (-0700) Subject: Merge branch 'maint-1.5.4' into maint X-Git-Tag: v1.5.5.1~7 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/464509f790f409d95e0820364ef7296d82942d8c?ds=inline;hp=-c Merge branch 'maint-1.5.4' into maint * maint-1.5.4: git-bisect: make "start", "good" and "skip" succeed or fail atomically git-am: cope better with an empty Subject: line Ignore leading empty lines while summarizing merges bisect: squelch "fatal: ref HEAD not a symref" misleading message builtin-apply: Show a more descriptive error on failure when opening a patch Clarify documentation of git-cvsserver, particularly in relation to git-shell --- 464509f790f409d95e0820364ef7296d82942d8c diff --combined Documentation/git-cvsserver.txt index 9cec8021b8,0b6db864fa..b1106714b2 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@@ -110,7 -110,9 +110,9 @@@ cvs -d ":ext;CVS_SERVER=git-cvsserver:u ------ This has the advantage that it will be saved in your 'CVS/Root' files and you don't need to worry about always setting the correct environment - variable. + variable. SSH users restricted to git-shell don't need to override the default + with CVS_SERVER (and shouldn't) as git-shell understands `cvs` to mean + git-cvsserver and pretends that the other end runs the real cvs better. -- 2. For each repo that you want accessible from CVS you need to edit config in the repo and add the following section. @@@ -141,25 -143,29 +143,29 @@@ allowing access over SSH enabled=1 ------ -- - 3. On the client machine you need to set the following variables. - CVSROOT should be set as per normal, but the directory should point at the - appropriate git repo. For example: + 3. If you didn't specify the CVSROOT/CVS_SERVER directly in the checkout command, + automatically saving it in your 'CVS/Root' files, then you need to set them + explicitly in your environment. CVSROOT should be set as per normal, but the + directory should point at the appropriate git repo. As above, for SSH clients + _not_ restricted to git-shell, CVS_SERVER should be set to git-cvsserver. + -- - For SSH access, CVS_SERVER should be set to git-cvsserver - - Example: - ------ export CVSROOT=:ext:user@server:/var/git/project.git export CVS_SERVER=git-cvsserver ------ -- - 4. For SSH clients that will make commits, make sure their .bashrc file - sets the GIT_AUTHOR and GIT_COMMITTER variables. + 4. For SSH clients that will make commits, make sure their server-side + .ssh/environment files (or .bashrc, etc., according to their specific shell) + export appropriate values for GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, + GIT_COMMITTER_NAME, and GIT_COMMITTER_EMAIL. For SSH clients whose login + shell is bash, .bashrc may be a reasonable alternative. 5. Clients should now be able to check out the project. Use the CVS 'module' - name to indicate what GIT 'head' you want to check out. Example: + name to indicate what GIT 'head' you want to check out. This also sets the + name of your newly checked-out directory, unless you tell it otherwise with + `-d `. For example, this checks out 'master' branch to the + `project-master` directory: + ------ cvs co -d project-master master @@@ -227,11 -233,6 +233,11 @@@ gitcvs.dbpass: Database password. Only useful if setting `dbdriver`, since SQLite has no concept of database passwords. +gitcvs.dbTableNamePrefix:: + Database table name prefix. Supports variable substitution + (see below). Any non-alphabetic characters will be replaced + with underscores. + All variables can also be set per access method, see <>. Variable substitution diff --combined builtin-apply.c index abe73a0f81,65388353a7..30d26e57b3 --- a/builtin-apply.c +++ b/builtin-apply.c @@@ -161,84 -161,6 +161,84 @@@ struct patch struct patch *next; }; +/* + * A line in a file, len-bytes long (includes the terminating LF, + * except for an incomplete line at the end if the file ends with + * one), and its contents hashes to 'hash'. + */ +struct line { + size_t len; + unsigned hash : 24; + unsigned flag : 8; +#define LINE_COMMON 1 +}; + +/* + * This represents a "file", which is an array of "lines". + */ +struct image { + char *buf; + size_t len; + size_t nr; + size_t alloc; + struct line *line_allocated; + struct line *line; +}; + +static uint32_t hash_line(const char *cp, size_t len) +{ + size_t i; + uint32_t h; + for (i = 0, h = 0; i < len; i++) { + if (!isspace(cp[i])) { + h = h * 3 + (cp[i] & 0xff); + } + } + return h; +} + +static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag) +{ + ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc); + img->line_allocated[img->nr].len = len; + img->line_allocated[img->nr].hash = hash_line(bol, len); + img->line_allocated[img->nr].flag = flag; + img->nr++; +} + +static void prepare_image(struct image *image, char *buf, size_t len, + int prepare_linetable) +{ + const char *cp, *ep; + + memset(image, 0, sizeof(*image)); + image->buf = buf; + image->len = len; + + if (!prepare_linetable) + return; + + ep = image->buf + image->len; + cp = image->buf; + while (cp < ep) { + const char *next; + for (next = cp; next < ep && *next != '\n'; next++) + ; + if (next < ep) + next++; + add_line_info(image, cp, next - cp, 0); + cp = next; + } + image->line = image->line_allocated; +} + +static void clear_image(struct image *image) +{ + free(image->buf); + image->buf = NULL; + image->len = 0; +} + static void say_patch_name(FILE *output, const char *pre, struct patch *patch, const char *post) { @@@ -1508,345 -1430,234 +1508,345 @@@ static int read_old_data(struct stat *s case S_IFREG: if (strbuf_read_file(buf, path, st->st_size) != st->st_size) return error("unable to open or read %s", path); - convert_to_git(path, buf->buf, buf->len, buf); + convert_to_git(path, buf->buf, buf->len, buf, 0); return 0; default: return -1; } } -static int find_offset(const char *buf, unsigned long size, - const char *fragment, unsigned long fragsize, - int line, int *lines) +static void update_pre_post_images(struct image *preimage, + struct image *postimage, + char *buf, + size_t len) { - int i; - unsigned long start, backwards, forwards; + int i, ctx; + char *new, *old, *fixed; + struct image fixed_preimage; - if (fragsize > size) - return -1; + /* + * Update the preimage with whitespace fixes. Note that we + * are not losing preimage->buf -- apply_one_fragment() will + * free "oldlines". + */ + prepare_image(&fixed_preimage, buf, len, 1); + assert(fixed_preimage.nr == preimage->nr); + for (i = 0; i < preimage->nr; i++) + fixed_preimage.line[i].flag = preimage->line[i].flag; + free(preimage->line_allocated); + *preimage = fixed_preimage; - start = 0; - if (line > 1) { - unsigned long offset = 0; - i = line-1; - while (offset + fragsize <= size) { - if (buf[offset++] == '\n') { - start = offset; - if (!--i) - break; - } + /* + * Adjust the common context lines in postimage, in place. + * This is possible because whitespace fixing does not make + * the string grow. + */ + new = old = postimage->buf; + fixed = preimage->buf; + for (i = ctx = 0; i < postimage->nr; i++) { + size_t len = postimage->line[i].len; + if (!(postimage->line[i].flag & LINE_COMMON)) { + /* an added line -- no counterparts in preimage */ + memmove(new, old, len); + old += len; + new += len; + continue; } + + /* a common context -- skip it in the original postimage */ + old += len; + + /* and find the corresponding one in the fixed preimage */ + while (ctx < preimage->nr && + !(preimage->line[ctx].flag & LINE_COMMON)) { + fixed += preimage->line[ctx].len; + ctx++; + } + if (preimage->nr <= ctx) + die("oops"); + + /* and copy it in, while fixing the line length */ + len = preimage->line[ctx].len; + memcpy(new, fixed, len); + new += len; + fixed += len; + postimage->line[i].len = len; + ctx++; } - /* Exact line number? */ - if ((start + fragsize <= size) && - !memcmp(buf + start, fragment, fragsize)) - return start; + /* Fix the length of the whole thing */ + postimage->len = new - postimage->buf; +} + +static int match_fragment(struct image *img, + struct image *preimage, + struct image *postimage, + unsigned long try, + int try_lno, + unsigned ws_rule, + int match_beginning, int match_end) +{ + int i; + char *fixed_buf, *buf, *orig, *target; + + if (preimage->nr + try_lno > img->nr) + return 0; + + if (match_beginning && try_lno) + return 0; + + if (match_end && preimage->nr + try_lno != img->nr) + return 0; + + /* Quick hash check */ + for (i = 0; i < preimage->nr; i++) + if (preimage->line[i].hash != img->line[try_lno + i].hash) + return 0; + + /* + * Do we have an exact match? If we were told to match + * at the end, size must be exactly at try+fragsize, + * otherwise try+fragsize must be still within the preimage, + * and either case, the old piece should match the preimage + * exactly. + */ + if ((match_end + ? (try + preimage->len == img->len) + : (try + preimage->len <= img->len)) && + !memcmp(img->buf + try, preimage->buf, preimage->len)) + return 1; + + if (ws_error_action != correct_ws_error) + return 0; + + /* + * The hunk does not apply byte-by-byte, but the hash says + * it might with whitespace fuzz. + */ + fixed_buf = xmalloc(preimage->len + 1); + buf = fixed_buf; + orig = preimage->buf; + target = img->buf + try; + for (i = 0; i < preimage->nr; i++) { + size_t fixlen; /* length after fixing the preimage */ + size_t oldlen = preimage->line[i].len; + size_t tgtlen = img->line[try_lno + i].len; + size_t tgtfixlen; /* length after fixing the target line */ + char tgtfixbuf[1024], *tgtfix; + int match; + + /* Try fixing the line in the preimage */ + fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL); + + /* Try fixing the line in the target */ + if (sizeof(tgtfixbuf) < tgtlen) + tgtfix = tgtfixbuf; + else + tgtfix = xmalloc(tgtlen); + tgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL); + + /* + * If they match, either the preimage was based on + * a version before our tree fixed whitespace breakage, + * or we are lacking a whitespace-fix patch the tree + * the preimage was based on already had (i.e. target + * has whitespace breakage, the preimage doesn't). + * In either case, we are fixing the whitespace breakages + * so we might as well take the fix together with their + * real change. + */ + match = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen)); + + if (tgtfix != tgtfixbuf) + free(tgtfix); + if (!match) + goto unmatch_exit; + + orig += oldlen; + buf += fixlen; + target += tgtlen; + } + + /* + * Yes, the preimage is based on an older version that still + * has whitespace breakages unfixed, and fixing them makes the + * hunk match. Update the context lines in the postimage. + */ + update_pre_post_images(preimage, postimage, + fixed_buf, buf - fixed_buf); + return 1; + + unmatch_exit: + free(fixed_buf); + return 0; +} + +static int find_pos(struct image *img, + struct image *preimage, + struct image *postimage, + int line, + unsigned ws_rule, + int match_beginning, int match_end) +{ + int i; + unsigned long backwards, forwards, try; + int backwards_lno, forwards_lno, try_lno; + + if (preimage->nr > img->nr) + return -1; + + /* + * If match_begining or match_end is specified, there is no + * point starting from a wrong line that will never match and + * wander around and wait for a match at the specified end. + */ + if (match_beginning) + line = 0; + else if (match_end) + line = img->nr - preimage->nr; + + if (line > img->nr) + line = img->nr; + + try = 0; + for (i = 0; i < line; i++) + try += img->line[i].len; /* * There's probably some smart way to do this, but I'll leave * that to the smart and beautiful people. I'm simple and stupid. */ - backwards = start; - forwards = start; + backwards = try; + backwards_lno = line; + forwards = try; + forwards_lno = line; + try_lno = line; + for (i = 0; ; i++) { - unsigned long try; - int n; + if (match_fragment(img, preimage, postimage, + try, try_lno, ws_rule, + match_beginning, match_end)) + return try_lno; + + again: + if (backwards_lno == 0 && forwards_lno == img->nr) + break; - /* "backward" */ if (i & 1) { - if (!backwards) { - if (forwards + fragsize > size) - break; - continue; + if (backwards_lno == 0) { + i++; + goto again; } - do { - --backwards; - } while (backwards && buf[backwards-1] != '\n'); + backwards_lno--; + backwards -= img->line[backwards_lno].len; try = backwards; + try_lno = backwards_lno; } else { - while (forwards + fragsize <= size) { - if (buf[forwards++] == '\n') - break; + if (forwards_lno == img->nr) { + i++; + goto again; } + forwards += img->line[forwards_lno].len; + forwards_lno++; try = forwards; + try_lno = forwards_lno; } - if (try + fragsize > size) - continue; - if (memcmp(buf + try, fragment, fragsize)) - continue; - n = (i >> 1)+1; - if (i & 1) - n = -n; - *lines = n; - return try; } - - /* - * We should start searching forward and backward. - */ return -1; } -static void remove_first_line(const char **rbuf, int *rsize) +static void remove_first_line(struct image *img) { - const char *buf = *rbuf; - int size = *rsize; - unsigned long offset; - offset = 0; - while (offset <= size) { - if (buf[offset++] == '\n') - break; - } - *rsize = size - offset; - *rbuf = buf + offset; + img->buf += img->line[0].len; + img->len -= img->line[0].len; + img->line++; + img->nr--; } -static void remove_last_line(const char **rbuf, int *rsize) +static void remove_last_line(struct image *img) { - const char *buf = *rbuf; - int size = *rsize; - unsigned long offset; - offset = size - 1; - while (offset > 0) { - if (buf[--offset] == '\n') - break; - } - *rsize = offset + 1; + img->len -= img->line[--img->nr].len; } -static int apply_line(char *output, const char *patch, int plen, - unsigned ws_rule) +static void update_image(struct image *img, + int applied_pos, + struct image *preimage, + struct image *postimage) { /* - * plen is number of bytes to be copied from patch, - * starting at patch+1 (patch[0] is '+'). Typically - * patch[plen] is '\n', unless this is the incomplete - * last line. + * remove the copy of preimage at offset in img + * and replace it with postimage */ - int i; - int add_nl_to_tail = 0; - int fixed = 0; - int last_tab_in_indent = 0; - int last_space_in_indent = 0; - int need_fix_leading_space = 0; - char *buf; - - if ((ws_error_action != correct_ws_error) || !whitespace_error || - *patch != '+') { - memcpy(output, patch + 1, plen); - return plen; - } - - /* - * Strip trailing whitespace - */ - if ((ws_rule & WS_TRAILING_SPACE) && - (1 < plen && isspace(patch[plen-1]))) { - if (patch[plen] == '\n') - add_nl_to_tail = 1; - plen--; - while (0 < plen && isspace(patch[plen])) - plen--; - fixed = 1; - } - - /* - * Check leading whitespaces (indent) - */ - for (i = 1; i < plen; i++) { - char ch = patch[i]; - if (ch == '\t') { - last_tab_in_indent = i; - if ((ws_rule & WS_SPACE_BEFORE_TAB) && - 0 < last_space_in_indent) - need_fix_leading_space = 1; - } else if (ch == ' ') { - last_space_in_indent = i; - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - 8 <= i - last_tab_in_indent) - need_fix_leading_space = 1; - } - else - break; - } - - buf = output; - if (need_fix_leading_space) { - int consecutive_spaces = 0; - int last = last_tab_in_indent + 1; - - if (ws_rule & WS_INDENT_WITH_NON_TAB) { - /* have "last" point at one past the indent */ - if (last_tab_in_indent < last_space_in_indent) - last = last_space_in_indent + 1; - else - last = last_tab_in_indent + 1; - } + int i, nr; + size_t remove_count, insert_count, applied_at = 0; + char *result; + for (i = 0; i < applied_pos; i++) + applied_at += img->line[i].len; + + remove_count = 0; + for (i = 0; i < preimage->nr; i++) + remove_count += img->line[applied_pos + i].len; + insert_count = postimage->len; + + /* Adjust the contents */ + result = xmalloc(img->len + insert_count - remove_count + 1); + memcpy(result, img->buf, applied_at); + memcpy(result + applied_at, postimage->buf, postimage->len); + memcpy(result + applied_at + postimage->len, + img->buf + (applied_at + remove_count), + img->len - (applied_at + remove_count)); + free(img->buf); + img->buf = result; + img->len += insert_count - remove_count; + result[img->len] = '\0'; + + /* Adjust the line table */ + nr = img->nr + postimage->nr - preimage->nr; + if (preimage->nr < postimage->nr) { /* - * between patch[1..last], strip the funny spaces, - * updating them to tab as needed. + * NOTE: this knows that we never call remove_first_line() + * on anything other than pre/post image. */ - for (i = 1; i < last; i++, plen--) { - char ch = patch[i]; - if (ch != ' ') { - consecutive_spaces = 0; - *output++ = ch; - } else { - consecutive_spaces++; - if (consecutive_spaces == 8) { - *output++ = '\t'; - consecutive_spaces = 0; - } - } - } - while (0 < consecutive_spaces--) - *output++ = ' '; - fixed = 1; - i = last; + img->line = xrealloc(img->line, nr * sizeof(*img->line)); + img->line_allocated = img->line; } - else - i = 1; - - memcpy(output, patch + i, plen); - if (add_nl_to_tail) - output[plen++] = '\n'; - if (fixed) - applied_after_fixing_ws++; - return output + plen - buf; + if (preimage->nr != postimage->nr) + memmove(img->line + applied_pos + postimage->nr, + img->line + applied_pos + preimage->nr, + (img->nr - (applied_pos + preimage->nr)) * + sizeof(*img->line)); + memcpy(img->line + applied_pos, + postimage->line, + postimage->nr * sizeof(*img->line)); + img->nr = nr; } -static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, +static int apply_one_fragment(struct image *img, struct fragment *frag, int inaccurate_eof, unsigned ws_rule) { int match_beginning, match_end; const char *patch = frag->patch; - int offset, size = frag->size; - char *old = xmalloc(size); - char *new = xmalloc(size); - const char *oldlines, *newlines; - int oldsize = 0, newsize = 0; + int size = frag->size; + char *old, *new, *oldlines, *newlines; int new_blank_lines_at_end = 0; unsigned long leading, trailing; - int pos, lines; + int pos, applied_pos; + struct image preimage; + struct image postimage; + + memset(&preimage, 0, sizeof(preimage)); + memset(&postimage, 0, sizeof(postimage)); + oldlines = xmalloc(size); + newlines = xmalloc(size); + old = oldlines; + new = newlines; while (size > 0) { char first; int len = linelen(patch, size); - int plen; + int plen, added; int added_blank_line = 0; if (!len) @@@ -1859,7 -1670,7 +1859,7 @@@ * followed by "\ No newline", then we also remove the * last one (which is the newline, of course). */ - plen = len-1; + plen = len - 1; if (len < size && patch[len] == '\\') plen--; first = *patch; @@@ -1876,40 -1687,25 +1876,40 @@@ if (plen < 0) /* ... followed by '\No newline'; nothing */ break; - old[oldsize++] = '\n'; - new[newsize++] = '\n'; + *old++ = '\n'; + *new++ = '\n'; + add_line_info(&preimage, "\n", 1, LINE_COMMON); + add_line_info(&postimage, "\n", 1, LINE_COMMON); break; case ' ': case '-': - memcpy(old + oldsize, patch + 1, plen); - oldsize += plen; + memcpy(old, patch + 1, plen); + add_line_info(&preimage, old, plen, + (first == ' ' ? LINE_COMMON : 0)); + old += plen; if (first == '-') break; /* Fall-through for ' ' */ case '+': - if (first != '+' || !no_add) { - int added = apply_line(new + newsize, patch, - plen, ws_rule); - newsize += added; - if (first == '+' && - added == 1 && new[newsize-1] == '\n') - added_blank_line = 1; + /* --no-add does not add new lines */ + if (first == '+' && no_add) + break; + + if (first != '+' || + !whitespace_error || + ws_error_action != correct_ws_error) { + memcpy(new, patch + 1, plen); + added = plen; } + else { + added = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws); + } + add_line_info(&postimage, new, added, + (first == '+' ? 0 : LINE_COMMON)); + new += added; + if (first == '+' && + added == 1 && new[-1] == '\n') + added_blank_line = 1; break; case '@': case '\\': /* Ignore it, we already handled it */ @@@ -1926,13 -1722,16 +1926,13 @@@ patch += len; size -= len; } - if (inaccurate_eof && - oldsize > 0 && old[oldsize - 1] == '\n' && - newsize > 0 && new[newsize - 1] == '\n') { - oldsize--; - newsize--; + old > oldlines && old[-1] == '\n' && + new > newlines && new[-1] == '\n') { + old--; + new--; } - oldlines = old; - newlines = new; leading = frag->leading; trailing = frag->trailing; @@@ -1956,21 -1755,33 +1956,21 @@@ */ match_end = !unidiff_zero && !trailing; - lines = 0; - pos = frag->newpos; + pos = frag->newpos ? (frag->newpos - 1) : 0; + preimage.buf = oldlines; + preimage.len = old - oldlines; + postimage.buf = newlines; + postimage.len = new - newlines; + preimage.line = preimage.line_allocated; + postimage.line = postimage.line_allocated; + for (;;) { - offset = find_offset(buf->buf, buf->len, - oldlines, oldsize, pos, &lines); - if (match_end && offset + oldsize != buf->len) - offset = -1; - if (match_beginning && offset) - offset = -1; - if (offset >= 0) { - if (ws_error_action == correct_ws_error && - (buf->len - oldsize - offset == 0)) /* end of file? */ - newsize -= new_blank_lines_at_end; - - /* Warn if it was necessary to reduce the number - * of context lines. - */ - if ((leading != frag->leading) || - (trailing != frag->trailing)) - fprintf(stderr, "Context reduced to (%ld/%ld)" - " to apply fragment at %d\n", - leading, trailing, pos + lines); - - strbuf_splice(buf, offset, oldsize, newlines, newsize); - offset = 0; + + applied_pos = find_pos(img, &preimage, &postimage, pos, + ws_rule, match_beginning, match_end); + + if (applied_pos >= 0) break; - } /* Am I at my context limits? */ if ((leading <= p_context) && (trailing <= p_context)) @@@ -1979,64 -1790,33 +1979,64 @@@ match_beginning = match_end = 0; continue; } + /* * Reduce the number of context lines; reduce both * leading and trailing if they are equal otherwise * just reduce the larger context. */ if (leading >= trailing) { - remove_first_line(&oldlines, &oldsize); - remove_first_line(&newlines, &newsize); + remove_first_line(&preimage); + remove_first_line(&postimage); pos--; leading--; } if (trailing > leading) { - remove_last_line(&oldlines, &oldsize); - remove_last_line(&newlines, &newsize); + remove_last_line(&preimage); + remove_last_line(&postimage); trailing--; } } - if (offset && apply_verbosely) - error("while searching for:\n%.*s", oldsize, oldlines); + if (applied_pos >= 0) { + if (ws_error_action == correct_ws_error && + new_blank_lines_at_end && + postimage.nr + applied_pos == img->nr) { + /* + * If the patch application adds blank lines + * at the end, and if the patch applies at the + * end of the image, remove those added blank + * lines. + */ + while (new_blank_lines_at_end--) + remove_last_line(&postimage); + } - free(old); - free(new); - return offset; + /* + * Warn if it was necessary to reduce the number + * of context lines. + */ + if ((leading != frag->leading) || + (trailing != frag->trailing)) + fprintf(stderr, "Context reduced to (%ld/%ld)" + " to apply fragment at %d\n", + leading, trailing, applied_pos+1); + update_image(img, applied_pos, &preimage, &postimage); + } else { + if (apply_verbosely) + error("while searching for:\n%.*s", + (int)(old - oldlines), oldlines); + } + + free(oldlines); + free(newlines); + free(preimage.line_allocated); + free(postimage.line_allocated); + + return (applied_pos < 0); } -static int apply_binary_fragment(struct strbuf *buf, struct patch *patch) +static int apply_binary_fragment(struct image *img, struct patch *patch) { struct fragment *fragment = patch->fragments; unsigned long len; @@@ -2053,26 -1833,22 +2053,26 @@@ } switch (fragment->binary_patch_method) { case BINARY_DELTA_DEFLATED: - dst = patch_delta(buf->buf, buf->len, fragment->patch, + dst = patch_delta(img->buf, img->len, fragment->patch, fragment->size, &len); if (!dst) return -1; - /* XXX patch_delta NUL-terminates */ - strbuf_attach(buf, dst, len, len + 1); + clear_image(img); + img->buf = dst; + img->len = len; return 0; case BINARY_LITERAL_DEFLATED: - strbuf_reset(buf); - strbuf_add(buf, fragment->patch, fragment->size); + clear_image(img); + img->len = fragment->size; + img->buf = xmalloc(img->len+1); + memcpy(img->buf, fragment->patch, img->len); + img->buf[img->len] = '\0'; return 0; } return -1; } -static int apply_binary(struct strbuf *buf, struct patch *patch) +static int apply_binary(struct image *img, struct patch *patch) { const char *name = patch->old_name ? patch->old_name : patch->new_name; unsigned char sha1[20]; @@@ -2093,7 -1869,7 +2093,7 @@@ * See if the old one matches what the patch * applies to. */ - hash_sha1_file(buf->buf, buf->len, blob_type, sha1); + hash_sha1_file(img->buf, img->len, blob_type, sha1); if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix)) return error("the patch applies to '%s' (%s), " "which does not match the " @@@ -2102,14 -1878,14 +2102,14 @@@ } else { /* Otherwise, the old one must be empty. */ - if (buf->len) + if (img->len) return error("the patch applies to an empty " "'%s' but it is not empty", name); } get_sha1_hex(patch->new_sha1_prefix, sha1); if (is_null_sha1(sha1)) { - strbuf_release(buf); + clear_image(img); return 0; /* deletion patch */ } @@@ -2124,21 -1900,20 +2124,21 @@@ return error("the necessary postimage %s for " "'%s' cannot be read", patch->new_sha1_prefix, name); - /* XXX read_sha1_file NUL-terminates */ - strbuf_attach(buf, result, size, size + 1); + clear_image(img); + img->buf = result; + img->len = size; } else { /* * We have verified buf matches the preimage; * apply the patch data to it, which is stored * in the patch->fragments->{patch,size}. */ - if (apply_binary_fragment(buf, patch)) + if (apply_binary_fragment(img, patch)) return error("binary patch does not apply to '%s'", name); /* verify that the result matches */ - hash_sha1_file(buf->buf, buf->len, blob_type, sha1); + hash_sha1_file(img->buf, img->len, blob_type, sha1); if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix)) return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1)); @@@ -2147,7 -1922,7 +2147,7 @@@ return 0; } -static int apply_fragments(struct strbuf *buf, struct patch *patch) +static int apply_fragments(struct image *img, struct patch *patch) { struct fragment *frag = patch->fragments; const char *name = patch->old_name ? patch->old_name : patch->new_name; @@@ -2155,10 -1930,10 +2155,10 @@@ unsigned inaccurate_eof = patch->inaccurate_eof; if (patch->is_binary) - return apply_binary(buf, patch); + return apply_binary(img, patch); while (frag) { - if (apply_one_fragment(buf, frag, inaccurate_eof, ws_rule)) { + if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule)) { error("patch failed: %s:%ld", name, frag->oldpos); if (!apply_with_reject) return -1; @@@ -2174,7 -1949,7 +2174,7 @@@ static int read_file_or_gitlink(struct if (!ce) return 0; - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { strbuf_grow(buf, 100); strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1)); } else { @@@ -2194,9 -1969,6 +2194,9 @@@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) { struct strbuf buf; + struct image image; + size_t len; + char *img; strbuf_init(&buf, 0); if (cached) { @@@ -2219,14 -1991,9 +2219,14 @@@ } } - if (apply_fragments(&buf, patch) < 0) + img = strbuf_detach(&buf, &len); + prepare_image(&image, img, len, !patch->is_binary); + + if (apply_fragments(&image, patch) < 0) return -1; /* note with --reject this succeeds. */ - patch->result = strbuf_detach(&buf, &patch->resultsize); + patch->result = image.buf; + patch->resultsize = image.len; + free(image.line_allocated); if (0 < patch->is_delete && patch->resultsize) return error("removal patch leaves file contents"); @@@ -2259,7 -2026,7 +2259,7 @@@ static int check_to_create_blob(const c static int verify_index_match(struct cache_entry *ce, struct stat *st) { - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { if (!S_ISDIR(st->st_mode)) return -1; return 0; @@@ -2318,12 -2085,12 +2318,12 @@@ static int check_patch(struct patch *pa return error("%s: does not match index", old_name); if (cached) - st_mode = ntohl(ce->ce_mode); + st_mode = ce->ce_mode; } else if (stat_ret < 0) return error("%s: %s", old_name, strerror(errno)); if (!cached) - st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode)); + st_mode = ce_mode_from_stat(ce, st.st_mode); if (patch->is_new < 0) patch->is_new = 0; @@@ -2624,7 -2391,7 +2624,7 @@@ static void add_index_file(const char * ce = xcalloc(1, ce_size); memcpy(ce->name, path, namelen); ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = htons(namelen); + ce->ce_flags = namelen; if (S_ISGITLINK(mode)) { const char *s = buf; @@@ -2997,7 -2764,7 +2997,7 @@@ int cmd_apply(int argc, const char **ar int read_stdin = 1; int inaccurate_eof = 0; int errs = 0; - int is_not_gitdir = 0; + int is_not_gitdir; const char *whitespace_option = NULL; @@@ -3121,7 -2888,7 +3121,7 @@@ fd = open(arg, O_RDONLY); if (fd < 0) - usage(apply_usage); + die("can't open patch '%s': %s", arg, strerror(errno)); read_stdin = 0; set_default_whitespace_mode(whitespace_option); errs |= apply_patch(fd, arg, inaccurate_eof); diff --combined builtin-fmt-merge-msg.c index ebb3f37cf1,03c2bc33eb..7077d52477 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@@ -187,8 -187,7 +187,8 @@@ static void shortlog(const char *name, add_pending_object(rev, branch, name); add_pending_object(rev, &head->object, "^HEAD"); head->object.flags |= UNINTERESTING; - prepare_revision_walk(rev); + if (prepare_revision_walk(rev)) + die("revision walk setup failed"); while ((commit = get_revision(rev)) != NULL) { char *oneline, *bol, *eol; @@@ -201,6 -200,15 +201,15 @@@ continue; bol = strstr(commit->buffer, "\n\n"); + if (bol) { + unsigned char c; + do { + c = *++bol; + } while (isspace(c)); + if (!c) + bol = NULL; + } + if (!bol) { append_to_list(&subjects, xstrdup(sha1_to_hex( commit->object.sha1)), @@@ -208,7 -216,6 +217,6 @@@ continue; } - bol += 2; eol = strchr(bol, '\n'); if (eol) { oneline = xmemdupz(bol, eol - bol); diff --combined git-am.sh index ac5c388060,0f05a2cfe3..245e1db1fc --- a/git-am.sh +++ b/git-am.sh @@@ -2,14 -2,13 +2,14 @@@ # # Copyright (c) 2005, 2006 Junio C Hamano +SUBDIRECTORY_OK=Yes OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ git-am [options] |... git-am [options] --resolved git-am [options] --skip -- -d,dotest= use and not .dotest +d,dotest= (removed -- do not use) i,interactive run interactively b,binary pass --allo-binary-replacement to git-apply 3,3way allow fall back on 3way merging if needed @@@ -21,14 -20,11 +21,14 @@@ C= pass it through git-app p= pass it through git-apply resolvemsg= override error message when patch failure occurs r,resolved to be used after a patch failure -skip skip the current patch" +skip skip the current patch +rebasing (internal use for git-rebase)" . git-sh-setup +prefix=$(git rev-parse --show-prefix) set_reflog_action am require_work_tree +cd_to_toplevel git var GIT_COMMITTER_IDENT >/dev/null || exit @@@ -51,6 -47,10 +51,6 @@@ stop_here_user_resolve () then cmdline="$cmdline -3" fi - if test '.dotest' != "$dotest" - then - cmdline="$cmdline -d=$dotest" - fi echo "When you have resolved this problem run \"$cmdline --resolved\"." echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"." @@@ -107,7 -107,7 +107,7 @@@ It does not apply to blobs recorded in # patch did not touch, so recursive ends up canceling them, # saying that we reverted all those changes. - eval GITHEAD_$his_tree='"$SUBJECT"' + eval GITHEAD_$his_tree='"$FIRSTLINE"' export GITHEAD_$his_tree git-merge-recursive $orig_tree -- HEAD $his_tree || { git rerere @@@ -117,13 -117,8 +117,9 @@@ unset GITHEAD_$his_tree } - reread_subject () { - git stripspace <"$1" | sed -e 1q - } - prec=4 -dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= +dotest=".dotest" +sign= utf8=t keep= skip= interactive= resolved= binary= rebasing= resolvemsg= resume= git_apply_opt= @@@ -148,11 -143,8 +144,11 @@@ d resolved=t ;; --skip) skip=t ;; + --rebasing) + rebasing=t threeway=t keep=t binary=t ;; -d|--dotest) - shift; dotest=$1;; + die "-d option is no longer supported. Do not use." + ;; --resolvemsg) shift; resolvemsg=$1 ;; --whitespace) @@@ -188,7 -180,7 +184,7 @@@ the 0,) # No file input but without resume parameters; catch # user error to feed us a patch from standard input - # when there is already .dotest. This is somewhat + # when there is already $dotest. This is somewhat # unreliable -- stdin could be /dev/null for example # and the caller did not intend to feed us a patch but # wanted to continue unattended. @@@ -208,24 -200,6 +204,24 @@@ els # Start afresh. mkdir -p "$dotest" || exit + if test -n "$prefix" && test $# != 0 + then + first=t + for arg + do + test -n "$first" && { + set x + first= + } + case "$arg" in + /*) + set "$@" "$arg" ;; + *) + set "$@" "$prefix$arg" ;; + esac + done + shift + fi git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || { rm -fr "$dotest" exit 1 @@@ -240,12 -214,6 +236,12 @@@ echo "$utf8" >"$dotest/utf8" echo "$keep" >"$dotest/keep" echo 1 >"$dotest/next" + if test -n "$rebasing" + then + : >"$dotest/rebasing" + else + : >"$dotest/applying" + fi fi case "$resolved" in @@@ -331,7 -299,11 +327,11 @@@ d echo "Patch is empty. Was it split wrong?" stop_here $this } - git stripspace < "$dotest/msg" > "$dotest/msg-clean" + SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" + case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac + + (echo "$SUBJECT" ; echo ; cat "$dotest/msg") | + git stripspace > "$dotest/msg-clean" ;; esac @@@ -347,9 -319,6 +347,6 @@@ export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE - SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")" - case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac - case "$resume" in '') if test '' != "$SIGNOFF" @@@ -357,7 -326,7 +354,7 @@@ LAST_SIGNED_OFF_BY=` sed -ne '/^Signed-off-by: /p' \ "$dotest/msg-clean" | - tail -n 1 + sed -ne '$p' ` ADD_SIGNOFF=` test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { @@@ -368,10 -337,8 +365,8 @@@ ADD_SIGNOFF= fi { - printf '%s\n' "$SUBJECT" if test -s "$dotest/msg-clean" then - echo cat "$dotest/msg-clean" fi if test '' != "$ADD_SIGNOFF" @@@ -388,6 -355,7 +383,7 @@@ ;; esac esac + FIRSTLINE=$(head -1 "$dotest/final-commit") resume= if test "$interactive" = t @@@ -408,7 -376,7 +404,7 @@@ [aA]*) action=yes interactive= ;; [nN]*) action=skip ;; [eE]*) git_editor "$dotest/final-commit" - SUBJECT=$(reread_subject "$dotest/final-commit") + FIRSTLINE=$(head -1 "$dotest/final-commit") action=again ;; [vV]*) action=again LESS=-S ${PAGER:-less} "$dotest/patch" ;; @@@ -431,7 -399,7 +427,7 @@@ stop_here $this fi - printf 'Applying %s\n' "$SUBJECT" + printf 'Applying %s\n' "$FIRSTLINE" case "$resolved" in '') @@@ -489,7 -457,7 +485,7 @@@ tree=$(git write-tree) && parent=$(git rev-parse --verify HEAD) && commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit") && - git update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent || + git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || stop_here $this if test -x "$GIT_DIR"/hooks/post-applypatch diff --combined git-bisect.sh index 5177a2a114,b42f94cd39..8e57e9a75d --- a/git-bisect.sh +++ b/git-bisect.sh @@@ -62,9 -62,10 +62,10 @@@ bisect_start() # Verify HEAD. If we were bisecting before this, reset to the # top-of-line master first! # - head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) || + head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) || head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) || die "Bad HEAD - I need a HEAD" + start_head='' case "$head" in refs/heads/bisect) if [ -s "$GIT_DIR/BISECT_START" ]; then @@@ -78,7 -79,7 +79,7 @@@ # This error message should only be triggered by cogito usage, # and cogito users should understand it relates to cg-seek. [ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree" - echo "${head#refs/heads/}" >"$GIT_DIR/BISECT_START" + start_head="${head#refs/heads/}" ;; *) die "Bad HEAD - strange symbolic ref" @@@ -99,6 -100,7 +100,7 @@@ done orig_args=$(sq "$@") bad_seen=0 + eval='' while [ $# -gt 0 ]; do arg="$1" case "$arg" in @@@ -116,13 -118,15 +118,15 @@@ 0) state='bad' ; bad_seen=1 ;; *) state='good' ;; esac - bisect_write "$state" "$rev" 'nolog' + eval="$eval bisect_write '$state' '$rev' 'nolog'; " shift ;; esac done sq "$@" >"$GIT_DIR/BISECT_NAMES" + test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START" + eval "$eval" echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" bisect_auto_next } @@@ -153,12 -157,14 +157,14 @@@ bisect_state() bisect_write "$state" "$rev" ;; 2,bad|*,good|*,skip) shift + eval='' for rev in "$@" do sha=$(git rev-parse --verify "$rev^{commit}") || die "Bad rev input: $rev" - bisect_write "$state" "$sha" - done ;; + eval="$eval bisect_write '$state' '$sha'; " + done + eval "$eval" ;; *,bad) die "'git bisect bad' can take only one argument." ;; *) @@@ -289,14 -295,14 +295,14 @@@ bisect_next() bisect_next_check good skip=$(git for-each-ref --format='%(objectname)' \ - "refs/bisect/skip-*" | tr '[\012]' ' ') || exit + "refs/bisect/skip-*" | tr '\012' ' ') || exit BISECT_OPT='' test -n "$skip" && BISECT_OPT='--bisect-all' bad=$(git rev-parse --verify refs/bisect/bad) && good=$(git for-each-ref --format='^%(objectname)' \ - "refs/bisect/good-*" | tr '[\012]' ' ') && + "refs/bisect/good-*" | tr '\012' ' ') && eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" && eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" && eval=$(filter_skipped "$eval" "$skip") && @@@ -329,9 -335,9 +335,9 @@@ bisect_visualize() if test $# = 0 then - case "${DISPLAY+set}" in + case "${DISPLAY+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in '') set git log ;; - set) set gitk ;; + set*) set gitk ;; esac else case "$1" in diff --combined t/t6030-bisect-porcelain.sh index 32d6118183,14e87967ff..5e3e5445c7 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@@ -71,8 -71,12 +71,12 @@@ test_expect_success 'bisect start with git bisect next ' - test_expect_success 'bisect good and bad fails if not given only revs' ' + test_expect_success 'bisect fails if given any junk instead of revs' ' git bisect reset && + test_must_fail git bisect start foo $HASH1 -- && + test_must_fail git bisect start $HASH4 $HASH1 bar -- && + test -z "$(git for-each-ref "refs/bisect/*")" && + test_must_fail ls .git/BISECT_* && git bisect start && test_must_fail git bisect good foo $HASH1 && test_must_fail git bisect good $HASH1 bar && @@@ -80,6 -84,7 +84,7 @@@ test_must_fail git bisect bad $HASH3 $HASH4 && test_must_fail git bisect skip bar $HASH3 && test_must_fail git bisect skip $HASH1 foo && + test -z "$(git for-each-ref "refs/bisect/*")" && git bisect good $HASH1 && git bisect bad $HASH4 ' @@@ -232,7 -237,7 +237,7 @@@ test_expect_success 'bisect run & skip add_line_into_file "6: Yet a line." hello && HASH6=$(git rev-parse --verify HEAD) && echo "#"\!"/bin/sh" > test_script.sh && - echo "tail -1 hello | grep Ciao > /dev/null && exit 125" >> test_script.sh && + echo "sed -ne \\\$p hello | grep Ciao > /dev/null && exit 125" >> test_script.sh && echo "grep line hello > /dev/null" >> test_script.sh && echo "test \$? -ne 0" >> test_script.sh && chmod +x test_script.sh && @@@ -257,8 -262,8 +262,8 @@@ test_expect_success 'bisect run & skip add_line_into_file "7: Should be the last line." hello && HASH7=$(git rev-parse --verify HEAD) && echo "#"\!"/bin/sh" > test_script.sh && - echo "tail -1 hello | grep Ciao > /dev/null && exit 125" >> test_script.sh && - echo "tail -1 hello | grep day > /dev/null && exit 125" >> test_script.sh && + echo "sed -ne \\\$p hello | grep Ciao > /dev/null && exit 125" >> test_script.sh && + echo "sed -ne \\\$p hello | grep day > /dev/null && exit 125" >> test_script.sh && echo "grep Yet hello > /dev/null" >> test_script.sh && echo "test \$? -ne 0" >> test_script.sh && chmod +x test_script.sh &&