Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making files in submodule read-only

I'm a git newbie suffering from prior svn experience. Many of my projects are using code from my own libraries, so naturally I want some "externals-like" functionality from git. I'm currently trying to use submodules.

But submodules (as far as I understand) can provide a lot of pain if you use them in the wrong way (for example, change files in submodule and forget to push them, or forget to commit them).

What if I make all files in submodule read-only? That's a good enough protection from accidental change. And if I really want to change something I should go and make that change in the original repo.

So, my question is:

  1. Is that a good idea or I'm trying to reinvent the wheel?
  2. What's the easiest way to do it?

EDIT: I hope that could be achieved with git hooks, but I'm not sure how exactly. I can't use client hooks when cloning the repo for the first time, can I?

EDIT2: With help of SRobertz I was able to come up with a post-checkout hook:

echo "you just checked out: $*"  
echo "submodules:"
for p in `grep path .gitmodules | sed 's/.*= //'`; do # get submodules list
    echo "making submodule directory $p read-only"
    chmod -R a-w $p;
    SAVEIFS=$IFS
    IFS=$(echo -en "\n\b") #set delimeter to \n\b to handle whitespaces in filenames
    for f in `ls $p`; do #get files in submodule dir
         echo "making file $f in directory $p read-only"
         chmod -R a-w $p\\$f;
    done
    IFS=$SAVEIFS #restore delimeter to default value
done 

Now the problem is that when cloning a new repo, this hook fires too early, when submodule directories are already created but files in them are not pulled yet.

like image 666
Amomum Avatar asked Feb 14 '15 21:02

Amomum


People also ask

Do submodules update automatically?

Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated. When adding a submodule to a repository a new . gitmodules file will be created.

Should submodules be in Gitignore?

No, you don't need to add your submodule to your . gitignore : what the parent will see from your submodule is a gitlink (a special entry, mode 160000 ). That means: any change directly made in a submodule needs to be followed by a commit in the parent directory.

What does recurse submodules mean?

If you pass --recurse-submodules to the git clone command, it will automatically initialize and update each submodule in the repository, including nested submodules if any of the submodules in the repository have submodules themselves.

Can I modify the submodule in git?

The submodule is just a separate repository. If you want to make changes to it, you should make the changes in its repository and push them like in a regular Git repository (just execute the git commands in the submodule's directory).


1 Answers

If you want svn-like externals you may want to look at giternal, https://github.com/patmaddox/giternal , either to use as-is or as a starting point. It is written in ruby, and should be fairly easy to adapt to what you want if the freeze command is not quite what you want (wich it perhaps isn't).

Short intro: http://www.rubyinside.com/giternal-easy-git-external-dependency-management-1322.html

A longer article with some alternatives at the end: https://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/

Edit: on client-side hook and its deployment: If you are aware of the quirks of git submodules and want to use that (perhaps for the stability you get from referencing a specific commit rather than HEAD) then this is a way to make it read-only when cloning or checking out.

The client-side hook to use is post-checkout, and iterate over the submodules, along the lines of (inspired by List submodules in a git repository, and git-clone and post-checkout hook. I used grep on .gitmodules as it works before the submodule is inited.)

#!/bin/sh
# An example post-checkout hook to make submodules read-only

echo "you just checked out: $*"
git submodule init
git submodule update --recursive
echo "submodules:"
for p in `grep path .gitmodules | sed 's/.*= //'`; do
    echo "making submodule directory $p read-only"
    chmod -R a-w $p;
done    

Then, to deploy the hook, one option is to set up a template directory for your developers and then make them do git clone --template=</your/template/dir> url-to-clone... (e.i., add the --template=... option to git clone, perhaps by making it an alias and somehow putting that in everybody's global config.

EDIT2: after discussion in comments:

If submodules have been made read-only, they need to be made writable before updating (according to comments, git on windows does this automagically, but it is required on linux/macos). To do that on a git pull, a post-merge hook like the following sketch can be used.

#!/bin/sh
# An example post-merge hook to 
#   1. make submodules writable,
#   2. init and update submodules, and 
#   3. make them read-only

# make all (existing) submodule directories writable
for p in `git submodule status | sed -e "s/^[+\ ][^\ ]*\ //" -e s/\ .*$//`; do
    echo "making submodule directory $p writable"
    chmod -R u+w $p;
done

echo "updating submodules:"   
git submodule init
git submodule update --recursive

# make all submodules read-only
for p in `grep path .gitmodules | sed 's/.*= //'`; do
    echo "making submodule directory $p read-only"
    chmod -R a-w $p;
done

This could be refined to check if any submodule was updated in the merge and only handle that, instead of always iterating over all submodules.

Caveat: how this interacts with git pull --recurse-submodules needs to be checked if you intend to use that.

Note that this does init and update all submodules, and make them read-only, after each merge (pull).

It does not, however, address doing git pull etc. inside the submodules. For that, the corresponding hooks need to be added to .git/modules/*/hooks (for git versions >= 1.7.8) or <submodule>/.git/hooks (for older git versions).

like image 144
drRobertz Avatar answered Sep 29 '22 11:09

drRobertz