unsigned int nsec;
};
+struct stat_data {
+ struct cache_time sd_ctime;
+ struct cache_time sd_mtime;
+ unsigned int sd_dev;
+ unsigned int sd_ino;
+ unsigned int sd_uid;
+ unsigned int sd_gid;
+ unsigned int sd_size;
+};
+
struct cache_entry {
- struct cache_time ce_ctime;
- struct cache_time ce_mtime;
- unsigned int ce_dev;
- unsigned int ce_ino;
+ struct stat_data ce_stat_data;
unsigned int ce_mode;
- unsigned int ce_uid;
- unsigned int ce_gid;
- unsigned int ce_size;
unsigned int ce_flags;
unsigned int ce_namelen;
unsigned char sha1[20];
* another. But we never change the name, or the hash state!
*/
#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
-static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry *src)
+static inline void copy_cache_entry(struct cache_entry *dst,
+ const struct cache_entry *src)
{
unsigned int state = dst->ce_flags & CE_STATE_MASK;
return S_IFGITLINK;
return S_IFREG | ce_permissions(mode);
}
-static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
+static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
+ unsigned int mode)
{
extern int trust_executable_bit, has_symlinks;
if (!has_symlinks && S_ISREG(mode) &&
extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int);
extern int init_db(const char *template_dir, unsigned int flags);
+extern void sanitize_stdfds(void);
+
#define alloc_nr(x) (((x)+16)*3/2)
/*
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
-extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
+extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
extern int index_name_is_other(const struct index_state *, const char *, int);
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
#define CE_MATCH_RACY_IS_DIRTY 02
/* do stat comparison even if CE_SKIP_WORKTREE is true */
#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
-extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
-extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
+extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern sastisfies GFNM_ONESTAR */
#define HASH_FORMAT_CHECK 2
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);
+
+/*
+ * Record to sd the data from st that we use to check whether a file
+ * might have changed.
+ */
+extern void fill_stat_data(struct stat_data *sd, struct stat *st);
+
+/*
+ * Return 0 if st is consistent with a file not having been changed
+ * since sd was filled. If there are differences, return a
+ * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
+ * INODE_CHANGED, and DATA_CHANGED.
+ */
+extern int match_stat_data(const struct stat_data *sd, struct stat *st);
+
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_REALLY 0x0001 /* ignore_valid */
extern int prefer_symlink_refs;
extern int log_all_ref_updates;
extern int warn_ambiguous_refs;
+ extern int warn_on_object_refname_ambiguity;
extern int shared_repository;
extern const char *apply_default_whitespace;
extern const char *apply_default_ignorewhitespace;
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
const char *absolute_path(const char *path);
-const char *relative_path(const char *abs, const char *base);
+const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
/* global flag to enable extra checks when accessing packed objects */
extern int do_check_packed_object_crc;
-/* for development: log offset of pack access */
-extern const char *log_pack_access;
-
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
extern int move_temp_to_file(const char *tmpfile, const char *filename);
struct strbuf *timebuf);
int parse_date(const char *date, char *buf, int bufsize);
int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
+int parse_expiry_date(const char *date, unsigned long *timestamp);
void datestamp(char *buf, int bufsize);
#define approxidate(s) approxidate_careful((s), NULL)
unsigned long approxidate_careful(const char *, int *);
unsigned int
force:1,
forced_update:1,
- merge:1,
deletion:1,
matched:1;
+
+ /*
+ * Order is important here, as we write to FETCH_HEAD
+ * in numeric order. And the default NOT_FOR_MERGE
+ * should be 0, so that xcalloc'd structures get it
+ * by default.
+ */
+ enum {
+ FETCH_HEAD_MERGE = -1,
+ FETCH_HEAD_NOT_FOR_MERGE = 0,
+ FETCH_HEAD_IGNORE = 1
+ } fetch_head_status;
+
enum {
REF_STATUS_NONE = 0,
REF_STATUS_OK,
struct object_info {
/* Request */
+ enum object_type *typep;
unsigned long *sizep;
unsigned long *disk_sizep;
typedef int (*config_fn_t)(const char *, const char *, void *);
extern int git_default_config(const char *, const char *, void *);
extern int git_config_from_file(config_fn_t fn, const char *, void *);
+extern int git_config_from_buf(config_fn_t fn, const char *name,
+ const char *buf, size_t len, void *data);
extern void git_config_push_parameter(const char *text);
extern int git_config_from_parameters(config_fn_t fn, void *data);
extern int git_config(config_fn_t fn, void *);
extern int git_config_with_options(config_fn_t fn, void *,
- const char *filename, int respect_includes);
+ const char *filename,
+ const char *blob_ref,
+ int respect_includes);
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
int sane_execvp(const char *file, char *const argv[]);
+/*
+ * A struct to encapsulate the concept of whether a file has changed
+ * since we last checked it. This uses criteria similar to those used
+ * for the index.
+ */
+struct stat_validity {
+ struct stat_data *sd;
+};
+
+void stat_validity_clear(struct stat_validity *sv);
+
+/*
+ * Returns 1 if the path is a regular file (or a symlink to a regular
+ * file) and matches the saved stat_validity, 0 otherwise. A missing
+ * or inaccessible file is considered a match if the struct was just
+ * initialized, or if the previous update found an inaccessible file.
+ */
+int stat_validity_check(struct stat_validity *sv, const char *path);
+
+/*
+ * Update the stat_validity from a file opened at descriptor fd. If
+ * the file is missing, inaccessible, or not a regular file, then
+ * future calls to stat_validity_check will match iff one of those
+ * conditions continues to be true.
+ */
+void stat_validity_update(struct stat_validity *sv, int fd);
+
#endif /* CACHE_H */
int is_bare_repository_cfg = -1; /* unspecified */
int log_all_ref_updates = -1; /* unspecified */
int warn_ambiguous_refs = 1;
+ int warn_on_object_refname_ambiguity = 1;
int repository_format_version;
const char *git_commit_encoding;
const char *git_log_output_encoding;
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
size_t delta_base_cache_limit = 16 * 1024 * 1024;
unsigned long big_file_threshold = 512 * 1024 * 1024;
-const char *log_pack_access;
const char *pager_program;
int pager_use_color = 1;
const char *editor_program;
const unsigned char null_sha1[20];
+static const char *no_log_pack_access = "no_log_pack_access";
+static const char *log_pack_access;
+
/*
* This is meant to hold a *small* number of objects that you would
* want read_sha1_file() to be able to return, but yet you do not want
}
}
+ static int stat_sha1_file(const unsigned char *sha1, struct stat *st)
+ {
+ char *name = sha1_file_name(sha1);
+ struct alternate_object_database *alt;
+
+ if (!lstat(name, st))
+ return 0;
+
+ prepare_alt_odb();
+ errno = ENOENT;
+ for (alt = alt_odb_list; alt; alt = alt->next) {
+ name = alt->name;
+ fill_sha1_path(name, sha1);
+ if (!lstat(alt->base, st))
+ return 0;
+ }
+
+ return -1;
+ }
+
static int open_sha1_file(const unsigned char *sha1)
{
int fd;
return type;
}
-
#define POI_STACK_PREALLOC 64
- static int packed_object_info(struct packed_git *p, off_t obj_offset,
- unsigned long *sizep, int *rtype,
- unsigned long *disk_sizep)
+ static enum object_type packed_to_object_type(struct packed_git *p,
+ off_t obj_offset,
+ enum object_type type,
+ struct pack_window **w_curs,
+ off_t curpos)
{
- struct pack_window *w_curs = NULL;
- unsigned long size;
- off_t curpos = obj_offset;
- enum object_type type;
off_t small_poi_stack[POI_STACK_PREALLOC];
off_t *poi_stack = small_poi_stack;
int poi_stack_nr = 0, poi_stack_alloc = POI_STACK_PREALLOC;
- type = unpack_object_header(p, &w_curs, &curpos, &size);
-
- if (rtype)
- *rtype = type; /* representation type */
-
- if (sizep) {
- if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
- off_t tmp_pos = curpos;
- off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
- type, obj_offset);
- if (!base_offset) {
- type = OBJ_BAD;
- goto out;
- }
- *sizep = get_size_from_delta(p, &w_curs, tmp_pos);
- if (*sizep == 0) {
- type = OBJ_BAD;
- goto out;
- }
- } else {
- *sizep = size;
- }
- }
-
- if (disk_sizep) {
- struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
- *disk_sizep = revidx[1].offset - obj_offset;
- }
-
while (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
off_t base_offset;
+ unsigned long size;
/* Push the object we're going to leave behind */
if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {
poi_stack_alloc = alloc_nr(poi_stack_nr);
}
poi_stack[poi_stack_nr++] = obj_offset;
/* If parsing the base offset fails, just unwind */
- base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
+ base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
if (!base_offset)
goto unwind;
curpos = obj_offset = base_offset;
- type = unpack_object_header(p, &w_curs, &curpos, &size);
+ type = unpack_object_header(p, w_curs, &curpos, &size);
if (type <= OBJ_NONE) {
/* If getting the base itself fails, we first
* retry the base, otherwise unwind */
out:
if (poi_stack != small_poi_stack)
free(poi_stack);
- unuse_pack(&w_curs);
return type;
unwind:
goto out;
}
+ static int packed_object_info(struct packed_git *p, off_t obj_offset,
+ struct object_info *oi)
+ {
+ struct pack_window *w_curs = NULL;
+ unsigned long size;
+ off_t curpos = obj_offset;
+ enum object_type type;
+
+ /*
+ * We always get the representation type, but only convert it to
+ * a "real" type later if the caller is interested.
+ */
+ type = unpack_object_header(p, &w_curs, &curpos, &size);
+
+ if (oi->sizep) {
+ if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+ off_t tmp_pos = curpos;
+ off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
+ type, obj_offset);
+ if (!base_offset) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
+ if (*oi->sizep == 0) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ } else {
+ *oi->sizep = size;
+ }
+ }
+
+ if (oi->disk_sizep) {
+ struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
+ *oi->disk_sizep = revidx[1].offset - obj_offset;
+ }
+
+ if (oi->typep) {
+ *oi->typep = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
+ if (*oi->typep < 0) {
+ type = OBJ_BAD;
+ goto out;
+ }
+ }
+
+ out:
+ unuse_pack(&w_curs);
+ return type;
+ }
+
static void *unpack_compressed_entry(struct packed_git *p,
struct pack_window **w_curs,
off_t curpos,
{
static FILE *log_file;
+ if (!log_pack_access)
+ log_pack_access = getenv("GIT_TRACE_PACK_ACCESS");
+ if (!log_pack_access)
+ log_pack_access = no_log_pack_access;
+ if (log_pack_access == no_log_pack_access)
+ return;
+
if (!log_file) {
log_file = fopen(log_pack_access, "w");
if (!log_file) {
error("cannot open pack access log '%s' for writing: %s",
log_pack_access, strerror(errno));
- log_pack_access = NULL;
+ log_pack_access = no_log_pack_access;
return;
}
}
int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC;
int base_from_cache = 0;
- if (log_pack_access)
+ if (log_pack_access != no_log_pack_access)
write_pack_access_log(p, obj_offset);
/* PHASE 1: drill down to the innermost base object */
data = patch_delta(base, base_size,
delta_data, delta_size,
&size);
+
+ /*
+ * We could not apply the delta; warn the user, but keep going.
+ * Our failure will be noticed either in the next iteration of
+ * the loop, or if this is the final delta, in the caller when
+ * we return NULL. Those code paths will take care of making
+ * a more explicit warning and retrying with another copy of
+ * the object.
+ */
if (!data)
- die("failed to apply delta");
+ error("failed to apply delta");
- free (delta_data);
+ free(delta_data);
}
*final_type = type;
}
- static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *sizep,
- unsigned long *disk_sizep)
+ static int sha1_loose_object_info(const unsigned char *sha1,
+ struct object_info *oi)
{
int status;
unsigned long mapsize, size;
git_zstream stream;
char hdr[32];
+ /*
+ * If we don't care about type or size, then we don't
+ * need to look inside the object at all.
+ */
+ if (!oi->typep && !oi->sizep) {
+ if (oi->disk_sizep) {
+ struct stat st;
+ if (stat_sha1_file(sha1, &st) < 0)
+ return -1;
+ *oi->disk_sizep = st.st_size;
+ }
+ return 0;
+ }
+
map = map_sha1_file(sha1, &mapsize);
if (!map)
- return error("unable to find %s", sha1_to_hex(sha1));
+ return -1;
- if (disk_sizep)
- *disk_sizep = mapsize;
+ if (oi->disk_sizep)
+ *oi->disk_sizep = mapsize;
if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error("unable to unpack %s header",
sha1_to_hex(sha1));
else if ((status = parse_sha1_header(hdr, &size)) < 0)
status = error("unable to parse %s header", sha1_to_hex(sha1));
- else if (sizep)
- *sizep = size;
+ else if (oi->sizep)
+ *oi->sizep = size;
git_inflate_end(&stream);
munmap(map, mapsize);
- return status;
+ if (oi->typep)
+ *oi->typep = status;
+ return 0;
}
/* returns enum object_type or negative */
{
struct cached_object *co;
struct pack_entry e;
- int status, rtype;
+ int rtype;
co = find_cached_object(sha1);
if (co) {
+ if (oi->typep)
+ *(oi->typep) = co->type;
if (oi->sizep)
*(oi->sizep) = co->size;
if (oi->disk_sizep)
*(oi->disk_sizep) = 0;
oi->whence = OI_CACHED;
- return co->type;
+ return 0;
}
if (!find_pack_entry(sha1, &e)) {
/* Most likely it's a loose object. */
- status = sha1_loose_object_info(sha1, oi->sizep, oi->disk_sizep);
- if (status >= 0) {
+ if (!sha1_loose_object_info(sha1, oi)) {
oi->whence = OI_LOOSE;
- return status;
+ return 0;
}
/* Not a loose object; someone else may have just packed it. */
reprepare_packed_git();
if (!find_pack_entry(sha1, &e))
- return status;
+ return -1;
}
- status = packed_object_info(e.p, e.offset, oi->sizep, &rtype,
- oi->disk_sizep);
- if (status < 0) {
+ rtype = packed_object_info(e.p, e.offset, oi);
+ if (rtype < 0) {
mark_bad_packed_object(e.p, sha1);
- status = sha1_object_info_extended(sha1, oi);
+ return sha1_object_info_extended(sha1, oi);
} else if (in_delta_base_cache(e.p, e.offset)) {
oi->whence = OI_DBCACHED;
} else {
rtype == OBJ_OFS_DELTA);
}
- return status;
+ return 0;
}
int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
{
- struct object_info oi = {0};
+ enum object_type type;
+ struct object_info oi = {NULL};
+ oi.typep = &type;
oi.sizep = sizep;
- return sha1_object_info_extended(sha1, &oi);
+ if (sha1_object_info_extended(sha1, &oi) < 0)
+ return -1;
+ return type;
}
static void *read_packed_sha1(const unsigned char *sha1,
return 0;
/* We need to do this the hard way... */
- obj = deref_tag(lookup_object(sha1), NULL, 0);
+ obj = deref_tag(parse_object(sha1), NULL, 0);
if (obj && obj->type == OBJ_COMMIT)
return 1;
return 0;
}
static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
+static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf);
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
{
unsigned char tmp_sha1[20];
char *real_ref = NULL;
int refs_found = 0;
- int at, reflog_len;
+ int at, reflog_len, nth_prior = 0;
if (len == 40 && !get_sha1_hex(str, sha1)) {
- refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
- if (refs_found > 0 && warn_ambiguous_refs) {
- warning(warn_msg, len, str);
- if (advice_object_name_warning)
- fprintf(stderr, "%s\n", _(object_name_msg));
+ if (warn_on_object_refname_ambiguity) {
+ refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
+ if (refs_found > 0 && warn_ambiguous_refs) {
+ warning(warn_msg, len, str);
+ if (advice_object_name_warning)
+ fprintf(stderr, "%s\n", _(object_name_msg));
+ }
+ free(real_ref);
}
- free(real_ref);
return 0;
}
/* basic@{time or number or -number} format to query ref-log */
reflog_len = at = 0;
if (len && str[len-1] == '}') {
- for (at = len-2; at >= 0; at--) {
+ for (at = len-4; at >= 0; at--) {
if (str[at] == '@' && str[at+1] == '{') {
+ if (str[at+2] == '-') {
+ if (at != 0)
+ /* @{-N} not at start */
+ return -1;
+ nth_prior = 1;
+ continue;
+ }
if (!upstream_mark(str + at, len - at)) {
reflog_len = (len-1) - (at+2);
len = at;
if (len && ambiguous_path(str, len))
return -1;
- if (!len && reflog_len) {
+ if (nth_prior) {
struct strbuf buf = STRBUF_INIT;
- int ret;
- /* try the @{-N} syntax for n-th checkout */
- ret = interpret_branch_name(str+at, &buf);
- if (ret > 0) {
- /* substitute this branch name and restart */
- return get_sha1_1(buf.buf, buf.len, sha1, 0);
- } else if (ret == 0) {
- return -1;
+ int detached;
+
+ if (interpret_nth_prior_checkout(str, &buf) > 0) {
+ detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
+ strbuf_release(&buf);
+ if (detached)
+ return 0;
}
+ }
+
+ if (!len && reflog_len)
/* allow "@{...}" to mean the current branch reflog */
refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
- } else if (reflog_len)
+ else if (reflog_len)
refs_found = dwim_log(str, len, sha1, &real_ref);
else
refs_found = dwim_ref(str, len, sha1, &real_ref);
unsigned long co_time;
int co_tz, co_cnt;
- /* a @{-N} placed anywhere except the start is an error */
- if (str[at+2] == '-')
- return -1;
-
/* Is it asking for N-th entry, or approxidate? */
for (i = nth = 0; 0 <= nth && i < reflog_len; i++) {
char ch = str[at+2+i];
}
if (read_ref_at(real_ref, at_time, nth, sha1, NULL,
&co_time, &co_tz, &co_cnt)) {
+ if (!len) {
+ if (!prefixcmp(real_ref, "refs/heads/")) {
+ str = real_ref + 11;
+ len = strlen(real_ref + 11);
+ } else {
+ /* detached HEAD */
+ str = "HEAD";
+ len = 4;
+ }
+ }
if (at_time)
warning("Log for '%.*s' only goes "
"back to %s.", len, str,
show_date(co_time, co_tz, DATE_RFC2822));
else {
- free(real_ref);
die("Log for '%.*s' only has %d entries.",
len, str, co_cnt);
}
return st;
}
+/* parse @something syntax, when 'something' is not {.*} */
+static int interpret_empty_at(const char *name, int namelen, int len, struct strbuf *buf)
+{
+ if (len || name[1] == '{')
+ return -1;
+
+ strbuf_reset(buf);
+ strbuf_add(buf, "HEAD", 4);
+ return 1;
+}
+
+static int reinterpret(const char *name, int namelen, int len, struct strbuf *buf)
+{
+ /* we have extra data, which might need further processing */
+ struct strbuf tmp = STRBUF_INIT;
+ int used = buf->len;
+ int ret;
+
+ strbuf_add(buf, name + len, namelen - len);
+ ret = interpret_branch_name(buf->buf, &tmp);
+ /* that data was not interpreted, remove our cruft */
+ if (ret < 0) {
+ strbuf_setlen(buf, used);
+ return len;
+ }
+ strbuf_reset(buf);
+ strbuf_addbuf(buf, &tmp);
+ strbuf_release(&tmp);
+ /* tweak for size of {-N} versus expanded ref name */
+ return ret - used + len;
+}
+
/*
* This reads short-hand syntax that not only evaluates to a commit
* object name, but also can act as if the end user spelled the name
int len = interpret_nth_prior_checkout(name, buf);
int tmp_len;
- if (!len)
+ if (!len) {
return len; /* syntax Ok, not enough switches */
- if (0 < len && len == namelen)
- return len; /* consumed all */
- else if (0 < len) {
- /* we have extra data, which might need further processing */
- struct strbuf tmp = STRBUF_INIT;
- int used = buf->len;
- int ret;
-
- strbuf_add(buf, name + len, namelen - len);
- ret = interpret_branch_name(buf->buf, &tmp);
- /* that data was not interpreted, remove our cruft */
- if (ret < 0) {
- strbuf_setlen(buf, used);
- return len;
- }
- strbuf_reset(buf);
- strbuf_addbuf(buf, &tmp);
- strbuf_release(&tmp);
- /* tweak for size of {-N} versus expanded ref name */
- return ret - used + len;
+ } else if (len > 0) {
+ if (len == namelen)
+ return len; /* consumed all */
+ else
+ return reinterpret(name, namelen, len, buf);
}
cp = strchr(name, '@');
if (!cp)
return -1;
+
+ len = interpret_empty_at(name, namelen, cp - name, buf);
+ if (len > 0)
+ return reinterpret(name, namelen, len, buf);
+
tmp_len = upstream_mark(cp, namelen - (cp - name));
if (!tmp_len)
return -1;
+
len = cp + tmp_len - name;
cp = xstrndup(name, cp - name);
upstream = branch_get(*cp ? cp : NULL);
* points to something different than a branch.
*/
if (!upstream)
- return error(_("HEAD does not point to a branch"));
+ die(_("HEAD does not point to a branch"));
if (!upstream->merge || !upstream->merge[0]->dst) {
if (!ref_exists(upstream->refname))
- return error(_("No such branch: '%s'"), cp);
- if (!upstream->merge)
- return error(_("No upstream configured for branch '%s'"),
- upstream->name);
- return error(
+ die(_("No such branch: '%s'"), cp);
+ if (!upstream->merge) {
+ die(_("No upstream configured for branch '%s'"),
+ upstream->name);
+ }
+ die(
_("Upstream branch '%s' not stored as a remote-tracking branch"),
upstream->merge[0]->src);
}
int strbuf_branchname(struct strbuf *sb, const char *name)
{
int len = strlen(name);
- if (interpret_branch_name(name, sb) == len)
+ int used = interpret_branch_name(name, sb);
+
+ if (used == len)
return 0;
- strbuf_add(sb, name, len);
+ if (used < 0)
+ used = 0;
+ strbuf_add(sb, name + used, len - used);
return len;
}
const char *filename)
{
struct stat st;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
int pos;
unsigned namelen = strlen(filename);
unsigned fullnamelen;
*/
if (name[0] == ':') {
int stage = 0;
- struct cache_entry *ce;
+ const struct cache_entry *ce;
char *new_path = NULL;
int pos;
if (!only_to_die && namelen > 2 && name[1] == '/') {
unsigned long size;
int status;
+ oi->typep = type;
oi->sizep = &size;
status = sha1_object_info_extended(sha1, oi);
if (status < 0)
return stream_error;
- *type = status;
switch (oi->whence) {
case OI_LOOSE:
struct stream_filter *filter)
{
struct git_istream *st;
- struct object_info oi = {0};
+ struct object_info oi = {NULL};
const unsigned char *real = lookup_replace_object(sha1);
enum input_source src = istream_source(real, type, &oi);
return NULL;
}
}
- if (st && filter) {
+ if (filter) {
/* Add "&& !is_null_stream_filter(filter)" for performance */
struct git_istream *nst = attach_stream_filter(st, filter);
if (!nst)