I have already written how useful a tool git filter-repo is for cleaning repositories. I made some extensive use of the newfound knowledge since to undo some previous bad decisions in my private repositories.

Here's a list of commands for merging project-a into project-b for a reference.

Optional: Revert git LFS

Depending on the complexity of the project, you might optionally consider reverting the LFS status of the files in the project-a repository:

git lfs migrate export --include="*" --everything

Check if there are really no files in with the Large File Storage (LFS) status:

git lfs ls-files

It might be even safe now to remove any mention of the .gitattribute file, which is used to store information about which files should LFS track:

git filter-repo --path .gitattributes --invert-paths

You can migrate import LFS files back later.

Preparation: Directory structure

Start by moving a project-a one level deeper in the directory structure while preserving git history using a path shortcut:

cd path/to/project-a
git-filter-repo --to-subdirectory-filter $(basename "$PWD")

Confirm by running ls. Only project-a directory should pop up.

Merge

Now the project-a is ready to be integrated into the project-b:

cd /path/to/project-b
git remote add project-a /path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master
git remote remove project-a

After confirming a merge commit, the project-a directory should now be contained inside a project-b. To get rid of the merge commit, rebase interactively:

git rebase --interactive HEAD~

Confirming a git rebase dialog without editing anything (every line should start with a pick keyword) should be sufficient.

Optional: Re-sign every commit

If you want to publish the cleaned repository publicly, it might be worthwhile to add your GPG signature to the commits, as changing history with a rebase or directly via a git-filter-repo tool can mess with signatures.

Note: before proceeding with this step, make sure that you are the sole contributor to the repository. Also, if the repository is very old, the email address associated with the commit might need updating, for instance using with git-filter-repo --use-mailmap command.

I have written about re-signing previous commits, so check it out. In short:

git rebase --exec 'git commit --amend --no-edit --no-verify -S' -i --root
git rebase --committer-date-is-author-date -i --root

The merged repository should be ready to be pushed to it's shiny place!