d45f8f9008182ff39f057dae4a4d5e6eb52324a7
1/*
2 * "git rebase" builtin command
3 *
4 * Copyright (c) 2018 Pratik Karki
5 */
6
7#include "builtin.h"
8#include "run-command.h"
9#include "exec-cmd.h"
10#include "argv-array.h"
11#include "dir.h"
12#include "packfile.h"
13#include "refs.h"
14#include "quote.h"
15#include "config.h"
16#include "cache-tree.h"
17#include "unpack-trees.h"
18#include "lockfile.h"
19#include "parse-options.h"
20#include "commit.h"
21#include "diff.h"
22#include "wt-status.h"
23#include "revision.h"
24
25static char const * const builtin_rebase_usage[] = {
26 N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
27 "[<upstream>] [<branch>]"),
28 N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
29 "--root [<branch>]"),
30 N_("git rebase --continue | --abort | --skip | --edit-todo"),
31 NULL
32};
33
34static GIT_PATH_FUNC(apply_dir, "rebase-apply")
35static GIT_PATH_FUNC(merge_dir, "rebase-merge")
36
37enum rebase_type {
38 REBASE_UNSPECIFIED = -1,
39 REBASE_AM,
40 REBASE_MERGE,
41 REBASE_INTERACTIVE,
42 REBASE_PRESERVE_MERGES
43};
44
45static int use_builtin_rebase(void)
46{
47 struct child_process cp = CHILD_PROCESS_INIT;
48 struct strbuf out = STRBUF_INIT;
49 int ret;
50
51 argv_array_pushl(&cp.args,
52 "config", "--bool", "rebase.usebuiltin", NULL);
53 cp.git_cmd = 1;
54 if (capture_command(&cp, &out, 6)) {
55 strbuf_release(&out);
56 return 0;
57 }
58
59 strbuf_trim(&out);
60 ret = !strcmp("true", out.buf);
61 strbuf_release(&out);
62 return ret;
63}
64
65static int apply_autostash(void)
66{
67 warning("TODO");
68 return 0;
69}
70
71struct rebase_options {
72 enum rebase_type type;
73 const char *state_dir;
74 struct commit *upstream;
75 const char *upstream_name;
76 const char *upstream_arg;
77 char *head_name;
78 struct object_id orig_head;
79 struct commit *onto;
80 const char *onto_name;
81 const char *revisions;
82 int root;
83 struct commit *restrict_revision;
84 int dont_finish_rebase;
85 enum {
86 REBASE_NO_QUIET = 1<<0,
87 REBASE_VERBOSE = 1<<1,
88 REBASE_DIFFSTAT = 1<<2,
89 REBASE_FORCE = 1<<3,
90 REBASE_INTERACTIVE_EXPLICIT = 1<<4,
91 } flags;
92 struct strbuf git_am_opt;
93};
94
95static int is_interactive(struct rebase_options *opts)
96{
97 return opts->type == REBASE_INTERACTIVE ||
98 opts->type == REBASE_PRESERVE_MERGES;
99}
100
101/* Returns the filename prefixed by the state_dir */
102static const char *state_dir_path(const char *filename, struct rebase_options *opts)
103{
104 static struct strbuf path = STRBUF_INIT;
105 static size_t prefix_len;
106
107 if (!prefix_len) {
108 strbuf_addf(&path, "%s/", opts->state_dir);
109 prefix_len = path.len;
110 }
111
112 strbuf_setlen(&path, prefix_len);
113 strbuf_addstr(&path, filename);
114 return path.buf;
115}
116
117static int finish_rebase(struct rebase_options *opts)
118{
119 struct strbuf dir = STRBUF_INIT;
120 const char *argv_gc_auto[] = { "gc", "--auto", NULL };
121
122 delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
123 apply_autostash();
124 close_all_packs(the_repository->objects);
125 /*
126 * We ignore errors in 'gc --auto', since the
127 * user should see them.
128 */
129 run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
130 strbuf_addstr(&dir, opts->state_dir);
131 remove_dir_recursively(&dir, 0);
132 strbuf_release(&dir);
133
134 return 0;
135}
136
137static struct commit *peel_committish(const char *name)
138{
139 struct object *obj;
140 struct object_id oid;
141
142 if (get_oid(name, &oid))
143 return NULL;
144 obj = parse_object(the_repository, &oid);
145 return (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
146}
147
148static void add_var(struct strbuf *buf, const char *name, const char *value)
149{
150 if (!value)
151 strbuf_addf(buf, "unset %s; ", name);
152 else {
153 strbuf_addf(buf, "%s=", name);
154 sq_quote_buf(buf, value);
155 strbuf_addstr(buf, "; ");
156 }
157}
158
159static int run_specific_rebase(struct rebase_options *opts)
160{
161 const char *argv[] = { NULL, NULL };
162 struct strbuf script_snippet = STRBUF_INIT;
163 int status;
164 const char *backend, *backend_func;
165
166 add_var(&script_snippet, "GIT_DIR", absolute_path(get_git_dir()));
167 add_var(&script_snippet, "state_dir", opts->state_dir);
168
169 add_var(&script_snippet, "upstream_name", opts->upstream_name);
170 add_var(&script_snippet, "upstream",
171 oid_to_hex(&opts->upstream->object.oid));
172 add_var(&script_snippet, "head_name", opts->head_name);
173 add_var(&script_snippet, "orig_head", oid_to_hex(&opts->orig_head));
174 add_var(&script_snippet, "onto", oid_to_hex(&opts->onto->object.oid));
175 add_var(&script_snippet, "onto_name", opts->onto_name);
176 add_var(&script_snippet, "revisions", opts->revisions);
177 add_var(&script_snippet, "restrict_revision", opts->restrict_revision ?
178 oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
179 add_var(&script_snippet, "GIT_QUIET",
180 opts->flags & REBASE_NO_QUIET ? "" : "t");
181 add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
182 add_var(&script_snippet, "verbose",
183 opts->flags & REBASE_VERBOSE ? "t" : "");
184 add_var(&script_snippet, "diffstat",
185 opts->flags & REBASE_DIFFSTAT ? "t" : "");
186 add_var(&script_snippet, "force_rebase",
187 opts->flags & REBASE_FORCE ? "t" : "");
188
189 switch (opts->type) {
190 case REBASE_AM:
191 backend = "git-rebase--am";
192 backend_func = "git_rebase__am";
193 break;
194 case REBASE_INTERACTIVE:
195 backend = "git-rebase--interactive";
196 backend_func = "git_rebase__interactive";
197 break;
198 case REBASE_MERGE:
199 backend = "git-rebase--merge";
200 backend_func = "git_rebase__merge";
201 break;
202 case REBASE_PRESERVE_MERGES:
203 backend = "git-rebase--preserve-merges";
204 backend_func = "git_rebase__preserve_merges";
205 break;
206 default:
207 BUG("Unhandled rebase type %d", opts->type);
208 break;
209 }
210
211 strbuf_addf(&script_snippet,
212 ". git-sh-setup && . git-rebase--common &&"
213 " . %s && %s", backend, backend_func);
214 argv[0] = script_snippet.buf;
215
216 status = run_command_v_opt(argv, RUN_USING_SHELL);
217 if (opts->dont_finish_rebase)
218 ; /* do nothing */
219 else if (status == 0) {
220 if (!file_exists(state_dir_path("stopped-sha", opts)))
221 finish_rebase(opts);
222 } else if (status == 2) {
223 struct strbuf dir = STRBUF_INIT;
224
225 apply_autostash();
226 strbuf_addstr(&dir, opts->state_dir);
227 remove_dir_recursively(&dir, 0);
228 strbuf_release(&dir);
229 die("Nothing to do");
230 }
231
232 strbuf_release(&script_snippet);
233
234 return status ? -1 : 0;
235}
236
237#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
238
239static int reset_head(struct object_id *oid, const char *action,
240 const char *switch_to_branch, int detach_head)
241{
242 struct object_id head_oid;
243 struct tree_desc desc;
244 struct lock_file lock = LOCK_INIT;
245 struct unpack_trees_options unpack_tree_opts;
246 struct tree *tree;
247 const char *reflog_action;
248 struct strbuf msg = STRBUF_INIT;
249 size_t prefix_len;
250 struct object_id *orig = NULL, oid_orig,
251 *old_orig = NULL, oid_old_orig;
252 int ret = 0;
253
254 if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
255 return -1;
256
257 if (!oid) {
258 if (get_oid("HEAD", &head_oid)) {
259 rollback_lock_file(&lock);
260 return error(_("could not determine HEAD revision"));
261 }
262 oid = &head_oid;
263 }
264
265 memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
266 setup_unpack_trees_porcelain(&unpack_tree_opts, action);
267 unpack_tree_opts.head_idx = 1;
268 unpack_tree_opts.src_index = the_repository->index;
269 unpack_tree_opts.dst_index = the_repository->index;
270 unpack_tree_opts.fn = oneway_merge;
271 unpack_tree_opts.update = 1;
272 unpack_tree_opts.merge = 1;
273 if (!detach_head)
274 unpack_tree_opts.reset = 1;
275
276 if (read_index_unmerged(the_repository->index) < 0) {
277 rollback_lock_file(&lock);
278 return error(_("could not read index"));
279 }
280
281 if (!fill_tree_descriptor(&desc, oid)) {
282 error(_("failed to find tree of %s"), oid_to_hex(oid));
283 rollback_lock_file(&lock);
284 free((void *)desc.buffer);
285 return -1;
286 }
287
288 if (unpack_trees(1, &desc, &unpack_tree_opts)) {
289 rollback_lock_file(&lock);
290 free((void *)desc.buffer);
291 return -1;
292 }
293
294 tree = parse_tree_indirect(oid);
295 prime_cache_tree(the_repository->index, tree);
296
297 if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0)
298 ret = error(_("could not write index"));
299 free((void *)desc.buffer);
300
301 if (ret)
302 return ret;
303
304 reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
305 strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
306 prefix_len = msg.len;
307
308 if (!get_oid("ORIG_HEAD", &oid_old_orig))
309 old_orig = &oid_old_orig;
310 if (!get_oid("HEAD", &oid_orig)) {
311 orig = &oid_orig;
312 strbuf_addstr(&msg, "updating ORIG_HEAD");
313 update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
314 UPDATE_REFS_MSG_ON_ERR);
315 } else if (old_orig)
316 delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
317 strbuf_setlen(&msg, prefix_len);
318 strbuf_addstr(&msg, "updating HEAD");
319 if (!switch_to_branch)
320 ret = update_ref(msg.buf, "HEAD", oid, orig, REF_NO_DEREF,
321 UPDATE_REFS_MSG_ON_ERR);
322 else {
323 ret = create_symref("HEAD", switch_to_branch, msg.buf);
324 if (!ret)
325 ret = update_ref(msg.buf, "HEAD", oid, NULL, 0,
326 UPDATE_REFS_MSG_ON_ERR);
327 }
328
329 strbuf_release(&msg);
330 return ret;
331}
332
333static int rebase_config(const char *var, const char *value, void *data)
334{
335 struct rebase_options *opts = data;
336
337 if (!strcmp(var, "rebase.stat")) {
338 if (git_config_bool(var, value))
339 opts->flags |= REBASE_DIFFSTAT;
340 else
341 opts->flags &= !REBASE_DIFFSTAT;
342 return 0;
343 }
344
345 return git_default_config(var, value, data);
346}
347
348/*
349 * Determines whether the commits in from..to are linear, i.e. contain
350 * no merge commits. This function *expects* `from` to be an ancestor of
351 * `to`.
352 */
353static int is_linear_history(struct commit *from, struct commit *to)
354{
355 while (to && to != from) {
356 parse_commit(to);
357 if (!to->parents)
358 return 1;
359 if (to->parents->next)
360 return 0;
361 to = to->parents->item;
362 }
363 return 1;
364}
365
366static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
367 struct object_id *merge_base)
368{
369 struct commit *head = lookup_commit(the_repository, head_oid);
370 struct commit_list *merge_bases;
371 int res;
372
373 if (!head)
374 return 0;
375
376 merge_bases = get_merge_bases(onto, head);
377 if (merge_bases && !merge_bases->next) {
378 oidcpy(merge_base, &merge_bases->item->object.oid);
379 res = !oidcmp(merge_base, &onto->object.oid);
380 } else {
381 oidcpy(merge_base, &null_oid);
382 res = 0;
383 }
384 free_commit_list(merge_bases);
385 return res && is_linear_history(onto, head);
386}
387
388int cmd_rebase(int argc, const char **argv, const char *prefix)
389{
390 struct rebase_options options = {
391 .type = REBASE_UNSPECIFIED,
392 .flags = REBASE_NO_QUIET,
393 .git_am_opt = STRBUF_INIT,
394 };
395 const char *branch_name;
396 int ret, flags, in_progress = 0;
397 int ok_to_skip_pre_rebase = 0;
398 struct strbuf msg = STRBUF_INIT;
399 struct strbuf revisions = STRBUF_INIT;
400 struct strbuf buf = STRBUF_INIT;
401 struct object_id merge_base;
402 struct option builtin_rebase_options[] = {
403 OPT_STRING(0, "onto", &options.onto_name,
404 N_("revision"),
405 N_("rebase onto given branch instead of upstream")),
406 OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
407 N_("allow pre-rebase hook to run")),
408 OPT_NEGBIT('q', "quiet", &options.flags,
409 N_("be quiet. implies --no-stat"),
410 REBASE_NO_QUIET| REBASE_VERBOSE | REBASE_DIFFSTAT),
411 OPT_BIT('v', "verbose", &options.flags,
412 N_("display a diffstat of what changed upstream"),
413 REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
414 {OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
415 N_("do not show diffstat of what changed upstream"),
416 PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
417 OPT_BIT('f', "force-rebase", &options.flags,
418 N_("cherry-pick all commits, even if unchanged"),
419 REBASE_FORCE),
420 OPT_BIT(0, "no-ff", &options.flags,
421 N_("cherry-pick all commits, even if unchanged"),
422 REBASE_FORCE),
423 OPT_END(),
424 };
425
426 /*
427 * NEEDSWORK: Once the builtin rebase has been tested enough
428 * and git-legacy-rebase.sh is retired to contrib/, this preamble
429 * can be removed.
430 */
431
432 if (!use_builtin_rebase()) {
433 const char *path = mkpath("%s/git-legacy-rebase",
434 git_exec_path());
435
436 if (sane_execvp(path, (char **)argv) < 0)
437 die_errno(_("could not exec %s"), path);
438 else
439 BUG("sane_execvp() returned???");
440 }
441
442 if (argc == 2 && !strcmp(argv[1], "-h"))
443 usage_with_options(builtin_rebase_usage,
444 builtin_rebase_options);
445
446 prefix = setup_git_directory();
447 trace_repo_setup(prefix);
448 setup_work_tree();
449
450 git_config(rebase_config, &options);
451
452 if (is_directory(apply_dir())) {
453 options.type = REBASE_AM;
454 options.state_dir = apply_dir();
455 } else if (is_directory(merge_dir())) {
456 strbuf_reset(&buf);
457 strbuf_addf(&buf, "%s/rewritten", merge_dir());
458 if (is_directory(buf.buf)) {
459 options.type = REBASE_PRESERVE_MERGES;
460 options.flags |= REBASE_INTERACTIVE_EXPLICIT;
461 } else {
462 strbuf_reset(&buf);
463 strbuf_addf(&buf, "%s/interactive", merge_dir());
464 if(file_exists(buf.buf)) {
465 options.type = REBASE_INTERACTIVE;
466 options.flags |= REBASE_INTERACTIVE_EXPLICIT;
467 } else
468 options.type = REBASE_MERGE;
469 }
470 options.state_dir = merge_dir();
471 }
472
473 if (options.type != REBASE_UNSPECIFIED)
474 in_progress = 1;
475
476 argc = parse_options(argc, argv, prefix,
477 builtin_rebase_options,
478 builtin_rebase_usage, 0);
479
480 if (argc > 2)
481 usage_with_options(builtin_rebase_usage,
482 builtin_rebase_options);
483
484 /* Make sure no rebase is in progress */
485 if (in_progress) {
486 const char *last_slash = strrchr(options.state_dir, '/');
487 const char *state_dir_base =
488 last_slash ? last_slash + 1 : options.state_dir;
489 const char *cmd_live_rebase =
490 "git rebase (--continue | --abort | --skip)";
491 strbuf_reset(&buf);
492 strbuf_addf(&buf, "rm -fr \"%s\"", options.state_dir);
493 die(_("It seems that there is already a %s directory, and\n"
494 "I wonder if you are in the middle of another rebase. "
495 "If that is the\n"
496 "case, please try\n\t%s\n"
497 "If that is not the case, please\n\t%s\n"
498 "and run me again. I am stopping in case you still "
499 "have something\n"
500 "valuable there.\n"),
501 state_dir_base, cmd_live_rebase, buf.buf);
502 }
503
504 if (!(options.flags & REBASE_NO_QUIET))
505 strbuf_addstr(&options.git_am_opt, " -q");
506
507 switch (options.type) {
508 case REBASE_MERGE:
509 case REBASE_INTERACTIVE:
510 case REBASE_PRESERVE_MERGES:
511 options.state_dir = merge_dir();
512 break;
513 case REBASE_AM:
514 options.state_dir = apply_dir();
515 break;
516 default:
517 /* the default rebase backend is `--am` */
518 options.type = REBASE_AM;
519 options.state_dir = apply_dir();
520 break;
521 }
522
523 if (!options.root) {
524 if (argc < 1)
525 die("TODO: handle @{upstream}");
526 else {
527 options.upstream_name = argv[0];
528 argc--;
529 argv++;
530 if (!strcmp(options.upstream_name, "-"))
531 options.upstream_name = "@{-1}";
532 }
533 options.upstream = peel_committish(options.upstream_name);
534 if (!options.upstream)
535 die(_("invalid upstream '%s'"), options.upstream_name);
536 options.upstream_arg = options.upstream_name;
537 } else
538 die("TODO: upstream for --root");
539
540 /* Make sure the branch to rebase onto is valid. */
541 if (!options.onto_name)
542 options.onto_name = options.upstream_name;
543 if (strstr(options.onto_name, "...")) {
544 if (get_oid_mb(options.onto_name, &merge_base) < 0)
545 die(_("'%s': need exactly one merge base"),
546 options.onto_name);
547 options.onto = lookup_commit_or_die(&merge_base,
548 options.onto_name);
549 } else {
550 options.onto = peel_committish(options.onto_name);
551 if (!options.onto)
552 die(_("Does not point to a valid commit '%s'"),
553 options.onto_name);
554 }
555
556 /*
557 * If the branch to rebase is given, that is the branch we will rebase
558 * branch_name -- branch/commit being rebased, or
559 * HEAD (already detached)
560 * orig_head -- commit object name of tip of the branch before rebasing
561 * head_name -- refs/heads/<that-branch> or "detached HEAD"
562 */
563 if (argc > 0)
564 die("TODO: handle switch_to");
565 else {
566 /* Do not need to switch branches, we are already on it. */
567 options.head_name =
568 xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL,
569 &flags));
570 if (!options.head_name)
571 die(_("No such ref: %s"), "HEAD");
572 if (flags & REF_ISSYMREF) {
573 if (!skip_prefix(options.head_name,
574 "refs/heads/", &branch_name))
575 branch_name = options.head_name;
576
577 } else {
578 options.head_name = xstrdup("detached HEAD");
579 branch_name = "HEAD";
580 }
581 if (get_oid("HEAD", &options.orig_head))
582 die(_("Could not resolve HEAD to a revision"));
583 }
584
585 if (read_index(the_repository->index) < 0)
586 die(_("could not read index"));
587
588 if (require_clean_work_tree("rebase",
589 _("Please commit or stash them."), 1, 1)) {
590 ret = 1;
591 goto cleanup;
592 }
593
594 /*
595 * Now we are rebasing commits upstream..orig_head (or with --root,
596 * everything leading up to orig_head) on top of onto.
597 */
598
599 /*
600 * Check if we are already based on onto with linear history,
601 * but this should be done only when upstream and onto are the same
602 * and if this is not an interactive rebase.
603 */
604 if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
605 !is_interactive(&options) && !options.restrict_revision &&
606 !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
607 int flag;
608
609 if (!(options.flags & REBASE_FORCE)) {
610 if (!(options.flags & REBASE_NO_QUIET))
611 ; /* be quiet */
612 else if (!strcmp(branch_name, "HEAD") &&
613 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
614 puts(_("HEAD is up to date."));
615 else
616 printf(_("Current branch %s is up to date.\n"),
617 branch_name);
618 ret = !!finish_rebase(&options);
619 goto cleanup;
620 } else if (!(options.flags & REBASE_NO_QUIET))
621 ; /* be quiet */
622 else if (!strcmp(branch_name, "HEAD") &&
623 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
624 puts(_("HEAD is up to date, rebase forced."));
625 else
626 printf(_("Current branch %s is up to date, rebase "
627 "forced.\n"), branch_name);
628 }
629
630 /* If a hook exists, give it a chance to interrupt*/
631 if (!ok_to_skip_pre_rebase &&
632 run_hook_le(NULL, "pre-rebase", options.upstream_arg,
633 argc ? argv[0] : NULL, NULL))
634 die(_("The pre-rebase hook refused to rebase."));
635
636 if (options.flags & REBASE_DIFFSTAT) {
637 struct diff_options opts;
638
639 if (options.flags & REBASE_VERBOSE)
640 printf(_("Changes from %s to %s:\n"),
641 oid_to_hex(&merge_base),
642 oid_to_hex(&options.onto->object.oid));
643
644 /* We want color (if set), but no pager */
645 diff_setup(&opts);
646 opts.stat_width = -1; /* use full terminal width */
647 opts.stat_graph_width = -1; /* respect statGraphWidth config */
648 opts.output_format |=
649 DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
650 opts.detect_rename = DIFF_DETECT_RENAME;
651 diff_setup_done(&opts);
652 diff_tree_oid(&merge_base, &options.onto->object.oid,
653 "", &opts);
654 diffcore_std(&opts);
655 diff_flush(&opts);
656 }
657
658 /* Detach HEAD and reset the tree */
659 if (options.flags & REBASE_NO_QUIET)
660 printf(_("First, rewinding head to replay your work on top of "
661 "it...\n"));
662
663 strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
664 if (reset_head(&options.onto->object.oid, "checkout", NULL, 1))
665 die(_("Could not detach HEAD"));
666 strbuf_release(&msg);
667
668 strbuf_addf(&revisions, "%s..%s",
669 options.root ? oid_to_hex(&options.onto->object.oid) :
670 (options.restrict_revision ?
671 oid_to_hex(&options.restrict_revision->object.oid) :
672 oid_to_hex(&options.upstream->object.oid)),
673 oid_to_hex(&options.orig_head));
674
675 options.revisions = revisions.buf;
676
677 ret = !!run_specific_rebase(&options);
678
679cleanup:
680 strbuf_release(&revisions);
681 free(options.head_name);
682 return ret;
683}