views:

1194

answers:

11

I'm using git for a PHP project, I think it's really handy. There is one thing that would be great if I get it to work.

I have created a branch, meant for deployment. It has some differences, like different configuration files and documentation.

I can't just ignore them, because then they will stay in both branches, while i would like to keep them different in both branches.

The problem is that when i merge the branches, those files that are meant to be different are merged too.

Is there any convenient way to accomplish such a thing? How is this normally done?

+3  A: 

Quick answer is, don't ever merge the branches. In fact you don't need to merge them at all, just merge from development (aka "master") to deployment to merge fixes and generic changes.

Keltia
I'm not really getting it. Don't merge, but just merge. Do you mean just merge one way?
Ikke
I think he's saying: Keep your deployment-specific files in branch B, keep local config files in branch A, do development in the master branch. Merge from master into A for testing, from master into B for deployment; never merge from A or B into master.
Paul
Exactly: I mean, don't merge the branches together, merge individual changesets between branches.
Keltia
+5  A: 

I am not sure Git is meant to be used this way.

First a quick Linus advice, always "colorful" and informative ;)

Git very fundamentally tracks project state, not file state. Which means that you very much can NOT try to "merge a file". It is a senseless operation in git, and in fact, any SCM that allows it pretty much is doomed to be a total piece of sh*t (*).

(*) And I'm not saying that just because git doesn't do it. It's much more fundamental than that. Once you start doing per-file branching and merging, you've basically screwed yourself, and you'll never be able to work on the project as a "whole project" any more - you no longer have a well-defined history that actually is the history of the whole project.


There.

That said, you could:

  • manage those config/doc files a separate git sub-projects (note: the use of submodules has been discussed here)
  • or record partial merge (using "ours" strategy for files we don't want to merge), then --amend it.


Other solutions in this thread involve working on a "server-specific" branch on your deployment server

Development        Deployment

#origin/master:
x--x               $ git clone

                   # master
                   x--x

                   $ git checkout -b deployment origin/master

                   x--x
                       \ 
                        -- #deployment

                   $ .... #makes changes for config files
                          #or other specific deployment files

                   x--x
                       \
                        --d1--d2 # no need to push that branch ever.

#new developments
x--x--x--x

                   $ git pull --rebase #pull origin/master and 
                                       #replay current branch on top of it
                   x--x--x--x
                             \
                              --d1'--d2' #SHA1 rewritten in deployment branch
                                         #not important since this branch 
                                         #is not pushed (published)
VonC
+1  A: 

If you want to keep your history nice, you can keep the deployment files in some commits on top of your clean branch. Then, when it's time to deploy a new version, you check out the deployment branch and 'git rebase master', to put those commits on top of the original branch.

That way, you can also make easy changes to the configuration files, and change the top commit with 'git commit --amend'.

Pieter
A: 

I do some silly tricks like:

  • Have the app read file config
  • Add config.development and config.production but not config to the repository
  • Have your deploy script not only clone the repository, but also then cp config.production config

Does that make any sense?

It works okay for me.

elliot42
I don't really have deploy script, but i have solved it to make a config.template.php and a config.php and then let git ignore the config.php
Ikke
A: 

currently i have a couple of patch files checked in, and the build server applies those patches for the relevant versions. though i'm having second thoughts about it at the moment

Tim Abell
+1  A: 

I mentioned earlier patch files. I've gone off this now, and instead maintain deployment branches.

ie, I branch off master with a new branch named 'master-deployed', and make changes on that branch that I need to be only in the test version on the build server (i.e. adding a warning that this is not the live version, and different db server in web.config).

The build server when building the bleeding edge version then checks out master-deployed, and rebases it onto origin/master before performing the usual build. If no-one has made any conflicting changes then everything is fine. If they have then I can't see any system handling this without manual intervention.

Same goes for tip of qa, which has a branch 'qa-deployed'

I use the --onto flag to make sure if a whole branch is rewritten then the patch doesn't take all the old commits with it.

So on the build server the qa build looks something like

git reset --hard
git clean -xfd
git checkout -f qa-deployed
git rebase --onto qa HEAD^ qa-deployed
build-script
Tim Abell
+1  A: 

I had a similar problem and created a tiny project called config-magic to help manage this.

Config-magic lets you create template conf files and then profiles of data for each of dev/staging/production. You then run "cfg dev" to produce the "dev" config files, "cfg staging" to produce the staging config, etc.

I then have this wired up with scripts, so that when I deploy to staging, I locally run "cfg staging" then scp over all of the config files after updating the codebase from git.

The "actual" config files are set to be ignored by git. This has worked really well for me so far.

https://github.com/apinstein/config-magic/tree

apinstein
+5  A: 

This works for me, and I make only minor configuration changes to deploy (3 lines in config files).

  1. Clone your repository from GitHub or wherever you keep it. To where you wish to deploy.

  2. run git checkout -b deployment origin/master

  3. Make your changes (push them if you like).

  4. Whenever your master (or whatever branch you made the deployment from) has changes you want to deploy, simply git pull --rebase.

It's a simple solution and it certainly works for me, I can't speak to wether or not it this makes it "shi*t" as others suggest, but it is certainly very useful for our purposes.

arbales
On second thought, I would avoid doing this because it's needlessly complex. Instead use SetEvn in your .conf file to set environment variables that affect/determine your configuration. For example, on my development server my site's DATABASE_URL='mysql:root@localhost/bla' and on production it could be DATABASE_URL='mysql:app@localhost/appdb'.
arbales
+1  A: 

I was thinking about all of these solutions for my situation but none of them seem to apply. I edit both on my live and development servers. Rebase works well if you dont need to republish that branch, but I make changes on my deployment branch and publish those back to the main repository. The submodule way only works if your files are in a seperate subdir, my config files are in several places. The merge ours method wouldnt work so well also since i'd have to pull that branch first and then the big branch. Maybe it would work if there was still a merge theirs and I could pull in the proper configuration branch when needed. For now a .gitignore works and I just manually upload the files.

After doing more research I've found my solution to not have a git repo on the live site but use a staging site to pull the latest changes into my branch with the staging/live config files. and then deploy by git archive and extracting the files onto my live site.

kzap
A: 

cherry-pick seems to work for this for this (at the expense of polluting the logs a bit).

git checkout -b testing make changes and commit git checkout master git checkout -b deploy make changes and commit git checkout master

do everything under master and git cherry-pick testing or git cherry-pick deploy to apply the diffs needed to switch from the current system into the testing or deployment version.

David