Skip to content

feat: libra add rebase subcommand.#1271

Merged
genedna merged 1 commit into
gitmono-dev:mainfrom
yyjeqhc:feat_libra_rebase
Jul 28, 2025
Merged

feat: libra add rebase subcommand.#1271
genedna merged 1 commit into
gitmono-dev:mainfrom
yyjeqhc:feat_libra_rebase

Conversation

@yyjeqhc

@yyjeqhc yyjeqhc commented Jul 27, 2025

Copy link
Copy Markdown
Contributor

Part of #1239
实现libra rebase子命令的基本功能
目前效果:
libra rebase main
把当前分支变基到main分支。
初始化仓库:

#!/bin/bash

# =================================================================
#  脚本:Rebase 基础功能测试
# =================================================================

# --- 1. 环境准备 ---
echo "===== SCENARIO: BASIC REBASE TEST ====="
rm -rf *.txt .libra
libra init
echo "✅ Repo initialized."

# --- 2. 创建 master 分支的两个基础提交 ---
echo "content1" > file.txt
libra add file.txt
libra commit -m "C1: Add file.txt on master"
echo "✅ C1: Commit on master."

echo "content2" >> file.txt
libra add file.txt
libra commit -m "C2: Modify file.txt on master"
echo "✅ C2: Commit on master. This will be the common ancestor."

# --- 3. 创建并切换到 feature 分支 ---
# feature 分支从 C2 开始
libra switch -c feature
echo "✅ Switched to new branch 'feature'."

# --- 4. 在 feature 分支上创建两个独有的提交 ---
echo "featureA" > feature_a.txt
libra add feature_a.txt
libra commit -m "F1: Add feature_a.txt on feature branch"
echo "✅ F1: Commit on feature branch."

echo "featureB" > feature_b.txt
libra add feature_b.txt
libra commit -m "F2: Add feature_b.txt on feature branch"
echo "✅ F2: Commit on feature branch."

# --- 5. 切换回 master 分支,并让它前进 ---
libra switch master
echo "✅ Switched back to master."

echo "master_change" > master_only.txt
libra add master_only.txt
libra commit -m "C3: Add master_only.txt on master"
echo "✅ C3: Master branch moved forward."

# --- 6. 显示最终状态 ---
echo
echo "🎉 Rebase test repo is ready. Current state:"
echo "Master and feature have diverged from C2."
echo
libra log

测试:

root@MSI:~/724/2# libra switch feature
root@MSI:~/724/2# ls
feature_a.txt  feature_b.txt  file.txt
root@MSI:~/724/2# libra rebase master
Found common ancestor: 6d9c421
Rebasing 2 commits from 'feature' onto 'master'...
Applied: 3c74626
Applied: c80375f
Successfully rebased branch 'feature' onto 'master'.
root@MSI:~/724/2# ls
feature_a.txt  feature_b.txt  file.txt  master_only.txt
root@MSI:~/724/2# cat file.txt
content1
content2

Copilot AI review requested due to automatic review settings July 27, 2025 15:51
@vercel

vercel Bot commented Jul 27, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
mega ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 27, 2025 4:03pm

This comment was marked as outdated.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements the libra rebase subcommand to reapply commits from the current branch on top of another base commit. This basic rebase functionality supports linear rebasing by finding the common ancestor, collecting commits to replay, and applying them sequentially on the new base.

  • Adds complete rebase command implementation with three-way merge logic
  • Implements comprehensive test coverage for basic rebase scenarios
  • Updates CLI interface and documentation for the new rebase functionality

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
libra/src/command/rebase.rs Core rebase implementation with commit replay, merge base finding, and tree operations
libra/tests/command/rebase_test.rs Test suite covering basic rebase and up-to-date scenarios
libra/src/command/mod.rs Module declaration for rebase command
libra/src/cli.rs CLI integration for rebase subcommand
libra/tests/command/mod.rs Test module registration
aria/contents/docs/libra/command/rebase/index.mdx User documentation for rebase command

let original_parent_id = commit_to_replay
.parent_commit_ids
.first()
.ok_or_else(|| "commit to replay has no parents".to_string())?;

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message should be more descriptive and follow standard Git error format. Consider: 'fatal: cannot rebase initial commit'

Suggested change
.ok_or_else(|| "commit to replay has no parents".to_string())?;
.ok_or_else(|| "fatal: cannot rebase initial commit".to_string())?;

Copilot uses AI. Check for mistakes.
// Fall back to commit hash resolution
match util::get_commit_base(reference).await {
Ok(id) => Ok(id),
Err(_) => Err(format!("invalid reference: {reference}")),

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message should follow Git's standard format. Consider: 'fatal: ambiguous argument '{reference}': unknown revision or path not in the working tree.'

Suggested change
Err(_) => Err(format!("invalid reference: {reference}")),
Err(_) => Err(format!("fatal: ambiguous argument '{reference}': unknown revision or path not in the working tree")),

Copilot uses AI. Check for mistakes.
let mut visited2 = HashSet::new();
let mut queue1 = vec![*commit1_id];
let mut queue2 = vec![*commit2_id];
while !queue1.is_empty() || !queue2.is_empty() {

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The merge base algorithm could be optimized. Consider implementing a more efficient approach using commit timestamps or generation numbers to avoid potentially exploring the entire commit history.

Suggested change
while !queue1.is_empty() || !queue2.is_empty() {
while !queue1.is_empty() || !queue2.is_empty() {
// Sort queues by generation numbers or timestamps
queue1.sort_by_key(|id| {
let commit: Commit = load_object(id).map_err(|e| e.to_string()).unwrap();
commit.generation_number // or commit.timestamp
});
queue2.sort_by_key(|id| {
let commit: Commit = load_object(id).map_err(|e| e.to_string()).unwrap();
commit.generation_number // or commit.timestamp
});

Copilot uses AI. Check for mistakes.
merged_items.remove(&path);
}
}
// TODO: Implement proper three-way merge with conflict detection

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation lacks conflict detection and resolution, which is essential for production rebase functionality. This could lead to data loss or incorrect merges when conflicts occur.

Copilot uses AI. Check for mistakes.
Comment on lines +351 to +356
let item = mercury::internal::object::tree::TreeItem {
mode: mercury::internal::object::tree::TreeItemMode::Blob,
name: path.file_name().unwrap().to_str().unwrap().to_string(),
id: *hash,
};
// TODO: Handle file modes properly - currently assumes all files are blobs

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming all files are blobs will cause incorrect behavior for executable files, symlinks, and submodules. This could corrupt the repository state during rebase.

Suggested change
let item = mercury::internal::object::tree::TreeItem {
mode: mercury::internal::object::tree::TreeItemMode::Blob,
name: path.file_name().unwrap().to_str().unwrap().to_string(),
id: *hash,
};
// TODO: Handle file modes properly - currently assumes all files are blobs
let mode = if path.is_file() {
let metadata = fs::metadata(path).map_err(|e| format!("Failed to read metadata: {}", e))?;
if metadata.permissions().mode() & 0o111 != 0 {
mercury::internal::object::tree::TreeItemMode::Executable
} else {
mercury::internal::object::tree::TreeItemMode::Blob
}
} else if path.is_symlink() {
mercury::internal::object::tree::TreeItemMode::Symlink
} else {
mercury::internal::object::tree::TreeItemMode::Submodule
};
let item = mercury::internal::object::tree::TreeItem {
mode,
name: path.file_name().unwrap().to_str().unwrap().to_string(),
id: *hash,
};

Copilot uses AI. Check for mistakes.
"master_change"
);

println!("Basic rebase test passed successfully!");

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Test output should use proper logging or assertions instead of println!. Consider removing this print statement or replacing with a proper test assertion.

Suggested change
println!("Basic rebase test passed successfully!");
// Test passed successfully: all assertions validated.

Copilot uses AI. Check for mistakes.
.await;

// Should complete without errors (already up to date)
println!("Already up-to-date rebase test passed!");

Copilot AI Jul 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Test output should use proper logging or assertions instead of println!. Consider removing this print statement or replacing with a proper test assertion.

Suggested change
println!("Already up-to-date rebase test passed!");
assert!(test::is_branch_up_to_date("feature", "master").await, "Feature branch is not up-to-date with master after rebase.");

Copilot uses AI. Check for mistakes.
@genedna
genedna added this pull request to the merge queue Jul 28, 2025
Merged via the queue into gitmono-dev:main with commit 0682444 Jul 28, 2025
13 checks passed
@yyjeqhc
yyjeqhc deleted the feat_libra_rebase branch July 28, 2025 02:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants