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:
What could have caused this situation (i.e. branch #1
getting detached)?
How can I detect whether there are similar issues in other repositories? (without having to know the hashes of detached commits such as #3
)
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.
git push --force
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...