diff --git a/.gitignore b/.gitignore
index 92d92cf..5aef53c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/libdnf-0.47.0.tar.gz
+SOURCES/libdnf-0.48.0.tar.gz
diff --git a/.libdnf.metadata b/.libdnf.metadata
index 5641ba6..b596b13 100644
--- a/.libdnf.metadata
+++ b/.libdnf.metadata
@@ -1 +1 @@
-66f7cc0af9afff54b06e1cb40ca42549b97ec9d7 SOURCES/libdnf-0.47.0.tar.gz
+452c2195741b627bd97b0be11cd4a4dc4118e330 SOURCES/libdnf-0.48.0.tar.gz
diff --git a/SOURCES/0001-Revert-SWIG-Set-CMake-policies-to-remove-warnings.patch b/SOURCES/0001-Revert-SWIG-Set-CMake-policies-to-remove-warnings.patch
deleted file mode 100644
index 051624a..0000000
--- a/SOURCES/0001-Revert-SWIG-Set-CMake-policies-to-remove-warnings.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0755993c2e06be319eab20f72217100be98f8988 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com>
-Date: Thu, 9 Apr 2020 10:27:34 +0200
-Subject: [PATCH] Revert "SWIG: Set CMake policies to remove warnings"
-
-This reverts commit afd511592195b867eab4e49801053dcc904d6dd0, for the
-most part. The duplicate include(UseSWIG) is kept removed, but the
-cmake_policies actually aren't backwards compatible with Cmake versions
-that don't know them, so we can't use them like this.
-
-Setting the policies behavior only removes some warnings, it's probably
-better to remove them than to wrap them in Cmake version checks.
----
- bindings/python/CMakeLists.txt | 3 ---
- 1 file changed, 3 deletions(-)
-
-diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt
-index 8ef97eb08..32973dce0 100644
---- a/bindings/python/CMakeLists.txt
-+++ b/bindings/python/CMakeLists.txt
-@@ -1,8 +1,5 @@
- find_package(PythonInstDir)
- find_package(SWIG REQUIRED)
--
--cmake_policy(SET CMP0078 OLD)
--cmake_policy(SET CMP0086 OLD)
- include(UseSWIG)
- 
- message(STATUS "Building for python${PYTHON_VERSION_MAJOR}")
diff --git a/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch b/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch
new file mode 100644
index 0000000..079524d
--- /dev/null
+++ b/SOURCES/0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch
@@ -0,0 +1,244 @@
+From a96d701f7f55ff475e11ac9cda63b81c31c54e7a Mon Sep 17 00:00:00 2001
+From: Daniel Mach <dmach@redhat.com>
+Date: Wed, 6 May 2020 08:34:46 +0200
+Subject: [PATCH] history: Fix dnf history rollback when a package was removed
+ (RhBug:1683134)
+
+---
+ libdnf/transaction/MergedTransaction.cpp      |  25 +++-
+ .../transaction/MergedTransactionTest.cpp     | 120 ++++++++++++++++--
+ .../transaction/MergedTransactionTest.hpp     |   6 +-
+ 3 files changed, 137 insertions(+), 14 deletions(-)
+
+diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp
+index a7c06ffa9..a8d878cb5 100644
+--- a/libdnf/transaction/MergedTransaction.cpp
++++ b/libdnf/transaction/MergedTransaction.cpp
+@@ -19,6 +19,7 @@
+  */
+ 
+ #include "MergedTransaction.hpp"
++#include <algorithm>
+ #include <vector>
+ 
+ namespace libdnf {
+@@ -171,6 +172,21 @@ MergedTransaction::getConsoleOutput()
+     return output;
+ }
+ 
++
++static bool transaction_item_sort_function(const std::shared_ptr<TransactionItemBase> lhs, const std::shared_ptr<TransactionItemBase> rhs) {
++    if (lhs->isForwardAction() && rhs->isForwardAction()) {
++        return false;
++    }
++    if (lhs->isBackwardAction() && rhs->isBackwardAction()) {
++        return false;
++    }
++    if (lhs->isBackwardAction()) {
++        return true;
++    }
++    return false;
++}
++
++
+ /**
+  * Get list of transaction items involved in the merged transaction
+  * Actions are merged using following rules:
+@@ -203,6 +219,9 @@ MergedTransaction::getItems()
+     // iterate over transaction
+     for (auto t : transactions) {
+         auto transItems = t->getItems();
++        // sort transaction items by their action type - forward/backward
++        // this fixes behavior of the merging algorithm in several edge cases
++        std::sort(transItems.begin(), transItems.end(), transaction_item_sort_function);
+         // iterate over transaction items
+         for (auto transItem : transItems) {
+             // get item and its type
+@@ -383,10 +402,6 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT
+     auto firstState = previousItemPair.first->getAction();
+     auto newState = mTransItem->getAction();
+ 
+-    if (firstState == TransactionItemAction::INSTALL && mTransItem->isBackwardAction()) {
+-        return;
+-    }
+-
+     switch (firstState) {
+         case TransactionItemAction::REMOVE:
+         case TransactionItemAction::OBSOLETED:
+@@ -399,6 +414,8 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT
+                 // Install -> Remove = (nothing)
+                 itemPairMap.erase(name);
+                 break;
++            } else if (mTransItem->isBackwardAction()) {
++                break;
+             }
+             // altered -> transfer install to the altered package
+             mTransItem->setAction(TransactionItemAction::INSTALL);
+diff --git a/tests/libdnf/transaction/MergedTransactionTest.cpp b/tests/libdnf/transaction/MergedTransactionTest.cpp
+index 90ad182cf..52507700b 100644
+--- a/tests/libdnf/transaction/MergedTransactionTest.cpp
++++ b/tests/libdnf/transaction/MergedTransactionTest.cpp
+@@ -700,7 +700,7 @@ MergedTransactionTest::test_downgrade()
+ }
+ 
+ void
+-MergedTransactionTest::test_install_downgrade()
++MergedTransactionTest::test_install_downgrade_upgrade_remove()
+ {
+     auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+     trans1->addItem(
+@@ -724,19 +724,123 @@ MergedTransactionTest::test_install_downgrade()
+         TransactionItemReason::USER
+     );
+ 
++    auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
++    trans3->addItem(
++        nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
++        "repo2",
++        TransactionItemAction::UPGRADED,
++        TransactionItemReason::USER
++    );
++    trans3->addItem(
++        nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
++        "repo1",
++        TransactionItemAction::UPGRADE,
++        TransactionItemReason::USER
++    );
++
++    auto trans4 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
++    trans4->addItem(
++        nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
++        "repo1",
++        TransactionItemAction::REMOVE,
++        TransactionItemReason::USER
++    );
++
+     MergedTransaction merged(trans1);
++
++    // test merging trans1, trans2
+     merged.merge(trans2);
++    auto items2 = merged.getItems();
++    CPPUNIT_ASSERT_EQUAL(1, (int)items2.size());
++    auto item2 = items2.at(0);
++    CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item2->getItem()->toStr());
++    CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item2->getRepoid());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item2->getAction());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
+ 
+-    auto items = merged.getItems();
+-    CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
++    // test merging trans1, trans2, trans3
++    merged.merge(trans3);
++    auto items3 = merged.getItems();
++    CPPUNIT_ASSERT_EQUAL(1, (int)items3.size());
++    auto item3 = items3.at(0);
++    CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr());
++    CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item3->getAction());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
+ 
+-    auto item = items.at(0);
+-    CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item->getItem()->toStr());
+-    CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item->getRepoid());
+-    CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item->getAction());
+-    CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason());
++    // test merging trans1, trans2, trans3, trans4
++    merged.merge(trans4);
++    auto items4 = merged.getItems();
++    CPPUNIT_ASSERT_EQUAL(0, (int)items4.size());
++    // trans4 removes the package, empty output is expected
+ }
+ 
++
++void
++MergedTransactionTest::test_downgrade_upgrade_remove()
++{
++    auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
++    trans1->addItem(
++        nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
++        "repo2",
++        TransactionItemAction::DOWNGRADE,
++        TransactionItemReason::USER
++    );
++    trans1->addItem(
++        nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
++        "repo1",
++        TransactionItemAction::DOWNGRADED,
++        TransactionItemReason::USER
++    );
++
++    // items are in reversed order than in test_install_downgrade_upgrade_remove()
++    // fixing this required ordering transaction items by forward/backward action
++    auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
++    trans2->addItem(
++        nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
++        "repo1",
++        TransactionItemAction::UPGRADE,
++        TransactionItemReason::USER
++    );
++    trans2->addItem(
++        nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
++        "repo2",
++        TransactionItemAction::UPGRADED,
++        TransactionItemReason::USER
++    );
++
++    auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
++    trans3->addItem(
++        nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
++        "repo1",
++        TransactionItemAction::REMOVE,
++        TransactionItemReason::USER
++    );
++
++    MergedTransaction merged(trans1);
++
++    // test merging trans1, trans2
++    merged.merge(trans2);
++    auto items2 = merged.getItems();
++    CPPUNIT_ASSERT_EQUAL(1, (int)items2.size());
++    auto item2 = items2.at(0);
++    CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item2->getItem()->toStr());
++    CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item2->getRepoid());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item2->getAction());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
++
++    // test merging trans1, trans2, trans3
++    merged.merge(trans3);
++    auto items3 = merged.getItems();
++    CPPUNIT_ASSERT_EQUAL(1, (int)items3.size());
++    auto item3 = items3.at(0);
++    CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr());
++    CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REMOVE, item3->getAction());
++    CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
++}
++
++
+ void
+ MergedTransactionTest::test_multilib_identity()
+ {
+diff --git a/tests/libdnf/transaction/MergedTransactionTest.hpp b/tests/libdnf/transaction/MergedTransactionTest.hpp
+index 9f1ed660a..77585e865 100644
+--- a/tests/libdnf/transaction/MergedTransactionTest.hpp
++++ b/tests/libdnf/transaction/MergedTransactionTest.hpp
+@@ -26,7 +26,8 @@ class MergedTransactionTest : public CppUnit::TestCase {
+     CPPUNIT_TEST(test_add_obsoleted_obsoleted);
+ 
+     CPPUNIT_TEST(test_downgrade);
+-    CPPUNIT_TEST(test_install_downgrade);
++    CPPUNIT_TEST(test_install_downgrade_upgrade_remove);
++    CPPUNIT_TEST(test_downgrade_upgrade_remove);
+ 
+     CPPUNIT_TEST(test_multilib_identity);
+ 
+@@ -56,7 +57,8 @@ class MergedTransactionTest : public CppUnit::TestCase {
+     // END: tests ported from DNF unit tests
+ 
+     void test_downgrade();
+-    void test_install_downgrade();
++    void test_install_downgrade_upgrade_remove();
++    void test_downgrade_upgrade_remove();
+ 
+     void test_multilib_identity();
+ private:
diff --git a/SPECS/libdnf.spec b/SPECS/libdnf.spec
index 340a735..65f8aac 100644
--- a/SPECS/libdnf.spec
+++ b/SPECS/libdnf.spec
@@ -1,10 +1,10 @@
 %global libsolv_version 0.7.7
 %global libmodulemd_version 2.5.0
-%global librepo_version 1.11.3
-%global dnf_conflict 4.2.13
+%global librepo_version 1.12.0
+%global dnf_conflict 4.2.23
 %global swig_version 3.0.12
 %global libdnf_major_version 0
-%global libdnf_minor_version 47
+%global libdnf_minor_version 48
 %global libdnf_micro_version 0
 
 # set sphinx package name according to distro
@@ -46,19 +46,20 @@
 %bcond_without zchunk
 %endif
 
+%bcond_with sanitizers
+
 %global _cmake_opts \\\
     -DENABLE_RHSM_SUPPORT=%{?with_rhsm:ON}%{!?with_rhsm:OFF} \\\
     %{nil}
 
 Name:           libdnf
 Version:        %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version}
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Library providing simplified C and Python API to libsolv
 License:        LGPLv2+
 URL:            https://github.com/rpm-software-management/libdnf
 Source0:        %{url}/archive/%{version}/%{name}-%{version}.tar.gz
-# This patch is needed because rhel has too old cmake version, patch was merged upstream and newer rebases will contain it
-Patch1:         0001-Revert-SWIG-Set-CMake-policies-to-remove-warnings.patch
+Patch1:         0001-history-Fix-dnf-history-rollback-when-a-package-was-removed-RhBug1683134.patch
 
 BuildRequires:  cmake
 BuildRequires:  gcc
@@ -87,6 +88,12 @@ BuildRequires:  pkgconfig(smartcols)
 BuildRequires:  gettext
 BuildRequires:  gpgme-devel
 
+%if %{with sanitizers}
+BuildRequires:  libasan-static
+BuildRequires:  liblsan-static
+BuildRequires:  libubsan-static
+%endif
+
 Requires:       libmodulemd%{?_isa} >= %{libmodulemd_version}
 Requires:       libsolv%{?_isa} >= %{libsolv_version}
 Requires:       librepo%{?_isa} >= %{librepo_version}
@@ -129,7 +136,8 @@ BuildRequires:  swig >= %{swig_version}
 
 %description -n python2-%{name}
 Python 2 bindings for the libdnf library.
-%endif # with python2
+%endif
+# endif with python2
 
 %if %{with python3}
 %package -n python3-%{name}
@@ -163,7 +171,8 @@ Conflicts:      python-dnf < %{dnf_conflict}
 
 %description -n python2-hawkey
 Python 2 bindings for the hawkey library.
-%endif # with python2
+%endif
+# endif with python2
 
 %if %{with python3}
 %package -n python3-hawkey
@@ -187,7 +196,7 @@ Python 3 bindings for the hawkey library.
 %autosetup -p1
 %if %{with python2}
 mkdir build-py2
-%endif # with python2
+%endif
 %if %{with python3}
 mkdir build-py3
 %endif
@@ -200,10 +209,12 @@ pushd build-py2
     %define _cmake_builddir build-py2
     %define __builddir build-py2
   %endif
-  %cmake -DPYTHON_DESIRED:FILEPATH=%{__python2} -DWITH_MAN=OFF ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version}
+  %cmake -DPYTHON_DESIRED:FILEPATH=%{__python2} -DWITH_MAN=OFF ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version} \
+    -DWITH_SANITIZERS=%{?with_sanitizers:ON}%{!?with_sanitizers:OFF}
   %make_build
 popd
-%endif # with python2
+%endif
+# endif with python2
 
 %if %{with python3}
 pushd build-py3
@@ -212,7 +223,8 @@ pushd build-py3
     %define _cmake_builddir build-py3
     %define __builddir build-py3
   %endif
-  %cmake -DPYTHON_DESIRED:FILEPATH=%{__python3} -DWITH_GIR=0 -DWITH_MAN=0 -Dgtkdoc=0 ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version}
+  %cmake -DPYTHON_DESIRED:FILEPATH=%{__python3} -DWITH_GIR=0 -DWITH_MAN=0 -Dgtkdoc=0 ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version} \
+    -DWITH_SANITIZERS=%{?with_sanitizers:ON}%{!?with_sanitizers:OFF}
   %make_build
 popd
 %endif
@@ -222,7 +234,7 @@ popd
 pushd build-py2
   make ARGS="-V" test
 popd
-%endif # with python2
+%endif
 %if %{with python3}
 # If we didn't run the general tests yet, do it now.
 %if %{without python2}
@@ -244,7 +256,7 @@ popd
 pushd build-py2
   %make_install
 popd
-%endif # with python2
+%endif
 %if %{with python3}
 pushd build-py3
   %make_install
@@ -277,7 +289,7 @@ popd
 %if %{with python2}
 %files -n python2-%{name}
 %{python2_sitearch}/%{name}/
-%endif # with python2
+%endif
 
 %if %{with python3}
 %files -n python3-%{name}
@@ -287,7 +299,7 @@ popd
 %if %{with python2}
 %files -n python2-hawkey
 %{python2_sitearch}/hawkey/
-%endif # with python2
+%endif
 
 %if %{with python3}
 %files -n python3-hawkey
@@ -295,6 +307,37 @@ popd
 %endif
 
 %changelog
+* Wed Jun 10 2020 Ales Matej <amatej@redhat.com> - 0.48.0-2
+- [history] Fix dnf history rollback when a package was removed (RhBug:1683134)
+
+* Wed Jun 03 2020 Nicola Sella <nsella@redhat.com> - 0.48.0-1
+- Update to 0.48.0
+- swdb: Catch only SQLite3 exceptions and simplify the messages
+- MergedTransaction list multiple comments (RhBug:1773679)
+- Modify CMake to pull *.po files from weblate
+- Optimize DependencyContainer creation from an existing queue
+- fix a memory leak in dnf_package_get_requires()
+- Fix memory leaks on g_build_filename()
+- Fix memory leak in dnf_context_setup()
+- Add `hy_goal_favor` and `hy_goal_disfavor`
+- Define a cleanup function for `DnfPackageSet`
+- dnf-repo: fix dnf_repo_get_public_keys double-free
+- Do not cache RPMDB
+- Use single-quotes around string literals used in SQL statements
+- SQLite3: Do not close the database if it wasn't opened (RhBug:1761976)
+- Don't create a new history DB connection for in-memory DB
+- transaction/Swdb: Use a single logger variable in constructor
+- utils: Add a safe version of pathExists()
+- swdb: Handle the case when pathExists() fails on e.g. permission
+- Repo: prepend "file://" if a local path is used as baseurl
+- Move urlEncode() to utils
+- utils: Add 'exclude' argument to urlEncode()
+- Encode package URL for downloading through librepo (RhBug:1817130)
+- Replace std::runtime_error with libdnf::RepoError
+- Fixes and error handling improvements of the File class
+- [context] Use ConfigRepo for gpgkey and baseurl (RhBug:1807864)
+- [context] support "priority" option in .repo config file (RhBug:1797265)
+
 * Fri Apr 03 2020 Ales Matej <amatej@redhat.com> - 0.47.0-1
 - Update to 0.47.0
 - Allow excluding packages with "excludepkgs" and globs