Broken Gitlinks

Course 2 · Ch 10 · Final Chapter · Scenario
A Repo Gone Messy After a Reorg
Diagnosing and fixing nested repos and broken gitlinks/submodules — the full version of the incident introduced back in Course 1

Course 1, Chapter 9 introduced the broken-gitlink incident from the website→debserver reorg as a teaser — enough to recognise the symptom. This final chapter of Course 2 goes the rest of the way: what a submodule actually is when set up correctly, why a folder can end up tracked as one by accident, and the full diagnose-and-fix process.

Picking the incident back up

During the reorg, a subfolder that used to be its own separate git repository lost its .git directory in the move. The parent repository, however, still had a recorded entry treating that subfolder as a gitlink — git's internal mechanism for "this folder is itself a repository, tracked by commit reference rather than by its actual file contents." With the inner .git gone, that reference pointed at a commit that no longer existed anywhere reachable.

The result: git status on the parent repo showed a single confusing M website line instead of the real, individual file changes inside that folder — because git was treating the entire folder as one opaque unit, exactly as it would a properly configured submodule.

What a Submodule Actually Is, Set Up Correctly

A real git submodule is a deliberate, supported feature: embedding one git repository inside another, where the outer repo tracks which exact commit of the inner repo to use — not the inner repo's file contents directly. This is genuinely useful for shared libraries or vendored dependencies that need to stay pinned to a specific version.

$ # The correct way to add a submodule
$ git submodule add https://github.com/someone/shared-lib.git libs/shared-lib
Cloning into 'libs/shared-lib'...

This creates a proper .gitmodules file at the repo root, recording the submodule's URL and path — and the inner folder gets a gitlink entry (mode 160000, same mode flagged in Course 1, Chapter 9) that's intentional and documented.

The defining symptom of a real problem: a gitlink with no .gitmodules entry
A properly configured submodule always has a matching entry in .gitmodules. A folder tracked with mode 160000 but with no corresponding .gitmodules entry is the unambiguous signature of an accident — exactly what the reorg produced. This is the single fastest way to distinguish "someone meant to do this" from "something broke."

How a Folder Becomes an Accidental Gitlink

📦 A nested repo existed, then lost its .git
Exactly the reorg scenario — a subfolder used to have its own .git, something (a partial move, a cloud-sync quirk per Course 1 Ch9) removed it, but the parent repo's earlier commit of the gitlink reference remains.
Diagnostic: check if .git ever existed there — old backups, git history of the parent repo itself, or memory of past project structure.
🆕 A nested git init happened by accident
Someone ran git init inside a subfolder of an already-tracked repo (Course 1, Chapter 2's warning about this exact mistake) — creating a brand-new, unintended nested repository.
Diagnostic: does the subfolder's .git/ look freshly created, with little or no history of its own?
📥 A cloned third-party project was dropped in wholesale
Someone copied an entire other project — including its own .git folder — directly into a subfolder of the current repo, rather than removing .git or using a real submodule.
Diagnostic: does the inner .git's remote (git remote -v from inside it, if it still exists) point at a recognisable external project?

The Full Diagnose-and-Fix Process

1
Confirm the gitlink with git ls-files -s
Mode 160000 on the suspicious path confirms git is treating it as a separate repository (Course 1, Ch9's diagnostic command, repeated here as the entry point).
2
Check for a matching .gitmodules entry
cat .gitmodules (or note its absence entirely) — confirms whether this was ever intentional.
3
Check whether the folder's own .git still exists on disk
If it does, the fix may just be re-adding it properly as a real submodule, or removing the gitlink reference and re-adding the folder normally if it was never meant to be separate.
4
If accidental and .git is gone: decide whether the content needs tracking normally
Usually yes — the folder's actual files should just be ordinary tracked content in the parent repo, not a gitlink to nothing.
5
Remove the broken gitlink entry, then re-add the folder as ordinary files
See commands below — this is the actual fix for the reorg incident's specific situation.
$ # Remove the broken gitlink reference from the index (doesn't touch files on disk)
$ git rm --cached website
rm 'website'

$ # Re-add the folder's actual contents as ordinary tracked files
$ git add website/
$ git status
Changes to be committed:
new file: website/index.html
new file: website/styles/main.css
... (every individual file, now tracked normally)

$ git commit -m "Stop tracking website/ as a broken gitlink; track contents normally"

After this, git status shows real, individual file changes inside that folder again — exactly the fix this session's actual incident needed, demonstrated here as a repeatable, named procedure rather than a one-off troubleshooting session.

Prevention is simpler than the fix
Avoiding nested git repositories entirely — one .git per project, full stop, unless deliberately using a properly documented submodule — sidesteps this entire category of problem. When reorganising folders (Course 1, Chapter 9), explicitly checking for stray .git directories with find . -name .git -type d before and after a move catches this before it becomes a confusing future incident.

Chapter 10 Quick Reference — and Course 2 Wrap-Up

  • A real submodule always has a matching .gitmodules entry — its absence is the signature of an accident
  • git ls-files -s, mode 160000 — confirms a path is tracked as a gitlink, intentional or not
  • Common causes: a nested repo lost its .git, an accidental git init inside a tracked folder, a wholesale-copied third-party project with its own .git left in place
  • The fix: git rm --cached <path> (removes the broken gitlink reference) → git add <path>/ (re-tracks contents normally) → commit
  • Prevention: one .git per project; check for stray nested .git folders before/after any reorg
  • Course 2 recap: branching strategies (Ch1) → merge vs rebase (Ch2) → conflicts (Ch3) → forks (Ch4) → stash/cherry-pick/tags (Ch5) → issues/projects (Ch6) → code review (Ch7) → Actions basics (Ch8) → team-scale collaboration (Ch9) → broken gitlinks (Ch10)
  • Next: Course 3 — Advanced Git & GitHub Mastery (internals, interactive rebase, reflog, proper submodules, advanced Actions, security, large repos, bisect, and full disaster-recovery scenarios)