Beispiel #1
0
int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
{
	const unsigned char *bases[21];
	unsigned bases_count = 0;
	int i, failed;
	unsigned char h1[20], h2[20];
	struct merge_options o;
	struct commit *result;

	init_merge_options(&o);
	if (argv[0] && ends_with(argv[0], "-subtree"))
		o.subtree_shift = "";

	if (argc < 4)
		usagef(builtin_merge_recursive_usage, argv[0]);

	for (i = 1; i < argc; ++i) {
		const char *arg = argv[i];

		if (starts_with(arg, "--")) {
			if (!arg[2])
				break;
			if (parse_merge_opt(&o, arg + 2))
				die("Unknown option %s", arg);
			continue;
		}
		if (bases_count < ARRAY_SIZE(bases)-1) {
			unsigned char *sha = xmalloc(20);
			if (get_sha1(argv[i], sha))
				die("Could not parse object '%s'", argv[i]);
			bases[bases_count++] = sha;
		}
		else
			warning("Cannot handle more than %d bases. "
				"Ignoring %s.",
				(int)ARRAY_SIZE(bases)-1, argv[i]);
	}
	if (argc - i != 3) /* "--" "<head>" "<remote>" */
		die("Not handling anything other than two heads merge.");

	o.branch1 = argv[++i];
	o.branch2 = argv[++i];

	if (get_sha1(o.branch1, h1))
		die("Could not resolve ref '%s'", o.branch1);
	if (get_sha1(o.branch2, h2))
		die("Could not resolve ref '%s'", o.branch2);

	o.branch1 = better_branch_name(o.branch1);
	o.branch2 = better_branch_name(o.branch2);

	if (o.verbosity >= 3)
		printf("Merging %s with %s\n", o.branch1, o.branch2);

	failed = merge_recursive_generic(&o, h1, h2, bases_count, bases, &result);
	if (failed < 0)
		return 128; /* die() error code */
	return failed;
}
Beispiel #2
0
void NORETURN usage(const char *err)
{
	usagef("%s", err);
}
Beispiel #3
0
int cmd_diff(int argc, const char **argv, const char *prefix)
{
	int i;
	struct rev_info rev;
	struct object_array ent = OBJECT_ARRAY_INIT;
	int blobs = 0, paths = 0;
	struct blobinfo blob[2];
	int nongit = 0, no_index = 0;
	int result = 0;

	/*
	 * We could get N tree-ish in the rev.pending_objects list.
	 * Also there could be M blobs there, and P pathspecs.
	 *
	 * N=0, M=0:
	 *	cache vs files (diff-files)
	 * N=0, M=2:
	 *      compare two random blobs.  P must be zero.
	 * N=0, M=1, P=1:
	 *	compare a blob with a working tree file.
	 *
	 * N=1, M=0:
	 *      tree vs cache (diff-index --cached)
	 *
	 * N=2, M=0:
	 *      tree vs tree (diff-tree)
	 *
	 * N=0, M=0, P=2:
	 *      compare two filesystem entities (aka --no-index).
	 *
	 * Other cases are errors.
	 */

	/* Were we asked to do --no-index explicitly? */
	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "--")) {
			i++;
			break;
		}
		if (!strcmp(argv[i], "--no-index"))
			no_index = DIFF_NO_INDEX_EXPLICIT;
		if (argv[i][0] != '-')
			break;
	}

	if (!no_index)
		prefix = setup_git_directory_gently(&nongit);

	/*
	 * Treat git diff with at least one path outside of the
	 * repo the same as if the command would have been executed
	 * outside of a git repository.  In this case it behaves
	 * the same way as "git diff --no-index <a> <b>", which acts
	 * as a colourful "diff" replacement.
	 */
	if (nongit || ((argc == i + 2) &&
		       (!path_inside_repo(prefix, argv[i]) ||
			!path_inside_repo(prefix, argv[i + 1]))))
		no_index = DIFF_NO_INDEX_IMPLICIT;

	if (!no_index)
		gitmodules_config();
	init_diff_ui_defaults();
	git_config(git_diff_ui_config, NULL);
	precompose_argv(argc, argv);

	init_revisions(&rev, prefix);

	if (no_index && argc != i + 2) {
		if (no_index == DIFF_NO_INDEX_IMPLICIT) {
			/*
			 * There was no --no-index and there were not two
			 * paths. It is possible that the user intended
			 * to do an inside-repository operation.
			 */
			fprintf(stderr, "Not a git repository\n");
			fprintf(stderr,
				"To compare two paths outside a working tree:\n");
		}
		/* Give the usage message for non-repository usage and exit. */
		usagef("git diff %s <path> <path>",
		       no_index == DIFF_NO_INDEX_EXPLICIT ?
		       "--no-index" : "[--no-index]");

	}
	if (no_index)
		/* If this is a no-index diff, just run it and exit there. */
		diff_no_index(&rev, argc, argv);

	/* Otherwise, we are doing the usual "git" diff */
	rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;

	/* Scale to real terminal size and respect statGraphWidth config */
	rev.diffopt.stat_width = -1;
	rev.diffopt.stat_graph_width = -1;

	/* Default to let external and textconv be used */
	DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
	DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);

	if (nongit)
		die(_("Not a git repository"));
	argc = setup_revisions(argc, argv, &rev, NULL);
	if (!rev.diffopt.output_format) {
		rev.diffopt.output_format = DIFF_FORMAT_PATCH;
		diff_setup_done(&rev.diffopt);
	}

	DIFF_OPT_SET(&rev.diffopt, RECURSIVE);

	setup_diff_pager(&rev.diffopt);

	/*
	 * Do we have --cached and not have a pending object, then
	 * default to HEAD by hand.  Eek.
	 */
	if (!rev.pending.nr) {
		int i;
		for (i = 1; i < argc; i++) {
			const char *arg = argv[i];
			if (!strcmp(arg, "--"))
				break;
			else if (!strcmp(arg, "--cached") ||
				 !strcmp(arg, "--staged")) {
				add_head_to_pending(&rev);
				if (!rev.pending.nr) {
					struct tree *tree;
					tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
					add_pending_object(&rev, &tree->object, "HEAD");
				}
				break;
			}
		}
	}

	for (i = 0; i < rev.pending.nr; i++) {
		struct object_array_entry *entry = &rev.pending.objects[i];
		struct object *obj = entry->item;
		const char *name = entry->name;
		int flags = (obj->flags & UNINTERESTING);
		if (!obj->parsed)
			obj = parse_object(obj->oid.hash);
		obj = deref_tag(obj, NULL, 0);
		if (!obj)
			die(_("invalid object '%s' given."), name);
		if (obj->type == OBJ_COMMIT)
			obj = &((struct commit *)obj)->tree->object;

		if (obj->type == OBJ_TREE) {
			obj->flags |= flags;
			add_object_array(obj, name, &ent);
		} else if (obj->type == OBJ_BLOB) {
			if (2 <= blobs)
				die(_("more than two blobs given: '%s'"), name);
			hashcpy(blob[blobs].sha1, obj->oid.hash);
			blob[blobs].name = name;
			blob[blobs].mode = entry->mode;
			blobs++;

		} else {
			die(_("unhandled object '%s' given."), name);
		}
	}
	if (rev.prune_data.nr)
		paths += rev.prune_data.nr;

	/*
	 * Now, do the arguments look reasonable?
	 */
	if (!ent.nr) {
		switch (blobs) {
		case 0:
			result = builtin_diff_files(&rev, argc, argv);
			break;
		case 1:
			if (paths != 1)
				usage(builtin_diff_usage);
			result = builtin_diff_b_f(&rev, argc, argv, blob);
			break;
		case 2:
			if (paths)
				usage(builtin_diff_usage);
			result = builtin_diff_blobs(&rev, argc, argv, blob);
			break;
		default:
			usage(builtin_diff_usage);
		}
	}
	else if (blobs)
		usage(builtin_diff_usage);
	else if (ent.nr == 1)
		result = builtin_diff_index(&rev, argc, argv);
	else if (ent.nr == 2)
		result = builtin_diff_tree(&rev, argc, argv,
					   &ent.objects[0], &ent.objects[1]);
	else if (ent.objects[0].item->flags & UNINTERESTING) {
		/*
		 * diff A...B where there is at least one merge base
		 * between A and B.  We have ent.objects[0] ==
		 * merge-base, ent.objects[ents-2] == A, and
		 * ent.objects[ents-1] == B.  Show diff between the
		 * base and B.  Note that we pick one merge base at
		 * random if there are more than one.
		 */
		result = builtin_diff_tree(&rev, argc, argv,
					   &ent.objects[0],
					   &ent.objects[ent.nr-1]);
	} else
		result = builtin_diff_combined(&rev, argc, argv,
					       ent.objects, ent.nr);
	result = diff_result_code(&rev.diffopt, result);
	if (1 < rev.diffopt.skip_stat_unmatch)
		refresh_index_quietly();
	return result;
}
Beispiel #4
0
void diff_no_index(struct rev_info *revs,
		   int argc, const char **argv,
		   int nongit, const char *prefix)
{
	int i, prefixlen;
	int no_index = 0;
	unsigned options = 0;
	const char *paths[2];

	/* Were we asked to do --no-index explicitly? */
	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "--")) {
			i++;
			break;
		}
		if (!strcmp(argv[i], "--no-index"))
			no_index = 1;
		if (argv[i][0] != '-')
			break;
	}

	if (!no_index && !nongit) {
		/*
		 * Inside a git repository, without --no-index.  Only
		 * when a path outside the repository is given,
		 * e.g. "git diff /var/tmp/[12]", or "git diff
		 * Makefile /var/tmp/Makefile", allow it to be used as
		 * a colourful "diff" replacement.
		 */
		if ((argc != i + 2) ||
		    (path_inside_repo(prefix, argv[i]) &&
		     path_inside_repo(prefix, argv[i+1])))
			return;
	}
	if (argc != i + 2)
		usagef("git diff %s <path> <path>",
		       no_index ? "--no-index" : "[--no-index]");

	diff_setup(&revs->diffopt);
	for (i = 1; i < argc - 2; ) {
		int j;
		if (!strcmp(argv[i], "--no-index"))
			i++;
		else if (!strcmp(argv[i], "-q")) {
			options |= DIFF_SILENT_ON_REMOVED;
			i++;
		}
		else if (!strcmp(argv[i], "--"))
			i++;
		else {
			j = diff_opt_parse(&revs->diffopt, argv + i, argc - i);
			if (!j)
				die("invalid diff option/value: %s", argv[i]);
			i += j;
		}
	}

	prefixlen = prefix ? strlen(prefix) : 0;
	for (i = 0; i < 2; i++) {
		const char *p = argv[argc - 2 + i];
		if (!strcmp(p, "-"))
			/*
			 * stdin should be spelled as "-"; if you have
			 * path that is "-", spell it as "./-".
			 */
			p = file_from_standard_input;
		else if (prefixlen)
			p = xstrdup(prefix_filename(prefix, prefixlen, p));
		paths[i] = p;
	}
	revs->diffopt.skip_stat_unmatch = 1;
	if (!revs->diffopt.output_format)
		revs->diffopt.output_format = DIFF_FORMAT_PATCH;

	DIFF_OPT_SET(&revs->diffopt, NO_INDEX);

	revs->max_count = -2;
	diff_setup_done(&revs->diffopt);

	setup_diff_pager(&revs->diffopt);
	DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);

	if (queue_diff(&revs->diffopt, paths[0], paths[1]))
		exit(1);
	diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
	diffcore_std(&revs->diffopt);
	diff_flush(&revs->diffopt);

	/*
	 * The return code for --no-index imitates diff(1):
	 * 0 = no changes, 1 = changes, else error
	 */
	exit(diff_result_code(&revs->diffopt, 0));
}
Beispiel #5
0
void usage(const char *err)
{
	usagef("%s", err);
}