git-add-nonsub

View script Copied!

Stage a git repository inside another git repository without treating it as a submodule.

Git has a feature called submodules for linking one repo into another: when you git add a directory containing its own .git, git records only a pointer to a specific commit in the inner repo, not the actual files. Submodules are powerful but add workflow friction (everyone cloning the outer repo needs to run git submodule update to fetch the inner contents; updates require coordinated commits in both repos).

If you don't want that coordination overhead -- e.g. you've vendored a third-party library, you want to snapshot an external project's source into your tree, or you're copying code you'll modify independently -- you want the nested directory's files tracked as plain files in the outer repo. This script makes that work by temporarily moving the inner .git directory aside so git sees regular files during git add, then putting the inner .git back.

Quick start

From your outer repository's working tree:

$ git-add-nonsub vendor/some-lib
[INF][git-add-nonsub] Backup created at /var/folders/.../tmp.xxxxx
[INF][git-add-nonsub] Running git add on 'vendor/some-lib'...
[INF][git-add-nonsub] git add completed successfully
[INF][git-add-nonsub] Restored .git directory

Now vendor/some-lib is staged in your outer repo with all its files, not as a submodule pointer.

Common examples

Stage a vendored library:

$ git-add-nonsub third_party/react

Stage a cloned project you want to absorb:

$ git-add-nonsub lib/parsing-lib

Verify the directory has a .git before running:

$ ls -la vendor/some-lib/.git
drwxr-xr-x  13 user  staff  416 Apr 21 10:00 .git

$ git-add-nonsub vendor/some-lib

How it works

When you try to git add a directory that contains a .git subdirectory, git treats it as a submodule and only records a commit reference -- not the actual files. This script works around that by:

  1. Moving the nested .git directory to a temporary location
  2. Running git add on the now-.git-free directory (so git sees regular files)
  3. Restoring the .git directory to its original location

The inner repository remains intact and functional after the operation completes. You can continue working in it or remove the .git entirely if you no longer need it as a separate repo.


Reference

All options

Flag Description
directory Path to a directory containing its own .git subdirectory
-h, --help Show help message

Exit codes

Code Meaning
0 Success
1 Runtime failure (backup, restore, or git add failed)
2 Usage / precondition error (no directory, directory doesn't exist, no .git found, not inside a git repo)
130 Interrupted (SIGINT/SIGTERM/SIGHUP); emergency restore attempted

Dependencies

Warnings

Do not interrupt the script while it's running. If the script is killed after moving .git but before restoring it, your nested repository will be in an inconsistent state (its .git directory will be in a temp location). The script prints the temp directory path when it creates the backup -- you can manually move it back if needed.

Do not run on uncommitted work in the nested repo. The script doesn't check the inner repo's status before proceeding. If you have uncommitted changes in the nested repository, consider committing them first or understanding that you're staging whatever state the working tree is currently in.

This doesn't remove the inner .git permanently. After running this script, the nested directory still contains a .git subdirectory -- it's just been added to the outer repo. If you commit and then run git status again, git will still see the nested repo as a potential submodule. If you want to fully absorb the nested repo, you'll need to remove its .git directory manually after running this script.