Skip to content

Commit 4971a48

Browse files
committed
fix: handle submodules whose entry in the index is a file.
1 parent b35e544 commit 4971a48

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

gix/src/submodule/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,17 +160,21 @@ impl<'repo> Submodule<'repo> {
160160
/// or `None` if it was deleted from the index.
161161
///
162162
/// If `None`, but `Some()` when calling [`Self::head_id()`], then the submodule was just deleted but the change
163-
/// wasn't yet committed.
163+
/// wasn't yet committed. Note that `None` is also returned if the entry at the submodule path isn't a submodule.
164164
/// If `Some()`, but `None` when calling [`Self::head_id()`], then the submodule was just added without having committed the change.
165165
pub fn index_id(&self) -> Result<Option<gix_hash::ObjectId>, index_id::Error> {
166166
let path = self.path()?;
167-
Ok(self.state.index()?.entry_by_path(&path).map(|entry| entry.id))
167+
Ok(self
168+
.state
169+
.index()?
170+
.entry_by_path(&path)
171+
.and_then(|entry| (entry.mode == gix_index::entry::Mode::COMMIT).then_some(entry.id)))
168172
}
169173

170174
/// Return the object id of the submodule as stored in `HEAD^{tree}` of the superproject, or `None` if it wasn't yet committed.
171175
///
172176
/// If `Some()`, but `None` when calling [`Self::index_id()`], then the submodule was just deleted but the change
173-
/// wasn't yet committed.
177+
/// wasn't yet committed. Note that `None` is also returned if the entry at the submodule path isn't a submodule.
174178
/// If `None`, but `Some()` when calling [`Self::index_id()`], then the submodule was just added without having committed the change.
175179
pub fn head_id(&self) -> Result<Option<gix_hash::ObjectId>, head_id::Error> {
176180
let path = self.path()?;
@@ -180,7 +184,7 @@ impl<'repo> Submodule<'repo> {
180184
.head_commit()?
181185
.tree()?
182186
.peel_to_entry_by_path(gix_path::from_bstr(path.as_ref()))?
183-
.map(|entry| entry.inner.oid))
187+
.and_then(|entry| (entry.mode() == gix_object::tree::EntryMode::Commit).then_some(entry.inner.oid)))
184188
}
185189

186190
/// Return the path at which the repository of the submodule should be located.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:0c0437e6ee0730c0ffcea0368777daec45e75f0d0ef6e7464d6b5de19f822b83
3-
size 21428
2+
oid sha256:78fe07f2f55b0f90ed2b2b70cab81ba11bacaa71943990d4206b6fef04152110
3+
size 23128

gix/tests/fixtures/make_submodules.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,12 @@ git clone --bare with-submodules with-submodules-after-clone.git
6262
git clone --bare ../module1 modules/m1
6363
)
6464

65+
git clone with-submodules not-a-submodule
66+
(cd not-a-submodule
67+
git submodule update --init
68+
cp .gitmodules modules.bak
69+
git rm m1
70+
echo fake > m1
71+
mv modules.bak .gitmodules
72+
git add m1 && git commit -m "no submodule in index and commit, but in configuration"
73+
)

gix/tests/submodule/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ mod open {
4646
},
4747
)],
4848
),
49+
(
50+
"not-a-submodule",
51+
&[(
52+
"m1",
53+
gix::submodule::State {
54+
repository_exists: true,
55+
is_old_form: false,
56+
worktree_checkout: false,
57+
superproject_configuration: true,
58+
},
59+
)],
60+
),
4961
] {
5062
let repo = repo(name)?;
5163
for (sm, (name, expected)) in repo.submodules()?.expect("modules present").zip(expected) {
@@ -81,6 +93,16 @@ mod open {
8193
Ok(())
8294
}
8395

96+
#[test]
97+
fn not_a_submodule() -> crate::Result {
98+
let repo = repo("not-a-submodule")?;
99+
let sm = repo.submodules()?.into_iter().flatten().next().expect("one submodule");
100+
assert!(sm.open()?.is_some(), "repo available as it was cloned");
101+
assert!(sm.index_id()?.is_none(), "no actual submodule");
102+
assert!(sm.head_id()?.is_none(), "no actual submodule");
103+
Ok(())
104+
}
105+
84106
#[test]
85107
fn old_form() -> crate::Result {
86108
for name in ["old-form-invalid-worktree-path", "old-form"] {

0 commit comments

Comments
 (0)