@@ -68,14 +68,50 @@ public GitDirLocator(
68
68
*/
69
69
@ Nullable
70
70
public File lookupGitDirectory (@ Nonnull File manuallyConfiguredDir ) throws GitCommitIdExecutionException {
71
- File dotGitDirectory = runSearch (manuallyConfiguredDir );
71
+ File dotGitDirectory = runSearch (manuallyConfiguredDir , true );
72
72
if (shouldFailOnNoGitDirectory && !directoryExists (dotGitDirectory )) {
73
73
throw new GitCommitIdExecutionException (
74
74
".git directory is not found! Please specify a valid [dotGitDirectory] in your"
75
75
+ " project" );
76
76
}
77
+ // assert dotGitDirectory != null
77
78
if (useNativeGit ) {
78
- dotGitDirectory = dotGitDirectory .getParentFile ();
79
+ // Check if the resolved directory structure looks like it is a submodule
80
+ // path like `your-project/.git/modules/remote-module`.
81
+ if (dotGitDirectory != null ) {
82
+ File parent = dotGitDirectory .getParentFile ();
83
+ if (parent != null ) {
84
+ File parentParent = parent .getParentFile ();
85
+ if (parentParent != null && parentParent .getName ().equals (".git" ) && parent .getName ().equals ("modules" )) {
86
+ // Yes, we have a submodule, so this becomes a bit more tricky!
87
+ // First what we need to find is the unresolvedGitDir
88
+ File unresolvedGitDir = runSearch (manuallyConfiguredDir , false );
89
+ // Now to be extra sure, check if the unresolved
90
+ // ".git" we have found is actually a file, which is the case for submodules
91
+ if (unresolvedGitDir != null && unresolvedGitDir .isFile ()) {
92
+ // Yes, it's a submodule!
93
+ // For the native git executable we can not use the resolved
94
+ // dotGitDirectory which looks like `your-project/.git/modules/remote-module`.
95
+ // The main reason seems that some git commands like `git config`
96
+ // consume the relative worktree configuration like
97
+ // `worktree = ../../../remote-module` from that location.
98
+ // When running `git config` in `your-project/.git/modules/remote-module`
99
+ // it would fail with an error since the relative worktree location is
100
+ // only valid from the original location (`your-project/remote-module/.git`).
101
+ //
102
+ // Hence instead of using the resolved git dir location we need to use the
103
+ // unresolvedGitDir, but we need to keep in mind that we initially have pointed to
104
+ // a `git`-File like `your-project/remote-module/.git`
105
+ dotGitDirectory = unresolvedGitDir ;
106
+ }
107
+ }
108
+ }
109
+ }
110
+ // The directory is likely an actual .dot-dir like `your-project/.git`.
111
+ // In such a directory we can not run any git commands so we need to use the parent.
112
+ if (dotGitDirectory != null ) {
113
+ dotGitDirectory = dotGitDirectory .getParentFile ();
114
+ }
79
115
}
80
116
return dotGitDirectory ;
81
117
}
@@ -84,15 +120,18 @@ private static boolean directoryExists(@Nullable File fileLocation) {
84
120
return fileLocation != null && fileLocation .exists () && fileLocation .isDirectory ();
85
121
}
86
122
87
-
88
- private File runSearch (@ Nonnull File manuallyConfiguredDir ) {
123
+ @ Nullable
124
+ private File runSearch (@ Nonnull File manuallyConfiguredDir , boolean resolveGitReferenceFile ) {
89
125
if (manuallyConfiguredDir .exists ()) {
90
126
91
127
// If manuallyConfiguredDir is a directory then we can use it as the git path.
92
128
if (manuallyConfiguredDir .isDirectory ()) {
93
129
return manuallyConfiguredDir ;
94
130
}
95
131
132
+ if (manuallyConfiguredDir .isFile () && !resolveGitReferenceFile ) {
133
+ return manuallyConfiguredDir ;
134
+ }
96
135
// If the path exists but is not a directory it might be a git submodule "gitdir" link.
97
136
File gitDirLinkPath = processGitDirFile (manuallyConfiguredDir );
98
137
@@ -108,7 +147,7 @@ private File runSearch(@Nonnull File manuallyConfiguredDir) {
108
147
*/
109
148
}
110
149
111
- return findProjectGitDirectory ();
150
+ return findProjectGitDirectory (resolveGitReferenceFile );
112
151
}
113
152
114
153
/**
@@ -117,15 +156,19 @@ private File runSearch(@Nonnull File manuallyConfiguredDir) {
117
156
* @return File which represents the location of the .git directory or NULL if none found.
118
157
*/
119
158
@ Nullable
120
- private File findProjectGitDirectory () {
159
+ private File findProjectGitDirectory (boolean resolveGitReferenceFile ) {
121
160
File basedir = this .projectBasedir ;
122
161
while (basedir != null ) {
123
162
File gitdir = new File (basedir , Constants .DOT_GIT );
124
163
if (gitdir .exists ()) {
125
164
if (gitdir .isDirectory ()) {
126
165
return gitdir ;
127
166
} else if (gitdir .isFile ()) {
128
- return processGitDirFile (gitdir );
167
+ if (resolveGitReferenceFile ) {
168
+ return processGitDirFile (gitdir );
169
+ } else {
170
+ return gitdir ;
171
+ }
129
172
} else {
130
173
return null ;
131
174
}
0 commit comments