]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/replace.c
refs.c: migrate internal ref iteration to pass thru repository argument
[thirdparty/git.git] / builtin / replace.c
CommitLineData
54b0c1e0
CC
1/*
2 * Builtin "git replace"
3 *
4 * Copyright (c) 2008 Christian Couder <chriscool@tuxfamily.org>
5 *
09b7e220 6 * Based on builtin/tag.c by Kristian Høgsberg <krh@redhat.com>
54b0c1e0
CC
7 * and Carlos Rica <jasampler@gmail.com> that was itself based on
8 * git-tag.sh and mktag.c by Linus Torvalds.
9 */
10
11#include "cache.h"
b2141fc1 12#include "config.h"
54b0c1e0
CC
13#include "builtin.h"
14#include "refs.h"
15#include "parse-options.h"
b892bb45 16#include "run-command.h"
60ce76d3
SB
17#include "object-store.h"
18#include "repository.h"
25a05a8c 19#include "tag.h"
54b0c1e0
CC
20
21static const char * const git_replace_usage[] = {
2477bebb 22 N_("git replace [-f] <object> <replacement>"),
ab77c309 23 N_("git replace [-f] --edit <object>"),
4228e8bc 24 N_("git replace [-f] --graft <commit> [<parent>...]"),
fb404291 25 N_("git replace [-f] --convert-graft-file"),
2477bebb 26 N_("git replace -d <object>..."),
44f9f850 27 N_("git replace [--format=<format>] [-l [<pattern>]]"),
54b0c1e0
CC
28 NULL
29};
30
663a8566 31enum replace_format {
3cc9d877
JK
32 REPLACE_FORMAT_SHORT,
33 REPLACE_FORMAT_MEDIUM,
34 REPLACE_FORMAT_LONG
663a8566 35};
44f9f850
CC
36
37struct show_data {
38 const char *pattern;
663a8566 39 enum replace_format format;
44f9f850
CC
40};
41
d70d7a8a 42static int show_reference(const char *refname, const struct object_id *oid,
54b0c1e0
CC
43 int flag, void *cb_data)
44{
44f9f850
CC
45 struct show_data *data = cb_data;
46
55d34269 47 if (!wildmatch(data->pattern, refname, 0)) {
663a8566 48 if (data->format == REPLACE_FORMAT_SHORT)
44f9f850 49 printf("%s\n", refname);
663a8566 50 else if (data->format == REPLACE_FORMAT_MEDIUM)
d70d7a8a 51 printf("%s -> %s\n", refname, oid_to_hex(oid));
663a8566 52 else { /* data->format == REPLACE_FORMAT_LONG */
d70d7a8a 53 struct object_id object;
44f9f850 54 enum object_type obj_type, repl_type;
54b0c1e0 55
e82caf38 56 if (get_oid(refname, &object))
44f9f850
CC
57 return error("Failed to resolve '%s' as a valid ref.", refname);
58
0df8e965
SB
59 obj_type = oid_object_info(the_repository, &object,
60 NULL);
61 repl_type = oid_object_info(the_repository, oid, NULL);
44f9f850 62
debca9d2
BW
63 printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
64 oid_to_hex(oid), type_name(repl_type));
44f9f850
CC
65 }
66 }
54b0c1e0
CC
67
68 return 0;
69}
70
44f9f850 71static int list_replace_refs(const char *pattern, const char *format)
54b0c1e0 72{
44f9f850
CC
73 struct show_data data;
74
54b0c1e0
CC
75 if (pattern == NULL)
76 pattern = "*";
44f9f850
CC
77 data.pattern = pattern;
78
79 if (format == NULL || *format == '\0' || !strcmp(format, "short"))
663a8566 80 data.format = REPLACE_FORMAT_SHORT;
44f9f850 81 else if (!strcmp(format, "medium"))
663a8566
CC
82 data.format = REPLACE_FORMAT_MEDIUM;
83 else if (!strcmp(format, "long"))
84 data.format = REPLACE_FORMAT_LONG;
44f9f850 85 else
e24e8719
JS
86 return error("invalid replace format '%s'\n"
87 "valid formats are 'short', 'medium' and 'long'\n",
88 format);
54b0c1e0 89
60ce76d3 90 for_each_replace_ref(the_repository, show_reference, (void *)&data);
54b0c1e0
CC
91
92 return 0;
93}
94
95typedef int (*each_replace_name_fn)(const char *name, const char *ref,
cea4332e 96 const struct object_id *oid);
54b0c1e0
CC
97
98static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
99{
9dfc3684 100 const char **p, *full_hex;
7f897b6f
JK
101 struct strbuf ref = STRBUF_INIT;
102 size_t base_len;
54b0c1e0 103 int had_error = 0;
cea4332e 104 struct object_id oid;
54b0c1e0 105
7f897b6f
JK
106 strbuf_addstr(&ref, git_replace_ref_base);
107 base_len = ref.len;
108
54b0c1e0 109 for (p = argv; *p; p++) {
cea4332e 110 if (get_oid(*p, &oid)) {
9dfc3684 111 error("Failed to resolve '%s' as a valid ref.", *p);
54b0c1e0
CC
112 had_error = 1;
113 continue;
114 }
7f897b6f
JK
115
116 strbuf_setlen(&ref, base_len);
117 strbuf_addstr(&ref, oid_to_hex(&oid));
118 full_hex = ref.buf + base_len;
119
34c290a6 120 if (read_ref(ref.buf, &oid)) {
9dfc3684 121 error("replace ref '%s' not found.", full_hex);
54b0c1e0
CC
122 had_error = 1;
123 continue;
124 }
7f897b6f 125 if (fn(full_hex, ref.buf, &oid))
54b0c1e0
CC
126 had_error = 1;
127 }
372b050b 128 strbuf_release(&ref);
54b0c1e0
CC
129 return had_error;
130}
131
132static int delete_replace_ref(const char *name, const char *ref,
cea4332e 133 const struct object_id *oid)
54b0c1e0 134{
2616a5e5 135 if (delete_ref(NULL, ref, oid, 0))
54b0c1e0
CC
136 return 1;
137 printf("Deleted replace ref '%s'\n", name);
138 return 0;
139}
140
e24e8719 141static int check_ref_valid(struct object_id *object,
cea4332e 142 struct object_id *prev,
7f897b6f 143 struct strbuf *ref,
b6e38840
CC
144 int force)
145{
7f897b6f
JK
146 strbuf_reset(ref);
147 strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
148 if (check_refname_format(ref->buf, 0))
e24e8719 149 return error("'%s' is not a valid ref name.", ref->buf);
7f897b6f 150
34c290a6 151 if (read_ref(ref->buf, prev))
cea4332e 152 oidclr(prev);
b6e38840 153 else if (!force)
e24e8719
JS
154 return error("replace ref '%s' already exists", ref->buf);
155 return 0;
b6e38840
CC
156}
157
cea4332e 158static int replace_object_oid(const char *object_ref,
159 struct object_id *object,
479bd757 160 const char *replace_ref,
cea4332e 161 struct object_id *repl,
479bd757 162 int force)
bebdd271 163{
cea4332e 164 struct object_id prev;
277336a5 165 enum object_type obj_type, repl_type;
7f897b6f 166 struct strbuf ref = STRBUF_INIT;
867c2fac
RS
167 struct ref_transaction *transaction;
168 struct strbuf err = STRBUF_INIT;
e24e8719 169 int res = 0;
bebdd271 170
0df8e965
SB
171 obj_type = oid_object_info(the_repository, object, NULL);
172 repl_type = oid_object_info(the_repository, repl, NULL);
277336a5 173 if (!force && obj_type != repl_type)
e24e8719
JS
174 return error("Objects must be of the same type.\n"
175 "'%s' points to a replaced object of type '%s'\n"
176 "while '%s' points to a replacement object of "
177 "type '%s'.",
178 object_ref, type_name(obj_type),
179 replace_ref, type_name(repl_type));
180
181 if (check_ref_valid(object, &prev, &ref, force)) {
182 strbuf_release(&ref);
183 return -1;
184 }
bebdd271 185
867c2fac
RS
186 transaction = ref_transaction_begin(&err);
187 if (!transaction ||
89f3bbdd 188 ref_transaction_update(transaction, ref.buf, repl, &prev,
1d147bdf 189 0, NULL, &err) ||
db7516ab 190 ref_transaction_commit(transaction, &err))
e24e8719 191 res = error("%s", err.buf);
bebdd271 192
867c2fac 193 ref_transaction_free(transaction);
7f897b6f 194 strbuf_release(&ref);
e24e8719 195 return res;
bebdd271
CC
196}
197
479bd757
JK
198static int replace_object(const char *object_ref, const char *replace_ref, int force)
199{
cea4332e 200 struct object_id object, repl;
479bd757 201
cea4332e 202 if (get_oid(object_ref, &object))
e24e8719
JS
203 return error("Failed to resolve '%s' as a valid ref.",
204 object_ref);
cea4332e 205 if (get_oid(replace_ref, &repl))
e24e8719
JS
206 return error("Failed to resolve '%s' as a valid ref.",
207 replace_ref);
479bd757 208
cea4332e 209 return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
479bd757
JK
210}
211
b892bb45 212/*
2deda629
JK
213 * Write the contents of the object named by "sha1" to the file "filename".
214 * If "raw" is true, then the object's raw contents are printed according to
215 * "type". Otherwise, we pretty-print the contents for human editing.
b892bb45 216 */
e24e8719 217static int export_object(const struct object_id *oid, enum object_type type,
2deda629 218 int raw, const char *filename)
b892bb45 219{
d3180279 220 struct child_process cmd = CHILD_PROCESS_INIT;
b892bb45
JK
221 int fd;
222
223 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
224 if (fd < 0)
e24e8719 225 return error_errno("unable to open %s for writing", filename);
b892bb45 226
36857e00
JK
227 argv_array_push(&cmd.args, "--no-replace-objects");
228 argv_array_push(&cmd.args, "cat-file");
2deda629 229 if (raw)
debca9d2 230 argv_array_push(&cmd.args, type_name(type));
2deda629
JK
231 else
232 argv_array_push(&cmd.args, "-p");
cea4332e 233 argv_array_push(&cmd.args, oid_to_hex(oid));
b892bb45
JK
234 cmd.git_cmd = 1;
235 cmd.out = fd;
236
237 if (run_command(&cmd))
e24e8719
JS
238 return error("cat-file reported failure");
239 return 0;
b892bb45
JK
240}
241
242/*
243 * Read a previously-exported (and possibly edited) object back from "filename",
244 * interpreting it as "type", and writing the result to the object database.
245 * The sha1 of the written object is returned via sha1.
246 */
e24e8719 247static int import_object(struct object_id *oid, enum object_type type,
2deda629 248 int raw, const char *filename)
b892bb45
JK
249{
250 int fd;
251
252 fd = open(filename, O_RDONLY);
253 if (fd < 0)
e24e8719 254 return error_errno("unable to open %s for reading", filename);
b892bb45 255
2deda629 256 if (!raw && type == OBJ_TREE) {
b892bb45 257 const char *argv[] = { "mktree", NULL };
d3180279 258 struct child_process cmd = CHILD_PROCESS_INIT;
b892bb45
JK
259 struct strbuf result = STRBUF_INIT;
260
261 cmd.argv = argv;
262 cmd.git_cmd = 1;
263 cmd.in = fd;
264 cmd.out = -1;
265
e24e8719
JS
266 if (start_command(&cmd)) {
267 close(fd);
268 return error("unable to spawn mktree");
269 }
b892bb45 270
e24e8719
JS
271 if (strbuf_read(&result, cmd.out, 41) < 0) {
272 error_errno("unable to read from mktree");
273 close(fd);
274 close(cmd.out);
275 return -1;
276 }
b892bb45
JK
277 close(cmd.out);
278
e24e8719
JS
279 if (finish_command(&cmd)) {
280 strbuf_release(&result);
281 return error("mktree reported failure");
282 }
283 if (get_oid_hex(result.buf, oid) < 0) {
284 strbuf_release(&result);
285 return error("mktree did not return an object name");
286 }
b892bb45
JK
287
288 strbuf_release(&result);
289 } else {
290 struct stat st;
291 int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
292
e24e8719
JS
293 if (fstat(fd, &st) < 0) {
294 error_errno("unable to fstat %s", filename);
295 close(fd);
296 return -1;
297 }
e3506559 298 if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
e24e8719 299 return error("unable to write object to database");
b892bb45
JK
300 /* index_fd close()s fd for us */
301 }
302
303 /*
304 * No need to close(fd) here; both run-command and index-fd
305 * will have done it for us.
306 */
e24e8719 307 return 0;
b892bb45
JK
308}
309
2deda629 310static int edit_and_replace(const char *object_ref, int force, int raw)
b892bb45 311{
e24e8719 312 char *tmpfile;
b892bb45 313 enum object_type type;
efdfe11f 314 struct object_id old_oid, new_oid, prev;
7f897b6f 315 struct strbuf ref = STRBUF_INIT;
b892bb45 316
efdfe11f 317 if (get_oid(object_ref, &old_oid) < 0)
e24e8719 318 return error("Not a valid object name: '%s'", object_ref);
b892bb45 319
0df8e965 320 type = oid_object_info(the_repository, &old_oid, NULL);
b892bb45 321 if (type < 0)
e24e8719
JS
322 return error("unable to get object type for %s",
323 oid_to_hex(&old_oid));
b892bb45 324
e24e8719
JS
325 if (check_ref_valid(&old_oid, &prev, &ref, force)) {
326 strbuf_release(&ref);
327 return -1;
328 }
7f897b6f 329 strbuf_release(&ref);
24790835 330
e24e8719
JS
331 tmpfile = git_pathdup("REPLACE_EDITOBJ");
332 if (export_object(&old_oid, type, raw, tmpfile)) {
333 free(tmpfile);
334 return -1;
335 }
336 if (launch_editor(tmpfile, NULL, NULL) < 0) {
337 free(tmpfile);
338 return error("editing object file failed");
339 }
340 if (import_object(&new_oid, type, raw, tmpfile)) {
341 free(tmpfile);
342 return -1;
343 }
b892bb45
JK
344 free(tmpfile);
345
efdfe11f
BW
346 if (!oidcmp(&old_oid, &new_oid))
347 return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid));
f22166b5 348
efdfe11f 349 return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
b892bb45
JK
350}
351
e24e8719 352static int replace_parents(struct strbuf *buf, int argc, const char **argv)
4228e8bc
CC
353{
354 struct strbuf new_parents = STRBUF_INIT;
355 const char *parent_start, *parent_end;
356 int i;
357
358 /* find existing parents */
359 parent_start = buf->buf;
cea4332e 360 parent_start += GIT_SHA1_HEXSZ + 6; /* "tree " + "hex sha1" + "\n" */
4228e8bc
CC
361 parent_end = parent_start;
362
363 while (starts_with(parent_end, "parent "))
364 parent_end += 48; /* "parent " + "hex sha1" + "\n" */
365
366 /* prepare new parents */
367 for (i = 0; i < argc; i++) {
cea4332e 368 struct object_id oid;
e24e8719
JS
369 if (get_oid(argv[i], &oid) < 0) {
370 strbuf_release(&new_parents);
371 return error(_("Not a valid object name: '%s'"),
372 argv[i]);
373 }
2122f675 374 if (!lookup_commit_reference(the_repository, &oid)) {
e24e8719
JS
375 strbuf_release(&new_parents);
376 return error(_("could not parse %s"), argv[i]);
377 }
cea4332e 378 strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid));
4228e8bc
CC
379 }
380
381 /* replace existing parents with new ones */
382 strbuf_splice(buf, parent_start - buf->buf, parent_end - parent_start,
383 new_parents.buf, new_parents.len);
384
385 strbuf_release(&new_parents);
e24e8719 386 return 0;
4228e8bc
CC
387}
388
25a05a8c
CC
389struct check_mergetag_data {
390 int argc;
391 const char **argv;
392};
393
fef461ea 394static int check_one_mergetag(struct commit *commit,
25a05a8c
CC
395 struct commit_extra_header *extra,
396 void *data)
397{
398 struct check_mergetag_data *mergetag_data = (struct check_mergetag_data *)data;
399 const char *ref = mergetag_data->argv[0];
cea4332e 400 struct object_id tag_oid;
25a05a8c
CC
401 struct tag *tag;
402 int i;
403
169c9c01 404 hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
ce71efb7 405 tag = lookup_tag(the_repository, &tag_oid);
25a05a8c 406 if (!tag)
e24e8719 407 return error(_("bad mergetag in commit '%s'"), ref);
0e740fed 408 if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
e24e8719 409 return error(_("malformed mergetag in commit '%s'"), ref);
25a05a8c
CC
410
411 /* iterate over new parents */
412 for (i = 1; i < mergetag_data->argc; i++) {
f2fd0760 413 struct object_id oid;
e82caf38 414 if (get_oid(mergetag_data->argv[i], &oid) < 0)
e24e8719
JS
415 return error(_("Not a valid object name: '%s'"),
416 mergetag_data->argv[i]);
f2fd0760 417 if (!oidcmp(&tag->tagged->oid, &oid))
fef461ea 418 return 0; /* found */
25a05a8c
CC
419 }
420
e24e8719
JS
421 return error(_("original commit '%s' contains mergetag '%s' that is "
422 "discarded; use --edit instead of --graft"), ref,
423 oid_to_hex(&tag_oid));
25a05a8c
CC
424}
425
fef461ea 426static int check_mergetags(struct commit *commit, int argc, const char **argv)
25a05a8c
CC
427{
428 struct check_mergetag_data mergetag_data;
429
430 mergetag_data.argc = argc;
431 mergetag_data.argv = argv;
fef461ea 432 return for_each_mergetag(check_one_mergetag, commit, &mergetag_data);
25a05a8c
CC
433}
434
041c98e2 435static int create_graft(int argc, const char **argv, int force, int gentle)
4228e8bc 436{
efdfe11f 437 struct object_id old_oid, new_oid;
4228e8bc
CC
438 const char *old_ref = argv[0];
439 struct commit *commit;
440 struct strbuf buf = STRBUF_INIT;
441 const char *buffer;
442 unsigned long size;
443
efdfe11f 444 if (get_oid(old_ref, &old_oid) < 0)
e24e8719 445 return error(_("Not a valid object name: '%s'"), old_ref);
2122f675 446 commit = lookup_commit_reference(the_repository, &old_oid);
e24e8719
JS
447 if (!commit)
448 return error(_("could not parse %s"), old_ref);
4228e8bc
CC
449
450 buffer = get_commit_buffer(commit, &size);
451 strbuf_add(&buf, buffer, size);
452 unuse_commit_buffer(commit, buffer);
453
e24e8719
JS
454 if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
455 strbuf_release(&buf);
456 return -1;
457 }
4228e8bc 458
0b05ab6f
CC
459 if (remove_signature(&buf)) {
460 warning(_("the original commit '%s' has a gpg signature."), old_ref);
461 warning(_("the signature will be removed in the replacement commit!"));
462 }
463
e24e8719
JS
464 if (check_mergetags(commit, argc, argv)) {
465 strbuf_release(&buf);
466 return -1;
467 }
25a05a8c 468
e24e8719
JS
469 if (write_object_file(buf.buf, buf.len, commit_type, &new_oid)) {
470 strbuf_release(&buf);
471 return error(_("could not write replacement commit for: '%s'"),
472 old_ref);
473 }
4228e8bc
CC
474
475 strbuf_release(&buf);
476
041c98e2
JS
477 if (!oidcmp(&old_oid, &new_oid)) {
478 if (gentle) {
479 warning("graft for '%s' unnecessary", oid_to_hex(&old_oid));
480 return 0;
481 }
efdfe11f 482 return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid));
041c98e2 483 }
4228e8bc 484
efdfe11f 485 return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force);
4228e8bc
CC
486}
487
fb404291
JS
488static int convert_graft_file(int force)
489{
b16b60f7 490 const char *graft_file = get_graft_file(the_repository);
fb404291
JS
491 FILE *fp = fopen_or_warn(graft_file, "r");
492 struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
493 struct argv_array args = ARGV_ARRAY_INIT;
494
495 if (!fp)
496 return -1;
497
498 while (strbuf_getline(&buf, fp) != EOF) {
499 if (*buf.buf == '#')
500 continue;
501
502 argv_array_split(&args, buf.buf);
503 if (args.argc && create_graft(args.argc, args.argv, force, 1))
504 strbuf_addf(&err, "\n\t%s", buf.buf);
505 argv_array_clear(&args);
506 }
507 fclose(fp);
508
509 strbuf_release(&buf);
510
511 if (!err.len)
512 return unlink_or_warn(graft_file);
513
514 warning(_("could not convert the following graft(s):\n%s"), err.buf);
515 strbuf_release(&err);
516
517 return -1;
518}
519
54b0c1e0
CC
520int cmd_replace(int argc, const char **argv, const char *prefix)
521{
70c7bd6d 522 int force = 0;
2deda629 523 int raw = 0;
44f9f850 524 const char *format = NULL;
70c7bd6d
JK
525 enum {
526 MODE_UNSPECIFIED = 0,
527 MODE_LIST,
528 MODE_DELETE,
b892bb45 529 MODE_EDIT,
4228e8bc 530 MODE_GRAFT,
fb404291 531 MODE_CONVERT_GRAFT_FILE,
70c7bd6d
JK
532 MODE_REPLACE
533 } cmdmode = MODE_UNSPECIFIED;
54b0c1e0 534 struct option options[] = {
70c7bd6d
JK
535 OPT_CMDMODE('l', "list", &cmdmode, N_("list replace refs"), MODE_LIST),
536 OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE),
b892bb45 537 OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT),
4228e8bc 538 OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT),
fb404291 539 OPT_CMDMODE(0, "convert-graft-file", &cmdmode, N_("convert existing graft file"), MODE_CONVERT_GRAFT_FILE),
1b354755
NTND
540 OPT_BOOL_F('f', "force", &force, N_("replace the ref if it exists"),
541 PARSE_OPT_NOCOMPLETE),
2deda629 542 OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")),
44f9f850 543 OPT_STRING(0, "format", &format, N_("format"), N_("use this format")),
54b0c1e0
CC
544 OPT_END()
545 };
546
6ebd1caf 547 read_replace_refs = 0;
36b14370 548 git_config(git_default_config, NULL);
769a4fa4 549
451bb210 550 argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
54b0c1e0 551
70c7bd6d
JK
552 if (!cmdmode)
553 cmdmode = argc ? MODE_REPLACE : MODE_LIST;
3f495f67 554
70c7bd6d 555 if (format && cmdmode != MODE_LIST)
3f495f67 556 usage_msg_opt("--format cannot be used when not listing",
44f9f850
CC
557 git_replace_usage, options);
558
4228e8bc
CC
559 if (force &&
560 cmdmode != MODE_REPLACE &&
561 cmdmode != MODE_EDIT &&
fb404291
JS
562 cmdmode != MODE_GRAFT &&
563 cmdmode != MODE_CONVERT_GRAFT_FILE)
70c7bd6d 564 usage_msg_opt("-f only makes sense when writing a replacement",
86af2caa 565 git_replace_usage, options);
bebdd271 566
2deda629
JK
567 if (raw && cmdmode != MODE_EDIT)
568 usage_msg_opt("--raw only makes sense with --edit",
569 git_replace_usage, options);
570
70c7bd6d
JK
571 switch (cmdmode) {
572 case MODE_DELETE:
54b0c1e0 573 if (argc < 1)
86af2caa
CC
574 usage_msg_opt("-d needs at least one argument",
575 git_replace_usage, options);
54b0c1e0 576 return for_each_replace_name(argv, delete_replace_ref);
54b0c1e0 577
70c7bd6d 578 case MODE_REPLACE:
bebdd271 579 if (argc != 2)
86af2caa
CC
580 usage_msg_opt("bad number of arguments",
581 git_replace_usage, options);
bebdd271 582 return replace_object(argv[0], argv[1], force);
bebdd271 583
b892bb45
JK
584 case MODE_EDIT:
585 if (argc != 1)
586 usage_msg_opt("-e needs exactly one argument",
587 git_replace_usage, options);
2deda629 588 return edit_and_replace(argv[0], force, raw);
b892bb45 589
4228e8bc
CC
590 case MODE_GRAFT:
591 if (argc < 1)
592 usage_msg_opt("-g needs at least one argument",
593 git_replace_usage, options);
041c98e2 594 return create_graft(argc, argv, force, 0);
4228e8bc 595
fb404291
JS
596 case MODE_CONVERT_GRAFT_FILE:
597 if (argc != 0)
598 usage_msg_opt("--convert-graft-file takes no argument",
599 git_replace_usage, options);
600 return !!convert_graft_file(force);
4228e8bc 601
70c7bd6d
JK
602 case MODE_LIST:
603 if (argc > 1)
604 usage_msg_opt("only one pattern can be given with -l",
605 git_replace_usage, options);
606 return list_replace_refs(argv[0], format);
54b0c1e0 607
70c7bd6d 608 default:
d398f2ea 609 BUG("invalid cmdmode %d", (int)cmdmode);
70c7bd6d 610 }
54b0c1e0 611}