コード例 #1
0
ファイル: reset.c プロジェクト: julesbowden/git
int cmd_reset(int argc, const char **argv, const char *prefix)
{
    int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
    int patch_mode = 0;
    const char *rev = "HEAD";
    unsigned char sha1[20], *orig = NULL, sha1_orig[20],
                             *old_orig = NULL, sha1_old_orig[20];
    struct commit *commit;
    struct strbuf msg = STRBUF_INIT;
    const struct option options[] = {
        OPT__QUIET(&quiet, "be quiet, only report errors"),
        OPT_SET_INT(0, "mixed", &reset_type,
        "reset HEAD and index", MIXED),
        OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
        OPT_SET_INT(0, "hard", &reset_type,
        "reset HEAD, index and working tree", HARD),
        OPT_SET_INT(0, "merge", &reset_type,
        "reset HEAD, index and working tree", MERGE),
        OPT_SET_INT(0, "keep", &reset_type,
        "reset HEAD but keep local changes", KEEP),
        OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
        OPT_END()
    };

    git_config(git_default_config, NULL);

    argc = parse_options(argc, argv, prefix, options, git_reset_usage,
                         PARSE_OPT_KEEP_DASHDASH);

    /*
     * Possible arguments are:
     *
     * git reset [-opts] <rev> <paths>...
     * git reset [-opts] <rev> -- <paths>...
     * git reset [-opts] -- <paths>...
     * git reset [-opts] <paths>...
     *
     * At this point, argv[i] points immediately after [-opts].
     */

    if (i < argc) {
        if (!strcmp(argv[i], "--")) {
            i++; /* reset to HEAD, possibly with paths */
        } else if (i + 1 < argc && !strcmp(argv[i+1], "--")) {
            rev = argv[i];
            i += 2;
        }
        /*
         * Otherwise, argv[i] could be either <rev> or <paths> and
         * has to be unambiguous.
         */
        else if (!get_sha1(argv[i], sha1)) {
            /*
             * Ok, argv[i] looks like a rev; it should not
             * be a filename.
             */
            verify_non_filename(prefix, argv[i]);
            rev = argv[i++];
        } else {
            /* Otherwise we treat this as a filename */
            verify_filename(prefix, argv[i]);
        }
    }

    if (get_sha1(rev, sha1))
        die(_("Failed to resolve '%s' as a valid ref."), rev);

    commit = lookup_commit_reference(sha1);
    if (!commit)
        die(_("Could not parse object '%s'."), rev);
    hashcpy(sha1, commit->object.sha1);

    if (patch_mode) {
        if (reset_type != NONE)
            die(_("--patch is incompatible with --{hard,mixed,soft}"));
        return interactive_reset(rev, argv + i, prefix);
    }

    /* git reset tree [--] paths... can be used to
     * load chosen paths from the tree into the index without
     * affecting the working tree nor HEAD. */
    if (i < argc) {
        if (reset_type == MIXED)
            warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
        else if (reset_type != NONE)
            die(_("Cannot do %s reset with paths."),
                _(reset_type_names[reset_type]));
        return read_from_tree(prefix, argv + i, sha1,
                              quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
    }
    if (reset_type == NONE)
        reset_type = MIXED; /* by default */

    if (reset_type != SOFT && reset_type != MIXED)
        setup_work_tree();

    if (reset_type == MIXED && is_bare_repository())
        die(_("%s reset is not allowed in a bare repository"),
            _(reset_type_names[reset_type]));

    /* Soft reset does not touch the index file nor the working tree
     * at all, but requires them in a good order.  Other resets reset
     * the index file to the tree object we are switching to. */
    if (reset_type == SOFT)
        die_if_unmerged_cache(reset_type);
    else {
        int err;
        if (reset_type == KEEP)
            die_if_unmerged_cache(reset_type);
        err = reset_index_file(sha1, reset_type, quiet);
        if (reset_type == KEEP)
            err = err || reset_index_file(sha1, MIXED, quiet);
        if (err)
            die(_("Could not reset index file to revision '%s'."), rev);
    }

    /* Any resets update HEAD to the head being switched to,
     * saving the previous head in ORIG_HEAD before. */
    if (!get_sha1("ORIG_HEAD", sha1_old_orig))
        old_orig = sha1_old_orig;
    if (!get_sha1("HEAD", sha1_orig)) {
        orig = sha1_orig;
        set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
        update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
    }
    else if (old_orig)
        delete_ref("ORIG_HEAD", old_orig, 0);
    set_reflog_message(&msg, "updating HEAD", rev);
    update_ref_status = update_ref(msg.buf, "HEAD", sha1, orig, 0, MSG_ON_ERR);

    switch (reset_type) {
    case HARD:
        if (!update_ref_status && !quiet)
            print_new_head_line(commit);
        break;
    case SOFT: /* Nothing else to do. */
        break;
    case MIXED: /* Report what has not been updated. */
        update_index_refresh(0, NULL,
                             quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
        break;
    }

    remove_branch_state();

    strbuf_release(&msg);

    return update_ref_status;
}
コード例 #2
0
ファイル: connect.c プロジェクト: 13leaf/git
static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
{
	ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
	hashcpy(&(extra->array[extra->nr][0]), sha1);
	extra->nr++;
}
コード例 #3
0
ファイル: refs.c プロジェクト: atispor/git
int rename_ref(const char *oldref, const char *newref, const char *logmsg)
{
	static const char renamed_ref[] = "RENAMED-REF";
	unsigned char sha1[20], orig_sha1[20];
	int flag = 0, logmoved = 0;
	struct ref_lock *lock;
	struct stat loginfo;
	int log = !lstat(git_path("logs/%s", oldref), &loginfo);
	const char *symref = NULL;

	if (log && S_ISLNK(loginfo.st_mode))
		return error("reflog for %s is a symlink", oldref);

	symref = resolve_ref(oldref, orig_sha1, 1, &flag);
	if (flag & REF_ISSYMREF)
		return error("refname %s is a symbolic ref, renaming it is not supported",
			oldref);
	if (!symref)
		return error("refname %s not found", oldref);

	if (!is_refname_available(newref, oldref, get_packed_refs(NULL), 0))
		return 1;

	if (!is_refname_available(newref, oldref, get_loose_refs(NULL), 0))
		return 1;

	lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);
	if (!lock)
		return error("unable to lock %s", renamed_ref);
	lock->force_write = 1;
	if (write_ref_sha1(lock, orig_sha1, logmsg))
		return error("unable to save current sha1 in %s", renamed_ref);

	if (log && rename(git_path("logs/%s", oldref), git_path(TMP_RENAMED_LOG)))
		return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s",
			oldref, strerror(errno));

	if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
		error("unable to delete old %s", oldref);
		goto rollback;
	}

	if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
		if (errno==EISDIR) {
			if (remove_empty_directories(git_path("%s", newref))) {
				error("Directory not empty: %s", newref);
				goto rollback;
			}
		} else {
			error("unable to delete existing %s", newref);
			goto rollback;
		}
	}

	if (log && safe_create_leading_directories(git_path("logs/%s", newref))) {
		error("unable to create directory for %s", newref);
		goto rollback;
	}

 retry:
	if (log && rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newref))) {
		if (errno==EISDIR || errno==ENOTDIR) {
			/*
			 * rename(a, b) when b is an existing
			 * directory ought to result in ISDIR, but
			 * Solaris 5.8 gives ENOTDIR.  Sheesh.
			 */
			if (remove_empty_directories(git_path("logs/%s", newref))) {
				error("Directory not empty: logs/%s", newref);
				goto rollback;
			}
			goto retry;
		} else {
			error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
				newref, strerror(errno));
			goto rollback;
		}
	}
	logmoved = log;

	lock = lock_ref_sha1_basic(newref, NULL, 0, NULL);
	if (!lock) {
		error("unable to lock %s for update", newref);
		goto rollback;
	}
	lock->force_write = 1;
	hashcpy(lock->old_sha1, orig_sha1);
	if (write_ref_sha1(lock, orig_sha1, logmsg)) {
		error("unable to write current sha1 into %s", newref);
		goto rollback;
	}

	return 0;

 rollback:
	lock = lock_ref_sha1_basic(oldref, NULL, 0, NULL);
	if (!lock) {
		error("unable to lock %s for rollback", oldref);
		goto rollbacklog;
	}

	lock->force_write = 1;
	flag = log_all_ref_updates;
	log_all_ref_updates = 0;
	if (write_ref_sha1(lock, orig_sha1, NULL))
		error("unable to write current sha1 into %s", oldref);
	log_all_ref_updates = flag;

 rollbacklog:
	if (logmoved && rename(git_path("logs/%s", newref), git_path("logs/%s", oldref)))
		error("unable to restore logfile %s from %s: %s",
			oldref, newref, strerror(errno));
	if (!logmoved && log &&
	    rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", oldref)))
		error("unable to restore logfile %s from "TMP_RENAMED_LOG": %s",
			oldref, strerror(errno));

	return 1;
}
コード例 #4
0
ファイル: reset.c プロジェクト: guban/git
int cmd_reset(int argc, const char **argv, const char *prefix)
{
	int reset_type = NONE, update_ref_status = 0, quiet = 0;
	int patch_mode = 0, nul_term_line = 0, read_from_stdin = 0, unborn;
	char **stdin_paths = NULL;
	int stdin_nr = 0, stdin_alloc = 0;
	const char *rev;
	struct object_id oid;
	struct pathspec pathspec;
	int intent_to_add = 0;
	const struct option options[] = {
		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
		OPT_SET_INT(0, "mixed", &reset_type,
						N_("reset HEAD and index"), MIXED),
		OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
		OPT_SET_INT(0, "hard", &reset_type,
				N_("reset HEAD, index and working tree"), HARD),
		OPT_SET_INT(0, "merge", &reset_type,
				N_("reset HEAD, index and working tree"), MERGE),
		OPT_SET_INT(0, "keep", &reset_type,
				N_("reset HEAD but keep local changes"), KEEP),
		{ OPTION_CALLBACK, 0, "recurse-submodules", NULL,
			    "reset", "control recursive updating of submodules",
			    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
		OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
		OPT_BOOL('N', "intent-to-add", &intent_to_add,
				N_("record only the fact that removed paths will be added later")),
		OPT_BOOL('z', NULL, &nul_term_line,
			N_("EXPERIMENTAL: paths are separated with NUL character")),
		OPT_BOOL(0, "stdin", &read_from_stdin,
				N_("EXPERIMENTAL: read paths from <stdin>")),
		OPT_END()
	};

	git_config(git_reset_config, NULL);

	argc = parse_options(argc, argv, prefix, options, git_reset_usage,
						PARSE_OPT_KEEP_DASHDASH);
	parse_args(&pathspec, argv, prefix, patch_mode, &rev);

	if (read_from_stdin) {
		strbuf_getline_fn getline_fn = nul_term_line ?
			strbuf_getline_nul : strbuf_getline_lf;
		int flags = PATHSPEC_PREFER_FULL;
		struct strbuf buf = STRBUF_INIT;
		struct strbuf unquoted = STRBUF_INIT;

		if (patch_mode)
			die(_("--stdin is incompatible with --patch"));

		if (pathspec.nr)
			die(_("--stdin is incompatible with path arguments"));

		while (getline_fn(&buf, stdin) != EOF) {
			if (!nul_term_line && buf.buf[0] == '"') {
				strbuf_reset(&unquoted);
				if (unquote_c_style(&unquoted, buf.buf, NULL))
					die(_("line is badly quoted"));
				strbuf_swap(&buf, &unquoted);
			}
			ALLOC_GROW(stdin_paths, stdin_nr + 1, stdin_alloc);
			stdin_paths[stdin_nr++] = xstrdup(buf.buf);
			strbuf_reset(&buf);
		}
		strbuf_release(&unquoted);
		strbuf_release(&buf);

		ALLOC_GROW(stdin_paths, stdin_nr + 1, stdin_alloc);
		stdin_paths[stdin_nr++] = NULL;
		flags |= PATHSPEC_LITERAL_PATH;
		parse_pathspec(&pathspec, 0, flags, prefix,
			       (const char **)stdin_paths);

	} else if (nul_term_line)
		die(_("-z requires --stdin"));

	unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
	if (unborn) {
		/* reset on unborn branch: treat as reset to empty tree */
		hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN);
	} else if (!pathspec.nr) {
		struct commit *commit;
		if (get_oid_committish(rev, &oid))
			die(_("Failed to resolve '%s' as a valid revision."), rev);
		commit = lookup_commit_reference(&oid);
		if (!commit)
			die(_("Could not parse object '%s'."), rev);
		oidcpy(&oid, &commit->object.oid);
	} else {
		struct tree *tree;
		if (get_oid_treeish(rev, &oid))
			die(_("Failed to resolve '%s' as a valid tree."), rev);
		tree = parse_tree_indirect(&oid);
		if (!tree)
			die(_("Could not parse object '%s'."), rev);
		oidcpy(&oid, &tree->object.oid);
	}

	if (patch_mode) {
		if (reset_type != NONE)
			die(_("--patch is incompatible with --{hard,mixed,soft}"));
		return run_add_interactive(rev, "--patch=reset", &pathspec);
	}

	/* git reset tree [--] paths... can be used to
	 * load chosen paths from the tree into the index without
	 * affecting the working tree nor HEAD. */
	if (pathspec.nr) {
		if (reset_type == MIXED)
			warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
		else if (reset_type != NONE)
			die(_("Cannot do %s reset with paths."),
					_(reset_type_names[reset_type]));
	}
	if (reset_type == NONE)
		reset_type = MIXED; /* by default */

	if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree()))
		setup_work_tree();

	if (reset_type == MIXED && is_bare_repository())
		die(_("%s reset is not allowed in a bare repository"),
		    _(reset_type_names[reset_type]));

	if (intent_to_add && reset_type != MIXED)
		die(_("-N can only be used with --mixed"));

	/* Soft reset does not touch the index file nor the working tree
	 * at all, but requires them in a good order.  Other resets reset
	 * the index file to the tree object we are switching to. */
	if (reset_type == SOFT || reset_type == KEEP)
		die_if_unmerged_cache(reset_type);

	if (reset_type != SOFT) {
		struct lock_file lock = LOCK_INIT;
		hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
		if (reset_type == MIXED) {
			int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
			if (read_from_tree(&pathspec, &oid, intent_to_add))
				return 1;
			if (get_git_work_tree())
				refresh_index(&the_index, flags, NULL, NULL,
					      _("Unstaged changes after reset:"));
		} else {
			int err = reset_index(&oid, reset_type, quiet);
			if (reset_type == KEEP && !err)
				err = reset_index(&oid, MIXED, quiet);
			if (err)
				die(_("Could not reset index file to revision '%s'."), rev);
		}

		if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
			die(_("Could not write new index file."));
	}

	if (!pathspec.nr && !unborn) {
		/* Any resets without paths update HEAD to the head being
		 * switched to, saving the previous head in ORIG_HEAD before. */
		update_ref_status = reset_refs(rev, &oid);

		if (reset_type == HARD && !update_ref_status && !quiet)
			print_new_head_line(lookup_commit_reference(&oid));
	}
	if (!pathspec.nr)
		remove_branch_state();

	if (stdin_paths) {
		while (stdin_nr)
			free(stdin_paths[--stdin_nr]);
		free(stdin_paths);
	}

	return update_ref_status;
}
コード例 #5
0
ファイル: bulk-checkin.c プロジェクト: 0369/git
static int deflate_to_pack(struct bulk_checkin_state *state,
			   unsigned char result_sha1[],
			   int fd, size_t size,
			   enum object_type type, const char *path,
			   unsigned flags)
{
	off_t seekback, already_hashed_to;
	git_SHA_CTX ctx;
	unsigned char obuf[16384];
	unsigned header_len;
	struct sha1file_checkpoint checkpoint;
	struct pack_idx_entry *idx = NULL;

	seekback = lseek(fd, 0, SEEK_CUR);
	if (seekback == (off_t) -1)
		return error("cannot find the current offset");

	header_len = xsnprintf((char *)obuf, sizeof(obuf), "%s %" PRIuMAX,
			       typename(type), (uintmax_t)size) + 1;
	git_SHA1_Init(&ctx);
	git_SHA1_Update(&ctx, obuf, header_len);

	/* Note: idx is non-NULL when we are writing */
	if ((flags & HASH_WRITE_OBJECT) != 0)
		idx = xcalloc(1, sizeof(*idx));

	already_hashed_to = 0;

	while (1) {
		prepare_to_stream(state, flags);
		if (idx) {
			sha1file_checkpoint(state->f, &checkpoint);
			idx->offset = state->offset;
			crc32_begin(state->f);
		}
		if (!stream_to_pack(state, &ctx, &already_hashed_to,
				    fd, size, type, path, flags))
			break;
		/*
		 * Writing this object to the current pack will make
		 * it too big; we need to truncate it, start a new
		 * pack, and write into it.
		 */
		if (!idx)
			die("BUG: should not happen");
		sha1file_truncate(state->f, &checkpoint);
		state->offset = checkpoint.offset;
		finish_bulk_checkin(state);
		if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
			return error("cannot seek back");
	}
	git_SHA1_Final(result_sha1, &ctx);
	if (!idx)
		return 0;

	idx->crc32 = crc32_end(state->f);
	if (already_written(state, result_sha1)) {
		sha1file_truncate(state->f, &checkpoint);
		state->offset = checkpoint.offset;
		free(idx);
	} else {
		hashcpy(idx->sha1, result_sha1);
		ALLOC_GROW(state->written,
			   state->nr_written + 1,
			   state->alloc_written);
		state->written[state->nr_written++] = idx;
	}
	return 0;
}
コード例 #6
0
ファイル: fmt-merge-msg.c プロジェクト: H1ghT0p/git
static int handle_line(char *line, struct merge_parents *merge_parents)
{
	int i, len = strlen(line);
	struct origin_data *origin_data;
	char *src;
	const char *origin;
	struct src_data *src_data;
	struct string_list_item *item;
	int pulling_head = 0;
	unsigned char sha1[20];

	if (len < 43 || line[40] != '\t')
		return 1;

	if (starts_with(line + 41, "not-for-merge"))
		return 0;

	if (line[41] != '\t')
		return 2;

	i = get_sha1_hex(line, sha1);
	if (i)
		return 3;

	if (!find_merge_parent(merge_parents, sha1, NULL))
		return 0; /* subsumed by other parents */

	origin_data = xcalloc(1, sizeof(struct origin_data));
	hashcpy(origin_data->sha1, sha1);

	if (line[len - 1] == '\n')
		line[len - 1] = 0;
	line += 42;

	/*
	 * At this point, line points at the beginning of comment e.g.
	 * "branch 'frotz' of git://that/repository.git".
	 * Find the repository name and point it with src.
	 */
	src = strstr(line, " of ");
	if (src) {
		*src = 0;
		src += 4;
		pulling_head = 0;
	} else {
		src = line;
		pulling_head = 1;
	}

	item = unsorted_string_list_lookup(&srcs, src);
	if (!item) {
		item = string_list_append(&srcs, src);
		item->util = xcalloc(1, sizeof(struct src_data));
		init_src_data(item->util);
	}
	src_data = item->util;

	if (pulling_head) {
		origin = src;
		src_data->head_status |= 1;
	} else if (starts_with(line, "branch ")) {
		origin_data->is_local_branch = 1;
		origin = line + 7;
		string_list_append(&src_data->branch, origin);
		src_data->head_status |= 2;
	} else if (starts_with(line, "tag ")) {
		origin = line;
		string_list_append(&src_data->tag, origin + 4);
		src_data->head_status |= 2;
	} else if (skip_prefix(line, "remote-tracking branch ", &origin)) {
		string_list_append(&src_data->r_branch, origin);
		src_data->head_status |= 2;
	} else {
		origin = src;
		string_list_append(&src_data->generic, line);
		src_data->head_status |= 2;
	}

	if (!strcmp(".", src) || !strcmp(src, origin)) {
		int len = strlen(origin);
		if (origin[0] == '\'' && origin[len - 1] == '\'')
			origin = xmemdupz(origin + 1, len - 2);
	} else
		origin = xstrfmt("%s of %s", origin, src);
	if (strcmp(".", src))
		origin_data->is_local_branch = 0;
	string_list_append(&origins, origin)->util = origin_data;
	return 0;
}
コード例 #7
0
ファイル: ui-patch.c プロジェクト: Gcrosby5269/cgit
void cgit_print_patch(const char *new_rev, const char *old_rev,
		      const char *prefix)
{
	struct rev_info rev;
	struct commit *commit;
	unsigned char new_rev_sha1[20], old_rev_sha1[20];
	char rev_range[2 * 40 + 3];
	char *rev_argv[] = { NULL, "--reverse", "--format=email", rev_range };
	char *patchname;

	if (!new_rev)
		new_rev = ctx.qry.head;

	if (get_sha1(new_rev, new_rev_sha1)) {
		cgit_print_error("Bad object id: %s", new_rev);
		return;
	}
	commit = lookup_commit_reference(new_rev_sha1);
	if (!commit) {
		cgit_print_error("Bad commit reference: %s", new_rev);
		return;
	}

	if (old_rev) {
		if (get_sha1(old_rev, old_rev_sha1)) {
			cgit_print_error("Bad object id: %s", old_rev);
			return;
		}
		if (!lookup_commit_reference(old_rev_sha1)) {
			cgit_print_error("Bad commit reference: %s", old_rev);
			return;
		}
	} else if (commit->parents && commit->parents->item) {
		hashcpy(old_rev_sha1, commit->parents->item->object.sha1);
	} else {
		hashclr(old_rev_sha1);
	}

	if (is_null_sha1(old_rev_sha1)) {
		memcpy(rev_range, sha1_to_hex(new_rev_sha1), 41);
	} else {
		sprintf(rev_range, "%s..%s", sha1_to_hex(old_rev_sha1),
			sha1_to_hex(new_rev_sha1));
	}

	patchname = fmt("%s.patch", rev_range);
	ctx.page.mimetype = "text/plain";
	ctx.page.filename = patchname;
	cgit_print_http_headers();

	if (ctx.cfg.noplainemail) {
		rev_argv[2] = "--format=format:From %H Mon Sep 17 00:00:00 "
			      "2001%nFrom: %an%nDate: %aD%n%w(78,0,1)Subject: "
			      "%s%n%n%w(0)%b";
	}

	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.verbose_header = 1;
	rev.diff = 1;
	rev.show_root_diff = 1;
	rev.max_parents = 1;
	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
	setup_revisions(ARRAY_SIZE(rev_argv), (const char **)rev_argv, &rev,
			NULL);
	prepare_revision_walk(&rev);

	while ((commit = get_revision(&rev)) != NULL) {
		log_tree_commit(&rev, commit);
		printf("-- \ncgit %s\n\n", cgit_version);
	}

	fflush(stdout);
}
コード例 #8
0
ファイル: branch.c プロジェクト: 00027jang27/git
void create_branch(const char *head,
		   const char *name, const char *start_name,
		   int force, int reflog, int clobber_head,
		   int quiet, enum branch_track track)
{
	struct ref_lock *lock = NULL;
	struct commit *commit;
	unsigned char sha1[20];
	char *real_ref, msg[PATH_MAX + 20];
	struct strbuf ref = STRBUF_INIT;
	int forcing = 0;
	int dont_change_ref = 0;
	int explicit_tracking = 0;

	if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE)
		explicit_tracking = 1;

	if (validate_new_branchname(name, &ref, force,
				    track == BRANCH_TRACK_OVERRIDE ||
				    clobber_head)) {
		if (!force)
			dont_change_ref = 1;
		else
			forcing = 1;
	}

	real_ref = NULL;
	if (get_sha1(start_name, sha1)) {
		if (explicit_tracking) {
			if (advice_set_upstream_failure) {
				error(_(upstream_missing), start_name);
				advise(_(upstream_advice));
				exit(1);
			}
			die(_(upstream_missing), start_name);
		}
		die(_("Not a valid object name: '%s'."), start_name);
	}

	switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
	case 0:
		/* Not branching from any existing branch */
		if (explicit_tracking)
			die(_(upstream_not_branch), start_name);
		break;
	case 1:
		/* Unique completion -- good, only if it is a real branch */
		if (prefixcmp(real_ref, "refs/heads/") &&
		    validate_remote_tracking_branch(real_ref)) {
			if (explicit_tracking)
				die(_(upstream_not_branch), start_name);
			else
				real_ref = NULL;
		}
		break;
	default:
		die(_("Ambiguous object name: '%s'."), start_name);
		break;
	}

	if ((commit = lookup_commit_reference(sha1)) == NULL)
		die(_("Not a valid branch point: '%s'."), start_name);
	hashcpy(sha1, commit->object.sha1);

	if (!dont_change_ref) {
		lock = lock_any_ref_for_update(ref.buf, NULL, 0);
		if (!lock)
			die_errno(_("Failed to lock ref for update"));
	}

	if (reflog)
		log_all_ref_updates = 1;

	if (forcing)
		snprintf(msg, sizeof msg, "branch: Reset to %s",
			 start_name);
	else if (!dont_change_ref)
		snprintf(msg, sizeof msg, "branch: Created from %s",
			 start_name);

	if (real_ref && track)
		setup_tracking(ref.buf+11, real_ref, track, quiet);

	if (!dont_change_ref)
		if (write_ref_sha1(lock, sha1, msg) < 0)
			die_errno(_("Failed to write ref"));

	strbuf_release(&ref);
	free(real_ref);
}
コード例 #9
0
ファイル: transport-helper.c プロジェクト: samv/git
static int push_refs(struct transport *transport,
		struct ref *remote_refs, int flags)
{
	int force_all = flags & TRANSPORT_PUSH_FORCE;
	int mirror = flags & TRANSPORT_PUSH_MIRROR;
	struct helper_data *data = transport->data;
	struct strbuf buf = STRBUF_INIT;
	struct child_process *helper;
	struct ref *ref;

	if (!remote_refs)
		return 0;

	helper = get_helper(transport);
	if (!data->push)
		return 1;

	for (ref = remote_refs; ref; ref = ref->next) {
		if (ref->peer_ref)
			hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
		else if (!mirror)
			continue;

		ref->deletion = is_null_sha1(ref->new_sha1);
		if (!ref->deletion &&
			!hashcmp(ref->old_sha1, ref->new_sha1)) {
			ref->status = REF_STATUS_UPTODATE;
			continue;
		}

		if (force_all)
			ref->force = 1;

		strbuf_addstr(&buf, "push ");
		if (!ref->deletion) {
			if (ref->force)
				strbuf_addch(&buf, '+');
			if (ref->peer_ref)
				strbuf_addstr(&buf, ref->peer_ref->name);
			else
				strbuf_addstr(&buf, sha1_to_hex(ref->new_sha1));
		}
		strbuf_addch(&buf, ':');
		strbuf_addstr(&buf, ref->name);
		strbuf_addch(&buf, '\n');
	}
	if (buf.len == 0)
		return 0;

	transport->verbose = flags & TRANSPORT_PUSH_VERBOSE ? 1 : 0;
	standard_options(transport);

	if (flags & TRANSPORT_PUSH_DRY_RUN) {
		if (set_helper_option(transport, "dry-run", "true") != 0)
			die("helper %s does not support dry-run", data->name);
	}

	strbuf_addch(&buf, '\n');
	if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
		exit(128);

	ref = remote_refs;
	while (1) {
		char *refname, *msg;
		int status;

		strbuf_reset(&buf);
		if (strbuf_getline(&buf, data->out, '\n') == EOF)
			exit(128); /* child died, message supplied already */
		if (!buf.len)
			break;

		if (!prefixcmp(buf.buf, "ok ")) {
			status = REF_STATUS_OK;
			refname = buf.buf + 3;
		} else if (!prefixcmp(buf.buf, "error ")) {
			status = REF_STATUS_REMOTE_REJECT;
			refname = buf.buf + 6;
		} else
			die("expected ok/error, helper said '%s'\n", buf.buf);

		msg = strchr(refname, ' ');
		if (msg) {
			struct strbuf msg_buf = STRBUF_INIT;
			const char *end;

			*msg++ = '\0';
			if (!unquote_c_style(&msg_buf, msg, &end))
				msg = strbuf_detach(&msg_buf, NULL);
			else
				msg = xstrdup(msg);
			strbuf_release(&msg_buf);

			if (!strcmp(msg, "no match")) {
				status = REF_STATUS_NONE;
				free(msg);
				msg = NULL;
			}
			else if (!strcmp(msg, "up to date")) {
				status = REF_STATUS_UPTODATE;
				free(msg);
				msg = NULL;
			}
			else if (!strcmp(msg, "non-fast forward")) {
				status = REF_STATUS_REJECT_NONFASTFORWARD;
				free(msg);
				msg = NULL;
			}
		}

		if (ref)
			ref = find_ref_by_name(ref, refname);
		if (!ref)
			ref = find_ref_by_name(remote_refs, refname);
		if (!ref) {
			warning("helper reported unexpected status of %s", refname);
			continue;
		}

		ref->status = status;
		ref->remote_status = msg;
	}
	strbuf_release(&buf);
	return 0;
}
コード例 #10
0
ファイル: cat-file.c プロジェクト: 00027jang27/git
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
{
	unsigned char sha1[20];
	enum object_type type;
	char *buf;
	unsigned long size;
	struct object_context obj_context;

	if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
		die("Not a valid object name %s", obj_name);

	buf = NULL;
	switch (opt) {
	case 't':
		type = sha1_object_info(sha1, NULL);
		if (type > 0) {
			printf("%s\n", typename(type));
			return 0;
		}
		break;

	case 's':
		type = sha1_object_info(sha1, &size);
		if (type > 0) {
			printf("%lu\n", size);
			return 0;
		}
		break;

	case 'e':
		return !has_sha1_file(sha1);

	case 'p':
		type = sha1_object_info(sha1, NULL);
		if (type < 0)
			die("Not a valid object name %s", obj_name);

		/* custom pretty-print here */
		if (type == OBJ_TREE) {
			const char *ls_args[3] = { NULL };
			ls_args[0] =  "ls-tree";
			ls_args[1] =  obj_name;
			return cmd_ls_tree(2, ls_args, NULL);
		}

		if (type == OBJ_BLOB)
			return stream_blob_to_fd(1, sha1, NULL, 0);
		buf = read_sha1_file(sha1, &type, &size);
		if (!buf)
			die("Cannot read object %s", obj_name);

		/* otherwise just spit out the data */
		break;

	case 'c':
		if (!obj_context.path[0])
			die("git cat-file --textconv %s: <object> must be <sha1:path>",
			    obj_name);

		if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
			die("git cat-file --textconv: unable to run textconv on %s",
			    obj_name);
		break;

	case 0:
		if (type_from_string(exp_type) == OBJ_BLOB) {
			unsigned char blob_sha1[20];
			if (sha1_object_info(sha1, NULL) == OBJ_TAG) {
				enum object_type type;
				unsigned long size;
				char *buffer = read_sha1_file(sha1, &type, &size);
				if (memcmp(buffer, "object ", 7) ||
				    get_sha1_hex(buffer + 7, blob_sha1))
					die("%s not a valid tag", sha1_to_hex(sha1));
				free(buffer);
			} else
				hashcpy(blob_sha1, sha1);

			if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
				return stream_blob_to_fd(1, blob_sha1, NULL, 0);
			/*
			 * we attempted to dereference a tag to a blob
			 * and failed; there may be new dereference
			 * mechanisms this code is not aware of.
			 * fall-back to the usual case.
			 */
		}
		buf = read_object_with_reference(sha1, exp_type, &size, NULL);
		break;

	default:
		die("git cat-file: unknown option: %s", exp_type);
	}
コード例 #11
0
ファイル: bisect.c プロジェクト: Barklad/first_app
static void sha1_array_push(struct sha1_array *array,
			    const unsigned char *sha1)
{
	ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc);
	hashcpy(array->sha1[array->sha1_nr++], sha1);
}
コード例 #12
0
ファイル: combine-diff.c プロジェクト: 136357477/git
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
	struct diff_queue_struct *q = &diff_queued_diff;
	struct combine_diff_path *p, **tail = &curr;
	int i, cmp;

	if (!n) {
		for (i = 0; i < q->nr; i++) {
			int len;
			const char *path;
			if (diff_unmodified_pair(q->queue[i]))
				continue;
			path = q->queue[i]->two->path;
			len = strlen(path);
			p = xmalloc(combine_diff_path_size(num_parent, len));
			p->path = (char *) &(p->parent[num_parent]);
			memcpy(p->path, path, len);
			p->path[len] = 0;
			p->next = NULL;
			memset(p->parent, 0,
			       sizeof(p->parent[0]) * num_parent);

			hashcpy(p->oid.hash, q->queue[i]->two->sha1);
			p->mode = q->queue[i]->two->mode;
			hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1);
			p->parent[n].mode = q->queue[i]->one->mode;
			p->parent[n].status = q->queue[i]->status;
			*tail = p;
			tail = &p->next;
		}
		return curr;
	}

	/*
	 * paths in curr (linked list) and q->queue[] (array) are
	 * both sorted in the tree order.
	 */
	i = 0;
	while ((p = *tail) != NULL) {
		cmp = ((i >= q->nr)
		       ? -1 : compare_paths(p, q->queue[i]->two));

		if (cmp < 0) {
			/* p->path not in q->queue[]; drop it */
			*tail = p->next;
			free(p);
			continue;
		}

		if (cmp > 0) {
			/* q->queue[i] not in p->path; skip it */
			i++;
			continue;
		}

		hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1);
		p->parent[n].mode = q->queue[i]->one->mode;
		p->parent[n].status = q->queue[i]->status;

		tail = &p->next;
		i++;
	}
	return curr;
}
コード例 #13
0
ファイル: refs.c プロジェクト: atispor/git
/*
 * If the "reading" argument is set, this function finds out what _object_
 * the ref points at by "reading" the ref.  The ref, if it is not symbolic,
 * has to exist, and if it is symbolic, it has to point at an existing ref,
 * because the "read" goes through the symref to the ref it points at.
 *
 * The access that is not "reading" may often be "writing", but does not
 * have to; it can be merely checking _where it leads to_. If it is a
 * prelude to "writing" to the ref, a write to a symref that points at
 * yet-to-be-born ref will create the real ref pointed by the symref.
 * reading=0 allows the caller to check where such a symref leads to.
 */
const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
{
	int depth = MAXDEPTH;
	ssize_t len;
	char buffer[256];
	static char ref_buffer[256];

	if (flag)
		*flag = 0;

	for (;;) {
		char path[PATH_MAX];
		struct stat st;
		char *buf;
		int fd;

		if (--depth < 0)
			return NULL;

		git_snpath(path, sizeof(path), "%s", ref);
		/* Special case: non-existing file. */
		if (lstat(path, &st) < 0) {
			struct ref_list *list = get_packed_refs(NULL);
			while (list) {
				if (!strcmp(ref, list->name)) {
					hashcpy(sha1, list->sha1);
					if (flag)
						*flag |= REF_ISPACKED;
					return ref;
				}
				list = list->next;
			}
			if (reading || errno != ENOENT)
				return NULL;
			hashclr(sha1);
			return ref;
		}

		/* Follow "normalized" - ie "refs/.." symlinks by hand */
		if (S_ISLNK(st.st_mode)) {
			len = readlink(path, buffer, sizeof(buffer)-1);
			if (len >= 5 && !memcmp("refs/", buffer, 5)) {
				buffer[len] = 0;
				strcpy(ref_buffer, buffer);
				ref = ref_buffer;
				if (flag)
					*flag |= REF_ISSYMREF;
				continue;
			}
		}

		/* Is it a directory? */
		if (S_ISDIR(st.st_mode)) {
			errno = EISDIR;
			return NULL;
		}

		/*
		 * Anything else, just open it and try to use it as
		 * a ref
		 */
		fd = open(path, O_RDONLY);
		if (fd < 0)
			return NULL;
		len = read_in_full(fd, buffer, sizeof(buffer)-1);
		close(fd);

		/*
		 * Is it a symbolic ref?
		 */
		if (len < 4 || memcmp("ref:", buffer, 4))
			break;
		buf = buffer + 4;
		len -= 4;
		while (len && isspace(*buf))
			buf++, len--;
		while (len && isspace(buf[len-1]))
			len--;
		buf[len] = 0;
		memcpy(ref_buffer, buf, len + 1);
		ref = ref_buffer;
		if (flag)
			*flag |= REF_ISSYMREF;
	}
	if (len < 40 || get_sha1_hex(buffer, sha1))
		return NULL;
	return ref;
}
コード例 #14
0
ファイル: reset.c プロジェクト: ANKIT-KS/git
int cmd_reset(int argc, const char **argv, const char *prefix)
{
	int reset_type = NONE, update_ref_status = 0, quiet = 0;
	int patch_mode = 0, unborn;
	const char *rev;
	unsigned char sha1[20];
	const char **pathspec = NULL;
	const struct option options[] = {
		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
		OPT_SET_INT(0, "mixed", &reset_type,
						N_("reset HEAD and index"), MIXED),
		OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
		OPT_SET_INT(0, "hard", &reset_type,
				N_("reset HEAD, index and working tree"), HARD),
		OPT_SET_INT(0, "merge", &reset_type,
				N_("reset HEAD, index and working tree"), MERGE),
		OPT_SET_INT(0, "keep", &reset_type,
				N_("reset HEAD but keep local changes"), KEEP),
		OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
		OPT_END()
	};

	git_config(git_default_config, NULL);

	argc = parse_options(argc, argv, prefix, options, git_reset_usage,
						PARSE_OPT_KEEP_DASHDASH);
	pathspec = parse_args(argv, prefix, &rev);

	unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1);
	if (unborn) {
		/* reset on unborn branch: treat as reset to empty tree */
		hashcpy(sha1, EMPTY_TREE_SHA1_BIN);
	} else if (!pathspec) {
		struct commit *commit;
		if (get_sha1_committish(rev, sha1))
			die(_("Failed to resolve '%s' as a valid revision."), rev);
		commit = lookup_commit_reference(sha1);
		if (!commit)
			die(_("Could not parse object '%s'."), rev);
		hashcpy(sha1, commit->object.sha1);
	} else {
		struct tree *tree;
		if (get_sha1_treeish(rev, sha1))
			die(_("Failed to resolve '%s' as a valid tree."), rev);
		tree = parse_tree_indirect(sha1);
		if (!tree)
			die(_("Could not parse object '%s'."), rev);
		hashcpy(sha1, tree->object.sha1);
	}

	if (patch_mode) {
		if (reset_type != NONE)
			die(_("--patch is incompatible with --{hard,mixed,soft}"));
		return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", pathspec);
	}

	/* git reset tree [--] paths... can be used to
	 * load chosen paths from the tree into the index without
	 * affecting the working tree nor HEAD. */
	if (pathspec) {
		if (reset_type == MIXED)
			warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
		else if (reset_type != NONE)
			die(_("Cannot do %s reset with paths."),
					_(reset_type_names[reset_type]));
	}
	if (reset_type == NONE)
		reset_type = MIXED; /* by default */

	if (reset_type != SOFT && reset_type != MIXED)
		setup_work_tree();

	if (reset_type == MIXED && is_bare_repository())
		die(_("%s reset is not allowed in a bare repository"),
		    _(reset_type_names[reset_type]));

	/* Soft reset does not touch the index file nor the working tree
	 * at all, but requires them in a good order.  Other resets reset
	 * the index file to the tree object we are switching to. */
	if (reset_type == SOFT || reset_type == KEEP)
		die_if_unmerged_cache(reset_type);

	if (reset_type != SOFT) {
		struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
		int newfd = hold_locked_index(lock, 1);
		if (reset_type == MIXED) {
			if (read_from_tree(pathspec, sha1))
				return 1;
		} else {
			int err = reset_index(sha1, reset_type, quiet);
			if (reset_type == KEEP && !err)
				err = reset_index(sha1, MIXED, quiet);
			if (err)
				die(_("Could not reset index file to revision '%s'."), rev);
		}

		if (reset_type == MIXED) { /* Report what has not been updated. */
			int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
			refresh_index(&the_index, flags, NULL, NULL,
				      _("Unstaged changes after reset:"));
		}

		if (write_cache(newfd, active_cache, active_nr) ||
		    commit_locked_index(lock))
			die(_("Could not write new index file."));
	}

	if (!pathspec && !unborn) {
		/* Any resets without paths update HEAD to the head being
		 * switched to, saving the previous head in ORIG_HEAD before. */
		update_ref_status = update_refs(rev, sha1);

		if (reset_type == HARD && !update_ref_status && !quiet)
			print_new_head_line(lookup_commit_reference(sha1));
	}
	if (!pathspec)
		remove_branch_state();

	return update_ref_status;
}
コード例 #15
0
ファイル: notes.c プロジェクト: 1tgr/git
static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
		struct int_node *node, unsigned int n)
{
	unsigned char object_sha1[20];
	unsigned int prefix_len;
	void *buf;
	struct tree_desc desc;
	struct name_entry entry;
	int len, path_len;
	unsigned char type;
	struct leaf_node *l;

	buf = fill_tree_descriptor(&desc, subtree->val_sha1);
	if (!buf)
		die("Could not read %s for notes-index",
		     sha1_to_hex(subtree->val_sha1));

	prefix_len = subtree->key_sha1[19];
	assert(prefix_len * 2 >= n);
	memcpy(object_sha1, subtree->key_sha1, prefix_len);
	while (tree_entry(&desc, &entry)) {
		path_len = strlen(entry.path);
		len = get_sha1_hex_segment(entry.path, path_len,
				object_sha1 + prefix_len, 20 - prefix_len);
		if (len < 0)
			goto handle_non_note; /* entry.path is not a SHA1 */
		len += prefix_len;

		/*
		 * If object SHA1 is complete (len == 20), assume note object
		 * If object SHA1 is incomplete (len < 20), and current
		 * component consists of 2 hex chars, assume note subtree
		 */
		if (len <= 20) {
			type = PTR_TYPE_NOTE;
			l = (struct leaf_node *)
				xcalloc(1, sizeof(struct leaf_node));
			hashcpy(l->key_sha1, object_sha1);
			hashcpy(l->val_sha1, entry.oid->hash);
			if (len < 20) {
				if (!S_ISDIR(entry.mode) || path_len != 2)
					goto handle_non_note; /* not subtree */
				l->key_sha1[19] = (unsigned char) len;
				type = PTR_TYPE_SUBTREE;
			}
			if (note_tree_insert(t, node, n, l, type,
					     combine_notes_concatenate))
				die("Failed to load %s %s into notes tree "
				    "from %s",
				    type == PTR_TYPE_NOTE ? "note" : "subtree",
				    sha1_to_hex(l->key_sha1), t->ref);
		}
		continue;

handle_non_note:
		/*
		 * Determine full path for this non-note entry:
		 * The filename is already found in entry.path, but the
		 * directory part of the path must be deduced from the subtree
		 * containing this entry. We assume here that the overall notes
		 * tree follows a strict byte-based progressive fanout
		 * structure (i.e. using 2/38, 2/2/36, etc. fanouts, and not
		 * e.g. 4/36 fanout). This means that if a non-note is found at
		 * path "dead/beef", the following code will register it as
		 * being found on "de/ad/beef".
		 * On the other hand, if you use such non-obvious non-note
		 * paths in the middle of a notes tree, you deserve what's
		 * coming to you ;). Note that for non-notes that are not
		 * SHA1-like at the top level, there will be no problems.
		 *
		 * To conclude, it is strongly advised to make sure non-notes
		 * have at least one non-hex character in the top-level path
		 * component.
		 */
		{
			struct strbuf non_note_path = STRBUF_INIT;
			const char *q = sha1_to_hex(subtree->key_sha1);
			int i;
			for (i = 0; i < prefix_len; i++) {
				strbuf_addch(&non_note_path, *q++);
				strbuf_addch(&non_note_path, *q++);
				strbuf_addch(&non_note_path, '/');
			}
			strbuf_addstr(&non_note_path, entry.path);
			add_non_note(t, strbuf_detach(&non_note_path, NULL),
				     entry.mode, entry.oid->hash);
		}
	}
	free(buf);
}
コード例 #16
0
ファイル: submodule.c プロジェクト: LittleForker/git
int merge_submodule(unsigned char result[20], const char *path,
		    const unsigned char base[20], const unsigned char a[20],
		    const unsigned char b[20])
{
	struct commit *commit_base, *commit_a, *commit_b;
	int parent_count;
	struct object_array merges;

	int i;

	/* store a in result in case we fail */
	hashcpy(result, a);

	/* we can not handle deletion conflicts */
	if (is_null_sha1(base))
		return 0;
	if (is_null_sha1(a))
		return 0;
	if (is_null_sha1(b))
		return 0;

	if (add_submodule_odb(path)) {
		MERGE_WARNING(path, "not checked out");
		return 0;
	}

	if (!(commit_base = lookup_commit_reference(base)) ||
	    !(commit_a = lookup_commit_reference(a)) ||
	    !(commit_b = lookup_commit_reference(b))) {
		MERGE_WARNING(path, "commits not present");
		return 0;
	}

	/* check whether both changes are forward */
	if (!in_merge_bases(commit_base, &commit_a, 1) ||
	    !in_merge_bases(commit_base, &commit_b, 1)) {
		MERGE_WARNING(path, "commits don't follow merge-base");
		return 0;
	}

	/* Case #1: a is contained in b or vice versa */
	if (in_merge_bases(commit_a, &commit_b, 1)) {
		hashcpy(result, b);
		return 1;
	}
	if (in_merge_bases(commit_b, &commit_a, 1)) {
		hashcpy(result, a);
		return 1;
	}

	/*
	 * Case #2: There are one or more merges that contain a and b in
	 * the submodule. If there is only one, then present it as a
	 * suggestion to the user, but leave it marked unmerged so the
	 * user needs to confirm the resolution.
	 */

	/* find commit which merges them */
	parent_count = find_first_merges(&merges, path, commit_a, commit_b);
	switch (parent_count) {
	case 0:
		MERGE_WARNING(path, "merge following commits not found");
		break;

	case 1:
		MERGE_WARNING(path, "not fast-forward");
		fprintf(stderr, "Found a possible merge resolution "
				"for the submodule:\n");
		print_commit((struct commit *) merges.objects[0].item);
		fprintf(stderr,
			"If this is correct simply add it to the index "
			"for example\n"
			"by using:\n\n"
			"  git update-index --cacheinfo 160000 %s \"%s\"\n\n"
			"which will accept this suggestion.\n",
			sha1_to_hex(merges.objects[0].item->sha1), path);
		break;

	default:
		MERGE_WARNING(path, "multiple merges found");
		for (i = 0; i < merges.nr; i++)
			print_commit((struct commit *) merges.objects[i].item);
	}

	free(merges.objects);
	return 0;
}
コード例 #17
0
ファイル: notes.c プロジェクト: 1tgr/git
int combine_notes_overwrite(unsigned char *cur_sha1,
		const unsigned char *new_sha1)
{
	hashcpy(cur_sha1, new_sha1);
	return 0;
}
コード例 #18
0
ファイル: fetch-pack.c プロジェクト: 4rch17/git
static int everything_local(struct fetch_pack_args *args,
			    struct ref **refs,
			    struct ref **sought, int nr_sought)
{
	struct ref *ref;
	int retval;
	unsigned long cutoff = 0;

	save_commit_buffer = 0;

	for (ref = *refs; ref; ref = ref->next) {
		struct object *o;

		if (!has_sha1_file(ref->old_sha1))
			continue;

		o = parse_object(ref->old_sha1);
		if (!o)
			continue;

		/* We already have it -- which may mean that we were
		 * in sync with the other side at some time after
		 * that (it is OK if we guess wrong here).
		 */
		if (o->type == OBJ_COMMIT) {
			struct commit *commit = (struct commit *)o;
			if (!cutoff || cutoff < commit->date)
				cutoff = commit->date;
		}
	}

	if (!args->depth) {
		for_each_ref(mark_complete, NULL);
		for_each_alternate_ref(mark_alternate_complete, NULL);
		if (cutoff)
			mark_recent_complete_commits(args, cutoff);
	}

	/*
	 * Mark all complete remote refs as common refs.
	 * Don't mark them common yet; the server has to be told so first.
	 */
	for (ref = *refs; ref; ref = ref->next) {
		struct object *o = deref_tag(lookup_object(ref->old_sha1),
					     NULL, 0);

		if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
			continue;

		if (!(o->flags & SEEN)) {
			rev_list_push((struct commit *)o, COMMON_REF | SEEN);

			mark_common((struct commit *)o, 1, 1);
		}
	}

	filter_refs(args, refs, sought, nr_sought);

	for (retval = 1, ref = *refs; ref ; ref = ref->next) {
		const unsigned char *remote = ref->old_sha1;
		unsigned char local[20];
		struct object *o;

		o = lookup_object(remote);
		if (!o || !(o->flags & COMPLETE)) {
			retval = 0;
			if (!args->verbose)
				continue;
			fprintf(stderr,
				"want %s (%s)\n", sha1_to_hex(remote),
				ref->name);
			continue;
		}

		hashcpy(ref->new_sha1, local);
		if (!args->verbose)
			continue;
		fprintf(stderr,
			"already have %s (%s)\n", sha1_to_hex(remote),
			ref->name);
	}
	return retval;
}
コード例 #19
0
ファイル: cache-tree.c プロジェクト: Inkdit/git
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
{
	const char *buf = *buffer;
	unsigned long size = *size_p;
	const char *cp;
	char *ep;
	struct cache_tree *it;
	int i, subtree_nr;

	it = NULL;
	/* skip name, but make sure name exists */
	while (size && *buf) {
		size--;
		buf++;
	}
	if (!size)
		goto free_return;
	buf++; size--;
	it = cache_tree();

	cp = buf;
	it->entry_count = strtol(cp, &ep, 10);
	if (cp == ep)
		goto free_return;
	cp = ep;
	subtree_nr = strtol(cp, &ep, 10);
	if (cp == ep)
		goto free_return;
	while (size && *buf && *buf != '\n') {
		size--;
		buf++;
	}
	if (!size)
		goto free_return;
	buf++; size--;
	if (0 <= it->entry_count) {
		if (size < 20)
			goto free_return;
		hashcpy(it->sha1, (const unsigned char*)buf);
		buf += 20;
		size -= 20;
	}

#if DEBUG
	if (0 <= it->entry_count)
		fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n",
			*buffer, it->entry_count, subtree_nr,
			sha1_to_hex(it->sha1));
	else
		fprintf(stderr, "cache-tree <%s> (%d subtrees) invalid\n",
			*buffer, subtree_nr);
#endif

	/*
	 * Just a heuristic -- we do not add directories that often but
	 * we do not want to have to extend it immediately when we do,
	 * hence +2.
	 */
	it->subtree_alloc = subtree_nr + 2;
	it->down = xcalloc(it->subtree_alloc, sizeof(struct cache_tree_sub *));
	for (i = 0; i < subtree_nr; i++) {
		/* read each subtree */
		struct cache_tree *sub;
		struct cache_tree_sub *subtree;
		const char *name = buf;

		sub = read_one(&buf, &size);
		if (!sub)
			goto free_return;
		subtree = cache_tree_sub(it, name);
		subtree->cache_tree = sub;
	}
	if (subtree_nr != it->subtree_nr)
		die("cache-tree: internal error");
	*buffer = buf;
	*size_p = size;
	return it;

 free_return:
	cache_tree_free(&it);
	return NULL;
}
コード例 #20
0
ファイル: branch.c プロジェクト: emk/git
void create_branch(const char *head,
		   const char *name, const char *start_name,
		   int force, int reflog, enum branch_track track)
{
	struct ref_lock *lock;
	struct commit *commit;
	unsigned char sha1[20];
	char *real_ref, msg[PATH_MAX + 20];
	struct strbuf ref = STRBUF_INIT;
	int forcing = 0;
	int len;

	len = strlen(name);
	if (interpret_nth_last_branch(name, &ref) != len) {
		strbuf_reset(&ref);
		strbuf_add(&ref, name, len);
	}
	strbuf_splice(&ref, 0, 0, "refs/heads/", 11);

	if (check_ref_format(ref.buf))
		die("'%s' is not a valid branch name.", name);

	if (resolve_ref(ref.buf, sha1, 1, NULL)) {
		if (!force)
			die("A branch named '%s' already exists.", name);
		else if (!is_bare_repository() && !strcmp(head, name))
			die("Cannot force update the current branch.");
		forcing = 1;
	}

	real_ref = NULL;
	if (get_sha1(start_name, sha1))
		die("Not a valid object name: '%s'.", start_name);

	switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
	case 0:
		/* Not branching from any existing branch */
		if (track == BRANCH_TRACK_EXPLICIT)
			die("Cannot setup tracking information; starting point is not a branch.");
		break;
	case 1:
		/* Unique completion -- good, only if it is a real ref */
		if (track == BRANCH_TRACK_EXPLICIT && !strcmp(real_ref, "HEAD"))
			die("Cannot setup tracking information; starting point is not a branch.");
		break;
	default:
		die("Ambiguous object name: '%s'.", start_name);
		break;
	}

	if ((commit = lookup_commit_reference(sha1)) == NULL)
		die("Not a valid branch point: '%s'.", start_name);
	hashcpy(sha1, commit->object.sha1);

	lock = lock_any_ref_for_update(ref.buf, NULL, 0);
	if (!lock)
		die("Failed to lock ref for update: %s.", strerror(errno));

	if (reflog)
		log_all_ref_updates = 1;

	if (forcing)
		snprintf(msg, sizeof msg, "branch: Reset from %s",
			 start_name);
	else
		snprintf(msg, sizeof msg, "branch: Created from %s",
			 start_name);

	if (real_ref && track)
		setup_tracking(name, real_ref, track);

	if (write_ref_sha1(lock, sha1, msg) < 0)
		die("Failed to write ref: %s.", strerror(errno));

	strbuf_release(&ref);
	free(real_ref);
}
コード例 #21
0
ファイル: diff-lib.c プロジェクト: Provab-Solutions/git
int run_diff_files(struct rev_info *revs, unsigned int option)
{
	int entries, i;
	int diff_unmerged_stage = revs->max_count;
	int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
			      ? CE_MATCH_RACY_IS_DIRTY : 0);

	diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");

	if (diff_unmerged_stage < 0)
		diff_unmerged_stage = 2;
	entries = active_nr;
	for (i = 0; i < entries; i++) {
		struct stat st;
		unsigned int oldmode, newmode;
		struct cache_entry *ce = active_cache[i];
		int changed;
		unsigned dirty_submodule = 0;

		if (DIFF_OPT_TST(&revs->diffopt, QUICK) &&
			DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
			break;

		if (!ce_path_match(ce, revs->prune_data))
			continue;

		if (ce_stage(ce)) {
			struct combine_diff_path *dpath;
			int num_compare_stages = 0;
			size_t path_len;

			path_len = ce_namelen(ce);

			dpath = xmalloc(combine_diff_path_size(5, path_len));
			dpath->path = (char *) &(dpath->parent[5]);

			dpath->next = NULL;
			dpath->len = path_len;
			memcpy(dpath->path, ce->name, path_len);
			dpath->path[path_len] = '\0';
			hashclr(dpath->sha1);
			memset(&(dpath->parent[0]), 0,
			       sizeof(struct combine_diff_parent)*5);

			changed = check_removed(ce, &st);
			if (!changed)
				dpath->mode = ce_mode_from_stat(ce, st.st_mode);
			else {
				if (changed < 0) {
					perror(ce->name);
					continue;
				}
				if (silent_on_removed)
					continue;
			}

			while (i < entries) {
				struct cache_entry *nce = active_cache[i];
				int stage;

				if (strcmp(ce->name, nce->name))
					break;

				/* Stage #2 (ours) is the first parent,
				 * stage #3 (theirs) is the second.
				 */
				stage = ce_stage(nce);
				if (2 <= stage) {
					int mode = nce->ce_mode;
					num_compare_stages++;
					hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
					dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
					dpath->parent[stage-2].status =
						DIFF_STATUS_MODIFIED;
				}

				/* diff against the proper unmerged stage */
				if (stage == diff_unmerged_stage)
					ce = nce;
				i++;
			}
			/*
			 * Compensate for loop update
			 */
			i--;

			if (revs->combine_merges && num_compare_stages == 2) {
				show_combined_diff(dpath, 2,
						   revs->dense_combined_merges,
						   revs);
				free(dpath);
				continue;
			}
			free(dpath);
			dpath = NULL;

			/*
			 * Show the diff for the 'ce' if we found the one
			 * from the desired stage.
			 */
			diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
			if (ce_stage(ce) != diff_unmerged_stage)
				continue;
		}

		if (ce_uptodate(ce) || ce_skip_worktree(ce))
			continue;

		/* If CE_VALID is set, don't look at workdir for file removal */
		changed = (ce->ce_flags & CE_VALID) ? 0 : check_removed(ce, &st);
		if (changed) {
			if (changed < 0) {
				perror(ce->name);
				continue;
			}
			if (silent_on_removed)
				continue;
			diff_addremove(&revs->diffopt, '-', ce->ce_mode,
				       ce->sha1, ce->name, 0);
			continue;
		}
		changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
						    ce_option, &dirty_submodule);
		if (!changed && !dirty_submodule) {
			ce_mark_uptodate(ce);
			if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
				continue;
		}
		oldmode = ce->ce_mode;
		newmode = ce_mode_from_stat(ce, st.st_mode);
		diff_change(&revs->diffopt, oldmode, newmode,
			    ce->sha1, (changed ? null_sha1 : ce->sha1),
			    ce->name, 0, dirty_submodule);

	}
	diffcore_std(&revs->diffopt);
	diff_flush(&revs->diffopt);
	return 0;
}
コード例 #22
0
ファイル: sequencer.c プロジェクト: binaryminds/git
static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
{
    unsigned char head[20];
    struct commit *base, *next, *parent;
    const char *base_label, *next_label;
    struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
    char *defmsg = NULL;
    struct strbuf msgbuf = STRBUF_INIT;
    int res, unborn = 0;

    if (opts->no_commit) {
        /*
         * We do not intend to commit immediately.  We just want to
         * merge the differences in, so let's compute the tree
         * that represents the "current" state for merge-recursive
         * to work on.
         */
        if (write_cache_as_tree(head, 0, NULL))
            die (_("Your index file is unmerged."));
    } else {
        unborn = get_sha1("HEAD", head);
        if (unborn)
            hashcpy(head, EMPTY_TREE_SHA1_BIN);
        if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0))
            return error_dirty_index(opts);
    }
    discard_cache();

    if (!commit->parents) {
        parent = NULL;
    }
    else if (commit->parents->next) {
        /* Reverting or cherry-picking a merge commit */
        int cnt;
        struct commit_list *p;

        if (!opts->mainline)
            return error(_("Commit %s is a merge but no -m option was given."),
                         sha1_to_hex(commit->object.sha1));

        for (cnt = 1, p = commit->parents;
                cnt != opts->mainline && p;
                cnt++)
            p = p->next;
        if (cnt != opts->mainline || !p)
            return error(_("Commit %s does not have parent %d"),
                         sha1_to_hex(commit->object.sha1), opts->mainline);
        parent = p->item;
    } else if (0 < opts->mainline)
        return error(_("Mainline was specified but commit %s is not a merge."),
                     sha1_to_hex(commit->object.sha1));
    else
        parent = commit->parents->item;

    if (opts->allow_ff &&
            ((parent && !hashcmp(parent->object.sha1, head)) ||
             (!parent && unborn)))
        return fast_forward_to(commit->object.sha1, head, unborn);

    if (parent && parse_commit(parent) < 0)
        /* TRANSLATORS: The first %s will be "revert" or
           "cherry-pick", the second %s a SHA1 */
        return error(_("%s: cannot parse parent commit %s"),
                     action_name(opts), sha1_to_hex(parent->object.sha1));

    if (get_message(commit, &msg) != 0)
        return error(_("Cannot get commit message for %s"),
                     sha1_to_hex(commit->object.sha1));

    /*
     * "commit" is an existing commit.  We would want to apply
     * the difference it introduces since its first parent "prev"
     * on top of the current HEAD if we are cherry-pick.  Or the
     * reverse of it if we are revert.
     */

    defmsg = git_pathdup("MERGE_MSG");

    if (opts->action == REPLAY_REVERT) {
        base = commit;
        base_label = msg.label;
        next = parent;
        next_label = msg.parent_label;
        strbuf_addstr(&msgbuf, "Revert \"");
        strbuf_addstr(&msgbuf, msg.subject);
        strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
        strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));

        if (commit->parents && commit->parents->next) {
            strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
            strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
        }
        strbuf_addstr(&msgbuf, ".\n");
    } else {
        const char *p;

        base = parent;
        base_label = msg.parent_label;
        next = commit;
        next_label = msg.label;

        /*
         * Append the commit log message to msgbuf; it starts
         * after the tree, parent, author, committer
         * information followed by "\n\n".
         */
        p = strstr(msg.message, "\n\n");
        if (p) {
            p += 2;
            strbuf_addstr(&msgbuf, p);
        }

        if (opts->record_origin) {
            if (!has_conforming_footer(&msgbuf, NULL, 0))
                strbuf_addch(&msgbuf, '\n');
            strbuf_addstr(&msgbuf, cherry_picked_prefix);
            strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
            strbuf_addstr(&msgbuf, ")\n");
        }
    }

    if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
        res = do_recursive_merge(base, next, base_label, next_label,
                                 head, &msgbuf, opts);
        write_message(&msgbuf, defmsg);
    } else {
        struct commit_list *common = NULL;
        struct commit_list *remotes = NULL;

        write_message(&msgbuf, defmsg);

        commit_list_insert(base, &common);
        commit_list_insert(next, &remotes);
        res = try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
                                common, sha1_to_hex(head), remotes);
        free_commit_list(common);
        free_commit_list(remotes);
    }

    /*
     * If the merge was clean or if it failed due to conflict, we write
     * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
     * However, if the merge did not even start, then we don't want to
     * write it at all.
     */
    if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
        write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
    if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
        write_cherry_pick_head(commit, "REVERT_HEAD");

    if (res) {
        error(opts->action == REPLAY_REVERT
              ? _("could not revert %s... %s")
              : _("could not apply %s... %s"),
              find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
              msg.subject);
        print_advice(res == 1, opts);
        rerere(opts->allow_rerere_auto);
    } else {
        int allow = allow_empty(opts, commit);
        if (allow < 0)
            return allow;
        if (!opts->no_commit)
            res = run_git_commit(defmsg, opts, allow);
    }

    free_message(&msg);
    free(defmsg);

    return res;
}
コード例 #23
0
ファイル: tree-diff.c プロジェクト: 2quala/git
/*
 * new path should be added to combine diff
 *
 * 3 cases on how/when it should be called and behaves:
 *
 *	 t, !tp		-> path added, all parents lack it
 *	!t,  tp		-> path removed from all parents
 *	 t,  tp		-> path modified/added
 *			   (M for tp[i]=tp[imin], A otherwise)
 */
static struct combine_diff_path *emit_path(struct combine_diff_path *p,
	struct strbuf *base, struct diff_options *opt, int nparent,
	struct tree_desc *t, struct tree_desc *tp,
	int imin)
{
	unsigned mode;
	const char *path;
	const unsigned char *sha1;
	int pathlen;
	int old_baselen = base->len;
	int i, isdir, recurse = 0, emitthis = 1;

	/* at least something has to be valid */
	assert(t || tp);

	if (t) {
		/* path present in resulting tree */
		sha1 = tree_entry_extract(t, &path, &mode);
		pathlen = tree_entry_len(&t->entry);
		isdir = S_ISDIR(mode);
	} else {
		/*
		 * a path was removed - take path from imin parent. Also take
		 * mode from that parent, to decide on recursion(1).
		 *
		 * 1) all modes for tp[i]=tp[imin] should be the same wrt
		 *    S_ISDIR, thanks to base_name_compare().
		 */
		tree_entry_extract(&tp[imin], &path, &mode);
		pathlen = tree_entry_len(&tp[imin].entry);

		isdir = S_ISDIR(mode);
		sha1 = NULL;
		mode = 0;
	}

	if (DIFF_OPT_TST(opt, RECURSIVE) && isdir) {
		recurse = 1;
		emitthis = DIFF_OPT_TST(opt, TREE_IN_RECURSIVE);
	}

	if (emitthis) {
		int keep;
		struct combine_diff_path *pprev = p;
		p = path_appendnew(p, nparent, base, path, pathlen, mode, sha1);

		for (i = 0; i < nparent; ++i) {
			/*
			 * tp[i] is valid, if present and if tp[i]==tp[imin] -
			 * otherwise, we should ignore it.
			 */
			int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);

			const unsigned char *sha1_i;
			unsigned mode_i;

			p->parent[i].status =
				!t ? DIFF_STATUS_DELETED :
					tpi_valid ?
						DIFF_STATUS_MODIFIED :
						DIFF_STATUS_ADDED;

			if (tpi_valid) {
				sha1_i = tp[i].entry.sha1;
				mode_i = tp[i].entry.mode;
			}
			else {
				sha1_i = NULL;
				mode_i = 0;
			}

			p->parent[i].mode = mode_i;
			hashcpy(p->parent[i].oid.hash, sha1_i ? sha1_i : null_sha1);
		}

		keep = 1;
		if (opt->pathchange)
			keep = opt->pathchange(opt, p);

		/*
		 * If a path was filtered or consumed - we don't need to add it
		 * to the list and can reuse its memory, leaving it as
		 * pre-allocated element on the tail.
		 *
		 * On the other hand, if path needs to be kept, we need to
		 * correct its .next to NULL, as it was pre-initialized to how
		 * much memory was allocated.
		 *
		 * see path_appendnew() for details.
		 */
		if (!keep)
			p = pprev;
		else
			p->next = NULL;
	}

	if (recurse) {
		const unsigned char **parents_sha1;

		parents_sha1 = xalloca(nparent * sizeof(parents_sha1[0]));
		for (i = 0; i < nparent; ++i) {
			/* same rule as in emitthis */
			int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);

			parents_sha1[i] = tpi_valid ? tp[i].entry.sha1
						    : NULL;
		}

		strbuf_add(base, path, pathlen);
		strbuf_addch(base, '/');
		p = ll_diff_tree_paths(p, sha1, parents_sha1, nparent, base, opt);
		xalloca_free(parents_sha1);
	}

	strbuf_setlen(base, old_baselen);
	return p;
}