summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-04-18 18:11:17 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-04-18 18:11:17 +0800
commit01c4be5d8819edfa2090da47ccec79b31244b853 (patch)
tree736d193e583c58757c4ff5a592b3d00f6fb0a4b6
parentbc4760cd1c0e8fd40c7bb66c743da13c0c841dc3 (diff)
downloadurn-01c4be5d8819edfa2090da47ccec79b31244b853.tar.gz
Detect staged deletions in status.
-rw-r--r--vcx74
1 files changed, 43 insertions, 31 deletions
diff --git a/vcx b/vcx
index 8c3cbc3..cf850ae 100644
--- a/vcx
+++ b/vcx
@@ -70,69 +70,81 @@ sub run_status {
my $it_idx = stream_index();
my $it_wrk = stream_tree(".");
- my $head = read_head() // '0';
+ # Get the base tree from the last commit
+ my $head = read_head() // to_hex_id(0);
+ my $parent_tree_hash = "";
+ if ($head ne to_hex_id(0)) {
+ my $rev_path = File::Spec->catfile(REV_DIR, $head);
+ if (open my $fh, '<', $rev_path) {
+ while (<$fh>) { if (/^tree:(.*)$/) { $parent_tree_hash = $1; last; } }
+ close $fh;
+ }
+ }
+ my $it_old = stream_tree_file($parent_tree_hash);
+
print "On Revision: $head\n\n";
my $idx = $it_idx->();
my $wrk = $it_wrk->();
+ my $old = $it_old->();
my $found_changes = 0;
- while ($idx || $wrk) {
- # Determine walk direction: -1 (Index only), 1 (Disk only), 0 (Both)
- my $cmp = !defined $idx ? 1
- : !defined $wrk ? -1
- : $idx->{path} cmp $wrk->{path};
+ # Iterate while any of the three sources have entries
+ while ($idx || $wrk || $old) {
+ # Find the alphabetically "lowest" path among the three streams
+ my $path = (sort grep { defined } ($idx->{path}, $wrk->{path}, $old->{path}))[0];
my $flag = "";
my $suffix = "";
- my $path = "";
- if ($cmp < 0) {
- # File exists in Index but is missing from the Disk
- $path = $idx->{path};
+ # Logical check for Deletions (In Old Tree, but missing elsewhere)
+ my $in_old = (defined $old && $old->{path} eq $path);
+ my $in_idx = (defined $idx && $idx->{path} eq $path);
+ my $in_wrk = (defined $wrk && $wrk->{path} eq $path);
+
+ if ($in_old && !$in_idx) {
+ # File existed in last commit but is gone from index -> Staged for Deletion
+ $flag = "[D]";
+ $suffix = "(staged)";
+ }
+ elsif ($in_idx && !$in_wrk) {
+ # In index but missing from disk -> Deleted but not staged
$flag = "[D]";
- $idx = $it_idx->();
}
- elsif ($cmp > 0) {
- # File is on Disk but not yet known to the Index
- $path = $wrk->{path};
+ elsif ($in_wrk && !$in_idx) {
+ # On disk but not in index -> New file (Unstaged)
$flag = "[N]";
- $wrk = $it_wrk->();
}
- else {
+ elsif ($in_idx && $in_wrk) {
# Path exists in both; check for modifications
- $path = $idx->{path};
my $stg_path = File::Spec->catfile(TMP_DIR, $path);
my $is_staged = -e $stg_path;
-
- # Compare workspace metadata against the metadata stored in the Index
- # (The Index metadata was updated during the last 'add' or 'commit')
my $workspace_changed = ($wrk->{mtime} != $idx->{mtime} || $wrk->{size} != $idx->{size});
if ($is_staged) {
if ($workspace_changed) {
- # It's staged, but the workspace has been touched since the 'add'
- $flag = "[M]";
+ $flag = "[M]";
$suffix = "(dirty)";
} else {
- # It's staged and matches the workspace exactly
- # Use hash comparison to see if it's a brand new file
- $flag = ($idx->{s_hash} eq $idx->{b_hash}) ? "[N]" : "[M]";
+ # Compare against c_hash (Committed Hash) to see if it's new or modified
+ $flag = ($idx->{c_hash} eq "-") ? "[N]" : "[M]";
$suffix = "(staged)";
}
- } elsif ($workspace_changed) {
- # Not staged, but differs from the last commit
+ } elsif ($workspace_changed || ($in_old && $idx->{c_hash} ne $old->{hash})) {
+ # Not staged, but differs from last commit
$flag = "[M]";
}
-
- $idx = $it_idx->();
- $wrk = $it_wrk->();
}
if ($flag ne "") {
- printf "%s %s %s\n", $flag, $path, $suffix;
+ printf "%s %s %s\n", $flag, $path, $suffix;
$found_changes = 1;
}
+
+ # Advance iterators if they matched the current path
+ $old = $it_old->() if $in_old;
+ $idx = $it_idx->() if $in_idx;
+ $wrk = $it_wrk->() if $in_wrk;
}
print "No changes detected.\n" unless $found_changes;