@@ -68,14 +68,50 @@ public GitDirLocator(
6868 */
6969 @ Nullable
7070 public File lookupGitDirectory (@ Nonnull File manuallyConfiguredDir ) throws GitCommitIdExecutionException {
71- File dotGitDirectory = runSearch (manuallyConfiguredDir );
71+ File dotGitDirectory = runSearch (manuallyConfiguredDir , true );
7272 if (shouldFailOnNoGitDirectory && !directoryExists (dotGitDirectory )) {
7373 throw new GitCommitIdExecutionException (
7474 ".git directory is not found! Please specify a valid [dotGitDirectory] in your"
7575 + " project" );
7676 }
77+ // assert dotGitDirectory != null
7778 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+ }
79115 }
80116 return dotGitDirectory ;
81117 }
@@ -84,15 +120,18 @@ private static boolean directoryExists(@Nullable File fileLocation) {
84120 return fileLocation != null && fileLocation .exists () && fileLocation .isDirectory ();
85121 }
86122
87-
88- private File runSearch (@ Nonnull File manuallyConfiguredDir ) {
123+ @ Nullable
124+ private File runSearch (@ Nonnull File manuallyConfiguredDir , boolean resolveGitReferenceFile ) {
89125 if (manuallyConfiguredDir .exists ()) {
90126
91127 // If manuallyConfiguredDir is a directory then we can use it as the git path.
92128 if (manuallyConfiguredDir .isDirectory ()) {
93129 return manuallyConfiguredDir ;
94130 }
95131
132+ if (manuallyConfiguredDir .isFile () && !resolveGitReferenceFile ) {
133+ return manuallyConfiguredDir ;
134+ }
96135 // If the path exists but is not a directory it might be a git submodule "gitdir" link.
97136 File gitDirLinkPath = processGitDirFile (manuallyConfiguredDir );
98137
@@ -108,7 +147,7 @@ private File runSearch(@Nonnull File manuallyConfiguredDir) {
108147 */
109148 }
110149
111- return findProjectGitDirectory ();
150+ return findProjectGitDirectory (resolveGitReferenceFile );
112151 }
113152
114153 /**
@@ -117,15 +156,19 @@ private File runSearch(@Nonnull File manuallyConfiguredDir) {
117156 * @return File which represents the location of the .git directory or NULL if none found.
118157 */
119158 @ Nullable
120- private File findProjectGitDirectory () {
159+ private File findProjectGitDirectory (boolean resolveGitReferenceFile ) {
121160 File basedir = this .projectBasedir ;
122161 while (basedir != null ) {
123162 File gitdir = new File (basedir , Constants .DOT_GIT );
124163 if (gitdir .exists ()) {
125164 if (gitdir .isDirectory ()) {
126165 return gitdir ;
127166 } else if (gitdir .isFile ()) {
128- return processGitDirFile (gitdir );
167+ if (resolveGitReferenceFile ) {
168+ return processGitDirFile (gitdir );
169+ } else {
170+ return gitdir ;
171+ }
129172 } else {
130173 return null ;
131174 }
0 commit comments