summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c122
-rw-r--r--builtin/apply.c40
-rw-r--r--builtin/blame.c22
-rw-r--r--builtin/branch.c40
-rw-r--r--builtin/check-ignore.c173
-rw-r--r--builtin/clean.c5
-rw-r--r--builtin/clone.c9
-rw-r--r--builtin/commit.c32
-rw-r--r--builtin/fetch.c22
-rw-r--r--builtin/fmt-merge-msg.c2
-rw-r--r--builtin/grep.c2
-rw-r--r--builtin/help.c32
-rw-r--r--builtin/ls-files.c15
-rw-r--r--builtin/merge.c5
-rw-r--r--builtin/notes.c34
-rw-r--r--builtin/push.c34
-rw-r--r--builtin/receive-pack.c25
-rw-r--r--builtin/reflog.c13
-rw-r--r--builtin/send-pack.c10
-rw-r--r--builtin/stripspace.c49
-rw-r--r--builtin/tag.c34
21 files changed, 472 insertions, 248 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 075312afcd..7738025a2e 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"
@@ -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, this warning can be
+ * turned into a die(...), and eventually we may
+ * reallow the command with a new behavior.
+ */
+ 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,7 +448,7 @@ 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])) {
diff --git a/builtin/apply.c b/builtin/apply.c
index 6c11e8bc73..080ce2ea3e 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;
}
@@ -3609,7 +3611,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 +3618,23 @@ 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 (get_sha1_hex(patch->old_sha1_prefix, sha1))
+ die("submoule change for %s without full index name",
+ 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 b431ba3209..86100e9662 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1420,32 +1420,18 @@ static void get_commit_info(struct commit *commit,
{
int len;
const char *subject, *encoding;
- char *reencoded, *message;
+ 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;
+ message = logmsg_reencode(commit, encoding);
get_ac_line(message, "\nauthor ",
&ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
if (!detailed) {
- free(reencoded);
+ logmsg_free(message, commit);
return;
}
@@ -1459,7 +1445,7 @@ static void get_commit_info(struct commit *commit,
else
strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
- free(reencoded);
+ logmsg_free(message, commit);
}
/*
diff --git a/builtin/branch.c b/builtin/branch.c
index 873f624d1c..6371bf96c4 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,7 +885,7 @@ 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]);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
new file mode 100644
index 0000000000..709535ce09
--- /dev/null
+++ b/builtin/check-ignore.c
@@ -0,0 +1,173 @@
+#include "builtin.h"
+#include "cache.h"
+#include "dir.h"
+#include "quote.h"
+#include "pathspec.h"
+#include "parse-options.h"
+
+static int quiet, verbose, stdin_paths;
+static const char * const check_ignore_usage[] = {
+"git check-ignore [options] pathname...",
+"git check-ignore [options] --stdin < <list-of-paths>",
+NULL
+};
+
+static int null_term_line;
+
+static const struct option check_ignore_options[] = {
+ OPT__QUIET(&quiet, N_("suppress progress reporting")),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
+ OPT_GROUP(""),
+ OPT_BOOLEAN(0, "stdin", &stdin_paths,
+ N_("read file names from stdin")),
+ OPT_BOOLEAN('z', NULL, &null_term_line,
+ N_("input paths are terminated by a null character")),
+ OPT_END()
+};
+
+static void output_exclude(const char *path, struct exclude *exclude)
+{
+ char *bang = exclude->flags & EXC_FLAG_NEGATIVE ? "!" : "";
+ char *slash = exclude->flags & EXC_FLAG_MUSTBEDIR ? "/" : "";
+ if (!null_term_line) {
+ if (!verbose) {
+ write_name_quoted(path, stdout, '\n');
+ } else {
+ quote_c_style(exclude->el->src, NULL, stdout, 0);
+ printf(":%d:%s%s%s\t",
+ exclude->srcpos,
+ bang, exclude->pattern, slash);
+ quote_c_style(path, NULL, stdout, 0);
+ fputc('\n', stdout);
+ }
+ } else {
+ if (!verbose) {
+ printf("%s%c", path, '\0');
+ } else {
+ printf("%s%c%d%c%s%s%s%c%s%c",
+ exclude->el->src, '\0',
+ exclude->srcpos, '\0',
+ bang, exclude->pattern, slash, '\0',
+ path, '\0');
+ }
+ }
+}
+
+static int check_ignore(const char *prefix, const char **pathspec)
+{
+ struct dir_struct dir;
+ const char *path, *full_path;
+ char *seen;
+ int num_ignored = 0, dtype = DT_UNKNOWN, i;
+ struct path_exclude_check check;
+ struct exclude *exclude;
+
+ /* read_cache() is only necessary so we can watch out for submodules. */
+ if (read_cache() < 0)
+ die(_("index file corrupt"));
+
+ memset(&dir, 0, sizeof(dir));
+ dir.flags |= DIR_COLLECT_IGNORED;
+ setup_standard_excludes(&dir);
+
+ if (!pathspec || !*pathspec) {
+ if (!quiet)
+ fprintf(stderr, "no pathspec given.\n");
+ return 0;
+ }
+
+ path_exclude_check_init(&check, &dir);
+ /*
+ * look for pathspecs matching entries in the index, since these
+ * should not be ignored, in order to be consistent with
+ * 'git status', 'git add' etc.
+ */
+ seen = find_pathspecs_matching_against_index(pathspec);
+ for (i = 0; pathspec[i]; i++) {
+ path = pathspec[i];
+ full_path = prefix_path(prefix, prefix
+ ? strlen(prefix) : 0, path);
+ full_path = check_path_for_gitlink(full_path);
+ die_if_path_beyond_symlink(full_path, prefix);
+ if (!seen[i] && path[0]) {
+ exclude = last_exclude_matching_path(&check, full_path,
+ -1, &dtype);
+ if (exclude) {
+ if (!quiet)
+ output_exclude(path, exclude);
+ num_ignored++;
+ }
+ }
+ }
+ free(seen);
+ clear_directory(&dir);
+ path_exclude_check_clear(&check);
+
+ return num_ignored;
+}
+
+static int check_ignore_stdin_paths(const char *prefix)
+{
+ struct strbuf buf, nbuf;
+ char **pathspec = NULL;
+ size_t nr = 0, alloc = 0;
+ int line_termination = null_term_line ? 0 : '\n';
+ int num_ignored;
+
+ strbuf_init(&buf, 0);
+ strbuf_init(&nbuf, 0);
+ while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
+ if (line_termination && buf.buf[0] == '"') {
+ strbuf_reset(&nbuf);
+ if (unquote_c_style(&nbuf, buf.buf, NULL))
+ die("line is badly quoted");
+ strbuf_swap(&buf, &nbuf);
+ }
+ ALLOC_GROW(pathspec, nr + 1, alloc);
+ pathspec[nr] = xcalloc(strlen(buf.buf) + 1, sizeof(*buf.buf));
+ strcpy(pathspec[nr++], buf.buf);
+ }
+ ALLOC_GROW(pathspec, nr + 1, alloc);
+ pathspec[nr] = NULL;
+ num_ignored = check_ignore(prefix, (const char **)pathspec);
+ maybe_flush_or_die(stdout, "attribute to stdout");
+ strbuf_release(&buf);
+ strbuf_release(&nbuf);
+ free(pathspec);
+ return num_ignored;
+}
+
+int cmd_check_ignore(int argc, const char **argv, const char *prefix)
+{
+ int num_ignored;
+
+ git_config(git_default_config, NULL);
+
+ argc = parse_options(argc, argv, prefix, check_ignore_options,
+ check_ignore_usage, 0);
+
+ if (stdin_paths) {
+ if (argc > 0)
+ die(_("cannot specify pathnames with --stdin"));
+ } else {
+ if (null_term_line)
+ die(_("-z only makes sense with --stdin"));
+ if (argc == 0)
+ die(_("no path specified"));
+ }
+ if (quiet) {
+ if (argc > 1)
+ die(_("--quiet is only valid with a single pathname"));
+ if (verbose)
+ die(_("cannot have both --quiet and --verbose"));
+ }
+
+ if (stdin_paths) {
+ num_ignored = check_ignore_stdin_paths(prefix);
+ } else {
+ num_ignored = check_ignore(prefix, argv);
+ maybe_flush_or_die(stdout, "ignore to stdout");
+ }
+
+ return !num_ignored;
+}
diff --git a/builtin/clean.c b/builtin/clean.c
index f4b760bf3d..04e396b17a 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -153,6 +153,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
static const char **pathspec;
struct strbuf buf = STRBUF_INIT;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
+ struct exclude_list *el;
const char *qname;
char *seen = NULL;
struct option options[] = {
@@ -205,9 +206,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (!ignored)
setup_standard_excludes(&dir);
+ el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++)
- add_exclude(exclude_list.items[i].string, "", 0,
- &dir.exclude_list[EXC_CMDL]);
+ add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
pathspec = get_pathspec(prefix, argv);
diff --git a/builtin/clone.c b/builtin/clone.c
index 36ec99db3f..e0aaf13583 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -767,8 +767,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
atexit(remove_junk);
sigchain_push_common(remove_junk_on_signal);
- setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
-
if (safe_create_leading_directories_const(git_dir) < 0)
die(_("could not create leading directories of '%s'"), git_dir);
@@ -787,13 +785,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
- /*
- * At this point, the config exists, so we do not need the
- * environment variable. We actually need to unset it, too, to
- * re-enable parsing of the global configs.
- */
- unsetenv(CONFIG_ENVIRONMENT);
-
git_config(git_default_config, NULL);
if (option_bare) {
diff --git a/builtin/commit.c b/builtin/commit.c
index 7c2a3d48b4..1a0e5f14a3 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -733,15 +733,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (cleanup_mode == CLEANUP_ALL)
status_printf(s, GIT_COLOR_NORMAL,
_("Please enter the commit message for your changes."
- " Lines starting\nwith '#' will be ignored, and an empty"
- " message aborts the commit.\n"));
+ " Lines starting\nwith '%c' will be ignored, and an empty"
+ " message aborts the commit.\n"), comment_line_char);
else /* CLEANUP_SPACE, that is. */
status_printf(s, GIT_COLOR_NORMAL,
_("Please enter the commit message for your changes."
- " Lines starting\n"
- "with '#' will be kept; you may remove them"
- " yourself if you want to.\n"
- "An empty message aborts the commit.\n"));
+ " Lines starting\n"
+ "with '%c' will be kept; you may remove them"
+ " yourself if you want to.\n"
+ "An empty message aborts the commit.\n"), comment_line_char);
if (only_include_assumed)
status_printf_ln(s, GIT_COLOR_NORMAL,
"%s", only_include_assumed);
@@ -946,24 +946,14 @@ static void handle_untracked_files_arg(struct wt_status *s)
static const char *read_commit_message(const char *name)
{
- const char *out_enc, *out;
+ const char *out_enc;
struct commit *commit;
commit = lookup_commit_reference_by_name(name);
if (!commit)
die(_("could not lookup commit %s"), name);
out_enc = get_commit_output_encoding();
- out = logmsg_reencode(commit, out_enc);
-
- /*
- * If we failed to reencode the buffer, just copy it
- * byte for byte so the user can try to fix it up.
- * This also handles the case where input and output
- * encodings are identical.
- */
- if (out == NULL)
- out = xstrdup(commit->buffer);
- return out;
+ return logmsg_reencode(commit, out_enc);
}
static int parse_and_validate_options(int argc, const char *argv[],
@@ -1329,8 +1319,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)
return git_status_config(k, v, s);
}
-static const char post_rewrite_hook[] = "hooks/post-rewrite";
-
static int run_rewrite_hook(const unsigned char *oldsha1,
const unsigned char *newsha1)
{
@@ -1341,10 +1329,10 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
int code;
size_t n;
- if (access(git_path(post_rewrite_hook), X_OK) < 0)
+ argv[0] = find_hook("post-rewrite");
+ if (!argv[0])
return 0;
- argv[0] = git_path(post_rewrite_hook);
argv[1] = "amend";
argv[2] = NULL;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 4b5a89839b..4b6b1dfe66 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -32,7 +32,7 @@ enum {
static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-static int tags = TAGS_DEFAULT;
+static int tags = TAGS_DEFAULT, unshallow;
static const char *depth;
static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
@@ -82,6 +82,9 @@ static struct option builtin_fetch_options[] = {
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
OPT_STRING(0, "depth", &depth, N_("depth"),
N_("deepen history of shallow clone")),
+ { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
+ N_("convert to a complete repository"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
{ OPTION_STRING, 0, "recurse-submodules-default",
@@ -959,6 +962,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct string_list list = STRING_LIST_INIT_NODUP;
struct remote *remote;
int result = 0;
+ static const char *argv_gc_auto[] = {
+ "gc", "--auto", NULL,
+ };
packet_trace_identity("fetch");
@@ -970,6 +976,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
+ if (unshallow) {
+ if (depth)
+ die(_("--depth and --unshallow cannot be used together"));
+ else if (!is_repository_shallow())
+ die(_("--unshallow on a complete repository does not make sense"));
+ else {
+ static char inf_depth[12];
+ sprintf(inf_depth, "%d", INFINITE_DEPTH);
+ depth = inf_depth;
+ }
+ }
+
if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
if (recurse_submodules_default) {
int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
@@ -1026,5 +1044,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
list.strdup_strings = 1;
string_list_clear(&list, 0);
+ run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+
return result;
}
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index d9af43c257..b49612f0ce 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -470,7 +470,7 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
strbuf_complete_line(tagbuf);
if (sig->len) {
strbuf_addch(tagbuf, '\n');
- strbuf_add_lines(tagbuf, "# ", sig->buf, sig->len);
+ strbuf_add_commented_lines(tagbuf, sig->buf, sig->len);
}
}
diff --git a/builtin/grep.c b/builtin/grep.c
index 0e1b6c860e..8025964987 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -823,6 +823,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
struct object *object = parse_object(sha1);
if (!object)
die(_("bad object %s"), arg);
+ if (!seen_dashdash)
+ verify_non_filename(prefix, arg);
add_object_array(object, arg, &list);
continue;
}
diff --git a/builtin/help.c b/builtin/help.c
index bd86253d83..d1d71816a9 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -6,7 +6,6 @@
#include "cache.h"
#include "builtin.h"
#include "exec_cmd.h"
-#include "common-cmds.h"
#include "parse-options.h"
#include "run-command.h"
#include "column.h"
@@ -237,21 +236,21 @@ static int add_man_viewer_cmd(const char *name,
static int add_man_viewer_info(const char *var, const char *value)
{
- const char *name = var + 4;
- const char *subkey = strrchr(name, '.');
+ const char *name, *subkey;
+ int namelen;
- if (!subkey)
+ if (parse_config_key(var, "man", &name, &namelen, &subkey) < 0 || !name)
return 0;
- if (!strcmp(subkey, ".path")) {
+ if (!strcmp(subkey, "path")) {
if (!value)
return config_error_nonbool(var);
- return add_man_viewer_path(name, subkey - name, value);
+ return add_man_viewer_path(name, namelen, value);
}
- if (!strcmp(subkey, ".cmd")) {
+ if (!strcmp(subkey, "cmd")) {
if (!value)
return config_error_nonbool(var);
- return add_man_viewer_cmd(name, subkey - name, value);
+ return add_man_viewer_cmd(name, namelen, value);
}
return 0;
@@ -287,23 +286,6 @@ static int git_help_config(const char *var, const char *value, void *cb)
static struct cmdnames main_cmds, other_cmds;
-void list_common_cmds_help(void)
-{
- int i, longest = 0;
-
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
- if (longest < strlen(common_cmds[i].name))
- longest = strlen(common_cmds[i].name);
- }
-
- puts(_("The most commonly used git commands are:"));
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
- printf(" %s ", common_cmds[i].name);
- mput_char(' ', longest - strlen(common_cmds[i].name));
- puts(_(common_cmds[i].help));
- }
-}
-
static int is_git_command(const char *s)
{
return is_in_cmdlist(&main_cmds, s) ||
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 373c573449..175e6e3e72 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -35,6 +35,7 @@ static int error_unmatch;
static char *ps_matched;
static const char *with_tree;
static int exc_given;
+static int exclude_args;
static const char *tag_cached = "";
static const char *tag_unmerged = "";
@@ -420,10 +421,10 @@ static int option_parse_z(const struct option *opt,
static int option_parse_exclude(const struct option *opt,
const char *arg, int unset)
{
- struct exclude_list *list = opt->value;
+ struct string_list *exclude_list = opt->value;
exc_given = 1;
- add_exclude(arg, "", 0, list);
+ string_list_append(exclude_list, arg);
return 0;
}
@@ -452,9 +453,11 @@ static int option_parse_exclude_standard(const struct option *opt,
int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{
- int require_work_tree = 0, show_tag = 0;
+ int require_work_tree = 0, show_tag = 0, i;
const char *max_prefix;
struct dir_struct dir;
+ struct exclude_list *el;
+ struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct option builtin_ls_files_options[] = {
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
N_("paths are separated with NUL character"),
@@ -488,7 +491,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
N_("show unmerged files in the output")),
OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
N_("show resolve-undo information")),
- { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], N_("pattern"),
+ { OPTION_CALLBACK, 'x', "exclude", &exclude_list, N_("pattern"),
N_("skip files matching pattern"),
0, option_parse_exclude },
{ OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"),
@@ -525,6 +528,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
ls_files_usage, 0);
+ el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
+ for (i = 0; i < exclude_list.nr; i++) {
+ add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
+ }
if (show_tag || show_valid_bit) {
tag_cached = "H ";
tag_unmerged = "M ";
diff --git a/builtin/merge.c b/builtin/merge.c
index 9307e9c726..7c8922c8b0 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -788,17 +788,16 @@ static const char merge_editor_comment[] =
N_("Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
"\n"
- "Lines starting with '#' will be ignored, and an empty message aborts\n"
+ "Lines starting with '%c' will be ignored, and an empty message aborts\n"
"the commit.\n");
static void prepare_to_commit(struct commit_list *remoteheads)
{
struct strbuf msg = STRBUF_INIT;
- const char *comment = _(merge_editor_comment);
strbuf_addbuf(&msg, &merge_msg);
strbuf_addch(&msg, '\n');
if (0 < option_edit)
- strbuf_add_lines(&msg, "# ", comment, strlen(comment));
+ strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
write_merge_msg(&msg);
if (run_hook(get_index_file(), "prepare-commit-msg",
git_path("MERGE_MSG"), "merge", NULL, NULL))
diff --git a/builtin/notes.c b/builtin/notes.c
index 453457adb9..57748a6fb6 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -92,10 +92,7 @@ static const char * const git_notes_get_ref_usage[] = {
};
static const char note_template[] =
- "\n"
- "#\n"
- "# Write/edit the notes for the following object:\n"
- "#\n";
+ "\nWrite/edit the notes for the following object:\n";
struct msg_arg {
int given;
@@ -129,7 +126,7 @@ static void write_commented_object(int fd, const unsigned char *object)
{"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
struct child_process show;
struct strbuf buf = STRBUF_INIT;
- FILE *show_out;
+ struct strbuf cbuf = STRBUF_INIT;
/* Invoke "git show --stat --no-notes $object" */
memset(&show, 0, sizeof(show));
@@ -142,21 +139,14 @@ static void write_commented_object(int fd, const unsigned char *object)
die(_("unable to start 'show' for object '%s'"),
sha1_to_hex(object));
- /* Open the output as FILE* so strbuf_getline() can be used. */
- show_out = xfdopen(show.out, "r");
- if (show_out == NULL)
- die_errno(_("can't fdopen 'show' output fd"));
+ if (strbuf_read(&buf, show.out, 0) < 0)
+ die_errno(_("could not read 'show' output"));
+ strbuf_add_commented_lines(&cbuf, buf.buf, buf.len);
+ write_or_die(fd, cbuf.buf, cbuf.len);
- /* Prepend "# " to each output line and write result to 'fd' */
- while (strbuf_getline(&buf, show_out, '\n') != EOF) {
- write_or_die(fd, "# ", 2);
- write_or_die(fd, buf.buf, buf.len);
- write_or_die(fd, "\n", 1);
- }
+ strbuf_release(&cbuf);
strbuf_release(&buf);
- if (fclose(show_out))
- die_errno(_("failed to close pipe to 'show' for object '%s'"),
- sha1_to_hex(object));
+
if (finish_command(&show))
die(_("failed to finish 'show' for object '%s'"),
sha1_to_hex(object));
@@ -170,6 +160,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
if (msg->use_editor || !msg->given) {
int fd;
+ struct strbuf buf = STRBUF_INIT;
/* write the template message before editing: */
path = git_pathdup("NOTES_EDITMSG");
@@ -181,11 +172,16 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
write_or_die(fd, msg->buf.buf, msg->buf.len);
else if (prev && !append_only)
write_note_data(fd, prev);
- write_or_die(fd, note_template, strlen(note_template));
+
+ strbuf_addch(&buf, '\n');
+ strbuf_add_commented_lines(&buf, note_template, strlen(note_template));
+ strbuf_addch(&buf, '\n');
+ write_or_die(fd, buf.buf, buf.len);
write_commented_object(fd, object);
close(fd);
+ strbuf_release(&buf);
strbuf_reset(&(msg->buf));
if (launch_editor(path, &(msg->buf), NULL)) {
diff --git a/builtin/push.c b/builtin/push.c
index 8491e431e4..42b129d36c 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -220,9 +220,20 @@ static const char message_advice_checkout_pull_push[] =
"(e.g. 'git pull') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
+static const char message_advice_ref_fetch_first[] =
+ N_("Updates were rejected because the remote contains work that you do\n"
+ "not have locally. This is usually caused by another repository pushing\n"
+ "to the same ref. You may want to first merge the remote changes (e.g.,\n"
+ "'git pull') before pushing again.\n"
+ "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
static const char message_advice_ref_already_exists[] =
- N_("Updates were rejected because the destination reference already exists\n"
- "in the remote.");
+ N_("Updates were rejected because the tag already exists in the remote.");
+
+static const char message_advice_ref_needs_force[] =
+ N_("You cannot update a remote ref that points at a non-commit object,\n"
+ "or update a remote ref to make it point at a non-commit object,\n"
+ "without using the '--force' option.\n");
static void advise_pull_before_push(void)
{
@@ -252,6 +263,20 @@ static void advise_ref_already_exists(void)
advise(_(message_advice_ref_already_exists));
}
+static void advise_ref_fetch_first(void)
+{
+ if (!advice_push_fetch_first || !advice_push_update_rejected)
+ return;
+ advise(_(message_advice_ref_fetch_first));
+}
+
+static void advise_ref_needs_force(void)
+{
+ if (!advice_push_needs_force || !advice_push_update_rejected)
+ return;
+ advise(_(message_advice_ref_needs_force));
+}
+
static int push_with_options(struct transport *transport, int flags)
{
int err;
@@ -285,6 +310,10 @@ static int push_with_options(struct transport *transport, int flags)
advise_checkout_pull_push();
} else if (reject_reasons & REJECT_ALREADY_EXISTS) {
advise_ref_already_exists();
+ } else if (reject_reasons & REJECT_FETCH_FIRST) {
+ advise_ref_fetch_first();
+ } else if (reject_reasons & REJECT_NEEDS_FORCE) {
+ advise_ref_needs_force();
}
return 1;
@@ -407,6 +436,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
TRANSPORT_PUSH_PRUNE),
+ OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK),
OPT_END()
};
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index ff781febca..e8878de45c 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -182,9 +182,6 @@ struct command {
char ref_name[FLEX_ARRAY]; /* more */
};
-static const char pre_receive_hook[] = "hooks/pre-receive";
-static const char post_receive_hook[] = "hooks/post-receive";
-
static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@ -242,10 +239,10 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
const char *argv[2];
int code;
- if (access(hook_name, X_OK) < 0)
+ argv[0] = find_hook(hook_name);
+ if (!argv[0])
return 0;
- argv[0] = hook_name;
argv[1] = NULL;
memset(&proc, 0, sizeof(proc));
@@ -331,15 +328,14 @@ static int run_receive_hook(struct command *commands, const char *hook_name,
static int run_update_hook(struct command *cmd)
{
- static const char update_hook[] = "hooks/update";
const char *argv[5];
struct child_process proc;
int code;
- if (access(update_hook, X_OK) < 0)
+ argv[0] = find_hook("update");
+ if (!argv[0])
return 0;
- argv[0] = update_hook;
argv[1] = cmd->ref_name;
argv[2] = sha1_to_hex(cmd->old_sha1);
argv[3] = sha1_to_hex(cmd->new_sha1);
@@ -532,24 +528,25 @@ static const char *update(struct command *cmd)
}
}
-static char update_post_hook[] = "hooks/post-update";
-
static void run_update_post_hook(struct command *commands)
{
struct command *cmd;
int argc;
const char **argv;
struct child_process proc;
+ char *hook;
+ hook = find_hook("post-update");
for (argc = 0, cmd = commands; cmd; cmd = cmd->next) {
if (cmd->error_string || cmd->did_not_exist)
continue;
argc++;
}
- if (!argc || access(update_post_hook, X_OK) < 0)
+ if (!argc || !hook)
return;
+
argv = xmalloc(sizeof(*argv) * (2 + argc));
- argv[0] = update_post_hook;
+ argv[0] = hook;
for (argc = 1, cmd = commands; cmd; cmd = cmd->next) {
char *p;
@@ -704,7 +701,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
0, &cmd))
set_connectivity_errors(commands);
- if (run_receive_hook(commands, pre_receive_hook, 0)) {
+ if (run_receive_hook(commands, "pre-receive", 0)) {
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
cmd->error_string = "pre-receive hook declined";
@@ -994,7 +991,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
unlink_or_warn(pack_lockfile);
if (report_status)
report(commands, unpack_status);
- run_receive_hook(commands, post_receive_hook, 1);
+ run_receive_hook(commands, "post-receive", 1);
run_update_post_hook(commands);
if (auto_gc) {
const char *argv_gc_auto[] = {
diff --git a/builtin/reflog.c b/builtin/reflog.c
index b3c9e27bde..1fedf66329 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -510,26 +510,27 @@ static int parse_expire_cfg_value(const char *var, const char *value, unsigned l
static int reflog_expire_config(const char *var, const char *value, void *cb)
{
- const char *lastdot = strrchr(var, '.');
+ const char *pattern, *key;
+ int pattern_len;
unsigned long expire;
int slot;
struct reflog_expire_cfg *ent;
- if (!lastdot || prefixcmp(var, "gc."))
+ if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
return git_default_config(var, value, cb);
- if (!strcmp(lastdot, ".reflogexpire")) {
+ if (!strcmp(key, "reflogexpire")) {
slot = EXPIRE_TOTAL;
if (parse_expire_cfg_value(var, value, &expire))
return -1;
- } else if (!strcmp(lastdot, ".reflogexpireunreachable")) {
+ } else if (!strcmp(key, "reflogexpireunreachable")) {
slot = EXPIRE_UNREACH;
if (parse_expire_cfg_value(var, value, &expire))
return -1;
} else
return git_default_config(var, value, cb);
- if (lastdot == var + 2) {
+ if (!pattern) {
switch (slot) {
case EXPIRE_TOTAL:
default_reflog_expire = expire;
@@ -541,7 +542,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
return 0;
}
- ent = find_cfg_ent(var + 3, lastdot - (var+3));
+ ent = find_cfg_ent(pattern, pattern_len);
if (!ent)
return -1;
switch (slot) {
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index f849e0a4a0..57a46b2654 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -44,6 +44,16 @@ static void print_helper_status(struct ref *ref)
msg = "non-fast forward";
break;
+ case REF_STATUS_REJECT_FETCH_FIRST:
+ res = "error";
+ msg = "fetch first";
+ break;
+
+ case REF_STATUS_REJECT_NEEDS_FORCE:
+ res = "error";
+ msg = "needs force";
+ break;
+
case REF_STATUS_REJECT_ALREADY_EXISTS:
res = "error";
msg = "already exists";
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index f16986c0ae..e981dfb9f0 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -30,7 +30,8 @@ static size_t cleanup(char *line, size_t len)
*
* If last line does not have a newline at the end, one is added.
*
- * Enable skip_comments to skip every line starting with "#".
+ * Enable skip_comments to skip every line starting with comment
+ * character.
*/
void stripspace(struct strbuf *sb, int skip_comments)
{
@@ -45,7 +46,7 @@ void stripspace(struct strbuf *sb, int skip_comments)
eol = memchr(sb->buf + i, '\n', sb->len - i);
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
- if (skip_comments && len && sb->buf[i] == '#') {
+ if (skip_comments && len && sb->buf[i] == comment_line_char) {
newlen = 0;
continue;
}
@@ -66,21 +67,53 @@ void stripspace(struct strbuf *sb, int skip_comments)
strbuf_setlen(sb, j);
}
+static void comment_lines(struct strbuf *buf)
+{
+ char *msg;
+ size_t len;
+
+ msg = strbuf_detach(buf, &len);
+ strbuf_add_commented_lines(buf, msg, len);
+ free(msg);
+}
+
+static const char *usage_msg = "\n"
+" git stripspace [-s | --strip-comments] < input\n"
+" git stripspace [-c | --comment-lines] < input";
+
int cmd_stripspace(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
int strip_comments = 0;
+ enum { INVAL = 0, STRIP_SPACE = 1, COMMENT_LINES = 2 } mode = STRIP_SPACE;
+
+ if (argc == 2) {
+ if (!strcmp(argv[1], "-s") ||
+ !strcmp(argv[1], "--strip-comments")) {
+ strip_comments = 1;
+ } else if (!strcmp(argv[1], "-c") ||
+ !strcmp(argv[1], "--comment-lines")) {
+ mode = COMMENT_LINES;
+ } else {
+ mode = INVAL;
+ }
+ } else if (argc > 1) {
+ mode = INVAL;
+ }
+
+ if (mode == INVAL)
+ usage(usage_msg);
- if (argc == 2 && (!strcmp(argv[1], "-s") ||
- !strcmp(argv[1], "--strip-comments")))
- strip_comments = 1;
- else if (argc > 1)
- usage("git stripspace [-s | --strip-comments] < input");
+ if (strip_comments || mode == COMMENT_LINES)
+ git_config(git_default_config, NULL);
if (strbuf_read(&buf, 0, 1024) < 0)
die_errno("could not read the input");
- stripspace(&buf, strip_comments);
+ if (mode == STRIP_SPACE)
+ stripspace(&buf, strip_comments);
+ else
+ comment_lines(&buf);
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
diff --git a/builtin/tag.c b/builtin/tag.c
index 9c3e0673d5..f8266888cc 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -246,19 +246,13 @@ static int do_sign(struct strbuf *buffer)
}
static const char tag_template[] =
- N_("\n"
- "#\n"
- "# Write a tag message\n"
- "# Lines starting with '#' will be ignored.\n"
- "#\n");
+ N_("\nWrite a tag message\n"
+ "Lines starting with '%c' will be ignored.\n");
static const char tag_template_nocleanup[] =
- N_("\n"
- "#\n"
- "# Write a tag message\n"
- "# Lines starting with '#' will be kept; you may remove them"
- " yourself if you want to.\n"
- "#\n");
+ N_("\nWrite a tag message\n"
+ "Lines starting with '%c' will be kept; you may remove them"
+ " yourself if you want to.\n");
static int git_tag_config(const char *var, const char *value, void *cb)
{
@@ -346,14 +340,18 @@ static void create_tag(const unsigned char *object, const char *tag,
if (fd < 0)
die_errno(_("could not create file '%s'"), path);
- if (!is_null_sha1(prev))
+ if (!is_null_sha1(prev)) {
write_tag_body(fd, prev);
- else if (opt->cleanup_mode == CLEANUP_ALL)
- write_or_die(fd, _(tag_template),
- strlen(_(tag_template)));
- else
- write_or_die(fd, _(tag_template_nocleanup),
- strlen(_(tag_template_nocleanup)));
+ } else {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addch(&buf, '\n');
+ if (opt->cleanup_mode == CLEANUP_ALL)
+ strbuf_commented_addf(&buf, _(tag_template), comment_line_char);
+ else
+ strbuf_commented_addf(&buf, _(tag_template_nocleanup), comment_line_char);
+ write_or_die(fd, buf.buf, buf.len);
+ strbuf_release(&buf);
+ }
close(fd);
if (launch_editor(path, buf, NULL)) {