Staging
v0.5.1
https://github.com/git/git
Revision 39ba7d54649b35c943b026b54bff40cfa0153f3e authored by Martin Mares on 18 February 2006, 20:44:20 UTC, committed by Junio C Hamano on 19 February 2006, 00:19:00 UTC
Fixed a couple of bugs in recovering from broken connections:

The _line() method now returns undef correctly when the connection
is broken instead of falling off the function and returning garbage.

Retries are now reported to stderr and the eventual partially
downloaded file is discarded instead of being appended to.

The "Server gone away" test has been removed, because it was
reachable only if the garbage return bug bit.

Signed-off-by: Martin Mares <mj@ucw.cz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
1 parent 3ff903b
Raw File
Tip revision: 39ba7d54649b35c943b026b54bff40cfa0153f3e authored by Martin Mares on 18 February 2006, 20:44:20 UTC
Fix retries in git-cvsimport
Tip revision: 39ba7d5
diff-tree.c
#include "cache.h"
#include "diff.h"
#include "commit.h"

static int show_root_diff = 0;
static int no_commit_id = 0;
static int verbose_header = 0;
static int ignore_merges = 1;
static int combine_merges = 0;
static int dense_combined_merges = 0;
static int read_stdin = 0;
static int always_show_header = 0;

static const char *header = NULL;
static const char *header_prefix = "";
static enum cmit_fmt commit_format = CMIT_FMT_RAW;

static struct diff_options diff_options;

static int call_diff_flush(void)
{
	diffcore_std(&diff_options);
	if (diff_queue_is_empty()) {
		int saved_fmt = diff_options.output_format;
		diff_options.output_format = DIFF_FORMAT_NO_OUTPUT;
		diff_flush(&diff_options);
		diff_options.output_format = saved_fmt;
		return 0;
	}
	if (header) {
		if (!no_commit_id)
			printf("%s%c", header, diff_options.line_termination);
		header = NULL;
	}
	diff_flush(&diff_options);
	return 1;
}

static int diff_tree_sha1_top(const unsigned char *old,
			      const unsigned char *new, const char *base)
{
	int ret;

	ret = diff_tree_sha1(old, new, base, &diff_options);
	call_diff_flush();
	return ret;
}

static int diff_root_tree(const unsigned char *new, const char *base)
{
	int retval;
	void *tree;
	struct tree_desc empty, real;

	tree = read_object_with_reference(new, "tree", &real.size, NULL);
	if (!tree)
		die("unable to read root tree (%s)", sha1_to_hex(new));
	real.buf = tree;

	empty.buf = "";
	empty.size = 0;
	retval = diff_tree(&empty, &real, base, &diff_options);
	free(tree);
	call_diff_flush();
	return retval;
}

static const char *generate_header(const unsigned char *commit_sha1,
				   const unsigned char *parent_sha1,
				   const struct commit *commit)
{
	static char this_header[16384];
	int offset;
	unsigned long len;
	int abbrev = diff_options.abbrev;
	const char *msg = commit->buffer;

	if (!verbose_header)
		return sha1_to_hex(commit_sha1);

	len = strlen(msg);

	offset = sprintf(this_header, "%s%s ",
			 header_prefix,
			 diff_unique_abbrev(commit_sha1, abbrev));
	if (commit_sha1 != parent_sha1)
		offset += sprintf(this_header + offset, "(from %s)\n",
				  parent_sha1
				  ? diff_unique_abbrev(parent_sha1, abbrev)
				  : "root");
	else
		offset += sprintf(this_header + offset, "(from parents)\n");
	offset += pretty_print_commit(commit_format, commit, len,
				      this_header + offset,
				      sizeof(this_header) - offset, abbrev);
	if (always_show_header) {
		puts(this_header);
		return NULL;
	}
	return this_header;
}

static int diff_tree_commit(struct commit *commit)
{
	struct commit_list *parents;
	unsigned const char *sha1 = commit->object.sha1;

	/* Root commit? */
	if (show_root_diff && !commit->parents) {
		header = generate_header(sha1, NULL, commit);
		diff_root_tree(sha1, "");
	}

	/* More than one parent? */
	if (commit->parents && commit->parents->next) {
		if (ignore_merges)
			return 0;
		else if (combine_merges) {
			header = generate_header(sha1, sha1, commit);
			header = diff_tree_combined_merge(sha1, header,
							dense_combined_merges,
							&diff_options);
			if (!header && verbose_header)
				header_prefix = "\ndiff-tree ";
			return 0;
		}
	}

	for (parents = commit->parents; parents; parents = parents->next) {
		struct commit *parent = parents->item;
		header = generate_header(sha1, parent->object.sha1, commit);
		diff_tree_sha1_top(parent->object.sha1, sha1, "");
		if (!header && verbose_header) {
			header_prefix = "\ndiff-tree ";
			/*
			 * Don't print multiple merge entries if we
			 * don't print the diffs.
			 */
		}
	}
	return 0;
}

static int diff_tree_commit_sha1(const unsigned char *sha1)
{
	struct commit *commit = lookup_commit_reference(sha1);
	if (!commit)
		return -1;
	return diff_tree_commit(commit);
}

static int diff_tree_stdin(char *line)
{
	int len = strlen(line);
	unsigned char sha1[20];
	struct commit *commit;

	if (!len || line[len-1] != '\n')
		return -1;
	line[len-1] = 0;
	if (get_sha1_hex(line, sha1))
		return -1;
	commit = lookup_commit(sha1);
	if (!commit || parse_commit(commit))
		return -1;
	if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) {
		/* Graft the fake parents locally to the commit */
		int pos = 41;
		struct commit_list **pptr, *parents;

		/* Free the real parent list */
		for (parents = commit->parents; parents; ) {
			struct commit_list *tmp = parents->next;
			free(parents);
			parents = tmp;
		}
		commit->parents = NULL;
		pptr = &(commit->parents);
		while (line[pos] && !get_sha1_hex(line + pos, sha1)) {
			struct commit *parent = lookup_commit(sha1);
			if (parent) {
				pptr = &commit_list_insert(parent, pptr)->next;
			}
			pos += 41;
		}
	}
	return diff_tree_commit(commit);
}

static const char diff_tree_usage[] =
"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
"  -r            diff recursively\n"
"  --root        include the initial commit as diff against /dev/null\n"
COMMON_DIFF_OPTIONS_HELP;

int main(int argc, const char **argv)
{
	int nr_sha1;
	char line[1000];
	unsigned char sha1[2][20];
	const char *prefix = setup_git_directory();

	git_config(git_diff_config);
	nr_sha1 = 0;
	diff_setup(&diff_options);

	for (;;) {
		int diff_opt_cnt;
		const char *arg;

		argv++;
		argc--;
		arg = *argv;
		if (!arg)
			break;

		if (*arg != '-') {
			if (nr_sha1 < 2 && !get_sha1(arg, sha1[nr_sha1])) {
				nr_sha1++;
				continue;
			}
			break;
		}

		diff_opt_cnt = diff_opt_parse(&diff_options, argv, argc);
		if (diff_opt_cnt < 0)
			usage(diff_tree_usage);
		else if (diff_opt_cnt) {
			argv += diff_opt_cnt - 1;
			argc -= diff_opt_cnt - 1;
			continue;
		}


		if (!strcmp(arg, "--")) {
			argv++;
			argc--;
			break;
		}
		if (!strcmp(arg, "-r")) {
			diff_options.recursive = 1;
			continue;
		}
		if (!strcmp(arg, "-t")) {
			diff_options.recursive = 1;
			diff_options.tree_in_recursive = 1;
			continue;
		}
		if (!strcmp(arg, "-m")) {
			ignore_merges = 0;
			continue;
		}
		if (!strcmp(arg, "-c")) {
			combine_merges = 1;
			continue;
		}
		if (!strcmp(arg, "--cc")) {
			dense_combined_merges = combine_merges = 1;
			continue;
		}
		if (!strcmp(arg, "-v")) {
			verbose_header = 1;
			header_prefix = "diff-tree ";
			continue;
		}
		if (!strncmp(arg, "--pretty", 8)) {
			verbose_header = 1;
			header_prefix = "diff-tree ";
			commit_format = get_commit_format(arg+8);
			continue;
		}
		if (!strcmp(arg, "--stdin")) {
			read_stdin = 1;
			continue;
		}
		if (!strcmp(arg, "--root")) {
			show_root_diff = 1;
			continue;
		}
		if (!strcmp(arg, "--no-commit-id")) {
			no_commit_id = 1;
			continue;
		}
		if (!strcmp(arg, "--always")) {
			always_show_header = 1;
			continue;
		}
		usage(diff_tree_usage);
	}

	if (combine_merges)
		ignore_merges = 0;

	/* We can only do dense combined merges with diff output */
	if (dense_combined_merges)
		diff_options.output_format = DIFF_FORMAT_PATCH;

	if (diff_options.output_format == DIFF_FORMAT_PATCH)
		diff_options.recursive = 1;

	diff_tree_setup_paths(get_pathspec(prefix, argv));
	diff_setup_done(&diff_options);

	switch (nr_sha1) {
	case 0:
		if (!read_stdin)
			usage(diff_tree_usage);
		break;
	case 1:
		diff_tree_commit_sha1(sha1[0]);
		break;
	case 2:
		diff_tree_sha1_top(sha1[0], sha1[1], "");
		break;
	}

	if (!read_stdin)
		return 0;

	if (diff_options.detect_rename)
		diff_options.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
				       DIFF_SETUP_USE_CACHE);
	while (fgets(line, sizeof(line), stdin))
		diff_tree_stdin(line);

	return 0;
}
back to top