Search code examples
gitgit-commitgit-dangling

git: Are these dangling commits?


Given at the end is an extracted screenshot from a SourceTree branch tree view (there is a gap in the middle of the screenshot)

In that, #1 points to the line which used to be branch 1.7.6.14.X and #2 points to the current status of the same branch.

The commit referred to by #3 and the preceding 8 commits on that line were previously attached to branch 1.7.6.14.X. Then another developer supposedly checked out the same branch and did the fix pointed to by #4. This #4 commit has removed the former 9 commits from branch 1.7.6.14.X and left them dangling.
As a result, the branch 1.7.6.14.X now starts from the original branching point instead of just extending from commit #3.

Running git fsck with --unreachable, --dangling etc doesn't give any errors. I tried --lost-found as well.

However, git fsck <hash of commit #3> produces five dangling commits and a whole bunch of dangling tags:

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3148/3148), done.
dangling commit ec213...
dangling commit ab82a...
dangling commit 7d262...
dangling commit a6f06...
dangling commit 6674a...

I have two questions:

  1. What could have caused this situation (i.e. branch #1 getting detached)?

  2. How can I detect whether there are similar issues in other repositories? (without having to know the hashes of detached commits such as #3)

Commits detached from branch

Update:

We found the answer to question (1). The situation was caused by a force push, to the central bare repo, by a developer who had an older snapshot of the branch.


Solution

    1. as you said; this is caused by using git push --force
    2. Since all your commits are attainable with a tag; git will never say that hey are dangling, since they are not. They will never be lost nor cleaned up since a tag refers to them.

    As to how to find these (for lack of a better word) dangling commits; I didn't find anything purely git, but I came up with a small script that allows detecting them. There might be a way to make this more performant, but is does the trick:

    for sha in $(git log --all --pretty=format:"%H")
    do
        if [ -z "$(git branch --contains $sha)" ]
        then
            echo "commit not on a branch: $sha"
        fi
    done
    

    note I know that the test -z "" isn't very clean, but the return value of git branch is always 0...