I am working on my first project using git and have ran into an issue.
The repo contains a a client/serve开发者_C百科r app. I have a 'master' and 'test' branches, with the intent that master is always the same as what's deployed.
My problem there are 3-4 places in the codebase where the server URL is stored. I want to change this in the 'test' branch, but not in the 'master' branch. The problem is, of course, that whenever I want to merge back to 'master', git wants to put this change in 'master'.
I can do a selective merge and merge all the commits but the one in question, but this seems tedious to do for every single merge. What's the best way to do this?
I've never had this problem in any SCM, so maybe I"m just going about this all wrong.
You want to merge in that change as not being actually merged, but mark it so in history. This way you will know from where to get subsequent changes.
There are a couple of ways to do this. One is
git checkout master
git merge -s ours --no-ff testing
git checkout testing
git merge -s ours --no-ff master
or
git checkout master
git merge testing --no-commit --no-ff
git checkout HEAD -- .
git submodule update # this is optional and only needed if you have submodules
git add -A
git commit
git checkout testing
git merge master --no-commit --no-ff
git checkout HEAD -- .
git submodule update # this is optional and only needed if you have submodules
git add -A
git commmit
Now you have 2 branches with differing configs but those commits are before the important merge-base
.
Now you need to script something like this to do the special merge, which is really a rebase underneath -- that's the only way to ignore what happened before:
git checkout master
git merge --no-ff -s ours testing
git checkout -b temp testing
git rebase -s recursive -Xtheirs master # these are the conflicts we care about
git reset --soft HEAD@{2}
git add -A
git submodule update
git commit --amend -C HEAD@{2}
git push . +HEAD:master
git checkout master
git branch -d temp
This just rebases what you don't have on master in branch testing and makes it look like a merge. Because it stores it as a merge, you can subsequently run this against other branches you want to publish to master. So you could separate all those commands with &&
s, replace testing with an argument, master with the second argument variables and alias it:
git config alias.smart-merge '...'
so that you can publish changes like so:
git smart-merge testing master
git smart-merge feature2 master
which should give you both testing and feature2 no matter at which point those 2 may have been merged in history already.
Also consider enabling rerere as the script expects no conflicts. So if you do want to publish, you can do a regular rebase first, recording conflict resolutions. Now you can alter the script to take advantage of those and not break on conflicts.
Rebase conflict resolution can be a pain. But not in this case as we only use master to publish. Other branch manipulation is still done via regular merge or rebase.
-- OR --
The non trivial is smudge clean scripts. Take a look at the git attributes chapter in progit.org/book.
Hope this helped.
git cherry-pick
would allow you to do that (although you'll need to select the commits to merge (and make sure you don't forget any)
Another way is that you can git revert
the commit(s) that changed the URL, merge to master and then put it back in your master branch.
Yet again another way is to do git commit --no-commit
, then change the file, git add
it before commit.
Another method that maybe would avoid to "forget" it is to have this kind of configuration (the URLs and such) into a separate file and add that file into the .gitignore...
I don't think any of those are really elegant, but it would work...
精彩评论