0

I noticed that after doing some git actions some commits are lost, as expected, but are still visible on github with the error: This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

To reproduce what I did:

  1. repository is now: A -> B -> C
  2. soft reset to commit A
  3. redo commits B and C as B(mod) and C(mod)
  4. repository is now: A -> B(mod) -> C(mod)
  5. force push to github
  6. now commit B and C can't be seen in rep history but are visible on github with above specified error

(example link where I can see it: https://github.com/user/rep/commit/B ;
while https://github.com/user/rep/commit/B(mod) appears with the expected modification)

  • what could be causing this?
  • does the rep contains the commits B and C or not? if yes, how can I delete them/clean the rep?

thanks

cory
  • 17
  • 4
  • To truly delete a commit and be certain its gone, you probably need to contact support. github has undo support and probably does garbage collection – Evert Sep 23 '21 at 23:13
  • https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository – dave Sep 23 '21 at 23:15
  • https://stackoverflow.com/a/32840385/7976758 Found in https://stackoverflow.com/search?q=%5Bgithub%5D+removed+commit+still+visible – phd Sep 23 '21 at 23:41

1 Answers1

0

A branch or a tag is a name that applies to a single commit. That commit is a named commit. What keeps a commit alive is that it is the parent, or the parent of the parent, or... [and so on] of a named commit.

Okay. Resetting your branch back to A means that the branch name applies now to A, not to B or to C. So there is nothing keeping B or C alive any more.

But they are not immediately destroyed either. The policy is that such commits remain until they are garbage collected. If you used the reflog you would find that they still exist on your local machine as well. It's rather like how on your computer you don't just delete a file; you put the file in the trash, and you empty the trash later. Well, Git empties its trash eventually.

You can delete them from your machine by forcing a garbage collection now. But you can't do that at GitHub; it doesn't belong to you. If you just wait, they will be destroyed on GitHub eventually.

If the matter is urgent to you, then fetch to your local repository and delete the GitHub repository altogether. Make new GitHub repository and mirror your local up to it.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • thanks for the clear answer! how can I see what commits in my rep are in the "trash"? how can I force a garbage collection? – cory Sep 24 '21 at 07:32
  • I executed `git gc --aggressive` but nothing seems to be changed and if i execute `git show B` the commit is still there – cory Sep 24 '21 at 09:03
  • Did you say `git gc --prune=now --aggressive`? Are you sure B is unreachable from any other branch or tag name? – matt Sep 24 '21 at 14:28
  • 1
    Note that GitHub do not promise to delete these objects in any sort of reasonable time frame by default. You really have to contact GitHub support (or use the delete repo method). Locally, you need to expire reflogs before running `git gc`. (Well, you can expire them *while* running `git gc`, I think. Have not tested.) – torek Sep 24 '21 at 18:48
  • 1
    @matt I now executed `git gc --prune=now --aggressive` which I think removed a so called "dangling blob" but the original B anc C commits were untouched. how can I check if commit B and C are reachable? – cory Sep 25 '21 at 16:25
  • @matt I executed `git fsck --unreachable --no-reflogs` which outputted different commits (with B and C included, a few tree objects and a blob object) – cory Sep 25 '21 at 16:32
  • Yeah, it sounds like these are unreachable. You could confirm by examining `git log --all --reflog --graph --oneline` I think – matt Sep 25 '21 at 16:35
  • @torek thanks for the info! How can I expire the reflogs? I'm not that interested in cleaning the github rep... but want to understand how to clean my local one. (anyway it seems strange that if i change/clean my local rep, the remote one is unaffected... how is it possible?) – cory Sep 25 '21 at 16:35
  • "it seems strange that if i change/clean my local rep, the remote one is unaffected... how is it possible" Because the only thing you can push is a commit. You cannot push "is not a commit". That is why I suggested deleting the remote repo. – matt Sep 25 '21 at 16:37
  • @matt a ok thanks for the clarification! I actually just tried cloning the rep from github and it seems that the commit does not exist, but in my original folder and on github the commit is there – cory Sep 25 '21 at 16:43
  • Well that's not new news. And that proves that my delete and mirror advice works. Which is also not new news. – matt Sep 25 '21 at 16:44
  • @matt thanks for the advice I'm not a git wizard... `git fsck --unreachable --no-reflogs` applied on the freshly cloned rep shows no unreachable commit so i think I'll fix this issue in this way... I still don't understand why the fresh clone is "clean" while the original rep and the github web interface still have the unreachable commits – cory Sep 25 '21 at 16:55
  • So you did https://stackoverflow.com/a/4528593/341994 but it still shows in your reflog? That's weird – matt Sep 25 '21 at 17:04
  • "I still don't understand why the fresh clone is "clean" while the original rep and the github web interface still have the unreachable commits" Because they are unreachable, so they are not part of the clone. – matt Sep 25 '21 at 17:04
  • ok thanks a lot! this link might be useful for future reference: https://stackoverflow.com/a/4528593/12336465 – cory Sep 25 '21 at 17:25
  • Cool, added that link to my answer. – matt Sep 25 '21 at 17:34
  • @cory: to expire reflogs, use `git reflog expire`. Note however that the *default* is 30 or 90 days. Run `git reflog ` to dump out the reflog entries for the given , and note the date-stamps on each reflog entry: if the entry is less than 30 or 90 days old, it won't expire, *unless* you set the `--expire=` or `--expire-unreachable=` time value to something different. See the documentation (`git help reflog`) for more. – torek Sep 25 '21 at 20:11
  • The one part that is kind of inexplicable from the [reflog manual page](https://git-scm.com/docs/git-reflog) is when a reflog entry has a 30 day expiry, and when something has a 90 day expiry. Clearly it has something to do with `expire` vs `expire-unreachable`, but what? The answer to *that* starts with reading [Think Like (a) Git](http://think-like-a-git.net/). Once you've read and digested that, it should become clear. – torek Sep 25 '21 at 20:14