Skip to content

Commit 9346b4e

Browse files
committed
Merge branch 'cr/reset'
* cr/reset: Simplify cache API An additional test for "git-reset -- path" Make "git reset" a builtin. Move make_cache_entry() from merge-recursive.c into read-cache.c Add tests for documented features of "git reset".
2 parents 148c630 + 58f6fb5 commit 9346b4e

File tree

14 files changed

+718
-44
lines changed

14 files changed

+718
-44
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ SCRIPT_SH = \
211211
git-ls-remote.sh \
212212
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
213213
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
214-
git-repack.sh git-request-pull.sh git-reset.sh \
214+
git-repack.sh git-request-pull.sh \
215215
git-sh-setup.sh \
216216
git-am.sh \
217217
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
@@ -358,6 +358,7 @@ BUILTIN_OBJS = \
358358
builtin-reflog.o \
359359
builtin-config.o \
360360
builtin-rerere.o \
361+
builtin-reset.o \
361362
builtin-rev-list.o \
362363
builtin-rev-parse.o \
363364
builtin-revert.o \

builtin-add.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ static void update_callback(struct diff_queue_struct *q,
103103
break;
104104
case DIFF_STATUS_DELETED:
105105
remove_file_from_cache(path);
106-
cache_tree_invalidate_path(active_cache_tree, path);
107106
if (verbose)
108107
printf("remove '%s'\n", path);
109108
break;

builtin-apply.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2423,7 +2423,6 @@ static void remove_file(struct patch *patch, int rmdir_empty)
24232423
if (update_index) {
24242424
if (remove_file_from_cache(patch->old_name) < 0)
24252425
die("unable to remove %s from index", patch->old_name);
2426-
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
24272426
}
24282427
if (!cached) {
24292428
if (S_ISGITLINK(patch->old_mode)) {
@@ -2578,7 +2577,6 @@ static void create_file(struct patch *patch)
25782577
mode = S_IFREG | 0644;
25792578
create_one_file(path, mode, buf, size);
25802579
add_index_file(path, mode, buf, size);
2581-
cache_tree_invalidate_path(active_cache_tree, path);
25822580
}
25832581

25842582
/* phase zero is to remove, phase one is to create */

builtin-mv.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
276276
add_file_to_cache(path, verbose);
277277
}
278278

279-
for (i = 0; i < deleted.nr; i++) {
280-
const char *path = deleted.items[i].path;
281-
remove_file_from_cache(path);
282-
cache_tree_invalidate_path(active_cache_tree, path);
283-
}
279+
for (i = 0; i < deleted.nr; i++)
280+
remove_file_from_cache(deleted.items[i].path);
284281

285282
if (active_cache_changed) {
286283
if (write_cache(newfd, active_cache, active_nr) ||

builtin-reset.c

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
/*
2+
* "git reset" builtin command
3+
*
4+
* Copyright (c) 2007 Carlos Rica
5+
*
6+
* Based on git-reset.sh, which is
7+
*
8+
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
9+
*/
10+
#include "cache.h"
11+
#include "tag.h"
12+
#include "object.h"
13+
#include "commit.h"
14+
#include "run-command.h"
15+
#include "refs.h"
16+
#include "diff.h"
17+
#include "diffcore.h"
18+
#include "tree.h"
19+
20+
static const char builtin_reset_usage[] =
21+
"git-reset [--mixed | --soft | --hard] [<commit-ish>] [ [--] <paths>...]";
22+
23+
static char *args_to_str(const char **argv)
24+
{
25+
char *buf = NULL;
26+
unsigned long len, space = 0, nr = 0;
27+
28+
for (; *argv; argv++) {
29+
len = strlen(*argv);
30+
ALLOC_GROW(buf, nr + 1 + len, space);
31+
if (nr)
32+
buf[nr++] = ' ';
33+
memcpy(buf + nr, *argv, len);
34+
nr += len;
35+
}
36+
ALLOC_GROW(buf, nr + 1, space);
37+
buf[nr] = '\0';
38+
39+
return buf;
40+
}
41+
42+
static inline int is_merge(void)
43+
{
44+
return !access(git_path("MERGE_HEAD"), F_OK);
45+
}
46+
47+
static int unmerged_files(void)
48+
{
49+
char b;
50+
ssize_t len;
51+
struct child_process cmd;
52+
const char *argv_ls_files[] = {"ls-files", "--unmerged", NULL};
53+
54+
memset(&cmd, 0, sizeof(cmd));
55+
cmd.argv = argv_ls_files;
56+
cmd.git_cmd = 1;
57+
cmd.out = -1;
58+
59+
if (start_command(&cmd))
60+
die("Could not run sub-command: git ls-files");
61+
62+
len = xread(cmd.out, &b, 1);
63+
if (len < 0)
64+
die("Could not read output from git ls-files: %s",
65+
strerror(errno));
66+
finish_command(&cmd);
67+
68+
return len;
69+
}
70+
71+
static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
72+
{
73+
int i = 0;
74+
const char *args[6];
75+
76+
args[i++] = "read-tree";
77+
args[i++] = "-v";
78+
args[i++] = "--reset";
79+
if (is_hard_reset)
80+
args[i++] = "-u";
81+
args[i++] = sha1_to_hex(sha1);
82+
args[i] = NULL;
83+
84+
return run_command_v_opt(args, RUN_GIT_CMD);
85+
}
86+
87+
static void print_new_head_line(struct commit *commit)
88+
{
89+
const char *hex, *dots = "...", *body;
90+
91+
hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
92+
if (!hex) {
93+
hex = sha1_to_hex(commit->object.sha1);
94+
dots = "";
95+
}
96+
printf("HEAD is now at %s%s", hex, dots);
97+
body = strstr(commit->buffer, "\n\n");
98+
if (body) {
99+
const char *eol;
100+
size_t len;
101+
body += 2;
102+
eol = strchr(body, '\n');
103+
len = eol ? eol - body : strlen(body);
104+
printf(" %.*s\n", (int) len, body);
105+
}
106+
else
107+
printf("\n");
108+
}
109+
110+
static int update_index_refresh(void)
111+
{
112+
const char *argv_update_index[] = {"update-index", "--refresh", NULL};
113+
return run_command_v_opt(argv_update_index, RUN_GIT_CMD);
114+
}
115+
116+
static void update_index_from_diff(struct diff_queue_struct *q,
117+
struct diff_options *opt, void *data)
118+
{
119+
int i;
120+
121+
/* do_diff_cache() mangled the index */
122+
discard_cache();
123+
read_cache();
124+
125+
for (i = 0; i < q->nr; i++) {
126+
struct diff_filespec *one = q->queue[i]->one;
127+
if (one->mode) {
128+
struct cache_entry *ce;
129+
ce = make_cache_entry(one->mode, one->sha1, one->path,
130+
0, 0);
131+
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
132+
ADD_CACHE_OK_TO_REPLACE);
133+
} else
134+
remove_file_from_cache(one->path);
135+
}
136+
}
137+
138+
static int read_from_tree(const char *prefix, const char **argv,
139+
unsigned char *tree_sha1)
140+
{
141+
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
142+
int index_fd;
143+
struct diff_options opt;
144+
145+
memset(&opt, 0, sizeof(opt));
146+
diff_tree_setup_paths(get_pathspec(prefix, (const char **)argv), &opt);
147+
opt.output_format = DIFF_FORMAT_CALLBACK;
148+
opt.format_callback = update_index_from_diff;
149+
150+
index_fd = hold_locked_index(lock, 1);
151+
read_cache();
152+
if (do_diff_cache(tree_sha1, &opt))
153+
return 1;
154+
diffcore_std(&opt);
155+
diff_flush(&opt);
156+
return write_cache(index_fd, active_cache, active_nr) ||
157+
close(index_fd) ||
158+
commit_locked_index(lock);
159+
}
160+
161+
static void prepend_reflog_action(const char *action, char *buf, size_t size)
162+
{
163+
const char *sep = ": ";
164+
const char *rla = getenv("GIT_REFLOG_ACTION");
165+
if (!rla)
166+
rla = sep = "";
167+
if (snprintf(buf, size, "%s%s%s", rla, sep, action) >= size)
168+
warning("Reflog action message too long: %.*s...", 50, buf);
169+
}
170+
171+
enum reset_type { MIXED, SOFT, HARD, NONE };
172+
static char *reset_type_names[] = { "mixed", "soft", "hard", NULL };
173+
174+
int cmd_reset(int argc, const char **argv, const char *prefix)
175+
{
176+
int i = 1, reset_type = NONE, update_ref_status = 0;
177+
const char *rev = "HEAD";
178+
unsigned char sha1[20], *orig = NULL, sha1_orig[20],
179+
*old_orig = NULL, sha1_old_orig[20];
180+
struct commit *commit;
181+
char *reflog_action, msg[1024];
182+
183+
git_config(git_default_config);
184+
185+
reflog_action = args_to_str(argv);
186+
setenv("GIT_REFLOG_ACTION", reflog_action, 0);
187+
188+
if (i < argc) {
189+
if (!strcmp(argv[i], "--mixed")) {
190+
reset_type = MIXED;
191+
i++;
192+
}
193+
else if (!strcmp(argv[i], "--soft")) {
194+
reset_type = SOFT;
195+
i++;
196+
}
197+
else if (!strcmp(argv[i], "--hard")) {
198+
reset_type = HARD;
199+
i++;
200+
}
201+
}
202+
203+
if (i < argc && argv[i][0] != '-')
204+
rev = argv[i++];
205+
206+
if (get_sha1(rev, sha1))
207+
die("Failed to resolve '%s' as a valid ref.", rev);
208+
209+
commit = lookup_commit_reference(sha1);
210+
if (!commit)
211+
die("Could not parse object '%s'.", rev);
212+
hashcpy(sha1, commit->object.sha1);
213+
214+
if (i < argc && !strcmp(argv[i], "--"))
215+
i++;
216+
else if (i < argc && argv[i][0] == '-')
217+
usage(builtin_reset_usage);
218+
219+
/* git reset tree [--] paths... can be used to
220+
* load chosen paths from the tree into the index without
221+
* affecting the working tree nor HEAD. */
222+
if (i < argc) {
223+
if (reset_type == MIXED)
224+
warning("--mixed option is deprecated with paths.");
225+
else if (reset_type != NONE)
226+
die("Cannot do %s reset with paths.",
227+
reset_type_names[reset_type]);
228+
if (read_from_tree(prefix, argv + i, sha1))
229+
return 1;
230+
return update_index_refresh() ? 1 : 0;
231+
}
232+
if (reset_type == NONE)
233+
reset_type = MIXED; /* by default */
234+
235+
/* Soft reset does not touch the index file nor the working tree
236+
* at all, but requires them in a good order. Other resets reset
237+
* the index file to the tree object we are switching to. */
238+
if (reset_type == SOFT) {
239+
if (is_merge() || unmerged_files())
240+
die("Cannot do a soft reset in the middle of a merge.");
241+
}
242+
else if (reset_index_file(sha1, (reset_type == HARD)))
243+
die("Could not reset index file to revision '%s'.", rev);
244+
245+
/* Any resets update HEAD to the head being switched to,
246+
* saving the previous head in ORIG_HEAD before. */
247+
if (!get_sha1("ORIG_HEAD", sha1_old_orig))
248+
old_orig = sha1_old_orig;
249+
if (!get_sha1("HEAD", sha1_orig)) {
250+
orig = sha1_orig;
251+
prepend_reflog_action("updating ORIG_HEAD", msg, sizeof(msg));
252+
update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
253+
}
254+
else if (old_orig)
255+
delete_ref("ORIG_HEAD", old_orig);
256+
prepend_reflog_action("updating HEAD", msg, sizeof(msg));
257+
update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
258+
259+
switch (reset_type) {
260+
case HARD:
261+
if (!update_ref_status)
262+
print_new_head_line(commit);
263+
break;
264+
case SOFT: /* Nothing else to do. */
265+
break;
266+
case MIXED: /* Report what has not been updated. */
267+
update_index_refresh();
268+
break;
269+
}
270+
271+
unlink(git_path("MERGE_HEAD"));
272+
unlink(git_path("rr-cache/MERGE_RR"));
273+
unlink(git_path("MERGE_MSG"));
274+
unlink(git_path("SQUASH_MSG"));
275+
276+
free(reflog_action);
277+
278+
return update_ref_status;
279+
}

builtin-rm.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
227227

228228
if (remove_file_from_cache(path))
229229
die("git-rm: unable to remove %s", path);
230-
cache_tree_invalidate_path(active_cache_tree, path);
231230
}
232231

233232
if (show_only)

builtin-update-index.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,6 @@ static int process_path(const char *path)
195195
int len;
196196
struct stat st;
197197

198-
/* We probably want to do this in remove_file_from_cache() and
199-
* add_cache_entry() instead...
200-
*/
201-
cache_tree_invalidate_path(active_cache_tree, path);
202-
203198
/*
204199
* First things first: get the stat information, to decide
205200
* what to do about the pathname!
@@ -239,7 +234,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
239234
return error("%s: cannot add to the index - missing --add option?",
240235
path);
241236
report("add '%s'", path);
242-
cache_tree_invalidate_path(active_cache_tree, path);
243237
return 0;
244238
}
245239

@@ -284,7 +278,6 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
284278
die("Unable to mark file %s", path);
285279
goto free_return;
286280
}
287-
cache_tree_invalidate_path(active_cache_tree, path);
288281

289282
if (force_remove) {
290283
if (remove_file_from_cache(p))
@@ -367,7 +360,6 @@ static void read_index_info(int line_termination)
367360
free(path_name);
368361
continue;
369362
}
370-
cache_tree_invalidate_path(active_cache_tree, path_name);
371363

372364
if (!mode) {
373365
/* mode == 0 means there is no such path -- remove */
@@ -474,7 +466,6 @@ static int unresolve_one(const char *path)
474466
goto free_return;
475467
}
476468

477-
cache_tree_invalidate_path(active_cache_tree, path);
478469
remove_file_from_cache(path);
479470
if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
480471
error("%s: cannot add our version to the index.", path);

builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
6060
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
6161
extern int cmd_config(int argc, const char **argv, const char *prefix);
6262
extern int cmd_rerere(int argc, const char **argv, const char *prefix);
63+
extern int cmd_reset(int argc, const char **argv, const char *prefix);
6364
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
6465
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
6566
extern int cmd_revert(int argc, const char **argv, const char *prefix);

0 commit comments

Comments
 (0)