Conditional Mercurial Ignore File - deployment

I have a file in mercurial that I want dev machines to pull the file, but I want the deployment server to NOT pull the file (it has special mods to it that the dev machines don't have). Is this possible, or should I just have a custom push to server solution instead of just doing an hg pull?

A typical way to do this would be to do the following:
You store a copy of each file in the repository, and name them correctly. For instance, if the file in question is web.config, you would store the following two in the repository:
web.server.config
web.dev.config
Then you would add a built step to ensure the right file was copied to the actual web.config file, you could use a batch file:
if "%COMPUTERNAME%" == "SERVER" copy web.server.config web.config
if not "%COMPUTERNAME%" == "SERVER" copy web.dev.config web.config
Then you would ignore web.config itself through .hgignore:
glob:web.config

A variant of Karlsen's answer that I always use.
I have /config or /etc directory in the project. That directory will often contain sample configs like:
dev.yaml
ci_server.yaml
Then my apps pull from /etc/app.yaml which is a symlink to the correct config depending on the host it's being run on.
The best think about doing it this way is you don't have variant code paths (the batch script branches) which eliminates a potential bug vector. This allows you to exercise the same code path that will be used in production (down to where to look for the override file).

Is this something that can be solved outside version control? For instance, include the file in all copies of the repository, but enable or disable its use with environment variables or something similar. This doesn't sound like something most version control systems are built to handle, unless you use nasty hacks to do things like add/remove/patch files after updating.

One option is to create a special hgignore file for the deployment server, that could or could not be included in the repository. Then in the server's hgrc file specify the path to the special hgignore file with the ignore variable.
This would ensure that updates to file would be ignored by the deployment server but could still be updated as usual for the development machines.

Related

SVN - lock local changes for check in

I am working with eclipse subversion plugin, and made some local changes to crucial files, which I don't wan't to check in. I'm looking for a way to "lock" (I know that the lock term means something else in svn...) these local files and disable checking them in, so that I won't accidentally check them in.
Maybe you can just ignore them:
Team --> add to svn:ignore
if necessary you can do this via the svn command line. This way you might add a pattern to svn ignore
svn pe svn:ignore .
then you can fill in something like:
*.d
NOTE that svn:ignore is different for each subfolder (hence the "." in the svn command)
The answer largely depends on if the file is already being tracked (versioned) by Subversion or not.
Not Versioned
Setting up an ignore via one of the several methods we have of ignoring files will do what you want. If you're using 1.8 we also have svn:global-ignores which supports inheritance (so if you want to say ignore all files with the .o extension you could just set a svn:global-ignores with *.o as a pattern.)
Versioned
If the file is already in the repository and is versioned then ignore won't help you since versioned files are not ignored by any configuration you do. One alternative, as mentioned in the answer to this question "How do I avoid checking in local changes to the SVN repository?", is to use a changelist and add the file to the changelist.
A better option might be to restructure your setup to not require making local changes to versioned files. A common pattern you will see is configuration files where the committed file is a template, developers then copy the template into another name that is used and customize it.

Protecting the sensitive files from pushing to version control

Here's the problem: I'm developing a few projects that need to somehow store credentials used for external services - for example, an e-mail address and password. I figured it falls into "configuration" and decided to move the variable data into a separate file the program reads from. I don't want this file to be pushed to upstream though, because in some of my smaller programs, written for personal needs, I test on a production environment and the data are usually quite sensitive.
On the other hand, I don't want a basic .gitignore solution or its equivalent - instead of not uploading the file at all, I'd prefer to send another file in its place, an example configuration file, while keeping the "real" file on its place on my computer. Is there any simple way of achieving it?
If you need more details to answer the question, I'd prefer an answer regarding Git VCS, Python scripts and Linux OS.
One possible solution:
Commit and push a "sample" config file. Then, make the modifications you want to the local config file. It will now be marked as modified in Git.
Use git update-index --assume-unchanged config to permanently ignore future local modifications to the config file (use --no-assume-unchanged to resume tracking modifications).
This way, you will have a sample config in the upstream repo, a customized config in your repo, and you will not accidentally commit the changed config because Git will not mark it as modified.
Another thing you can do is use .gitattributes filters. It lets you specify certain files to pipe through a unix command. You could write a ruby script to scrub out your passwords and replace them with dummy values, or just use sed or awk. You could go a lot crazier than that and use it for some really dangerous things also, heh. See this other answer for some details.

Mercurial. Version control and deployment. Different config files. How to?

I have a setup as follows.
A private repository at bitbucket where I keep the 'master' repository.
A repository on my server which acts as the 'live' website.
A repository on my laptop which acts as my working copy.
My process is as follows. I make a change to a file in my local repository. I commit these locally. I push these changes to bitbucket. I then pull these changes from my bitbucket to the webserver.
The problem that I have however is that my local copy utilizes different configuration settings for databases, paths etc, ergo what I want is my 'config.php' file at bitbucket to contain the server settings, and the config.php on my local host to contain local settings.
I believe this can be achieved with .hgignore but i have had no success researching.
The problem i encounter is that i make my server settings file, push it to bitbucket, 'forget' the file in my local repository, create a .hgignore, and then recreate the file. However when i 'forget' the file TortoiseHG notices and asks me to commit the change to bitbucket....
Any ideas would be greatly appreciated.
Thanks
Additional Points.
Following the advice below I have developed a setup as follows:
I have my local repository on my laptop where i do my edits.
I have bitbucket which is essentially the 'main' repository - if any other developers join the team they clone this.
I have my live repository on my web host.
On my live repository I have a .hgignore file whichs ignores the respective config files.
As such when I do hg pull from my host, it pulls the repository as is with the localhost configuration files, but when i type hg update (to the live working copy), these files are ignored/not updated.
Could someone clarify as to if i have understood this correctly, and as to whether this is a suitable way of achieving what I want?
Thanks
.hgignore only ignores files if they are not versioned already, so I don’t think your idea in the question will work.
The common approach regarding local configuration is generally a variation on the same theme, like of one of the following:
Do not check in the config.php at all. You can check in a config.example.php with the most common settings, and document in the README that users have to copy it to config.php and then edit it.
Put any shared settings in config.php, and add an include statement to point to an unversioned file with settings specific to the machine, e.g. config.local.php. You can also provide an config.local.example.php-file for this.
Like 2, but the config.php contains all default settings and the local file has the ability to override them.
Check in a config.dev.php and config.server.php-file containing the settings for both environments, and then have an unversioned config.php which includes one of the above files. Advantage is that the configurations themselves are versioned and you can update them.
Which of these variations to pick, or whether you make another variation, depends on your environment.
The basic idea for working with version control and different configuration files is always the same, but I don't know enough PHP to give a detailed answer how you can do this in PHP.
I answered a similar question for .net/Visual Studio a few months ago, so I'll just give you the link to this answer and try to describe the basic idea again, but this time language-agnostic:
For your use case, the basic idea is to have two config files in the repository, one with your local data and one with your server data, for example like this:
config.local.php
config.server.php
The "real" config.php is not in the repository, and it should be in .hgignore, so it never will be in the repository either.
After pulling, you need to run something that copies one of these files (the "correct" one depending on the current environment, local or server) to config.php.
And exactly this last part is the part that I can not answer in detail, because I don't know how to do that in PHP and/or on a web server because I'm a .net/Windows guy.
As far as I know, deploying a PHP site is just copying the files on the web server, so there is no "build/compile" step where the copying/renaming of the config file could be done (where I would do it in .net). Correct me if I'm wrong...
EDIT:
Thomas, I'm not sure if I understood your edits correctly. Your "local" repository on your laptop and your "live" repository on your webserver are basically clones of your "main" repository on Bitbucket, correct?
If yes, are you saying that you have different .hgignore files in the different clones?? That's the part that confuses me.
No matter how you actually do it in the end (there are several possibilities to deal with configuration files, see below), the .hgignore file should be the same in all clones of your repository.
So all your repositories (no matter which clone on which machine) should all contain the same configuration file(s).
Then, you only need to make sure that different configurations are used in different environments. There's already an excellent list of different ways to achieve this in Lauren Holst's answer, so I'll just point you there.
As Laurens Holst already said, we can't tell which of these ways is the best for you - it depends on your environment.
You might want to check here. If both the config file and .hgignore are commited, the .hgignore will have no effect. You could also add a domain check conditional:
$domain = $_SERVER['HTTP_HOST'];
if ($domain=="localhost") {
//local copy config
}
else if ($domain=="yourdomain.com") {
//webserver config
}

Where to put .hgignore?

I'm wondering where to put .hgignore file; in the main repository or each programmer should have it on his cloned copy?
Please clarify. Thanks.
You should put the file at the root of your repository.
See :
https://www.selenic.com/mercurial/hgignore.5.html
https://www.mercurial-scm.org/wiki/.hgignore
It says:
These files can be ignored by listing them in a .hgignore file in the root of the working directory. The .hgignore file must be created manually. It is typically put under version control, so that the settings will propagate to other repositories with push and pull.
Also another advantage is that, you might be working on multiple projects. Each having it's own set of pattern of files to ignore. For example, working on a Visual Studio project or a simple C++ project or a Python project. This ensures that patterns to ignore are relevant to the project.
How ever, you may not want to replicate these patterns in every ignore files. In such a case Mercurial configuration file can reference a set of per-user or global ignore files.
Example for global ignore files
in ~/.hgrc1:
[ui]
ignore = ~/.hgignore
in ~/.hgignore:
syntax: glob
*.tex
*.R
1 On Windows: %USERPROFILE%\mercurial.ini, ~ refers to %USERPROFILE% on Windows.
I've never seen it anywhere but the main repository.
How are you going to ignore the .hgignore without an .hgignore file in the repositry to ignore it ;P
Seriously.. it should probably be in the repository, since the files to be ignored are respositry-specific; a user can of course specify their own ignores additionally in a file specified in their .hgrc
you can have a global one inside your ~/.hgrc directory or a project specific one inside
the project's root directory
It belongs in the top folder of the repository. It is not meant for personal ignores but for project-wide ignores (i.e. applying for everyone). However, usually developers will add e.g. their faviourite editor's temp. files to that file - doesn't hurt anyone.
If you want to ignore something others probably do NOT want to ignore, put it in your personal ignore in ~/.hgrc.

Keeping divergent versions of a hg version-controlled file on different machines?

I am working on a project that depends on external programs, and needs to know the paths to them. I develop and use the project on several machines, using mercurial for version control. The paths are machine-dependent, so I keep them in a machine-specific config file. I would like the config file for each host to be version-controlled, but I need to ensure that the config file from one host would never overwrite the config file for another host when pushing or pulling between hosts. Is there any way to accomplish this?
In principle, Wim is right: machine specific configurations shouldn't be part of the project's source control. As long as you walk alone, this isn't a real problem, but once you want to provide generic releases of your project, you have to get rid of them. In that case you might not be happy about the fact, that the change history contains files with machine specific data.
Nevertheless, it may make sense to have machine specific data in version controlled files (personally I do this for my dot-rc files and shell scripts). In that case I would suggest to separate generic and specific configurations into different files and include/utilize the specific one at build- or runtime, depending on the currently used machine.
If it is not possible to detect the current machine automatically, you could still create an unversioned symbolic link on each machine, pointing to the appropriate specific configuration file. For instance, on the machine foo the file layout could look like this:
generic.conf version-controlled
specific-foo.conf version-controlled
specific-bar.conf version-controlled
specific.conf → specific-foo.conf unversioned symbolic link
An alternative to symbolic links is to use a hook which automatically creates specific.conf, e.g. on each invocation of hg update. As hooks are set in a repository's hgrc file, it can be defined individually on each machine. Here's an example of a corresponding hooks section in the .hg/hgrc file of a repository clone on the machine foo:
[hooks]
update = cp specific-foo.conf specific.conf
Machine specific configuration settings should not be version controlled in the same repository as the project code.
However, it is still a good idea to put an inactive sample configuration file in your code repository. And this sample could show a bunch of typical locations for the external program paths you mentioned as lines that are commented out. That way you make it easier to get your project running on new machines.