3

I have a config file in our project that holds a connection string to the database, as well as several application settings, e.g:

...
<setting name="ConnectionString"><value>Server=prodServer;Database=myDataBase;</value></setting>
<setting name="AnotherSetting1"><value>Lorem</value></setting>
<setting name="AnotherSetting2"><value>Ipsum</value></setting>
<setting name="AnotherSetting3"><value>dolor </value></setting>
...

During my development, I always change the ConnectionString value to my local database which causes git to put the file mark the file as "modified".

I read about the option of doing the following:

git update-index --assume-unchanged app.config

However, that would mean that if I do ANY other change to the file (e.g, change AnotherSetting1) then git would ignore that as well.

Is there a way to tell git to ignore a specific change in file, but to mark it as modified if any other changes occur? Or is there another similar solution to this problem?

Please assume that I can't make any changes to architecture of the config file itself - I'd like a local-only solution.

VitalyB
  • 12,397
  • 9
  • 72
  • 94

4 Answers4

6

filters are made for stuff like this. In your repo,

cat >.git/info/saved-connection <<EOD
<setting name="ConnectionString"><value>Server=prodServer;Database=myDataBase;</value></setting>
EOD

cat >.git/info/my-connection <<EOD
<setting name="ConnectionString"><value>Server=myprivateserver;Database=myDataBase;</value></setting>
EOD

git config filter.use-my-connection.smudge 'sed -f ".git/info/use-my-connection.smudge"'
git config filter.use-my-connection.clean  'sed -f ".git/info/use-my-connection.clean"'

cat >.git/info/use-my-connection.smudge    <<EOD
/^<setting name="ConnectionString">/ {
     w .git/info/saved-connection
     r .git/info/my-connection
     d
}
EOD

cat >.git/info/use-my-connection.clean     <<EOD
/^<setting name="ConnectionString">/ {
     w .git/info/my-connection
     r .git/info/saved-connection
     d
}
EOD

echo >> .git/info/attributes     path/to/app.config filter=use-my-connection
jthill
  • 55,082
  • 5
  • 77
  • 137
  • :-) glad it helped. I'd never used filters that way before, learned by doing here, thanks back atcha. – jthill Apr 11 '13 at 17:49
1

I do not think git has such facility. And the proposed way of managing the app.config file, treating part of the file version controlled and other part not, does not smell right to me.

In your situation I would seek a way to arrange the app.config to be generated from two files. The ConnectionString setting would be placed in user created (build) configuration file, and the other parts would be put in some sort of template file (conceptually speaking). The user created configuration file could be added to the .gitignore file. The template file would be controlled by git. We would need to have a method to build the app.config file by applying the settings in your build configuration file to the template file.

We are lacking background information about the development setting to tell how all this could be implemented. If you are using make or ant or similar thing, then this would be a simple dependency and rule to create the app.config to make sure the file is created if it does not exist or if the build config file or template file change. Also the natural choice for how to generate the app.config file from the template file depends on your build environment and the nature of the app.config file. For longer than couple of lines of text, even a shell script can be used for simple expansion of a given template file easily (couple of lines of lines to expand ${VARIABLE} constructs, but gets more complicated if the file needs to include dollar signs or back ticks or backslashes etc). More complicated expansion we could use eruby, or eperl or similar thing (even perhaps PHP). The app.config file could also be generated manually whenever you need to change the setting. But all this is somewhat useless speculation without further context.

FooF
  • 4,323
  • 2
  • 31
  • 47
  • Thanks for the answer, however, while I can't really change the config structure. Moreover, I was really just curious as to how I can solve it via git, or if it is at all possible. I believe I now solved it in another way (accepted answer). Please let me know if you see any issue in that. – VitalyB Mar 13 '13 at 14:31
1

Let me put some suggestions on how this might be done.

When adding changes to the index you can use git add -p app.config and manually skip some of the changes in your file. If you don't add changes to the index before doing commit these changes would not be committed. This is a kind of 'local-only' solution. But it might be really boring to always see the file modified in git status report.

All other suggestions might require changes in the architecture and there for can not be considered as 'local-only' solution. Anyway I think they might worth reviewing.

The main idea for all changes is to have local file added to .gitignore which contains local system specific settings. We have used several slightly different solutions here.

  • You can have properties file with key-value pairs containing all local system specific values. This file should be updated manually. Then it is used on the application and merged into the application configuration. Details depend on the tools you are using. But I do believe this should not introduce any big difficulties but most likely would require application changes.
  • You can have app-original.config file in git repository and app.config file in git ignore list. The app.config file should be created manually from app-original.config file.

What is really boring with all these solutions is that some manual work is required when the structure of config file is altered. For example on every config file update you should check if new properties have been introduced and update your local properties file. As well when you update your local file because of some application changes you need to remember to commit related changes in configuration files (remember your local files are in .gitignore).

smit patel
  • 129
  • 4
Victor Smirnov
  • 3,450
  • 4
  • 30
  • 49
  • Thanks for the insightful answer. I solved it in another way (accepted answer). Please let me know if you see any issue in that. – VitalyB Mar 13 '13 at 14:30
0

I think I found a good solution to this issue.

As I said, in my project there is a config file that (wrongly) stores the connection string inside that config file.

I'd like to be able to work with a modified version of the config but without having the file constantly in the "modified" files list and without completely ignoring all its changes.

Here is what I do

After I clone from our servers my log graph looks like so:

A---B---C master

All my development will be done in another branch, "development". So I branch it. Then I change the config file and change the connection string and commit.

A---B---C master, origin/master
         \
          X development

Next I checkout master and merge the changes back with "--nocommit" flag. Then in the merge commit, I revert the config changes and commit. In effect, I've created an empty commit that just serves as a notice to Git that these changes were merged and there is no need to merge them again.

A---B---C---D master, origin/master
         \ /
          X development

Now as I continue developing new features on the X, I can safely merge the changes back to master - Git will only try to merge back the new changes since the last merge.

A---B---C---D---E---F master, origin/master
         \ /       /
          X---Y---Z development

So in the example above, only the changes in "Y" and "Z" will be me merged back.

I've tried it and it seems to be working fine. It does mean, however, that whenever I switch to the master branch, I'm going to have the config with incorrect connection string, but since most of my development is done on "development" branch, it doesn't seem like a big issue to me.

If there is any issue with my solution, please let me know in the comments.

UPDATE

An issue with this is that if the config file is changed, in any way, on the "master", and then you merge "master" changes to the "development" branch, then the config file would get overwritten without warning.

VitalyB
  • 12,397
  • 9
  • 72
  • 94
  • 1
    Well, this seems like possible way to do if you cannot or do not want to change how your `app.config` is stored/built in the repository. Another way would be to do all your work in private `development`, and when want to merge your changes to `master` first do `git rebase -i master` on your `development` and move `X` to the top. Then on `master` simply do `git merge --ff development^`. Basically your commit `X` would be floating on the top and never merged to origin/master. The benefit would be to not have those ugly merge commits in your `master` (for `X` and subsequent merges). – FooF Mar 14 '13 at 05:48