diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/apply.c | 6 | ||||
-rw-r--r-- | builtin/blame.c | 11 | ||||
-rw-r--r-- | builtin/clean.c | 3 | ||||
-rw-r--r-- | builtin/clone.c | 25 | ||||
-rw-r--r-- | builtin/commit.c | 40 | ||||
-rw-r--r-- | builtin/config.c | 31 | ||||
-rw-r--r-- | builtin/describe.c | 13 | ||||
-rw-r--r-- | builtin/diff-tree.c | 4 | ||||
-rw-r--r-- | builtin/for-each-ref.c | 16 | ||||
-rw-r--r-- | builtin/fsck.c | 5 | ||||
-rw-r--r-- | builtin/index-pack.c | 3 | ||||
-rw-r--r-- | builtin/init-db.c | 32 | ||||
-rw-r--r-- | builtin/pack-objects.c | 1 | ||||
-rw-r--r-- | builtin/receive-pack.c | 6 | ||||
-rw-r--r-- | builtin/remote.c | 5 | ||||
-rw-r--r-- | builtin/replace.c | 126 | ||||
-rw-r--r-- | builtin/rev-parse.c | 7 | ||||
-rw-r--r-- | builtin/show-branch.c | 1 | ||||
-rw-r--r-- | builtin/tag.c | 68 | ||||
-rw-r--r-- | builtin/update-ref.c | 20 |
20 files changed, 300 insertions, 123 deletions
diff --git a/builtin/apply.c b/builtin/apply.c index 5fd099ed40..be2b4ce2fd 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1075,7 +1075,7 @@ static int gitdiff_index(const char *line, struct patch *patch) line = ptr + 2; ptr = strchr(line, ' '); - eol = strchr(line, '\n'); + eol = strchrnul(line, '\n'); if (!ptr || eol < ptr) ptr = eol; @@ -2867,9 +2867,7 @@ static int apply_binary_fragment(struct image *img, struct patch *patch) case BINARY_LITERAL_DEFLATED: clear_image(img); img->len = fragment->size; - img->buf = xmalloc(img->len+1); - memcpy(img->buf, fragment->patch, img->len); - img->buf[img->len] = '\0'; + img->buf = xmemdupz(fragment->patch, img->len); return 0; } return -1; diff --git a/builtin/blame.c b/builtin/blame.c index c59e702021..17d30d00aa 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1371,11 +1371,8 @@ static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit static int num_scapegoats(struct rev_info *revs, struct commit *commit) { - int cnt; struct commit_list *l = first_scapegoat(revs, commit); - for (cnt = 0; l; l = l->next) - cnt++; - return cnt; + return commit_list_count(l); } /* Distribute collected unsorted blames to the respected sorted lists @@ -2287,7 +2284,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, commit = alloc_commit_node(); commit->object.parsed = 1; commit->date = now; - commit->object.type = OBJ_COMMIT; parent_tail = &commit->parents; if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) @@ -2707,11 +2703,8 @@ parse_done: die("revision walk setup failed"); if (is_null_sha1(sb.final->object.sha1)) { - char *buf; o = sb.final->util; - buf = xmalloc(o->file.size + 1); - memcpy(buf, o->file.ptr, o->file.size + 1); - sb.final_buf = buf; + sb.final_buf = xmemdupz(o->file.ptr, o->file.size); sb.final_buf_size = o->file.size; } else { diff --git a/builtin/clean.c b/builtin/clean.c index 27701d222c..1032563e5f 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -621,8 +621,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff) nr += chosen[i]; } - result = xmalloc(sizeof(int) * (nr + 1)); - memset(result, 0, sizeof(int) * (nr + 1)); + result = xcalloc(nr + 1, sizeof(int)); for (i = 0; i < stuff->nr && j < nr; i++) { if (chosen[i]) result[j++] = i; diff --git a/builtin/clone.c b/builtin/clone.c index f0dabecca8..bbd169ceb4 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -799,18 +799,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die(_("repository '%s' does not exist"), repo_name); else repo = repo_name; - is_local = option_local != 0 && path && !is_bundle; - if (is_local) { - if (option_depth) - warning(_("--depth is ignored in local clones; use file:// instead.")); - if (!access(mkpath("%s/shallow", path), F_OK)) { - if (option_local > 0) - warning(_("source repository is shallow, ignoring --local")); - is_local = 0; - } - } - if (option_local > 0 && !is_local) - warning(_("--local is ignored")); /* no need to be strict, transport_set_option() will validate it again */ if (option_depth && atoi(option_depth) < 1) @@ -903,6 +891,19 @@ int cmd_clone(int argc, const char **argv, const char *prefix) remote = remote_get(option_origin); transport = transport_get(remote, remote->url[0]); + path = get_repo_path(remote->url[0], &is_bundle); + is_local = option_local != 0 && path && !is_bundle; + if (is_local) { + if (option_depth) + warning(_("--depth is ignored in local clones; use file:// instead.")); + if (!access(mkpath("%s/shallow", path), F_OK)) { + if (option_local > 0) + warning(_("source repository is shallow, ignoring --local")); + is_local = 0; + } + } + if (option_local > 0 && !is_local) + warning(_("--local is ignored")); transport->cloning = 1; if (!transport->get_refs_list || (!is_local && !transport->fetch)) diff --git a/builtin/commit.c b/builtin/commit.c index 72eb3beb36..a3eaf4b5ea 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -42,7 +42,20 @@ static const char * const builtin_status_usage[] = { NULL }; -static const char implicit_ident_advice[] = +static const char implicit_ident_advice_noconfig[] = +N_("Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly. Run the\n" +"following command and follow the instructions in your editor to edit\n" +"your configuration file:\n" +"\n" +" git config --global --edit\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n"); + +static const char implicit_ident_advice_config[] = N_("Your name and email address were configured automatically based\n" "on your username and hostname. Please check that they are accurate.\n" "You can suppress this message by setting them explicitly:\n" @@ -420,8 +433,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, die(_("cannot do a partial commit during a cherry-pick.")); } - memset(&partial, 0, sizeof(partial)); - partial.strdup_strings = 1; + string_list_init(&partial, 1); if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec)) exit(1); @@ -702,7 +714,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, char *buffer; buffer = strstr(use_message_buffer, "\n\n"); if (buffer) - strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); + strbuf_addstr(&sb, buffer + 2); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { @@ -1403,6 +1415,24 @@ int cmd_status(int argc, const char **argv, const char *prefix) return 0; } +static const char *implicit_ident_advice(void) +{ + char *user_config = NULL; + char *xdg_config = NULL; + int config_exists; + + home_config_paths(&user_config, &xdg_config, "config"); + config_exists = file_exists(user_config) || file_exists(xdg_config); + free(user_config); + free(xdg_config); + + if (config_exists) + return _(implicit_ident_advice_config); + else + return _(implicit_ident_advice_noconfig); + +} + static void print_summary(const char *prefix, const unsigned char *sha1, int initial_commit) { @@ -1441,7 +1471,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1, strbuf_addbuf_percentquote(&format, &committer_ident); if (advice_implicit_identity) { strbuf_addch(&format, '\n'); - strbuf_addstr(&format, _(implicit_ident_advice)); + strbuf_addstr(&format, implicit_ident_advice()); } } strbuf_release(&author_ident); diff --git a/builtin/config.c b/builtin/config.c index fcd8474701..aba71355f8 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -445,6 +445,20 @@ static int get_urlmatch(const char *var, const char *url) return 0; } +static char *default_user_config(void) +{ + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, + _("# This is Git's per-user configuration file.\n" + "[core]\n" + "# Please adapt and uncomment the following lines:\n" + "# user = %s\n" + "# email = %s\n"), + ident_default_name(), + ident_default_email()); + return strbuf_detach(&buf, NULL); +} + int cmd_config(int argc, const char **argv, const char *prefix) { int nongit = !startup_info->have_repository; @@ -551,6 +565,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (actions == ACTION_EDIT) { + const char *config_file = given_config_source.file ? + given_config_source.file : git_path("config"); check_argc(argc, 0, 0); if (!given_config_source.file && nongit) die("not in a git directory"); @@ -559,9 +575,18 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (given_config_source.blob) die("editing blobs is not supported"); git_config(git_default_config, NULL); - launch_editor(given_config_source.file ? - given_config_source.file : git_path("config"), - NULL, NULL); + if (use_global_config) { + int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd) { + char *content = default_user_config(); + write_str_in_full(fd, content); + free(content); + close(fd); + } + else if (errno != EEXIST) + die_errno(_("cannot create configuration file %s"), config_file); + } + launch_editor(config_file, NULL, NULL); } else if (actions == ACTION_SET) { int ret; diff --git a/builtin/describe.c b/builtin/describe.c index 24d740c8b1..ee6a3b998f 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -56,18 +56,9 @@ static int commit_name_cmp(const struct commit_name *cn1, return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled); } -static inline unsigned int hash_sha1(const unsigned char *sha1) -{ - unsigned int hash; - memcpy(&hash, sha1, sizeof(hash)); - return hash; -} - static inline struct commit_name *find_commit_name(const unsigned char *peeled) { - struct commit_name key; - hashmap_entry_init(&key, hash_sha1(peeled)); - return hashmap_get(&names, &key, peeled); + return hashmap_get_from_hash(&names, sha1hash(peeled), peeled); } static int replace_name(struct commit_name *e, @@ -114,7 +105,7 @@ static void add_to_known_names(const char *path, if (!e) { e = xmalloc(sizeof(struct commit_name)); hashcpy(e->peeled, peeled); - hashmap_entry_init(e, hash_sha1(peeled)); + hashmap_entry_init(e, sha1hash(peeled)); hashmap_add(&names, e); e->path = NULL; } diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index ce0e019e0c..1c4ad6223e 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -68,9 +68,7 @@ static int diff_tree_stdin(char *line) line[len-1] = 0; if (get_sha1_hex(line, sha1)) return -1; - obj = lookup_unknown_object(sha1); - if (!obj || !obj->parsed) - obj = parse_object(sha1); + obj = parse_object(sha1); if (!obj) return -1; if (obj->type == OBJ_COMMIT) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 4135980f20..47bd624696 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -283,18 +283,6 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob } } -static int num_parents(struct commit *commit) -{ - struct commit_list *parents; - int i; - - for (i = 0, parents = commit->parents; - parents; - parents = parents->next) - i++; - return i; -} - /* See grab_values */ static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) { @@ -315,12 +303,12 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object } if (!strcmp(name, "numparent")) { char *s = xmalloc(40); - v->ul = num_parents(commit); + v->ul = commit_list_count(commit->parents); sprintf(s, "%lu", v->ul); v->s = s; } else if (!strcmp(name, "parent")) { - int num = num_parents(commit); + int num = commit_list_count(commit->parents); int i; struct commit_list *parents; char *s = xmalloc(41 * num + 1); diff --git a/builtin/fsck.c b/builtin/fsck.c index 8aadca160e..d42a27da89 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -481,11 +481,6 @@ static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, in return 0; } -static int is_branch(const char *refname) -{ - return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/"); -} - static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct object *obj; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index fc40411892..5568a5bc3b 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -362,8 +362,7 @@ static void set_thread_data(struct thread_local *data) static struct base_data *alloc_base_data(void) { - struct base_data *base = xmalloc(sizeof(struct base_data)); - memset(base, 0, sizeof(*base)); + struct base_data *base = xcalloc(1, sizeof(struct base_data)); base->ref_last = -1; base->ofs_last = -1; return base; diff --git a/builtin/init-db.c b/builtin/init-db.c index 56f85e239a..587a5055ed 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -330,12 +330,12 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir, * moving the target repo later on in separate_git_dir() */ git_link = xstrdup(real_path(git_dir)); + set_git_dir(real_path(real_git_dir)); } else { - real_git_dir = real_path(git_dir); + set_git_dir(real_path(git_dir)); git_link = NULL; } - set_git_dir(real_path(real_git_dir)); return 0; } @@ -426,8 +426,9 @@ int init_db(const char *template_dir, unsigned int flags) static int guess_repository_type(const char *git_dir) { - char cwd[PATH_MAX]; const char *slash; + char *cwd; + int cwd_is_git_dir; /* * "GIT_DIR=. git init" is always bare. @@ -435,9 +436,10 @@ static int guess_repository_type(const char *git_dir) */ if (!strcmp(".", git_dir)) return 1; - if (!getcwd(cwd, sizeof(cwd))) - die_errno(_("cannot tell cwd")); - if (!strcmp(git_dir, cwd)) + cwd = xgetcwd(); + cwd_is_git_dir = !strcmp(git_dir, cwd); + free(cwd); + if (cwd_is_git_dir) return 1; /* * "GIT_DIR=.git or GIT_DIR=something/.git is usually not. @@ -535,10 +537,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) usage(init_db_usage[0]); } if (is_bare_repository_cfg == 1) { - static char git_dir[PATH_MAX+1]; - - setenv(GIT_DIR_ENVIRONMENT, - getcwd(git_dir, sizeof(git_dir)), argc > 0); + char *cwd = xgetcwd(); + setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0); + free(cwd); } if (init_shared_repository != -1) @@ -572,13 +573,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) git_work_tree_cfg = xstrdup(real_path(rel)); free(rel); } - if (!git_work_tree_cfg) { - git_work_tree_cfg = xcalloc(PATH_MAX, 1); - if (!getcwd(git_work_tree_cfg, PATH_MAX)) - die_errno (_("Cannot access current working directory")); - } + if (!git_work_tree_cfg) + git_work_tree_cfg = xgetcwd(); if (work_tree) - set_git_work_tree(real_path(work_tree)); + set_git_work_tree(work_tree); else set_git_work_tree(git_work_tree_cfg); if (access(get_git_work_tree(), X_OK)) @@ -587,7 +585,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) } else { if (work_tree) - set_git_work_tree(real_path(work_tree)); + set_git_work_tree(work_tree); } set_git_dir_init(git_dir, real_git_dir, 1); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 238b5021eb..b59f5d895e 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2494,6 +2494,7 @@ static void get_object_list(int ac, const char **av) if (get_sha1_hex(line + 10, sha1)) die("not an SHA-1 '%s'", line + 10); register_shallow(sha1); + use_bitmap_index = 0; continue; } die("not a rev '%s'", line); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 18458e81c6..f93ac454b4 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -438,7 +438,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) uint32_t mask = 1 << (cmd->index % 32); int i; - trace_printf_key("GIT_TRACE_SHALLOW", + trace_printf_key(&trace_shallow, "shallow: update_shallow_ref %s\n", cmd->ref_name); for (i = 0; i < si->shallow->nr; i++) if (si->used_shallow[i] && @@ -1122,7 +1122,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) int advertise_refs = 0; int stateless_rpc = 0; int i; - char *dir = NULL; + const char *dir = NULL; struct command *commands; struct sha1_array shallow = SHA1_ARRAY_INIT; struct sha1_array ref = SHA1_ARRAY_INIT; @@ -1157,7 +1157,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) } if (dir) usage(receive_pack_usage); - dir = xstrdup(arg); + dir = arg; } if (!dir) usage(receive_pack_usage); diff --git a/builtin/remote.c b/builtin/remote.c index 8e1dc39162..9a4640dbf0 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -754,7 +754,7 @@ static int remove_branches(struct string_list *branches) branch_names = xmalloc(branches->nr * sizeof(*branch_names)); for (i = 0; i < branches->nr; i++) branch_names[i] = branches->items[i].string; - result |= repack_without_refs(branch_names, branches->nr); + result |= repack_without_refs(branch_names, branches->nr, NULL); free(branch_names); for (i = 0; i < branches->nr; i++) { @@ -1332,7 +1332,8 @@ static int prune_remote(const char *remote, int dry_run) for (i = 0; i < states.stale.nr; i++) delete_refs[i] = states.stale.items[i].util; if (!dry_run) - result |= repack_without_refs(delete_refs, states.stale.nr); + result |= repack_without_refs(delete_refs, + states.stale.nr, NULL); free(delete_refs); } diff --git a/builtin/replace.c b/builtin/replace.c index d1ea2c2e56..294b61b97e 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -13,10 +13,12 @@ #include "refs.h" #include "parse-options.h" #include "run-command.h" +#include "tag.h" static const char * const git_replace_usage[] = { N_("git replace [-f] <object> <replacement>"), N_("git replace [-f] --edit <object>"), + N_("git replace [-f] --graft <commit> [<parent>...]"), N_("git replace -d <object>..."), N_("git replace [--format=<format>] [-l [<pattern>]]"), NULL @@ -299,6 +301,117 @@ static int edit_and_replace(const char *object_ref, int force, int raw) return replace_object_sha1(object_ref, old, "replacement", new, force); } +static void replace_parents(struct strbuf *buf, int argc, const char **argv) +{ + struct strbuf new_parents = STRBUF_INIT; + const char *parent_start, *parent_end; + int i; + + /* find existing parents */ + parent_start = buf->buf; + parent_start += 46; /* "tree " + "hex sha1" + "\n" */ + parent_end = parent_start; + + while (starts_with(parent_end, "parent ")) + parent_end += 48; /* "parent " + "hex sha1" + "\n" */ + + /* prepare new parents */ + for (i = 0; i < argc; i++) { + unsigned char sha1[20]; + if (get_sha1(argv[i], sha1) < 0) + die(_("Not a valid object name: '%s'"), argv[i]); + lookup_commit_or_die(sha1, argv[i]); + strbuf_addf(&new_parents, "parent %s\n", sha1_to_hex(sha1)); + } + + /* replace existing parents with new ones */ + strbuf_splice(buf, parent_start - buf->buf, parent_end - parent_start, + new_parents.buf, new_parents.len); + + strbuf_release(&new_parents); +} + +struct check_mergetag_data { + int argc; + const char **argv; +}; + +static void check_one_mergetag(struct commit *commit, + struct commit_extra_header *extra, + void *data) +{ + struct check_mergetag_data *mergetag_data = (struct check_mergetag_data *)data; + const char *ref = mergetag_data->argv[0]; + unsigned char tag_sha1[20]; + struct tag *tag; + int i; + + hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_sha1); + tag = lookup_tag(tag_sha1); + if (!tag) + die(_("bad mergetag in commit '%s'"), ref); + if (parse_tag_buffer(tag, extra->value, extra->len)) + die(_("malformed mergetag in commit '%s'"), ref); + + /* iterate over new parents */ + for (i = 1; i < mergetag_data->argc; i++) { + unsigned char sha1[20]; + if (get_sha1(mergetag_data->argv[i], sha1) < 0) + die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]); + if (!hashcmp(tag->tagged->sha1, sha1)) + return; /* found */ + } + + die(_("original commit '%s' contains mergetag '%s' that is discarded; " + "use --edit instead of --graft"), ref, sha1_to_hex(tag_sha1)); +} + +static void check_mergetags(struct commit *commit, int argc, const char **argv) +{ + struct check_mergetag_data mergetag_data; + + mergetag_data.argc = argc; + mergetag_data.argv = argv; + for_each_mergetag(check_one_mergetag, commit, &mergetag_data); +} + +static int create_graft(int argc, const char **argv, int force) +{ + unsigned char old[20], new[20]; + const char *old_ref = argv[0]; + struct commit *commit; + struct strbuf buf = STRBUF_INIT; + const char *buffer; + unsigned long size; + + if (get_sha1(old_ref, old) < 0) + die(_("Not a valid object name: '%s'"), old_ref); + commit = lookup_commit_or_die(old, old_ref); + + buffer = get_commit_buffer(commit, &size); + strbuf_add(&buf, buffer, size); + unuse_commit_buffer(commit, buffer); + + replace_parents(&buf, argc - 1, &argv[1]); + + if (remove_signature(&buf)) { + warning(_("the original commit '%s' has a gpg signature."), old_ref); + warning(_("the signature will be removed in the replacement commit!")); + } + + check_mergetags(commit, argc, argv); + + if (write_sha1_file(buf.buf, buf.len, commit_type, new)) + die(_("could not write replacement commit for: '%s'"), old_ref); + + strbuf_release(&buf); + + if (!hashcmp(old, new)) + return error("new commit is the same as the old one: '%s'", sha1_to_hex(old)); + + return replace_object_sha1(old_ref, old, "replacement", new, force); +} + int cmd_replace(int argc, const char **argv, const char *prefix) { int force = 0; @@ -309,12 +422,14 @@ int cmd_replace(int argc, const char **argv, const char *prefix) MODE_LIST, MODE_DELETE, MODE_EDIT, + MODE_GRAFT, MODE_REPLACE } cmdmode = MODE_UNSPECIFIED; struct option options[] = { OPT_CMDMODE('l', "list", &cmdmode, N_("list replace refs"), MODE_LIST), OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE), OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT), + OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT), OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")), OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")), OPT_STRING(0, "format", &format, N_("format"), N_("use this format")), @@ -332,7 +447,10 @@ int cmd_replace(int argc, const char **argv, const char *prefix) usage_msg_opt("--format cannot be used when not listing", git_replace_usage, options); - if (force && cmdmode != MODE_REPLACE && cmdmode != MODE_EDIT) + if (force && + cmdmode != MODE_REPLACE && + cmdmode != MODE_EDIT && + cmdmode != MODE_GRAFT) usage_msg_opt("-f only makes sense when writing a replacement", git_replace_usage, options); @@ -359,6 +477,12 @@ int cmd_replace(int argc, const char **argv, const char *prefix) git_replace_usage, options); return edit_and_replace(argv[0], force, raw); + case MODE_GRAFT: + if (argc < 1) + usage_msg_opt("-g needs at least one argument", + git_replace_usage, options); + return create_graft(argc, argv, force); + case MODE_LIST: if (argc > 1) usage_msg_opt("only one pattern can be given with -l", diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 8102aaa924..c911b456de 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -151,6 +151,7 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) error("refname '%s' is ambiguous", name); break; } + free(full); } else { show_with_type(type, name); } @@ -735,7 +736,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "--git-dir")) { const char *gitdir = getenv(GIT_DIR_ENVIRONMENT); - static char cwd[PATH_MAX]; + char *cwd; int len; if (gitdir) { puts(gitdir); @@ -745,10 +746,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) puts(".git"); continue; } - if (!getcwd(cwd, PATH_MAX)) - die_errno("unable to get current working directory"); + cwd = xgetcwd(); len = strlen(cwd); printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : ""); + free(cwd); continue; } if (!strcmp(arg, "--resolve-git-dir")) { diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 5fd4e4e488..298c95e3f8 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -777,6 +777,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) sprintf(nth_desc, "%s@{%d}", *av, base+i); append_ref(nth_desc, sha1, 1); } + free(ref); } else if (all_heads + all_remotes) snarf_refs(all_heads, all_remotes); diff --git a/builtin/tag.c b/builtin/tag.c index 9d7643f127..19eb747820 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -32,6 +32,8 @@ static const char * const git_tag_usage[] = { #define SORT_MASK 0x7fff #define REVERSE_SORT 0x8000 +static int tag_sort; + struct tag_filter { const char **patterns; int lines; @@ -346,9 +348,51 @@ static const char tag_template_nocleanup[] = "Lines starting with '%c' will be kept; you may remove them" " yourself if you want to.\n"); +/* + * Parse a sort string, and return 0 if parsed successfully. Will return + * non-zero when the sort string does not parse into a known type. If var is + * given, the error message becomes a warning and includes information about + * the configuration value. + */ +static int parse_sort_string(const char *var, const char *arg, int *sort) +{ + int type = 0, flags = 0; + + if (skip_prefix(arg, "-", &arg)) + flags |= REVERSE_SORT; + + if (skip_prefix(arg, "version:", &arg) || skip_prefix(arg, "v:", &arg)) + type = VERCMP_SORT; + else + type = STRCMP_SORT; + + if (strcmp(arg, "refname")) { + if (!var) + return error(_("unsupported sort specification '%s'"), arg); + else { + warning(_("unsupported sort specification '%s' in variable '%s'"), + var, arg); + return -1; + } + } + + *sort = (type | flags); + + return 0; +} + static int git_tag_config(const char *var, const char *value, void *cb) { - int status = git_gpg_config(var, value, cb); + int status; + + if (!strcmp(var, "tag.sort")) { + if (!value) + return config_error_nonbool(var); + parse_sort_string(var, value, &tag_sort); + return 0; + } + + status = git_gpg_config(var, value, cb); if (status) return status; if (starts_with(var, "column.")) @@ -522,20 +566,8 @@ static int parse_opt_points_at(const struct option *opt __attribute__((unused)), static int parse_opt_sort(const struct option *opt, const char *arg, int unset) { int *sort = opt->value; - int flags = 0; - if (skip_prefix(arg, "-", &arg)) - flags |= REVERSE_SORT; - - if (skip_prefix(arg, "version:", &arg) || skip_prefix(arg, "v:", &arg)) - *sort = VERCMP_SORT; - else - *sort = STRCMP_SORT; - - if (strcmp(arg, "refname")) - die(_("unsupported sort specification %s"), arg); - *sort |= flags; - return 0; + return parse_sort_string(NULL, arg, sort); } int cmd_tag(int argc, const char **argv, const char *prefix) @@ -548,7 +580,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct create_tag_options opt; char *cleanup_arg = NULL; int annotate = 0, force = 0, lines = -1; - int cmdmode = 0, sort = 0; + int cmdmode = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct commit_list *with_commit = NULL; @@ -574,7 +606,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT__FORCE(&force, N_("replace the tag if exists")), OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), { - OPTION_CALLBACK, 0, "sort", &sort, N_("type"), N_("sort tags"), + OPTION_CALLBACK, 0, "sort", &tag_sort, N_("type"), N_("sort tags"), PARSE_OPT_NONEG, parse_opt_sort }, @@ -630,9 +662,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix) copts.padding = 2; run_column_filter(colopts, &copts); } - if (lines != -1 && sort) + if (lines != -1 && tag_sort) die(_("--sort and -n are incompatible")); - ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, sort); + ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, tag_sort); if (column_active(colopts)) stop_column_filter(); return ret; diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 405267f6e2..3067b11310 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -16,6 +16,7 @@ static struct ref_transaction *transaction; static char line_termination = '\n'; static int update_flags; +static struct strbuf err = STRBUF_INIT; /* * Parse one whitespace- or NUL-terminated, possibly C-quoted argument @@ -197,8 +198,9 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next) if (*next != line_termination) die("update %s: extra input: %s", refname, next); - ref_transaction_update(transaction, refname, new_sha1, old_sha1, - update_flags, have_old); + if (ref_transaction_update(transaction, refname, new_sha1, old_sha1, + update_flags, have_old, &err)) + die("%s", err.buf); update_flags = 0; free(refname); @@ -286,8 +288,9 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next) if (*next != line_termination) die("verify %s: extra input: %s", refname, next); - ref_transaction_update(transaction, refname, new_sha1, old_sha1, - update_flags, have_old); + if (ref_transaction_update(transaction, refname, new_sha1, old_sha1, + update_flags, have_old, &err)) + die("%s", err.buf); update_flags = 0; free(refname); @@ -359,17 +362,16 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) die("Refusing to perform update with empty message."); if (read_stdin) { - int ret; transaction = ref_transaction_begin(); - if (delete || no_deref || argc > 0) usage_with_options(git_update_ref_usage, options); if (end_null) line_termination = '\0'; update_refs_stdin(); - ret = ref_transaction_commit(transaction, msg, - UPDATE_REFS_DIE_ON_ERR); - return ret; + if (ref_transaction_commit(transaction, msg, &err)) + die("%s", err.buf); + ref_transaction_free(transaction); + return 0; } if (end_null) |