72

How can I delete a commit that I made on GitLab? This commit that I made is not the HEAD now.

If I can't delete it, can I edit?

When it was the HEAD, I tried:

git reset  --soft HEAD

git reset  --soft HEAD^1

git revert HEAD

git rebase -i HEAD

git rebase -i HEAD~1

git reset --hard HEAD

git reset --hard Id-Code

I already tried to rebase it, but it still stays on the branch. Now I just removed it from the HEAD, but it is still there.

There is another command?

mhery
  • 2,097
  • 4
  • 26
  • 35
  • Did you push the commit to your gitlab server – marcusshep Oct 25 '16 at 17:26
  • As @Álvaro-p mentioned on a comment after his answer below, you need to force (-f) when you push and also ensure that the branch is not protected in GitLab. – user12345 Sep 05 '17 at 22:28
  • Most solutions do not mean about force push after changes in the local repo. I am not able to do --force push on GitLab even with Maintainer permissions `git push origin master --force` `Counting objects: 5, done.` `Delta compression using up to 4 threads.` `Compressing objects: 100% (5/5), done.` `Writing objects: 100% (5/5), 1.02 KiB | 131.00 KiB/s, done.` `Total 5 (delta 0), reused 0 (delta 0)` `remote: GitLab: You are not allowed to force push code to a protected branch on this project.` So there is still no solution for GitLab – Roman Shishkin Jun 16 '19 at 13:10
  • 1
    @RomanShishkin your GitLab project is configured to prevent force push on protected branches. Just temporarily allow it to do your force push and disable it again afterwards. – Didier L Mar 03 '22 at 09:57

4 Answers4

98
  1. git reset --hard CommitId
  2. git push -f origin master

1st command will rest your head to commitid and 2nd command will delete all commit after that commit id on master branch.

Note: Don't forget to add -f in push otherwise it will be rejected.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
ABHAY JOHRI
  • 1,997
  • 15
  • 19
  • Remember to add -f in push otherwise it will be rejected. – ABHAY JOHRI Dec 18 '17 at 14:17
  • 10
    This response does not solve the Issue stated by the OP. Your solution removes All the commits after an arbitrary commit, but does not remove only one commit which is not in the branch tip anymore. – Álvaro P. Apr 16 '18 at 15:41
  • CAUTION!! This will REMOVE all updates and commits – yan Jan 06 '20 at 10:37
  • 5
    +1. Note that you might need to temporary unprotect the master branch for (2) to work, if it's protected on Gitlab – Mario Orlandi May 22 '20 at 15:46
  • I agree that the response doe not really address the question, but it solved my problem (trying to revert to a previous commit). :-) – Alek Davis Feb 10 '23 at 20:22
67

Supose you have the following scenario:

* 1bd2200 (HEAD, master) another commit
* d258546 bad commit
* 0f1efa9 3rd commit
* bd8aa13 2nd commit
* 34c4f95 1st commit

Where you want to remove d258546 i.e. "bad commit".

You shall try an interactive rebase to remove it: git rebase -i 34c4f95

then your default editor will pop with something like this:

 pick bd8aa13 2nd commit
 pick 0f1efa9 3rd commit
 pick d258546 bad commit
 pick 1bd2200 another commit

 # Rebase 34c4f95..1bd2200 onto 34c4f95
 #
 # Commands:
 #  p, pick = use commit
 #  r, reword = use commit, but edit the commit message
 #  e, edit = use commit, but stop for amending
 #  s, squash = use commit, but meld into previous commit
 #  f, fixup = like "squash", but discard this commit's log message
 #  x, exec = run command (the rest of the line) using shell
 #
 # These lines can be re-ordered; they are executed from top to bottom.
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 #
 # However, if you remove everything, the rebase will be aborted.
 #
 # Note that empty commits are commented out

just remove the line with the commit you want to strip and save+exit the editor:

 pick bd8aa13 2nd commit
 pick 0f1efa9 3rd commit
 pick 1bd2200 another commit
 ...

git will proceed to remove this commit from your history leaving something like this (mind the hash change in the commits descendant from the removed commit):

 * 34fa994 (HEAD, master) another commit
 * 0f1efa9 3rd commit
 * bd8aa13 2nd commit
 * 34c4f95 1st commit

Now, since I suppose that you already pushed the bad commit to gitlab, you'll need to repush your graph to the repository (but with the -f option to prevent it from being rejected due to a non fastforwardeable history i.e. git push -f <your remote> <your branch>)

Please be extra careful and make sure that none coworker is already using the history containing the "bad commit" in their branches.

Alternative option:

Instead of rewrite the history, you may simply create a new commit which negates the changes introduced by your bad commit, to do this just type git revert <your bad commit hash>. This option is maybe not as clean, but is far more safe (in case you are not fully aware of what are you doing with an interactive rebase).

Álvaro P.
  • 1,031
  • 9
  • 9
  • Would definitely recommend a `git revert`. Much less work, and much safer than overwriting history (which is difficult by design). Of course, this is assuming no sensitive information was pushed. – tcooc Oct 25 '16 at 17:31
  • @tcooc well, in my case, sensitive information was pushed – mhery Oct 25 '16 at 17:36
  • 1
    @mhery then the first option is what you want. Make sure you double check that all of your commits are in order before pushing because `git push -f` is permanent and not reversible. – tcooc Oct 25 '16 at 17:38
  • Álvaro, does this delete it from repo? – mhery Oct 25 '16 at 17:42
  • @tcooc but I dont get if these instructions delete the commit from repo – mhery Oct 25 '16 at 17:43
  • 6
    To remove it from the gitlab server you'll need to push your branch. Remember to set the `-f` (i.e. force) option, otherwise it will be rejected. (and since you're using gitlab, you shall ensure that your branch is not protected against forced pushes; in this case, you, or your repository master, shall deactivare the "protected branch" toggle in the repository settings prior to the forced push). – Álvaro P. Oct 25 '16 at 17:45
  • 9
    This removes the commit from the branch's history graph, effectively orphaning it, but does not delete the commit entirely - if you know the commit hash, you may still be able to find the commit on Gitlab's web interface even if it's not included in any branch or tag. This is at least the case if an open merge request remembers that it used to include that commit before a force push. I'm not sure if the commit would be retained in a branch without a merge request though, but I wouldn't want to risk it. – Zeust the Unoobian Jan 24 '18 at 16:12
  • 7
    Zeust the Unoobian is right. The commit is still in GitLab. Even running "Housekeeping" does not remove it "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects. " I suspect this is because it is still linked from the Pipeline, so it is not really unreachable. – John Vandenberg Apr 04 '18 at 23:35
  • 1
    It looks like it's now possible to [delete a list of commits](https://docs.gitlab.com/ee/user/project/repository/reducing_the_repo_size_using_git.html#repository-cleanup) which should no longer be reachable in GitLab. – l0b0 Jan 15 '21 at 22:31
  • GitHub does not remove rewrited commits in case if the user request them to run a garbage collector (Please see https://stackoverflow.com/a/34594815/2402577). Does same apply for GitLab? – alper Sep 04 '21 at 20:23
20

We've had similar problem and it was not enough to only remove commit and force push to GitLab.
It was still available in GitLab interface using url:

https://gitlab.example.com/<group>/<project>/commit/<commit hash>

We've had to remove project from GitLab and recreate it to get rid of this commit in GitLab UI.

Tadeusz Kleszcz
  • 388
  • 1
  • 5
  • 10
  • Same thing here, even after running their housekeeping tool... I decided to leave it that way as without knowing the correct hash it's not findable. The fun thing that brought me to this page : after upgrading MacOs, for my first commit I add to set up again my git username and email via the IntelliJ box. I was too fast and by habit entered my username and... my password, a password that I use with other accounts (but with 2FA unabled) and to unlock my MacBook... So in the GitLab UI you were able to over the icon related to my commit and just see "mailto:MYPASSWORD" He he he – lboix Nov 17 '20 at 01:26
  • Is there any other solution to this? – Charalamm Nov 24 '21 at 16:59
  • 1
    As per [another comment under Álavro P.’s answer](https://stackoverflow.com/questions/40245767/delete-commit-on-gitlab#comment116240168_40246125), you can now [delete a list of commits](https://docs.gitlab.com/ee/user/project/repository/reducing_the_repo_size_using_git.html#repository-cleanup) (didn’t try it myself though) – Didier L Mar 03 '22 at 10:20
3

I will assume that you want to edit all commits to remove some strings from them, like for example leaked credentials.

Really purging old commits from a Gitlab server is a tricky task, as mentioned in the Gitlab purge doc, because it involves deleting all internal refs from the server. This is possible with Gitlab versions above or equal to 11.6 (see said doc).

These are the main steps :

  • install git-filter-repo
  • download all git references from Gitlab by exporting the project
  • then loop these steps :
    • update the repository contents with git filter-repo
    • upload the modified contents
    • cleanup dangling references When this is done, the Gitlab project will be purged of all references to those old commits.

a word of warning

Beware that any local copy of the repo made before this will still contain the deleted commits. Also, users trying to pull from those old local copies will end up in a mess.

the detailed process

  • install git-filter-repo
  • export the project from Gitlab following the Gitlab export doc: go to Settings->Advanced, click the Export project button, follow the link you receive by email to download the export
  • create a temporary folder and jump to it : mkdir tmp && cd tmp
  • unpack the exported archive : tar xf path/to/downloaded...export.tar.gz
  • clone the project bundle : git clone --bare --mirror export.bundle
  • copy all expressions that you want changed to expressions.txt

Example content :

a_sample_password==>DELETED
  • jump to the cloned repo : cd project.git
  • update the origin remote : git remote set-url origin YOUR_REMOTE_ORIGIN
  • run git filter-repo --replace-text ../expressions.txt
  • go to Gitlab Settings->Repository->Protected and unprotect any protected branches
  • upload the results with git push origin --force 'refs/heads/*'
  • remove dangling commits with git push origin --force 'refs/replace/*'
  • wait 30 minutes
  • in Gitlab Settings->Repository, run Repository Cleanup with the file filter-repo/commit-map
  • re-protect the unprotected branches in Gitlab Settings->Repository->Protected

See more examples at git-filter-repo examples. Gitlab cleanup details are at Gitlab docs on repo cleanup. I made a sample repository to illustrate the process.

la Fleur
  • 426
  • 3
  • 11