1526d0fcfd
This parameter is only needed when a ref is going to be updated and the caller does not pass an explicit reflog message. Callers that are only discarding uncommitted changes in the working tree such as such as "rebase --skip" or create_autostash() do not update any refs so should not have to worry about passing this parameter. This change is not intended to have any user visible changes. The pointer comparison between `oid` and `&head_oid` checks that the caller did not pass an oid to be checked out. As no callers pass RESET_HEAD_RUN_POST_CHECKOUT_HOOK without passing an oid there are no changes to when the post-checkout hook is run. As update_ref() only updates the ref if the oid passed to it differs from the current ref there are no changes to when HEAD is updated. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
166 lines
4.9 KiB
C
166 lines
4.9 KiB
C
#include "git-compat-util.h"
|
|
#include "cache-tree.h"
|
|
#include "lockfile.h"
|
|
#include "refs.h"
|
|
#include "reset.h"
|
|
#include "run-command.h"
|
|
#include "tree-walk.h"
|
|
#include "tree.h"
|
|
#include "unpack-trees.h"
|
|
|
|
static int update_refs(const struct object_id *oid, const char *switch_to_branch,
|
|
const struct object_id *head, const char *reflog_head,
|
|
const char *reflog_orig_head,
|
|
const char *default_reflog_action, unsigned flags)
|
|
{
|
|
unsigned detach_head = flags & RESET_HEAD_DETACH;
|
|
unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
|
|
unsigned update_orig_head = flags & RESET_ORIG_HEAD;
|
|
struct object_id *old_orig = NULL, oid_old_orig;
|
|
struct strbuf msg = STRBUF_INIT;
|
|
const char *reflog_action;
|
|
size_t prefix_len;
|
|
int ret;
|
|
|
|
if ((update_orig_head && !reflog_orig_head) || !reflog_head) {
|
|
if (!default_reflog_action)
|
|
BUG("default_reflog_action must be given when reflog messages are omitted");
|
|
reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
|
|
strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action :
|
|
default_reflog_action);
|
|
}
|
|
prefix_len = msg.len;
|
|
|
|
if (update_orig_head) {
|
|
if (!get_oid("ORIG_HEAD", &oid_old_orig))
|
|
old_orig = &oid_old_orig;
|
|
if (head) {
|
|
if (!reflog_orig_head) {
|
|
strbuf_addstr(&msg, "updating ORIG_HEAD");
|
|
reflog_orig_head = msg.buf;
|
|
}
|
|
update_ref(reflog_orig_head, "ORIG_HEAD", head,
|
|
old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
|
|
} else if (old_orig)
|
|
delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
|
|
}
|
|
|
|
if (!reflog_head) {
|
|
strbuf_setlen(&msg, prefix_len);
|
|
strbuf_addstr(&msg, "updating HEAD");
|
|
reflog_head = msg.buf;
|
|
}
|
|
if (!switch_to_branch)
|
|
ret = update_ref(reflog_head, "HEAD", oid, head,
|
|
detach_head ? REF_NO_DEREF : 0,
|
|
UPDATE_REFS_MSG_ON_ERR);
|
|
else {
|
|
ret = update_ref(reflog_head, switch_to_branch, oid,
|
|
NULL, 0, UPDATE_REFS_MSG_ON_ERR);
|
|
if (!ret)
|
|
ret = create_symref("HEAD", switch_to_branch,
|
|
reflog_head);
|
|
}
|
|
if (!ret && run_hook)
|
|
run_hook_le(NULL, "post-checkout",
|
|
oid_to_hex(head ? head : null_oid()),
|
|
oid_to_hex(oid), "1", NULL);
|
|
strbuf_release(&msg);
|
|
return ret;
|
|
}
|
|
|
|
int reset_head(struct repository *r, struct object_id *oid,
|
|
const char *switch_to_branch, unsigned flags,
|
|
const char *reflog_orig_head, const char *reflog_head,
|
|
const char *default_reflog_action)
|
|
{
|
|
unsigned reset_hard = flags & RESET_HEAD_HARD;
|
|
unsigned refs_only = flags & RESET_HEAD_REFS_ONLY;
|
|
unsigned update_orig_head = flags & RESET_ORIG_HEAD;
|
|
struct object_id *head = NULL, head_oid;
|
|
struct tree_desc desc[2] = { { NULL }, { NULL } };
|
|
struct lock_file lock = LOCK_INIT;
|
|
struct unpack_trees_options unpack_tree_opts = { 0 };
|
|
struct tree *tree;
|
|
const char *action;
|
|
int ret = 0, nr = 0;
|
|
|
|
if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
|
|
BUG("Not a fully qualified branch: '%s'", switch_to_branch);
|
|
|
|
if (!refs_only && repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
|
|
ret = -1;
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
if (!get_oid("HEAD", &head_oid)) {
|
|
head = &head_oid;
|
|
} else if (!oid || !reset_hard) {
|
|
ret = error(_("could not determine HEAD revision"));
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
if (!oid)
|
|
oid = &head_oid;
|
|
|
|
if (refs_only)
|
|
return update_refs(oid, switch_to_branch, head, reflog_head,
|
|
reflog_orig_head, default_reflog_action,
|
|
flags);
|
|
|
|
action = reset_hard ? "reset" : "checkout";
|
|
setup_unpack_trees_porcelain(&unpack_tree_opts, action);
|
|
unpack_tree_opts.head_idx = 1;
|
|
unpack_tree_opts.src_index = r->index;
|
|
unpack_tree_opts.dst_index = r->index;
|
|
unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
|
|
unpack_tree_opts.update = 1;
|
|
unpack_tree_opts.merge = 1;
|
|
unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
|
|
init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
|
|
if (reset_hard)
|
|
unpack_tree_opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
|
|
|
|
if (repo_read_index_unmerged(r) < 0) {
|
|
ret = error(_("could not read index"));
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
if (!reset_hard && !fill_tree_descriptor(r, &desc[nr++], &head_oid)) {
|
|
ret = error(_("failed to find tree of %s"),
|
|
oid_to_hex(&head_oid));
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
if (!fill_tree_descriptor(r, &desc[nr++], oid)) {
|
|
ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
if (unpack_trees(nr, desc, &unpack_tree_opts)) {
|
|
ret = -1;
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
tree = parse_tree_indirect(oid);
|
|
prime_cache_tree(r, r->index, tree);
|
|
|
|
if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) {
|
|
ret = error(_("could not write index"));
|
|
goto leave_reset_head;
|
|
}
|
|
|
|
if (oid != &head_oid || update_orig_head || switch_to_branch)
|
|
ret = update_refs(oid, switch_to_branch, head, reflog_head,
|
|
reflog_orig_head, default_reflog_action,
|
|
flags);
|
|
|
|
leave_reset_head:
|
|
rollback_lock_file(&lock);
|
|
clear_unpack_trees_porcelain(&unpack_tree_opts);
|
|
while (nr)
|
|
free((void *)desc[--nr].buffer);
|
|
return ret;
|
|
|
|
}
|