int cmd_verify_pack(int argc, const char **argv, const char *prefix) { int err = 0; unsigned int flags = 0; int i; #ifdef USE_CPLUSPLUS_FOR_INIT #pragma cplusplus on #endif const struct option verify_pack_options[] = { OPT_BIT('v', "verbose", &flags, "verbose", VERIFY_PACK_VERBOSE), OPT_BIT('s', "stat-only", &flags, "show statistics only", VERIFY_PACK_STAT_ONLY), OPT_END() }; #ifdef USE_CPLUSPLUS_FOR_INIT #pragma cplusplus reset #endif git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, verify_pack_options, verify_pack_usage, 0); if (argc < 1) usage_with_options(verify_pack_usage, verify_pack_options); for (i = 0; i < argc; i++) { if (verify_one_pack(argv[i], flags)) err = 1; discard_revindex(); } return err; }
int cmd_pack_refs(int argc, const char **argv, const char *prefix) { unsigned int flags = PACK_REFS_PRUNE; struct option opts[] = { OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL), OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE), OPT_END(), }; if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0)) usage_with_options(pack_refs_usage, opts); return pack_refs(flags); }
int cmd_push(int argc, const char **argv, const char *prefix) { int flags = 0; int tags = 0; int rc; const char *repo = NULL; /* default repository */ struct option options[] = { OPT__VERBOSITY(&verbosity), OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")), OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL), OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"), (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), OPT_BOOLEAN( 0, "delete", &deleterefs, N_("delete refs")), OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")), OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN), OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN), OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"), N_("control recursive pushing of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")), OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"), TRANSPORT_PUSH_SET_UPSTREAM), OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"), TRANSPORT_PUSH_PRUNE), OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK), OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"), TRANSPORT_PUSH_FOLLOW_TAGS), OPT_END() }; packet_trace_identity("push"); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, push_usage, 0); if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR)))) die(_("--delete is incompatible with --all, --mirror and --tags")); if (deleterefs && argc < 2) die(_("--delete doesn't make sense without any refs")); if (tags) add_refspec("refs/tags/*"); if (argc > 0) { repo = argv[0]; set_refspecs(argv + 1, argc - 1); } rc = do_push(repo, flags); if (rc == -1) usage_with_options(push_usage, options); else return rc; }
int cmd_verify_commit(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; unsigned flags = 0; const struct option verify_commit_options[] = { OPT__VERBOSE(&verbose, N_("print commit contents")), OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW), OPT_END() }; git_config(git_verify_commit_config, NULL); argc = parse_options(argc, argv, prefix, verify_commit_options, verify_commit_usage, PARSE_OPT_KEEP_ARGV0); if (argc <= i) usage_with_options(verify_commit_usage, verify_commit_options); if (verbose) flags |= GPG_VERIFY_VERBOSE; /* sometimes the program was terminated because this signal * was received in the process of writing the gpg input: */ signal(SIGPIPE, SIG_IGN); while (i < argc) if (verify_commit(argv[i++], flags)) had_error = 1; return had_error; }
int main(int argc, const char **argv) { const char *prefix = "prefix/"; const char *usage[] = { "test-parse-options <options>", NULL }; struct option options[] = { OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"), OPT_BIT('4', "or4", &boolean, "bitwise-or boolean with ...0100", 4), OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), OPT_GROUP(""), OPT_INTEGER('i', "integer", &integer, "get a integer"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"), OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), OPT_DATE('t', NULL, ×tamp, "get timestamp of <time>"), OPT_CALLBACK('L', "length", &integer, "str", "get length of <str>", length_callback), OPT_FILENAME('F', "file", &file, "set file to <FILE>"), OPT_GROUP("String options"), OPT_STRING('s', "string", &string, "string", "get a string"), OPT_STRING(0, "string2", &string, "str", "get another string"), OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"), OPT_STRING('o', NULL, &string, "str", "get another string"), OPT_SET_PTR(0, "default-string", &string, "set string to default", (unsigned long)"default"), OPT_GROUP("Magic arguments"), OPT_ARGUMENT("quux", "means --quux"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", number_callback), { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, OPT_GROUP("Standard options"), OPT__ABBREV(&abbrev), OPT__VERBOSE(&verbose), OPT__DRY_RUN(&dry_run), OPT__QUIET(&quiet), OPT_END(), }; int i; argc = parse_options(argc, argv, prefix, options, usage, 0); printf("boolean: %d\n", boolean); printf("integer: %u\n", integer); printf("timestamp: %lu\n", timestamp); printf("string: %s\n", string ? string : "(not set)"); printf("abbrev: %d\n", abbrev); printf("verbose: %d\n", verbose); printf("quiet: %s\n", quiet ? "yes" : "no"); printf("dry run: %s\n", dry_run ? "yes" : "no"); printf("file: %s\n", file ? file : "(not set)"); for (i = 0; i < argc; i++) printf("arg %02d: %s\n", i, argv[i]); return 0; }
int cmd_push(int argc, const char **argv, const char *prefix) { int flags = 0; int tags = 0; int rc; const char *repo = NULL; /* default repository */ struct option options[] = { OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE), OPT_STRING( 0 , "repo", &repo, "repository", "repository"), OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL), OPT_BIT( 0 , "mirror", &flags, "mirror all refs", (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), OPT_BOOLEAN( 0 , "tags", &tags, "push tags"), OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN), OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE), OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"), OPT_END() }; argc = parse_options(argc, argv, options, push_usage, 0); if (tags) add_refspec("refs/tags/*"); if (argc > 0) { repo = argv[0]; set_refspecs(argv + 1, argc - 1); } rc = do_push(repo, flags); if (rc == -1) usage_with_options(push_usage, options); else return rc; }
int cmd_prune_packed(int argc, const char **argv, const char *prefix) { int opts = isatty(2) ? VERBOSE : 0; const struct option prune_packed_options[] = { OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN), OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE), OPT_END() }; argc = parse_options(argc, argv, prefix, prune_packed_options, prune_packed_usage, 0); prune_packed_objects(opts); return 0; }
int cmd_verify_tag(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; unsigned flags = 0; struct ref_format format = REF_FORMAT_INIT; const struct option verify_tag_options[] = { OPT__VERBOSE(&verbose, N_("print tag contents")), OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW), OPT_STRING(0, "format", &format.format, N_("format"), N_("format to use for the output")), OPT_END() }; git_config(git_verify_tag_config, NULL); argc = parse_options(argc, argv, prefix, verify_tag_options, verify_tag_usage, PARSE_OPT_KEEP_ARGV0); if (argc <= i) usage_with_options(verify_tag_usage, verify_tag_options); if (verbose) flags |= GPG_VERIFY_VERBOSE; if (format.format) { if (verify_ref_format(&format)) usage_with_options(verify_tag_usage, verify_tag_options); flags |= GPG_VERIFY_OMIT_STATUS; } while (i < argc) { struct object_id oid; const char *name = argv[i++]; if (get_oid(name, &oid)) { had_error = !!error("tag '%s' not found.", name); continue; } if (gpg_verify_tag(&oid, name, flags)) { had_error = 1; continue; } if (format.format) pretty_print_ref(name, oid.hash, &format); } return had_error; }
int cmd_prune_packed(int argc, const char **argv, const char *prefix) { int opts = isatty(2) ? PRUNE_PACKED_VERBOSE : 0; const struct option prune_packed_options[] = { OPT_BIT('n', "dry-run", &opts, N_("dry run"), PRUNE_PACKED_DRY_RUN), OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"), PRUNE_PACKED_VERBOSE), OPT_END() }; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, prune_packed_options, prune_packed_usage, 0); prune_packed_objects(opts); return 0; }
static int remove_cmd(int argc, const char **argv, const char *prefix) { unsigned flag = 0; int from_stdin = 0; struct option options[] = { OPT_BIT(0, "ignore-missing", &flag, N_("attempt to remove non-existent note is not an error"), IGNORE_MISSING), OPT_BOOL(0, "stdin", &from_stdin, N_("read object names from the standard input")), OPT_END() }; struct notes_tree *t; int retval = 0; argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); t = init_notes_check("remove"); if (!argc && !from_stdin) { retval = remove_one_note(t, "HEAD", flag); } else { while (*argv) { retval |= remove_one_note(t, *argv, flag); argv++; } } if (from_stdin) { struct strbuf sb = STRBUF_INIT; while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { strbuf_rtrim(&sb); retval |= remove_one_note(t, sb.buf, flag); } strbuf_release(&sb); } if (!retval) commit_notes(t, "Notes removed by 'git notes remove'"); free_notes(t); return retval; }
int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) { int flags = 0, ret; const char *prefix = NULL; unsigned char sha1[20]; const char *me = "git-write-tree"; struct option write_tree_options[] = { OPT_BIT(0, "missing-ok", &flags, "allow missing objects", WRITE_TREE_MISSING_OK), { OPTION_STRING, 0, "prefix", &prefix, "<prefix>/", "write tree object for a subdirectory <prefix>" , PARSE_OPT_LITERAL_ARGHELP }, { OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL, "only useful for debugging", PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL, WRITE_TREE_IGNORE_CACHE_TREE }, OPT_END() }; git_config(git_default_config, NULL); argc = parse_options(argc, argv, unused_prefix, write_tree_options, write_tree_usage, 0); ret = write_cache_as_tree(sha1, flags, prefix); switch (ret) { case 0: printf("%s\n", sha1_to_hex(sha1)); break; case WRITE_TREE_UNREADABLE_INDEX: die("%s: error reading the index", me); break; case WRITE_TREE_UNMERGED_INDEX: die("%s: error building trees", me); break; case WRITE_TREE_PREFIX_ERROR: die("%s: prefix %s not found", me, prefix); break; } return ret; }
static int absorb_git_dirs(int argc, const char **argv, const char *prefix) { int i; struct pathspec pathspec; struct module_list list = MODULE_LIST_INIT; unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES; struct option embed_gitdir_options[] = { OPT_STRING(0, "prefix", &prefix, N_("path"), N_("path into the working tree")), OPT_BIT(0, "--recursive", &flags, N_("recurse into submodules"), ABSORB_GITDIR_RECURSE_SUBMODULES), OPT_END() }; const char *const git_submodule_helper_usage[] = { N_("git submodule--helper embed-git-dir [<path>...]"), NULL }; argc = parse_options(argc, argv, prefix, embed_gitdir_options, git_submodule_helper_usage, 0); gitmodules_config(); git_config(submodule_config, NULL); if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) return 1; for (i = 0; i < list.nr; i++) absorb_git_dir_into_superproject(prefix, list.entries[i]->name, flags); return 0; }
int cmd_ls_tree(int argc, const char **argv, const char *prefix) { unsigned char sha1[20]; struct tree *tree; int i, full_tree = 0; const struct option ls_tree_options[] = { OPT_BIT('d', NULL, &ls_options, N_("only show trees"), LS_TREE_ONLY), OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"), LS_RECURSIVE), OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"), LS_SHOW_TREES), OPT_SET_INT('z', NULL, &line_termination, N_("terminate entries with NUL byte"), 0), OPT_BIT('l', "long", &ls_options, N_("include object size"), LS_SHOW_SIZE), OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"), LS_NAME_ONLY), OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"), LS_NAME_ONLY), OPT_SET_INT(0, "full-name", &chomp_prefix, N_("use full path names"), 0), OPT_BOOL(0, "full-tree", &full_tree, N_("list entire tree; not just current directory " "(implies --full-name)")), OPT__ABBREV(&abbrev), OPT_END() }; git_config(git_default_config, NULL); ls_tree_prefix = prefix; if (prefix && *prefix) chomp_prefix = strlen(prefix); argc = parse_options(argc, argv, prefix, ls_tree_options, ls_tree_usage, 0); if (full_tree) { ls_tree_prefix = prefix = NULL; chomp_prefix = 0; } /* -d -r should imply -t, but -d by itself should not have to. */ if ( (LS_TREE_ONLY|LS_RECURSIVE) == ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options)) ls_options |= LS_SHOW_TREES; if (argc < 1) usage_with_options(ls_tree_usage, ls_tree_options); if (get_sha1(argv[0], sha1)) die("Not a valid object name %s", argv[0]); /* * show_recursive() rolls its own matching code and is * generally ignorant of 'struct pathspec'. The magic mask * cannot be lifted until it is converted to use * match_pathspec() or tree_entry_interesting() */ parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE | PATHSPEC_EXCLUDE, PATHSPEC_PREFER_CWD, prefix, argv + 1); for (i = 0; i < pathspec.nr; i++) pathspec.items[i].nowildcard_len = pathspec.items[i].len; pathspec.has_wildcard = 0; tree = parse_tree_indirect(sha1); if (!tree) die("not a tree object"); return !!read_tree_recursive(tree, "", 0, 0, &pathspec, show_tree, NULL); }
int cmd_ls_remote(int argc, const char **argv, const char *prefix) { const char *dest = NULL; unsigned flags = 0; int get_url = 0; int quiet = 0; int status = 0; int show_symref_target = 0; const char *uploadpack = NULL; const char **pattern = NULL; struct remote *remote; struct transport *transport; const struct ref *ref; struct option options[] = { OPT__QUIET(&quiet, N_("do not print remote URL")), OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"), N_("path of git-upload-pack on the remote host")), { OPTION_STRING, 0, "exec", &uploadpack, N_("exec"), N_("path of git-upload-pack on the remote host"), PARSE_OPT_HIDDEN }, OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS), OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS), OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL), OPT_BOOL(0, "get-url", &get_url, N_("take url.<base>.insteadOf into account")), OPT_SET_INT(0, "exit-code", &status, N_("exit with exit code 2 if no matching refs are found"), 2), OPT_BOOL(0, "symref", &show_symref_target, N_("show underlying ref in addition to the object pointed by it")), OPT_END() }; argc = parse_options(argc, argv, prefix, options, ls_remote_usage, PARSE_OPT_STOP_AT_NON_OPTION); dest = argv[0]; if (argc > 1) { int i; pattern = xcalloc(argc, sizeof(const char *)); for (i = 1; i < argc; i++) pattern[i - 1] = xstrfmt("*/%s", argv[i]); } remote = remote_get(dest); if (!remote) { if (dest) die("bad repository '%s'", dest); die("No remote configured to list refs from."); } if (!remote->url_nr) die("remote %s has no configured URL", dest); if (get_url) { printf("%s\n", *remote->url); return 0; } transport = transport_get(remote, NULL); if (uploadpack != NULL) transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); ref = transport_get_remote_refs(transport); if (transport_disconnect(transport)) return 1; if (!dest && !quiet) fprintf(stderr, "From %s\n", *remote->url); for ( ; ref; ref = ref->next) { if (!check_ref_type(ref, flags)) continue; if (!tail_match(pattern, ref->name)) continue; if (show_symref_target && ref->symref) printf("ref: %s\t%s\n", ref->symref, ref->name); printf("%s\t%s\n", oid_to_hex(&ref->old_oid), ref->name); status = 0; /* we found something */ } return status; }
int cmd_update_index(int argc, const char **argv, const char *prefix) { int newfd, entries, has_errors = 0, line_termination = '\n'; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; int preferred_index_format = 0; char set_executable_bit = 0; struct refresh_params refresh_args = {0, &has_errors}; int lock_error = 0; int split_index = -1; struct lock_file *lock_file; struct parse_opt_ctx_t ctx; int parseopt_state = PARSE_OPT_UNKNOWN; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, N_("continue refresh even when index needs update"), REFRESH_QUIET), OPT_BIT(0, "ignore-submodules", &refresh_args.flags, N_("refresh: ignore submodules"), REFRESH_IGNORE_SUBMODULES), OPT_SET_INT(0, "add", &allow_add, N_("do not ignore new files"), 1), OPT_SET_INT(0, "replace", &allow_replace, N_("let files replace directories and vice-versa"), 1), OPT_SET_INT(0, "remove", &allow_remove, N_("notice files missing from worktree"), 1), OPT_BIT(0, "unmerged", &refresh_args.flags, N_("refresh even if index contains unmerged entries"), REFRESH_UNMERGED), {OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL, N_("refresh stat information"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, refresh_callback}, {OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL, N_("like --refresh, but ignore assume-unchanged setting"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, really_refresh_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, N_("<mode>,<object>,<path>"), N_("add the specified entry to the index"), PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, (parse_opt_cb *) cacheinfo_callback}, {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"), N_("override the executable bit of the listed files"), PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, chmod_callback}, {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, N_("mark files as \"not changing\""), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, N_("clear assumed-unchanged bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, N_("mark files as \"index-only\""), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, N_("clear skip-worktree bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, OPT_SET_INT(0, "info-only", &info_only, N_("add to index only; do not add content to object database"), 1), OPT_SET_INT(0, "force-remove", &force_remove, N_("remove named paths even if present in worktree"), 1), OPT_SET_INT('z', NULL, &line_termination, N_("with --stdin: input lines are terminated by null bytes"), '\0'), {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, N_("read list of paths to be updated from standard input"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL, N_("add entries from standard input to the index"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_cacheinfo_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, N_("repopulate stages #2 and #3 for the listed paths"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) unresolve_callback}, {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, N_("only update entries that differ from HEAD"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) reupdate_callback}, OPT_BIT(0, "ignore-missing", &refresh_args.flags, N_("ignore files missing from worktree"), REFRESH_IGNORE_MISSING), OPT_SET_INT(0, "verbose", &verbose, N_("report actions to standard output"), 1), {OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL, N_("(for porcelains) forget saved unresolved conflicts"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, resolve_undo_clear_callback}, OPT_INTEGER(0, "index-version", &preferred_index_format, N_("write index in this format")), OPT_BOOL(0, "split-index", &split_index, N_("enable or disable split index")), OPT_END() }; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(update_index_usage, options); git_config(git_default_config, NULL); /* We can't free this memory, it becomes part of a linked list parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 0); if (newfd < 0) lock_error = errno; entries = read_cache(); if (entries < 0) die("cache corrupted"); /* * Custom copy of parse_options() because we want to handle * filename arguments as they come. */ parse_options_start(&ctx, argc, argv, prefix, options, PARSE_OPT_STOP_AT_NON_OPTION); while (ctx.argc) { if (parseopt_state != PARSE_OPT_DONE) parseopt_state = parse_options_step(&ctx, options, update_index_usage); if (!ctx.argc) break; switch (parseopt_state) { case PARSE_OPT_HELP: exit(129); case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: { const char *path = ctx.argv[0]; const char *p; setup_work_tree(); p = prefix_path(prefix, prefix_length, path); update_one(p); if (set_executable_bit) chmod_path(set_executable_bit, p); free((char *)p); ctx.argc--; ctx.argv++; break; } case PARSE_OPT_UNKNOWN: if (ctx.argv[0][1] == '-') error("unknown option '%s'", ctx.argv[0] + 2); else error("unknown switch '%c'", *ctx.opt); usage_with_options(update_index_usage, options); } } argc = parse_options_end(&ctx); if (preferred_index_format) { if (preferred_index_format < INDEX_FORMAT_LB || INDEX_FORMAT_UB < preferred_index_format) die("index-version %d not in range: %d..%d", preferred_index_format, INDEX_FORMAT_LB, INDEX_FORMAT_UB); if (the_index.version != preferred_index_format) active_cache_changed |= SOMETHING_CHANGED; the_index.version = preferred_index_format; } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; setup_work_tree(); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; if (line_termination && buf.buf[0] == '"') { strbuf_reset(&nbuf); if (unquote_c_style(&nbuf, buf.buf, NULL)) die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } p = prefix_path(prefix, prefix_length, buf.buf); update_one(p); if (set_executable_bit) chmod_path(set_executable_bit, p); free((char *)p); } strbuf_release(&nbuf); strbuf_release(&buf); } if (split_index > 0) { init_split_index(&the_index); the_index.cache_changed |= SPLIT_INDEX_ORDERED; } else if (!split_index && the_index.split_index) { /* * can't discard_split_index(&the_index); because that * will destroy split_index->base->cache[], which may * be shared with the_index.cache[]. So yeah we're * leaking a bit here. */ the_index.split_index = NULL; the_index.cache_changed |= SOMETHING_CHANGED; } if (active_cache_changed) { if (newfd < 0) { if (refresh_args.flags & REFRESH_QUIET) exit(128); unable_to_lock_die(get_index_file(), lock_error); } if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die("Unable to write new index file"); } rollback_lock_file(lock_file); return has_errors ? 1 : 0; }
int cmd_for_each_ref(int argc, const char **argv, const char *prefix) { int i; const char *format = "%(objectname) %(objecttype)\t%(refname)"; struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; int maxcount = 0, quote_style = 0; struct ref_array array; struct ref_filter filter; struct option opts[] = { OPT_BIT('s', "shell", "e_style, N_("quote placeholders suitably for shells"), QUOTE_SHELL), OPT_BIT('p', "perl", "e_style, N_("quote placeholders suitably for perl"), QUOTE_PERL), OPT_BIT(0 , "python", "e_style, N_("quote placeholders suitably for python"), QUOTE_PYTHON), OPT_BIT(0 , "tcl", "e_style, N_("quote placeholders suitably for Tcl"), QUOTE_TCL), OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), N_("field name to sort on"), &parse_opt_ref_sorting), OPT_CALLBACK(0, "points-at", &filter.points_at, N_("object"), N_("print only refs which points at the given object"), parse_opt_object_name), OPT_MERGED(&filter, N_("print only refs that are merged")), OPT_NO_MERGED(&filter, N_("print only refs that are not merged")), OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")), OPT_END(), }; memset(&array, 0, sizeof(array)); memset(&filter, 0, sizeof(filter)); parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0); if (maxcount < 0) { error("invalid --count argument: `%d'", maxcount); usage_with_options(for_each_ref_usage, opts); } if (HAS_MULTI_BITS(quote_style)) { error("more than one quoting style?"); usage_with_options(for_each_ref_usage, opts); } if (verify_ref_format(format)) usage_with_options(for_each_ref_usage, opts); if (!sorting) sorting = ref_default_sorting(); /* for warn_ambiguous_refs */ git_config(git_default_config, NULL); filter.name_patterns = argv; filter.match_as_path = 1; filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN); ref_array_sort(sorting, &array); if (!maxcount || array.nr < maxcount) maxcount = array.nr; for (i = 0; i < maxcount; i++) show_ref_array_item(array.items[i], format, quote_style); ref_array_clear(&array); return 0; }
#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) #define TYPE_PATH (1<<3) 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_BOOLEAN(0, "local", &use_local_config, "use repository 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_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL), OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
int cmd_ls_remote(int argc, const char **argv, const char *prefix) { const char *dest = NULL; unsigned flags = 0; int get_url = 0; int quiet = 0; int status = 0; int show_symref_target = 0; const char *uploadpack = NULL; const char **pattern = NULL; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; int i; struct remote *remote; struct transport *transport; const struct ref *ref; struct ref_array ref_array; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; struct option options[] = { OPT__QUIET(&quiet, N_("do not print remote URL")), OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"), N_("path of git-upload-pack on the remote host")), { OPTION_STRING, 0, "exec", &uploadpack, N_("exec"), N_("path of git-upload-pack on the remote host"), PARSE_OPT_HIDDEN }, OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS), OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS), OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL), OPT_BOOL(0, "get-url", &get_url, N_("take url.<base>.insteadOf into account")), OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), N_("field name to sort on"), &parse_opt_ref_sorting), OPT_SET_INT_F(0, "exit-code", &status, N_("exit with exit code 2 if no matching refs are found"), 2, PARSE_OPT_NOCOMPLETE), OPT_BOOL(0, "symref", &show_symref_target, N_("show underlying ref in addition to the object pointed by it")), OPT_END() }; memset(&ref_array, 0, sizeof(ref_array)); argc = parse_options(argc, argv, prefix, options, ls_remote_usage, PARSE_OPT_STOP_AT_NON_OPTION); dest = argv[0]; if (argc > 1) { int i; pattern = xcalloc(argc, sizeof(const char *)); for (i = 1; i < argc; i++) { const char *glob; pattern[i - 1] = xstrfmt("*/%s", argv[i]); glob = strchr(argv[i], '*'); if (glob) argv_array_pushf(&ref_prefixes, "%.*s", (int)(glob - argv[i]), argv[i]); else expand_ref_prefix(&ref_prefixes, argv[i]); } } remote = remote_get(dest); if (!remote) { if (dest) die("bad repository '%s'", dest); die("No remote configured to list refs from."); } if (!remote->url_nr) die("remote %s has no configured URL", dest); if (get_url) { printf("%s\n", *remote->url); UNLEAK(sorting); return 0; } transport = transport_get(remote, NULL); if (uploadpack != NULL) transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); ref = transport_get_remote_refs(transport, &ref_prefixes); if (transport_disconnect(transport)) { UNLEAK(sorting); return 1; } if (!dest && !quiet) fprintf(stderr, "From %s\n", *remote->url); for ( ; ref; ref = ref->next) { struct ref_array_item *item; if (!check_ref_type(ref, flags)) continue; if (!tail_match(pattern, ref->name)) continue; item = ref_array_push(&ref_array, ref->name, &ref->old_oid); item->symref = xstrdup_or_null(ref->symref); } if (sorting) ref_array_sort(sorting, &ref_array); for (i = 0; i < ref_array.nr; i++) { const struct ref_array_item *ref = ref_array.items[i]; if (show_symref_target && ref->symref) printf("ref: %s\t%s\n", ref->symref, ref->refname); printf("%s\t%s\n", oid_to_hex(&ref->objectname), ref->refname); status = 0; /* we found something */ } UNLEAK(sorting); UNLEAK(ref_array); return status; }
int cmd_update_index(int argc, const char **argv, const char *prefix) { int newfd, entries, has_errors = 0, nul_term_line = 0; enum uc_mode untracked_cache = UC_UNSPECIFIED; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; int preferred_index_format = 0; char set_executable_bit = 0; struct refresh_params refresh_args = {0, &has_errors}; int lock_error = 0; int split_index = -1; int force_write = 0; int fsmonitor = -1; struct lock_file lock_file = LOCK_INIT; struct parse_opt_ctx_t ctx; strbuf_getline_fn getline_fn; int parseopt_state = PARSE_OPT_UNKNOWN; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, N_("continue refresh even when index needs update"), REFRESH_QUIET), OPT_BIT(0, "ignore-submodules", &refresh_args.flags, N_("refresh: ignore submodules"), REFRESH_IGNORE_SUBMODULES), OPT_SET_INT(0, "add", &allow_add, N_("do not ignore new files"), 1), OPT_SET_INT(0, "replace", &allow_replace, N_("let files replace directories and vice-versa"), 1), OPT_SET_INT(0, "remove", &allow_remove, N_("notice files missing from worktree"), 1), OPT_BIT(0, "unmerged", &refresh_args.flags, N_("refresh even if index contains unmerged entries"), REFRESH_UNMERGED), {OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL, N_("refresh stat information"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, refresh_callback}, {OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL, N_("like --refresh, but ignore assume-unchanged setting"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, really_refresh_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, N_("<mode>,<object>,<path>"), N_("add the specified entry to the index"), PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, (parse_opt_cb *) cacheinfo_callback}, {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x", N_("override the executable bit of the listed files"), PARSE_OPT_NONEG, chmod_callback}, {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, N_("mark files as \"not changing\""), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, N_("clear assumed-unchanged bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, N_("mark files as \"index-only\""), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, N_("clear skip-worktree bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, OPT_SET_INT(0, "info-only", &info_only, N_("add to index only; do not add content to object database"), 1), OPT_SET_INT(0, "force-remove", &force_remove, N_("remove named paths even if present in worktree"), 1), OPT_BOOL('z', NULL, &nul_term_line, N_("with --stdin: input lines are terminated by null bytes")), {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, N_("read list of paths to be updated from standard input"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL, N_("add entries from standard input to the index"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_cacheinfo_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, N_("repopulate stages #2 and #3 for the listed paths"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) unresolve_callback}, {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, N_("only update entries that differ from HEAD"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) reupdate_callback}, OPT_BIT(0, "ignore-missing", &refresh_args.flags, N_("ignore files missing from worktree"), REFRESH_IGNORE_MISSING), OPT_SET_INT(0, "verbose", &verbose, N_("report actions to standard output"), 1), {OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL, N_("(for porcelains) forget saved unresolved conflicts"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, resolve_undo_clear_callback}, OPT_INTEGER(0, "index-version", &preferred_index_format, N_("write index in this format")), OPT_BOOL(0, "split-index", &split_index, N_("enable or disable split index")), OPT_BOOL(0, "untracked-cache", &untracked_cache, N_("enable/disable untracked cache")), OPT_SET_INT(0, "test-untracked-cache", &untracked_cache, N_("test if the filesystem supports untracked cache"), UC_TEST), OPT_SET_INT(0, "force-untracked-cache", &untracked_cache, N_("enable untracked cache without testing the filesystem"), UC_FORCE), OPT_SET_INT(0, "force-write-index", &force_write, N_("write out the index even if is not flagged as changed"), 1), OPT_BOOL(0, "fsmonitor", &fsmonitor, N_("enable or disable file system monitor")), {OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL, N_("mark files as fsmonitor valid"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL, N_("clear fsmonitor valid bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, OPT_END() }; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(update_index_usage, options); git_config(git_default_config, NULL); /* we will diagnose later if it turns out that we need to update it */ newfd = hold_locked_index(&lock_file, 0); if (newfd < 0) lock_error = errno; entries = read_cache(); if (entries < 0) die("cache corrupted"); /* * Custom copy of parse_options() because we want to handle * filename arguments as they come. */ parse_options_start(&ctx, argc, argv, prefix, options, PARSE_OPT_STOP_AT_NON_OPTION); while (ctx.argc) { if (parseopt_state != PARSE_OPT_DONE) parseopt_state = parse_options_step(&ctx, options, update_index_usage); if (!ctx.argc) break; switch (parseopt_state) { case PARSE_OPT_HELP: case PARSE_OPT_ERROR: exit(129); case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: { const char *path = ctx.argv[0]; char *p; setup_work_tree(); p = prefix_path(prefix, prefix_length, path); update_one(p); if (set_executable_bit) chmod_path(set_executable_bit, p); free(p); ctx.argc--; ctx.argv++; break; } case PARSE_OPT_UNKNOWN: if (ctx.argv[0][1] == '-') error("unknown option '%s'", ctx.argv[0] + 2); else error("unknown switch '%c'", *ctx.opt); usage_with_options(update_index_usage, options); } } argc = parse_options_end(&ctx); getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; if (preferred_index_format) { if (preferred_index_format < INDEX_FORMAT_LB || INDEX_FORMAT_UB < preferred_index_format) die("index-version %d not in range: %d..%d", preferred_index_format, INDEX_FORMAT_LB, INDEX_FORMAT_UB); if (the_index.version != preferred_index_format) active_cache_changed |= SOMETHING_CHANGED; the_index.version = preferred_index_format; } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT; struct strbuf unquoted = STRBUF_INIT; setup_work_tree(); while (getline_fn(&buf, stdin) != EOF) { char *p; if (!nul_term_line && buf.buf[0] == '"') { strbuf_reset(&unquoted); if (unquote_c_style(&unquoted, buf.buf, NULL)) die("line is badly quoted"); strbuf_swap(&buf, &unquoted); } p = prefix_path(prefix, prefix_length, buf.buf); update_one(p); if (set_executable_bit) chmod_path(set_executable_bit, p); free(p); } strbuf_release(&unquoted); strbuf_release(&buf); } if (split_index > 0) { if (git_config_get_split_index() == 0) warning(_("core.splitIndex is set to false; " "remove or change it, if you really want to " "enable split index")); if (the_index.split_index) the_index.cache_changed |= SPLIT_INDEX_ORDERED; else add_split_index(&the_index); } else if (!split_index) { if (git_config_get_split_index() == 1) warning(_("core.splitIndex is set to true; " "remove or change it, if you really want to " "disable split index")); remove_split_index(&the_index); } switch (untracked_cache) { case UC_UNSPECIFIED: break; case UC_DISABLE: if (git_config_get_untracked_cache() == 1) warning(_("core.untrackedCache is set to true; " "remove or change it, if you really want to " "disable the untracked cache")); remove_untracked_cache(&the_index); report(_("Untracked cache disabled")); break; case UC_TEST: setup_work_tree(); return !test_if_untracked_cache_is_supported(); case UC_ENABLE: case UC_FORCE: if (git_config_get_untracked_cache() == 0) warning(_("core.untrackedCache is set to false; " "remove or change it, if you really want to " "enable the untracked cache")); add_untracked_cache(&the_index); report(_("Untracked cache enabled for '%s'"), get_git_work_tree()); break; default: BUG("bad untracked_cache value: %d", untracked_cache); } if (fsmonitor > 0) { if (git_config_get_fsmonitor() == 0) warning(_("core.fsmonitor is unset; " "set it if you really want to " "enable fsmonitor")); add_fsmonitor(&the_index); report(_("fsmonitor enabled")); } else if (!fsmonitor) { if (git_config_get_fsmonitor() == 1) warning(_("core.fsmonitor is set; " "remove it if you really want to " "disable fsmonitor")); remove_fsmonitor(&the_index); report(_("fsmonitor disabled")); } if (active_cache_changed || force_write) { if (newfd < 0) { if (refresh_args.flags & REFRESH_QUIET) exit(128); unable_to_lock_die(get_index_file(), lock_error); } if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die("Unable to write new index file"); } rollback_lock_file(&lock_file); return has_errors ? 1 : 0; }
/* * If you want to, you can share the DB area with any number of branches. * That has advantages: you can save space by sharing all the SHA1 objects. * On the other hand, it might just make lookup slower and messier. You * be the judge. The default case is to have one DB per managed directory. */ int cmd_init_db(int argc, const char **argv, const char *prefix) { const char *git_dir; const char *real_git_dir = NULL; const char *work_tree; const char *template_dir = NULL; unsigned int flags = 0; const struct option init_db_options[] = { OPT_STRING(0, "template", &template_dir, N_("template-directory"), N_("directory from which templates will be used")), OPT_SET_INT(0, "bare", &is_bare_repository_cfg, N_("create a bare repository"), 1), { OPTION_CALLBACK, 0, "shared", &init_shared_repository, N_("permissions"), N_("specify that the git repository is to be shared amongst several users"), PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0}, OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), N_("separate git dir from working tree")), OPT_END() }; argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0); if (real_git_dir && !is_absolute_path(real_git_dir)) real_git_dir = real_pathdup(real_git_dir, 1); if (argc == 1) { int mkdir_tried = 0; retry: if (chdir(argv[0]) < 0) { if (!mkdir_tried) { int saved; /* * At this point we haven't read any configuration, * and we know shared_repository should always be 0; * but just in case we play safe. */ saved = get_shared_repository(); set_shared_repository(0); switch (safe_create_leading_directories_const(argv[0])) { case SCLD_OK: case SCLD_PERMS: break; case SCLD_EXISTS: errno = EEXIST; /* fallthru */ default: die_errno(_("cannot mkdir %s"), argv[0]); break; } set_shared_repository(saved); if (mkdir(argv[0], 0777) < 0) die_errno(_("cannot mkdir %s"), argv[0]); mkdir_tried = 1; goto retry; } die_errno(_("cannot chdir to %s"), argv[0]); } } else if (0 < argc) { usage(init_db_usage[0]); } if (is_bare_repository_cfg == 1) { char *cwd = xgetcwd(); setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0); free(cwd); } if (init_shared_repository != -1) set_shared_repository(init_shared_repository); /* * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR * without --bare. Catch the error early. */ git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT)); work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT)); if ((!git_dir || is_bare_repository_cfg == 1) && work_tree) die(_("%s (or --work-tree=<directory>) not allowed without " "specifying %s (or --git-dir=<directory>)"), GIT_WORK_TREE_ENVIRONMENT, GIT_DIR_ENVIRONMENT); /* * Set up the default .git directory contents */ if (!git_dir) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; if (is_bare_repository_cfg < 0) is_bare_repository_cfg = guess_repository_type(git_dir); if (!is_bare_repository_cfg) { const char *git_dir_parent = strrchr(git_dir, '/'); if (git_dir_parent) { char *rel = xstrndup(git_dir, git_dir_parent - git_dir); git_work_tree_cfg = real_pathdup(rel, 1); free(rel); } if (!git_work_tree_cfg) git_work_tree_cfg = xgetcwd(); if (work_tree) set_git_work_tree(work_tree); else set_git_work_tree(git_work_tree_cfg); if (access(get_git_work_tree(), X_OK)) die_errno (_("Cannot access work tree '%s'"), get_git_work_tree()); } else { if (work_tree) set_git_work_tree(work_tree); } UNLEAK(real_git_dir); UNLEAK(git_dir); UNLEAK(work_tree); flags |= INIT_DB_EXIST_OK; return init_db(git_dir, real_git_dir, template_dir, flags); }
int cmd_push(int argc, const char **argv, const char *prefix) { int flags = 0; int tags = 0; int push_cert = -1; int rc; const char *repo = NULL; /* default repository */ struct option options[] = { OPT__VERBOSITY(&verbosity), OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")), OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL), OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"), (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), OPT_BOOL( 0, "delete", &deleterefs, N_("delete refs")), OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")), OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN), OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN), OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), { OPTION_CALLBACK, 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"), N_("require old value of ref to be at this value"), PARSE_OPT_OPTARG, parseopt_push_cas_option }, { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "check|on-demand|no", N_("control recursive pushing of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOL( 0 , "thin", &thin, N_("use thin pack")), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")), OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"), TRANSPORT_PUSH_SET_UPSTREAM), OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"), TRANSPORT_PUSH_PRUNE), OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK), OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"), TRANSPORT_PUSH_FOLLOW_TAGS), { OPTION_CALLBACK, 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC), OPT_END() }; packet_trace_identity("push"); git_config(git_push_config, &flags); argc = parse_options(argc, argv, prefix, options, push_usage, 0); set_push_cert_flags(&flags, push_cert); if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR)))) die(_("--delete is incompatible with --all, --mirror and --tags")); if (deleterefs && argc < 2) die(_("--delete doesn't make sense without any refs")); if (recurse_submodules == RECURSE_SUBMODULES_CHECK) flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK; else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND; if (tags) add_refspec("refs/tags/*"); if (argc > 0) { repo = argv[0]; set_refspecs(argv + 1, argc - 1, repo); } rc = do_push(repo, flags); if (rc == -1) usage_with_options(push_usage, options); else return rc; }
int cmd_push(int argc, const char **argv, const char *prefix) { int flags = 0; int tags = 0; int push_cert = -1; int rc; const char *repo = NULL; /* default repository */ struct string_list push_options_cmdline = STRING_LIST_INIT_DUP; struct string_list *push_options; const struct string_list_item *item; struct option options[] = { OPT__VERBOSITY(&verbosity), OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")), OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL), OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"), (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")), OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")), OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN), OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN), OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), { OPTION_CALLBACK, 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), N_("require old value of ref to be at this value"), PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option }, { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", N_("control recursive pushing of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")), OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"), TRANSPORT_PUSH_SET_UPSTREAM), OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"), TRANSPORT_PUSH_PRUNE), OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK), OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"), TRANSPORT_PUSH_FOLLOW_TAGS), { OPTION_CALLBACK, 0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC), OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")), OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), TRANSPORT_FAMILY_IPV4), OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), TRANSPORT_FAMILY_IPV6), OPT_END() }; packet_trace_identity("push"); git_config(git_push_config, &flags); argc = parse_options(argc, argv, prefix, options, push_usage, 0); push_options = (push_options_cmdline.nr ? &push_options_cmdline : &push_options_config); set_push_cert_flags(&flags, push_cert); if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR)))) die(_("--delete is incompatible with --all, --mirror and --tags")); if (deleterefs && argc < 2) die(_("--delete doesn't make sense without any refs")); if (flags & TRANSPORT_PUSH_ALL) { if (tags) die(_("--all and --tags are incompatible")); if (argc >= 2) die(_("--all can't be combined with refspecs")); } if (flags & TRANSPORT_PUSH_MIRROR) { if (tags) die(_("--mirror and --tags are incompatible")); if (argc >= 2) die(_("--mirror can't be combined with refspecs")); } if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR)) die(_("--all and --mirror are incompatible")); if (recurse_submodules == RECURSE_SUBMODULES_CHECK) flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK; else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND; else if (recurse_submodules == RECURSE_SUBMODULES_ONLY) flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY; if (tags) refspec_append(&rs, "refs/tags/*"); if (argc > 0) { repo = argv[0]; set_refspecs(argv + 1, argc - 1, repo); } for_each_string_list_item(item, push_options) if (strchr(item->string, '\n')) die(_("push options must not have new line characters")); rc = do_push(repo, flags, push_options); string_list_clear(&push_options_cmdline, 0); string_list_clear(&push_options_config, 0); if (rc == -1) usage_with_options(push_usage, options); else return rc; }
int cmd_ls_files(int argc, const char **argv, const char *prefix) { 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_NEGBIT(0, "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"), OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo, "show resolve-undo information"), { 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 <file>", 0, option_parse_exclude_from }, OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file", "read additional per-directory exclude patterns in <file>"), { 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 <file> is not in the index, treat this as an error"), OPT_STRING(0, "with-tree", &with_tree, "tree-ish", "pretend that paths removed since <tree-ish> 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); if (read_cache() < 0) die("index file corrupt"); argc = parse_options(argc, argv, prefix, 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 "; tag_skip_worktree = "S "; tag_resolve_undo = "U "; } if (show_modified || show_others || show_deleted || (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); /* be nice with submodule paths ending in a slash */ if (pathspec) strip_trailing_slash_from_submodules(); /* Verify that the pathspec matches the prefix */ if (pathspec) prefix = verify_pathspec(prefix); /* Treat unmatching pathspec elements as errors */ if (pathspec && error_unmatch) { int num; for (num = 0; pathspec[num]; num++) ; ps_matched = xcalloc(1, num); } if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) die("ls-files --ignored needs some exclude pattern"); /* With no flags, we default to showing the cached files */ if (!(show_stage | show_deleted | show_others | show_unmerged | show_killed | show_modified | show_resolve_undo)) show_cached = 1; if (prefix) prune_cache(prefix); if (with_tree) { /* * Basic sanity check; show-stages and show-unmerged * would not make any sense with this option. */ if (show_stage || show_unmerged) die("ls-files --with-tree is incompatible with -s or -u"); overlay_tree_on_cache(with_tree, prefix); } show_files(&dir, prefix); if (show_resolve_undo) show_ru_info(prefix); if (ps_matched) { int bad; bad = report_path_error(ps_matched, pathspec, prefix_offset); if (bad) fprintf(stderr, "Did you forget to 'git add'?\n"); return bad ? 1 : 0; } return 0; }
int cmd_gidit(int argc, const char **argv, const char *prefix) { int flags = 0; int init = 0, verbose = 0, pushobj = 0, updatepl = 0, sign = 0, proj_init = 0, polist = 0, store_bundle = 0, get_bundle = 0, pobj_val = 0, create_bundle = 0, push = 0, verify_polist = 0, list_missing = 0; const char *basepath = NULL; const char *keyid = NULL; const char *projname = NULL; char * url = NULL; char *nodekey = NULL; char *message = NULL; int rc; struct option options[] = { OPT__VERBOSE(&verbose), OPT_GROUP(""), OPT_BIT( 0 , "tags", &flags, "include tags", INCLUDE_TAGS), OPT_BIT( 0 , "force", &flags, "force", TRANSPORT_PUSH_FORCE), OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"), OPT_STRING('u', NULL, &keyid, "key-id", "use another key to sign the tag"), OPT_BOOLEAN( 0 , "pushobj", &pushobj, "generate push object"), OPT_STRING('k',NULL, &nodekey, "nodekey", "key of node"), OPT_STRING('m',NULL, &message, "message", "message to send"), OPT_STRING('p',NULL, &projname, "project-name", "Project name"), OPT_BOOLEAN( 0 , "verify-pobj", &pobj_val, "validate a given pushobject"), OPT_BOOLEAN( 0 , "verify-polist", &verify_polist, "verify given polist as all known"), OPT_BOOLEAN( 0 , "list-missing", &list_missing, "List sha1's of missing pushobjs"), OPT_BOOLEAN( 0 , "push", &push, "Do a push over gidit"), OPT_BOOLEAN( 0 , "create-bundle", &create_bundle, "validate a given pushobject"), OPT_GROUP(""), OPT_BOOLEAN( 0 , "updatepl", &updatepl, "Update push list"), OPT_STRING('b', NULL, &basepath, "base-path", "base-path for daemon"), OPT_BOOLEAN( 0 , "init", &init, "init gidit directory"), OPT_BOOLEAN( 0 , "proj-init", &proj_init, "init user's gidit project directory"), OPT_BOOLEAN( 0 , "polist", &polist, "Generate list of push objects"), OPT_BOOLEAN( 0 , "store-bundle", &store_bundle, "store a given bundle"), OPT_BOOLEAN( 0 , "get-bundle", &get_bundle, "get a bundle"), OPT_END() }; git_config(git_gidit_config, NULL); argc = parse_options(argc, argv, options, gidit_usage, 0); if (push) sign = 1; if (keyid) { sign = 1; set_signingkey(keyid); } else if (sign) { set_default_signingkey(); } if (sign) flags |= SIGN; if (pushobj) return !!gidit_pushobj(stdout, signingkey, flags); else if (pobj_val) return !!gidit_verify_pushobj(stdin, flags); else if (pushobj) return !!gidit_pushobj(stdout, signingkey, flags); else if (create_bundle) return !!gidit_gen_bundle(stdin, flags); else if (verify_polist) return !!gidit_verify_pushobj_list(stdin); else if (list_missing) return !!gidit_missing_pushobjs(stdin); else if (push) { url = (char*)malloc(strlen("gidit://127.0.0.1:9418/") + strlen(projname) + 1 + strlen(signingkey) + 1); sprintf(url, "gidit://127.0.0.1:9418/%s:%s", projname, signingkey); return !!gidit_push(url, 0, NULL, flags); } if (!basepath) usage_with_options(gidit_usage, options); if (base_path_test(basepath)) return -1; if (init) rc = gidit_init(basepath); else if (proj_init) rc = gidit_proj_init_stream(stdin, basepath, flags); else if (updatepl) rc = gidit_update_pl(stdin, basepath, flags); else if (polist) rc = gidit_po_list_stream(stdin, basepath, flags); else if (store_bundle) rc = gidit_store_bundle_stream(stdin, basepath, flags); else if (get_bundle) rc = gidit_get_bundle(stdin, stdout, basepath, flags); else rc = -1; if (rc == -1) usage_with_options(gidit_usage, options); else return rc; }
int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; int i; int dummy; int nongit = 0, use_index = 1; struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, "search in index instead of in the work tree"), OPT_BOOLEAN(0, "index", &use_index, "--no-index finds in contents not managed by git"), OPT_GROUP(""), OPT_BOOLEAN('v', "invert-match", &opt.invert, "show non-matching lines"), OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case, "case insensitive matching"), OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp, "match patterns only at word boundaries"), OPT_SET_INT('a', "text", &opt.binary, "process binary files as text", GREP_BINARY_TEXT), OPT_SET_INT('I', NULL, &opt.binary, "don't match patterns in binary files", GREP_BINARY_NOMATCH), { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth", "descend at most <depth> levels", PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), OPT_BIT('E', "extended-regexp", &opt.regflags, "use extended POSIX regular expressions", REG_EXTENDED), OPT_NEGBIT('G', "basic-regexp", &opt.regflags, "use basic POSIX regular expressions (default)", REG_EXTENDED), OPT_BOOLEAN('F', "fixed-strings", &opt.fixed, "interpret patterns as fixed strings"), OPT_GROUP(""), OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"), OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1), OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1), OPT_NEGBIT(0, "full-name", &opt.relative, "show filenames relative to top directory", 1), OPT_BOOLEAN('l', "files-with-matches", &opt.name_only, "show only filenames instead of matching lines"), OPT_BOOLEAN(0, "name-only", &opt.name_only, "synonym for --files-with-matches"), OPT_BOOLEAN('L', "files-without-match", &opt.unmatch_name_only, "show only the names of files without match"), OPT_BOOLEAN('z', "null", &opt.null_following_name, "print NUL after filenames"), OPT_BOOLEAN('c', "count", &opt.count, "show the number of matches instead of matching lines"), OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1), OPT_GROUP(""), OPT_CALLBACK('C', NULL, &opt, "n", "show <n> context lines before and after matches", context_callback), OPT_INTEGER('B', NULL, &opt.pre_context, "show <n> context lines before matches"), OPT_INTEGER('A', NULL, &opt.post_context, "show <n> context lines after matches"), OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", context_callback), OPT_BOOLEAN('p', "show-function", &opt.funcname, "show a line with the function name before matches"), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, "file", "read patterns from file", file_callback), { OPTION_CALLBACK, 'e', NULL, &opt, "pattern", "match <pattern>", PARSE_OPT_NONEG, pattern_callback }, { OPTION_CALLBACK, 0, "and", &opt, NULL, "combine patterns specified with -e", PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, OPT_BOOLEAN(0, "or", &dummy, ""), { OPTION_CALLBACK, 0, "not", &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback }, { OPTION_CALLBACK, '(', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, open_callback }, { OPTION_CALLBACK, ')', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, close_callback }, OPT_BOOLEAN('q', "quiet", &opt.status_only, "indicate hit with exit status without output"), OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; prefix = setup_git_directory_gently(&nongit); /* * 'git grep -h', unlike 'git grep -h <pattern>', is a request * to show usage information and exit. */ if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(grep_usage, options); memset(&opt, 0, sizeof(opt)); opt.prefix = prefix; opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; opt.relative = 1; opt.pathname = 1; opt.pattern_tail = &opt.pattern_list; opt.regflags = REG_NEWLINE; opt.max_depth = -1; strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD); opt.color = -1; git_config(grep_config, &opt); if (opt.color == -1) opt.color = git_use_color_default; /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or * -f, we take the first unrecognized non option to be the * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ argc = parse_options(argc, argv, prefix, options, grep_usage, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); if (use_index && nongit) /* die the same way as if we did it at the beginning */ setup_git_directory(); /* * skip a -- separator; we know it cannot be * separating revisions from pathnames if * we haven't even had any patterns yet */ if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) { argv++; argc--; } /* First unrecognized non-option token */ if (argc > 0 && !opt.pattern_list) { append_grep_pattern(&opt, argv[0], "command line", 0, GREP_PATTERN); argv++; argc--; } if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) opt.regflags |= REG_ICASE; if ((opt.regflags != REG_NEWLINE) && opt.fixed) die("cannot mix --fixed-strings and regexp"); #ifndef NO_PTHREADS if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; if (use_threads) start_threads(&opt); #else use_threads = 0; #endif compile_grep_patterns(&opt); /* Check revs and then paths */ for (i = 0; i < argc; i++) { const char *arg = argv[i]; unsigned char sha1[20]; /* Is it a rev? */ if (!get_sha1(arg, sha1)) { struct object *object = parse_object(sha1); if (!object) die("bad object %s", arg); add_object_array(object, arg, &list); continue; } if (!strcmp(arg, "--")) { i++; seen_dashdash = 1; } break; } /* The rest are paths */ if (!seen_dashdash) { int j; for (j = i; j < argc; j++) verify_filename(prefix, argv[j]); } if (i < argc) paths = get_pathspec(prefix, argv + i); else if (prefix) { paths = xcalloc(2, sizeof(const char *)); paths[0] = prefix; paths[1] = NULL; } if (!use_index) { int hit; if (cached) die("--cached cannot be used with --no-index."); if (list.nr) die("--no-index cannot be used with revs."); hit = grep_directory(&opt, paths); if (use_threads) hit |= wait_all(); return !hit; } if (!list.nr) { int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); if (use_threads) hit |= wait_all(); return !hit; } if (cached) die("both --cached and trees are given."); for (i = 0; i < list.nr; i++) { struct object *real_obj; real_obj = deref_tag(list.objects[i].item, NULL, 0); if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { hit = 1; if (opt.status_only) break; } } if (use_threads) hit |= wait_all(); free_grep_patterns(&opt); return !hit; }
int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0, untracked = 0, opt_exclude = -1; int seen_dashdash = 0; int external_grep_allowed__ignored; const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = OBJECT_ARRAY_INIT; struct pathspec pathspec; struct string_list path_list = STRING_LIST_INIT_NODUP; int i; int dummy; int use_index = 1; int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED; int allow_revs; struct option options[] = { OPT_BOOL(0, "cached", &cached, N_("search in index instead of in the work tree")), OPT_NEGBIT(0, "no-index", &use_index, N_("find in contents not managed by git"), 1), OPT_BOOL(0, "untracked", &untracked, N_("search in both tracked and untracked files")), OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("ignore files specified via '.gitignore'"), 1), OPT_BOOL(0, "recurse-submodules", &recurse_submodules, N_("recursively search in each submodule")), OPT_GROUP(""), OPT_BOOL('v', "invert-match", &opt.invert, N_("show non-matching lines")), OPT_BOOL('i', "ignore-case", &opt.ignore_case, N_("case insensitive matching")), OPT_BOOL('w', "word-regexp", &opt.word_regexp, N_("match patterns only at word boundaries")), OPT_SET_INT('a', "text", &opt.binary, N_("process binary files as text"), GREP_BINARY_TEXT), OPT_SET_INT('I', NULL, &opt.binary, N_("don't match patterns in binary files"), GREP_BINARY_NOMATCH), OPT_BOOL(0, "textconv", &opt.allow_textconv, N_("process binary files with textconv filters")), { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"), N_("descend at most <depth> levels"), PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), OPT_SET_INT('E', "extended-regexp", &pattern_type_arg, N_("use extended POSIX regular expressions"), GREP_PATTERN_TYPE_ERE), OPT_SET_INT('G', "basic-regexp", &pattern_type_arg, N_("use basic POSIX regular expressions (default)"), GREP_PATTERN_TYPE_BRE), OPT_SET_INT('F', "fixed-strings", &pattern_type_arg, N_("interpret patterns as fixed strings"), GREP_PATTERN_TYPE_FIXED), OPT_SET_INT('P', "perl-regexp", &pattern_type_arg, N_("use Perl-compatible regular expressions"), GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")), OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, N_("show filenames relative to top directory"), 1), OPT_BOOL('l', "files-with-matches", &opt.name_only, N_("show only filenames instead of matching lines")), OPT_BOOL(0, "name-only", &opt.name_only, N_("synonym for --files-with-matches")), OPT_BOOL('L', "files-without-match", &opt.unmatch_name_only, N_("show only the names of files without match")), OPT_BOOL('z', "null", &opt.null_following_name, N_("print NUL after filenames")), OPT_BOOL('c', "count", &opt.count, N_("show the number of matches instead of matching lines")), OPT__COLOR(&opt.color, N_("highlight matches")), OPT_BOOL(0, "break", &opt.file_break, N_("print empty line between matches from different files")), OPT_BOOL(0, "heading", &opt.heading, N_("show filename only once above matches from same file")), OPT_GROUP(""), OPT_CALLBACK('C', "context", &opt, N_("n"), N_("show <n> context lines before and after matches"), context_callback), OPT_INTEGER('B', "before-context", &opt.pre_context, N_("show <n> context lines before matches")), OPT_INTEGER('A', "after-context", &opt.post_context, N_("show <n> context lines after matches")), OPT_INTEGER(0, "threads", &num_threads, N_("use <n> worker threads")), OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"), context_callback), OPT_BOOL('p', "show-function", &opt.funcname, N_("show a line with the function name before matches")), OPT_BOOL('W', "function-context", &opt.funcbody, N_("show the surrounding function")), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, N_("file"), N_("read patterns from file"), file_callback), { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"), N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback }, { OPTION_CALLBACK, 0, "and", &opt, NULL, N_("combine patterns specified with -e"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, OPT_BOOL(0, "or", &dummy, ""), { OPTION_CALLBACK, 0, "not", &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback }, { OPTION_CALLBACK, '(', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, open_callback }, { OPTION_CALLBACK, ')', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, close_callback }, OPT__QUIET(&opt.status_only, N_("indicate hit with exit status without output")), OPT_BOOL(0, "all-match", &opt.all_match, N_("show only matches from files that match all patterns")), { OPTION_SET_INT, 0, "debug", &opt.debug, NULL, N_("show parse tree for grep expression"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 }, OPT_GROUP(""), { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, N_("pager"), N_("show matching files in the pager"), PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored, N_("allow calling of grep(1) (ignored by this build)")), OPT_END() }; init_grep_defaults(); git_config(grep_cmd_config, NULL); grep_init(&opt, prefix); /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or * -f, we take the first unrecognized non option to be the * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ argc = parse_options(argc, argv, prefix, options, grep_usage, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION); grep_commit_pattern_type(pattern_type_arg, &opt); if (use_index && !startup_info->have_repository) { int fallback = 0; git_config_get_bool("grep.fallbacktonoindex", &fallback); if (fallback) use_index = 0; else /* die the same way as if we did it at the beginning */ setup_git_directory(); } /* * skip a -- separator; we know it cannot be * separating revisions from pathnames if * we haven't even had any patterns yet */ if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) { argv++; argc--; } /* First unrecognized non-option token */ if (argc > 0 && !opt.pattern_list) { append_grep_pattern(&opt, argv[0], "command line", 0, GREP_PATTERN); argv++; argc--; } if (show_in_pager == default_pager) show_in_pager = git_pager(1); if (show_in_pager) { opt.color = 0; opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; string_list_append(&path_list, show_in_pager); } if (!opt.pattern_list) die(_("no pattern given.")); /* * We have to find "--" in a separate pass, because its presence * influences how we will parse arguments that come before it. */ for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "--")) { seen_dashdash = 1; break; } } /* * Resolve any rev arguments. If we have a dashdash, then everything up * to it must resolve as a rev. If not, then we stop at the first * non-rev and assume everything else is a path. */ allow_revs = use_index && !untracked; for (i = 0; i < argc; i++) { const char *arg = argv[i]; struct object_id oid; struct object_context oc; struct object *object; if (!strcmp(arg, "--")) { i++; break; } if (!allow_revs) { if (seen_dashdash) die(_("--no-index or --untracked cannot be used with revs")); break; } if (get_oid_with_context(arg, GET_OID_RECORD_PATH, &oid, &oc)) { if (seen_dashdash) die(_("unable to resolve revision: %s"), arg); break; } object = parse_object_or_die(&oid, arg); if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); free(oc.path); } /* * Anything left over is presumed to be a path. But in the non-dashdash * "do what I mean" case, we verify and complain when that isn't true. */ if (!seen_dashdash) { int j; for (j = i; j < argc; j++) verify_filename(prefix, argv[j], j == i && allow_revs); } parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD | (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0), prefix, argv + i); pathspec.max_depth = opt.max_depth; pathspec.recursive = 1; pathspec.recurse_submodules = !!recurse_submodules; #ifndef NO_PTHREADS if (list.nr || cached || show_in_pager) num_threads = 0; else if (num_threads == 0) num_threads = GREP_NUM_THREADS_DEFAULT; else if (num_threads < 0) die(_("invalid number of threads specified (%d)"), num_threads); if (num_threads == 1) num_threads = 0; #else if (num_threads) warning(_("no threads support, ignoring --threads")); num_threads = 0; #endif if (!num_threads) /* * The compiled patterns on the main path are only * used when not using threading. Otherwise * start_threads() below calls compile_grep_patterns() * for each thread. */ compile_grep_patterns(&opt); #ifndef NO_PTHREADS if (num_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) skip_first_line = 1; start_threads(&opt); } #endif if (show_in_pager && (cached || list.nr)) die(_("--open-files-in-pager only works on the worktree")); if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { const char *pager = path_list.items[0].string; int len = strlen(pager); if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-I"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", strcmp("less", pager) ? "" : "*", opt.pattern_list->pattern); string_list_append(&path_list, buf.buf); strbuf_detach(&buf, NULL); } } if (recurse_submodules && (!use_index || untracked)) die(_("option not supported with --recurse-submodules.")); if (!show_in_pager && !opt.status_only) setup_pager(); if (!use_index && (untracked || cached)) die(_("--cached or --untracked cannot be used with --no-index.")); if (!use_index || untracked) { int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; hit = grep_directory(&opt, &pathspec, use_exclude, use_index); } else if (0 <= opt_exclude) { die(_("--[no-]exclude-standard cannot be used for tracked contents.")); } else if (!list.nr) { if (!cached) setup_work_tree(); hit = grep_cache(&opt, the_repository, &pathspec, cached); } else { if (cached) die(_("both --cached and trees are given.")); hit = grep_objects(&opt, &pathspec, the_repository, &list); } if (num_threads) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); clear_pathspec(&pathspec); free_grep_patterns(&opt); return !hit; }
int main(int argc, char **argv) { const char *prefix = "prefix/"; const char *usage[] = { "test-parse-options <options>", NULL }; struct string_list expect = STRING_LIST_INIT_NODUP; struct option options[] = { OPT_BOOL(0, "yes", &boolean, "get a boolean"), OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"), { OPTION_SET_INT, 'B', "no-fear", &boolean, NULL, "be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, OPT_COUNTUP('b', "boolean", &boolean, "increment by one"), OPT_BIT('4', "or4", &boolean, "bitwise-or boolean with ...0100", 4), OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), OPT_GROUP(""), OPT_INTEGER('i', "integer", &integer, "get a integer"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"), OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"), OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), OPT_DATE('t', NULL, ×tamp, "get timestamp of <time>"), OPT_CALLBACK('L', "length", &integer, "str", "get length of <str>", length_callback), OPT_FILENAME('F', "file", &file, "set file to <file>"), OPT_GROUP("String options"), OPT_STRING('s', "string", &string, "string", "get a string"), OPT_STRING(0, "string2", &string, "str", "get another string"), OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"), OPT_STRING('o', NULL, &string, "str", "get another string"), OPT_NOOP_NOARG(0, "obsolete"), OPT_STRING_LIST(0, "list", &list, "str", "add str to list"), OPT_GROUP("Magic arguments"), OPT_ARGUMENT("quux", "means --quux"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", number_callback), { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, { OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL, "positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, { OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL, "negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, OPT_GROUP("Standard options"), OPT__ABBREV(&abbrev), OPT__VERBOSE(&verbose, "be verbose"), OPT__DRY_RUN(&dry_run, "dry run"), OPT__QUIET(&quiet, "be quiet"), OPT_CALLBACK(0, "expect", &expect, "string", "expected output in the variable dump", collect_expect), OPT_END(), }; int i; int ret = 0; argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0); if (length_cb.called) { const char *arg = length_cb.arg; int unset = length_cb.unset; show(&expect, &ret, "Callback: \"%s\", %d", (arg ? arg : "not set"), unset); } show(&expect, &ret, "boolean: %d", boolean); show(&expect, &ret, "integer: %d", integer); show(&expect, &ret, "magnitude: %lu", magnitude); show(&expect, &ret, "timestamp: %lu", timestamp); show(&expect, &ret, "string: %s", string ? string : "(not set)"); show(&expect, &ret, "abbrev: %d", abbrev); show(&expect, &ret, "verbose: %d", verbose); show(&expect, &ret, "quiet: %d", quiet); show(&expect, &ret, "dry run: %s", dry_run ? "yes" : "no"); show(&expect, &ret, "file: %s", file ? file : "(not set)"); for (i = 0; i < list.nr; i++) show(&expect, &ret, "list: %s", list.items[i].string); for (i = 0; i < argc; i++) show(&expect, &ret, "arg %02d: %s", i, argv[i]); return ret; }
int cmd_hash_object(int argc, const char **argv, const char *prefix) { static const char * const hash_object_usage[] = { N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."), N_("git hash-object --stdin-paths"), NULL }; const char *type = blob_type; int hashstdin = 0; int stdin_paths = 0; int no_filters = 0; int literally = 0; int nongit = 0; unsigned flags = HASH_FORMAT_CHECK; const char *vpath = NULL; const struct option hash_object_options[] = { OPT_STRING('t', NULL, &type, N_("type"), N_("object type")), OPT_BIT('w', NULL, &flags, N_("write the object into the object database"), HASH_WRITE_OBJECT), OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")), OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")), OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")), OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")), OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")), OPT_END() }; int i; const char *errstr = NULL; argc = parse_options(argc, argv, NULL, hash_object_options, hash_object_usage, 0); if (flags & HASH_WRITE_OBJECT) prefix = setup_git_directory(); else prefix = setup_git_directory_gently(&nongit); if (vpath && prefix) vpath = xstrdup(prefix_filename(prefix, vpath)); git_config(git_default_config, NULL); if (stdin_paths) { if (hashstdin) errstr = "Can't use --stdin-paths with --stdin"; else if (argc) errstr = "Can't specify files with --stdin-paths"; else if (vpath) errstr = "Can't use --stdin-paths with --path"; } else { if (hashstdin > 1) errstr = "Multiple --stdin arguments are not supported"; if (vpath && no_filters) errstr = "Can't use --path with --no-filters"; } if (errstr) { error("%s", errstr); usage_with_options(hash_object_usage, hash_object_options); } if (hashstdin) hash_fd(0, type, vpath, flags, literally); for (i = 0 ; i < argc; i++) { const char *arg = argv[i]; char *to_free = NULL; if (prefix) arg = to_free = prefix_filename(prefix, arg); hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg, flags, literally); free(to_free); } if (stdin_paths) hash_stdin_paths(type, no_filters, flags, literally); return 0; }
int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; int cached = 0, untracked = 0, opt_exclude = -1; int seen_dashdash = 0; int external_grep_allowed__ignored; const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = OBJECT_ARRAY_INIT; const char **paths = NULL; struct pathspec pathspec; struct string_list path_list = STRING_LIST_INIT_NODUP; int i; int dummy; int use_index = 1; int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED; struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, N_("search in index instead of in the work tree")), OPT_NEGBIT(0, "no-index", &use_index, N_("find in contents not managed by git"), 1), OPT_BOOLEAN(0, "untracked", &untracked, N_("search in both tracked and untracked files")), OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("search also in ignored files"), 1), OPT_GROUP(""), OPT_BOOLEAN('v', "invert-match", &opt.invert, N_("show non-matching lines")), OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case, N_("case insensitive matching")), OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp, N_("match patterns only at word boundaries")), OPT_SET_INT('a', "text", &opt.binary, N_("process binary files as text"), GREP_BINARY_TEXT), OPT_SET_INT('I', NULL, &opt.binary, N_("don't match patterns in binary files"), GREP_BINARY_NOMATCH), { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"), N_("descend at most <depth> levels"), PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), OPT_SET_INT('E', "extended-regexp", &pattern_type_arg, N_("use extended POSIX regular expressions"), GREP_PATTERN_TYPE_ERE), OPT_SET_INT('G', "basic-regexp", &pattern_type_arg, N_("use basic POSIX regular expressions (default)"), GREP_PATTERN_TYPE_BRE), OPT_SET_INT('F', "fixed-strings", &pattern_type_arg, N_("interpret patterns as fixed strings"), GREP_PATTERN_TYPE_FIXED), OPT_SET_INT('P', "perl-regexp", &pattern_type_arg, N_("use Perl-compatible regular expressions"), GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")), OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, N_("show filenames relative to top directory"), 1), OPT_BOOLEAN('l', "files-with-matches", &opt.name_only, N_("show only filenames instead of matching lines")), OPT_BOOLEAN(0, "name-only", &opt.name_only, N_("synonym for --files-with-matches")), OPT_BOOLEAN('L', "files-without-match", &opt.unmatch_name_only, N_("show only the names of files without match")), OPT_BOOLEAN('z', "null", &opt.null_following_name, N_("print NUL after filenames")), OPT_BOOLEAN('c', "count", &opt.count, N_("show the number of matches instead of matching lines")), OPT__COLOR(&opt.color, N_("highlight matches")), OPT_BOOLEAN(0, "break", &opt.file_break, N_("print empty line between matches from different files")), OPT_BOOLEAN(0, "heading", &opt.heading, N_("show filename only once above matches from same file")), OPT_GROUP(""), OPT_CALLBACK('C', "context", &opt, N_("n"), N_("show <n> context lines before and after matches"), context_callback), OPT_INTEGER('B', "before-context", &opt.pre_context, N_("show <n> context lines before matches")), OPT_INTEGER('A', "after-context", &opt.post_context, N_("show <n> context lines after matches")), OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"), context_callback), OPT_BOOLEAN('p', "show-function", &opt.funcname, N_("show a line with the function name before matches")), OPT_BOOLEAN('W', "function-context", &opt.funcbody, N_("show the surrounding function")), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, N_("file"), N_("read patterns from file"), file_callback), { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"), N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback }, { OPTION_CALLBACK, 0, "and", &opt, NULL, N_("combine patterns specified with -e"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, OPT_BOOLEAN(0, "or", &dummy, ""), { OPTION_CALLBACK, 0, "not", &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback }, { OPTION_CALLBACK, '(', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, open_callback }, { OPTION_CALLBACK, ')', NULL, &opt, NULL, "", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, close_callback }, OPT__QUIET(&opt.status_only, N_("indicate hit with exit status without output")), OPT_BOOLEAN(0, "all-match", &opt.all_match, N_("show only matches from files that match all patterns")), { OPTION_SET_INT, 0, "debug", &opt.debug, NULL, N_("show parse tree for grep expression"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 }, OPT_GROUP(""), { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, N_("pager"), N_("show matching files in the pager"), PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, N_("allow calling of grep(1) (ignored by this build)")), { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; /* * 'git grep -h', unlike 'git grep -h <pattern>', is a request * to show usage information and exit. */ if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(grep_usage, options); init_grep_defaults(); git_config(grep_cmd_config, NULL); grep_init(&opt, prefix); /* * If there is no -- then the paths must exist in the working * tree. If there is no explicit pattern specified with -e or * -f, we take the first unrecognized non option to be the * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ argc = parse_options(argc, argv, prefix, options, grep_usage, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); grep_commit_pattern_type(pattern_type_arg, &opt); if (use_index && !startup_info->have_repository) /* die the same way as if we did it at the beginning */ setup_git_directory(); /* * skip a -- separator; we know it cannot be * separating revisions from pathnames if * we haven't even had any patterns yet */ if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) { argv++; argc--; } /* First unrecognized non-option token */ if (argc > 0 && !opt.pattern_list) { append_grep_pattern(&opt, argv[0], "command line", 0, GREP_PATTERN); argv++; argc--; } if (show_in_pager == default_pager) show_in_pager = git_pager(1); if (show_in_pager) { opt.color = 0; opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; string_list_append(&path_list, show_in_pager); use_threads = 0; } if ((opt.binary & GREP_BINARY_NOMATCH)) use_threads = 0; if (!opt.pattern_list) die(_("no pattern given.")); if (!opt.fixed && opt.ignore_case) opt.regflags |= REG_ICASE; compile_grep_patterns(&opt); /* Check revs and then paths */ for (i = 0; i < argc; i++) { const char *arg = argv[i]; unsigned char sha1[20]; /* Is it a rev? */ if (!get_sha1(arg, sha1)) { struct object *object = parse_object(sha1); if (!object) die(_("bad object %s"), arg); add_object_array(object, arg, &list); continue; } if (!strcmp(arg, "--")) { i++; seen_dashdash = 1; } break; } #ifndef NO_PTHREADS if (list.nr || cached || online_cpus() == 1) use_threads = 0; #else use_threads = 0; #endif #ifndef NO_PTHREADS if (use_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) skip_first_line = 1; start_threads(&opt); } #endif /* The rest are paths */ if (!seen_dashdash) { int j; for (j = i; j < argc; j++) verify_filename(prefix, argv[j], j == i); } paths = get_pathspec(prefix, argv + i); init_pathspec(&pathspec, paths); pathspec.max_depth = opt.max_depth; pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die(_("--open-files-in-pager only works on the worktree")); if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { const char *pager = path_list.items[0].string; int len = strlen(pager); if (len > 4 && is_dir_sep(pager[len - 5])) pager += len - 4; if (opt.ignore_case && !strcmp("less", pager)) string_list_append(&path_list, "-i"); if (!strcmp("less", pager) || !strcmp("vi", pager)) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "+/%s%s", strcmp("less", pager) ? "" : "*", opt.pattern_list->pattern); string_list_append(&path_list, buf.buf); strbuf_detach(&buf, NULL); } } if (!show_in_pager) setup_pager(); if (!use_index && (untracked || cached)) die(_("--cached or --untracked cannot be used with --no-index.")); if (!use_index || untracked) { int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; if (list.nr) die(_("--no-index or --untracked cannot be used with revs.")); hit = grep_directory(&opt, &pathspec, use_exclude); } else if (0 <= opt_exclude) { die(_("--[no-]exclude-standard cannot be used for tracked contents.")); } else if (!list.nr) { if (!cached) setup_work_tree(); hit = grep_cache(&opt, &pathspec, cached); } else { if (cached) die(_("both --cached and trees are given.")); hit = grep_objects(&opt, &pathspec, &list); } if (use_threads) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); free_grep_patterns(&opt); return !hit; }
int cmd_blame(int argc, const char **argv, const char *prefix) { struct rev_info revs; const char *path; struct blame_scoreboard sb; struct blame_origin *o; struct blame_entry *ent = NULL; long dashdash_pos, lno; struct progress_info pi = { NULL, 0 }; struct string_list range_list = STRING_LIST_INIT_NODUP; int output_option = 0, opt = 0; int show_stats = 0; const char *revs_file = NULL; const char *contents_from = NULL; const struct option options[] = { OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")), OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")), OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")), OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")), OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")), OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE), OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME), OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER), OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN), OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN), OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT), OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP), OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME), OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR), OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL), OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE), /* * The following two options are parsed by parse_revision_opt() * and are only included here to get included in the "-h" * output: */ { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL), OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")), OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")), { OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback }, { OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback }, OPT_STRING_LIST('L', NULL, &range_list, N_("n,m"), N_("Process only line range n,m, counting from 1")), OPT__ABBREV(&abbrev), OPT_END() }; struct parse_opt_ctx_t ctx; int cmd_is_annotate = !strcmp(argv[0], "annotate"); struct range_set ranges; unsigned int range_i; long anchor; git_config(git_blame_config, &output_option); init_revisions(&revs, NULL); revs.date_mode = blame_date_mode; revs.diffopt.flags.allow_textconv = 1; revs.diffopt.flags.follow_renames = 1; save_commit_buffer = 0; dashdash_pos = 0; show_progress = -1; parse_options_start(&ctx, argc, argv, prefix, options, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0); for (;;) { switch (parse_options_step(&ctx, options, blame_opt_usage)) { case PARSE_OPT_HELP: exit(129); case PARSE_OPT_DONE: if (ctx.argv[0]) dashdash_pos = ctx.cpidx; goto parse_done; } if (!strcmp(ctx.argv[0], "--reverse")) { ctx.argv[0] = "--children"; reverse = 1; } parse_revision_opt(&revs, &ctx, options, blame_opt_usage); } parse_done: no_whole_file_rename = !revs.diffopt.flags.follow_renames; xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC; revs.diffopt.flags.follow_renames = 0; argc = parse_options_end(&ctx); if (incremental || (output_option & OUTPUT_PORCELAIN)) { if (show_progress > 0) die(_("--progress can't be used with --incremental or porcelain formats")); show_progress = 0; } else if (show_progress < 0) show_progress = isatty(2); if (0 < abbrev && abbrev < GIT_SHA1_HEXSZ) /* one more abbrev length is needed for the boundary commit */ abbrev++; else if (!abbrev) abbrev = GIT_SHA1_HEXSZ; if (revs_file && read_ancestry(revs_file)) die_errno("reading graft file '%s' failed", revs_file); if (cmd_is_annotate) { output_option |= OUTPUT_ANNOTATE_COMPAT; blame_date_mode.type = DATE_ISO8601; } else { blame_date_mode = revs.date_mode; } /* The maximum width used to show the dates */ switch (blame_date_mode.type) { case DATE_RFC2822: blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700"); break; case DATE_ISO8601_STRICT: blame_date_width = sizeof("2006-10-19T16:00:04-07:00"); break; case DATE_ISO8601: blame_date_width = sizeof("2006-10-19 16:00:04 -0700"); break; case DATE_RAW: blame_date_width = sizeof("1161298804 -0700"); break; case DATE_UNIX: blame_date_width = sizeof("1161298804"); break; case DATE_SHORT: blame_date_width = sizeof("2006-10-19"); break; case DATE_RELATIVE: /* * TRANSLATORS: This string is used to tell us the * maximum display width for a relative timestamp in * "git blame" output. For C locale, "4 years, 11 * months ago", which takes 22 places, is the longest * among various forms of relative timestamps, but * your language may need more or fewer display * columns. */ blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */ break; case DATE_NORMAL: blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700"); break; case DATE_STRFTIME: blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */ break; } blame_date_width -= 1; /* strip the null */ if (revs.diffopt.flags.find_copies_harder) opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE | PICKAXE_BLAME_COPY_HARDER); /* * We have collected options unknown to us in argv[1..unk] * which are to be passed to revision machinery if we are * going to do the "bottom" processing. * * The remaining are: * * (1) if dashdash_pos != 0, it is either * "blame [revisions] -- <path>" or * "blame -- <path> <rev>" * * (2) otherwise, it is one of the two: * "blame [revisions] <path>" * "blame <path> <rev>" * * Note that we must strip out <path> from the arguments: we do not * want the path pruning but we may want "bottom" processing. */ if (dashdash_pos) { switch (argc - dashdash_pos - 1) { case 2: /* (1b) */ if (argc != 4) usage_with_options(blame_opt_usage, options); /* reorder for the new way: <rev> -- <path> */ argv[1] = argv[3]; argv[3] = argv[2]; argv[2] = "--"; /* FALLTHROUGH */ case 1: /* (1a) */ path = add_prefix(prefix, argv[--argc]); argv[argc] = NULL; break; default: usage_with_options(blame_opt_usage, options); } } else { if (argc < 2) usage_with_options(blame_opt_usage, options); if (argc == 3 && is_a_rev(argv[argc - 1])) { /* (2b) */ path = add_prefix(prefix, argv[1]); argv[1] = argv[2]; } else { /* (2a) */ if (argc == 2 && is_a_rev(argv[1]) && !get_git_work_tree()) die("missing <path> to blame"); path = add_prefix(prefix, argv[argc - 1]); } argv[argc - 1] = "--"; } revs.disable_stdin = 1; setup_revisions(argc, argv, &revs, NULL); init_scoreboard(&sb); sb.revs = &revs; sb.contents_from = contents_from; sb.reverse = reverse; setup_scoreboard(&sb, path, &o); lno = sb.num_lines; if (lno && !range_list.nr) string_list_append(&range_list, "1"); anchor = 1; range_set_init(&ranges, range_list.nr); for (range_i = 0; range_i < range_list.nr; ++range_i) { long bottom, top; if (parse_range_arg(range_list.items[range_i].string, nth_line_cb, &sb, lno, anchor, &bottom, &top, sb.path)) usage(blame_usage); if (lno < top || ((lno || bottom) && lno < bottom)) die(Q_("file %s has only %lu line", "file %s has only %lu lines", lno), path, lno); if (bottom < 1) bottom = 1; if (top < 1) top = lno; bottom--; range_set_append_unsafe(&ranges, bottom, top); anchor = top + 1; } sort_and_merge_range_set(&ranges); for (range_i = ranges.nr; range_i > 0; --range_i) { const struct range *r = &ranges.ranges[range_i - 1]; ent = blame_entry_prepend(ent, r->start, r->end, o); } o->suspects = ent; prio_queue_put(&sb.commits, o->commit); blame_origin_decref(o); range_set_release(&ranges); string_list_clear(&range_list, 0); sb.ent = NULL; sb.path = path; if (blame_move_score) sb.move_score = blame_move_score; if (blame_copy_score) sb.copy_score = blame_copy_score; sb.debug = DEBUG; sb.on_sanity_fail = &sanity_check_on_fail; sb.show_root = show_root; sb.xdl_opts = xdl_opts; sb.no_whole_file_rename = no_whole_file_rename; read_mailmap(&mailmap, NULL); sb.found_guilty_entry = &found_guilty_entry; sb.found_guilty_entry_data = π if (show_progress) pi.progress = start_delayed_progress(_("Blaming lines"), sb.num_lines); assign_blame(&sb, opt); stop_progress(&pi.progress); if (!incremental) setup_pager(); else return 0; blame_sort_final(&sb); blame_coalesce(&sb); if (!(output_option & OUTPUT_PORCELAIN)) find_alignment(&sb, &output_option); output(&sb, output_option); free((void *)sb.final_buf); for (ent = sb.ent; ent; ) { struct blame_entry *e = ent->next; free(ent); ent = e; } if (show_stats) { printf("num read blob: %d\n", sb.num_read_blob); printf("num get patch: %d\n", sb.num_get_patch); printf("num commits: %d\n", sb.num_commits); } return 0; }