From 37d07f8f9841a29cb53a1eda6acd3804c957f0e3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 12 Dec 2007 19:09:16 -0800 Subject: [PATCH 01/84] git-commit: squelch needless message during an empty merge When recording a merge that conflicted and ends up in no changes after manual resolution, commit callchain looked like this: cmd_commit() -> prepare_log_message() -> run_status() -> wt_status_print() This invocation of run_status() is asked to find out if there is a committable change, but it unconditionally gave instructions such as "use git-add" at the same time. When in merge, we do allow an empty change to be recorded, so after showing this message the code still went ahead and made a commit. This introduces "nowarn" parameter to run_status() to avoid these useless messages. If we are not allowed to create an empty commit, we already call run_status() again in the original codepath, and the message will be shown from that call anyway. Signed-off-by: Junio C Hamano --- builtin-commit.c | 9 +++++---- wt-status.c | 2 ++ wt-status.h | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 9cb7589ac6..ad9f9211b3 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -280,7 +280,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) return false_lock.filename; } -static int run_status(FILE *fp, const char *index_file, const char *prefix) +static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn) { struct wt_status s; @@ -296,6 +296,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix) s.untracked = untracked_files; s.index_file = index_file; s.fp = fp; + s.nowarn = nowarn; wt_status_print(&s); @@ -412,7 +413,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) saved_color_setting = wt_status_use_color; wt_status_use_color = 0; - commitable = run_status(fp, index_file, prefix); + commitable = run_status(fp, index_file, prefix, 1); wt_status_use_color = saved_color_setting; fclose(fp); @@ -606,7 +607,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) index_file = prepare_index(argc, argv, prefix); - commitable = run_status(stdout, index_file, prefix); + commitable = run_status(stdout, index_file, prefix, 0); rollback_index_files(); @@ -717,7 +718,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!prepare_log_message(index_file, prefix) && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { - run_status(stdout, index_file, prefix); + run_status(stdout, index_file, prefix, 0); rollback_index_files(); unlink(commit_editmsg); return 1; diff --git a/wt-status.c b/wt-status.c index 51c1879691..c0c247243b 100644 --- a/wt-status.c +++ b/wt-status.c @@ -381,6 +381,8 @@ void wt_status_print(struct wt_status *s) if (!s->commitable) { if (s->amend) fprintf(s->fp, "# No changes\n"); + else if (s->nowarn) + ; /* nothing */ else if (s->workdir_dirty) printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"); else if (s->workdir_untracked) diff --git a/wt-status.h b/wt-status.h index 63d50f2871..02afaa60ee 100644 --- a/wt-status.h +++ b/wt-status.h @@ -17,6 +17,7 @@ struct wt_status { int verbose; int amend; int untracked; + int nowarn; /* These are computed during processing of the individual sections */ int commitable; int workdir_dirty; From 9e5d87d49070fe0463040e826824d6ce41beb089 Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Wed, 12 Dec 2007 22:36:21 -0600 Subject: [PATCH 02/84] Fix spelling mistakes in user manual Signed-off-by: Shawn Bohrer Acked-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- Documentation/user-manual.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 93a47b439b..f2b42068f3 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -1994,7 +1994,7 @@ $ git push ssh://yourserver.com/~you/proj.git +master ------------------------------------------------- Normally whenever a branch head in a public repository is modified, it -is modified to point to a descendent of the commit that it pointed to +is modified to point to a descendant of the commit that it pointed to before. By forcing a push in this situation, you break that convention. (See <>.) @@ -2921,7 +2921,7 @@ As you can see, a commit is defined by: - a tree: The SHA1 name of a tree object (as defined below), representing the contents of a directory at a certain point in time. - parent(s): The SHA1 name of some number of commits which represent the - immediately prevoius step(s) in the history of the project. The + immediately previous step(s) in the history of the project. The example above has one parent; merge commits may have more than one. A commit with no parents is called a "root" commit, and represents the initial revision of a project. Each project must have @@ -3242,7 +3242,7 @@ to replace them by hand. Back up your repository before attempting this in case you corrupt things even more in the process. We'll assume that the problem is a single missing or corrupted blob, -which is sometimes a solveable problem. (Recovering missing trees and +which is sometimes a solvable problem. (Recovering missing trees and especially commits is *much* harder). Before starting, verify that there is corruption, and figure out where From 5ff6aae8951268d8287337b1875bccae267d2b56 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Thu, 13 Dec 2007 06:58:15 +0000 Subject: [PATCH 03/84] git-svn: expand handling of From: and Signed-off-by: The current parsing for From: and Signed-off-by: lines handles fully specified names: From: Full Name Expand this to include the raw email addresses and straight "names": From: email@address -> email From: Full Name -> Full Name Signed-off-by: Andy Whitcroft Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 54d784469a..34c5e3d2e4 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2363,11 +2363,20 @@ sub make_log_entry { my ($commit_name, $commit_email) = ($name, $email); if ($_use_log_author) { - if ($log_entry{log} =~ /From:\s+(.*?)\s+<(.*)>\s*\n/) { - ($name, $email) = ($1, $2); - } elsif ($log_entry{log} =~ - /Signed-off-by:\s+(.*?)\s+<(.*)>\s*\n/) { + my $name_field; + if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) { + $name_field = $1; + } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) { + $name_field = $1; + } + if (!defined $name_field) { + # + } elsif ($name_field =~ /(.*?)\s+<(.*)>/) { ($name, $email) = ($1, $2); + } elsif ($name_field =~ /(.*)@/) { + ($name, $email) = ($1, $name_field); + } else { + ($name, $email) = ($name_field, 'unknown'); } } if (defined $headrev && $self->use_svm_props) { From 3157dd9e89a71e80673d0bc21b5c0630f3b1fe68 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 13 Dec 2007 08:27:34 -0800 Subject: [PATCH 04/84] git-svn: unlink internal index files after operations Being git, we can generate these very quickly on the fly as needed, so there's no point in wasting space for these things for large projects. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-svn.perl b/git-svn.perl index 34c5e3d2e4..3aa7f8cb40 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -396,6 +396,7 @@ sub cmd_set_tree { } $gs->set_tree($_) foreach @revs; print "Done committing ",scalar @revs," revisions to SVN\n"; + unlink $gs->{index}; } sub cmd_dcommit { @@ -514,6 +515,7 @@ sub cmd_dcommit { $last_rev = $cmt_rev; } } + unlink $gs->{index}; } sub cmd_find_rev { @@ -1374,6 +1376,7 @@ sub fetch_all { ($base, $head) = parse_revision_argument($base, $head); $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs); + unlink $_->{index} foreach @gs; } sub read_all_remotes { From 792c1583c8ab94c8cee77ca66685983259d7510e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 13 Dec 2007 22:32:36 -0500 Subject: [PATCH 05/84] provide advance warning of some future pack default changes Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.4.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/RelNotes-1.5.4.txt b/Documentation/RelNotes-1.5.4.txt index 6645565c52..d6fd3ddd16 100644 --- a/Documentation/RelNotes-1.5.4.txt +++ b/Documentation/RelNotes-1.5.4.txt @@ -43,6 +43,17 @@ Deprecation notices * "git peek-remote" is deprecated, as "git ls-remote" was written in C and works for all transports, and will be removed in the future. + * From v1.5.5, the repack.usedeltabaseoffset config option will default + to true, which will give denser packfile (i.e. more efficient storage). + The downside is that git older than version 1.4.4 will not be able + to directly use a repository packed using this setting. + + * From v1.5.5, the pack.indexversion config option will default to 2, + which is slightly more efficient, and makes repacking more immune to + data corruptions. Git older than version 1.5.2 may revert to version 1 + of the pack index with a manual "git index-pack" to be able to directly + access corresponding pack files. + Updates since v1.5.3 -------------------- From c279d7e9869740a6d64b0d1d70f7968af68d2071 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Dec 2007 13:25:07 -0800 Subject: [PATCH 06/84] xdl_diff: identify call sites. This inserts a new function xdi_diff() that currently does not do anything other than calling the underlying xdl_diff() to the callchain of current callers of xdl_diff() function. Signed-off-by: Junio C Hamano --- builtin-blame.c | 2 +- builtin-rerere.c | 2 +- combine-diff.c | 2 +- diff.c | 10 +++++----- merge-file.c | 2 +- merge-tree.c | 2 +- xdiff-interface.c | 5 +++++ xdiff-interface.h | 1 + 8 files changed, 16 insertions(+), 10 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index 5466d01f9a..99ea0a02cb 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -542,7 +542,7 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, state.ret->chunks = NULL; state.ret->num = 0; - xdl_diff(file_p, file_o, &xpp, &xecfg, &ecb); + xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb); if (state.ret->num) { struct chunk *chunk; diff --git a/builtin-rerere.c b/builtin-rerere.c index 74493237c9..37e6248138 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -260,7 +260,7 @@ static int diff_two(const char *file1, const char *label1, memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; ecb.outf = outf; - xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb); + xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); diff --git a/combine-diff.c b/combine-diff.c index 5a658dc0d5..e22db89932 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -226,7 +226,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file, state.num_parent = num_parent; state.n = n; - xdl_diff(&parent_file, result_file, &xpp, &xecfg, &ecb); + xdi_diff(&parent_file, result_file, &xpp, &xecfg, &ecb); free(parent_file.ptr); /* Assign line numbers for this parent. diff --git a/diff.c b/diff.c index 9c79ee2891..3dd2f35f73 100644 --- a/diff.c +++ b/diff.c @@ -439,7 +439,7 @@ static void diff_words_show(struct diff_words_data *diff_words) ecb.outf = xdiff_outf; ecb.priv = diff_words; diff_words->xm.consume = fn_out_diff_words_aux; - xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb); + xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); @@ -1393,7 +1393,7 @@ static void builtin_diff(const char *name_a, if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); - xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); } @@ -1446,7 +1446,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b, xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; ecb.outf = xdiff_outf; ecb.priv = diffstat; - xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } free_and_return: @@ -1486,7 +1486,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, xpp.flags = XDF_NEED_MINIMAL; ecb.outf = xdiff_outf; ecb.priv = &data; - xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } free_and_return: diff_free_filespec_data(one); @@ -2898,7 +2898,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) xecfg.flags = XDL_EMIT_FUNCNAMES; ecb.outf = xdiff_outf; ecb.priv = &data; - xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } SHA1_Final(sha1, &ctx); diff --git a/merge-file.c b/merge-file.c index 1e031eafe0..2a939c9dd8 100644 --- a/merge-file.c +++ b/merge-file.c @@ -71,7 +71,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2) res->size = 0; ecb.priv = res; - return xdl_diff(f1, f2, &xpp, &xecfg, &ecb); + return xdi_diff(f1, f2, &xpp, &xecfg, &ecb); } void *merge_file(struct blob *base, struct blob *our, struct blob *their, unsigned long *size) diff --git a/merge-tree.c b/merge-tree.c index 7d4f628444..e08324686c 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -119,7 +119,7 @@ static void show_diff(struct merge_list *entry) if (!dst.ptr) size = 0; dst.size = size; - xdl_diff(&src, &dst, &xpp, &xecfg, &ecb); + xdi_diff(&src, &dst, &xpp, &xecfg, &ecb); free(src.ptr); free(dst.ptr); } diff --git a/xdiff-interface.c b/xdiff-interface.c index be866d12d3..69a022c134 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -103,6 +103,11 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) return 0; } +int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb) +{ + return xdl_diff(mf1, mf2, xpp, xecfg, xecb); +} + int read_mmfile(mmfile_t *ptr, const char *filename) { struct stat st; diff --git a/xdiff-interface.h b/xdiff-interface.h index fb742dbb6b..f7f791d96b 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -13,6 +13,7 @@ struct xdiff_emit_state { unsigned long remainder_size; }; +int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf); int parse_hunk_header(char *line, int len, int *ob, int *on, From 913b45f51b151d8e29f86df67d3e10853d831470 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Dec 2007 14:24:18 -0800 Subject: [PATCH 07/84] xdi_diff: trim common trailing lines This implements earlier Linus's optimization to trim common lines at the end before passing them down to low level xdiff interface for all of our xdiff users. We could later enhance this to also trim common leading lines, but that would need tweaking the output function to add the number of lines trimmed at the beginning to line numbers that appear in the hunk headers. Signed-off-by: Junio C Hamano --- xdiff-interface.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/xdiff-interface.c b/xdiff-interface.c index 69a022c134..f2cd488de0 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -103,9 +103,41 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) return 0; } +/* + * Trim down common substring at the end of the buffers, + * but leave at least ctx lines at the end. + */ +static void trim_common_tail(mmfile_t *a, mmfile_t *b, int ctx) +{ + const int blk = 1024; + long trimmed = 0, recovered = 0; + int i; + char *ap = a->ptr + a->size; + char *bp = b->ptr + b->size; + long smaller = (a->size < b->size) ? a->size : b->size; + + while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) { + trimmed += blk; + ap -= blk; + bp -= blk; + } + + for (i = 0, recovered = 0; recovered < trimmed && i <= ctx; i++) { + while (recovered < trimmed && ap[recovered] != '\n') + recovered++; + } + a->size -= (trimmed - recovered); + b->size -= (trimmed - recovered); +} + int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb) { - return xdl_diff(mf1, mf2, xpp, xecfg, xecb); + mmfile_t a = *mf1; + mmfile_t b = *mf2; + + trim_common_tail(&a, &b, xecfg->ctxlen); + + return xdl_diff(&a, &b, xpp, xecfg, xecb); } int read_mmfile(mmfile_t *ptr, const char *filename) From 62c64895cfcf3bbf34969a69fa96a631f7d5b14e Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Thu, 13 Dec 2007 21:24:52 +0100 Subject: [PATCH 08/84] "diff --check" should affect exit status "git diff" has a --check option that can be used to check for whitespace problems but it only reported by printing warnings to the console. Now when the --check option is used we give a non-zero exit status, making "git diff --check" nicer to use in scripts and hooks. Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 4 +- builtin-diff-files.c | 2 + builtin-diff-index.c | 2 + builtin-diff-tree.c | 28 +++---- builtin-diff.c | 6 +- diff.c | 9 +++ diff.h | 1 + t/t4015-diff-whitespace.sh | 137 ++++++++++++++++++++++++++++++++- 8 files changed, 171 insertions(+), 18 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 5d22b7b58c..9ecc1d7bc4 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -93,7 +93,9 @@ endif::git-format-patch[] --check:: Warn if changes introduce trailing whitespace - or an indent that uses a space before a tab. + or an indent that uses a space before a tab. Exits with + non-zero status if problems are found. Not compatible with + --exit-code. --full-index:: Instead of the first handful characters, show full diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 046b7e34b5..4afc8724e7 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -33,5 +33,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) result = run_diff_files_cmd(&rev, argc, argv); if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; + if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; return result; } diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 556c506bfa..532b284b10 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -46,5 +46,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) result = run_diff_index(&rev, cached); if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; + if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; return result; } diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 2e13716eec..9ab90cb4c5 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -117,23 +117,23 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) break; } - if (!read_stdin) - return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) - && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); + if (read_stdin) { + if (opt->diffopt.detect_rename) + opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | + DIFF_SETUP_USE_CACHE); + while (fgets(line, sizeof(line), stdin)) { + unsigned char sha1[20]; - if (opt->diffopt.detect_rename) - opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | - DIFF_SETUP_USE_CACHE); - while (fgets(line, sizeof(line), stdin)) { - unsigned char sha1[20]; - - if (get_sha1_hex(line, sha1)) { - fputs(line, stdout); - fflush(stdout); + if (get_sha1_hex(line, sha1)) { + fputs(line, stdout); + fflush(stdout); + } + else + diff_tree_stdin(line); } - else - diff_tree_stdin(line); } + if (opt->diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&opt->diffopt, CHECK_FAILED) != 0; return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); } diff --git a/builtin-diff.c b/builtin-diff.c index 55fb84c730..9d878f6a71 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -247,7 +247,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* If the user asked for our exit code then don't start a * pager or we would end up reporting its exit code instead. */ - if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) + if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) && + (!(rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF))) setup_pager(); /* Do we have --cached and not have a pending object, then @@ -353,7 +354,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) ent, ents); if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - + if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); return result; diff --git a/diff.c b/diff.c index 3dd2f35f73..8237075484 100644 --- a/diff.c +++ b/diff.c @@ -1031,6 +1031,7 @@ struct checkdiff_t { const char *filename; int lineno, color_diff; unsigned ws_rule; + unsigned status; }; static void checkdiff_consume(void *priv, char *line, unsigned long len) @@ -1064,6 +1065,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) white_space_at_end = 1; if (space_before_tab || white_space_at_end) { + data->status = 1; printf("%s:%d: %s", data->filename, data->lineno, ws); if (space_before_tab) { printf("space before tab"); @@ -1491,6 +1493,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, free_and_return: diff_free_filespec_data(one); diff_free_filespec_data(two); + if (data.status) + DIFF_OPT_SET(o, CHECK_FAILED); } struct diff_filespec *alloc_filespec(const char *path) @@ -2121,7 +2125,12 @@ int diff_setup_done(struct diff_options *options) if (options->output_format & DIFF_FORMAT_NAME_STATUS) count++; if (options->output_format & DIFF_FORMAT_CHECKDIFF) + { count++; + if (DIFF_OPT_TST(options, QUIET) || + DIFF_OPT_TST(options, EXIT_WITH_STATUS)) + die("--check may not be used with --quiet or --exit-code"); + } if (options->output_format & DIFF_FORMAT_NO_OUTPUT) count++; if (count > 1) diff --git a/diff.h b/diff.h index a52496a108..5d50d93a52 100644 --- a/diff.h +++ b/diff.h @@ -59,6 +59,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_ALLOW_EXTERNAL (1 << 13) #define DIFF_OPT_EXIT_WITH_STATUS (1 << 14) #define DIFF_OPT_REVERSE_DIFF (1 << 15) +#define DIFF_OPT_CHECK_FAILED (1 << 16) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 6adf9d11d0..dc538b3e33 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -117,7 +117,6 @@ EOF git diff -b > out test_expect_success 'another test, with -b' 'git diff expect out' - test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. @@ -126,4 +125,140 @@ test_expect_success 'check mixed spaces and tabs in indent' ' ' +test_expect_success 'check with no whitespace errors' ' + + git commit -m "snapshot" && + echo "foo();" > x && + git diff --check + +' + +test_expect_failure 'check with trailing whitespace' ' + + echo "foo(); " > x && + git diff --check + +' + +test_expect_failure 'check with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git diff --check + +' + +test_expect_failure '--check and --exit-code are exclusive' ' + + git checkout x && + git diff --check --exit-code + +' + +test_expect_failure '--check and --quiet are exclusive' ' + + git diff --check --quiet + +' + +test_expect_success 'check staged with no whitespace errors' ' + + echo "foo();" > x && + git add x && + git diff --cached --check + +' + +test_expect_failure 'check staged with trailing whitespace' ' + + echo "foo(); " > x && + git add x && + git diff --cached --check + +' + +test_expect_failure 'check staged with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + git diff --cached --check + +' + +test_expect_success 'check with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_failure 'check with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_failure 'check with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_success 'check staged with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_failure 'check staged with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_failure 'check staged with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_success 'check with no whitespace errors (diff-tree)' ' + + echo "foo();" > x && + git commit -m "new commit" x && + git diff-tree --check HEAD^ HEAD + +' + +test_expect_failure 'check with trailing whitespace (diff-tree)' ' + + echo "foo(); " > x && + git commit -m "another commit" x && + git diff-tree --check HEAD^ HEAD + +' + +test_expect_failure 'check with space before tab in indent (diff-tree)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git commit -m "yet another" x && + git diff-tree --check HEAD^ HEAD + +' + test_done From da31b358fb39b32622c14343ffe157a765f3948b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Dec 2007 23:40:27 -0800 Subject: [PATCH 09/84] diff --check: minor fixups There is no reason --exit-code and --check-diff must be mutually exclusive, so assign different bits to different results and allow them to be returned from the command. Introduce diff_result_code() to factor out the common code to decide final status code based on diffopt settings and use it everywhere. Update tests to match the above fix. Turning pager off when "diff --check" is used is a regression. Signed-off-by: Junio C Hamano --- builtin-diff-files.c | 6 +----- builtin-diff-index.c | 6 +----- builtin-diff-tree.c | 6 ++---- builtin-diff.c | 11 ++++------- diff.c | 19 ++++++++++++++----- diff.h | 2 ++ t/t4015-diff-whitespace.sh | 4 ++-- 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 4afc8724e7..9c04111656 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -31,9 +31,5 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) if (!rev.diffopt.output_format) rev.diffopt.output_format = DIFF_FORMAT_RAW; result = run_diff_files_cmd(&rev, argc, argv); - if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) - return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; - return result; + return diff_result_code(&rev.diffopt, result); } diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 532b284b10..0f2390a20a 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -44,9 +44,5 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) return -1; } result = run_diff_index(&rev, cached); - if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) - return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; - return result; + return diff_result_code(&rev.diffopt, result); } diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 9ab90cb4c5..ebc50efbd2 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -132,8 +132,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) diff_tree_stdin(line); } } - if (opt->diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&opt->diffopt, CHECK_FAILED) != 0; - return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) - && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); + + return diff_result_code(&opt->diffopt, 0); } diff --git a/builtin-diff.c b/builtin-diff.c index 9d878f6a71..29365a0b17 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -244,11 +244,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix) DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, RECURSIVE); - /* If the user asked for our exit code then don't start a + /* + * If the user asked for our exit code then don't start a * pager or we would end up reporting its exit code instead. */ - if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) && - (!(rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF))) + if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) setup_pager(); /* Do we have --cached and not have a pending object, then @@ -352,10 +352,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) else result = builtin_diff_combined(&rev, argc, argv, ent, ents); - if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) - result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; + result = diff_result_code(&rev.diffopt, result); if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); return result; diff --git a/diff.c b/diff.c index 8237075484..3e46ff8a75 100644 --- a/diff.c +++ b/diff.c @@ -2125,12 +2125,7 @@ int diff_setup_done(struct diff_options *options) if (options->output_format & DIFF_FORMAT_NAME_STATUS) count++; if (options->output_format & DIFF_FORMAT_CHECKDIFF) - { count++; - if (DIFF_OPT_TST(options, QUIET) || - DIFF_OPT_TST(options, EXIT_WITH_STATUS)) - die("--check may not be used with --quiet or --exit-code"); - } if (options->output_format & DIFF_FORMAT_NO_OUTPUT) count++; if (count > 1) @@ -3180,6 +3175,20 @@ void diffcore_std(struct diff_options *options) DIFF_OPT_CLR(options, HAS_CHANGES); } +int diff_result_code(struct diff_options *opt, int status) +{ + int result = 0; + if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && + !(opt->output_format & DIFF_FORMAT_CHECKDIFF)) + return status; + if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && + DIFF_OPT_TST(opt, HAS_CHANGES)) + result |= 01; + if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) && + DIFF_OPT_TST(opt, CHECK_FAILED)) + result |= 02; + return result; +} void diff_addremove(struct diff_options *options, int addremove, unsigned mode, diff --git a/diff.h b/diff.h index 5d50d93a52..7e8000a5d7 100644 --- a/diff.h +++ b/diff.h @@ -247,4 +247,6 @@ extern int run_diff_index(struct rev_info *revs, int cached); extern int do_diff_cache(const unsigned char *, struct diff_options *); extern int diff_flush_patch_id(struct diff_options *, unsigned char *); +extern int diff_result_code(struct diff_options *, int); + #endif /* DIFF_H */ diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index dc538b3e33..757a27abdb 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -148,14 +148,14 @@ test_expect_failure 'check with space before tab in indent' ' ' -test_expect_failure '--check and --exit-code are exclusive' ' +test_expect_success '--check and --exit-code are not exclusive' ' git checkout x && git diff --check --exit-code ' -test_expect_failure '--check and --quiet are exclusive' ' +test_expect_success '--check and --quiet are not exclusive' ' git diff --check --quiet From c1795bb08aae9fb7e4dc1a01e292b85e59b1c640 Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Thu, 13 Dec 2007 14:32:29 +0100 Subject: [PATCH 10/84] Unify whitespace checking This commit unifies three separate places where whitespace checking was performed: - the whitespace checking previously done in builtin-apply.c is extracted into a function in ws.c - the equivalent logic in "git diff" is removed - the emit_line_with_ws() function is also removed because that also rechecks the whitespace, and its functionality is rolled into ws.c The new function is called check_and_emit_line() and it does two things: checks a line for whitespace errors and optionally emits it. The checking is based on lines of content rather than patch lines (in other words, the caller must strip the leading "+" or "-"); this was suggested by Junio on the mailing list to allow for a future extension to "git show" to display whitespace errors in blobs. At the same time we teach it to report all classes of whitespace errors found for a given line rather than reporting only the first found error. Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- builtin-apply.c | 54 +++------------ cache.h | 4 ++ diff.c | 138 +++++-------------------------------- t/t4015-diff-whitespace.sh | 2 +- ws.c | 105 ++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 164 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index f2e9a332ca..ab393f32e9 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -900,56 +900,22 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc static void check_whitespace(const char *line, int len, unsigned ws_rule) { - const char *err = "Adds trailing whitespace"; - int seen_space = 0; - int i; + char *err; + unsigned result = check_and_emit_line(line + 1, len - 1, ws_rule, + NULL, NULL, NULL, NULL); + if (!result) + return; - /* - * We know len is at least two, since we have a '+' and we - * checked that the last character was a '\n' before calling - * this function. That is, an addition of an empty line would - * check the '+' here. Sneaky... - */ - if ((ws_rule & WS_TRAILING_SPACE) && isspace(line[len-2])) - goto error; - - /* - * Make sure that there is no space followed by a tab in - * indentation. - */ - if (ws_rule & WS_SPACE_BEFORE_TAB) { - err = "Space in indent is followed by a tab"; - for (i = 1; i < len; i++) { - if (line[i] == '\t') { - if (seen_space) - goto error; - } - else if (line[i] == ' ') - seen_space = 1; - else - break; - } - } - - /* - * Make sure that the indentation does not contain more than - * 8 spaces. - */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - (8 < len) && !strncmp("+ ", line, 9)) { - err = "Indent more than 8 places with spaces"; - goto error; - } - return; - - error: whitespace_error++; if (squelch_whitespace_errors && squelch_whitespace_errors < whitespace_error) ; - else + else { + err = whitespace_error_string(result); fprintf(stderr, "%s.\n%s:%d:%.*s\n", - err, patch_input_file, linenr, len-2, line+1); + err, patch_input_file, linenr, len - 2, line + 1); + free(err); + } } /* diff --git a/cache.h b/cache.h index 27d90fe543..39331c28be 100644 --- a/cache.h +++ b/cache.h @@ -655,6 +655,10 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i extern unsigned whitespace_rule_cfg; extern unsigned whitespace_rule(const char *); extern unsigned parse_whitespace_rule(const char *); +extern unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, + FILE *stream, const char *set, + const char *reset, const char *ws); +extern char *whitespace_error_string(unsigned ws); /* ls-files */ int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen); diff --git a/diff.c b/diff.c index 3e46ff8a75..577c773c3e 100644 --- a/diff.c +++ b/diff.c @@ -486,88 +486,9 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) static void emit_line(const char *set, const char *reset, const char *line, int len) { - if (len > 0 && line[len-1] == '\n') - len--; fputs(set, stdout); fwrite(line, len, 1, stdout); - puts(reset); -} - -static void emit_line_with_ws(int nparents, - const char *set, const char *reset, const char *ws, - const char *line, int len, unsigned ws_rule) -{ - int col0 = nparents; - int last_tab_in_indent = -1; - int last_space_in_indent = -1; - int i; - int tail = len; - int need_highlight_leading_space = 0; - /* - * The line is a newly added line. Does it have funny leading - * whitespaces? In indent, SP should never precede a TAB. In - * addition, under "indent with non tab" rule, there should not - * be more than 8 consecutive spaces. - */ - for (i = col0; i < len; i++) { - if (line[i] == '\t') { - last_tab_in_indent = i; - if ((ws_rule & WS_SPACE_BEFORE_TAB) && - 0 <= last_space_in_indent) - need_highlight_leading_space = 1; - } - else if (line[i] == ' ') - last_space_in_indent = i; - else - break; - } - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - 0 <= last_space_in_indent && - last_tab_in_indent < 0 && - 8 <= (i - col0)) { - last_tab_in_indent = i; - need_highlight_leading_space = 1; - } - fputs(set, stdout); - fwrite(line, col0, 1, stdout); fputs(reset, stdout); - if (((i == len) || line[i] == '\n') && i != col0) { - /* The whole line was indent */ - emit_line(ws, reset, line + col0, len - col0); - return; - } - i = col0; - if (need_highlight_leading_space) { - while (i < last_tab_in_indent) { - if (line[i] == ' ') { - fputs(ws, stdout); - putchar(' '); - fputs(reset, stdout); - } - else - putchar(line[i]); - i++; - } - } - tail = len - 1; - if (line[tail] == '\n' && i < tail) - tail--; - if (ws_rule & WS_TRAILING_SPACE) { - while (i < tail) { - if (!isspace(line[tail])) - break; - tail--; - } - } - if ((i < tail && line[tail + 1] != '\n')) { - /* This has whitespace between tail+1..len */ - fputs(set, stdout); - fwrite(line + i, tail - i + 1, 1, stdout); - fputs(reset, stdout); - emit_line(ws, reset, line + tail + 1, len - tail - 1); - } - else - emit_line(set, reset, line + i, len - i); } static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) @@ -577,9 +498,13 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons if (!*ws) emit_line(set, reset, line, len); - else - emit_line_with_ws(ecbdata->nparents, set, reset, ws, - line, len, ecbdata->ws_rule); + else { + /* Emit just the prefix, then the rest. */ + emit_line(set, reset, line, ecbdata->nparents); + (void)check_and_emit_line(line + ecbdata->nparents, + len - ecbdata->nparents, ecbdata->ws_rule, + stdout, set, reset, ws); + } } static void fn_out_consume(void *priv, char *line, unsigned long len) @@ -1040,45 +965,20 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE); const char *reset = diff_get_color(data->color_diff, DIFF_RESET); const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW); + char *err; if (line[0] == '+') { - int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0; - - /* check space before tab */ - for (i = 1; i < len; i++) { - if (line[i] == ' ') - spaces++; - else if (line[i] == '\t') { - if (spaces) { - space_before_tab = 1; - break; - } - } - else - break; - } - - /* check whitespace at line end */ - if (line[len - 1] == '\n') - len--; - if (isspace(line[len - 1])) - white_space_at_end = 1; - - if (space_before_tab || white_space_at_end) { - data->status = 1; - printf("%s:%d: %s", data->filename, data->lineno, ws); - if (space_before_tab) { - printf("space before tab"); - if (white_space_at_end) - putchar(','); - } - if (white_space_at_end) - printf("whitespace at end"); - printf(":%s ", reset); - emit_line_with_ws(1, set, reset, ws, line, len, - data->ws_rule); - } - + data->status = check_and_emit_line(line + 1, len - 1, + data->ws_rule, NULL, NULL, NULL, NULL); + if (!data->status) + return; + err = whitespace_error_string(data->status); + printf("%s:%d: %s%s:%s ", data->filename, data->lineno, + ws, err, reset); + free(err); + emit_line(set, reset, line, 1); + (void)check_and_emit_line(line + 1, len - 1, data->ws_rule, + stdout, set, reset, ws); data->lineno++; } else if (line[0] == ' ') data->lineno++; diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 757a27abdb..595cd60623 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -121,7 +121,7 @@ test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. echo " foo();" > x && - git diff --check | grep "space before tab" + git diff --check | grep "Space in indent is followed by a tab" ' diff --git a/ws.c b/ws.c index 52c10caf35..d7d1522f8a 100644 --- a/ws.c +++ b/ws.c @@ -94,3 +94,108 @@ unsigned whitespace_rule(const char *pathname) return whitespace_rule_cfg; } } + +/* The returned string should be freed by the caller. */ +char *whitespace_error_string(unsigned ws) +{ + struct strbuf err; + strbuf_init(&err, 0); + if (ws & WS_TRAILING_SPACE) + strbuf_addstr(&err, "Adds trailing whitespace"); + if (ws & WS_SPACE_BEFORE_TAB) { + if (err.len) + strbuf_addstr(&err, ", "); + strbuf_addstr(&err, "Space in indent is followed by a tab"); + } + if (ws & WS_INDENT_WITH_NON_TAB) { + if (err.len) + strbuf_addstr(&err, ", "); + strbuf_addstr(&err, "Indent more than 8 places with spaces"); + } + return strbuf_detach(&err, NULL); +} + +/* If stream is non-NULL, emits the line after checking. */ +unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, + FILE *stream, const char *set, + const char *reset, const char *ws) +{ + unsigned result = 0; + int leading_space = -1; + int trailing_whitespace = -1; + int trailing_newline = 0; + int i; + + /* Logic is simpler if we temporarily ignore the trailing newline. */ + if (len > 0 && line[len - 1] == '\n') { + trailing_newline = 1; + len--; + } + + /* Check for trailing whitespace. */ + if (ws_rule & WS_TRAILING_SPACE) { + for (i = len - 1; i >= 0; i--) { + if (isspace(line[i])) { + trailing_whitespace = i; + result |= WS_TRAILING_SPACE; + } + else + break; + } + } + + /* Check for space before tab in initial indent. */ + for (i = 0; i < len; i++) { + if (line[i] == '\t') { + if ((ws_rule & WS_SPACE_BEFORE_TAB) && + (leading_space != -1)) + result |= WS_SPACE_BEFORE_TAB; + break; + } + else if (line[i] == ' ') + leading_space = i; + else + break; + } + + /* Check for indent using non-tab. */ + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && leading_space >= 8) + result |= WS_INDENT_WITH_NON_TAB; + + if (stream) { + /* Highlight errors in leading whitespace. */ + if ((result & WS_SPACE_BEFORE_TAB) || + (result & WS_INDENT_WITH_NON_TAB)) { + fputs(ws, stream); + fwrite(line, leading_space + 1, 1, stream); + fputs(reset, stream); + leading_space++; + } + else + leading_space = 0; + + /* Now the rest of the line starts at leading_space. + * The non-highlighted part ends at trailing_whitespace. */ + if (trailing_whitespace == -1) + trailing_whitespace = len; + + /* Emit non-highlighted (middle) segment. */ + if (trailing_whitespace - leading_space > 0) { + fputs(set, stream); + fwrite(line + leading_space, + trailing_whitespace - leading_space, 1, stream); + fputs(reset, stream); + } + + /* Highlight errors in trailing whitespace. */ + if (trailing_whitespace != len) { + fputs(ws, stream); + fwrite(line + trailing_whitespace, + len - trailing_whitespace, 1, stream); + fputs(reset, stream); + } + if (trailing_newline) + fputc('\n', stream); + } + return result; +} From 45e2a4b2b0a07cda05dda08b47906100c4711e4e Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Thu, 13 Dec 2007 14:32:30 +0100 Subject: [PATCH 11/84] Make "diff --check" output match "git apply" For consistency, make the two tools report whitespace errors in the same way (the output of "diff --check" has been tweaked to match that of "git apply"). Note that although the textual content is basically the same only "git diff --check" provides a colorized version of the problematic lines; making "git apply" do colorization will require more extensive changes (figuring out the diff colorization preferences of the user) and so that will be a subject for another commit. Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- builtin-apply.c | 4 ++-- diff.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index ab393f32e9..2edd83bf40 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -912,8 +912,8 @@ static void check_whitespace(const char *line, int len, unsigned ws_rule) ; else { err = whitespace_error_string(result); - fprintf(stderr, "%s.\n%s:%d:%.*s\n", - err, patch_input_file, linenr, len - 2, line + 1); + fprintf(stderr, "%s:%d: %s.\n%.*s\n", + patch_input_file, linenr, err, len - 2, line + 1); free(err); } } diff --git a/diff.c b/diff.c index 577c773c3e..08ec66c794 100644 --- a/diff.c +++ b/diff.c @@ -973,8 +973,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) if (!data->status) return; err = whitespace_error_string(data->status); - printf("%s:%d: %s%s:%s ", data->filename, data->lineno, - ws, err, reset); + printf("%s:%d: %s.\n", data->filename, data->lineno, err); free(err); emit_line(set, reset, line, 1); (void)check_and_emit_line(line + 1, len - 1, data->ws_rule, From f817546652812ad5f20a8ab4a4a7290a9759ac4e Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Thu, 13 Dec 2007 14:32:31 +0100 Subject: [PATCH 12/84] Add tests for "git diff --check" with core.whitespace options Make sure that "git diff --check" does the right thing when the core.whitespace options are set. While we are at it, correct many uses of test_expect_failure that ran sequence of commands. Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- t/t4015-diff-whitespace.sh | 90 +++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 595cd60623..05ef78b2c0 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -133,18 +133,18 @@ test_expect_success 'check with no whitespace errors' ' ' -test_expect_failure 'check with trailing whitespace' ' +test_expect_success 'check with trailing whitespace' ' echo "foo(); " > x && - git diff --check + ! git diff --check ' -test_expect_failure 'check with space before tab in indent' ' +test_expect_success 'check with space before tab in indent' ' # indent has space followed by hard tab echo " foo();" > x && - git diff --check + ! git diff --check ' @@ -169,20 +169,20 @@ test_expect_success 'check staged with no whitespace errors' ' ' -test_expect_failure 'check staged with trailing whitespace' ' +test_expect_success 'check staged with trailing whitespace' ' echo "foo(); " > x && git add x && - git diff --cached --check + ! git diff --cached --check ' -test_expect_failure 'check staged with space before tab in indent' ' +test_expect_success 'check staged with space before tab in indent' ' # indent has space followed by hard tab echo " foo();" > x && git add x && - git diff --cached --check + ! git diff --cached --check ' @@ -194,20 +194,20 @@ test_expect_success 'check with no whitespace errors (diff-index)' ' ' -test_expect_failure 'check with trailing whitespace (diff-index)' ' +test_expect_success 'check with trailing whitespace (diff-index)' ' echo "foo(); " > x && git add x && - git diff-index --check HEAD + ! git diff-index --check HEAD ' -test_expect_failure 'check with space before tab in indent (diff-index)' ' +test_expect_success 'check with space before tab in indent (diff-index)' ' # indent has space followed by hard tab echo " foo();" > x && git add x && - git diff-index --check HEAD + ! git diff-index --check HEAD ' @@ -219,20 +219,20 @@ test_expect_success 'check staged with no whitespace errors (diff-index)' ' ' -test_expect_failure 'check staged with trailing whitespace (diff-index)' ' +test_expect_success 'check staged with trailing whitespace (diff-index)' ' echo "foo(); " > x && git add x && - git diff-index --cached --check HEAD + ! git diff-index --cached --check HEAD ' -test_expect_failure 'check staged with space before tab in indent (diff-index)' ' +test_expect_success 'check staged with space before tab in indent (diff-index)' ' # indent has space followed by hard tab echo " foo();" > x && git add x && - git diff-index --cached --check HEAD + ! git diff-index --cached --check HEAD ' @@ -244,20 +244,70 @@ test_expect_success 'check with no whitespace errors (diff-tree)' ' ' -test_expect_failure 'check with trailing whitespace (diff-tree)' ' +test_expect_success 'check with trailing whitespace (diff-tree)' ' echo "foo(); " > x && git commit -m "another commit" x && - git diff-tree --check HEAD^ HEAD + ! git diff-tree --check HEAD^ HEAD ' -test_expect_failure 'check with space before tab in indent (diff-tree)' ' +test_expect_success 'check with space before tab in indent (diff-tree)' ' # indent has space followed by hard tab echo " foo();" > x && git commit -m "yet another" x && - git diff-tree --check HEAD^ HEAD + ! git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check trailing whitespace (trailing-space: off)' ' + + git config core.whitespace "-trailing-space" && + echo "foo (); " > x && + git diff --check + +' + +test_expect_success 'check trailing whitespace (trailing-space: on)' ' + + git config core.whitespace "trailing-space" && + echo "foo (); " > x && + ! git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: off)' ' + + # indent contains space followed by HT + git config core.whitespace "-space-before-tab" && + echo " foo ();" > x && + git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: on)' ' + + # indent contains space followed by HT + git config core.whitespace "space-before-tab" && + echo " foo (); " > x && + ! git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' + + git config core.whitespace "-indent-with-non-tab" + echo " foo ();" > x && + git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + ! git diff --check ' From 29ab27f4b505dd6a56ded42ab2797c3e56f810b2 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 12:00:42 -0800 Subject: [PATCH 13/84] xdiff tail trimming: use correct type. Inside xdiff library, the number of context lines is represented in long, not int. Noticed by Peter Baumann. Signed-off-by: Junio C Hamano --- xdiff-interface.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xdiff-interface.c b/xdiff-interface.c index f2cd488de0..700def211e 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -107,11 +107,10 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) * Trim down common substring at the end of the buffers, * but leave at least ctx lines at the end. */ -static void trim_common_tail(mmfile_t *a, mmfile_t *b, int ctx) +static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx) { const int blk = 1024; - long trimmed = 0, recovered = 0; - int i; + long trimmed = 0, recovered = 0, i; char *ap = a->ptr + a->size; char *bp = b->ptr + b->size; long smaller = (a->size < b->size) ? a->size : b->size; From 71362bd55280bb0f4aa67f89435308a4b26213b5 Mon Sep 17 00:00:00 2001 From: "linux@horizon.com" Date: Fri, 14 Dec 2007 06:28:14 -0500 Subject: [PATCH 14/84] Documentation: describe pack idx v2 Lifted from the log message of c553ca25bd60dc9fd50b8bc7bd329601b81cee66 (pack-objects: learn about pack index version 2). Acked-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- Documentation/technical/pack-format.txt | 94 ++++++++++++++++--------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt index e5b31c81fa..a80baa4382 100644 --- a/Documentation/technical/pack-format.txt +++ b/Documentation/technical/pack-format.txt @@ -1,9 +1,9 @@ GIT pack format =============== -= pack-*.pack file has the following format: += pack-*.pack files have the following format: - - The header appears at the beginning and consists of the following: + - A header appears at the beginning and consists of the following: 4-byte signature: The signature is: {'P', 'A', 'C', 'K'} @@ -34,18 +34,14 @@ GIT pack format - The trailer records 20-byte SHA1 checksum of all of the above. -= pack-*.idx file has the following format: += Original (version 1) pack-*.idx files have the following format: - The header consists of 256 4-byte network byte order integers. N-th entry of this table records the number of objects in the corresponding pack, the first byte of whose - object name are smaller than N. This is called the + object name is less than or equal to N. This is called the 'first-level fan-out' table. - Observation: we would need to extend this to an array of - 8-byte integers to go beyond 4G objects per pack, but it is - not strictly necessary. - - The header is followed by sorted 24-byte entries, one entry per object in the pack. Each entry is: @@ -55,10 +51,6 @@ GIT pack format 20-byte object name. - Observation: we would definitely need to extend this to - 8-byte integer plus 20-byte object name to handle a packfile - that is larger than 4GB. - - The file is concluded with a trailer: A copy of the 20-byte SHA1 checksum at the end of @@ -68,31 +60,30 @@ GIT pack format Pack Idx file: - idx - +--------------------------------+ - | fanout[0] = 2 |-. - +--------------------------------+ | + -- +--------------------------------+ +fanout | fanout[0] = 2 (for example) |-. +table +--------------------------------+ | | fanout[1] | | +--------------------------------+ | | fanout[2] | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | - | fanout[255] | | - +--------------------------------+ | -main | offset | | -index | object name 00XXXXXXXXXXXXXXXX | | -table +--------------------------------+ | - | offset | | - | object name 00XXXXXXXXXXXXXXXX | | - +--------------------------------+ | - .-| offset |<+ - | | object name 01XXXXXXXXXXXXXXXX | - | +--------------------------------+ - | | offset | - | | object name 01XXXXXXXXXXXXXXXX | - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | offset | - | | object name FFXXXXXXXXXXXXXXXX | - | +--------------------------------+ + | fanout[255] = total objects |---. + -- +--------------------------------+ | | +main | offset | | | +index | object name 00XXXXXXXXXXXXXXXX | | | +table +--------------------------------+ | | + | offset | | | + | object name 00XXXXXXXXXXXXXXXX | | | + +--------------------------------+<+ | + .-| offset | | + | | object name 01XXXXXXXXXXXXXXXX | | + | +--------------------------------+ | + | | offset | | + | | object name 01XXXXXXXXXXXXXXXX | | + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | + | | offset | | + | | object name FFXXXXXXXXXXXXXXXX | | + --| +--------------------------------+<--+ trailer | | packfile checksum | | +--------------------------------+ | | idxfile checksum | @@ -116,3 +107,40 @@ Pack file entry: <+ 20-byte base object name SHA1 (the size above is the size of the delta data that follows). delta data, deflated. + + += Version 2 pack-*.idx files support packs larger than 4 GiB, and + have some other reorganizations. They have the format: + + - A 4-byte magic number '\377tOc' which is an unreasonable + fanout[0] value. + + - A 4-byte version number (= 2) + + - A 256-entry fan-out table just like v1. + + - A table of sorted 20-byte SHA1 object names. These are + packed together without offset values to reduce the cache + footprint of the binary search for a specific object name. + + - A table of 4-byte CRC32 values of the packed object data. + This is new in v2 so compressed data can be copied directly + from pack to pack during repacking withough undetected + data corruption. + + - A table of 4-byte offset values (in network byte order). + These are usually 31-bit pack file offsets, but large + offsets are encoded as an index into the next table with + the msbit set. + + - A table of 8-byte offset entries (empty for pack files less + than 2 GiB). Pack files are organized with heavily used + objects toward the front, so most object references should + not need to refer to this table. + + - The same trailer as a v1 pack file: + + A copy of the 20-byte SHA1 checksum at the end of + corresponding packfile. + + 20-byte SHA1-checksum of all of the above. From 38a5b1d6ed2ba632504be7748e63f1441c93976d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 14 Dec 2007 04:15:47 -0500 Subject: [PATCH 15/84] cvsexportcommit: fix massive commits Because we feed the changed filenames to CVS on the command line, it was possible for massive commits to overflow the system exec limits. Instead, we now do an xargs-like split of the arguments. This means that we lose some of the atomicity of calling CVS in one shot. Since CVS commits are not atomic, but the CVS protocol is, the possible effects of this are not clear; however, since CVS doesn't provide a different interface, this is our only option for large commits (short of writing a CVS client library). The argument size limit is arbitrarily set to 64kB. This should be high enough to trigger only in rare cases where it is necessary, so normal-sized commits are not affected by the atomicity change. Signed-off-by: Junio C Hamano --- git-cvsexportcommit.perl | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index 92e41620fd..d2e50c3429 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -195,11 +195,11 @@ foreach my $f (@files) { my %cvsstat; if (@canstatusfiles) { if ($opt_u) { - my @updated = safe_pipe_capture(@cvs, 'update', @canstatusfiles); + my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles); print @updated; } my @cvsoutput; - @cvsoutput= safe_pipe_capture(@cvs, 'status', @canstatusfiles); + @cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles); my $matchcount = 0; foreach my $l (@cvsoutput) { chomp $l; @@ -295,7 +295,7 @@ if ($dirtypatch) { if ($opt_c) { print "Autocommit\n $cmd\n"; - print safe_pipe_capture(@cvs, 'commit', '-F', '.msg', @files); + print xargs_safe_pipe_capture([@cvs, 'commit', '-F', '.msg'], @files); if ($?) { die "Exiting: The commit did not succeed"; } @@ -335,15 +335,24 @@ sub safe_pipe_capture { return wantarray ? @output : join('',@output); } -sub safe_pipe_capture_blob { - my $output; - if (my $pid = open my $child, '-|') { - local $/; - undef $/; - $output = (<$child>); - close $child or die join(' ',@_).": $! $?"; - } else { - exec(@_) or die "$! $?"; # exec() can fail the executable can't be found - } - return $output; +sub xargs_safe_pipe_capture { + my $MAX_ARG_LENGTH = 65536; + my $cmd = shift; + my @output; + my $output; + while(@_) { + my @args; + my $length = 0; + while(@_ && $length < $MAX_ARG_LENGTH) { + push @args, shift; + $length += length($args[$#args]); + } + if (wantarray) { + push @output, safe_pipe_capture(@$cmd, @args); + } + else { + $output .= safe_pipe_capture(@$cmd, @args); + } + } + return wantarray ? @output : $output; } From 12a6d752fb61b10194b2897defb2b34e09099b12 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 14 Dec 2007 08:39:09 -0800 Subject: [PATCH 16/84] git-svn: handle our top-level path being deleted and later re-added Previously, git-svn would ignore cases where the path we're tracking is removed from the repository. This was to prevent heads with follow-parent from ending up with a tree full of empty revisions (and thus breaking rename detection). The previous behavior is fine until the path we're tracking is re-added later on, leading to the old files being merged in with the new files in the directory (because the old files were never marked as deleted) We will now only remove all the old files locally that were deleted remotely iff we detect the directory we're in is being created from scratch. Thanks for Marcus D. Hanwell for the bug report and Peter Baumann for the analysis. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 14 +++++++ t/t9103-git-svn-tracked-directory-removed.sh | 39 ++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100755 t/t9103-git-svn-tracked-directory-removed.sh diff --git a/git-svn.perl b/git-svn.perl index 3aa7f8cb40..d411a34317 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3045,6 +3045,20 @@ sub add_file { sub add_directory { my ($self, $path, $cp_path, $cp_rev) = @_; + my $gpath = $self->git_path($path); + if ($gpath eq '') { + my ($ls, $ctx) = command_output_pipe(qw/ls-tree + -r --name-only -z/, + $self->{c}); + local $/ = "\0"; + while (<$ls>) { + chomp; + $self->{gii}->remove($_); + print "\tD\t$_\n" unless $::_q; + } + command_close_pipe($ls, $ctx); + $self->{empty}->{$path} = 0; + } my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#); delete $self->{empty}->{$dir}; $self->{empty}->{$path} = 1; diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh new file mode 100755 index 0000000000..0f0b0fd2c6 --- /dev/null +++ b/t/t9103-git-svn-tracked-directory-removed.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# Copyright (c) 2007 Eric Wong +# + +test_description='git-svn tracking removed top-level path' +. ./lib-git-svn.sh + +test_expect_success 'make history for tracking' ' + mkdir import && + mkdir import/trunk && + echo hello >> import/trunk/README && + svn import -m initial import $svnrepo && + rm -rf import && + svn co $svnrepo/trunk trunk && + echo bye bye >> trunk/README && + svn rm -m "gone" $svnrepo/trunk && + rm -rf trunk && + mkdir trunk && + echo "new" > trunk/FOLLOWME && + svn import -m "new trunk" trunk $svnrepo/trunk +' + +test_expect_success 'clone repo with git' ' + git svn clone -s $svnrepo x && + test -f x/FOLLOWME && + test ! -f x/README +' + +test_expect_success 'make sure r2 still has old file' ' + cd x && + test -n "$(git svn find-rev r1)" && + git reset --hard $(git svn find-rev r1) && + test -f README && + test ! -f FOLLOWME && + test x$(git svn find-rev r2) = x +' + +test_done From 1eb1e9eea480059d4fba171e74a4375b8191e3f3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 11:57:22 -0800 Subject: [PATCH 17/84] commit: allow --amend to reuse message from another commit After tentatively applying a patch from a contributor, you can get a replacement patch with corrected code and unusable commit log message. In such a case, this sequence ought to give you an editor based on the message in the earlier commit, to let you describe an incremental improvement: git reset --hard HEAD^ ;# discard the earlier one git am --- builtin-commit.c | 2 +- t/t7501-commit.sh | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/builtin-commit.c b/builtin-commit.c index ad9f9211b3..518ebe0347 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -537,7 +537,7 @@ static int parse_and_validate_options(int argc, const char *argv[], die("Option -m cannot be combined with -c/-C/-F."); if (edit_message) use_message = edit_message; - if (amend) + if (amend && !use_message) use_message = "HEAD"; if (use_message) { unsigned char sha1[20]; diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 05aa97d6f3..d1a415a126 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -310,4 +310,21 @@ test_expect_success 'same tree (merge and amend merge)' ' ' +test_expect_success 'amend using the message from another commit' ' + + git reset --hard && + test_tick && + git commit --allow-empty -m "old commit" && + old=$(git rev-parse --verify HEAD) && + test_tick && + git commit --allow-empty -m "new commit" && + new=$(git rev-parse --verify HEAD) && + test_tick && + git commit --allow-empty --amend -C "$old" && + git show --pretty="format:%ad %s" "$old" >expected && + git show --pretty="format:%ad %s" HEAD >actual && + diff -u expected actual + +' + test_done From 896c0535afe2f00683f7d4e8171fad7ec156f16f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 20:34:56 -0800 Subject: [PATCH 18/84] remote: Fix bogus make_branch() call in configuration reader. The configuration reader to enumerate branches that have configuration data were not careful enough and failed to skip "branch." entries (e.g. branch.autosetupmerge). This resulted in bogus attempt to allocate huge memory. Noticed by David Miller. Signed-off-by: Junio C Hamano --- remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote.c b/remote.c index 3fb0f99b29..0e006804ef 100644 --- a/remote.c +++ b/remote.c @@ -220,11 +220,11 @@ static int handle_config(const char *key, const char *value) if (!prefixcmp(key, "branch.")) { name = key + 7; subkey = strrchr(name, '.'); - branch = make_branch(name, subkey - name); if (!subkey) return 0; if (!value) return 0; + branch = make_branch(name, subkey - name); if (!strcmp(subkey, ".remote")) { branch->remote_name = xstrdup(value); if (branch == current_branch) From 69ae517541ed5ab7d4fdcd8f82a9b8bd949df347 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 14 Dec 2007 20:39:16 -0800 Subject: [PATCH 19/84] fast-import: fix unalinged allocation and access The specialized pool allocator fast-import uses aligned objects on the size of a pointer, which was not sufficient at least on Sparc. Instead, make the alignment for objects of type unitmax_t. Signed-off-by: David S. Miller Signed-off-by: Junio C Hamano --- fast-import.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fast-import.c b/fast-import.c index 98c2bd5359..4646c056f3 100644 --- a/fast-import.c +++ b/fast-import.c @@ -196,7 +196,7 @@ struct mem_pool struct mem_pool *next_pool; char *next_free; char *end; - char space[FLEX_ARRAY]; /* more */ + uintmax_t space[FLEX_ARRAY]; /* more */ }; struct atom_str @@ -534,15 +534,15 @@ static void *pool_alloc(size_t len) total_allocd += sizeof(struct mem_pool) + mem_pool_alloc; p = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc); p->next_pool = mem_pool; - p->next_free = p->space; + p->next_free = (char *) p->space; p->end = p->next_free + mem_pool_alloc; mem_pool = p; } r = p->next_free; - /* round out to a pointer alignment */ - if (len & (sizeof(void*) - 1)) - len += sizeof(void*) - (len & (sizeof(void*) - 1)); + /* round out to a 'uintmax_t' alignment */ + if (len & (sizeof(uintmax_t) - 1)) + len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1)); p->next_free += len; return r; } From cb891a5989c41ed479db9eb4b0a69cef8bb98ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 14 Dec 2007 15:59:58 -0500 Subject: [PATCH 20/84] Use a strbuf for building up section header and key/value pair strings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids horrible 1-byte write(2) calls and cleans up the logic a bit. Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- config.c | 91 +++++++++++++++++++++++--------------------------------- 1 file changed, 38 insertions(+), 53 deletions(-) diff --git a/config.c b/config.c index 49d2b427e5..9a5c5470cc 100644 --- a/config.c +++ b/config.c @@ -610,46 +610,36 @@ static int write_error(void) static int store_write_section(int fd, const char* key) { - const char *dot = strchr(key, '.'); - int len1 = store.baselen, len2 = -1; + const char *dot; + int i, success; + struct strbuf sb; - dot = strchr(key, '.'); + strbuf_init(&sb, 0); + dot = memchr(key, '.', store.baselen); if (dot) { - int dotlen = dot - key; - if (dotlen < len1) { - len2 = len1 - dotlen - 1; - len1 = dotlen; + strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key); + for (i = dot - key + 1; i < store.baselen; i++) { + if (key[i] == '"') + strbuf_addch(&sb, '\\'); + strbuf_addch(&sb, key[i]); } + strbuf_addstr(&sb, "\"]\n"); + } else { + strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); } - if (write_in_full(fd, "[", 1) != 1 || - write_in_full(fd, key, len1) != len1) - return 0; - if (len2 >= 0) { - if (write_in_full(fd, " \"", 2) != 2) - return 0; - while (--len2 >= 0) { - unsigned char c = *++dot; - if (c == '"') - if (write_in_full(fd, "\\", 1) != 1) - return 0; - if (write_in_full(fd, &c, 1) != 1) - return 0; - } - if (write_in_full(fd, "\"", 1) != 1) - return 0; - } - if (write_in_full(fd, "]\n", 2) != 2) - return 0; + success = write_in_full(fd, sb.buf, sb.len) == sb.len; + strbuf_release(&sb); - return 1; + return success; } static int store_write_pair(int fd, const char* key, const char* value) { - int i; - int length = strlen(key+store.baselen+1); - int quote = 0; + int i, success; + int length = strlen(key + store.baselen + 1); + const char *quote = ""; + struct strbuf sb; /* * Check to see if the value needs to be surrounded with a dq pair. @@ -659,43 +649,38 @@ static int store_write_pair(int fd, const char* key, const char* value) * configuration parser. */ if (value[0] == ' ') - quote = 1; + quote = "\""; for (i = 0; value[i]; i++) if (value[i] == ';' || value[i] == '#') - quote = 1; - if (i && value[i-1] == ' ') - quote = 1; + quote = "\""; + if (i && value[i - 1] == ' ') + quote = "\""; + + strbuf_init(&sb, 0); + strbuf_addf(&sb, "\t%.*s = %s", + length, key + store.baselen + 1, quote); - if (write_in_full(fd, "\t", 1) != 1 || - write_in_full(fd, key+store.baselen+1, length) != length || - write_in_full(fd, " = ", 3) != 3) - return 0; - if (quote && write_in_full(fd, "\"", 1) != 1) - return 0; for (i = 0; value[i]; i++) switch (value[i]) { case '\n': - if (write_in_full(fd, "\\n", 2) != 2) - return 0; + strbuf_addstr(&sb, "\\n"); break; case '\t': - if (write_in_full(fd, "\\t", 2) != 2) - return 0; + strbuf_addstr(&sb, "\\t"); break; case '"': case '\\': - if (write_in_full(fd, "\\", 1) != 1) - return 0; + strbuf_addch(&sb, '\\'); default: - if (write_in_full(fd, value+i, 1) != 1) - return 0; + strbuf_addch(&sb, value[i]); break; } - if (quote && write_in_full(fd, "\"", 1) != 1) - return 0; - if (write_in_full(fd, "\n", 1) != 1) - return 0; - return 1; + strbuf_addf(&sb, "%s\n", quote); + + success = write_in_full(fd, sb.buf, sb.len) == sb.len; + strbuf_release(&sb); + + return success; } static ssize_t find_beginning_of_line(const char* contents, size_t size, From 420f4f04de9b3790da695918ac168d4115665d92 Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Fri, 14 Dec 2007 12:23:43 +0100 Subject: [PATCH 21/84] Use shorter error messages for whitespace problems The initial version of the whitespace_error_string() function took the messages from builtin-apply.c rather than the shorter messages from diff.c. This commit addresses Junio's concern that these messages might be too long (now that we can emit multiple warnings per line). Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- t/t4015-diff-whitespace.sh | 2 +- ws.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 05ef78b2c0..9bff8f5e4b 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -121,7 +121,7 @@ test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. echo " foo();" > x && - git diff --check | grep "Space in indent is followed by a tab" + git diff --check | grep "space before tab in indent" ' diff --git a/ws.c b/ws.c index d7d1522f8a..46cbdd6379 100644 --- a/ws.c +++ b/ws.c @@ -101,16 +101,16 @@ char *whitespace_error_string(unsigned ws) struct strbuf err; strbuf_init(&err, 0); if (ws & WS_TRAILING_SPACE) - strbuf_addstr(&err, "Adds trailing whitespace"); + strbuf_addstr(&err, "trailing whitespace"); if (ws & WS_SPACE_BEFORE_TAB) { if (err.len) strbuf_addstr(&err, ", "); - strbuf_addstr(&err, "Space in indent is followed by a tab"); + strbuf_addstr(&err, "space before tab in indent"); } if (ws & WS_INDENT_WITH_NON_TAB) { if (err.len) strbuf_addstr(&err, ", "); - strbuf_addstr(&err, "Indent more than 8 places with spaces"); + strbuf_addstr(&err, "indent with spaces"); } return strbuf_detach(&err, NULL); } From 5973a07937f2c64b595c6784b06eb4441c07b5ef Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Fri, 14 Dec 2007 12:23:44 +0100 Subject: [PATCH 22/84] Test interaction between diff --check and --exit-code Make sure that it works as advertised in the man page. Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- t/t4017-diff-retval.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh index 68731908be..dc0b7126cc 100755 --- a/t/t4017-diff-retval.sh +++ b/t/t4017-diff-retval.sh @@ -76,4 +76,33 @@ test_expect_success 'git diff-index --cached HEAD' ' } ' +test_expect_success '--check --exit-code returns 0 for no difference' ' + + git diff --check --exit-code + +' + +test_expect_success '--check --exit-code returns 1 for a clean difference' ' + + echo "good" > a && + git diff --check --exit-code + test $? = 1 + +' + +test_expect_success '--check --exit-code returns 3 for a dirty difference' ' + + echo "bad " >> a && + git diff --check --exit-code + test $? = 3 + +' + +test_expect_success '--check with --no-pager returns 2 for dirty difference' ' + + git --no-pager diff --check + test $? = 2 + +' + test_done From 3b683b91cd78dec027105a2810079eb0b27ab2c0 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 14 Dec 2007 22:18:00 +0100 Subject: [PATCH 23/84] Fix some more memory leaks in http-push.c Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-push.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/http-push.c b/http-push.c index fffbe9ccb4..fc60bfd5f4 100644 --- a/http-push.c +++ b/http-push.c @@ -925,11 +925,14 @@ static int fetch_index(unsigned char *sha1) hex); } } else { + free(url); return error("Unable to start request"); } - if (has_pack_index(sha1)) + if (has_pack_index(sha1)) { + free(url); return 0; + } if (push_verbosely) fprintf(stderr, "Getting index for pack %s\n", hex); @@ -939,9 +942,11 @@ static int fetch_index(unsigned char *sha1) filename = sha1_pack_index_name(sha1); snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename); indexfile = fopen(tmpfile, "a"); - if (!indexfile) + if (!indexfile) { + free(url); return error("Unable to open local file %s for pack index", tmpfile); + } slot = get_active_slot(); slot->results = &results; @@ -1135,10 +1140,12 @@ int fetch_ref(char *ref, unsigned char *sha1) curl_easy_setopt(slot->curl, CURLOPT_URL, url); if (start_active_slot(slot)) { run_active_slot(slot); + free(url); if (results.curl_result != CURLE_OK) return error("Couldn't get %s for %s\n%s", url, ref, curl_errorstr); } else { + free(url); return error("Unable to start request"); } @@ -2107,6 +2114,7 @@ static int remote_exists(const char *path) if (start_active_slot(slot)) { run_active_slot(slot); + free(url); if (results.http_code == 404) return 0; else if (results.curl_result == CURLE_OK) @@ -2114,6 +2122,7 @@ static int remote_exists(const char *path) else fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code); } else { + free(url); fprintf(stderr, "Unable to start HEAD request\n"); } From a096bb18af5b7214d9b87b64ae733d106eb96544 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 14 Dec 2007 22:18:01 +0100 Subject: [PATCH 24/84] Fix random sha1 in error message in http-fetch and http-push When a downloaded ref doesn't contain a sha1, the error message displays a random sha1 because of uninitialized memory. This happens when cloning a repository that is already a clone of another one, in which case refs/remotes/origin/HEAD is a symref. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-push.c | 5 +++-- http-walker.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/http-push.c b/http-push.c index fc60bfd5f4..c96e43da16 100644 --- a/http-push.c +++ b/http-push.c @@ -1149,9 +1149,10 @@ int fetch_ref(char *ref, unsigned char *sha1) return error("Unable to start request"); } + if (buffer.posn != 41) + return 1; hex[40] = '\0'; - get_sha1_hex(hex, sha1); - return 0; + return get_sha1_hex(hex, sha1); } static void one_remote_object(const char *hex) diff --git a/http-walker.c b/http-walker.c index a3fb596542..0faafbce61 100644 --- a/http-walker.c +++ b/http-walker.c @@ -986,9 +986,10 @@ static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1) return error("Unable to start request"); } + if (buffer.posn != 41) + return 1; hex[40] = '\0'; - get_sha1_hex(hex, sha1); - return 0; + return get_sha1_hex(hex, sha1); } static void cleanup(struct walker *walker) From c20f290808efb85fbc7a57e7bc6eddeb4a0208a8 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 10 Dec 2007 22:36:07 +0100 Subject: [PATCH 25/84] Remove the default_headers variable from http-push.c It appears that despite being initialized, it was never used. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-push.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/http-push.c b/http-push.c index c96e43da16..176bb29fab 100644 --- a/http-push.c +++ b/http-push.c @@ -75,7 +75,6 @@ static int aborted; static signed char remote_dir_exists[256]; static struct curl_slist *no_pragma_header; -static struct curl_slist *default_headers; static int push_verbosely; static int push_all = MATCH_REFS_NONE; @@ -2364,11 +2363,6 @@ int main(int argc, char **argv) http_init(); no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); - default_headers = curl_slist_append(default_headers, "Range:"); - default_headers = curl_slist_append(default_headers, "Destination:"); - default_headers = curl_slist_append(default_headers, "If:"); - default_headers = curl_slist_append(default_headers, - "Pragma: no-cache"); /* Verify DAV compliance/lock support */ if (!locking_available()) { @@ -2548,7 +2542,6 @@ int main(int argc, char **argv) free(remote); curl_slist_free_all(no_pragma_header); - curl_slist_free_all(default_headers); http_cleanup(); From 02dc534fc6eb8a08c686b7cb2d979545853889d0 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 10 Dec 2007 22:36:08 +0100 Subject: [PATCH 26/84] Remove a CURLOPT_HTTPHEADER (un)setting Setting CURLOPT_HTTPHEADER doesn't add HTTP headers, but replaces whatever set of headers was configured before, so setting to NULL doesn't have any magic meaning, and is pretty much useless when setting to another list right after. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http.c | 1 - 1 file changed, 1 deletion(-) diff --git a/http.c b/http.c index 146f62609d..ae57073a36 100644 --- a/http.c +++ b/http.c @@ -370,7 +370,6 @@ struct active_request_slot *get_active_slot(void) slot->finished = NULL; slot->callback_data = NULL; slot->callback_func = NULL; - curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header); curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL); From e8dc37e0e30dbbed532b7471516d1ba5e6e08f27 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 10 Dec 2007 22:36:09 +0100 Subject: [PATCH 27/84] Avoid redundant declaration of missing_target() Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-walker.c | 13 ------------- http.h | 13 +++++++++++++ transport.c | 13 ------------- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/http-walker.c b/http-walker.c index 0faafbce61..ad874b98cb 100644 --- a/http-walker.c +++ b/http-walker.c @@ -90,19 +90,6 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, return size; } -static int missing__target(int code, int result) -{ - return /* file:// URL -- do we ever use one??? */ - (result == CURLE_FILE_COULDNT_READ_FILE) || - /* http:// and https:// URL */ - (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) || - /* ftp:// URL */ - (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE) - ; -} - -#define missing_target(a) missing__target((a)->http_code, (a)->curl_result) - static void fetch_alternates(struct walker *walker, const char *base); static void process_object_response(void *callback_data); diff --git a/http.h b/http.h index fe1b0d153b..b9d6f4823d 100644 --- a/http.h +++ b/http.h @@ -82,4 +82,17 @@ extern int active_requests; extern char curl_errorstr[CURL_ERROR_SIZE]; +static inline int missing__target(int code, int result) +{ + return /* file:// URL -- do we ever use one??? */ + (result == CURLE_FILE_COULDNT_READ_FILE) || + /* http:// and https:// URL */ + (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) || + /* ftp:// URL */ + (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE) + ; +} + +#define missing_target(a) missing__target((a)->http_code, (a)->curl_result) + #endif /* HTTP_H */ diff --git a/transport.c b/transport.c index 58e66f6c11..1f840a0498 100644 --- a/transport.c +++ b/transport.c @@ -426,19 +426,6 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons return !!err; } -static int missing__target(int code, int result) -{ - return /* file:// URL -- do we ever use one??? */ - (result == CURLE_FILE_COULDNT_READ_FILE) || - /* http:// and https:// URL */ - (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) || - /* ftp:// URL */ - (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE) - ; -} - -#define missing_target(a) missing__target((a)->http_code, (a)->curl_result) - static struct ref *get_refs_via_curl(struct transport *transport) { struct buffer buffer; From 028c2976389f70e7349bbfeeef0ed0a000d5e447 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 9 Dec 2007 20:30:59 +0100 Subject: [PATCH 28/84] Use strbuf in http code Also, replace whitespaces with tabs in some places Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-push.c | 187 ++++++++++++++++---------------------------------- http-walker.c | 59 ++++++---------- http.c | 34 ++++----- http.h | 11 +-- transport.c | 18 ++--- 5 files changed, 108 insertions(+), 201 deletions(-) diff --git a/http-push.c b/http-push.c index 176bb29fab..0257291b9b 100644 --- a/http-push.c +++ b/http-push.c @@ -494,10 +494,11 @@ static void start_put(struct transfer_request *request) memset(&stream, 0, sizeof(stream)); deflateInit(&stream, zlib_compression_level); size = deflateBound(&stream, len + hdrlen); - request->buffer.buffer = xmalloc(size); + strbuf_init(&request->buffer.buf, size); + request->buffer.posn = 0; /* Compress it */ - stream.next_out = request->buffer.buffer; + stream.next_out = (unsigned char *)request->buffer.buf.buf; stream.avail_out = size; /* First header.. */ @@ -514,8 +515,7 @@ static void start_put(struct transfer_request *request) deflateEnd(&stream); free(unpacked); - request->buffer.size = stream.total_out; - request->buffer.posn = 0; + request->buffer.buf.len = stream.total_out; request->url = xmalloc(strlen(remote->url) + strlen(request->lock->token) + 51); @@ -537,7 +537,7 @@ static void start_put(struct transfer_request *request) slot->callback_func = process_response; slot->callback_data = request; curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer); - curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.size); + curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT); @@ -1007,18 +1007,13 @@ static int fetch_indices(void) { unsigned char sha1[20]; char *url; - struct buffer buffer; + struct strbuf buffer = STRBUF_INIT; char *data; int i = 0; struct active_request_slot *slot; struct slot_results results; - data = xcalloc(1, 4096); - buffer.size = 4096; - buffer.posn = 0; - buffer.buffer = data; - if (push_verbosely) fprintf(stderr, "Getting pack list\n"); @@ -1034,7 +1029,7 @@ static int fetch_indices(void) if (start_active_slot(slot)) { run_active_slot(slot); if (results.curl_result != CURLE_OK) { - free(buffer.buffer); + strbuf_release(&buffer); free(url); if (results.http_code == 404) return 0; @@ -1042,18 +1037,18 @@ static int fetch_indices(void) return error("%s", curl_errorstr); } } else { - free(buffer.buffer); + strbuf_release(&buffer); free(url); return error("Unable to start request"); } free(url); - data = buffer.buffer; - while (i < buffer.posn) { + data = buffer.buf; + while (i < buffer.len) { switch (data[i]) { case 'P': i++; - if (i + 52 < buffer.posn && + if (i + 52 < buffer.len && !prefixcmp(data + i, " pack-") && !prefixcmp(data + i + 46, ".pack\n")) { get_sha1_hex(data + i + 6, sha1); @@ -1068,7 +1063,7 @@ static int fetch_indices(void) i++; } - free(buffer.buffer); + strbuf_release(&buffer); return 0; } @@ -1119,16 +1114,11 @@ static char *quote_ref_url(const char *base, const char *ref) int fetch_ref(char *ref, unsigned char *sha1) { - char *url; - char hex[42]; - struct buffer buffer; + char *url; + struct strbuf buffer = STRBUF_INIT; char *base = remote->url; struct active_request_slot *slot; struct slot_results results; - buffer.size = 41; - buffer.posn = 0; - buffer.buffer = hex; - hex[41] = '\0'; url = quote_ref_url(base, ref); slot = get_active_slot(); @@ -1148,10 +1138,10 @@ int fetch_ref(char *ref, unsigned char *sha1) return error("Unable to start request"); } - if (buffer.posn != 41) + strbuf_rtrim(&buffer); + if (buffer.len != 40) return 1; - hex[40] = '\0'; - return get_sha1_hex(hex, sha1); + return get_sha1_hex(buffer.buf, sha1); } static void one_remote_object(const char *hex) @@ -1274,10 +1264,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout) { struct active_request_slot *slot; struct slot_results results; - struct buffer out_buffer; - struct buffer in_buffer; - char *out_data; - char *in_data; + struct buffer out_buffer = { STRBUF_INIT, 0 }; + struct strbuf in_buffer = STRBUF_INIT; char *url; char *ep; char timeout_header[25]; @@ -1317,16 +1305,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) ep = strchr(ep + 1, '/'); } - out_buffer.size = strlen(LOCK_REQUEST) + strlen(git_default_email) - 2; - out_data = xmalloc(out_buffer.size + 1); - snprintf(out_data, out_buffer.size + 1, LOCK_REQUEST, git_default_email); - out_buffer.posn = 0; - out_buffer.buffer = out_data; - - in_buffer.size = 4096; - in_data = xmalloc(in_buffer.size); - in_buffer.posn = 0; - in_buffer.buffer = in_data; + strbuf_addf(&out_buffer.buf, LOCK_REQUEST, git_default_email); sprintf(timeout_header, "Timeout: Second-%ld", timeout); dav_headers = curl_slist_append(dav_headers, timeout_header); @@ -1335,7 +1314,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); - curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size); + curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); @@ -1361,8 +1340,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout) XML_SetElementHandler(parser, xml_start_tag, xml_end_tag); XML_SetCharacterDataHandler(parser, xml_cdata); - result = XML_Parse(parser, in_buffer.buffer, - in_buffer.posn, 1); + result = XML_Parse(parser, in_buffer.buf, + in_buffer.len, 1); free(ctx.name); if (result != XML_STATUS_OK) { fprintf(stderr, "XML error: %s\n", @@ -1377,8 +1356,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout) } curl_slist_free_all(dav_headers); - free(out_data); - free(in_data); + strbuf_release(&out_buffer.buf); + strbuf_release(&in_buffer); if (lock->token == NULL || lock->timeout <= 0) { if (lock->token != NULL) @@ -1529,10 +1508,8 @@ static void remote_ls(const char *path, int flags, char *url = xmalloc(strlen(remote->url) + strlen(path) + 1); struct active_request_slot *slot; struct slot_results results; - struct buffer in_buffer; - struct buffer out_buffer; - char *in_data; - char *out_data; + struct strbuf in_buffer = STRBUF_INIT; + struct buffer out_buffer = { STRBUF_INIT, 0 }; struct curl_slist *dav_headers = NULL; struct xml_ctx ctx; struct remote_ls_ctx ls; @@ -1546,16 +1523,7 @@ static void remote_ls(const char *path, int flags, sprintf(url, "%s%s", remote->url, path); - out_buffer.size = strlen(PROPFIND_ALL_REQUEST); - out_data = xmalloc(out_buffer.size + 1); - snprintf(out_data, out_buffer.size + 1, PROPFIND_ALL_REQUEST); - out_buffer.posn = 0; - out_buffer.buffer = out_data; - - in_buffer.size = 4096; - in_data = xmalloc(in_buffer.size); - in_buffer.posn = 0; - in_buffer.buffer = in_data; + strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST); dav_headers = curl_slist_append(dav_headers, "Depth: 1"); dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); @@ -1563,7 +1531,7 @@ static void remote_ls(const char *path, int flags, slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); - curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size); + curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); @@ -1586,8 +1554,8 @@ static void remote_ls(const char *path, int flags, XML_SetElementHandler(parser, xml_start_tag, xml_end_tag); XML_SetCharacterDataHandler(parser, xml_cdata); - result = XML_Parse(parser, in_buffer.buffer, - in_buffer.posn, 1); + result = XML_Parse(parser, in_buffer.buf, + in_buffer.len, 1); free(ctx.name); if (result != XML_STATUS_OK) { @@ -1603,8 +1571,8 @@ static void remote_ls(const char *path, int flags, free(ls.path); free(url); - free(out_data); - free(in_buffer.buffer); + strbuf_release(&out_buffer.buf); + strbuf_release(&in_buffer); curl_slist_free_all(dav_headers); } @@ -1625,27 +1593,13 @@ static int locking_available(void) { struct active_request_slot *slot; struct slot_results results; - struct buffer in_buffer; - struct buffer out_buffer; - char *in_data; - char *out_data; + struct strbuf in_buffer = STRBUF_INIT; + struct buffer out_buffer = { STRBUF_INIT, 0 }; struct curl_slist *dav_headers = NULL; struct xml_ctx ctx; int lock_flags = 0; - out_buffer.size = - strlen(PROPFIND_SUPPORTEDLOCK_REQUEST) + - strlen(remote->url) - 2; - out_data = xmalloc(out_buffer.size + 1); - snprintf(out_data, out_buffer.size + 1, - PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url); - out_buffer.posn = 0; - out_buffer.buffer = out_data; - - in_buffer.size = 4096; - in_data = xmalloc(in_buffer.size); - in_buffer.posn = 0; - in_buffer.buffer = in_data; + strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url); dav_headers = curl_slist_append(dav_headers, "Depth: 0"); dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); @@ -1653,7 +1607,7 @@ static int locking_available(void) slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); - curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size); + curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); @@ -1675,8 +1629,8 @@ static int locking_available(void) XML_SetUserData(parser, &ctx); XML_SetElementHandler(parser, xml_start_tag, xml_end_tag); - result = XML_Parse(parser, in_buffer.buffer, - in_buffer.posn, 1); + result = XML_Parse(parser, in_buffer.buf, + in_buffer.len, 1); free(ctx.name); if (result != XML_STATUS_OK) { @@ -1691,8 +1645,8 @@ static int locking_available(void) fprintf(stderr, "Unable to start PROPFIND request\n"); } - free(out_data); - free(in_buffer.buffer); + strbuf_release(&out_buffer.buf); + strbuf_release(&in_buffer); curl_slist_free_all(dav_headers); return lock_flags; @@ -1810,30 +1764,20 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) { struct active_request_slot *slot; struct slot_results results; - char *out_data; char *if_header; - struct buffer out_buffer; + struct buffer out_buffer = { STRBUF_INIT, 0 }; struct curl_slist *dav_headers = NULL; - int i; if_header = xmalloc(strlen(lock->token) + 25); sprintf(if_header, "If: ()", lock->token); dav_headers = curl_slist_append(dav_headers, if_header); - out_buffer.size = 41; - out_data = xmalloc(out_buffer.size + 1); - i = snprintf(out_data, out_buffer.size + 1, "%s\n", sha1_to_hex(sha1)); - if (i != out_buffer.size) { - fprintf(stderr, "Unable to initialize PUT request body\n"); - return 0; - } - out_buffer.posn = 0; - out_buffer.buffer = out_data; + strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1)); slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer); - curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size); + curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT); @@ -1844,7 +1788,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) if (start_active_slot(slot)) { run_active_slot(slot); - free(out_data); + strbuf_release(&out_buffer.buf); free(if_header); if (results.curl_result != CURLE_OK) { fprintf(stderr, @@ -1854,7 +1798,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) return 0; } } else { - free(out_data); + strbuf_release(&out_buffer.buf); free(if_header); fprintf(stderr, "Unable to start PUT request\n"); return 0; @@ -2011,7 +1955,7 @@ static void mark_edges_uninteresting(struct commit_list *list) static void add_remote_info_ref(struct remote_ls_ctx *ls) { - struct buffer *buf = (struct buffer *)ls->userData; + struct strbuf *buf = (struct strbuf *)ls->userData; unsigned char remote_sha1[20]; struct object *o; int len; @@ -2056,17 +2000,14 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls) static void update_remote_info_refs(struct remote_lock *lock) { - struct buffer buffer; + struct buffer buffer = { STRBUF_INIT, 0 }; struct active_request_slot *slot; struct slot_results results; char *if_header; struct curl_slist *dav_headers = NULL; - buffer.buffer = xcalloc(1, 4096); - buffer.size = 4096; - buffer.posn = 0; remote_ls("refs/", (PROCESS_FILES | RECURSIVE), - add_remote_info_ref, &buffer); + add_remote_info_ref, &buffer.buf); if (!aborted) { if_header = xmalloc(strlen(lock->token) + 25); sprintf(if_header, "If: ()", lock->token); @@ -2075,7 +2016,7 @@ static void update_remote_info_refs(struct remote_lock *lock) slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer); - curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.posn); + curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT); @@ -2084,8 +2025,6 @@ static void update_remote_info_refs(struct remote_lock *lock) curl_easy_setopt(slot->curl, CURLOPT_PUT, 1); curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url); - buffer.posn = 0; - if (start_active_slot(slot)) { run_active_slot(slot); if (results.curl_result != CURLE_OK) { @@ -2096,7 +2035,7 @@ static void update_remote_info_refs(struct remote_lock *lock) } free(if_header); } - free(buffer.buffer); + strbuf_release(&buffer.buf); } static int remote_exists(const char *path) @@ -2107,12 +2046,12 @@ static int remote_exists(const char *path) sprintf(url, "%s%s", remote->url, path); - slot = get_active_slot(); + slot = get_active_slot(); slot->results = &results; - curl_easy_setopt(slot->curl, CURLOPT_URL, url); - curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1); + curl_easy_setopt(slot->curl, CURLOPT_URL, url); + curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1); - if (start_active_slot(slot)) { + if (start_active_slot(slot)) { run_active_slot(slot); free(url); if (results.http_code == 404) @@ -2132,17 +2071,13 @@ static int remote_exists(const char *path) static void fetch_symref(const char *path, char **symref, unsigned char *sha1) { char *url; - struct buffer buffer; + struct strbuf buffer = STRBUF_INIT; struct active_request_slot *slot; struct slot_results results; url = xmalloc(strlen(remote->url) + strlen(path) + 1); sprintf(url, "%s%s", remote->url, path); - buffer.size = 4096; - buffer.posn = 0; - buffer.buffer = xmalloc(buffer.size); - slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer); @@ -2165,17 +2100,17 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) *symref = NULL; hashclr(sha1); - if (buffer.posn == 0) + if (buffer.len == 0) return; /* If it's a symref, set the refname; otherwise try for a sha1 */ - if (!prefixcmp((char *)buffer.buffer, "ref: ")) { - *symref = xmemdupz((char *)buffer.buffer + 5, buffer.posn - 6); + if (!prefixcmp((char *)buffer.buf, "ref: ")) { + *symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6); } else { - get_sha1_hex(buffer.buffer, sha1); + get_sha1_hex(buffer.buf, sha1); } - free(buffer.buffer); + strbuf_release(&buffer); } static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1) diff --git a/http-walker.c b/http-walker.c index ad874b98cb..8dbf9cc369 100644 --- a/http-walker.c +++ b/http-walker.c @@ -48,7 +48,7 @@ struct alternates_request { struct walker *walker; const char *base; char *url; - struct buffer *buffer; + struct strbuf *buffer; struct active_request_slot *slot; int http_specific; }; @@ -462,7 +462,7 @@ static void process_alternates_response(void *callback_data) if (alt_req->http_specific) { if (slot->curl_result != CURLE_OK || - !alt_req->buffer->posn) { + !alt_req->buffer->len) { /* Try reusing the slot to get non-http alternates */ alt_req->http_specific = 0; @@ -490,12 +490,12 @@ static void process_alternates_response(void *callback_data) } fwrite_buffer(&null_byte, 1, 1, alt_req->buffer); - alt_req->buffer->posn--; - data = alt_req->buffer->buffer; + alt_req->buffer->len--; + data = alt_req->buffer->buf; - while (i < alt_req->buffer->posn) { + while (i < alt_req->buffer->len) { int posn = i; - while (posn < alt_req->buffer->posn && data[posn] != '\n') + while (posn < alt_req->buffer->len && data[posn] != '\n') posn++; if (data[posn] == '\n') { int okay = 0; @@ -583,9 +583,8 @@ static void process_alternates_response(void *callback_data) static void fetch_alternates(struct walker *walker, const char *base) { - struct buffer buffer; + struct strbuf buffer = STRBUF_INIT; char *url; - char *data; struct active_request_slot *slot; struct alternates_request alt_req; struct walker_data *cdata = walker->data; @@ -606,11 +605,6 @@ static void fetch_alternates(struct walker *walker, const char *base) /* Start the fetch */ cdata->got_alternates = 0; - data = xmalloc(4096); - buffer.size = 4096; - buffer.posn = 0; - buffer.buffer = data; - if (walker->get_verbosely) fprintf(stderr, "Getting alternates list for %s\n", base); @@ -639,7 +633,7 @@ static void fetch_alternates(struct walker *walker, const char *base) else cdata->got_alternates = -1; - free(data); + strbuf_release(&buffer); free(url); } @@ -647,7 +641,7 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) { unsigned char sha1[20]; char *url; - struct buffer buffer; + struct strbuf buffer = STRBUF_INIT; char *data; int i = 0; @@ -657,11 +651,6 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) if (repo->got_indices) return 0; - data = xmalloc(4096); - buffer.size = 4096; - buffer.posn = 0; - buffer.buffer = data; - if (walker->get_verbosely) fprintf(stderr, "Getting pack list for %s\n", repo->base); @@ -677,28 +666,27 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) if (start_active_slot(slot)) { run_active_slot(slot); if (results.curl_result != CURLE_OK) { + strbuf_release(&buffer); if (missing_target(&results)) { repo->got_indices = 1; - free(buffer.buffer); return 0; } else { repo->got_indices = 0; - free(buffer.buffer); return error("%s", curl_errorstr); } } } else { repo->got_indices = 0; - free(buffer.buffer); + strbuf_release(&buffer); return error("Unable to start request"); } - data = buffer.buffer; - while (i < buffer.posn) { + data = buffer.buf; + while (i < buffer.len) { switch (data[i]) { case 'P': i++; - if (i + 52 <= buffer.posn && + if (i + 52 <= buffer.len && !prefixcmp(data + i, " pack-") && !prefixcmp(data + i + 46, ".pack\n")) { get_sha1_hex(data + i + 6, sha1); @@ -707,13 +695,13 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) break; } default: - while (i < buffer.posn && data[i] != '\n') + while (i < buffer.len && data[i] != '\n') i++; } i++; } - free(buffer.buffer); + strbuf_release(&buffer); repo->got_indices = 1; return 0; } @@ -945,17 +933,12 @@ static char *quote_ref_url(const char *base, const char *ref) static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1) { - char *url; - char hex[42]; - struct buffer buffer; + char *url; + struct strbuf buffer = STRBUF_INIT; struct walker_data *data = walker->data; const char *base = data->alt->base; struct active_request_slot *slot; struct slot_results results; - buffer.size = 41; - buffer.posn = 0; - buffer.buffer = hex; - hex[41] = '\0'; url = quote_ref_url(base, ref); slot = get_active_slot(); @@ -973,10 +956,10 @@ static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1) return error("Unable to start request"); } - if (buffer.posn != 41) + strbuf_rtrim(&buffer); + if (buffer.len != 40) return 1; - hex[40] = '\0'; - return get_sha1_hex(hex, sha1); + return get_sha1_hex(buffer.buf, sha1); } static void cleanup(struct walker *walker) diff --git a/http.c b/http.c index ae57073a36..dcc569343e 100644 --- a/http.c +++ b/http.c @@ -34,31 +34,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, struct buffer *buffer) { size_t size = eltsize * nmemb; - if (size > buffer->size - buffer->posn) - size = buffer->size - buffer->posn; - memcpy(ptr, (char *) buffer->buffer + buffer->posn, size); + if (size > buffer->buf.len - buffer->posn) + size = buffer->buf.len - buffer->posn; + memcpy(ptr, buffer->buf.buf + buffer->posn, size); buffer->posn += size; + return size; } size_t fwrite_buffer(const void *ptr, size_t eltsize, - size_t nmemb, struct buffer *buffer) + size_t nmemb, struct strbuf *buffer) { size_t size = eltsize * nmemb; - if (size > buffer->size - buffer->posn) { - buffer->size = buffer->size * 3 / 2; - if (buffer->size < buffer->posn + size) - buffer->size = buffer->posn + size; - buffer->buffer = xrealloc(buffer->buffer, buffer->size); - } - memcpy((char *) buffer->buffer + buffer->posn, ptr, size); - buffer->posn += size; + strbuf_add(buffer, ptr, size); data_received++; return size; } size_t fwrite_null(const void *ptr, size_t eltsize, - size_t nmemb, struct buffer *buffer) + size_t nmemb, struct strbuf *buffer) { data_received++; return eltsize * nmemb; @@ -507,8 +501,8 @@ void run_active_slot(struct active_request_slot *slot) static void closedown_active_slot(struct active_request_slot *slot) { - active_requests--; - slot->in_use = 0; + active_requests--; + slot->in_use = 0; } void release_active_slot(struct active_request_slot *slot) @@ -529,7 +523,7 @@ void release_active_slot(struct active_request_slot *slot) static void finish_active_slot(struct active_request_slot *slot) { closedown_active_slot(slot); - curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); + curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); if (slot->finished != NULL) (*slot->finished) = 1; @@ -540,10 +534,10 @@ static void finish_active_slot(struct active_request_slot *slot) slot->results->http_code = slot->http_code; } - /* Run callback if appropriate */ - if (slot->callback_func != NULL) { - slot->callback_func(slot->callback_data); - } + /* Run callback if appropriate */ + if (slot->callback_func != NULL) { + slot->callback_func(slot->callback_data); + } } void finish_all_active_slots(void) diff --git a/http.h b/http.h index b9d6f4823d..1528d4196f 100644 --- a/http.h +++ b/http.h @@ -6,6 +6,8 @@ #include #include +#include "strbuf.h" + #if LIBCURL_VERSION_NUM >= 0x071000 #define USE_CURL_MULTI #define DEFAULT_MAX_REQUESTS 5 @@ -48,18 +50,17 @@ struct active_request_slot struct buffer { - size_t posn; - size_t size; - void *buffer; + struct strbuf buf; + size_t posn; }; /* Curl request read/write callbacks */ extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, struct buffer *buffer); extern size_t fwrite_buffer(const void *ptr, size_t eltsize, - size_t nmemb, struct buffer *buffer); + size_t nmemb, struct strbuf *buffer); extern size_t fwrite_null(const void *ptr, size_t eltsize, - size_t nmemb, struct buffer *buffer); + size_t nmemb, struct strbuf *buffer); /* Slot lifecycle functions */ extern struct active_request_slot *get_active_slot(void); diff --git a/transport.c b/transport.c index 1f840a0498..4e151a9e87 100644 --- a/transport.c +++ b/transport.c @@ -428,7 +428,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons static struct ref *get_refs_via_curl(struct transport *transport) { - struct buffer buffer; + struct strbuf buffer = STRBUF_INIT; char *data, *start, *mid; char *ref_name; char *refs_url; @@ -441,11 +441,6 @@ static struct ref *get_refs_via_curl(struct transport *transport) struct ref *ref = NULL; struct ref *last_ref = NULL; - data = xmalloc(4096); - buffer.size = 4096; - buffer.posn = 0; - buffer.buffer = data; - refs_url = xmalloc(strlen(transport->url) + 11); sprintf(refs_url, "%s/info/refs", transport->url); @@ -464,27 +459,26 @@ static struct ref *get_refs_via_curl(struct transport *transport) if (start_active_slot(slot)) { run_active_slot(slot); if (results.curl_result != CURLE_OK) { + strbuf_release(&buffer); if (missing_target(&results)) { - free(buffer.buffer); return NULL; } else { - free(buffer.buffer); error("%s", curl_errorstr); return NULL; } } } else { - free(buffer.buffer); + strbuf_release(&buffer); error("Unable to start request"); return NULL; } http_cleanup(); - data = buffer.buffer; + data = buffer.buf; start = NULL; mid = data; - while (i < buffer.posn) { + while (i < buffer.len) { if (!start) start = &data[i]; if (data[i] == '\t') @@ -507,7 +501,7 @@ static struct ref *get_refs_via_curl(struct transport *transport) i++; } - free(buffer.buffer); + strbuf_release(&buffer); return refs; } From 3a462bc9ba8cc46dcd5e49ae884968e1921c265f Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 10 Dec 2007 22:36:11 +0100 Subject: [PATCH 29/84] Fix various memory leaks in http-push.c and http-walker.c Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-push.c | 33 ++++++++++++++++++++------------- http-walker.c | 40 +++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/http-push.c b/http-push.c index 0257291b9b..af00ea10b9 100644 --- a/http-push.c +++ b/http-push.c @@ -1119,6 +1119,7 @@ int fetch_ref(char *ref, unsigned char *sha1) char *base = remote->url; struct active_request_slot *slot; struct slot_results results; + int ret; url = quote_ref_url(base, ref); slot = get_active_slot(); @@ -1129,19 +1130,23 @@ int fetch_ref(char *ref, unsigned char *sha1) curl_easy_setopt(slot->curl, CURLOPT_URL, url); if (start_active_slot(slot)) { run_active_slot(slot); - free(url); - if (results.curl_result != CURLE_OK) - return error("Couldn't get %s for %s\n%s", - url, ref, curl_errorstr); + if (results.curl_result == CURLE_OK) { + strbuf_rtrim(&buffer); + if (buffer.len == 40) + ret = get_sha1_hex(buffer.buf, sha1); + else + ret = 1; + } else { + ret = error("Couldn't get %s for %s\n%s", + url, ref, curl_errorstr); + } } else { - free(url); - return error("Unable to start request"); + ret = error("Unable to start request"); } - strbuf_rtrim(&buffer); - if (buffer.len != 40) - return 1; - return get_sha1_hex(buffer.buf, sha1); + strbuf_release(&buffer); + free(url); + return ret; } static void one_remote_object(const char *hex) @@ -2043,6 +2048,7 @@ static int remote_exists(const char *path) char *url = xmalloc(strlen(remote->url) + strlen(path) + 1); struct active_request_slot *slot; struct slot_results results; + int ret = -1; sprintf(url, "%s%s", remote->url, path); @@ -2055,9 +2061,9 @@ static int remote_exists(const char *path) run_active_slot(slot); free(url); if (results.http_code == 404) - return 0; + ret = 0; else if (results.curl_result == CURLE_OK) - return 1; + ret = 1; else fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code); } else { @@ -2065,7 +2071,8 @@ static int remote_exists(const char *path) fprintf(stderr, "Unable to start HEAD request\n"); } - return -1; + free(url); + return ret; } static void fetch_symref(const char *path, char **symref, unsigned char *sha1) diff --git a/http-walker.c b/http-walker.c index 8dbf9cc369..4e878b3c8f 100644 --- a/http-walker.c +++ b/http-walker.c @@ -644,6 +644,7 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) struct strbuf buffer = STRBUF_INIT; char *data; int i = 0; + int ret = 0; struct active_request_slot *slot; struct slot_results results; @@ -666,19 +667,19 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) if (start_active_slot(slot)) { run_active_slot(slot); if (results.curl_result != CURLE_OK) { - strbuf_release(&buffer); if (missing_target(&results)) { repo->got_indices = 1; - return 0; + goto cleanup; } else { repo->got_indices = 0; - return error("%s", curl_errorstr); + ret = error("%s", curl_errorstr); + goto cleanup; } } } else { repo->got_indices = 0; - strbuf_release(&buffer); - return error("Unable to start request"); + ret = error("Unable to start request"); + goto cleanup; } data = buffer.buf; @@ -701,9 +702,11 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) i++; } - strbuf_release(&buffer); repo->got_indices = 1; - return 0; +cleanup: + strbuf_release(&buffer); + free(url); + return ret; } static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1) @@ -939,6 +942,7 @@ static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1) const char *base = data->alt->base; struct active_request_slot *slot; struct slot_results results; + int ret; url = quote_ref_url(base, ref); slot = get_active_slot(); @@ -949,17 +953,23 @@ static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1) curl_easy_setopt(slot->curl, CURLOPT_URL, url); if (start_active_slot(slot)) { run_active_slot(slot); - if (results.curl_result != CURLE_OK) - return error("Couldn't get %s for %s\n%s", - url, ref, curl_errorstr); + if (results.curl_result == CURLE_OK) { + strbuf_rtrim(&buffer); + if (buffer.len == 40) + ret = get_sha1_hex(buffer.buf, sha1); + else + ret = 1; + } else { + ret = error("Couldn't get %s for %s\n%s", + url, ref, curl_errorstr); + } } else { - return error("Unable to start request"); + ret = error("Unable to start request"); } - strbuf_rtrim(&buffer); - if (buffer.len != 40) - return 1; - return get_sha1_hex(buffer.buf, sha1); + strbuf_release(&buffer); + free(url); + return ret; } static void cleanup(struct walker *walker) From d7e92806cdc5ca78c4db879c68f91c70ff9e1ade Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 11 Dec 2007 00:08:25 +0100 Subject: [PATCH 30/84] Move fetch_ref from http-push.c and http-walker.c to http.c Make the necessary changes to be ok with their difference, and rename the function http_fetch_ref. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http-push.c | 88 +++------------------------------------------------ http-walker.c | 80 +--------------------------------------------- http.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ http.h | 2 ++ 4 files changed, 89 insertions(+), 163 deletions(-) diff --git a/http-push.c b/http-push.c index af00ea10b9..64be904921 100644 --- a/http-push.c +++ b/http-push.c @@ -1067,88 +1067,6 @@ static int fetch_indices(void) return 0; } -static inline int needs_quote(int ch) -{ - if (((ch >= 'A') && (ch <= 'Z')) - || ((ch >= 'a') && (ch <= 'z')) - || ((ch >= '0') && (ch <= '9')) - || (ch == '/') - || (ch == '-') - || (ch == '.')) - return 0; - return 1; -} - -static inline int hex(int v) -{ - if (v < 10) return '0' + v; - else return 'A' + v - 10; -} - -static char *quote_ref_url(const char *base, const char *ref) -{ - const char *cp; - char *dp, *qref; - int len, baselen, ch; - - baselen = strlen(base); - len = baselen + 1; - for (cp = ref; (ch = *cp) != 0; cp++, len++) - if (needs_quote(ch)) - len += 2; /* extra two hex plus replacement % */ - qref = xmalloc(len); - memcpy(qref, base, baselen); - for (cp = ref, dp = qref + baselen; (ch = *cp) != 0; cp++) { - if (needs_quote(ch)) { - *dp++ = '%'; - *dp++ = hex((ch >> 4) & 0xF); - *dp++ = hex(ch & 0xF); - } - else - *dp++ = ch; - } - *dp = 0; - - return qref; -} - -int fetch_ref(char *ref, unsigned char *sha1) -{ - char *url; - struct strbuf buffer = STRBUF_INIT; - char *base = remote->url; - struct active_request_slot *slot; - struct slot_results results; - int ret; - - url = quote_ref_url(base, ref); - slot = get_active_slot(); - slot->results = &results; - curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer); - curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); - curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); - curl_easy_setopt(slot->curl, CURLOPT_URL, url); - if (start_active_slot(slot)) { - run_active_slot(slot); - if (results.curl_result == CURLE_OK) { - strbuf_rtrim(&buffer); - if (buffer.len == 40) - ret = get_sha1_hex(buffer.buf, sha1); - else - ret = 1; - } else { - ret = error("Couldn't get %s for %s\n%s", - url, ref, curl_errorstr); - } - } else { - ret = error("Unable to start request"); - } - - strbuf_release(&buffer); - free(url); - return ret; -} - static void one_remote_object(const char *hex) { unsigned char sha1[20]; @@ -1834,7 +1752,8 @@ static void one_remote_ref(char *refname) struct object *obj; int len = strlen(refname) + 1; - if (fetch_ref(refname, remote_sha1) != 0) { + if (http_fetch_ref(remote->url, refname + 5 /* "refs/" */, + remote_sha1) != 0) { fprintf(stderr, "Unable to fetch ref %s from %s\n", refname, remote->url); @@ -1966,7 +1885,8 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls) int len; char *ref_info; - if (fetch_ref(ls->dentry_name, remote_sha1) != 0) { + if (http_fetch_ref(remote->url, ls->dentry_name + 5 /* "refs/" */, + remote_sha1) != 0) { fprintf(stderr, "Unable to fetch ref %s from %s\n", ls->dentry_name, remote->url); diff --git a/http-walker.c b/http-walker.c index 4e878b3c8f..2c3786870e 100644 --- a/http-walker.c +++ b/http-walker.c @@ -888,88 +888,10 @@ static int fetch(struct walker *walker, unsigned char *sha1) data->alt->base); } -static inline int needs_quote(int ch) -{ - if (((ch >= 'A') && (ch <= 'Z')) - || ((ch >= 'a') && (ch <= 'z')) - || ((ch >= '0') && (ch <= '9')) - || (ch == '/') - || (ch == '-') - || (ch == '.')) - return 0; - return 1; -} - -static inline int hex(int v) -{ - if (v < 10) return '0' + v; - else return 'A' + v - 10; -} - -static char *quote_ref_url(const char *base, const char *ref) -{ - const char *cp; - char *dp, *qref; - int len, baselen, ch; - - baselen = strlen(base); - len = baselen + 7; /* "/refs/" + NUL */ - for (cp = ref; (ch = *cp) != 0; cp++, len++) - if (needs_quote(ch)) - len += 2; /* extra two hex plus replacement % */ - qref = xmalloc(len); - memcpy(qref, base, baselen); - memcpy(qref + baselen, "/refs/", 6); - for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) { - if (needs_quote(ch)) { - *dp++ = '%'; - *dp++ = hex((ch >> 4) & 0xF); - *dp++ = hex(ch & 0xF); - } - else - *dp++ = ch; - } - *dp = 0; - - return qref; -} - static int fetch_ref(struct walker *walker, char *ref, unsigned char *sha1) { - char *url; - struct strbuf buffer = STRBUF_INIT; struct walker_data *data = walker->data; - const char *base = data->alt->base; - struct active_request_slot *slot; - struct slot_results results; - int ret; - - url = quote_ref_url(base, ref); - slot = get_active_slot(); - slot->results = &results; - curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer); - curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); - curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); - curl_easy_setopt(slot->curl, CURLOPT_URL, url); - if (start_active_slot(slot)) { - run_active_slot(slot); - if (results.curl_result == CURLE_OK) { - strbuf_rtrim(&buffer); - if (buffer.len == 40) - ret = get_sha1_hex(buffer.buf, sha1); - else - ret = 1; - } else { - ret = error("Couldn't get %s for %s\n%s", - url, ref, curl_errorstr); - } - } else { - ret = error("Unable to start request"); - } - - strbuf_release(&buffer); - free(url); - return ret; + return http_fetch_ref(data->alt->base, ref, sha1); } static void cleanup(struct walker *walker) diff --git a/http.c b/http.c index dcc569343e..d2c11aee90 100644 --- a/http.c +++ b/http.c @@ -552,3 +552,85 @@ void finish_all_active_slots(void) slot = slot->next; } } + +static inline int needs_quote(int ch) +{ + if (((ch >= 'A') && (ch <= 'Z')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= '0') && (ch <= '9')) + || (ch == '/') + || (ch == '-') + || (ch == '.')) + return 0; + return 1; +} + +static inline int hex(int v) +{ + if (v < 10) return '0' + v; + else return 'A' + v - 10; +} + +static char *quote_ref_url(const char *base, const char *ref) +{ + const char *cp; + char *dp, *qref; + int len, baselen, ch; + + baselen = strlen(base); + len = baselen + 7; /* "/refs/" + NUL */ + for (cp = ref; (ch = *cp) != 0; cp++, len++) + if (needs_quote(ch)) + len += 2; /* extra two hex plus replacement % */ + qref = xmalloc(len); + memcpy(qref, base, baselen); + memcpy(qref + baselen, "/refs/", 6); + for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) { + if (needs_quote(ch)) { + *dp++ = '%'; + *dp++ = hex((ch >> 4) & 0xF); + *dp++ = hex(ch & 0xF); + } + else + *dp++ = ch; + } + *dp = 0; + + return qref; +} + +int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1) +{ + char *url; + struct strbuf buffer = STRBUF_INIT; + struct active_request_slot *slot; + struct slot_results results; + int ret; + + url = quote_ref_url(base, ref); + slot = get_active_slot(); + slot->results = &results; + curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer); + curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); + curl_easy_setopt(slot->curl, CURLOPT_URL, url); + if (start_active_slot(slot)) { + run_active_slot(slot); + if (results.curl_result == CURLE_OK) { + strbuf_rtrim(&buffer); + if (buffer.len == 40) + ret = get_sha1_hex(buffer.buf, sha1); + else + ret = 1; + } else { + ret = error("Couldn't get %s for %s\n%s", + url, ref, curl_errorstr); + } + } else { + ret = error("Unable to start request"); + } + + strbuf_release(&buffer); + free(url); + return ret; +} diff --git a/http.h b/http.h index 1528d4196f..aeba9301f8 100644 --- a/http.h +++ b/http.h @@ -96,4 +96,6 @@ static inline int missing__target(int code, int result) #define missing_target(a) missing__target((a)->http_code, (a)->curl_result) +extern int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1); + #endif /* HTTP_H */ From 70087cdbd3671f5929689a9b77f414b8297641c2 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sat, 15 Dec 2007 05:57:28 +0100 Subject: [PATCH 31/84] git-help: add "help.format" config variable. This config variable makes it possible to choose the default format used to display help. This format will be used only if no option like -a|--all|-i|--info|-m|--man|-w|--web is passed to "git-help". The following values are possible for this variable: - "man" --> "man" program is used - "info" --> "info" program is used - "web" --> "git-browse-help" is used By default we still show help using "man". This patch also adds -m|--man command line option to use "man" to allow overriding the "help.format" configuration variable. Note that this patch also revert some recent changes in "git-browse-help" because they prevented to look for config variables in the global configuration file. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-help.txt | 37 ++++++++++++++++++++-- git-browse-help.sh | 4 +-- git-sh-setup.sh | 7 +---- help.c | 64 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 100 insertions(+), 12 deletions(-) diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index ac9e15d774..31ec403a70 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -7,7 +7,7 @@ git-help - display help information about git SYNOPSIS -------- -'git help' [-a|--all|-i|--info|-w|--web] [COMMAND] +'git help' [-a|--all|-i|--info|-m|--man|-w|--web] [COMMAND] DESCRIPTION ----------- @@ -21,7 +21,7 @@ printed on the standard output. If a git command is named, a manual page for that command is brought up. The 'man' program is used by default for this purpose, but this -can be overriden by other options. +can be overriden by other options or configuration variables. Note that 'git --help ...' is identical as 'git help ...' because the former is internally converted into the latter. @@ -36,6 +36,11 @@ OPTIONS Use the 'info' program to display the manual page, instead of the 'man' program that is used by default. +-m|--man:: + Use the 'man' program to display the manual page. This may be + used to override a value set in the 'help.format' + configuration variable. + -w|--web:: Use a web browser to display the HTML manual page, instead of the 'man' program that is used by default. @@ -54,6 +59,34 @@ is available in PATH. Note that the script tries, as much as possible, to display the HTML page in a new tab on an already opened browser. +CONFIGURATION VARIABLES +----------------------- + +If no command line option is passed, the 'help.format' configuration +variable will be checked. The following values are supported for this +variable; they make 'git-help' behave as their corresponding command +line option: + +* "man" corresponds to '-m|--man', +* "info" corresponds to '-i|--info', +* "web" or "html" correspond to '-w|--web', + +The 'help.browser', 'web.browser' and 'browser..path' will also +be checked if the 'web' format is choosen (either by command line +option or configuration variable). See '-w|--web' in the OPTIONS +section above. + +Note that these configuration variables should probably be set using +the '--global' flag, for example like this: + +------------------------------------------------ +$ git config --global help.format web +$ git config --global web.browser firefox +------------------------------------------------ + +as they are probably more user specific than repository specific. +See gitlink:git-config[1] for more information about this. + Author ------ Written by Junio C Hamano and the git-list diff --git a/git-browse-help.sh b/git-browse-help.sh index b465911c9a..10b0a36a3d 100755 --- a/git-browse-help.sh +++ b/git-browse-help.sh @@ -39,7 +39,7 @@ valid_tool() { } init_browser_path() { - test -z "$GIT_DIR" || browser_path=`git config browser.$1.path` + browser_path=`git config browser.$1.path` test -z "$browser_path" && browser_path=$1 } @@ -71,7 +71,7 @@ do shift done -if test -z "$browser" && test -n "$GIT_DIR" +if test -z "$browser" then for opt in "help.browser" "web.browser" do diff --git a/git-sh-setup.sh b/git-sh-setup.sh index b366761b97..270d559297 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -124,13 +124,8 @@ get_author_ident_from_commit () { # Make sure we are in a valid repository of a vintage we understand, # if we require to be in a git repository. -if test -n "$NONGIT_OK" +if test -z "$NONGIT_OK" then - if git rev-parse --git-dir >/dev/null 2>&1 - then - : ${GIT_DIR=.git} - fi -else if [ -z "$SUBDIRECTORY_OK" ] then : ${GIT_DIR=.git} diff --git a/help.c b/help.c index c96b1670f3..551b5b93b3 100644 --- a/help.c +++ b/help.c @@ -8,6 +8,44 @@ #include "exec_cmd.h" #include "common-cmds.h" +static const char *help_default_format; + +static enum help_format { + man_format, + info_format, + web_format, +} help_format = man_format; + +static void parse_help_format(const char *format) +{ + if (!format) { + help_format = man_format; + return; + } + if (!strcmp(format, "man")) { + help_format = man_format; + return; + } + if (!strcmp(format, "info")) { + help_format = info_format; + return; + } + if (!strcmp(format, "web") || !strcmp(format, "html")) { + help_format = web_format; + return; + } + die("unrecognized help format '%s'", format); +} + +static int git_help_config(const char *var, const char *value) +{ + if (!strcmp(var, "help.format")) { + help_default_format = xstrdup(value); + return 0; + } + return git_default_config(var, value); +} + /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) { @@ -331,8 +369,30 @@ int cmd_help(int argc, const char **argv, const char *prefix) show_info_page(argc > 2 ? argv[2] : NULL); } - else - show_man_page(help_cmd); + else if (!strcmp(help_cmd, "--man") || !strcmp(help_cmd, "-m")) { + show_man_page(argc > 2 ? argv[2] : NULL); + } + + else { + int nongit; + + setup_git_directory_gently(&nongit); + git_config(git_help_config); + if (help_default_format) + parse_help_format(help_default_format); + + switch (help_format) { + case man_format: + show_man_page(help_cmd); + break; + case info_format: + show_info_page(help_cmd); + break; + case web_format: + show_html_page(help_cmd); + break; + } + } return 0; } From 5b4617c7490921f3ea871231f71d6baa2288bf93 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 22:02:57 -0800 Subject: [PATCH 32/84] Rename git-browse-help helper to git-browse--help Signed-off-by: Junio C Hamano --- .gitignore | 2 +- Documentation/git-help.txt | 6 +++--- Makefile | 7 +++---- git-browse-help.sh => git-browse--help.sh | 0 help.c | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) rename git-browse-help.sh => git-browse--help.sh (100%) diff --git a/.gitignore b/.gitignore index 5eaba41995..aef01c5a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ git-archive git-bisect git-blame git-branch -git-browse-help +git-browse--help git-bundle git-cat-file git-check-attr diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index 31ec403a70..8cd69e7129 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -47,13 +47,13 @@ OPTIONS + The web browser can be specified using the configuration variable 'help.browser', or 'web.browser' if the former is not set. If none of -these config variables is set, the 'git-browse-help' script (called by -'git-help') will pick a suitable default. +these config variables is set, the 'git-browse--help' helper script +(called by 'git-help') will pick a suitable default. + You can explicitly provide a full path to your prefered browser by setting the configuration variable 'browser..path'. For example, you can configure the absolute path to firefox by setting -'browser.firefox.path'. Otherwise, 'git-browse-help' assumes the tool +'browser.firefox.path'. Otherwise, 'git-browse--help' assumes the tool is available in PATH. + Note that the script tries, as much as possible, to display the HTML diff --git a/Makefile b/Makefile index 16de2f3e25..43d6197495 100644 --- a/Makefile +++ b/Makefile @@ -227,7 +227,7 @@ SCRIPT_SH = \ git-lost-found.sh git-quiltimport.sh git-submodule.sh \ git-filter-branch.sh \ git-stash.sh \ - git-browse-help.sh + git-browse--help.sh SCRIPT_PERL = \ git-add--interactive.perl \ @@ -1144,9 +1144,8 @@ check-docs:: case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ git-merge-resolve | git-merge-stupid | git-merge-subtree | \ - git-add--interactive | git-fsck-objects | git-init-db | \ - git-rebase--interactive | \ - git-repo-config | git-fetch--tool ) continue ;; \ + git-fsck-objects | git-init-db | git-repo-config | \ + git-?*--?* ) continue ;; \ esac ; \ test -f "Documentation/$$v.txt" || \ echo "no doc: $$v"; \ diff --git a/git-browse-help.sh b/git-browse--help.sh similarity index 100% rename from git-browse-help.sh rename to git-browse--help.sh diff --git a/help.c b/help.c index 551b5b93b3..f9ce6db34f 100644 --- a/help.c +++ b/help.c @@ -331,7 +331,7 @@ static void show_info_page(const char *git_cmd) static void show_html_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - execl_git_cmd("browse-help", page, NULL); + execl_git_cmd("browse--help", page, NULL); } void help_unknown_cmd(const char *cmd) From fa4701601a62664a9246a211c5d26f238820737e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 22:08:25 -0800 Subject: [PATCH 33/84] Retire git-runstatus for real. The command was removed from the builtin command list and there was no way to invoke it, but the code was still there. Signed-off-by: Junio C Hamano --- Documentation/git-runstatus.txt | 68 --------------------------------- Makefile | 2 +- builtin-runstatus.c | 38 ------------------ command-list.txt | 1 - 4 files changed, 1 insertion(+), 108 deletions(-) delete mode 100644 Documentation/git-runstatus.txt delete mode 100644 builtin-runstatus.c diff --git a/Documentation/git-runstatus.txt b/Documentation/git-runstatus.txt deleted file mode 100644 index dee5d0da9d..0000000000 --- a/Documentation/git-runstatus.txt +++ /dev/null @@ -1,68 +0,0 @@ -git-runstatus(1) -================ - -NAME ----- -git-runstatus - A helper for git-status and git-commit - - -SYNOPSIS --------- -'git-runstatus' [--color|--nocolor] [--amend] [--verbose] [--untracked] - - -DESCRIPTION ------------ -Examines paths in the working tree that has changes unrecorded -to the index file, and changes between the index file and the -current HEAD commit. The former paths are what you _could_ -commit by running 'git add' (or 'git rm' if you are deleting) before running 'git -commit', and the latter paths are what you _would_ commit by -running 'git commit'. - -If there is no path that is different between the index file and -the current HEAD commit, the command exits with non-zero status. - -Note that this is _not_ the user level command you would want to -run from the command line. Use 'git-status' instead. - - -OPTIONS -------- ---color:: - Show colored status, highlighting modified file names. - ---nocolor:: - Turn off coloring. - ---amend:: - Show status based on HEAD^1, not HEAD, i.e. show what - 'git-commit --amend' would do. - ---verbose:: - Show unified diff of all file changes. - ---untracked:: - Show files in untracked directories, too. Without this - option only its name and a trailing slash are displayed - for each untracked directory. - - -OUTPUT ------- -The output from this command is designed to be used as a commit -template comments, and all the output lines are prefixed with '#'. - - -Author ------- -Originally written by Linus Torvalds as part -of git-commit, and later rewritten in C by Jeff King. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list . - -GIT ---- -Part of the gitlink:git[7] suite diff --git a/Makefile b/Makefile index 43d6197495..b9fe40bd43 100644 --- a/Makefile +++ b/Makefile @@ -933,7 +933,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) -builtin-revert.o builtin-runstatus.o wt-status.o: wt-status.h +builtin-revert.o wt-status.o: wt-status.h $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) diff --git a/builtin-runstatus.c b/builtin-runstatus.c deleted file mode 100644 index 8d167a9674..0000000000 --- a/builtin-runstatus.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "builtin.h" -#include "cache.h" -#include "wt-status.h" - -extern int wt_status_use_color; - -static const char runstatus_usage[] = -"git-runstatus [--color|--nocolor] [--amend] [--verbose] [--untracked]"; - -int cmd_runstatus(int argc, const char **argv, const char *prefix) -{ - struct wt_status s; - int i; - - git_config(git_status_config); - wt_status_prepare(&s); - s.prefix = prefix; - - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "--color")) - wt_status_use_color = 1; - else if (!strcmp(argv[i], "--nocolor")) - wt_status_use_color = 0; - else if (!strcmp(argv[i], "--amend")) { - s.amend = 1; - s.reference = "HEAD^1"; - } - else if (!strcmp(argv[i], "--verbose")) - s.verbose = 1; - else if (!strcmp(argv[i], "--untracked")) - s.untracked = 1; - else - usage(runstatus_usage); - } - - wt_status_print(&s); - return s.commitable ? 0 : 1; -} diff --git a/command-list.txt b/command-list.txt index 28342da959..6c2b1d830d 100644 --- a/command-list.txt +++ b/command-list.txt @@ -98,7 +98,6 @@ git-revert mainporcelain git-rev-list plumbinginterrogators git-rev-parse ancillaryinterrogators git-rm mainporcelain common -git-runstatus ancillaryinterrogators git-send-email foreignscminterface git-send-pack synchingrepositories git-shell synchelpers From 530e741c726a612d78de21957d531dd2215483b4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 24 Nov 2007 23:48:04 -0800 Subject: [PATCH 34/84] Start preparing the API documents. Most of them are still stubs, but the procedure to build the HTML documentation, maintaining the index and installing the end product are there. I placed names of people who are likely to know the most about the topic in the stub files, so that volunteers will know whom to ask questions as needed. Signed-off-by: Junio C Hamano --- Documentation/.gitignore | 1 + Documentation/Makefile | 17 +- Documentation/git.txt | 2 + Documentation/install-webdoc.sh | 16 +- Documentation/technical/.gitignore | 1 + .../technical/api-allocation-growing.txt | 34 ++++ Documentation/technical/api-builtin.txt | 63 +++++++ Documentation/technical/api-decorate.txt | 6 + Documentation/technical/api-diff.txt | 166 ++++++++++++++++++ .../technical/api-directory-listing.txt | 76 ++++++++ Documentation/technical/api-gitattributes.txt | 111 ++++++++++++ Documentation/technical/api-grep.txt | 8 + Documentation/technical/api-hash.txt | 6 + Documentation/technical/api-in-core-index.txt | 21 +++ Documentation/technical/api-index-skel.txt | 15 ++ Documentation/technical/api-index.sh | 28 +++ Documentation/technical/api-lockfile.txt | 12 ++ Documentation/technical/api-object-access.txt | 15 ++ Documentation/technical/api-parse-options.txt | 6 + Documentation/technical/api-path-list.txt | 9 + Documentation/technical/api-quote.txt | 10 ++ .../technical/api-revision-walking.txt | 9 + Documentation/technical/api-run-command.txt | 10 ++ Documentation/technical/api-setup.txt | 13 ++ Documentation/technical/api-strbuf.txt | 6 + Documentation/technical/api-tree-walking.txt | 12 ++ .../technical/api-xdiff-interface.txt | 7 + 27 files changed, 675 insertions(+), 5 deletions(-) create mode 100644 Documentation/technical/.gitignore create mode 100644 Documentation/technical/api-allocation-growing.txt create mode 100644 Documentation/technical/api-builtin.txt create mode 100644 Documentation/technical/api-decorate.txt create mode 100644 Documentation/technical/api-diff.txt create mode 100644 Documentation/technical/api-directory-listing.txt create mode 100644 Documentation/technical/api-gitattributes.txt create mode 100644 Documentation/technical/api-grep.txt create mode 100644 Documentation/technical/api-hash.txt create mode 100644 Documentation/technical/api-in-core-index.txt create mode 100644 Documentation/technical/api-index-skel.txt create mode 100755 Documentation/technical/api-index.sh create mode 100644 Documentation/technical/api-lockfile.txt create mode 100644 Documentation/technical/api-object-access.txt create mode 100644 Documentation/technical/api-parse-options.txt create mode 100644 Documentation/technical/api-path-list.txt create mode 100644 Documentation/technical/api-quote.txt create mode 100644 Documentation/technical/api-revision-walking.txt create mode 100644 Documentation/technical/api-run-command.txt create mode 100644 Documentation/technical/api-setup.txt create mode 100644 Documentation/technical/api-strbuf.txt create mode 100644 Documentation/technical/api-tree-walking.txt create mode 100644 Documentation/technical/api-xdiff-interface.txt diff --git a/Documentation/.gitignore b/Documentation/.gitignore index a37b2152bd..2f938f471a 100644 --- a/Documentation/.gitignore +++ b/Documentation/.gitignore @@ -2,6 +2,7 @@ *.html *.[1-8] *.made +git.info howto-index.txt doc.dep cmds-*.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index 1fd48ab367..76df06cd61 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -24,6 +24,9 @@ ARTICLES += git-tools ARTICLES += glossary # with their own formatting rules. SP_ARTICLES = howto/revert-branch-rebase user-manual +API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt))) +SP_ARTICLES += $(API_DOCS) +SP_ARTICLES += technical/api-index DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES)) @@ -142,10 +145,12 @@ cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) git.7 git.html: git.txt clean: - $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 *.texi *.texi+ howto-index.txt howto/*.html doc.dep + $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 *.texi *.texi+ git.info + $(RM) howto-index.txt howto/*.html doc.dep + $(RM) technical/api-*.html technical/api-index.txt $(RM) $(cmds_txt) *.made -%.html : %.txt +$(MAN_HTML): %.html : %.txt $(RM) $@+ $@ $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< @@ -164,6 +169,14 @@ clean: user-manual.xml: user-manual.txt user-manual.conf $(ASCIIDOC) -b docbook -d book $< +technical/api-index.txt: technical/api-index-skel.txt \ + technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) + cd technical && sh ./api-index.sh + +$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt + $(ASCIIDOC) -b xhtml11 -f asciidoc.conf \ + $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt + XSLT = docbook.xsl XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css diff --git a/Documentation/git.txt b/Documentation/git.txt index a29b634e7a..e0f9a4490c 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -153,6 +153,8 @@ introductions to the underlying git architecture. See also the link:howto-index.html[howto] documents for some useful examples. +The internals are documented link:technical/api-index.html[here]. + GIT COMMANDS ------------ diff --git a/Documentation/install-webdoc.sh b/Documentation/install-webdoc.sh index cd3a18eb7f..2135a8ee1f 100755 --- a/Documentation/install-webdoc.sh +++ b/Documentation/install-webdoc.sh @@ -2,9 +2,16 @@ T="$1" -for h in *.html *.txt howto/*.txt howto/*.html RelNotes-*.txt *.css +for h in \ + *.txt *.html \ + howto/*.txt howto/*.html \ + technical/*.txt technical/*.html \ + RelNotes-*.txt *.css do - if test -f "$T/$h" && + if test ! -f "$h" + then + : did not match + elif test -f "$T/$h" && diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h" then :; # up to date @@ -16,7 +23,10 @@ do fi done strip_leading=`echo "$T/" | sed -e 's|.|.|g'` -for th in "$T"/*.html "$T"/*.txt "$T"/howto/*.txt "$T"/howto/*.html +for th in \ + "$T"/*.html "$T"/*.txt \ + "$T"/howto/*.txt "$T"/howto/*.html \ + "$T"/technical/*.txt "$T"/technical/*.html do h=`expr "$th" : "$strip_leading"'\(.*\)'` case "$h" in diff --git a/Documentation/technical/.gitignore b/Documentation/technical/.gitignore new file mode 100644 index 0000000000..8aa891daee --- /dev/null +++ b/Documentation/technical/.gitignore @@ -0,0 +1 @@ +api-index.txt diff --git a/Documentation/technical/api-allocation-growing.txt b/Documentation/technical/api-allocation-growing.txt new file mode 100644 index 0000000000..43dbe09f73 --- /dev/null +++ b/Documentation/technical/api-allocation-growing.txt @@ -0,0 +1,34 @@ +allocation growing API +====================== + +Dynamically growing an array using realloc() is error prone and boring. + +Define your array with: + +* a pointer (`ary`) that points at the array, initialized to `NULL`; + +* an integer variable (`alloc`) that keeps track of how big the current + allocation is, initialized to `0`; + +* another integer variable (`nr`) to keep track of how many elements the + array currently has, initialized to `0`. + +Then before adding `n`th element to the array, call `ALLOC_GROW(ary, n, +alloc)`. This ensures that the array can hold at least `n` elements by +calling `realloc(3)` and adjusting `alloc` variable. + +------------ +sometype *ary; +size_t nr; +size_t alloc + +for (i = 0; i < nr; i++) + if (we like ary[i] already) + return; + +/* we did not like any existing one, so add one */ +ALLOC_GROW(ary, nr + 1, alloc); +ary[nr++] = value you like; +------------ + +You are responsible for updating the `nr` variable. diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt new file mode 100644 index 0000000000..52cdb4c520 --- /dev/null +++ b/Documentation/technical/api-builtin.txt @@ -0,0 +1,63 @@ +builtin API +=========== + +Adding a new built-in +--------------------- + +There are 4 things to do to add a bulit-in command implementation to +git: + +. Define the implementation of the built-in command `foo` with + signature: + + int cmd_foo(int argc, const char **argv, const char *prefix); + +. Add the external declaration for the function to `builtin.h`. + +. Add the command to `commands[]` table in `handle_internal_command()`, + defined in `git.c`. The entry should look like: + + { "foo", cmd_foo, }, + + where options is the bitwise-or of: + +`RUN_SETUP`:: + + Make sure there is a git directory to work on, and if there is a + work tree, chdir to the top of it if the command was invoked + in a subdirectory. If there is no work tree, no chdir() is + done. + +`USE_PAGER`:: + + If the standard output is connected to a tty, spawn a pager and + feed our output to it. + +. Add `builtin-foo.o` to `BUILTIN_OBJS` in `Makefile`. + +Additionally, if `foo` is a new command, there are 3 more things to do: + +. Add tests to `t/` directory. + +. Write documentation in `Documentation/git-foo.txt`. + +. Add an entry for `git-foo` to the list at the end of + `Documentation/cmd-list.perl`. + + +How a built-in is called +------------------------ + +The implementation `cmd_foo()` takes three parameters, `argc`, `argv, +and `prefix`. The first two are similar to what `main()` of a +standalone command would be called with. + +When `RUN_SETUP` is specified in the `commands[]` table, and when you +were started from a subdirectory of the work tree, `cmd_foo()` is called +after chdir(2) to the top of the work tree, and `prefix` gets the path +to the subdirectory the command started from. This allows you to +convert a user-supplied pathname (typically relative to that directory) +to a pathname relative to the top of the work tree. + +The return value from `cmd_foo()` becomes the exit status of the +command. diff --git a/Documentation/technical/api-decorate.txt b/Documentation/technical/api-decorate.txt new file mode 100644 index 0000000000..1d52a6ce14 --- /dev/null +++ b/Documentation/technical/api-decorate.txt @@ -0,0 +1,6 @@ +decorate API +============ + +Talk about + +(Linus) diff --git a/Documentation/technical/api-diff.txt b/Documentation/technical/api-diff.txt new file mode 100644 index 0000000000..822609bcd1 --- /dev/null +++ b/Documentation/technical/api-diff.txt @@ -0,0 +1,166 @@ +diff API +======== + +The diff API is for programs that compare two sets of files (e.g. two +trees, one tree and the index) and present the found difference in +various ways. The calling program is responsible for feeding the API +pairs of files, one from the "old" set and the corresponding one from +"new" set, that are different. The library called through this API is +called diffcore, and is responsible for two things. + +* finding total rewrites (`-B`), renames (`-M`) and copies (`-C`), and + changes that touch a string (`-S`), as specified by the caller. + +* outputting the differences in various formats, as specified by the + caller. + +Calling sequence +---------------- + +* Prepare `struct diff_options` to record the set of diff options, and + then call `diff_setup()` to initialize this structure. This sets up + the vanilla default. + +* Fill in the options structure to specify desired output format, rename + detection, etc. `diff_opt_parse()` can be used to parse options given + from the command line in a way consistent with existing git-diff + family of programs. + +* Call `diff_setup_done()`; this inspects the options set up so far for + internal consistency and make necessary tweaking to it (e.g. if + textual patch output was asked, recursive behaviour is turned on). + +* As you find different pairs of files, call `diff_change()` to feed + modified files, `diff_addremove()` to feed created or deleted files, + or `diff_unmerged()` to feed a file whose state is 'unmerged' to the + API. These are thin wrappers to a lower-level `diff_queue()` function + that is flexible enough to record any of these kinds of changes. + +* Once you finish feeding the pairs of files, call `diffcore_std()`. + This will tell the diffcore library to go ahead and do its work. + +* Calling `diffcore_flush()` will produce the output. + + +Data structures +--------------- + +* `struct diff_filespec` + +This is the internal representation for a single file (blob). It +records the blob object name (if known -- for a work tree file it +typically is a NUL SHA-1), filemode and pathname. This is what the +`diff_addremove()`, `diff_change()` and `diff_unmerged()` synthesize and +feed `diff_queue()` function with. + +* `struct diff_filepair` + +This records a pair of `struct diff_filespec`; the filespec for a file +in the "old" set (i.e. preimage) is called `one`, and the filespec for a +file in the "new" set (i.e. postimage) is called `two`. A change that +represents file creation has NULL in `one`, and file deletion has NULL +in `two`. + +A `filepair` starts pointing at `one` and `two` that are from the same +filename, but `diffcore_std()` can break pairs and match component +filespecs with other filespecs from a different filepair to form new +filepair. This is called 'rename detection'. + +* `struct diff_queue` + +This is a collection of filepairs. Notable members are: + +`queue`:: + + An array of pointers to `struct diff_filepair`. This + dynamically grows as you add filepairs; + +`alloc`:: + + The allocated size of the `queue` array; + +`nr`:: + + The number of elements in the `queue` array. + + +* `struct diff_options` + +This describes the set of options the calling program wants to affect +the operation of diffcore library with. + +Notable members are: + +`output_format`:: + The output format used when `diff_flush()` is run. + +`context`:: + Number of context lines to generate in patch output. + +`break_opt`, `detect_rename`, `rename-score`, `rename_limit`:: + Affects the way detection logic for complete rewrites, renames + and copies. + +`abbrev`:: + Number of hexdigits to abbrevate raw format output to. + +`pickaxe`:: + A constant string (can and typically does contain newlines to + look for a block of text, not just a single line) to filter out + the filepairs that do not change the number of strings contained + in its preimage and postmage of the diff_queue. + +`flags`:: + This is mostly a collection of boolean options that affects the + operation, but some do not have anything to do with the diffcore + library. + +BINARY, TEXT;; + Affects the way how a file that is seemingly binary is treated. + +FULL_INDEX;; + Tells the patch output format not to use abbreviated object + names on the "index" lines. + +FIND_COPIES_HARDER;; + Tells the diffcore library that the caller is feeding unchanged + filepairs to allow copies from unmodified files be detected. + +COLOR_DIFF;; + Output should be colored. + +COLOR_DIFF_WORDS;; + Output is a colored word-diff. + +NO_INDEX;; + Tells diff-files that the input is not tracked files but files + in random locations on the filesystem. + +ALLOW_EXTERNAL;; + Tells output routine that it is Ok to call user specified patch + output routine. Plumbing disables this to ensure stable output. + +QUIET;; + Do not show any output. + +REVERSE_DIFF;; + Tells the library that the calling program is feeding the + filepairs reversed; `one` is two, and `two` is one. + +EXIT_WITH_STATUS;; + For communication between the calling program and the options + parser; tell the calling program to signal the presense of + difference using program exit code. + +HAS_CHANGES;; + Internal; used for optimization to see if there is any change. + +SILENT_ON_REMOVE;; + Affects if diff-files shows removed files. + +RECURSIVE, TREE_IN_RECURSIVE;; + Tells if tree traversal done by tree-diff should recursively + descend into a tree object pair that are different in preimage + and postimage set. + +(JC) diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt new file mode 100644 index 0000000000..5bbd18f020 --- /dev/null +++ b/Documentation/technical/api-directory-listing.txt @@ -0,0 +1,76 @@ +directory listing API +===================== + +The directory listing API is used to enumerate paths in the work tree, +optionally taking `.git/info/exclude` and `.gitignore` files per +directory into account. + +Data structure +-------------- + +`struct dir_struct` structure is used to pass directory traversal +options to the library and to record the paths discovered. The notable +options are: + +`exclude_per_dir`:: + + The name of the file to be read in each directory for excluded + files (typically `.gitignore`). + +`collect_ignored`:: + + Include paths that are to be excluded in the result. + +`show_ignored`:: + + The traversal is for finding just ignored files, not unignored + files. + +`show_other_directories`:: + + Include a directory that is not tracked. + +`hide_empty_directories`:: + + Do not include a directory that is not tracked and is empty. + +`no_gitlinks`:: + + If set, recurse into a directory that looks like a git + directory. Otherwise it is shown as a directory. + +The result of the enumeration is left in these fields:: + +`entries[]`:: + + An array of `struct dir_entry`, each element of which describes + a path. + +`nr`:: + + The number of members in `entries[]` array. + +`alloc`:: + + Internal use; keeps track of allocation of `entries[]` array. + + +Calling sequence +---------------- + +* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0, + sizeof(dir))`. + +* Call `add_exclude()` to add single exclude pattern, + `add_excludes_from_file()` to add patterns from a file + (e.g. `.git/info/exclude`), and/or set `dir.exclude_per_dir`. A + short-hand function `setup_standard_excludes()` can be used to set up + the standard set of exclude settings. + +* Set options described in the Data Structure section above. + +* Call `read_directory()`. + +* Use `dir.entries[]`. + +(JC) diff --git a/Documentation/technical/api-gitattributes.txt b/Documentation/technical/api-gitattributes.txt new file mode 100644 index 0000000000..9d97eaa9de --- /dev/null +++ b/Documentation/technical/api-gitattributes.txt @@ -0,0 +1,111 @@ +gitattributes API +================= + +gitattributes mechanism gives a uniform way to associate various +attributes to set of paths. + + +Data Structure +-------------- + +`struct git_attr`:: + + An attribute is an opaque object that is identified by its name. + Pass the name and its length to `git_attr()` function to obtain + the object of this type. The internal representation of this + structure is of no interest to the calling programs. + +`struct git_attr_check`:: + + This structure represents a set of attributes to check in a call + to `git_checkattr()` function, and receives the results. + + +Calling Sequence +---------------- + +* Prepare an array of `struct git_attr_check` to define the list of + attributes you would want to check. To populate this array, you would + need to define necessary attributes by calling `git_attr()` function. + +* Call git_checkattr() to check the attributes for the path. + +* Inspect `git_attr_check` structure to see how each of the attribute in + the array is defined for the path. + + +Attribute Values +---------------- + +An attribute for a path can be in one of four states: Set, Unset, +Unspecified or set to a string, and `.value` member of `struct +git_attr_check` records it. There are three macros to check these: + +`ATTR_TRUE()`:: + + Returns true if the attribute is Set for the path. + +`ATTR_FALSE()`:: + + Returns true if the attribute is Unset for the path. + +`ATTR_UNSET()`:: + + Returns true if the attribute is Unspecified for the path. + +If none of the above returns true, `.value` member points at a string +value of the attribute for the path. + + +Example +------- + +To see how attributes "crlf" and "indent" are set for different paths. + +. Prepare an array of `struct git_attr_check` with two elements (because + we are checking two attributes). Initialize their `attr` member with + pointers to `struct git_attr` obtained by calling `git_attr()`: + +------------ +static struct git_attr_check check[2]; +static void setup_check(void) +{ + if (check[0].attr) + return; /* already done */ + check[0].attr = git_attr("crlf", 4); + check[1].attr = git_attr("ident", 5); +} +------------ + +. Call `git_checkattr()` with the prepared array of `struct git_attr_check`: + +------------ + const char *path; + + setup_check(); + git_checkattr(path, ARRAY_SIZE(check), check); +------------ + +. Act on `.value` member of the result, left in `check[]`: + +------------ + const char *value = check[0].value; + + if (ATTR_TRUE(value)) { + The attribute is Set, by listing only the name of the + attribute in the gitattributes file for the path. + } else if (ATTR_FALSE(value)) { + The attribute is Unset, by listing the name of the + attribute prefixed with a dash - for the path. + } else if (ATTR_UNSET(value)) { + The attribute is not set nor unset for the path. + } else if (!strcmp(value, "input")) { + If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is + true, the value is a string set in the gitattributes + file for the path by saying "attr=value". + } else if (... other check using value as string ...) { + ... + } +------------ + +(JC) diff --git a/Documentation/technical/api-grep.txt b/Documentation/technical/api-grep.txt new file mode 100644 index 0000000000..a69cc8964d --- /dev/null +++ b/Documentation/technical/api-grep.txt @@ -0,0 +1,8 @@ +grep API +======== + +Talk about , things like: + +* grep_buffer() + +(JC) diff --git a/Documentation/technical/api-hash.txt b/Documentation/technical/api-hash.txt new file mode 100644 index 0000000000..c784d3edcb --- /dev/null +++ b/Documentation/technical/api-hash.txt @@ -0,0 +1,6 @@ +hash API +======== + +Talk about + +(Linus) diff --git a/Documentation/technical/api-in-core-index.txt b/Documentation/technical/api-in-core-index.txt new file mode 100644 index 0000000000..adbdbf5d75 --- /dev/null +++ b/Documentation/technical/api-in-core-index.txt @@ -0,0 +1,21 @@ +in-core index API +================= + +Talk about and , things like: + +* cache -> the_index macros +* read_index() +* write_index() +* ie_match_stat() and ie_modified(); how they are different and when to + use which. +* index_name_pos() +* remove_index_entry_at() +* remove_file_from_index() +* add_file_to_index() +* add_index_entry() +* refresh_index() +* discard_index() +* cache_tree_invalidate_path() +* cache_tree_update() + +(JC, Linus) diff --git a/Documentation/technical/api-index-skel.txt b/Documentation/technical/api-index-skel.txt new file mode 100644 index 0000000000..af7cc2e395 --- /dev/null +++ b/Documentation/technical/api-index-skel.txt @@ -0,0 +1,15 @@ +GIT API Documents +================= + +GIT has grown a set of internal API over time. This collection +documents them. + +//////////////////////////////////////////////////////////////// +// table of contents begin +//////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////// +// table of contents end +//////////////////////////////////////////////////////////////// + +2007-11-24 diff --git a/Documentation/technical/api-index.sh b/Documentation/technical/api-index.sh new file mode 100755 index 0000000000..9c3f4131b8 --- /dev/null +++ b/Documentation/technical/api-index.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +( + c=//////////////////////////////////////////////////////////////// + skel=api-index-skel.txt + sed -e '/^\/\/ table of contents begin/q' "$skel" + echo "$c" + + ls api-*.txt | + while read filename + do + case "$filename" in + api-index-skel.txt | api-index.txt) continue ;; + esac + title=$(sed -e 1q "$filename") + html=${filename%.txt}.html + echo "* link:$html[$title]" + done + echo "$c" + sed -n -e '/^\/\/ table of contents end/,$p' "$skel" +) >api-index.txt+ + +if test -f api-index.txt && cmp api-index.txt api-index.txt+ >/dev/null +then + rm -f api-index.txt+ +else + mv api-index.txt+ api-index.txt +fi diff --git a/Documentation/technical/api-lockfile.txt b/Documentation/technical/api-lockfile.txt new file mode 100644 index 0000000000..73ac1025fd --- /dev/null +++ b/Documentation/technical/api-lockfile.txt @@ -0,0 +1,12 @@ +lockfile API +============ + +Talk about , things like: + +* lockfile lifetime -- atexit(3) looks at them, do not put them on the + stack; +* hold_lock_file_for_update() +* commit_lock_file() +* rollback_rock_file() + +(JC, Dscho, Shawn) diff --git a/Documentation/technical/api-object-access.txt b/Documentation/technical/api-object-access.txt new file mode 100644 index 0000000000..03bb0e950d --- /dev/null +++ b/Documentation/technical/api-object-access.txt @@ -0,0 +1,15 @@ +object access API +================= + +Talk about and family, things like + +* read_sha1_file() +* read_object_with_reference() +* has_sha1_file() +* write_sha1_file() +* pretend_sha1_file() +* lookup_{object,commit,tag,blob,tree} +* parse_{object,commit,tag,blob,tree} +* Use of object flags + +(JC, Shawn, Daniel, Dscho, Linus) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt new file mode 100644 index 0000000000..b7cda94f54 --- /dev/null +++ b/Documentation/technical/api-parse-options.txt @@ -0,0 +1,6 @@ +parse-options API +================= + +Talk about + +(Pierre) diff --git a/Documentation/technical/api-path-list.txt b/Documentation/technical/api-path-list.txt new file mode 100644 index 0000000000..d077683171 --- /dev/null +++ b/Documentation/technical/api-path-list.txt @@ -0,0 +1,9 @@ +path-list API +============= + +Talk about , things like + +* it is not just paths but strings in general; +* the calling sequence. + +(Dscho) diff --git a/Documentation/technical/api-quote.txt b/Documentation/technical/api-quote.txt new file mode 100644 index 0000000000..e8a1bce94e --- /dev/null +++ b/Documentation/technical/api-quote.txt @@ -0,0 +1,10 @@ +quote API +========= + +Talk about , things like + +* sq_quote and unquote +* c_style quote and unquote +* quoting for foreign languages + +(JC) diff --git a/Documentation/technical/api-revision-walking.txt b/Documentation/technical/api-revision-walking.txt new file mode 100644 index 0000000000..01a24551af --- /dev/null +++ b/Documentation/technical/api-revision-walking.txt @@ -0,0 +1,9 @@ +revision walking API +==================== + +Talk about , things like: + +* two diff_options, one for path limiting, another for output; +* calling sequence: init_revisions(), setup_revsions(), get_revision(); + +(Linus, JC, Dscho) diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt new file mode 100644 index 0000000000..19d2f64f73 --- /dev/null +++ b/Documentation/technical/api-run-command.txt @@ -0,0 +1,10 @@ +run-command API +=============== + +Talk about , and things like: + +* Environment the command runs with (e.g. GIT_DIR); +* File descriptors and pipes; +* Exit status; + +(Hannes, Dscho, Shawn) diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt new file mode 100644 index 0000000000..4f63a04d7d --- /dev/null +++ b/Documentation/technical/api-setup.txt @@ -0,0 +1,13 @@ +setup API +========= + +Talk about + +* setup_git_directory() +* setup_git_directory_gently() +* is_inside_git_dir() +* is_inside_work_tree() +* setup_work_tree() +* get_pathspec() + +(Dscho) diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt new file mode 100644 index 0000000000..a52e4f36d5 --- /dev/null +++ b/Documentation/technical/api-strbuf.txt @@ -0,0 +1,6 @@ +strbuf API +========== + +Talk about + +(Pierre, JC) diff --git a/Documentation/technical/api-tree-walking.txt b/Documentation/technical/api-tree-walking.txt new file mode 100644 index 0000000000..e3ddf91284 --- /dev/null +++ b/Documentation/technical/api-tree-walking.txt @@ -0,0 +1,12 @@ +tree walking API +================ + +Talk about , things like + +* struct tree_desc +* init_tree_desc +* tree_entry_extract +* update_tree_entry +* get_tree_entry + +(JC, Linus) diff --git a/Documentation/technical/api-xdiff-interface.txt b/Documentation/technical/api-xdiff-interface.txt new file mode 100644 index 0000000000..6296ecad1d --- /dev/null +++ b/Documentation/technical/api-xdiff-interface.txt @@ -0,0 +1,7 @@ +xdiff interface API +=================== + +Talk about our calling convention to xdiff library, including +xdiff_emit_consume_fn. + +(Dscho, JC) From 7680087e7c8125e7397aa5761f5c5ddbb02a8326 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 22:30:38 -0800 Subject: [PATCH 35/84] Update draft release notes for 1.5.4 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.4.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes-1.5.4.txt b/Documentation/RelNotes-1.5.4.txt index d6fd3ddd16..89e6fe32b8 100644 --- a/Documentation/RelNotes-1.5.4.txt +++ b/Documentation/RelNotes-1.5.4.txt @@ -7,6 +7,9 @@ Removal * "git svnimport" was removed in favor of "git svn". It is still there in the source tree (contrib/examples) but unsupported. + * As git-commit and git-status have been rewritten, "git runstatus" + helper script lost all its users and has been removed. + Deprecation notices ------------------- @@ -261,6 +264,9 @@ Updates since v1.5.3 between svn and git; a new representation that is much more compact for this information has been introduced to correct this. + * "git svn" left temporary index files it used without cleaning them + up; this was corrected. + * "git status" from a subdirectory now shows relative paths, which makes copy-and-pasting for git-checkout/git-add/git-rm easier. The traditional behaviour to show the full path relative to the top of @@ -297,6 +303,9 @@ this release, unless otherwise noted. These fixes are only in v1.5.4 and not backported to v1.5.3 maintenance series. + * The way "git diff --check" behaves is much more consistent with the way + "git apply --whitespace=warn" works. + * "git svn" talking with the SVN over http will correctly quote branch and project names. @@ -305,6 +314,6 @@ series. -- exec >/var/tmp/1 -O=v1.5.4-rc0 +O=v1.5.4-rc0-35-g530e741 echo O=`git describe refs/heads/master` git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint From 52499977350b95ba7166e5c835b09cdbc20a3d02 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 16 Dec 2007 02:06:14 -0500 Subject: [PATCH 36/84] trim_common_tail: brown paper bag fix. The recovered context lines were not LF terminated due to off-by-one error, which also caused the outer loop to count the number of recovered lines to terminate after running only once. Signed-off-by: Junio C Hamano --- xdiff-interface.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/xdiff-interface.c b/xdiff-interface.c index 700def211e..98b02eda35 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -110,7 +110,7 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx) { const int blk = 1024; - long trimmed = 0, recovered = 0, i; + long trimmed = 0, recovered = 0; char *ap = a->ptr + a->size; char *bp = b->ptr + b->size; long smaller = (a->size < b->size) ? a->size : b->size; @@ -121,10 +121,9 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx) bp -= blk; } - for (i = 0, recovered = 0; recovered < trimmed && i <= ctx; i++) { - while (recovered < trimmed && ap[recovered] != '\n') - recovered++; - } + while (recovered < trimmed && ctx) + if (ap[recovered++] == '\n') + ctx--; a->size -= (trimmed - recovered); b->size -= (trimmed - recovered); } From 718a087a47cc148f74027a3a26d71994ff71bdd8 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 15 Dec 2007 06:11:54 -0500 Subject: [PATCH 37/84] teach bash completion to treat commands with "--" as a helper There is a convention that commands containing a double-dash are implementation details and not to be used by mortals. We should automatically remove them from the completion suggestions as such. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 58e0e53cd6..343364de04 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -291,7 +291,7 @@ __git_commands () for i in $(git help -a|egrep '^ ') do case $i in - add--interactive) : plumbing;; + *--*) : helper pattern;; applymbox) : ask gittus;; applypatch) : ask gittus;; archimport) : import;; @@ -308,7 +308,6 @@ __git_commands () diff-tree) : plumbing;; fast-import) : import;; fsck-objects) : plumbing;; - fetch--tool) : plumbing;; fetch-pack) : plumbing;; fmt-merge-msg) : plumbing;; for-each-ref) : plumbing;; From bf901f8e748144a19d057d9d00582417d480c795 Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 15 Dec 2007 15:40:28 +0100 Subject: [PATCH 38/84] gitweb: disambiguate heads and tags withs the same name Avoid wrong disambiguation that would link logs/trees of tags and heads which share the same name to the same page, leading to a disambiguation that would prefer the tag, thus making it impossible to access the corresponding head log and tree without hacking the url by hand. It does it by using full refname (with 'refs/heads/' or 'refs/tags/' prefix) instead of shortened one in the URLs in 'heads' and 'tags' tables. This makes URLs (and refs) provided by gitweb unambiguous. Signed-off-by: Guillaume Seguin Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 24b31582af..32c1907021 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2233,6 +2233,7 @@ sub git_get_heads_list { my ($hash, $name, $title) = split(' ', $refinfo, 3); my ($committer, $epoch, $tz) = ($committerinfo =~ /^(.*) ([0-9]+) (.*)$/); + $ref_item{'fullname'} = $name; $name =~ s!^refs/heads/!!; $ref_item{'name'} = $name; @@ -2270,6 +2271,7 @@ sub git_get_tags_list { my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6); my ($creator, $epoch, $tz) = ($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/); + $ref_item{'fullname'} = $name; $name =~ s!^refs/tags/!!; $ref_item{'type'} = $type; @@ -3690,8 +3692,8 @@ sub git_tags_body { "" . " | " . $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'}); if ($tag{'reftype'} eq "commit") { - print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . - " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log"); + print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'fullname'})}, "shortlog") . + " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'fullname'})}, "log"); } elsif ($tag{'reftype'} eq "blob") { print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw"); } @@ -3726,13 +3728,13 @@ sub git_heads_body { $alternate ^= 1; print "$ref{'age'}\n" . ($curr ? "" : "") . - $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}), + $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'}), -class => "list name"},esc_html($ref{'name'})) . "\n" . "" . - $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " . - $cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " . - $cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") . + $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'})}, "shortlog") . " | " . + $cgi->a({-href => href(action=>"log", hash=>$ref{'fullname'})}, "log") . " | " . + $cgi->a({-href => href(action=>"tree", hash=>$ref{'fullname'}, hash_base=>$ref{'name'})}, "tree") . "\n" . ""; } From dfa7c7d221d05499063f9bf95f507af8a882bfeb Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Sat, 15 Dec 2007 15:41:49 +0100 Subject: [PATCH 39/84] gitweb: Teach "a=blob" action to be more lenient about blob/file mime type Since 930cf7dd7cc6b87d173f182230763e1f1913d319 'blob' action knows the file type; if the file type is not "text/*" or one of common network image formats/mimetypes (gif, png, jpeg) then the action "blob" defaulted to "blob_plain". This caused the problem if mimetypes file was not well suited for web, for example returning "application/x-sh" for "*.sh" shell scripts, instead of "text/plain" (or other "text/*"). Now "blob" action defaults to "blob_plain" ('raw' view) only if file is of type which is neither "text/*" nor "image/{gif,png,jpeg}" AND it is binary file. Otherwise it assumes that it can be displayed either in tag ("image/*" mimetype), or can be displayed line by line (otherwise). Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 32c1907021..2a0c46c234 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -4290,7 +4290,7 @@ sub git_blob { open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or die_error(undef, "Couldn't cat $file_name, $hash"); my $mimetype = blob_mimetype($fd, $file_name); - if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)!) { + if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) { close $fd; return git_blob_plain($mimetype); } @@ -4331,16 +4331,7 @@ sub git_blob { } git_print_page_path($file_name, "blob", $hash_base); print "
\n"; - if ($mimetype =~ m!^text/!) { - my $nr; - while (my $line = <$fd>) { - chomp $line; - $nr++; - $line = untabify($line); - printf "
%4i %s
\n", - $nr, $nr, $nr, esc_html($line, -nbsp=>1); - } - } elsif ($mimetype =~ m!^image/!) { + if ($mimetype =~ m!^image/!) { print qq!$file_name"blob_plain", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name) . qq!" />\n!; + } else { + my $nr; + while (my $line = <$fd>) { + chomp $line; + $nr++; + $line = untabify($line); + printf "
%4i %s
\n", + $nr, $nr, $nr, esc_html($line, -nbsp=>1); + } } close $fd or print "Reading blob failed.\n"; From bc8b95ae4a4b21753e84bbfd28cbcbf1b3f6e0a8 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sat, 8 Dec 2007 12:30:59 +0100 Subject: [PATCH 40/84] gitweb: Make config_to_multi return [] instead of [undef] This is important for the list of clone urls, where if there are no per-repository clone URL configured, the default base URLs are never used for URL construction without this patch. Add tests for different ways of setting project URLs, just in case. Note that those tests in current form wouldn't detect breakage fixed by this patch, as it only checks for errors and not for expected output. Signed-off-by: Petr Baudis Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 2 +- t/t9500-gitweb-standalone-no-errors.sh | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 2a0c46c234..28bb8c3933 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1511,7 +1511,7 @@ sub config_to_int { sub config_to_multi { my $val = shift; - return ref($val) ? $val : [ $val ]; + return ref($val) ? $val : (defined($val) ? [ $val ] : []); } sub git_get_project_config { diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 35fff3ddba..796cd7dba0 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -557,6 +557,31 @@ test_expect_success \ 'gitweb_run "p=.git;a=tree;opt=--no-merges"' test_debug 'cat gitweb.log' +# ---------------------------------------------------------------------- +# testing config_to_multi / cloneurl + +test_expect_success \ + 'URL: no project URLs, no base URL' \ + 'gitweb_run "p=.git;a=summary"' +test_debug 'cat gitweb.log' + +test_expect_success \ + 'URL: project URLs via gitweb.url' \ + 'git config --add gitweb.url git://example.com/git/trash.git && + git config --add gitweb.url http://example.com/git/trash.git && + gitweb_run "p=.git;a=summary"' +test_debug 'cat gitweb.log' + +cat >.git/cloneurl <<\EOF +git://example.com/git/trash.git +http://example.com/git/trash.git +EOF + +test_expect_success \ + 'URL: project URLs via cloneurl file' \ + 'gitweb_run "p=.git;a=summary"' +test_debug 'cat gitweb.log' + # ---------------------------------------------------------------------- # gitweb config and repo config From 6ba78238a824282816944550edc4297dd2808a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B8=BF?= Date: Sun, 16 Dec 2007 12:53:26 +0800 Subject: [PATCH 41/84] Fix a memory leak Signed-off-by: Li Hong Signed-off-by: Junio C Hamano --- dir.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dir.c b/dir.c index 6b3273d1d1..3e345c2fc5 100644 --- a/dir.c +++ b/dir.c @@ -169,7 +169,10 @@ static int add_excludes_from_file_1(const char *fname, } buf = xmalloc(size+1); if (read_in_full(fd, buf, size) != size) + { + free(buf); goto err; + } close(fd); if (buf_p) From d7e522cffb2224b91c9c0edde093fbb81a0289b0 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 16 Dec 2007 02:21:04 -0500 Subject: [PATCH 42/84] rename git-browse--help to git-help--browse The convention for helper scripts has been git-$TOOL--$HELPER. Since this is a "browse" helper for the "help" tool, git-help--browse is a more sensible name. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- .gitignore | 2 +- Documentation/git-help.txt | 4 ++-- Makefile | 2 +- git-browse--help.sh => git-help--browse.sh | 0 help.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename git-browse--help.sh => git-help--browse.sh (100%) diff --git a/.gitignore b/.gitignore index aef01c5a2b..dab5bc2a3c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ git-archive git-bisect git-blame git-branch -git-browse--help git-bundle git-cat-file git-check-attr @@ -52,6 +51,7 @@ git-gc git-get-tar-commit-id git-grep git-hash-object +git-help--browse git-http-fetch git-http-push git-imap-send diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index 8cd69e7129..da3f71850a 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -47,13 +47,13 @@ OPTIONS + The web browser can be specified using the configuration variable 'help.browser', or 'web.browser' if the former is not set. If none of -these config variables is set, the 'git-browse--help' helper script +these config variables is set, the 'git-help--browse' helper script (called by 'git-help') will pick a suitable default. + You can explicitly provide a full path to your prefered browser by setting the configuration variable 'browser..path'. For example, you can configure the absolute path to firefox by setting -'browser.firefox.path'. Otherwise, 'git-browse--help' assumes the tool +'browser.firefox.path'. Otherwise, 'git-help--browse' assumes the tool is available in PATH. + Note that the script tries, as much as possible, to display the HTML diff --git a/Makefile b/Makefile index b9fe40bd43..617e5f5a4b 100644 --- a/Makefile +++ b/Makefile @@ -227,7 +227,7 @@ SCRIPT_SH = \ git-lost-found.sh git-quiltimport.sh git-submodule.sh \ git-filter-branch.sh \ git-stash.sh \ - git-browse--help.sh + git-help--browse.sh SCRIPT_PERL = \ git-add--interactive.perl \ diff --git a/git-browse--help.sh b/git-help--browse.sh similarity index 100% rename from git-browse--help.sh rename to git-help--browse.sh diff --git a/help.c b/help.c index f9ce6db34f..1302a61c83 100644 --- a/help.c +++ b/help.c @@ -331,7 +331,7 @@ static void show_info_page(const char *git_cmd) static void show_html_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - execl_git_cmd("browse--help", page, NULL); + execl_git_cmd("help--browse", page, NULL); } void help_unknown_cmd(const char *cmd) From 4d9697c7871e513712eb9cfd30611049b10e5132 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 11:31:37 -0500 Subject: [PATCH 43/84] whitespace: fix off-by-one error in non-space-in-indent checking If there were no tabs, and the last space was at position 7, then positions 0..7 had spaces, so there were 8 spaces. Update test to check exactly this case. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- t/t4015-diff-whitespace.sh | 4 ++-- ws.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 9bff8f5e4b..0f16bca373 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -298,7 +298,7 @@ test_expect_success 'check space before tab in indent (space-before-tab: on)' ' test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' git config core.whitespace "-indent-with-non-tab" - echo " foo ();" > x && + echo " foo ();" > x && git diff --check ' @@ -306,7 +306,7 @@ test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" > x && ! git diff --check ' diff --git a/ws.c b/ws.c index 46cbdd6379..5ebd1095a2 100644 --- a/ws.c +++ b/ws.c @@ -159,7 +159,7 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, } /* Check for indent using non-tab. */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && leading_space >= 8) + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && leading_space >= 7) result |= WS_INDENT_WITH_NON_TAB; if (stream) { From 1020999a981e0dadedc475c41e33e20fd7832019 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 11:31:38 -0500 Subject: [PATCH 44/84] whitespace: reorganize initial-indent check Reorganize to emphasize the most complicated part of the code (the tab case). Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- ws.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ws.c b/ws.c index 5ebd1095a2..716587498c 100644 --- a/ws.c +++ b/ws.c @@ -146,16 +146,15 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, /* Check for space before tab in initial indent. */ for (i = 0; i < len; i++) { - if (line[i] == '\t') { - if ((ws_rule & WS_SPACE_BEFORE_TAB) && - (leading_space != -1)) - result |= WS_SPACE_BEFORE_TAB; - break; - } - else if (line[i] == ' ') + if (line[i] == ' ') { leading_space = i; - else + continue; + } + if (line[i] != '\t') break; + if ((ws_rule & WS_SPACE_BEFORE_TAB) && (leading_space != -1)) + result |= WS_SPACE_BEFORE_TAB; + break; } /* Check for indent using non-tab. */ From 954ecd435389916643efeb5b1ade82250170c071 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 11:31:39 -0500 Subject: [PATCH 45/84] whitespace: minor cleanup The variable leading_space is initially used to represent the index of the last space seen before a non-space. Then later it represents the index of the first non-indent character. It will prove simpler to replace it by a variable representing a number of bytes. Eventually it will represent the number of bytes written so far (in the stream != NULL case). Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- ws.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/ws.c b/ws.c index 716587498c..1b32e45204 100644 --- a/ws.c +++ b/ws.c @@ -121,7 +121,7 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, const char *reset, const char *ws) { unsigned result = 0; - int leading_space = -1; + int written = 0; int trailing_whitespace = -1; int trailing_newline = 0; int i; @@ -147,18 +147,18 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, /* Check for space before tab in initial indent. */ for (i = 0; i < len; i++) { if (line[i] == ' ') { - leading_space = i; + written = i + 1; continue; } if (line[i] != '\t') break; - if ((ws_rule & WS_SPACE_BEFORE_TAB) && (leading_space != -1)) + if ((ws_rule & WS_SPACE_BEFORE_TAB) && (written != 0)) result |= WS_SPACE_BEFORE_TAB; break; } /* Check for indent using non-tab. */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && leading_space >= 7) + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && written >= 8) result |= WS_INDENT_WITH_NON_TAB; if (stream) { @@ -166,23 +166,20 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, if ((result & WS_SPACE_BEFORE_TAB) || (result & WS_INDENT_WITH_NON_TAB)) { fputs(ws, stream); - fwrite(line, leading_space + 1, 1, stream); + fwrite(line, written, 1, stream); fputs(reset, stream); - leading_space++; } - else - leading_space = 0; - /* Now the rest of the line starts at leading_space. + /* Now the rest of the line starts at written. * The non-highlighted part ends at trailing_whitespace. */ if (trailing_whitespace == -1) trailing_whitespace = len; /* Emit non-highlighted (middle) segment. */ - if (trailing_whitespace - leading_space > 0) { + if (trailing_whitespace - written > 0) { fputs(set, stream); - fwrite(line + leading_space, - trailing_whitespace - leading_space, 1, stream); + fwrite(line + written, + trailing_whitespace - written, 1, stream); fputs(reset, stream); } From 9afa2d4aa9423ab594c7281cc2360df55498a407 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 11:31:40 -0500 Subject: [PATCH 46/84] whitespace: fix initial-indent checking After this patch, "written" counts the number of bytes up to and including the most recently seen tab. This allows us to detect (and count) spaces by comparing to "i". This allows catching initial indents like '\t ' (a tab followed by 8 spaces), while previously indent-with-non-tab caught only indents that consisted entirely of spaces. This also allows fixing an indent-with-non-tab regression, so we can again detect indents like '\t \t'. Also update tests to catch these cases. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- t/t4015-diff-whitespace.sh | 15 +++++++++++++++ ws.c | 10 ++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 0f16bca373..d30169fbdc 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -125,6 +125,14 @@ test_expect_success 'check mixed spaces and tabs in indent' ' ' +test_expect_success 'check mixed tabs and spaces in indent' ' + + # This is indented with HT SP HT. + echo " foo();" > x && + git diff --check | grep "space before tab in indent" + +' + test_expect_success 'check with no whitespace errors' ' git commit -m "snapshot" && @@ -311,4 +319,11 @@ test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' ' +test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + ! git diff --check + +' test_done diff --git a/ws.c b/ws.c index 1b32e45204..aabd50902b 100644 --- a/ws.c +++ b/ws.c @@ -146,19 +146,17 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, /* Check for space before tab in initial indent. */ for (i = 0; i < len; i++) { - if (line[i] == ' ') { - written = i + 1; + if (line[i] == ' ') continue; - } if (line[i] != '\t') break; - if ((ws_rule & WS_SPACE_BEFORE_TAB) && (written != 0)) + if ((ws_rule & WS_SPACE_BEFORE_TAB) && written < i) result |= WS_SPACE_BEFORE_TAB; - break; + written = i + 1; } /* Check for indent using non-tab. */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && written >= 8) + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && i - written >= 8) result |= WS_INDENT_WITH_NON_TAB; if (stream) { From ffe568859ba89b4283afc36251561a9be3173bf8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 11:31:41 -0500 Subject: [PATCH 47/84] whitespace: more accurate initial-indent highlighting Instead of highlighting the entire initial indent, highlight only the problematic spaces. In the case of an indent like ' \t \t' there may be multiple problematic ranges, so it's easiest to emit the highlighting as we go instead of trying rember disjoint ranges and do it all at the end. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- ws.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ws.c b/ws.c index aabd50902b..d09b9df89a 100644 --- a/ws.c +++ b/ws.c @@ -150,24 +150,32 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, continue; if (line[i] != '\t') break; - if ((ws_rule & WS_SPACE_BEFORE_TAB) && written < i) + if ((ws_rule & WS_SPACE_BEFORE_TAB) && written < i) { result |= WS_SPACE_BEFORE_TAB; + if (stream) { + fputs(ws, stream); + fwrite(line + written, i - written, 1, stream); + fputs(reset, stream); + } + } else if (stream) + fwrite(line + written, i - written, 1, stream); + if (stream) + fwrite(line + i, 1, 1, stream); written = i + 1; } /* Check for indent using non-tab. */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && i - written >= 8) + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && i - written >= 8) { result |= WS_INDENT_WITH_NON_TAB; - - if (stream) { - /* Highlight errors in leading whitespace. */ - if ((result & WS_SPACE_BEFORE_TAB) || - (result & WS_INDENT_WITH_NON_TAB)) { + if (stream) { fputs(ws, stream); - fwrite(line, written, 1, stream); + fwrite(line + written, i - written, 1, stream); fputs(reset, stream); } + written = i; + } + if (stream) { /* Now the rest of the line starts at written. * The non-highlighted part ends at trailing_whitespace. */ if (trailing_whitespace == -1) From 127f72e6897d6671725dc13db42ab5ee1d086721 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 11:31:42 -0500 Subject: [PATCH 48/84] whitespace: fix config.txt description of indent-with-non-tab Fix garbled description. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- Documentation/config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index fabe7f859f..ce16fc79eb 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -307,7 +307,7 @@ core.whitespace:: before a tab character in the initial indent part of the line as an error (enabled by default). * `indent-with-non-tab` treats a line that is indented with 8 or more - space characters that can be replaced with tab characters. + space characters as an error (not enabled by default). alias.*:: Command aliases for the gitlink:git[1] command wrapper - e.g. From 079fe1dae8504c988c50ce41eba78743d3f588e0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 16 Dec 2007 13:49:17 -0800 Subject: [PATCH 49/84] Re-re-re-fix common tail optimization We need to be extra careful recovering the removed common section, so that we do not break context nor the changed incomplete line (i.e. the last line that does not end with LF). Signed-off-by: Junio C Hamano --- t/t4024-diff-optimize-common.sh | 69 +++++++++++++++++++++++++++++++++ xdiff-interface.c | 2 +- 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100755 t/t4024-diff-optimize-common.sh diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh new file mode 100755 index 0000000000..20fe87b7dd --- /dev/null +++ b/t/t4024-diff-optimize-common.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +test_description='common tail optimization' + +. ./test-lib.sh + +z=zzzzzzzz ;# 8 +z="$z$z$z$z$z$z$z$z" ;# 64 +z="$z$z$z$z$z$z$z$z" ;# 512 +z="$z$z$z$z" ;# 2048 +z2047=$(expr "$z" : '.\(.*\)') ; #2047 + +test_expect_success setup ' + + echo "a$z2047" >file-a && + echo "b" >file-b && + echo "$z2047" >>file-b && + echo "c$z2047" | tr -d "\012" >file-c && + echo "d" >file-d && + echo "$z2047" | tr -d "\012" >>file-d && + + git add file-a file-b file-c file-d && + + echo "A$z2047" >file-a && + echo "B" >file-b && + echo "$z2047" >>file-b && + echo "C$z2047" | tr -d "\012" >file-c && + echo "D" >file-d && + echo "$z2047" | tr -d "\012" >>file-d + +' + +cat >expect <<\EOF +diff --git a/file-a b/file-a +--- a/file-a ++++ b/file-a +@@ -1 +1 @@ +-aZ ++AZ +diff --git a/file-b b/file-b +--- a/file-b ++++ b/file-b +@@ -1 +1 @@ +-b ++B +diff --git a/file-c b/file-c +--- a/file-c ++++ b/file-c +@@ -1 +1 @@ +-cZ +\ No newline at end of file ++CZ +\ No newline at end of file +diff --git a/file-d b/file-d +--- a/file-d ++++ b/file-d +@@ -1 +1 @@ +-d ++D +EOF + +test_expect_success 'diff -U0' ' + + git diff -U0 | sed -e "/^index/d" -e "s/$z2047/Z/g" >actual && + diff -u expect actual + +' + +test_done diff --git a/xdiff-interface.c b/xdiff-interface.c index 98b02eda35..9ee877c6f4 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -121,7 +121,7 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx) bp -= blk; } - while (recovered < trimmed && ctx) + while (recovered < trimmed && 0 <= ctx) if (ap[recovered++] == '\n') ctx--; a->size -= (trimmed - recovered); From 95f9b92700585eb9afa6978c350dc07ec5769ec6 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 12:58:01 -0500 Subject: [PATCH 50/84] builtin-apply: minor cleanup of whitespace detection Use 0 instead of -1 for the case where not tabs or spaces are found; it will make some later math slightly simpler. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- builtin-apply.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 2edd83bf40..bd94a4bdb0 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1550,8 +1550,8 @@ static int apply_line(char *output, const char *patch, int plen, int i; int add_nl_to_tail = 0; int fixed = 0; - int last_tab_in_indent = -1; - int last_space_in_indent = -1; + int last_tab_in_indent = 0; + int last_space_in_indent = 0; int need_fix_leading_space = 0; char *buf; @@ -1582,12 +1582,12 @@ static int apply_line(char *output, const char *patch, int plen, if (ch == '\t') { last_tab_in_indent = i; if ((ws_rule & WS_SPACE_BEFORE_TAB) && - 0 <= last_space_in_indent) + 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) && - last_tab_in_indent < 0 && + last_tab_in_indent <= 0 && 8 <= i) need_fix_leading_space = 1; } From b90ced0f7da0b8dcdac1aabd8840a23daef25b43 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 16 Dec 2007 12:58:02 -0500 Subject: [PATCH 51/84] builtin-apply: stronger indent-with-on-tab fixing Fix any sequence of 8 spaces in initial indent, not just the case where the 8 spaces are the first thing on the line. Signed-off-by: J. Bruce Fields Signed-off-by: Junio C Hamano --- builtin-apply.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index bd94a4bdb0..5e3b4a1447 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1587,8 +1587,7 @@ static int apply_line(char *output, const char *patch, int plen, } else if (ch == ' ') { last_space_in_indent = i; if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - last_tab_in_indent <= 0 && - 8 <= i) + 8 <= i - last_tab_in_indent) need_fix_leading_space = 1; } else From 1596456309315befb3fd0a985d50a70ed09493e4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 16 Dec 2007 15:03:58 -0800 Subject: [PATCH 52/84] builtin-commit: fix summary output. Because print_summary() forgot to call diff_setup_done() after futzing with diff output options, it failed to activate recursive diff, which resulted in an incorrect summary. Signed-off-by: Junio C Hamano --- builtin-commit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-commit.c b/builtin-commit.c index 518ebe0347..61770ef456 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -662,6 +662,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) rev.show_root_diff = 1; rev.commit_format = get_commit_format("format:%h: %s"); rev.always_show_header = 0; + diff_setup_done(&rev.diffopt); printf("Created %scommit ", initial_commit ? "initial " : ""); From 3eb2a15eb385749fbfe59b4e37fc754416275760 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 16 Dec 2007 15:05:39 -0800 Subject: [PATCH 53/84] builtin-commit: make summary output consistent with status This enables -B -M to the summary output after a commit is made so that it is in line with what is shown in git-status and commit log template. Signed-off-by: Junio C Hamano --- builtin-commit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin-commit.c b/builtin-commit.c index 61770ef456..0a9101324f 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -662,6 +662,9 @@ static void print_summary(const char *prefix, const unsigned char *sha1) rev.show_root_diff = 1; rev.commit_format = get_commit_format("format:%h: %s"); rev.always_show_header = 0; + rev.diffopt.detect_rename = 1; + rev.diffopt.rename_limit = 100; + rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); printf("Created %scommit ", initial_commit ? "initial " : ""); From 50f22ada523f448986dd6273da14a477cea5a646 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Dec 2007 20:45:34 +0100 Subject: [PATCH 54/84] threaded pack-objects: Use condition variables for thread communication. In the threaded pack-objects code the main thread and the worker threads must mutually signal that they have assigned a new pack of work or have completed their work, respectively. Previously, the code used mutexes that were locked in one thread and unlocked from a different thread, which is bogus (and happens to work on Linux). Here we rectify the implementation by using condition variables: There is one condition variable on which the main thread waits until a thread requests new work; and each worker thread has its own condition variable on which it waits until it is assigned new work or signaled to terminate. As a cleanup, the worker threads are spawned only after the initial work packages have been assigned. Signed-off-by: Johannes Sixt Acked-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-pack-objects.c | 131 +++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 51 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 7dd0d7f826..5765d02f54 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1594,6 +1594,15 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, #ifdef THREADED_DELTA_SEARCH +/* + * The main thread waits on the condition that (at least) one of the workers + * has stopped working (which is indicated in the .working member of + * struct thread_params). + * When a work thread has completed its work, it sets .working to 0 and + * signals the main thread and waits on the condition that .data_ready + * becomes 1. + */ + struct thread_params { pthread_t thread; struct object_entry **list; @@ -1601,37 +1610,50 @@ struct thread_params { unsigned remaining; int window; int depth; + int working; + int data_ready; + pthread_mutex_t mutex; + pthread_cond_t cond; unsigned *processed; }; -static pthread_mutex_t data_request = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t data_ready = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t data_provider = PTHREAD_MUTEX_INITIALIZER; -static struct thread_params *data_requester; +static pthread_cond_t progress_cond = PTHREAD_COND_INITIALIZER; static void *threaded_find_deltas(void *arg) { struct thread_params *me = arg; - for (;;) { - pthread_mutex_lock(&data_request); - data_requester = me; - pthread_mutex_unlock(&data_provider); - pthread_mutex_lock(&data_ready); - pthread_mutex_unlock(&data_request); - - if (!me->remaining) - return NULL; - + while (me->remaining) { find_deltas(me->list, &me->remaining, me->window, me->depth, me->processed); + + progress_lock(); + me->working = 0; + pthread_cond_signal(&progress_cond); + progress_unlock(); + + /* + * We must not set ->data_ready before we wait on the + * condition because the main thread may have set it to 1 + * before we get here. In order to be sure that new + * work is available if we see 1 in ->data_ready, it + * was initialized to 0 before this thread was spawned + * and we reset it to 0 right away. + */ + pthread_mutex_lock(&me->mutex); + while (!me->data_ready) + pthread_cond_wait(&me->cond, &me->mutex); + me->data_ready = 0; + pthread_mutex_unlock(&me->mutex); } + /* leave ->working 1 so that this doesn't get more work assigned */ + return NULL; } static void ll_find_deltas(struct object_entry **list, unsigned list_size, int window, int depth, unsigned *processed) { - struct thread_params *target, p[delta_search_threads]; + struct thread_params p[delta_search_threads]; int i, ret, active_threads = 0; if (delta_search_threads <= 1) { @@ -1639,49 +1661,42 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, return; } - pthread_mutex_lock(&data_provider); - pthread_mutex_lock(&data_ready); - - /* Start work threads. */ - for (i = 0; i < delta_search_threads; i++) { - p[i].window = window; - p[i].depth = depth; - p[i].processed = processed; - p[i].remaining = 0; - ret = pthread_create(&p[i].thread, NULL, - threaded_find_deltas, &p[i]); - if (ret) - die("unable to create thread: %s", strerror(ret)); - active_threads++; - } - - /* Then partition the work amongst them. */ + /* Partition the work amongst work threads. */ for (i = 0; i < delta_search_threads; i++) { unsigned sub_size = list_size / (delta_search_threads - i); - pthread_mutex_lock(&data_provider); - target = data_requester; - if (!sub_size) { - pthread_mutex_unlock(&data_ready); - pthread_join(target->thread, NULL); - active_threads--; - continue; - } + p[i].window = window; + p[i].depth = depth; + p[i].processed = processed; + p[i].working = 1; + p[i].data_ready = 0; + pthread_mutex_init(&p[i].mutex, NULL); + pthread_cond_init(&p[i].cond, NULL); /* try to split chunks on "path" boundaries */ while (sub_size < list_size && list[sub_size]->hash && list[sub_size]->hash == list[sub_size-1]->hash) sub_size++; - target->list = list; - target->list_size = sub_size; - target->remaining = sub_size; - pthread_mutex_unlock(&data_ready); + p[i].list = list; + p[i].list_size = sub_size; + p[i].remaining = sub_size; list += sub_size; list_size -= sub_size; } + /* Start work threads. */ + for (i = 0; i < delta_search_threads; i++) { + if (!p[i].list_size) + continue; + ret = pthread_create(&p[i].thread, NULL, + threaded_find_deltas, &p[i]); + if (ret) + die("unable to create thread: %s", strerror(ret)); + active_threads++; + } + /* * Now let's wait for work completion. Each time a thread is done * with its work, we steal half of the remaining work from the @@ -1690,13 +1705,21 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, * until the remaining object list segments are simply too short * to be worth splitting anymore. */ - do { + while (active_threads) { + struct thread_params *target = NULL; struct thread_params *victim = NULL; unsigned sub_size = 0; - pthread_mutex_lock(&data_provider); - target = data_requester; progress_lock(); + for (;;) { + for (i = 0; !target && i < delta_search_threads; i++) + if (!p[i].working) + target = &p[i]; + if (target) + break; + pthread_cond_wait(&progress_cond, &progress_mutex); + } + for (i = 0; i < delta_search_threads; i++) if (p[i].remaining > 2*window && (!victim || victim->remaining < p[i].remaining)) @@ -1723,17 +1746,23 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, victim->list_size -= sub_size; victim->remaining -= sub_size; } - progress_unlock(); - target->list_size = sub_size; target->remaining = sub_size; - pthread_mutex_unlock(&data_ready); + target->working = 1; + progress_unlock(); + + pthread_mutex_lock(&target->mutex); + target->data_ready = 1; + pthread_cond_signal(&target->cond); + pthread_mutex_unlock(&target->mutex); if (!sub_size) { pthread_join(target->thread, NULL); + pthread_cond_destroy(&target->cond); + pthread_mutex_destroy(&target->mutex); active_threads--; } - } while (active_threads); + } } #else From 6fbe42c7ee99b4cafa792b46a16b0158d305fe29 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 16 Dec 2007 22:03:21 -0800 Subject: [PATCH 55/84] Documentation/git-submodule: refer to gitmodules(5) Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 335e973a6a..3f59705686 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -68,7 +68,8 @@ FILES When initializing submodules, a .gitmodules file in the top-level directory of the containing repository is used to find the url of each submodule. This file should be formatted in the same way as $GIR_DIR/config. The key -to each submodule url is "submodule.$name.url". +to each submodule url is "submodule.$name.url". See gitlink:gitmodules[5] +for details. AUTHOR From 6851162adf29762cd121555645214468451a3111 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 17 Dec 2007 07:43:59 -0500 Subject: [PATCH 56/84] clone: correctly report http_fetch errors The exit status from curl was accidentally lost by the 'case' statement. We need to explicitly save it so that $? doesn't get overwritten. This improves the error message when fetching from an http repository which has never had update-server-info run. Previously, it would fail to note the fetch error and produce multiple errors about the lack of origin branches. It now correctly suggests running git-update-server-info. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- git-clone.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 0ea3c24f59..036a37e85c 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -35,11 +35,12 @@ fi http_fetch () { # $1 = Remote, $2 = Local - curl -nsfL $curl_extra_args "$1" >"$2" || - case $? in - 126|127) exit ;; - *) return $? ;; - esac + curl -nsfL $curl_extra_args "$1" >"$2" + curl_exit_status=$? + case $curl_exit_status in + 126|127) exit ;; + *) return $curl_exit_status ;; + esac } clone_dumb_http () { From 4f3d37035a7c735a3b69f962656819f4ff7e4927 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 17 Dec 2007 15:51:34 -0500 Subject: [PATCH 57/84] git-send-email: avoid duplicate message-ids We used to unconditionally add a message-id to the outgoing email without bothering to check if it already had one. Instead, let's use the existing one. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- git-send-email.perl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index b03297c9d7..e8354c760b 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -527,7 +527,7 @@ sub send_message $ccline = "\nCc: $cc"; } my $sanitized_sender = sanitize_address($sender); - make_message_id(); + make_message_id() unless defined($message_id); my $header = "From: $sanitized_sender To: $to${ccline} @@ -643,6 +643,9 @@ foreach my $t (@files) { } push @xh, $_; } + elsif (/^Message-Id: (.*)/i) { + $message_id = $1; + } elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) { push @xh, $_; } @@ -728,6 +731,7 @@ foreach my $t (@files) { $references = "$message_id"; } } + $message_id = undef; } if ($compose) { From 68e6a4f80d4bea2d281c30fa2bbcd4968b0ccc4e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 17 Dec 2007 20:12:52 +0100 Subject: [PATCH 58/84] Plug a resource leak in threaded pack-objects code. A mutex and a condition variable is allocated for each thread and torn down when the thread terminates. However, for certain workloads it can happen that some threads are actually not started at all. In this case we would leak the mutex and condition variable. Now we allocate them only for those threads that are actually started. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- builtin-pack-objects.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 5765d02f54..e0ce114be7 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1670,8 +1670,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, p[i].processed = processed; p[i].working = 1; p[i].data_ready = 0; - pthread_mutex_init(&p[i].mutex, NULL); - pthread_cond_init(&p[i].cond, NULL); /* try to split chunks on "path" boundaries */ while (sub_size < list_size && list[sub_size]->hash && @@ -1690,6 +1688,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, for (i = 0; i < delta_search_threads; i++) { if (!p[i].list_size) continue; + pthread_mutex_init(&p[i].mutex, NULL); + pthread_cond_init(&p[i].cond, NULL); ret = pthread_create(&p[i].thread, NULL, threaded_find_deltas, &p[i]); if (ret) From 3175b0cfc1392de1ff00c01796f85b92df317cc8 Mon Sep 17 00:00:00 2001 From: "H.Merijn Brand" Date: Mon, 17 Dec 2007 23:28:46 +0100 Subject: [PATCH 59/84] the use of 'tr' in the test suite isn't really portable Some versions of 'tr' only accept octal codes if entered with three digits, and therefor misinterpret the '\0' in the test suite. Some versions of 'tr' reject the (needless) use of character classes. Signed-off-by: H.Merijn Brand Signed-off-by: Junio C Hamano --- git-filter-branch.sh | 2 +- t/diff-lib.sh | 4 ++-- t/t0020-crlf.sh | 2 +- t/t1300-repo-config.sh | 4 ++-- t/t3300-funny-names.sh | 6 +++--- t/t4020-diff-external.sh | 2 +- t/t4103-apply-binary.sh | 4 ++-- t/t4116-apply-reverse.sh | 4 ++-- t/t4200-rerere.sh | 2 +- t/t5300-pack-object.sh | 2 +- test-sha1.sh | 4 ++-- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 29d35fd27c..3bb2f676bd 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -290,7 +290,7 @@ while read commit parents; do eval "$filter_tree" < /dev/null || die "tree filter failed: $filter_tree" - git diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \ + git diff-index -r $commit | cut -f 2- | tr '\n' '\000' | \ xargs -0 git update-index --add --replace --remove git ls-files -z --others | \ xargs -0 git update-index --add --replace --remove diff --git a/t/diff-lib.sh b/t/diff-lib.sh index 4624fe654c..7dc6d7eb1e 100644 --- a/t/diff-lib.sh +++ b/t/diff-lib.sh @@ -21,8 +21,8 @@ compare_diff_raw_z () { # Also we do not check SHA1 hash generation in this test, which # is a job for t0000-basic.sh - tr '\0' '\012' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1 - tr '\0' '\012' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2 + tr '\000' '\012' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1 + tr '\000' '\012' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2 git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 } diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 62bc4bb077..89baebdfa6 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -5,7 +5,7 @@ test_description='CRLF conversion' . ./test-lib.sh q_to_nul () { - tr Q '\0' + tr Q '\000' } append_cr () { diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 1d2bf2c060..e894629e7e 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -591,12 +591,12 @@ Qsection.sub=section.val4 Qsection.sub=section.val5Q EOF -git config --null --list | tr '[\000]' 'Q' > result +git config --null --list | tr '\000' 'Q' > result echo >>result test_expect_success '--null --list' 'cmp result expect' -git config --null --get-regexp 'val[0-9]' | tr '[\000]' 'Q' > result +git config --null --get-regexp 'val[0-9]' | tr '\000' 'Q' > result echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index dc8c369310..98c133db50 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -54,7 +54,7 @@ echo 'just space no-funny tabs ," (dq) and spaces' >expected test_expect_success 'git ls-files -z with-funny' \ - 'git ls-files -z | tr \\0 \\012 >current && + 'git ls-files -z | tr \\000 \\012 >current && git diff expected current' t1=`git write-tree` @@ -83,11 +83,11 @@ test_expect_success 'git diff-tree with-funny' \ echo 'A tabs ," (dq) and spaces' >expected test_expect_success 'git diff-index -z with-funny' \ - 'git diff-index -z --name-status $t0 | tr \\0 \\012 >current && + 'git diff-index -z --name-status $t0 | tr \\000 \\012 >current && git diff expected current' test_expect_success 'git diff-tree -z with-funny' \ - 'git diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current && + 'git diff-tree -z --name-status $t0 $t1 | tr \\000 \\012 >current && git diff expected current' cat > expected <<\EOF diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index ed3bd5b3fe..888293361d 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -99,7 +99,7 @@ test_expect_success 'no diff with -diff' ' git diff | grep Binary ' -echo NULZbetweenZwords | tr Z '\0' > file +echo NULZbetweenZwords | tr Z '\000' > file test_expect_success 'force diff with "diff"' ' echo >.gitattributes "file diff" && diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index 011126f336..74f06ec730 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -24,10 +24,10 @@ git update-index --add --remove file1 file2 file4 git-commit -m 'Initial Version' 2>/dev/null git-checkout -b binary -tr 'x' '\0' file3 +tr 'x' '\000' file3 cat file3 >file4 git add file2 -tr '\0' 'v' file1 +tr '\000' 'v' file1 rm -f file2 git update-index --add --remove file1 file2 file3 file4 git-commit -m 'Second Version' diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 9ae2b3a8ef..b1d35ab04d 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -12,14 +12,14 @@ test_description='git apply in reverse test_expect_success setup ' for i in a b c d e f g h i j k l m n; do echo $i; done >file1 && - tr "[ijk]" '\''[\0\1\2]'\'' file2 && + tr "ijk" '\''\000\001\002'\'' file2 && git add file1 file2 && git commit -m initial && git tag initial && for i in a b c g h i J K L m o n p q; do echo $i; done >file1 && - tr "[mon]" '\''[\0\1\2]'\'' file2 && + tr "mon" '\''\000\001\002'\'' file2 && git commit -a -m second && git tag second && diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index cfcdb69dc8..eeff3c9c07 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -129,7 +129,7 @@ test_expect_success 'rerere kicked in' "! grep ======= a1" test_expect_success 'rerere prefers first change' 'git diff a1 expect' rm $rr/postimage -echo "$sha1 a1" | tr '\012' '\0' > .git/rr-cache/MERGE_RR +echo "$sha1 a1" | tr '\012' '\000' > .git/rr-cache/MERGE_RR test_expect_success 'rerere clear' 'git rerere clear' diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index f1106e6542..6e594bf1e2 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -15,7 +15,7 @@ test_expect_success \ 'rm -f .git/index* for i in a b c do - dd if=/dev/zero bs=4k count=1 | tr "\\0" $i >$i && + dd if=/dev/zero bs=4k count=1 | tr "\\000" $i >$i && git update-index --add $i || return 1 done && cat c >d && echo foo >>d && git update-index --add d && diff --git a/test-sha1.sh b/test-sha1.sh index 640856af5a..bf526c8f5e 100755 --- a/test-sha1.sh +++ b/test-sha1.sh @@ -10,7 +10,7 @@ do { test -z "$pfx" || echo "$pfx" dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | - tr '[\0]' '[g]' + tr '\000' 'g' } | ./test-sha1 $cnt ` if test "$expect" = "$actual" @@ -55,7 +55,7 @@ do { test -z "$pfx" || echo "$pfx" dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | - tr '[\0]' '[g]' + tr '\000' 'g' } | sha1sum | sed -e 's/ .*//' ` From 5f48741a5a47643bf1b46ba1d23688f2ef8b1216 Mon Sep 17 00:00:00 2001 From: Sam Vilain Date: Tue, 18 Dec 2007 01:00:43 +1300 Subject: [PATCH 60/84] Clarify error response from 'git fetch' for bad responses This error message prints the reponse from the server at this point. Label it as such in the output. Signed-off-by: Sam Vilain Signed-off-by: Junio C Hamano --- walker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/walker.c b/walker.c index 397b80de9e..adc3e80ce1 100644 --- a/walker.c +++ b/walker.c @@ -274,7 +274,7 @@ int walker_fetch(struct walker *walker, int targets, char **target, for (i = 0; i < targets; i++) { if (interpret_target(walker, target[i], &sha1[20 * i])) { - error("Could not interpret %s as something to pull", target[i]); + error("Could not interpret response from server '%s' as something to pull", target[i]); goto unlock_and_fail; } if (process(walker, lookup_unknown_object(&sha1[20 * i]))) From f029427259c97af9ea98358866e1d28974fa4da5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 17 Dec 2007 10:08:23 +0100 Subject: [PATCH 61/84] Clean up documentation that references deprecated 'git peek-remote'. Now that 'git peek-remote' is deprecated and only an alias for 'git ls-remote', it should not be referenced from other manual pages. This also removes the description of the --exec option, which is no longer present. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Documentation/git-daemon.txt | 6 +++--- Documentation/git-ls-remote.txt | 2 +- Documentation/git-peek-remote.txt | 3 --- Documentation/git-show-ref.txt | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index 99e47c9c25..f1e48dd021 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -31,8 +31,8 @@ pass some directory paths as 'git-daemon' arguments, you can further restrict the offers to a whitelist comprising of those. By default, only `upload-pack` service is enabled, which serves -`git-fetch-pack` and `git-peek-remote` clients that are invoked -from `git-fetch`, `git-ls-remote`, and `git-clone`. +`git-fetch-pack` and `git-ls-remote` clients, which are invoked +from `git-fetch`, `git-pull`, and `git-clone`. This is ideally suited for read-only updates, i.e., pulling from git repositories. @@ -166,7 +166,7 @@ the per-repository configuration file can be used to enable or disable them. upload-pack:: - This serves `git-fetch-pack` and `git-peek-remote` + This serves `git-fetch-pack` and `git-ls-remote` clients. It is enabled by default, but a repository can disable it by setting `daemon.uploadpack` configuration item to `false`. diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index 93e9a60330..445bedaa95 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -30,7 +30,7 @@ OPTIONS Specify the full path of gitlink:git-upload-pack[1] on the remote host. This allows listing references from repositories accessed via SSH and where the SSH daemon does not use the PATH configured by the - user. Also see the '--exec' option for gitlink:git-peek-remote[1]. + user. :: Location of the repository. The shorthand defined in diff --git a/Documentation/git-peek-remote.txt b/Documentation/git-peek-remote.txt index 38a5325af7..09b005b10f 100644 --- a/Documentation/git-peek-remote.txt +++ b/Documentation/git-peek-remote.txt @@ -28,9 +28,6 @@ OPTIONS shells, but prefer having a lean .bashrc file (they set most of the things up in .bash_profile). -\--exec=:: - Same \--upload-pack=. - :: A remote host that houses the repository. When this part is specified, 'git-upload-pack' is invoked via diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt index 2355aa5e86..7893a50886 100644 --- a/Documentation/git-show-ref.txt +++ b/Documentation/git-show-ref.txt @@ -160,7 +160,7 @@ to get a listing of all tags together with what they dereference. SEE ALSO -------- -gitlink:git-ls-remote[1], gitlink:git-peek-remote[1] +gitlink:git-ls-remote[1] AUTHORS ------- From cbe021004fc8762076bf497cc0b259d110b3a753 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 17 Dec 2007 13:42:20 +0000 Subject: [PATCH 62/84] Support config variable diff.external We had the diff.external variable in the documentation of the config file since its conception, but failed to respect it. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/diff.c b/diff.c index 08ec66c794..e26584cdfc 100644 --- a/diff.c +++ b/diff.c @@ -20,6 +20,7 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 100; static int diff_use_color_default; +static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static char diff_colors[][COLOR_MAXLEN] = { @@ -163,6 +164,10 @@ int git_diff_ui_config(const char *var, const char *value) diff_auto_refresh_index = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.external")) { + external_diff_cmd_cfg = xstrdup(value); + return 0; + } if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); @@ -209,6 +214,8 @@ static const char *external_diff(void) if (done_preparing) return external_diff_cmd; external_diff_cmd = getenv("GIT_EXTERNAL_DIFF"); + if (!external_diff_cmd) + external_diff_cmd = external_diff_cmd_cfg; done_preparing = 1; return external_diff_cmd; } From 77680caadb939cf47fd08447b81faadc7c3bd436 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 17 Dec 2007 12:21:22 +0000 Subject: [PATCH 63/84] Document diff.external and mergetool..path There was no documentation for the config variables diff.external and mergetool..path. Noticed by Sebastian Schuberth. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/config.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index ce16fc79eb..8a0df5736e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -448,6 +448,13 @@ diff.autorefreshindex:: affects only `git diff` Porcelain, and not lower level `diff` commands, such as `git diff-files`. +diff.external:: + If this config variable is set, diff generation is not + performed using the internal diff machinery, but using the + given command. Note: if you want to use an external diff + program only on a subset of your files, you might want to + use gitlink:gitattributes[5] instead. + diff.renameLimit:: The number of files to consider when performing the copy/rename detection; equivalent to the git diff option '-l'. @@ -671,6 +678,10 @@ merge..recursive:: performing an internal merge between common ancestors. See gitlink:gitattributes[5] for details. +mergetool..path:: + Override the path for the given tool. This is useful in case + your tool is not in the PATH. + pack.window:: The size of the window used by gitlink:git-pack-objects[1] when no window size is given on the command line. Defaults to 10. From 34454e858d2a648b0a6ce56acd9def84bd2a8712 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 17 Dec 2007 21:01:25 +0000 Subject: [PATCH 64/84] rebase -p -i: handle "no changes" gracefully Since commit 376ccb8cbb453343998e734d8a1ce79f57a4e092 (rebase -i: style fixes and minor cleanups), unchanged SHA-1s are no longer mapped via $REWRITTEN. But the updating phase was not prepared for the old head not being rewritten. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 7 ++++++- t/t3404-rebase-interactive.sh | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f83e00fe8f..cd7e43faeb 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -322,7 +322,12 @@ do_next () { test -f "$DOTEST"/current-commit && current_commit=$(cat "$DOTEST"/current-commit) && git rev-parse HEAD > "$REWRITTEN"/$current_commit - NEWHEAD=$(cat "$REWRITTEN"/$OLDHEAD) + if test -f "$REWRITTEN"/$OLDHEAD + then + NEWHEAD=$(cat "$REWRITTEN"/$OLDHEAD) + else + NEWHEAD=$OLDHEAD + fi else NEWHEAD=$(git rev-parse HEAD) fi && diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 907c7f9f6b..74a7eb30f8 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -184,6 +184,12 @@ test_expect_success 'retain authorship when squashing' ' git show HEAD | grep "^Author: Twerp Snog" ' +test_expect_success '-p handles "no changes" gracefully' ' + HEAD=$(git rev-parse HEAD) && + git rebase -i -p HEAD^ && + test $HEAD = $(git rev-parse HEAD) +' + test_expect_success 'preserve merges with -p' ' git checkout -b to-be-preserved master^ && : > unrelated-file && From f9c5a80cdf2265f2df7712fad9f1fb7ef68b4768 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Tue, 18 Dec 2007 02:39:57 +0100 Subject: [PATCH 65/84] Fix segfault in diff-delta.c when FLEX_ARRAY is 1 aka don't do pointer arithmetics on structs that have a FLEX_ARRAY member, or you'll end up believing your array is 1 cell off its real address. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- diff-delta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff-delta.c b/diff-delta.c index 9e440a9299..601b49e37f 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -264,7 +264,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) index->src_size = bufsize; index->hash_mask = hmask; - mem = index + 1; + mem = index->hash; packed_hash = mem; mem = packed_hash + (hsize+1); packed_entry = mem; From f2fdd10ab76feb0e141fc3f9cf4e5efd87f7fcdf Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 17 Dec 2007 22:12:03 -0800 Subject: [PATCH 66/84] unpack-trees: FLEX_ARRAY fix In unpack-trees.c (line 593), we do .. if (same(old, merge)) { *merge = *old; } else { .. and that "merge" is a cache_entry pointer. If we have a non-zero FLEX_ARRAY size, it will cause us to copy the first few bytes of the name too. That is technically wrong even for FLEX_ARRAY being 1, but you'll never notice, since the filenames should always be the same with the current code. But if we do the same thing for a rename, we'd be screwed. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- unpack-trees.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpack-trees.c b/unpack-trees.c index e9eb795d64..aa2513ed79 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -590,7 +590,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, * a match. */ if (same(old, merge)) { - *merge = *old; + memcpy(merge, old, offsetof(struct cache_entry, name)); } else { verify_uptodate(old, o); invalidate_ce_path(old); From 4808ab8f87551967d61fc4f4164e2f99e2fa4d71 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 18 Dec 2007 01:46:04 -0800 Subject: [PATCH 67/84] builtin-blame.c: remove unneeded memclr() Signed-off-by: Junio C Hamano --- builtin-blame.c | 1 - 1 file changed, 1 deletion(-) diff --git a/builtin-blame.c b/builtin-blame.c index 99ea0a02cb..d98caaf217 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -125,7 +125,6 @@ static void origin_decref(struct origin *o) if (o && --o->refcnt <= 0) { if (o->file.ptr) free(o->file.ptr); - memset(o, 0, sizeof(*o)); free(o); } } From 02ff62504e12cb1925a59b6956508dc70984c5b4 Mon Sep 17 00:00:00 2001 From: Ralf Wildenhues Date: Tue, 18 Dec 2007 07:07:36 +0100 Subject: [PATCH 68/84] Fix some documentation typos. Signed-off-by: Ralf Wildenhues Signed-off-by: Junio C Hamano --- Documentation/config.txt | 2 +- Documentation/git-help.txt | 8 ++++---- Documentation/git-init.txt | 2 +- Documentation/git-rev-list.txt | 2 +- Documentation/git-send-email.txt | 2 +- Documentation/git.txt | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 8a0df5736e..ee0884545b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -476,7 +476,7 @@ fetch.unpackLimit:: format.numbered:: A boolean which can enable sequence numbers in patch subjects. - Seting this option to "auto" will enable it only if there is + Setting this option to "auto" will enable it only if there is more than one patch. See --numbered option in gitlink:git-format-patch[1]. diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index da3f71850a..a8ffcbe78b 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -21,7 +21,7 @@ printed on the standard output. If a git command is named, a manual page for that command is brought up. The 'man' program is used by default for this purpose, but this -can be overriden by other options or configuration variables. +can be overridden by other options or configuration variables. Note that 'git --help ...' is identical as 'git help ...' because the former is internally converted into the latter. @@ -30,7 +30,7 @@ OPTIONS ------- -a|--all:: Prints all the available commands on the standard output. This - option superseeds any other option. + option supersedes any other option. -i|--info:: Use the 'info' program to display the manual page, instead of @@ -50,7 +50,7 @@ The web browser can be specified using the configuration variable these config variables is set, the 'git-help--browse' helper script (called by 'git-help') will pick a suitable default. + -You can explicitly provide a full path to your prefered browser by +You can explicitly provide a full path to your preferred browser by setting the configuration variable 'browser..path'. For example, you can configure the absolute path to firefox by setting 'browser.firefox.path'. Otherwise, 'git-help--browse' assumes the tool @@ -72,7 +72,7 @@ line option: * "web" or "html" correspond to '-w|--web', The 'help.browser', 'web.browser' and 'browser..path' will also -be checked if the 'web' format is choosen (either by command line +be checked if the 'web' format is chosen (either by command line option or configuration variable). See '-w|--web' in the OPTIONS section above. diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt index 07484a4fd0..e51351dd53 100644 --- a/Documentation/git-init.txt +++ b/Documentation/git-init.txt @@ -52,7 +52,7 @@ is given: - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository readable by all users. -By default, the configuration flag receive.denyNonFastforward is enabled +By default, the configuration flag receive.denyNonFastForwards is enabled in shared repositories, so that you cannot force a non fast-forwarding push into it. diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 989fbf3562..a03f9fe5fa 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -274,7 +274,7 @@ limiting may be applied. --quiet:: Don't print anything to standard output. This form of - git-rev-list is primarly meant to allow the caller to + git-rev-list is primarily meant to allow the caller to test the exit status to see if a range of objects is fully connected (or not). It is faster than redirecting stdout to /dev/null as the output does not have to be formatted. diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 659215ac72..f0bd2851d8 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -148,7 +148,7 @@ sendemail.identity:: 'sendemail..' will have higher precedence than 'sendemail.'. This is useful to declare multiple SMTP identities and to hoist sensitive authentication information - out of the repository and into the global configuation file. + out of the repository and into the global configuration file. sendemail.aliasesfile:: To avoid typing long email addresses, point this to one or more diff --git a/Documentation/git.txt b/Documentation/git.txt index e0f9a4490c..37235b993d 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -502,7 +502,7 @@ as tags and branch heads. The object database contains objects of three main types: blobs, which hold file data; trees, which point to blobs and other trees to build up -directory heirarchies; and commits, which each reference a single tree +directory hierarchies; and commits, which each reference a single tree and some number of parent commits. The commit, equivalent to what other systems call a "changeset" or @@ -522,7 +522,7 @@ efficiency may later be compressed together into "pack files". Named pointers called refs mark interesting points in history. A ref may contain the SHA1 name of an object or the name of another ref. Refs with names beginning `ref/head/` contain the SHA1 name of the most -recent commit (or "head") of a branch under developement. SHA1 names of +recent commit (or "head") of a branch under development. SHA1 names of tags of interest are stored under `ref/tags/`. A special ref named `HEAD` contains the name of the currently checked-out branch. From 91c3aced4c9b961e162f9acd706f4b03a85aed2c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Dec 2007 08:30:47 +0100 Subject: [PATCH 69/84] filter-branch: Remove broken and unnecessary summary of rewritten refs. There was an attempt to list the refs that were rewritten by filtering the output of 'git show-ref' for 'refs/original'. But it got the grep argument wrong, which did not account for the SHA1 that is listed before the ref. Moreover, right before this summary is the loop that actually does the rewriting, and the rewritten refs are listed there anyway. So this extra summary is plainly too verbose. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- git-filter-branch.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 3bb2f676bd..7f52b591a3 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -342,7 +342,6 @@ done < "$tempdir"/heads _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" -count=0 echo while read ref do @@ -380,7 +379,6 @@ do ;; esac git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1 - count=$(($count+1)) done < "$tempdir"/heads # TODO: This should possibly go, with the semantics that all positive given @@ -423,9 +421,6 @@ fi cd ../.. rm -rf "$tempdir" -echo -test $count -gt 0 && echo "These refs were rewritten:" -git show-ref | grep ^"$orig_namespace" unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE test -z "$ORIG_GIT_DIR" || GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR From e8a3f90994067a154fafcec9bbb18cf7865cd94c Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Tue, 18 Dec 2007 11:03:23 +0100 Subject: [PATCH 70/84] git-filter-branch.sh: more portable tr usage: use \012, not \n. I hesitate to suggest this, since GNU tr has accepted \n for 15 years, but there are supposedly a few crufty vendor-supplied versions of tr still in use. Also, all of the other uses of tr-with-newline in git use \012. Signed-off-by: Jim Meyering Signed-off-by: Junio C Hamano --- git-filter-branch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 7f52b591a3..ae29f47e41 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -290,7 +290,7 @@ while read commit parents; do eval "$filter_tree" < /dev/null || die "tree filter failed: $filter_tree" - git diff-index -r $commit | cut -f 2- | tr '\n' '\000' | \ + git diff-index -r $commit | cut -f 2- | tr '\012' '\000' | \ xargs -0 git update-index --add --replace --remove git ls-files -z --others | \ xargs -0 git update-index --add --replace --remove From ce85b053d827e2f7c2ee2683cc09393e4768cc22 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 18 Dec 2007 10:15:39 -0500 Subject: [PATCH 71/84] fix style of a few comments in diff-delta.c Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- diff-delta.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/diff-delta.c b/diff-delta.c index 601b49e37f..a4e28df714 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -212,11 +212,24 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) if (hash_count[i] <= HASH_LIMIT) continue; - entries -= hash_count[i] - HASH_LIMIT; /* We leave exactly HASH_LIMIT entries in the bucket */ + entries -= hash_count[i] - HASH_LIMIT; entry = hash[i]; acc = 0; + + /* + * Assume that this loop is gone through exactly + * HASH_LIMIT times and is entered and left with + * acc==0. So the first statement in the loop + * contributes (hash_count[i]-HASH_LIMIT)*HASH_LIMIT + * to the accumulator, and the inner loop consequently + * is run (hash_count[i]-HASH_LIMIT) times, removing + * one element from the list each time. Since acc + * balances out to 0 at the final run, the inner loop + * body can't be left with entry==NULL. So we indeed + * encounter entry==NULL in the outer loop only. + */ do { acc += hash_count[i] - HASH_LIMIT; if (acc > 0) { @@ -229,30 +242,17 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) } entry = entry->next; } while (entry); - - /* Assume that this loop is gone through exactly - * HASH_LIMIT times and is entered and left with - * acc==0. So the first statement in the loop - * contributes (hash_count[i]-HASH_LIMIT)*HASH_LIMIT - * to the accumulator, and the inner loop consequently - * is run (hash_count[i]-HASH_LIMIT) times, removing - * one element from the list each time. Since acc - * balances out to 0 at the final run, the inner loop - * body can't be left with entry==NULL. So we indeed - * encounter entry==NULL in the outer loop only. - */ } free(hash_count); - /* Now create the packed index in array form rather than - * linked lists */ - + /* + * Now create the packed index in array form + * rather than linked lists. + */ memsize = sizeof(*index) + sizeof(*packed_hash) * (hsize+1) + sizeof(*packed_entry) * entries; - mem = malloc(memsize); - if (!mem) { free(hash); return NULL; @@ -269,19 +269,19 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) mem = packed_hash + (hsize+1); packed_entry = mem; - /* Coalesce all entries belonging to one linked list into - * consecutive array entries */ - for (i = 0; i < hsize; i++) { + /* + * Coalesce all entries belonging to one linked list + * into consecutive array entries. + */ packed_hash[i] = packed_entry; for (entry = hash[i]; entry; entry = entry->next) *packed_entry++ = entry->entry; } - /* Sentinel value to indicate the length of the last hash - * bucket */ - + /* Sentinel value to indicate the length of the last hash bucket */ packed_hash[hsize] = packed_entry; + assert(packed_entry - (struct index_entry *)mem == entries); free(hash); From ad94802a7bc599ade73ec0b04c61b2f80b3c1b23 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 15 Dec 2007 19:08:22 -0800 Subject: [PATCH 72/84] git-svn: avoid leaving leftover committer/author info in rebase We set the 6 environment variables for controlling committer/author email/name/time for every commit. We do this in the parent process to be passed to git-commit-tree, because open3() doesn't afford us the control of doing it only in the child process. This means we leave them hanging around in the main process until the next revision comes around and all 6 environment variables are overwridden again. Unfortunately, for the last commit, leaving them hanging around means the git-rebase invocation will pick it up, rewriting the rebased commit with incorrect author information. This should fix it. Signed-off-by: Eric Wong --- git-svn.perl | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index d411a34317..7cd62fc5c4 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2052,6 +2052,43 @@ sub full_url { $self->{url} . (length $self->{path} ? '/' . $self->{path} : ''); } + +sub set_commit_header_env { + my ($log_entry) = @_; + my %env; + foreach my $ned (qw/NAME EMAIL DATE/) { + foreach my $ac (qw/AUTHOR COMMITTER/) { + $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"}; + } + } + + $ENV{GIT_AUTHOR_NAME} = $log_entry->{name}; + $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email}; + $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date}; + + $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name}) + ? $log_entry->{commit_name} + : $log_entry->{name}; + $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email}) + ? $log_entry->{commit_email} + : $log_entry->{email}; + \%env; +} + +sub restore_commit_header_env { + my ($env) = @_; + foreach my $ned (qw/NAME EMAIL DATE/) { + foreach my $ac (qw/AUTHOR COMMITTER/) { + my $k = "GIT_${ac}_${ned}"; + if (defined $env->{$k}) { + $ENV{$k} = $env->{$k}; + } else { + delete $ENV{$k}; + } + } + } +} + sub do_git_commit { my ($self, $log_entry) = @_; my $lr = $self->last_rev; @@ -2064,17 +2101,7 @@ sub do_git_commit { croak "$log_entry->{revision} = $c already exists! ", "Why are we refetching it?\n"; } - $ENV{GIT_AUTHOR_NAME} = $log_entry->{name}; - $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email}; - $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date}; - - $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name}) - ? $log_entry->{commit_name} - : $log_entry->{name}; - $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email}) - ? $log_entry->{commit_email} - : $log_entry->{email}; - + my $old_env = set_commit_header_env($log_entry); my $tree = $log_entry->{tree}; if (!defined $tree) { $tree = $self->tmp_index_do(sub { @@ -2089,6 +2116,7 @@ sub do_git_commit { defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) or croak $!; print $msg_fh $log_entry->{log} or croak $!; + restore_commit_header_env($old_env); unless ($self->no_metadata) { print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n" or croak $!; From 7fc35e0e94782bbbefb920875813519038659930 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 19 Dec 2007 00:06:45 -0800 Subject: [PATCH 73/84] git-svn: workaround a for broken symlinks in SVN It's possible for bad clients to commit symlinks without the 5-character "link " prefix in symlinks. So guard around this bug in SVN and make a best effort to create symlinks if the "link " prefix is missing. More information on this SVN bug is described here: http://subversion.tigris.org/issues/show_bug.cgi?id=2692 To be pedantic, there is still a corner case that neither we nor SVN can handle: If somebody made a link using a broken SVN client where "link " is the first part of its path, e.g. "link sausage", then we'd end up having a symlink which points to "sausage" because we incorrectly stripped the "link ". Hopefully this hasn't happened in practice, but if it has, it's not our fault SVN is broken :) Thanks to Benoit Sigoure and Sverre Johansen for reporting and feedback. Signed-off-by: Eric Wong --- git-svn.perl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 7cd62fc5c4..41fedf5979 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3177,9 +3177,15 @@ sub close_file { } sysseek($fh, 0, 0) or croak $!; if ($fb->{mode_b} == 120000) { - sysread($fh, my $buf, 5) == 5 or croak $!; - $buf eq 'link ' or die "$path has mode 120000", - "but is not a link\n"; + eval { + sysread($fh, my $buf, 5) == 5 or croak $!; + $buf eq 'link ' or die "$path has mode 120000", + " but is not a link"; + }; + if ($@) { + warn "$@\n"; + sysseek($fh, 0, 0) or croak $!; + } } defined(my $pid = open my $out,'-|') or die "Can't fork: $!\n"; if (!$pid) { From 540424b263d626aa762757a31ca9b4becc7fb513 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 19 Dec 2007 00:31:43 -0800 Subject: [PATCH 74/84] git-svn: avoid warning when run without arguments While we're in the area, finish writing a halfway-written comment describing what that block does... Signed-off-by: Eric Wong --- git-svn.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 41fedf5979..c51f1e7391 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -197,8 +197,8 @@ for (my $i = 0; $i < @ARGV; $i++) { } }; -# make sure we're always running -unless ($cmd =~ /(?:clone|init|multi-init)$/) { +# make sure we're always running at the top-level working directory +unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) { unless (-d $ENV{GIT_DIR}) { if ($git_dir_user_set) { die "GIT_DIR=$ENV{GIT_DIR} explicitly set, ", From 56122ed87af181c88e3121795c292689ac574f01 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 18 Dec 2007 18:01:33 +0000 Subject: [PATCH 75/84] git show : show the tagger For commit objects, the Author is shown, so do the equivalent for tag objects, too. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-log.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index cc3cc9069a..dcc9f81793 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -244,7 +244,28 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix) return cmd_log_walk(&rev); } -static int show_object(const unsigned char *sha1, int suppress_header) +static void show_tagger(char *buf, int len, struct rev_info *rev) +{ + char *email_end, *p; + unsigned long date; + int tz; + + email_end = memchr(buf, '>', len); + if (!email_end) + return; + p = ++email_end; + while (isspace(*p)) + p++; + date = strtoul(p, &p, 10); + while (isspace(*p)) + p++; + tz = (int)strtol(p, NULL, 10); + printf("Tagger: %.*s\nDate: %s\n", (int)(email_end - buf), buf, + show_date(date, tz, rev->date_mode)); +} + +static int show_object(const unsigned char *sha1, int show_tag_object, + struct rev_info *rev) { unsigned long size; enum object_type type; @@ -254,11 +275,14 @@ static int show_object(const unsigned char *sha1, int suppress_header) if (!buf) return error("Could not read object %s", sha1_to_hex(sha1)); - if (suppress_header) - while (offset < size && buf[offset++] != '\n') { - int new_offset = offset; + if (show_tag_object) + while (offset < size && buf[offset] != '\n') { + int new_offset = offset + 1; while (new_offset < size && buf[new_offset++] != '\n') ; /* do nothing */ + if (!prefixcmp(buf + offset, "tagger ")) + show_tagger(buf + offset + 7, + new_offset - offset - 7, rev); offset = new_offset; } @@ -299,16 +323,16 @@ int cmd_show(int argc, const char **argv, const char *prefix) const char *name = objects[i].name; switch (o->type) { case OBJ_BLOB: - ret = show_object(o->sha1, 0); + ret = show_object(o->sha1, 0, NULL); break; case OBJ_TAG: { struct tag *t = (struct tag *)o; - printf("%stag %s%s\n\n", + printf("%stag %s%s\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), t->tag, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); - ret = show_object(o->sha1, 1); + ret = show_object(o->sha1, 1, &rev); objects[i].item = (struct object *)t->tagged; i--; break; From 9d81e03b5ca4e3841d56e6e57ff2b8100202ed6f Mon Sep 17 00:00:00 2001 From: Marco Roeland Date: Wed, 19 Dec 2007 10:15:15 +0100 Subject: [PATCH 76/84] clone: fix options '-o' and '--origin' to be recognised again Due to a subtle typo in a shell case pattern neither alternative worked. Signed-off-by: Marco Roeland Signed-off-by: Junio C Hamano --- git-clone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-clone.sh b/git-clone.sh index 9a160eea52..b4e858c388 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -152,7 +152,7 @@ do die "clones are always made with separate-remote layout" ;; --reference) shift; reference="$1" ;; - -o,--origin) + -o|--origin) shift; case "$1" in '') From ecaa0cff44577700400903aa47eb0e99a135e423 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 19 Dec 2007 10:43:50 -0500 Subject: [PATCH 77/84] test "git clone -o" This tests a recently fixed regression in which "git clone -o" didn't work at all. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t5702-clone-options.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 t/t5702-clone-options.sh diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh new file mode 100755 index 0000000000..328e4d9a33 --- /dev/null +++ b/t/t5702-clone-options.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +test_description='basic clone options' +. ./test-lib.sh + +test_expect_success 'setup' ' + + mkdir parent && + (cd parent && git init && + echo one >file && git add file && + git commit -m one) + +' + +test_expect_success 'clone -o' ' + + git clone -o foo parent clone-o && + (cd clone-o && git rev-parse --verify refs/remotes/foo/master) + +' + +test_done From c5699693638d0471bf74425238d802d2bc9e8c0f Mon Sep 17 00:00:00 2001 From: Charles Bailey Date: Wed, 19 Dec 2007 12:25:27 +0000 Subject: [PATCH 78/84] Fix git-instaweb breakage on MacOS X due to the limited sed functionality git-instaweb relied on a pipe in a sed script, but this is not supported by MacOS X sed when using BREs. git-instaweb relies on a working perl in any case, and perl re are more consistent between platforms, so replace sed invocation with an equivalent perl invocation. Also, fix the documented -b "" to work without giving a spurious 'command not found' error. Signed-off-by: Charles Bailey Signed-off-by: Junio C Hamano --- Makefile | 1 + git-instaweb.sh | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 617e5f5a4b..d6d3d65b1b 100644 --- a/Makefile +++ b/Makefile @@ -880,6 +880,7 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css -e '/@@GITWEB_CGI@@/d' \ -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \ -e '/@@GITWEB_CSS@@/d' \ + -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ $@.sh > $@+ && \ chmod +x $@+ && \ mv $@+ $@ diff --git a/git-instaweb.sh b/git-instaweb.sh index 42d8d7fc6e..ad0723ccc6 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -3,6 +3,7 @@ # Copyright (c) 2006 Eric Wong # +PERL='@@PERL@@' OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ git-instaweb [options] (--start | --stop | --restart) @@ -232,16 +233,18 @@ EOF } script=' -s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'$(dirname "$fqgitdir")'";# -s#\(my\|our\) $gitbin =.*#\1 $gitbin = "'$GIT_EXEC_PATH'";# -s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;# -s#\(my\|our\) $git_temp =.*#\1 $git_temp = "'$fqgitdir/gitweb/tmp'";#' +s#^(my|our) \$projectroot =.*#$1 \$projectroot = "'$(dirname "$fqgitdir")'";#; +s#(my|our) \$gitbin =.*#$1 \$gitbin = "'$GIT_EXEC_PATH'";#; +s#(my|our) \$projects_list =.*#$1 \$projects_list = \$projectroot;#; +s#(my|our) \$git_temp =.*#$1 \$git_temp = "'$fqgitdir/gitweb/tmp'";#;' gitweb_cgi () { cat > "$1.tmp" <<\EOFGITWEB @@GITWEB_CGI@@ EOFGITWEB - sed "$script" "$1.tmp" > "$1" + # Use the configured full path to perl to match the generated + # scripts' 'hashpling' line + "$PERL" -p -e "$script" "$1.tmp" > "$1" chmod +x "$1" rm -f "$1.tmp" } @@ -273,4 +276,4 @@ esac start_httpd url=http://127.0.0.1:$port -"$browser" $url || echo $url +test -n "$browser" && "$browser" $url || echo $url From 3f7701a4db4c26d37e804dc4cdd6641677ea97e8 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 19 Dec 2007 12:53:16 -0500 Subject: [PATCH 79/84] make 'git describe --all --contains' work Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-describe.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/builtin-describe.c b/builtin-describe.c index 6eeb9b5045..7a148a2c26 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -267,12 +267,14 @@ int cmd_describe(int argc, const char **argv, const char *prefix) if (contains) { const char **args = xmalloc((4 + argc) * sizeof(char*)); - args[0] = "name-rev"; - args[1] = "--name-only"; - args[2] = "--tags"; - memcpy(args + 3, argv, argc * sizeof(char*)); - args[3 + argc] = NULL; - return cmd_name_rev(3 + argc, args, prefix); + int i = 0; + args[i++] = "name-rev"; + args[i++] = "--name-only"; + if (!all) + args[i++] = "--tags"; + memcpy(args + i, argv, argc * sizeof(char*)); + args[i + argc] = NULL; + return cmd_name_rev(i + argc, args, prefix); } if (argc == 0) { From 5909651ea2be69932d9b739b4441ca857ced7660 Mon Sep 17 00:00:00 2001 From: Sean Date: Wed, 19 Dec 2007 16:34:27 -0500 Subject: [PATCH 80/84] Fix interactive rebase to preserve author email address Signed-off-by: Sean Estabrooks Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index cd7e43faeb..7153ac7877 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -371,7 +371,7 @@ do . "$DOTEST"/author-script && { test ! -f "$DOTEST"/amend || git reset --soft HEAD^ } && - export GIT_AUTHOR_NAME GIT_AUTHOR_NAME GIT_AUTHOR_DATE && + export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE && git commit -F "$DOTEST"/message -e require_clean_work_tree From 20b178de7b20a0ebf02b8da3b4791c06fc8e3a63 Mon Sep 17 00:00:00 2001 From: Finn Arne Gangstad Date: Tue, 18 Dec 2007 20:50:28 +0100 Subject: [PATCH 81/84] Improved submodule merge support When merging conflicting submodule changes from a supermodule, generate a conflict message saying what went wrong. Also leave the tree in a state where git status shows the conflict, and git submodule status gives the user enough information to do the merge manally. Previously this would just fail. Signed-off-by: Finn Arne Gangstad Signed-off-by: Junio C Hamano --- merge-recursive.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/merge-recursive.c b/merge-recursive.c index 2a58dad3f4..33ccc40ecd 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -549,6 +549,10 @@ static void update_file_flags(const unsigned char *sha, void *buf; unsigned long size; + if (S_ISGITLINK(mode)) + die("cannot read object %s '%s': It is a submodule!", + sha1_to_hex(sha), path); + buf = read_sha1_file(sha, &type, &size); if (!buf) die("cannot read object %s '%s'", sha1_to_hex(sha), path); @@ -1463,10 +1467,13 @@ static int process_entry(const char *path, struct stage_data *entry, mfi = merge_file(&o, &a, &b, branch1, branch2); + clean_merge = mfi.clean; if (mfi.clean) update_file(1, mfi.sha, mfi.mode, path); + else if (S_ISGITLINK(mfi.mode)) + output(1, "CONFLICT (submodule): Merge conflict in %s " + "- needs %s", path, sha1_to_hex(b.sha1)); else { - clean_merge = 0; output(1, "CONFLICT (%s): Merge conflict in %s", reason, path); From c5b09feb786f6a2456ec3d8203d0f4d67f09f043 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Dec 2007 01:41:26 -0500 Subject: [PATCH 82/84] Avoid update hook during git-rebase --interactive If we are rebasing changes that contain potential whitespace errors that our .git/hooks/pre-commit hook looks for and fails on then git-commit will fail to commit that change. This causes git-rebase--interactive to squash commits together, even though it was not requested to do so by the todo file. Passing --no-verify to git-commit makes git-rebase -i behave more like git-rebase normally would in such conditions, providing more consistent behavior between the different rebase implementations. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 7153ac7877..fa9c11f173 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -296,7 +296,7 @@ do_next () { 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 + $USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT ;; t) cp "$MSG" "$GIT_DIR"/MERGE_MSG @@ -372,7 +372,7 @@ do test ! -f "$DOTEST"/amend || git reset --soft HEAD^ } && export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE && - git commit -F "$DOTEST"/message -e + git commit --no-verify -F "$DOTEST"/message -e require_clean_work_tree do_rest From dbedf9729bd349c7667630d50728214ed531f74d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Dec 2007 01:45:00 -0500 Subject: [PATCH 83/84] Catch and handle git-commit failures in git-rebase --interactive If git-commit fails for any reason then git-rebase needs to stop and not plow through the rest of the series. Its unlikely that a future git-commit will succeed if the current attempt failed. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index fa9c11f173..47581ced5a 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -289,22 +289,22 @@ do_next () { output git reset --soft HEAD^ pick_one -n $sha1 || failed=t echo "$author_script" > "$DOTEST"/author-script - case $failed in - f) + if test $failed = f + then # This is like --amend, but with a different message eval "$author_script" GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \ GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \ GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \ - $USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT - ;; - t) + $USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT || failed=t + fi + if test $failed = t + then cp "$MSG" "$GIT_DIR"/MERGE_MSG warn warn "Could not apply $sha1... $rest" die_with_patch $sha1 "" - ;; - esac + fi ;; *) warn "Unknown command: $command $sha1 $rest" @@ -372,7 +372,8 @@ do test ! -f "$DOTEST"/amend || git reset --soft HEAD^ } && export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE && - git commit --no-verify -F "$DOTEST"/message -e + git commit --no-verify -F "$DOTEST"/message -e || + die "Could not commit staged changes." require_clean_work_tree do_rest From 74f6b03c5c8fceef416de9f9a18e5d64712b6d96 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 19 Dec 2007 17:21:04 -0800 Subject: [PATCH 84/84] GIT 1.5.4-rc1 It's been a week since -rc0, and we have quite a lot of fixes, so here it is. Signed-off-by: Junio C Hamano --- .mailmap | 1 + Documentation/RelNotes-1.5.4.txt | 28 +++++++++++++++++++--------- GIT-VERSION-GEN | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/.mailmap b/.mailmap index 1f729c223c..695739ea70 100644 --- a/.mailmap +++ b/.mailmap @@ -25,6 +25,7 @@ Karl Hasselström Kent Engstrom Lars Doelle Lars Doelle +Li Hong Lukas Sandström Martin Langhoff Michael Coleman diff --git a/Documentation/RelNotes-1.5.4.txt b/Documentation/RelNotes-1.5.4.txt index 89e6fe32b8..cd79124958 100644 --- a/Documentation/RelNotes-1.5.4.txt +++ b/Documentation/RelNotes-1.5.4.txt @@ -14,11 +14,10 @@ Removal Deprecation notices ------------------- - * Next feature release of git (this change is scheduled for v1.5.5 but - it could slip) will by default install dashed form of commands - (e.g. "git-commit") outside of users' normal $PATH, and will install - only selected commands ("git" itself, and "gitk") in $PATH. This - implies: + * Next feature release of git (this change is scheduled for v1.6.0) + will by default install dashed form of commands (e.g. "git-commit") + outside of users' normal $PATH, and will install only selected + commands ("git" itself, and "gitk") in $PATH. This implies: - Using dashed form of git commands (e.g. "git-commit") from the command line has been informally deprecated since early 2006, but @@ -38,7 +37,7 @@ Deprecation notices * The post-receive hook was introduced in March 2007 to supersede post-update hook, primarily to overcome the command line length limitation of the latter. Use of post-update hook will be deprecated - in future versions of git, perhaps in v1.5.5. + in future versions of git, starting from v1.6.0. * "git lost-found" was deprecated in favor of "git fsck"'s --lost-found option, and will be removed in the future. @@ -46,12 +45,12 @@ Deprecation notices * "git peek-remote" is deprecated, as "git ls-remote" was written in C and works for all transports, and will be removed in the future. - * From v1.5.5, the repack.usedeltabaseoffset config option will default + * From v1.6.0, the repack.usedeltabaseoffset config option will default to true, which will give denser packfile (i.e. more efficient storage). The downside is that git older than version 1.4.4 will not be able to directly use a repository packed using this setting. - * From v1.5.5, the pack.indexversion config option will default to 2, + * From v1.6.0, the pack.indexversion config option will default to 2, which is slightly more efficient, and makes repacking more immune to data corruptions. Git older than version 1.5.2 may revert to version 1 of the pack index with a manual "git index-pack" to be able to directly @@ -88,6 +87,9 @@ Updates since v1.5.3 mean "always" (even when the output is not going to a terminal). This has been corrected to mean the same thing as "auto". + * "git diff" Porcelain now respects diff.external configuration, which + is another way to specify GIT_EXTERNAL_DIFF. + * HTTP proxy can be specified per remote repository using remote.*.httpproxy configuration, or global http.proxy configuration variable. @@ -112,6 +114,8 @@ Updates since v1.5.3 * "git rebase --interactive" mode can now work on detached HEAD. + * Other minor to serious bugs in "git rebase -i" has been fixed. + * "git rebase" now detaches head during its operation, so after a successful "git rebase" operation, the reflog entry branch@{1} for the current branch points at the commit before the rebase was @@ -238,6 +242,12 @@ Updates since v1.5.3 "git commit"; the parameters to -m options are formatted as separate paragraphs. + * The format "git show" outputs an annotated tag has been updated to + include "Tagger: " and "Date: " lines from the tag itself. Strictly + speaking this is a backward incompatible change, but this is a + reasonable usability fix and people's script shouldn't have been + relying on the exact output from "git show" Porcelain anyway. + * "git cvsexportcommit" learned -w option to specify and switch to the CVS working directory. @@ -314,6 +324,6 @@ series. -- exec >/var/tmp/1 -O=v1.5.4-rc0-35-g530e741 +O=v1.5.4-rc0-85-gdbedf97 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 eaf5abf1a7..ad7e056620 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.4-rc0.GIT +DEF_VER=v1.5.4-rc1.GIT LF=' '