/* Get the name for the merge commit's message. */ static void merge_name(const char *remote, struct strbuf *msg) { struct commit *remote_head; unsigned char branch_head[20]; struct strbuf buf = STRBUF_INIT; struct strbuf bname = STRBUF_INIT; const char *ptr; char *found_ref; int len, early; strbuf_branchname(&bname, remote); remote = bname.buf; memset(branch_head, 0, sizeof(branch_head)); remote_head = get_merge_parent(remote); if (!remote_head) die(_("'%s' does not point to a commit"), remote); if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) { if (!prefixcmp(found_ref, "refs/heads/")) { strbuf_addf(msg, "%s\t\tbranch '%s' of .\n", sha1_to_hex(branch_head), remote); goto cleanup; } if (!prefixcmp(found_ref, "refs/tags/")) { strbuf_addf(msg, "%s\t\ttag '%s' of .\n", sha1_to_hex(branch_head), remote); goto cleanup; } if (!prefixcmp(found_ref, "refs/remotes/")) { strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n", sha1_to_hex(branch_head), remote); goto cleanup; } } /* See if remote matches <name>^^^.. or <name>~<number> */ for (len = 0, ptr = remote + strlen(remote); remote < ptr && ptr[-1] == '^'; ptr--) len++; if (len) early = 1; else { early = 0; ptr = strrchr(remote, '~'); if (ptr) { int seen_nonzero = 0; len++; /* count ~ */ while (*++ptr && isdigit(*ptr)) { seen_nonzero |= (*ptr != '0'); len++; } if (*ptr) len = 0; /* not ...~<number> */ else if (seen_nonzero) early = 1; else if (len == 1) early = 1; /* "name~" is "name~1"! */ } } if (len) { struct strbuf truname = STRBUF_INIT; strbuf_addstr(&truname, "refs/heads/"); strbuf_addstr(&truname, remote); strbuf_setlen(&truname, truname.len - len); if (ref_exists(truname.buf)) { strbuf_addf(msg, "%s\t\tbranch '%s'%s of .\n", sha1_to_hex(remote_head->object.sha1), truname.buf + 11, (early ? " (early part)" : "")); strbuf_release(&truname); goto cleanup; } } if (!strcmp(remote, "FETCH_HEAD") && !access(git_path("FETCH_HEAD"), R_OK)) { const char *filename; FILE *fp; struct strbuf line = STRBUF_INIT; char *ptr; filename = git_path("FETCH_HEAD"); fp = fopen(filename, "r"); if (!fp) die_errno(_("could not open '%s' for reading"), filename); strbuf_getline(&line, fp, '\n'); fclose(fp); ptr = strstr(line.buf, "\tnot-for-merge\t"); if (ptr) strbuf_remove(&line, ptr-line.buf+1, 13); strbuf_addbuf(msg, &line); strbuf_release(&line); goto cleanup; } if (remote_head->util) { struct merge_remote_desc *desc; desc = merge_remote_util(remote_head); if (desc && desc->obj && desc->obj->type == OBJ_TAG) { strbuf_addf(msg, "%s\t\t%s '%s'\n", sha1_to_hex(desc->obj->sha1), typename(desc->obj->type), remote); goto cleanup; } }
int main(int argc, const char **argv) { struct strbuf buf = STRBUF_INIT; int nongit; git_setup_gettext(); git_extract_argv0_path(argv[0]); setup_git_directory_gently(&nongit); if (argc < 2) { error("remote-curl: usage: git remote-curl <remote> [<url>]"); return 1; } options.verbosity = 1; options.progress = !!isatty(2); options.thin = 1; remote = remote_get(argv[1]); if (argc > 2) { end_url_with_slash(&url, argv[2]); } else { end_url_with_slash(&url, remote->url[0]); } http_init(remote, url.buf, 0); do { const char *arg; if (strbuf_getline(&buf, stdin, '\n') == EOF) { if (ferror(stdin)) error("remote-curl: error reading command stream from git"); return 1; } if (buf.len == 0) break; if (starts_with(buf.buf, "fetch ")) { if (nongit) die("remote-curl: fetch attempted without a local repo"); parse_fetch(&buf); } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) { int for_push = !!strstr(buf.buf + 4, "for-push"); output_refs(get_refs(for_push)); } else if (starts_with(buf.buf, "push ")) { parse_push(&buf); } else if (skip_prefix(buf.buf, "option ", &arg)) { char *value = strchr(arg, ' '); int result; if (value) *value++ = '\0'; else value = "true"; result = set_option(arg, value); if (!result) printf("ok\n"); else if (result < 0) printf("error invalid value\n"); else printf("unsupported\n"); fflush(stdout); } else if (!strcmp(buf.buf, "capabilities")) { printf("fetch\n"); printf("option\n"); printf("push\n"); printf("check-connectivity\n"); printf("\n"); fflush(stdout); } else { error("remote-curl: unknown command '%s' from git", buf.buf); return 1; } strbuf_reset(&buf); } while (1); http_cleanup(); return 0; }
int main(int argc, const char **argv) { struct strbuf buf = STRBUF_INIT; int nongit; git_extract_argv0_path(argv[0]); setup_git_directory_gently(&nongit); if (argc < 2) { fprintf(stderr, "Remote needed\n"); return 1; } options.verbosity = 1; options.progress = !!isatty(2); options.thin = 1; remote = remote_get(argv[1]); if (argc > 2) { end_url_with_slash(&buf, argv[2]); } else { end_url_with_slash(&buf, remote->url[0]); } url = strbuf_detach(&buf, NULL); http_init(remote, url, 0); do { if (strbuf_getline(&buf, stdin, '\n') == EOF) { if (ferror(stdin)) fprintf(stderr, "Error reading command stream\n"); else fprintf(stderr, "Unexpected end of command stream\n"); return 1; } if (buf.len == 0) break; if (!prefixcmp(buf.buf, "fetch ")) { if (nongit) die("Fetch attempted without a local repo"); parse_fetch(&buf); } else if (!strcmp(buf.buf, "list") || !prefixcmp(buf.buf, "list ")) { int for_push = !!strstr(buf.buf + 4, "for-push"); output_refs(get_refs(for_push)); } else if (!prefixcmp(buf.buf, "push ")) { parse_push(&buf); } else if (!prefixcmp(buf.buf, "option ")) { char *name = buf.buf + strlen("option "); char *value = strchr(name, ' '); int result; if (value) *value++ = '\0'; else value = "true"; result = set_option(name, value); if (!result) printf("ok\n"); else if (result < 0) printf("error invalid value\n"); else printf("unsupported\n"); fflush(stdout); } else if (!strcmp(buf.buf, "capabilities")) { printf("fetch\n"); printf("option\n"); printf("push\n"); printf("\n"); fflush(stdout); } else { fprintf(stderr, "Unknown command '%s'\n", buf.buf); return 1; } strbuf_reset(&buf); } while (1); http_cleanup(); return 0; }
int cmd_fetch_pack(int argc, const char **argv, const char *prefix) { int i, ret; struct ref *ref = NULL; const char *dest = NULL; struct ref **sought = NULL; int nr_sought = 0, alloc_sought = 0; int fd[2]; char *pack_lockfile = NULL; char **pack_lockfile_ptr = NULL; struct child_process *conn; struct fetch_pack_args args; struct sha1_array shallow = SHA1_ARRAY_INIT; packet_trace_identity("fetch-pack"); memset(&args, 0, sizeof(args)); args.uploadpack = "git-upload-pack"; for (i = 1; i < argc && *argv[i] == '-'; i++) { const char *arg = argv[i]; if (starts_with(arg, "--upload-pack=")) { args.uploadpack = arg + 14; continue; } if (starts_with(arg, "--exec=")) { args.uploadpack = arg + 7; continue; } if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) { args.quiet = 1; continue; } if (!strcmp("--keep", arg) || !strcmp("-k", arg)) { args.lock_pack = args.keep_pack; args.keep_pack = 1; continue; } if (!strcmp("--thin", arg)) { args.use_thin_pack = 1; continue; } if (!strcmp("--include-tag", arg)) { args.include_tag = 1; continue; } if (!strcmp("--all", arg)) { args.fetch_all = 1; continue; } if (!strcmp("--stdin", arg)) { args.stdin_refs = 1; continue; } if (!strcmp("--diag-url", arg)) { args.diag_url = 1; continue; } if (!strcmp("-v", arg)) { args.verbose = 1; continue; } if (starts_with(arg, "--depth=")) { args.depth = strtol(arg + 8, NULL, 0); continue; } if (!strcmp("--no-progress", arg)) { args.no_progress = 1; continue; } if (!strcmp("--stateless-rpc", arg)) { args.stateless_rpc = 1; continue; } if (!strcmp("--lock-pack", arg)) { args.lock_pack = 1; pack_lockfile_ptr = &pack_lockfile; continue; } if (!strcmp("--check-self-contained-and-connected", arg)) { args.check_self_contained_and_connected = 1; continue; } if (!strcmp("--cloning", arg)) { args.cloning = 1; continue; } if (!strcmp("--update-shallow", arg)) { args.update_shallow = 1; continue; } usage(fetch_pack_usage); } if (i < argc) dest = argv[i++]; else usage(fetch_pack_usage); /* * Copy refs from cmdline to growable list, then append any * refs from the standard input: */ for (; i < argc; i++) add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]); if (args.stdin_refs) { if (args.stateless_rpc) { /* in stateless RPC mode we use pkt-line to read * from stdin, until we get a flush packet */ for (;;) { char *line = packet_read_line(0, NULL); if (!line) break; add_sought_entry(&sought, &nr_sought, &alloc_sought, line); } } else { /* read from stdin one ref per line, until EOF */ struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, stdin, '\n') != EOF) add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf); strbuf_release(&line); } } if (args.stateless_rpc) { conn = NULL; fd[0] = 0; fd[1] = 1; } else { int flags = args.verbose ? CONNECT_VERBOSE : 0; if (args.diag_url) flags |= CONNECT_DIAG_URL; conn = git_connect(fd, dest, args.uploadpack, flags); if (!conn) return args.diag_url ? 0 : 1; } get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow); ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought, &shallow, pack_lockfile_ptr); if (pack_lockfile) { printf("lock %s\n", pack_lockfile); fflush(stdout); } if (args.check_self_contained_and_connected && args.self_contained_and_connected) { printf("connectivity-ok\n"); fflush(stdout); } close(fd[0]); close(fd[1]); if (finish_connect(conn)) return 1; ret = !ref; /* * If the heads to pull were given, we should have consumed * all of them by matching the remote. Otherwise, 'git fetch * remote no-such-ref' would silently succeed without issuing * an error. */ for (i = 0; i < nr_sought; i++) { if (!sought[i] || sought[i]->matched) continue; error("no such remote ref %s", sought[i]->name); ret = 1; } while (ref) { printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name); ref = ref->next; } return ret; }
int cmd_commit(int argc, const char **argv, const char *prefix) { struct strbuf sb = STRBUF_INIT; const char *index_file, *reflog_msg; char *nl, *p; unsigned char commit_sha1[20]; struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; struct wt_status s; wt_status_prepare(&s); git_config(git_commit_config, &s); in_merge = file_exists(git_path("MERGE_HEAD")); s.in_merge = in_merge; if (s.use_color == -1) s.use_color = git_use_color_default; argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix, &s); if (dry_run) { if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; return dry_run_commit(argc, argv, prefix, &s); } index_file = prepare_index(argc, argv, prefix, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ if (!prepare_to_commit(index_file, prefix, &s)) { rollback_index_files(); return 1; } /* Determine parents */ if (initial_commit) { reflog_msg = "commit (initial)"; } else if (amend) { struct commit_list *c; struct commit *commit; reflog_msg = "commit (amend)"; commit = lookup_commit(head_sha1); if (!commit || parse_commit(commit)) die("could not parse HEAD commit"); for (c = commit->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; } else if (in_merge) { struct strbuf m = STRBUF_INIT; FILE *fp; reflog_msg = "commit (merge)"; pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die_errno("could not open '%s' for reading", git_path("MERGE_HEAD")); while (strbuf_getline(&m, fp, '\n') != EOF) { unsigned char sha1[20]; if (get_sha1_hex(m.buf, sha1) < 0) die("Corrupt MERGE_HEAD file (%s)", m.buf); pptr = &commit_list_insert(lookup_commit(sha1), pptr)->next; } fclose(fp); strbuf_release(&m); if (!stat(git_path("MERGE_MODE"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0) die_errno("could not read MERGE_MODE"); if (!strcmp(sb.buf, "no-ff")) allow_fast_forward = 0; } if (allow_fast_forward) parents = reduce_heads(parents); } else { reflog_msg = "commit"; pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; } /* Finally, get the commit message */ strbuf_reset(&sb); if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { int saved_errno = errno; rollback_index_files(); die("could not read commit message: %s", strerror(saved_errno)); } /* Truncate the message just before the diff, if any. */ if (verbose) { p = strstr(sb.buf, "\ndiff --git "); if (p != NULL) strbuf_setlen(&sb, p - sb.buf + 1); } if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, cleanup_mode == CLEANUP_ALL); if (message_is_empty(&sb)) { rollback_index_files(); fprintf(stderr, "Aborting commit due to empty commit message.\n"); exit(1); } if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1, fmt_ident(author_name, author_email, author_date, IDENT_ERROR_ON_NO_NAME))) { rollback_index_files(); die("failed to write commit object"); } ref_lock = lock_any_ref_for_update("HEAD", initial_commit ? NULL : head_sha1, 0); nl = strchr(sb.buf, '\n'); if (nl) strbuf_setlen(&sb, nl + 1 - sb.buf); else strbuf_addch(&sb, '\n'); strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg)); strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); if (!ref_lock) { rollback_index_files(); die("cannot lock HEAD ref"); } if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) { rollback_index_files(); die("cannot update HEAD ref"); } unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); unlink(git_path("MERGE_MODE")); unlink(git_path("SQUASH_MSG")); if (commit_index_files()) die ("Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" "not exceeded, and then \"git reset HEAD\" to recover."); rerere(0); run_hook(get_index_file(), "post-commit", NULL); if (!quiet) print_summary(prefix, commit_sha1); return 0; }
/** * Given a fd, read stuff into pushobj */ static int read_pobj(FILE * fp, struct pushobj *po) { int ii; int head = 0; char * cbuf = NULL; struct strbuf buf = STRBUF_INIT; struct strbuf sig = STRBUF_INIT; struct string_list list; pobj_release(po); memset(&list, 0, sizeof(struct string_list)); memset(po->head, 0, 40); while (strbuf_getline(&buf, fp, '\n') != EOF) { if (strncmp(buf.buf, PGP_SIGNATURE, strlen(PGP_SIGNATURE)) == 0) break; // check to see if this is the HEAD ref if (strncmp(buf.buf + 41, "HEAD", 4) == 0) { strncpy(po->head, buf.buf, 40); head = 1; continue; } cbuf = (char*)malloc(buf.len); strcpy(cbuf, buf.buf); string_list_append(cbuf, &list); } if (!head) die("pushobject did not contain HEAD ref"); po->lines = list.nr; po->refs = (char**)malloc(sizeof(char*) * list.nr); for (ii = 0; ii < list.nr; ii++) { po->refs[ii] = (char*)malloc(strlen(list.items[ii].string) + 1); strcpy(po->refs[ii], list.items[ii].string); } // rest of the stuff is signature strbuf_add(&sig, buf.buf, buf.len); strbuf_addstr(&sig, "\n"); while (strbuf_getline(&buf, fp, '\n') != EOF) { strbuf_add(&sig, buf.buf, buf.len); strbuf_addstr(&sig, "\n"); if (strncmp(buf.buf, END_PGP_SIGNATURE, strlen(END_PGP_SIGNATURE)) == 0) break; } po->signature = (char*)malloc(sig.len); strcpy(po->signature, sig.buf); memset(po->prev, 0, 40); // now the rest of the stuff is the prev pointer if (strbuf_getline(&buf, fp, '\n') != EOF) { strncpy(po->prev, buf.buf, 40); po->prev[40] = '\0'; } strbuf_release(&buf); strbuf_release(&sig); string_list_clear(&list, 0); return 1; }
/** * Initialize user directories, takes PGP */ int gidit_proj_init(FILE *fp, const char * basepath, unsigned int flags) { FILE * pgp_fp; struct strbuf pgp_key = STRBUF_INIT; struct strbuf proj_name = STRBUF_INIT; unsigned char sha1[20]; char pgp_sha1[41]; git_SHA_CTX c; strbuf_getline(&proj_name, fp, '\n'); if (proj_name.len == 0) { strbuf_release(&pgp_key); strbuf_release(&proj_name); return error("Error while reading project name\n"); } strbuf_getline(&pgp_key, fp, EOF); if (pgp_key.len == 0) { strbuf_release(&pgp_key); strbuf_release(&proj_name); return error("Error while reading pgp_key"); } // hash the pgp key git_SHA1_Init(&c); git_SHA1_Update(&c, pgp_key.buf, pgp_key.len); git_SHA1_Final(sha1, &c); // change dir to pushobjects dir if (chdir(basepath) || chdir(PUSHOBJ_DIR)) return error("Error going to pushobjects directory\n"); sprintf(pgp_sha1, "%s", sha1_to_hex(sha1)); if (safe_create_dir(pgp_sha1)) exit(1); chdir(pgp_sha1); // now ensure the project directories existence if (safe_create_dir(proj_name.buf)) exit(1); // if pgp key file already exists, not need to resave if (access("PGP", F_OK)) { // save the PGP key in there pgp_fp = fopen("PGP", "w"); if (!pgp_fp) die("Error while saving PGP key"); fwrite(pgp_key.buf, pgp_key.len, 1, pgp_fp); fclose(pgp_fp); } strbuf_release(&pgp_key); strbuf_release(&proj_name); return 0; }
int cmd_commit(int argc, const char **argv, const char *prefix) { static struct wt_status s; static struct option builtin_commit_options[] = { OPT__QUIET(&quiet, N_("suppress summary after successful commit")), OPT__VERBOSE(&verbose, N_("show diff in commit message template")), OPT_GROUP(N_("Commit message options")), OPT_FILENAME('F', "file", &logfile, N_("read message from file")), OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")), OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")), OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m), OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")), OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")), OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")), OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")), OPT_BOOLEAN(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")), OPT_BOOLEAN('s', "signoff", &signoff, N_("add Signed-off-by:")), OPT_FILENAME('t', "template", &template_file, N_("use specified template file")), OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")), OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")), OPT_BOOLEAN(0, "status", &include_status, N_("include status in commit message template")), { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, /* end commit message options */ OPT_GROUP(N_("Commit contents options")), OPT_BOOLEAN('a', "all", &all, N_("commit all changed files")), OPT_BOOLEAN('i', "include", &also, N_("add specified files to index for commit")), OPT_BOOLEAN(0, "interactive", &interactive, N_("interactively add files")), OPT_BOOLEAN('p', "patch", &patch_interactive, N_("interactively add changes")), OPT_BOOLEAN('o', "only", &only, N_("commit only specified files")), OPT_BOOLEAN('n', "no-verify", &no_verify, N_("bypass pre-commit hook")), OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")), OPT_SET_INT(0, "short", &status_format, N_("show status concisely"), STATUS_FORMAT_SHORT), OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")), OPT_SET_INT(0, "porcelain", &status_format, N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), OPT_SET_INT(0, "long", &status_format, N_("show status in long format (default)"), STATUS_FORMAT_LONG), OPT_BOOLEAN('z', "null", &s.null_termination, N_("terminate entries with NUL")), OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")), OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, /* end commit contents options */ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL, N_("ok to record an empty change"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL, N_("ok to record a change with an empty message"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_END() }; struct strbuf sb = STRBUF_INIT; struct strbuf author_ident = STRBUF_INIT; const char *index_file, *reflog_msg; char *nl, *p; unsigned char sha1[20]; struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; struct commit *current_head = NULL; struct commit_extra_header *extra = NULL; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); wt_status_prepare(&s); gitmodules_config(); git_config(git_commit_config, &s); determine_whence(&s); s.colopts = 0; if (get_sha1("HEAD", sha1)) current_head = NULL; else { current_head = lookup_commit_or_die(sha1, "HEAD"); if (!current_head || parse_commit(current_head)) die(_("could not parse HEAD commit")); } argc = parse_and_validate_options(argc, argv, builtin_commit_options, builtin_commit_usage, prefix, current_head, &s); if (dry_run) return dry_run_commit(argc, argv, prefix, current_head, &s); index_file = prepare_index(argc, argv, prefix, current_head, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ if (!prepare_to_commit(index_file, prefix, current_head, &s, &author_ident)) { rollback_index_files(); return 1; } /* Determine parents */ reflog_msg = getenv("GIT_REFLOG_ACTION"); if (!current_head) { if (!reflog_msg) reflog_msg = "commit (initial)"; } else if (amend) { struct commit_list *c; if (!reflog_msg) reflog_msg = "commit (amend)"; for (c = current_head->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; } else if (whence == FROM_MERGE) { struct strbuf m = STRBUF_INIT; FILE *fp; if (!reflog_msg) reflog_msg = "commit (merge)"; pptr = &commit_list_insert(current_head, pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die_errno(_("could not open '%s' for reading"), git_path("MERGE_HEAD")); while (strbuf_getline(&m, fp, '\n') != EOF) { struct commit *parent; parent = get_merge_parent(m.buf); if (!parent) die(_("Corrupt MERGE_HEAD file (%s)"), m.buf); pptr = &commit_list_insert(parent, pptr)->next; } fclose(fp); strbuf_release(&m); if (!stat(git_path("MERGE_MODE"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0) die_errno(_("could not read MERGE_MODE")); if (!strcmp(sb.buf, "no-ff")) allow_fast_forward = 0; } if (allow_fast_forward) parents = reduce_heads(parents); } else { if (!reflog_msg) reflog_msg = (whence == FROM_CHERRY_PICK) ? "commit (cherry-pick)" : "commit"; pptr = &commit_list_insert(current_head, pptr)->next; } /* Finally, get the commit message */ strbuf_reset(&sb); if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { int saved_errno = errno; rollback_index_files(); die(_("could not read commit message: %s"), strerror(saved_errno)); } /* Truncate the message just before the diff, if any. */ if (verbose) { p = strstr(sb.buf, "\ndiff --git "); if (p != NULL) strbuf_setlen(&sb, p - sb.buf + 1); } if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, cleanup_mode == CLEANUP_ALL); if (template_untouched(&sb) && !allow_empty_message) { rollback_index_files(); fprintf(stderr, _("Aborting commit; you did not edit the message.\n")); exit(1); } if (message_is_empty(&sb) && !allow_empty_message) { rollback_index_files(); fprintf(stderr, _("Aborting commit due to empty commit message.\n")); exit(1); } if (amend) { const char *exclude_gpgsig[2] = { "gpgsig", NULL }; extra = read_commit_extra_headers(current_head, exclude_gpgsig); } else { struct commit_extra_header **tail = &extra; append_merge_tag_headers(parents, &tail); } if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1, author_ident.buf, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); } strbuf_release(&author_ident); free_commit_extra_headers(extra); ref_lock = lock_any_ref_for_update("HEAD", !current_head ? NULL : current_head->object.sha1, 0); nl = strchr(sb.buf, '\n'); if (nl) strbuf_setlen(&sb, nl + 1 - sb.buf); else strbuf_addch(&sb, '\n'); strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg)); strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); if (!ref_lock) { rollback_index_files(); die(_("cannot lock HEAD ref")); } if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) { rollback_index_files(); die(_("cannot update HEAD ref")); } unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path("REVERT_HEAD")); unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); unlink(git_path("MERGE_MODE")); unlink(git_path("SQUASH_MSG")); if (commit_index_files()) die (_("Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" "not exceeded, and then \"git reset HEAD\" to recover.")); rerere(0); run_hook(get_index_file(), "post-commit", NULL); if (amend && !no_post_rewrite) { struct notes_rewrite_cfg *cfg; cfg = init_copy_notes_for_rewrite("amend"); if (cfg) { /* we are amending, so current_head is not NULL */ copy_note_for_rewrite(cfg, current_head->object.sha1, sha1); finish_copy_notes_for_rewrite(cfg); } run_rewrite_hook(current_head->object.sha1, sha1); } if (!quiet) print_summary(prefix, sha1, !current_head); return 0; }
static int cmd_parseopt(int argc, const char **argv, const char *prefix) { static int keep_dashdash = 0, stop_at_non_option = 0; static char const * const parseopt_usage[] = { N_("git rev-parse --parseopt [options] -- [<args>...]"), NULL }; static struct option parseopt_opts[] = { OPT_BOOL(0, "keep-dashdash", &keep_dashdash, N_("keep the `--` passed as an arg")), OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option, N_("stop parsing after the " "first non-option argument")), OPT_BOOL(0, "stuck-long", &stuck_long, N_("output in stuck long form")), OPT_END(), }; struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT; const char **usage = NULL; struct option *opts = NULL; int onb = 0, osz = 0, unb = 0, usz = 0; strbuf_addstr(&parsed, "set --"); argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage, PARSE_OPT_KEEP_DASHDASH); if (argc < 1 || strcmp(argv[0], "--")) usage_with_options(parseopt_usage, parseopt_opts); /* get the usage up to the first line with a -- on it */ for (;;) { if (strbuf_getline(&sb, stdin, '\n') == EOF) die("premature end of input"); ALLOC_GROW(usage, unb + 1, usz); if (!strcmp("--", sb.buf)) { if (unb < 1) die("no usage string given before the `--' separator"); usage[unb] = NULL; break; } usage[unb++] = strbuf_detach(&sb, NULL); } /* parse: (<short>|<short>,<long>|<long>)[=?]? SP+ <help> */ while (strbuf_getline(&sb, stdin, '\n') != EOF) { const char *s; struct option *o; if (!sb.len) continue; ALLOC_GROW(opts, onb + 1, osz); memset(opts + onb, 0, sizeof(opts[onb])); o = &opts[onb++]; s = strchr(sb.buf, ' '); if (!s || *sb.buf == ' ') { o->type = OPTION_GROUP; o->help = xstrdup(skipspaces(sb.buf)); continue; } o->type = OPTION_CALLBACK; o->help = xstrdup(skipspaces(s)); o->value = &parsed; o->flags = PARSE_OPT_NOARG; o->callback = &parseopt_dump; while (s > sb.buf && strchr("*=?!", s[-1])) { switch (*--s) { case '=': o->flags &= ~PARSE_OPT_NOARG; break; case '?': o->flags &= ~PARSE_OPT_NOARG; o->flags |= PARSE_OPT_OPTARG; break; case '!': o->flags |= PARSE_OPT_NONEG; break; case '*': o->flags |= PARSE_OPT_HIDDEN; break; } } if (s - sb.buf == 1) /* short option only */ o->short_name = *sb.buf; else if (sb.buf[1] != ',') /* long option only */ o->long_name = xmemdupz(sb.buf, s - sb.buf); else { o->short_name = *sb.buf; o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2); } } strbuf_release(&sb); /* put an OPT_END() */ ALLOC_GROW(opts, onb + 1, osz); memset(opts + onb, 0, sizeof(opts[onb])); argc = parse_options(argc, argv, prefix, opts, usage, (keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) | (stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) | PARSE_OPT_SHELL_EVAL); strbuf_addf(&parsed, " --"); sq_quote_argv(&parsed, argv, 0); puts(parsed.buf); return 0; }
static int decode_file(idn_resconf_t conf1, idn_resconf_t conf2, FILE *fp, int flags) { idn_result_t r; idnconv_strbuf_t buf1, buf2; idn_action_t actions1, actions2; int nl_trimmed; int local_ace_hack, idn_ace_hack; idn_converter_t conv; /* * See if the input codeset is an ACE. */ conv = idn_resconf_getidnconverter(conf1); if (conv != NULL && idn_converter_isasciicompatible(conv) && (flags & FLAG_SELECTIVE)) idn_ace_hack = 1; else idn_ace_hack = 0; if (conv != NULL) idn_converter_destroy(conv); conv = idn_resconf_getlocalconverter(conf1); if (conv != NULL && idn_converter_isasciicompatible(conv) && (flags & FLAG_SELECTIVE)) local_ace_hack = 1; else local_ace_hack = 0; if (conv != NULL) idn_converter_destroy(conv); actions1 = IDN_IDNCONV; if (local_ace_hack) { actions2 = IDN_IDNCONV; if (flags & FLAG_MAP) actions2 |= IDN_MAP; if (flags & FLAG_NORMALIZE) actions2 |= IDN_NORMALIZE; if (flags & FLAG_PROHIBITCHECK) actions2 |= IDN_PROHCHECK; if (flags & FLAG_UNASSIGNCHECK) actions2 |= IDN_UNASCHECK; if (flags & FLAG_BIDICHECK) actions2 |= IDN_BIDICHECK; if (flags & FLAG_ASCIICHECK) actions2 |= IDN_ASCCHECK; if (flags & FLAG_LENGTHCHECK) actions2 |= IDN_LENCHECK; } else { actions2 = IDN_LOCALCONV; } if (flags & FLAG_DELIMMAP) actions1 |= IDN_DELIMMAP; if (flags & FLAG_MAP) actions1 |= IDN_MAP; if (flags & FLAG_NORMALIZE) actions1 |= IDN_NORMALIZE; if (flags & FLAG_NORMALIZE) actions1 |= IDN_NORMALIZE; if (flags & FLAG_PROHIBITCHECK) actions1 |= IDN_PROHCHECK; if (flags & FLAG_UNASSIGNCHECK) actions1 |= IDN_UNASCHECK; if (flags & FLAG_BIDICHECK) actions1 |= IDN_BIDICHECK; if (flags & FLAG_ASCIICHECK) actions1 |= IDN_ASCCHECK; if (flags & FLAG_ROUNDTRIPCHECK) actions1 |= IDN_RTCHECK; strbuf_init(&buf1); strbuf_init(&buf2); line_number = 1; while (strbuf_getline(&buf1, fp) != NULL) { /* * Trim newline at the end. This is needed for * those ascii-comatible encodings such as UTF-5 or RACE * not to try converting newlines, which will result * in `invalid encoding' error. */ nl_trimmed = trim_newline(&buf1); /* * Treat input line as the string encoded in local * encoding and convert it to UTF-8 encoded string. */ if (local_ace_hack) { if (strbuf_copy(&buf2, strbuf_get(&buf1)) == NULL) r = idn_nomemory; else r = idn_success; } else { r = convert_line(&buf1, &buf2, conf1, IDN_LOCALCONV, 0); } if (r != idn_success) { errormsg("conversion failed at line %d: %s\n", line_number, idn_result_tostring(r)); goto error; } /* * Convert internationalized domain names in the line. */ if (idn_ace_hack) { r = convert_line(&buf2, &buf1, conf1, actions1, FLAG_REVERSE|FLAG_SELECTIVE); } else { r = convert_line(&buf2, &buf1, conf1, actions1, FLAG_REVERSE); } if (r != idn_success) { errormsg("conversion failed at line %d: %s\n", line_number, idn_result_tostring(r)); goto error; } if (!idn_utf8_isvalidstring(strbuf_get(&buf1))) { errormsg("conversion to utf-8 failed at line %d\n", line_number); goto error; } /* * Perform round trip check and convert to the output * codeset. */ if (local_ace_hack) { r = convert_line(&buf1, &buf2, conf2, actions2, FLAG_SELECTIVE); } else { r = convert_line(&buf1, &buf2, conf1, actions2, FLAG_REVERSE); } if (r != idn_success) { errormsg("error in nameprep or output conversion " "at line %d: %s\n", line_number, idn_result_tostring(r)); goto error; } fputs(strbuf_get(&buf2), stdout); if (nl_trimmed) putc('\n', stdout); if (flush_every_line) fflush(stdout); line_number++; } strbuf_reset(&buf1); strbuf_reset(&buf2); return (0); error: strbuf_reset(&buf1); strbuf_reset(&buf2); return (1); }
int cmd_checkout_index(int argc, const char **argv, const char *prefix) { int i; int newfd = -1; int all = 0; int read_from_stdin = 0; int prefix_length; int force = 0, quiet = 0, not_new = 0; struct option builtin_checkout_index_options[] = { OPT_BOOLEAN('a', "all", &all, "checks out all files in the index"), OPT_BOOLEAN('f', "force", &force, "forces overwrite of existing files"), OPT__QUIET(&quiet), OPT_BOOLEAN('n', "no-create", ¬_new, "don't checkout new files"), { OPTION_CALLBACK, 'u', "index", &newfd, NULL, "update stat information in the index file", PARSE_OPT_NOARG, option_parse_u }, { OPTION_CALLBACK, 'z', NULL, NULL, NULL, "paths are separated with NUL character", PARSE_OPT_NOARG, option_parse_z }, OPT_BOOLEAN(0, "stdin", &read_from_stdin, "read list of paths from the standard input"), OPT_BOOLEAN(0, "temp", &to_tempfile, "write the content to temporary files"), OPT_CALLBACK(0, "prefix", NULL, "string", "when creating files, prepend <string>", option_parse_prefix), OPT_CALLBACK(0, "stage", NULL, NULL, "copy out the files from named stage", option_parse_stage), OPT_END() }; git_config(git_default_config, NULL); state.base_dir = ""; prefix_length = prefix ? strlen(prefix) : 0; if (read_cache() < 0) { die("invalid cache"); } argc = parse_options(argc, argv, prefix, builtin_checkout_index_options, builtin_checkout_index_usage, 0); state.force = force; state.quiet = quiet; state.not_new = not_new; if (state.base_dir_len || to_tempfile) { /* when --prefix is specified we do not * want to update cache. */ if (state.refresh_cache) { rollback_lock_file(&lock_file); newfd = -1; } state.refresh_cache = 0; } /* Check out named files first */ for (i = 0; i < argc; i++) { const char *arg = argv[i]; const char *p; if (all) die("git checkout-index: don't mix '--all' and explicit filenames"); if (read_from_stdin) die("git checkout-index: don't mix '--stdin' and explicit filenames"); p = prefix_path(prefix, prefix_length, arg); checkout_file(p, prefix_length); if (p < arg || p > arg + strlen(arg)) free((char *)p); } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; if (all) die("git checkout-index: don't mix '--all' and '--stdin'"); 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); checkout_file(p, prefix_length); if (p < buf.buf || p > buf.buf + buf.len) free((char *)p); } strbuf_release(&nbuf); strbuf_release(&buf); } if (all) checkout_all(prefix, prefix_length); if (0 <= newfd && (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file))) die("Unable to write new index file"); return 0; }
static int push_refs(struct transport *transport, struct ref *remote_refs, int flags) { int force_all = flags & TRANSPORT_PUSH_FORCE; int mirror = flags & TRANSPORT_PUSH_MIRROR; struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; struct child_process *helper; struct ref *ref; if (!remote_refs) return 0; helper = get_helper(transport); if (!data->push) return 1; for (ref = remote_refs; ref; ref = ref->next) { if (ref->peer_ref) hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); else if (!mirror) continue; ref->deletion = is_null_sha1(ref->new_sha1); if (!ref->deletion && !hashcmp(ref->old_sha1, ref->new_sha1)) { ref->status = REF_STATUS_UPTODATE; continue; } if (force_all) ref->force = 1; strbuf_addstr(&buf, "push "); if (!ref->deletion) { if (ref->force) strbuf_addch(&buf, '+'); if (ref->peer_ref) strbuf_addstr(&buf, ref->peer_ref->name); else strbuf_addstr(&buf, sha1_to_hex(ref->new_sha1)); } strbuf_addch(&buf, ':'); strbuf_addstr(&buf, ref->name); strbuf_addch(&buf, '\n'); } if (buf.len == 0) return 0; transport->verbose = flags & TRANSPORT_PUSH_VERBOSE ? 1 : 0; standard_options(transport); if (flags & TRANSPORT_PUSH_DRY_RUN) { if (set_helper_option(transport, "dry-run", "true") != 0) die("helper %s does not support dry-run", data->name); } strbuf_addch(&buf, '\n'); if (write_in_full(helper->in, buf.buf, buf.len) != buf.len) exit(128); ref = remote_refs; while (1) { char *refname, *msg; int status; strbuf_reset(&buf); if (strbuf_getline(&buf, data->out, '\n') == EOF) exit(128); /* child died, message supplied already */ if (!buf.len) break; if (!prefixcmp(buf.buf, "ok ")) { status = REF_STATUS_OK; refname = buf.buf + 3; } else if (!prefixcmp(buf.buf, "error ")) { status = REF_STATUS_REMOTE_REJECT; refname = buf.buf + 6; } else die("expected ok/error, helper said '%s'\n", buf.buf); msg = strchr(refname, ' '); if (msg) { struct strbuf msg_buf = STRBUF_INIT; const char *end; *msg++ = '\0'; if (!unquote_c_style(&msg_buf, msg, &end)) msg = strbuf_detach(&msg_buf, NULL); else msg = xstrdup(msg); strbuf_release(&msg_buf); if (!strcmp(msg, "no match")) { status = REF_STATUS_NONE; free(msg); msg = NULL; } else if (!strcmp(msg, "up to date")) { status = REF_STATUS_UPTODATE; free(msg); msg = NULL; } else if (!strcmp(msg, "non-fast forward")) { status = REF_STATUS_REJECT_NONFASTFORWARD; free(msg); msg = NULL; } } if (ref) ref = find_ref_by_name(ref, refname); if (!ref) ref = find_ref_by_name(remote_refs, refname); if (!ref) { warning("helper reported unexpected status of %s", refname); continue; } ref->status = status; ref->remote_status = msg; } strbuf_release(&buf); return 0; }