Merge branch 'ab/config-based-hooks-base' into seen
[git] / reset.c
1 #include "git-compat-util.h"
2 #include "cache-tree.h"
3 #include "lockfile.h"
4 #include "refs.h"
5 #include "reset.h"
6 #include "run-command.h"
7 #include "tree-walk.h"
8 #include "tree.h"
9 #include "unpack-trees.h"
10 #include "hook.h"
11
12 int reset_head(struct repository *r, struct object_id *oid, const char *action,
13                const char *switch_to_branch, unsigned flags,
14                const char *reflog_orig_head, const char *reflog_head,
15                const char *default_reflog_action)
16 {
17         unsigned detach_head = flags & RESET_HEAD_DETACH;
18         unsigned reset_hard = flags & RESET_HEAD_HARD;
19         unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
20         unsigned refs_only = flags & RESET_HEAD_REFS_ONLY;
21         unsigned update_orig_head = flags & RESET_ORIG_HEAD;
22         struct object_id head_oid;
23         struct tree_desc desc[2] = { { NULL }, { NULL } };
24         struct lock_file lock = LOCK_INIT;
25         struct unpack_trees_options unpack_tree_opts;
26         struct tree *tree;
27         const char *reflog_action;
28         struct strbuf msg = STRBUF_INIT;
29         size_t prefix_len;
30         struct object_id *orig = NULL, oid_orig,
31                 *old_orig = NULL, oid_old_orig;
32         int ret = 0, nr = 0;
33
34         if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
35                 BUG("Not a fully qualified branch: '%s'", switch_to_branch);
36
37         if (!refs_only && repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
38                 ret = -1;
39                 goto leave_reset_head;
40         }
41
42         if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
43                 ret = error(_("could not determine HEAD revision"));
44                 goto leave_reset_head;
45         }
46
47         if (!oid)
48                 oid = &head_oid;
49
50         if (refs_only)
51                 goto reset_head_refs;
52
53         memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
54         setup_unpack_trees_porcelain(&unpack_tree_opts, action);
55         unpack_tree_opts.head_idx = 1;
56         unpack_tree_opts.src_index = r->index;
57         unpack_tree_opts.dst_index = r->index;
58         unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
59         unpack_tree_opts.update = 1;
60         unpack_tree_opts.merge = 1;
61         init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
62         if (!detach_head)
63                 unpack_tree_opts.reset = 1;
64
65         if (repo_read_index_unmerged(r) < 0) {
66                 ret = error(_("could not read index"));
67                 goto leave_reset_head;
68         }
69
70         if (!reset_hard && !fill_tree_descriptor(r, &desc[nr++], &head_oid)) {
71                 ret = error(_("failed to find tree of %s"),
72                             oid_to_hex(&head_oid));
73                 goto leave_reset_head;
74         }
75
76         if (!fill_tree_descriptor(r, &desc[nr++], oid)) {
77                 ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
78                 goto leave_reset_head;
79         }
80
81         if (unpack_trees(nr, desc, &unpack_tree_opts)) {
82                 ret = -1;
83                 goto leave_reset_head;
84         }
85
86         tree = parse_tree_indirect(oid);
87         prime_cache_tree(r, r->index, tree);
88
89         if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) {
90                 ret = error(_("could not write index"));
91                 goto leave_reset_head;
92         }
93
94 reset_head_refs:
95         reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
96         strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : default_reflog_action);
97         prefix_len = msg.len;
98
99         if (update_orig_head) {
100                 if (!get_oid("ORIG_HEAD", &oid_old_orig))
101                         old_orig = &oid_old_orig;
102                 if (!get_oid("HEAD", &oid_orig)) {
103                         orig = &oid_orig;
104                         if (!reflog_orig_head) {
105                                 strbuf_addstr(&msg, "updating ORIG_HEAD");
106                                 reflog_orig_head = msg.buf;
107                         }
108                         update_ref(reflog_orig_head, "ORIG_HEAD", orig,
109                                    old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
110                 } else if (old_orig)
111                         delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
112         }
113
114         if (!reflog_head) {
115                 strbuf_setlen(&msg, prefix_len);
116                 strbuf_addstr(&msg, "updating HEAD");
117                 reflog_head = msg.buf;
118         }
119         if (!switch_to_branch)
120                 ret = update_ref(reflog_head, "HEAD", oid, orig,
121                                  detach_head ? REF_NO_DEREF : 0,
122                                  UPDATE_REFS_MSG_ON_ERR);
123         else {
124                 ret = update_ref(reflog_head, switch_to_branch, oid,
125                                  NULL, 0, UPDATE_REFS_MSG_ON_ERR);
126                 if (!ret)
127                         ret = create_symref("HEAD", switch_to_branch,
128                                             reflog_head);
129         }
130         if (run_hook) {
131                 struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
132                 strvec_pushl(&opt.args,
133                              oid_to_hex(orig ? orig : null_oid()),
134                              oid_to_hex(oid),
135                              "1",
136                              NULL);
137                 run_hooks("post-checkout", &opt);
138                 run_hooks_opt_clear(&opt);
139         }
140
141 leave_reset_head:
142         strbuf_release(&msg);
143         rollback_lock_file(&lock);
144         while (nr)
145                 free((void *)desc[--nr].buffer);
146         return ret;
147
148 }