Question

I have two branches that are different enough that rebasing seems to not work -- or I don't know how to do it.

I have a "public" branch with a bunch of files removed (using filter-branch). Even though most of the commits match up in terms of deltas, the commit ids are all different. I've tried quite a few methods to pull changes from my dev branch to my public branch... I find it hard to believe it can do what I want it to do -- but I suspect I just don't know how to do it. In any case, this works fine, but seems wrong.

git checkout dev
git format-patch --stdout last_sync_tag > catchup.mbox
git checkout public
git am catchup.mbox
git --skip # talks about a missing file
git --skip # talks about a missing file
git --skip # talks about a missing file

Any tips or suggestions, which will probably include not filter-branching out files you don't want on the public branch (though, how do you then get rid of them?), are welcome.

My tree(s) look more or less like this:

dev: a-b-c-d-e-f-g-h-i-j-k
pub: t-u-v-w-x

t ≅ a, u ≅ c, v ≅ d, w ≅ e, x ≅ g. i,j,k are new patches I'd like to move over.

checkout pub
rebase --onto pub i  # I really expected this to work
Was it helpful?

Solution

Git's cherry-pick command may be useful. I haven't used it in your situation but I think it should work. The only pain is that it's not designed to work over a range of commits so if you want to script/automate it you'd have to use something like git rev-list.

Again, I haven't tried this but a bash script like this may give you a good starting point

git checkout public
for rev in $(git rev-list --reverse last_sync_tag..dev) ; do
   git cherry-pick $rev && git tag -f last_sync_tag $rev || exit 1
done

OTHER TIPS

Do you regularly maintain the files on your dev branch that aren't on public? Or are they just hanging around?

If you don't tend to make changes to them, and you're OK with rewriting the history a bit, what you could do is arrange to have them created as a single commit based on your public branch; and merge that back into public but with "-s ours" to stop them actually getting in. (previous answer about git merge -s ours)

Something like:

git checkout -b dev public
git am create-dev-only-files.patch
git checkout public
git merge -s ours dev
git checkout dev
# write more dev patches...
git checkout public
git merge dev
# and this should merge in the patches without bringing in the
#  dev-only files

So if you then made subsequent changes on your dev branch and merged them into public, if you're not changing those files that aren't on public, everything else will simply apply. But if the set of files you want to suppress on public changes, this could be tricky. You could try to prevent it by adding a pre-commit hook to unstage particular files before starting any commit on the public branch, for example.

Because you've used "filter-branch" you're going to have to help git find the correct commit to perform the rebase onto.

I'm going to guess here, but presumably you have an 'almost' common commit which has two versions, the head of your public branch and the place on your dev branch that this commit corresponds to (un-filtered). Call the public head commit <PH> and the dev commit that this corresponds to (before filtering) <DevPH>.

with the dev branch checked out, you want to do something like this:

git rebase --onto <PH> <DevPH>

This tells rebase to take the patches introduced by each commit since <DevPH> on the current branch and to apply these commits to <PH>. I think that this is what you need.

Edit:

Your update to the question shows that h is equivalent to the head of the public stream on the dev branch and that you want to transplant everything from here onwards on the dev branch onto the public branch. If so the command is

git rebase --onto pub h

Well if I don't want a fileit lands in .gitignore. Probably it is the config not real code so it doesn't need tracking at all.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top