We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
unnecessary remote repository fetches
DVC has started cloning external repositories even on cases where it's not strictly required. 
Anything that uses `outs_graph` has started cloning external repositories.

Commands like `add/plots modify/pull/push/fetch/move` are affected, and maybe potentially others.

### Reproduce

```bash
git clone https://github.com/iterative/example-get-started.git
cd example-get-started
dvc add foo
```

### Expected

No cloning occurs.




--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dvc/repo/graph.py`
Content:
```
1 from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Set, TypeVar
2 
3 from dvc.fs import localfs
4 from dvc.utils.fs import path_isin
5 
6 if TYPE_CHECKING:
7     from networkx import DiGraph
8 
9     from dvc.stage import Stage
10 
11 T = TypeVar("T")
12 
13 
14 def check_acyclic(graph: "DiGraph") -> None:
15     import networkx as nx
16 
17     from dvc.exceptions import CyclicGraphError
18 
19     try:
20         edges = nx.find_cycle(graph, orientation="original")
21     except nx.NetworkXNoCycle:
22         return
23 
24     stages: Set["Stage"] = set()
25     for from_node, to_node, _ in edges:
26         stages.add(from_node)
27         stages.add(to_node)
28 
29     raise CyclicGraphError(list(stages))
30 
31 
32 def get_pipeline(pipelines, node):
33     found = [i for i in pipelines if i.has_node(node)]
34     if not found:
35         return None
36 
37     assert len(found) == 1
38     return found[0]
39 
40 
41 def get_pipelines(graph: "DiGraph"):
42     import networkx as nx
43 
44     return [graph.subgraph(c).copy() for c in nx.weakly_connected_components(graph)]
45 
46 
47 def get_subgraph_of_nodes(
48     graph: "DiGraph", sources: Optional[List[Any]] = None, downstream: bool = False
49 ) -> "DiGraph":
50     from networkx import dfs_postorder_nodes, reverse_view
51 
52     if not sources:
53         return graph
54 
55     g = reverse_view(graph) if downstream else graph
56     nodes = []
57     for source in sources:
58         nodes.extend(dfs_postorder_nodes(g, source))
59     return graph.subgraph(nodes)
60 
61 
62 def collect_pipeline(stage: "Stage", graph: "DiGraph") -> Iterator["Stage"]:
63     import networkx as nx
64 
65     pipeline = get_pipeline(get_pipelines(graph), stage)
66     if not pipeline:
67         return iter([])
68 
69     return nx.dfs_postorder_nodes(pipeline, stage)
70 
71 
72 def collect_inside_path(path: str, graph: "DiGraph") -> List["Stage"]:
73     import networkx as nx
74 
75     stages = nx.dfs_postorder_nodes(graph)
76     return [stage for stage in stages if path_isin(stage.path, path)]
77 
78 
79 def build_graph(stages, outs_trie=None):
80     """Generate a graph by using the given stages on the given directory
81 
82     The nodes of the graph are the stage's path relative to the root.
83 
84     Edges are created when the output of one stage is used as a
85     dependency in other stage.
86 
87     The direction of the edges goes from the stage to its dependency:
88 
89     For example, running the following:
90 
91         $ dvc run -o A "echo A > A"
92         $ dvc run -d A -o B "echo B > B"
93         $ dvc run -d B -o C "echo C > C"
94 
95     Will create the following graph:
96 
97            ancestors <--
98                        |
99             C.dvc -> B.dvc -> A.dvc
100             |          |
101             |          --> descendants
102             |
103             ------- pipeline ------>
104                        |
105                        v
106           (weakly connected components)
107 
108     Args:
109         stages (list): used to build a graph from
110 
111     Raises:
112         OutputDuplicationError: two outputs with the same path
113         StagePathAsOutputError: stage inside an output directory
114         OverlappingOutputPathsError: output inside output directory
115         CyclicGraphError: resulting graph has cycles
116     """
117     import networkx as nx
118 
119     from dvc.exceptions import StagePathAsOutputError
120 
121     from .trie import build_outs_trie
122 
123     graph = nx.DiGraph()
124 
125     # Use trie to efficiently find overlapping outs and deps
126     outs_trie = outs_trie or build_outs_trie(stages)
127 
128     for stage in stages:
129         out = outs_trie.shortest_prefix(localfs.path.parts(stage.path)).value
130         if out:
131             raise StagePathAsOutputError(stage, str(out))
132 
133     # Building graph
134     graph.add_nodes_from(stages)
135     for stage in stages:
136         if stage.is_repo_import:
137             continue
138 
139         for dep in stage.deps:
140             dep_key = dep.fs.path.parts(dep.fs_path)
141             overlapping = [n.value for n in outs_trie.prefixes(dep_key)]
142             if outs_trie.has_subtrie(dep_key):
143                 overlapping.extend(outs_trie.values(prefix=dep_key))
144 
145             graph.add_edges_from((stage, out.stage) for out in overlapping)
146     check_acyclic(graph)
147 
148     return graph
149 
150 
151 # NOTE: using stage graph instead of just list of stages to make sure that it
152 # has already passed all the sanity checks like cycles/overlapping outputs and
153 # so on.
154 def build_outs_graph(graph, outs_trie):
155     import networkx as nx
156 
157     outs_graph = nx.DiGraph()
158 
159     outs_graph.add_nodes_from(outs_trie.values())
160     for stage in graph.nodes():
161         for dep in stage.deps:
162             if dep.fs_path is None:
163                 # RepoDependency don't have a path
164                 continue
165             dep_key = dep.fs.path.parts(dep.fs_path)
166             overlapping = [n.value for n in outs_trie.prefixes(dep_key)]
167             if outs_trie.has_subtrie(dep_key):
168                 overlapping.extend(outs_trie.values(prefix=dep_key))
169 
170             for from_out in stage.outs:
171                 outs_graph.add_edges_from((from_out, out) for out in overlapping)
172     return outs_graph
173
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dvc/repo/graph.py b/dvc/repo/graph.py
--- a/dvc/repo/graph.py
+++ b/dvc/repo/graph.py
@@ -158,10 +158,9 @@
 
     outs_graph.add_nodes_from(outs_trie.values())
     for stage in graph.nodes():
+        if stage.is_repo_import:
+            continue
         for dep in stage.deps:
-            if dep.fs_path is None:
-                # RepoDependency don't have a path
-                continue
             dep_key = dep.fs.path.parts(dep.fs_path)
             overlapping = [n.value for n in outs_trie.prefixes(dep_key)]
             if outs_trie.has_subtrie(dep_key):

{"golden_diff": "diff --git a/dvc/repo/graph.py b/dvc/repo/graph.py\n--- a/dvc/repo/graph.py\n+++ b/dvc/repo/graph.py\n@@ -158,10 +158,9 @@\n \n     outs_graph.add_nodes_from(outs_trie.values())\n     for stage in graph.nodes():\n+        if stage.is_repo_import:\n+            continue\n         for dep in stage.deps:\n-            if dep.fs_path is None:\n-                # RepoDependency don't have a path\n-                continue\n             dep_key = dep.fs.path.parts(dep.fs_path)\n             overlapping = [n.value for n in outs_trie.prefixes(dep_key)]\n             if outs_trie.has_subtrie(dep_key):\n", "issue": "unnecessary remote repository fetches\nDVC has started cloning external repositories even on cases where it's not strictly required. \r\nAnything that uses `outs_graph` has started cloning external repositories.\r\n\r\nCommands like `add/plots modify/pull/push/fetch/move` are affected, and maybe potentially others.\r\n\r\n### Reproduce\r\n\r\n```bash\r\ngit clone https://github.com/iterative/example-get-started.git\r\ncd example-get-started\r\ndvc add foo\r\n```\r\n\r\n### Expected\r\n\r\nNo cloning occurs.\r\n\r\n\r\n\n", "before_files": [{"content": "from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Set, TypeVar\n\nfrom dvc.fs import localfs\nfrom dvc.utils.fs import path_isin\n\nif TYPE_CHECKING:\n    from networkx import DiGraph\n\n    from dvc.stage import Stage\n\nT = TypeVar(\"T\")\n\n\ndef check_acyclic(graph: \"DiGraph\") -> None:\n    import networkx as nx\n\n    from dvc.exceptions import CyclicGraphError\n\n    try:\n        edges = nx.find_cycle(graph, orientation=\"original\")\n    except nx.NetworkXNoCycle:\n        return\n\n    stages: Set[\"Stage\"] = set()\n    for from_node, to_node, _ in edges:\n        stages.add(from_node)\n        stages.add(to_node)\n\n    raise CyclicGraphError(list(stages))\n\n\ndef get_pipeline(pipelines, node):\n    found = [i for i in pipelines if i.has_node(node)]\n    if not found:\n        return None\n\n    assert len(found) == 1\n    return found[0]\n\n\ndef get_pipelines(graph: \"DiGraph\"):\n    import networkx as nx\n\n    return [graph.subgraph(c).copy() for c in nx.weakly_connected_components(graph)]\n\n\ndef get_subgraph_of_nodes(\n    graph: \"DiGraph\", sources: Optional[List[Any]] = None, downstream: bool = False\n) -> \"DiGraph\":\n    from networkx import dfs_postorder_nodes, reverse_view\n\n    if not sources:\n        return graph\n\n    g = reverse_view(graph) if downstream else graph\n    nodes = []\n    for source in sources:\n        nodes.extend(dfs_postorder_nodes(g, source))\n    return graph.subgraph(nodes)\n\n\ndef collect_pipeline(stage: \"Stage\", graph: \"DiGraph\") -> Iterator[\"Stage\"]:\n    import networkx as nx\n\n    pipeline = get_pipeline(get_pipelines(graph), stage)\n    if not pipeline:\n        return iter([])\n\n    return nx.dfs_postorder_nodes(pipeline, stage)\n\n\ndef collect_inside_path(path: str, graph: \"DiGraph\") -> List[\"Stage\"]:\n    import networkx as nx\n\n    stages = nx.dfs_postorder_nodes(graph)\n    return [stage for stage in stages if path_isin(stage.path, path)]\n\n\ndef build_graph(stages, outs_trie=None):\n    \"\"\"Generate a graph by using the given stages on the given directory\n\n    The nodes of the graph are the stage's path relative to the root.\n\n    Edges are created when the output of one stage is used as a\n    dependency in other stage.\n\n    The direction of the edges goes from the stage to its dependency:\n\n    For example, running the following:\n\n        $ dvc run -o A \"echo A > A\"\n        $ dvc run -d A -o B \"echo B > B\"\n        $ dvc run -d B -o C \"echo C > C\"\n\n    Will create the following graph:\n\n           ancestors <--\n                       |\n            C.dvc -> B.dvc -> A.dvc\n            |          |\n            |          --> descendants\n            |\n            ------- pipeline ------>\n                       |\n                       v\n          (weakly connected components)\n\n    Args:\n        stages (list): used to build a graph from\n\n    Raises:\n        OutputDuplicationError: two outputs with the same path\n        StagePathAsOutputError: stage inside an output directory\n        OverlappingOutputPathsError: output inside output directory\n        CyclicGraphError: resulting graph has cycles\n    \"\"\"\n    import networkx as nx\n\n    from dvc.exceptions import StagePathAsOutputError\n\n    from .trie import build_outs_trie\n\n    graph = nx.DiGraph()\n\n    # Use trie to efficiently find overlapping outs and deps\n    outs_trie = outs_trie or build_outs_trie(stages)\n\n    for stage in stages:\n        out = outs_trie.shortest_prefix(localfs.path.parts(stage.path)).value\n        if out:\n            raise StagePathAsOutputError(stage, str(out))\n\n    # Building graph\n    graph.add_nodes_from(stages)\n    for stage in stages:\n        if stage.is_repo_import:\n            continue\n\n        for dep in stage.deps:\n            dep_key = dep.fs.path.parts(dep.fs_path)\n            overlapping = [n.value for n in outs_trie.prefixes(dep_key)]\n            if outs_trie.has_subtrie(dep_key):\n                overlapping.extend(outs_trie.values(prefix=dep_key))\n\n            graph.add_edges_from((stage, out.stage) for out in overlapping)\n    check_acyclic(graph)\n\n    return graph\n\n\n# NOTE: using stage graph instead of just list of stages to make sure that it\n# has already passed all the sanity checks like cycles/overlapping outputs and\n# so on.\ndef build_outs_graph(graph, outs_trie):\n    import networkx as nx\n\n    outs_graph = nx.DiGraph()\n\n    outs_graph.add_nodes_from(outs_trie.values())\n    for stage in graph.nodes():\n        for dep in stage.deps:\n            if dep.fs_path is None:\n                # RepoDependency don't have a path\n                continue\n            dep_key = dep.fs.path.parts(dep.fs_path)\n            overlapping = [n.value for n in outs_trie.prefixes(dep_key)]\n            if outs_trie.has_subtrie(dep_key):\n                overlapping.extend(outs_trie.values(prefix=dep_key))\n\n            for from_out in stage.outs:\n                outs_graph.add_edges_from((from_out, out) for out in overlapping)\n    return outs_graph\n", "path": "dvc/repo/graph.py"}], "after_files": [{"content": "from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Set, TypeVar\n\nfrom dvc.fs import localfs\nfrom dvc.utils.fs import path_isin\n\nif TYPE_CHECKING:\n    from networkx import DiGraph\n\n    from dvc.stage import Stage\n\nT = TypeVar(\"T\")\n\n\ndef check_acyclic(graph: \"DiGraph\") -> None:\n    import networkx as nx\n\n    from dvc.exceptions import CyclicGraphError\n\n    try:\n        edges = nx.find_cycle(graph, orientation=\"original\")\n    except nx.NetworkXNoCycle:\n        return\n\n    stages: Set[\"Stage\"] = set()\n    for from_node, to_node, _ in edges:\n        stages.add(from_node)\n        stages.add(to_node)\n\n    raise CyclicGraphError(list(stages))\n\n\ndef get_pipeline(pipelines, node):\n    found = [i for i in pipelines if i.has_node(node)]\n    if not found:\n        return None\n\n    assert len(found) == 1\n    return found[0]\n\n\ndef get_pipelines(graph: \"DiGraph\"):\n    import networkx as nx\n\n    return [graph.subgraph(c).copy() for c in nx.weakly_connected_components(graph)]\n\n\ndef get_subgraph_of_nodes(\n    graph: \"DiGraph\", sources: Optional[List[Any]] = None, downstream: bool = False\n) -> \"DiGraph\":\n    from networkx import dfs_postorder_nodes, reverse_view\n\n    if not sources:\n        return graph\n\n    g = reverse_view(graph) if downstream else graph\n    nodes = []\n    for source in sources:\n        nodes.extend(dfs_postorder_nodes(g, source))\n    return graph.subgraph(nodes)\n\n\ndef collect_pipeline(stage: \"Stage\", graph: \"DiGraph\") -> Iterator[\"Stage\"]:\n    import networkx as nx\n\n    pipeline = get_pipeline(get_pipelines(graph), stage)\n    if not pipeline:\n        return iter([])\n\n    return nx.dfs_postorder_nodes(pipeline, stage)\n\n\ndef collect_inside_path(path: str, graph: \"DiGraph\") -> List[\"Stage\"]:\n    import networkx as nx\n\n    stages = nx.dfs_postorder_nodes(graph)\n    return [stage for stage in stages if path_isin(stage.path, path)]\n\n\ndef build_graph(stages, outs_trie=None):\n    \"\"\"Generate a graph by using the given stages on the given directory\n\n    The nodes of the graph are the stage's path relative to the root.\n\n    Edges are created when the output of one stage is used as a\n    dependency in other stage.\n\n    The direction of the edges goes from the stage to its dependency:\n\n    For example, running the following:\n\n        $ dvc run -o A \"echo A > A\"\n        $ dvc run -d A -o B \"echo B > B\"\n        $ dvc run -d B -o C \"echo C > C\"\n\n    Will create the following graph:\n\n           ancestors <--\n                       |\n            C.dvc -> B.dvc -> A.dvc\n            |          |\n            |          --> descendants\n            |\n            ------- pipeline ------>\n                       |\n                       v\n          (weakly connected components)\n\n    Args:\n        stages (list): used to build a graph from\n\n    Raises:\n        OutputDuplicationError: two outputs with the same path\n        StagePathAsOutputError: stage inside an output directory\n        OverlappingOutputPathsError: output inside output directory\n        CyclicGraphError: resulting graph has cycles\n    \"\"\"\n    import networkx as nx\n\n    from dvc.exceptions import StagePathAsOutputError\n\n    from .trie import build_outs_trie\n\n    graph = nx.DiGraph()\n\n    # Use trie to efficiently find overlapping outs and deps\n    outs_trie = outs_trie or build_outs_trie(stages)\n\n    for stage in stages:\n        out = outs_trie.shortest_prefix(localfs.path.parts(stage.path)).value\n        if out:\n            raise StagePathAsOutputError(stage, str(out))\n\n    # Building graph\n    graph.add_nodes_from(stages)\n    for stage in stages:\n        if stage.is_repo_import:\n            continue\n\n        for dep in stage.deps:\n            dep_key = dep.fs.path.parts(dep.fs_path)\n            overlapping = [n.value for n in outs_trie.prefixes(dep_key)]\n            if outs_trie.has_subtrie(dep_key):\n                overlapping.extend(outs_trie.values(prefix=dep_key))\n\n            graph.add_edges_from((stage, out.stage) for out in overlapping)\n    check_acyclic(graph)\n\n    return graph\n\n\n# NOTE: using stage graph instead of just list of stages to make sure that it\n# has already passed all the sanity checks like cycles/overlapping outputs and\n# so on.\ndef build_outs_graph(graph, outs_trie):\n    import networkx as nx\n\n    outs_graph = nx.DiGraph()\n\n    outs_graph.add_nodes_from(outs_trie.values())\n    for stage in graph.nodes():\n        if stage.is_repo_import:\n            continue\n        for dep in stage.deps:\n            dep_key = dep.fs.path.parts(dep.fs_path)\n            overlapping = [n.value for n in outs_trie.prefixes(dep_key)]\n            if outs_trie.has_subtrie(dep_key):\n                overlapping.extend(outs_trie.values(prefix=dep_key))\n\n            for from_out in stage.outs:\n                outs_graph.add_edges_from((from_out, out) for out in overlapping)\n    return outs_graph\n", "path": "dvc/repo/graph.py"}]}