unpack-trees.c: assume submodules are clean during check-out

In particular, when moving back to a commit without a given submodule
and then moving back forward to a commit with the given submodule,
we shouldn't complain that updating would lose untracked file in
the submodule, because git currently does not checkout subprojects
during superproject check-out.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Sven Verdoolaege 2007-07-17 20:28:28 +02:00 коммит произвёл Junio C Hamano
Родитель c1c10a3f27
Коммит 0cf7375542
2 изменённых файлов: 59 добавлений и 25 удалений

Просмотреть файл

@ -21,6 +21,10 @@ subcommands of git-submodule.
# -add an entry to .gitmodules for submodule 'example' # -add an entry to .gitmodules for submodule 'example'
# #
test_expect_success 'Prepare submodule testing' ' test_expect_success 'Prepare submodule testing' '
: > t &&
git-add t &&
git-commit -m "initial commit" &&
git branch initial HEAD &&
mkdir lib && mkdir lib &&
cd lib && cd lib &&
git init && git init &&
@ -166,4 +170,9 @@ test_expect_success 'status should be "up-to-date" after update' '
git-submodule status | grep "^ $rev1" git-submodule status | grep "^ $rev1"
' '
test_expect_success 'checkout superproject with subproject already present' '
git-checkout initial &&
git-checkout master
'
test_done test_done

Просмотреть файл

@ -5,6 +5,7 @@
#include "cache-tree.h" #include "cache-tree.h"
#include "unpack-trees.h" #include "unpack-trees.h"
#include "progress.h" #include "progress.h"
#include "refs.h"
#define DBRT_DEBUG 1 #define DBRT_DEBUG 1
@ -425,11 +426,24 @@ static void invalidate_ce_path(struct cache_entry *ce)
cache_tree_invalidate_path(active_cache_tree, ce->name); cache_tree_invalidate_path(active_cache_tree, ce->name);
} }
static int verify_clean_subdirectory(const char *path, const char *action, /*
* Check that checking out ce->sha1 in subdir ce->name is not
* going to overwrite any working files.
*
* Currently, git does not checkout subprojects during a superproject
* checkout, so it is not going to overwrite anything.
*/
static int verify_clean_submodule(struct cache_entry *ce, const char *action,
struct unpack_trees_options *o)
{
return 0;
}
static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
struct unpack_trees_options *o) struct unpack_trees_options *o)
{ {
/* /*
* we are about to extract "path"; we would not want to lose * we are about to extract "ce->name"; we would not want to lose
* anything in the existing directory there. * anything in the existing directory there.
*/ */
int namelen; int namelen;
@ -437,13 +451,24 @@ static int verify_clean_subdirectory(const char *path, const char *action,
struct dir_struct d; struct dir_struct d;
char *pathbuf; char *pathbuf;
int cnt = 0; int cnt = 0;
unsigned char sha1[20];
if (S_ISGITLINK(ntohl(ce->ce_mode)) &&
resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) {
/* If we are not going to update the submodule, then
* we don't care.
*/
if (!hashcmp(sha1, ce->sha1))
return 0;
return verify_clean_submodule(ce, action, o);
}
/* /*
* First let's make sure we do not have a local modification * First let's make sure we do not have a local modification
* in that directory. * in that directory.
*/ */
namelen = strlen(path); namelen = strlen(ce->name);
pos = cache_name_pos(path, namelen); pos = cache_name_pos(ce->name, namelen);
if (0 <= pos) if (0 <= pos)
return cnt; /* we have it as nondirectory */ return cnt; /* we have it as nondirectory */
pos = -pos - 1; pos = -pos - 1;
@ -451,7 +476,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
struct cache_entry *ce = active_cache[i]; struct cache_entry *ce = active_cache[i];
int len = ce_namelen(ce); int len = ce_namelen(ce);
if (len < namelen || if (len < namelen ||
strncmp(path, ce->name, namelen) || strncmp(ce->name, ce->name, namelen) ||
ce->name[namelen] != '/') ce->name[namelen] != '/')
break; break;
/* /*
@ -469,16 +494,16 @@ static int verify_clean_subdirectory(const char *path, const char *action,
* present file that is not ignored. * present file that is not ignored.
*/ */
pathbuf = xmalloc(namelen + 2); pathbuf = xmalloc(namelen + 2);
memcpy(pathbuf, path, namelen); memcpy(pathbuf, ce->name, namelen);
strcpy(pathbuf+namelen, "/"); strcpy(pathbuf+namelen, "/");
memset(&d, 0, sizeof(d)); memset(&d, 0, sizeof(d));
if (o->dir) if (o->dir)
d.exclude_per_dir = o->dir->exclude_per_dir; d.exclude_per_dir = o->dir->exclude_per_dir;
i = read_directory(&d, path, pathbuf, namelen+1, NULL); i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
if (i) if (i)
die("Updating '%s' would lose untracked files in it", die("Updating '%s' would lose untracked files in it",
path); ce->name);
free(pathbuf); free(pathbuf);
return cnt; return cnt;
} }
@ -487,7 +512,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
* We do not want to remove or overwrite a working tree file that * We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored. * is not tracked, unless it is ignored.
*/ */
static void verify_absent(const char *path, const char *action, static void verify_absent(struct cache_entry *ce, const char *action,
struct unpack_trees_options *o) struct unpack_trees_options *o)
{ {
struct stat st; struct stat st;
@ -495,15 +520,15 @@ static void verify_absent(const char *path, const char *action,
if (o->index_only || o->reset || !o->update) if (o->index_only || o->reset || !o->update)
return; return;
if (has_symlink_leading_path(path, NULL)) if (has_symlink_leading_path(ce->name, NULL))
return; return;
if (!lstat(path, &st)) { if (!lstat(ce->name, &st)) {
int cnt; int cnt;
if (o->dir && excluded(o->dir, path)) if (o->dir && excluded(o->dir, ce->name))
/* /*
* path is explicitly excluded, so it is Ok to * ce->name is explicitly excluded, so it is Ok to
* overwrite it. * overwrite it.
*/ */
return; return;
@ -515,7 +540,7 @@ static void verify_absent(const char *path, const char *action,
* files that are in "foo/" we would lose * files that are in "foo/" we would lose
* it. * it.
*/ */
cnt = verify_clean_subdirectory(path, action, o); cnt = verify_clean_subdirectory(ce, action, o);
/* /*
* If this removed entries from the index, * If this removed entries from the index,
@ -543,7 +568,7 @@ static void verify_absent(const char *path, const char *action,
* delete this path, which is in a subdirectory that * delete this path, which is in a subdirectory that
* is being replaced with a blob. * is being replaced with a blob.
*/ */
cnt = cache_name_pos(path, strlen(path)); cnt = cache_name_pos(ce->name, strlen(ce->name));
if (0 <= cnt) { if (0 <= cnt) {
struct cache_entry *ce = active_cache[cnt]; struct cache_entry *ce = active_cache[cnt];
if (!ce_stage(ce) && !ce->ce_mode) if (!ce_stage(ce) && !ce->ce_mode)
@ -551,7 +576,7 @@ static void verify_absent(const char *path, const char *action,
} }
die("Untracked working tree file '%s' " die("Untracked working tree file '%s' "
"would be %s by merge.", path, action); "would be %s by merge.", ce->name, action);
} }
} }
@ -575,7 +600,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
} }
} }
else { else {
verify_absent(merge->name, "overwritten", o); verify_absent(merge, "overwritten", o);
invalidate_ce_path(merge); invalidate_ce_path(merge);
} }
@ -590,7 +615,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
if (old) if (old)
verify_uptodate(old, o); verify_uptodate(old, o);
else else
verify_absent(ce->name, "removed", o); verify_absent(ce, "removed", o);
ce->ce_mode = 0; ce->ce_mode = 0;
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
invalidate_ce_path(ce); invalidate_ce_path(ce);
@ -707,18 +732,18 @@ int threeway_merge(struct cache_entry **stages,
if (o->aggressive) { if (o->aggressive) {
int head_deleted = !head && !df_conflict_head; int head_deleted = !head && !df_conflict_head;
int remote_deleted = !remote && !df_conflict_remote; int remote_deleted = !remote && !df_conflict_remote;
const char *path = NULL; struct cache_entry *ce = NULL;
if (index) if (index)
path = index->name; ce = index;
else if (head) else if (head)
path = head->name; ce = head;
else if (remote) else if (remote)
path = remote->name; ce = remote;
else { else {
for (i = 1; i < o->head_idx; i++) { for (i = 1; i < o->head_idx; i++) {
if (stages[i] && stages[i] != o->df_conflict_entry) { if (stages[i] && stages[i] != o->df_conflict_entry) {
path = stages[i]->name; ce = stages[i];
break; break;
} }
} }
@ -733,8 +758,8 @@ int threeway_merge(struct cache_entry **stages,
(remote_deleted && head && head_match)) { (remote_deleted && head && head_match)) {
if (index) if (index)
return deleted_entry(index, index, o); return deleted_entry(index, index, o);
else if (path && !head_deleted) else if (ce && !head_deleted)
verify_absent(path, "removed", o); verify_absent(ce, "removed", o);
return 0; return 0;
} }
/* /*