Coverage Report

Created: 2026-10-17 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/reset.c
Line
Count
Source
1
#include "git-compat-util.h"
2
#include "cache-tree.h"
3
#include "gettext.h"
4
#include "hex.h"
5
#include "lockfile.h"
6
#include "object-name.h"
7
#include "refs.h"
8
#include "reset.h"
9
#include "tree-walk.h"
10
#include "tree.h"
11
#include "unpack-trees.h"
12
#include "hook.h"
13
14
static int update_refs(struct repository *repo,
15
           const struct reset_working_tree_options *opts,
16
           const struct object_id *oid,
17
           const struct object_id *head)
18
0
{
19
0
  unsigned detach_head = opts->flags & RESET_WORKING_TREE_DETACH;
20
0
  unsigned run_hook = opts->flags & RESET_WORKING_TREE_RUN_POST_CHECKOUT_HOOK;
21
0
  unsigned update_orig_head = opts->flags & RESET_WORKING_TREE_UPDATE_ORIG_HEAD;
22
0
  const struct object_id *orig_head = opts->orig_head;
23
0
  const char *switch_to_branch = opts->branch;
24
0
  const char *reflog_branch = opts->branch_msg;
25
0
  const char *reflog_head = opts->head_msg;
26
0
  const char *reflog_orig_head = opts->orig_head_msg;
27
0
  const char *default_reflog_action = opts->default_reflog_action;
28
0
  struct object_id *old_orig = NULL, oid_old_orig;
29
0
  struct strbuf msg = STRBUF_INIT;
30
0
  const char *reflog_action;
31
0
  size_t prefix_len;
32
0
  int ret;
33
34
0
  if ((update_orig_head && !reflog_orig_head) || !reflog_head) {
35
0
    if (!default_reflog_action)
36
0
      BUG("default_reflog_action must be given when reflog messages are omitted");
37
0
    reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
38
0
    strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action :
39
0
                default_reflog_action);
40
0
  }
41
0
  prefix_len = msg.len;
42
43
0
  if (update_orig_head) {
44
0
    if (!repo_get_oid(repo, "ORIG_HEAD", &oid_old_orig))
45
0
      old_orig = &oid_old_orig;
46
0
    if (head) {
47
0
      if (!reflog_orig_head) {
48
0
        strbuf_addstr(&msg, "updating ORIG_HEAD");
49
0
        reflog_orig_head = msg.buf;
50
0
      }
51
0
      refs_update_ref(get_main_ref_store(repo),
52
0
          reflog_orig_head, "ORIG_HEAD",
53
0
          orig_head ? orig_head : head,
54
0
          old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
55
0
    } else if (old_orig)
56
0
      refs_delete_ref(get_main_ref_store(repo),
57
0
          NULL, "ORIG_HEAD", old_orig, 0);
58
0
  }
59
60
0
  if (!reflog_head) {
61
0
    strbuf_setlen(&msg, prefix_len);
62
0
    strbuf_addstr(&msg, "updating HEAD");
63
0
    reflog_head = msg.buf;
64
0
  }
65
0
  if (!switch_to_branch)
66
0
    ret = refs_update_ref(get_main_ref_store(repo),
67
0
              reflog_head, "HEAD", oid, head,
68
0
              detach_head ? REF_NO_DEREF : 0,
69
0
              UPDATE_REFS_MSG_ON_ERR);
70
0
  else {
71
0
    ret = refs_update_ref(get_main_ref_store(repo),
72
0
              reflog_branch ? reflog_branch : reflog_head,
73
0
              switch_to_branch, oid, NULL, 0,
74
0
              UPDATE_REFS_MSG_ON_ERR);
75
0
    if (!ret)
76
0
      ret = refs_update_symref(get_main_ref_store(repo),
77
0
             "HEAD", switch_to_branch,
78
0
             reflog_head);
79
0
  }
80
0
  if (!ret && run_hook)
81
0
    run_hooks_l(repo, "post-checkout",
82
0
          oid_to_hex(head ? head : null_oid(repo->hash_algo)),
83
0
          oid_to_hex(oid), "1", NULL);
84
0
  strbuf_release(&msg);
85
0
  return ret;
86
0
}
87
88
int reset_working_tree(struct repository *r,
89
           const struct reset_working_tree_options *opts)
90
0
{
91
0
  const struct object_id *oid = opts->oid;
92
0
  const char *switch_to_branch = opts->branch;
93
0
  unsigned reset_hard = opts->flags & RESET_WORKING_TREE_HARD;
94
0
  unsigned refs_only = opts->flags & RESET_WORKING_TREE_REFS_ONLY;
95
0
  unsigned update_head = opts->flags & RESET_WORKING_TREE_UPDATE_HEAD;
96
0
  unsigned update_orig_head = opts->flags & RESET_WORKING_TREE_UPDATE_ORIG_HEAD;
97
0
  unsigned dry_run = opts->flags & RESET_WORKING_TREE_DRY_RUN;
98
0
  struct object_id *head = NULL, head_oid;
99
0
  struct tree_desc desc[2] = { { NULL }, { NULL } };
100
0
  struct lock_file lock = LOCK_INIT;
101
0
  struct unpack_trees_options unpack_tree_opts = { 0 };
102
0
  struct tree *tree;
103
0
  struct index_state scratch_index = INDEX_STATE_INIT(r);
104
0
  struct index_state *istate;
105
0
  const char *action;
106
0
  int ret = 0, nr = 0;
107
108
0
  if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
109
0
    BUG("Not a fully qualified branch: '%s'", switch_to_branch);
110
111
0
  if (opts->orig_head_msg && !update_orig_head)
112
0
    BUG("ORIG_HEAD reflog message given without updating ORIG_HEAD");
113
114
0
  if (opts->branch_msg && !opts->branch)
115
0
    BUG("branch reflog message given without a branch");
116
117
0
  if (update_orig_head && !update_head)
118
0
    BUG("cannot update ORIG_HEAD without updating HEAD");
119
120
0
  if (!refs_only && !dry_run && repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
121
0
    ret = -1;
122
0
    goto leave_reset_head;
123
0
  }
124
125
0
  if (opts->oid_from) {
126
0
    oidcpy(&head_oid, opts->oid_from);
127
0
    head = &head_oid;
128
0
  } else if (!repo_get_oid(r, "HEAD", &head_oid)) {
129
0
    head = &head_oid;
130
0
  } else if (!oid || !reset_hard) {
131
0
    ret = error(_("could not determine HEAD revision"));
132
0
    goto leave_reset_head;
133
0
  }
134
135
0
  if (!oid)
136
0
    oid = &head_oid;
137
138
0
  if (refs_only) {
139
0
    if (!dry_run && update_head)
140
0
      return update_refs(r, opts, oid, head);
141
0
    return 0;
142
0
  }
143
144
0
  if (dry_run) {
145
0
    if (read_index_from(&scratch_index, r->index_file, r->gitdir) < 0 ||
146
0
        index_state_unmerged_to_stage0(&scratch_index) < 0) {
147
0
      ret = error(_("could not read index"));
148
0
      goto leave_reset_head;
149
0
    }
150
151
0
    istate = &scratch_index;
152
0
  } else {
153
0
    if (repo_read_index_unmerged(r) < 0) {
154
0
      ret = error(_("could not read index"));
155
0
      goto leave_reset_head;
156
0
    }
157
0
    istate = r->index;
158
0
  }
159
160
0
  action = reset_hard ? "reset" : "checkout";
161
0
  setup_unpack_trees_porcelain(&unpack_tree_opts, action);
162
0
  unpack_tree_opts.head_idx = 1;
163
0
  unpack_tree_opts.src_index = istate;
164
0
  unpack_tree_opts.dst_index = istate;
165
0
  unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
166
0
  unpack_tree_opts.update = !dry_run;
167
0
  unpack_tree_opts.dry_run = dry_run;
168
0
  unpack_tree_opts.merge = 1;
169
0
  unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
170
0
  init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
171
0
  if (reset_hard) {
172
0
    unpack_tree_opts.skip_cache_tree_update = 1;
173
0
    unpack_tree_opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
174
0
  }
175
176
0
  if (!reset_hard && !fill_tree_descriptor(r, &desc[nr++], &head_oid)) {
177
0
    ret = error(_("failed to find tree of %s"),
178
0
          oid_to_hex(&head_oid));
179
0
    goto leave_reset_head;
180
0
  }
181
182
0
  if (!fill_tree_descriptor(r, &desc[nr++], oid)) {
183
0
    ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
184
0
    goto leave_reset_head;
185
0
  }
186
187
0
  if (unpack_trees(nr, desc, &unpack_tree_opts)) {
188
0
    ret = -1;
189
0
    goto leave_reset_head;
190
0
  }
191
192
0
  if (dry_run)
193
0
    goto leave_reset_head;
194
195
0
  tree = repo_parse_tree_indirect(r, oid);
196
0
  if (!tree) {
197
0
    ret = error(_("unable to read tree (%s)"), oid_to_hex(oid));
198
0
    goto leave_reset_head;
199
0
  }
200
201
0
  if (reset_hard)
202
0
    prime_cache_tree(r, r->index, tree);
203
204
0
  if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) {
205
0
    ret = error(_("could not write index"));
206
0
    goto leave_reset_head;
207
0
  }
208
209
0
  if (update_head &&
210
0
      (oid != &head_oid || update_orig_head || switch_to_branch))
211
0
    ret = update_refs(r, opts, oid, head);
212
213
0
leave_reset_head:
214
0
  rollback_lock_file(&lock);
215
0
  clear_unpack_trees_porcelain(&unpack_tree_opts);
216
0
  release_index(&scratch_index);
217
0
  while (nr)
218
0
    free((void *)desc[--nr].buffer);
219
0
  return ret;
220
221
0
}