Repository: conan-io/conan

Issue:
scm Attribute fails to clone tag
Since conan 1.18.0 the scm attribute is broken for Git tags. Setting `revision` to a branch – eg. `master` – still works, but tags fail.

The following recipe (*excerpt*) worked up to conan 1.17.0 but fails since 1.18.0:

```python
class RestclientcppConan(ConanFile):+
    name = "restclient-cpp"
    version = "0.5.1"
    _source_dir = "{}-{}".format(name, version)
    scm = {
        "type": "git",
        "subfolder": _source_dir,
        "url": "https://github.com/mrtazz/restclient-cpp.git",
        "revision": "0.5.1"
    }
```
_(The full example recipe is available [here](https://github.com/offa/conan-restclient-cpp/blob/6-conan_issue_example/conanfile.py).)_

Building locally as well as via Travis CI / Conan Build Tools Container fail with this error:

```
ERROR: Command 'git -c http.sslVerify=false checkout "0.5.1"' returned non-zero exit status 1.
/bin/sh: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
error: pathspec '0.5.1' did not match any file(s) known to git
```

It turned out that branches still work. Removing the `scm` attribute and putting the scm part into `source()` works too.

**_Note:_** There's a `source()` method in all that cases to apply patches.

#### Broken: scm with tag

```python
scm = {
    ...
    "revision": "0.5.1" # Tag, broken
}
```
Fails with the error mentioned above

#### Working: scm with branch

```python
scm = {
    ...
    "revision": "master" # Branch, ok
}
```
Builds without an error. 

#### Working: `source()` with tag

```python
# scm part removed
def source(self):
     git = tools.Git(folder=self._source_dir)
     git.clone("https://github.com/mrtazz/restclient-cpp.git", "0.5.1") # Tag, ok
```
Builds without an error too – even though a tag is used.

### Reproduce

1. Install Conan 1.18.0
1. Ensure there's no conan data from previous builds
1. Conan Recipe with `scm` attribute and git tag as mentioned ([ready to use example](https://github.com/offa/conan-restclient-cpp/blob/6-conan_issue_example/conanfile.py)
1. Build package: `conan create . restclient-cpp/0.5.1`
1. Build fails with git error

### Stacktrace
_(From a failed Travis CI build)_

```
Traceback (most recent call last):
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/client/source.py", line 182, in _run_source
    _run_scm(conanfile, src_folder, local_sources_path, output, cache=cache)
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/client/source.py", line 243, in _run_scm
    scm.checkout()
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/model/scm.py", line 99, in checkout
    submodule=self._data.submodule)
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/client/tools/scm.py", line 149, in checkout
    output = self.run('checkout "%s"' % element)
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/client/tools/scm.py", line 100, in run
    return super(Git, self).run(command)
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/client/tools/scm.py", line 66, in run
    return check_output(command).strip()
  File "/opt/pyenv/versions/3.7.1/lib/python3.7/site-packages/conans/client/tools/oss.py", line 507, in check_output
    raise CalledProcessErrorWithStderr(process.returncode, cmd, output=stderr)
conans.errors.CalledProcessErrorWithStderr: Command 'git -c http.sslVerify=false checkout "0.5.1"' returned non-zero exit status 1.
error: pathspec '0.5.1' did not match any file(s) known to git.
```

### System:

- **Compiler:** GCC 4.9 - 9.1 and Clang 3.9 - 8.0
- **Conan:** 1.17.0 (ok), 1.18.0 (affected)
- **Python:** 3.7
- **OS:** Linux and Travis CI with Conan Build Tools Docker Container




Discussion:

Resolving patch:
diff --git a/conans/client/tools/scm.py b/conans/client/tools/scm.py
--- a/conans/client/tools/scm.py
+++ b/conans/client/tools/scm.py
@@ -145,23 +145,30 @@ def clone(self, url, branch=None, args="", shallow=False):
         return output
 
     def checkout(self, element, submodule=None):
+        # Element can be a tag, branch or commit
         self.check_repo()
         output = self.run('checkout "%s"' % element)
+        output += self.checkout_submodules(submodule)
 
-        if submodule:
-            if submodule == "shallow":
-                output += self.run("submodule sync")
-                output += self.run("submodule update --init")
-            elif submodule == "recursive":
-                output += self.run("submodule sync --recursive")
-                output += self.run("submodule update --init --recursive")
-            else:
-                raise ConanException("Invalid 'submodule' attribute value in the 'scm'. "
-                                     "Unknown value '%s'. Allowed values: ['shallow', 'recursive']"
-                                     % submodule)
-        # Element can be a tag, branch or commit
         return output
 
+    def checkout_submodules(self, submodule=None):
+        """Do the checkout only for submodules"""
+        if not submodule:
+            return ""
+        if submodule == "shallow":
+            output = self.run("submodule sync")
+            output += self.run("submodule update --init")
+            return output
+        elif submodule == "recursive":
+            output = self.run("submodule sync --recursive")
+            output += self.run("submodule update --init --recursive")
+            return output
+        else:
+            raise ConanException("Invalid 'submodule' attribute value in the 'scm'. "
+                                 "Unknown value '%s'. Allowed values: ['shallow', 'recursive']"
+                                 % submodule)
+
     def excluded_files(self):
         ret = []
         try:
diff --git a/conans/model/scm.py b/conans/model/scm.py
--- a/conans/model/scm.py
+++ b/conans/model/scm.py
@@ -89,14 +89,17 @@ def checkout(self):
         output = ""
         if self._data.type == "git":
             try:
-                output += self.repo.clone(url=self._data.url, branch=self._data.revision, shallow=True)
+                output += self.repo.clone(url=self._data.url, branch=self._data.revision,
+                                          shallow=True)
             except subprocess.CalledProcessError:
                 # remove the .git directory, otherwise, fallback clone cannot be successful
                 # it's completely safe to do here, as clone without branch expects empty directory
                 rmdir(os.path.join(self.repo_folder, ".git"))
                 output += self.repo.clone(url=self._data.url, shallow=False)
-            output += self.repo.checkout(element=self._data.revision,
-                                         submodule=self._data.submodule)
+                output += self.repo.checkout(element=self._data.revision,
+                                             submodule=self._data.submodule)
+            else:
+                output += self.repo.checkout_submodules(submodule=self._data.submodule)
         else:
             output += self.repo.checkout(url=self._data.url, revision=self._data.revision)
         return output


Test patch:
diff --git a/conans/test/functional/scm/scm_test.py b/conans/test/functional/scm/scm_test.py
--- a/conans/test/functional/scm/scm_test.py
+++ b/conans/test/functional/scm/scm_test.py
@@ -4,6 +4,7 @@
 from collections import namedtuple
 
 from nose.plugins.attrib import attr
+from parameterized.parameterized import parameterized
 
 from conans.client.tools.scm import Git, SVN
 from conans.client.tools.win import get_cased_path
@@ -290,6 +291,38 @@ def source(self):
         self.assertTrue(os.path.exists(os.path.join(curdir, "source", "mysub", "myfile.txt")))
         self.assertIn("SOURCE METHOD CALLED", self.client.out)
 
+    @parameterized.expand([
+        ("local", "v1.0", True),
+        ("local", None, False),
+        ("https://github.com/conan-io/conan.git", "0.22.1", True),
+        ("https://github.com/conan-io/conan.git", "c6cc15fa2f4b576bd70c9df11942e61e5cc7d746", False)])
+    def test_shallow_clone_remote(self, remote, revision, is_tag):
+        # https://github.com/conan-io/conan/issues/5570
+        self.client = TestClient()
+
+        # "remote" git
+        if remote == "local":
+            remote, rev = create_local_git_repo(tags=[revision] if is_tag else None,
+                                                files={"conans/model/username.py": "foo"})
+            if revision is None:  # Get the generated commit
+                revision = rev
+
+        # Use explicit URL to avoid local optimization (scm_folder.txt)
+        conanfile = '''
+import os
+from conans import ConanFile, tools
+
+class ConanLib(ConanFile):
+    name = "lib"
+    version = "0.1"
+    scm = {"type": "git", "url": "%s", "revision": "%s"}
+
+    def build(self):
+        assert os.path.exists(os.path.join(self.build_folder, "conans", "model", "username.py"))
+''' % (remote, revision)
+        self.client.save({"conanfile.py": conanfile})
+        self.client.run("create . user/channel")
+
     def test_install_checked_out(self):
         test_server = TestServer()
         self.servers = {"myremote": test_server}