diff --git a/docs/changelog.md b/docs/changelog.md index b5ac213b..3afb486b 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,16 @@ -### v1.4.0 - 2024-04-24 (DEV) +### vX.X.X - 2024-06-13 (DEV) -Description +Bug Fix and Feature release + +#### Added + +* Add commit filter to show only the first parent in the commit list view + +---- + +### v1.4.0 - 2024-04-24 + +Bug Fix and Feature release #### Added diff --git a/src/git/Commit.cpp b/src/git/Commit.cpp index 334120c5..1cdae15f 100644 --- a/src/git/Commit.cpp +++ b/src/git/Commit.cpp @@ -200,7 +200,7 @@ QList Commit::refs() const { return refs; } -RevWalk Commit::walker(int sort) const { +RevWalk Commit::walker(int sort, bool firstCommitOnly) const { git_revwalk *revwalk = nullptr; if (git_revwalk_new(&revwalk, git_object_owner(d.data()))) return RevWalk(); @@ -209,6 +209,9 @@ RevWalk Commit::walker(int sort) const { if (git_revwalk_push(revwalk, git_object_id(d.data()))) return RevWalk(); + if (firstCommitOnly && git_revwalk_simplify_first_parent(revwalk)) + return RevWalk(); + git_revwalk_sorting(revwalk, sort); return walker; diff --git a/src/git/Commit.h b/src/git/Commit.h index 51d02be5..11c73a1c 100644 --- a/src/git/Commit.h +++ b/src/git/Commit.h @@ -56,7 +56,7 @@ public: QList refs() const; // Create a walker starting from this commit. - RevWalk walker(int sort = GIT_SORT_NONE) const; + RevWalk walker(int sort = GIT_SORT_NONE, bool firstCommitOnly = false) const; // Calculate difference in commits between this and the given commit. // Commits that have diverged calculate the distance to a common base. diff --git a/src/git/Config.h b/src/git/Config.h index fa5ae1cc..fe2afd8f 100644 --- a/src/git/Config.h +++ b/src/git/Config.h @@ -111,13 +111,15 @@ template <> void Config::setValue(const QString &, const QString &); template T Config::value(const QString &key, const T &defaultValue) const { - static_assert(sizeof(T) == 0, "no specialization found"); + static_assert(sizeof(T) == 0, "no specialization found. Please implement " + "specialization for this type!"); return T(); } template void Config::setValue(const QString &key, const T &value) { - static_assert(sizeof(T) == 0, "no specialization found"); + static_assert(sizeof(T) == 0, "no specialization found. Please implement " + "specialization for this type!"); } } // namespace git diff --git a/src/git/Reference.cpp b/src/git/Reference.cpp index 1e0fb6e5..d0226b2e 100644 --- a/src/git/Reference.cpp +++ b/src/git/Reference.cpp @@ -73,9 +73,9 @@ QString Reference::qualifiedName() const { return git_reference_name(d.data()); } -RevWalk Reference::walker(int sort) const { +RevWalk Reference::walker(int sort, bool firstCommitOnly) const { Commit commit = target(); - return commit.isValid() ? commit.walker(sort) : RevWalk(); + return commit.isValid() ? commit.walker(sort, firstCommitOnly) : RevWalk(); } int Reference::difference(const Reference &ref) const { diff --git a/src/git/Reference.h b/src/git/Reference.h index 3fccd972..8dbe137a 100644 --- a/src/git/Reference.h +++ b/src/git/Reference.h @@ -47,7 +47,7 @@ public: QString qualifiedName() const; // Create a walker over the referenced commit. - RevWalk walker(int sort = GIT_SORT_NONE) const; + RevWalk walker(int sort = GIT_SORT_NONE, bool firstCommitOnly = false) const; // Calculate difference in commits between this and the given reference. // References that have diverged calculate the distance to a common base. diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 2e69f48e..79d96f80 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -53,7 +53,8 @@ add_library( TreeProxy.cpp TreeView.cpp TreeWidget.cpp - ViewDelegate.cpp) + ViewDelegate.cpp + ConfigKeys.cpp) target_compile_definitions(ui PRIVATE BUILD_DESCRIPTION="${BUILD_DESCRIPTION}") diff --git a/src/ui/CommitList.cpp b/src/ui/CommitList.cpp index c3222233..4f303a97 100644 --- a/src/ui/CommitList.cpp +++ b/src/ui/CommitList.cpp @@ -14,6 +14,7 @@ #include "ProgressIndicator.h" #include "RepoView.h" #include "Debug.h" +#include "ConfigKeys.h" #include "app/Application.h" #include "conf/Settings.h" #include "dialogs/MergeDialog.h" @@ -208,7 +209,8 @@ public: sort |= GIT_SORT_TOPOLOGICAL; } - mWalker = mRef.walker(sort); + mWalker = mRef.walker( + sort, mRefsFilter == CommitList::RefsFilter::SelectedRefIgnoreMerge); if (mRef.isLocalBranch()) { // Add the upstream branch. if (git::Branch upstream = git::Branch(mRef).upstream()) @@ -221,7 +223,7 @@ public: mWalker.push(mergeHead); } - if (mRefsAll) { + if (mRefsFilter == CommitList::RefsFilter::AllRefs) { foreach (const git::Reference ref, mRepo.refs()) { if (!ref.isStash()) mWalker.push(ref); @@ -237,10 +239,11 @@ public: void resetSettings(bool walk = false) { git::Config config = mRepo.appConfig(); - mRefsAll = config.value("commit.refs.all", true); - mSortDate = config.value("commit.sort.date", true); - mShowCleanStatus = config.value("commit.show.status", true); - mGraphVisible = config.value("commit.graph.visible", true); + mRefsFilter = static_cast(config.value( + ConfigKeys::kRefsKey, (int)CommitList::RefsFilter::AllRefs)); + mSortDate = config.value(ConfigKeys::kSortKey, true); + mShowCleanStatus = config.value(ConfigKeys::kStatusKey, true); + mGraphVisible = config.value(ConfigKeys::kGraphKey, true); if (walk) resetWalker(); @@ -273,6 +276,9 @@ public: // FIXME: Mark commits that point to existing parent? if (indexOf(parent) < 0 && !contains(parent, rows)) replacements.append(parent); + if (mRefsFilter == CommitList::RefsFilter::SelectedRefIgnoreMerge) { + break; + } } // Set parents for next row. @@ -557,7 +563,7 @@ private: // walker settings bool mSuppressResetWalker{false}; - bool mRefsAll = true; + CommitList::RefsFilter mRefsFilter{CommitList::RefsFilter::AllRefs}; bool mSortDate = true; bool mShowCleanStatus = true; bool mGraphVisible = true; diff --git a/src/ui/CommitList.h b/src/ui/CommitList.h index ac236f6a..1454d781 100644 --- a/src/ui/CommitList.h +++ b/src/ui/CommitList.h @@ -25,6 +25,11 @@ class CommitList : public QListView { public: enum Role { DiffRole = Qt::UserRole, CommitRole, GraphRole, GraphColorRole }; + enum class RefsFilter { + AllRefs, + SelectedRef, + SelectedRefIgnoreMerge, + }; CommitList(Index *index, QWidget *parent = nullptr); diff --git a/src/ui/CommitToolBar.cpp b/src/ui/CommitToolBar.cpp index a8eb3751..f4c5178d 100644 --- a/src/ui/CommitToolBar.cpp +++ b/src/ui/CommitToolBar.cpp @@ -8,8 +8,10 @@ // #include "CommitToolBar.h" +#include "CommitList.h" #include "ContextMenuButton.h" #include "RepoView.h" +#include "ConfigKeys.h" #include "conf/Settings.h" #include "git/Config.h" #include @@ -22,10 +24,6 @@ namespace { -const QString kRefsKey = "commit.refs.all"; -const QString kSortKey = "commit.sort.date"; -const QString kGraphKey = "commit.graph.visible"; -const QString kStatusKey = "commit.show.status"; const QString kStyleSheet = "QToolBar {" " border: none" "}" @@ -34,17 +32,16 @@ const QString kStyleSheet = "QToolBar {" " border-radius: 4px;" " padding-right: 12px" "}"; - -struct SettingsEntry { +template struct SettingsEntry { QString key; - bool value; + T value; }; -using SettingsMap = QMap; +template using SettingsMap = QMap>; -class ToolButton : public QToolButton { +template class ToolButton : public QToolButton { public: - ToolButton(const SettingsMap &map, CommitToolBar *parent) + ToolButton(const SettingsMap &map, CommitToolBar *parent, T defaultValue) : QToolButton(parent) { setPopupMode(QToolButton::InstantPopup); @@ -58,8 +55,8 @@ public: action->setCheckable(true); actions->addAction(action); - const SettingsEntry &entry = map.value(key); - if (config.value(entry.key, true) == entry.value) { + const SettingsEntry &entry = map.value(key); + if (config.value(entry.key, defaultValue) == entry.value) { action->setChecked(true); setText(action->text()); } @@ -119,15 +116,22 @@ CommitToolBar::CommitToolBar(QWidget *parent) : QToolBar(parent) { setStyleSheet(kStyleSheet); setToolButtonStyle(Qt::ToolButtonTextOnly); - SettingsMap refsMap; - refsMap.insert(tr("Show All Branches"), {kRefsKey, true}); - refsMap.insert(tr("Show Selected Branch"), {kRefsKey, false}); - addWidget(new ToolButton(refsMap, this)); + SettingsMap refsMap; + refsMap.insert(tr("Show All Branches"), + {ConfigKeys::kRefsKey, (int)CommitList::RefsFilter::AllRefs}); + refsMap.insert( + tr("Show Selected Branch"), + {ConfigKeys::kRefsKey, (int)CommitList::RefsFilter::SelectedRef}); + refsMap.insert(tr("Show Selected Branch, First Parent Only"), + {ConfigKeys::kRefsKey, + (int)CommitList::RefsFilter::SelectedRefIgnoreMerge}); + addWidget( + new ToolButton(refsMap, this, (int)CommitList::RefsFilter::AllRefs)); - SettingsMap sortMap; - sortMap.insert(tr("Sort by Date"), {kSortKey, true}); - sortMap.insert(tr("Sort Topologically"), {kSortKey, false}); - addWidget(new ToolButton(sortMap, this)); + SettingsMap sortMap; + sortMap.insert(tr("Sort by Date"), {ConfigKeys::kSortKey, true}); + sortMap.insert(tr("Sort Topologically"), {ConfigKeys::kSortKey, false}); + addWidget(new ToolButton(sortMap, this, true)); QWidget *spacer = new QWidget(this); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -145,20 +149,20 @@ CommitToolBar::CommitToolBar(QWidget *parent) : QToolBar(parent) { QAction *graph = menu->addAction(tr("Show Graph")); graph->setCheckable(true); - graph->setChecked(config.value(kGraphKey, true)); + graph->setChecked(config.value(ConfigKeys::kGraphKey, true)); connect(graph, &QAction::triggered, [this](bool checked) { RepoView *view = RepoView::parentView(this); git::Config config = view->repo().appConfig(); - config.setValue(kGraphKey, checked); + config.setValue(ConfigKeys::kGraphKey, checked); emit settingsChanged(); }); QAction *status = menu->addAction(tr("Show Clean Status")); status->setCheckable(true); - status->setChecked(config.value(kStatusKey, true)); + status->setChecked(config.value(ConfigKeys::kStatusKey, true)); connect(status, &QAction::triggered, [this](bool checked) { RepoView *view = RepoView::parentView(this); - view->repo().appConfig().setValue(kStatusKey, checked); + view->repo().appConfig().setValue(ConfigKeys::kStatusKey, checked); emit settingsChanged(); }); diff --git a/src/ui/ConfigKeys.cpp b/src/ui/ConfigKeys.cpp new file mode 100644 index 00000000..267b6ef7 --- /dev/null +++ b/src/ui/ConfigKeys.cpp @@ -0,0 +1,9 @@ +#include +#include "ConfigKeys.h" + +namespace ConfigKeys { +const QString kRefsKey = "commit.refs.all"; +const QString kSortKey = "commit.sort.date"; +const QString kGraphKey = "commit.graph.visible"; +const QString kStatusKey = "commit.show.status"; +} // namespace ConfigKeys diff --git a/src/ui/ConfigKeys.h b/src/ui/ConfigKeys.h new file mode 100644 index 00000000..11bfd8c7 --- /dev/null +++ b/src/ui/ConfigKeys.h @@ -0,0 +1,13 @@ +#ifndef CONFIGKEYS_H +#define CONFIGKEYS_H + +#include + +namespace ConfigKeys { +extern const QString kRefsKey; +extern const QString kSortKey; +extern const QString kGraphKey; +extern const QString kStatusKey; +} // namespace ConfigKeys + +#endif // CONFIGKEYS_H diff --git a/src/ui/ReferenceWidget.cpp b/src/ui/ReferenceWidget.cpp index f7f54f7d..495b029f 100644 --- a/src/ui/ReferenceWidget.cpp +++ b/src/ui/ReferenceWidget.cpp @@ -9,6 +9,7 @@ #include "ReferenceWidget.h" #include "ExpandButton.h" +#include "ConfigKeys.h" #include "git/Config.h" #include "git/Reference.h" #include "git/Repository.h" @@ -88,7 +89,7 @@ public: QItemSelectionModel::SelectionFlags command) override { QModelIndex current = index; git::Reference head = mRepo.head(); - bool all = mRepo.appConfig().value("commit.refs.all", true); + bool all = mRepo.appConfig().value(ConfigKeys::kRefsKey, true); git::Reference ref = index.data(Qt::UserRole).value(); if (all && ref && !ref.isHead() && !ref.isStash() && head.isValid()) current = findReference(model(), head); @@ -201,7 +202,7 @@ void ReferenceWidget::updateLabel(const git::Reference &ref) { git::Reference ReferenceWidget::currentReference() const { git::Reference ref = mView->currentReference(); - bool all = mRepo.appConfig().value("commit.refs.all", true); + bool all = mRepo.appConfig().value(ConfigKeys::kRefsKey, true); return (!all || (ref.isValid() && ref.isStash())) ? ref : mRepo.head(); }