Repository: geopandas/geopandas

Issue:
BUG: GeoDataFrame.merge incorrectly returning dataframe when geometry columns are present.
Originally discussed in #2931, 

A merge which retains geometry columns, but loses the active geometry column (as in the below) should return a geodataframe to follow consistent downcasting rules with the same case with `loc`/`drop` or `concat`
```python
import geopandas
import shapely
point = shapely.Point(600000, 5000000)
df_1 = geopandas.GeoDataFrame(data={"geom": [shapely.Point([1, 2])]}, geometry="geom", crs="25832")
df_merged = df_1.merge(df_1, left_index=True, right_index=True)
assert type(df_merged) == geopandas.GeoDataFrame # returns a dataframe instead
# Expect this to be the same, but this assertion passes:
res = pd.concat([df_1.geom.rename("geom_x"), df_1.geom.rename("geom_y")], axis=1)
assert type(res) == geopandas.GeoDataFrame
```



Discussion:

Resolving patch:
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -1550,34 +1550,6 @@ def copy(self, deep=True):
             copied._geometry_column_name = self._geometry_column_name
         return copied
 
-    def merge(self, *args, **kwargs):
-        r"""Merge two ``GeoDataFrame`` objects with a database-style join.
-
-        Returns a ``GeoDataFrame`` if a geometry column is present; otherwise,
-        returns a pandas ``DataFrame``.
-
-        Returns
-        -------
-        GeoDataFrame or DataFrame
-
-        Notes
-        -----
-        The extra arguments ``*args`` and keyword arguments ``**kwargs`` are
-        passed to DataFrame.merge.
-        See https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas\
-.DataFrame.merge.html
-        for more details.
-        """
-        result = DataFrame.merge(self, *args, **kwargs)
-        geo_col = self._geometry_column_name
-        if isinstance(result, DataFrame) and geo_col in result:
-            result.__class__ = GeoDataFrame
-            result.crs = self.crs
-            result._geometry_column_name = geo_col
-        elif isinstance(result, DataFrame) and geo_col not in result:
-            result.__class__ = DataFrame
-        return result
-
     @doc(pd.DataFrame)
     def apply(self, func, axis=0, raw=False, result_type=None, args=(), **kwargs):
         result = super().apply(


Test patch:
diff --git a/geopandas/tests/test_op_output_types.py b/geopandas/tests/test_op_output_types.py
--- a/geopandas/tests/test_op_output_types.py
+++ b/geopandas/tests/test_op_output_types.py
@@ -6,7 +6,7 @@
 import numpy as np
 
 from geopandas import GeoDataFrame, GeoSeries
-
+from geopandas.testing import assert_geodataframe_equal
 
 crs_osgb = pyproj.CRS(27700)
 crs_wgs = pyproj.CRS(4326)
@@ -370,3 +370,13 @@ def test_constructor_sliced_in_pandas_methods(df2):
     assert type(hashable_test_df.duplicated()) == pd.Series
     assert type(df2.quantile(numeric_only=True)) == pd.Series
     assert type(df2.memory_usage()) == pd.Series
+
+
+def test_merge_preserve_geodataframe():
+    # https://github.com/geopandas/geopandas/issues/2932
+    ser = GeoSeries.from_xy([1], [1])
+    df = GeoDataFrame({"geo": ser})
+    res = df.merge(df, left_index=True, right_index=True)
+    assert_obj_no_active_geo_col(res, GeoDataFrame, geo_colname=None)
+    expected = GeoDataFrame({"geo_x": ser, "geo_y": ser})
+    assert_geodataframe_equal(expected, res)