We are currently in the process of consolidating many of our packages for a large
project into a single project.core
package. We do this in order to simplify the
dependency graph, testing, GitHub workflow and general maintenance. These are
packages that we first decided should be optional, but now have grown to be such
integral parts of the system that we have to have a hard dependency on them anyway.
We already merged packages with the structure
project.base/project/base
project.journal/project/journal
project.search/project/search
...
into a single egg project.core
that looks like
project.core/project/base
project.core/project/journal
project.core/project/search
...
So the former eggs will now be python subpackages inside the one project.core
egg, project
being a namespace package.
In a perfect world, that massive subtree merge (kudos to senny and jone!) would be the end of it and we would switch to the new package’s repo immediately and deploy the new codebase at all our clients’ sites at the same time.
But since that’s not possible, we’ll have a short time window where we’ll be working on the new repo, but also have to backport changes that need to be pushed to deployments to the old repositories.
Because the new subpackages still have the same location relative to the containing egg, their dotted names and therefore the imports don’t change. This should make for very easy backporting of those changes by simply applying the changeset’s patch to the respective old repo.
However, a few paths did change, so for atomicity’s sake git fails the whole patch when some of the hunks don’t apply, and doesn’t modify the working tree at all:
1 |
|
error: patch failed: docs/HISTORY.txt:4
error: docs/HISTORY.txt: patch does not apply
Yeah. Whereas before each package had its own docs/HISTORY.txt, now there’s
only one in the new project.core
package, and its structure doesn’t match
(git can not locate the couple of lines of context that surround that hunk). Bummer.
Especially because I know that 90% of that patch would apply cleanly.
That’s where git apply --reject
comes in. Git will apply all the hunks it can, and
leave the rejected hunks in corresponding *.rej
files:
1 |
|
Checking patch docs/HISTORY.txt...
error: while searching for:
3.0 (unreleased)
----------------
- Some changelog context that doesn't exist in the new file...
[some_guy]
error: patch failed: docs/HISTORY.txt:4
Checking patch project/search/portlets/configure.zcml...
Checking patch project/search/portlets/search_portlet.py...
Applying patch docs/HISTORY.txt with 1 rejects...
Rejected hunk #1.
Applied patch project/search/portlets/configure.zcml cleanly.
Applied patch project/search/portlets/search_portlet.py cleanly.
So the resulting working tree looks like this:
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: project/search/portlets/configure.zcml
# modified: project/search/portlets/search_portlet.py
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# docs/HISTORY.txt.rej
no changes added to commit (use "git add" and/or "git commit -a")
All that’s left to do is to manually merge the change from docs/HISTORY.txt.rej
into docs/HISTORY.txt
and remove the *.rej
file.