Reputation: 1915
I essentially want to mark a commit in branch B as merged in master so when I (eventually) merge from B back to master, I don't have to reverse those edits. I've tried both cherry-pick and merge --strategy=ours
. (How to avoid pushing 'branch-specific' files to master branch? doesn't ask this question.)
Take a simple code repo which has a corresponding .../tests repo for tests. travis.yml
clones the .../tests repo for running tests. It has some random commits on master and B:
git init
echo '... git clone --branch=master .../tests' > travis.yml
echo a > a.txt
git add . && git commit -m "master has a.txt and a travis.yml"
git checkout -b B
echo b > b.txt && git add . && git commit -m "B has b.txt"
Now I want travis.yml
to grab tests from a parallel branch in a tests repo.
In a separate commit, I update travis.yml
to checkout B in the test repo:
echo '... git clone --branch=B .../tests' > travis.yml
git add . && git commit -m "B tests on .../tests branch B"
Now I want to mark this commit as merged in master. cherry-pick doesn't work 'cause it only has one parent:
git checkout master
git cherry-pick --no-commit --strategy=ours B
git commit --allow-empty -m "cherry-pick B's tests but keep ours"
This did not have the desired effect of adding the last commit on B to master's history as cherry-picks have only one parent:
git log --abbrev-commit --parents --oneline -1
ee71621 46bf9bb (HEAD -> master) cherry-pick B's tests but keep ours
This problem manifests later when we are ready to merge B, which will tromp our travis.yml with its own:
git merge B -m "absorb B's wisdom"
cat travis.yml
... git clone --branch=B .../tests
So much for cherry-pick, let's try using a temporary branch. Rewind master and B to before I monkeyed with B's travis.yml:
git reset --hard master~2
git branch -f B B~1
Create a temporary branch with the desired edit:
git checkout -b B-tmp
echo '... git clone --branch=B .../tests' > travis.yml
git add . && git commit -m "B tests on .../tests branch B"
Merge B-tmp into B and merge it into master with --strategy=ours
:
git checkout B
git merge B-tmp -m "merge B's branch-specific changes"
git checkout master
git merge --strategy=ours B-tmp -m "keep master's changes"
HEAD now has two parents:
git log --abbrev-commit --parents --oneline -1
a8c0375 166af70 3f661f8 (HEAD -> master) keep --branch=master on master
but the next time I merge master back to B, it tromps travis.yml
:
echo aa > a.txt && git add . && git commit -m "aa"
git checkout B
git merge master -m "fetch changes to a.txt"
cat travis.yml
... git clone --branch=master .../tests
I've effectively moved the problem from remembering to update travis.yml
once (when B's merged back to master) to having to update it every time I have to keep B up-to-date with master.
What's an elegant way to accomplish this (besides sticking a post-it on my monitor)?
[[ Edit:
In light of the "git doesn't do that" answer, I added .git/hooks/pre-commit
to tell me when I'd merged something inappropriate into master:
if [ $(git rev-parse --abbrev-ref HEAD) = "master" ] && test $(grep git\ clone travis.yml | grep branch=master | wc -l) != 1
then echo "should be testing on master" ; exit -1
fi
]]
Upvotes: 0
Views: 61
Reputation: 487765
What's an elegant way to accomplish this (besides sticking a post-it on my monitor)?
There isn't one, in general. There might be one for your specific problem.
The "Git way" to deal with files that should be similar, but not identical, in different commits at different branch-tips is to use multiple files. This works really well and avoids all these headaches ... except when the file name has to be one specific name, common to all branch-tips, to satisfy some external software.
You can often, but not always, work around that by having a Git hook run in post-checkout and/or post-merge to create, as an untracked file, the specific name that the other software demands. This clearly does not work for travis.yml
, since that file must be present in the commit that Travis-CI is using.
However, the build
step in a travis.yml
can include commands that create and then use untracked files, and can inspect the repository in various ways. So you can write up a build script that looks at "what is to be built" and from there, chooses files that depend on what you are building.
In short, don't even attempt to put the full set of rules into travis.yml
itself directly. Instead, have travis.yml
grab additional rules from branch-dependent files. This may mean giving up some handy Travis feature in favor of re-coding it yourself.
Upvotes: 1