Teach core object handling functions about gitlinks
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Apr 2007 04:20:29 +0000 (21:20 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 10 Apr 2007 20:50:43 +0000 (13:50 -0700)
This teaches the really fundamental core SHA1 object handling routines
about gitlinks.  We can compare trees with gitlinks in them (although we
can not actually generate patches for them yet - just raw git diffs),
and they show up as commits in "git ls-tree".

We also know to compare gitlinks as if they were directories (ie the
normal "sort as trees" rules apply).

[jc: amended a cut&paste error]

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-ls-tree.c
cache-tree.c
read-cache.c
sha1_file.c

index 6472610ac2fecb8096ecab8fe29331a6fd6c009b..1cb4dca277b511315d3b914239c57621fc60bcf3 100644 (file)
@@ -6,6 +6,7 @@
 #include "cache.h"
 #include "blob.h"
 #include "tree.h"
+#include "commit.h"
 #include "quote.h"
 #include "builtin.h"
 
@@ -59,7 +60,24 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
        int retval = 0;
        const char *type = blob_type;
 
-       if (S_ISDIR(mode)) {
+       if (S_ISDIRLNK(mode)) {
+               /*
+                * Maybe we want to have some recursive version here?
+                *
+                * Something like:
+                *
+               if (show_subprojects(base, baselen, pathname)) {
+                       if (fork()) {
+                               chdir(base);
+                               exec ls-tree;
+                       }
+                       waitpid();
+               }
+                *
+                * ..or similar..
+                */
+               type = commit_type;
+       } else if (S_ISDIR(mode)) {
                if (show_recursive(base, baselen, pathname)) {
                        retval = READ_TREE_RECURSIVE;
                        if (!(ls_options & LS_SHOW_TREES))
index 9b73c8669a0946c3bcbf1de777e9acd4cd34bcae..6369cc7c536ba7b82a6afcb191628beefe889b72 100644 (file)
@@ -326,7 +326,7 @@ static int update_one(struct cache_tree *it,
                        mode = ntohl(ce->ce_mode);
                        entlen = pathlen - baselen;
                }
-               if (!missing_ok && !has_sha1_file(sha1))
+               if (mode != S_IFDIRLNK && !missing_ok && !has_sha1_file(sha1))
                        return error("invalid object %s", sha1_to_hex(sha1));
 
                if (!ce->ce_mode)
index 54573ce2ee3b2c70d5419716b20ade61683bc289..f458f50458299a3f306812f29a33d2b53dcfdcb2 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include "cache.h"
 #include "cache-tree.h"
+#include "refs.h"
 
 /* Index extensions.
  *
@@ -91,6 +92,23 @@ static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
        return match;
 }
 
+static int ce_compare_gitlink(struct cache_entry *ce)
+{
+       unsigned char sha1[20];
+
+       /*
+        * We don't actually require that the .git directory
+        * under DIRLNK directory be a valid git directory. It
+        * might even be missing (in case nobody populated that
+        * sub-project).
+        *
+        * If so, we consider it always to match.
+        */
+       if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0)
+               return 0;
+       return hashcmp(sha1, ce->sha1);
+}
+
 static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
 {
        switch (st->st_mode & S_IFMT) {
@@ -102,6 +120,9 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
                if (ce_compare_link(ce, xsize_t(st->st_size)))
                        return DATA_CHANGED;
                break;
+       case S_IFDIRLNK:
+               /* No need to do anything, we did the exact compare in "match_stat_basic" */
+               break;
        default:
                return TYPE_CHANGED;
        }
@@ -127,6 +148,12 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
                    (has_symlinks || !S_ISREG(st->st_mode)))
                        changed |= TYPE_CHANGED;
                break;
+       case S_IFDIRLNK:
+               if (!S_ISDIR(st->st_mode))
+                       changed |= TYPE_CHANGED;
+               else if (ce_compare_gitlink(ce))
+                       changed |= DATA_CHANGED;
+               break;
        default:
                die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
        }
@@ -250,9 +277,9 @@ int base_name_compare(const char *name1, int len1, int mode1,
                return cmp;
        c1 = name1[len];
        c2 = name2[len];
-       if (!c1 && S_ISDIR(mode1))
+       if (!c1 && (S_ISDIR(mode1) || S_ISDIRLNK(mode1)))
                c1 = '/';
-       if (!c2 && S_ISDIR(mode2))
+       if (!c2 && (S_ISDIR(mode2) || S_ISDIRLNK(mode2)))
                c2 = '/';
        return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
 }
@@ -334,8 +361,8 @@ int add_file_to_cache(const char *path, int verbose)
        if (lstat(path, &st))
                die("%s: unable to stat (%s)", path, strerror(errno));
 
-       if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
-               die("%s: can only add regular files or symbolic links", path);
+       if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
+               die("%s: can only add regular files, symbolic links or git-directories", path);
 
        namelen = strlen(path);
        size = cache_entry_size(namelen);
index 4304fe9bbc2b8e796e944fa7ddb2ea2791000adf..ab915faa6b5a7dc0967f8890f706ba81c1c35f44 100644 (file)
@@ -13,6 +13,7 @@
 #include "commit.h"
 #include "tag.h"
 #include "tree.h"
+#include "refs.h"
 
 #ifndef O_NOATIME
 #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -2332,6 +2333,8 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
                                     path);
                free(target);
                break;
+       case S_IFDIR:
+               return resolve_gitlink_ref(path, "HEAD", sha1);
        default:
                return error("%s: unsupported file type", path);
        }