From: Junio C Hamano Date: Sun, 4 Jun 2006 07:01:52 +0000 (-0700) Subject: Merge branch 'vb/sendemail' into next X-Git-Tag: v1.4.1-rc1~40 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/f63237a18e951b93ac46a0e594f286255e1eaaaf?ds=inline;hp=-c Merge branch 'vb/sendemail' into next * vb/sendemail: Cleanup git-send-email.perl:extract_valid_email read-tree --reset: update working tree file for conflicted paths. Documentation: Spelling fixes Builtin git-rev-parse. fetch: do not report "same" unless -verbose. --- f63237a18e951b93ac46a0e594f286255e1eaaaf diff --combined Documentation/git-read-tree.txt index 1f21d95684,02c7e99fe6..1c01d00df2 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@@ -8,7 -8,7 +8,7 @@@ git-read-tree - Reads tree information SYNOPSIS -------- -'git-read-tree' ( | [[-m [--aggressive]| --reset] [-u | -i]] [ []]) +'git-read-tree' ( | [[-m [--aggressive] | --reset | --prefix=] [-u | -i]] [ []]) DESCRIPTION @@@ -63,15 -63,6 +63,15 @@@ OPTION * when both sides adds a path identically. The resolution is to add that path. +--prefix=/:: + Keep the current index contents, and read the contents + of named tree-ish under directory at ``. The + original index file cannot have anything at the path + `` itself, and have nothing in `/` + directory. Note that the `/` value must end + with a slash. + + :: The id of the tree object(s) to be read/merged. @@@ -214,7 -205,7 +214,7 @@@ The `git-write-tree` command refuses t will complain about unmerged entries if it sees a single entry that is not stage 0. - Ok, this all sounds like a collection of totally nonsensical rules, + OK, this all sounds like a collection of totally nonsensical rules, but it's actually exactly what you want in order to do a fast merge. The different stages represent the "result tree" (stage 0, aka "merged"), the original tree (stage 1, aka "orig"), and the two trees @@@ -235,7 -226,7 +235,7 @@@ populated. Here is an outline of how t - the index file saves and restores with all this information, so you can merge things incrementally, but as long as it has entries in - stages 1/2/3 (ie "unmerged entries") you can't write the result. So + stages 1/2/3 (i.e., "unmerged entries") you can't write the result. So now the merge algorithm ends up being really simple: * you walk the index in order, and ignore all entries of stage 0, diff --combined builtin-read-tree.c index 0c6ba3d8a5,085e11e7c4..cc61c2d813 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@@ -24,7 -24,6 +24,7 @@@ static int trivial_merges_only = 0 static int aggressive = 0; static int verbose_update = 0; static volatile int progress_update = 0; +static const char *prefix = NULL; static int head_idx = -1; static int merge_size = 0; @@@ -412,8 -411,7 +412,8 @@@ static int unpack_trees(merge_fn_t fn posns[i] = create_tree_entry_list((struct tree *) posn->item); posn = posn->next; } - if (unpack_trees_rec(posns, len, "", fn, &indpos)) + if (unpack_trees_rec(posns, len, prefix ? prefix : "", + fn, &indpos)) return -1; } @@@ -762,28 -760,6 +762,28 @@@ static int twoway_merge(struct cache_en return deleted_entry(oldtree, current); } +/* + * Bind merge. + * + * Keep the index entries at stage0, collapse stage1 but make sure + * stage0 does not have anything there. + */ +static int bind_merge(struct cache_entry **src) +{ + struct cache_entry *old = src[0]; + struct cache_entry *a = src[1]; + + if (merge_size != 1) + return error("Cannot do a bind merge of %d trees\n", + merge_size); + if (a && old) + die("Entry '%s' overlaps. Cannot bind.", a->name); + if (!a) + return keep_entry(old); + else + return merged_entry(a, NULL); +} + /* * One-way merge. * @@@ -799,10 -775,8 +799,10 @@@ static int oneway_merge(struct cache_en return error("Cannot do a oneway merge of %d trees", merge_size); - if (!a) + if (!a) { + invalidate_ce_path(old); return deleted_entry(old, old); + } if (old && same(old, a)) { if (reset) { struct stat st; @@@ -817,25 -791,26 +817,26 @@@ static int read_cache_unmerged(void) { - int i, deleted; + int i; struct cache_entry **dst; + struct cache_entry *last = NULL; read_cache(); dst = active_cache; - deleted = 0; for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) { - deleted++; + if (last && !strcmp(ce->name, last->name)) + continue; invalidate_ce_path(ce); - continue; + last = ce; + ce->ce_mode = 0; + ce->ce_flags &= ~htons(CE_STAGEMASK); } - if (deleted) - *dst = ce; - dst++; + *dst++ = ce; } - active_nr -= deleted; - return deleted; + active_nr = dst - active_cache; + return !!last; } static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) @@@ -875,7 -850,7 +876,7 @@@ static void prime_cache_tree(void } -static const char read_tree_usage[] = "git-read-tree ( | -m [--aggressive] [-u | -i] [ []])"; +static const char read_tree_usage[] = "git-read-tree ( | [[-m [--aggressive] | --reset | --prefix=] [-u | -i]] [ []])"; static struct cache_file cache_file; @@@ -920,24 -895,12 +921,27 @@@ int cmd_read_tree(int argc, const char continue; } + /* "--prefix=/" means keep the current index + * entries and put the entries from the tree under the + * given subdirectory. + */ + if (!strncmp(arg, "--prefix=", 9)) { + if (stage || merge || prefix) + usage(read_tree_usage); + prefix = arg + 9; + merge = 1; + stage = 1; + if (read_cache_unmerged()) + die("you need to resolve your current index first"); + continue; + } + - /* This differs from "-m" in that we'll silently ignore unmerged entries */ + /* This differs from "-m" in that we'll silently ignore + * unmerged entries and overwrite working tree files that + * correspond to them. + */ if (!strcmp(arg, "--reset")) { - if (stage || merge) + if (stage || merge || prefix) usage(read_tree_usage); reset = 1; merge = 1; @@@ -958,7 -921,7 +962,7 @@@ /* "-m" stands for "merge", meaning we start in stage 1 */ if (!strcmp(arg, "-m")) { - if (stage || merge) + if (stage || merge || prefix) usage(read_tree_usage); if (read_cache_unmerged()) die("you need to resolve your current index first"); @@@ -980,31 -943,12 +984,31 @@@ if ((update||index_only) && !merge) usage(read_tree_usage); + if (prefix) { + int pfxlen = strlen(prefix); + int pos; + if (prefix[pfxlen-1] != '/') + die("prefix must end with /"); + if (stage != 2) + die("binding merge takes only one tree"); + pos = cache_name_pos(prefix, pfxlen); + if (0 <= pos) + die("corrupt index file"); + pos = -pos-1; + if (pos < active_nr && + !strncmp(active_cache[pos]->name, prefix, pfxlen)) + die("subdirectory '%s' already exists.", prefix); + pos = cache_name_pos(prefix, pfxlen-1); + if (0 <= pos) + die("file '%.*s' already exists.", pfxlen-1, prefix); + } + if (merge) { if (stage < 2) die("just how do you expect me to merge %d trees?", stage-1); switch (stage - 1) { case 1: - fn = oneway_merge; + fn = prefix ? bind_merge : oneway_merge; break; case 2: fn = twoway_merge;