diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts
index 459e4b99445a7f96ccc7737ece63dc2e46ce714a..7f55240fa31f9b9437a8cb7157cf6bda2f2712e2 100644
--- a/lib/util/git/index.spec.ts
+++ b/lib/util/git/index.spec.ts
@@ -1056,4 +1056,30 @@ describe('util/git/index', () => {
       expect(sha).toBe(git.getBranchCommit(defaultBranch));
     });
   });
+
+  describe('installHook()', () => {
+    it('installHook()', async () => {
+      //git.getCommitMessages() only returns the first line (i.e. subject) of each msg
+      await git.installHook(
+        'commit-msg',
+        '#!/bin/sh\necho "APPENDED FROM COMMIT-MSG HOOK" >> $1;'
+      );
+      const files: FileChange[] = [
+        {
+          type: 'addition',
+          path: 'some-new-file',
+          contents: 'some new-contents',
+        },
+      ];
+      setNoVerify(['push']);
+      await git.commitFiles({
+        branchName: 'renovate/something',
+        files,
+        message: 'Orig-commit-msg',
+      });
+
+      const messages = await git.getCommitMessages();
+      expect(messages[0]).toBe('Orig-commit-msg APPENDED FROM COMMIT-MSG HOOK');
+    });
+  });
 });
diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts
index 4698779d97765c422a9ab90c7e6967609636c428..95fb7c10804f55ee69b391607d0daf7f41eab737 100644
--- a/lib/util/git/index.ts
+++ b/lib/util/git/index.ts
@@ -249,6 +249,17 @@ export async function initRepo(args: StorageConfig): Promise<void> {
   await fetchBranchCommits();
 }
 
+export async function installHook(
+  name: string,
+  hookSource: string
+): Promise<void> {
+  await syncGit();
+  const localDir = GlobalConfig.get('localDir')!;
+  const gitHooks = upath.join(localDir, '.git/hooks');
+  await fs.writeFile(`${gitHooks}/${name}`, hookSource);
+  await fs.chmod(`${gitHooks}/${name}`, 0o500);
+}
+
 async function resetToBranch(branchName: string): Promise<void> {
   logger.debug(`resetToBranch(${branchName})`);
   await git.raw(['reset', '--hard']);