for h in *.html *.txt howto/*.txt howto/*.html
do
- diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h" || {
+ if test -f "$T/$h" &&
+ diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h"
+ then
+ :; # up to date
+ else
echo >&2 "# install $h $T/$h"
rm -f "$T/$h"
mkdir -p `dirname "$T/$h"`
cp "$h" "$T/$h"
- }
+ fi
done
strip_leading=`echo "$T/" | sed -e 's|.|.|g'`
for th in "$T"/*.html "$T"/*.txt "$T"/howto/*.txt "$T"/howto/*.html
git-convert-objects$X git-diff-files$X \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
- git-hash-object$X git-index-pack$X git-init-db$X git-local-fetch$X \
+ git-hash-object$X git-index-pack$X git-local-fetch$X \
git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-read-tree$X \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
- git-grep$X git-rev-list$X git-check-ref-format$X
+ git-grep$X git-rev-list$X git-check-ref-format$X \
+ git-init-db$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
- builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o
+ builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
+ builtin-init-db.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS)
$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
+ -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' \
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-init-db.o: init-db.c
- $(CC) -c $(ALL_CFLAGS) \
- -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
-
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS)
$(DIFF_OBJS): diffcore.h
rpm: dist
$(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
+htmldocs = git-htmldocs-$(GIT_VERSION)
+manpages = git-manpages-$(GIT_VERSION)
+dist-doc:
+ rm -fr .doc-tmp-dir
+ mkdir .doc-tmp-dir
+ $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
+ cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
+ gzip -n -9 -f $(htmldocs).tar
+ :
+ rm -fr .doc-tmp-dir
+ mkdir .doc-tmp-dir .doc-tmp-dir/man1 .doc-tmp-dir/man7
+ $(MAKE) -C Documentation DESTDIR=. \
+ man1=../.doc-tmp-dir/man1 \
+ man7=../.doc-tmp-dir/man7 \
+ install
+ cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
+ gzip -n -9 -f $(manpages).tar
+ rm -fr .doc-tmp-dir
+
### Cleaning rules
clean:
$(LIB_FILE) $(XDIFF_LIB)
rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
- rm -rf $(GIT_TARNAME)
+ rm -rf $(GIT_TARNAME) .doc-tmp-dir
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
+ rm -f $(htmldocs).tar $(manpages).tar
$(MAKE) -C Documentation/ clean
$(MAKE) -C templates clean
$(MAKE) -C t/ clean
// --stat does just a diffstat, and doesn't actually apply
// --numstat does numeric diffstat, and doesn't actually apply
// --index-info shows the old and new index info for paths if available.
+// --index updates the cache as well.
+// --cached updates only the cache without ever touching the working tree.
//
static const char *prefix;
static int prefix_length = -1;
static int allow_binary_replacement = 0;
static int check_index = 0;
static int write_index = 0;
+static int cached = 0;
static int diffstat = 0;
static int numstat = 0;
static int summary = 0;
static int line_termination = '\n';
static unsigned long p_context = -1;
static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
+"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
static enum whitespace_eol {
nowarn_whitespace,
return 0;
}
-static int apply_data(struct patch *patch, struct stat *st)
+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
char *buf;
unsigned long size, alloc;
size = 0;
alloc = 0;
buf = NULL;
- if (patch->old_name) {
+ if (cached) {
+ if (ce) {
+ char type[20];
+ buf = read_sha1_file(ce->sha1, type, &size);
+ if (!buf)
+ return error("read of %s failed",
+ patch->old_name);
+ alloc = size;
+ }
+ }
+ else if (patch->old_name) {
size = st->st_size;
alloc = size + 8192;
buf = xmalloc(alloc);
const char *old_name = patch->old_name;
const char *new_name = patch->new_name;
const char *name = old_name ? old_name : new_name;
+ struct cache_entry *ce = NULL;
if (old_name) {
- int changed;
- int stat_ret = lstat(old_name, &st);
+ int changed = 0;
+ int stat_ret = 0;
+ unsigned st_mode = 0;
+ if (!cached)
+ stat_ret = lstat(old_name, &st);
if (check_index) {
int pos = cache_name_pos(old_name, strlen(old_name));
if (pos < 0)
return error("%s: does not exist in index",
old_name);
+ ce = active_cache[pos];
if (stat_ret < 0) {
struct checkout costate;
if (errno != ENOENT)
costate.quiet = 0;
costate.not_new = 0;
costate.refresh_cache = 1;
- if (checkout_entry(active_cache[pos],
+ if (checkout_entry(ce,
&costate,
NULL) ||
lstat(old_name, &st))
return -1;
}
-
- changed = ce_match_stat(active_cache[pos], &st, 1);
+ if (!cached)
+ changed = ce_match_stat(ce, &st, 1);
if (changed)
return error("%s: does not match index",
old_name);
+ if (cached)
+ st_mode = ntohl(ce->ce_mode);
}
else if (stat_ret < 0)
return error("%s: %s", old_name, strerror(errno));
+ if (!cached)
+ st_mode = ntohl(create_ce_mode(st.st_mode));
+
if (patch->is_new < 0)
patch->is_new = 0;
- st.st_mode = ntohl(create_ce_mode(st.st_mode));
if (!patch->old_mode)
- patch->old_mode = st.st_mode;
- if ((st.st_mode ^ patch->old_mode) & S_IFMT)
+ patch->old_mode = st_mode;
+ if ((st_mode ^ patch->old_mode) & S_IFMT)
return error("%s: wrong type", old_name);
- if (st.st_mode != patch->old_mode)
+ if (st_mode != patch->old_mode)
fprintf(stderr, "warning: %s has type %o, expected %o\n",
- old_name, st.st_mode, patch->old_mode);
+ old_name, st_mode, patch->old_mode);
}
if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {
if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0)
return error("%s: already exists in index", new_name);
- if (!lstat(new_name, &st))
+ if (!cached && !lstat(new_name, &st))
return error("%s: already exists in working directory", new_name);
if (errno != ENOENT)
return error("%s: %s", new_name, strerror(errno));
return error("new mode (%o) of %s does not match old mode (%o)%s%s",
patch->new_mode, new_name, patch->old_mode,
same ? "" : " of ", same ? "" : old_name);
- }
+ }
- if (apply_data(patch, &st) < 0)
+ if (apply_data(patch, &st, ce) < 0)
return error("%s: patch does not apply", name);
return 0;
}
{
for ( ; patch; patch = patch->next) {
const char *name;
- name = patch->old_name ? patch->old_name : patch->new_name;
+ name = patch->new_name ? patch->new_name : patch->old_name;
printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
if (line_termination && quote_c_style(name, NULL, NULL, 0))
quote_c_style(name, NULL, stdout, 0);
if (remove_file_from_cache(patch->old_name) < 0)
die("unable to remove %s from index", patch->old_name);
}
- unlink(patch->old_name);
+ if (!cached)
+ unlink(patch->old_name);
}
static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = htons(namelen);
- if (lstat(path, &st) < 0)
- die("unable to stat newly created file %s", path);
- fill_stat_cache_info(ce, &st);
+ if (!cached) {
+ if (lstat(path, &st) < 0)
+ die("unable to stat newly created file %s", path);
+ fill_stat_cache_info(ce, &st);
+ }
if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
die("unable to create backing store for newly created file %s", path);
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
*/
static void create_one_file(char *path, unsigned mode, const char *buf, unsigned long size)
{
+ if (cached)
+ return;
if (!try_create_file(path, mode, buf, size))
return;
check_index = 1;
continue;
}
+ if (!strcmp(arg, "--cached")) {
+ check_index = 1;
+ cached = 1;
+ continue;
+ }
if (!strcmp(arg, "--apply")) {
apply = 1;
continue;
len = nr = 0;
push_arg("grep");
- push_arg("-H");
if (opt->fixed)
push_arg("-F");
if (opt->linenum)
push_arg("-e");
push_arg(p->pattern);
}
- push_arg("--");
+
+ /*
+ * To make sure we get the header printed out when we want it,
+ * add /dev/null to the paths to grep. This is unnecessary
+ * (and wrong) with "-l" or "-L", which always print out the
+ * name anyway.
+ *
+ * GNU grep has "-H", but this is portable.
+ */
+ if (!opt->name_only && !opt->unmatch_name_only)
+ push_arg("/dev/null");
hit = 0;
argc = nr;
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
+ const char *name;
if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
continue;
if (!pathspec_matches(paths, ce->name))
continue;
- argv[argc++] = ce->name;
+ name = ce->name;
+ if (name[0] == '-') {
+ int len = ce_namelen(ce);
+ name = xmalloc(len + 3);
+ memcpy(name, "./", 2);
+ memcpy(name + 2, ce->name, len + 1);
+ }
+ argv[argc++] = name;
if (argc < MAXARGS)
continue;
hit += exec_grep(argc, argv);
--- /dev/null
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "cache.h"
+#include "builtin.h"
+
+#ifndef DEFAULT_GIT_TEMPLATE_DIR
+#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
+#endif
+
+static void safe_create_dir(const char *dir, int share)
+{
+ if (mkdir(dir, 0777) < 0) {
+ if (errno != EEXIST) {
+ perror(dir);
+ exit(1);
+ }
+ }
+ else if (share && adjust_shared_perm(dir))
+ die("Could not make %s writable by group\n", dir);
+}
+
+static int copy_file(const char *dst, const char *src, int mode)
+{
+ int fdi, fdo, status;
+
+ mode = (mode & 0111) ? 0777 : 0666;
+ if ((fdi = open(src, O_RDONLY)) < 0)
+ return fdi;
+ if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
+ close(fdi);
+ return fdo;
+ }
+ status = copy_fd(fdi, fdo);
+ close(fdo);
+
+ if (!status && adjust_shared_perm(dst))
+ return -1;
+
+ return status;
+}
+
+static void copy_templates_1(char *path, int baselen,
+ char *template, int template_baselen,
+ DIR *dir)
+{
+ struct dirent *de;
+
+ /* Note: if ".git/hooks" file exists in the repository being
+ * re-initialized, /etc/core-git/templates/hooks/update would
+ * cause git-init-db to fail here. I think this is sane but
+ * it means that the set of templates we ship by default, along
+ * with the way the namespace under .git/ is organized, should
+ * be really carefully chosen.
+ */
+ safe_create_dir(path, 1);
+ while ((de = readdir(dir)) != NULL) {
+ struct stat st_git, st_template;
+ int namelen;
+ int exists = 0;
+
+ if (de->d_name[0] == '.')
+ continue;
+ namelen = strlen(de->d_name);
+ if ((PATH_MAX <= baselen + namelen) ||
+ (PATH_MAX <= template_baselen + namelen))
+ die("insanely long template name %s", de->d_name);
+ memcpy(path + baselen, de->d_name, namelen+1);
+ memcpy(template + template_baselen, de->d_name, namelen+1);
+ if (lstat(path, &st_git)) {
+ if (errno != ENOENT)
+ die("cannot stat %s", path);
+ }
+ else
+ exists = 1;
+
+ if (lstat(template, &st_template))
+ die("cannot stat template %s", template);
+
+ if (S_ISDIR(st_template.st_mode)) {
+ DIR *subdir = opendir(template);
+ int baselen_sub = baselen + namelen;
+ int template_baselen_sub = template_baselen + namelen;
+ if (!subdir)
+ die("cannot opendir %s", template);
+ path[baselen_sub++] =
+ template[template_baselen_sub++] = '/';
+ path[baselen_sub] =
+ template[template_baselen_sub] = 0;
+ copy_templates_1(path, baselen_sub,
+ template, template_baselen_sub,
+ subdir);
+ closedir(subdir);
+ }
+ else if (exists)
+ continue;
+ else if (S_ISLNK(st_template.st_mode)) {
+ char lnk[256];
+ int len;
+ len = readlink(template, lnk, sizeof(lnk));
+ if (len < 0)
+ die("cannot readlink %s", template);
+ if (sizeof(lnk) <= len)
+ die("insanely long symlink %s", template);
+ lnk[len] = 0;
+ if (symlink(lnk, path))
+ die("cannot symlink %s %s", lnk, path);
+ }
+ else if (S_ISREG(st_template.st_mode)) {
+ if (copy_file(path, template, st_template.st_mode))
+ die("cannot copy %s to %s", template, path);
+ }
+ else
+ error("ignoring template %s", template);
+ }
+}
+
+static void copy_templates(const char *git_dir, int len, const char *template_dir)
+{
+ char path[PATH_MAX];
+ char template_path[PATH_MAX];
+ int template_len;
+ DIR *dir;
+
+ if (!template_dir)
+ template_dir = DEFAULT_GIT_TEMPLATE_DIR;
+ strcpy(template_path, template_dir);
+ template_len = strlen(template_path);
+ if (template_path[template_len-1] != '/') {
+ template_path[template_len++] = '/';
+ template_path[template_len] = 0;
+ }
+ dir = opendir(template_path);
+ if (!dir) {
+ fprintf(stderr, "warning: templates not found %s\n",
+ template_dir);
+ return;
+ }
+
+ /* Make sure that template is from the correct vintage */
+ strcpy(template_path + template_len, "config");
+ repository_format_version = 0;
+ git_config_from_file(check_repository_format_version,
+ template_path);
+ template_path[template_len] = 0;
+
+ if (repository_format_version &&
+ repository_format_version != GIT_REPO_VERSION) {
+ fprintf(stderr, "warning: not copying templates of "
+ "a wrong format version %d from '%s'\n",
+ repository_format_version,
+ template_dir);
+ closedir(dir);
+ return;
+ }
+
+ memcpy(path, git_dir, len);
+ path[len] = 0;
+ copy_templates_1(path, len,
+ template_path, template_len,
+ dir);
+ closedir(dir);
+}
+
+static void create_default_files(const char *git_dir, const char *template_path)
+{
+ unsigned len = strlen(git_dir);
+ static char path[PATH_MAX];
+ unsigned char sha1[20];
+ struct stat st1;
+ char repo_version_string[10];
+
+ if (len > sizeof(path)-50)
+ die("insane git directory %s", git_dir);
+ memcpy(path, git_dir, len);
+
+ if (len && path[len-1] != '/')
+ path[len++] = '/';
+
+ /*
+ * Create .git/refs/{heads,tags}
+ */
+ strcpy(path + len, "refs");
+ safe_create_dir(path, 1);
+ strcpy(path + len, "refs/heads");
+ safe_create_dir(path, 1);
+ strcpy(path + len, "refs/tags");
+ safe_create_dir(path, 1);
+
+ /* First copy the templates -- we might have the default
+ * config file there, in which case we would want to read
+ * from it after installing.
+ */
+ path[len] = 0;
+ copy_templates(path, len, template_path);
+
+ git_config(git_default_config);
+
+ /*
+ * Create the default symlink from ".git/HEAD" to the "master"
+ * branch, if it does not exist yet.
+ */
+ strcpy(path + len, "HEAD");
+ if (read_ref(path, sha1) < 0) {
+ if (create_symref(path, "refs/heads/master") < 0)
+ exit(1);
+ }
+
+ /* This forces creation of new config file */
+ sprintf(repo_version_string, "%d", GIT_REPO_VERSION);
+ git_config_set("core.repositoryformatversion", repo_version_string);
+
+ path[len] = 0;
+ strcpy(path + len, "config");
+
+ /* Check filemode trustability */
+ if (!lstat(path, &st1)) {
+ struct stat st2;
+ int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
+ !lstat(path, &st2) &&
+ st1.st_mode != st2.st_mode);
+ git_config_set("core.filemode",
+ filemode ? "true" : "false");
+ }
+}
+
+static const char init_db_usage[] =
+"git-init-db [--template=<template-directory>] [--shared]";
+
+/*
+ * If you want to, you can share the DB area with any number of branches.
+ * That has advantages: you can save space by sharing all the SHA1 objects.
+ * On the other hand, it might just make lookup slower and messier. You
+ * be the judge. The default case is to have one DB per managed directory.
+ */
+int cmd_init_db(int argc, const char **argv, char **envp)
+{
+ const char *git_dir;
+ const char *sha1_dir;
+ const char *template_dir = NULL;
+ char *path;
+ int len, i;
+
+ for (i = 1; i < argc; i++, argv++) {
+ const char *arg = argv[1];
+ if (!strncmp(arg, "--template=", 11))
+ template_dir = arg+11;
+ else if (!strcmp(arg, "--shared"))
+ shared_repository = 1;
+ else
+ die(init_db_usage);
+ }
+
+ /*
+ * Set up the default .git directory contents
+ */
+ git_dir = getenv(GIT_DIR_ENVIRONMENT);
+ if (!git_dir) {
+ git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+ fprintf(stderr, "defaulting to local storage area\n");
+ }
+ safe_create_dir(git_dir, 0);
+
+ /* Check to see if the repository version is right.
+ * Note that a newly created repository does not have
+ * config file, so this will not fail. What we are catching
+ * is an attempt to reinitialize new repository with an old tool.
+ */
+ check_repository_format();
+
+ create_default_files(git_dir, template_dir);
+
+ /*
+ * And set up the object store.
+ */
+ sha1_dir = get_object_directory();
+ len = strlen(sha1_dir);
+ path = xmalloc(len + 40);
+ memcpy(path, sha1_dir, len);
+
+ safe_create_dir(sha1_dir, 1);
+ strcpy(path+len, "/pack");
+ safe_create_dir(path, 1);
+ strcpy(path+len, "/info");
+ safe_create_dir(path, 1);
+
+ if (shared_repository)
+ git_config_set("core.sharedRepository", "true");
+
+ return 0;
+}
rev->commit_format = CMIT_FMT_DEFAULT;
rev->verbose_header = 1;
argc = setup_revisions(argc, argv, rev, "HEAD");
+ if (rev->always_show_header) {
+ if (rev->diffopt.pickaxe || rev->diffopt.filter) {
+ rev->always_show_header = 0;
+ if (rev->diffopt.output_format == DIFF_FORMAT_RAW)
+ rev->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
+ }
+ }
if (argc > 1)
die("unrecognized argument: %s", argv[1]);
extern int cmd_grep(int argc, const char **argv, char **envp);
extern int cmd_rev_list(int argc, const char **argv, char **envp);
extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
+extern int cmd_init_db(int argc, const char **argv, char **envp);
#endif
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);
+#define REFRESH_REALLY 0x0001 /* ignore_valid */
+#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
+#define REFRESH_QUIET 0x0004 /* be quiet about it */
+#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
+extern int refresh_cache(unsigned int flags);
+
struct cache_file {
struct cache_file *next;
char lockfile[PATH_MAX];
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
git-write-tree >"$dotest/patch-merge-base+" &&
# index has the base tree now.
- (
- cd "$dotest/patch-merge-tmp-dir" &&
- GIT_INDEX_FILE="../patch-merge-tmp-index" \
- GIT_OBJECT_DIRECTORY="$O_OBJECT" \
- git-apply $binary --index <../patch
- )
+ GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
+ git-apply $binary --cached <"$dotest/patch"
then
echo Using index info to reconstruct a base tree...
mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
- else
- # Otherwise, try nearby trees that can be used to apply the
- # patch.
- (
- N=10
-
- # Hoping the patch is against our recent commits...
- git-rev-list --max-count=$N HEAD
-
- # or hoping the patch is against known tags...
- git-ls-remote --tags .
- ) |
- while read base junk
- do
- # See if we have it as a tree...
- git-cat-file tree "$base" >/dev/null 2>&1 || continue
-
- rm -fr "$dotest"/patch-merge-* &&
- mkdir "$dotest/patch-merge-tmp-dir" || break
- (
- cd "$dotest/patch-merge-tmp-dir" &&
- GIT_INDEX_FILE=../patch-merge-tmp-index &&
- GIT_OBJECT_DIRECTORY="$O_OBJECT" &&
- export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&
- git-read-tree "$base" &&
- git-apply $binary --index &&
- mv ../patch-merge-tmp-index ../patch-merge-index &&
- echo "$base" >../patch-merge-base
- ) <"$dotest/patch" 2>/dev/null && break
- done
fi
test -f "$dotest/patch-merge-index" &&
{ "diff", cmd_diff },
{ "grep", cmd_grep },
{ "rev-list", cmd_rev_list },
+ { "init-db", cmd_init_db },
{ "check-ref-format", cmd_check_ref_format }
};
int i;
+++ /dev/null
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include "cache.h"
-
-#ifndef DEFAULT_GIT_TEMPLATE_DIR
-#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
-#endif
-
-static void safe_create_dir(const char *dir, int share)
-{
- if (mkdir(dir, 0777) < 0) {
- if (errno != EEXIST) {
- perror(dir);
- exit(1);
- }
- }
- else if (share && adjust_shared_perm(dir))
- die("Could not make %s writable by group\n", dir);
-}
-
-static int copy_file(const char *dst, const char *src, int mode)
-{
- int fdi, fdo, status;
-
- mode = (mode & 0111) ? 0777 : 0666;
- if ((fdi = open(src, O_RDONLY)) < 0)
- return fdi;
- if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
- close(fdi);
- return fdo;
- }
- status = copy_fd(fdi, fdo);
- close(fdo);
-
- if (!status && adjust_shared_perm(dst))
- return -1;
-
- return status;
-}
-
-static void copy_templates_1(char *path, int baselen,
- char *template, int template_baselen,
- DIR *dir)
-{
- struct dirent *de;
-
- /* Note: if ".git/hooks" file exists in the repository being
- * re-initialized, /etc/core-git/templates/hooks/update would
- * cause git-init-db to fail here. I think this is sane but
- * it means that the set of templates we ship by default, along
- * with the way the namespace under .git/ is organized, should
- * be really carefully chosen.
- */
- safe_create_dir(path, 1);
- while ((de = readdir(dir)) != NULL) {
- struct stat st_git, st_template;
- int namelen;
- int exists = 0;
-
- if (de->d_name[0] == '.')
- continue;
- namelen = strlen(de->d_name);
- if ((PATH_MAX <= baselen + namelen) ||
- (PATH_MAX <= template_baselen + namelen))
- die("insanely long template name %s", de->d_name);
- memcpy(path + baselen, de->d_name, namelen+1);
- memcpy(template + template_baselen, de->d_name, namelen+1);
- if (lstat(path, &st_git)) {
- if (errno != ENOENT)
- die("cannot stat %s", path);
- }
- else
- exists = 1;
-
- if (lstat(template, &st_template))
- die("cannot stat template %s", template);
-
- if (S_ISDIR(st_template.st_mode)) {
- DIR *subdir = opendir(template);
- int baselen_sub = baselen + namelen;
- int template_baselen_sub = template_baselen + namelen;
- if (!subdir)
- die("cannot opendir %s", template);
- path[baselen_sub++] =
- template[template_baselen_sub++] = '/';
- path[baselen_sub] =
- template[template_baselen_sub] = 0;
- copy_templates_1(path, baselen_sub,
- template, template_baselen_sub,
- subdir);
- closedir(subdir);
- }
- else if (exists)
- continue;
- else if (S_ISLNK(st_template.st_mode)) {
- char lnk[256];
- int len;
- len = readlink(template, lnk, sizeof(lnk));
- if (len < 0)
- die("cannot readlink %s", template);
- if (sizeof(lnk) <= len)
- die("insanely long symlink %s", template);
- lnk[len] = 0;
- if (symlink(lnk, path))
- die("cannot symlink %s %s", lnk, path);
- }
- else if (S_ISREG(st_template.st_mode)) {
- if (copy_file(path, template, st_template.st_mode))
- die("cannot copy %s to %s", template, path);
- }
- else
- error("ignoring template %s", template);
- }
-}
-
-static void copy_templates(const char *git_dir, int len, char *template_dir)
-{
- char path[PATH_MAX];
- char template_path[PATH_MAX];
- int template_len;
- DIR *dir;
-
- if (!template_dir)
- template_dir = DEFAULT_GIT_TEMPLATE_DIR;
- strcpy(template_path, template_dir);
- template_len = strlen(template_path);
- if (template_path[template_len-1] != '/') {
- template_path[template_len++] = '/';
- template_path[template_len] = 0;
- }
- dir = opendir(template_path);
- if (!dir) {
- fprintf(stderr, "warning: templates not found %s\n",
- template_dir);
- return;
- }
-
- /* Make sure that template is from the correct vintage */
- strcpy(template_path + template_len, "config");
- repository_format_version = 0;
- git_config_from_file(check_repository_format_version,
- template_path);
- template_path[template_len] = 0;
-
- if (repository_format_version &&
- repository_format_version != GIT_REPO_VERSION) {
- fprintf(stderr, "warning: not copying templates of "
- "a wrong format version %d from '%s'\n",
- repository_format_version,
- template_dir);
- closedir(dir);
- return;
- }
-
- memcpy(path, git_dir, len);
- path[len] = 0;
- copy_templates_1(path, len,
- template_path, template_len,
- dir);
- closedir(dir);
-}
-
-static void create_default_files(const char *git_dir, char *template_path)
-{
- unsigned len = strlen(git_dir);
- static char path[PATH_MAX];
- unsigned char sha1[20];
- struct stat st1;
- char repo_version_string[10];
-
- if (len > sizeof(path)-50)
- die("insane git directory %s", git_dir);
- memcpy(path, git_dir, len);
-
- if (len && path[len-1] != '/')
- path[len++] = '/';
-
- /*
- * Create .git/refs/{heads,tags}
- */
- strcpy(path + len, "refs");
- safe_create_dir(path, 1);
- strcpy(path + len, "refs/heads");
- safe_create_dir(path, 1);
- strcpy(path + len, "refs/tags");
- safe_create_dir(path, 1);
-
- /* First copy the templates -- we might have the default
- * config file there, in which case we would want to read
- * from it after installing.
- */
- path[len] = 0;
- copy_templates(path, len, template_path);
-
- git_config(git_default_config);
-
- /*
- * Create the default symlink from ".git/HEAD" to the "master"
- * branch, if it does not exist yet.
- */
- strcpy(path + len, "HEAD");
- if (read_ref(path, sha1) < 0) {
- if (create_symref(path, "refs/heads/master") < 0)
- exit(1);
- }
-
- /* This forces creation of new config file */
- sprintf(repo_version_string, "%d", GIT_REPO_VERSION);
- git_config_set("core.repositoryformatversion", repo_version_string);
-
- path[len] = 0;
- strcpy(path + len, "config");
-
- /* Check filemode trustability */
- if (!lstat(path, &st1)) {
- struct stat st2;
- int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
- !lstat(path, &st2) &&
- st1.st_mode != st2.st_mode);
- git_config_set("core.filemode",
- filemode ? "true" : "false");
- }
-}
-
-static const char init_db_usage[] =
-"git-init-db [--template=<template-directory>] [--shared]";
-
-/*
- * If you want to, you can share the DB area with any number of branches.
- * That has advantages: you can save space by sharing all the SHA1 objects.
- * On the other hand, it might just make lookup slower and messier. You
- * be the judge. The default case is to have one DB per managed directory.
- */
-int main(int argc, char **argv)
-{
- const char *git_dir;
- const char *sha1_dir;
- char *path, *template_dir = NULL;
- int len, i;
-
- for (i = 1; i < argc; i++, argv++) {
- char *arg = argv[1];
- if (!strncmp(arg, "--template=", 11))
- template_dir = arg+11;
- else if (!strcmp(arg, "--shared"))
- shared_repository = 1;
- else
- die(init_db_usage);
- }
-
- /*
- * Set up the default .git directory contents
- */
- git_dir = getenv(GIT_DIR_ENVIRONMENT);
- if (!git_dir) {
- git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
- fprintf(stderr, "defaulting to local storage area\n");
- }
- safe_create_dir(git_dir, 0);
-
- /* Check to see if the repository version is right.
- * Note that a newly created repository does not have
- * config file, so this will not fail. What we are catching
- * is an attempt to reinitialize new repository with an old tool.
- */
- check_repository_format();
-
- create_default_files(git_dir, template_dir);
-
- /*
- * And set up the object store.
- */
- sha1_dir = get_object_directory();
- len = strlen(sha1_dir);
- path = xmalloc(len + 40);
- memcpy(path, sha1_dir, len);
-
- safe_create_dir(sha1_dir, 1);
- strcpy(path+len, "/pack");
- safe_create_dir(path, 1);
- strcpy(path+len, "/info");
- safe_create_dir(path, 1);
-
- if (shared_repository)
- git_config_set("core.sharedRepository", "true");
-
- return 0;
-}
return 0;
}
+/* Three functions to allow overloaded pointer return; see linux/err.h */
+static inline void *ERR_PTR(long error)
+{
+ return (void *) error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+ return (long) ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+ return (unsigned long)ptr > (unsigned long)-1000L;
+}
+
+/*
+ * "refresh" does not calculate a new sha1 file or bring the
+ * cache up-to-date for mode/content changes. But what it
+ * _does_ do is to "re-match" the stat information of a file
+ * with the cache, so that you can refresh the cache for a
+ * file that hasn't been changed but where the stat entry is
+ * out of date.
+ *
+ * For example, you'd want to do this after doing a "git-read-tree",
+ * to link up the stat cache details with the proper files.
+ */
+static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)
+{
+ struct stat st;
+ struct cache_entry *updated;
+ int changed, size;
+
+ if (lstat(ce->name, &st) < 0)
+ return ERR_PTR(-errno);
+
+ changed = ce_match_stat(ce, &st, really);
+ if (!changed) {
+ if (really && assume_unchanged &&
+ !(ce->ce_flags & htons(CE_VALID)))
+ ; /* mark this one VALID again */
+ else
+ return NULL;
+ }
+
+ if (ce_modified(ce, &st, really))
+ return ERR_PTR(-EINVAL);
+
+ size = ce_size(ce);
+ updated = xmalloc(size);
+ memcpy(updated, ce, size);
+ fill_stat_cache_info(updated, &st);
+
+ /* In this case, if really is not set, we should leave
+ * CE_VALID bit alone. Otherwise, paths marked with
+ * --no-assume-unchanged (i.e. things to be edited) will
+ * reacquire CE_VALID bit automatically, which is not
+ * really what we want.
+ */
+ if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
+ updated->ce_flags &= ~htons(CE_VALID);
+
+ return updated;
+}
+
+int refresh_cache(unsigned int flags)
+{
+ int i;
+ int has_errors = 0;
+ int really = (flags & REFRESH_REALLY) != 0;
+ int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
+ int quiet = (flags & REFRESH_QUIET) != 0;
+ int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
+
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce, *new;
+ ce = active_cache[i];
+ if (ce_stage(ce)) {
+ while ((i < active_nr) &&
+ ! strcmp(active_cache[i]->name, ce->name))
+ i++;
+ i--;
+ if (allow_unmerged)
+ continue;
+ printf("%s: needs merge\n", ce->name);
+ has_errors = 1;
+ continue;
+ }
+
+ new = refresh_entry(ce, really);
+ if (!new)
+ continue;
+ if (IS_ERR(new)) {
+ if (not_new && PTR_ERR(new) == -ENOENT)
+ continue;
+ if (really && PTR_ERR(new) == -EINVAL) {
+ /* If we are doing --really-refresh that
+ * means the index is not valid anymore.
+ */
+ ce->ce_flags &= ~htons(CE_VALID);
+ active_cache_changed = 1;
+ }
+ if (quiet)
+ continue;
+ printf("%s: needs update\n", ce->name);
+ has_errors = 1;
+ continue;
+ }
+ active_cache_changed = 1;
+ /* You can NOT just free active_cache[i] here, since it
+ * might not be necessarily malloc()ed but can also come
+ * from mmap(). */
+ active_cache[i] = new;
+ }
+ return has_errors;
+}
+
static int verify_hdr(struct cache_header *hdr, unsigned long size)
{
SHA_CTX c;
int get_ref_sha1(const char *ref, unsigned char *sha1)
{
- const char *filename;
-
if (check_ref_format(ref))
return -1;
- filename = git_path("refs/%s", ref);
- return read_ref(filename, sha1);
+ return read_ref(git_path("refs/%s", ref), sha1);
}
static int lock_ref_file(const char *filename, const char *lock_filename,
static int allow_add;
static int allow_remove;
static int allow_replace;
-static int allow_unmerged; /* --refresh needing merge is not error */
-static int not_new; /* --refresh not having working tree files is not error */
-static int quiet; /* --refresh needing update is not error */
static int info_only;
static int force_remove;
static int verbose;
#define MARK_VALID 1
#define UNMARK_VALID 2
-
-/* Three functions to allow overloaded pointer return; see linux/err.h */
-static inline void *ERR_PTR(long error)
-{
- return (void *) error;
-}
-
-static inline long PTR_ERR(const void *ptr)
-{
- return (long) ptr;
-}
-
-static inline long IS_ERR(const void *ptr)
-{
- return (unsigned long)ptr > (unsigned long)-1000L;
-}
-
static void report(const char *fmt, ...)
{
va_list vp;
}
/*
- * "refresh" does not calculate a new sha1 file or bring the
- * cache up-to-date for mode/content changes. But what it
- * _does_ do is to "re-match" the stat information of a file
- * with the cache, so that you can refresh the cache for a
- * file that hasn't been changed but where the stat entry is
- * out of date.
- *
- * For example, you'd want to do this after doing a "git-read-tree",
- * to link up the stat cache details with the proper files.
- */
-static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)
-{
- struct stat st;
- struct cache_entry *updated;
- int changed, size;
-
- if (lstat(ce->name, &st) < 0)
- return ERR_PTR(-errno);
-
- changed = ce_match_stat(ce, &st, really);
- if (!changed) {
- if (really && assume_unchanged &&
- !(ce->ce_flags & htons(CE_VALID)))
- ; /* mark this one VALID again */
- else
- return NULL;
- }
-
- if (ce_modified(ce, &st, really))
- return ERR_PTR(-EINVAL);
-
- size = ce_size(ce);
- updated = xmalloc(size);
- memcpy(updated, ce, size);
- fill_stat_cache_info(updated, &st);
-
- /* In this case, if really is not set, we should leave
- * CE_VALID bit alone. Otherwise, paths marked with
- * --no-assume-unchanged (i.e. things to be edited) will
- * reacquire CE_VALID bit automatically, which is not
- * really what we want.
- */
- if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
- updated->ce_flags &= ~htons(CE_VALID);
-
- return updated;
-}
-
-static int refresh_cache(int really)
-{
- int i;
- int has_errors = 0;
-
- for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce, *new;
- ce = active_cache[i];
- if (ce_stage(ce)) {
- while ((i < active_nr) &&
- ! strcmp(active_cache[i]->name, ce->name))
- i++;
- i--;
- if (allow_unmerged)
- continue;
- printf("%s: needs merge\n", ce->name);
- has_errors = 1;
- continue;
- }
-
- new = refresh_entry(ce, really);
- if (!new)
- continue;
- if (IS_ERR(new)) {
- if (not_new && PTR_ERR(new) == -ENOENT)
- continue;
- if (really && PTR_ERR(new) == -EINVAL) {
- /* If we are doing --really-refresh that
- * means the index is not valid anymore.
- */
- ce->ce_flags &= ~htons(CE_VALID);
- active_cache_changed = 1;
- }
- if (quiet)
- continue;
- printf("%s: needs update\n", ce->name);
- has_errors = 1;
- continue;
- }
- active_cache_changed = 1;
- /* You can NOT just free active_cache[i] here, since it
- * might not be necessarily malloc()ed but can also come
- * from mmap(). */
- active_cache[i] = new;
- }
- return has_errors;
-}
-
-/*
* We fundamentally don't like some paths: we don't want
* dot or dot-dot anywhere, and for obvious reasons don't
* want to recurse into ".git" either.
const char *prefix = setup_git_directory();
int prefix_length = prefix ? strlen(prefix) : 0;
char set_executable_bit = 0;
+ unsigned int refresh_flags = 0;
git_config(git_default_config);
continue;
}
if (!strcmp(path, "-q")) {
- quiet = 1;
+ refresh_flags |= REFRESH_QUIET;
continue;
}
if (!strcmp(path, "--add")) {
continue;
}
if (!strcmp(path, "--unmerged")) {
- allow_unmerged = 1;
+ refresh_flags |= REFRESH_UNMERGED;
continue;
}
if (!strcmp(path, "--refresh")) {
- has_errors |= refresh_cache(0);
+ has_errors |= refresh_cache(refresh_flags);
continue;
}
if (!strcmp(path, "--really-refresh")) {
- has_errors |= refresh_cache(1);
+ has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags);
continue;
}
if (!strcmp(path, "--cacheinfo")) {
goto finish;
}
if (!strcmp(path, "--ignore-missing")) {
- not_new = 1;
+ refresh_flags |= REFRESH_IGNORE_MISSING;
continue;
}
if (!strcmp(path, "--verbose")) {