diff options
98 files changed, 1446 insertions, 625 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index 2b0efe7921..6dbe45b506 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -46,6 +46,7 @@ all: html man html: $(DOC_HTML) +$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN7): asciidoc.conf man: man1 man7 man1: $(DOC_MAN1) diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index 7ce71510de..8196d787ab 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -9,6 +9,8 @@ [attributes] caret=^ +startsb=[ +endsb=] ifdef::backend-docbook[] [gitlink-inlinemacro] diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 4d8a2ad2d7..8520b97111 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -207,7 +207,7 @@ An exclude pattern is of the following format: An example: -------------------------------------------------------------- - $ cat .git/ignore + $ cat .git/info/exclude # ignore objects and archives, anywhere in the tree. *.[oa] $ cat Documentation/.gitignore @@ -217,7 +217,7 @@ An example: !foo.html $ git-ls-files --ignored \ --exclude='Documentation/*.[0-9]' \ - --exclude-from=.git/ignore \ + --exclude-from=.git/info/exclude \ --exclude-per-directory=.gitignore -------------------------------------------------------------- diff --git a/Documentation/git.txt b/Documentation/git.txt index d00cc3ea52..ce3058182f 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -615,6 +615,13 @@ git Diffs gitlink:git-diff-files[1]; gitlink:git-diff-tree[1] +other +~~~~~ +'GIT_TRACE':: + If this variable is set git will print `trace:` messages on + stderr telling about alias expansion, built-in command + execution and external command execution. + Discussion[[Discussion]] ------------------------ include::README[] diff --git a/Documentation/repository-layout.txt b/Documentation/repository-layout.txt index b52dfdc308..275d18bb54 100644 --- a/Documentation/repository-layout.txt +++ b/Documentation/repository-layout.txt @@ -120,9 +120,11 @@ info/grafts:: info/exclude:: This file, by convention among Porcelains, stores the - exclude pattern list. `git status` looks at it, but - otherwise it is not looked at by any of the core git - commands. + exclude pattern list. `.gitignore` is the per-directory + ignore file. `git status`, `git add`, `git rm` and `git + clean` look at it but the core git commands do not look + at it. See also: gitlink:git-ls-files[1] `--exclude-from` + and `--exclude-per-directory`. remotes:: Stores shorthands to be used to give URL and default diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 9abec806d9..26ecba53fb 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -10,20 +10,21 @@ to name the remote repository: - https://host.xz/path/to/repo.git/ - git://host.xz/path/to/repo.git/ - git://host.xz/~user/path/to/repo.git/ -- ssh://[user@]host.xz/path/to/repo.git/ -- ssh://[user@]host.xz/~user/path/to/repo.git/ -- ssh://[user@]host.xz/~/path/to/repo.git +- ssh://{startsb}user@{endsb}host.xz/path/to/repo.git/ +- ssh://{startsb}user@{endsb}host.xz/~user/path/to/repo.git/ +- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git =============================================================== -SSH Is the default transport protocol and also supports an -scp-like syntax. Both syntaxes support username expansion, +SSH is the default transport protocol. You can optionally specify +which user to log-in as, and an alternate, scp-like syntax is also +supported. Both syntaxes support username expansion, as does the native git protocol. The following three are identical to the last three above, respectively: =============================================================== -- host.xz:/path/to/repo.git/ -- host.xz:~user/path/to/repo.git/ -- host.xz:path/to/repo.git +- {startsb}user@{endsb}host.xz:/path/to/repo.git/ +- {startsb}user@{endsb}host.xz:~user/path/to/repo.git/ +- {startsb}user@{endsb}host.xz:path/to/repo.git =============================================================== To sync with a local directory, use: @@ -124,7 +124,7 @@ SCRIPT_SH = \ git-fetch.sh \ git-ls-remote.sh \ git-merge-one-file.sh git-parse-remote.sh \ - git-prune.sh git-pull.sh git-rebase.sh \ + git-pull.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ git-resolve.sh git-revert.sh git-sh-setup.sh \ git-tag.sh git-verify-tag.sh \ @@ -178,7 +178,7 @@ BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \ git-read-tree$X git-commit-tree$X git-write-tree$X \ git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \ git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \ - git-fmt-merge-msg$X + git-fmt-merge-msg$X git-prune$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@ -222,7 +222,7 @@ LIB_OBJS = \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ - alloc.o $(DIFF_OBJS) + alloc.o merge-file.o $(DIFF_OBJS) BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ @@ -234,7 +234,7 @@ BUILTIN_OBJS = \ builtin-apply.o builtin-show-branch.o builtin-diff-files.o \ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \ - builtin-update-ref.o builtin-fmt-merge-msg.o + builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@ -10,12 +10,12 @@ struct blob *lookup_blob(const unsigned char *sha1) if (!obj) { struct blob *ret = alloc_blob_node(); created_object(sha1, &ret->object); - ret->object.type = TYPE_BLOB; + ret->object.type = OBJ_BLOB; return ret; } if (!obj->type) - obj->type = TYPE_BLOB; - if (obj->type != TYPE_BLOB) { + obj->type = OBJ_BLOB; + if (obj->type != OBJ_BLOB) { error("Object %s is a %s, not a blob", sha1_to_hex(sha1), typename(obj->type)); return NULL; diff --git a/builtin-diff.c b/builtin-diff.c index ae901dd25e..cb38f44561 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -285,9 +285,9 @@ int cmd_diff(int argc, const char **argv, char **envp) obj = deref_tag(obj, NULL, 0); if (!obj) die("invalid object '%s' given.", name); - if (obj->type == TYPE_COMMIT) + if (obj->type == OBJ_COMMIT) obj = &((struct commit *)obj)->tree->object; - if (obj->type == TYPE_TREE) { + if (obj->type == OBJ_TREE) { if (ARRAY_SIZE(ent) <= ents) die("more than %d trees given: '%s'", (int) ARRAY_SIZE(ent), name); @@ -297,7 +297,7 @@ int cmd_diff(int argc, const char **argv, char **envp) ents++; continue; } - if (obj->type == TYPE_BLOB) { + if (obj->type == OBJ_BLOB) { if (2 <= blobs) die("more than two blobs given: '%s'", name); memcpy(blob[blobs].sha1, obj->sha1, 20); diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index 65274824d3..f20b27b8a9 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -76,6 +76,7 @@ static int handle_line(char *line) unsigned char *sha1; char *src, *origin; struct src_data *src_data; + int pulling_head = 0; if (len < 43 || line[40] != '\t') return 1; @@ -101,8 +102,11 @@ static int handle_line(char *line) if (src) { *src = 0; src += 4; - } else - src = "HEAD"; + pulling_head = 0; + } else { + src = line; + pulling_head = 1; + } i = find_in_list(&srcs, src); if (i < 0) { @@ -112,7 +116,10 @@ static int handle_line(char *line) } src_data = srcs.payload[i]; - if (!strncmp(line, "branch ", 7)) { + if (pulling_head) { + origin = strdup(src); + src_data->head_status |= 1; + } else if (!strncmp(line, "branch ", 7)) { origin = strdup(line + 7); append_to_list(&src_data->branch, origin, NULL); src_data->head_status |= 2; @@ -124,9 +131,6 @@ static int handle_line(char *line) origin = strdup(line + 14); append_to_list(&src_data->r_branch, origin, NULL); src_data->head_status |= 2; - } else if (!strcmp(line, "HEAD")) { - origin = strdup(src); - src_data->head_status |= 1; } else { origin = strdup(src); append_to_list(&src_data->generic, strdup(line), NULL); @@ -177,7 +181,7 @@ static void shortlog(const char *name, unsigned char *sha1, int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED; branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40); - if (!branch || branch->type != TYPE_COMMIT) + if (!branch || branch->type != OBJ_COMMIT) return; setup_revisions(0, NULL, rev, NULL); diff --git a/builtin-grep.c b/builtin-grep.c index 4c2f7dfe03..a79bac305a 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -891,9 +891,9 @@ static int grep_tree(struct grep_opt *opt, const char **paths, static int grep_object(struct grep_opt *opt, const char **paths, struct object *obj, const char *name) { - if (obj->type == TYPE_BLOB) + if (obj->type == OBJ_BLOB) return grep_sha1(opt, obj->sha1, name); - if (obj->type == TYPE_COMMIT || obj->type == TYPE_TREE) { + if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) { struct tree_desc tree; void *data; int hit; diff --git a/builtin-prune.c b/builtin-prune.c new file mode 100644 index 0000000000..d196c41f13 --- /dev/null +++ b/builtin-prune.c @@ -0,0 +1,259 @@ +#include "cache.h" +#include "refs.h" +#include "tag.h" +#include "commit.h" +#include "tree.h" +#include "blob.h" +#include "tree-walk.h" +#include "diff.h" +#include "revision.h" +#include "builtin.h" +#include "cache-tree.h" + +static const char prune_usage[] = "git prune [-n]"; +static int show_only = 0; +static struct rev_info revs; + +static int prune_object(char *path, const char *filename, const unsigned char *sha1) +{ + if (show_only) { + printf("would prune %s/%s\n", path, filename); + return 0; + } + unlink(mkpath("%s/%s", path, filename)); + rmdir(path); + return 0; +} + +static int prune_dir(int i, char *path) +{ + DIR *dir = opendir(path); + struct dirent *de; + + if (!dir) + return 0; + + while ((de = readdir(dir)) != NULL) { + char name[100]; + unsigned char sha1[20]; + int len = strlen(de->d_name); + + switch (len) { + case 2: + if (de->d_name[1] != '.') + break; + case 1: + if (de->d_name[0] != '.') + break; + continue; + case 38: + sprintf(name, "%02x", i); + memcpy(name+2, de->d_name, len+1); + if (get_sha1_hex(name, sha1) < 0) + break; + + /* + * Do we know about this object? + * It must have been reachable + */ + if (lookup_object(sha1)) + continue; + + prune_object(path, de->d_name, sha1); + continue; + } + fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); + } + closedir(dir); + return 0; +} + +static void prune_object_dir(const char *path) +{ + int i; + for (i = 0; i < 256; i++) { + static char dir[4096]; + sprintf(dir, "%s/%02x", path, i); + prune_dir(i, dir); + } +} + +static void process_blob(struct blob *blob, + struct object_array *p, + struct name_path *path, + const char *name) +{ + struct object *obj = &blob->object; + + if (obj->flags & SEEN) + return; + obj->flags |= SEEN; + /* Nothing to do, really .. The blob lookup was the important part */ +} + +static void process_tree(struct tree *tree, + struct object_array *p, + struct name_path *path, + const char *name) +{ + struct object *obj = &tree->object; + struct tree_desc desc; + struct name_entry entry; + struct name_path me; + + if (obj->flags & SEEN) + return; + obj->flags |= SEEN; + if (parse_tree(tree) < 0) + die("bad tree object %s", sha1_to_hex(obj->sha1)); + name = strdup(name); + add_object(obj, p, path, name); + me.up = path; + me.elem = name; + me.elem_len = strlen(name); + + desc.buf = tree->buffer; + desc.size = tree->size; + + while (tree_entry(&desc, &entry)) { + if (S_ISDIR(entry.mode)) + process_tree(lookup_tree(entry.sha1), p, &me, entry.path); + else + process_blob(lookup_blob(entry.sha1), p, &me, entry.path); + } + free(tree->buffer); + tree->buffer = NULL; +} + +static void process_tag(struct tag *tag, struct object_array *p, const char *name) +{ + struct object *obj = &tag->object; + struct name_path me; + + if (obj->flags & SEEN) + return; + obj->flags |= SEEN; + + me.up = NULL; + me.elem = "tag:/"; + me.elem_len = 5; + + if (parse_tag(tag) < 0) + die("bad tag object %s", sha1_to_hex(obj->sha1)); + add_object(tag->tagged, p, NULL, name); +} + +static void walk_commit_list(struct rev_info *revs) +{ + int i; + struct commit *commit; + struct object_array objects = { 0, 0, NULL }; + + /* Walk all commits, process their trees */ + while ((commit = get_revision(revs)) != NULL) + process_tree(commit->tree, &objects, NULL, ""); + + /* Then walk all the pending objects, recursively processing them too */ + for (i = 0; i < revs->pending.nr; i++) { + struct object_array_entry *pending = revs->pending.objects + i; + struct object *obj = pending->item; + const char *name = pending->name; + if (obj->type == OBJ_TAG) { + process_tag((struct tag *) obj, &objects, name); + continue; + } + if (obj->type == OBJ_TREE) { + process_tree((struct tree *)obj, &objects, NULL, name); + continue; + } + if (obj->type == OBJ_BLOB) { + process_blob((struct blob *)obj, &objects, NULL, name); + continue; + } + die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); + } +} + +static int add_one_ref(const char *path, const unsigned char *sha1) +{ + struct object *object = parse_object(sha1); + if (!object) + die("bad object ref: %s:%s", path, sha1_to_hex(sha1)); + add_pending_object(&revs, object, ""); + return 0; +} + +static void add_one_tree(const unsigned char *sha1) +{ + struct tree *tree = lookup_tree(sha1); + add_pending_object(&revs, &tree->object, ""); +} + +static void add_cache_tree(struct cache_tree *it) +{ + int i; + + if (it->entry_count >= 0) + add_one_tree(it->sha1); + for (i = 0; i < it->subtree_nr; i++) + add_cache_tree(it->down[i]->cache_tree); +} + +static void add_cache_refs(void) +{ + int i; + + read_cache(); + for (i = 0; i < active_nr; i++) { + lookup_blob(active_cache[i]->sha1); + /* + * We could add the blobs to the pending list, but quite + * frankly, we don't care. Once we've looked them up, and + * added them as objects, we've really done everything + * there is to do for a blob + */ + } + if (active_cache_tree) + add_cache_tree(active_cache_tree); +} + +int cmd_prune(int argc, const char **argv, char **envp) +{ + int i; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (!strcmp(arg, "-n")) { + show_only = 1; + continue; + } + usage(prune_usage); + } + + /* + * Set up revision parsing, and mark us as being interested + * in all object types, not just commits. + */ + init_revisions(&revs); + revs.tag_objects = 1; + revs.blob_objects = 1; + revs.tree_objects = 1; + + /* Add all external refs */ + for_each_ref(add_one_ref); + + /* Add all refs from the index file */ + add_cache_refs(); + + /* + * Set up the revision walk - this will move all commits + * from the pending list to the commit walking list. + */ + prepare_revision_walk(&revs); + + walk_commit_list(&revs); + + prune_object_dir(get_object_directory()); + + return 0; +} diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 63bad0e96a..8f32871337 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -167,16 +167,16 @@ static void show_commit_list(struct rev_info *revs) const char *name = pending->name; if (obj->flags & (UNINTERESTING | SEEN)) continue; - if (obj->type == TYPE_TAG) { + if (obj->type == OBJ_TAG) { obj->flags |= SEEN; add_object_array(obj, name, &objects); continue; } - if (obj->type == TYPE_TREE) { + if (obj->type == OBJ_TREE) { process_tree((struct tree *)obj, &objects, NULL, name); continue; } - if (obj->type == TYPE_BLOB) { + if (obj->type == OBJ_BLOB) { process_blob((struct blob *)obj, &objects, NULL, name); continue; } diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 260cb221b9..3d240ca435 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -172,7 +172,7 @@ static void name_commits(struct commit_list *list, static int mark_seen(struct commit *commit, struct commit_list **seen_p) { if (!commit->object.flags) { - insert_by_date(commit, seen_p); + commit_list_insert(commit, seen_p); return 1; } return 0; @@ -218,9 +218,8 @@ static void join_revs(struct commit_list **list_p, * Postprocess to complete well-poisoning. * * At this point we have all the commits we have seen in - * seen_p list (which happens to be sorted chronologically but - * it does not really matter). Mark anything that can be - * reached from uninteresting commits not interesting. + * seen_p list. Mark anything that can be reached from + * uninteresting commits not interesting. */ for (;;) { int changed = 0; @@ -701,6 +700,8 @@ int cmd_show_branch(int ac, const char **av, char **envp) if (0 <= extra) join_revs(&list, &seen, num_rev, extra); + sort_by_date(&seen); + if (merge_base) return show_merge_base(seen, num_rev); @@ -25,6 +25,8 @@ extern int cmd_diff(int argc, const char **argv, char **envp); extern int cmd_format_patch(int argc, const char **argv, char **envp); extern int cmd_count_objects(int argc, const char **argv, char **envp); +extern int cmd_prune(int argc, const char **argv, char **envp); + extern int cmd_push(int argc, const char **argv, char **envp); extern int cmd_grep(int argc, const char **argv, char **envp); extern int cmd_rm(int argc, const char **argv, char **envp); @@ -56,7 +56,7 @@ static struct commit *check_commit(struct object *obj, const unsigned char *sha1, int quiet) { - if (obj->type != TYPE_COMMIT) { + if (obj->type != OBJ_COMMIT) { if (!quiet) error("Object %s is a %s, not a commit", sha1_to_hex(sha1), typename(obj->type)); @@ -86,11 +86,11 @@ struct commit *lookup_commit(const unsigned char *sha1) if (!obj) { struct commit *ret = alloc_commit_node(); created_object(sha1, &ret->object); - ret->object.type = TYPE_COMMIT; + ret->object.type = OBJ_COMMIT; return ret; } if (!obj->type) - obj->type = TYPE_COMMIT; + obj->type = OBJ_COMMIT; return check_commit(obj, sha1, 0); } @@ -655,6 +655,9 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit continue; } + if (!subject) + body = 1; + if (is_empty_line(line, &linelen)) { if (!body) continue; @@ -662,8 +665,6 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit continue; if (fmt == CMIT_FMT_SHORT) break; - } else { - body = 1; } if (subject) { @@ -702,6 +703,12 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) buf[offset++] = '\n'; + /* + * make sure there is another EOLN to separate the headers from whatever + * body the caller appends if we haven't already written a body + */ + if (fmt == CMIT_FMT_EMAIL && !body) + buf[offset++] = '\n'; buf[offset] = '\0'; return offset; } @@ -854,6 +861,7 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo, #define PARENT1 (1u<< 8) #define PARENT2 (1u<< 9) #define STALE (1u<<10) +#define RESULT (1u<<11) static struct commit *interesting(struct commit_list *list) { @@ -867,183 +875,42 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -/* - * A pathological example of how this thing works. - * - * Suppose we had this commit graph, where chronologically - * the timestamp on the commit are A <= B <= C <= D <= E <= F - * and we are trying to figure out the merge base for E and F - * commits. - * - * F - * / \ - * E A D - * \ / / - * B / - * \ / - * C - * - * First we push E and F to list to be processed. E gets bit 1 - * and F gets bit 2. The list becomes: - * - * list=F(2) E(1), result=empty - * - * Then we pop F, the newest commit, from the list. Its flag is 2. - * We scan its parents, mark them reachable from the side that F is - * reachable from, and push them to the list: - * - * list=E(1) D(2) A(2), result=empty - * - * Next pop E and do the same. - * - * list=D(2) B(1) A(2), result=empty - * - * Next pop D and do the same. - * - * list=C(2) B(1) A(2), result=empty - * - * Next pop C and do the same. - * - * list=B(1) A(2), result=empty - * - * Now it is B's turn. We mark its parent, C, reachable from B's side, - * and push it to the list: - * - * list=C(3) A(2), result=empty - * - * Now pop C and notice it has flags==3. It is placed on the result list, - * and the list now contains: - * - * list=A(2), result=C(3) - * - * We pop A and do the same. - * - * list=B(3), result=C(3) - * - * Next, we pop B and something very interesting happens. It has flags==3 - * so it is also placed on the result list, and its parents are marked - * stale, retroactively, and placed back on the list: - * - * list=C(7), result=C(7) B(3) - * - * Now, list does not have any interesting commit. So we find the newest - * commit from the result list that is not marked stale. Which is - * commit B. - * - * - * Another pathological example how this thing used to fail to mark an - * ancestor of a merge base as STALE before we introduced the - * postprocessing phase (mark_reachable_commits). - * - * 2 - * H - * 1 / \ - * G A \ - * |\ / \ - * | B \ - * | \ \ - * \ C F - * \ \ / - * \ D / - * \ | / - * \| / - * E - * - * list A B C D E F G H - * G1 H2 - - - - - - 1 2 - * H2 E1 B1 - 1 - - 1 - 1 2 - * F2 E1 B1 A2 2 1 - - 1 2 1 2 - * E3 B1 A2 2 1 - - 3 2 1 2 - * B1 A2 2 1 - - 3 2 1 2 - * C1 A2 2 1 1 - 3 2 1 2 - * D1 A2 2 1 1 1 3 2 1 2 - * A2 2 1 1 1 3 2 1 2 - * B3 2 3 1 1 3 2 1 2 - * C7 2 3 7 1 3 2 1 2 - * - * At this point, unfortunately, everybody in the list is - * stale, so we fail to complete the following two - * steps to fully marking stale commits. - * - * D7 2 3 7 7 3 2 1 2 - * E7 2 3 7 7 7 2 1 2 - * - * and we ended up showing E as an interesting merge base. - * The postprocessing phase re-injects C and continues traversal - * to contaminate D and E. - */ - -static void mark_reachable_commits(struct commit_list *result, - struct commit_list *list) -{ - struct commit_list *tmp; - - /* - * Postprocess to fully contaminate the well. - */ - for (tmp = result; tmp; tmp = tmp->next) { - struct commit *c = tmp->item; - /* Reinject stale ones to list, - * so we can scan their parents. - */ - if (c->object.flags & STALE) - commit_list_insert(c, &list); - } - while (list) { - struct commit *c = list->item; - struct commit_list *parents; - - tmp = list; - list = list->next; - free(tmp); - - /* Anything taken out of the list is stale, so - * mark all its parents stale. We do not - * parse new ones (we already parsed all the relevant - * ones). - */ - parents = c->parents; - while (parents) { - struct commit *p = parents->item; - parents = parents->next; - if (!(p->object.flags & STALE)) { - p->object.flags |= STALE; - commit_list_insert(p, &list); - } - } - } -} - -struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, - int cleanup) +static struct commit_list *merge_bases(struct commit *one, struct commit *two) { struct commit_list *list = NULL; struct commit_list *result = NULL; - struct commit_list *tmp = NULL; - if (rev1 == rev2) - return commit_list_insert(rev1, &result); + if (one == two) + /* We do not mark this even with RESULT so we do not + * have to clean it up. + */ + return commit_list_insert(one, &result); - parse_commit(rev1); - parse_commit(rev2); + parse_commit(one); + parse_commit(two); - rev1->object.flags |= PARENT1; - rev2->object.flags |= PARENT2; - insert_by_date(rev1, &list); - insert_by_date(rev2, &list); + one->object.flags |= PARENT1; + two->object.flags |= PARENT2; + insert_by_date(one, &list); + insert_by_date(two, &list); while (interesting(list)) { - struct commit *commit = list->item; + struct commit *commit; struct commit_list *parents; - int flags = commit->object.flags - & (PARENT1 | PARENT2 | STALE); + struct commit_list *n; + int flags; - tmp = list; - list = list->next; - free(tmp); - if (flags == (PARENT1 | PARENT2)) { - insert_by_date(commit, &result); + commit = list->item; + n = list->next; + free(list); + list = n; + flags = commit->object.flags & (PARENT1 | PARENT2 | STALE); + if (flags == (PARENT1 | PARENT2)) { + if (!(commit->object.flags & RESULT)) { + commit->object.flags |= RESULT; + insert_by_date(commit, &result); + } /* Mark parents of a found merge stale */ flags |= STALE; } @@ -1059,35 +926,75 @@ struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, } } - if (!result) - goto finish; - - if (result->next && list) - mark_reachable_commits(result, list); - - /* cull duplicates */ - for (tmp = result, list = NULL; tmp; ) { - struct commit *commit = tmp->item; - struct commit_list *next = tmp->next; - if (commit->object.flags & STALE) { - if (list != NULL) - list->next = next; - free(tmp); - } else { - if (list == NULL) - result = tmp; - list = tmp; - commit->object.flags |= STALE; - } + /* Clean up the result to remove stale ones */ + list = result; result = NULL; + while (list) { + struct commit_list *n = list->next; + if (!(list->item->object.flags & STALE)) + insert_by_date(list->item, &result); + free(list); + list = n; + } + return result; +} - tmp = next; +struct commit_list *get_merge_bases(struct commit *one, + struct commit *two, + int cleanup) +{ + const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT); + struct commit_list *list; + struct commit **rslt; + struct commit_list *result; + int cnt, i, j; + + result = merge_bases(one, two); + if (one == two) + return result; + if (!result || !result->next) { + if (cleanup) { + clear_commit_marks(one, all_flags); + clear_commit_marks(two, all_flags); + } + return result; } - finish: - if (cleanup) { - clear_commit_marks(rev1, PARENT1 | PARENT2 | STALE); - clear_commit_marks(rev2, PARENT1 | PARENT2 | STALE); + /* There are more than one */ + cnt = 0; + list = result; + while (list) { + list = list->next; + cnt++; + } + rslt = xcalloc(cnt, sizeof(*rslt)); + for (list = result, i = 0; list; list = list->next) + rslt[i++] = list->item; + free_commit_list(result); + + clear_commit_marks(one, all_flags); + clear_commit_marks(two, all_flags); + for (i = 0; i < cnt - 1; i++) { + for (j = i+1; j < cnt; j++) { + if (!rslt[i] || !rslt[j]) + continue; + result = merge_bases(rslt[i], rslt[j]); + clear_commit_marks(rslt[i], all_flags); + clear_commit_marks(rslt[j], all_flags); + for (list = result; list; list = list->next) { + if (rslt[i] == list->item) + rslt[i] = NULL; + if (rslt[j] == list->item) + rslt[j] = NULL; + } + } } + /* Surviving ones in rslt[] are the independent results */ + result = NULL; + for (i = 0; i < cnt; i++) { + if (rslt[i]) + insert_by_date(rslt[i], &result); + } + free(rslt); return result; } diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index ebd00ef9c4..34c995046d 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -59,14 +59,16 @@ (defcustom git-committer-name nil "User name to use for commits. -The default is to fall back to the repository config, then to `add-log-full-name' and then to `user-full-name'." +The default is to fall back to the repository config, +then to `add-log-full-name' and then to `user-full-name'." :group 'git :type '(choice (const :tag "Default" nil) (string :tag "Name"))) (defcustom git-committer-email nil "Email address to use for commits. -The default is to fall back to the git repository config, then to `add-log-mailing-address' and then to `user-mail-address'." +The default is to fall back to the git repository config, +then to `add-log-mailing-address' and then to `user-mail-address'." :group 'git :type '(choice (const :tag "Default" nil) (string :tag "Email"))) @@ -86,6 +88,7 @@ The default is to fall back to the git repository config, then to `add-log-maili :group 'git :type 'string) + (defface git-status-face '((((class color) (background light)) (:foreground "purple"))) "Git mode face used to highlight added and modified files." @@ -149,7 +152,8 @@ The default is to fall back to the git repository config, then to `add-log-maili (apply #'call-process "git" nil buffer nil args))) (defun git-call-process-env-string (env &rest args) - "Wrapper for call-process that sets environment strings, and returns the process output as a string." + "Wrapper for call-process that sets environment strings, +and returns the process output as a string." (with-temp-buffer (and (eq 0 (apply #' git-call-process-env t env args)) (buffer-string)))) @@ -939,6 +943,8 @@ The default is to fall back to the git repository config, then to `add-log-maili (let ((map (make-keymap)) (diff-map (make-sparse-keymap))) (suppress-keymap map) + (define-key map "?" 'git-help) + (define-key map "h" 'git-help) (define-key map " " 'git-next-file) (define-key map "a" 'git-add-file) (define-key map "c" 'git-commit-file) @@ -1008,5 +1014,10 @@ Commands: (goto-char (point-min))) (message "%s is not a git working tree." dir))) +(defun git-help () + "Display help for Git mode." + (interactive) + (describe-function 'git-status-mode)) + (provide 'git) ;;; git.el ends here @@ -95,6 +95,12 @@ static void loginfo(const char *err, ...) va_end(params); } +static void NORETURN daemon_die(const char *err, va_list params) +{ + logreport(LOG_ERR, err, params); + exit(1); +} + static int avoid_alias(char *p) { int sl, ndot; @@ -656,6 +662,45 @@ static int service_loop(int socknum, int *socklist) } } +/* if any standard file descriptor is missing open it to /dev/null */ +static void sanitize_stdfds(void) +{ + int fd = open("/dev/null", O_RDWR, 0); + while (fd != -1 && fd < 2) + fd = dup(fd); + if (fd == -1) + die("open /dev/null or dup failed: %s", strerror(errno)); + if (fd > 2) + close(fd); +} + +static void daemonize(void) +{ + switch (fork()) { + case 0: + break; + case -1: + die("fork failed: %s", strerror(errno)); + default: + exit(0); + } + if (setsid() == -1) + die("setsid failed: %s", strerror(errno)); + close(0); + close(1); + close(2); + sanitize_stdfds(); +} + +static void store_pid(const char *path) +{ + FILE *f = fopen(path, "w"); + if (!f) + die("cannot open pid file %s: %s", path, strerror(errno)); + fprintf(f, "%d\n", getpid()); + fclose(f); +} + static int serve(int port) { int socknum, *socklist; @@ -671,6 +716,8 @@ int main(int argc, char **argv) { int port = DEFAULT_GIT_PORT; int inetd_mode = 0; + const char *pid_file = NULL; + int detach = 0; int i; /* Without this we cannot rely on waitpid() to tell @@ -735,6 +782,15 @@ int main(int argc, char **argv) user_path = arg + 12; continue; } + if (!strncmp(arg, "--pid-file=", 11)) { + pid_file = arg + 11; + continue; + } + if (!strcmp(arg, "--detach")) { + detach = 1; + log_syslog = 1; + continue; + } if (!strcmp(arg, "--")) { ok_paths = &argv[i+1]; break; @@ -746,17 +802,14 @@ int main(int argc, char **argv) usage(daemon_usage); } - if (log_syslog) + if (log_syslog) { openlog("git-daemon", 0, LOG_DAEMON); - - if (strict_paths && (!ok_paths || !*ok_paths)) { - if (!inetd_mode) - die("git-daemon: option --strict-paths requires a whitelist"); - - logerror("option --strict-paths requires a whitelist"); - exit (1); + set_die_routine(daemon_die); } + if (strict_paths && (!ok_paths || !*ok_paths)) + die("option --strict-paths requires a whitelist"); + if (inetd_mode) { struct sockaddr_storage ss; struct sockaddr *peer = (struct sockaddr *)&ss; @@ -770,5 +823,13 @@ int main(int argc, char **argv) return execute(peer); } + if (detach) + daemonize(); + else + sanitize_stdfds(); + + if (pid_file) + store_pid(pid_file); + return serve(port); } diff --git a/describe.c b/describe.c index 8e68d5df33..324ca8965b 100644 --- a/describe.c +++ b/describe.c @@ -67,7 +67,7 @@ static int get_name(const char *path, const unsigned char *sha1) * Otherwise only annotated tags are used. */ if (!strncmp(path, "refs/tags/", 10)) { - if (object->type == TYPE_TAG) + if (object->type == OBJ_TAG) prio = 2; else prio = 1; @@ -26,30 +26,14 @@ enum color_diff { DIFF_FILE_NEW = 5, }; -#define COLOR_NORMAL "" -#define COLOR_BOLD "\033[1m" -#define COLOR_DIM "\033[2m" -#define COLOR_UL "\033[4m" -#define COLOR_BLINK "\033[5m" -#define COLOR_REVERSE "\033[7m" -#define COLOR_RESET "\033[m" - -#define COLOR_BLACK "\033[30m" -#define COLOR_RED "\033[31m" -#define COLOR_GREEN "\033[32m" -#define COLOR_YELLOW "\033[33m" -#define COLOR_BLUE "\033[34m" -#define COLOR_MAGENTA "\033[35m" -#define COLOR_CYAN "\033[36m" -#define COLOR_WHITE "\033[37m" - -static const char *diff_colors[] = { - COLOR_RESET, - COLOR_NORMAL, - COLOR_BOLD, - COLOR_CYAN, - COLOR_RED, - COLOR_GREEN +/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ +static char diff_colors[][24] = { + "\033[m", /* reset */ + "", /* normal */ + "\033[1m", /* bold */ + "\033[36m", /* cyan */ + "\033[31m", /* red */ + "\033[32m" /* green */ }; static int parse_diff_color_slot(const char *var, int ofs) @@ -67,38 +51,116 @@ static int parse_diff_color_slot(const char *var, int ofs) die("bad config variable '%s'", var); } -static const char *parse_diff_color_value(const char *value, const char *var) -{ - if (!strcasecmp(value, "normal")) - return COLOR_NORMAL; - if (!strcasecmp(value, "bold")) - return COLOR_BOLD; - if (!strcasecmp(value, "dim")) - return COLOR_DIM; - if (!strcasecmp(value, "ul")) - return COLOR_UL; - if (!strcasecmp(value, "blink")) - return COLOR_BLINK; - if (!strcasecmp(value, "reverse")) - return COLOR_REVERSE; - if (!strcasecmp(value, "reset")) - return COLOR_RESET; - if (!strcasecmp(value, "black")) - return COLOR_BLACK; - if (!strcasecmp(value, "red")) - return COLOR_RED; - if (!strcasecmp(value, "green")) - return COLOR_GREEN; - if (!strcasecmp(value, "yellow")) - return COLOR_YELLOW; - if (!strcasecmp(value, "blue")) - return COLOR_BLUE; - if (!strcasecmp(value, "magenta")) - return COLOR_MAGENTA; - if (!strcasecmp(value, "cyan")) - return COLOR_CYAN; - if (!strcasecmp(value, "white")) - return COLOR_WHITE; +static int parse_color(const char *name, int len) +{ + static const char * const color_names[] = { + "normal", "black", "red", "green", "yellow", + "blue", "magenta", "cyan", "white" + }; + char *end; + int i; + for (i = 0; i < ARRAY_SIZE(color_names); i++) { + const char *str = color_names[i]; + if (!strncasecmp(name, str, len) && !str[len]) + return i - 1; + } + i = strtol(name, &end, 10); + if (*name && !*end && i >= -1 && i <= 255) + return i; + return -2; +} + +static int parse_attr(const char *name, int len) +{ + static const int attr_values[] = { 1, 2, 4, 5, 7 }; + static const char * const attr_names[] = { + "bold", "dim", "ul", "blink", "reverse" + }; + int i; + for (i = 0; i < ARRAY_SIZE(attr_names); i++) { + const char *str = attr_names[i]; + if (!strncasecmp(name, str, len) && !str[len]) + return attr_values[i]; + } + return -1; +} + +static void parse_diff_color_value(const char *value, const char *var, char *dst) +{ + const char *ptr = value; + int attr = -1; + int fg = -2; + int bg = -2; + + if (!strcasecmp(value, "reset")) { + strcpy(dst, "\033[m"); + return; + } + + /* [fg [bg]] [attr] */ + while (*ptr) { + const char *word = ptr; + int val, len = 0; + + while (word[len] && !isspace(word[len])) + len++; + + ptr = word + len; + while (*ptr && isspace(*ptr)) + ptr++; + + val = parse_color(word, len); + if (val >= -1) { + if (fg == -2) { + fg = val; + continue; + } + if (bg == -2) { + bg = val; + continue; + } + goto bad; + } + val = parse_attr(word, len); + if (val < 0 || attr != -1) + goto bad; + attr = val; + } + + if (attr >= 0 || fg >= 0 || bg >= 0) { + int sep = 0; + + *dst++ = '\033'; + *dst++ = '['; + if (attr >= 0) { + *dst++ = '0' + attr; + sep++; + } + if (fg >= 0) { + if (sep++) + *dst++ = ';'; + if (fg < 8) { + *dst++ = '3'; + *dst++ = '0' + fg; + } else { + dst += sprintf(dst, "38;5;%d", fg); + } + } + if (bg >= 0) { + if (sep++) + *dst++ = ';'; + if (bg < 8) { + *dst++ = '4'; + *dst++ = '0' + bg; + } else { + dst += sprintf(dst, "48;5;%d", bg); + } + } + *dst++ = 'm'; + } + *dst = 0; + return; +bad: die("bad config value '%s' for variable '%s'", value, var); } @@ -145,7 +207,7 @@ int git_diff_ui_config(const char *var, const char *value) } if (!strncmp(var, "diff.color.", 11)) { int slot = parse_diff_color_slot(var, 11); - diff_colors[slot] = parse_diff_color_value(value, var); + parse_diff_color_value(value, var, diff_colors[slot]); return 0; } return git_default_config(var, value); diff --git a/exec_cmd.c b/exec_cmd.c index c1539d12ce..62f51fcd6e 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,5 +1,6 @@ #include "cache.h" #include "exec_cmd.h" +#include "quote.h" #define MAX_ARGS 32 extern char **environ; @@ -96,9 +97,27 @@ int execv_git_cmd(const char **argv) tmp = argv[0]; argv[0] = git_command; + if (getenv("GIT_TRACE")) { + const char **p = argv; + fputs("trace: exec:", stderr); + while (*p) { + fputc(' ', stderr); + sq_quote_print(stderr, *p); + ++p; + } + putc('\n', stderr); + fflush(stderr); + } + /* execve() can only ever return if it fails */ execve(git_command, (char **)argv, environ); + if (getenv("GIT_TRACE")) { + fprintf(stderr, "trace: exec failed: %s\n", + strerror(errno)); + fflush(stderr); + } + argv[0] = tmp; } return -1; diff --git a/fetch-pack.c b/fetch-pack.c index f2c51ebe4b..b7824dbed4 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -46,7 +46,7 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1) { struct object *o = deref_tag(parse_object(sha1), path, 0); - if (o && o->type == TYPE_COMMIT) + if (o && o->type == OBJ_COMMIT) rev_list_push((struct commit *)o, SEEN); return 0; @@ -256,14 +256,14 @@ static int mark_complete(const char *path, const unsigned char *sha1) { struct object *o = parse_object(sha1); - while (o && o->type == TYPE_TAG) { + while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o->flags |= COMPLETE; o = parse_object(t->tagged->sha1); } - if (o && o->type == TYPE_COMMIT) { + if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; commit->object.flags |= COMPLETE; insert_by_date(commit, &complete); @@ -357,7 +357,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match) * in sync with the other side at some time after * that (it is OK if we guess wrong here). */ - if (o->type == TYPE_COMMIT) { + if (o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; if (!cutoff || cutoff < commit->date) cutoff = commit->date; @@ -376,7 +376,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match) struct object *o = deref_tag(lookup_object(ref->old_sha1), NULL, 0); - if (!o || o->type != TYPE_COMMIT || !(o->flags & COMPLETE)) + if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) continue; if (!(o->flags & SEEN)) { @@ -118,20 +118,20 @@ static struct object_list **process_queue_end = &process_queue; static int process_object(struct object *obj) { - if (obj->type == TYPE_COMMIT) { + if (obj->type == OBJ_COMMIT) { if (process_commit((struct commit *)obj)) return -1; return 0; } - if (obj->type == TYPE_TREE) { + if (obj->type == OBJ_TREE) { if (process_tree((struct tree *)obj)) return -1; return 0; } - if (obj->type == TYPE_BLOB) { + if (obj->type == OBJ_BLOB) { return 0; } - if (obj->type == TYPE_TAG) { + if (obj->type == OBJ_TAG) { if (process_tag((struct tag *)obj)) return -1; return 0; diff --git a/fsck-objects.c b/fsck-objects.c index ef54a8a411..e167f4105f 100644 --- a/fsck-objects.c +++ b/fsck-objects.c @@ -297,13 +297,13 @@ static int fsck_sha1(unsigned char *sha1) if (obj->flags & SEEN) return 0; obj->flags |= SEEN; - if (obj->type == TYPE_BLOB) + if (obj->type == OBJ_BLOB) return 0; - if (obj->type == TYPE_TREE) + if (obj->type == OBJ_TREE) return fsck_tree((struct tree *) obj); - if (obj->type == TYPE_COMMIT) + if (obj->type == OBJ_COMMIT) return fsck_commit((struct commit *) obj); - if (obj->type == TYPE_TAG) + if (obj->type == OBJ_TAG) return fsck_tag((struct tag *) obj); /* By now, parse_object() would've returned NULL instead. */ return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type); @@ -472,7 +472,7 @@ static int fsck_cache_tree(struct cache_tree *it) } mark_reachable(obj, REACHABLE); obj->used = 1; - if (obj->type != TYPE_TREE) + if (obj->type != OBJ_TREE) err |= objerror(obj, "non-tree in cache-tree"); } for (i = 0; i < it->subtree_nr; i++) diff --git a/git-commit.sh b/git-commit.sh index 802dd7243e..4cf3fab05c 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -138,32 +138,26 @@ run_status () { if test -z "$untracked_files"; then option="--directory --no-empty-directory" fi + hdr_shown= if test -f "$GIT_DIR/info/exclude" then - git-ls-files -z --others $option \ + git-ls-files --others $option \ --exclude-from="$GIT_DIR/info/exclude" \ --exclude-per-directory=.gitignore else - git-ls-files -z --others $option \ + git-ls-files --others $option \ --exclude-per-directory=.gitignore fi | - @@PERL@@ -e '$/ = "\0"; - my $shown = 0; - while (<>) { - chomp; - s|\\|\\\\|g; - s|\t|\\t|g; - s|\n|\\n|g; - s/^/# /; - if (!$shown) { - print "#\n# Untracked files:\n"; - print "# (use \"git add\" to add to commit)\n"; - print "#\n"; - $shown = 1; - } - print "$_\n"; - } - ' + while read line; do + if [ -z "$hdr_shown" ]; then + echo '#' + echo '# Untracked files:' + echo '# (use "git add" to add to commit)' + echo '#' + hdr_shown=1 + fi + echo "# $line" + done if test -n "$verbose" -a -z "$IS_INITIAL" then diff --git a/git-fetch.sh b/git-fetch.sh index ff1769952b..ee99280a2a 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -153,7 +153,7 @@ fast_forward_local () { then if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2" then - [ "$verbose" ] && echo >&2 "* $1: same as $3" + [ "$verbose" ] && echo >&2 "* $1: same as $3" ||: else echo >&2 "* $1: updating with $3" git-update-ref -m "$rloga: updating tag" "$1" "$2" diff --git a/git-prune.sh b/git-prune.sh deleted file mode 100755 index c5a5d29aaa..0000000000 --- a/git-prune.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -USAGE='[-n] [--] [<head>...]' -. git-sh-setup - -dryrun= -echo= -while case "$#" in 0) break ;; esac -do - case "$1" in - -n) dryrun=-n echo=echo ;; - --) break ;; - -*) usage ;; - *) break ;; - esac - shift; -done - -sync -case "$#" in -0) git-fsck-objects --full --cache --unreachable ;; -*) git-fsck-objects --full --cache --unreachable $(git-rev-parse --all) "$@" ;; -esac | - -sed -ne '/unreachable /{ - s/unreachable [^ ][^ ]* // - s|\(..\)|\1/|p -}' | { - cd "$GIT_OBJECT_DIRECTORY" || exit - xargs $echo rm -f - rmdir 2>/dev/null [0-9a-f][0-9a-f] -} - -git-prune-packed $dryrun - -if redundant=$(git-pack-redundant --all 2>/dev/null) && test "" != "$redundant" -then - if test "" = "$dryrun" - then - echo "$redundant" | xargs rm -f - else - echo rm -f "$redundant" - fi -fi diff --git a/git-repack.sh b/git-repack.sh index 640ad8d90b..9da92fb061 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -43,7 +43,9 @@ case ",$all_into_one," in ;; esac pack_objects="$pack_objects $local $quiet $no_reuse_delta$extra" -name=$(git-rev-list --objects --all $rev_list 2>&1 | +name=$( { git-rev-list --objects --all $rev_list || + echo "git-rev-list died with exit code $?" + } | git-pack-objects --non-empty $pack_objects .tmp-pack) || exit 1 if [ -z "$name" ]; then diff --git a/git-revert.sh b/git-revert.sh index de8b5f0f0f..2bf35d116c 100755 --- a/git-revert.sh +++ b/git-revert.sh @@ -84,7 +84,7 @@ revert) s/^[^ ]* /Revert "/ s/$/"/' echo - echo "This reverts $commit commit." + echo "This reverts commit $commit." test "$rev" = "$commit" || echo "(original 'git revert' arguments: $@)" base=$commit next=$prev diff --git a/git-svn.perl b/git-svn.perl index 4530ffe42c..89ad840dbf 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -147,7 +147,7 @@ init_vars(); load_authors() if $_authors; load_all_refs() if $_branch_all_refs; svn_compat_check() unless $_use_lib; -migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/; +migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init|commit-diff)$/; $cmd{$cmd}->[0]->(@ARGV); exit 0; @@ -11,6 +11,7 @@ #include "git-compat-util.h" #include "exec_cmd.h" #include "cache.h" +#include "quote.h" #include "builtin.h" @@ -120,14 +121,25 @@ static int handle_alias(int *argcp, const char ***argv) if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); - /* insert after command name */ - if (*argcp > 1) { - new_argv = realloc(new_argv, sizeof(char*) * - (count + *argcp)); - memcpy(new_argv + count, *argv + 1, - sizeof(char*) * *argcp); + if (getenv("GIT_TRACE")) { + int i; + fprintf(stderr, "trace: alias expansion: %s =>", + alias_command); + for (i = 0; i < count; ++i) { + fputc(' ', stderr); + sq_quote_print(stderr, new_argv[i]); + } + fputc('\n', stderr); + fflush(stderr); } + new_argv = realloc(new_argv, sizeof(char*) * + (count + *argcp + 1)); + /* insert after command name */ + memcpy(new_argv + count, *argv + 1, + sizeof(char*) * *argcp); + new_argv[count+*argcp] = NULL; + *argv = new_argv; *argcp += count - 1; @@ -188,7 +200,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "stripspace", cmd_stripspace }, { "update-index", cmd_update_index }, { "update-ref", cmd_update_ref }, - { "fmt-merge-msg", cmd_fmt_merge_msg } + { "fmt-merge-msg", cmd_fmt_merge_msg }, + { "prune", cmd_prune }, }; int i; @@ -202,6 +215,18 @@ static void handle_internal_command(int argc, const char **argv, char **envp) struct cmd_struct *p = commands+i; if (strcmp(p->cmd, cmd)) continue; + + if (getenv("GIT_TRACE")) { + int i; + fprintf(stderr, "trace: built-in: git"); + for (i = 0; i < argc; ++i) { + fputc(' ', stderr); + sq_quote_print(stderr, argv[i]); + } + putc('\n', stderr); + fflush(stderr); + } + exit(p->fn(argc, argv, envp)); } } diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi index 2e87de4769..2fd1e5f78e 100755 --- a/gitweb/gitweb.cgi +++ b/gitweb/gitweb.cgi @@ -22,20 +22,16 @@ our $my_url = $cgi->url(); our $my_uri = $cgi->url(-absolute => 1); our $rss_link = ""; -# location of the git-core binaries -our $gitbin = "/usr/bin"; +# core git executable to use +# this can just be "git" if your webserver has a sensible PATH +our $GIT = "/usr/bin/git"; # absolute fs-path which will be prepended to the project path #our $projectroot = "/pub/scm"; our $projectroot = "/home/kay/public_html/pub/scm"; -# version of the git-core binaries -our $git_version = qx($gitbin/git --version); -if ($git_version =~ m/git version (.*)$/) { - $git_version = $1; -} else { - $git_version = "unknown"; -} +# version of the core git binary +our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown"; # location for temporary files needed for diffs our $git_temp = "/tmp/gitweb"; @@ -46,6 +42,10 @@ if (! -d $git_temp) { # target of the home link on top of all pages our $home_link = $my_uri; +# name of your site or organization to appear in page titles +# replace this with something more descriptive for clearer bookmarks +our $site_name = $ENV{'SERVER_NAME'} || "Untitled"; + # html text to include at home page our $home_text = "indextext.html"; @@ -280,7 +280,7 @@ sub git_header_html { my $status = shift || "200 OK"; my $expires = shift; - my $title = "git"; + my $title = "$site_name git"; if (defined $project) { $title .= " - $project"; if (defined $action) { @@ -293,7 +293,17 @@ sub git_header_html { } } } - print $cgi->header(-type=>'text/html', -charset => 'utf-8', -status=> $status, -expires => $expires); + my $content_type; + # require explicit support from the UA if we are to send the page as + # 'application/xhtml+xml', otherwise send it as plain old 'text/html'. + # we have to do this because MSIE sometimes globs '*/*', pretending to + # support xhtml+xml but choking when it gets what it asked for. + if ($cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && $cgi->Accept('application/xhtml+xml') != 0) { + $content_type = 'application/xhtml+xml'; + } else { + $content_type = 'text/html'; + } + print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires); print <<EOF; <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> @@ -301,7 +311,7 @@ sub git_header_html { <!-- git web interface v$version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke --> <!-- git core binaries version $git_version --> <head> -<meta http-equiv="content-type" content="text/html; charset=utf-8"/> +<meta http-equiv="content-type" content="$content_type; charset=utf-8"/> <meta name="robots" content="index, nofollow"/> <title>$title</title> <link rel="stylesheet" type="text/css" href="$stylesheet"/> @@ -378,7 +388,7 @@ sub die_error { sub git_get_type { my $hash = shift; - open my $fd, "-|", "$gitbin/git-cat-file -t $hash" or return; + open my $fd, "-|", "$GIT cat-file -t $hash" or return; my $type = <$fd>; close $fd or return; chomp $type; @@ -390,7 +400,7 @@ sub git_read_head { my $oENV = $ENV{'GIT_DIR'}; my $retval = undef; $ENV{'GIT_DIR'} = "$projectroot/$project"; - if (open my $fd, "-|", "$gitbin/git-rev-parse", "--verify", "HEAD") { + if (open my $fd, "-|", $GIT, "rev-parse", "--verify", "HEAD") { my $head = <$fd>; close $fd; if (defined $head && $head =~ /^([0-9a-fA-F]{40})$/) { @@ -430,7 +440,7 @@ sub git_read_tag { my %tag; my @comment; - open my $fd, "-|", "$gitbin/git-cat-file tag $tag_id" or return; + open my $fd, "-|", "$GIT cat-file tag $tag_id" or return; $tag{'id'} = $tag_id; while (my $line = <$fd>) { chomp $line; @@ -502,7 +512,7 @@ sub git_read_commit { @commit_lines = @$commit_text; } else { $/ = "\0"; - open my $fd, "-|", "$gitbin/git-rev-list --header --parents --max-count=1 $commit_id" or return; + open my $fd, "-|", "$GIT rev-list --header --parents --max-count=1 $commit_id" or return; @commit_lines = split '\n', <$fd>; close $fd or return; $/ = "\n"; @@ -600,7 +610,7 @@ sub git_diff_print { if (defined $from) { $from_tmp = "$git_temp/gitweb_" . $$ . "_from"; open my $fd2, "> $from_tmp"; - open my $fd, "-|", "$gitbin/git-cat-file blob $from"; + open my $fd, "-|", "$GIT cat-file blob $from"; my @file = <$fd>; print $fd2 @file; close $fd2; @@ -611,7 +621,7 @@ sub git_diff_print { if (defined $to) { $to_tmp = "$git_temp/gitweb_" . $$ . "_to"; open my $fd2, "> $to_tmp"; - open my $fd, "-|", "$gitbin/git-cat-file blob $to"; + open my $fd, "-|", "$GIT cat-file blob $to"; my @file = <$fd>; print $fd2 @file; close $fd2; @@ -830,7 +840,7 @@ sub git_get_project_config { $key =~ s/^gitweb\.//; return if ($key =~ m/\W/); - my $val = qx($gitbin/git-repo-config --get gitweb.$key); + my $val = qx($GIT repo-config --get gitweb.$key); return ($val); } @@ -1052,7 +1062,7 @@ sub git_summary { "<tr><td>owner</td><td>$owner</td></tr>\n" . "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n" . "</table>\n"; - open my $fd, "-|", "$gitbin/git-rev-list --max-count=17 " . git_read_head($project) or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT rev-list --max-count=17 " . git_read_head($project) or die_error(undef, "Open failed."); my (@revlist) = map { chomp; $_ } <$fd>; close $fd; print "<div>\n" . @@ -1240,7 +1250,7 @@ sub git_blame { $hash = git_get_hash_by_path($hash_base, $file_name, "blob") or die_error(undef, "Error lookup file."); } - open ($fd, "-|", "$gitbin/git-annotate", '-l', '-t', '-r', $file_name, $hash_base) + open ($fd, "-|", $GIT, "annotate", '-l', '-t', '-r', $file_name, $hash_base) or die_error(undef, "Open failed."); git_header_html(); print "<div class=\"page_nav\">\n" . @@ -1435,7 +1445,7 @@ sub git_get_hash_by_path { my $tree = $base; my @parts = split '/', $path; while (my $part = shift @parts) { - open my $fd, "-|", "$gitbin/git-ls-tree $tree" or die_error(undef, "Open git-ls-tree failed."); + open my $fd, "-|", "$GIT ls-tree $tree" or die_error(undef, "Open git-ls-tree failed."); my (@entries) = map { chomp; $_ } <$fd>; close $fd or return undef; foreach my $line (@entries) { @@ -1522,7 +1532,7 @@ sub git_blob_plain_mimetype { sub git_blob_plain { my $type = shift; - open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or die_error("Couldn't cat $file_name, $hash"); + open my $fd, "-|", "$GIT cat-file blob $hash" or die_error("Couldn't cat $file_name, $hash"); $type ||= git_blob_plain_mimetype($fd, $file_name); @@ -1549,7 +1559,7 @@ sub git_blob { $hash = git_get_hash_by_path($base, $file_name, "blob") || die_error(undef, "Error lookup file."); } my $have_blame = git_get_project_config_bool ('blame'); - open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT cat-file blob $hash" or die_error(undef, "Open failed."); my $mimetype = git_blob_plain_mimetype($fd, $file_name); if ($mimetype !~ m/^text\//) { close $fd; @@ -1615,7 +1625,7 @@ sub git_tree { } } $/ = "\0"; - open my $fd, "-|", "$gitbin/git-ls-tree -z $hash" or die_error(undef, "Open git-ls-tree failed."); + open my $fd, "-|", "$GIT ls-tree -z $hash" or die_error(undef, "Open git-ls-tree failed."); chomp (my (@entries) = <$fd>); close $fd or die_error(undef, "Reading tree failed."); $/ = "\n"; @@ -1698,7 +1708,7 @@ sub git_tree { sub git_rss { # http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ - open my $fd, "-|", "$gitbin/git-rev-list --max-count=150 " . git_read_head($project) or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT rev-list --max-count=150 " . git_read_head($project) or die_error(undef, "Open failed."); my (@revlist) = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading rev-list failed."); print $cgi->header(-type => 'text/xml', -charset => 'utf-8'); @@ -1718,7 +1728,7 @@ sub git_rss { last; } my %cd = date_str($co{'committer_epoch'}); - open $fd, "-|", "$gitbin/git-diff-tree -r $co{'parent'} $co{'id'}" or next; + open $fd, "-|", "$GIT diff-tree -r $co{'parent'} $co{'id'}" or next; my @difftree = map { chomp; $_ } <$fd>; close $fd or next; print "<item>\n" . @@ -1760,7 +1770,7 @@ sub git_opml { print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n". "<opml version=\"1.0\">\n". "<head>". - " <title>Git OPML Export</title>\n". + " <title>$site_name Git OPML Export</title>\n". "</head>\n". "<body>\n". "<outline text=\"git RSS feeds\">\n"; @@ -1806,7 +1816,7 @@ sub git_log { " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n"; my $limit = sprintf("--max-count=%i", (100 * ($page+1))); - open my $fd, "-|", "$gitbin/git-rev-list $limit $hash" or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT rev-list $limit $hash" or die_error(undef, "Open failed."); my (@revlist) = map { chomp; $_ } <$fd>; close $fd; @@ -1897,7 +1907,7 @@ sub git_commit { $root = " --root"; $parent = ""; } - open my $fd, "-|", "$gitbin/git-diff-tree -r -M $root $parent $hash" or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT diff-tree -r -M $root $parent $hash" or die_error(undef, "Open failed."); @difftree = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading diff-tree failed."); @@ -2139,7 +2149,7 @@ sub git_commitdiff { if (!defined $hash_parent) { $hash_parent = $co{'parent'}; } - open my $fd, "-|", "$gitbin/git-diff-tree -r $hash_parent $hash" or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT diff-tree -r $hash_parent $hash" or die_error(undef, "Open failed."); my (@difftree) = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading diff-tree failed."); @@ -2229,14 +2239,14 @@ sub git_commitdiff { sub git_commitdiff_plain { mkdir($git_temp, 0700); - open my $fd, "-|", "$gitbin/git-diff-tree -r $hash_parent $hash" or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT diff-tree -r $hash_parent $hash" or die_error(undef, "Open failed."); my (@difftree) = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading diff-tree failed."); # try to figure out the next tag after this commit my $tagname; my $refs = read_info_ref("tags"); - open $fd, "-|", "$gitbin/git-rev-list HEAD"; + open $fd, "-|", "$GIT rev-list HEAD"; chomp (my (@commits) = <$fd>); close $fd; foreach my $commit (@commits) { @@ -2307,7 +2317,7 @@ sub git_history { print "<div class=\"page_path\"><b>/" . esc_html($file_name) . "</b><br/></div>\n"; open my $fd, "-|", - "$gitbin/git-rev-list --full-history $hash -- \'$file_name\'"; + "$GIT rev-list --full-history $hash -- \'$file_name\'"; print "<table cellspacing=\"0\">\n"; my $alternate = 0; while (my $line = <$fd>) { @@ -2394,7 +2404,7 @@ sub git_search { my $alternate = 0; if ($commit_search) { $/ = "\0"; - open my $fd, "-|", "$gitbin/git-rev-list --header --parents $hash" or next; + open my $fd, "-|", "$GIT rev-list --header --parents $hash" or next; while (my $commit_text = <$fd>) { if (!grep m/$searchtext/i, $commit_text) { next; @@ -2444,7 +2454,7 @@ sub git_search { if ($pickaxe_search) { $/ = "\n"; - open my $fd, "-|", "$gitbin/git-rev-list $hash | $gitbin/git-diff-tree -r --stdin -S\'$searchtext\'"; + open my $fd, "-|", "$GIT rev-list $hash | $GIT diff-tree -r --stdin -S\'$searchtext\'"; undef %co; my @files; while (my $line = <$fd>) { @@ -2515,7 +2525,7 @@ sub git_shortlog { " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n"; my $limit = sprintf("--max-count=%i", (100 * ($page+1))); - open my $fd, "-|", "$gitbin/git-rev-list $limit $hash" or die_error(undef, "Open failed."); + open my $fd, "-|", "$GIT rev-list $limit $hash" or die_error(undef, "Open failed."); my (@revlist) = map { chomp; $_ } <$fd>; close $fd; diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 98410f5b6c..fffdb13d09 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -60,6 +60,7 @@ div.page_footer_text { div.page_body { padding: 8px; + font-family: monospace; } div.title, a.title { @@ -79,6 +80,7 @@ div.title_text { padding: 6px 0px; border: solid #d9d8d1; border-width: 0px 0px 1px; + font-family: monospace; } div.log_body { @@ -142,8 +144,13 @@ table { padding: 8px 4px; } -table.project_list, table.diff_tree { +table.project_list { + border-spacing: 0; +} + +table.diff_tree { border-spacing: 0; + font-family: monospace; } table.blame { diff --git a/http-push.c b/http-push.c index f761584d7e..47686195cd 100644 --- a/http-push.c +++ b/http-push.c @@ -1784,16 +1784,16 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock) if (obj->flags & (UNINTERESTING | SEEN)) continue; - if (obj->type == TYPE_TAG) { + if (obj->type == OBJ_TAG) { obj->flags |= SEEN; p = add_one_object(obj, p); continue; } - if (obj->type == TYPE_TREE) { + if (obj->type == OBJ_TREE) { p = process_tree((struct tree *)obj, p, NULL, name); continue; } - if (obj->type == TYPE_BLOB) { + if (obj->type == OBJ_BLOB) { p = process_blob((struct blob *)obj, p, NULL, name); continue; } @@ -1960,12 +1960,12 @@ static int ref_newer(const unsigned char *new_sha1, * old. Otherwise we require --force. */ o = deref_tag(parse_object(old_sha1), NULL, 0); - if (!o || o->type != TYPE_COMMIT) + if (!o || o->type != OBJ_COMMIT) return 0; old = (struct commit *) o; o = deref_tag(parse_object(new_sha1), NULL, 0); - if (!o || o->type != TYPE_COMMIT) + if (!o || o->type != OBJ_COMMIT) return 0; new = (struct commit *) o; @@ -2044,7 +2044,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls) fwrite_buffer(ref_info, 1, len, buf); free(ref_info); - if (o->type == TYPE_TAG) { + if (o->type == OBJ_TAG) { o = deref_tag(o, ls->dentry_name, 0); if (o) { len = strlen(ls->dentry_name) + 45; diff --git a/merge-file.c b/merge-file.c new file mode 100644 index 0000000000..f32c653825 --- /dev/null +++ b/merge-file.c @@ -0,0 +1,166 @@ +#include "cache.h" +#include "run-command.h" +#include "xdiff-interface.h" +#include "blob.h" + +static void rm_temp_file(const char *filename) +{ + unlink(filename); + free((void *)filename); +} + +static const char *write_temp_file(mmfile_t *f) +{ + int fd; + const char *tmp = getenv("TMPDIR"); + char *filename; + + if (!tmp) + tmp = "/tmp"; + filename = mkpath("%s/%s", tmp, "git-tmp-XXXXXX"); + fd = mkstemp(filename); + if (fd < 0) + return NULL; + filename = strdup(filename); + if (f->size != xwrite(fd, f->ptr, f->size)) { + rm_temp_file(filename); + return NULL; + } + close(fd); + return filename; +} + +static void *read_temp_file(const char *filename, unsigned long *size) +{ + struct stat st; + char *buf = NULL; + int fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + if (!fstat(fd, &st)) { + *size = st.st_size; + buf = xmalloc(st.st_size); + if (st.st_size != xread(fd, buf, st.st_size)) { + free(buf); + buf = NULL; + } + } + close(fd); + return buf; +} + +static int fill_mmfile_blob(mmfile_t *f, struct blob *obj) +{ + void *buf; + unsigned long size; + char type[20]; + + buf = read_sha1_file(obj->object.sha1, type, &size); + if (!buf) + return -1; + if (strcmp(type, blob_type)) + return -1; + f->ptr = buf; + f->size = size; + return 0; +} + +static void free_mmfile(mmfile_t *f) +{ + free(f->ptr); +} + +static void *three_way_filemerge(mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size) +{ + void *res; + const char *t1, *t2, *t3; + + t1 = write_temp_file(base); + t2 = write_temp_file(our); + t3 = write_temp_file(their); + res = NULL; + if (t1 && t2 && t3) { + int code = run_command("merge", t2, t1, t3, NULL); + if (!code || code == -1) + res = read_temp_file(t2, size); + } + rm_temp_file(t1); + rm_temp_file(t2); + rm_temp_file(t3); + return res; +} + +static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf) +{ + int i; + mmfile_t *dst = priv_; + + for (i = 0; i < nbuf; i++) { + memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size); + dst->size += mb[i].size; + } + return 0; +} + +static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2) +{ + unsigned long size = f1->size < f2->size ? f1->size : f2->size; + void *ptr = xmalloc(size); + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t ecb; + + xpp.flags = XDF_NEED_MINIMAL; + xecfg.ctxlen = 3; + xecfg.flags = XDL_EMIT_COMMON; + ecb.outf = common_outf; + + res->ptr = ptr; + res->size = 0; + + ecb.priv = res; + return xdl_diff(f1, f2, &xpp, &xecfg, &ecb); +} + +void *merge_file(struct blob *base, struct blob *our, struct blob *their, unsigned long *size) +{ + void *res = NULL; + mmfile_t f1, f2, common; + + /* + * Removed in either branch? + * + * NOTE! This depends on the caller having done the + * proper warning about removing a file that got + * modified in the other branch! + */ + if (!our || !their) { + char type[20]; + if (base) + return NULL; + if (!our) + our = their; + return read_sha1_file(our->object.sha1, type, size); + } + + if (fill_mmfile_blob(&f1, our) < 0) + goto out_no_mmfile; + if (fill_mmfile_blob(&f2, their) < 0) + goto out_free_f1; + + if (base) { + if (fill_mmfile_blob(&common, base) < 0) + goto out_free_f2_f1; + } else { + if (generate_common_file(&common, &f1, &f2) < 0) + goto out_free_f2_f1; + } + res = three_way_filemerge(&common, &f1, &f2, size); + free_mmfile(&common); +out_free_f2_f1: + free_mmfile(&f2); +out_free_f1: + free_mmfile(&f1); +out_no_mmfile: + return res; +} diff --git a/merge-tree.c b/merge-tree.c index 9dcaab7a85..7cf00be6d5 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -1,11 +1,152 @@ #include "cache.h" #include "tree-walk.h" +#include "xdiff-interface.h" +#include "blob.h" static const char merge_tree_usage[] = "git-merge-tree <base-tree> <branch1> <branch2>"; static int resolve_directories = 1; +struct merge_list { + struct merge_list *next; + struct merge_list *link; /* other stages for this object */ + + unsigned int stage : 2, + flags : 30; + unsigned int mode; + const char *path; + struct blob *blob; +}; + +static struct merge_list *merge_result, **merge_result_end = &merge_result; + +static void add_merge_entry(struct merge_list *entry) +{ + *merge_result_end = entry; + merge_result_end = &entry->next; +} + static void merge_trees(struct tree_desc t[3], const char *base); +static const char *explanation(struct merge_list *entry) +{ + switch (entry->stage) { + case 0: + return "merged"; + case 3: + return "added in remote"; + case 2: + if (entry->link) + return "added in both"; + return "added in local"; + } + + /* Existed in base */ + entry = entry->link; + if (!entry) + return "removed in both"; + + if (entry->link) + return "changed in both"; + + if (entry->stage == 3) + return "removed in local"; + return "removed in remote"; +} + +extern void *merge_file(struct blob *, struct blob *, struct blob *, unsigned long *); + +static void *result(struct merge_list *entry, unsigned long *size) +{ + char type[20]; + struct blob *base, *our, *their; + + if (!entry->stage) + return read_sha1_file(entry->blob->object.sha1, type, size); + base = NULL; + if (entry->stage == 1) { + base = entry->blob; + entry = entry->link; + } + our = NULL; + if (entry && entry->stage == 2) { + our = entry->blob; + entry = entry->link; + } + their = NULL; + if (entry) + their = entry->blob; + return merge_file(base, our, their, size); +} + +static void *origin(struct merge_list *entry, unsigned long *size) +{ + char type[20]; + while (entry) { + if (entry->stage == 2) + return read_sha1_file(entry->blob->object.sha1, type, size); + entry = entry->link; + } + return NULL; +} + +static int show_outf(void *priv_, mmbuffer_t *mb, int nbuf) +{ + int i; + for (i = 0; i < nbuf; i++) + printf("%.*s", (int) mb[i].size, mb[i].ptr); + return 0; +} + +static void show_diff(struct merge_list *entry) +{ + unsigned long size; + mmfile_t src, dst; + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t ecb; + + xpp.flags = XDF_NEED_MINIMAL; + xecfg.ctxlen = 3; + xecfg.flags = 0; + ecb.outf = show_outf; + ecb.priv = NULL; + + src.ptr = origin(entry, &size); + if (!src.ptr) + size = 0; + src.size = size; + dst.ptr = result(entry, &size); + if (!dst.ptr) + size = 0; + dst.size = size; + xdl_diff(&src, &dst, &xpp, &xecfg, &ecb); + free(src.ptr); + free(dst.ptr); +} + +static void show_result_list(struct merge_list *entry) +{ + printf("%s\n", explanation(entry)); + do { + struct merge_list *link = entry->link; + static const char *desc[4] = { "result", "base", "our", "their" }; + printf(" %-6s %o %s %s\n", desc[entry->stage], entry->mode, sha1_to_hex(entry->blob->object.sha1), entry->path); + entry = link; + } while (entry); +} + +static void show_result(void) +{ + struct merge_list *walk; + + walk = merge_result; + while (walk) { + show_result_list(walk); + show_diff(walk); + walk = walk->next; + } +} + /* An empty entry never compares same, not even to another empty entry */ static int same_entry(struct name_entry *a, struct name_entry *b) { @@ -15,24 +156,34 @@ static int same_entry(struct name_entry *a, struct name_entry *b) a->mode == b->mode; } -static const char *sha1_to_hex_zero(const unsigned char *sha1) +static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsigned char *sha1, const char *path) { - if (sha1) - return sha1_to_hex(sha1); - return "0000000000000000000000000000000000000000"; + struct merge_list *res = xmalloc(sizeof(*res)); + + memset(res, 0, sizeof(*res)); + res->stage = stage; + res->path = path; + res->mode = mode; + res->blob = lookup_blob(sha1); + return res; } static void resolve(const char *base, struct name_entry *branch1, struct name_entry *result) { + struct merge_list *orig, *final; + const char *path; + /* If it's already branch1, don't bother showing it */ if (!branch1) return; - printf("0 %06o->%06o %s->%s %s%s\n", - branch1->mode, result->mode, - sha1_to_hex_zero(branch1->sha1), - sha1_to_hex_zero(result->sha1), - base, result->path); + path = strdup(mkpath("%s%s", base, result->path)); + orig = create_entry(2, branch1->mode, branch1->sha1, path); + final = create_entry(0, result->mode, result->sha1, path); + + final->link = orig; + + add_merge_entry(final); } static int unresolved_directory(const char *base, struct name_entry n[3]) @@ -71,16 +222,40 @@ static int unresolved_directory(const char *base, struct name_entry n[3]) return 1; } + +static struct merge_list *link_entry(unsigned stage, const char *base, struct name_entry *n, struct merge_list *entry) +{ + const char *path; + struct merge_list *link; + + if (!n->mode) + return entry; + if (entry) + path = entry->path; + else + path = strdup(mkpath("%s%s", base, n->path)); + link = create_entry(stage, n->mode, n->sha1, path); + link->link = entry; + return link; +} + static void unresolved(const char *base, struct name_entry n[3]) { + struct merge_list *entry = NULL; + if (unresolved_directory(base, n)) return; - if (n[0].sha1) - printf("1 %06o %s %s%s\n", n[0].mode, sha1_to_hex(n[0].sha1), base, n[0].path); - if (n[1].sha1) - printf("2 %06o %s %s%s\n", n[1].mode, sha1_to_hex(n[1].sha1), base, n[1].path); - if (n[2].sha1) - printf("3 %06o %s %s%s\n", n[2].mode, sha1_to_hex(n[2].sha1), base, n[2].path); + + /* + * Do them in reverse order so that the resulting link + * list has the stages in order - link_entry adds new + * links at the front. + */ + entry = link_entry(3, base, n + 2, entry); + entry = link_entry(2, base, n + 1, entry); + entry = link_entry(1, base, n + 0, entry); + + add_merge_entry(entry); } /* @@ -172,5 +347,7 @@ int main(int argc, char **argv) free(buf1); free(buf2); free(buf3); + + show_result(); return 0; } diff --git a/name-rev.c b/name-rev.c index 083d067e17..f92f14e32f 100644 --- a/name-rev.c +++ b/name-rev.c @@ -84,14 +84,14 @@ static int name_ref(const char *path, const unsigned char *sha1) if (tags_only && strncmp(path, "refs/tags/", 10)) return 0; - while (o && o->type == TYPE_TAG) { + while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o = parse_object(t->tagged->sha1); deref = 1; } - if (o && o->type == TYPE_COMMIT) { + if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; if (!strncmp(path, "refs/heads/", 11)) @@ -111,7 +111,7 @@ static const char* get_rev_name(struct object *o) struct rev_name *n; struct commit *c; - if (o->type != TYPE_COMMIT) + if (o->type != OBJ_COMMIT) return "undefined"; c = (struct commit *) o; n = c->util; @@ -172,7 +172,7 @@ int main(int argc, char **argv) } o = deref_tag(parse_object(sha1), *argv, 0); - if (!o || o->type != TYPE_COMMIT) { + if (!o || o->type != OBJ_COMMIT) { fprintf(stderr, "Could not get commit for %s. Skipping.\n", *argv); continue; @@ -19,7 +19,8 @@ struct object *get_indexed_object(unsigned int idx) } const char *type_names[] = { - "none", "blob", "tree", "commit", "bad" + "none", "commit", "tree", "blob", "tag", + "bad type 5", "bad type 6", "delta", "bad", }; static unsigned int hash_obj(struct object *obj, unsigned int n) @@ -88,7 +89,7 @@ void created_object(const unsigned char *sha1, struct object *obj) { obj->parsed = 0; obj->used = 0; - obj->type = TYPE_NONE; + obj->type = OBJ_NONE; obj->flags = 0; memcpy(obj->sha1, sha1, 20); @@ -131,7 +132,7 @@ struct object *lookup_unknown_object(const unsigned char *sha1) if (!obj) { union any_object *ret = xcalloc(1, sizeof(*ret)); created_object(sha1, &ret->object); - ret->object.type = TYPE_NONE; + ret->object.type = OBJ_NONE; return &ret->object; } return obj; @@ -24,12 +24,19 @@ struct object_array { #define TYPE_BITS 3 #define FLAG_BITS 27 -#define TYPE_NONE 0 -#define TYPE_BLOB 1 -#define TYPE_TREE 2 -#define TYPE_COMMIT 3 -#define TYPE_TAG 4 -#define TYPE_BAD 5 +/* + * The object type is stored in 3 bits. + */ +enum object_type { + OBJ_NONE = 0, + OBJ_COMMIT = 1, + OBJ_TREE = 2, + OBJ_BLOB = 3, + OBJ_TAG = 4, + /* 5/6 for future expansion */ + OBJ_DELTA = 7, + OBJ_BAD, +}; struct object { unsigned parsed : 1; @@ -40,14 +47,14 @@ struct object { }; extern int track_object_refs; -extern const char *type_names[]; +extern const char *type_names[9]; extern unsigned int get_max_object_index(void); extern struct object *get_indexed_object(unsigned int); static inline const char *typename(unsigned int type) { - return type_names[type > TYPE_TAG ? TYPE_BAD : type]; + return type_names[type > OBJ_BAD ? OBJ_BAD : type]; } extern struct object_refs *lookup_object_refs(struct object *); @@ -1,20 +1,7 @@ #ifndef PACK_H #define PACK_H -/* - * The packed object type is stored in 3 bits. - * The type value 0 is a reserved prefix if ever there is more than 7 - * object types, or any future format extensions. - */ -enum object_type { - OBJ_EXT = 0, - OBJ_COMMIT = 1, - OBJ_TREE = 2, - OBJ_BLOB = 3, - OBJ_TAG = 4, - /* 5/6 for future expansion */ - OBJ_DELTA = 7, -}; +#include "object.h" /* * Packed object header @@ -45,6 +45,23 @@ size_t sq_quote_buf(char *dst, size_t n, const char *src) return len; } +void sq_quote_print(FILE *stream, const char *src) +{ + char c; + + fputc('\'', stream); + while ((c = *src++)) { + if (need_bs_quote(c)) { + fputs("'\\", stream); + fputc(c, stream); + fputc('\'', stream); + } else { + fputc(c, stream); + } + } + fputc('\'', stream); +} + char *sq_quote(const char *src) { char *buf; @@ -29,6 +29,7 @@ */ extern char *sq_quote(const char *src); +extern void sq_quote_print(FILE *stream, const char *src); extern size_t sq_quote_buf(char *dst, size_t n, const char *src); /* This unwraps what sq_quote() produces in place, but returns diff --git a/revision.c b/revision.c index 7df9089f53..874e349db8 100644 --- a/revision.c +++ b/revision.c @@ -135,7 +135,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object /* * Tag object? Look what it points to.. */ - while (object->type == TYPE_TAG) { + while (object->type == OBJ_TAG) { struct tag *tag = (struct tag *) object; if (revs->tag_objects && !(flags & UNINTERESTING)) add_pending_object(revs, object, tag->tag); @@ -148,7 +148,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object * Commit object? Just return it, we'll do all the complex * reachability crud. */ - if (object->type == TYPE_COMMIT) { + if (object->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)object; if (parse_commit(commit) < 0) die("unable to parse commit %s", name); @@ -164,7 +164,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object * Tree object? Either mark it uniniteresting, or add it * to the list of objects to look at later.. */ - if (object->type == TYPE_TREE) { + if (object->type == OBJ_TREE) { struct tree *tree = (struct tree *)object; if (!revs->tree_objects) return NULL; @@ -179,7 +179,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object /* * Blob object? You know the drill by now.. */ - if (object->type == TYPE_BLOB) { + if (object->type == OBJ_BLOB) { struct blob *blob = (struct blob *)object; if (!revs->blob_objects) return NULL; @@ -494,11 +494,11 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags) return 0; while (1) { it = get_reference(revs, arg, sha1, 0); - if (it->type != TYPE_TAG) + if (it->type != OBJ_TAG) break; memcpy(sha1, ((struct tag*)it)->tagged->sha1, 20); } - if (it->type != TYPE_COMMIT) + if (it->type != OBJ_COMMIT) return 0; commit = (struct commit *)it; for (parents = commit->parents; parents; parents = parents->next) { diff --git a/send-pack.c b/send-pack.c index 4019a4b981..10bc8bc359 100644 --- a/send-pack.c +++ b/send-pack.c @@ -151,12 +151,12 @@ static int ref_newer(const unsigned char *new_sha1, * old. Otherwise we require --force. */ o = deref_tag(parse_object(old_sha1), NULL, 0); - if (!o || o->type != TYPE_COMMIT) + if (!o || o->type != OBJ_COMMIT) return 0; old = (struct commit *) o; o = deref_tag(parse_object(new_sha1), NULL, 0); - if (!o || o->type != TYPE_COMMIT) + if (!o || o->type != OBJ_COMMIT) return 0; new = (struct commit *) o; diff --git a/server-info.c b/server-info.c index fdfe05a2da..7df628f2b2 100644 --- a/server-info.c +++ b/server-info.c @@ -12,7 +12,7 @@ static int add_info_ref(const char *path, const unsigned char *sha1) struct object *o = parse_object(sha1); fprintf(info_ref_fp, "%s %s\n", sha1_to_hex(sha1), path); - if (o->type == TYPE_TAG) { + if (o->type == OBJ_TAG) { o = deref_tag(o, path, 0); if (o) fprintf(info_ref_fp, "%s %s^{}\n", diff --git a/sha1_file.c b/sha1_file.c index 8734d501fe..e666aec502 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1331,31 +1331,29 @@ char *write_sha1_file_prepare(void *buf, static int link_temp_to_file(const char *tmpfile, char *filename) { int ret; + char *dir; if (!link(tmpfile, filename)) return 0; /* - * Try to mkdir the last path component if that failed - * with an ENOENT. + * Try to mkdir the last path component if that failed. * * Re-try the "link()" regardless of whether the mkdir * succeeds, since a race might mean that somebody * else succeeded. */ ret = errno; - if (ret == ENOENT) { - char *dir = strrchr(filename, '/'); - if (dir) { - *dir = 0; - mkdir(filename, 0777); - if (adjust_shared_perm(filename)) - return -2; - *dir = '/'; - if (!link(tmpfile, filename)) - return 0; - ret = errno; - } + dir = strrchr(filename, '/'); + if (dir) { + *dir = 0; + mkdir(filename, 0777); + if (adjust_shared_perm(filename)) + return -2; + *dir = '/'; + if (!link(tmpfile, filename)) + return 0; + ret = errno; } return ret; } diff --git a/sha1_name.c b/sha1_name.c index f2cbafa496..5fe8e5d4bf 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -381,13 +381,13 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) sp++; /* beginning of type name, or closing brace for empty */ if (!strncmp(commit_type, sp, 6) && sp[6] == '}') - expected_type = TYPE_COMMIT; + expected_type = OBJ_COMMIT; else if (!strncmp(tree_type, sp, 4) && sp[4] == '}') - expected_type = TYPE_TREE; + expected_type = OBJ_TREE; else if (!strncmp(blob_type, sp, 4) && sp[4] == '}') - expected_type = TYPE_BLOB; + expected_type = OBJ_BLOB; else if (sp[0] == '}') - expected_type = TYPE_NONE; + expected_type = OBJ_NONE; else return -1; @@ -416,9 +416,9 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) memcpy(sha1, o->sha1, 20); return 0; } - if (o->type == TYPE_TAG) + if (o->type == OBJ_TAG) o = ((struct tag*) o)->tagged; - else if (o->type == TYPE_COMMIT) + else if (o->type == OBJ_COMMIT) o = &(((struct commit *) o)->tree->object); else return error("%.*s: expected %s type, but the object dereferences to %s type", diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 36658fb17d..b24c829f0f 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -7,6 +7,9 @@ test_description='Various diff formatting options' . ./test-lib.sh +LF=' +' + test_expect_success setup ' GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" && @@ -31,7 +34,7 @@ test_expect_success setup ' for i in C D; do echo $i; done >>dir/sub && rm -f file2 && git update-index --remove file0 file2 dir/sub && - git commit -m Second && + git commit -m "Second${LF}${LF}This is the second commit." && GIT_AUTHOR_DATE="2006-06-26 00:02:00 +0000" && GIT_COMMITTER_DATE="2006-06-26 00:02:00 +0000" && diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master index 0ac9800913..3a9f78a09d 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --patch-with-stat --summary master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master index f6ecf76366..49f23b9215 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --patch-with-stat master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master index 712ffd2d89..cc6eb3b3d5 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --stat --summary master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master index 8d5bdc985a..fae7f33255 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --stat master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_master b/t/t4013/diff.diff-tree_--cc_master index e57d943bdc..5ecb4e14ae 100644 --- a/t/t4013/diff.diff-tree_--cc_master +++ b/t/t4013/diff.diff-tree_--cc_master @@ -1,5 +1,5 @@ $ git diff-tree --cc master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --cc dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.diff-tree_-c_--abbrev_master b/t/t4013/diff.diff-tree_-c_--abbrev_master index 39d511a7cf..b8e4aa2530 100644 --- a/t/t4013/diff.diff-tree_-c_--abbrev_master +++ b/t/t4013/diff.diff-tree_-c_--abbrev_master @@ -1,5 +1,5 @@ $ git diff-tree -c --abbrev master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e... 7289e35... 992913c... MM dir/sub ::100644 100644 100644 b414108... f4615da... 10a8a9f... MM file0 $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master index 2d239feb5d..ac9f641fb4 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master @@ -1,5 +1,5 @@ $ git diff-tree -c --stat --summary master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master index 226300b93c..c2fe6a98c5 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_master +++ b/t/t4013/diff.diff-tree_-c_--stat_master @@ -1,5 +1,5 @@ $ git diff-tree -c --stat master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_-c_master b/t/t4013/diff.diff-tree_-c_master index c258efe222..e2d2bb2611 100644 --- a/t/t4013/diff.diff-tree_-c_master +++ b/t/t4013/diff.diff-tree_-c_master @@ -1,5 +1,5 @@ $ git diff-tree -c master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e925b1420c84c14cbf7cf755e7e45af8ad 7289e35bff32727c08dda207511bec138fdb9ea5 992913c5aa0a5476d10c49ed0f21fc0c6d1aedf3 MM dir/sub ::100644 100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 f4615da674c09df322d6ba8d6b21ecfb1b1ba510 10a8a9f3657f91a156b9f0184ed79a20adef9f7f MM file0 $ diff --git a/t/t4013/diff.diff-tree_-p_-m_master b/t/t4013/diff.diff-tree_-p_-m_master index 1be721560a..b60bea039d 100644 --- a/t/t4013/diff.diff-tree_-p_-m_master +++ b/t/t4013/diff.diff-tree_-p_-m_master @@ -1,5 +1,5 @@ $ git diff-tree -p -m master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --git a/dir/sub b/dir/sub index cead32e..992913c 100644 --- a/dir/sub @@ -21,7 +21,7 @@ index b414108..10a8a9f 100644 +A +B +C -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --git a/dir/sub b/dir/sub index 7289e35..992913c 100644 --- a/dir/sub diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index a89bbbbcfb..b4745e1001 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -1,5 +1,5 @@ $ git format-patch --attach --stdout initial..master -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second @@ -11,6 +11,9 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -18,10 +21,10 @@ Content-Transfer-Encoding: 8bit 3 files changed, 5 insertions(+), 3 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -57,7 +60,7 @@ index 01e79c3..0000000 -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third @@ -69,16 +72,17 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file1 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -116,6 +120,7 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index 4de9091a40..a9d1cd368b 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -1,5 +1,5 @@ $ git format-patch --attach --stdout initial..master^ -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second @@ -11,6 +11,9 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -18,10 +21,10 @@ Content-Transfer-Encoding: 8bit 3 files changed, 5 insertions(+), 3 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -57,7 +60,7 @@ index 01e79c3..0000000 -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third @@ -69,16 +72,17 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file1 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side index 3769fa6daf..57b9d0bdc1 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -11,6 +11,7 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master index b7b4e7ca91..c33302e92f 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--stdout_initial..master @@ -1,8 +1,10 @@ $ git format-patch --stdout initial..master -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -42,10 +44,11 @@ index 01e79c3..0000000 g-i-t--v-e-r-s-i-o-n -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third + --- dir/sub | 2 ++ file1 | 3 +++ @@ -78,6 +81,7 @@ From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^ index e56dd98df3..03d0f9693c 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_initial..master^ @@ -1,8 +1,10 @@ $ git format-patch --stdout initial..master^ -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -42,10 +44,11 @@ index 01e79c3..0000000 g-i-t--v-e-r-s-i-o-n -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third + --- dir/sub | 2 ++ file1 | 3 +++ diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side index e7ddbf4814..d10a46523b 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--stdout_initial..side @@ -3,6 +3,7 @@ From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ index cc5537697d..3ceb8e73c5 100644 --- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ @@ -1,6 +1,6 @@ $ git log --patch-with-stat --summary master -- dir/ -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -25,7 +25,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -45,11 +45,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master index b97969dc98..43d77761f9 100644 --- a/t/t4013/diff.log_--patch-with-stat_master +++ b/t/t4013/diff.log_--patch-with-stat_master @@ -1,6 +1,6 @@ $ git log --patch-with-stat master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -48,7 +48,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -78,11 +78,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ index 71a6d0f853..5187a26816 100644 --- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ @@ -1,6 +1,6 @@ $ git log --patch-with-stat master -- dir/ -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -25,7 +25,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -45,11 +45,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master index b652c6a823..c9640976a8 100644 --- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git log --root --cc --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master index b24a504759..ad050af55f 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git log --root --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -49,7 +49,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -80,11 +80,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master index 1e9bdc4c1c..628c6c03bc 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_master @@ -1,6 +1,6 @@ $ git log --root --patch-with-stat master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -48,7 +48,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -78,11 +78,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master index 3a155d288c..5d4e0f13b5 100644 --- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git log --root -c --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_-p_master b/t/t4013/diff.log_--root_-p_master index 2296986ad1..217a2eb203 100644 --- a/t/t4013/diff.log_--root_-p_master +++ b/t/t4013/diff.log_--root_-p_master @@ -1,6 +1,6 @@ $ git log --root -p master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -43,7 +43,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -69,11 +69,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.log_--root_master b/t/t4013/diff.log_--root_master index 7554a468d1..e17ccfc234 100644 --- a/t/t4013/diff.log_--root_master +++ b/t/t4013/diff.log_--root_master @@ -1,6 +1,6 @@ $ git log --root master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -12,17 +12,19 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 Third -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. commit 444ac553ac7612cc88969031b02b3767fb8a353a Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.log_-SF_-p_master b/t/t4013/diff.log_-SF_-p_master index db2264c6e9..5e32438972 100644 --- a/t/t4013/diff.log_-SF_-p_master +++ b/t/t4013/diff.log_-SF_-p_master @@ -1,5 +1,5 @@ $ git log -SF -p master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-SF_master b/t/t4013/diff.log_-SF_master index f307b4d2a8..6162ed2018 100644 --- a/t/t4013/diff.log_-SF_master +++ b/t/t4013/diff.log_-SF_master @@ -1,5 +1,5 @@ $ git log -SF master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-p_master b/t/t4013/diff.log_-p_master index e82a72f6f8..f8fefef2c3 100644 --- a/t/t4013/diff.log_-p_master +++ b/t/t4013/diff.log_-p_master @@ -1,6 +1,6 @@ $ git log -p master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -43,7 +43,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -69,11 +69,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.log_master b/t/t4013/diff.log_master index 7b86ed1f5d..e9d9e7b40a 100644 --- a/t/t4013/diff.log_master +++ b/t/t4013/diff.log_master @@ -1,6 +1,6 @@ $ git log master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -12,17 +12,19 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 Third -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. commit 444ac553ac7612cc88969031b02b3767fb8a353a Author: A U Thor <author@example.com> diff --git a/t/t4013/diff.show_master b/t/t4013/diff.show_master index 3772a87e13..9e6e1f2710 100644 --- a/t/t4013/diff.show_master +++ b/t/t4013/diff.show_master @@ -1,6 +1,6 @@ $ git show master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ index 054513f312..6a467cccc1 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ @@ -18,7 +18,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -38,11 +38,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master index a89b573f45..1e1bbe1963 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master @@ -41,7 +41,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -71,11 +71,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ index b6d9752164..13789f169b 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ @@ -18,7 +18,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -38,11 +38,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master index e9e17cdafb..5facf2543d 100644 --- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git whatchanged --root --cc --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master index f707bfa3a1..0291153587 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master @@ -42,7 +42,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -73,11 +73,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master index 61aca41711..9b0349cd55 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master @@ -41,7 +41,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -71,11 +71,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master index 596765e804..10f6767e49 100644 --- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git whatchanged --root -c --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_-p_master b/t/t4013/diff.whatchanged_--root_-p_master index b4cd05e576..ebf1f0661e 100644 --- a/t/t4013/diff.whatchanged_--root_-p_master +++ b/t/t4013/diff.whatchanged_--root_-p_master @@ -36,7 +36,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -62,11 +62,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.whatchanged_--root_master b/t/t4013/diff.whatchanged_--root_master index 011a22178f..a405cb6138 100644 --- a/t/t4013/diff.whatchanged_--root_master +++ b/t/t4013/diff.whatchanged_--root_master @@ -9,7 +9,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 :100644 100644 01e79c3... f4615da... M file0 :000000 100644 0000000... 7289e35... A file3 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -18,11 +18,13 @@ Date: Mon Jun 26 00:02:00 2006 +0000 :100644 100644 8422d40... cead32e... M dir/sub :000000 100644 0000000... b1e6722... A file1 -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. :100644 100644 35d242b... 8422d40... M dir/sub :100644 100644 01e79c3... b414108... M file0 diff --git a/t/t4013/diff.whatchanged_-SF_-p_master b/t/t4013/diff.whatchanged_-SF_-p_master index 6a76f4e604..f39da84822 100644 --- a/t/t4013/diff.whatchanged_-SF_-p_master +++ b/t/t4013/diff.whatchanged_-SF_-p_master @@ -1,5 +1,5 @@ $ git whatchanged -SF -p master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-SF_master b/t/t4013/diff.whatchanged_-SF_master index a4fe6f8a39..0499321d0e 100644 --- a/t/t4013/diff.whatchanged_-SF_master +++ b/t/t4013/diff.whatchanged_-SF_master @@ -1,5 +1,5 @@ $ git whatchanged -SF master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-p_master b/t/t4013/diff.whatchanged_-p_master index f9a4456725..f18d43209c 100644 --- a/t/t4013/diff.whatchanged_-p_master +++ b/t/t4013/diff.whatchanged_-p_master @@ -36,7 +36,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -62,11 +62,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.whatchanged_master b/t/t4013/diff.whatchanged_master index c22416c006..cd3bcc2c72 100644 --- a/t/t4013/diff.whatchanged_master +++ b/t/t4013/diff.whatchanged_master @@ -9,7 +9,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 :100644 100644 01e79c3... f4615da... M file0 :000000 100644 0000000... 7289e35... A file3 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:02:00 2006 +0000 @@ -18,11 +18,13 @@ Date: Mon Jun 26 00:02:00 2006 +0000 :100644 100644 8422d40... cead32e... M dir/sub :000000 100644 0000000... b1e6722... A file1 -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. :100644 100644 35d242b... 8422d40... M dir/sub :100644 100644 01e79c3... b414108... M file0 diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh index 1dce123aec..b15920b852 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -44,6 +44,43 @@ A=$(doit 1 A $B) G=$(doit 7 G $B $E) H=$(doit 8 H $A $F) +# Setup for second test to demonstrate that relying on timestamps in a +# distributed SCM to provide a _consistent_ partial ordering of commits +# leads to insanity. +# +# Relative +# Structure timestamps +# +# PL PR +4 +4 +# / \/ \ / \/ \ +# L2 C2 R2 +3 -1 +3 +# | | | | | | +# L1 C1 R1 +2 -2 +2 +# | | | | | | +# L0 C0 R0 +1 -3 +1 +# \ | / \ | / +# S 0 +# +# The left and right chains of commits can be of any length and complexity as +# long as all of the timestamps are greater than that of S. + +S=$(doit 0 S) + +C0=$(doit -3 C0 $S) +C1=$(doit -2 C1 $C0) +C2=$(doit -1 C2 $C1) + +L0=$(doit 1 L0 $S) +L1=$(doit 2 L1 $L0) +L2=$(doit 3 L2 $L1) + +R0=$(doit 1 R0 $S) +R1=$(doit 2 R1 $R0) +R2=$(doit 3 R2 $R1) + +PL=$(doit 4 PL $L2 $C2) +PR=$(doit 4 PR $C2 $R2) + test_expect_success 'compute merge-base (single)' \ 'MB=$(git-merge-base G H) && expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"' @@ -56,4 +93,12 @@ test_expect_success 'compute merge-base with show-branch' \ 'MB=$(git-show-branch --merge-base G H) && expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"' +test_expect_success 'compute merge-base (single)' \ + 'MB=$(git-merge-base PL PR) && + expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/C2"' + +test_expect_success 'compute merge-base (all)' \ + 'MB=$(git-merge-base --all PL PR) && + expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/C2"' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index b0d7990a66..470a909891 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -28,6 +28,7 @@ unset GIT_DIR unset GIT_EXTERNAL_DIFF unset GIT_INDEX_FILE unset GIT_OBJECT_DIRECTORY +unset GIT_TRACE unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME @@ -5,7 +5,7 @@ const char *tag_type = "tag"; struct object *deref_tag(struct object *o, const char *warn, int warnlen) { - while (o && o->type == TYPE_TAG) + while (o && o->type == OBJ_TAG) o = parse_object(((struct tag *)o)->tagged->sha1); if (!o && warn) { if (!warnlen) @@ -21,12 +21,12 @@ struct tag *lookup_tag(const unsigned char *sha1) if (!obj) { struct tag *ret = alloc_tag_node(); created_object(sha1, &ret->object); - ret->object.type = TYPE_TAG; + ret->object.type = OBJ_TAG; return ret; } if (!obj->type) - obj->type = TYPE_TAG; - if (obj->type != TYPE_TAG) { + obj->type = OBJ_TAG; + if (obj->type != OBJ_TAG) { error("Object %s is a %s, not a tree", sha1_to_hex(sha1), typename(obj->type)); return NULL; @@ -131,12 +131,12 @@ struct tree *lookup_tree(const unsigned char *sha1) if (!obj) { struct tree *ret = alloc_tree_node(); created_object(sha1, &ret->object); - ret->object.type = TYPE_TREE; + ret->object.type = OBJ_TREE; return ret; } if (!obj->type) - obj->type = TYPE_TREE; - if (obj->type != TYPE_TREE) { + obj->type = OBJ_TREE; + if (obj->type != OBJ_TREE) { error("Object %s is a %s, not a tree", sha1_to_hex(sha1), typename(obj->type)); return NULL; @@ -216,11 +216,11 @@ struct tree *parse_tree_indirect(const unsigned char *sha1) do { if (!obj) return NULL; - if (obj->type == TYPE_TREE) + if (obj->type == OBJ_TREE) return (struct tree *) obj; - else if (obj->type == TYPE_COMMIT) + else if (obj->type == OBJ_COMMIT) obj = &(((struct commit *) obj)->tree->object); - else if (obj->type == TYPE_TAG) + else if (obj->type == OBJ_TAG) obj = ((struct tag *) obj)->tagged; else return NULL; diff --git a/upload-pack.c b/upload-pack.c index b18eb9ba0d..f6f5a7e3db 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -51,6 +51,10 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz) if (fd == 3) /* emergency quit */ fd = 2; + if (fd == 2) { + xwrite(fd, data, sz); + return sz; + } return safe_write(fd, data, sz); } p = data; @@ -326,7 +330,7 @@ static int got_sha1(char *hex, unsigned char *sha1) o = parse_object(sha1); if (!o) die("oops (%s)", sha1_to_hex(sha1)); - if (o->type == TYPE_COMMIT) { + if (o->type == OBJ_COMMIT) { struct commit_list *parents; if (o->flags & THEY_HAVE) return 0; @@ -457,7 +461,7 @@ static int send_ref(const char *refname, const unsigned char *sha1) o->flags |= OUR_REF; nr_our_refs++; } - if (o->type == TYPE_TAG) { + if (o->type == OBJ_TAG) { o = deref_tag(o, refname, 0); packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname); } diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 2ce10b4c0d..c9f817818a 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -39,6 +39,7 @@ extern "C" { #define XDL_PATCH_IGNOREBSPACE (1 << 8) #define XDL_EMIT_FUNCNAMES (1 << 0) +#define XDL_EMIT_COMMON (1 << 1) #define XDL_MMB_READONLY (1 << 0) diff --git a/xdiff/xemit.c b/xdiff/xemit.c index ad5bfb1910..714c563547 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -100,6 +100,21 @@ static void xdl_find_func(xdfile_t *xf, long i, char *buf, long sz, long *ll) { } +int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, + xdemitconf_t const *xecfg) { + xdfile_t *xdf = &xe->xdf1; + const char *rchg = xdf->rchg; + long ix; + + for (ix = 0; ix < xdf->nrec; ix++) { + if (rchg[ix]) + continue; + if (xdl_emit_record(xdf, ix, "", ecb)) + return -1; + } + return 0; +} + int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { long s1, s2, e1, e2, lctx; @@ -107,6 +122,9 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, char funcbuf[40]; long funclen = 0; + if (xecfg->flags & XDL_EMIT_COMMON) + return xdl_emit_common(xe, xscr, ecb, xecfg); + for (xch = xche = xscr; xch; xch = xche->next) { xche = xdl_get_hunk(xch, xecfg); |