I've committed a bunch of commits to many repositories on Gitlab over two years. However I realized I hadn't set up the proper email.
I used git filter-branch
to filter the history and change the user Email.
$ git filter-branch --env-filter '
OLD_EMAIL="old@example.com"
NEW_NAME="New Example"
NEW_EMAIL="new@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$NEW_NAME"
export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$NEW_NAME"
export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
then I force pushed these changes with git push --force
.
It updates the contributor on master branch.
After git push --force --tags origin 'refs/heads/master'
it changes the contributor on tags, too.
Problem:
It does not change the commits on Activity Page. Go to {Repository} > Project information > activity (shows updated contributor) but clicking on any commit number --> it loads an commit with not updated contributor.
Question:
How to rewrite the proper history including commits published in the activity log.
Unfortunately, the activity feed comes directly from the database event records and is completely separated from git once records are created. As far as I know, it is not possible to remove the entries in the activity feed, unless you have database level access.
However, it is possible to remove those commits completely using git-filter-repo
and running a repository cleanup so that they can't be viewed in GitLab. The links will still exist in the activity feed, but you'll get a 404 page when trying to view the re-written/removed commit SHA.
Another possible workaround would be to remove the activity feed entirely -- to do this, simply export your project, then import it. If you do that before pushing the git-filter-repo changes, then all the activity for all commits will show as the timestamp in which you push those changes:
If you do it after, there will simply be no activity in the feed at all:
Going beyond commits on branches, GitLab keeps (additional) internal references that are normally not present on your local git repo when you clone it. Including references in merge requests, pipelines, notes, and other places. Even if you update your refs/heads/*
you may need to update additional refs on the remote in order to see the change take effect in different places.
This will break certain UI pages and potentially lead to data loss, but is the only way to get GitLab to completely remove old references aside from deleting and re-creating the project.
Before starting MAKE A BACKUP of your repo by exporting it.
To completely change things, you'll need to alter these references as well:
refs/merge-requests/* for merge requests.
refs/pipelines/* for pipelines.
refs/environments/* for environments.
refs/keep-around/* are created as hidden refs to prevent commits referenced in the database from being removed
Unfortunately, GitLab doesn't let you access some of these "hidden refs" directly. To completely remove these references, you have to export your project to a tarball and restore the local git repo from the tarball, then apply the filter again, and push to the remote.
Export your project, then in the tarball there is a project.bundle
file.
git clone --bare --mirror ./project.bundle myrepo
cd myrepo
Then use git-filter-repo to completely change the email everywhere.
# replace with your actual filter-repo command needed
git filter-repo --name-callback '...' --email-callback '...' --commit-callback '...'
Then force push back all the refs, including hidden refs:
# reset the origin
git remote remove origin
git remote add origin https://gitlab.example.com/<namespace>/<project_name>.git
# push all refs
git push origin --force 'refs/heads/*'
# tags
git push origin --force 'refs/tags/*'
# prevent dead links to commits that no longer exist
git push origin --force 'refs/replace/*'
After this, you need to initialize a repository cleanup using the commit-map
generated by git filter-repo
. It's located in the repo at ./filter-repo/commit-map
. It looks something like this:
$ cat filter-repo/commit-map
old new
87c5016db64c6e8f4fc0feba4810b17c2c2222b5 2bb77407040e8a658eceacdf3034d24cedcc1ecd
cea6d9aa25e52dd755b694876a482a158debc60a 9a9b1d1a845d1096f4d3734191f883b52ffac6e9
5f1ac8c5fa47ac393d5e3f24b4b9812aaefbf5d7 b659497ed15ab0a3191dc5c6451c9440ca10d6e4
With the commit-map in hand, go to settings -> repository -> cleanup and upload the commit-map
file. You'll see a message:
Repository cleanup has started. You will receive an email once the cleanup operation is complete.
After some time (depends on repo size), the old commits should be completely gone.
In the activity feed, as mentioned, the links to old commits will still be there:
But if you click on the link, the commit itself now produces a 404 and can't be viewed in GitLab (gone forever!):