4

For the project I am working on, we decided to develop a tool to help the development, so this is something that should not be in production.
So I was wondering, as git is so awesome, if maybe there was a feature to prevent some files (yes, only files: this is a Magento project and the tool we are going to develop will be in his own module, no intersection with the rest of the application) to be merged into master, but should be available in other branches.
We are thinking in using git-flow, if that helps. So we would have master, from which we'll create develop, from which will create all our feature branches. The idea would be to have this module in develop but never merged back into master.

I am thinking now, something like ignoring those files (.gitignore) only in the master branch, would that work?

edit 1: project structure
I feel I have to give more info about the structure of the project, here it comes:

+ main_folder/
    + magento/
    |---+ app/
    |   |--+ code/
    |   |  |--+ community/
    |   |  |--+ core/
    |   |  |--+ local/
    |   |     |--+ Namespace1/
    |   |        |--+ Module1/
    |   |        |--+ Module2/
    |   |     |--+ Namespace2/
    |   |        |--+ Module1/
    |   |        |--+ Module2/
    |   |--+ design/
    |   |  |--+ frontend/
    |   |     |--+ default/
    |   |        |--+ default/
    |   |           |--+ layout/
    |   |           |--+ template/
    |   +  js/
    |   +  lib/
    +  ezpublish/

the development tool module will have to be included in the main project (only the magento part) in differents places, i.e. app/code/local/Namespace1/Module3/, app/design/frontend/layout/dev.xml, app/design/frontend/template/dev/tool.phtml and js/dev/

edit 2: submodule option
exploring @VonC's answer, here is what I've done:

  • in branch master:
    • git submodule add git@github.com:path/to/submodule.git devtool
    • cd devtool
    • git checkout 123abc #submodule's initial commit
    • cd ..
    • git add devtool
    • git commit -m "added submodule at initial commit"
  • in branch develop:
    • cd devtool
    • git checkout abc213 #submodule's last commit
    • cd ..
    • git add devtool
    • git commit -m "submodule at last commit"
  • back in branch master:
    • touch .gitattributes
    • in .gitattributes I've put this: devtool merge=ours
    • git add .gitattributes
    • git commit -m ".gitattributes directive"

but the submodule in master has the content of the last commit, and if I checkout the inital commit in master and checkout back to develop, the initial commit is still there (when I want the last commit in develop).
So I am obviously doing something wrong, but what?

Community
  • 1
  • 1
OSdave
  • 8,538
  • 7
  • 45
  • 60
  • 2
    that would be an idea, since I don't know and I think it doesn't exist any git construct to prevent a file from exist on a branch, except the .gitignore. The problem is you'll always have that code in a branch. Also, if your code depends on code in the master branch, you'll have to constantly rebase or merge master into your tool branch, but if that's not a problem go with it. – bitoiu Sep 16 '13 at 18:12
  • @bitoiu the code will not depend on master, so that wouldn't be a problem. But I can't find any information about having different `.gitignore` per branch. When I try, when I merge a branch into master, master's `.gitignore` includes the branch's too. Any info about that? – OSdave Sep 17 '13 at 09:10
  • @OSdave, this is about having different .gitignore per branch : There is good explanation about that here http://stackoverflow.com/questions/1836742/using-git-how-do-i-ignore-a-file-in-one-branch-but-have-it-committed-in-another (please check the "excludesfile" section) – Shunya Sep 19 '13 at 09:30
  • @Meabed not yet, just turned on the pc, will do later today, I will keep you posted – OSdave Sep 23 '13 at 07:07
  • did it do the job :) have you give it a try ? – Meabed Sep 24 '13 at 12:46
  • you should try my answer and work on it, im sure its the best answer !! as i am magento developer also and i am using it for the same purpose ! – Meabed Sep 27 '13 at 19:46

3 Answers3

11

I would really recommend to use a submodule to isolate a set of files in its own repo.

The idea is: if you are using a submodule, all you need to do in your parent directory is to prevent the merge of one element (and only one): the special entry recording the SHA1 of said submodule.
You don't have to worry about the merge of the submodule files.

You can:

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • thanks for your answer. I have expanded my question with what I think I should do to apply your suggestion. As I am not familiar with submodule, would you mind reviewing the steps I have identified and telling me if I am on the right path? – OSdave Sep 17 '13 at 09:54
  • @OSdave the gitattribute should contains the name of the folder added for that submodule, not a SHA1 reference. That folder is actually sotred in the git repo as a special entry. – VonC Sep 17 '13 at 10:18
  • @OSdave and in your submodule, you can add a remote (`git remote add /url/of/your/submodule/repo`) in order to fetch and checkout the right commit you want to be visible from your parent repo. – VonC Sep 17 '13 at 10:19
  • thanx again: I am on it now, will keep you posted of my progress, and will accept your answer as soon as I get it working – OSdave Sep 17 '13 at 10:40
  • I must do something wrong: I've edited my question with what I've done, would you mind review it to see if you can spot my mistake(s)? – OSdave Sep 18 '13 at 15:48
  • @OSdave you are missing some `git submodule update` after your checkouts. – VonC Sep 18 '13 at 16:56
  • @OSdave Plus, if your submodule must, in devel branch, track the latest of a submodule branch, you need to follow this http://stackoverflow.com/questions/1777854/git-submodules-specify-a-branch-tag/18799234#18799234 in your devel branch. – VonC Sep 18 '13 at 16:57
  • I have tried to apply all this, but can't get it to work, when I switch back to master the submodule is at the latest commit. I've started a bounty, hopefully I'll can get a detailed and comprehensive answer to make it work. – OSdave Sep 19 '13 at 08:11
2

Best Solution is to use git hooks !

Here is working example " I have tested it and made sure it works fine "

Usage :

git add . // add all the files for example ( including the files you want to exclude )
git commit -am 'Test pre-commit' // commit all the files "pre-commit" hook will run


Directory Structure example

|-- ex.file
|-- module
|   |-- f2.php
|   |-- f3.php
|   `-- file.php
`-- xml
    |-- file.xml
    `-- file1.xml

Create file in your git root directory and call it { .ignorefolders } with files or folders you want to exclude " example below "

/module/
/xml/file.xml
/ex.file

I have added "/" at the beginning of each line as i wanted it to be relevant to the root dir
" You can add complete folders, individual files "


Create file { pre-commit } in folder { .git/hooks } with content below

ROOTDIR=$(git rev-parse --show-toplevel) #root folder
FILENAME="$ROOTDIR/.ignorefolders" #configuration file

if [ ! -f $FILENAME ]; then
    echo "File '.ignorefolders' not found!"
    exit 1
fi

BRANCHES=("master") # branches array to untrack this folders and files from if you want to remove this files from more than branch for example BRANCHES=("master" "branch2" "branch3")
CURRENTBRANCH=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p') #get current branch name

if [[ ! "$(declare -p BRANCHES)" =~ '['([0-9]+)']="'$CURRENTBRANCH'"' ]];then  #check if the current branch is NOT in the array of the branches
    exit 0
else
  echo "Executing pre-commit hook in $CURRENTBRANCH Branch"
fi

function removeFromGitAdd {
   PARAM="$ROOTDIR$1"
   if [ -e $PARAM ]; then
        #file or folder exist
        if [[ -n $(git ls-files $PARAM ) ]]; then
            #echo "there are files with this path added in the current commit"
            git rm --cached $PARAM -r #removing this files/folders
        else
            #echo "There is no file"
            echo ''
        fi
        
   fi
}
cat $FILENAME | while read LINE
do
       #echo $LINE
       removeFromGitAdd $LINE
done

Notes :

Code is well documented ( You can use exit or return ) in the conditional statements depends on the logic you want !

return ==> commit will continue
exit ===> commit will be aborted

Use-case :

If you add "git-add ." and all the files you added is excluded in the config file ".ignorefolders", Then you try to commit!
The files will be removed from the commit but you will be able to commit an empty "without any changes" commit.

Community
  • 1
  • 1
Meabed
  • 3,828
  • 1
  • 27
  • 37
  • I've followed your instructions to the letter, but when I merge the branch (wich contains files that I don't want in master) into master the files are present in master :( – OSdave Sep 25 '13 at 10:07
  • I have tested this and its working. Does the pre-commit works ? are you able to see this message Executing pre-commit hook in master Branch – Meabed Sep 25 '13 at 10:43
  • I am using this on live environment and it works perfectly ! can you give it try ? – Meabed Sep 26 '13 at 06:53
2

After switching branches with

git checkout <branch>,

you have to run

git submodule update

This is to resolve the problem you are having as described in Edit 2.

As per VonC's answer, a gitsubmodule object is one object in the repo that maps to a SHA commit, not the contents of the submodule itself.

Thus, git submodule update is necessary to initialize your local directory with the contents from this commit. Running this command is necessary after you do a fresh clone, or when you switch branches. The problem you are having is that when you are switching branches, the submodule contents from the last branch is still there. Run git submodule update to replace those contents with the contents pointed to by the new branch's submodule object.

EDIT:

Running git submodule update overrides all current changes in the submodule with the commit that the submodule object is pointing too (in the parent repo). If you want to change the commit that your parent repo is pointing to, checkout the right version in the submodule, then cd .. and commit the changes to the submodule object.

Johnny Z
  • 14,329
  • 4
  • 28
  • 35
  • I have tried that, but when I execute `git submodule update` it gets back to the latest commit – OSdave Sep 25 '13 at 09:11
  • Did you do a 'git submodule add' in your develop branch? – Johnny Z Sep 25 '13 at 11:04
  • I am not even there: in branch master, after checking out a specific commit of the submodule and doing `git submodule update` the submodule is back to the last commit, which I don't want (I want the submodule to be at a previous commit, where there is no code) – OSdave Sep 25 '13 at 15:22
  • switch to your master branch and run `git submodule status` from the top level. Does the commit hash displayed next to your submodule correspond to the commit that you want in master? – Johnny Z Sep 25 '13 at 16:05
  • And it seems like you are overriding the submodule contents. See my last edit for overriding submodule changes. – Johnny Z Sep 25 '13 at 16:09