summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin-ls-tree.c20
-rw-r--r--cache-tree.c2
-rw-r--r--read-cache.c35
-rw-r--r--sha1_file.c3
4 files changed, 54 insertions, 6 deletions
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index 6472610ac2..1cb4dca277 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -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))
diff --git a/cache-tree.c b/cache-tree.c
index 9b73c8669a..6369cc7c53 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -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)
diff --git a/read-cache.c b/read-cache.c
index 54573ce2ee..f458f50458 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -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);
diff --git a/sha1_file.c b/sha1_file.c
index 4304fe9bbc..ab915faa6b 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -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);
}