+
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions builtin/rev-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
flags |= GET_SHA1_QUIETLY;
continue;
}
if (!strcmp(arg, "--recurse-submodules")) {
flags |= GET_SHA1_FOLLOW_GITLINKS;
continue;
}
if (!strcmp(arg, "--short") ||
starts_with(arg, "--short=")) {
filter &= ~(DO_FLAGS|DO_NOREV);
Expand Down
1 change: 1 addition & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ struct object_context {
#define GET_SHA1_TREEISH 020
#define GET_SHA1_BLOB 040
#define GET_SHA1_FOLLOW_SYMLINKS 0100
#define GET_SHA1_FOLLOW_GITLINKS 0200
#define GET_SHA1_ONLY_TO_DIE 04000

extern int get_sha1(const char *str, unsigned char *sha1);
Expand Down
3 changes: 3 additions & 0 deletions sha1_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,9 @@ static int get_sha1_with_context_1(const char *name,
ret = get_tree_entry_follow_symlinks(tree_sha1,
filename, sha1, &oc->symlink_path,
&oc->mode);
} else if (flags & GET_SHA1_FOLLOW_GITLINKS) {
ret = get_tree_entry_recurse_submodules(tree_sha1,
filename, sha1, &oc->mode);
} else {
ret = get_tree_entry(tree_sha1, filename,
sha1, &oc->mode);
Expand Down
41 changes: 41 additions & 0 deletions submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,47 @@ static int add_submodule_odb(const char *path)
return ret;
}

/* Add the submodule's database to alt_odb_list if it exists. Optionally
* lookup the commit at sha1 to determine reachability.
*/
int add_submodule_odb_from_tree(const char *path, int len, const unsigned char *toplevel_sha1, const unsigned char *sha1)
{
int retval=0;
struct strbuf sm_name = STRBUF_INIT;

strbuf_addstr(&sm_name, path);

if (!len)
return ODB_SUBMODULE_BADPATH;

if (toplevel_sha1)
{
struct strbuf gitdir = STRBUF_INIT;
const struct submodule *sm;
if (path[len-1]=='/') --len;
strbuf_add(&gitdir, path, len);

sm=submodule_from_path(toplevel_sha1, gitdir.buf);
if (!sm)
retval = ODB_SUBMODULE_MISSING;
else {
strbuf_reset(&sm_name);
strbuf_addstr(&sm_name, sm->name);
}
}

if (retval)
(void)0;/* all done */
else if (add_submodule_odb(sm_name.buf))
retval = ODB_SUBMODULE_MISSING;
else if ( sha1 && !lookup_commit_reference(sha1))
retval = ODB_SUBMODULE_MISSING_REF;
else
retval = ODB_SUBMODULE_OK;

return retval;
}

void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
const char *path)
{
Expand Down
8 changes: 8 additions & 0 deletions submodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ enum {
RECURSE_SUBMODULES_ON = 2
};

enum {
ODB_SUBMODULE_MISSING_REF = -1,
ODB_SUBMODULE_OK = 0,
ODB_SUBMODULE_MISSING = 1,
ODB_SUBMODULE_BADPATH = 2,
};

int is_staging_gitmodules_ok(void);
int update_path_in_gitmodules(const char *oldpath, const char *newpath);
int remove_path_from_gitmodules(const char *path);
Expand Down Expand Up @@ -41,5 +48,6 @@ int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_nam
struct string_list *needs_pushing);
int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name);
void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
int add_submodule_odb_from_tree(const char *path, int len, const unsigned char *toplevel_sha1, const unsigned char *sha1);

#endif
188 changes: 188 additions & 0 deletions t/t6102-rev-parse--recurse-submodules.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#!/bin/sh
#

test_description='Native support for rev-parse of objects in submodules

This test verifies that rev-parse understands how to parse names of objects
belonging to submodules of the current project.
'

. ./test-lib.sh


test_expect_success 'setup a submodule tree' '
echo file > file &&
git add file &&
test_tick &&
git commit -m upstream &&
git clone . super &&
git clone super submodule &&
(
cd super &&
git submodule add ../submodule submodule1 &&
git submodule add ../submodule submodule2 &&
git submodule add ../submodule sub3 &&
git config -f .gitmodules --rename-section \
submodule.submodule1 submodule.foo1 &&
git config -f .gitmodules --rename-section \
submodule.submodule2 submodule.foo2 &&
git config -f .gitmodules --rename-section \
submodule.sub3 submodule.foo3 &&
git add .gitmodules &&
test_tick &&
git commit -m "submodules" &&
git submodule init submodule1 &&
git submodule init submodule2 &&
git submodule init sub3
) &&
(
cd submodule &&
echo different > file &&
git add file &&
test_tick &&
git commit -m "different"
) &&
(
cd super &&
(
cd sub3 &&
git pull
) &&
git add sub3 &&
test_tick &&
git commit -m "update sub3"
)
'

submodule1sha1=$(cd super/submodule1 && git rev-parse HEAD)
submodule2sha1=$(cd super/submodule2 && git rev-parse HEAD)
sub3sha1=$(cd super/sub3 && git rev-parse HEAD)

cat > expect <<EOF
100644 blob f73f3093ff865c514c6c51f867e35f693487d0d3 file
160000 commit $submodule1sha1 submodule1
160000 commit $submodule2sha1 submodule2
160000 commit $sub3sha1 sub3
EOF

test_expect_success 'setup nested submodules' '
git clone submodule nested1 &&
git clone submodule nested2 &&
(
cd nested1 &&
mkdir subdir &&
git submodule add ../nested2 subdir/nested3 &&
git submodule add ../nested2 nested2 &&
test_tick &&
git commit -m "nested2 and subdir/nested3" &&
git submodule init nested2 &&
git submodule init subdir/nested3
) &&
(
cd super &&
mkdir subdir &&
git submodule add ../nested1 subdir/nested1 &&
cd subdir &&
test_tick &&
git commit -m "nested1" &&
git submodule update --init --recursive
)
'

test_expect_success 'setup partially updated nested submodules' '
git clone super clone2 &&
(
cd clone2 &&
git submodule update --init &&
test_must_fail git rev-parse --resolve-git-dir subdir/nested1/nested2/.git &&
git submodule foreach "git submodule update --init" &&
git rev-parse --resolve-git-dir subdir/nested1/nested2/.git &&
test_must_fail git rev-parse --resolve-git-dir subdir/nested1/nested2/nested3/.git
)
'
test_expect_success 'rev-parse does not recurse by default' '
(
cd super &&
test_must_fail git rev-parse HEAD:submodule1/file
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:submodule/file' '
(
cd super &&
git -C submodule1 rev-parse $(git rev-parse master:submodule1):file >expected &&
git rev-parse --recurse-submodules master:submodule1/file >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $sha1:submodule/file' '
(
cd super &&
git -C submodule1 rev-parse $(git rev-parse HEAD:submodule1):file >expected &&
git rev-parse --recurse-submodules $(git rev-parse HEAD):submodule1/file >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules HEAD:submodule/non-existent-file fails' '
(
cd super &&
test_must_fail git rev-parse --recurse-submodules HEAD:submodule1/notafile
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:subdir/submodule/file' '
(
cd super &&
git -C subdir/nested1 rev-parse $(git rev-parse HEAD:subdir/nested1):file >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/file >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:subdir/submodule1/submodule2/file' '
(
cd super &&
git -C subdir/nested1/nested2 rev-parse $(git -C subdir/nested1 rev-parse HEAD:nested2):file >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/nested2/file >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:submodule1/dir1/submodule2' '
(
cd super &&
git -C subdir/nested1 rev-parse HEAD:subdir/nested3 >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/subdir/nested3 >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:submodule1/dir1/submodule2/' '
(
cd super &&
git -C subdir/nested1 rev-parse HEAD:subdir/nested3 >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/subdir/nested3/ >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:submodule1/dir1/submodule2/file' '
(
cd super &&
git -C subdir/nested1/subdir/nested3 rev-parse $(git -C subdir/nested1 rev-parse HEAD:subdir/nested3):file >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/subdir/nested3/file >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:dir1/submodule1/submodule2' '
(
cd super &&
git -C subdir/nested1 rev-parse $(git rev-parse HEAD:subdir/nested1):nested2 >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/nested2 >actual &&
test_cmp expected actual
)
'
test_expect_success 'rev-parse --recurse-submodules $branch:dir1/submodule1/submodule2/file' '
(
cd super &&
git -C subdir/nested1/nested2 rev-parse $(git -C subdir/nested1 rev-parse HEAD:nested2):file >expected &&
git rev-parse --recurse-submodules HEAD:subdir/nested1/nested2/file >actual &&
test_cmp expected actual
)
'

test_done
50 changes: 45 additions & 5 deletions tree-walk.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "unpack-trees.h"
#include "dir.h"
#include "tree.h"
#include "submodule.h"
#include "pathspec.h"

static const char *get_mode(const char *str, unsigned int *modep)
Expand Down Expand Up @@ -415,13 +416,26 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
return error;
}

/* Bookmark the topmost tree for gitlink following. */
struct bookmark {
const unsigned char *sha1;
const char *path;
unsigned int len;
};

struct dir_state {
void *tree;
unsigned long size;
unsigned char sha1[20];
};

static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)
static int get_tree_entry_1(const unsigned char *tree_sha1, const char *name,
unsigned char *sha1, unsigned *mode,
struct bookmark *top);

static int find_tree_entry(struct tree_desc *t, const char *name,
unsigned char *result, unsigned *mode,
struct bookmark *top)
{
int namelen = strlen(name);
while (t->size) {
Expand All @@ -445,18 +459,37 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
}
if (name[entrylen] != '/')
continue;
if (!S_ISDIR(*mode))
if (!S_ISDIR(*mode) && (!top || !S_ISGITLINK(*mode)))
break;
if (++entrylen == namelen) {
hashcpy(result, sha1);
return 0;
}
return get_tree_entry(sha1, name + entrylen, result, mode);
if (top) top->len += entrylen;
if (S_ISGITLINK(*mode))
{
add_submodule_odb_from_tree(top->path, top->len-1, top->sha1, sha1);
top->sha1 = NULL;
}
return get_tree_entry_1(sha1, name + entrylen, result, mode, top);
}
return -1;
}

int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode)
{
return get_tree_entry_1(tree_sha1, name, sha1, mode, NULL);
}

int get_tree_entry_recurse_submodules(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode)
{
struct bookmark top = {NULL, NULL, 0};
return get_tree_entry_1(tree_sha1, name, sha1, mode, &top);
}

static int get_tree_entry_1(const unsigned char *tree_sha1, const char *name,
unsigned char *sha1, unsigned *mode,
struct bookmark *top)
{
int retval;
void *tree;
Expand All @@ -473,12 +506,19 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
return 0;
}

if (top && !top->sha1)
{
top->sha1 = root;
top->path = name;
top->len = 0;
}

if (!size) {
retval = -1;
} else {
struct tree_desc t;
init_tree_desc(&t, tree, size);
retval = find_tree_entry(&t, name, sha1, mode);
retval = find_tree_entry(&t, name, sha1, mode, top);
}
free(tree);
return retval;
Expand Down Expand Up @@ -602,7 +642,7 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(unsigned char *tree_s

/* Look up the first (or only) path component in the tree. */
find_result = find_tree_entry(&t, namebuf.buf,
current_tree_sha1, mode);
current_tree_sha1, mode, NULL);
if (find_result) {
goto done;
}
Expand Down
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载