GitLab account hacked and repo wiped

You can use git reflog in a clone and checkout the last commit before this happened.

It happened because .git/config on your webserver (in the directory of the cloned repo) includes the remote URLs and people added username:password in it which should never be the case - people should use SSH, deploy keys or authenticate on each pull. Never store your credentials in a config file. Use the credential helper(s).


hello, it is me , the guy with your backups ..

i will reveal your sins

Here is an article from 2015, its more detailed,

Article by Internetwache about this:

To prevent this either block access to directories starting with a dot, see

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# Block access to all hidden files and directories with the exception of
# the visible content from within the `/.well-known/` hidden directory.
# These types of files usually contain user preferences or the preserved
# state of an utility, and can include rather private places like, for
# example, the `.git` or `.svn` directories.
# The `/.well-known/` directory represents the standard (RFC 5785) path
# prefix for "well-known locations" (e.g.: `/.well-known/manifest.json`,
# `/.well-known/keybase.txt`), and therefore, access to its visible
# content should not be blocked.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
    RewriteCond %{SCRIPT_FILENAME} -d [OR]
    RewriteCond %{SCRIPT_FILENAME} -f
    RewriteRule "(^|/)\." - [F]

Or separate the .git directory and the data using --separate-git-dir.

--separate-git-dir=<git dir>
Instead of initializing the repository as a directory to either $GIT_DIR or ./.git/, create a text file there containing the path to the actual repository. This file acts as filesystem-agnostic Git symbolic link to the repository.

If this is reinitialization, the repository will be moved to the specified path.

But the best is to rm -rf .git after a deployment - which should just copy a build artefact to the destination using rsync.

--separate-git-dir=<git dir>
Instead of placing the cloned repository where it is supposed to be, place the cloned repository at the specified directory, then make a filesystem-agnostic Git symbolic link to there. The result is Git repository can be separated from working tree.

Information about deploy keys and the credential helpers:

Deploy keys are read-only by default, but you can give them write access when adding them to a repository.

Use git push -u origin master -f && git push --tags -f from your local clone to push all references for master, tags and so on to the remote and then enable 2FA in your account.

If more branches are affected use git push -u --all -f

Also please enable 2FA to decrease the possibility of such attacks.

Please do not forget to change all compromised logins / passwords and revoke any unknown sessions.

I doubt that the hackers pushed a "delete all" commit, or else you could simply revert the last commit. Rather, they force-pushed a different commit with the note to the HEAD of the master branch, making it look like your entire commit history is gone.

As others have pointed out, you can easily use a local repo to force push the correct code to the server. Due to the distributed nature of Git, this always works whether or not the server was wiped since every local repo has a complete clone of the server, including both commits and code. Of course, you should make sure the server has been secured first before attempting recovery efforts. :-)

If you don't have a local repo that includes the most recent commit, the commit history (and all associated files) will still exist on the server for a while. However, the server will eventually run git gc, which will clean up those unreachable commits. As of 2013, GitHub said they will run git gc at most once per day but it can also be triggered manually, while BitBucket will run it as needed, or perhaps after each push. GitLab runs it after 200 pushes by default, or it can be triggered manually.

However, even if all of the commits and files are still on the server, you would need to find the hash of the commit so you can restore it. Without a local repo with a reflog, it's hard to find the correct commit to restore. Some ideas that you could try:

  • If you are using GitHub, check the Events API for your repo at to see if you can locate the proper commit. I don't know if other services offer a similar feature.
  • Pull requests are typically kept forever, so you should be able to look at the most recent pull request merged into the master branch. Just make sure to pick the hash of the merge commit, not the hash of the branch. (GitHub has a green check mark next to the merge commit hash, GitLab shows "merged into master with", not sure about BitBucket).
  • If you have a build server, see what the most recent build of the master branch was (perhaps in the build log?)
  • You may want to check forks of your repo as well. GitHub allows you to see them either in Forks or Network views.

Once you find the correct hash for master, you can restore your server using the following commands (assuming you have a Git remote called 'origin').

git fetch origin <hash>
git checkout master
git reset --hard <hash>
git push --force origin master:master

Note that you should never use git push --force unless you intend to overwrite someone's work.

If more branches are affected, you may need to checkout all branches first with the following command before performing git push -u --all -f

for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master `; do
   git branch --track ${branch#remotes/origin/} $branch