static void show_one(const char *refname, const struct object_id *oid) { const char *hex; struct object_id peeled; if (!has_sha1_file(oid->hash)) die("git show-ref: bad ref %s (%s)", refname, oid_to_hex(oid)); if (quiet) return; hex = find_unique_abbrev(oid->hash, abbrev); if (hash_only) printf("%s\n", hex); else printf("%s %s\n", hex, refname); if (!deref_tags) return; if (!peel_ref(refname, &peeled)) { hex = find_unique_abbrev(peeled.hash, abbrev); printf("%s %s^{}\n", hex, refname); } }
int fetch(unsigned char *sha1) { if (has_sha1_file(sha1)) return 0; else return fetch_file(sha1) && fetch_pack(sha1); }
void mark_parents_uninteresting(struct commit *commit) { struct commit_list *parents = commit->parents; while (parents) { struct commit *commit = parents->item; if (!(commit->object.flags & UNINTERESTING)) { commit->object.flags |= UNINTERESTING; /* * Normally we haven't parsed the parent * yet, so we won't have a parent of a parent * here. However, it may turn out that we've * reached this commit some other way (where it * wasn't uninteresting), in which case we need * to mark its parents recursively too.. */ if (commit->parents) mark_parents_uninteresting(commit); } /* * A missing commit is ok iff its parent is marked * uninteresting. * * We just mark such a thing parsed, so that when * it is popped next time around, we won't be trying * to parse it and get an error. */ if (!has_sha1_file(commit->object.sha1)) commit->object.parsed = 1; parents = parents->next; } }
static int got_sha1(char *hex, unsigned char *sha1) { struct object *o; int we_knew_they_have = 0; if (get_sha1_hex(hex, sha1)) die("git upload-pack: expected SHA1 object, got '%s'", hex); if (!has_sha1_file(sha1)) return -1; o = parse_object(sha1); if (!o) die("oops (%s)", sha1_to_hex(sha1)); if (o->type == OBJ_COMMIT) { struct commit_list *parents; struct commit *commit = (struct commit *)o; if (o->flags & THEY_HAVE) we_knew_they_have = 1; else o->flags |= THEY_HAVE; if (!oldest_have || (commit->date < oldest_have)) oldest_have = commit->date; for (parents = commit->parents; parents; parents = parents->next) parents->item->object.flags |= THEY_HAVE; } if (!we_knew_they_have) { add_object_array(o, NULL, &have_obj); return 1; } return 0; }
static void finish_object(struct object *obj, const struct name_path *path, const char *name, void *cb_data) { if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1)) die("missing blob object '%s'", sha1_to_hex(obj->sha1)); }
static int cat_one_file(int opt, const char *exp_type, const char *obj_name) { unsigned char sha1[20]; enum object_type type; void *buf; unsigned long size; if (get_sha1(obj_name, sha1)) die("Not a valid object name %s", obj_name); buf = NULL; switch (opt) { case 't': type = sha1_object_info(sha1, NULL); if (type > 0) { printf("%s\n", typename(type)); return 0; } break; case 's': type = sha1_object_info(sha1, &size); if (type > 0) { printf("%lu\n", size); return 0; } break; case 'e': return !has_sha1_file(sha1); case 'p': type = sha1_object_info(sha1, NULL); if (type < 0) die("Not a valid object name %s", obj_name); /* custom pretty-print here */ if (type == OBJ_TREE) { const char *ls_args[3] = {"ls-tree", obj_name, NULL}; return cmd_ls_tree(2, ls_args, NULL); } buf = read_sha1_file(sha1, &type, &size); if (!buf) die("Cannot read object %s", obj_name); if (type == OBJ_TAG) { pprint_tag(sha1, buf, size); return 0; } /* otherwise just spit out the data */ break; case 0: buf = read_object_with_reference(sha1, exp_type, &size, NULL); break; default: die("git cat-file: unknown option: %s", exp_type); }
static void feed_object(const unsigned char *sha1, FILE *fh, int negative) { if (negative && !has_sha1_file(sha1)) return; if (negative) putc('^', fh); fputs(sha1_to_hex(sha1), fh); putc('\n', fh); }
static void finish_object(struct object *obj, const struct name_path *path, const char *name, void *cb_data) { struct rev_list_info *info = cb_data; if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1)) die("missing blob object '%s'", sha1_to_hex(obj->sha1)); if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) parse_object(obj->sha1); }
static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned char *sha1) { char *hex = sha1_to_hex(sha1); int ret = 0; struct object_request *obj_req = object_queue_head; while (obj_req != NULL && hashcmp(obj_req->sha1, sha1)) obj_req = obj_req->next; if (obj_req == NULL) return error("Couldn't find request for %s in the queue", hex); if (has_sha1_file(obj_req->sha1)) { abort_object_request(obj_req); return 0; } #ifdef USE_CURL_MULTI while (obj_req->state == WAITING) { step_active_slots(); } #else start_object_request(walker, obj_req); #endif while (obj_req->state == ACTIVE) { run_active_slot(obj_req->slot); } if (obj_req->local != -1) { close(obj_req->local); obj_req->local = -1; } if (obj_req->state == ABORTED) { ret = error("Request for %s aborted", hex); } else if (obj_req->curl_result != CURLE_OK && obj_req->http_code != 416) { if (missing_target(obj_req)) ret = -1; /* Be silent, it is probably in a pack. */ else ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)", obj_req->errorstr, obj_req->curl_result, obj_req->http_code, hex); } else if (obj_req->zret != Z_STREAM_END) { walker->corrupt_object_found++; ret = error("File %s (%s) corrupt", hex, obj_req->url); } else if (hashcmp(obj_req->sha1, obj_req->real_sha1)) { ret = error("File %s has bad hash", hex); } else if (obj_req->rename < 0) { ret = error("unable to write sha1 filename %s", obj_req->filename); } release_object_request(obj_req); return ret; }
static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) { struct string_list existing_refs = { NULL, 0, 0, 0 }; struct string_list new_refs = { NULL, 0, 0, 1 }; char *ref_name; int ref_name_len; const unsigned char *ref_sha1; const struct ref *tag_ref; struct ref *rm = NULL; const struct ref *ref; for_each_ref(add_existing, &existing_refs); for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { if (prefixcmp(ref->name, "refs/tags")) continue; ref_name = xstrdup(ref->name); ref_name_len = strlen(ref_name); ref_sha1 = ref->old_sha1; if (!strcmp(ref_name + ref_name_len - 3, "^{}")) { ref_name[ref_name_len - 3] = 0; tag_ref = transport_get_remote_refs(transport); while (tag_ref) { if (!strcmp(tag_ref->name, ref_name)) { ref_sha1 = tag_ref->old_sha1; break; } tag_ref = tag_ref->next; } } if (!string_list_has_string(&existing_refs, ref_name) && !string_list_has_string(&new_refs, ref_name) && (has_sha1_file(ref->old_sha1) || will_fetch(head, ref->old_sha1))) { string_list_insert(ref_name, &new_refs); rm = alloc_ref(ref_name); rm->peer_ref = alloc_ref(ref_name); hashcpy(rm->old_sha1, ref_sha1); **tail = rm; *tail = &rm->next; } free(ref_name); } string_list_clear(&existing_refs, 0); string_list_clear(&new_refs, 0); }
static int feed_object(const unsigned char *sha1, int fd, int negative) { char buf[42]; if (negative && !has_sha1_file(sha1)) return 1; memcpy(buf + negative, sha1_to_hex(sha1), 40); if (negative) buf[0] = '^'; buf[40 + negative] = '\n'; return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs"); }
int cache_tree_fully_valid(struct cache_tree *it) { int i; if (!it) return 0; if (it->entry_count < 0 || !has_sha1_file(it->sha1)) return 0; for (i = 0; i < it->subtree_nr; i++) { if (!cache_tree_fully_valid(it->down[i]->cache_tree)) return 0; } return 1; }
static void write_followtags(const struct ref *refs, const char *msg) { const struct ref *ref; for (ref = refs; ref; ref = ref->next) { if (prefixcmp(ref->name, "refs/tags/")) continue; if (!suffixcmp(ref->name, "^{}")) continue; if (!has_sha1_file(ref->old_sha1)) continue; update_ref(msg, ref->name, ref->old_sha1, NULL, 0, DIE_ON_ERR); } }
static void write_followtags(const struct ref *refs, const char *msg) { const struct ref *ref; for (ref = refs; ref; ref = ref->next) { if (!starts_with(ref->name, "refs/tags/")) continue; if (ends_with(ref->name, "^{}")) continue; if (!has_sha1_file(ref->old_sha1)) continue; update_ref(msg, ref->name, ref->old_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); } }
static int do_one_ref(const char *base, each_ref_fn fn, int trim, void *cb_data, struct ref_list *entry) { if (strncmp(base, entry->name, trim)) return 0; if (is_null_sha1(entry->sha1)) return 0; if (!has_sha1_file(entry->sha1)) { error("%s does not point to a valid object!", entry->name); return 0; } current_ref = entry; return fn(entry->name + trim, entry->sha1, entry->flag, cb_data); }
static int fill_active_slot(struct walker *walker) { struct object_request *obj_req; for (obj_req = object_queue_head; obj_req; obj_req = obj_req->next) { if (obj_req->state == WAITING) { if (has_sha1_file(obj_req->sha1)) obj_req->state = COMPLETE; else { start_object_request(walker, obj_req); return 1; } } } return 0; }
static int fill_active_slot(struct walker *walker) { struct object_request *obj_req; struct list_head *pos, *tmp, *head = &object_queue_head; list_for_each_safe(pos, tmp, head) { obj_req = list_entry(pos, struct object_request, node); if (obj_req->state == WAITING) { if (has_sha1_file(obj_req->oid.hash)) obj_req->state = COMPLETE; else { start_object_request(walker, obj_req); return 1; } } }
static int already_written(struct bulk_checkin_state *state, unsigned char sha1[]) { int i; /* The object may already exist in the repository */ if (has_sha1_file(sha1)) return 1; /* Might want to keep the list sorted */ for (i = 0; i < state->nr_written; i++) if (!hashcmp(state->written[i]->oid.hash, sha1)) return 1; /* This is a new object we need to keep */ return 0; }
static int prune_notes_helper(const unsigned char *object_sha1, const unsigned char *note_sha1, char *note_path, void *cb_data) { struct note_delete_list **l = (struct note_delete_list **) cb_data; struct note_delete_list *n; if (has_sha1_file(object_sha1)) return 0; /* nothing to do for this note */ /* failed to find object => prune this note */ n = (struct note_delete_list *) xmalloc(sizeof(*n)); n->next = *l; n->sha1 = object_sha1; *l = n; return 0; }
static int do_one_ref(const char *base, each_ref_fn fn, int trim, int flags, void *cb_data, struct ref_list *entry) { if (strncmp(base, entry->name, trim)) return 0; if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { if (entry->flag & REF_BROKEN) return 0; /* ignore dangling symref */ if (!has_sha1_file(entry->sha1)) { error("%s does not point to a valid object!", entry->name); return 0; } } current_ref = entry; return fn(entry->name + trim, entry->sha1, entry->flag, cb_data); }
static int process(struct walker *walker, struct object *obj) { if (obj->flags & SEEN) return 0; obj->flags |= SEEN; if (has_sha1_file(obj->sha1)) { /* We already have it, so we should scan it now. */ obj->flags |= TO_SCAN; } else { if (obj->flags & COMPLETE) return 0; walker->prefetch(walker, obj->sha1); } object_list_insert(obj, process_queue_end); process_queue_end = &(*process_queue_end)->next; return 0; }
void mark_tree_uninteresting(struct tree *tree) { struct tree_desc desc; struct name_entry entry; struct object *obj = &tree->object; if (!tree) return; if (obj->flags & UNINTERESTING) return; obj->flags |= UNINTERESTING; if (!has_sha1_file(obj->sha1)) return; if (parse_tree(tree) < 0) die("bad tree %s", sha1_to_hex(obj->sha1)); init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: mark_tree_uninteresting(lookup_tree(entry.sha1)); break; case OBJ_BLOB: mark_blob_uninteresting(lookup_blob(entry.sha1)); break; default: /* Subproject commit - not in this repository */ break; } } /* * We don't care about the tree any more * after it has been marked uninteresting. */ free(tree->buffer); tree->buffer = NULL; }
static void update_shallow(struct fetch_pack_args *args, struct ref **sought, int nr_sought, struct shallow_info *si) { struct sha1_array ref = SHA1_ARRAY_INIT; int *status; int i; if (args->depth > 0 && alternate_shallow_file) { if (*alternate_shallow_file == '\0') { /* --unshallow */ unlink_or_warn(git_path("shallow")); rollback_lock_file(&shallow_lock); } else commit_lock_file(&shallow_lock); return; } if (!si->shallow || !si->shallow->nr) return; if (args->cloning) { /* * remote is shallow, but this is a clone, there are * no objects in repo to worry about. Accept any * shallow points that exist in the pack (iow in repo * after get_pack() and reprepare_packed_git()) */ struct sha1_array extra = SHA1_ARRAY_INIT; unsigned char (*sha1)[20] = si->shallow->sha1; for (i = 0; i < si->shallow->nr; i++) if (has_sha1_file(sha1[i])) sha1_array_append(&extra, sha1[i]); if (extra.nr) { setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, &extra); commit_lock_file(&shallow_lock); } sha1_array_clear(&extra); return; } if (!si->nr_ours && !si->nr_theirs) return; remove_nonexistent_theirs_shallow(si); if (!si->nr_ours && !si->nr_theirs) return; for (i = 0; i < nr_sought; i++) sha1_array_append(&ref, sought[i]->old_sha1); si->ref = &ref; if (args->update_shallow) { /* * remote is also shallow, .git/shallow may be updated * so all refs can be accepted. Make sure we only add * shallow roots that are actually reachable from new * refs. */ struct sha1_array extra = SHA1_ARRAY_INIT; unsigned char (*sha1)[20] = si->shallow->sha1; assign_shallow_commits_to_refs(si, NULL, NULL); if (!si->nr_ours && !si->nr_theirs) { sha1_array_clear(&ref); return; } for (i = 0; i < si->nr_ours; i++) sha1_array_append(&extra, sha1[si->ours[i]]); for (i = 0; i < si->nr_theirs; i++) sha1_array_append(&extra, sha1[si->theirs[i]]); setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, &extra); commit_lock_file(&shallow_lock); sha1_array_clear(&extra); sha1_array_clear(&ref); return; } /* * remote is also shallow, check what ref is safe to update * without updating .git/shallow */ status = xcalloc(nr_sought, sizeof(*status)); assign_shallow_commits_to_refs(si, NULL, status); if (si->nr_ours || si->nr_theirs) { for (i = 0; i < nr_sought; i++) if (status[i]) sought[i]->status = REF_STATUS_REJECT_SHALLOW; } free(status); sha1_array_clear(&ref); }
static int everything_local(struct fetch_pack_args *args, struct ref **refs, struct ref **sought, int nr_sought) { struct ref *ref; int retval; unsigned long cutoff = 0; save_commit_buffer = 0; for (ref = *refs; ref; ref = ref->next) { struct object *o; if (!has_sha1_file(ref->old_sha1)) continue; o = parse_object(ref->old_sha1); if (!o) continue; /* We already have it -- which may mean that we were * in sync with the other side at some time after * that (it is OK if we guess wrong here). */ if (o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; if (!cutoff || cutoff < commit->date) cutoff = commit->date; } } if (!args->depth) { for_each_ref(mark_complete, NULL); for_each_alternate_ref(mark_alternate_complete, NULL); commit_list_sort_by_date(&complete); if (cutoff) mark_recent_complete_commits(args, cutoff); } /* * Mark all complete remote refs as common refs. * Don't mark them common yet; the server has to be told so first. */ for (ref = *refs; ref; ref = ref->next) { struct object *o = deref_tag(lookup_object(ref->old_sha1), NULL, 0); if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) continue; if (!(o->flags & SEEN)) { rev_list_push((struct commit *)o, COMMON_REF | SEEN); mark_common((struct commit *)o, 1, 1); } } filter_refs(args, refs, sought, nr_sought); for (retval = 1, ref = *refs; ref ; ref = ref->next) { const unsigned char *remote = ref->old_sha1; unsigned char local[20]; struct object *o; o = lookup_object(remote); if (!o || !(o->flags & COMPLETE)) { retval = 0; if (!args->verbose) continue; fprintf(stderr, "want %s (%s)\n", sha1_to_hex(remote), ref->name); continue; } hashcpy(ref->new_sha1, local); if (!args->verbose) continue; fprintf(stderr, "already have %s (%s)\n", sha1_to_hex(remote), ref->name); } return retval; }
int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, struct extra_have_objects *extra_have) { int in = fd[0]; int out = fd[1]; struct ref *ref; int new_refs; int ask_for_status_report = 0; int allow_deleting_refs = 0; int expect_status_report = 0; int ret; /* Does the other end support the reporting? */ if (server_supports("report-status")) ask_for_status_report = 1; if (server_supports("delete-refs")) allow_deleting_refs = 1; if (server_supports("ofs-delta")) args->use_ofs_delta = 1; if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" "Perhaps you should specify a branch such as 'master'.\n"); return 0; } /* * Finally, tell the other end! */ new_refs = 0; for (ref = remote_refs; ref; ref = ref->next) { if (ref->peer_ref) hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); else if (!args->send_mirror) continue; ref->deletion = is_null_sha1(ref->new_sha1); if (ref->deletion && !allow_deleting_refs) { ref->status = REF_STATUS_REJECT_NODELETE; continue; } if (!ref->deletion && !hashcmp(ref->old_sha1, ref->new_sha1)) { ref->status = REF_STATUS_UPTODATE; continue; } /* This part determines what can overwrite what. * The rules are: * * (0) you can always use --force or +A:B notation to * selectively force individual ref pairs. * * (1) if the old thing does not exist, it is OK. * * (2) if you do not have the old thing, you are not allowed * to overwrite it; you would not know what you are losing * otherwise. * * (3) if both new and old are commit-ish, and new is a * descendant of old, it is OK. * * (4) regardless of all of the above, removing :B is * always allowed. */ ref->nonfastforward = !ref->deletion && !is_null_sha1(ref->old_sha1) && (!has_sha1_file(ref->old_sha1) || !ref_newer(ref->new_sha1, ref->old_sha1)); if (ref->nonfastforward && !ref->force && !args->force_update) { ref->status = REF_STATUS_REJECT_NONFASTFORWARD; continue; } if (!ref->deletion) new_refs++; if (!args->dry_run) { char *old_hex = sha1_to_hex(ref->old_sha1); char *new_hex = sha1_to_hex(ref->new_sha1); if (ask_for_status_report) { packet_write(out, "%s %s %s%c%s", old_hex, new_hex, ref->name, 0, "report-status"); ask_for_status_report = 0; expect_status_report = 1; } else packet_write(out, "%s %s %s", old_hex, new_hex, ref->name); } ref->status = expect_status_report ? REF_STATUS_EXPECTING_REPORT : REF_STATUS_OK; } packet_flush(out); if (new_refs && !args->dry_run) { if (pack_objects(out, remote_refs, extra_have, args) < 0) { for (ref = remote_refs; ref; ref = ref->next) ref->status = REF_STATUS_NONE; return -1; } } if (expect_status_report) ret = receive_status(in, remote_refs); else ret = 0; if (ret < 0) return ret; for (ref = remote_refs; ref; ref = ref->next) { switch (ref->status) { case REF_STATUS_NONE: case REF_STATUS_UPTODATE: case REF_STATUS_OK: break; default: return -1; } } return 0; }
static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) { struct string_list existing_refs = { NULL, 0, 0, 0 }; struct string_list remote_refs = { NULL, 0, 0, 0 }; struct tag_data data = {head, tail}; const struct ref *ref; struct string_list_item *item = NULL; for_each_ref(add_existing, &existing_refs); for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { if (prefixcmp(ref->name, "refs/tags")) continue; /* * The peeled ref always follows the matching base * ref, so if we see a peeled ref that we don't want * to fetch then we can mark the ref entry in the list * as one to ignore by setting util to NULL. */ if (!suffixcmp(ref->name, "^{}")) { if (item && !has_sha1_file(ref->old_sha1) && !will_fetch(head, ref->old_sha1) && !has_sha1_file(item->util) && !will_fetch(head, item->util)) item->util = NULL; item = NULL; continue; } /* * If item is non-NULL here, then we previously saw a * ref not followed by a peeled reference, so we need * to check if it is a lightweight tag that we want to * fetch. */ if (item && !has_sha1_file(item->util) && !will_fetch(head, item->util)) item->util = NULL; item = NULL; /* skip duplicates and refs that we already have */ if (string_list_has_string(&remote_refs, ref->name) || string_list_has_string(&existing_refs, ref->name)) continue; item = string_list_insert(ref->name, &remote_refs); item->util = (void *)ref->old_sha1; } string_list_clear(&existing_refs, 0); /* * We may have a final lightweight tag that needs to be * checked to see if it needs fetching. */ if (item && !has_sha1_file(item->util) && !will_fetch(head, item->util)) item->util = NULL; /* * For all the tags in the remote_refs string list, call * add_to_tail to add them to the list of refs to be fetched */ for_each_string_list(add_to_tail, &remote_refs, &data); string_list_clear(&remote_refs, 0); }
static int cat_one_file(int opt, const char *exp_type, const char *obj_name) { unsigned char sha1[20]; enum object_type type; char *buf; unsigned long size; struct object_context obj_context; if (get_sha1_with_context(obj_name, 0, sha1, &obj_context)) die("Not a valid object name %s", obj_name); buf = NULL; switch (opt) { case 't': type = sha1_object_info(sha1, NULL); if (type > 0) { printf("%s\n", typename(type)); return 0; } break; case 's': type = sha1_object_info(sha1, &size); if (type > 0) { printf("%lu\n", size); return 0; } break; case 'e': return !has_sha1_file(sha1); case 'p': type = sha1_object_info(sha1, NULL); if (type < 0) die("Not a valid object name %s", obj_name); /* custom pretty-print here */ if (type == OBJ_TREE) { const char *ls_args[3] = { NULL }; ls_args[0] = "ls-tree"; ls_args[1] = obj_name; return cmd_ls_tree(2, ls_args, NULL); } if (type == OBJ_BLOB) return stream_blob_to_fd(1, sha1, NULL, 0); buf = read_sha1_file(sha1, &type, &size); if (!buf) die("Cannot read object %s", obj_name); if (type == OBJ_TAG) { pprint_tag(sha1, buf, size); return 0; } /* otherwise just spit out the data */ break; case 'c': if (!obj_context.path[0]) die("git cat-file --textconv %s: <object> must be <sha1:path>", obj_name); if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size)) die("git cat-file --textconv: unable to run textconv on %s", obj_name); break; case 0: if (type_from_string(exp_type) == OBJ_BLOB) { unsigned char blob_sha1[20]; if (sha1_object_info(sha1, NULL) == OBJ_TAG) { enum object_type type; unsigned long size; char *buffer = read_sha1_file(sha1, &type, &size); if (memcmp(buffer, "object ", 7) || get_sha1_hex(buffer + 7, blob_sha1)) die("%s not a valid tag", sha1_to_hex(sha1)); free(buffer); } else hashcpy(blob_sha1, sha1); if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB) return stream_blob_to_fd(1, blob_sha1, NULL, 0); /* * we attempted to dereference a tag to a blob * and failed; there may be new dereference * mechanisms this code is not aware of. * fall-back to the usual case. */ } buf = read_object_with_reference(sha1, exp_type, &size, NULL); break; default: die("git cat-file: unknown option: %s", exp_type); }
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata) { const char *hex; unsigned char peeled[20]; if (show_head && !strcmp(refname, "HEAD")) goto match; if (tags_only || heads_only) { int match; match = heads_only && !prefixcmp(refname, "refs/heads/"); match |= tags_only && !prefixcmp(refname, "refs/tags/"); if (!match) return 0; } if (pattern) { int reflen = strlen(refname); const char **p = pattern, *m; while ((m = *p++) != NULL) { int len = strlen(m); if (len > reflen) continue; if (memcmp(m, refname + reflen - len, len)) continue; if (len == reflen) goto match; /* "--verify" requires an exact match */ if (verify) continue; if (refname[reflen - len - 1] == '/') goto match; } return 0; } match: found_match++; /* This changes the semantics slightly that even under quiet we * detect and return error if the repository is corrupt and * ref points at a nonexistent object. */ if (!has_sha1_file(sha1)) die("git show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1)); if (quiet) return 0; show_one(refname, sha1); if (!deref_tags) return 0; if (!peel_ref(refname, peeled)) { hex = find_unique_abbrev(peeled, abbrev); printf("%s %s^{}\n", hex, refname); } return 0; }
static const char *update(struct command *cmd) { const char *name = cmd->ref_name; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; struct ref_lock *lock; /* only refs/... are allowed */ if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) { error("refusing to create funny ref '%s' remotely", name); return "funny refname"; } if (is_ref_checked_out(name)) { switch (deny_current_branch) { case DENY_IGNORE: break; case DENY_UNCONFIGURED: case DENY_WARN: warning("updating the current branch"); if (deny_current_branch == DENY_UNCONFIGURED) warn_unconfigured_deny(); break; case DENY_REFUSE: error("refusing to update checked out branch: %s", name); return "branch is currently checked out"; } } if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { error("unpack should have generated %s, " "but I can't find it!", sha1_to_hex(new_sha1)); return "bad pack"; } if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) { if (deny_deletes && !prefixcmp(name, "refs/heads/")) { error("denying ref deletion for %s", name); return "deletion prohibited"; } if (!strcmp(name, head_name)) { switch (deny_delete_current) { case DENY_IGNORE: break; case DENY_WARN: case DENY_UNCONFIGURED: if (deny_delete_current == DENY_UNCONFIGURED) warn_unconfigured_deny_delete_current(); warning("deleting the current branch"); break; case DENY_REFUSE: error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; } } } if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && !is_null_sha1(old_sha1) && !prefixcmp(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; struct commit_list *bases, *ent; old_object = parse_object(old_sha1); new_object = parse_object(new_sha1); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || new_object->type != OBJ_COMMIT) { error("bad sha1 objects for %s", name); return "bad ref"; } old_commit = (struct commit *)old_object; new_commit = (struct commit *)new_object; bases = get_merge_bases(old_commit, new_commit, 1); for (ent = bases; ent; ent = ent->next) if (!hashcmp(old_sha1, ent->item->object.sha1)) break; free_commit_list(bases); if (!ent) { error("denying non-fast forward %s" " (you should pull first)", name); return "non-fast forward"; } } if (run_update_hook(cmd)) { error("hook declined to update %s", name); return "hook declined"; } if (is_null_sha1(new_sha1)) { if (!parse_object(old_sha1)) { warning ("Allowing deletion of corrupt ref."); old_sha1 = NULL; } if (delete_ref(name, old_sha1, 0)) { error("failed to delete %s", name); return "failed to delete"; } return NULL; /* good */ } else { lock = lock_any_ref_for_update(name, old_sha1, 0); if (!lock) { error("failed to lock %s", name); return "failed to lock"; } if (write_ref_sha1(lock, new_sha1, "push")) { return "failed to write"; /* error() already called */ } return NULL; /* good */ } }
static int update_one(struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen, int missing_ok, int dryrun) { struct strbuf buffer; int i; if (0 <= it->entry_count && has_sha1_file(it->sha1)) return it->entry_count; /* * We first scan for subtrees and update them; we start by * marking existing subtrees -- the ones that are unmarked * should not be in the result. */ for (i = 0; i < it->subtree_nr; i++) it->down[i]->used = 0; /* * Find the subtrees and update them. */ for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, sublen, subcnt; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (!slash) continue; /* * a/bbb/c (base = a/, slash = /c) * ==> * path+baselen = bbb/c, sublen = 3 */ sublen = slash - (path + baselen); sub = find_subtree(it, path + baselen, sublen, 1); if (!sub->cache_tree) sub->cache_tree = cache_tree(); subcnt = update_one(sub->cache_tree, cache + i, entries - i, path, baselen + sublen + 1, missing_ok, dryrun); if (subcnt < 0) return subcnt; i += subcnt - 1; sub->used = 1; } discard_unused_subtrees(it); /* * Then write out the tree object for this level. */ strbuf_init(&buffer, 8192); for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, entlen; const unsigned char *sha1; unsigned mode; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = find_subtree(it, path + baselen, entlen, 0); if (!sub) die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); i += sub->cache_tree->entry_count - 1; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) return error("invalid object %06o %s for '%.*s'", mode, sha1_to_hex(sha1), entlen+baselen, path); if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ strbuf_grow(&buffer, entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); strbuf_add(&buffer, sha1, 20); #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } if (dryrun) hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) { strbuf_release(&buffer); return -1; } strbuf_release(&buffer); it->entry_count = i; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, sha1_to_hex(it->sha1)); #endif return i; }