Teach core object handling functions about gitlinks
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>
This commit is contained in:
parent
8d9721c86b
commit
f35a6d3bce
@ -6,6 +6,7 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "blob.h"
|
#include "blob.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "commit.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
|
||||||
@ -59,7 +60,24 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
const char *type = blob_type;
|
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)) {
|
if (show_recursive(base, baselen, pathname)) {
|
||||||
retval = READ_TREE_RECURSIVE;
|
retval = READ_TREE_RECURSIVE;
|
||||||
if (!(ls_options & LS_SHOW_TREES))
|
if (!(ls_options & LS_SHOW_TREES))
|
||||||
|
@ -326,7 +326,7 @@ static int update_one(struct cache_tree *it,
|
|||||||
mode = ntohl(ce->ce_mode);
|
mode = ntohl(ce->ce_mode);
|
||||||
entlen = pathlen - baselen;
|
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));
|
return error("invalid object %s", sha1_to_hex(sha1));
|
||||||
|
|
||||||
if (!ce->ce_mode)
|
if (!ce->ce_mode)
|
||||||
|
35
read-cache.c
35
read-cache.c
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
/* Index extensions.
|
/* Index extensions.
|
||||||
*
|
*
|
||||||
@ -91,6 +92,23 @@ static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
|
|||||||
return match;
|
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)
|
static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
|
||||||
{
|
{
|
||||||
switch (st->st_mode & S_IFMT) {
|
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)))
|
if (ce_compare_link(ce, xsize_t(st->st_size)))
|
||||||
return DATA_CHANGED;
|
return DATA_CHANGED;
|
||||||
break;
|
break;
|
||||||
|
case S_IFDIRLNK:
|
||||||
|
/* No need to do anything, we did the exact compare in "match_stat_basic" */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return TYPE_CHANGED;
|
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)))
|
(has_symlinks || !S_ISREG(st->st_mode)))
|
||||||
changed |= TYPE_CHANGED;
|
changed |= TYPE_CHANGED;
|
||||||
break;
|
break;
|
||||||
|
case S_IFDIRLNK:
|
||||||
|
if (!S_ISDIR(st->st_mode))
|
||||||
|
changed |= TYPE_CHANGED;
|
||||||
|
else if (ce_compare_gitlink(ce))
|
||||||
|
changed |= DATA_CHANGED;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
|
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;
|
return cmp;
|
||||||
c1 = name1[len];
|
c1 = name1[len];
|
||||||
c2 = name2[len];
|
c2 = name2[len];
|
||||||
if (!c1 && S_ISDIR(mode1))
|
if (!c1 && (S_ISDIR(mode1) || S_ISDIRLNK(mode1)))
|
||||||
c1 = '/';
|
c1 = '/';
|
||||||
if (!c2 && S_ISDIR(mode2))
|
if (!c2 && (S_ISDIR(mode2) || S_ISDIRLNK(mode2)))
|
||||||
c2 = '/';
|
c2 = '/';
|
||||||
return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
|
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))
|
if (lstat(path, &st))
|
||||||
die("%s: unable to stat (%s)", path, strerror(errno));
|
die("%s: unable to stat (%s)", path, strerror(errno));
|
||||||
|
|
||||||
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
|
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
|
||||||
die("%s: can only add regular files or symbolic links", path);
|
die("%s: can only add regular files, symbolic links or git-directories", path);
|
||||||
|
|
||||||
namelen = strlen(path);
|
namelen = strlen(path);
|
||||||
size = cache_entry_size(namelen);
|
size = cache_entry_size(namelen);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
#ifndef O_NOATIME
|
#ifndef O_NOATIME
|
||||||
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
|
#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);
|
path);
|
||||||
free(target);
|
free(target);
|
||||||
break;
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
return resolve_gitlink_ref(path, "HEAD", sha1);
|
||||||
default:
|
default:
|
||||||
return error("%s: unsupported file type", path);
|
return error("%s: unsupported file type", path);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user