diff --git a/source_control/git b/source_control/git index b839540e842..c241b8b5e61 100644 --- a/source_control/git +++ b/source_control/git @@ -41,7 +41,8 @@ options: default: "HEAD" description: - What version of the repository to check out. This can be the - git I(SHA), the literal string C(HEAD), a branch name, or a tag name. + full 40-character I(SHA-1) hash, the literal string C(HEAD), a + branch name, or a tag name. remote: required: false default: "origin" @@ -107,7 +108,7 @@ import tempfile def get_version(git_path, dest): ''' samples the version of the git repo ''' os.chdir(dest) - cmd = "%s show --abbrev-commit" % (git_path,) + cmd = "%s show" % (git_path,) sha = os.popen(cmd).read().split("\n") sha = sha[0].split()[1] return sha @@ -121,8 +122,9 @@ def clone(git_path, module, repo, dest, remote, depth, version): pass os.chdir(dest_dirname) cmd = [ git_path, 'clone', '-o', remote, '--recursive' ] - if version and version != 'HEAD': - cmd.extend([ '--branch', str(version) ]) + if is_remote_branch(git_path, module, dest, repo, version) \ + or is_remote_tag(git_path, module, dest, repo, version): + cmd.extend([ '--branch', version ]) if depth: cmd.extend([ '--depth', str(depth) ]) cmd.extend([ repo, dest ]) @@ -135,24 +137,30 @@ def has_local_mods(git_path, dest): lines = filter(lambda c: not re.search('^\\?\\?.*$', c), lines) return len(lines) > 0 -def reset(git_path, module, dest, force): +def reset(git_path, module, dest): ''' Resets the index and working tree to HEAD. Discards any changes to tracked files in working tree since that commit. ''' os.chdir(dest) - if not force and has_local_mods(git_path, dest): - module.fail_json(msg="Local modifications exist in repository (force=no).") cmd = "%s reset --hard HEAD" % (git_path,) return module.run_command(cmd, check_rc=True) def get_remote_head(git_path, module, dest, version, remote): - cmd = '' - os.chdir(dest) + cloning = False + if remote == module.params['repo']: + cloning = True + else: + os.chdir(dest) if version == 'HEAD': - version = get_head_branch(git_path, module, dest, remote) - if is_remote_branch(git_path, module, dest, remote, version): + if cloning: + # cloning the repo, just get the remote's HEAD version + cmd = '%s ls-remote %s -h HEAD' % (git_path, remote) + else: + head_branch = get_head_branch(git_path, module, dest, remote) + cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, head_branch) + elif is_remote_branch(git_path, module, dest, remote, version): cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, version) elif is_remote_tag(git_path, module, dest, remote, version): cmd = '%s ls-remote %s -t refs/tags/%s' % (git_path, remote, version) @@ -167,9 +175,8 @@ def get_remote_head(git_path, module, dest, version, remote): return rev def is_remote_tag(git_path, module, dest, remote, version): - os.chdir(dest) cmd = '%s ls-remote %s -t refs/tags/%s' % (git_path, remote, version) - (rc, out, err) = module.run_command(cmd) + (rc, out, err) = module.run_command(cmd, check_rc=True) if version in out: return True else: @@ -186,10 +193,10 @@ def get_branches(git_path, module, dest): branches.append(line.strip()) return branches -def is_remote_branch(git_path, module, dest, remote, branch): - branches = get_branches(git_path, module, dest) - rbranch = 'remotes/%s/%s' % (remote, branch) - if rbranch in branches: +def is_remote_branch(git_path, module, dest, remote, version): + cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, version) + (rc, out, err) = module.run_command(cmd, check_rc=True) + if version in out: return True else: return False @@ -335,8 +342,9 @@ def main(): local_mods = False if not os.path.exists(gitconfig): if module.check_mode: - module.exit_json(changed=True) - (rc, out, err) = clone(git_path, module, repo, dest, remote, depth, version) + remote_head = get_remote_head(git_path, module, dest, version, repo) + module.exit_json(changed=True, before=before, after=remote_head) + clone(git_path, module, repo, dest, remote, depth, version) elif not update: # Just return having found a repo already in the dest path # this does no checking that the repo is the actual repo @@ -347,44 +355,28 @@ def main(): # else do a pull local_mods = has_local_mods(git_path, dest) before = get_version(git_path, dest) - # if force, do a reset - if local_mods and module.check_mode: - module.exit_json(changed=True, msg='Local modifications exist') - (rc, out, err) = reset(git_path, module, dest, force) - if rc != 0: - module.fail_json(msg=err) - # exit if already at desired sha version - # abbreviate version in case full sha is given - if before == str(version)[:7]: - module.exit_json(changed=False) - # check or get changes from remote remote_head = get_remote_head(git_path, module, dest, version, remote) - if module.check_mode: - changed = False - if remote_head == version: - # get_remote_head returned version as-is - # were given a sha1 object, see if it is present - (rc, out, err) = module.run_command("%s show %s" % (git_path, version)) - if version in out: - changed = False - else: - changed = True + if local_mods: + # failure should happen regardless of check mode + if not force: + module.fail_json(msg="Local modifications exist in repository (force=no).") + # if force and in non-check mode, do a reset + if not module.check_mode: + reset(git_path, module, dest) + # exit if already at desired sha version + if before == remote_head: + if local_mods: + module.exit_json(changed=True, before=before, after=remote_head, + msg="Local modifications exist") else: - remote_head = remote_head[0:7] - if before != remote_head: - changed = True - else: - changed = False - module.exit_json(changed=changed, before=before, after=remote_head) - (rc, out, err) = fetch(git_path, module, repo, dest, version, remote) - if rc != 0: - module.fail_json(msg=err) + module.exit_json(changed=False, before=before, after=remote_head) + if module.check_mode: + module.exit_json(changed=True, before=before, after=remote_head) + fetch(git_path, module, repo, dest, version, remote) # switch to version specified regardless of whether # we cloned or pulled - (rc, out, err) = switch_version(git_path, module, dest, remote, version) - if rc != 0: - module.fail_json(msg=err) + switch_version(git_path, module, dest, remote, version) # determine if we changed anything after = get_version(git_path, dest)