static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data) { int is_tag = starts_with(path, "refs/tags/"); unsigned char peeled[20]; int is_annotated, prio; /* Reject anything outside refs/tags/ unless --all */ if (!all && !is_tag) return 0; /* Accept only tags that match the pattern, if given */ if (pattern && (!is_tag || wildmatch(pattern, path + 10, 0, NULL))) return 0; /* Is it annotated? */ if (!peel_ref(path, peeled)) { is_annotated = !!hashcmp(sha1, peeled); } else { hashcpy(peeled, sha1); is_annotated = 0; } /* * By default, we only use annotated tags, but with --tags * we fall back to lightweight ones (even without --tags, * we still remember lightweight ones, only to give hints * in an error message). --all allows any refs to be used. */ if (is_annotated) prio = 2; else if (is_tag) prio = 1; else prio = 0; add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1); return 0; }
/* UDisks2 is almost, but not quite, entirely unlike UDisks. * It would have been easy to make it backwards compatible, but where would be the fun in that? */ static BOOL udisks2_add_devices( const char *changed ) { DBusMessage *request, *reply; DBusMessageIter dict, iter, block; DBusError error; const char *udi; request = p_dbus_message_new_method_call( "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects" ); if (!request) return FALSE; p_dbus_error_init( &error ); reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error ); p_dbus_message_unref( request ); if (!reply) { WARN( "failed: %s\n", error.message ); p_dbus_error_free( &error ); return FALSE; } p_dbus_error_free( &error ); p_dbus_message_iter_init( reply, &dict ); if (p_dbus_message_iter_get_arg_type( &dict ) == DBUS_TYPE_ARRAY) { p_dbus_message_iter_recurse( &dict, &iter ); while ((udi = udisks_next_dict_entry( &iter, &block ))) { if (!starts_with( udi, "/org/freedesktop/UDisks2/block_devices/" )) continue; if (changed && strcmp( changed, udi )) continue; udisks2_add_device( udi, &dict, &block ); } } else WARN( "unexpected args in GetManagedObjects reply\n" ); p_dbus_message_unref( reply ); return TRUE; }
int refname_is_safe(const char *refname) { if (starts_with(refname, "refs/")) { char *buf; int result; buf = xmallocz(strlen(refname)); /* * Does the refname try to escape refs/? * For example: refs/foo/../bar is safe but refs/foo/../../bar * is not. */ result = !normalize_path_copy(buf, refname + strlen("refs/")); free(buf); return result; } while (*refname) { if (!isupper(*refname) && *refname != '_') return 0; refname++; } return 1; }
int parse_hide_refs_config(const char *var, const char *value, const char *section) { if (!strcmp("transfer.hiderefs", var) || /* NEEDSWORK: use parse_config_key() once both are merged */ (starts_with(var, section) && var[strlen(section)] == '.' && !strcmp(var + strlen(section), ".hiderefs"))) { char *ref; int len; if (!value) return config_error_nonbool(var); ref = xstrdup(value); len = strlen(ref); while (len && ref[len - 1] == '/') ref[--len] = '\0'; if (!hide_refs) { hide_refs = xcalloc(1, sizeof(*hide_refs)); hide_refs->strdup_strings = 1; } string_list_append(hide_refs, ref); } return 0; }
int plotstuff_run_command(plot_args_t* pargs, const char* cmd) { int i; anbool matched = FALSE; if (!cmd || (strlen(cmd) == 0) || (cmd[0] == '#')) { return 0; } if (!plotstuff_plot_layer(pargs, cmd)) { return 0; } for (i=0; i<pargs->NP; i++) { if (starts_with(cmd, pargs->plotters[i].name)) { char* cmdcmd; char* cmdargs; if (!split_string_once(cmd, " ", &cmdcmd, &cmdargs)) { //ERROR("Failed to split command \"%s\" into words\n", cmd); //return -1; cmdcmd = strdup(cmd); cmdargs = NULL; } logmsg("Command \"%s\", args \"%s\"\n", cmdcmd, cmdargs); if (pargs->plotters[i].command(cmdcmd, cmdargs, pargs, pargs->plotters[i].baton)) { ERROR("Plotter \"%s\" failed on command \"%s\"", pargs->plotters[i].name, cmd); return -1; } free(cmdcmd); free(cmdargs); } else continue; matched = TRUE; break; } if (!matched) { ERROR("Did not find a plotter for command \"%s\"", cmd); return -1; } return 0; }
/** 从指定的命令集中挑选出匹配名称的子集 */ std::vector<rc_ptr<ICommand> > IConsole::match_commands(const std::vector<rc_ptr<ICommand> >& commands, const std::string& to_match) { // 匹配命令 std::vector<rc_ptr<ICommand> > matched_cmds; for (size_t i = 0, size = commands.size(); i < size; ++i) { rc_ptr<ICommand> cmd = commands.at(i); assert(!cmd.is_null()); // 强匹配 if (nullptr != cmd->get_command_name() && to_match == cmd->get_command_name()) { matched_cmds.clear(); matched_cmds.push_back(std::move(cmd)); return matched_cmds; } // 弱匹配 if (nullptr != cmd->get_command_name() && starts_with(cmd->get_command_name(), to_match.c_str())) { matched_cmds.push_back(std::move(cmd)); } else if (nullptr != cmd->get_command_nick_names()) { const char** nn = cmd->get_command_nick_names(); for (size_t j = 0; nullptr != nn[j]; ++j) { if (to_match == nn[j]) { matched_cmds.push_back(std::move(cmd)); break; } } } } return matched_cmds; }
bool unmount_all(const std::string &dir) { int failed; struct mntent ent; char buf[1024]; for (int tries = 0; tries < MAX_UNMOUNT_TRIES; ++tries) { failed = 0; autoclose::file fp(setmntent("/proc/mounts", "r"), endmntent); if (!fp) { LOGE("Failed to read /proc/mounts: %s", strerror(errno)); return false; } while (getmntent_r(fp.get(), &ent, buf, sizeof(buf))) { if (starts_with(ent.mnt_dir, dir)) { //LOGD("Attempting to unmount %s", ent.mnt_dir); if (!util::umount(ent.mnt_dir)) { LOGE("Failed to unmount %s: %s", ent.mnt_dir, strerror(errno)); ++failed; } } } if (failed == 0) { return true; } // Retry } LOGE("Failed to unmount %d partitions", failed); return false; }
static const char *map_refspec(const char *ref, struct remote *remote, struct ref *local_refs) { struct ref *matched = NULL; /* Does "ref" uniquely name our ref? */ if (count_refspec_match(ref, local_refs, &matched) != 1) return ref; if (remote->push) { struct refspec query; memset(&query, 0, sizeof(struct refspec)); query.src = matched->name; if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) && query.dst) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s%s:%s", query.force ? "+" : "", query.src, query.dst); return strbuf_detach(&buf, NULL); } } if (push_default == PUSH_DEFAULT_UPSTREAM && starts_with(matched->name, "refs/heads/")) { struct branch *branch = branch_get(matched->name + 11); if (branch->merge_nr == 1 && branch->merge[0]->src) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s:%s", ref, branch->merge[0]->src); return strbuf_detach(&buf, NULL); } } return ref; }
static int replace_parents(struct strbuf *buf, int argc, const char **argv) { struct strbuf new_parents = STRBUF_INIT; const char *parent_start, *parent_end; int i; /* find existing parents */ parent_start = buf->buf; parent_start += GIT_SHA1_HEXSZ + 6; /* "tree " + "hex sha1" + "\n" */ parent_end = parent_start; while (starts_with(parent_end, "parent ")) parent_end += 48; /* "parent " + "hex sha1" + "\n" */ /* prepare new parents */ for (i = 0; i < argc; i++) { struct object_id oid; if (get_oid(argv[i], &oid) < 0) { strbuf_release(&new_parents); return error(_("Not a valid object name: '%s'"), argv[i]); } if (!lookup_commit_reference(&oid)) { strbuf_release(&new_parents); return error(_("could not parse %s"), argv[i]); } strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid)); } /* replace existing parents with new ones */ strbuf_splice(buf, parent_start - buf->buf, parent_end - parent_start, new_parents.buf, new_parents.len); strbuf_release(&new_parents); return 0; }
int main (int argc, char **argv) { unsigned int i, newline = 1, as_int = 0, as_double = 0; char *arg, *opt, *nl, *yesnl = "\n", *nonl = ""; for (i=1; i<argc; i++) { arg = argv[i]; if (!starts_with(arg,"-")) die("Unknown argument %s\n",arg); opt = arg; while (*opt && opt[0] == '-') opt++; if (is_in(opt,"int","i",(char*)NULL)) { as_int = 1; } else if (is_in(opt,"double","d",(char*)NULL)) { as_double = 1; } else if (is_in(opt,"b","bare","nonl","no-newline",(char*)NULL)) { newline = 0; } else { die("Unknown option %s\n",opt); } } nl = newline ? yesnl : nonl; if (!as_int) as_double++; if (as_double) printf("%f%s",NOW(),nl); if (as_int) printf("%.0f%s",NOW(),nl); return 0; }
const char *cgit_repobasename(const char *reponame) { /* I assume we don't need to store more than one repo basename */ static char rvbuf[1024]; int p; const char *rv; strncpy(rvbuf, reponame, sizeof(rvbuf)); if (rvbuf[sizeof(rvbuf)-1]) die("cgit_repobasename: truncated repository name '%s'", reponame); p = strlen(rvbuf)-1; /* strip trailing slashes */ while (p && rvbuf[p] == '/') rvbuf[p--] = 0; /* strip trailing .git */ if (p >= 3 && starts_with(&rvbuf[p-3], ".git")) { p -= 3; rvbuf[p--] = 0; } /* strip more trailing slashes if any */ while ( p && rvbuf[p] == '/') rvbuf[p--] = 0; /* find last slash in the remaining string */ rv = strrchr(rvbuf,'/'); if (rv) return ++rv; return rvbuf; }
static int git_tag_config(const char *var, const char *value, void *cb) { int status; struct ref_sorting **sorting_tail = (struct ref_sorting **)cb; if (!strcmp(var, "tag.sort")) { if (!value) return config_error_nonbool(var); parse_sorting_string(value, sorting_tail); return 0; } status = git_gpg_config(var, value, cb); if (status) return status; if (!strcmp(var, "tag.forcesignannotated")) { force_sign_annotate = git_config_bool(var, value); return 0; } if (starts_with(var, "column.")) return git_column_config(var, value, "tag", &colopts); return git_default_config(var, value, cb); }
void ConfigureLoggers(const Config& config) { const ConfigProperties* props = config.get_child("logs"); if (!props) { THROW_EXCEPTION("Cannot find logs config section"); } stringstream stream; for (auto i = props->begin(); i != props->end(); ++i) { string key = i->first; string value = i->second.get_value<string>(); if (!starts_with(key, "log4cplus.")) { key = "log4cplus." + key; } stream << key << "=" << value << endl; } log4cplus::PropertyConfigurator configurator(stream); configurator.configure(); }
static enum ack_type get_ack(int fd, unsigned char *result_sha1) { int len; char *line = packet_read_line(fd, &len); if (!len) die("git fetch-pack: expected ACK/NAK, got EOF"); if (!strcmp(line, "NAK")) return NAK; if (starts_with(line, "ACK ")) { if (!get_sha1_hex(line+4, result_sha1)) { if (len < 45) return ACK; if (strstr(line+45, "continue")) return ACK_continue; if (strstr(line+45, "common")) return ACK_common; if (strstr(line+45, "ready")) return ACK_ready; return ACK; } } die("git fetch_pack: expected ACK/NAK, got '%s'", line); }
static void credit_people(struct strbuf *out, struct string_list *them, int kind) { const char *label; const char *me; if (kind == 'a') { label = "By"; me = git_author_info(IDENT_NO_DATE); } else { label = "Via"; me = git_committer_info(IDENT_NO_DATE); } if (!them->nr || (them->nr == 1 && me && skip_prefix(me, them->items->string, &me) && starts_with(me, " <"))) return; strbuf_addf(out, "\n%c %s ", comment_line_char, label); add_people_count(out, them); }
/* * Identify the command used at the shell */ int parse_command(char *buf) { int cmd; if (starts_with(buf, CMD_CHILD_PID)) cmd = CHILD_PID; else if (starts_with(buf, CMD_P2P)) cmd = P2P; else if (starts_with(buf, CMD_LIST_USERS)) cmd = LIST_USERS; else if (starts_with(buf, CMD_ADD_USER)) cmd = ADD_USER; else if (starts_with(buf, CMD_EXIT)) cmd = EXIT; else if (starts_with(buf, CMD_KICK)) cmd = KICK; else cmd = BROADCAST; return cmd; }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; int depth = 0; int has_non_tip = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; unsigned char sha1_buf[20]; char *line = packet_read_line(0, NULL); reset_timeout(); if (!line) break; if (starts_with(line, "shallow ")) { unsigned char sha1[20]; struct object *object; if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); object = parse_object(sha1); if (!object) continue; if (object->type != OBJ_COMMIT) die("invalid shallow object %s", sha1_to_hex(sha1)); if (!(object->flags & CLIENT_SHALLOW)) { object->flags |= CLIENT_SHALLOW; add_object_array(object, NULL, &shallows); } continue; } if (starts_with(line, "deepen ")) { char *end; depth = strtol(line + 7, &end, 0); if (end == line + 7 || depth <= 0) die("Invalid deepen: %s", line); continue; } if (!starts_with(line, "want ") || get_sha1_hex(line+5, sha1_buf)) die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); features = line + 45; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) multi_ack = 1; if (parse_feature_request(features, "no-done")) no_done = 1; if (parse_feature_request(features, "thin-pack")) use_thin_pack = 1; if (parse_feature_request(features, "ofs-delta")) use_ofs_delta = 1; if (parse_feature_request(features, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (parse_feature_request(features, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (parse_feature_request(features, "no-progress")) no_progress = 1; if (parse_feature_request(features, "include-tag")) use_include_tag = 1; o = parse_object(sha1_buf); if (!o) die("git upload-pack: not our ref %s", sha1_to_hex(sha1_buf)); if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!is_our_ref(o)) has_non_tip = 1; add_object_array(o, NULL, &want_obj); } } /* * We have sent all our refs already, and the other end * should have chosen out of them. When we are operating * in the stateless RPC mode, however, their choice may * have been based on the set of older refs advertised * by another process that handled the initial request. */ if (has_non_tip) check_non_tip(); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && shallows.nr == 0) return; if (depth > 0) { struct commit_list *result = NULL, *backup = NULL; int i; if (depth == INFINITE_DEPTH && !is_repository_shallow()) for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; object->flags |= NOT_SHALLOW; } else backup = result = get_shallow_commits(&want_obj, depth, SHALLOW, NOT_SHALLOW); while (result) { struct object *object = &result->item->object; if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { packet_write(1, "shallow %s", sha1_to_hex(object->sha1)); register_shallow(object->sha1); shallow_nr++; } result = result->next; } free_commit_list(backup); for (i = 0; i < shallows.nr; i++) { struct object *object = shallows.objects[i].item; if (object->flags & NOT_SHALLOW) { struct commit_list *parents; packet_write(1, "unshallow %s", sha1_to_hex(object->sha1)); object->flags &= ~CLIENT_SHALLOW; /* make sure the real parents are parsed */ unregister_shallow(object->sha1); object->parsed = 0; parse_commit_or_die((struct commit *)object); parents = ((struct commit *)object)->parents; while (parents) { add_object_array(&parents->item->object, NULL, &want_obj); parents = parents->next; } add_object_array(object, NULL, &extra_edge_obj); } /* make sure commit traversal conforms to client */ register_shallow(object->sha1); } packet_flush(1); } else if (shallows.nr > 0) { int i; for (i = 0; i < shallows.nr; i++) register_shallow(shallows.objects[i].item->sha1); } shallow_nr += shallows.nr; free(shallows.objects); }
static int get_common_commits(void) { unsigned char sha1[20]; char last_hex[41]; int got_common = 0; int got_other = 0; int sent_ready = 0; save_commit_buffer = 0; for (;;) { char *line = packet_read_line(0, NULL); reset_timeout(); if (!line) { if (multi_ack == 2 && got_common && !got_other && ok_to_give_up()) { sent_ready = 1; packet_write(1, "ACK %s ready\n", last_hex); } if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); if (no_done && sent_ready) { packet_write(1, "ACK %s\n", last_hex); return 0; } if (stateless_rpc) exit(0); got_common = 0; got_other = 0; continue; } if (starts_with(line, "have ")) { switch (got_sha1(line+5, sha1)) { case -1: /* they have what we do not */ got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); if (multi_ack == 2) { sent_ready = 1; packet_write(1, "ACK %s ready\n", hex); } else packet_write(1, "ACK %s continue\n", hex); } break; default: got_common = 1; memcpy(last_hex, sha1_to_hex(sha1), 41); if (multi_ack == 2) packet_write(1, "ACK %s common\n", last_hex); else if (multi_ack) packet_write(1, "ACK %s continue\n", last_hex); else if (have_obj.nr == 1) packet_write(1, "ACK %s\n", last_hex); break; } continue; } if (!strcmp(line, "done")) { if (have_obj.nr > 0) { if (multi_ack) packet_write(1, "ACK %s\n", last_hex); return 0; } packet_write(1, "NAK\n"); return -1; } die("git upload-pack: expected SHA1 list, got '%s'", line); } }
/* * Try to read the location of the git directory from the .git file, * return path to git directory if found. * * On failure, if return_error_code is not NULL, return_error_code * will be set to an error code and NULL will be returned. If * return_error_code is NULL the function will die instead (for most * cases). */ const char *read_gitfile_gently(const char *path, int *return_error_code) { const int max_file_size = 1 << 20; /* 1MB */ int error_code = 0; char *buf = NULL; char *dir = NULL; const char *slash; struct stat st; int fd; ssize_t len; if (stat(path, &st)) { error_code = READ_GITFILE_ERR_STAT_FAILED; goto cleanup_return; } if (!S_ISREG(st.st_mode)) { error_code = READ_GITFILE_ERR_NOT_A_FILE; goto cleanup_return; } if (st.st_size > max_file_size) { error_code = READ_GITFILE_ERR_TOO_LARGE; goto cleanup_return; } fd = open(path, O_RDONLY); if (fd < 0) { error_code = READ_GITFILE_ERR_OPEN_FAILED; goto cleanup_return; } buf = xmalloc(st.st_size + 1); len = read_in_full(fd, buf, st.st_size); close(fd); if (len != st.st_size) { error_code = READ_GITFILE_ERR_READ_FAILED; goto cleanup_return; } buf[len] = '\0'; if (!starts_with(buf, "gitdir: ")) { error_code = READ_GITFILE_ERR_INVALID_FORMAT; goto cleanup_return; } while (buf[len - 1] == '\n' || buf[len - 1] == '\r') len--; if (len < 9) { error_code = READ_GITFILE_ERR_NO_PATH; goto cleanup_return; } buf[len] = '\0'; dir = buf + 8; if (!is_absolute_path(dir) && (slash = strrchr(path, '/'))) { size_t pathlen = slash+1 - path; dir = xstrfmt("%.*s%.*s", (int)pathlen, path, (int)(len - 8), buf + 8); free(buf); buf = dir; } if (!is_git_directory(dir)) { error_code = READ_GITFILE_ERR_NOT_A_REPO; goto cleanup_return; } update_linked_gitdir(path, dir); path = real_path(dir); cleanup_return: if (return_error_code) *return_error_code = error_code; else if (error_code) { switch (error_code) { case READ_GITFILE_ERR_STAT_FAILED: case READ_GITFILE_ERR_NOT_A_FILE: /* non-fatal; follow return path */ break; case READ_GITFILE_ERR_OPEN_FAILED: die_errno("Error opening '%s'", path); case READ_GITFILE_ERR_TOO_LARGE: die("Too large to be a .git file: '%s'", path); case READ_GITFILE_ERR_READ_FAILED: die("Error reading %s", path); case READ_GITFILE_ERR_INVALID_FORMAT: die("Invalid gitfile format: %s", path); case READ_GITFILE_ERR_NO_PATH: die("No path in gitfile: %s", path); case READ_GITFILE_ERR_NOT_A_REPO: die("Not a git repository: %s", dir); default: assert(0); } } free(buf); return error_code ? NULL : path; }
/* * Move the iterator to the next record in the snapshot, without * respect for whether the record is actually required by the current * iteration. Adjust the fields in `iter` and return `ITER_OK` or * `ITER_DONE`. This function does not free the iterator in the case * of `ITER_DONE`. */ static int next_record(struct packed_ref_iterator *iter) { const char *p = iter->pos, *eol; strbuf_reset(&iter->refname_buf); if (iter->pos == iter->eof) return ITER_DONE; iter->base.flags = REF_ISPACKED; if (iter->eof - p < GIT_SHA1_HEXSZ + 2 || parse_oid_hex(p, &iter->oid, &p) || !isspace(*p++)) die_invalid_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); eol = memchr(p, '\n', iter->eof - p); if (!eol) die_unterminated_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); strbuf_add(&iter->refname_buf, p, eol - p); iter->base.refname = iter->refname_buf.buf; if (check_refname_format(iter->base.refname, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(iter->base.refname)) die("packed refname is dangerous: %s", iter->base.refname); oidclr(&iter->oid); iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN; } if (iter->snapshot->peeled == PEELED_FULLY || (iter->snapshot->peeled == PEELED_TAGS && starts_with(iter->base.refname, "refs/tags/"))) iter->base.flags |= REF_KNOWS_PEELED; iter->pos = eol + 1; if (iter->pos < iter->eof && *iter->pos == '^') { p = iter->pos + 1; if (iter->eof - p < GIT_SHA1_HEXSZ + 1 || parse_oid_hex(p, &iter->peeled, &p) || *p++ != '\n') die_invalid_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); iter->pos = p; /* * Regardless of what the file header said, we * definitely know the value of *this* reference. But * we suppress it if the reference is broken: */ if ((iter->base.flags & REF_ISBROKEN)) { oidclr(&iter->peeled); iter->base.flags &= ~REF_KNOWS_PEELED; } else { iter->base.flags |= REF_KNOWS_PEELED; } } else { oidclr(&iter->peeled); } return ITER_OK; }
/* * Fill the given strbuf with the notes associated with the given object. * * If the given notes_tree structure is not initialized, it will be auto- * initialized to the default value (see documentation for init_notes() above). * If the given notes_tree is NULL, the internal/default notes_tree will be * used instead. * * (raw != 0) gives the %N userformat; otherwise, the note message is given * for human consumption. */ static void format_note(struct notes_tree *t, const struct object_id *object_oid, struct strbuf *sb, const char *output_encoding, int raw) { static const char utf8[] = "utf-8"; const struct object_id *oid; char *msg, *msg_p; unsigned long linelen, msglen; enum object_type type; if (!t) t = &default_notes_tree; if (!t->initialized) init_notes(t, NULL, NULL, 0); oid = get_note(t, object_oid); if (!oid) return; if (!(msg = read_object_file(oid, &type, &msglen)) || type != OBJ_BLOB) { free(msg); return; } if (output_encoding && *output_encoding && !is_encoding_utf8(output_encoding)) { char *reencoded = reencode_string(msg, output_encoding, utf8); if (reencoded) { free(msg); msg = reencoded; msglen = strlen(msg); } } /* we will end the annotation by a newline anyway */ if (msglen && msg[msglen - 1] == '\n') msglen--; if (!raw) { const char *ref = t->ref; if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) { strbuf_addstr(sb, "\nNotes:\n"); } else { if (starts_with(ref, "refs/")) ref += 5; if (starts_with(ref, "notes/")) ref += 6; strbuf_addf(sb, "\nNotes (%s):\n", ref); } } for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) { linelen = strchrnul(msg_p, '\n') - msg_p; if (!raw) strbuf_addstr(sb, " "); strbuf_add(sb, msg_p, linelen); strbuf_addch(sb, '\n'); } free(msg); }
static void print_summary(const char *prefix, const unsigned char *sha1, int initial_commit) { struct rev_info rev; struct commit *commit; struct strbuf format = STRBUF_INIT; unsigned char junk_sha1[20]; const char *head; struct pretty_print_context pctx = {0}; struct strbuf author_ident = STRBUF_INIT; struct strbuf committer_ident = STRBUF_INIT; commit = lookup_commit(sha1); if (!commit) die(_("couldn't look up newly created commit")); if (parse_commit(commit)) die(_("could not parse newly created commit")); strbuf_addstr(&format, "format:%h] %s"); format_commit_message(commit, "%an <%ae>", &author_ident, &pctx); format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx); if (strbuf_cmp(&author_ident, &committer_ident)) { strbuf_addstr(&format, "\n Author: "); strbuf_addbuf_percentquote(&format, &author_ident); } if (!committer_ident_sufficiently_given()) { strbuf_addstr(&format, "\n Committer: "); strbuf_addbuf_percentquote(&format, &committer_ident); if (advice_implicit_identity) { strbuf_addch(&format, '\n'); strbuf_addstr(&format, _(implicit_ident_advice)); } } strbuf_release(&author_ident); strbuf_release(&committer_ident); init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.diff = 1; rev.diffopt.output_format = DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY; rev.verbose_header = 1; rev.show_root_diff = 1; get_commit_format(format.buf, &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL); printf("[%s%s ", starts_with(head, "refs/heads/") ? head + 11 : !strcmp(head, "HEAD") ? _("detached HEAD") : head, initial_commit ? _(" (root-commit)") : ""); if (!log_tree_commit(&rev, commit)) { rev.always_show_header = 1; rev.use_terminator = 1; log_tree_commit(&rev, commit); } strbuf_release(&format); }
struct transport *transport_get(struct remote *remote, const char *url) { const char *helper; struct transport *ret = xcalloc(1, sizeof(*ret)); ret->progress = isatty(2); if (!remote) BUG("No remote provided to transport_get()"); ret->got_remote_refs = 0; ret->remote = remote; helper = remote->foreign_vcs; if (!url && remote->url) url = remote->url[0]; ret->url = url; /* maybe it is a foreign URL? */ if (url) { const char *p = url; while (is_urlschemechar(p == url, *p)) p++; if (starts_with(p, "::")) helper = xstrndup(url, p - url); } if (helper) { transport_helper_init(ret, helper); } else if (starts_with(url, "rsync:")) { die(_("git-over-rsync is no longer supported")); } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); transport_check_allowed("file"); ret->data = data; ret->vtable = &bundle_vtable; ret->smart_options = NULL; } else if (!is_url(url) || starts_with(url, "file://") || starts_with(url, "git://") || starts_with(url, "ssh://") || starts_with(url, "git+ssh://") /* deprecated - do not use */ || starts_with(url, "ssh+git://") /* deprecated - do not use */ ) { /* * These are builtin smart transports; "allowed" transports * will be checked individually in git_connect. */ struct git_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->vtable = &builtin_smart_vtable; ret->smart_options = &(data->options); data->conn = NULL; data->got_remote_heads = 0; } else { /* Unknown protocol in URL. Pass to external handler. */ int len = external_specification_len(url); char *handler = xmemdupz(url, len); transport_helper_init(ret, handler); } if (ret->smart_options) { ret->smart_options->thin = 1; ret->smart_options->uploadpack = "git-upload-pack"; if (remote->uploadpack) ret->smart_options->uploadpack = remote->uploadpack; ret->smart_options->receivepack = "git-receive-pack"; if (remote->receivepack) ret->smart_options->receivepack = remote->receivepack; } return ret; }
static struct match_attr *parse_attr_line(const char *line, const char *src, int lineno, int macro_ok) { int namelen; int num_attr, i; const char *cp, *name, *states; struct match_attr *res = NULL; int is_macro; struct strbuf pattern = STRBUF_INIT; cp = line + strspn(line, blank); if (!*cp || *cp == '#') return NULL; name = cp; if (*cp == '"' && !unquote_c_style(&pattern, name, &states)) { name = pattern.buf; namelen = pattern.len; } else { namelen = strcspn(name, blank); states = name + namelen; } if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen && starts_with(name, ATTRIBUTE_MACRO_PREFIX)) { if (!macro_ok) { fprintf(stderr, "%s not allowed: %s:%d\n", name, src, lineno); goto fail_return; } is_macro = 1; name += strlen(ATTRIBUTE_MACRO_PREFIX); name += strspn(name, blank); namelen = strcspn(name, blank); if (!attr_name_valid(name, namelen)) { report_invalid_attr(name, namelen, src, lineno); goto fail_return; } } else is_macro = 0; states += strspn(states, blank); /* First pass to count the attr_states */ for (cp = states, num_attr = 0; *cp; num_attr++) { cp = parse_attr(src, lineno, cp, NULL); if (!cp) goto fail_return; } res = xcalloc(1, sizeof(*res) + sizeof(struct attr_state) * num_attr + (is_macro ? 0 : namelen + 1)); if (is_macro) { res->u.attr = git_attr_internal(name, namelen); } else { char *p = (char *)&(res->state[num_attr]); memcpy(p, name, namelen); res->u.pat.pattern = p; parse_exclude_pattern(&res->u.pat.pattern, &res->u.pat.patternlen, &res->u.pat.flags, &res->u.pat.nowildcardlen); if (res->u.pat.flags & EXC_FLAG_NEGATIVE) { warning(_("Negative patterns are ignored in git attributes\n" "Use '\\!' for literal leading exclamation.")); goto fail_return; } } res->is_macro = is_macro; res->num_attr = num_attr; /* Second pass to fill the attr_states */ for (cp = states, i = 0; *cp; i++) { cp = parse_attr(src, lineno, cp, &(res->state[i])); } strbuf_release(&pattern); return res; fail_return: strbuf_release(&pattern); free(res); return NULL; }
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, int argc, const char **argv) { char tmpdir[PATH_MAX]; struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT; struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT; struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT; struct strbuf wtdir = STRBUF_INIT; char *lbase_dir, *rbase_dir; size_t ldir_len, rdir_len, wtdir_len; const char *workdir, *tmp; int ret = 0, i; FILE *fp; struct hashmap working_tree_dups, submodules, symlinks2; struct hashmap_iter iter; struct pair_entry *entry; struct index_state wtindex; struct checkout lstate, rstate; int rc, flags = RUN_GIT_CMD, err = 0; struct child_process child = CHILD_PROCESS_INIT; const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL }; struct hashmap wt_modified, tmp_modified; int indices_loaded = 0; workdir = get_git_work_tree(); /* Setup temp directories */ tmp = getenv("TMPDIR"); xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp"); if (!mkdtemp(tmpdir)) return error("could not create '%s'", tmpdir); strbuf_addf(&ldir, "%s/left/", tmpdir); strbuf_addf(&rdir, "%s/right/", tmpdir); strbuf_addstr(&wtdir, workdir); if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1])) strbuf_addch(&wtdir, '/'); mkdir(ldir.buf, 0700); mkdir(rdir.buf, 0700); memset(&wtindex, 0, sizeof(wtindex)); memset(&lstate, 0, sizeof(lstate)); lstate.base_dir = lbase_dir = xstrdup(ldir.buf); lstate.base_dir_len = ldir.len; lstate.force = 1; memset(&rstate, 0, sizeof(rstate)); rstate.base_dir = rbase_dir = xstrdup(rdir.buf); rstate.base_dir_len = rdir.len; rstate.force = 1; ldir_len = ldir.len; rdir_len = rdir.len; wtdir_len = wtdir.len; hashmap_init(&working_tree_dups, (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0); hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0); hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0); child.no_stdin = 1; child.git_cmd = 1; child.use_shell = 0; child.clean_on_exit = 1; child.dir = prefix; child.out = -1; argv_array_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z", NULL); for (i = 0; i < argc; i++) argv_array_push(&child.args, argv[i]); if (start_command(&child)) die("could not obtain raw diff"); fp = xfdopen(child.out, "r"); /* Build index info for left and right sides of the diff */ i = 0; while (!strbuf_getline_nul(&info, fp)) { int lmode, rmode; struct object_id loid, roid; char status; const char *src_path, *dst_path; if (starts_with(info.buf, "::")) die(N_("combined diff formats('-c' and '--cc') are " "not supported in\n" "directory diff mode('-d' and '--dir-diff').")); if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid, &status)) break; if (strbuf_getline_nul(&lpath, fp)) break; src_path = lpath.buf; i++; if (status != 'C' && status != 'R') { dst_path = src_path; } else { if (strbuf_getline_nul(&rpath, fp)) break; dst_path = rpath.buf; } if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) { strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&loid)); add_left_or_right(&submodules, src_path, buf.buf, 0); strbuf_reset(&buf); strbuf_addf(&buf, "Subproject commit %s", oid_to_hex(&roid)); if (!oidcmp(&loid, &roid)) strbuf_addstr(&buf, "-dirty"); add_left_or_right(&submodules, dst_path, buf.buf, 1); continue; } if (S_ISLNK(lmode)) { char *content = get_symlink(&loid, src_path); add_left_or_right(&symlinks2, src_path, content, 0); free(content); } if (S_ISLNK(rmode)) { char *content = get_symlink(&roid, dst_path); add_left_or_right(&symlinks2, dst_path, content, 1); free(content); } if (lmode && status != 'C') { if (checkout_path(lmode, &loid, src_path, &lstate)) { ret = error("could not write '%s'", src_path); goto finish; } } if (rmode && !S_ISLNK(rmode)) { struct working_tree_entry *entry; /* Avoid duplicate working_tree entries */ FLEX_ALLOC_STR(entry, path, dst_path); hashmap_entry_init(entry, strhash(dst_path)); if (hashmap_get(&working_tree_dups, entry, NULL)) { free(entry); continue; } hashmap_add(&working_tree_dups, entry); if (!use_wt_file(workdir, dst_path, &roid)) { if (checkout_path(rmode, &roid, dst_path, &rstate)) { ret = error("could not write '%s'", dst_path); goto finish; } } else if (!is_null_oid(&roid)) { /* * Changes in the working tree need special * treatment since they are not part of the * index. */ struct cache_entry *ce2 = make_cache_entry(rmode, roid.hash, dst_path, 0, 0); add_index_entry(&wtindex, ce2, ADD_CACHE_JUST_APPEND); add_path(&rdir, rdir_len, dst_path); if (ensure_leading_directories(rdir.buf)) { ret = error("could not create " "directory for '%s'", dst_path); goto finish; } add_path(&wtdir, wtdir_len, dst_path); if (symlinks) { if (symlink(wtdir.buf, rdir.buf)) { ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } } else { struct stat st; if (stat(wtdir.buf, &st)) st.st_mode = 0644; if (copy_file(rdir.buf, wtdir.buf, st.st_mode)) { ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } } } } } fclose(fp); fp = NULL; if (finish_command(&child)) { ret = error("error occurred running diff --raw"); goto finish; } if (!i) goto finish; /* * Changes to submodules require special treatment.This loop writes a * temporary file to both the left and right directories to show the * change in the recorded SHA1 for the submodule. */ hashmap_iter_init(&submodules, &iter); while ((entry = hashmap_iter_next(&iter))) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); write_file(ldir.buf, "%s", entry->left); } if (*entry->right) { add_path(&rdir, rdir_len, entry->path); ensure_leading_directories(rdir.buf); write_file(rdir.buf, "%s", entry->right); } } /* * Symbolic links require special treatment.The standard "git diff" * shows only the link itself, not the contents of the link target. * This loop replicates that behavior. */ hashmap_iter_init(&symlinks2, &iter); while ((entry = hashmap_iter_next(&iter))) { if (*entry->left) { add_path(&ldir, ldir_len, entry->path); ensure_leading_directories(ldir.buf); write_file(ldir.buf, "%s", entry->left); } if (*entry->right) { add_path(&rdir, rdir_len, entry->path); ensure_leading_directories(rdir.buf); write_file(rdir.buf, "%s", entry->right); } } strbuf_release(&buf); strbuf_setlen(&ldir, ldir_len); helper_argv[1] = ldir.buf; strbuf_setlen(&rdir, rdir_len); helper_argv[2] = rdir.buf; if (extcmd) { helper_argv[0] = extcmd; flags = 0; } else setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1); rc = run_command_v_opt(helper_argv, flags); /* * If the diff includes working copy files and those * files were modified during the diff, then the changes * should be copied back to the working tree. * Do not copy back files when symlinks are used and the * external tool did not replace the original link with a file. * * These hashes are loaded lazily since they aren't needed * in the common case of --symlinks and the difftool updating * files through the symlink. */ hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp, NULL, wtindex.cache_nr); hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp, NULL, wtindex.cache_nr); for (i = 0; i < wtindex.cache_nr; i++) { struct hashmap_entry dummy; const char *name = wtindex.cache[i]->name; struct stat st; add_path(&rdir, rdir_len, name); if (lstat(rdir.buf, &st)) continue; if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode)) continue; if (!indices_loaded) { static struct lock_file lock; strbuf_reset(&buf); strbuf_addf(&buf, "%s/wtindex", tmpdir); if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 || write_locked_index(&wtindex, &lock, COMMIT_LOCK)) { ret = error("could not write %s", buf.buf); rollback_lock_file(&lock); goto finish; } changed_files(&wt_modified, buf.buf, workdir); strbuf_setlen(&rdir, rdir_len); changed_files(&tmp_modified, buf.buf, rdir.buf); add_path(&rdir, rdir_len, name); indices_loaded = 1; } hashmap_entry_init(&dummy, strhash(name)); if (hashmap_get(&tmp_modified, &dummy, name)) { add_path(&wtdir, wtdir_len, name); if (hashmap_get(&wt_modified, &dummy, name)) { warning(_("both files modified: '%s' and '%s'."), wtdir.buf, rdir.buf); warning(_("working tree file has been left.")); warning("%s", ""); err = 1; } else if (unlink(wtdir.buf) || copy_file(wtdir.buf, rdir.buf, st.st_mode)) warning_errno(_("could not copy '%s' to '%s'"), rdir.buf, wtdir.buf); } } if (err) { warning(_("temporary files exist in '%s'."), tmpdir); warning(_("you may want to cleanup or recover these.")); exit(1); } else exit_cleanup(tmpdir, rc); finish: if (fp) fclose(fp); free(lbase_dir); free(rbase_dir); strbuf_release(&ldir); strbuf_release(&rdir); strbuf_release(&wtdir); strbuf_release(&buf); return ret; }
const char *help_unknown_cmd(const char *cmd) { int i, n, best_similarity = 0; struct cmdnames main_cmds, other_cmds; memset(&main_cmds, 0, sizeof(main_cmds)); memset(&other_cmds, 0, sizeof(other_cmds)); memset(&aliases, 0, sizeof(aliases)); git_config(git_unknown_cmd_config, NULL); load_command_list("git-", &main_cmds, &other_cmds); add_cmd_list(&main_cmds, &aliases); add_cmd_list(&main_cmds, &other_cmds); qsort(main_cmds.names, main_cmds.cnt, sizeof(*main_cmds.names), cmdname_compare); uniq(&main_cmds); /* This abuses cmdname->len for levenshtein distance */ for (i = 0, n = 0; i < main_cmds.cnt; i++) { int cmp = 0; /* avoid compiler stupidity */ const char *candidate = main_cmds.names[i]->name; /* * An exact match means we have the command, but * for some reason exec'ing it gave us ENOENT; probably * it's a bad interpreter in the #! line. */ if (!strcmp(candidate, cmd)) die(_(bad_interpreter_advice), cmd, cmd); /* Does the candidate appear in common_cmds list? */ while (n < ARRAY_SIZE(common_cmds) && (cmp = strcmp(common_cmds[n].name, candidate)) < 0) n++; if ((n < ARRAY_SIZE(common_cmds)) && !cmp) { /* Yes, this is one of the common commands */ n++; /* use the entry from common_cmds[] */ if (starts_with(candidate, cmd)) { /* Give prefix match a very good score */ main_cmds.names[i]->len = 0; continue; } } main_cmds.names[i]->len = levenshtein(cmd, candidate, 0, 2, 1, 3) + 1; } qsort(main_cmds.names, main_cmds.cnt, sizeof(*main_cmds.names), levenshtein_compare); if (!main_cmds.cnt) die(_("Uh oh. Your system reports no Git commands at all.")); /* skip and count prefix matches */ for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++) ; /* still counting */ if (main_cmds.cnt <= n) { /* prefix matches with everything? that is too ambiguous */ best_similarity = SIMILARITY_FLOOR + 1; } else { /* count all the most similar ones */ for (best_similarity = main_cmds.names[n++]->len; (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len); n++) ; /* still counting */ } if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) { const char *assumed = main_cmds.names[0]->name; main_cmds.names[0] = NULL; clean_cmdnames(&main_cmds); fprintf_ln(stderr, _("WARNING: You called a Git command named '%s', " "which does not exist.\n" "Continuing under the assumption that you meant '%s'"), cmd, assumed); if (autocorrect > 0) { fprintf_ln(stderr, _("in %0.1f seconds automatically..."), (float)autocorrect/10.0); poll(NULL, 0, autocorrect * 100); } return assumed; } fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd); if (SIMILAR_ENOUGH(best_similarity)) { fprintf_ln(stderr, Q_("\nDid you mean this?", "\nDid you mean one of these?", n)); for (i = 0; i < n; i++) fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); } exit(1); }
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, const struct option *options) { const struct option *all_opts = options; const char *arg_end = strchrnul(arg, '='); const struct option *abbrev_option = NULL, *ambiguous_option = NULL; int abbrev_flags = 0, ambiguous_flags = 0; for (; options->type != OPTION_END; options++) { const char *rest, *long_name = options->long_name; int flags = 0, opt_flags = 0; if (!long_name) continue; again: if (!skip_prefix(arg, long_name, &rest)) rest = NULL; if (options->type == OPTION_ARGUMENT) { if (!rest) continue; if (*rest == '=') return opterror(options, "takes no value", flags); if (*rest) continue; p->out[p->cpidx++] = arg - 2; return 0; } if (!rest) { /* abbreviated? */ if (!strncmp(long_name, arg, arg_end - arg)) { is_abbreviated: if (abbrev_option) { /* * If this is abbreviated, it is * ambiguous. So when there is no * exact match later, we need to * error out. */ ambiguous_option = abbrev_option; ambiguous_flags = abbrev_flags; } if (!(flags & OPT_UNSET) && *arg_end) p->opt = arg_end + 1; abbrev_option = options; abbrev_flags = flags ^ opt_flags; continue; } /* negation allowed? */ if (options->flags & PARSE_OPT_NONEG) continue; /* negated and abbreviated very much? */ if (starts_with("no-", arg)) { flags |= OPT_UNSET; goto is_abbreviated; } /* negated? */ if (!starts_with(arg, "no-")) { if (starts_with(long_name, "no-")) { long_name += 3; opt_flags |= OPT_UNSET; goto again; } continue; } flags |= OPT_UNSET; if (!skip_prefix(arg + 3, long_name, &rest)) { /* abbreviated and negated? */ if (starts_with(long_name, arg + 3)) goto is_abbreviated; else continue; } } if (*rest) { if (*rest != '=') continue; p->opt = rest + 1; } return get_value(p, options, all_opts, flags ^ opt_flags); } if (ambiguous_option) return error("Ambiguous option: %s " "(could be --%s%s or --%s%s)", arg, (ambiguous_flags & OPT_UNSET) ? "no-" : "", ambiguous_option->long_name, (abbrev_flags & OPT_UNSET) ? "no-" : "", abbrev_option->long_name); if (abbrev_option) return get_value(p, abbrev_option, all_opts, abbrev_flags); return -2; }
static const char *rsync_url(const char *url) { return !starts_with(url, "rsync://") ? skip_prefix(url, "rsync:") : url; }
static int prepare_to_commit(const char *index_file, const char *prefix, struct commit *current_head, struct wt_status *s, struct strbuf *author_ident) { struct stat statbuf; struct strbuf committer_ident = STRBUF_INIT; int commitable; struct strbuf sb = STRBUF_INIT; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int clean_message_contents = (cleanup_mode != CLEANUP_NONE); int old_display_comment_prefix; /* This checks and barfs if author is badly specified */ determine_author_info(author_ident); if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die(_("could not lookup commit %s"), squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, _("(reading log message from standard input)\n")); if (strbuf_read(&sb, 0, 0) < 0) die_errno(_("could not read log from standard input")); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno(_("could not read log file '%s'"), logfile); hook_arg1 = "message"; } else if (use_message) { char *buffer; buffer = strstr(use_message_buffer, "\n\n"); if (!use_editor && (!buffer || buffer[2] == '\0')) die(_("commit has empty message")); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die(_("could not lookup commit %s"), fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die_errno(_("could not read MERGE_MSG")); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else if (template_file) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno(_("could not read '%s'"), template_file); hook_arg1 = "template"; clean_message_contents = 0; } /* * The remaining cases don't modify the template message, but * just set the argument(s) to the prepare-commit-msg hook. */ else if (whence == FROM_MERGE) hook_arg1 = "merge"; else if (whence == FROM_CHERRY_PICK) { hook_arg1 = "commit"; hook_arg2 = "CHERRY_PICK_HEAD"; } if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } s->fp = fopen(git_path(commit_editmsg), "w"); if (s->fp == NULL) die_errno(_("could not open '%s'"), git_path(commit_editmsg)); /* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */ old_display_comment_prefix = s->display_comment_prefix; s->display_comment_prefix = 1; /* * Most hints are counter-productive when the commit has * already started. */ s->hints = 0; if (clean_message_contents) stripspace(&sb, 0); if (signoff) { /* * See if we have a Conflicts: block at the end. If yes, count * its size, so we can ignore it. */ int ignore_footer = 0; int i, eol, previous = 0; const char *nl; for (i = 0; i < sb.len; i++) { nl = memchr(sb.buf + i, '\n', sb.len - i); if (nl) eol = nl - sb.buf; else eol = sb.len; if (starts_with(sb.buf + previous, "\nConflicts:\n")) { ignore_footer = sb.len - previous; break; } while (i < eol) i++; previous = eol; } append_signoff(&sb, ignore_footer, 0); } if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); strbuf_release(&sb); /* This checks if committer ident is explicitly given */ strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT)); if (use_editor && include_status) { int ident_shown = 0; int saved_color_setting; char *ai_tmp, *ci_tmp; if (whence != FROM_COMMIT) status_printf_ln(s, GIT_COLOR_NORMAL, whence == FROM_MERGE ? _("\n" "It looks like you may be committing a merge.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n") : _("\n" "It looks like you may be committing a cherry-pick.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n"), git_path(whence == FROM_MERGE ? "MERGE_HEAD" : "CHERRY_PICK_HEAD")); fprintf(s->fp, "\n"); if (cleanup_mode == CLEANUP_ALL) status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\nwith '%c' will be ignored, and an empty" " message aborts the commit.\n"), comment_line_char); else /* CLEANUP_SPACE, that is. */ status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\n" "with '%c' will be kept; you may remove them" " yourself if you want to.\n" "An empty message aborts the commit.\n"), comment_line_char); if (only_include_assumed) status_printf_ln(s, GIT_COLOR_NORMAL, "%s", only_include_assumed); ai_tmp = cut_ident_timestamp_part(author_ident->buf); ci_tmp = cut_ident_timestamp_part(committer_ident.buf); if (strcmp(author_ident->buf, committer_ident.buf)) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Author: %s"), ident_shown++ ? "" : "\n", author_ident->buf); if (!committer_ident_sufficiently_given()) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Committer: %s"), ident_shown++ ? "" : "\n", committer_ident.buf); if (ident_shown) status_printf_ln(s, GIT_COLOR_NORMAL, ""); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; *ai_tmp = ' '; *ci_tmp = ' '; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die(_("Cannot read index")); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } strbuf_release(&committer_ident); fclose(s->fp); /* * Reject an attempt to record a non-merge empty commit without * explicit --allow-empty. In the cherry-pick case, it may be * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && !(amend && is_a_merge(current_head))) { s->display_comment_prefix = old_display_comment_prefix; run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); else if (whence == FROM_CHERRY_PICK) { fputs(_(empty_cherry_pick_advice), stderr); if (!sequencer_in_use) fputs(_(empty_cherry_pick_advice_single), stderr); else fputs(_(empty_cherry_pick_advice_multi), stderr); } return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (update_main_cache_tree(0)) { error(_("Error building trees")); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { NULL }; env[0] = index; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); if (launch_editor(git_path(commit_editmsg), NULL, env)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
struct transport *transport_get(struct remote *remote, const char *url) { const char *helper; struct transport *ret = xcalloc(1, sizeof(*ret)); ret->progress = isatty(2); if (!remote) die("No remote provided to transport_get()"); ret->got_remote_refs = 0; ret->remote = remote; helper = remote->foreign_vcs; if (!url && remote->url) url = remote->url[0]; ret->url = url; /* maybe it is a foreign URL? */ if (url) { const char *p = url; while (is_urlschemechar(p == url, *p)) p++; if (starts_with(p, "::")) helper = xstrndup(url, p - url); } if (helper) { transport_helper_init(ret, helper); } else if (starts_with(url, "rsync:")) { ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; ret->push = rsync_transport_push; ret->smart_options = NULL; } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->get_refs_list = get_refs_from_bundle; ret->fetch = fetch_refs_from_bundle; ret->disconnect = close_bundle; ret->smart_options = NULL; } else if (!is_url(url) || starts_with(url, "file://") || starts_with(url, "git://") || starts_with(url, "ssh://") || starts_with(url, "git+ssh://") || starts_with(url, "ssh+git://")) { /* These are builtin smart transports. */ struct git_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->set_option = NULL; ret->get_refs_list = get_refs_via_connect; ret->fetch = fetch_refs_via_pack; ret->push_refs = git_transport_push; ret->connect = connect_git; ret->disconnect = disconnect_git; ret->smart_options = &(data->options); data->conn = NULL; data->got_remote_heads = 0; } else { /* Unknown protocol in URL. Pass to external handler. */ int len = external_specification_len(url); char *handler = xmalloc(len + 1); handler[len] = 0; strncpy(handler, url, len); transport_helper_init(ret, handler); } if (ret->smart_options) { ret->smart_options->thin = 1; ret->smart_options->uploadpack = "git-upload-pack"; if (remote->uploadpack) ret->smart_options->uploadpack = remote->uploadpack; ret->smart_options->receivepack = "git-receive-pack"; if (remote->receivepack) ret->smart_options->receivepack = remote->receivepack; } return ret; }