Merge branch 'lt/grep'
authorJunio C Hamano <junkio@cox.net>
Fri, 19 May 2006 23:26:45 +0000 (16:26 -0700)
committerJunio C Hamano <junkio@cox.net>
Fri, 19 May 2006 23:26:45 +0000 (16:26 -0700)
* lt/grep:
  builtin-grep: workaround for non GNU grep.
  git-am: use apply --cached
  apply --cached: apply a patch without using working tree.
  apply --numstat: show new name, not old name.

19 files changed:
Documentation/SubmittingPatches
Documentation/install-webdoc.sh
Makefile
builtin-check-ref-format.c [new file with mode: 0644]
builtin-diff.c
builtin-init-db.c [new file with mode: 0644]
builtin-log.c
builtin-rev-list.c [new file with mode: 0644]
builtin.h
cache.h
check-ref-format.c [deleted file]
diff-tree.c
git-cvsimport.perl
git.c
init-db.c [deleted file]
read-cache.c
refs.c
rev-list.c [deleted file]
update-index.c

index 318b04f..8601949 100644 (file)
@@ -266,8 +266,8 @@ This recipe appears to work with the current [*1*] Thunderbird from Suse.
 The following Thunderbird extensions are needed:
        AboutConfig 0.5
                http://aboutconfig.mozdev.org/
-       External Editor 0.5.4
-               http://extensionroom.mozdev.org/more-info/exteditor
+       External Editor 0.7.2
+               http://globs.org/articles.php?lng=en&pg=8
 
 1) Prepare the patch as a text file using your method of choice.
 
index 50638c7..60211a5 100755 (executable)
@@ -4,12 +4,16 @@ T="$1"
 
 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
index 9ba608c..e804010 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -154,23 +154,24 @@ PROGRAMS = \
        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 \
-       git-receive-pack$X git-rev-list$X git-rev-parse$X \
+       git-receive-pack$X git-rev-parse$X \
        git-send-pack$X git-show-branch$X git-shell$X \
        git-show-index$X git-ssh-fetch$X \
        git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
        git-unpack-objects$X git-update-index$X git-update-server-info$X \
        git-upload-pack$X git-verify-pack$X git-write-tree$X \
-       git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
+       git-update-ref$X git-symbolic-ref$X \
        git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
        git-describe$X git-merge-tree$X git-blame$X git-imap-send$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-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)
@@ -218,7 +219,8 @@ LIB_OBJS = \
 
 BUILTIN_OBJS = \
        builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
-       builtin-grep.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
@@ -473,6 +475,7 @@ strip: $(PROGRAMS) git$X
 
 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)
 
@@ -565,10 +568,6 @@ git-http-push$X: revision.o http.o http-push.o $(LIB_FILE)
        $(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
@@ -652,6 +651,25 @@ dist: git.spec git-tar-tree
 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:
@@ -659,8 +677,9 @@ 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
diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c
new file mode 100644 (file)
index 0000000..4a23936
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * GIT - The information manager from hell
+ */
+
+#include "cache.h"
+#include "refs.h"
+#include "builtin.h"
+
+int cmd_check_ref_format(int argc, const char **argv, char **envp)
+{
+       if (argc != 2)
+               usage("git check-ref-format refname");
+       return !!check_ref_format(argv[1]);
+}
index b0c9cad..de81b05 100644 (file)
@@ -122,7 +122,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
        stuff_change(&revs->diffopt,
                     canon_mode(st.st_mode), canon_mode(st.st_mode),
                     blob[0].sha1, null_sha1,
-                    blob[0].name, path);
+                    path, path);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        return 0;
diff --git a/builtin-init-db.c b/builtin-init-db.c
new file mode 100644 (file)
index 0000000..2a1384c
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * 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;
+}
index 69f2911..c4ceee0 100644 (file)
@@ -19,6 +19,13 @@ static int cmd_log_wc(int argc, const char **argv, char **envp,
        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]);
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
new file mode 100644 (file)
index 0000000..446802d
--- /dev/null
@@ -0,0 +1,358 @@
+#include "cache.h"
+#include "refs.h"
+#include "tag.h"
+#include "commit.h"
+#include "tree.h"
+#include "blob.h"
+#include "tree-walk.h"
+#include "diff.h"
+#include "revision.h"
+#include "builtin.h"
+
+/* bits #0-15 in revision.h */
+
+#define COUNTED                (1u<<16)
+
+static const char rev_list_usage[] =
+"git-rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
+"  limiting output:\n"
+"    --max-count=nr\n"
+"    --max-age=epoch\n"
+"    --min-age=epoch\n"
+"    --sparse\n"
+"    --no-merges\n"
+"    --remove-empty\n"
+"    --all\n"
+"  ordering output:\n"
+"    --topo-order\n"
+"    --date-order\n"
+"  formatting output:\n"
+"    --parents\n"
+"    --objects | --objects-edge\n"
+"    --unpacked\n"
+"    --header | --pretty\n"
+"    --abbrev=nr | --no-abbrev\n"
+"    --abbrev-commit\n"
+"  special purpose:\n"
+"    --bisect"
+;
+
+static struct rev_info revs;
+
+static int bisect_list = 0;
+static int show_timestamp = 0;
+static int hdr_termination = 0;
+static const char *header_prefix;
+
+static void show_commit(struct commit *commit)
+{
+       if (show_timestamp)
+               printf("%lu ", commit->date);
+       if (header_prefix)
+               fputs(header_prefix, stdout);
+       if (commit->object.flags & BOUNDARY)
+               putchar('-');
+       if (revs.abbrev_commit && revs.abbrev)
+               fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
+                     stdout);
+       else
+               fputs(sha1_to_hex(commit->object.sha1), stdout);
+       if (revs.parents) {
+               struct commit_list *parents = commit->parents;
+               while (parents) {
+                       struct object *o = &(parents->item->object);
+                       parents = parents->next;
+                       if (o->flags & TMP_MARK)
+                               continue;
+                       printf(" %s", sha1_to_hex(o->sha1));
+                       o->flags |= TMP_MARK;
+               }
+               /* TMP_MARK is a general purpose flag that can
+                * be used locally, but the user should clean
+                * things up after it is done with them.
+                */
+               for (parents = commit->parents;
+                    parents;
+                    parents = parents->next)
+                       parents->item->object.flags &= ~TMP_MARK;
+       }
+       if (revs.commit_format == CMIT_FMT_ONELINE)
+               putchar(' ');
+       else
+               putchar('\n');
+
+       if (revs.verbose_header) {
+               static char pretty_header[16384];
+               pretty_print_commit(revs.commit_format, commit, ~0,
+                                   pretty_header, sizeof(pretty_header),
+                                   revs.abbrev);
+               printf("%s%c", pretty_header, hdr_termination);
+       }
+       fflush(stdout);
+}
+
+static struct object_list **process_blob(struct blob *blob,
+                                        struct object_list **p,
+                                        struct name_path *path,
+                                        const char *name)
+{
+       struct object *obj = &blob->object;
+
+       if (!revs.blob_objects)
+               return p;
+       if (obj->flags & (UNINTERESTING | SEEN))
+               return p;
+       obj->flags |= SEEN;
+       return add_object(obj, p, path, name);
+}
+
+static struct object_list **process_tree(struct tree *tree,
+                                        struct object_list **p,
+                                        struct name_path *path,
+                                        const char *name)
+{
+       struct object *obj = &tree->object;
+       struct tree_entry_list *entry;
+       struct name_path me;
+
+       if (!revs.tree_objects)
+               return p;
+       if (obj->flags & (UNINTERESTING | SEEN))
+               return p;
+       if (parse_tree(tree) < 0)
+               die("bad tree object %s", sha1_to_hex(obj->sha1));
+       obj->flags |= SEEN;
+       p = add_object(obj, p, path, name);
+       me.up = path;
+       me.elem = name;
+       me.elem_len = strlen(name);
+       entry = tree->entries;
+       tree->entries = NULL;
+       while (entry) {
+               struct tree_entry_list *next = entry->next;
+               if (entry->directory)
+                       p = process_tree(entry->item.tree, p, &me, entry->name);
+               else
+                       p = process_blob(entry->item.blob, p, &me, entry->name);
+               free(entry);
+               entry = next;
+       }
+       return p;
+}
+
+static void show_commit_list(struct rev_info *revs)
+{
+       struct commit *commit;
+       struct object_list *objects = NULL, **p = &objects, *pending;
+
+       while ((commit = get_revision(revs)) != NULL) {
+               p = process_tree(commit->tree, p, NULL, "");
+               show_commit(commit);
+       }
+       for (pending = revs->pending_objects; pending; pending = pending->next) {
+               struct object *obj = pending->item;
+               const char *name = pending->name;
+               if (obj->flags & (UNINTERESTING | SEEN))
+                       continue;
+               if (obj->type == tag_type) {
+                       obj->flags |= SEEN;
+                       p = add_object(obj, p, NULL, name);
+                       continue;
+               }
+               if (obj->type == tree_type) {
+                       p = process_tree((struct tree *)obj, p, NULL, name);
+                       continue;
+               }
+               if (obj->type == blob_type) {
+                       p = process_blob((struct blob *)obj, p, NULL, name);
+                       continue;
+               }
+               die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
+       }
+       while (objects) {
+               /* An object with name "foo\n0000000..." can be used to
+                * confuse downstream git-pack-objects very badly.
+                */
+               const char *ep = strchr(objects->name, '\n');
+               if (ep) {
+                       printf("%s %.*s\n", sha1_to_hex(objects->item->sha1),
+                              (int) (ep - objects->name),
+                              objects->name);
+               }
+               else
+                       printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
+               objects = objects->next;
+       }
+}
+
+/*
+ * This is a truly stupid algorithm, but it's only
+ * used for bisection, and we just don't care enough.
+ *
+ * We care just barely enough to avoid recursing for
+ * non-merge entries.
+ */
+static int count_distance(struct commit_list *entry)
+{
+       int nr = 0;
+
+       while (entry) {
+               struct commit *commit = entry->item;
+               struct commit_list *p;
+
+               if (commit->object.flags & (UNINTERESTING | COUNTED))
+                       break;
+               if (!revs.prune_fn || (commit->object.flags & TREECHANGE))
+                       nr++;
+               commit->object.flags |= COUNTED;
+               p = commit->parents;
+               entry = p;
+               if (p) {
+                       p = p->next;
+                       while (p) {
+                               nr += count_distance(p);
+                               p = p->next;
+                       }
+               }
+       }
+
+       return nr;
+}
+
+static void clear_distance(struct commit_list *list)
+{
+       while (list) {
+               struct commit *commit = list->item;
+               commit->object.flags &= ~COUNTED;
+               list = list->next;
+       }
+}
+
+static struct commit_list *find_bisection(struct commit_list *list)
+{
+       int nr, closest;
+       struct commit_list *p, *best;
+
+       nr = 0;
+       p = list;
+       while (p) {
+               if (!revs.prune_fn || (p->item->object.flags & TREECHANGE))
+                       nr++;
+               p = p->next;
+       }
+       closest = 0;
+       best = list;
+
+       for (p = list; p; p = p->next) {
+               int distance;
+
+               if (revs.prune_fn && !(p->item->object.flags & TREECHANGE))
+                       continue;
+
+               distance = count_distance(p);
+               clear_distance(list);
+               if (nr - distance < distance)
+                       distance = nr - distance;
+               if (distance > closest) {
+                       best = p;
+                       closest = distance;
+               }
+       }
+       if (best)
+               best->next = NULL;
+       return best;
+}
+
+static void mark_edge_parents_uninteresting(struct commit *commit)
+{
+       struct commit_list *parents;
+
+       for (parents = commit->parents; parents; parents = parents->next) {
+               struct commit *parent = parents->item;
+               if (!(parent->object.flags & UNINTERESTING))
+                       continue;
+               mark_tree_uninteresting(parent->tree);
+               if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
+                       parent->object.flags |= SHOWN;
+                       printf("-%s\n", sha1_to_hex(parent->object.sha1));
+               }
+       }
+}
+
+static void mark_edges_uninteresting(struct commit_list *list)
+{
+       for ( ; list; list = list->next) {
+               struct commit *commit = list->item;
+
+               if (commit->object.flags & UNINTERESTING) {
+                       mark_tree_uninteresting(commit->tree);
+                       continue;
+               }
+               mark_edge_parents_uninteresting(commit);
+       }
+}
+
+int cmd_rev_list(int argc, const char **argv, char **envp)
+{
+       struct commit_list *list;
+       int i;
+
+       init_revisions(&revs);
+       revs.abbrev = 0;
+       revs.commit_format = CMIT_FMT_UNSPECIFIED;
+       argc = setup_revisions(argc, argv, &revs, NULL);
+
+       for (i = 1 ; i < argc; i++) {
+               const char *arg = argv[i];
+
+               if (!strcmp(arg, "--header")) {
+                       revs.verbose_header = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--timestamp")) {
+                       show_timestamp = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--bisect")) {
+                       bisect_list = 1;
+                       continue;
+               }
+               usage(rev_list_usage);
+
+       }
+       if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
+               /* The command line has a --pretty  */
+               hdr_termination = '\n';
+               if (revs.commit_format == CMIT_FMT_ONELINE)
+                       header_prefix = "";
+               else
+                       header_prefix = "commit ";
+       }
+       else if (revs.verbose_header)
+               /* Only --header was specified */
+               revs.commit_format = CMIT_FMT_RAW;
+
+       list = revs.commits;
+
+       if ((!list &&
+            (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
+             !revs.pending_objects)) ||
+           revs.diff)
+               usage(rev_list_usage);
+
+       save_commit_buffer = revs.verbose_header;
+       track_object_refs = 0;
+       if (bisect_list)
+               revs.limited = 1;
+
+       prepare_revision_walk(&revs);
+       if (revs.tree_objects)
+               mark_edges_uninteresting(revs.commits);
+
+       if (bisect_list)
+               revs.commits = find_bisection(revs.commits);
+
+       show_commit_list(&revs);
+
+       return 0;
+}
index 7744f7d..6054126 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -24,5 +24,8 @@ extern int cmd_count_objects(int argc, const char **argv, char **envp);
 
 extern int cmd_push(int argc, const char **argv, char **envp);
 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
diff --git a/cache.h b/cache.h
index 4b7a439..afa8e4f 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -158,6 +158,12 @@ extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_o
 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];
diff --git a/check-ref-format.c b/check-ref-format.c
deleted file mode 100644 (file)
index a0adb3d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * GIT - The information manager from hell
- */
-
-#include "cache.h"
-#include "refs.h"
-
-#include <stdio.h>
-
-int main(int ac, char **av)
-{
-       if (ac != 2)
-               usage("git-check-ref-format refname");
-       if (check_ref_format(av[1]))
-               exit(1);
-       return 0;
-}
index 7207867..69bb74b 100644 (file)
@@ -138,7 +138,10 @@ int main(int argc, const char **argv)
                opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
                                       DIFF_SETUP_USE_CACHE);
        while (fgets(line, sizeof(line), stdin))
-               diff_tree_stdin(line);
+               if (line[0] == '\n')
+                       fflush(stdout);
+               else
+                       diff_tree_stdin(line);
 
        return 0;
 }
index c0ae00b..8c707f2 100755 (executable)
@@ -350,7 +350,7 @@ sub _line {
                                return $res;
                        } elsif($line =~ s/^E //) {
                                # print STDERR "S: $line\n";
-                       } elsif($line =~ /^Remove-entry /i) {
+                       } elsif($line =~ /^(Remove-entry|Removed) /i) {
                                $line = $self->readline(); # filename
                                $line = $self->readline(); # OK
                                chomp $line;
diff --git a/git.c b/git.c
index a94d9ee..3216d31 100644 (file)
--- a/git.c
+++ b/git.c
@@ -50,6 +50,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "count-objects", cmd_count_objects },
                { "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;
 
diff --git a/init-db.c b/init-db.c
deleted file mode 100644 (file)
index ff29496..0000000
--- a/init-db.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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;
-}
index a917ab0..b95edcc 100644 (file)
@@ -496,6 +496,123 @@ int add_cache_entry(struct cache_entry *ce, int option)
        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;
diff --git a/refs.c b/refs.c
index 6c91ae6..0f3491f 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -220,12 +220,9 @@ static char *ref_lock_file_name(const char *ref)
 
 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,
diff --git a/rev-list.c b/rev-list.c
deleted file mode 100644 (file)
index 8b0ec38..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-#include "cache.h"
-#include "refs.h"
-#include "tag.h"
-#include "commit.h"
-#include "tree.h"
-#include "blob.h"
-#include "tree-walk.h"
-#include "diff.h"
-#include "revision.h"
-
-/* bits #0-15 in revision.h */
-
-#define COUNTED                (1u<<16)
-
-static const char rev_list_usage[] =
-"git-rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
-"  limiting output:\n"
-"    --max-count=nr\n"
-"    --max-age=epoch\n"
-"    --min-age=epoch\n"
-"    --sparse\n"
-"    --no-merges\n"
-"    --remove-empty\n"
-"    --all\n"
-"  ordering output:\n"
-"    --topo-order\n"
-"    --date-order\n"
-"  formatting output:\n"
-"    --parents\n"
-"    --objects | --objects-edge\n"
-"    --unpacked\n"
-"    --header | --pretty\n"
-"    --abbrev=nr | --no-abbrev\n"
-"    --abbrev-commit\n"
-"  special purpose:\n"
-"    --bisect"
-;
-
-struct rev_info revs;
-
-static int bisect_list = 0;
-static int show_timestamp = 0;
-static int hdr_termination = 0;
-static const char *header_prefix;
-
-static void show_commit(struct commit *commit)
-{
-       if (show_timestamp)
-               printf("%lu ", commit->date);
-       if (header_prefix)
-               fputs(header_prefix, stdout);
-       if (commit->object.flags & BOUNDARY)
-               putchar('-');
-       if (revs.abbrev_commit && revs.abbrev)
-               fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
-                     stdout);
-       else
-               fputs(sha1_to_hex(commit->object.sha1), stdout);
-       if (revs.parents) {
-               struct commit_list *parents = commit->parents;
-               while (parents) {
-                       struct object *o = &(parents->item->object);
-                       parents = parents->next;
-                       if (o->flags & TMP_MARK)
-                               continue;
-                       printf(" %s", sha1_to_hex(o->sha1));
-                       o->flags |= TMP_MARK;
-               }
-               /* TMP_MARK is a general purpose flag that can
-                * be used locally, but the user should clean
-                * things up after it is done with them.
-                */
-               for (parents = commit->parents;
-                    parents;
-                    parents = parents->next)
-                       parents->item->object.flags &= ~TMP_MARK;
-       }
-       if (revs.commit_format == CMIT_FMT_ONELINE)
-               putchar(' ');
-       else
-               putchar('\n');
-
-       if (revs.verbose_header) {
-               static char pretty_header[16384];
-               pretty_print_commit(revs.commit_format, commit, ~0,
-                                   pretty_header, sizeof(pretty_header),
-                                   revs.abbrev);
-               printf("%s%c", pretty_header, hdr_termination);
-       }
-       fflush(stdout);
-}
-
-static struct object_list **process_blob(struct blob *blob,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
-{
-       struct object *obj = &blob->object;
-
-       if (!revs.blob_objects)
-               return p;
-       if (obj->flags & (UNINTERESTING | SEEN))
-               return p;
-       obj->flags |= SEEN;
-       return add_object(obj, p, path, name);
-}
-
-static struct object_list **process_tree(struct tree *tree,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
-{
-       struct object *obj = &tree->object;
-       struct tree_entry_list *entry;
-       struct name_path me;
-
-       if (!revs.tree_objects)
-               return p;
-       if (obj->flags & (UNINTERESTING | SEEN))
-               return p;
-       if (parse_tree(tree) < 0)
-               die("bad tree object %s", sha1_to_hex(obj->sha1));
-       obj->flags |= SEEN;
-       p = add_object(obj, p, path, name);
-       me.up = path;
-       me.elem = name;
-       me.elem_len = strlen(name);
-       entry = tree->entries;
-       tree->entries = NULL;
-       while (entry) {
-               struct tree_entry_list *next = entry->next;
-               if (entry->directory)
-                       p = process_tree(entry->item.tree, p, &me, entry->name);
-               else
-                       p = process_blob(entry->item.blob, p, &me, entry->name);
-               free(entry);
-               entry = next;
-       }
-       return p;
-}
-
-static void show_commit_list(struct rev_info *revs)
-{
-       struct commit *commit;
-       struct object_list *objects = NULL, **p = &objects, *pending;
-
-       while ((commit = get_revision(revs)) != NULL) {
-               p = process_tree(commit->tree, p, NULL, "");
-               show_commit(commit);
-       }
-       for (pending = revs->pending_objects; pending; pending = pending->next) {
-               struct object *obj = pending->item;
-               const char *name = pending->name;
-               if (obj->flags & (UNINTERESTING | SEEN))
-                       continue;
-               if (obj->type == tag_type) {
-                       obj->flags |= SEEN;
-                       p = add_object(obj, p, NULL, name);
-                       continue;
-               }
-               if (obj->type == tree_type) {
-                       p = process_tree((struct tree *)obj, p, NULL, name);
-                       continue;
-               }
-               if (obj->type == blob_type) {
-                       p = process_blob((struct blob *)obj, p, NULL, name);
-                       continue;
-               }
-               die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
-       }
-       while (objects) {
-               /* An object with name "foo\n0000000..." can be used to
-                * confuse downstream git-pack-objects very badly.
-                */
-               const char *ep = strchr(objects->name, '\n');
-               if (ep) {
-                       printf("%s %.*s\n", sha1_to_hex(objects->item->sha1),
-                              (int) (ep - objects->name),
-                              objects->name);
-               }
-               else
-                       printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
-               objects = objects->next;
-       }
-}
-
-/*
- * This is a truly stupid algorithm, but it's only
- * used for bisection, and we just don't care enough.
- *
- * We care just barely enough to avoid recursing for
- * non-merge entries.
- */
-static int count_distance(struct commit_list *entry)
-{
-       int nr = 0;
-
-       while (entry) {
-               struct commit *commit = entry->item;
-               struct commit_list *p;
-
-               if (commit->object.flags & (UNINTERESTING | COUNTED))
-                       break;
-               if (!revs.prune_fn || (commit->object.flags & TREECHANGE))
-                       nr++;
-               commit->object.flags |= COUNTED;
-               p = commit->parents;
-               entry = p;
-               if (p) {
-                       p = p->next;
-                       while (p) {
-                               nr += count_distance(p);
-                               p = p->next;
-                       }
-               }
-       }
-
-       return nr;
-}
-
-static void clear_distance(struct commit_list *list)
-{
-       while (list) {
-               struct commit *commit = list->item;
-               commit->object.flags &= ~COUNTED;
-               list = list->next;
-       }
-}
-
-static struct commit_list *find_bisection(struct commit_list *list)
-{
-       int nr, closest;
-       struct commit_list *p, *best;
-
-       nr = 0;
-       p = list;
-       while (p) {
-               if (!revs.prune_fn || (p->item->object.flags & TREECHANGE))
-                       nr++;
-               p = p->next;
-       }
-       closest = 0;
-       best = list;
-
-       for (p = list; p; p = p->next) {
-               int distance;
-
-               if (revs.prune_fn && !(p->item->object.flags & TREECHANGE))
-                       continue;
-
-               distance = count_distance(p);
-               clear_distance(list);
-               if (nr - distance < distance)
-                       distance = nr - distance;
-               if (distance > closest) {
-                       best = p;
-                       closest = distance;
-               }
-       }
-       if (best)
-               best->next = NULL;
-       return best;
-}
-
-static void mark_edge_parents_uninteresting(struct commit *commit)
-{
-       struct commit_list *parents;
-
-       for (parents = commit->parents; parents; parents = parents->next) {
-               struct commit *parent = parents->item;
-               if (!(parent->object.flags & UNINTERESTING))
-                       continue;
-               mark_tree_uninteresting(parent->tree);
-               if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
-                       parent->object.flags |= SHOWN;
-                       printf("-%s\n", sha1_to_hex(parent->object.sha1));
-               }
-       }
-}
-
-static void mark_edges_uninteresting(struct commit_list *list)
-{
-       for ( ; list; list = list->next) {
-               struct commit *commit = list->item;
-
-               if (commit->object.flags & UNINTERESTING) {
-                       mark_tree_uninteresting(commit->tree);
-                       continue;
-               }
-               mark_edge_parents_uninteresting(commit);
-       }
-}
-
-int main(int argc, const char **argv)
-{
-       struct commit_list *list;
-       int i;
-
-       init_revisions(&revs);
-       revs.abbrev = 0;
-       revs.commit_format = CMIT_FMT_UNSPECIFIED;
-       argc = setup_revisions(argc, argv, &revs, NULL);
-
-       for (i = 1 ; i < argc; i++) {
-               const char *arg = argv[i];
-
-               if (!strcmp(arg, "--header")) {
-                       revs.verbose_header = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--timestamp")) {
-                       show_timestamp = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--bisect")) {
-                       bisect_list = 1;
-                       continue;
-               }
-               usage(rev_list_usage);
-
-       }
-       if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
-               /* The command line has a --pretty  */
-               hdr_termination = '\n';
-               if (revs.commit_format == CMIT_FMT_ONELINE)
-                       header_prefix = "";
-               else
-                       header_prefix = "commit ";
-       }
-       else if (revs.verbose_header)
-               /* Only --header was specified */
-               revs.commit_format = CMIT_FMT_RAW;
-
-       list = revs.commits;
-
-       if ((!list &&
-            (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
-             !revs.pending_objects)) ||
-           revs.diff)
-               usage(rev_list_usage);
-
-       save_commit_buffer = revs.verbose_header;
-       track_object_refs = 0;
-       if (bisect_list)
-               revs.limited = 1;
-
-       prepare_revision_walk(&revs);
-       if (revs.tree_objects)
-               mark_edges_uninteresting(revs.commits);
-
-       if (bisect_list)
-               revs.commits = find_bisection(revs.commits);
-
-       show_commit_list(&revs);
-
-       return 0;
-}
index 3d7e02d..7d6de82 100644 (file)
@@ -18,9 +18,6 @@
 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;
@@ -28,23 +25,6 @@ static int mark_valid_only = 0;
 #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;
@@ -141,103 +121,6 @@ static int add_file_to_cache(const char *path)
 }
 
 /*
- * "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.
@@ -653,6 +536,7 @@ int main(int argc, const char **argv)
        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);
 
@@ -673,7 +557,7 @@ int main(int argc, const char **argv)
                                continue;
                        }
                        if (!strcmp(path, "-q")) {
-                               quiet = 1;
+                               refresh_flags |= REFRESH_QUIET;
                                continue;
                        }
                        if (!strcmp(path, "--add")) {
@@ -689,15 +573,15 @@ int main(int argc, const char **argv)
                                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")) {
@@ -770,7 +654,7 @@ int main(int argc, const char **argv)
                                goto finish;
                        }
                        if (!strcmp(path, "--ignore-missing")) {
-                               not_new = 1;
+                               refresh_flags |= REFRESH_IGNORE_MISSING;
                                continue;
                        }
                        if (!strcmp(path, "--verbose")) {