The ideal solution would be to track my patch using Git, but at the top-level
(e.g. directly on main, not on foo). Theoretically, it would be possible to
add a blob on the Git tree that points into the submodule location:
Even if this is doable, personally I find it very convoluted. Unless this was
implemented natively and included user-facing commands that make it easy to
understand and manage, I'd stay away from it.
Alternative 1: Patch
Is there are more elegant/streamlined way of doing a patch in a git
submodule, other than the accepted answer?
If you would like to avoid messing with the submodule at all, I would suggest
copying over/checking out the worktree somewhere else and using only that
during the build. That way, the submodule is always "clean" (and perhaps
"immutable", from main
's point of view) and you only have to worry about it
in the build directory.
Simplified build process example:
cd main
mkdir -p build
cp -R foo/ build/
cp myconfig.patch build/
cd build
patch <myconfig.patch
make
Note that this builds only foo
, and that main
's build process does not need
to be altered besides having to point to build/
instead of foo/
.
If you do not intend on modifying foo
itself/would rather keep it "pristine",
you could also turn it into a bare repository and use
GIT_WORK_TREE="$PWD/build" git checkout HEAD
instead of cp
, so that it is
only checked out during the build. This is similar to how
makepkg(8) does it (at least in my experience with the AUR) in order
to avoid modifying the original sources ($source
array vs $srcdir
). It
also splits source retrieval from the build itself (prepare()
vs build()
).
See also PKGBUILD(5) and Creating packages.
In your case, development and an IDE are also involved, so it might be trickier
if you want to inspect both the original and the build files at once.
Pros:
- Sources are separated from the build files
main
does not affect foo
- Does not depend on git/makes it merely a build automation issue
- Only requires a patch file
Cons:
- Need to keep the patch file updated (vs rebasing changes)
- Need to change the build process
I'd go with this one if your patches are small and/or very specific to main
.
P.S.: It is possible to go one step further and track foo
's version
directly in the build process instead of using submodules if you wanted to:
Move foo
one directory up, then in the build process:
cd build
GIT_DIR='../../foo/.git' git checkout "$myrev"
patch <myconfig.patch
make
Alternative 2: Separate Branch
Also, when I update foo to the latest version, I will have to cherry-pick the
patch too which introduces a lot of noise in foo's history.
You don't really have to cherry-pick it, you could just keep the changes in
your branch instead and merge master
every once in a while.
Personally, I would avoid this unless your changes are much more significant
than the noise caused by keeping it in sync (i.e.: the merges and conflicts).
I find merge commits to be very opaque, especially when conflicts are involved,
as unrelated/accidental changes are harder to detect.
Rebasing your commits onto master
is also an option.
Pros:
- No need for a separate repository
- Keeps the worktree in the same place (no need to mess with your IDE)
Cons:
- Pollutes
foo
's repository with unrelated commits (when merging)
- Pollutes
foo
's repository with unrelated commit objects (when rebasing)
- Murky history of the evolution of your changes to
config.h
(when rebasing)
Alternative 3: Soft Fork
Also, when I update foo to the latest version, I will have to cherry-pick the
patch too which introduces a lot of noise in foo's history.
Unfortunately, this is a very bad approach because I am making changes to foo
that only matters to main
If you want to change foo
to suit main
, but not mess with foo
upstream,
why not create a soft-fork of foo
? If you do not care too much about
foo-fork
's history, you could just commit your changes on the main-project
branch and keep it in sync with foo
's master
through rebase:
Creating the fork:
cd foo
git remote add foo-fork 'https://foo-fork.com'
git branch main-project master
git push -u foo-fork main-project
Keeping it in sync:
git checkout main-project
git pull --rebase foo/master
# (resolve the conflicts, if any)
git push foo-fork
Pros:
- Easy to sync with upstream (e.g.: with
pull --rebase
)
- Keeps the worktree in the same place (no need to mess with your IDE)
Cons:
- Murky history of the evolution of your changes to
config.h
(because of
rebasing)
The added benefit of using a patch instead of rebasing is that you keep the
history of the patch. But if you want to keep things really simple sync-wise,
I suppose that this is the way.
Alternative 4: Hard Fork
If you find that foo
changes too much/too often and/or you need to patch too
many things, your best bet is probably creating a full fork and cherry-picking
their changes instead.