Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c3d9056
improve interactive rebase ui
quakj Jun 30, 2026
1e588c2
Merge branch 'main' into feat/rebase
quakj Jun 30, 2026
ba334ab
fix interactive rebase bugs
quakj Jul 1, 2026
b5322aa
add animation support to interactive rebase
quakj Jul 1, 2026
a562111
improved interactive rebase, fixed context menu showing sha instead o…
quakj Jul 1, 2026
d94e180
fix mouse click release outside window
quakj Jul 2, 2026
4afcb0f
fix interactive rebase drag reordering
quakj Jul 2, 2026
8ac7979
initial squash feature implementation
quakj Jul 2, 2026
8b0172a
fix context menu icon alingment, zoom scaling and word wrap
quakj Jul 2, 2026
3b39826
fix review findings: context menu truncation, popover width clamps, p…
quakj Jul 3, 2026
e50459a
fix drag animation flicker
quakj Jul 3, 2026
14a814a
rebase is now implemented per repo
quakj Jul 3, 2026
eadb857
fix code review findings
quakj Jul 3, 2026
ff7e2c1
Merge branch 'feat/rebase' into dev/squash-rebase
quakj Jul 3, 2026
989fc55
fix rebase drag animation
quakj Jul 3, 2026
40b3f4c
refactor interactive rebase to use uniform list
quakj Jul 3, 2026
b5fde94
improve animations
quakj Jul 4, 2026
febf567
support squashing intermediate commit ranges
quakj Jul 4, 2026
fcdc5f1
Merge branch 'dev/squash-rebase' into feat/rebase
quakj Jul 4, 2026
fdf337e
add ScrollbarDriver impl for gpui ListState
quakj Jul 4, 2026
da6c73f
port interactive rebase list to virtualized gpui::list
quakj Jul 4, 2026
3ca09bc
squash-history rebase toast says 'Rebase', not 'Interactive rebase'
quakj Jul 6, 2026
4187402
rebase --continue paused at next conflict is not a failure
quakj Jul 6, 2026
a3c156e
autosquash: fold fixup!/squash!/amend! prefixed commits into their ta…
quakj Jul 6, 2026
98e1068
fmt
quakj Jul 6, 2026
2bb7fbe
hide rebase-onto entries on the HEAD commit
quakj Jul 6, 2026
069d9b0
clippy
quakj Jul 7, 2026
b326772
cherry-pick: add commit cherry-pick via generalized commit editor
quakj Jul 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ __pycache__/
*.pyc
criterion
.codex
.worktrees/
1 change: 1 addition & 0 deletions crates/gitcomet-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ pub mod mergetool_trace;
pub mod path_utils;
pub mod process;
pub mod services;
pub mod squash;
pub mod text_utils;
98 changes: 98 additions & 0 deletions crates/gitcomet-core/src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,49 @@ pub enum RemoteUrlKind {
Push,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InteractiveRebaseAction {
Pick,
Reword,
Edit,
Squash,
Fixup,
Drop,
}

impl InteractiveRebaseAction {
pub fn to_todo_str(self) -> &'static str {
match self {
Self::Pick => "pick",
Self::Reword => "reword",
Self::Edit => "edit",
Self::Squash => "squash",
Self::Fixup => "fixup",
Self::Drop => "drop",
}
}

pub fn label(self) -> &'static str {
match self {
Self::Pick => "Pick",
Self::Reword => "Reword",
Self::Edit => "Edit",
Self::Squash => "Squash",
Self::Fixup => "Fixup",
Self::Drop => "Drop",
}
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InteractiveRebaseEntry {
pub action: InteractiveRebaseAction,
pub commit_id: String,
pub summary: String,
/// New commit message, used only when action is Reword.
pub new_message: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SubmoduleTrustTarget {
pub submodule_path: PathBuf,
Expand Down Expand Up @@ -511,6 +554,11 @@ pub trait GitRepository: Send + Sync {
}
fn checkout_commit(&self, id: &CommitId) -> Result<()>;
fn cherry_pick(&self, id: &CommitId) -> Result<()>;
fn cherry_pick_with_output(&self, _id: &CommitId, _commit: bool) -> Result<CommandOutput> {
Err(Error::new(ErrorKind::Unsupported(
"git cherry-pick is not implemented for this backend",
)))
}
fn revert(&self, id: &CommitId) -> Result<()>;

fn stash_create(&self, message: &str, include_untracked: bool) -> Result<()>;
Expand Down Expand Up @@ -556,6 +604,31 @@ pub trait GitRepository: Send + Sync {
"git rebase --abort is not implemented for this backend",
)))
}
fn list_commits_for_interactive_rebase(
&self,
_base: &str,
) -> Result<Vec<InteractiveRebaseEntry>> {
Err(Error::new(ErrorKind::Unsupported(
"listing commits for interactive rebase is not implemented for this backend",
)))
}
fn interactive_rebase_with_output(
&self,
_base: &str,
_entries: &[InteractiveRebaseEntry],
) -> Result<CommandOutput> {
Err(Error::new(ErrorKind::Unsupported(
"git rebase -i is not implemented for this backend",
)))
}
fn interactive_cherry_pick_with_output(
&self,
_entries: &[InteractiveRebaseEntry],
) -> Result<CommandOutput> {
Err(Error::new(ErrorKind::Unsupported(
"interactive cherry-pick is not implemented for this backend",
)))
}
fn merge_abort_with_output(&self) -> Result<CommandOutput> {
Err(Error::new(ErrorKind::Unsupported(
"git merge --abort is not implemented for this backend",
Expand Down Expand Up @@ -768,6 +841,31 @@ pub trait GitRepository: Send + Sync {
)))
}

/// Builds the default combined message for squashing the linear commit
/// range `oldest..=head`: the oldest commit's full message first, younger
/// messages appended as paragraphs.
fn squash_message_preview(&self, _oldest: &CommitId, _head: &CommitId) -> Result<String> {
Err(Error::new(ErrorKind::Unsupported(
"squashing commits is not implemented for this backend",
)))
}

/// Squashes the linear first-parent range `oldest..=expected_head` (which
/// must end at the current HEAD) into a single commit carrying `message`,
/// preserving the oldest commit's author. Must not touch the worktree or
/// index, and must fail without changing refs when HEAD no longer equals
/// `expected_head`.
fn squash_commits_with_output(
&self,
_oldest: &CommitId,
_expected_head: &CommitId,
_message: &str,
) -> Result<CommandOutput> {
Err(Error::new(ErrorKind::Unsupported(
"squashing commits is not implemented for this backend",
)))
}

fn reset_with_output(&self, _target: &str, _mode: ResetMode) -> Result<CommandOutput> {
Err(Error::new(ErrorKind::Unsupported(
"git reset is not implemented for this backend",
Expand Down
Loading
Loading