--- /dev/null
+#include "cache.h"
+#include "commit.h"
+#include "refs.h"
+#include "pkt-line.h"
+#include "sideband.h"
+#include "run-command.h"
+#include "remote.h"
+#include "send-pack.h"
+#include "quote.h"
+#include "transport.h"
+
+static const char send_pack_usage[] =
+"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
+" --all and explicit <ref> specification are mutually exclusive.";
+
+static struct send_pack_args args;
+
+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");
+}
+
+/*
+ * Make a pack stream and spit it out into file descriptor fd
+ */
+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
+{
+ /*
+ * The child becomes pack-objects --revs; we feed
+ * the revision parameters to it via its stdin and
+ * let its stdout go back to the other end.
+ */
+ const char *argv[] = {
+ "pack-objects",
+ "--all-progress-implied",
+ "--revs",
+ "--stdout",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ };
+ struct child_process po;
+ int i;
+
+ i = 4;
+ if (args->use_thin_pack)
+ argv[i++] = "--thin";
+ if (args->use_ofs_delta)
+ argv[i++] = "--delta-base-offset";
+ if (args->quiet)
+ argv[i++] = "-q";
+ if (args->progress)
+ argv[i++] = "--progress";
+ memset(&po, 0, sizeof(po));
+ po.argv = argv;
+ po.in = -1;
+ po.out = args->stateless_rpc ? -1 : fd;
+ po.git_cmd = 1;
+ if (start_command(&po))
+ die_errno("git pack-objects failed");
+
+ /*
+ * We feed the pack-objects we just spawned with revision
+ * parameters by writing to the pipe.
+ */
+ for (i = 0; i < extra->nr; i++)
+ if (!feed_object(extra->array[i], po.in, 1))
+ break;
+
+ while (refs) {
+ if (!is_null_sha1(refs->old_sha1) &&
+ !feed_object(refs->old_sha1, po.in, 1))
+ break;
+ if (!is_null_sha1(refs->new_sha1) &&
+ !feed_object(refs->new_sha1, po.in, 0))
+ break;
+ refs = refs->next;
+ }
+
+ close(po.in);
+
+ if (args->stateless_rpc) {
+ char *buf = xmalloc(LARGE_PACKET_MAX);
+ while (1) {
+ ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
+ if (n <= 0)
+ break;
+ send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
+ }
+ free(buf);
+ close(po.out);
+ po.out = -1;
+ }
+
+ if (finish_command(&po))
+ return -1;
+ return 0;
+}
+
+static int receive_status(int in, struct ref *refs)
+{
+ struct ref *hint;
+ char line[1000];
+ int ret = 0;
+ int len = packet_read_line(in, line, sizeof(line));
+ if (len < 10 || memcmp(line, "unpack ", 7))
+ return error("did not receive remote status");
+ if (memcmp(line, "unpack ok\n", 10)) {
+ char *p = line + strlen(line) - 1;
+ if (*p == '\n')
+ *p = '\0';
+ error("unpack failed: %s", line + 7);
+ ret = -1;
+ }
+ hint = NULL;
+ while (1) {
+ char *refname;
+ char *msg;
+ len = packet_read_line(in, line, sizeof(line));
+ if (!len)
+ break;
+ if (len < 3 ||
+ (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
+ fprintf(stderr, "protocol error: %s\n", line);
+ ret = -1;
+ break;
+ }
+
+ line[strlen(line)-1] = '\0';
+ refname = line + 3;
+ msg = strchr(refname, ' ');
+ if (msg)
+ *msg++ = '\0';
+
+ /* first try searching at our hint, falling back to all refs */
+ if (hint)
+ hint = find_ref_by_name(hint, refname);
+ if (!hint)
+ hint = find_ref_by_name(refs, refname);
+ if (!hint) {
+ warning("remote reported status on unknown ref: %s",
+ refname);
+ continue;
+ }
+ if (hint->status != REF_STATUS_EXPECTING_REPORT) {
+ warning("remote reported status on unexpected ref: %s",
+ refname);
+ continue;
+ }
+
+ if (line[0] == 'o' && line[1] == 'k')
+ hint->status = REF_STATUS_OK;
+ else {
+ hint->status = REF_STATUS_REMOTE_REJECT;
+ ret = -1;
+ }
+ if (msg)
+ hint->remote_status = xstrdup(msg);
+ /* start our next search from the next ref */
+ hint = hint->next;
+ }
+ return ret;
+}
+
+static void print_helper_status(struct ref *ref)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ for (; ref; ref = ref->next) {
+ const char *msg = NULL;
+ const char *res;
+
+ switch(ref->status) {
+ case REF_STATUS_NONE:
+ res = "error";
+ msg = "no match";
+ break;
+
+ case REF_STATUS_OK:
+ res = "ok";
+ break;
+
+ case REF_STATUS_UPTODATE:
+ res = "ok";
+ msg = "up to date";
+ break;
+
+ case REF_STATUS_REJECT_NONFASTFORWARD:
+ res = "error";
+ msg = "non-fast forward";
+ break;
+
+ case REF_STATUS_REJECT_NODELETE:
+ case REF_STATUS_REMOTE_REJECT:
+ res = "error";
+ break;
+
+ case REF_STATUS_EXPECTING_REPORT:
+ default:
+ continue;
+ }
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s %s", res, ref->name);
+ if (ref->remote_status)
+ msg = ref->remote_status;
+ if (msg) {
+ strbuf_addch(&buf, ' ');
+ quote_two_c_style(&buf, "", msg, 0);
+ }
+ strbuf_addch(&buf, '\n');
+
+ safe_write(1, buf.buf, buf.len);
+ }
+ strbuf_release(&buf);
+}
+
+static int sideband_demux(int in, int out, void *data)
+{
+ int *fd = data, ret;
+#ifdef NO_PTHREADS
+ close(fd[1]);
+#endif
+ ret = recv_sideband("send-pack", fd[0], out);
+ close(out);
+ return ret;
+}
+
+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 strbuf req_buf = STRBUF_INIT;
+ struct ref *ref;
+ int new_refs;
+ int allow_deleting_refs = 0;
+ int status_report = 0;
+ int use_sideband = 0;
+ unsigned cmds_sent = 0;
+ int ret;
+ struct async demux;
+
+ /* Does the other end support the reporting? */
+ if (server_supports("report-status"))
+ status_report = 1;
+ if (server_supports("delete-refs"))
+ allow_deleting_refs = 1;
+ if (server_supports("ofs-delta"))
+ args->use_ofs_delta = 1;
+ if (server_supports("side-band-64k"))
+ use_sideband = 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 && !args->send_mirror)
+ continue;
+
+ /* Check for statuses set by set_ref_status_for_push() */
+ switch (ref->status) {
+ case REF_STATUS_REJECT_NONFASTFORWARD:
+ case REF_STATUS_UPTODATE:
+ continue;
+ default:
+ ; /* do nothing */
+ }
+
+ if (ref->deletion && !allow_deleting_refs) {
+ ref->status = REF_STATUS_REJECT_NODELETE;
+ continue;
+ }
+
+ if (!ref->deletion)
+ new_refs++;
+
+ if (args->dry_run) {
+ ref->status = REF_STATUS_OK;
+ } else {
+ char *old_hex = sha1_to_hex(ref->old_sha1);
+ char *new_hex = sha1_to_hex(ref->new_sha1);
+
+ if (!cmds_sent && (status_report || use_sideband)) {
+ packet_buf_write(&req_buf, "%s %s %s%c%s%s",
+ old_hex, new_hex, ref->name, 0,
+ status_report ? " report-status" : "",
+ use_sideband ? " side-band-64k" : "");
+ }
+ else
+ packet_buf_write(&req_buf, "%s %s %s",
+ old_hex, new_hex, ref->name);
+ ref->status = status_report ?
+ REF_STATUS_EXPECTING_REPORT :
+ REF_STATUS_OK;
+ cmds_sent++;
+ }
+ }
+
+ if (args->stateless_rpc) {
+ if (!args->dry_run && cmds_sent) {
+ packet_buf_flush(&req_buf);
+ send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
+ }
+ } else {
+ safe_write(out, req_buf.buf, req_buf.len);
+ packet_flush(out);
+ }
+ strbuf_release(&req_buf);
+
+ if (use_sideband && cmds_sent) {
+ memset(&demux, 0, sizeof(demux));
+ demux.proc = sideband_demux;
+ demux.data = fd;
+ demux.out = -1;
+ if (start_async(&demux))
+ die("receive-pack: unable to fork off sideband demultiplexer");
+ in = demux.out;
+ }
+
+ if (new_refs && cmds_sent) {
+ if (pack_objects(out, remote_refs, extra_have, args) < 0) {
+ for (ref = remote_refs; ref; ref = ref->next)
+ ref->status = REF_STATUS_NONE;
+ if (args->stateless_rpc)
+ close(out);
++ if (git_connection_is_socket(conn))
++ shutdown(fd[0], SHUT_WR);
+ if (use_sideband)
+ finish_async(&demux);
+ return -1;
+ }
+ }
+ if (args->stateless_rpc && cmds_sent)
+ packet_flush(out);
+
+ if (status_report && cmds_sent)
+ ret = receive_status(in, remote_refs);
+ else
+ ret = 0;
+ if (args->stateless_rpc)
+ packet_flush(out);
+
+ if (use_sideband && cmds_sent) {
+ if (finish_async(&demux)) {
+ error("error in sideband demultiplexer");
+ ret = -1;
+ }
+ close(demux.out);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (args->porcelain)
+ return 0;
+
+ 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;
+}
+
+int cmd_send_pack(int argc, const char **argv, const char *prefix)
+{
+ int i, nr_refspecs = 0;
+ const char **refspecs = NULL;
+ const char *remote_name = NULL;
+ struct remote *remote = NULL;
+ const char *dest = NULL;
+ int fd[2];
+ struct child_process *conn;
+ struct extra_have_objects extra_have;
+ struct ref *remote_refs, *local_refs;
+ int ret;
+ int helper_status = 0;
+ int send_all = 0;
+ const char *receivepack = "git-receive-pack";
+ int flags;
+ int nonfastforward = 0;
+
+ argv++;
+ for (i = 1; i < argc; i++, argv++) {
+ const char *arg = *argv;
+
+ if (*arg == '-') {
+ if (!prefixcmp(arg, "--receive-pack=")) {
+ receivepack = arg + 15;
+ continue;
+ }
+ if (!prefixcmp(arg, "--exec=")) {
+ receivepack = arg + 7;
+ continue;
+ }
+ if (!prefixcmp(arg, "--remote=")) {
+ remote_name = arg + 9;
+ continue;
+ }
+ if (!strcmp(arg, "--all")) {
+ send_all = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--dry-run")) {
+ args.dry_run = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--mirror")) {
+ args.send_mirror = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--force")) {
+ args.force_update = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--verbose")) {
+ args.verbose = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--thin")) {
+ args.use_thin_pack = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--stateless-rpc")) {
+ args.stateless_rpc = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--helper-status")) {
+ helper_status = 1;
+ continue;
+ }
+ usage(send_pack_usage);
+ }
+ if (!dest) {
+ dest = arg;
+ continue;
+ }
+ refspecs = (const char **) argv;
+ nr_refspecs = argc - i;
+ break;
+ }
+ if (!dest)
+ usage(send_pack_usage);
+ /*
+ * --all and --mirror are incompatible; neither makes sense
+ * with any refspecs.
+ */
+ if ((refspecs && (send_all || args.send_mirror)) ||
+ (send_all && args.send_mirror))
+ usage(send_pack_usage);
+
+ if (remote_name) {
+ remote = remote_get(remote_name);
+ if (!remote_has_url(remote, dest)) {
+ die("Destination %s is not a uri for %s",
+ dest, remote_name);
+ }
+ }
+
+ if (args.stateless_rpc) {
+ conn = NULL;
+ fd[0] = 0;
+ fd[1] = 1;
+ } else {
+ conn = git_connect(fd, dest, receivepack,
+ args.verbose ? CONNECT_VERBOSE : 0);
+ }
+
+ memset(&extra_have, 0, sizeof(extra_have));
+
+ get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
+ &extra_have);
+
+ transport_verify_remote_names(nr_refspecs, refspecs);
+
+ local_refs = get_local_heads();
+
+ flags = MATCH_REFS_NONE;
+
+ if (send_all)
+ flags |= MATCH_REFS_ALL;
+ if (args.send_mirror)
+ flags |= MATCH_REFS_MIRROR;
+
+ /* match them up */
+ if (match_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
+ return -1;
+
+ set_ref_status_for_push(remote_refs, args.send_mirror,
+ args.force_update);
+
+ ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
+
+ if (helper_status)
+ print_helper_status(remote_refs);
+
+ close(fd[1]);
+ close(fd[0]);
+
+ ret |= finish_connect(conn);
+
+ if (!helper_status)
+ transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
+
+ if (!args.dry_run && remote) {
+ struct ref *ref;
+ for (ref = remote_refs; ref; ref = ref->next)
+ transport_update_tracking_ref(remote, ref, args.verbose);
+ }
+
+ if (!ret && !transport_refs_pushed(remote_refs))
+ fprintf(stderr, "Everything up-to-date\n");
+
+ return ret;
+}
*
* In-memory only flags
*/
-#define CE_UPDATE (0x10000)
-#define CE_REMOVE (0x20000)
-#define CE_UPTODATE (0x40000)
-#define CE_ADDED (0x80000)
+#define CE_UPDATE (1 << 16)
+#define CE_REMOVE (1 << 17)
+#define CE_UPTODATE (1 << 18)
+#define CE_ADDED (1 << 19)
-#define CE_HASHED (0x100000)
-#define CE_UNHASHED (0x200000)
+#define CE_HASHED (1 << 20)
+#define CE_UNHASHED (1 << 21)
+#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
+#define CE_CONFLICTED (1 << 23)
+
+#define CE_UNPACKED (1 << 24)
+#define CE_NEW_SKIP_WORKTREE (1 << 25)
/*
* Extended on-disk flags
*/
-#define CE_INTENT_TO_ADD 0x20000000
+#define CE_INTENT_TO_ADD (1 << 29)
+#define CE_SKIP_WORKTREE (1 << 30)
/* CE_EXTENDED2 is for future extension */
-#define CE_EXTENDED2 0x80000000
+#define CE_EXTENDED2 (1 << 31)
-#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
+#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
/*
* Safeguard to avoid saving wrong flags:
ondisk_cache_entry_size(ce_namelen(ce)))
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
else
return DT_UNKNOWN;
}
-#define canon_mode(mode) \
- (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
- S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
+static inline unsigned int canon_mode(unsigned int mode)
+{
+ if (S_ISREG(mode))
+ return S_IFREG | ce_permissions(mode);
+ if (S_ISLNK(mode))
+ return S_IFLNK;
+ if (S_ISDIR(mode))
+ return S_IFDIR;
+ return S_IFGITLINK;
+}
#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
#define cache_entry_size(len) flexible_size(cache_entry,len)
struct index_state {
struct cache_entry **cache;
unsigned int cache_nr, cache_alloc, cache_changed;
+ struct string_list *resolve_undo;
struct cache_tree *cache_tree;
struct cache_time timestamp;
void *alloc;
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
+#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
+#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
+#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
#endif
enum object_type {
OBJ_OFS_DELTA = 6,
OBJ_REF_DELTA = 7,
OBJ_ANY,
- OBJ_MAX,
+ OBJ_MAX
};
static inline enum object_type object_type(unsigned int mode)
#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
#define CONFIG_ENVIRONMENT "GIT_CONFIG"
+#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
+#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
+#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
+#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
+
+/*
+ * Repository-local GIT_* environment variables
+ * The array is NULL-terminated to simplify its usage in contexts such
+ * environment creation or simple walk of the list.
+ * The number of non-NULL entries is available as a macro.
+ */
+#define LOCAL_REPO_ENV_SIZE 9
+extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1];
extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
-extern const char *prefix_path(const char *prefix, int len, const char *path);
+extern char *prefix_path(const char *prefix, int len, const char *path);
extern const char *prefix_filename(const char *prefix, int len, const char *path);
extern int check_filename(const char *prefix, const char *name);
extern void verify_filename(const char *prefix, const char *name);
* at least 'nr' entries; the number of entries currently allocated
* is 'alloc', using the standard growing factor alloc_nr() macro.
*
- * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
+ * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
*/
#define ALLOC_GROW(x, nr, alloc) \
do { \
alloc = alloc_nr(alloc); \
x = xrealloc((x), alloc * sizeof(*(x))); \
} \
- } while(0)
+ } while (0)
/* Initialize and use the cache information */
extern int read_index(struct index_state *);
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
-extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
extern int remove_index_entry_at(struct index_state *, int pos);
extern void remove_marked_cache_entries(struct index_state *istate);
/* do stat comparison even if CE_VALID is true */
#define CE_MATCH_IGNORE_VALID 01
/* do not check the contents but report dirty on racily-clean entries */
-#define CE_MATCH_RACY_IS_DIRTY 02
+#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 index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
-/* "careful lstat()" */
-extern int check_path(const char *path, int len, struct stat *st, int skiplen);
-
#define REFRESH_REALLY 0x0001 /* ignore_valid */
#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
#define REFRESH_QUIET 0x0004 /* be quiet about it */
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
extern int commit_lock_file(struct lock_file *);
+extern void update_index_if_able(struct index_state *, struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
extern int commit_locked_index(struct lock_file *);
extern int trust_ctime;
extern int quote_path_fully;
extern int has_symlinks;
+extern int minimum_abbrev, default_abbrev;
extern int ignore_case;
extern int assume_unchanged;
extern int prefer_symlink_refs;
extern size_t packed_git_window_size;
extern size_t packed_git_limit;
extern size_t delta_base_cache_limit;
-extern int auto_crlf;
extern int read_replace_refs;
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,
+ 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 eol;
+
enum branch_track {
BRANCH_TRACK_UNSPECIFIED = -1,
BRANCH_TRACK_NEVER = 0,
BRANCH_TRACK_REMOTE,
BRANCH_TRACK_ALWAYS,
BRANCH_TRACK_EXPLICIT,
+ BRANCH_TRACK_OVERRIDE
};
enum rebase_setup_type {
AUTOREBASE_NEVER = 0,
AUTOREBASE_LOCAL,
AUTOREBASE_REMOTE,
- AUTOREBASE_ALWAYS,
+ AUTOREBASE_ALWAYS
};
enum push_default_type {
PUSH_DEFAULT_NOTHING = 0,
PUSH_DEFAULT_MATCHING,
- PUSH_DEFAULT_TRACKING,
- PUSH_DEFAULT_CURRENT,
+ PUSH_DEFAULT_UPSTREAM,
+ PUSH_DEFAULT_CURRENT
};
extern enum branch_track git_branch_track;
enum object_creation_mode {
OBJECT_CREATION_USES_HARDLINKS = 0,
- OBJECT_CREATION_USES_RENAMES = 1,
+ OBJECT_CREATION_USES_RENAMES = 1
};
extern enum object_creation_mode object_creation_mode;
/* Return a statically allocated filename matching the sha1 signature */
extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern char *git_path_submodule(const char *path, const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+
extern char *sha1_file_name(const unsigned char *sha1);
extern char *sha1_pack_name(const unsigned char *sha1);
extern char *sha1_pack_index_name(const unsigned char *sha1);
{
memset(hash, 0, 20);
}
-extern int is_empty_blob_sha1(const unsigned char *sha1);
#define EMPTY_TREE_SHA1_HEX \
"4b825dc642cb6eb9a060e54bf8d69288fbee4904"
-#define EMPTY_TREE_SHA1_BIN \
+#define EMPTY_TREE_SHA1_BIN_LITERAL \
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
+#define EMPTY_TREE_SHA1_BIN \
+ ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
int git_mkstemp(char *path, size_t n, const char *template);
int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
+/* set default permissions by passing mode arguments to open(2) */
+int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
+int git_mkstemp_mode(char *pattern, int mode);
+
/*
* NOTE NOTE NOTE!!
*
OLD_PERM_GROUP = 1,
OLD_PERM_EVERYBODY = 2,
PERM_GROUP = 0660,
- PERM_EVERYBODY = 0664,
+ PERM_EVERYBODY = 0664
};
int git_config_perm(const char *var, const char *value);
int set_shared_perm(const char *path, int mode);
int longest_ancestor_length(const char *path, const char *prefix_list);
char *strip_path_suffix(const char *path, const char *suffix);
int daemon_avoid_alias(const char *path);
+int offset_1st_component(const char *path);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
return read_sha1_file_repl(sha1, type, size, NULL);
}
extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
+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 int has_sha1_file(const unsigned char *sha1);
extern int has_loose_object_nonlocal(const unsigned char *sha1);
-extern int has_pack_file(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1);
+extern void assert_sha1_type(const unsigned char *sha1, enum object_type expect);
+
extern const signed char hexval_table[256];
static inline unsigned int hexval(unsigned char c)
{
}
/* Convert to/from hex/sha1 representation */
-#define MINIMUM_ABBREV 4
-#define DEFAULT_ABBREV 7
+#define MINIMUM_ABBREV minimum_abbrev
+#define DEFAULT_ABBREV default_abbrev
+
+struct object_context {
+ unsigned char tree[20];
+ char path[PATH_MAX];
+ unsigned mode;
+};
extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
+extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
+static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
+{
+ return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
+}
+extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int gently, const char *prefix);
+static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
+{
+ return get_sha1_with_context_1(str, sha1, orc, 1, NULL);
+}
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern int read_ref(const char *filename, unsigned char *sha1);
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
extern int interpret_branch_name(const char *str, struct strbuf *);
+extern int get_sha1_mb(const char *str, unsigned char *sha1);
extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
extern const char *ref_rev_parse_rules[];
char *timebuf,
size_t timebuf_size);
int parse_date(const char *date, char *buf, int bufsize);
+int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
void datestamp(char *buf, int bufsize);
-unsigned long approxidate(const char *);
+#define approxidate(s) approxidate_careful((s), NULL)
+unsigned long approxidate_careful(const char *, int *);
unsigned long approxidate_relative(const char *date, const struct timeval *now);
enum date_mode parse_date_format(const char *format);
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
extern const char *fmt_name(const char *name, const char *email);
extern const char *git_editor(void);
-extern const char *git_pager(void);
+extern const char *git_pager(int stdout_is_tty);
struct checkout {
const char *base_dir;
extern int has_symlink_leading_path(const char *name, int len);
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
-extern int has_symlink_or_noent_leading_path(const char *name, int len);
+extern int check_leading_path(const char *name, int len);
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
-extern void invalidate_lstat_cache(const char *name, int len);
-extern void clear_lstat_cache(void);
extern void schedule_dir_for_removal(const char *name, int len);
extern void remove_scheduled_dirs(void);
time_t mtime;
int pack_fd;
unsigned pack_local:1,
- pack_keep:1;
+ pack_keep:1,
+ do_not_close:1;
unsigned char sha1[20];
/* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[FLEX_ARRAY]; /* more */
REF_STATUS_REJECT_NODELETE,
REF_STATUS_UPTODATE,
REF_STATUS_REMOTE_REJECT,
- REF_STATUS_EXPECTING_REPORT,
+ REF_STATUS_EXPECTING_REPORT
} status;
char *remote_status;
struct ref *peer_ref; /* when renaming */
extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
#define CONNECT_VERBOSE (1u << 0)
+extern char *git_getpass(const char *prompt);
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
extern int finish_connect(struct child_process *conn);
+ extern int git_connection_is_socket(struct child_process *conn);
extern int path_match(const char *path, int nr, char **match);
struct extra_have_objects {
int nr, alloc;
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
-extern struct packed_git *parse_pack_index(unsigned char *sha1);
+extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
extern void prepare_packed_git(void);
extern void reprepare_packed_git(void);
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 void close_pack_windows(struct packed_git *);
extern void unuse_pack(struct pack_window **);
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 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);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
extern int git_config_bool_or_int(const char *, const char *, int *);
extern int git_config_bool(const char *, const char *);
+extern int git_config_maybe_bool(const char *, const char *);
extern int git_config_string(const char **, const char *, const char *);
extern int git_config_pathname(const char **, const char *, const char *);
extern int git_config_set(const char *, const char *);
+extern int git_config_parse_key(const char *, char **, int *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int git_config_rename_section(const char *, const char *);
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value, void *cb);
+extern int git_env_bool(const char *, int);
extern int git_config_system(void);
extern int git_config_global(void);
extern int config_error_nonbool(const char *);
+extern const char *get_log_output_encoding(void);
+extern const char *get_commit_output_encoding(void);
+
extern const char *config_exclusive_filename;
#define MAX_GITNAME (1000)
extern char git_default_email[MAX_GITNAME];
extern char git_default_name[MAX_GITNAME];
+#define IDENT_NAME_GIVEN 01
+#define IDENT_MAIL_GIVEN 02
+#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
extern int user_ident_explicitly_given;
+extern int user_ident_sufficiently_given(void);
extern const char *git_commit_encoding;
extern const char *git_log_output_encoding;
extern int pager_use_color;
extern const char *editor_program;
+extern const char *askpass_program;
extern const char *excludes_file;
/* base85 */
extern void trace_printf(const char *format, ...);
__attribute__((format (printf, 2, 3)))
extern void trace_argv_printf(const char **argv, const char *format, ...);
+extern void trace_repo_setup(const char *prefix);
/* 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 */
/*
/* match-trees.c */
void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
+void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *, const char *);
/*
* whitespace rules.
* used by both diff and apply
+ * last two digits are tab width
*/
-#define WS_BLANK_AT_EOL 01
-#define WS_SPACE_BEFORE_TAB 02
-#define WS_INDENT_WITH_NON_TAB 04
-#define WS_CR_AT_EOL 010
-#define WS_BLANK_AT_EOF 020
+#define WS_BLANK_AT_EOL 0100
+#define WS_SPACE_BEFORE_TAB 0200
+#define WS_INDENT_WITH_NON_TAB 0400
+#define WS_CR_AT_EOL 01000
+#define WS_BLANK_AT_EOF 02000
+#define WS_TAB_IN_INDENT 04000
#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
-#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
+#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
+#define WS_TAB_WIDTH_MASK 077
extern unsigned whitespace_rule_cfg;
extern unsigned whitespace_rule(const char *);
extern unsigned parse_whitespace_rule(const char *);
extern unsigned ws_check(const char *line, int len, unsigned ws_rule);
extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
extern char *whitespace_error_string(unsigned ws);
-extern int ws_fix_copy(char *, const char *, int, unsigned, int *);
+extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
+#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
/* ls-files */
int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset);
char *alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
+/* Takes a negative value returned by split_cmdline */
+const char *split_cmdline_strerror(int cmdline_errno);
+
+/* git.c */
+struct startup_info {
+ int have_repository;
+ const char *prefix;
+};
+extern struct startup_info *startup_info;
+
+/* builtin/merge.c */
+int checkout_fast_forward(const unsigned char *from, const unsigned char *to);
#endif /* CACHE_H */
#include "refs.h"
#include "run-command.h"
#include "remote.h"
+#include "url.h"
static char *server_capabilities;
enum protocol {
PROTO_LOCAL = 1,
PROTO_SSH,
- PROTO_GIT,
+ PROTO_GIT
};
static enum protocol get_protocol(const char *name)
#define STR_(s) # s
#define STR(s) STR_(s)
+static void get_host_and_port(char **host, const char **port)
+{
+ char *colon, *end;
+
+ if (*host[0] == '[') {
+ end = strchr(*host + 1, ']');
+ if (end) {
+ *end = 0;
+ end++;
+ (*host)++;
+ } else
+ end = *host;
+ } else
+ end = *host;
+ colon = strchr(end, ':');
+
+ if (colon) {
+ *colon = 0;
+ *port = colon + 1;
+ }
+}
+
#ifndef NO_IPV6
static const char *ai_name(const struct addrinfo *ai)
static int git_tcp_connect_sock(char *host, int flags)
{
int sockfd = -1, saved_errno = 0;
- char *colon, *end;
const char *port = STR(DEFAULT_GIT_PORT);
struct addrinfo hints, *ai0, *ai;
int gai;
int cnt = 0;
- if (host[0] == '[') {
- end = strchr(host + 1, ']');
- if (end) {
- *end = 0;
- end++;
- host++;
- } else
- end = host;
- } else
- end = host;
- colon = strchr(end, ':');
-
- if (colon) {
- *colon = 0;
- port = colon + 1;
- if (!*port)
- port = "<none>";
- }
+ get_host_and_port(&host, &port);
+ if (!*port)
+ port = "<none>";
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
static int git_tcp_connect_sock(char *host, int flags)
{
int sockfd = -1, saved_errno = 0;
- char *colon, *end;
- char *port = STR(DEFAULT_GIT_PORT), *ep;
+ const char *port = STR(DEFAULT_GIT_PORT);
+ char *ep;
struct hostent *he;
struct sockaddr_in sa;
char **ap;
unsigned int nport;
int cnt;
- if (host[0] == '[') {
- end = strchr(host + 1, ']');
- if (end) {
- *end = 0;
- end++;
- host++;
- } else
- end = host;
- } else
- end = host;
- colon = strchr(end, ':');
-
- if (colon) {
- *colon = 0;
- port = colon + 1;
- }
+ get_host_and_port(&host, &port);
if (flags & CONNECT_VERBOSE)
fprintf(stderr, "Looking up %s ... ", host);
return (git_proxy_command && *git_proxy_command);
}
- static void git_proxy_connect(int fd[2], char *host)
+ static struct child_process *git_proxy_connect(int fd[2], char *host)
{
const char *port = STR(DEFAULT_GIT_PORT);
- const char *argv[4];
- struct child_process proxy;
- char *colon, *end;
+ const char **argv;
+ struct child_process *proxy;
- if (host[0] == '[') {
- end = strchr(host + 1, ']');
- if (end) {
- *end = 0;
- end++;
- host++;
- } else
- end = host;
- } else
- end = host;
- colon = strchr(end, ':');
-
- if (colon) {
- *colon = 0;
- port = colon + 1;
- }
+ get_host_and_port(&host, &port);
+ argv = xmalloc(sizeof(*argv) * 4);
argv[0] = git_proxy_command;
argv[1] = host;
argv[2] = port;
argv[3] = NULL;
- memset(&proxy, 0, sizeof(proxy));
- proxy.argv = argv;
- proxy.in = -1;
- proxy.out = -1;
- if (start_command(&proxy))
+ proxy = xcalloc(1, sizeof(*proxy));
+ proxy->argv = argv;
+ proxy->in = -1;
+ proxy->out = -1;
+ if (start_command(proxy))
die("cannot start proxy %s", argv[0]);
- fd[0] = proxy.out; /* read from proxy stdout */
- fd[1] = proxy.in; /* write to proxy stdin */
+ fd[0] = proxy->out; /* read from proxy stdout */
+ fd[1] = proxy->in; /* write to proxy stdin */
+ return proxy;
}
#define MAX_CMD_LEN 1024
struct child_process *git_connect(int fd[2], const char *url_orig,
const char *prog, int flags)
{
- char *url = xstrdup(url_orig);
+ char *url;
char *host, *path;
char *end;
int c;
- struct child_process *conn;
+ struct child_process *conn = &no_fork;
enum protocol protocol = PROTO_LOCAL;
int free_path = 0;
char *port = NULL;
*/
signal(SIGCHLD, SIG_DFL);
+ if (is_url(url_orig))
+ url = url_decode(url_orig);
+ else
+ url = xstrdup(url_orig);
+
host = strstr(url, "://");
if (host) {
*host = '\0';
c = ':';
}
+ /*
+ * Don't do destructive transforms with git:// as that
+ * protocol code does '[]' unwrapping of its own.
+ */
if (host[0] == '[') {
end = strchr(host + 1, ']');
if (end) {
- *end = 0;
+ if (protocol != PROTO_GIT) {
+ *end = 0;
+ host++;
+ }
end++;
- host++;
} else
end = host;
} else
*/
char *target_host = xstrdup(host);
if (git_use_proxy(host))
- git_proxy_connect(fd, host);
+ conn = git_proxy_connect(fd, host);
else
git_tcp_connect(fd, host, flags);
/*
free(url);
if (free_path)
free(path);
- return &no_fork;
+ return conn;
}
conn = xcalloc(1, sizeof(*conn));
*arg++ = host;
}
else {
- /* remove these from the environment */
- const char *env[] = {
- ALTERNATE_DB_ENVIRONMENT,
- DB_ENVIRONMENT,
- GIT_DIR_ENVIRONMENT,
- GIT_WORK_TREE_ENVIRONMENT,
- GRAFT_ENVIRONMENT,
- INDEX_ENVIRONMENT,
- NO_REPLACE_OBJECTS_ENVIRONMENT,
- NULL
- };
- conn->env = env;
- *arg++ = "sh";
- *arg++ = "-c";
+ /* remove repo-local variables from the environment */
+ conn->env = local_repo_env;
+ conn->use_shell = 1;
}
*arg++ = cmd.buf;
*arg = NULL;
return conn;
}
+ int git_connection_is_socket(struct child_process *conn)
+ {
+ return conn == &no_fork;
+ }
+
int finish_connect(struct child_process *conn)
{
int code;
- if (!conn || conn == &no_fork)
+ if (!conn || git_connection_is_socket(conn))
return 0;
code = finish_command(conn);
free(conn);
return code;
}
+
+char *git_getpass(const char *prompt)
+{
+ const char *askpass;
+ struct child_process pass;
+ const char *args[3];
+ static struct strbuf buffer = STRBUF_INIT;
+
+ askpass = getenv("GIT_ASKPASS");
+ if (!askpass)
+ askpass = askpass_program;
+ if (!askpass)
+ askpass = getenv("SSH_ASKPASS");
+ if (!askpass || !(*askpass)) {
+ char *result = getpass(prompt);
+ if (!result)
+ die_errno("Could not read password");
+ return result;
+ }
+
+ args[0] = askpass;
+ args[1] = prompt;
+ args[2] = NULL;
+
+ memset(&pass, 0, sizeof(pass));
+ pass.argv = args;
+ pass.out = -1;
+
+ if (start_command(&pass))
+ exit(1);
+
+ strbuf_reset(&buffer);
+ if (strbuf_read(&buffer, pass.out, 20) < 0)
+ die("failed to read password from %s\n", askpass);
+
+ close(pass.out);
+
+ if (finish_command(&pass))
+ exit(1);
+
+ strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n"));
+
+ return buffer.buf;
+}