int delete_ref(const char *refname, const unsigned char *sha1) { struct ref_lock *lock; int err, i, ret = 0, flag = 0; lock = lock_ref_sha1_basic(refname, sha1, 0, &flag); if (!lock) return 1; if (!(flag & REF_ISPACKED)) { /* loose */ i = strlen(lock->lk->filename) - 5; /* .lock */ lock->lk->filename[i] = 0; err = unlink(lock->lk->filename); if (err) { ret = 1; error("unlink(%s) failed: %s", lock->lk->filename, strerror(errno)); } lock->lk->filename[i] = '.'; } /* removing the loose one could have resurrected an earlier * packed one. Also, if it was not loose we need to repack * without it. */ ret |= repack_without_ref(refname); err = unlink(git_path("logs/%s", lock->ref_name)); if (err && errno != ENOENT) fprintf(stderr, "warning: unlink(%s) failed: %s", git_path("logs/%s", lock->ref_name), strerror(errno)); invalidate_cached_refs(); unlock_ref(lock); return ret; }
int delete_ref(const char *refname, const unsigned char *sha1, int delopt) { struct ref_lock *lock; int err, i = 0, ret = 0, flag = 0; lock = lock_ref_sha1_basic(refname, sha1, 0, &flag); if (!lock) return 1; if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) { /* loose */ const char *path; if (!(delopt & REF_NODEREF)) { i = strlen(lock->lk->filename) - 5; /* .lock */ lock->lk->filename[i] = 0; path = lock->lk->filename; } else { path = git_path("%s", refname); } err = unlink_or_warn(path); if (err && errno != ENOENT) ret = 1; if (!(delopt & REF_NODEREF)) lock->lk->filename[i] = '.'; } /* removing the loose one could have resurrected an earlier * packed one. Also, if it was not loose we need to repack * without it. */ ret |= repack_without_ref(refname); unlink_or_warn(git_path("logs/%s", lock->ref_name)); invalidate_cached_refs(); unlock_ref(lock); return ret; }
int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *logmsg) { static char term = '\n'; struct object *o; if (!lock) return -1; if (!lock->force_write && !hashcmp(lock->old_sha1, sha1)) { unlock_ref(lock); return 0; } o = parse_object(sha1); if (!o) { error("Trying to write ref %s with nonexistant object %s", lock->ref_name, sha1_to_hex(sha1)); unlock_ref(lock); return -1; } if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) { error("Trying to write non-commit object %s to branch %s", sha1_to_hex(sha1), lock->ref_name); unlock_ref(lock); return -1; } if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 || write_in_full(lock->lock_fd, &term, 1) != 1 || close_ref(lock) < 0) { error("Couldn't write %s", lock->lk->filename); unlock_ref(lock); return -1; } invalidate_cached_refs(); if (log_ref_write(lock->ref_name, lock->old_sha1, sha1, logmsg) < 0 || (strcmp(lock->ref_name, lock->orig_ref_name) && log_ref_write(lock->orig_ref_name, lock->old_sha1, sha1, logmsg) < 0)) { unlock_ref(lock); return -1; } if (strcmp(lock->orig_ref_name, "HEAD") != 0) { /* * Special hack: If a branch is updated directly and HEAD * points to it (may happen on the remote side of a push * for example) then logically the HEAD reflog should be * updated too. * A generic solution implies reverse symref information, * but finding all symrefs pointing to the given branch * would be rather costly for this rare event (the direct * update of a branch) to be worth it. So let's cheat and * check with HEAD only which should cover 99% of all usage * scenarios (even 100% of the default ones). */ unsigned char head_sha1[20]; int head_flag; const char *head_ref; head_ref = resolve_ref("HEAD", head_sha1, 1, &head_flag); if (head_ref && (head_flag & REF_ISSYMREF) && !strcmp(head_ref, lock->ref_name)) log_ref_write("HEAD", lock->old_sha1, sha1, logmsg); } if (commit_ref(lock)) { error("Couldn't set %s", lock->ref_name); unlock_ref(lock); return -1; } unlock_ref(lock); return 0; }
const char *git_resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag) { invalidate_cached_refs(); return resolve_ref(ref,sha1,reading, flag); }
int git_for_each_ref_in(const char * refname, each_ref_fn fn, void * data) { invalidate_cached_refs(); return for_each_ref_in(refname, fn, data); }