From 7c4c97c0ac0cd66861d0c2b8bd7a47ed3c523ea7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 13:20:25 +0100 Subject: [PATCH 01/52] Turn the flags in struct dir_struct into a single variable By having flags represented as bits in the new member variable 'flags', it will be easier to use parse_options when dir_struct is involved. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-add.c | 2 +- builtin-checkout.c | 2 +- builtin-clean.c | 4 ++-- builtin-ls-files.c | 14 ++++++++------ builtin-merge.c | 2 +- builtin-read-tree.c | 2 +- dir.c | 17 +++++++++-------- dir.h | 12 +++++++----- wt-status.c | 7 +++---- 9 files changed, 33 insertions(+), 29 deletions(-) diff --git a/builtin-add.c b/builtin-add.c index ac98c8354d..c986a3ada1 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -104,7 +104,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec, /* Set up the default git porcelain excludes */ memset(dir, 0, sizeof(*dir)); if (!ignored_too) { - dir->collect_ignored = 1; + dir->flags |= DIR_COLLECT_IGNORED; setup_standard_excludes(dir); } diff --git a/builtin-checkout.c b/builtin-checkout.c index 20b34ce6e1..5b4921d48c 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -405,7 +405,7 @@ static int merge_working_tree(struct checkout_opts *opts, topts.verbose_update = !opts->quiet; topts.fn = twoway_merge; topts.dir = xcalloc(1, sizeof(*topts.dir)); - topts.dir->show_ignored = 1; + topts.dir->flags |= DIR_SHOW_IGNORED; topts.dir->exclude_per_dir = ".gitignore"; tree = parse_tree_indirect(old->commit->object.sha1); init_tree_desc(&trees[0], tree->buffer, tree->size); diff --git a/builtin-clean.c b/builtin-clean.c index f78c2fb108..c5ad33d3e6 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -60,7 +60,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) memset(&dir, 0, sizeof(dir)); if (ignored_only) - dir.show_ignored = 1; + dir.flags |= DIR_SHOW_IGNORED; if (ignored && ignored_only) die("-x and -X cannot be used together"); @@ -69,7 +69,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) die("clean.requireForce%s set and -n or -f not given; " "refusing to clean", config_set ? "" : " not"); - dir.show_other_directories = 1; + dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; if (!ignored) setup_standard_excludes(&dir); diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 9dec282fba..d36f80b3de 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -174,7 +174,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; int dtype = ce_to_dtype(ce); - if (excluded(dir, ce->name, &dtype) != dir->show_ignored) + if (excluded(dir, ce->name, &dtype) != + !!(dir->flags & DIR_SHOW_IGNORED)) continue; if (show_unmerged && !ce_stage(ce)) continue; @@ -189,7 +190,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) struct stat st; int err; int dtype = ce_to_dtype(ce); - if (excluded(dir, ce->name, &dtype) != dir->show_ignored) + if (excluded(dir, ce->name, &dtype) != + !!(dir->flags & DIR_SHOW_IGNORED)) continue; if (ce->ce_flags & CE_UPDATE) continue; @@ -432,7 +434,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) { - dir.show_ignored = 1; + dir.flags |= DIR_SHOW_IGNORED; require_work_tree = 1; continue; } @@ -446,11 +448,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--directory")) { - dir.show_other_directories = 1; + dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; continue; } if (!strcmp(arg, "--no-empty-directory")) { - dir.hide_empty_directories = 1; + dir.flags |= DIR_HIDE_EMPTY_DIRECTORIES; continue; } if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) { @@ -542,7 +544,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) ps_matched = xcalloc(1, num); } - if (dir.show_ignored && !exc_given) { + if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) { fprintf(stderr, "%s: --ignored needs some exclude pattern\n", argv[0]); exit(1); diff --git a/builtin-merge.c b/builtin-merge.c index 6d2160d0a3..4c119359e7 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -636,7 +636,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) memset(&opts, 0, sizeof(opts)); memset(&t, 0, sizeof(t)); memset(&dir, 0, sizeof(dir)); - dir.show_ignored = 1; + dir.flags |= DIR_SHOW_IGNORED; dir.exclude_per_dir = ".gitignore"; opts.dir = &dir; diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 38fef34d3f..8e0273864d 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -170,7 +170,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) die("more than one --exclude-per-directory are given."); dir = xcalloc(1, sizeof(*opts.dir)); - dir->show_ignored = 1; + dir->flags |= DIR_SHOW_IGNORED; dir->exclude_per_dir = arg + 24; opts.dir = dir; /* We do not need to nor want to do read-directory diff --git a/dir.c b/dir.c index cfd1ea587d..5011cb4dd4 100644 --- a/dir.c +++ b/dir.c @@ -487,14 +487,14 @@ static enum directory_treatment treat_directory(struct dir_struct *dir, return recurse_into_directory; case index_gitdir: - if (dir->show_other_directories) + if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES) return ignore_directory; return show_directory; case index_nonexistent: - if (dir->show_other_directories) + if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES) break; - if (!dir->no_gitlinks) { + if (!(dir->flags & DIR_NO_GITLINKS)) { unsigned char sha1[20]; if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0) return show_directory; @@ -503,7 +503,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir, } /* This is the "show_other_directories" case */ - if (!dir->hide_empty_directories) + if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES)) return show_directory; if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify)) return ignore_directory; @@ -601,7 +601,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co dtype = DTYPE(de); exclude = excluded(dir, fullname, &dtype); - if (exclude && dir->collect_ignored + if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && in_pathspec(fullname, baselen + len, simplify)) dir_add_ignored(dir, fullname, baselen + len); @@ -609,7 +609,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co * Excluded? If we don't explicitly want to show * ignored files, ignore it */ - if (exclude && !dir->show_ignored) + if (exclude && !(dir->flags & DIR_SHOW_IGNORED)) continue; if (dtype == DT_UNKNOWN) @@ -621,7 +621,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co * even if we don't ignore them, since the * directory may contain files that we do.. */ - if (!exclude && dir->show_ignored) { + if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) { if (dtype != DT_DIR) continue; } @@ -634,7 +634,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co len++; switch (treat_directory(dir, fullname, baselen + len, simplify)) { case show_directory: - if (exclude != dir->show_ignored) + if (exclude != !!(dir->flags + & DIR_SHOW_IGNORED)) continue; break; case recurse_into_directory: diff --git a/dir.h b/dir.h index bdc2d47447..541286ad1d 100644 --- a/dir.h +++ b/dir.h @@ -34,11 +34,13 @@ struct exclude_stack { struct dir_struct { int nr, alloc; int ignored_nr, ignored_alloc; - unsigned int show_ignored:1, - show_other_directories:1, - hide_empty_directories:1, - no_gitlinks:1, - collect_ignored:1; + enum { + DIR_SHOW_IGNORED = 1<<0, + DIR_SHOW_OTHER_DIRECTORIES = 1<<1, + DIR_HIDE_EMPTY_DIRECTORIES = 1<<2, + DIR_NO_GITLINKS = 1<<3, + DIR_COLLECT_IGNORED = 1<<4 + } flags; struct dir_entry **entries; struct dir_entry **ignored; diff --git a/wt-status.c b/wt-status.c index 96ff2f8f56..f2eae20d89 100644 --- a/wt-status.c +++ b/wt-status.c @@ -250,10 +250,9 @@ static void wt_status_print_untracked(struct wt_status *s) memset(&dir, 0, sizeof(dir)); - if (!s->untracked) { - dir.show_other_directories = 1; - dir.hide_empty_directories = 1; - } + if (!s->untracked) + dir.flags |= + DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; setup_standard_excludes(&dir); read_directory(&dir, ".", "", 0, NULL); From ce8e8804068772a24354ee24641ca65ffa417837 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Tue, 17 Feb 2009 15:27:11 +0100 Subject: [PATCH 02/52] parse-opt: migrate builtin-ls-files. Signed-off-by: Miklos Vajna Signed-off-by: Junio C Hamano --- builtin-ls-files.c | 255 +++++++++++++++++++++------------------------ 1 file changed, 120 insertions(+), 135 deletions(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index d36f80b3de..1742c0f80d 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -10,6 +10,7 @@ #include "dir.h" #include "builtin.h" #include "tree.h" +#include "parse-options.h" static int abbrev; static int show_deleted; @@ -28,6 +29,7 @@ static const char **pathspec; static int error_unmatch; static char *ps_matched; static const char *with_tree; +static int exc_given; static const char *tag_cached = ""; static const char *tag_unmerged = ""; @@ -376,156 +378,139 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_ return errors; } -static const char ls_files_usage[] = - "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* " - "[ --ignored ] [--exclude=] [--exclude-from=] " - "[ --exclude-per-directory= ] [--exclude-standard] " - "[--full-name] [--abbrev] [--] []*"; +static const char * const ls_files_usage[] = { + "git ls-files [options] []*", + NULL +}; + +static int option_parse_z(const struct option *opt, + const char *arg, int unset) +{ + line_terminator = unset ? '\n' : '\0'; + + return 0; +} + +static int option_parse_exclude(const struct option *opt, + const char *arg, int unset) +{ + struct exclude_list *list = opt->value; + + exc_given = 1; + add_exclude(arg, "", 0, list); + + return 0; +} + +static int option_parse_exclude_from(const struct option *opt, + const char *arg, int unset) +{ + struct dir_struct *dir = opt->value; + + exc_given = 1; + add_excludes_from_file(dir, arg); + + return 0; +} + +static int option_parse_exclude_standard(const struct option *opt, + const char *arg, int unset) +{ + struct dir_struct *dir = opt->value; + + exc_given = 1; + setup_standard_excludes(dir); + + return 0; +} int cmd_ls_files(int argc, const char **argv, const char *prefix) { - int i; - int exc_given = 0, require_work_tree = 0; + int require_work_tree = 0, show_tag = 0; struct dir_struct dir; + struct option builtin_ls_files_options[] = { + { OPTION_CALLBACK, 'z', NULL, NULL, NULL, + "paths are separated with NUL character", + PARSE_OPT_NOARG, option_parse_z }, + OPT_BOOLEAN('t', NULL, &show_tag, + "identify the file status with tags"), + OPT_BOOLEAN('v', NULL, &show_valid_bit, + "use lowercase letters for 'assume unchanged' files"), + OPT_BOOLEAN('c', "cached", &show_cached, + "show cached files in the output (default)"), + OPT_BOOLEAN('d', "deleted", &show_deleted, + "show deleted files in the output"), + OPT_BOOLEAN('m', "modified", &show_modified, + "show modified files in the output"), + OPT_BOOLEAN('o', "others", &show_others, + "show other files in the output"), + OPT_BIT('i', "ignored", &dir.flags, + "show ignored files in the output", + DIR_SHOW_IGNORED), + OPT_BOOLEAN('s', "stage", &show_stage, + "show staged contents' object name in the output"), + OPT_BOOLEAN('k', "killed", &show_killed, + "show files on the filesystem that need to be removed"), + OPT_BIT(0, "directory", &dir.flags, + "show 'other' directories' name only", + DIR_SHOW_OTHER_DIRECTORIES), + OPT_BIT(0, "empty-directory", &dir.flags, + "list empty directories", + DIR_HIDE_EMPTY_DIRECTORIES), + OPT_BOOLEAN('u', "unmerged", &show_unmerged, + "show unmerged files in the output"), + { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern", + "skip files matching pattern", + 0, option_parse_exclude }, + { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file", + "exclude patterns are read from ", + 0, option_parse_exclude_from }, + OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file", + "read additional per-directory exclude patterns in "), + { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL, + "add the standard git exclusions", + PARSE_OPT_NOARG, option_parse_exclude_standard }, + { OPTION_SET_INT, 0, "full-name", &prefix_offset, NULL, + "make the output relative to the project top directory", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL }, + OPT_BOOLEAN(0, "error-unmatch", &error_unmatch, + "if any is not in the index, treat this as an error"), + OPT_STRING(0, "with-tree", &with_tree, "tree-ish", + "pretend that paths removed since are still present"), + OPT__ABBREV(&abbrev), + OPT_END() + }; memset(&dir, 0, sizeof(dir)); if (prefix) prefix_offset = strlen(prefix); git_config(git_default_config, NULL); - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - - if (!strcmp(arg, "--")) { - i++; - break; - } - if (!strcmp(arg, "-z")) { - line_terminator = 0; - continue; - } - if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) { - tag_cached = "H "; - tag_unmerged = "M "; - tag_removed = "R "; - tag_modified = "C "; - tag_other = "? "; - tag_killed = "K "; - if (arg[1] == 'v') - show_valid_bit = 1; - continue; - } - if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) { - show_cached = 1; - continue; - } - if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) { - show_deleted = 1; - continue; - } - if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) { - show_modified = 1; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) { - show_others = 1; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) { - dir.flags |= DIR_SHOW_IGNORED; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) { - show_stage = 1; - continue; - } - if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) { - show_killed = 1; - require_work_tree = 1; - continue; - } - if (!strcmp(arg, "--directory")) { - dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; - continue; - } - if (!strcmp(arg, "--no-empty-directory")) { - dir.flags |= DIR_HIDE_EMPTY_DIRECTORIES; - continue; - } - if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) { - /* There's no point in showing unmerged unless - * you also show the stage information. - */ - show_stage = 1; - show_unmerged = 1; - continue; - } - if (!strcmp(arg, "-x") && i+1 < argc) { - exc_given = 1; - add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]); - continue; - } - if (!prefixcmp(arg, "--exclude=")) { - exc_given = 1; - add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]); - continue; - } - if (!strcmp(arg, "-X") && i+1 < argc) { - exc_given = 1; - add_excludes_from_file(&dir, argv[++i]); - continue; - } - if (!prefixcmp(arg, "--exclude-from=")) { - exc_given = 1; - add_excludes_from_file(&dir, arg+15); - continue; - } - if (!prefixcmp(arg, "--exclude-per-directory=")) { - exc_given = 1; - dir.exclude_per_dir = arg + 24; - continue; - } - if (!strcmp(arg, "--exclude-standard")) { - exc_given = 1; - setup_standard_excludes(&dir); - continue; - } - if (!strcmp(arg, "--full-name")) { - prefix_offset = 0; - continue; - } - if (!strcmp(arg, "--error-unmatch")) { - error_unmatch = 1; - continue; - } - if (!prefixcmp(arg, "--with-tree=")) { - with_tree = arg + 12; - continue; - } - if (!prefixcmp(arg, "--abbrev=")) { - abbrev = strtoul(arg+9, NULL, 10); - if (abbrev && abbrev < MINIMUM_ABBREV) - abbrev = MINIMUM_ABBREV; - else if (abbrev > 40) - abbrev = 40; - continue; - } - if (!strcmp(arg, "--abbrev")) { - abbrev = DEFAULT_ABBREV; - continue; - } - if (*arg == '-') - usage(ls_files_usage); - break; + argc = parse_options(argc, argv, builtin_ls_files_options, + ls_files_usage, 0); + if (show_tag || show_valid_bit) { + tag_cached = "H "; + tag_unmerged = "M "; + tag_removed = "R "; + tag_modified = "C "; + tag_other = "? "; + tag_killed = "K "; } + if (show_modified || show_others || (dir.flags & DIR_SHOW_IGNORED) || show_killed) + require_work_tree = 1; + if (show_unmerged) + /* + * There's no point in showing unmerged unless + * you also show the stage information. + */ + show_stage = 1; + if (dir.exclude_per_dir) + exc_given = 1; if (require_work_tree && !is_inside_work_tree()) setup_work_tree(); - pathspec = get_pathspec(prefix, argv + i); + pathspec = get_pathspec(prefix, argv); /* be nice with submodule patsh ending in a slash */ read_cache(); From aa387407914a574d41df4d64328498d093337ccd Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:48:55 +0200 Subject: [PATCH 03/52] git_config(): not having a per-repo config file is not an error Currently git_config() returns an error if there is no repo config file available (cwd is not a git repo); it will correctly parse the system and global config files, but still return an error. It doesn't affect anything else since almost nobody is checking for the return code (with the exception of 'git remote update'). A reorganization in 'git config' would benefit from being able to properly detect errors in git_config() without the noise generated when cwd is not a git repo. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- config.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/config.c b/config.c index e5d5b4bd06..b4aae71bd3 100644 --- a/config.c +++ b/config.c @@ -637,28 +637,37 @@ int git_config_global(void) int git_config(config_fn_t fn, void *data) { - int ret = 0; + int ret = 0, found = 0; char *repo_config = NULL; const char *home = NULL; /* Setting $GIT_CONFIG makes git read _only_ the given config file. */ if (config_exclusive_filename) return git_config_from_file(fn, config_exclusive_filename, data); - if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) + if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); + found += 1; + } home = getenv("HOME"); if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - if (!access(user_config, R_OK)) + if (!access(user_config, R_OK)) { ret += git_config_from_file(fn, user_config, data); + found += 1; + } free(user_config); } repo_config = git_pathdup("config"); - ret += git_config_from_file(fn, repo_config, data); + if (!access(repo_config, R_OK)) { + ret += git_config_from_file(fn, repo_config, data); + found += 1; + } free(repo_config); + if (found == 0) + return -1; return ret; } From b408457f2e167aaf8e7a087b374357f4a74e9680 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:48:56 +0200 Subject: [PATCH 04/52] git config: trivial rename in preparation for parseopt Essentially this replaces 'file' with 'prefix' in the cases where the variable is used as a prefix, which is consistent with other git commands. When using the --list option general errors where not properly reported, only errors related with the 'file'. Now they are reported, and 'file' is irrelevant. That reduces the rest of 'file' usage to nothing, therefore now only 'prefix' remains. Suggested by Johannes Schindelin. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index d52a057444..5074c6123e 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -178,6 +178,7 @@ static char *normalize_value(const char *key, const char *value) static int get_color_found; static const char *get_color_slot; +static const char *get_colorbool_slot; static char parsed_color[COLOR_MAXLEN]; static int git_get_color_config(const char *var, const char *value, void *cb) @@ -231,7 +232,7 @@ static int get_diff_color_found; static int git_get_colorbool_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, get_color_slot)) { + if (!strcmp(var, get_colorbool_slot)) { get_colorbool_found = git_config_colorbool(var, value, stdout_is_tty); } @@ -263,11 +264,11 @@ static int get_colorbool(int argc, const char **argv) usage(git_config_set_usage); get_colorbool_found = -1; get_diff_color_found = -1; - get_color_slot = argv[0]; + get_colorbool_slot = argv[0]; git_config(git_get_colorbool_config, NULL); if (get_colorbool_found < 0) { - if (!strcmp(get_color_slot, "color.diff")) + if (!strcmp(get_colorbool_slot, "color.diff")) get_colorbool_found = get_diff_color_found; if (get_colorbool_found < 0) get_colorbool_found = git_use_color_default; @@ -281,11 +282,11 @@ static int get_colorbool(int argc, const char **argv) } } -int cmd_config(int argc, const char **argv, const char *prefix) +int cmd_config(int argc, const char **argv, const char *unused_prefix) { int nongit; char *value; - const char *file = setup_git_directory_gently(&nongit); + const char *prefix = setup_git_directory_gently(&nongit); config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); @@ -299,10 +300,13 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { if (argc != 2) usage(git_config_set_usage); - if (git_config(show_all_config, NULL) < 0 && - file && errno) - die("unable to read config file %s: %s", file, - strerror(errno)); + if (git_config(show_all_config, NULL) < 0) { + if (config_exclusive_filename) + die("unable to read config file %s: %s", + config_exclusive_filename, strerror(errno)); + else + die("error processing config file(s)"); + } return 0; } else if (!strcmp(argv[1], "--global")) { @@ -319,12 +323,12 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) { if (argc < 3) usage(git_config_set_usage); - if (!is_absolute_path(argv[2]) && file) - file = prefix_filename(file, strlen(file), - argv[2]); + if (!is_absolute_path(argv[2]) && prefix) + config_exclusive_filename = prefix_filename(prefix, + strlen(prefix), + argv[2]); else - file = argv[2]; - config_exclusive_filename = file; + config_exclusive_filename = argv[2]; argc--; argv++; } From 0e854a280a0b064f48ee308ef16283e321a9aa6e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:48:57 +0200 Subject: [PATCH 05/52] git config: reorganize get_color* In preparation for parseopt. Also remove some unecessary comments since the usage is described in the documentation. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 62 ++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index 5074c6123e..a2ef5f7c08 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -192,29 +192,8 @@ static int git_get_color_config(const char *var, const char *value, void *cb) return 0; } -static int get_color(int argc, const char **argv) +static void get_color(const char *def_color) { - /* - * grab the color setting for the given slot from the configuration, - * or parse the default value if missing, and return ANSI color - * escape sequence. - * - * e.g. - * git config --get-color color.diff.whitespace "blue reverse" - */ - const char *def_color = NULL; - - switch (argc) { - default: - usage(git_config_set_usage); - case 2: - def_color = argv[1]; - /* fallthru */ - case 1: - get_color_slot = argv[0]; - break; - } - get_color_found = 0; parsed_color[0] = '\0'; git_config(git_get_color_config, NULL); @@ -223,7 +202,6 @@ static int get_color(int argc, const char **argv) color_parse(def_color, "command line", parsed_color); fputs(parsed_color, stdout); - return 0; } static int stdout_is_tty; @@ -247,24 +225,10 @@ static int git_get_colorbool_config(const char *var, const char *value, return 0; } -static int get_colorbool(int argc, const char **argv) +static int get_colorbool(int print) { - /* - * git config --get-colorbool [] - * - * returns "true" or "false" depending on how - * is configured. - */ - - if (argc == 2) - stdout_is_tty = git_config_bool("command line", argv[1]); - else if (argc == 1) - stdout_is_tty = isatty(1); - else - usage(git_config_set_usage); get_colorbool_found = -1; get_diff_color_found = -1; - get_colorbool_slot = argv[0]; git_config(git_get_colorbool_config, NULL); if (get_colorbool_found < 0) { @@ -274,12 +238,11 @@ static int get_colorbool(int argc, const char **argv) get_colorbool_found = git_use_color_default; } - if (argc == 1) { - return get_colorbool_found ? 0 : 1; - } else { + if (print) { printf("%s\n", get_colorbool_found ? "true" : "false"); return 0; - } + } else + return get_colorbool_found ? 0 : 1; } int cmd_config(int argc, const char **argv, const char *unused_prefix) @@ -363,9 +326,20 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } return 0; } else if (!strcmp(argv[1], "--get-color")) { - return get_color(argc-2, argv+2); + if (argc > 4 || argc < 3) + usage(git_config_set_usage); + get_color_slot = argv[2]; + get_color(argv[3]); + return 0; } else if (!strcmp(argv[1], "--get-colorbool")) { - return get_colorbool(argc-2, argv+2); + if (argc == 4) + stdout_is_tty = git_config_bool("command line", argv[3]); + else if (argc == 3) + stdout_is_tty = isatty(1); + else + usage(git_config_set_usage); + get_colorbool_slot = argv[2]; + return get_colorbool(argc != 3); } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) { if (argc != 2) usage(git_config_set_usage); From d64ec16c2af4ddcf3985d11d5dc28a15db181de5 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:49:25 +0200 Subject: [PATCH 06/52] git config: reorganize to use parseopt This patch has benefited from comments by Johannes Schindelin and Junio C Hamano. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 351 ++++++++++++++++++++++++++--------------------- 1 file changed, 196 insertions(+), 155 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index a2ef5f7c08..08a77cd7df 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -1,9 +1,12 @@ #include "builtin.h" #include "cache.h" #include "color.h" +#include "parse-options.h" -static const char git_config_set_usage[] = -"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty] | --edit | -e ]"; +static const char *const builtin_config_usage[] = { + "git config [options]", + NULL +}; static char *key; static regex_t *key_regexp; @@ -18,6 +21,63 @@ static char key_delim = ' '; static char term = '\n'; static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW; +static int use_global_config, use_system_config; +static const char *given_config_file; +static int actions; +static const char *get_color_slot, *get_colorbool_slot; +static int end_null; + +#define ACTION_GET (1<<0) +#define ACTION_GET_ALL (1<<1) +#define ACTION_GET_REGEXP (1<<2) +#define ACTION_REPLACE_ALL (1<<3) +#define ACTION_ADD (1<<4) +#define ACTION_UNSET (1<<5) +#define ACTION_UNSET_ALL (1<<6) +#define ACTION_RENAME_SECTION (1<<7) +#define ACTION_REMOVE_SECTION (1<<8) +#define ACTION_LIST (1<<9) +#define ACTION_EDIT (1<<10) +#define ACTION_SET (1<<11) +#define ACTION_SET_ALL (1<<12) +#define ACTION_GET_COLOR (1<<13) +#define ACTION_GET_COLORBOOL (1<<14) + +static struct option builtin_config_options[] = { + OPT_GROUP("Config file location"), + OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"), + OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"), + OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"), + OPT_GROUP("Action"), + OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET), + OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL), + OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP), + OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name [value [value_regex]", ACTION_REPLACE_ALL), + OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD), + OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET), + OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL), + OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION), + OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION), + OPT_BIT('l', "list", &actions, "list all", ACTION_LIST), + OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT), + OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"), + OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"), + OPT_GROUP("Type"), + OPT_SET_INT(0, "bool", &type, "value is \"true\" or \"false\"", T_BOOL), + OPT_SET_INT(0, "int", &type, "value is decimal number", T_INT), + OPT_SET_INT(0, "bool-or-int", &type, NULL, T_BOOL_OR_INT), + OPT_GROUP("Other"), + OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), + OPT_END(), +}; + +static void check_argc(int argc, int min, int max) { + if (argc >= min && argc <= max) + return; + error("wrong number of arguments"); + usage_with_options(builtin_config_usage, builtin_config_options); +} + static int show_all_config(const char *key_, const char *value_, void *cb) { if (value_) @@ -253,162 +313,143 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); - while (1 < argc) { - if (!strcmp(argv[1], "--int")) - type = T_INT; - else if (!strcmp(argv[1], "--bool")) - type = T_BOOL; - else if (!strcmp(argv[1], "--bool-or-int")) - type = T_BOOL_OR_INT; - else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { - if (argc != 2) - usage(git_config_set_usage); - if (git_config(show_all_config, NULL) < 0) { - if (config_exclusive_filename) - die("unable to read config file %s: %s", - config_exclusive_filename, strerror(errno)); - else - die("error processing config file(s)"); - } - return 0; + argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + if (use_global_config) { + char *home = getenv("HOME"); + if (home) { + char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); + config_exclusive_filename = user_config; + } else { + die("$HOME not set"); } - else if (!strcmp(argv[1], "--global")) { - char *home = getenv("HOME"); - if (home) { - char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - config_exclusive_filename = user_config; - } else { - die("$HOME not set"); - } - } - else if (!strcmp(argv[1], "--system")) - config_exclusive_filename = git_etc_gitconfig(); - else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) { - if (argc < 3) - usage(git_config_set_usage); - if (!is_absolute_path(argv[2]) && prefix) - config_exclusive_filename = prefix_filename(prefix, - strlen(prefix), - argv[2]); - else - config_exclusive_filename = argv[2]; - argc--; - argv++; - } - else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) { - term = '\0'; - delim = '\n'; - key_delim = '\n'; - } - else if (!strcmp(argv[1], "--rename-section")) { - int ret; - if (argc != 4) - usage(git_config_set_usage); - ret = git_config_rename_section(argv[2], argv[3]); - if (ret < 0) - return ret; - if (ret == 0) { - fprintf(stderr, "No such section!\n"); - return 1; - } - return 0; - } - else if (!strcmp(argv[1], "--remove-section")) { - int ret; - if (argc != 3) - usage(git_config_set_usage); - ret = git_config_rename_section(argv[2], NULL); - if (ret < 0) - return ret; - if (ret == 0) { - fprintf(stderr, "No such section!\n"); - return 1; - } - return 0; - } else if (!strcmp(argv[1], "--get-color")) { - if (argc > 4 || argc < 3) - usage(git_config_set_usage); - get_color_slot = argv[2]; - get_color(argv[3]); - return 0; - } else if (!strcmp(argv[1], "--get-colorbool")) { - if (argc == 4) - stdout_is_tty = git_config_bool("command line", argv[3]); - else if (argc == 3) - stdout_is_tty = isatty(1); - else - usage(git_config_set_usage); - get_colorbool_slot = argv[2]; - return get_colorbool(argc != 3); - } else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) { - if (argc != 2) - usage(git_config_set_usage); - git_config(git_default_config, NULL); - launch_editor(config_exclusive_filename ? - config_exclusive_filename : git_path("config"), - NULL, NULL); - return 0; - } else - break; - argc--; - argv++; + } + else if (use_system_config) + config_exclusive_filename = git_etc_gitconfig(); + else if (given_config_file) { + if (!is_absolute_path(given_config_file) && prefix) + config_exclusive_filename = prefix_filename(prefix, + strlen(prefix), + argv[2]); + else + config_exclusive_filename = given_config_file; } - switch (argc) { - case 2: - return get_value(argv[1], NULL); - case 3: - if (!strcmp(argv[1], "--unset")) - return git_config_set(argv[2], NULL); - else if (!strcmp(argv[1], "--unset-all")) - return git_config_set_multivar(argv[2], NULL, NULL, 1); - else if (!strcmp(argv[1], "--get")) - return get_value(argv[2], NULL); - else if (!strcmp(argv[1], "--get-all")) { - do_all = 1; - return get_value(argv[2], NULL); - } else if (!strcmp(argv[1], "--get-regexp")) { - show_keys = 1; - use_key_regexp = 1; - do_all = 1; - return get_value(argv[2], NULL); - } else { - value = normalize_value(argv[1], argv[2]); - return git_config_set(argv[1], value); - } - case 4: - if (!strcmp(argv[1], "--unset")) - return git_config_set_multivar(argv[2], NULL, argv[3], 0); - else if (!strcmp(argv[1], "--unset-all")) - return git_config_set_multivar(argv[2], NULL, argv[3], 1); - else if (!strcmp(argv[1], "--get")) - return get_value(argv[2], argv[3]); - else if (!strcmp(argv[1], "--get-all")) { - do_all = 1; - return get_value(argv[2], argv[3]); - } else if (!strcmp(argv[1], "--get-regexp")) { - show_keys = 1; - use_key_regexp = 1; - do_all = 1; - return get_value(argv[2], argv[3]); - } else if (!strcmp(argv[1], "--add")) { - value = normalize_value(argv[2], argv[3]); - return git_config_set_multivar(argv[2], value, "^$", 0); - } else if (!strcmp(argv[1], "--replace-all")) { - value = normalize_value(argv[2], argv[3]); - return git_config_set_multivar(argv[2], value, NULL, 1); - } else { - value = normalize_value(argv[1], argv[2]); - return git_config_set_multivar(argv[1], value, argv[3], 0); - } - case 5: - if (!strcmp(argv[1], "--replace-all")) { - value = normalize_value(argv[2], argv[3]); - return git_config_set_multivar(argv[2], value, argv[4], 1); - } - case 1: - default: - usage(git_config_set_usage); + if (end_null) { + term = '\0'; + delim = '\n'; + key_delim = '\n'; } + + if (get_color_slot) + actions |= ACTION_GET_COLOR; + if (get_colorbool_slot) + actions |= ACTION_GET_COLORBOOL; + + if (HAS_MULTI_BITS(actions)) { + error("only one action at a time."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (actions == 0) + switch (argc) { + case 1: actions = ACTION_GET; break; + case 2: actions = ACTION_SET; break; + case 3: actions = ACTION_SET_ALL; break; + default: + usage_with_options(builtin_config_usage, builtin_config_options); + } + + if (actions == ACTION_LIST) { + if (git_config(show_all_config, NULL) < 0) { + if (config_exclusive_filename) + die("unable to read config file %s: %s", + config_exclusive_filename, strerror(errno)); + else + die("error processing config file(s)"); + } + } + else if (actions == ACTION_EDIT) { + git_config(git_default_config, NULL); + launch_editor(config_exclusive_filename ? + config_exclusive_filename : git_path("config"), + NULL, NULL); + } + else if (actions == ACTION_SET) { + check_argc(argc, 2, 2); + value = normalize_value(argv[0], argv[1]); + return git_config_set(argv[0], value); + } + else if (actions == ACTION_SET_ALL) { + check_argc(argc, 2, 3); + value = normalize_value(argv[0], argv[1]); + return git_config_set_multivar(argv[0], value, argv[2], 0); + } + else if (actions == ACTION_ADD) { + check_argc(argc, 2, 2); + value = normalize_value(argv[0], argv[1]); + return git_config_set_multivar(argv[0], value, "^$", 0); + } + else if (actions == ACTION_REPLACE_ALL) { + check_argc(argc, 2, 3); + value = normalize_value(argv[0], argv[1]); + return git_config_set_multivar(argv[0], value, argv[2], 1); + } + else if (actions == ACTION_GET) { + check_argc(argc, 1, 2); + return get_value(argv[0], argv[1]); + } + else if (actions == ACTION_GET_ALL) { + do_all = 1; + check_argc(argc, 1, 2); + return get_value(argv[0], argv[1]); + } + else if (actions == ACTION_GET_REGEXP) { + show_keys = 1; + use_key_regexp = 1; + do_all = 1; + check_argc(argc, 1, 2); + return get_value(argv[0], argv[1]); + } + else if (actions == ACTION_UNSET) { + check_argc(argc, 1, 2); + if (argc == 2) + return git_config_set_multivar(argv[0], NULL, argv[1], 0); + else + return git_config_set(argv[0], NULL); + } + else if (actions == ACTION_UNSET_ALL) { + check_argc(argc, 1, 2); + return git_config_set_multivar(argv[0], NULL, argv[1], 1); + } + else if (actions == ACTION_RENAME_SECTION) { + int ret; + check_argc(argc, 2, 2); + ret = git_config_rename_section(argv[0], argv[1]); + if (ret < 0) + return ret; + if (ret == 0) + die("No such section!"); + } + else if (actions == ACTION_REMOVE_SECTION) { + int ret; + check_argc(argc, 1, 1); + ret = git_config_rename_section(argv[0], NULL); + if (ret < 0) + return ret; + if (ret == 0) + die("No such section!"); + } + else if (actions == ACTION_GET_COLOR) { + get_color(argv[0]); + } + else if (actions == ACTION_GET_COLORBOOL) { + if (argc == 1) + stdout_is_tty = git_config_bool("command line", argv[0]); + else if (argc == 0) + stdout_is_tty = isatty(1); + return get_colorbool(argc != 0); + } + return 0; } From 67052c9dcfb3ab46b18e734ea4a9117eb61fea4e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:49:26 +0200 Subject: [PATCH 07/52] git config: don't allow multiple config file locations Either --global, --system, or --file can be used, but not any combination. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index 08a77cd7df..d037e4745c 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -316,6 +316,11 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage, PARSE_OPT_STOP_AT_NON_OPTION); + if (use_global_config + use_system_config + !!given_config_file > 1) { + error("only one config file at a time."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (use_global_config) { char *home = getenv("HOME"); if (home) { From 16c1e939856f6ced97c60beb64936d564d198be3 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:49:27 +0200 Subject: [PATCH 08/52] git config: don't allow multiple variable types Only --bool, --int, or --bool-or-int can be used, but not any combination of them. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/builtin-config.c b/builtin-config.c index d037e4745c..6dc205d1f4 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -19,11 +19,10 @@ static int seen; static char delim = '='; static char key_delim = ' '; static char term = '\n'; -static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW; static int use_global_config, use_system_config; static const char *given_config_file; -static int actions; +static int actions, types; static const char *get_color_slot, *get_colorbool_slot; static int end_null; @@ -43,6 +42,10 @@ static int end_null; #define ACTION_GET_COLOR (1<<13) #define ACTION_GET_COLORBOOL (1<<14) +#define TYPE_BOOL (1<<0) +#define TYPE_INT (1<<1) +#define TYPE_BOOL_OR_INT (1<<2) + static struct option builtin_config_options[] = { OPT_GROUP("Config file location"), OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"), @@ -63,9 +66,9 @@ static struct option builtin_config_options[] = { OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"), OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"), OPT_GROUP("Type"), - OPT_SET_INT(0, "bool", &type, "value is \"true\" or \"false\"", T_BOOL), - OPT_SET_INT(0, "int", &type, "value is decimal number", T_INT), - OPT_SET_INT(0, "bool-or-int", &type, NULL, T_BOOL_OR_INT), + OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL), + OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT), + OPT_BIT(0, "bool-or-int", &types, NULL, TYPE_BOOL_OR_INT), OPT_GROUP("Other"), OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), OPT_END(), @@ -109,11 +112,11 @@ static int show_config(const char *key_, const char *value_, void *cb) } if (seen && !do_all) dup_error = 1; - if (type == T_INT) + if (types == TYPE_INT) sprintf(value, "%d", git_config_int(key_, value_?value_:"")); - else if (type == T_BOOL) + else if (types == TYPE_BOOL) vptr = git_config_bool(key_, value_) ? "true" : "false"; - else if (type == T_BOOL_OR_INT) { + else if (types == TYPE_BOOL_OR_INT) { int is_bool, v; v = git_config_bool_or_int(key_, value_, &is_bool); if (is_bool) @@ -212,18 +215,18 @@ static char *normalize_value(const char *key, const char *value) if (!value) return NULL; - if (type == T_RAW) + if (types == 0) normalized = xstrdup(value); else { normalized = xmalloc(64); - if (type == T_INT) { + if (types == TYPE_INT) { int v = git_config_int(key, value); sprintf(normalized, "%d", v); } - else if (type == T_BOOL) + else if (types == TYPE_BOOL) sprintf(normalized, "%s", git_config_bool(key, value) ? "true" : "false"); - else if (type == T_BOOL_OR_INT) { + else if (types == TYPE_BOOL_OR_INT) { int is_bool, v; v = git_config_bool_or_int(key, value, &is_bool); if (!is_bool) @@ -347,6 +350,11 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) key_delim = '\n'; } + if (HAS_MULTI_BITS(types)) { + error("only one type at a time."); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (get_color_slot) actions |= ACTION_GET_COLOR; if (get_colorbool_slot) From 225a9caf18911bffe2f32e4960c94e51f135182b Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:49:28 +0200 Subject: [PATCH 09/52] git config: don't allow extra arguments for -e or -l. As suggested by Johannes Schindelin. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index 6dc205d1f4..a3a334bc63 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -374,6 +374,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } if (actions == ACTION_LIST) { + check_argc(argc, 0, 0); if (git_config(show_all_config, NULL) < 0) { if (config_exclusive_filename) die("unable to read config file %s: %s", @@ -383,6 +384,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) } } else if (actions == ACTION_EDIT) { + check_argc(argc, 0, 0); git_config(git_default_config, NULL); launch_editor(config_exclusive_filename ? config_exclusive_filename : git_path("config"), From c23873589483eb5dc753190309af8c5821169118 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 21 Feb 2009 02:49:29 +0200 Subject: [PATCH 10/52] git config: don't allow --get-color* and variable type Doing so would be incoherent since --get-color would pick a color slot and ignore the variable type option (e.g. --bool), and the type would require a variable name. Suggested by Junio C Hamano. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- builtin-config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/builtin-config.c b/builtin-config.c index a3a334bc63..b11a0961bd 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -360,6 +360,11 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) if (get_colorbool_slot) actions |= ACTION_GET_COLORBOOL; + if ((get_color_slot || get_colorbool_slot) && types) { + error("--get-color and variable type are incoherent"); + usage_with_options(builtin_config_usage, builtin_config_options); + } + if (HAS_MULTI_BITS(actions)) { error("only one action at a time."); usage_with_options(builtin_config_usage, builtin_config_options); From 0e757e30c726d9d8ae82bd9989be3cff5d230288 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 3 Mar 2009 10:55:31 +0100 Subject: [PATCH 11/52] rebase -i: avoid 'git reset' when possible When picking commits whose parents have not changed, we do not need to rewrite the commit. We do not need to reset the working directory to the parent's state, either. Requested by Sverre Rabbelier. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 26 ++++++++++++++++++++++++++ t/t3404-rebase-interactive.sh | 11 +++++++++++ 2 files changed, 37 insertions(+) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 3dc659dd58..314cd364b8 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -442,6 +442,30 @@ do_rest () { done } +# skip picking commits whose parents are unchanged +skip_unnecessary_picks () { + fd=3 + while read command sha1 rest + do + # fd=3 means we skip the command + case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in + 3,pick,"$ONTO"*|3,p,"$ONTO"*) + # pick a commit whose parent is current $ONTO -> skip + ONTO=$sha1 + ;; + 3,#*|3,,*) + # copy comments + ;; + *) + fd=1 + ;; + esac + echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd + done <"$TODO" >"$TODO.new" 3>>"$DONE" && + mv -f "$TODO".new "$TODO" || + die "Could not skip unnecessary pick commands" +} + # check if no other options are set is_standalone () { test $# -eq 2 -a "$2" = '--' && @@ -746,6 +770,8 @@ EOF has_action "$TODO" || die_abort "Nothing to do" + test -d "$REWRITTEN" || skip_unnecessary_picks + git update-ref ORIG_HEAD $HEAD output git checkout $ONTO && do_rest ;; diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 603b003edf..c32ff6682b 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -459,4 +459,15 @@ test_expect_success 'submodule rebase -i' ' FAKE_LINES="1 squash 2 3" git rebase -i A ' +test_expect_success 'avoid unnecessary reset' ' + git checkout master && + test-chmtime =123456789 file3 && + git update-index --refresh && + HEAD=$(git rev-parse HEAD) && + git rebase -i HEAD~4 && + test $HEAD = $(git rev-parse HEAD) && + MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') && + test 123456789 = $MTIME +' + test_done From a9f2c13685ae9040d52d53cd719a18040f1dd123 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 3 Mar 2009 22:29:55 -0800 Subject: [PATCH 12/52] Make git-clone respect branch.autosetuprebase When git-clone creates an initial branch it was not checking the branch.autosetuprebase configuration option (which may exist in ~/.gitconfig). Refactor the code used by "git branch" to create a new branch, and use it instead of the insufficiently duplicated code in builtin-clone. Changes are partly, and the test is mostly, based on the previous work by Pat Notz. Signed-off-by: Junio C Hamano --- branch.c | 49 ++++++++++++++++++++++++++++++++---------------- branch.h | 7 +++++++ builtin-clone.c | 18 +++--------------- t/t5601-clone.sh | 15 +++++++++++++++ 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/branch.c b/branch.c index 1f00e44deb..d20fb0490b 100644 --- a/branch.c +++ b/branch.c @@ -32,21 +32,48 @@ static int find_tracked_branch(struct remote *remote, void *priv) return 0; } -static int should_setup_rebase(const struct tracking *tracking) +static int should_setup_rebase(const char *origin) { switch (autorebase) { case AUTOREBASE_NEVER: return 0; case AUTOREBASE_LOCAL: - return tracking->remote == NULL; + return origin == NULL; case AUTOREBASE_REMOTE: - return tracking->remote != NULL; + return origin != NULL; case AUTOREBASE_ALWAYS: return 1; } return 0; } +void install_branch_config(int flag, const char *local, const char *origin, const char *remote) +{ + struct strbuf key = STRBUF_INIT; + int rebasing = should_setup_rebase(origin); + + strbuf_addf(&key, "branch.%s.remote", local); + git_config_set(key.buf, origin ? origin : "."); + + strbuf_reset(&key); + strbuf_addf(&key, "branch.%s.merge", local); + git_config_set(key.buf, remote); + + if (rebasing) { + strbuf_reset(&key); + strbuf_addf(&key, "branch.%s.rebase", local); + git_config_set(key.buf, "true"); + } + + if (flag & BRANCH_CONFIG_VERBOSE) + printf("Branch %s set up to track %s branch %s %s.\n", + local, + origin ? "remote" : "local", + remote, + rebasing ? "by rebasing" : "by merging"); + strbuf_release(&key); +} + /* * This is called when new_ref is branched off of orig_ref, and tries * to infer the settings for branch..{remote,merge} from the @@ -55,7 +82,6 @@ static int should_setup_rebase(const struct tracking *tracking) static int setup_tracking(const char *new_ref, const char *orig_ref, enum branch_track track) { - char key[1024]; struct tracking tracking; if (strlen(new_ref) > 1024 - 7 - 7 - 1) @@ -80,19 +106,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref, return error("Not tracking: ambiguous information for ref %s", orig_ref); - sprintf(key, "branch.%s.remote", new_ref); - git_config_set(key, tracking.remote ? tracking.remote : "."); - sprintf(key, "branch.%s.merge", new_ref); - git_config_set(key, tracking.src ? tracking.src : orig_ref); - printf("Branch %s set up to track %s branch %s.\n", new_ref, - tracking.remote ? "remote" : "local", orig_ref); - if (should_setup_rebase(&tracking)) { - sprintf(key, "branch.%s.rebase", new_ref); - git_config_set(key, "true"); - printf("This branch will rebase on pull.\n"); - } - free(tracking.src); + install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote, + tracking.src ? tracking.src : orig_ref); + free(tracking.src); return 0; } diff --git a/branch.h b/branch.h index 9f0c2a2c1f..eed817a64c 100644 --- a/branch.h +++ b/branch.h @@ -21,4 +21,11 @@ void create_branch(const char *head, const char *name, const char *start_name, */ void remove_branch_state(void); +/* + * Configure local branch "local" to merge remote branch "remote" + * taken from origin "origin". + */ +#define BRANCH_CONFIG_VERBOSE 01 +extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote); + #endif diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..a5f000adf4 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -20,6 +20,7 @@ #include "dir.h" #include "pack-refs.h" #include "sigchain.h" +#include "branch.h" /* * Overall FIXMEs: @@ -350,19 +351,6 @@ static struct ref *write_remote_refs(const struct ref *refs, return local_refs; } -static void install_branch_config(const char *local, - const char *origin, - const char *remote) -{ - struct strbuf key = STRBUF_INIT; - strbuf_addf(&key, "branch.%s.remote", local); - git_config_set(key.buf, origin); - strbuf_reset(&key); - strbuf_addf(&key, "branch.%s.merge", local); - git_config_set(key.buf, remote); - strbuf_release(&key); -} - int cmd_clone(int argc, const char **argv, const char *prefix) { int use_local_hardlinks = 1; @@ -553,7 +541,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) remote_head = NULL; option_no_checkout = 1; if (!option_bare) - install_branch_config("master", option_origin, + install_branch_config(0, "master", option_origin, "refs/heads/master"); } @@ -583,7 +571,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) head_points_at->peer_ref->name, reflog_msg.buf); - install_branch_config(head, option_origin, + install_branch_config(0, head, option_origin, head_points_at->name); } } else if (remote_head) { diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 44793f2eee..2335d8bc85 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -159,4 +159,19 @@ test_expect_success 'clone a void' ' test_cmp target-6/.git/config target-7/.git/config ' +test_expect_success 'clone respects global branch.autosetuprebase' ' + ( + HOME=$(pwd) && + export HOME && + test_config="$HOME/.gitconfig" && + unset GIT_CONFIG_NOGLOBAL && + git config -f "$test_config" branch.autosetuprebase remote && + rm -fr dst && + git clone src dst && + cd dst && + actual="z$(git config branch.master.rebase)" && + test ztrue = $actual + ) +' + test_done From ba048224685e661a4cf4736dcffab5fc60cbc70b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 7 Mar 2009 12:14:05 -0500 Subject: [PATCH 13/52] config: set help text for --bool-or-int The conversion to parse_opt left this as NULL; on glibc systems, the usage message prints --bool-or-int (null) and on other ones, segfaults. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-config.c b/builtin-config.c index b11a0961bd..1a3baa1f46 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -68,7 +68,7 @@ static struct option builtin_config_options[] = { OPT_GROUP("Type"), OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL), OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT), - OPT_BIT(0, "bool-or-int", &types, NULL, TYPE_BOOL_OR_INT), + OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT), OPT_GROUP("Other"), OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), OPT_END(), From 689f03964360114bc1139d82b1f6a0d7b897bbf0 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 5 Mar 2009 23:56:16 -0500 Subject: [PATCH 14/52] Make clone parse the default refspec with the normal code Instead of creating a refspec by hand, go through the refspec parsing code, so that changes in the refspec storage will be accounted for. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-clone.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..06b5a7fc39 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -378,7 +378,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) struct transport *transport = NULL; char *src_ref_prefix = "refs/heads/"; - struct refspec refspec; + struct refspec *refspec; + const char *fetch_pattern; junk_pid = getpid(); @@ -487,8 +488,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin); } + strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); + if (option_mirror || !option_bare) { /* Configure the remote */ + strbuf_addf(&key, "remote.%s.fetch", option_origin); + git_config_set_multivar(key.buf, value.buf, "^$", 0); + strbuf_reset(&key); + if (option_mirror) { strbuf_addf(&key, "remote.%s.mirror", option_origin); git_config_set(key.buf, "true"); @@ -497,19 +504,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_addf(&key, "remote.%s.url", option_origin); git_config_set(key.buf, repo); - strbuf_reset(&key); - - strbuf_addf(&key, "remote.%s.fetch", option_origin); - strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); - git_config_set_multivar(key.buf, value.buf, "^$", 0); strbuf_reset(&key); - strbuf_reset(&value); } - refspec.force = 0; - refspec.pattern = 1; - refspec.src = src_ref_prefix; - refspec.dst = branch_top.buf; + fetch_pattern = value.buf; + refspec = parse_fetch_refspec(1, &fetch_pattern); + + strbuf_reset(&value); if (path && !is_bundle) refs = clone_local(path, git_dir); @@ -543,7 +544,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (refs) { clear_extra_refs(); - mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf); + mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf); head_points_at = locate_head(refs, mapped_refs, &remote_head); } From a3c8423901ec4996369b137b46354ddf1cfc0e0e Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Sat, 7 Mar 2009 01:11:29 -0500 Subject: [PATCH 15/52] Use a single function to match names against patterns This will help when the matching changes. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- remote.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/remote.c b/remote.c index d7079c6dd8..2816723bb9 100644 --- a/remote.c +++ b/remote.c @@ -719,6 +719,12 @@ int remote_has_url(struct remote *remote, const char *url) return 0; } +static int match_name_with_pattern(const char *key, const char *name) +{ + int ret = !prefixcmp(key, name); + return ret; +} + int remote_find_tracking(struct remote *remote, struct refspec *refspec) { int find_src = refspec->src == NULL; @@ -742,7 +748,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (!prefixcmp(needle, key)) { + if (match_name_with_pattern(key, needle)) { *result = xmalloc(strlen(value) + strlen(needle) - strlen(key) + 1); @@ -1020,7 +1026,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, continue; } - if (rs[i].pattern && !prefixcmp(src->name, rs[i].src)) + if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name)) return rs + i; } if (matching_refs != -1) @@ -1160,7 +1166,7 @@ static struct ref *get_expanded_map(const struct ref *remote_refs, for (ref = remote_refs; ref; ref = ref->next) { if (strchr(ref->name, '^')) continue; /* a dereference item */ - if (!prefixcmp(ref->name, refspec->src)) { + if (match_name_with_pattern(refspec->src, ref->name)) { const char *match; struct ref *cpy = copy_ref(ref); match = ref->name + remote_prefix_len; From e928213fb40c106650dca2632b5e830cfaffb86a Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Sat, 7 Mar 2009 01:11:34 -0500 Subject: [PATCH 16/52] Use the matching function to generate the match results This puts all of the interpretation of the pattern representation in a single function for easy manipulation. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- remote.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/remote.c b/remote.c index 2816723bb9..01b8f91c5b 100644 --- a/remote.c +++ b/remote.c @@ -719,9 +719,19 @@ int remote_has_url(struct remote *remote, const char *url) return 0; } -static int match_name_with_pattern(const char *key, const char *name) +static int match_name_with_pattern(const char *key, const char *name, + const char *value, char **result) { - int ret = !prefixcmp(key, name); + size_t klen = strlen(key); + int ret = !strncmp(key, name, klen); + if (ret && value) { + size_t vlen = strlen(value); + *result = xmalloc(vlen + + strlen(name) - + klen + 1); + strcpy(*result, value); + strcpy(*result + vlen, name + klen); + } return ret; } @@ -748,13 +758,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (match_name_with_pattern(key, needle)) { - *result = xmalloc(strlen(value) + - strlen(needle) - - strlen(key) + 1); - strcpy(*result, value); - strcpy(*result + strlen(value), - needle + strlen(key)); + if (match_name_with_pattern(key, needle, value, result)) { refspec->force = fetch->force; return 0; } @@ -1026,7 +1030,8 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, continue; } - if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name)) + if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name, + NULL, NULL)) return rs + i; } if (matching_refs != -1) @@ -1080,11 +1085,9 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, } else { const char *dst_side = pat->dst ? pat->dst : pat->src; - dst_name = xmalloc(strlen(dst_side) + - strlen(src->name) - - strlen(pat->src) + 2); - strcpy(dst_name, dst_side); - strcat(dst_name, src->name + strlen(pat->src)); + if (!match_name_with_pattern(pat->src, src->name, + dst_side, &dst_name)) + die("Didn't think it matches any more"); } dst_peer = find_ref_by_name(dst, dst_name); if (dst_peer) { @@ -1160,19 +1163,17 @@ static struct ref *get_expanded_map(const struct ref *remote_refs, struct ref *ret = NULL; struct ref **tail = &ret; - int remote_prefix_len = strlen(refspec->src); - int local_prefix_len = strlen(refspec->dst); + char *expn_name; for (ref = remote_refs; ref; ref = ref->next) { if (strchr(ref->name, '^')) continue; /* a dereference item */ - if (match_name_with_pattern(refspec->src, ref->name)) { - const char *match; + if (match_name_with_pattern(refspec->src, ref->name, + refspec->dst, &expn_name)) { struct ref *cpy = copy_ref(ref); - match = ref->name + remote_prefix_len; - cpy->peer_ref = alloc_ref_with_prefix(refspec->dst, - local_prefix_len, match); + cpy->peer_ref = alloc_ref(expn_name); + free(expn_name); if (refspec->force) cpy->peer_ref->force = 1; *tail = cpy; From 08fbdb30438fd7087c5abe15840a22fe21094515 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Sat, 7 Mar 2009 01:11:36 -0500 Subject: [PATCH 17/52] Keep '*' in pattern refspecs In order to do anything more capable with refspecs, the first step is to keep the entire input. Additionally, validate patterns by checking for the ref matching the rules for a pattern as given by check_ref_format(). This requires a slight change to check_ref_format() to make it enforce the requirement that the '*' immediately follow a '/'. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- refs.c | 4 +--- remote.c | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/refs.c b/refs.c index 6eb5f53846..a50ba79270 100644 --- a/refs.c +++ b/refs.c @@ -718,9 +718,7 @@ int check_ref_format(const char *ref) while ((ch = *cp++) != 0) { bad_type = bad_ref_char(ch); if (bad_type) { - return (bad_type == 2 && !*cp) - ? CHECK_REF_FORMAT_WILDCARD - : CHECK_REF_FORMAT_ERROR; + return CHECK_REF_FORMAT_ERROR; } if (ch == '/') break; diff --git a/remote.c b/remote.c index 01b8f91c5b..d596a48651 100644 --- a/remote.c +++ b/remote.c @@ -10,8 +10,8 @@ static struct refspec s_tag_refspec = { 0, 1, 0, - "refs/tags/", - "refs/tags/" + "refs/tags/*", + "refs/tags/*" }; const struct refspec *tag_refspec = &s_tag_refspec; @@ -451,16 +451,11 @@ static void read_config(void) */ static int verify_refname(char *name, int is_glob) { - int result, len = -1; + int result; - if (is_glob) { - len = strlen(name); - assert(name[len - 1] == '/'); - name[len - 1] = '\0'; - } result = check_ref_format(name); - if (is_glob) - name[len - 1] = '/'; + if (is_glob && result == CHECK_REF_FORMAT_WILDCARD) + result = CHECK_REF_FORMAT_OK; return result; } @@ -517,7 +512,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if (rhs) { size_t rlen = strlen(++rhs); is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); - rs[i].dst = xstrndup(rhs, rlen - is_glob); + rs[i].dst = xstrndup(rhs, rlen); } llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); @@ -525,7 +520,6 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if ((rhs && !is_glob) || (!rhs && fetch)) goto invalid; is_glob = 1; - llen--; } else if (rhs && is_glob) { goto invalid; } @@ -722,10 +716,19 @@ int remote_has_url(struct remote *remote, const char *url) static int match_name_with_pattern(const char *key, const char *name, const char *value, char **result) { - size_t klen = strlen(key); - int ret = !strncmp(key, name, klen); + const char *kstar = strchr(key, '*'); + size_t klen; + int ret; + if (!kstar) + die("Key '%s' of pattern had no '*'", key); + klen = kstar - key; + ret = !strncmp(key, name, klen); if (ret && value) { - size_t vlen = strlen(value); + const char *vstar = strchr(value, '*'); + size_t vlen; + if (!vstar) + die("Value '%s' of pattern has no '*'", value); + vlen = vstar - value; *result = xmalloc(vlen + strlen(name) - klen + 1); From abd2bde78bd994166900290434a2048e660dabed Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Sat, 7 Mar 2009 01:11:39 -0500 Subject: [PATCH 18/52] Support '*' in the middle of a refspec In order to keep the requirements strict, each * has to be a full path component, and there may only be one * per side. This requirement is enforced entirely by check_ref_format(); the matching implementation will substitute the whatever matches the * in the lhs for the * in the rhs. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- refs.c | 11 +++++++---- remote.c | 24 +++++++++++++++++------- t/t5511-refspec.sh | 12 ++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/refs.c b/refs.c index a50ba79270..fef7c9f26d 100644 --- a/refs.c +++ b/refs.c @@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch) int check_ref_format(const char *ref) { int ch, level, bad_type; + int ret = CHECK_REF_FORMAT_OK; const char *cp = ref; level = 0; @@ -709,9 +710,11 @@ int check_ref_format(const char *ref) return CHECK_REF_FORMAT_ERROR; bad_type = bad_ref_char(ch); if (bad_type) { - return (bad_type == 2 && !*cp) - ? CHECK_REF_FORMAT_WILDCARD - : CHECK_REF_FORMAT_ERROR; + if (bad_type == 2 && (!*cp || *cp == '/') && + ret == CHECK_REF_FORMAT_OK) + ret = CHECK_REF_FORMAT_WILDCARD; + else + return CHECK_REF_FORMAT_ERROR; } /* scan the rest of the path component */ @@ -729,7 +732,7 @@ int check_ref_format(const char *ref) if (!ch) { if (level < 2) return CHECK_REF_FORMAT_ONELEVEL; - return CHECK_REF_FORMAT_OK; + return ret; } } } diff --git a/remote.c b/remote.c index d596a48651..90203e2fe1 100644 --- a/remote.c +++ b/remote.c @@ -511,12 +511,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp if (rhs) { size_t rlen = strlen(++rhs); - is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); + is_glob = (1 <= rlen && strchr(rhs, '*')); rs[i].dst = xstrndup(rhs, rlen); } llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); - if (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2)) { + if (1 <= llen && memchr(lhs, '*', llen)) { if ((rhs && !is_glob) || (!rhs && fetch)) goto invalid; is_glob = 1; @@ -718,22 +718,32 @@ static int match_name_with_pattern(const char *key, const char *name, { const char *kstar = strchr(key, '*'); size_t klen; + size_t ksuffixlen; + size_t namelen; int ret; if (!kstar) die("Key '%s' of pattern had no '*'", key); klen = kstar - key; - ret = !strncmp(key, name, klen); + ksuffixlen = strlen(kstar + 1); + namelen = strlen(name); + ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen && + !memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen); if (ret && value) { const char *vstar = strchr(value, '*'); size_t vlen; + size_t vsuffixlen; if (!vstar) die("Value '%s' of pattern has no '*'", value); vlen = vstar - value; - *result = xmalloc(vlen + + vsuffixlen = strlen(vstar + 1); + *result = xmalloc(vlen + vsuffixlen + strlen(name) - - klen + 1); - strcpy(*result, value); - strcpy(*result + vlen, name + klen); + klen - ksuffixlen + 1); + strncpy(*result, value, vlen); + strncpy(*result + vlen, + name + klen, namelen - klen - ksuffixlen); + strcpy(*result + vlen + namelen - klen - ksuffixlen, + vstar + 1); } return ret; } diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 22ba380034..c28932216b 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid + +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' + test_done From 8a3b25da8cdd7f3aa75f18d3245ce83aca90bb1a Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 7 Mar 2009 20:22:07 -0500 Subject: [PATCH 19/52] t3000: use test_cmp instead of diff These ancient tests predate test_cmp. While we're at it, let's switch to our usual "expected before actual" order of arguments; this makes the diff output "here's what is changed from expected" instead of the reverse. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t3000-ls-files-others.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index bc0a351392..36eee0f8ae 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -42,7 +42,7 @@ test_expect_success \ test_expect_success \ 'git ls-files --others should pick up symlinks.' \ - 'diff output expected1' + 'test_cmp expected1 output' test_expect_success \ 'git ls-files --others --directory to show output.' \ @@ -51,6 +51,6 @@ test_expect_success \ test_expect_success \ 'git ls-files --others --directory should not get confused.' \ - 'diff output expected2' + 'test_cmp expected2 output' test_done From 2fb6d6d6dd1033bfe82d6d327ac270f9cf8943cd Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 7 Mar 2009 20:27:22 -0500 Subject: [PATCH 20/52] ls-files: fix broken --no-empty-directory Commit ce8e880 converted ls-files to use parseopt; the --no-empty-directory option was converted as an OPT_BIT for "empty-directory" to set the DIR_HIDE_EMPTY_DIRECTORY flag. However, that makes it do the opposite of what it should: --empty-directory would hide, but --no-empty-directory would turn off hiding. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-ls-files.c | 4 ++-- t/t3000-ls-files-others.sh | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 1742c0f80d..437c366c9e 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -454,8 +454,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) OPT_BIT(0, "directory", &dir.flags, "show 'other' directories' name only", DIR_SHOW_OTHER_DIRECTORIES), - OPT_BIT(0, "empty-directory", &dir.flags, - "list empty directories", + OPT_BIT(0, "no-empty-directory", &dir.flags, + "don't show empty directories", DIR_HIDE_EMPTY_DIRECTORIES), OPT_BOOLEAN('u', "unmerged", &show_unmerged, "show unmerged files in the output"), diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index 36eee0f8ae..379d963cea 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -13,12 +13,13 @@ filesystem. path2/file2 - a file in a directory path3-junk - a file to confuse things path3/file3 - a file in a directory + path4 - an empty directory ' . ./test-lib.sh date >path0 ln -s xyzzy path1 -mkdir path2 path3 +mkdir path2 path3 path4 date >path2/file2 date >path2-junk date >path3/file3 @@ -28,6 +29,7 @@ git update-index --add path3-junk path3/file3 cat >expected1 <expected2 +cat expected3 +echo path4/ >>expected2 test_expect_success \ 'git ls-files --others to show output.' \ @@ -53,4 +57,12 @@ test_expect_success \ 'git ls-files --others --directory should not get confused.' \ 'test_cmp expected2 output' +test_expect_success \ + 'git ls-files --others --directory --no-empty-directory to show output.' \ + 'git ls-files --others --directory --no-empty-directory >output' + +test_expect_success \ + '--no-empty-directory hides empty directory' \ + 'test_cmp expected3 output' + test_done From 72f600832f75db626fd9290a21d02d49c92ca9ca Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 10 Mar 2009 01:20:42 -0700 Subject: [PATCH 21/52] Improve "git branch --tracking" output An earlier patch always spelled the full name of the ref that we track (e.g. "refs/heads/frotz" instead of just "frotz" when we mean the branch whose name is "frotz"). Worse yet, because we now use the true name of the ref at the original repository when talk about a tracking branch that copies from a remote, such a full name alone still does not give enough information. This reorganizes the verbose codepath to: - differentiate "refs/heads/something" and everything else; we say that the branch tracks "branch " if it begins with "refs/heads/", and otherwise the branch tracks "ref refs//"; - report the name of the remote when we talk about a tracking branch, by saying "branch frotz from origin"; - not say "by merging" at the end; it is the default and is not worth reporting. Signed-off-by: Junio C Hamano Signed-off-by: Junio C Hamano --- branch.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/branch.c b/branch.c index d20fb0490b..5f889fee6b 100644 --- a/branch.c +++ b/branch.c @@ -65,12 +65,23 @@ void install_branch_config(int flag, const char *local, const char *origin, cons git_config_set(key.buf, "true"); } - if (flag & BRANCH_CONFIG_VERBOSE) - printf("Branch %s set up to track %s branch %s %s.\n", - local, - origin ? "remote" : "local", - remote, - rebasing ? "by rebasing" : "by merging"); + if (flag & BRANCH_CONFIG_VERBOSE) { + strbuf_reset(&key); + + strbuf_addstr(&key, origin ? "remote" : "local"); + + /* Are we tracking a proper "branch"? */ + if (!prefixcmp(remote, "refs/heads/")) { + strbuf_addf(&key, " branch %s", remote + 11); + if (origin) + strbuf_addf(&key, " from %s", origin); + } + else + strbuf_addf(&key, " ref %s", remote); + printf("Branch %s set up to track %s%s.\n", + local, key.buf, + rebasing ? " by rebasing" : ""); + } strbuf_release(&key); } From e068f4f53b22c64f2058c316d858a892a5e24a6e Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:06 -0400 Subject: [PATCH 22/52] configure: ensure settings from user are also usable in the script Allow things set by the user (--with-lib, --with-iconv, etc) to set variables for use by other parts of the script. Display values as they're set. Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/configure.ac b/configure.ac index 082a03d3cf..0b314d7359 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,8 @@ else \ if test "$withval" = "yes"; then \ AC_MSG_WARN([You should provide path for --with-$1=PATH]); \ else \ + m4_toupper($1)_PATH=$withval; \ + AC_MSG_NOTICE([Setting m4_toupper($1)_PATH to $withval]); \ GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval); \ fi; \ fi; \ @@ -61,6 +63,8 @@ elif test "$withval" = "yes"; then \ m4_toupper(NO_$1)=; \ else \ m4_toupper(NO_$1)=; \ + m4_toupper($1)DIR=$withval; \ + AC_MSG_NOTICE([Setting m4_toupper($1)DIR to $withval]); \ GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval); \ fi \ ])# GIT_PARSE_WITH @@ -86,9 +90,16 @@ AC_ARG_WITH([lib], [if test "$withval" = "no" || test "$withval" = "yes"; then \ AC_MSG_WARN([You should provide name for --with-lib=ARG]); \ else \ + lib=$withval; \ + AC_MSG_NOTICE([Setting lib to '$lib']); \ GIT_CONF_APPEND_LINE(lib=$withval); \ fi; \ ],[]) + +if test -z "$lib"; then + AC_MSG_NOTICE([Setting lib to 'lib' (the default)]) + lib=lib +fi # # Define SHELL_PATH to provide path to shell. GIT_ARG_SET_PATH(shell) From 08df6a3086f4bcd5b224d442f103a7f63a605967 Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:07 -0400 Subject: [PATCH 23/52] configure: reorganize flow of argument checks Move the argument tests from the 'site overrides' so that they are ahead of any library tests. This allows for library tests to take user specified paths into account. The intent here is to avoid things like NO_DEFLATE_BOUND being set due to finding old zlib when the user has specified an alternate location for zlib. (Ignore the fact that properly set *FLAGS can avoid solve this issue.) Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 174 +++++++++++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/configure.ac b/configure.ac index 0b314d7359..0bff4808c0 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,93 @@ if test -z "$lib"; then AC_MSG_NOTICE([Setting lib to 'lib' (the default)]) lib=lib fi + +## Site configuration (override autodetection) +## --with-PACKAGE[=ARG] and --without-PACKAGE +AC_MSG_NOTICE([CHECKS for site configuration]) +# +# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability +# tests. These tests take up a significant amount of the total test time +# but are not needed unless you plan to talk to SVN repos. +# +# Define MOZILLA_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast +# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default +# choice) has very fast version optimized for i586. +# +# Define PPC_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for PowerPC. +# +# Define ARM_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for ARM. +# +# Define NO_OPENSSL environment variable if you do not have OpenSSL. +# This also implies MOZILLA_SHA1. +# +# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +AC_ARG_WITH(openssl, +AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)]) +AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\ +GIT_PARSE_WITH(openssl)) +# +# Define NO_CURL if you do not have curl installed. git-http-pull and +# git-http-push are not built, and you cannot use http:// and https:// +# transports. +# +# Define CURLDIR=/foo/bar if your curl header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +AC_ARG_WITH(curl, +AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)]) +AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]), +GIT_PARSE_WITH(curl)) +# +# Define NO_EXPAT if you do not have expat installed. git-http-push is +# not built, and you cannot push using http:// and https:// transports. +# +# Define EXPATDIR=/foo/bar if your expat header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +AC_ARG_WITH(expat, +AS_HELP_STRING([--with-expat], +[support git-push using http:// and https:// transports via WebDAV (default is YES)]) +AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]), +GIT_PARSE_WITH(expat)) +# +# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink +# installed in /sw, but don't want GIT to link against any libraries +# installed there. If defined you may specify your own (or Fink's) +# include directories and library directories by defining CFLAGS +# and LDFLAGS appropriately. +# +# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, +# have DarwinPorts installed in /opt/local, but don't want GIT to +# link against any libraries installed there. If defined you may +# specify your own (or DarwinPort's) include directories and +# library directories by defining CFLAGS and LDFLAGS appropriately. +# +# Define NO_MMAP if you want to avoid mmap. +# +# Define NO_ICONV if your libc does not properly support iconv. +AC_ARG_WITH(iconv, +AS_HELP_STRING([--without-iconv], +[if your architecture doesn't properly support iconv]) +AS_HELP_STRING([--with-iconv=PATH], +[PATH is prefix for libiconv library and headers]) +AS_HELP_STRING([], +[used only if you need linking with libiconv]), +GIT_PARSE_WITH(iconv)) + +## --enable-FEATURE[=ARG] and --disable-FEATURE +# +# Define USE_NSEC below if you want git to care about sub-second file mtimes +# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and +# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely +# randomly break unless your underlying filesystem supports those sub-second +# times (my ext3 doesn't). +# +# Define USE_STDEV below if you want git to care about the underlying device +# change being considered an inode change from the update-index perspective. + # # Define SHELL_PATH to provide path to shell. GIT_ARG_SET_PATH(shell) @@ -526,93 +613,6 @@ AC_SUBST(PTHREAD_LIBS) AC_SUBST(NO_PTHREADS) AC_SUBST(THREADED_DELTA_SEARCH) -## Site configuration (override autodetection) -## --with-PACKAGE[=ARG] and --without-PACKAGE -AC_MSG_NOTICE([CHECKS for site configuration]) -# -# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability -# tests. These tests take up a significant amount of the total test time -# but are not needed unless you plan to talk to SVN repos. -# -# Define MOZILLA_SHA1 environment variable when running make to make use of -# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast -# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default -# choice) has very fast version optimized for i586. -# -# Define PPC_SHA1 environment variable when running make to make use of -# a bundled SHA1 routine optimized for PowerPC. -# -# Define ARM_SHA1 environment variable when running make to make use of -# a bundled SHA1 routine optimized for ARM. -# -# Define NO_OPENSSL environment variable if you do not have OpenSSL. -# This also implies MOZILLA_SHA1. -# -# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -AC_ARG_WITH(openssl, -AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)]) -AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\ -GIT_PARSE_WITH(openssl)) -# -# Define NO_CURL if you do not have curl installed. git-http-pull and -# git-http-push are not built, and you cannot use http:// and https:// -# transports. -# -# Define CURLDIR=/foo/bar if your curl header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -AC_ARG_WITH(curl, -AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)]) -AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]), -GIT_PARSE_WITH(curl)) -# -# Define NO_EXPAT if you do not have expat installed. git-http-push is -# not built, and you cannot push using http:// and https:// transports. -# -# Define EXPATDIR=/foo/bar if your expat header and library files are in -# /foo/bar/include and /foo/bar/lib directories. -AC_ARG_WITH(expat, -AS_HELP_STRING([--with-expat], -[support git-push using http:// and https:// transports via WebDAV (default is YES)]) -AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]), -GIT_PARSE_WITH(expat)) -# -# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink -# installed in /sw, but don't want GIT to link against any libraries -# installed there. If defined you may specify your own (or Fink's) -# include directories and library directories by defining CFLAGS -# and LDFLAGS appropriately. -# -# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, -# have DarwinPorts installed in /opt/local, but don't want GIT to -# link against any libraries installed there. If defined you may -# specify your own (or DarwinPort's) include directories and -# library directories by defining CFLAGS and LDFLAGS appropriately. -# -# Define NO_MMAP if you want to avoid mmap. -# -# Define NO_ICONV if your libc does not properly support iconv. -AC_ARG_WITH(iconv, -AS_HELP_STRING([--without-iconv], -[if your architecture doesn't properly support iconv]) -AS_HELP_STRING([--with-iconv=PATH], -[PATH is prefix for libiconv library and headers]) -AS_HELP_STRING([], -[used only if you need linking with libiconv]), -GIT_PARSE_WITH(iconv)) - -## --enable-FEATURE[=ARG] and --disable-FEATURE -# -# Define USE_NSEC below if you want git to care about sub-second file mtimes -# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and -# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely -# randomly break unless your underlying filesystem supports those sub-second -# times (my ext3 doesn't). -# -# Define USE_STDEV below if you want git to care about the underlying device -# change being considered an inode change from the update-index perspective. - - ## Output files AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"]) AC_OUTPUT From 918c8120172514704809cbdf889794d8b1345d0a Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:08 -0400 Subject: [PATCH 24/52] configure: add macros to stash FLAG variables Allow for quick stash/unstash of CPPFLAGS and LDFLAGS. Library tests can now be easily bracketted with these macros to allow for values set in user/site arguments. Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/configure.ac b/configure.ac index 0bff4808c0..469c9a98d2 100644 --- a/configure.ac +++ b/configure.ac @@ -80,6 +80,32 @@ AC_DEFUN([GIT_CHECK_FUNC],[AC_CHECK_FUNC([$1],[ AC_SEARCH_LIBS([$1],, [$2],[$3]) ],[$3])]) + +dnl +dnl GIT_STASH_FLAGS(BASEPATH_VAR) +dnl ----------------------------- +dnl Allow for easy stashing of LDFLAGS and CPPFLAGS before running +dnl tests that may want to take user settings into account. +AC_DEFUN([GIT_STASH_FLAGS],[ +if test -n "$1"; then + old_CPPFLAGS="$CPPFLAGS" + old_LDFLAGS="$LDFLAGS" + CPPFLAGS="-I$1/include $CPPFLAGS" + LDFLAGS="-L$1/$lib $LDFLAGS" +fi +]) + +dnl +dnl GIT_UNSTASH_FLAGS(BASEPATH_VAR) +dnl ----------------------------- +dnl Restore the stashed *FLAGS values. +AC_DEFUN([GIT_UNSTASH_FLAGS],[ +if test -n "$1"; then + CPPFLAGS="$old_CPPFLAGS" + LDFLAGS="$old_LDFLAGS" +fi +]) + ## Site configuration related to programs (before tests) ## --with-PACKAGE[=ARG] and --without-PACKAGE # From 310386f07b5ef3dc337db1be37345fbd8d7a3af8 Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:09 -0400 Subject: [PATCH 25/52] configure: wrap some library tests with GIT_STASH_FLAGS Libraries that can have user specificed base paths are wrapped with GIT_STASH_FLAGS/GIT_UNSTASH_FLAGS to ensure that the proper versions on the system are tested. This ensures, for example, that the zlib tests for deflateUnbound are done with the version of zlib requested by the user. This is most useful in the absence of good settings for CPPFLAGS and/or LDFLAGS. Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 469c9a98d2..fe9d7eb463 100644 --- a/configure.ac +++ b/configure.ac @@ -315,33 +315,57 @@ AC_MSG_NOTICE([CHECKS for libraries]) # # Define NO_OPENSSL environment variable if you do not have OpenSSL. # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). + +GIT_STASH_FLAGS($OPENSSLDIR) + AC_CHECK_LIB([crypto], [SHA1_Init], [NEEDS_SSL_WITH_CRYPTO=], [AC_CHECK_LIB([ssl], [SHA1_Init], [NEEDS_SSL_WITH_CRYPTO=YesPlease NEEDS_SSL_WITH_CRYPTO=], [NO_OPENSSL=YesPlease])]) + +GIT_UNSTASH_FLAGS($OPENSSLDIR) + AC_SUBST(NEEDS_SSL_WITH_CRYPTO) AC_SUBST(NO_OPENSSL) + # # Define NO_CURL if you do not have libcurl installed. git-http-pull and # git-http-push are not built, and you cannot use http:// and https:// # transports. + +GIT_STASH_FLAGS($CURLDIR) + AC_CHECK_LIB([curl], [curl_global_init], [NO_CURL=], [NO_CURL=YesPlease]) + +GIT_UNSTASH_FLAGS($CURLDIR) + AC_SUBST(NO_CURL) + # # Define NO_EXPAT if you do not have expat installed. git-http-push is # not built, and you cannot push using http:// and https:// transports. + +GIT_STASH_FLAGS($EXPATDIR) + AC_CHECK_LIB([expat], [XML_ParserCreate], [NO_EXPAT=], [NO_EXPAT=YesPlease]) + +GIT_UNSTASH_FLAGS($EXPATDIR) + AC_SUBST(NO_EXPAT) + # # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and # some Solaris installations). # Define NO_ICONV if neither libc nor libiconv support iconv. + +GIT_STASH_FLAGS($ICONVDIR) + AC_DEFUN([ICONVTEST_SRC], [ #include @@ -365,11 +389,17 @@ AC_LINK_IFELSE(ICONVTEST_SRC, [AC_MSG_RESULT([no]) NO_ICONV=YesPlease]) LIBS="$old_LIBS"]) + +GIT_UNSTASH_FLAGS($ICONVDIR) + AC_SUBST(NEEDS_LIBICONV) AC_SUBST(NO_ICONV) -test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv" + # # Define NO_DEFLATE_BOUND if deflateBound is missing from zlib. + +GIT_STASH_FLAGS($ZLIB_PATH) + AC_DEFUN([ZLIBTEST_SRC], [ #include @@ -387,7 +417,11 @@ AC_LINK_IFELSE(ZLIBTEST_SRC, [AC_MSG_RESULT([no]) NO_DEFLATE_BOUND=yes]) LIBS="$old_LIBS" + +GIT_UNSTASH_FLAGS($ZLIB_PATH) + AC_SUBST(NO_DEFLATE_BOUND) + # # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Patrick Mauritz). From 29adc8baf997e143d8aeac9a0aeb257539d32e6d Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:10 -0400 Subject: [PATCH 26/52] configure: asciidoc version test cleanup Redirect stderr to /dev/null instead of stdout. This discards warnings generated by python 2.6 related to the reorganization of functions within modules. The warnings were causing the version detection to break. Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fe9d7eb463..f4b8e49dc3 100644 --- a/configure.ac +++ b/configure.ac @@ -291,7 +291,7 @@ fi AC_CHECK_PROGS(ASCIIDOC, [asciidoc]) if test -n "$ASCIIDOC"; then AC_MSG_CHECKING([for asciidoc version]) - asciidoc_version=`$ASCIIDOC --version 2>&1` + asciidoc_version=`$ASCIIDOC --version 2>/dev/null` case "${asciidoc_version}" in asciidoc' '8*) ASCIIDOC8=YesPlease From a8304f7a70832a8e333fcf547589bc9d3bc0ca3c Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:11 -0400 Subject: [PATCH 27/52] configure: make iconv tests aware of user arguments --with-iconv is now taken into account when doing the tests for iconv. If the user requests alternate handling for libiconv, the -liconv test is run before the -lc test. Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index f4b8e49dc3..6fe4bfe738 100644 --- a/configure.ac +++ b/configure.ac @@ -375,20 +375,35 @@ int main(void) return 0; } ]) -AC_MSG_CHECKING([for iconv in -lc]) -AC_LINK_IFELSE(ICONVTEST_SRC, + +if test -n "$ICONVDIR"; then + lib_order="-liconv -lc" +else + lib_order="-lc -liconv" +fi + +NO_ICONV=YesPlease + +for l in $lib_order; do + if test "$l" = "-liconv"; then + NEEDS_LIBICONV=YesPlease + else + NEEDS_LIBICONV= + fi + + old_LIBS="$LIBS" + LIBS="$LIBS $l" + AC_MSG_CHECKING([for iconv in $l]) + AC_LINK_IFELSE(ICONVTEST_SRC, [AC_MSG_RESULT([yes]) - NEEDS_LIBICONV=], - [AC_MSG_RESULT([no]) - old_LIBS="$LIBS" - LIBS="$LIBS -liconv" - AC_MSG_CHECKING([for iconv in -liconv]) - AC_LINK_IFELSE(ICONVTEST_SRC, - [AC_MSG_RESULT([yes]) - NEEDS_LIBICONV=YesPlease], - [AC_MSG_RESULT([no]) - NO_ICONV=YesPlease]) - LIBS="$old_LIBS"]) + NO_ICONV= + break], + [AC_MSG_RESULT([no])]) + LIBS="$old_LIBS" +done + +#in case of break +LIBS="$old_LIBS" GIT_UNSTASH_FLAGS($ICONVDIR) @@ -455,13 +470,18 @@ int main(void) return 0; } ]]) + +GIT_STASH_FLAGS($ICONVDIR) + AC_MSG_CHECKING([for old iconv()]) AC_COMPILE_IFELSE(OLDICONVTEST_SRC, [AC_MSG_RESULT([no])], [AC_MSG_RESULT([yes]) OLD_ICONV=UnfortunatelyYes]) -AC_SUBST(OLD_ICONV) +GIT_UNSTASH_FLAGS($ICONVDIR) + +AC_SUBST(OLD_ICONV) ## Checks for typedefs, structures, and compiler characteristics. AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics]) From 1973b0d790155b5d8a32a6f7401116fad2205721 Mon Sep 17 00:00:00 2001 From: Ben Walton Date: Thu, 12 Mar 2009 15:20:12 -0400 Subject: [PATCH 28/52] configure: rework pthread handling to allow for user defined flags The tests for POSIX threads can now be controlled by the user with the --enable-pthreads=FLAGS option. If this is set (to some value other than yes or no), the value is passed to the compiler. Thread support is based solely on the outcome of this test. The user may specify not to use threading at all or to use the default tests (first -pthread then -lpthread) by not specifying FLAGS when passing --enable-pthreads. Signed-off-by: Ben Walton Signed-off-by: Junio C Hamano --- configure.ac | 89 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index 6fe4bfe738..4e728bca35 100644 --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,27 @@ if test -z "$lib"; then lib=lib fi +AC_ARG_ENABLE([pthreads], + [AS_HELP_STRING([--enable-pthreads=FLAGS], + [FLAGS is the value to pass to the compiler to enable POSIX Threads.] + [The default if FLAGS is not specified is to try first -pthread] + [and then -lpthread.] + [--without-pthreads will disable threading.])], +[ +if test "x$enableval" = "xyes"; then + AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads]) +elif test "x$enableval" != "xno"; then + PTHREAD_CFLAGS=$enableval + AC_MSG_NOTICE([Setting '$PTHREAD_CFLAGS' as the FLAGS to enable POSIX Threads]) +else + AC_MSG_NOTICE([POSIX Threads will be disabled.]) + NO_PTHREADS=YesPlease + USER_NOPTHREAD=1 +fi], +[ + AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads.]) +]) + ## Site configuration (override autodetection) ## --with-PACKAGE[=ARG] and --without-PACKAGE AC_MSG_NOTICE([CHECKS for site configuration]) @@ -672,23 +693,61 @@ AC_SUBST(NO_MKDTEMP) # # Define PTHREAD_LIBS to the linker flag used for Pthread support and define # THREADED_DELTA_SEARCH if Pthreads are available. -AC_LANG_CONFTEST([AC_LANG_PROGRAM( - [[#include ]], - [[pthread_mutex_t test_mutex;]] -)]) -${CC} -pthread conftest.c -o conftest.o > /dev/null 2>&1 -if test $? -eq 0;then - PTHREAD_LIBS="-pthread" - THREADED_DELTA_SEARCH=YesPlease +AC_DEFUN([PTHREADTEST_SRC], [ +#include + +int main(void) +{ + pthread_mutex_t test_mutex; + return (0); +} +]) + +dnl AC_LANG_CONFTEST([AC_LANG_PROGRAM( +dnl [[#include ]], +dnl [[pthread_mutex_t test_mutex;]] +dnl )]) + +NO_PTHREADS=UnfortunatelyYes +THREADED_DELTA_SEARCH= +PTHREAD_LIBS= + +if test -n "$USER_NOPTHREAD"; then + AC_MSG_NOTICE([Skipping POSIX Threads at user request.]) +# handle these separately since PTHREAD_CFLAGS could be '-lpthreads +# -D_REENTRANT' or some such. +elif test -z "$PTHREAD_CFLAGS"; then + for opt in -pthread -lpthread; do + old_CFLAGS="$CFLAGS" + CFLAGS="$opt $CFLAGS" + AC_MSG_CHECKING([Checking for POSIX Threads with '$opt']) + AC_LINK_IFELSE(PTHREADTEST_SRC, + [AC_MSG_RESULT([yes]) + NO_PTHREADS= + PTHREAD_LIBS="$opt" + THREADED_DELTA_SEARCH=YesPlease + break + ], + [AC_MSG_RESULT([no])]) + CFLAGS="$old_CFLAGS" + done else - ${CC} -lpthread conftest.c -o conftest.o > /dev/null 2>&1 - if test $? -eq 0;then - PTHREAD_LIBS="-lpthread" - THREADED_DELTA_SEARCH=YesPlease - else - NO_PTHREADS=UnfortunatelyYes - fi + old_CFLAGS="$CFLAGS" + CFLAGS="$PTHREAD_CFLAGS $CFLAGS" + AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS']) + AC_LINK_IFELSE(PTHREADTEST_SRC, + [AC_MSG_RESULT([yes]) + NO_PTHREADS= + PTHREAD_LIBS="$PTHREAD_CFLAGS" + THREADED_DELTA_SEARCH=YesPlease + ], + [AC_MSG_RESULT([no])]) + + CFLAGS="$old_CFLAGS" fi + +CFLAGS="$old_CFLAGS" + AC_SUBST(PTHREAD_LIBS) AC_SUBST(NO_PTHREADS) AC_SUBST(THREADED_DELTA_SEARCH) From bf71b4b3ee07291e97c4dabfb97e7397eec904e0 Mon Sep 17 00:00:00 2001 From: Carlos Rica Date: Tue, 17 Mar 2009 10:46:37 +0100 Subject: [PATCH 29/52] config: test for --replace-all with one argument and fix documentation. Option --replace-all only allows at least two arguments, so documentation was needing to be updated accordingly. A test showing that the command fails with only one parameter is also provided. Signed-off-by: Carlos Rica Signed-off-by: Junio C Hamano --- Documentation/git-config.txt | 2 +- builtin-config.c | 2 +- t/t1300-repo-config.sh | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 7d140073b1..8b94f19b17 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git config' [] [type] [-z|--null] name [value [value_regex]] 'git config' [] [type] --add name value -'git config' [] [type] --replace-all name [value [value_regex]] +'git config' [] [type] --replace-all name value [value_regex] 'git config' [] [type] [-z|--null] --get name [value_regex] 'git config' [] [type] [-z|--null] --get-all name [value_regex] 'git config' [] [type] [-z|--null] --get-regexp name_regex [value_regex] diff --git a/builtin-config.c b/builtin-config.c index 1a3baa1f46..d8da72cf20 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -55,7 +55,7 @@ static struct option builtin_config_options[] = { OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET), OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL), OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP), - OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name [value [value_regex]", ACTION_REPLACE_ALL), + OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL), OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD), OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET), OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL), diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 11b82f43dd..f0a75380b3 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -118,7 +118,14 @@ EOF test_expect_success 'multiple unset is correct' 'cmp .git/config expect' -mv .git/config2 .git/config +cp .git/config2 .git/config + +test_expect_success '--replace-all missing value' ' + test_must_fail git config --replace-all beta.haha && + test_cmp .git/config2 .git/config +' + +rm .git/config2 test_expect_success '--replace-all' \ 'git config --replace-all beta.haha gamma' From 7fd3ef1fd73dffdb9b3445893ab579723ce08e74 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 7 Mar 2009 00:04:09 +0100 Subject: [PATCH 30/52] t9400, t9401: Do not force hard-linked clone The tests do not depend on that the clones are hard-linked, but used --local only as an optimization: At the time that --local was used first in t9400 hard-linked clones were not the default, yet. By removing --local, we help filesystems that do not support hard-links. Signed-off-by: Johannes Sixt --- t/t9400-git-cvsserver-server.sh | 4 ++-- t/t9401-git-cvsserver-crlf.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 6a37f71d11..9ccb1232bb 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -44,7 +44,7 @@ test_expect_success 'setup' ' git add secondrootfile && git commit -m "second root") && git pull secondroot master && - git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && + git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ' @@ -267,7 +267,7 @@ test_expect_success 'gitcvs.ext.dbname' \ rm -fr "$SERVERDIR" cd "$WORKDIR" && -git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && +git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" || exit 1 diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index e27a1c5f85..5d6200c4df 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -84,7 +84,7 @@ test_expect_success 'setup' ' echo "subdir/file.h crlf" >> .gitattributes && git add .gitattributes textfile.c binfile.bin mixedUp.c subdir/* && git commit -q -m "First Commit" && - git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && + git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ' From ec2956df592338ccd789428e9232fe6b709dc2be Mon Sep 17 00:00:00 2001 From: Nate Case Date: Wed, 18 Mar 2009 12:00:45 -0500 Subject: [PATCH 31/52] format-patch: Respect --quiet option Hide the patch filename output from 'git format-patch' when --quiet is used. The man pages suggested that this should have already worked. Signed-off-by: Nate Case Signed-off-by: Junio C Hamano --- builtin-log.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 8684fcdb67..8af55d2879 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -573,7 +573,7 @@ static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; -static int reopen_stdout(const char *oneline, int nr, int total) +static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev) { char filename[PATH_MAX]; int len = 0; @@ -598,7 +598,9 @@ static int reopen_stdout(const char *oneline, int nr, int total) strcpy(filename + len, fmt_patch_suffix); } - fprintf(realstdout, "%s\n", filename + outdir_offset); + if (!DIFF_OPT_TST(&rev->diffopt, QUIET)) + fprintf(realstdout, "%s\n", filename + outdir_offset); + if (freopen(filename, "w", stdout) == NULL) return error("Cannot open patch file %s",filename); @@ -687,7 +689,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, die("Cover letter needs email format"); if (!use_stdout && reopen_stdout(numbered_files ? - NULL : "cover-letter", 0, rev->total)) + NULL : "cover-letter", 0, rev)) return; head_sha1 = sha1_to_hex(head->object.sha1); @@ -1106,7 +1108,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } if (!use_stdout && reopen_stdout(numbered_files ? NULL : get_oneline_for_filename(commit, keep_subject), - rev.nr, rev.total)) + rev.nr, &rev)) die("Failed to create output files"); shown = log_tree_commit(&rev, commit); free(commit->buffer); From 40bac1512b0063ad3e235bca3cb66644ccf7e510 Mon Sep 17 00:00:00 2001 From: Michele Ballabio Date: Wed, 18 Mar 2009 19:05:39 +0100 Subject: [PATCH 32/52] apply: consistent spelling of "don't" Signed-off-by: Michele Ballabio Signed-off-by: Junio C Hamano --- builtin-apply.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-apply.c b/builtin-apply.c index 106be94105..1a02c7ce75 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -3212,7 +3212,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) struct option builtin_apply_options[] = { { OPTION_CALLBACK, 0, "exclude", NULL, "path", - "don“t apply changes matching the given path", + "don't apply changes matching the given path", 0, option_parse_exclude }, { OPTION_CALLBACK, 0, "include", NULL, "path", "apply changes matching the given path", From 092927c1b01632d030d9d746d36ad6dd02bc3967 Mon Sep 17 00:00:00 2001 From: Michele Ballabio Date: Wed, 18 Mar 2009 19:05:40 +0100 Subject: [PATCH 33/52] apply: hide unused options from short help The options "--binary" and "--allow-binary-replacement" of git-apply are no-op and maintained for backward compatibility, so avoid to show them in the short help screen. Signed-off-by: Michele Ballabio Signed-off-by: Junio C Hamano --- builtin-apply.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 1a02c7ce75..b52aa20cfa 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -3224,10 +3224,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) "ignore additions made by the patch"), OPT_BOOLEAN(0, "stat", &diffstat, "instead of applying the patch, output diffstat for the input"), - OPT_BOOLEAN(0, "allow-binary-replacement", &binary, - "now no-op"), - OPT_BOOLEAN(0, "binary", &binary, - "now no-op"), + { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary, + NULL, "old option, now no-op", PARSE_OPT_HIDDEN }, + { OPTION_BOOLEAN, 0, "binary", &binary, + NULL, "old option, now no-op", PARSE_OPT_HIDDEN }, OPT_BOOLEAN(0, "numstat", &numstat, "shows number of added and deleted lines in decimal notation"), OPT_BOOLEAN(0, "summary", &summary, From ba150a3fdce48e4b973db6e153e6b3ffb28a0cea Mon Sep 17 00:00:00 2001 From: Michele Ballabio Date: Wed, 18 Mar 2009 21:53:27 +0100 Subject: [PATCH 34/52] git log: avoid segfault with --all-match Avoid a segfault when the command git log --all-match was issued, by ignoring the option. Signed-off-by: Michele Ballabio Signed-off-by: Junio C Hamano --- grep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grep.c b/grep.c index be99b34168..f3a27d7d6e 100644 --- a/grep.c +++ b/grep.c @@ -192,7 +192,8 @@ void compile_grep_patterns(struct grep_opt *opt) * A classic recursive descent parser would do. */ p = opt->pattern_list; - opt->pattern_expression = compile_pattern_expr(&p); + if (p) + opt->pattern_expression = compile_pattern_expr(&p); if (p) die("incomplete pattern expression: %s", p->pattern); } From 1c192f3442414a6ce83f9a524806fc26a0861d2d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 6 Dec 2007 12:03:38 +0000 Subject: [PATCH 35/52] gc --aggressive: make it really aggressive The default was not to change the window or depth at all. As suggested by Jon Smirl, Linus Torvalds and others, default to --window=250 --depth=250 Signed-off-by: Johannes Schindelin Acked-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-gc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin-gc.c b/builtin-gc.c index 8d990ed493..fc556ed7f3 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -23,7 +23,7 @@ static const char * const builtin_gc_usage[] = { }; static int pack_refs = 1; -static int aggressive_window = -1; +static int aggressive_window = 250; static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; static const char *prune_expire = "2.weeks.ago"; @@ -200,6 +200,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) if (aggressive) { append_option(argv_repack, "-f", MAX_ADD); + append_option(argv_repack, "--depth=250", MAX_ADD); if (aggressive_window > 0) { sprintf(buf, "--window=%d", aggressive_window); append_option(argv_repack, buf, MAX_ADD); From b130a72b274441bb5d687de93efef4d990c40c0a Mon Sep 17 00:00:00 2001 From: Janos Laube Date: Fri, 13 Mar 2009 16:50:45 +0100 Subject: [PATCH 36/52] MinGW: implement mmap Add USE_WIN32_MMAP which triggers the use of windows' native file memory mapping functionality in git_mmap()/git_munmap() functions. As git functions currently use mmap with MAP_PRIVATE set only, this implementation supports only that mode for now. On Windows, offsets for memory mapped files need to match the allocation granularity. Take this into account when calculating the packed git- windowsize and file offsets. At the moment, the only function which makes use of offsets in conjunction with mmap is use_pack() in sha1-file.c. Git fast-import's code path tries to map a portion of the temporary packfile that exceeds the current filesize, i.e. offset+length is greater than the filesize. The NO_MMAP code worked with that since pread() just reads the file content until EOF and returns gracefully, while MapViewOfFile() aborts the mapping and returns 'Access Denied'. Working around that by determining the filesize and adjusting the length parameter. Signed-off-by: Janos Laube Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 7 +++++- compat/mingw.h | 5 +++++ compat/win32mmap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 12 ++++++++--- 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 compat/win32mmap.c diff --git a/Makefile b/Makefile index b96c2b316f..aae3b09411 100644 --- a/Makefile +++ b/Makefile @@ -784,7 +784,6 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) - NO_MMAP = YesPlease NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_CURL = YesPlease @@ -808,6 +807,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_NSEC = YesPlease + USE_WIN32_MMAP = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -985,6 +985,11 @@ endif ifdef NO_MMAP COMPAT_CFLAGS += -DNO_MMAP COMPAT_OBJS += compat/mmap.o +else + ifdef USE_WIN32_MMAP + COMPAT_CFLAGS += -DUSE_WIN32_MMAP + COMPAT_OBJS += compat/win32mmap.o + endif endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD diff --git a/compat/mingw.h b/compat/mingw.h index 7e52f3607f..762eb143a7 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -159,6 +159,11 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); int mingw_rename(const char*, const char*); #define rename mingw_rename +#ifdef USE_WIN32_MMAP +int mingw_getpagesize(void); +#define getpagesize mingw_getpagesize +#endif + /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ diff --git a/compat/win32mmap.c b/compat/win32mmap.c new file mode 100644 index 0000000000..779d796cd5 --- /dev/null +++ b/compat/win32mmap.c @@ -0,0 +1,53 @@ +#include "../git-compat-util.h" + +/* + * Note that this doesn't return the actual pagesize, but + * the allocation granularity. If future Windows specific git code + * needs the real getpagesize function, we need to find another solution. + */ +int mingw_getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + HANDLE hmap; + void *temp; + size_t len; + struct stat st; + uint64_t o = offset; + uint32_t l = o & 0xFFFFFFFF; + uint32_t h = (o >> 32) & 0xFFFFFFFF; + + if (!fstat(fd, &st)) + len = xsize_t(st.st_size); + else + die("mmap: could not determine filesize"); + + if ((length + offset) > len) + length = len - offset; + + if (!(flags & MAP_PRIVATE)) + die("Invalid usage of mmap when built with USE_WIN32_MMAP"); + + hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY, + 0, 0, 0); + + if (!hmap) + return MAP_FAILED; + + temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start); + + if (!CloseHandle(hmap)) + warning("unable to close file mapping handle\n"); + + return temp ? temp : MAP_FAILED; +} + +int git_munmap(void *start, size_t length) +{ + return !UnmapViewOfFile(start); +} diff --git a/git-compat-util.h b/git-compat-util.h index 19062534a1..f09f244061 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -166,7 +166,7 @@ static inline const char *skip_prefix(const char *str, const char *prefix) return strncmp(str, prefix, len) ? NULL : str + len; } -#ifdef NO_MMAP +#if defined(NO_MMAP) || defined(USE_WIN32_MMAP) #ifndef PROT_READ #define PROT_READ 1 @@ -180,13 +180,19 @@ static inline const char *skip_prefix(const char *str, const char *prefix) extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); extern int git_munmap(void *start, size_t length); +#else /* NO_MMAP || USE_WIN32_MMAP */ + +#include + +#endif /* NO_MMAP || USE_WIN32_MMAP */ + +#ifdef NO_MMAP + /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) #else /* NO_MMAP */ -#include - /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ From 5e75d56f1182c99364c9f5375665c814985f384d Mon Sep 17 00:00:00 2001 From: Michele Ballabio Date: Wed, 18 Mar 2009 21:53:39 +0100 Subject: [PATCH 37/52] document --force-rebase Signed-off-by: Michele Ballabio Signed-off-by: Junio C Hamano --- Documentation/git-rebase.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 57bd333f0b..276f1510c6 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -258,6 +258,13 @@ OPTIONS context exist they all must match. By default no context is ever ignored. +-f:: +--force-rebase:: + Force the rebase even if the current branch is a descendant + of the commit you are rebasing onto. Normally the command will + exit with the message "Current branch is up to date" in such a + situation. + --whitespace=