Repository: ansible/ansible-modules-core

Issue:
git module force does not apply force to submodules
Issue Type: Bug report
Component Name: git
Ansible Version: ansible 1.7.2
Environment: Ubuntu 14.04
Summary:

When we make changes to submodule repositories, ansible consistently fails to apply force to submodule  updates.

Steps to reproduce:
1) Make some garbage changes in a submodule repo checkout on the server on the server (for example change the permissions of a file).
2) apply any change in a submodule and push it
3) update master repo to make sure its pointing to the new submodule commit.
4) run playbook, and see it fail with errors

```
TASK: [checkout the app] ******************************************************
failed: [web01-sj-us-p] => {"failed": true}
msg: Failed to init/update submodules: error: Your local changes to the following files would be overwritten by checkout:
    README.md
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout 'bf34f97c6f01fa9bb2bfbcc3672adf627811113b' in submodule path 'templates/account'

FATAL: all hosts have already failed -- aborting
```

This is our checkout

```
- name: checkout the app
    git: repo=git@somegitrepothathassubmodulereposinsideit.git dest={{ nginx_webroot }}/{{ domain }} update=yes force=yes accept_hostkey=true
```



Discussion:
Here's the -vvvv output.

```
TASK: [checkout the app] ****************************************************** 
<web01-sj-us-p> ESTABLISH CONNECTION FOR USER: root
<web01-sj-us-p> REMOTE_MODULE git repo=git@bitbucket.org:construct-server-team/construct-server.git dest=/var/www/construct.pm update=yes force=yes accept_hostkey=true
<web01-sj-us-p> EXEC ['ssh', '-C', '-tt', '-vvv', '-o', 'ForwardAgent=yes', '-o', 'KbdInteractiveAuthentication=no', '-o', 'PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey', '-o', 'PasswordAuthentication=no', '-o', 'ConnectTimeout=10', 'web01-sj-us-p', "/bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1414670997.28-112919533066504 && echo $HOME/.ansible/tmp/ansible-tmp-1414670997.28-112919533066504'"]
<web01-sj-us-p> PUT /tmp/tmpMQCkp2 TO /root/.ansible/tmp/ansible-tmp-1414670997.28-112919533066504/git
<web01-sj-us-p> EXEC ['ssh', '-C', '-tt', '-vvv', '-o', 'ForwardAgent=yes', '-o', 'KbdInteractiveAuthentication=no', '-o', 'PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey', '-o', 'PasswordAuthentication=no', '-o', 'ConnectTimeout=10', 'web01-sj-us-p', u"/bin/sh -c 'LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1414670997.28-112919533066504/git; rm -rf /root/.ansible/tmp/ansible-tmp-1414670997.28-112919533066504/ >/dev/null 2>&1'"]
failed: [web01-sj-us-p] => {"failed": true}
msg: Failed to init/update submodules: error: Your local changes to the following files would be overwritten by checkout:
    README.md
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout 'bf34f97c6f01fa9bb2bfbcc3672adf627811113b' in submodule path 'templates/account'


FATAL: all hosts have already failed -- aborting
```

+1 would be great if this could be fixed

I've been running into this issue as well. If there are changes to files in the submodule, the ansible git module will not update the submodule. Even when `force=yes`. 

I'm still using Ansible 1.9.4. I've set `recursive=yes` on the git task.

The cause of my issue is that I modify file permissions on the checked out repo after updating. Apparently one of the submodules doesn't match the apps recommended file permissions. So git thinks I changed something.

+1

@ansible, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/jctanner/ansibullbot/blob/ISSUE_TRIAGE_CLASS/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->

@ansible, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->

Reproduced error with 1.7.2 ...

```
TASK: [re-clone] **************************************************************
failed: [u1404] => {"failed": true}
msg: Failed to init/update submodules: error: Your local changes to the following files would be overwritten by checkout:
        submod6.file
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout '72dfcab2de85220c0f3ff7dd19a6013de22a6b1a' in submodule path 'submod6.dir'


FATAL: all hosts have already failed -- aborting
```

and with devel c669a38...

```
TASK [re-clone] ****************************************************************
fatal: [u1404]: FAILED! => {"changed": false, "failed": true, "msg": "Failed to init/update submodules: error: Your local changes to the following files would be overwritten by checkout:\n\tsubmod6.file\nPlease, commit your changes or stash them before you can switch branches.\nAborting\nUnable to checkout 'c85cb4803037d391d5b810836fce415daf7883d8' in submodule path 'submod6.dir'\n"}
```


Resolving patch:
diff --git a/source_control/git.py b/source_control/git.py
--- a/source_control/git.py
+++ b/source_control/git.py
@@ -661,7 +661,7 @@ def submodules_fetch(git_path, module, remote, track_submodules, dest):
                     break
     return changed
 
-def submodule_update(git_path, module, dest, track_submodules):
+def submodule_update(git_path, module, dest, track_submodules, force=False):
     ''' init and update any submodules '''
 
     # get the valid submodule params
@@ -676,6 +676,8 @@ def submodule_update(git_path, module, dest, track_submodules):
         cmd = [ git_path, 'submodule', 'update', '--init', '--recursive' ,'--remote' ]
     else:
         cmd = [ git_path, 'submodule', 'update', '--init', '--recursive' ]
+    if force:
+        cmd.append('--force')
     (rc, out, err) = module.run_command(cmd, cwd=dest)
     if rc != 0:
         module.fail_json(msg="Failed to init/update submodules: %s" % out + err)
@@ -938,7 +940,7 @@ def main():
 
         if submodules_updated:
             # Switch to version specified
-            submodule_update(git_path, module, dest, track_submodules)
+            submodule_update(git_path, module, dest, track_submodules, force=force)
 
     # determine if we changed anything
     result['after'] = get_version(module, git_path, dest)


Test patch: