prompt: 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()
  
  ```
  
golden_diff: 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):
  
verification_info: {"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"}]}