#include "cache.h"
+#include "commit-reach.h"
#include "config.h"
#include "diff.h"
+#include "environment.h"
+#include "hex.h"
#include "object-store.h"
#include "repository.h"
+#include "tmp-objdir.h"
#include "commit.h"
#include "tag.h"
#include "graph.h"
#include "log-tree.h"
+#include "merge-ort.h"
#include "reflog-walk.h"
#include "refs.h"
+#include "replace-object.h"
#include "string-list.h"
#include "color.h"
#include "gpg-interface.h"
#include "line-log.h"
#include "help.h"
#include "range-diff.h"
+#include "strmap.h"
static struct decoration name_decoration = { "object names" };
static int decoration_loaded;
const struct string_list_item *item)
{
int matched = 0;
- if (item->util == NULL) {
+ if (!item->util) {
if (!wildmatch(item->string, refname, 0))
matched = 1;
} else {
}
static int add_ref_decoration(const char *refname, const struct object_id *oid,
- int flags, void *cb_data)
+ int flags UNUSED,
+ void *cb_data)
{
+ int i;
struct object *obj;
enum object_type objtype;
enum decoration_type deco_type = DECORATION_NONE;
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
+ const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
if (filter && !ref_filter_match(refname, filter))
return 0;
return 0;
obj = lookup_object_by_type(the_repository, oid, objtype);
- if (starts_with(refname, "refs/heads/"))
- deco_type = DECORATION_REF_LOCAL;
- else if (starts_with(refname, "refs/remotes/"))
- deco_type = DECORATION_REF_REMOTE;
- else if (starts_with(refname, "refs/tags/"))
- deco_type = DECORATION_REF_TAG;
- else if (!strcmp(refname, "refs/stash"))
- deco_type = DECORATION_REF_STASH;
- else if (!strcmp(refname, "HEAD"))
- deco_type = DECORATION_REF_HEAD;
+ for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
+ struct ref_namespace_info *info = &ref_namespace[i];
+
+ if (!info->decoration)
+ continue;
+ if (info->exact) {
+ if (!strcmp(refname, info->ref)) {
+ deco_type = info->decoration;
+ break;
+ }
+ } else if (starts_with(refname, info->ref)) {
+ deco_type = info->decoration;
+ break;
+ }
+ }
add_name_decoration(deco_type, refname, obj);
while (obj->type == OBJ_TAG) {
return 0;
}
-static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
+static int add_graft_decoration(const struct commit_graft *graft,
+ void *cb_data UNUSED)
{
struct commit *commit = lookup_commit(the_repository, &graft->oid);
if (!commit)
struct strbuf signature = STRBUF_INIT;
hash_object_file(the_hash_algo, extra->value, extra->len,
- type_name(OBJ_TAG), &oid);
+ OBJ_TAG, &oid);
tag = lookup_tag(the_repository, &oid);
if (!tag)
return -1; /* error message already given */
opt->shown_dashes = 0;
diffcore_std(&opt->diffopt);
- if (diff_queue_is_empty()) {
+ if (diff_queue_is_empty(&opt->diffopt)) {
int saved_fmt = opt->diffopt.output_format;
opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_flush(&opt->diffopt);
return !opt->loginfo;
}
+static void setup_additional_headers(struct diff_options *o,
+ struct strmap *all_headers)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+
+ /*
+ * Make o->additional_path_headers contain the subset of all_headers
+ * that match o->pathspec. If there aren't any that match o->pathspec,
+ * then make o->additional_path_headers be NULL.
+ */
+
+ if (!o->pathspec.nr) {
+ o->additional_path_headers = all_headers;
+ return;
+ }
+
+ o->additional_path_headers = xmalloc(sizeof(struct strmap));
+ strmap_init_with_options(o->additional_path_headers, NULL, 0);
+ strmap_for_each_entry(all_headers, &iter, entry) {
+ if (match_pathspec(the_repository->index, &o->pathspec,
+ entry->key, strlen(entry->key),
+ 0 /* prefix */, NULL /* seen */,
+ 0 /* is_dir */))
+ strmap_put(o->additional_path_headers,
+ entry->key, entry->value);
+ }
+ if (!strmap_get_size(o->additional_path_headers)) {
+ strmap_clear(o->additional_path_headers, 0);
+ FREE_AND_NULL(o->additional_path_headers);
+ }
+}
+
+static void cleanup_additional_headers(struct diff_options *o)
+{
+ if (!o->pathspec.nr) {
+ o->additional_path_headers = NULL;
+ return;
+ }
+ if (!o->additional_path_headers)
+ return;
+
+ strmap_clear(o->additional_path_headers, 0);
+ FREE_AND_NULL(o->additional_path_headers);
+}
+
+static int do_remerge_diff(struct rev_info *opt,
+ struct commit_list *parents,
+ struct object_id *oid)
+{
+ struct merge_options o;
+ struct commit_list *bases;
+ struct merge_result res = {0};
+ struct pretty_print_context ctx = {0};
+ struct commit *parent1 = parents->item;
+ struct commit *parent2 = parents->next->item;
+ struct strbuf parent1_desc = STRBUF_INIT;
+ struct strbuf parent2_desc = STRBUF_INIT;
+
+ /* Setup merge options */
+ init_merge_options(&o, the_repository);
+ o.show_rename_progress = 0;
+ o.record_conflict_msgs_as_headers = 1;
+ o.msg_header_prefix = "remerge";
+
+ ctx.abbrev = DEFAULT_ABBREV;
+ format_commit_message(parent1, "%h (%s)", &parent1_desc, &ctx);
+ format_commit_message(parent2, "%h (%s)", &parent2_desc, &ctx);
+ o.branch1 = parent1_desc.buf;
+ o.branch2 = parent2_desc.buf;
+
+ /* Parse the relevant commits and get the merge bases */
+ parse_commit_or_die(parent1);
+ parse_commit_or_die(parent2);
+ bases = get_merge_bases(parent1, parent2);
+
+ /* Re-merge the parents */
+ merge_incore_recursive(&o, bases, parent1, parent2, &res);
+
+ /* Show the diff */
+ setup_additional_headers(&opt->diffopt, res.path_messages);
+ diff_tree_oid(&res.tree->object.oid, oid, "", &opt->diffopt);
+ log_tree_diff_flush(opt);
+
+ /* Cleanup */
+ cleanup_additional_headers(&opt->diffopt);
+ strbuf_release(&parent1_desc);
+ strbuf_release(&parent2_desc);
+ merge_finalize(&o, &res);
+
+ /* Clean up the contents of the temporary object directory */
+ if (opt->remerge_objdir)
+ tmp_objdir_discard_objects(opt->remerge_objdir);
+ else
+ BUG("did a remerge diff without remerge_objdir?!?");
+
+ return !opt->loginfo;
+}
+
/*
* Show the diff of a commit.
*
}
if (is_merge) {
+ int octopus = (parents->next->next != NULL);
+
+ if (opt->remerge_diff) {
+ if (octopus) {
+ show_log(opt);
+ fprintf(opt->diffopt.file,
+ "diff: warning: Skipping remerge-diff "
+ "for octopus merges.\n");
+ return 1;
+ }
+ return do_remerge_diff(opt, parents, oid);
+ }
if (opt->combine_merges)
return do_diff_combined(opt, commit);
if (opt->separate_merges) {
opt->loginfo = &log;
opt->diffopt.no_free = 1;
+ /* NEEDSWORK: no restoring of no_free? Why? */
if (opt->line_level_traverse)
return line_log_print(opt, commit);