diff --git a/lib/datasource/npm/get.spec.ts b/lib/datasource/npm/get.spec.ts
index a983e37223a9f96688e2b9b8fde61de4bcb1c202..c9e7e4baf127ab0476ca191c6c6cbd18876bd9e2 100644
--- a/lib/datasource/npm/get.spec.ts
+++ b/lib/datasource/npm/get.spec.ts
@@ -269,7 +269,45 @@ describe('datasource/npm/get', () => {
     `);
   });
 
-  it('warns about repo directory override', async () => {
+  it('handles mixed sourceUrls in releases', async () => {
+    setNpmrc('registry=https://test.org\n_authToken=XXX');
+
+    httpMock
+      .scope('https://test.org')
+      .get('/vue')
+      .reply(200, {
+        name: 'vue',
+        repository: {
+          type: 'git',
+          url: 'https://github.com/vuejs/vue.git',
+        },
+        versions: {
+          '2.0.0': {
+            repository: {
+              type: 'git',
+              url: 'https://github.com/vuejs/vue.git',
+            },
+          },
+          '3.0.0': {
+            repository: {
+              type: 'git',
+              url: 'https://github.com/vuejs/vue-next.git',
+            },
+          },
+        },
+        'dist-tags': { latest: '2.0.0' },
+      });
+
+    const dep = await getDependency('vue');
+
+    expect(dep.sourceUrl).toBe('https://github.com/vuejs/vue.git');
+    expect(dep.releases[0].sourceUrl).toBeUndefined();
+    expect(dep.releases[1].sourceUrl).toEqual(
+      'https://github.com/vuejs/vue-next.git'
+    );
+  });
+
+  it('does not override sourceDirectory', async () => {
     setNpmrc('registry=https://test.org\n_authToken=XXX');
 
     httpMock
@@ -280,7 +318,7 @@ describe('datasource/npm/get', () => {
         repository: {
           type: 'git',
           url: 'https://github.com/neutrinojs/neutrino/tree/master/packages/react',
-          directory: 'path/to/directory',
+          directory: 'packages/foo',
         },
         versions: { '1.0.0': {} },
         'dist-tags': { latest: '1.0.0' },
@@ -289,7 +327,7 @@ describe('datasource/npm/get', () => {
     const dep = await getDependency('@neutrinojs/react');
 
     expect(dep.sourceUrl).toBe('https://github.com/neutrinojs/neutrino');
-    expect(dep.sourceDirectory).toBe('packages/react');
+    expect(dep.sourceDirectory).toBe('packages/foo');
 
     expect(httpMock.getTrace()).toMatchInlineSnapshot(`
       Array [
diff --git a/lib/datasource/npm/get.ts b/lib/datasource/npm/get.ts
index 98ee0b7388b72e0a3edf42be5d31183dc7e88f68..d9de4aedc91b03b71a6549a48bab532e30452a07 100644
--- a/lib/datasource/npm/get.ts
+++ b/lib/datasource/npm/get.ts
@@ -21,6 +21,37 @@ export function resetCache(): void {
   resetMemCache();
 }
 
+interface PackageSource {
+  sourceUrl?: string;
+  sourceDirectory?: string;
+}
+
+function getPackageSource(repository: any): PackageSource {
+  const res: PackageSource = {};
+  if (repository) {
+    if (is.nonEmptyString(repository)) {
+      res.sourceUrl = repository;
+    } else if (is.nonEmptyString(repository.url)) {
+      res.sourceUrl = repository.url;
+    }
+    if (is.nonEmptyString(repository.directory)) {
+      res.sourceDirectory = repository.directory;
+    }
+    const sourceUrlCopy = `${res.sourceUrl}`;
+    const sourceUrlSplit: string[] = sourceUrlCopy.split('/');
+    if (sourceUrlSplit.length > 7 && sourceUrlSplit[2] === 'github.com') {
+      // Massage the repository URL for non-compliant strings for github (see issue #4610)
+      // Remove the non-compliant segments of path, so the URL looks like "<scheme>://<domain>/<vendor>/<repo>"
+      // and add directory to the repository
+      res.sourceUrl = sourceUrlSplit.slice(0, 5).join('/');
+      res.sourceDirectory ||= sourceUrlSplit
+        .slice(7, sourceUrlSplit.length)
+        .join('/');
+    }
+  }
+  return res;
+}
+
 export async function getDependency(
   packageName: string
 ): Promise<NpmDependency | null> {
@@ -70,49 +101,19 @@ export async function getDependency(
     res.repository = res.repository || latestVersion.repository;
     res.homepage = res.homepage || latestVersion.homepage;
 
-    // Determine repository URL
-    let sourceUrl: string;
-
-    if (res.repository) {
-      if (is.string(res.repository)) {
-        sourceUrl = res.repository;
-      } else if (res.repository.url) {
-        sourceUrl = res.repository.url;
-      }
-    }
+    const { sourceUrl, sourceDirectory } = getPackageSource(res.repository);
 
     // Simplify response before caching and returning
     const dep: NpmDependency = {
       name: res.name,
       homepage: res.homepage,
       sourceUrl,
+      sourceDirectory,
       versions: {},
       releases: null,
       'dist-tags': res['dist-tags'],
       registryUrl,
     };
-    if (res.repository?.directory) {
-      dep.sourceDirectory = res.repository.directory;
-    }
-
-    // Massage the repository URL for non-compliant strings for github (see issue #4610)
-    // Remove the non-compliant segments of path, so the URL looks like "<scheme>://<domain>/<vendor>/<repo>"
-    // and add directory to the repository
-    const sourceUrlCopy = `${sourceUrl}`;
-    const sourceUrlSplit: string[] = sourceUrlCopy.split('/');
-
-    if (sourceUrlSplit.length > 7 && sourceUrlSplit[2] === 'github.com') {
-      if (dep.sourceDirectory) {
-        logger.debug(
-          { dependency: packageName },
-          `Ambiguity: dependency has the repository URL path and repository/directory set at once; have to override repository/directory`
-        );
-      }
-      dep.sourceUrl = sourceUrlSplit.slice(0, 5).join('/');
-      dep.sourceDirectory = sourceUrlSplit
-        .slice(7, sourceUrlSplit.length)
-        .join('/');
-    }
 
     if (latestVersion.deprecated) {
       dep.deprecationMessage = `On registry \`${registryUrl}\`, the "latest" version of dependency \`${packageName}\` has the following deprecation notice:\n\n\`${latestVersion.deprecated}\`\n\nMarking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake.`;
@@ -131,6 +132,16 @@ export async function getDependency(
       if (res.versions[version].deprecated) {
         release.isDeprecated = true;
       }
+      const source = getPackageSource(res.versions[version].repository);
+      if (source.sourceUrl && source.sourceUrl !== dep.sourceUrl) {
+        release.sourceUrl = source.sourceUrl;
+      }
+      if (
+        source.sourceDirectory &&
+        source.sourceDirectory !== dep.sourceDirectory
+      ) {
+        release.sourceDirectory = source.sourceDirectory;
+      }
       return release;
     });
     logger.trace({ dep }, 'dep');
diff --git a/lib/datasource/types.ts b/lib/datasource/types.ts
index 098a17274259c01e8a9047b0266f384fe60b868d..1d271a8a9ad17ddd5d495363b7f6a39636ebb515 100644
--- a/lib/datasource/types.ts
+++ b/lib/datasource/types.ts
@@ -44,6 +44,8 @@ export interface Release {
   dependencies?: Record<string, string>;
   devDependencies?: Record<string, string>;
   registryUrl?: string;
+  sourceUrl?: string;
+  sourceDirectory?: string;
 }
 
 export interface ReleaseResult {