From: Junio C Hamano Date: Thu, 18 Aug 2011 00:35:38 +0000 (-0700) Subject: Merge branch 'js/ref-namespaces' X-Git-Tag: v1.7.7-rc0~28 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/6ed547b53b90bebd2371b086b83b416b22b243b2?hp=-c Merge branch 'js/ref-namespaces' * js/ref-namespaces: ref namespaces: tests ref namespaces: documentation ref namespaces: Support remote repositories via upload-pack and receive-pack ref namespaces: infrastructure Fix prefix handling in ref iteration functions --- 6ed547b53b90bebd2371b086b83b416b22b243b2 diff --combined Documentation/Makefile index 18c71d763f,2004fbe630..6346a75dda --- a/Documentation/Makefile +++ b/Documentation/Makefile @@@ -6,7 -6,7 +6,7 @@@ MAN5_TXT=gitattributes.txt gitignore.tx gitrepository-layout.txt MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \ gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt \ - gitdiffcore.txt gitrevisions.txt gitworkflows.txt + gitdiffcore.txt gitnamespaces.txt gitrevisions.txt gitworkflows.txt MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT)) @@@ -232,7 -232,6 +232,7 @@@ cmd-list.made: cmd-list.perl ../command clean: $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 $(RM) *.texi *.texi+ *.texi++ git.info gitman.info + $(RM) *.pdf $(RM) howto-index.txt howto/*.html doc.dep $(RM) technical/api-*.html technical/api-index.txt $(RM) $(cmds_txt) *.made diff --combined Documentation/git-receive-pack.txt index d7b68afbc2,3534ba01c4..a3a1d8eea3 --- a/Documentation/git-receive-pack.txt +++ b/Documentation/git-receive-pack.txt @@@ -8,8 -8,7 +8,8 @@@ git-receive-pack - Receive what is push SYNOPSIS -------- -'git-receive-pack' +[verse] +'git-receive-pack' [--quiet] DESCRIPTION ----------- @@@ -35,9 -34,6 +35,9 @@@ are not fast-forwards OPTIONS ------- +--quiet:: + Print only error messages. + :: The repository to sync into. @@@ -153,7 -149,7 +153,7 @@@ if the repository is packed and is serv SEE ALSO -------- - linkgit:git-send-pack[1] + linkgit:git-send-pack[1], linkgit:gitnamespaces[7] GIT --- diff --combined Documentation/git-upload-pack.txt index a58e90ca8d,61a9a04a8d..71f16083d6 --- a/Documentation/git-upload-pack.txt +++ b/Documentation/git-upload-pack.txt @@@ -8,7 -8,6 +8,7 @@@ git-upload-pack - Send objects packed b SYNOPSIS -------- +[verse] 'git-upload-pack' [--strict] [--timeout=] DESCRIPTION @@@ -34,6 -33,10 +34,10 @@@ OPTION :: The repository to sync from. + SEE ALSO + -------- + linkgit:gitnamespaces[7] + GIT --- Part of the linkgit:git[1] suite diff --combined Documentation/git.txt index 0172cd7014,1fe4341791..710d750cfd --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -10,8 -10,8 +10,8 @@@ SYNOPSI -------- [verse] 'git' [--version] [--exec-path[=]] [--html-path] [--man-path] [--info-path] - [-p|--paginate|--no-pager] [--no-replace-objects] - [--bare] [--git-dir=] [--work-tree=] + [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] + [--git-dir=] [--work-tree=] [--namespace=] [-c =] [--help] [] @@@ -44,16 -44,9 +44,16 @@@ unreleased) version of git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.7.5.2/git.html[documentation for release 1.7.5.2] +* link:v1.7.6/git.html[documentation for release 1.7.6] * release notes for + link:RelNotes/1.7.6.txt[1.7.6]. + +* link:v1.7.5.4/git.html[documentation for release 1.7.5.4] + +* release notes for + link:RelNotes/1.7.5.4.txt[1.7.5.4], + link:RelNotes/1.7.5.3.txt[1.7.5.3], link:RelNotes/1.7.5.2.txt[1.7.5.2], link:RelNotes/1.7.5.1.txt[1.7.5.1], link:RelNotes/1.7.5.txt[1.7.5]. @@@ -330,6 -323,11 +330,11 @@@ help ...` variable (see core.worktree in linkgit:git-config[1] for a more detailed discussion). + --namespace=:: + Set the git namespace. See linkgit:gitnamespaces[7] for more + details. Equivalent to setting the `GIT_NAMESPACE` environment + variable. + --bare:: Treat the repository as a bare repository. If GIT_DIR environment is not set, it is set to the current working @@@ -523,15 -521,16 +528,15 @@@ Any git command accepting any symbolic notation: HEAD:: - indicates the head of the current branch (i.e. the - contents of `$GIT_DIR/HEAD`). + indicates the head of the current branch. :: a valid tag 'name' - (i.e. the contents of `$GIT_DIR/refs/tags/`). + (i.e. a `refs/tags/` reference). :: a valid head 'name' - (i.e. the contents of `$GIT_DIR/refs/heads/`). + (i.e. a `refs/heads/` reference). For a more complete list of ways to spell object names, see "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7]. @@@ -593,6 -592,10 +598,10 @@@ git so take care if using Cogito etc This can also be controlled by the '--work-tree' command line option and the core.worktree configuration variable. + 'GIT_NAMESPACE':: + Set the git namespace; see linkgit:gitnamespaces[7] for details. + The '--namespace' command-line option also sets this value. + 'GIT_CEILING_DIRECTORIES':: This should be a colon-separated list of absolute paths. If set, it is a list of directories that git should not chdir diff --combined builtin/receive-pack.c index 0d51bfb79e,e589082b31..60260d0aa9 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@@ -10,7 -10,6 +10,7 @@@ #include "remote.h" #include "transport.h" #include "string-list.h" +#include "sha1-array.h" static const char receive_pack_usage[] = "git receive-pack "; @@@ -120,9 -119,25 +120,25 @@@ static int show_ref(const char *path, c return 0; } + static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *cb_data) + { + path = strip_namespace(path); + /* + * Advertise refs outside our current namespace as ".have" + * refs, so that the client can use them to minimize data + * transfer but will otherwise ignore them. This happens to + * cover ".have" that are thrown in by add_one_alternate_ref() + * to mark histories that are complete in our alternates as + * well. + */ + if (!path) + path = ".have"; + return show_ref(path, sha1, flag, cb_data); + } + static void write_head_info(void) { - for_each_ref(show_ref, NULL); + for_each_ref(show_ref_cb, NULL); if (!sent_capabilities) show_ref("capabilities^{}", null_sha1, 0, NULL); @@@ -333,6 -348,8 +349,8 @@@ static void refuse_unconfigured_deny_de static const char *update(struct command *cmd) { const char *name = cmd->ref_name; + struct strbuf namespaced_name_buf = STRBUF_INIT; + const char *namespaced_name; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; struct ref_lock *lock; @@@ -343,7 -360,10 +361,10 @@@ return "funny refname"; } - if (is_ref_checked_out(name)) { + strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); + namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); + + if (is_ref_checked_out(namespaced_name)) { switch (deny_current_branch) { case DENY_IGNORE: break; @@@ -371,7 -391,7 +392,7 @@@ return "deletion prohibited"; } - if (!strcmp(name, head_name)) { + if (!strcmp(namespaced_name, head_name)) { switch (deny_delete_current) { case DENY_IGNORE: break; @@@ -427,14 -447,14 +448,14 @@@ rp_warning("Allowing deletion of corrupt ref."); old_sha1 = NULL; } - if (delete_ref(name, old_sha1, 0)) { + if (delete_ref(namespaced_name, old_sha1, 0)) { rp_error("failed to delete %s", name); return "failed to delete"; } return NULL; /* good */ } else { - lock = lock_any_ref_for_update(name, old_sha1, 0); + lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0); if (!lock) { rp_error("failed to lock %s", name); return "failed to lock"; @@@ -491,17 -511,29 +512,29 @@@ static void run_update_post_hook(struc static void check_aliased_update(struct command *cmd, struct string_list *list) { + struct strbuf buf = STRBUF_INIT; + const char *dst_name; struct string_list_item *item; struct command *dst_cmd; unsigned char sha1[20]; char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41]; int flag; - const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag); + strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); + dst_name = resolve_ref(buf.buf, sha1, 0, &flag); + strbuf_release(&buf); if (!(flag & REF_ISSYMREF)) return; + dst_name = strip_namespace(dst_name); + if (!dst_name) { + rp_error("refusing update to broken symref '%s'", cmd->ref_name); + cmd->skip_update = 1; + cmd->error_string = "broken symref"; + return; + } + if ((item = string_list_lookup(list, dst_name)) == NULL) return; @@@ -636,7 -668,7 +669,7 @@@ static const char *parse_pack_header(st static const char *pack_lockfile; -static const char *unpack(void) +static const char *unpack(int quiet) { struct pack_header hdr; const char *hdr_err; @@@ -651,10 -683,8 +684,10 @@@ if (ntohl(hdr.hdr_entries) < unpack_limit) { int code, i = 0; - const char *unpacker[4]; + const char *unpacker[5]; unpacker[i++] = "unpack-objects"; + if (quiet) + unpacker[i++] = "-q"; if (receive_fsck_objects) unpacker[i++] = "--strict"; unpacker[i++] = hdr_arg; @@@ -734,28 -764,18 +767,28 @@@ static int delete_only(struct command * return 1; } -static void add_one_alternate_ref(const struct ref *ref, void *unused) +static void add_one_alternate_sha1(const unsigned char sha1[20], void *unused) { - add_extra_ref(".have", ref->old_sha1, 0); + add_extra_ref(".have", sha1, 0); +} + +static void collect_one_alternate_ref(const struct ref *ref, void *data) +{ + struct sha1_array *sa = data; + sha1_array_append(sa, ref->old_sha1); } static void add_alternate_refs(void) { - foreach_alt_odb(refs_from_alternate_cb, add_one_alternate_ref); + struct sha1_array sa = SHA1_ARRAY_INIT; + for_each_alternate_ref(collect_one_alternate_ref, &sa); + sha1_array_for_each_unique(&sa, add_one_alternate_sha1, NULL); + sha1_array_clear(&sa); } int cmd_receive_pack(int argc, const char **argv, const char *prefix) { + int quiet = 0; int advertise_refs = 0; int stateless_rpc = 0; int i; @@@ -769,11 -789,6 +802,11 @@@ const char *arg = *argv++; if (*arg == '-') { + if (!strcmp(arg, "--quiet")) { + quiet = 1; + continue; + } + if (!strcmp(arg, "--advertise-refs")) { advertise_refs = 1; continue; @@@ -822,7 -837,7 +855,7 @@@ const char *unpack_status = NULL; if (!delete_only(commands)) - unpack_status = unpack(); + unpack_status = unpack(quiet); execute_commands(commands, unpack_status); if (pack_lockfile) unlink_or_warn(pack_lockfile); diff --combined cache.h index b33ba73197,26310c464e..fcf4501a60 --- a/cache.h +++ b/cache.h @@@ -6,7 -6,6 +6,7 @@@ #include "hash.h" #include "advice.h" #include "gettext.h" +#include "convert.h" #include SHA1_HEADER #ifndef git_SHA_CTX @@@ -17,27 -16,13 +17,27 @@@ #endif #include -#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200 -#define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11) -#endif - -void git_inflate_init(z_streamp strm); -void git_inflate_end(z_streamp strm); -int git_inflate(z_streamp strm, int flush); +typedef struct git_zstream { + z_stream z; + unsigned long avail_in; + unsigned long avail_out; + unsigned long total_in; + unsigned long total_out; + unsigned char *next_in; + unsigned char *next_out; +} git_zstream; + +void git_inflate_init(git_zstream *); +void git_inflate_init_gzip_only(git_zstream *); +void git_inflate_end(git_zstream *); +int git_inflate(git_zstream *, int flush); + +void git_deflate_init(git_zstream *, int level); +void git_deflate_init_gzip(git_zstream *, int level); +void git_deflate_end(git_zstream *); +int git_deflate_end_gently(git_zstream *); +int git_deflate(git_zstream *, int flush); +unsigned long git_deflate_bound(git_zstream *, unsigned long); #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) #define DTYPE(de) ((de)->d_type) @@@ -394,6 -379,7 +394,7 @@@ static inline enum object_type object_t } #define GIT_DIR_ENVIRONMENT "GIT_DIR" + #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE" #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY" @@@ -434,6 -420,8 +435,8 @@@ extern char *get_object_directory(void) extern char *get_index_file(void); extern char *get_graft_file(void); extern int set_git_dir(const char *path); + extern const char *get_git_namespace(void); + extern const char *strip_namespace(const char *namespaced_ref); extern const char *get_git_work_tree(void); extern const char *read_gitfile_gently(const char *path); extern void set_git_work_tree(const char *tree); @@@ -441,7 -429,6 +444,7 @@@ #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES" extern const char **get_pathspec(const char *prefix, const char **pathspec); +extern const char *pathspec_prefix(const char *prefix, const char **pathspec); extern void setup_work_tree(void); extern const char *setup_git_directory_gently(int *); extern const char *setup_git_directory(void); @@@ -534,11 -521,8 +537,11 @@@ struct pathspec extern int init_pathspec(struct pathspec *, const char **); extern void free_pathspec(struct pathspec *); extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec); -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check); -extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); + +#define HASH_WRITE_OBJECT 1 +#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); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_REALLY 0x0001 /* ignore_valid */ @@@ -598,6 -582,35 +601,6 @@@ extern int fsync_object_files extern int core_preload_index; extern int core_apply_sparse_checkout; -enum safe_crlf { - SAFE_CRLF_FALSE = 0, - SAFE_CRLF_FAIL = 1, - SAFE_CRLF_WARN = 2 -}; - -extern enum safe_crlf safe_crlf; - -enum auto_crlf { - AUTO_CRLF_FALSE = 0, - AUTO_CRLF_TRUE = 1, - AUTO_CRLF_INPUT = -1 -}; - -extern enum auto_crlf auto_crlf; - -enum eol { - EOL_UNSET, - EOL_CRLF, - EOL_LF, -#ifdef NATIVE_CRLF - EOL_NATIVE = EOL_CRLF -#else - EOL_NATIVE = EOL_LF -#endif -}; - -extern enum eol core_eol; - enum branch_track { BRANCH_TRACK_UNSPECIFIED = -1, BRANCH_TRACK_NEVER = 0, @@@ -734,7 -747,7 +737,7 @@@ extern char *expand_user_path(const cha char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { - return path[0] == '/' || has_dos_drive_prefix(path); + return is_dir_sep(path[0]) || has_dos_drive_prefix(path); } int is_directory(const char *); const char *real_path(const char *path); @@@ -767,16 -780,10 +770,16 @@@ extern int hash_sha1_file(const void *b extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1); extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *); extern int force_object_loose(const unsigned char *sha1, time_t mtime); +extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size); +extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz); +extern int parse_sha1_header(const char *hdr, unsigned long *sizep); /* 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); @@@ -1002,7 -1009,7 +1005,7 @@@ extern struct packed_git *find_sha1_pac extern void pack_report(void); extern int open_pack_index(struct packed_git *); extern void close_pack_index(struct packed_git *); -extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); +extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *); extern void close_pack_windows(struct packed_git *); extern void unuse_pack(struct pack_window **); extern void free_pack_by_name(const char *); @@@ -1014,36 -1021,7 +1017,36 @@@ extern off_t find_pack_entry_one(const extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *); extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t); -extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *); +extern int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *); + +struct object_info { + /* Request */ + unsigned long *sizep; + + /* Response */ + enum { + OI_CACHED, + OI_LOOSE, + OI_PACKED, + OI_DBCACHED + } whence; + union { + /* + * struct { + * ... Nothing to expose in this case + * } cached; + * struct { + * ... Nothing to expose in this case + * } loose; + */ + struct { + struct packed_git *pack; + off_t offset; + unsigned int is_delta; + } packed; + } u; +}; +extern int sha1_object_info_extended(const unsigned char *, struct object_info *); /* Dumb servers support */ extern int update_server_info(int); @@@ -1062,6 -1040,8 +1065,6 @@@ typedef int (*config_fn_t)(const char * extern int git_default_config(const char *, const char *, void *); extern int git_config_from_file(config_fn_t fn, const char *, void *); extern void git_config_push_parameter(const char *text); -extern int git_config_parse_parameter(const char *text); -extern int git_config_parse_environment(void); 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_early(config_fn_t fn, void *, const char *repo_config); @@@ -1085,8 -1065,6 +1088,8 @@@ extern int config_error_nonbool(const c extern const char *get_log_output_encoding(void); extern const char *get_commit_output_encoding(void); +extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data); + extern const char *config_exclusive_filename; #define MAX_GITNAME (1000) @@@ -1153,6 -1131,13 +1156,6 @@@ extern void trace_strbuf(const char *ke void packet_trace_identity(const char *prog); -/* convert.c */ -/* returns 1 if *dst was used */ -extern int convert_to_git(const char *path, const char *src, size_t len, - struct strbuf *dst, enum safe_crlf checksafe); -extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst); -extern int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst); - /* add */ /* * return 0 if success, 1 - if addition of a file failed and diff --combined contrib/completion/git-completion.bash index 5a8309076d,9b426ff76c..8648a36e7b --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@@ -1441,9 -1441,8 +1441,9 @@@ _git_grep ( __gitcomp " --cached --text --ignore-case --word-regexp --invert-match - --full-name + --full-name --line-number --extended-regexp --basic-regexp --fixed-strings + --perl-regexp --files-with-matches --name-only --files-without-match --max-depth @@@ -1469,7 -1468,7 +1469,7 @@@ _git_help ( __gitcomp "$__git_all_commands $(__git_aliases) attributes cli core-tutorial cvs-migration diffcore gitk glossary hooks ignore modules - repository-layout tutorial tutorial-2 + namespaces repository-layout tutorial tutorial-2 workflows " } @@@ -2058,7 -2057,7 +2058,7 @@@ _git_config ( color.ui commit.status commit.template - core.abbrevguard + core.abbrev core.askpass core.attributesfile core.autocrlf @@@ -2640,6 -2639,7 +2640,7 @@@ _git ( --exec-path --html-path --work-tree= + --namespace= --help " ;; diff --combined environment.c index 19351024f5,aad274b37d..03d29e8d48 --- a/environment.c +++ b/environment.c @@@ -8,6 -8,7 +8,7 @@@ * are. */ #include "cache.h" + #include "refs.h" char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; @@@ -36,7 -37,6 +37,7 @@@ size_t packed_git_window_size = DEFAULT 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; @@@ -66,6 -66,9 +67,9 @@@ int core_preload_index = 0 char *git_work_tree_cfg; static char *work_tree; + static const char *namespace; + static size_t namespace_len; + static const char *git_dir; static char *git_object_dir, *git_index_file, *git_graft_file; @@@ -87,6 -90,27 +91,27 @@@ const char * const local_repo_env[LOCAL NULL }; + static char *expand_namespace(const char *raw_namespace) + { + struct strbuf buf = STRBUF_INIT; + struct strbuf **components, **c; + + if (!raw_namespace || !*raw_namespace) + return xstrdup(""); + + strbuf_addstr(&buf, raw_namespace); + components = strbuf_split(&buf, '/'); + strbuf_reset(&buf); + for (c = components; *c; c++) + if (strcmp((*c)->buf, "/") != 0) + strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf); + strbuf_list_free(components); + if (check_ref_format(buf.buf) != CHECK_REF_FORMAT_OK) + die("bad git namespace path \"%s\"", raw_namespace); + strbuf_addch(&buf, '/'); + return strbuf_detach(&buf, NULL); + } + static void setup_git_env(void) { git_dir = getenv(GIT_DIR_ENVIRONMENT); @@@ -112,6 -136,8 +137,8 @@@ git_graft_file = git_pathdup("info/grafts"); if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT)) read_replace_refs = 0; + namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT)); + namespace_len = strlen(namespace); } int is_bare_repository(void) @@@ -132,6 -158,20 +159,20 @@@ const char *get_git_dir(void return git_dir; } + const char *get_git_namespace(void) + { + if (!namespace) + setup_git_env(); + return namespace; + } + + const char *strip_namespace(const char *namespaced_ref) + { + if (prefixcmp(namespaced_ref, get_git_namespace()) != 0) + return NULL; + return namespaced_ref + namespace_len; + } + static int git_work_tree_initialized; /* diff --combined git.c index 8828c18d6c,ad95efe5b3..304522b532 --- a/git.c +++ b/git.c @@@ -7,8 -7,8 +7,8 @@@ const char git_usage_string[] = "git [--version] [--exec-path[=]] [--html-path] [--man-path] [--info-path]\n" - " [-p|--paginate|--no-pager] [--no-replace-objects]\n" - " [--bare] [--git-dir=] [--work-tree=]\n" + " [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n" + " [--git-dir=] [--work-tree=] [--namespace=]\n" " [-c name=value] [--help]\n" " []"; @@@ -66,7 -66,7 +66,7 @@@ static void commit_pager_choice(void) static int handle_options(const char ***argv, int *argc, int *envchanged) { - int handled = 0; + const char **orig_argv = *argv; while (*argc > 0) { const char *cmd = (*argv)[0]; @@@ -122,10 -122,25 +122,24 @@@ *envchanged = 1; (*argv)++; (*argc)--; - handled++; } else if (!prefixcmp(cmd, "--git-dir=")) { setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); if (envchanged) *envchanged = 1; + } else if (!strcmp(cmd, "--namespace")) { + if (*argc < 2) { + fprintf(stderr, "No namespace given for --namespace.\n" ); + usage(git_usage_string); + } + setenv(GIT_NAMESPACE_ENVIRONMENT, (*argv)[1], 1); + if (envchanged) + *envchanged = 1; + (*argv)++; + (*argc)--; + } else if (!prefixcmp(cmd, "--namespace=")) { + setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); + if (envchanged) + *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { if (*argc < 2) { fprintf(stderr, "No directory given for --work-tree.\n" ); @@@ -161,8 -176,9 +175,8 @@@ (*argv)++; (*argc)--; - handled++; } - return handled; + return (*argv) - orig_argv; } static int handle_alias(int *argcp, const char ***argv) @@@ -183,6 -199,8 +197,6 @@@ if (alias_string[0] == '!') { const char **alias_argv; int argc = *argcp, i; - struct strbuf sb = STRBUF_INIT; - const char *env[2]; commit_pager_choice(); @@@ -193,7 -211,13 +207,7 @@@ alias_argv[i] = (*argv)[i]; alias_argv[argc] = NULL; - strbuf_addstr(&sb, "GIT_PREFIX="); - if (subdir) - strbuf_addstr(&sb, subdir); - env[0] = sb.buf; - env[1] = NULL; - ret = run_command_v_opt_cd_env(alias_argv, RUN_USING_SHELL, NULL, env); - strbuf_release(&sb); + ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); if (ret >= 0) /* normal exit */ exit(ret); diff --combined refs.c index 3a8789d385,e83bbf804a..6f313a9e0c --- a/refs.c +++ b/refs.c @@@ -584,7 -584,7 +584,7 @@@ int read_ref(const char *ref, unsigned 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)) + if (prefixcmp(entry->name, base)) return 0; if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { @@@ -728,12 -728,12 +728,12 @@@ int head_ref_submodule(const char *subm int for_each_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref(NULL, "refs/", fn, 0, 0, cb_data); + return do_for_each_ref(NULL, "", fn, 0, 0, cb_data); } int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data) { - return do_for_each_ref(submodule, "refs/", fn, 0, 0, cb_data); + return do_for_each_ref(submodule, "", fn, 0, 0, cb_data); } int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) @@@ -782,6 -782,31 +782,31 @@@ int for_each_replace_ref(each_ref_fn fn return do_for_each_ref(NULL, "refs/replace/", fn, 13, 0, cb_data); } + int head_ref_namespaced(each_ref_fn fn, void *cb_data) + { + struct strbuf buf = STRBUF_INIT; + int ret = 0; + unsigned char sha1[20]; + int flag; + + strbuf_addf(&buf, "%sHEAD", get_git_namespace()); + if (resolve_ref(buf.buf, sha1, 1, &flag)) + ret = fn(buf.buf, sha1, flag, cb_data); + strbuf_release(&buf); + + return ret; + } + + int for_each_namespaced_ref(each_ref_fn fn, void *cb_data) + { + struct strbuf buf = STRBUF_INIT; + int ret; + strbuf_addf(&buf, "%srefs/", get_git_namespace()); + ret = do_for_each_ref(NULL, buf.buf, fn, 0, 0, cb_data); + strbuf_release(&buf); + return ret; + } + int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data) { @@@ -819,7 -844,7 +844,7 @@@ int for_each_glob_ref(each_ref_fn fn, c int for_each_rawref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref(NULL, "refs/", fn, 0, + return do_for_each_ref(NULL, "", fn, 0, DO_FOR_EACH_INCLUDE_BROKEN, cb_data); } @@@ -1451,7 -1476,7 +1476,7 @@@ int write_ref_sha1(struct ref_lock *loc } o = parse_object(sha1); if (!o) { - error("Trying to write ref %s with nonexistant object %s", + error("Trying to write ref %s with nonexistent object %s", lock->ref_name, sha1_to_hex(sha1)); unlock_ref(lock); return -1; @@@ -1826,12 -1851,6 +1851,12 @@@ int update_ref(const char *action, cons return 0; } +int ref_exists(char *refname) +{ + unsigned char sha1[20]; + return !!resolve_ref(refname, sha1, 1, NULL); +} + struct ref *find_ref_by_name(const struct ref *list, const char *name) { for ( ; list; list = list->next) diff --combined refs.h index 5de06e57e7,9a5c9e02fb..dfb086e933 --- a/refs.h +++ b/refs.h @@@ -36,6 -36,9 +36,9 @@@ extern int for_each_tag_ref_submodule(c extern int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data); extern int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data); + extern int head_ref_namespaced(each_ref_fn fn, void *cb_data); + extern int for_each_namespaced_ref(each_ref_fn fn, void *cb_data); + static inline const char *has_glob_specials(const char *pattern) { return strpbrk(pattern, "?*["); @@@ -54,7 -57,6 +57,7 @@@ extern void warn_dangling_symref(FILE * */ extern void add_extra_ref(const char *refname, const unsigned char *sha1, int flags); extern void clear_extra_refs(void); +extern int ref_exists(char *); extern int peel_ref(const char *, unsigned char *);