diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/add.c | 126 | ||||
-rw-r--r-- | builtin/apply.c | 76 | ||||
-rw-r--r-- | builtin/blame.c | 211 | ||||
-rw-r--r-- | builtin/branch.c | 67 | ||||
-rw-r--r-- | builtin/check-ignore.c | 173 | ||||
-rw-r--r-- | builtin/clean.c | 159 | ||||
-rw-r--r-- | builtin/clone.c | 15 | ||||
-rw-r--r-- | builtin/commit.c | 40 | ||||
-rw-r--r-- | builtin/count-objects.c | 30 | ||||
-rw-r--r-- | builtin/describe.c | 4 | ||||
-rw-r--r-- | builtin/fetch-pack.c | 40 | ||||
-rw-r--r-- | builtin/fetch.c | 22 | ||||
-rw-r--r-- | builtin/fmt-merge-msg.c | 23 | ||||
-rw-r--r-- | builtin/grep.c | 2 | ||||
-rw-r--r-- | builtin/help.c | 32 | ||||
-rw-r--r-- | builtin/index-pack.c | 9 | ||||
-rw-r--r-- | builtin/log.c | 49 | ||||
-rw-r--r-- | builtin/ls-files.c | 17 | ||||
-rw-r--r-- | builtin/merge-index.c | 4 | ||||
-rw-r--r-- | builtin/merge-tree.c | 92 | ||||
-rw-r--r-- | builtin/merge.c | 6 | ||||
-rw-r--r-- | builtin/notes.c | 34 | ||||
-rw-r--r-- | builtin/push.c | 34 | ||||
-rw-r--r-- | builtin/receive-pack.c | 49 | ||||
-rw-r--r-- | builtin/reflog.c | 13 | ||||
-rw-r--r-- | builtin/reset.c | 287 | ||||
-rw-r--r-- | builtin/send-pack.c | 10 | ||||
-rw-r--r-- | builtin/shortlog.c | 54 | ||||
-rw-r--r-- | builtin/stripspace.c | 49 | ||||
-rw-r--r-- | builtin/tag.c | 34 | ||||
-rw-r--r-- | builtin/update-index.c | 2 |
31 files changed, 1111 insertions, 652 deletions
diff --git a/builtin/add.c b/builtin/add.c index e664100c71..ab1c9e8fb7 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -6,6 +6,7 @@ #include "cache.h" #include "builtin.h" #include "dir.h" +#include "pathspec.h" #include "exec_cmd.h" #include "cache-tree.h" #include "run-command.h" @@ -16,7 +17,7 @@ #include "bulk-checkin.h" static const char * const builtin_add_usage[] = { - N_("git add [options] [--] <filepattern>..."), + N_("git add [options] [--] <pathspec>..."), NULL }; static int patch_interactive, add_interactive, edit_interactive; @@ -97,39 +98,6 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags) return !!data.add_errors; } -static void fill_pathspec_matches(const char **pathspec, char *seen, int specs) -{ - int num_unmatched = 0, i; - - /* - * Since we are walking the index as if we were walking the directory, - * we have to mark the matched pathspec as seen; otherwise we will - * mistakenly think that the user gave a pathspec that did not match - * anything. - */ - for (i = 0; i < specs; i++) - if (!seen[i]) - num_unmatched++; - if (!num_unmatched) - return; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen); - } -} - -static char *find_used_pathspec(const char **pathspec) -{ - char *seen; - int i; - - for (i = 0; pathspec[i]; i++) - ; /* just counting */ - seen = xcalloc(i, 1); - fill_pathspec_matches(pathspec, seen, i); - return seen; -} - static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix) { char *seen; @@ -149,10 +117,14 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int *dst++ = entry; } dir->nr = dst - dir->entries; - fill_pathspec_matches(pathspec, seen, specs); + add_pathspec_matches_against_index(pathspec, seen, specs); return seen; } +/* + * Checks the index to see whether any path in pathspec refers to + * something inside a submodule. If so, dies with an error message. + */ static void treat_gitlinks(const char **pathspec) { int i; @@ -160,24 +132,8 @@ static void treat_gitlinks(const char **pathspec) if (!pathspec || !*pathspec) return; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (S_ISGITLINK(ce->ce_mode)) { - int len = ce_namelen(ce), j; - for (j = 0; pathspec[j]; j++) { - int len2 = strlen(pathspec[j]); - if (len2 <= len || pathspec[j][len] != '/' || - memcmp(ce->name, pathspec[j], len)) - continue; - if (len2 == len + 1) - /* strip trailing slash */ - pathspec[j] = xstrndup(ce->name, len); - else - die (_("Path '%s' is in submodule '%.*s'"), - pathspec[j], len, ce->name); - } - } - } + for (i = 0; pathspec[i]; i++) + pathspec[i] = check_path_for_gitlink(pathspec[i]); } static void refresh(int verbose, const char **pathspec) @@ -197,17 +153,19 @@ static void refresh(int verbose, const char **pathspec) free(seen); } -static const char **validate_pathspec(int argc, const char **argv, const char *prefix) +/* + * Normalizes argv relative to prefix, via get_pathspec(), and then + * runs die_if_path_beyond_symlink() on each path in the normalized + * list. + */ +static const char **validate_pathspec(const char **argv, const char *prefix) { const char **pathspec = get_pathspec(prefix, argv); if (pathspec) { const char **p; for (p = pathspec; *p; p++) { - if (has_symlink_leading_path(*p, strlen(*p))) { - int len = prefix ? strlen(prefix) : 0; - die(_("'%s' is beyond a symbolic link"), *p + len); - } + die_if_path_beyond_symlink(*p, prefix); } } @@ -248,7 +206,7 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch) const char **pathspec = NULL; if (argc) { - pathspec = validate_pathspec(argc, argv, prefix); + pathspec = validate_pathspec(argv, prefix); if (!pathspec) return -1; } @@ -363,6 +321,35 @@ static int add_files(struct dir_struct *dir, int flags) return exit_status; } +static void warn_pathless_add(const char *option_name, const char *short_name) { + /* + * To be consistent with "git add -p" and most Git + * commands, we should default to being tree-wide, but + * this is not the original behavior and can't be + * changed until users trained themselves not to type + * "git add -u" or "git add -A". For now, we warn and + * keep the old behavior. Later, the behavior can be changed + * to tree-wide, keeping the warning for a while, and + * eventually we can drop the warning. + */ + warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n" + "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n" + "To add content for the whole tree, run:\n" + "\n" + " git add %s :/\n" + " (or git add %s :/)\n" + "\n" + "To restrict the command to the current directory, run:\n" + "\n" + " git add %s .\n" + " (or git add %s .)\n" + "\n" + "With the current Git version, the command is restricted to the current directory."), + option_name, short_name, + option_name, short_name, + option_name, short_name); +} + int cmd_add(int argc, const char **argv, const char *prefix) { int exit_status = 0; @@ -373,6 +360,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) int add_new_files; int require_pathspec; char *seen = NULL; + const char *option_with_implicit_dot = NULL; + const char *short_option_with_implicit_dot = NULL; git_config(add_config, NULL); @@ -392,8 +381,19 @@ int cmd_add(int argc, const char **argv, const char *prefix) die(_("-A and -u are mutually incompatible")); if (!show_only && ignore_missing) die(_("Option --ignore-missing can only be used together with --dry-run")); - if ((addremove || take_worktree_changes) && !argc) { + if (addremove) { + option_with_implicit_dot = "--all"; + short_option_with_implicit_dot = "-A"; + } + if (take_worktree_changes) { + option_with_implicit_dot = "--update"; + short_option_with_implicit_dot = "-u"; + } + if (option_with_implicit_dot && !argc) { static const char *here[2] = { ".", NULL }; + if (prefix) + warn_pathless_add(option_with_implicit_dot, + short_option_with_implicit_dot); argc = 1; argv = here; } @@ -415,7 +415,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n")); return 0; } - pathspec = validate_pathspec(argc, argv, prefix); + pathspec = validate_pathspec(argv, prefix); if (read_cache() < 0) die(_("index file corrupt")); @@ -448,13 +448,13 @@ int cmd_add(int argc, const char **argv, const char *prefix) path_exclude_check_init(&check, &dir); if (!seen) - seen = find_used_pathspec(pathspec); + seen = find_pathspecs_matching_against_index(pathspec); for (i = 0; pathspec[i]; i++) { if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i])) { if (ignore_missing) { int dtype = DT_UNKNOWN; - if (path_excluded(&check, pathspec[i], -1, &dtype)) + if (is_path_excluded(&check, pathspec[i], -1, &dtype)) dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i])); } else die(_("pathspec '%s' did not match any files"), diff --git a/builtin/apply.c b/builtin/apply.c index 6c11e8bc73..06f5320b18 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1041,15 +1041,17 @@ static int gitdiff_renamedst(const char *line, struct patch *patch) static int gitdiff_similarity(const char *line, struct patch *patch) { - if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX) - patch->score = 0; + unsigned long val = strtoul(line, NULL, 10); + if (val <= 100) + patch->score = val; return 0; } static int gitdiff_dissimilarity(const char *line, struct patch *patch) { - if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX) - patch->score = 0; + unsigned long val = strtoul(line, NULL, 10); + if (val <= 100) + patch->score = val; return 0; } @@ -3598,6 +3600,40 @@ static int get_current_sha1(const char *path, unsigned char *sha1) return 0; } +static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20]) +{ + /* + * A usable gitlink patch has only one fragment (hunk) that looks like: + * @@ -1 +1 @@ + * -Subproject commit <old sha1> + * +Subproject commit <new sha1> + * or + * @@ -1 +0,0 @@ + * -Subproject commit <old sha1> + * for a removal patch. + */ + struct fragment *hunk = p->fragments; + static const char heading[] = "-Subproject commit "; + char *preimage; + + if (/* does the patch have only one hunk? */ + hunk && !hunk->next && + /* is its preimage one line? */ + hunk->oldpos == 1 && hunk->oldlines == 1 && + /* does preimage begin with the heading? */ + (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL && + !prefixcmp(++preimage, heading) && + /* does it record full SHA-1? */ + !get_sha1_hex(preimage + sizeof(heading) - 1, sha1) && + preimage[sizeof(heading) + 40 - 1] == '\n' && + /* does the abbreviated name on the index line agree with it? */ + !prefixcmp(preimage + sizeof(heading) - 1, p->old_sha1_prefix)) + return 0; /* it all looks fine */ + + /* we may have full object name on the index line */ + return get_sha1_hex(p->old_sha1_prefix, sha1); +} + /* Build an index that contains the just the files needed for a 3way merge */ static void build_fake_ancestor(struct patch *list, const char *filename) { @@ -3609,7 +3645,6 @@ static void build_fake_ancestor(struct patch *list, const char *filename) * worth showing the new sha1 prefix, but until then... */ for (patch = list; patch; patch = patch->next) { - const unsigned char *sha1_ptr; unsigned char sha1[20]; struct cache_entry *ce; const char *name; @@ -3617,20 +3652,25 @@ static void build_fake_ancestor(struct patch *list, const char *filename) name = patch->old_name ? patch->old_name : patch->new_name; if (0 < patch->is_new) continue; - else if (get_sha1_blob(patch->old_sha1_prefix, sha1)) - /* git diff has no index line for mode/type changes */ - if (!patch->lines_added && !patch->lines_deleted) { - if (get_current_sha1(patch->old_name, sha1)) - die("mode change for %s, which is not " - "in current HEAD", name); - sha1_ptr = sha1; - } else - die("sha1 information is lacking or useless " - "(%s).", name); - else - sha1_ptr = sha1; - ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0); + if (S_ISGITLINK(patch->old_mode)) { + if (!preimage_sha1_in_gitlink_patch(patch, sha1)) + ; /* ok, the textual part looks sane */ + else + die("sha1 information is lacking or useless for submoule %s", + name); + } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) { + ; /* ok */ + } else if (!patch->lines_added && !patch->lines_deleted) { + /* mode-only change: update the current */ + if (get_current_sha1(patch->old_name, sha1)) + die("mode change for %s, which is not " + "in current HEAD", name); + } else + die("sha1 information is lacking or useless " + "(%s).", name); + + ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0); if (!ce) die(_("make_cache_entry failed for path '%s'"), name); if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) diff --git a/builtin/blame.c b/builtin/blame.c index cfae569905..86100e9662 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -42,6 +42,7 @@ static int blank_boundary; static int incremental; static int xdl_opts; static int abbrev = -1; +static int no_whole_file_rename; static enum date_mode blame_date_mode = DATE_ISO8601; static size_t blame_date_width; @@ -1226,7 +1227,7 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) * The first pass looks for unrenamed path to optimize for * common cases, then we look for renames in the second pass. */ - for (pass = 0; pass < 2; pass++) { + for (pass = 0; pass < 2 - no_whole_file_rename; pass++) { struct origin *(*find)(struct scoreboard *, struct commit *, struct origin *); find = pass ? find_rename : find_origin; @@ -1321,30 +1322,31 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) * Information on commits, used for output. */ struct commit_info { - const char *author; - const char *author_mail; + struct strbuf author; + struct strbuf author_mail; unsigned long author_time; - const char *author_tz; + struct strbuf author_tz; /* filled only when asked for details */ - const char *committer; - const char *committer_mail; + struct strbuf committer; + struct strbuf committer_mail; unsigned long committer_time; - const char *committer_tz; + struct strbuf committer_tz; - const char *summary; + struct strbuf summary; }; /* * Parse author/committer line in the commit object buffer */ static void get_ac_line(const char *inbuf, const char *what, - int person_len, char *person, - int mail_len, char *mail, - unsigned long *time, const char **tz) + struct strbuf *name, struct strbuf *mail, + unsigned long *time, struct strbuf *tz) { - int len, tzlen, maillen; - char *tmp, *endp, *timepos, *mailpos; + struct ident_split ident; + size_t len, maillen, namelen; + char *tmp, *endp; + const char *namebuf, *mailbuf; tmp = strstr(inbuf, what); if (!tmp) @@ -1355,69 +1357,61 @@ static void get_ac_line(const char *inbuf, const char *what, len = strlen(tmp); else len = endp - tmp; - if (person_len <= len) { + + if (split_ident_line(&ident, tmp, len)) { error_out: /* Ugh */ - *tz = "(unknown)"; - strcpy(person, *tz); - strcpy(mail, *tz); + tmp = "(unknown)"; + strbuf_addstr(name, tmp); + strbuf_addstr(mail, tmp); + strbuf_addstr(tz, tmp); *time = 0; return; } - memcpy(person, tmp, len); - - tmp = person; - tmp += len; - *tmp = 0; - while (person < tmp && *tmp != ' ') - tmp--; - if (tmp <= person) - goto error_out; - *tz = tmp+1; - tzlen = (person+len)-(tmp+1); - *tmp = 0; - while (person < tmp && *tmp != ' ') - tmp--; - if (tmp <= person) - goto error_out; - *time = strtoul(tmp, NULL, 10); - timepos = tmp; + namelen = ident.name_end - ident.name_begin; + namebuf = ident.name_begin; - *tmp = 0; - while (person < tmp && !(*tmp == ' ' && tmp[1] == '<')) - tmp--; - if (tmp <= person) - return; - mailpos = tmp + 1; - *tmp = 0; - maillen = timepos - tmp; - memcpy(mail, mailpos, maillen); + maillen = ident.mail_end - ident.mail_begin; + mailbuf = ident.mail_begin; - if (!mailmap.nr) - return; + *time = strtoul(ident.date_begin, NULL, 10); - /* - * mailmap expansion may make the name longer. - * make room by pushing stuff down. - */ - tmp = person + person_len - (tzlen + 1); - memmove(tmp, *tz, tzlen); - tmp[tzlen] = 0; - *tz = tmp; + len = ident.tz_end - ident.tz_begin; + strbuf_add(tz, ident.tz_begin, len); /* * Now, convert both name and e-mail using mailmap */ - if (map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) { - /* Add a trailing '>' to email, since map_user returns plain emails - Note: It already has '<', since we replace from mail+1 */ - mailpos = memchr(mail, '\0', mail_len); - if (mailpos && mailpos-mail < mail_len - 1) { - *mailpos = '>'; - *(mailpos+1) = '\0'; - } - } + map_user(&mailmap, &mailbuf, &maillen, + &namebuf, &namelen); + + strbuf_addf(mail, "<%.*s>", (int)maillen, mailbuf); + strbuf_add(name, namebuf, namelen); +} + +static void commit_info_init(struct commit_info *ci) +{ + + strbuf_init(&ci->author, 0); + strbuf_init(&ci->author_mail, 0); + strbuf_init(&ci->author_tz, 0); + strbuf_init(&ci->committer, 0); + strbuf_init(&ci->committer_mail, 0); + strbuf_init(&ci->committer_tz, 0); + strbuf_init(&ci->summary, 0); +} + +static void commit_info_destroy(struct commit_info *ci) +{ + + strbuf_release(&ci->author); + strbuf_release(&ci->author_mail); + strbuf_release(&ci->author_tz); + strbuf_release(&ci->committer); + strbuf_release(&ci->committer_mail); + strbuf_release(&ci->committer_tz); + strbuf_release(&ci->summary); } static void get_commit_info(struct commit *commit, @@ -1426,57 +1420,32 @@ static void get_commit_info(struct commit *commit, { int len; const char *subject, *encoding; - char *reencoded, *message; - static char author_name[1024]; - static char author_mail[1024]; - static char committer_name[1024]; - static char committer_mail[1024]; - static char summary_buf[1024]; + char *message; + + commit_info_init(ret); - /* - * We've operated without save_commit_buffer, so - * we now need to populate them for output. - */ - if (!commit->buffer) { - enum object_type type; - unsigned long size; - commit->buffer = - read_sha1_file(commit->object.sha1, &type, &size); - if (!commit->buffer) - die("Cannot read commit %s", - sha1_to_hex(commit->object.sha1)); - } encoding = get_log_output_encoding(); - reencoded = logmsg_reencode(commit, encoding); - message = reencoded ? reencoded : commit->buffer; - ret->author = author_name; - ret->author_mail = author_mail; + message = logmsg_reencode(commit, encoding); get_ac_line(message, "\nauthor ", - sizeof(author_name), author_name, - sizeof(author_mail), author_mail, + &ret->author, &ret->author_mail, &ret->author_time, &ret->author_tz); if (!detailed) { - free(reencoded); + logmsg_free(message, commit); return; } - ret->committer = committer_name; - ret->committer_mail = committer_mail; get_ac_line(message, "\ncommitter ", - sizeof(committer_name), committer_name, - sizeof(committer_mail), committer_mail, + &ret->committer, &ret->committer_mail, &ret->committer_time, &ret->committer_tz); - ret->summary = summary_buf; len = find_commit_subject(message, &subject); - if (len && len < sizeof(summary_buf)) { - memcpy(summary_buf, subject, len); - summary_buf[len] = 0; - } else { - sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1)); - } - free(reencoded); + if (len) + strbuf_add(&ret->summary, subject, len); + else + strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1)); + + logmsg_free(message, commit); } /* @@ -1504,15 +1473,15 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat) suspect->commit->object.flags |= METAINFO_SHOWN; get_commit_info(suspect->commit, &ci, 1); - printf("author %s\n", ci.author); - printf("author-mail %s\n", ci.author_mail); + printf("author %s\n", ci.author.buf); + printf("author-mail %s\n", ci.author_mail.buf); printf("author-time %lu\n", ci.author_time); - printf("author-tz %s\n", ci.author_tz); - printf("committer %s\n", ci.committer); - printf("committer-mail %s\n", ci.committer_mail); + printf("author-tz %s\n", ci.author_tz.buf); + printf("committer %s\n", ci.committer.buf); + printf("committer-mail %s\n", ci.committer_mail.buf); printf("committer-time %lu\n", ci.committer_time); - printf("committer-tz %s\n", ci.committer_tz); - printf("summary %s\n", ci.summary); + printf("committer-tz %s\n", ci.committer_tz.buf); + printf("summary %s\n", ci.summary.buf); if (suspect->commit->object.flags & UNINTERESTING) printf("boundary\n"); if (suspect->previous) { @@ -1520,6 +1489,9 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat) printf("previous %s ", sha1_to_hex(prev->commit->object.sha1)); write_name_quoted(prev->path, stdout, '\n'); } + + commit_info_destroy(&ci); + return 1; } @@ -1706,11 +1678,11 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) if (opt & OUTPUT_ANNOTATE_COMPAT) { const char *name; if (opt & OUTPUT_SHOW_EMAIL) - name = ci.author_mail; + name = ci.author_mail.buf; else - name = ci.author; + name = ci.author.buf; printf("\t(%10s\t%10s\t%d)", name, - format_time(ci.author_time, ci.author_tz, + format_time(ci.author_time, ci.author_tz.buf, show_raw_time), ent->lno + 1 + cnt); } else { @@ -1729,14 +1701,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) const char *name; int pad; if (opt & OUTPUT_SHOW_EMAIL) - name = ci.author_mail; + name = ci.author_mail.buf; else - name = ci.author; + name = ci.author.buf; pad = longest_author - utf8_strwidth(name); printf(" (%s%*s %10s", name, pad, "", format_time(ci.author_time, - ci.author_tz, + ci.author_tz.buf, show_raw_time)); } printf(" %*d) ", @@ -1751,6 +1723,8 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) if (sb->final_buf_size && cp[-1] != '\n') putchar('\n'); + + commit_info_destroy(&ci); } static void output(struct scoreboard *sb, int option) @@ -1875,9 +1849,9 @@ static void find_alignment(struct scoreboard *sb, int *option) suspect->commit->object.flags |= METAINFO_SHOWN; get_commit_info(suspect->commit, &ci, 1); if (*option & OUTPUT_SHOW_EMAIL) - num = utf8_strwidth(ci.author_mail); + num = utf8_strwidth(ci.author_mail.buf); else - num = utf8_strwidth(ci.author); + num = utf8_strwidth(ci.author.buf); if (longest_author < num) longest_author = num; } @@ -1889,6 +1863,8 @@ static void find_alignment(struct scoreboard *sb, int *option) longest_dst_lines = num; if (largest_score < ent_score(sb, e)) largest_score = ent_score(sb, e); + + commit_info_destroy(&ci); } max_orig_digits = decimal_width(longest_src_lines); max_digits = decimal_width(longest_dst_lines); @@ -2403,6 +2379,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) init_revisions(&revs, NULL); revs.date_mode = blame_date_mode; DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV); + DIFF_OPT_SET(&revs.diffopt, FOLLOW_RENAMES); save_commit_buffer = 0; dashdash_pos = 0; @@ -2426,6 +2403,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix) parse_revision_opt(&revs, &ctx, options, blame_opt_usage); } parse_done: + no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES); + DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES); argc = parse_options_end(&ctx); if (0 < abbrev) diff --git a/builtin/branch.c b/builtin/branch.c index 873f624d1c..00d17d25d1 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -466,7 +466,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item, int verbose, int abbrev) { struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT; - const char *sub = " **** invalid ref ****"; + const char *sub = _(" **** invalid ref ****"); struct commit *commit = item->commit; if (commit && !parse_commit(commit)) { @@ -590,7 +590,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); if (!filter) - die("object '%s' does not point to a commit", + die(_("object '%s' does not point to a commit"), sha1_to_hex(merge_filter_ref)); filter->object.flags |= UNINTERESTING; @@ -706,11 +706,11 @@ static int edit_branch_description(const char *branch_name) read_branch_desc(&buf, branch_name); if (!buf.len || buf.buf[buf.len-1] != '\n') strbuf_addch(&buf, '\n'); - strbuf_addf(&buf, - "# Please edit the description for the branch\n" - "# %s\n" - "# Lines starting with '#' will be stripped.\n", - branch_name); + strbuf_commented_addf(&buf, + "Please edit the description for the branch\n" + " %s\n" + "Lines starting with '%c' will be stripped.\n", + branch_name, comment_line_char); fp = fopen(git_path(edit_description), "w"); if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) { strbuf_release(&buf); @@ -825,6 +825,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0) list = 1; + if (with_commit || merge_filter != NO_FILTER) + list = 1; + if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1) usage_with_options(builtin_branch_usage, options); @@ -837,9 +840,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix) colopts = 0; } - if (delete) + if (delete) { + if (!argc) + die(_("branch name required")); return delete_branches(argc, argv, delete > 1, kinds, quiet); - else if (list) { + } else if (list) { int ret = print_ref_list(kinds, detached, verbose, abbrev, with_commit, argv); print_columns(&output, colopts, NULL); @@ -850,24 +855,25 @@ int cmd_branch(int argc, const char **argv, const char *prefix) const char *branch_name; struct strbuf branch_ref = STRBUF_INIT; - if (detached) - die("Cannot give description to detached HEAD"); - if (!argc) + if (!argc) { + if (detached) + die(_("Cannot give description to detached HEAD")); branch_name = head; - else if (argc == 1) + } else if (argc == 1) branch_name = argv[0]; else - usage_with_options(builtin_branch_usage, options); + die(_("cannot edit description of more than one branch")); strbuf_addf(&branch_ref, "refs/heads/%s", branch_name); if (!ref_exists(branch_ref.buf)) { strbuf_release(&branch_ref); if (!argc) - return error("No commit on branch '%s' yet.", + return error(_("No commit on branch '%s' yet."), branch_name); else - return error("No such branch '%s'.", branch_name); + return error(_("No branch named '%s'."), + branch_name); } strbuf_release(&branch_ref); @@ -879,10 +885,21 @@ int cmd_branch(int argc, const char **argv, const char *prefix) else if (argc == 2) rename_branch(argv[0], argv[1], rename > 1); else - usage_with_options(builtin_branch_usage, options); + die(_("too many branches for a rename operation")); } else if (new_upstream) { struct branch *branch = branch_get(argv[0]); + if (argc > 1) + die(_("too many branches to set new upstream")); + + if (!branch) { + if (!argc || !strcmp(argv[0], "HEAD")) + die(_("could not set upstream of HEAD to %s when " + "it does not point to any branch."), + new_upstream); + die(_("no such branch '%s'"), argv[0]); + } + if (!ref_exists(branch->refname)) die(_("branch '%s' does not exist"), branch->name); @@ -895,6 +912,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix) struct branch *branch = branch_get(argv[0]); struct strbuf buf = STRBUF_INIT; |