How to exclude the unit test directory in Git - php

A large existing PHP project that is having Unit Tests retrofitted to it. I want to have a "tests" directory in the code on the development branch which contains these unit tests and perhaps the DB fixtures also. Naturally I don't want anything in there making its way onto the production environment so I want a way of automatically excluding this directory when it's deployed. Or ideally, a way to avoid anything in there that is committed from being merged into master in the first place.
How do I manage this? There will be frequent and unpredictable commits to the test directory so I can't simply skip certain commits manually.
EDIT: I've now got four answers telling me about .gitignore. I don't believe .gitignore is appropriate here because I want to exclude something that IS to be committed but only from a specific branch.

it's called .gitignore
From the docs:
A gitignore file specifies intentionally untracked files that Git should ignore. Files already tracked by Git are not affected
source: https://git-scm.com/docs/gitignore
For examples sake, let's say you have this working tree:
|-app
|-test
|-index.php
to exclude test/ the test directory add a .gitignore on the same level as the .git folder and in it just add:
test/
commit the git ignore and make a change/add a file to test/ and you'll notice it doesn't appear when you run
$ git status

You can use .gitignore. This is a file in your project root and you can list all files and directories you don't want to commit/push. They are separated by a new line.

I've found that the way to keep a part of a branch from being merged into another branch on a permanent basis is to use sub-modules.
I created my unit tests folder as its own repository and then included it in my mainline branch (which is not the production/master branch) as a sub-module.
https://git-scm.com/book/en/v2/Git-Tools-Submodules
By default when you clone a repository, sub-modules are not cloned with it. The sub-module directory is created but remains empty, unless you also execute
git submodule init
git submodule update
Therefore it's as simple as not including the above commands in your production git clone but including them when you clone the repository for testing or development. You can make any changes to the tests directory along with the codebase and commit both together. This means tests can be developed alongside the code base without risking them being deployed to production.
I found the following aliases useful to set up to streamline git operations:
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'
This seems to be the correct approach to solving the problem of wanting separation of code in a single repository to be different on a per-branch basis.

Related

GIT post-receive hook for more branches - workflow or timestamp problem?

I have a development and production folder on the same server and 1 repo behind them to push to both folders depending on the branch that is pushed. I would like the development (test) folder to be deployed to when dev is pushed to the repo and the production folder (www) when master is pushed.
This works, but I have the problem of rewriting all files, not just those that have changed.
Example:
I am on local dev branch, make change only to file index.php, commit,
push - Changes are deployed do development folder, with only
index.php changed (new file timestamp).
Next step: git checkout master, git merge with dev branch and then
push to master - Changes are properly deployed to production folder,
but not only index.php is changed, but all files on FTP have new
timestamp.
Next step: git checkout dev, make some changes to fileX.php, commit and push to dev - Changes are properly deployed to dev folder, but again all files on FTP have new timestamp, not only fileX.php
Is it normal or am I doing something wrong? Maybe can you recommend a better git workflow if I have 1 local PC with git - 1 development domain and 1 production domain ?
Thanks for help
post-receive hook:
#!/bin/sh
while read oldrev newrev ref
do
branch=`echo $ref | cut -d/ -f3`
if [ "master" == "$branch" ]; then
git --work-tree=/home/www/domain.com/subdomains/www --git-dir=/home/www/domain.com/subdomains/repos/myrepo.git checkout master -f
echo 'changes pushed to production'
else
git --work-tree=/home/www/domain.com/subdomains/test--git-dir=/home/www/domain.com/subdomains/repos/myrepo.git checkout dev -f
echo 'changes pushed to dev'
fi
done
This post-receive hook is badly flawed. The good news is that it's easily fixed.
The root of your particular problem is that every Git repository, including the bare one1 that is receiving the push here, starts out with one (just one) index. The index keeps track of the (single, as in just one again) work-tree. This is true even though the whole point of a bare repository is to have no work-tree: it still has an index.
When one uses git --work-tree=<path> with this bare repository to do a git checkout operation, that checkout operation uses the (one, single) index to keep track of what it has stored in the (temporarily added) work-tree. That is, for the duration of the git checkout, this bare repository becomes non-bare: it has one index and one work-tree, and the work-tree is the one chosen for this one git checkout operation.
For each subsequent git --work-tree=<path> checkout operation, Git will assume that the index correctly describes the current checkout to the target work-tree. (Git may discover, as it does its work, that the index doesn't correctly describe the target work-tree, but it starts out assuming that it does.) The files that Git decides to update in that work-tree will be based on this assumption, with some corrections potentially, but not always, inserted as it goes. This main assumption, that the index correctly describes the current checkout to the work-tree, holds if and only if the path argument used in the subsequent git checkout is the same as the path argument used in the previous git checkout.
But we have two different git checkout commands:
git --work-tree=/home/www/domain.com/subdomains/www ...
and:
git --work-tree=/home/www/domain.com/subdomains/test
(small aside here: something went wrong with the cut-and-paste above as the --git-dir option is fused with the --work-tree; I have made my own assumption here about fixing it).
These are two different paths. They therefore need two different index files—or no index at all.2
1A bare repository is a Git repository where core.bare is set to true. A bare repository has no work-tree and its Git database files are stored in the top level, rather than under a separate .git directory.
2When there is no index, as in the initial git checkout, Git will build one as needed. This is more compute-intensive, and in a non-bare repository, where we actually use the index to build the next commit, destroying the index loses our carefully-built next commit: Git builds the new one from the current commit again so we have to start over.
The work-tree itself is not affected by this rebuilding process, but if we can afford the space for one index file per work-tree—and index files are generally pretty small—it seems likely that we should do that. Still, it's an option, if you want it.
Fixing the problem
First, although it's not really related, let's fix the other obvious (but minor) problem:
while read oldrev newrev ref
do
branch=`echo $ref | cut -d/ -f3`
Suppose we add a tag named master/v1.1. This ref has, as its full spelling, the name refs/tags/master/v1.1. Let's see what we get here:
$ ref=refs/tags/master/v1.1
$ branch=`echo $ref | cut -d/ -f3`
$ echo $branch
master
Whoops: our code will think we've updated branch master, when what we did is add the tag master/v1.1. We probably won't use such a tag, but why not do this correctly? Instead of using cut, let's check the whole reference:
case $ref in
refs/heads/*) branch=${ref#refs/heads/};;
*) continue;; # not a branch
esac
Trying this out with our test ref we get:
$ case $ref in
> refs/heads/*) branch=${ref#refs/heads/};;
> *) echo not a branch;;
> esac
not a branch
Replacing ref with refs/heads/master we get:
$ ref=refs/heads/master
$ case $ref in
refs/heads/*) branch=${ref#refs/heads/};;
*) echo not a branch;;
esac
$ echo $branch
master
(There's no PS2 output in this section because I used control-P to redo the previous case.)
For real correctness, we should also look at $old and $new to determine whether the ref in question is being created, updated, or deleted; but in this case we can just assume that branch names master and dev won't ever be deleted. So our new code reads:
#!/bin/sh
while read oldrev newrev ref
do
case $ref in
refs/heads/*) branch=${ref#refs/heads/};;
*) continue;; # not a branch - do not deploy
esac
case "$branch" in
master) wt=/home/www/domain.com/subdomains/www loc=production;;
dev) wt=home/www/domain.com/subdomains/test loc=dev;;
*) continue;; # not an INTERESTING branch - do not deploy
esac
# It's an interesting branch; deploy it to $wt. Use an index
# based on the branch name. There is no need to specify the
# git directory, which is in $GIT_DIR right now because this is
# a post-receive script.
GIT_INDEX_FILE=index.$branch git --work-tree=$wt checkout $branch -f
echo "deployed to $loc"
done
The -f option to git checkout here is somewhat dangerous: it will overwrite or remove files that got modified in the work-tree, even though we now have a proper index to keep track of which files should be in which state. But it was there before, so I've kept it.
This post-receive script (which I should note is entirely untested: watch out for typos) still has a flaw. Whatever branch we git checkout here, that will leave this repository set to recommend that branch to whoever clones this repository. Fixing this requires updating HEAD:
git symbolic-ref HEAD refs/heads/master
after the git checkout step. You have been living with this flaw all along, so maybe you don't really care about this one.

Is it possible to validate vendor folder integrity in composer?

I just inherited a composer project in a very bad shape. They sent me a zip file with the vendor directory in it and I suspect that the previous developer has edited files directly inside vendor.
Is there a way to "validate" the vendor folder to ensure that the files inside are unmodified?
Change the name of the old vendor to something else.
Execute composer install again.
Run diff to compare both directories.
E.g. for a sample project where I intentionally modified a single file inside vendor.
$ mv vendor vendor_old
$ composer install
### install output...
$ diff -rq vendor vendor_old
Files vendor/autoload.php and vendor_old/autoload.php differ
Files vendor/composer/autoload_files.php and vendor_old/composer/autoload_files.php differ
Files vendor/composer/autoload_real.php and vendor_old/composer/autoload_real.php differ
Files vendor/composer/autoload_static.php and vendor_old/composer/autoload_static.php differ
Files vendor/symfony/console/Terminal.php and vendor_old/symfony/console/Terminal.php differ
You can mostly ignore the changes to the autoload* files, but with this listing you can concentrate in those other files that report differences (and run a more exhaustive diff from them).
In the example, only vendor/symfony/console/Terminal.php was actually modified.
Copy the project into some other folder, and delete the vendor directory. Run composer install and compare two vendor files.
The easiest way to do this is by using composer status command.
The prerequisite is that package is installed from source (as described on the official Composer site):
If you often need to modify the code of your dependencies and they are installed from source, the status command allows you to check if you have local changes in any of them.

Automatically `pull` when there is what to pull to my repo: `post-merge` git server hook using PHP

What I want to accomplish:
I have juts installed git on my development server.
I create a branch out of my 'develop' branch, work on my new feature branch, commit, and when I'm done - I merge the new feature branch with the 'develop' branch.
To apply the changes for the 'develop' branch on my development server I have to log in to my server and use git pull - which I'm trying to prevent and happen automatically - when there is something to pull from my development server - it will be done automatically.
I hope I'm clear about that I'm trying to accomplish ;)
What I have done up till now is:
Created a folder inside my project /www/hooks/ and added a file called post-merge: Following git documentation - this should get triggered whenever I merge a branch.
Inside this folder I added the text:
which should execute whatever is in between the backticks symbol ( ` ) as a shell command (following this PHP documentation)
Inside the folder /www/.git/hooks/ I added a symbolic-link to the file I previously mentioned with the same exact name: /www/hooks/post-merge :
sudo ln -s -f /www/hooks/post-merge /www/.git/hooks/post-merge
I gave the linked file under /www/.git/hooks/post-merge 775 file permission as the other files.
Some notes:
My repo is on Bitbucket
My directory /www/homepage/ is the one with the index file, so nothing can run outside of it on a browser (apache2 points to it..) - (but i guess there shouldn't be a problem since it's self executed via /.git/hooks ?)
I tried renaming both my files (the one under /www/.git/hooks/ & /www/hooks/) to post-merge.php and this didn't work.
just to have Carriage return
#!/bin/bash
git --git-dir "path/master/.git" --work-tree "path/master" pull origin master
you could try this in your post-merge

Getting specific folder structure from git

i have some files and folder in my git repo. But some of them have a very long path that when i try to synchronize my workspace with git it gives me an error because windows cannot have characters in a path more than 260. Is there a way to pull specific files and folders? for example *.php files from /file/*.php?
I do not know much from git and also all other tutorials and answers i found here do not work. i even tried the git git_core.longpathenabled true but nothing happened.
Any ideas?
Is there a way to pull specific files and folders
Yes, you can use git filter-branch and or git subtree split
Sample code:
filter-branch
# Filter the master branch to your directory and remove empty commits
git filter-branch --prune-empty --subdirectory-filter YOUR_FOLDER_NAME filter_from_branch
This will checkout all your desired files from the given folder to the current directory
subtree split
git subtree split -P <name-of-folder> -b <name-of-new-branch>
If your repository is hosted on Github or similar, you can download the file individually over HTTP, but you obviously will not be able to push changes.
Finally, if your copy of the repo is located in a deeply-nested folder you could move it somewhere like Users\You\Projects\cloned.

Move a Git repository to another directory

I want to move a git repository to a sub-directory which is there in its present root folder.
Let me explain the things first.
I have Git repository testing in $HOME/repos/ (contains PHP code-base).
Now i want to move testing into $HOME/repos/php/ where php will be sub-directory which i want to create (anyway php directory is not a git repository)
My questions are
if i do above explained move then does this effect my testing repository ?
Does this effect any branches or commits or uncommitted changes in testing repository ?
Moving a repository to a different directory should have no effect on the repository. Simply move everything as you would with any other kind of files, taking care to move the .git directory along with it. That .git directory is what git looks at and compares against other stuff in the project directory (wherever that .git directory lives).

Categories