Skip to content

fix(git): pass \r through unchanged so clone progress renders correctly - #79

Merged
popomore merged 1 commit into
popomore:masterfrom
xc1427:fix/clone-progress
Apr 8, 2026
Merged

popomore merged 1 commit into
popomore:masterfrom
xc1427:fix/clone-progress

Conversation

@xc1427

@xc1427 xc1427 commented Apr 8, 2026 •

Copy link
Copy Markdown
Contributor

Problem

projj add <repo> shows no clone progress. The output from git clone --progress is piped through a byte loop that re-emits each byte with a 3-space indent prefix. However, the loop set at_line_start = true after every \r and \n.

git uses bare \r (carriage return without \n) to overwrite the current terminal line in-place for progress lines like:

Receiving objects:  45%\rReceiving objects:  46%\r...

Because the old code triggered a new indent after each \r, a " " prefix was injected immediately after the \r — before the next progress text. This placed three spaces between the cursor-reset and the overwrite text, garbling the display and making progress appear blank.

Fix

Only treat \n as a line boundary. \r is now passed through untouched, so git's in-place progress renders correctly. This works for both SSH and HTTPS remotes since the byte-streaming logic is transport-agnostic.

One-line diff in src/git.rs:

- if b == b'\r' || b == b'\n' {
+ if b == b'\n' {

Tests

Two new unit tests added to src/git.rs:

  • test_clone_remote_progress_visible — end-to-end clone via a local bare repo, verifies the cloned file is present after clone_remote returns
  • test_indent_after_newline_not_carriage_return — directly exercises the byte-loop logic, asserting that \r does not inject an indent prefix and \n does

Summary by CodeRabbit

  • Bug Fixes

    • Fixed stderr streaming to avoid inserting extra indentation on carriage returns, preserving git's in-place progress overwrites during cloning.
  • Tests

    • Added an end-to-end clone test verifying cloned contents.
    • Added a unit test ensuring newline vs. carriage-return handling in progress output.

@coderabbitai

coderabbitai Bot commented Apr 8, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Refined clone_remote stderr streaming: indentation (3 spaces) is applied only after \n, not \r, so carriage returns no longer reset line-start state. Added an end-to-end clone test and a unit test for newline vs. carriage-return behavior.

Changes

Cohort / File(s) Summary
Stderr streaming & tests
src/git.rs
Updated clone_remote byte-loop to set at_line_start only on b'\n' (carriage returns emitted without resetting indentation). Added test_clone_remote_progress_visible (end-to-end clone from local bare repo) and test_indent_after_newline_not_carriage_return (verifies \r does not trigger indent, \n does).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibble bytes and watch the stream,
Carriage returns keep their gleam,
Newlines get three spaces shown,
Progress stays alive and known,
Tests hop in to guard the beam.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main change: fixing how carriage returns are handled in clone progress output so it renders correctly.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/git.rs (1)

50-55: ⚠️ Potential issue | 🟡 Minor

Preserve raw stderr bytes instead of formatting chars.

eprint!("{}", b as char) only preserves ASCII. Any UTF-8 coming from git stderr (repo paths, localized messages) will be garbled, so the stream is still not being passed through unchanged. Write the original bytes with Write::write_all instead.

Minimal fix
-        use std::io::{BufReader, Read};
+        use std::io::{self, BufReader, Read, Write};
         let mut reader = BufReader::new(stderr);
+        let stderr_out = io::stderr();
+        let mut out = stderr_out.lock();
         let mut buf = [0u8; 256];
         let mut at_line_start = true;
         loop {
             let n = reader.read(&mut buf)?;
             if n == 0 {
@@
             for &b in &buf[..n] {
                 if at_line_start {
-                    eprint!("   ");
+                    out.write_all(b"   ")?;
                     at_line_start = false;
                 }
-                eprint!("{}", b as char);
+                out.write_all(&[b])?;
                 if b == b'\n' {
                     at_line_start = true;
                 }
             }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/git.rs` around lines 50 - 55, The stderr printing currently converts each
byte to a char with eprint!("{}", b as char) which garbles non-ASCII UTF-8;
change the logic in the same block that uses at_line_start and the byte variable
b to write the raw byte(s) to stderr using a Write implementation (e.g.,
stderr().write_all(&[b])) so the original bytes are preserved; ensure
std::io::Write is in scope and handle any potential write errors the same way
other errors are handled in this function.
🧹 Nitpick comments (1)
src/git.rs (1)

445-496: Unit-test the shared formatter instead of duplicating the loop.

test_clone_remote_progress_visible only proves cloning succeeded, and test_indent_after_newline_not_carriage_return reimplements the current loop instead of calling it. A future regression in clone_remote can therefore pass both tests. Consider extracting the stderr-formatting loop into a small Read -> Write helper and testing that helper directly.

Also applies to: 498-527

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/git.rs` around lines 445 - 496, The tests duplicate the stderr-formatting
loop instead of exercising it, so extract the loop in clone_remote into a small
helper (e.g., format_clone_progress<R: Read, W: Write> or write_stderr_progress)
that takes a Read input and Write output and performs the
newline/carriage-return handling currently duplicated in
test_indent_after_newline_not_carriage_return; update clone_remote to call that
helper, then add a focused unit test for the helper that feeds crafted stderr
bytes and verifies the formatted output instead of reimplementing the loop in
tests like test_clone_remote_progress_visible and
test_indent_after_newline_not_carriage_return.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/git.rs`:
- Around line 50-55: The stderr printing currently converts each byte to a char
with eprint!("{}", b as char) which garbles non-ASCII UTF-8; change the logic in
the same block that uses at_line_start and the byte variable b to write the raw
byte(s) to stderr using a Write implementation (e.g., stderr().write_all(&[b]))
so the original bytes are preserved; ensure std::io::Write is in scope and
handle any potential write errors the same way other errors are handled in this
function.

---

Nitpick comments:
In `@src/git.rs`:
- Around line 445-496: The tests duplicate the stderr-formatting loop instead of
exercising it, so extract the loop in clone_remote into a small helper (e.g.,
format_clone_progress<R: Read, W: Write> or write_stderr_progress) that takes a
Read input and Write output and performs the newline/carriage-return handling
currently duplicated in test_indent_after_newline_not_carriage_return; update
clone_remote to call that helper, then add a focused unit test for the helper
that feeds crafted stderr bytes and verifies the formatted output instead of
reimplementing the loop in tests like test_clone_remote_progress_visible and
test_indent_after_newline_not_carriage_return.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 415616eb-1437-49a8-ba24-23c3cd48fac5

📥 Commits

Reviewing files that changed from the base of the PR and between bc0c088 and d6d6844.

📒 Files selected for processing (1)
  • src/git.rs

@xc1427

xc1427 commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

Here is evidence of the fix working — projj add now shows git clone progress in real time:
2

git uses bare \r (carriage return without \n) to overwrite the current
terminal line in-place for progress output like "Receiving objects: 45%".
The previous code set at_line_start=true after every \r, causing a 3-space
indent prefix to be injected immediately after the \r — before the next
progress text arrived. This placed spaces between the cursor-reset and the
overwrite text, garbling the display.

Fix: only treat \n as a line boundary. \r is now passed through untouched,
so git's in-place progress renders correctly for both SSH and HTTPS remotes.

Adds two tests:
- test_clone_remote_progress_visible: end-to-end clone via local bare repo
- test_indent_after_newline_not_carriage_return: unit-tests the byte loop
@xc1427
xc1427 force-pushed the fix/clone-progress branch from d6d6844 to 717b209 Compare April 8, 2026 11:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/git.rs (1)

453-486: Consider checking git command exit status for better diagnostics.

The git commands don't explicitly verify success. While failures would ultimately cause the final assertions to fail, explicit checks would make test failures easier to diagnose.

🔧 Optional: Add success checks for easier debugging
         let src = tmp.path().join("source.git");
-        std::process::Command::new("git")
+        let output = std::process::Command::new("git")
             .args(["init", "--bare", src.to_str().unwrap()])
             .output()
             .unwrap();
+        assert!(output.status.success(), "git init --bare failed");

Apply similar pattern to other git commands in the test.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/git.rs` around lines 453 - 486, The git Command::new(...) invocations
(the sequences that create the bare repo, clone into work, add/commit/push using
variables src and work) do not verify exit status; change each
.output().unwrap() to capture the output (let out =
std::process::Command::new("git")... .output().expect(...)) and assert or panic
if !out.status.success(), including out.stdout and out.stderr in the message so
failures show git diagnostics (apply this pattern to the init, clone, add,
commit, and push calls).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/git.rs`:
- Around line 453-486: The git Command::new(...) invocations (the sequences that
create the bare repo, clone into work, add/commit/push using variables src and
work) do not verify exit status; change each .output().unwrap() to capture the
output (let out = std::process::Command::new("git")... .output().expect(...))
and assert or panic if !out.status.success(), including out.stdout and
out.stderr in the message so failures show git diagnostics (apply this pattern
to the init, clone, add, commit, and push calls).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 400db3ca-36f2-462c-9f53-62be5a0b2c3b

📥 Commits

Reviewing files that changed from the base of the PR and between d6d6844 and 717b209.

📒 Files selected for processing (1)
  • src/git.rs

@popomore popomore left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Nice catch on the bare \r semantics — fix is minimal and correct, tests lock down the regression. 👍

@codecov

codecov Bot commented Apr 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.00%. Comparing base (bc0c088) to head (717b209).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #79      +/-   ##
==========================================
+ Coverage   91.85%   94.00%   +2.14%     
==========================================
  Files          14       14              
  Lines        1658     1717      +59     
==========================================
+ Hits         1523     1614      +91     
+ Misses        135      103      -32     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@popomore
popomore merged commit 6144eb9 into popomore:master Apr 8, 2026
10 checks passed
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.

2 participants