Show More
@@ -1,343 +1,400 | |||||
1 | // status.rs |
|
1 | // status.rs | |
2 | // |
|
2 | // | |
3 | // Copyright 2020, Georges Racinet <georges.racinets@octobus.net> |
|
3 | // Copyright 2020, Georges Racinet <georges.racinets@octobus.net> | |
4 | // |
|
4 | // | |
5 | // This software may be used and distributed according to the terms of the |
|
5 | // This software may be used and distributed according to the terms of the | |
6 | // GNU General Public License version 2 or any later version. |
|
6 | // GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | use crate::error::CommandError; |
|
8 | use crate::error::CommandError; | |
9 |
use crate::ui:: |
|
9 | use crate::ui::Ui; | |
10 | use crate::utils::path_utils::relativize_paths; |
|
10 | use crate::utils::path_utils::relativize_paths; | |
11 | use clap::{Arg, SubCommand}; |
|
11 | use clap::{Arg, SubCommand}; | |
|
12 | use format_bytes::format_bytes; | |||
12 | use hg; |
|
13 | use hg; | |
13 | use hg::config::Config; |
|
14 | use hg::config::Config; | |
14 | use hg::dirstate::{has_exec_bit, TruncatedTimestamp}; |
|
15 | use hg::dirstate::{has_exec_bit, TruncatedTimestamp}; | |
15 | use hg::errors::HgError; |
|
16 | use hg::errors::HgError; | |
16 | use hg::manifest::Manifest; |
|
17 | use hg::manifest::Manifest; | |
17 | use hg::matchers::AlwaysMatcher; |
|
18 | use hg::matchers::AlwaysMatcher; | |
18 | use hg::repo::Repo; |
|
19 | use hg::repo::Repo; | |
19 | use hg::utils::files::get_bytes_from_os_string; |
|
20 | use hg::utils::files::get_bytes_from_os_string; | |
20 | use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; |
|
21 | use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; | |
21 | use hg::{HgPathCow, StatusOptions}; |
|
22 | use hg::{HgPathCow, StatusOptions}; | |
22 | use log::{info, warn}; |
|
23 | use log::{info, warn}; | |
23 | use std::borrow::Cow; |
|
|||
24 |
|
24 | |||
25 | pub const HELP_TEXT: &str = " |
|
25 | pub const HELP_TEXT: &str = " | |
26 | Show changed files in the working directory |
|
26 | Show changed files in the working directory | |
27 |
|
27 | |||
28 | This is a pure Rust version of `hg status`. |
|
28 | This is a pure Rust version of `hg status`. | |
29 |
|
29 | |||
30 | Some options might be missing, check the list below. |
|
30 | Some options might be missing, check the list below. | |
31 | "; |
|
31 | "; | |
32 |
|
32 | |||
33 | pub fn args() -> clap::App<'static, 'static> { |
|
33 | pub fn args() -> clap::App<'static, 'static> { | |
34 | SubCommand::with_name("status") |
|
34 | SubCommand::with_name("status") | |
35 | .alias("st") |
|
35 | .alias("st") | |
36 | .about(HELP_TEXT) |
|
36 | .about(HELP_TEXT) | |
37 | .arg( |
|
37 | .arg( | |
38 | Arg::with_name("all") |
|
38 | Arg::with_name("all") | |
39 | .help("show status of all files") |
|
39 | .help("show status of all files") | |
40 | .short("-A") |
|
40 | .short("-A") | |
41 | .long("--all"), |
|
41 | .long("--all"), | |
42 | ) |
|
42 | ) | |
43 | .arg( |
|
43 | .arg( | |
44 | Arg::with_name("modified") |
|
44 | Arg::with_name("modified") | |
45 | .help("show only modified files") |
|
45 | .help("show only modified files") | |
46 | .short("-m") |
|
46 | .short("-m") | |
47 | .long("--modified"), |
|
47 | .long("--modified"), | |
48 | ) |
|
48 | ) | |
49 | .arg( |
|
49 | .arg( | |
50 | Arg::with_name("added") |
|
50 | Arg::with_name("added") | |
51 | .help("show only added files") |
|
51 | .help("show only added files") | |
52 | .short("-a") |
|
52 | .short("-a") | |
53 | .long("--added"), |
|
53 | .long("--added"), | |
54 | ) |
|
54 | ) | |
55 | .arg( |
|
55 | .arg( | |
56 | Arg::with_name("removed") |
|
56 | Arg::with_name("removed") | |
57 | .help("show only removed files") |
|
57 | .help("show only removed files") | |
58 | .short("-r") |
|
58 | .short("-r") | |
59 | .long("--removed"), |
|
59 | .long("--removed"), | |
60 | ) |
|
60 | ) | |
61 | .arg( |
|
61 | .arg( | |
62 | Arg::with_name("clean") |
|
62 | Arg::with_name("clean") | |
63 | .help("show only clean files") |
|
63 | .help("show only clean files") | |
64 | .short("-c") |
|
64 | .short("-c") | |
65 | .long("--clean"), |
|
65 | .long("--clean"), | |
66 | ) |
|
66 | ) | |
67 | .arg( |
|
67 | .arg( | |
68 | Arg::with_name("deleted") |
|
68 | Arg::with_name("deleted") | |
69 | .help("show only deleted files") |
|
69 | .help("show only deleted files") | |
70 | .short("-d") |
|
70 | .short("-d") | |
71 | .long("--deleted"), |
|
71 | .long("--deleted"), | |
72 | ) |
|
72 | ) | |
73 | .arg( |
|
73 | .arg( | |
74 | Arg::with_name("unknown") |
|
74 | Arg::with_name("unknown") | |
75 | .help("show only unknown (not tracked) files") |
|
75 | .help("show only unknown (not tracked) files") | |
76 | .short("-u") |
|
76 | .short("-u") | |
77 | .long("--unknown"), |
|
77 | .long("--unknown"), | |
78 | ) |
|
78 | ) | |
79 | .arg( |
|
79 | .arg( | |
80 | Arg::with_name("ignored") |
|
80 | Arg::with_name("ignored") | |
81 | .help("show only ignored files") |
|
81 | .help("show only ignored files") | |
82 | .short("-i") |
|
82 | .short("-i") | |
83 | .long("--ignored"), |
|
83 | .long("--ignored"), | |
84 | ) |
|
84 | ) | |
|
85 | .arg( | |||
|
86 | Arg::with_name("no-status") | |||
|
87 | .help("hide status prefix") | |||
|
88 | .short("-n") | |||
|
89 | .long("--no-status"), | |||
|
90 | ) | |||
85 | } |
|
91 | } | |
86 |
|
92 | |||
87 | /// Pure data type allowing the caller to specify file states to display |
|
93 | /// Pure data type allowing the caller to specify file states to display | |
88 | #[derive(Copy, Clone, Debug)] |
|
94 | #[derive(Copy, Clone, Debug)] | |
89 | pub struct DisplayStates { |
|
95 | pub struct DisplayStates { | |
90 | pub modified: bool, |
|
96 | pub modified: bool, | |
91 | pub added: bool, |
|
97 | pub added: bool, | |
92 | pub removed: bool, |
|
98 | pub removed: bool, | |
93 | pub clean: bool, |
|
99 | pub clean: bool, | |
94 | pub deleted: bool, |
|
100 | pub deleted: bool, | |
95 | pub unknown: bool, |
|
101 | pub unknown: bool, | |
96 | pub ignored: bool, |
|
102 | pub ignored: bool, | |
97 | } |
|
103 | } | |
98 |
|
104 | |||
99 | pub const DEFAULT_DISPLAY_STATES: DisplayStates = DisplayStates { |
|
105 | pub const DEFAULT_DISPLAY_STATES: DisplayStates = DisplayStates { | |
100 | modified: true, |
|
106 | modified: true, | |
101 | added: true, |
|
107 | added: true, | |
102 | removed: true, |
|
108 | removed: true, | |
103 | clean: false, |
|
109 | clean: false, | |
104 | deleted: true, |
|
110 | deleted: true, | |
105 | unknown: true, |
|
111 | unknown: true, | |
106 | ignored: false, |
|
112 | ignored: false, | |
107 | }; |
|
113 | }; | |
108 |
|
114 | |||
109 | pub const ALL_DISPLAY_STATES: DisplayStates = DisplayStates { |
|
115 | pub const ALL_DISPLAY_STATES: DisplayStates = DisplayStates { | |
110 | modified: true, |
|
116 | modified: true, | |
111 | added: true, |
|
117 | added: true, | |
112 | removed: true, |
|
118 | removed: true, | |
113 | clean: true, |
|
119 | clean: true, | |
114 | deleted: true, |
|
120 | deleted: true, | |
115 | unknown: true, |
|
121 | unknown: true, | |
116 | ignored: true, |
|
122 | ignored: true, | |
117 | }; |
|
123 | }; | |
118 |
|
124 | |||
119 | impl DisplayStates { |
|
125 | impl DisplayStates { | |
120 | pub fn is_empty(&self) -> bool { |
|
126 | pub fn is_empty(&self) -> bool { | |
121 | !(self.modified |
|
127 | !(self.modified | |
122 | || self.added |
|
128 | || self.added | |
123 | || self.removed |
|
129 | || self.removed | |
124 | || self.clean |
|
130 | || self.clean | |
125 | || self.deleted |
|
131 | || self.deleted | |
126 | || self.unknown |
|
132 | || self.unknown | |
127 | || self.ignored) |
|
133 | || self.ignored) | |
128 | } |
|
134 | } | |
129 | } |
|
135 | } | |
130 |
|
136 | |||
131 | pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { |
|
137 | pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { | |
132 | let status_enabled_default = false; |
|
138 | let status_enabled_default = false; | |
133 | let status_enabled = invocation.config.get_option(b"rhg", b"status")?; |
|
139 | let status_enabled = invocation.config.get_option(b"rhg", b"status")?; | |
134 | if !status_enabled.unwrap_or(status_enabled_default) { |
|
140 | if !status_enabled.unwrap_or(status_enabled_default) { | |
135 | return Err(CommandError::unsupported( |
|
141 | return Err(CommandError::unsupported( | |
136 | "status is experimental in rhg (enable it with 'rhg.status = true' \ |
|
142 | "status is experimental in rhg (enable it with 'rhg.status = true' \ | |
137 | or enable fallback with 'rhg.on-unsupported = fallback')" |
|
143 | or enable fallback with 'rhg.on-unsupported = fallback')" | |
138 | )); |
|
144 | )); | |
139 | } |
|
145 | } | |
140 |
|
146 | |||
141 | // TODO: lift these limitations |
|
147 | // TODO: lift these limitations | |
142 | if invocation.config.get_bool(b"ui", b"tweakdefaults")? { |
|
148 | if invocation.config.get_bool(b"ui", b"tweakdefaults")? { | |
143 | return Err(CommandError::unsupported( |
|
149 | return Err(CommandError::unsupported( | |
144 | "ui.tweakdefaults is not yet supported with rhg status", |
|
150 | "ui.tweakdefaults is not yet supported with rhg status", | |
145 | )); |
|
151 | )); | |
146 | } |
|
152 | } | |
147 | if invocation.config.get_bool(b"ui", b"statuscopies")? { |
|
153 | if invocation.config.get_bool(b"ui", b"statuscopies")? { | |
148 | return Err(CommandError::unsupported( |
|
154 | return Err(CommandError::unsupported( | |
149 | "ui.statuscopies is not yet supported with rhg status", |
|
155 | "ui.statuscopies is not yet supported with rhg status", | |
150 | )); |
|
156 | )); | |
151 | } |
|
157 | } | |
152 | if invocation |
|
158 | if invocation | |
153 | .config |
|
159 | .config | |
154 | .get(b"commands", b"status.terse") |
|
160 | .get(b"commands", b"status.terse") | |
155 | .is_some() |
|
161 | .is_some() | |
156 | { |
|
162 | { | |
157 | return Err(CommandError::unsupported( |
|
163 | return Err(CommandError::unsupported( | |
158 | "status.terse is not yet supported with rhg status", |
|
164 | "status.terse is not yet supported with rhg status", | |
159 | )); |
|
165 | )); | |
160 | } |
|
166 | } | |
161 |
|
167 | |||
162 | let ui = invocation.ui; |
|
168 | let ui = invocation.ui; | |
163 | let config = invocation.config; |
|
169 | let config = invocation.config; | |
164 | let args = invocation.subcommand_args; |
|
170 | let args = invocation.subcommand_args; | |
165 | let display_states = if args.is_present("all") { |
|
171 | let display_states = if args.is_present("all") { | |
166 | // TODO when implementing `--quiet`: it excludes clean files |
|
172 | // TODO when implementing `--quiet`: it excludes clean files | |
167 | // from `--all` |
|
173 | // from `--all` | |
168 | ALL_DISPLAY_STATES |
|
174 | ALL_DISPLAY_STATES | |
169 | } else { |
|
175 | } else { | |
170 | let requested = DisplayStates { |
|
176 | let requested = DisplayStates { | |
171 | modified: args.is_present("modified"), |
|
177 | modified: args.is_present("modified"), | |
172 | added: args.is_present("added"), |
|
178 | added: args.is_present("added"), | |
173 | removed: args.is_present("removed"), |
|
179 | removed: args.is_present("removed"), | |
174 | clean: args.is_present("clean"), |
|
180 | clean: args.is_present("clean"), | |
175 | deleted: args.is_present("deleted"), |
|
181 | deleted: args.is_present("deleted"), | |
176 | unknown: args.is_present("unknown"), |
|
182 | unknown: args.is_present("unknown"), | |
177 | ignored: args.is_present("ignored"), |
|
183 | ignored: args.is_present("ignored"), | |
178 | }; |
|
184 | }; | |
179 | if requested.is_empty() { |
|
185 | if requested.is_empty() { | |
180 | DEFAULT_DISPLAY_STATES |
|
186 | DEFAULT_DISPLAY_STATES | |
181 | } else { |
|
187 | } else { | |
182 | requested |
|
188 | requested | |
183 | } |
|
189 | } | |
184 | }; |
|
190 | }; | |
|
191 | let no_status = args.is_present("no-status"); | |||
185 |
|
192 | |||
186 | let repo = invocation.repo?; |
|
193 | let repo = invocation.repo?; | |
187 | let mut dmap = repo.dirstate_map_mut()?; |
|
194 | let mut dmap = repo.dirstate_map_mut()?; | |
188 |
|
195 | |||
189 | let options = StatusOptions { |
|
196 | let options = StatusOptions { | |
190 | // TODO should be provided by the dirstate parsing and |
|
197 | // TODO should be provided by the dirstate parsing and | |
191 | // hence be stored on dmap. Using a value that assumes we aren't |
|
198 | // hence be stored on dmap. Using a value that assumes we aren't | |
192 | // below the time resolution granularity of the FS and the |
|
199 | // below the time resolution granularity of the FS and the | |
193 | // dirstate. |
|
200 | // dirstate. | |
194 | last_normal_time: TruncatedTimestamp::new_truncate(0, 0), |
|
201 | last_normal_time: TruncatedTimestamp::new_truncate(0, 0), | |
195 | // we're currently supporting file systems with exec flags only |
|
202 | // we're currently supporting file systems with exec flags only | |
196 | // anyway |
|
203 | // anyway | |
197 | check_exec: true, |
|
204 | check_exec: true, | |
198 | list_clean: display_states.clean, |
|
205 | list_clean: display_states.clean, | |
199 | list_unknown: display_states.unknown, |
|
206 | list_unknown: display_states.unknown, | |
200 | list_ignored: display_states.ignored, |
|
207 | list_ignored: display_states.ignored, | |
201 | collect_traversed_dirs: false, |
|
208 | collect_traversed_dirs: false, | |
202 | }; |
|
209 | }; | |
203 | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded |
|
210 | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded | |
204 | let (mut ds_status, pattern_warnings) = dmap.status( |
|
211 | let (mut ds_status, pattern_warnings) = dmap.status( | |
205 | &AlwaysMatcher, |
|
212 | &AlwaysMatcher, | |
206 | repo.working_directory_path().to_owned(), |
|
213 | repo.working_directory_path().to_owned(), | |
207 | vec![ignore_file], |
|
214 | vec![ignore_file], | |
208 | options, |
|
215 | options, | |
209 | )?; |
|
216 | )?; | |
210 | if !pattern_warnings.is_empty() { |
|
217 | if !pattern_warnings.is_empty() { | |
211 | warn!("Pattern warnings: {:?}", &pattern_warnings); |
|
218 | warn!("Pattern warnings: {:?}", &pattern_warnings); | |
212 | } |
|
219 | } | |
213 |
|
220 | |||
214 | if !ds_status.bad.is_empty() { |
|
221 | if !ds_status.bad.is_empty() { | |
215 | warn!("Bad matches {:?}", &(ds_status.bad)) |
|
222 | warn!("Bad matches {:?}", &(ds_status.bad)) | |
216 | } |
|
223 | } | |
217 | if !ds_status.unsure.is_empty() { |
|
224 | if !ds_status.unsure.is_empty() { | |
218 | info!( |
|
225 | info!( | |
219 | "Files to be rechecked by retrieval from filelog: {:?}", |
|
226 | "Files to be rechecked by retrieval from filelog: {:?}", | |
220 | &ds_status.unsure |
|
227 | &ds_status.unsure | |
221 | ); |
|
228 | ); | |
222 | } |
|
229 | } | |
223 | if !ds_status.unsure.is_empty() |
|
230 | if !ds_status.unsure.is_empty() | |
224 | && (display_states.modified || display_states.clean) |
|
231 | && (display_states.modified || display_states.clean) | |
225 | { |
|
232 | { | |
226 | let p1 = repo.dirstate_parents()?.p1; |
|
233 | let p1 = repo.dirstate_parents()?.p1; | |
227 | let manifest = repo.manifest_for_node(p1).map_err(|e| { |
|
234 | let manifest = repo.manifest_for_node(p1).map_err(|e| { | |
228 | CommandError::from((e, &*format!("{:x}", p1.short()))) |
|
235 | CommandError::from((e, &*format!("{:x}", p1.short()))) | |
229 | })?; |
|
236 | })?; | |
230 | for to_check in ds_status.unsure { |
|
237 | for to_check in ds_status.unsure { | |
231 | if unsure_is_modified(repo, &manifest, &to_check)? { |
|
238 | if unsure_is_modified(repo, &manifest, &to_check)? { | |
232 | if display_states.modified { |
|
239 | if display_states.modified { | |
233 | ds_status.modified.push(to_check); |
|
240 | ds_status.modified.push(to_check); | |
234 | } |
|
241 | } | |
235 | } else { |
|
242 | } else { | |
236 | if display_states.clean { |
|
243 | if display_states.clean { | |
237 | ds_status.clean.push(to_check); |
|
244 | ds_status.clean.push(to_check); | |
238 | } |
|
245 | } | |
239 | } |
|
246 | } | |
240 | } |
|
247 | } | |
241 | } |
|
248 | } | |
242 | if display_states.modified { |
|
249 | if display_states.modified { | |
243 | display_status_paths(ui, repo, config, &mut ds_status.modified, b"M")?; |
|
250 | display_status_paths( | |
|
251 | ui, | |||
|
252 | repo, | |||
|
253 | config, | |||
|
254 | no_status, | |||
|
255 | &mut ds_status.modified, | |||
|
256 | b"M", | |||
|
257 | )?; | |||
244 | } |
|
258 | } | |
245 | if display_states.added { |
|
259 | if display_states.added { | |
246 | display_status_paths(ui, repo, config, &mut ds_status.added, b"A")?; |
|
260 | display_status_paths( | |
|
261 | ui, | |||
|
262 | repo, | |||
|
263 | config, | |||
|
264 | no_status, | |||
|
265 | &mut ds_status.added, | |||
|
266 | b"A", | |||
|
267 | )?; | |||
247 | } |
|
268 | } | |
248 | if display_states.removed { |
|
269 | if display_states.removed { | |
249 | display_status_paths(ui, repo, config, &mut ds_status.removed, b"R")?; |
|
270 | display_status_paths( | |
|
271 | ui, | |||
|
272 | repo, | |||
|
273 | config, | |||
|
274 | no_status, | |||
|
275 | &mut ds_status.removed, | |||
|
276 | b"R", | |||
|
277 | )?; | |||
250 | } |
|
278 | } | |
251 | if display_states.deleted { |
|
279 | if display_states.deleted { | |
252 | display_status_paths(ui, repo, config, &mut ds_status.deleted, b"!")?; |
|
280 | display_status_paths( | |
|
281 | ui, | |||
|
282 | repo, | |||
|
283 | config, | |||
|
284 | no_status, | |||
|
285 | &mut ds_status.deleted, | |||
|
286 | b"!", | |||
|
287 | )?; | |||
253 | } |
|
288 | } | |
254 | if display_states.unknown { |
|
289 | if display_states.unknown { | |
255 | display_status_paths(ui, repo, config, &mut ds_status.unknown, b"?")?; |
|
290 | display_status_paths( | |
|
291 | ui, | |||
|
292 | repo, | |||
|
293 | config, | |||
|
294 | no_status, | |||
|
295 | &mut ds_status.unknown, | |||
|
296 | b"?", | |||
|
297 | )?; | |||
256 | } |
|
298 | } | |
257 | if display_states.ignored { |
|
299 | if display_states.ignored { | |
258 | display_status_paths(ui, repo, config, &mut ds_status.ignored, b"I")?; |
|
300 | display_status_paths( | |
|
301 | ui, | |||
|
302 | repo, | |||
|
303 | config, | |||
|
304 | no_status, | |||
|
305 | &mut ds_status.ignored, | |||
|
306 | b"I", | |||
|
307 | )?; | |||
259 | } |
|
308 | } | |
260 | if display_states.clean { |
|
309 | if display_states.clean { | |
261 | display_status_paths(ui, repo, config, &mut ds_status.clean, b"C")?; |
|
310 | display_status_paths( | |
|
311 | ui, | |||
|
312 | repo, | |||
|
313 | config, | |||
|
314 | no_status, | |||
|
315 | &mut ds_status.clean, | |||
|
316 | b"C", | |||
|
317 | )?; | |||
262 | } |
|
318 | } | |
263 | Ok(()) |
|
319 | Ok(()) | |
264 | } |
|
320 | } | |
265 |
|
321 | |||
266 | // Probably more elegant to use a Deref or Borrow trait rather than |
|
322 | // Probably more elegant to use a Deref or Borrow trait rather than | |
267 | // harcode HgPathBuf, but probably not really useful at this point |
|
323 | // harcode HgPathBuf, but probably not really useful at this point | |
268 | fn display_status_paths( |
|
324 | fn display_status_paths( | |
269 | ui: &Ui, |
|
325 | ui: &Ui, | |
270 | repo: &Repo, |
|
326 | repo: &Repo, | |
271 | config: &Config, |
|
327 | config: &Config, | |
|
328 | no_status: bool, | |||
272 | paths: &mut [HgPathCow], |
|
329 | paths: &mut [HgPathCow], | |
273 | status_prefix: &[u8], |
|
330 | status_prefix: &[u8], | |
274 | ) -> Result<(), CommandError> { |
|
331 | ) -> Result<(), CommandError> { | |
275 | paths.sort_unstable(); |
|
332 | paths.sort_unstable(); | |
276 | let mut relative: bool = config.get_bool(b"ui", b"relative-paths")?; |
|
333 | let mut relative: bool = config.get_bool(b"ui", b"relative-paths")?; | |
277 | relative = config |
|
334 | relative = config | |
278 | .get_option(b"commands", b"status.relative")? |
|
335 | .get_option(b"commands", b"status.relative")? | |
279 | .unwrap_or(relative); |
|
336 | .unwrap_or(relative); | |
|
337 | let print_path = |path: &[u8]| { | |||
|
338 | // TODO optim, probably lots of unneeded copies here, especially | |||
|
339 | // if out stream is buffered | |||
|
340 | if no_status { | |||
|
341 | ui.write_stdout(&format_bytes!(b"{}\n", path)) | |||
|
342 | } else { | |||
|
343 | ui.write_stdout(&format_bytes!(b"{} {}\n", status_prefix, path)) | |||
|
344 | } | |||
|
345 | }; | |||
|
346 | ||||
280 | if relative && !ui.plain() { |
|
347 | if relative && !ui.plain() { | |
281 | relativize_paths( |
|
348 | relativize_paths(repo, paths.iter().map(Ok), |path| { | |
282 |
|
|
349 | print_path(&path) | |
283 | paths.iter().map(Ok), |
|
350 | })?; | |
284 | |path: Cow<[u8]>| -> Result<(), UiError> { |
|
|||
285 | ui.write_stdout( |
|
|||
286 | &[status_prefix, b" ", path.as_ref(), b"\n"].concat(), |
|
|||
287 | ) |
|
|||
288 | }, |
|
|||
289 | )?; |
|
|||
290 | } else { |
|
351 | } else { | |
291 | for path in paths { |
|
352 | for path in paths { | |
292 | // Same TODO as in commands::root |
|
353 | print_path(path.as_bytes())? | |
293 | let bytes: &[u8] = path.as_bytes(); |
|
|||
294 | // TODO optim, probably lots of unneeded copies here, especially |
|
|||
295 | // if out stream is buffered |
|
|||
296 | ui.write_stdout(&[status_prefix, b" ", bytes, b"\n"].concat())?; |
|
|||
297 | } |
|
354 | } | |
298 | } |
|
355 | } | |
299 | Ok(()) |
|
356 | Ok(()) | |
300 | } |
|
357 | } | |
301 |
|
358 | |||
302 | /// Check if a file is modified by comparing actual repo store and file system. |
|
359 | /// Check if a file is modified by comparing actual repo store and file system. | |
303 | /// |
|
360 | /// | |
304 | /// This meant to be used for those that the dirstate cannot resolve, due |
|
361 | /// This meant to be used for those that the dirstate cannot resolve, due | |
305 | /// to time resolution limits. |
|
362 | /// to time resolution limits. | |
306 | fn unsure_is_modified( |
|
363 | fn unsure_is_modified( | |
307 | repo: &Repo, |
|
364 | repo: &Repo, | |
308 | manifest: &Manifest, |
|
365 | manifest: &Manifest, | |
309 | hg_path: &HgPath, |
|
366 | hg_path: &HgPath, | |
310 | ) -> Result<bool, HgError> { |
|
367 | ) -> Result<bool, HgError> { | |
311 | let vfs = repo.working_directory_vfs(); |
|
368 | let vfs = repo.working_directory_vfs(); | |
312 | let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion"); |
|
369 | let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion"); | |
313 | let fs_metadata = vfs.symlink_metadata(&fs_path)?; |
|
370 | let fs_metadata = vfs.symlink_metadata(&fs_path)?; | |
314 | let is_symlink = fs_metadata.file_type().is_symlink(); |
|
371 | let is_symlink = fs_metadata.file_type().is_symlink(); | |
315 | // TODO: Also account for `FALLBACK_SYMLINK` and `FALLBACK_EXEC` from the dirstate |
|
372 | // TODO: Also account for `FALLBACK_SYMLINK` and `FALLBACK_EXEC` from the dirstate | |
316 | let fs_flags = if is_symlink { |
|
373 | let fs_flags = if is_symlink { | |
317 | Some(b'l') |
|
374 | Some(b'l') | |
318 | } else if has_exec_bit(&fs_metadata) { |
|
375 | } else if has_exec_bit(&fs_metadata) { | |
319 | Some(b'x') |
|
376 | Some(b'x') | |
320 | } else { |
|
377 | } else { | |
321 | None |
|
378 | None | |
322 | }; |
|
379 | }; | |
323 |
|
380 | |||
324 | let entry = manifest |
|
381 | let entry = manifest | |
325 | .find_file(hg_path)? |
|
382 | .find_file(hg_path)? | |
326 | .expect("ambgious file not in p1"); |
|
383 | .expect("ambgious file not in p1"); | |
327 | if entry.flags != fs_flags { |
|
384 | if entry.flags != fs_flags { | |
328 | return Ok(true); |
|
385 | return Ok(true); | |
329 | } |
|
386 | } | |
330 | let filelog = repo.filelog(hg_path)?; |
|
387 | let filelog = repo.filelog(hg_path)?; | |
331 | let filelog_entry = |
|
388 | let filelog_entry = | |
332 | filelog.data_for_node(entry.node_id()?).map_err(|_| { |
|
389 | filelog.data_for_node(entry.node_id()?).map_err(|_| { | |
333 | HgError::corrupted("filelog missing node from manifest") |
|
390 | HgError::corrupted("filelog missing node from manifest") | |
334 | })?; |
|
391 | })?; | |
335 | let contents_in_p1 = filelog_entry.data()?; |
|
392 | let contents_in_p1 = filelog_entry.data()?; | |
336 |
|
393 | |||
337 | let fs_contents = if is_symlink { |
|
394 | let fs_contents = if is_symlink { | |
338 | get_bytes_from_os_string(vfs.read_link(fs_path)?.into_os_string()) |
|
395 | get_bytes_from_os_string(vfs.read_link(fs_path)?.into_os_string()) | |
339 | } else { |
|
396 | } else { | |
340 | vfs.read(fs_path)? |
|
397 | vfs.read(fs_path)? | |
341 | }; |
|
398 | }; | |
342 | return Ok(contents_in_p1 != &*fs_contents); |
|
399 | return Ok(contents_in_p1 != &*fs_contents); | |
343 | } |
|
400 | } |
@@ -1,969 +1,976 | |||||
1 | #testcases dirstate-v1 dirstate-v2 |
|
1 | #testcases dirstate-v1 dirstate-v2 | |
2 |
|
2 | |||
3 | #if dirstate-v2 |
|
3 | #if dirstate-v2 | |
4 | $ cat >> $HGRCPATH << EOF |
|
4 | $ cat >> $HGRCPATH << EOF | |
5 | > [format] |
|
5 | > [format] | |
6 | > exp-rc-dirstate-v2=1 |
|
6 | > exp-rc-dirstate-v2=1 | |
7 | > [storage] |
|
7 | > [storage] | |
8 | > dirstate-v2.slow-path=allow |
|
8 | > dirstate-v2.slow-path=allow | |
9 | > EOF |
|
9 | > EOF | |
10 | #endif |
|
10 | #endif | |
11 |
|
11 | |||
12 | TODO: fix rhg bugs that make this test fail when status is enabled |
|
12 | TODO: fix rhg bugs that make this test fail when status is enabled | |
13 | $ unset RHG_STATUS |
|
13 | $ unset RHG_STATUS | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | $ hg init repo1 |
|
16 | $ hg init repo1 | |
17 | $ cd repo1 |
|
17 | $ cd repo1 | |
18 | $ mkdir a b a/1 b/1 b/2 |
|
18 | $ mkdir a b a/1 b/1 b/2 | |
19 | $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2 |
|
19 | $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2 | |
20 |
|
20 | |||
21 | hg status in repo root: |
|
21 | hg status in repo root: | |
22 |
|
22 | |||
23 | $ hg status |
|
23 | $ hg status | |
24 | ? a/1/in_a_1 |
|
24 | ? a/1/in_a_1 | |
25 | ? a/in_a |
|
25 | ? a/in_a | |
26 | ? b/1/in_b_1 |
|
26 | ? b/1/in_b_1 | |
27 | ? b/2/in_b_2 |
|
27 | ? b/2/in_b_2 | |
28 | ? b/in_b |
|
28 | ? b/in_b | |
29 | ? in_root |
|
29 | ? in_root | |
30 |
|
30 | |||
31 | hg status . in repo root: |
|
31 | hg status . in repo root: | |
32 |
|
32 | |||
33 | $ hg status . |
|
33 | $ hg status . | |
34 | ? a/1/in_a_1 |
|
34 | ? a/1/in_a_1 | |
35 | ? a/in_a |
|
35 | ? a/in_a | |
36 | ? b/1/in_b_1 |
|
36 | ? b/1/in_b_1 | |
37 | ? b/2/in_b_2 |
|
37 | ? b/2/in_b_2 | |
38 | ? b/in_b |
|
38 | ? b/in_b | |
39 | ? in_root |
|
39 | ? in_root | |
40 |
|
40 | |||
41 | $ hg status --cwd a |
|
41 | $ hg status --cwd a | |
42 | ? a/1/in_a_1 |
|
42 | ? a/1/in_a_1 | |
43 | ? a/in_a |
|
43 | ? a/in_a | |
44 | ? b/1/in_b_1 |
|
44 | ? b/1/in_b_1 | |
45 | ? b/2/in_b_2 |
|
45 | ? b/2/in_b_2 | |
46 | ? b/in_b |
|
46 | ? b/in_b | |
47 | ? in_root |
|
47 | ? in_root | |
48 | $ hg status --cwd a . |
|
48 | $ hg status --cwd a . | |
49 | ? 1/in_a_1 |
|
49 | ? 1/in_a_1 | |
50 | ? in_a |
|
50 | ? in_a | |
51 | $ hg status --cwd a .. |
|
51 | $ hg status --cwd a .. | |
52 | ? 1/in_a_1 |
|
52 | ? 1/in_a_1 | |
53 | ? in_a |
|
53 | ? in_a | |
54 | ? ../b/1/in_b_1 |
|
54 | ? ../b/1/in_b_1 | |
55 | ? ../b/2/in_b_2 |
|
55 | ? ../b/2/in_b_2 | |
56 | ? ../b/in_b |
|
56 | ? ../b/in_b | |
57 | ? ../in_root |
|
57 | ? ../in_root | |
58 |
|
58 | |||
59 | $ hg status --cwd b |
|
59 | $ hg status --cwd b | |
60 | ? a/1/in_a_1 |
|
60 | ? a/1/in_a_1 | |
61 | ? a/in_a |
|
61 | ? a/in_a | |
62 | ? b/1/in_b_1 |
|
62 | ? b/1/in_b_1 | |
63 | ? b/2/in_b_2 |
|
63 | ? b/2/in_b_2 | |
64 | ? b/in_b |
|
64 | ? b/in_b | |
65 | ? in_root |
|
65 | ? in_root | |
66 | $ hg status --cwd b . |
|
66 | $ hg status --cwd b . | |
67 | ? 1/in_b_1 |
|
67 | ? 1/in_b_1 | |
68 | ? 2/in_b_2 |
|
68 | ? 2/in_b_2 | |
69 | ? in_b |
|
69 | ? in_b | |
70 | $ hg status --cwd b .. |
|
70 | $ hg status --cwd b .. | |
71 | ? ../a/1/in_a_1 |
|
71 | ? ../a/1/in_a_1 | |
72 | ? ../a/in_a |
|
72 | ? ../a/in_a | |
73 | ? 1/in_b_1 |
|
73 | ? 1/in_b_1 | |
74 | ? 2/in_b_2 |
|
74 | ? 2/in_b_2 | |
75 | ? in_b |
|
75 | ? in_b | |
76 | ? ../in_root |
|
76 | ? ../in_root | |
77 |
|
77 | |||
78 | $ hg status --cwd a/1 |
|
78 | $ hg status --cwd a/1 | |
79 | ? a/1/in_a_1 |
|
79 | ? a/1/in_a_1 | |
80 | ? a/in_a |
|
80 | ? a/in_a | |
81 | ? b/1/in_b_1 |
|
81 | ? b/1/in_b_1 | |
82 | ? b/2/in_b_2 |
|
82 | ? b/2/in_b_2 | |
83 | ? b/in_b |
|
83 | ? b/in_b | |
84 | ? in_root |
|
84 | ? in_root | |
85 | $ hg status --cwd a/1 . |
|
85 | $ hg status --cwd a/1 . | |
86 | ? in_a_1 |
|
86 | ? in_a_1 | |
87 | $ hg status --cwd a/1 .. |
|
87 | $ hg status --cwd a/1 .. | |
88 | ? in_a_1 |
|
88 | ? in_a_1 | |
89 | ? ../in_a |
|
89 | ? ../in_a | |
90 |
|
90 | |||
91 | $ hg status --cwd b/1 |
|
91 | $ hg status --cwd b/1 | |
92 | ? a/1/in_a_1 |
|
92 | ? a/1/in_a_1 | |
93 | ? a/in_a |
|
93 | ? a/in_a | |
94 | ? b/1/in_b_1 |
|
94 | ? b/1/in_b_1 | |
95 | ? b/2/in_b_2 |
|
95 | ? b/2/in_b_2 | |
96 | ? b/in_b |
|
96 | ? b/in_b | |
97 | ? in_root |
|
97 | ? in_root | |
98 | $ hg status --cwd b/1 . |
|
98 | $ hg status --cwd b/1 . | |
99 | ? in_b_1 |
|
99 | ? in_b_1 | |
100 | $ hg status --cwd b/1 .. |
|
100 | $ hg status --cwd b/1 .. | |
101 | ? in_b_1 |
|
101 | ? in_b_1 | |
102 | ? ../2/in_b_2 |
|
102 | ? ../2/in_b_2 | |
103 | ? ../in_b |
|
103 | ? ../in_b | |
104 |
|
104 | |||
105 | $ hg status --cwd b/2 |
|
105 | $ hg status --cwd b/2 | |
106 | ? a/1/in_a_1 |
|
106 | ? a/1/in_a_1 | |
107 | ? a/in_a |
|
107 | ? a/in_a | |
108 | ? b/1/in_b_1 |
|
108 | ? b/1/in_b_1 | |
109 | ? b/2/in_b_2 |
|
109 | ? b/2/in_b_2 | |
110 | ? b/in_b |
|
110 | ? b/in_b | |
111 | ? in_root |
|
111 | ? in_root | |
112 | $ hg status --cwd b/2 . |
|
112 | $ hg status --cwd b/2 . | |
113 | ? in_b_2 |
|
113 | ? in_b_2 | |
114 | $ hg status --cwd b/2 .. |
|
114 | $ hg status --cwd b/2 .. | |
115 | ? ../1/in_b_1 |
|
115 | ? ../1/in_b_1 | |
116 | ? in_b_2 |
|
116 | ? in_b_2 | |
117 | ? ../in_b |
|
117 | ? ../in_b | |
118 |
|
118 | |||
119 | combining patterns with root and patterns without a root works |
|
119 | combining patterns with root and patterns without a root works | |
120 |
|
120 | |||
121 | $ hg st a/in_a re:.*b$ |
|
121 | $ hg st a/in_a re:.*b$ | |
122 | ? a/in_a |
|
122 | ? a/in_a | |
123 | ? b/in_b |
|
123 | ? b/in_b | |
124 |
|
124 | |||
125 | tweaking defaults works |
|
125 | tweaking defaults works | |
126 | $ hg status --cwd a --config ui.tweakdefaults=yes |
|
126 | $ hg status --cwd a --config ui.tweakdefaults=yes | |
127 | ? 1/in_a_1 |
|
127 | ? 1/in_a_1 | |
128 | ? in_a |
|
128 | ? in_a | |
129 | ? ../b/1/in_b_1 |
|
129 | ? ../b/1/in_b_1 | |
130 | ? ../b/2/in_b_2 |
|
130 | ? ../b/2/in_b_2 | |
131 | ? ../b/in_b |
|
131 | ? ../b/in_b | |
132 | ? ../in_root |
|
132 | ? ../in_root | |
133 | $ HGPLAIN=1 hg status --cwd a --config ui.tweakdefaults=yes |
|
133 | $ HGPLAIN=1 hg status --cwd a --config ui.tweakdefaults=yes | |
134 | ? a/1/in_a_1 (glob) |
|
134 | ? a/1/in_a_1 (glob) | |
135 | ? a/in_a (glob) |
|
135 | ? a/in_a (glob) | |
136 | ? b/1/in_b_1 (glob) |
|
136 | ? b/1/in_b_1 (glob) | |
137 | ? b/2/in_b_2 (glob) |
|
137 | ? b/2/in_b_2 (glob) | |
138 | ? b/in_b (glob) |
|
138 | ? b/in_b (glob) | |
139 | ? in_root |
|
139 | ? in_root | |
140 | $ HGPLAINEXCEPT=tweakdefaults hg status --cwd a --config ui.tweakdefaults=yes |
|
140 | $ HGPLAINEXCEPT=tweakdefaults hg status --cwd a --config ui.tweakdefaults=yes | |
141 | ? 1/in_a_1 |
|
141 | ? 1/in_a_1 | |
142 | ? in_a |
|
142 | ? in_a | |
143 | ? ../b/1/in_b_1 |
|
143 | ? ../b/1/in_b_1 | |
144 | ? ../b/2/in_b_2 |
|
144 | ? ../b/2/in_b_2 | |
145 | ? ../b/in_b |
|
145 | ? ../b/in_b | |
146 | ? ../in_root (glob) |
|
146 | ? ../in_root (glob) | |
147 |
|
147 | |||
148 | relative paths can be requested |
|
148 | relative paths can be requested | |
149 |
|
149 | |||
150 | $ hg status --cwd a --config ui.relative-paths=yes |
|
150 | $ hg status --cwd a --config ui.relative-paths=yes | |
151 | ? 1/in_a_1 |
|
151 | ? 1/in_a_1 | |
152 | ? in_a |
|
152 | ? in_a | |
153 | ? ../b/1/in_b_1 |
|
153 | ? ../b/1/in_b_1 | |
154 | ? ../b/2/in_b_2 |
|
154 | ? ../b/2/in_b_2 | |
155 | ? ../b/in_b |
|
155 | ? ../b/in_b | |
156 | ? ../in_root |
|
156 | ? ../in_root | |
157 |
|
157 | |||
158 | $ hg status --cwd a . --config ui.relative-paths=legacy |
|
158 | $ hg status --cwd a . --config ui.relative-paths=legacy | |
159 | ? 1/in_a_1 |
|
159 | ? 1/in_a_1 | |
160 | ? in_a |
|
160 | ? in_a | |
161 | $ hg status --cwd a . --config ui.relative-paths=no |
|
161 | $ hg status --cwd a . --config ui.relative-paths=no | |
162 | ? a/1/in_a_1 |
|
162 | ? a/1/in_a_1 | |
163 | ? a/in_a |
|
163 | ? a/in_a | |
164 |
|
164 | |||
165 | commands.status.relative overrides ui.relative-paths |
|
165 | commands.status.relative overrides ui.relative-paths | |
166 |
|
166 | |||
167 | $ cat >> $HGRCPATH <<EOF |
|
167 | $ cat >> $HGRCPATH <<EOF | |
168 | > [ui] |
|
168 | > [ui] | |
169 | > relative-paths = False |
|
169 | > relative-paths = False | |
170 | > [commands] |
|
170 | > [commands] | |
171 | > status.relative = True |
|
171 | > status.relative = True | |
172 | > EOF |
|
172 | > EOF | |
173 | $ hg status --cwd a |
|
173 | $ hg status --cwd a | |
174 | ? 1/in_a_1 |
|
174 | ? 1/in_a_1 | |
175 | ? in_a |
|
175 | ? in_a | |
176 | ? ../b/1/in_b_1 |
|
176 | ? ../b/1/in_b_1 | |
177 | ? ../b/2/in_b_2 |
|
177 | ? ../b/2/in_b_2 | |
178 | ? ../b/in_b |
|
178 | ? ../b/in_b | |
179 | ? ../in_root |
|
179 | ? ../in_root | |
180 | $ HGPLAIN=1 hg status --cwd a |
|
180 | $ HGPLAIN=1 hg status --cwd a | |
181 | ? a/1/in_a_1 (glob) |
|
181 | ? a/1/in_a_1 (glob) | |
182 | ? a/in_a (glob) |
|
182 | ? a/in_a (glob) | |
183 | ? b/1/in_b_1 (glob) |
|
183 | ? b/1/in_b_1 (glob) | |
184 | ? b/2/in_b_2 (glob) |
|
184 | ? b/2/in_b_2 (glob) | |
185 | ? b/in_b (glob) |
|
185 | ? b/in_b (glob) | |
186 | ? in_root |
|
186 | ? in_root | |
187 |
|
187 | |||
188 | if relative paths are explicitly off, tweakdefaults doesn't change it |
|
188 | if relative paths are explicitly off, tweakdefaults doesn't change it | |
189 | $ cat >> $HGRCPATH <<EOF |
|
189 | $ cat >> $HGRCPATH <<EOF | |
190 | > [commands] |
|
190 | > [commands] | |
191 | > status.relative = False |
|
191 | > status.relative = False | |
192 | > EOF |
|
192 | > EOF | |
193 | $ hg status --cwd a --config ui.tweakdefaults=yes |
|
193 | $ hg status --cwd a --config ui.tweakdefaults=yes | |
194 | ? a/1/in_a_1 |
|
194 | ? a/1/in_a_1 | |
195 | ? a/in_a |
|
195 | ? a/in_a | |
196 | ? b/1/in_b_1 |
|
196 | ? b/1/in_b_1 | |
197 | ? b/2/in_b_2 |
|
197 | ? b/2/in_b_2 | |
198 | ? b/in_b |
|
198 | ? b/in_b | |
199 | ? in_root |
|
199 | ? in_root | |
200 |
|
200 | |||
201 | $ cd .. |
|
201 | $ cd .. | |
202 |
|
202 | |||
203 | $ hg init repo2 |
|
203 | $ hg init repo2 | |
204 | $ cd repo2 |
|
204 | $ cd repo2 | |
205 | $ touch modified removed deleted ignored |
|
205 | $ touch modified removed deleted ignored | |
206 | $ echo "^ignored$" > .hgignore |
|
206 | $ echo "^ignored$" > .hgignore | |
207 | $ hg ci -A -m 'initial checkin' |
|
207 | $ hg ci -A -m 'initial checkin' | |
208 | adding .hgignore |
|
208 | adding .hgignore | |
209 | adding deleted |
|
209 | adding deleted | |
210 | adding modified |
|
210 | adding modified | |
211 | adding removed |
|
211 | adding removed | |
212 | $ touch modified added unknown ignored |
|
212 | $ touch modified added unknown ignored | |
213 | $ hg add added |
|
213 | $ hg add added | |
214 | $ hg remove removed |
|
214 | $ hg remove removed | |
215 | $ rm deleted |
|
215 | $ rm deleted | |
216 |
|
216 | |||
217 | hg status: |
|
217 | hg status: | |
218 |
|
218 | |||
219 | $ hg status |
|
219 | $ hg status | |
220 | A added |
|
220 | A added | |
221 | R removed |
|
221 | R removed | |
222 | ! deleted |
|
222 | ! deleted | |
223 | ? unknown |
|
223 | ? unknown | |
224 |
|
224 | |||
|
225 | hg status -n: | |||
|
226 | $ env RHG_STATUS=1 RHG_ON_UNSUPPORTED=abort hg status -n | |||
|
227 | added | |||
|
228 | removed | |||
|
229 | deleted | |||
|
230 | unknown | |||
|
231 | ||||
225 | hg status modified added removed deleted unknown never-existed ignored: |
|
232 | hg status modified added removed deleted unknown never-existed ignored: | |
226 |
|
233 | |||
227 | $ hg status modified added removed deleted unknown never-existed ignored |
|
234 | $ hg status modified added removed deleted unknown never-existed ignored | |
228 | never-existed: * (glob) |
|
235 | never-existed: * (glob) | |
229 | A added |
|
236 | A added | |
230 | R removed |
|
237 | R removed | |
231 | ! deleted |
|
238 | ! deleted | |
232 | ? unknown |
|
239 | ? unknown | |
233 |
|
240 | |||
234 | $ hg copy modified copied |
|
241 | $ hg copy modified copied | |
235 |
|
242 | |||
236 | hg status -C: |
|
243 | hg status -C: | |
237 |
|
244 | |||
238 | $ hg status -C |
|
245 | $ hg status -C | |
239 | A added |
|
246 | A added | |
240 | A copied |
|
247 | A copied | |
241 | modified |
|
248 | modified | |
242 | R removed |
|
249 | R removed | |
243 | ! deleted |
|
250 | ! deleted | |
244 | ? unknown |
|
251 | ? unknown | |
245 |
|
252 | |||
246 | hg status -A: |
|
253 | hg status -A: | |
247 |
|
254 | |||
248 | $ hg status -A |
|
255 | $ hg status -A | |
249 | A added |
|
256 | A added | |
250 | A copied |
|
257 | A copied | |
251 | modified |
|
258 | modified | |
252 | R removed |
|
259 | R removed | |
253 | ! deleted |
|
260 | ! deleted | |
254 | ? unknown |
|
261 | ? unknown | |
255 | I ignored |
|
262 | I ignored | |
256 | C .hgignore |
|
263 | C .hgignore | |
257 | C modified |
|
264 | C modified | |
258 |
|
265 | |||
259 | $ hg status -A -T '{status} {path} {node|shortest}\n' |
|
266 | $ hg status -A -T '{status} {path} {node|shortest}\n' | |
260 | A added ffff |
|
267 | A added ffff | |
261 | A copied ffff |
|
268 | A copied ffff | |
262 | R removed ffff |
|
269 | R removed ffff | |
263 | ! deleted ffff |
|
270 | ! deleted ffff | |
264 | ? unknown ffff |
|
271 | ? unknown ffff | |
265 | I ignored ffff |
|
272 | I ignored ffff | |
266 | C .hgignore ffff |
|
273 | C .hgignore ffff | |
267 | C modified ffff |
|
274 | C modified ffff | |
268 |
|
275 | |||
269 | $ hg status -A -Tjson |
|
276 | $ hg status -A -Tjson | |
270 | [ |
|
277 | [ | |
271 | { |
|
278 | { | |
272 | "itemtype": "file", |
|
279 | "itemtype": "file", | |
273 | "path": "added", |
|
280 | "path": "added", | |
274 | "status": "A" |
|
281 | "status": "A" | |
275 | }, |
|
282 | }, | |
276 | { |
|
283 | { | |
277 | "itemtype": "file", |
|
284 | "itemtype": "file", | |
278 | "path": "copied", |
|
285 | "path": "copied", | |
279 | "source": "modified", |
|
286 | "source": "modified", | |
280 | "status": "A" |
|
287 | "status": "A" | |
281 | }, |
|
288 | }, | |
282 | { |
|
289 | { | |
283 | "itemtype": "file", |
|
290 | "itemtype": "file", | |
284 | "path": "removed", |
|
291 | "path": "removed", | |
285 | "status": "R" |
|
292 | "status": "R" | |
286 | }, |
|
293 | }, | |
287 | { |
|
294 | { | |
288 | "itemtype": "file", |
|
295 | "itemtype": "file", | |
289 | "path": "deleted", |
|
296 | "path": "deleted", | |
290 | "status": "!" |
|
297 | "status": "!" | |
291 | }, |
|
298 | }, | |
292 | { |
|
299 | { | |
293 | "itemtype": "file", |
|
300 | "itemtype": "file", | |
294 | "path": "unknown", |
|
301 | "path": "unknown", | |
295 | "status": "?" |
|
302 | "status": "?" | |
296 | }, |
|
303 | }, | |
297 | { |
|
304 | { | |
298 | "itemtype": "file", |
|
305 | "itemtype": "file", | |
299 | "path": "ignored", |
|
306 | "path": "ignored", | |
300 | "status": "I" |
|
307 | "status": "I" | |
301 | }, |
|
308 | }, | |
302 | { |
|
309 | { | |
303 | "itemtype": "file", |
|
310 | "itemtype": "file", | |
304 | "path": ".hgignore", |
|
311 | "path": ".hgignore", | |
305 | "status": "C" |
|
312 | "status": "C" | |
306 | }, |
|
313 | }, | |
307 | { |
|
314 | { | |
308 | "itemtype": "file", |
|
315 | "itemtype": "file", | |
309 | "path": "modified", |
|
316 | "path": "modified", | |
310 | "status": "C" |
|
317 | "status": "C" | |
311 | } |
|
318 | } | |
312 | ] |
|
319 | ] | |
313 |
|
320 | |||
314 | $ hg status -A -Tpickle > pickle |
|
321 | $ hg status -A -Tpickle > pickle | |
315 | >>> from __future__ import print_function |
|
322 | >>> from __future__ import print_function | |
316 | >>> from mercurial import util |
|
323 | >>> from mercurial import util | |
317 | >>> pickle = util.pickle |
|
324 | >>> pickle = util.pickle | |
318 | >>> data = sorted((x[b'status'].decode(), x[b'path'].decode()) for x in pickle.load(open("pickle", r"rb"))) |
|
325 | >>> data = sorted((x[b'status'].decode(), x[b'path'].decode()) for x in pickle.load(open("pickle", r"rb"))) | |
319 | >>> for s, p in data: print("%s %s" % (s, p)) |
|
326 | >>> for s, p in data: print("%s %s" % (s, p)) | |
320 | ! deleted |
|
327 | ! deleted | |
321 | ? pickle |
|
328 | ? pickle | |
322 | ? unknown |
|
329 | ? unknown | |
323 | A added |
|
330 | A added | |
324 | A copied |
|
331 | A copied | |
325 | C .hgignore |
|
332 | C .hgignore | |
326 | C modified |
|
333 | C modified | |
327 | I ignored |
|
334 | I ignored | |
328 | R removed |
|
335 | R removed | |
329 | $ rm pickle |
|
336 | $ rm pickle | |
330 |
|
337 | |||
331 | $ echo "^ignoreddir$" > .hgignore |
|
338 | $ echo "^ignoreddir$" > .hgignore | |
332 | $ mkdir ignoreddir |
|
339 | $ mkdir ignoreddir | |
333 | $ touch ignoreddir/file |
|
340 | $ touch ignoreddir/file | |
334 |
|
341 | |||
335 | Test templater support: |
|
342 | Test templater support: | |
336 |
|
343 | |||
337 | $ hg status -AT "[{status}]\t{if(source, '{source} -> ')}{path}\n" |
|
344 | $ hg status -AT "[{status}]\t{if(source, '{source} -> ')}{path}\n" | |
338 | [M] .hgignore |
|
345 | [M] .hgignore | |
339 | [A] added |
|
346 | [A] added | |
340 | [A] modified -> copied |
|
347 | [A] modified -> copied | |
341 | [R] removed |
|
348 | [R] removed | |
342 | [!] deleted |
|
349 | [!] deleted | |
343 | [?] ignored |
|
350 | [?] ignored | |
344 | [?] unknown |
|
351 | [?] unknown | |
345 | [I] ignoreddir/file |
|
352 | [I] ignoreddir/file | |
346 | [C] modified |
|
353 | [C] modified | |
347 | $ hg status -AT default |
|
354 | $ hg status -AT default | |
348 | M .hgignore |
|
355 | M .hgignore | |
349 | A added |
|
356 | A added | |
350 | A copied |
|
357 | A copied | |
351 | modified |
|
358 | modified | |
352 | R removed |
|
359 | R removed | |
353 | ! deleted |
|
360 | ! deleted | |
354 | ? ignored |
|
361 | ? ignored | |
355 | ? unknown |
|
362 | ? unknown | |
356 | I ignoreddir/file |
|
363 | I ignoreddir/file | |
357 | C modified |
|
364 | C modified | |
358 | $ hg status -T compact |
|
365 | $ hg status -T compact | |
359 | abort: "status" not in template map |
|
366 | abort: "status" not in template map | |
360 | [255] |
|
367 | [255] | |
361 |
|
368 | |||
362 | hg status ignoreddir/file: |
|
369 | hg status ignoreddir/file: | |
363 |
|
370 | |||
364 | $ hg status ignoreddir/file |
|
371 | $ hg status ignoreddir/file | |
365 |
|
372 | |||
366 | hg status -i ignoreddir/file: |
|
373 | hg status -i ignoreddir/file: | |
367 |
|
374 | |||
368 | $ hg status -i ignoreddir/file |
|
375 | $ hg status -i ignoreddir/file | |
369 | I ignoreddir/file |
|
376 | I ignoreddir/file | |
370 | $ cd .. |
|
377 | $ cd .. | |
371 |
|
378 | |||
372 | Check 'status -q' and some combinations |
|
379 | Check 'status -q' and some combinations | |
373 |
|
380 | |||
374 | $ hg init repo3 |
|
381 | $ hg init repo3 | |
375 | $ cd repo3 |
|
382 | $ cd repo3 | |
376 | $ touch modified removed deleted ignored |
|
383 | $ touch modified removed deleted ignored | |
377 | $ echo "^ignored$" > .hgignore |
|
384 | $ echo "^ignored$" > .hgignore | |
378 | $ hg commit -A -m 'initial checkin' |
|
385 | $ hg commit -A -m 'initial checkin' | |
379 | adding .hgignore |
|
386 | adding .hgignore | |
380 | adding deleted |
|
387 | adding deleted | |
381 | adding modified |
|
388 | adding modified | |
382 | adding removed |
|
389 | adding removed | |
383 | $ touch added unknown ignored |
|
390 | $ touch added unknown ignored | |
384 | $ hg add added |
|
391 | $ hg add added | |
385 | $ echo "test" >> modified |
|
392 | $ echo "test" >> modified | |
386 | $ hg remove removed |
|
393 | $ hg remove removed | |
387 | $ rm deleted |
|
394 | $ rm deleted | |
388 | $ hg copy modified copied |
|
395 | $ hg copy modified copied | |
389 |
|
396 | |||
390 | Specify working directory revision explicitly, that should be the same as |
|
397 | Specify working directory revision explicitly, that should be the same as | |
391 | "hg status" |
|
398 | "hg status" | |
392 |
|
399 | |||
393 | $ hg status --change "wdir()" |
|
400 | $ hg status --change "wdir()" | |
394 | M modified |
|
401 | M modified | |
395 | A added |
|
402 | A added | |
396 | A copied |
|
403 | A copied | |
397 | R removed |
|
404 | R removed | |
398 | ! deleted |
|
405 | ! deleted | |
399 | ? unknown |
|
406 | ? unknown | |
400 |
|
407 | |||
401 | Run status with 2 different flags. |
|
408 | Run status with 2 different flags. | |
402 | Check if result is the same or different. |
|
409 | Check if result is the same or different. | |
403 | If result is not as expected, raise error |
|
410 | If result is not as expected, raise error | |
404 |
|
411 | |||
405 | $ assert() { |
|
412 | $ assert() { | |
406 | > hg status $1 > ../a |
|
413 | > hg status $1 > ../a | |
407 | > hg status $2 > ../b |
|
414 | > hg status $2 > ../b | |
408 | > if diff ../a ../b > /dev/null; then |
|
415 | > if diff ../a ../b > /dev/null; then | |
409 | > out=0 |
|
416 | > out=0 | |
410 | > else |
|
417 | > else | |
411 | > out=1 |
|
418 | > out=1 | |
412 | > fi |
|
419 | > fi | |
413 | > if [ $3 -eq 0 ]; then |
|
420 | > if [ $3 -eq 0 ]; then | |
414 | > df="same" |
|
421 | > df="same" | |
415 | > else |
|
422 | > else | |
416 | > df="different" |
|
423 | > df="different" | |
417 | > fi |
|
424 | > fi | |
418 | > if [ $out -ne $3 ]; then |
|
425 | > if [ $out -ne $3 ]; then | |
419 | > echo "Error on $1 and $2, should be $df." |
|
426 | > echo "Error on $1 and $2, should be $df." | |
420 | > fi |
|
427 | > fi | |
421 | > } |
|
428 | > } | |
422 |
|
429 | |||
423 | Assert flag1 flag2 [0-same | 1-different] |
|
430 | Assert flag1 flag2 [0-same | 1-different] | |
424 |
|
431 | |||
425 | $ assert "-q" "-mard" 0 |
|
432 | $ assert "-q" "-mard" 0 | |
426 | $ assert "-A" "-marduicC" 0 |
|
433 | $ assert "-A" "-marduicC" 0 | |
427 | $ assert "-qA" "-mardcC" 0 |
|
434 | $ assert "-qA" "-mardcC" 0 | |
428 | $ assert "-qAui" "-A" 0 |
|
435 | $ assert "-qAui" "-A" 0 | |
429 | $ assert "-qAu" "-marducC" 0 |
|
436 | $ assert "-qAu" "-marducC" 0 | |
430 | $ assert "-qAi" "-mardicC" 0 |
|
437 | $ assert "-qAi" "-mardicC" 0 | |
431 | $ assert "-qu" "-u" 0 |
|
438 | $ assert "-qu" "-u" 0 | |
432 | $ assert "-q" "-u" 1 |
|
439 | $ assert "-q" "-u" 1 | |
433 | $ assert "-m" "-a" 1 |
|
440 | $ assert "-m" "-a" 1 | |
434 | $ assert "-r" "-d" 1 |
|
441 | $ assert "-r" "-d" 1 | |
435 | $ cd .. |
|
442 | $ cd .. | |
436 |
|
443 | |||
437 | $ hg init repo4 |
|
444 | $ hg init repo4 | |
438 | $ cd repo4 |
|
445 | $ cd repo4 | |
439 | $ touch modified removed deleted |
|
446 | $ touch modified removed deleted | |
440 | $ hg ci -q -A -m 'initial checkin' |
|
447 | $ hg ci -q -A -m 'initial checkin' | |
441 | $ touch added unknown |
|
448 | $ touch added unknown | |
442 | $ hg add added |
|
449 | $ hg add added | |
443 | $ hg remove removed |
|
450 | $ hg remove removed | |
444 | $ rm deleted |
|
451 | $ rm deleted | |
445 | $ echo x > modified |
|
452 | $ echo x > modified | |
446 | $ hg copy modified copied |
|
453 | $ hg copy modified copied | |
447 | $ hg ci -m 'test checkin' -d "1000001 0" |
|
454 | $ hg ci -m 'test checkin' -d "1000001 0" | |
448 | $ rm * |
|
455 | $ rm * | |
449 | $ touch unrelated |
|
456 | $ touch unrelated | |
450 | $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0" |
|
457 | $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0" | |
451 |
|
458 | |||
452 | hg status --change 1: |
|
459 | hg status --change 1: | |
453 |
|
460 | |||
454 | $ hg status --change 1 |
|
461 | $ hg status --change 1 | |
455 | M modified |
|
462 | M modified | |
456 | A added |
|
463 | A added | |
457 | A copied |
|
464 | A copied | |
458 | R removed |
|
465 | R removed | |
459 |
|
466 | |||
460 | hg status --change 1 unrelated: |
|
467 | hg status --change 1 unrelated: | |
461 |
|
468 | |||
462 | $ hg status --change 1 unrelated |
|
469 | $ hg status --change 1 unrelated | |
463 |
|
470 | |||
464 | hg status -C --change 1 added modified copied removed deleted: |
|
471 | hg status -C --change 1 added modified copied removed deleted: | |
465 |
|
472 | |||
466 | $ hg status -C --change 1 added modified copied removed deleted |
|
473 | $ hg status -C --change 1 added modified copied removed deleted | |
467 | M modified |
|
474 | M modified | |
468 | A added |
|
475 | A added | |
469 | A copied |
|
476 | A copied | |
470 | modified |
|
477 | modified | |
471 | R removed |
|
478 | R removed | |
472 |
|
479 | |||
473 | hg status -A --change 1 and revset: |
|
480 | hg status -A --change 1 and revset: | |
474 |
|
481 | |||
475 | $ hg status -A --change '1|1' |
|
482 | $ hg status -A --change '1|1' | |
476 | M modified |
|
483 | M modified | |
477 | A added |
|
484 | A added | |
478 | A copied |
|
485 | A copied | |
479 | modified |
|
486 | modified | |
480 | R removed |
|
487 | R removed | |
481 | C deleted |
|
488 | C deleted | |
482 |
|
489 | |||
483 | $ cd .. |
|
490 | $ cd .. | |
484 |
|
491 | |||
485 | hg status with --rev and reverted changes: |
|
492 | hg status with --rev and reverted changes: | |
486 |
|
493 | |||
487 | $ hg init reverted-changes-repo |
|
494 | $ hg init reverted-changes-repo | |
488 | $ cd reverted-changes-repo |
|
495 | $ cd reverted-changes-repo | |
489 | $ echo a > file |
|
496 | $ echo a > file | |
490 | $ hg add file |
|
497 | $ hg add file | |
491 | $ hg ci -m a |
|
498 | $ hg ci -m a | |
492 | $ echo b > file |
|
499 | $ echo b > file | |
493 | $ hg ci -m b |
|
500 | $ hg ci -m b | |
494 |
|
501 | |||
495 | reverted file should appear clean |
|
502 | reverted file should appear clean | |
496 |
|
503 | |||
497 | $ hg revert -r 0 . |
|
504 | $ hg revert -r 0 . | |
498 | reverting file |
|
505 | reverting file | |
499 | $ hg status -A --rev 0 |
|
506 | $ hg status -A --rev 0 | |
500 | C file |
|
507 | C file | |
501 |
|
508 | |||
502 | #if execbit |
|
509 | #if execbit | |
503 | reverted file with changed flag should appear modified |
|
510 | reverted file with changed flag should appear modified | |
504 |
|
511 | |||
505 | $ chmod +x file |
|
512 | $ chmod +x file | |
506 | $ hg status -A --rev 0 |
|
513 | $ hg status -A --rev 0 | |
507 | M file |
|
514 | M file | |
508 |
|
515 | |||
509 | $ hg revert -r 0 . |
|
516 | $ hg revert -r 0 . | |
510 | reverting file |
|
517 | reverting file | |
511 |
|
518 | |||
512 | reverted and committed file with changed flag should appear modified |
|
519 | reverted and committed file with changed flag should appear modified | |
513 |
|
520 | |||
514 | $ hg co -C . |
|
521 | $ hg co -C . | |
515 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
522 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
516 | $ chmod +x file |
|
523 | $ chmod +x file | |
517 | $ hg ci -m 'change flag' |
|
524 | $ hg ci -m 'change flag' | |
518 | $ hg status -A --rev 1 --rev 2 |
|
525 | $ hg status -A --rev 1 --rev 2 | |
519 | M file |
|
526 | M file | |
520 | $ hg diff -r 1 -r 2 |
|
527 | $ hg diff -r 1 -r 2 | |
521 |
|
528 | |||
522 | #endif |
|
529 | #endif | |
523 |
|
530 | |||
524 | $ cd .. |
|
531 | $ cd .. | |
525 |
|
532 | |||
526 | hg status of binary file starting with '\1\n', a separator for metadata: |
|
533 | hg status of binary file starting with '\1\n', a separator for metadata: | |
527 |
|
534 | |||
528 | $ hg init repo5 |
|
535 | $ hg init repo5 | |
529 | $ cd repo5 |
|
536 | $ cd repo5 | |
530 | >>> open("010a", r"wb").write(b"\1\nfoo") and None |
|
537 | >>> open("010a", r"wb").write(b"\1\nfoo") and None | |
531 | $ hg ci -q -A -m 'initial checkin' |
|
538 | $ hg ci -q -A -m 'initial checkin' | |
532 | $ hg status -A |
|
539 | $ hg status -A | |
533 | C 010a |
|
540 | C 010a | |
534 |
|
541 | |||
535 | >>> open("010a", r"wb").write(b"\1\nbar") and None |
|
542 | >>> open("010a", r"wb").write(b"\1\nbar") and None | |
536 | $ hg status -A |
|
543 | $ hg status -A | |
537 | M 010a |
|
544 | M 010a | |
538 | $ hg ci -q -m 'modify 010a' |
|
545 | $ hg ci -q -m 'modify 010a' | |
539 | $ hg status -A --rev 0:1 |
|
546 | $ hg status -A --rev 0:1 | |
540 | M 010a |
|
547 | M 010a | |
541 |
|
548 | |||
542 | $ touch empty |
|
549 | $ touch empty | |
543 | $ hg ci -q -A -m 'add another file' |
|
550 | $ hg ci -q -A -m 'add another file' | |
544 | $ hg status -A --rev 1:2 010a |
|
551 | $ hg status -A --rev 1:2 010a | |
545 | C 010a |
|
552 | C 010a | |
546 |
|
553 | |||
547 | $ cd .. |
|
554 | $ cd .. | |
548 |
|
555 | |||
549 | test "hg status" with "directory pattern" which matches against files |
|
556 | test "hg status" with "directory pattern" which matches against files | |
550 | only known on target revision. |
|
557 | only known on target revision. | |
551 |
|
558 | |||
552 | $ hg init repo6 |
|
559 | $ hg init repo6 | |
553 | $ cd repo6 |
|
560 | $ cd repo6 | |
554 |
|
561 | |||
555 | $ echo a > a.txt |
|
562 | $ echo a > a.txt | |
556 | $ hg add a.txt |
|
563 | $ hg add a.txt | |
557 | $ hg commit -m '#0' |
|
564 | $ hg commit -m '#0' | |
558 | $ mkdir -p 1/2/3/4/5 |
|
565 | $ mkdir -p 1/2/3/4/5 | |
559 | $ echo b > 1/2/3/4/5/b.txt |
|
566 | $ echo b > 1/2/3/4/5/b.txt | |
560 | $ hg add 1/2/3/4/5/b.txt |
|
567 | $ hg add 1/2/3/4/5/b.txt | |
561 | $ hg commit -m '#1' |
|
568 | $ hg commit -m '#1' | |
562 |
|
569 | |||
563 | $ hg update -C 0 > /dev/null |
|
570 | $ hg update -C 0 > /dev/null | |
564 | $ hg status -A |
|
571 | $ hg status -A | |
565 | C a.txt |
|
572 | C a.txt | |
566 |
|
573 | |||
567 | the directory matching against specified pattern should be removed, |
|
574 | the directory matching against specified pattern should be removed, | |
568 | because directory existence prevents 'dirstate.walk()' from showing |
|
575 | because directory existence prevents 'dirstate.walk()' from showing | |
569 | warning message about such pattern. |
|
576 | warning message about such pattern. | |
570 |
|
577 | |||
571 | $ test ! -d 1 |
|
578 | $ test ! -d 1 | |
572 | $ hg status -A --rev 1 1/2/3/4/5/b.txt |
|
579 | $ hg status -A --rev 1 1/2/3/4/5/b.txt | |
573 | R 1/2/3/4/5/b.txt |
|
580 | R 1/2/3/4/5/b.txt | |
574 | $ hg status -A --rev 1 1/2/3/4/5 |
|
581 | $ hg status -A --rev 1 1/2/3/4/5 | |
575 | R 1/2/3/4/5/b.txt |
|
582 | R 1/2/3/4/5/b.txt | |
576 | $ hg status -A --rev 1 1/2/3 |
|
583 | $ hg status -A --rev 1 1/2/3 | |
577 | R 1/2/3/4/5/b.txt |
|
584 | R 1/2/3/4/5/b.txt | |
578 | $ hg status -A --rev 1 1 |
|
585 | $ hg status -A --rev 1 1 | |
579 | R 1/2/3/4/5/b.txt |
|
586 | R 1/2/3/4/5/b.txt | |
580 |
|
587 | |||
581 | $ hg status --config ui.formatdebug=True --rev 1 1 |
|
588 | $ hg status --config ui.formatdebug=True --rev 1 1 | |
582 | status = [ |
|
589 | status = [ | |
583 | { |
|
590 | { | |
584 | 'itemtype': 'file', |
|
591 | 'itemtype': 'file', | |
585 | 'path': '1/2/3/4/5/b.txt', |
|
592 | 'path': '1/2/3/4/5/b.txt', | |
586 | 'status': 'R' |
|
593 | 'status': 'R' | |
587 | }, |
|
594 | }, | |
588 | ] |
|
595 | ] | |
589 |
|
596 | |||
590 | #if windows |
|
597 | #if windows | |
591 | $ hg --config ui.slash=false status -A --rev 1 1 |
|
598 | $ hg --config ui.slash=false status -A --rev 1 1 | |
592 | R 1\2\3\4\5\b.txt |
|
599 | R 1\2\3\4\5\b.txt | |
593 | #endif |
|
600 | #endif | |
594 |
|
601 | |||
595 | $ cd .. |
|
602 | $ cd .. | |
596 |
|
603 | |||
597 | Status after move overwriting a file (issue4458) |
|
604 | Status after move overwriting a file (issue4458) | |
598 | ================================================= |
|
605 | ================================================= | |
599 |
|
606 | |||
600 |
|
607 | |||
601 | $ hg init issue4458 |
|
608 | $ hg init issue4458 | |
602 | $ cd issue4458 |
|
609 | $ cd issue4458 | |
603 | $ echo a > a |
|
610 | $ echo a > a | |
604 | $ echo b > b |
|
611 | $ echo b > b | |
605 | $ hg commit -Am base |
|
612 | $ hg commit -Am base | |
606 | adding a |
|
613 | adding a | |
607 | adding b |
|
614 | adding b | |
608 |
|
615 | |||
609 |
|
616 | |||
610 | with --force |
|
617 | with --force | |
611 |
|
618 | |||
612 | $ hg mv b --force a |
|
619 | $ hg mv b --force a | |
613 | $ hg st --copies |
|
620 | $ hg st --copies | |
614 | M a |
|
621 | M a | |
615 | b |
|
622 | b | |
616 | R b |
|
623 | R b | |
617 | $ hg revert --all |
|
624 | $ hg revert --all | |
618 | reverting a |
|
625 | reverting a | |
619 | undeleting b |
|
626 | undeleting b | |
620 | $ rm *.orig |
|
627 | $ rm *.orig | |
621 |
|
628 | |||
622 | without force |
|
629 | without force | |
623 |
|
630 | |||
624 | $ hg rm a |
|
631 | $ hg rm a | |
625 | $ hg st --copies |
|
632 | $ hg st --copies | |
626 | R a |
|
633 | R a | |
627 | $ hg mv b a |
|
634 | $ hg mv b a | |
628 | $ hg st --copies |
|
635 | $ hg st --copies | |
629 | M a |
|
636 | M a | |
630 | b |
|
637 | b | |
631 | R b |
|
638 | R b | |
632 |
|
639 | |||
633 | using ui.statuscopies setting |
|
640 | using ui.statuscopies setting | |
634 | $ hg st --config ui.statuscopies=true |
|
641 | $ hg st --config ui.statuscopies=true | |
635 | M a |
|
642 | M a | |
636 | b |
|
643 | b | |
637 | R b |
|
644 | R b | |
638 | $ hg st --config ui.statuscopies=false |
|
645 | $ hg st --config ui.statuscopies=false | |
639 | M a |
|
646 | M a | |
640 | R b |
|
647 | R b | |
641 | $ hg st --config ui.tweakdefaults=yes |
|
648 | $ hg st --config ui.tweakdefaults=yes | |
642 | M a |
|
649 | M a | |
643 | b |
|
650 | b | |
644 | R b |
|
651 | R b | |
645 |
|
652 | |||
646 | using log status template (issue5155) |
|
653 | using log status template (issue5155) | |
647 | $ hg log -Tstatus -r 'wdir()' -C |
|
654 | $ hg log -Tstatus -r 'wdir()' -C | |
648 | changeset: 2147483647:ffffffffffff |
|
655 | changeset: 2147483647:ffffffffffff | |
649 | parent: 0:8c55c58b4c0e |
|
656 | parent: 0:8c55c58b4c0e | |
650 | user: test |
|
657 | user: test | |
651 | date: * (glob) |
|
658 | date: * (glob) | |
652 | files: |
|
659 | files: | |
653 | M a |
|
660 | M a | |
654 | b |
|
661 | b | |
655 | R b |
|
662 | R b | |
656 |
|
663 | |||
657 | $ hg log -GTstatus -r 'wdir()' -C |
|
664 | $ hg log -GTstatus -r 'wdir()' -C | |
658 | o changeset: 2147483647:ffffffffffff |
|
665 | o changeset: 2147483647:ffffffffffff | |
659 | | parent: 0:8c55c58b4c0e |
|
666 | | parent: 0:8c55c58b4c0e | |
660 | ~ user: test |
|
667 | ~ user: test | |
661 | date: * (glob) |
|
668 | date: * (glob) | |
662 | files: |
|
669 | files: | |
663 | M a |
|
670 | M a | |
664 | b |
|
671 | b | |
665 | R b |
|
672 | R b | |
666 |
|
673 | |||
667 |
|
674 | |||
668 | Other "bug" highlight, the revision status does not report the copy information. |
|
675 | Other "bug" highlight, the revision status does not report the copy information. | |
669 | This is buggy behavior. |
|
676 | This is buggy behavior. | |
670 |
|
677 | |||
671 | $ hg commit -m 'blah' |
|
678 | $ hg commit -m 'blah' | |
672 | $ hg st --copies --change . |
|
679 | $ hg st --copies --change . | |
673 | M a |
|
680 | M a | |
674 | R b |
|
681 | R b | |
675 |
|
682 | |||
676 | using log status template, the copy information is displayed correctly. |
|
683 | using log status template, the copy information is displayed correctly. | |
677 | $ hg log -Tstatus -r. -C |
|
684 | $ hg log -Tstatus -r. -C | |
678 | changeset: 1:6685fde43d21 |
|
685 | changeset: 1:6685fde43d21 | |
679 | tag: tip |
|
686 | tag: tip | |
680 | user: test |
|
687 | user: test | |
681 | date: * (glob) |
|
688 | date: * (glob) | |
682 | summary: blah |
|
689 | summary: blah | |
683 | files: |
|
690 | files: | |
684 | M a |
|
691 | M a | |
685 | b |
|
692 | b | |
686 | R b |
|
693 | R b | |
687 |
|
694 | |||
688 |
|
695 | |||
689 | $ cd .. |
|
696 | $ cd .. | |
690 |
|
697 | |||
691 | Make sure .hg doesn't show up even as a symlink |
|
698 | Make sure .hg doesn't show up even as a symlink | |
692 |
|
699 | |||
693 | $ hg init repo0 |
|
700 | $ hg init repo0 | |
694 | $ mkdir symlink-repo0 |
|
701 | $ mkdir symlink-repo0 | |
695 | $ cd symlink-repo0 |
|
702 | $ cd symlink-repo0 | |
696 | $ ln -s ../repo0/.hg |
|
703 | $ ln -s ../repo0/.hg | |
697 | $ hg status |
|
704 | $ hg status | |
698 |
|
705 | |||
699 | If the size hasn’t changed but mtime has, status needs to read the contents |
|
706 | If the size hasn’t changed but mtime has, status needs to read the contents | |
700 | of the file to check whether it has changed |
|
707 | of the file to check whether it has changed | |
701 |
|
708 | |||
702 | $ echo 1 > a |
|
709 | $ echo 1 > a | |
703 | $ echo 1 > b |
|
710 | $ echo 1 > b | |
704 | $ touch -t 200102030000 a b |
|
711 | $ touch -t 200102030000 a b | |
705 | $ hg commit -Aqm '#0' |
|
712 | $ hg commit -Aqm '#0' | |
706 | $ echo 2 > a |
|
713 | $ echo 2 > a | |
707 | $ touch -t 200102040000 a b |
|
714 | $ touch -t 200102040000 a b | |
708 | $ hg status |
|
715 | $ hg status | |
709 | M a |
|
716 | M a | |
710 |
|
717 | |||
711 | Asking specifically for the status of a deleted/removed file |
|
718 | Asking specifically for the status of a deleted/removed file | |
712 |
|
719 | |||
713 | $ rm a |
|
720 | $ rm a | |
714 | $ rm b |
|
721 | $ rm b | |
715 | $ hg status a |
|
722 | $ hg status a | |
716 | ! a |
|
723 | ! a | |
717 | $ hg rm a |
|
724 | $ hg rm a | |
718 | $ hg rm b |
|
725 | $ hg rm b | |
719 | $ hg status a |
|
726 | $ hg status a | |
720 | R a |
|
727 | R a | |
721 | $ hg commit -qm '#1' |
|
728 | $ hg commit -qm '#1' | |
722 | $ hg status a |
|
729 | $ hg status a | |
723 | a: $ENOENT$ |
|
730 | a: $ENOENT$ | |
724 |
|
731 | |||
725 | Check using include flag with pattern when status does not need to traverse |
|
732 | Check using include flag with pattern when status does not need to traverse | |
726 | the working directory (issue6483) |
|
733 | the working directory (issue6483) | |
727 |
|
734 | |||
728 | $ cd .. |
|
735 | $ cd .. | |
729 | $ hg init issue6483 |
|
736 | $ hg init issue6483 | |
730 | $ cd issue6483 |
|
737 | $ cd issue6483 | |
731 | $ touch a.py b.rs |
|
738 | $ touch a.py b.rs | |
732 | $ hg add a.py b.rs |
|
739 | $ hg add a.py b.rs | |
733 | $ hg st -aI "*.py" |
|
740 | $ hg st -aI "*.py" | |
734 | A a.py |
|
741 | A a.py | |
735 |
|
742 | |||
736 | Also check exclude pattern |
|
743 | Also check exclude pattern | |
737 |
|
744 | |||
738 | $ hg st -aX "*.rs" |
|
745 | $ hg st -aX "*.rs" | |
739 | A a.py |
|
746 | A a.py | |
740 |
|
747 | |||
741 | issue6335 |
|
748 | issue6335 | |
742 | When a directory containing a tracked file gets symlinked, as of 5.8 |
|
749 | When a directory containing a tracked file gets symlinked, as of 5.8 | |
743 | `hg st` only gives the correct answer about clean (or deleted) files |
|
750 | `hg st` only gives the correct answer about clean (or deleted) files | |
744 | if also listing unknowns. |
|
751 | if also listing unknowns. | |
745 | The tree-based dirstate and status algorithm fix this: |
|
752 | The tree-based dirstate and status algorithm fix this: | |
746 |
|
753 | |||
747 | #if symlink no-dirstate-v1 rust |
|
754 | #if symlink no-dirstate-v1 rust | |
748 |
|
755 | |||
749 | $ cd .. |
|
756 | $ cd .. | |
750 | $ hg init issue6335 |
|
757 | $ hg init issue6335 | |
751 | $ cd issue6335 |
|
758 | $ cd issue6335 | |
752 | $ mkdir foo |
|
759 | $ mkdir foo | |
753 | $ touch foo/a |
|
760 | $ touch foo/a | |
754 | $ hg ci -Ama |
|
761 | $ hg ci -Ama | |
755 | adding foo/a |
|
762 | adding foo/a | |
756 | $ mv foo bar |
|
763 | $ mv foo bar | |
757 | $ ln -s bar foo |
|
764 | $ ln -s bar foo | |
758 | $ hg status |
|
765 | $ hg status | |
759 | ! foo/a |
|
766 | ! foo/a | |
760 | ? bar/a |
|
767 | ? bar/a | |
761 | ? foo |
|
768 | ? foo | |
762 |
|
769 | |||
763 | $ hg status -c # incorrect output without the Rust implementation |
|
770 | $ hg status -c # incorrect output without the Rust implementation | |
764 | $ hg status -cu |
|
771 | $ hg status -cu | |
765 | ? bar/a |
|
772 | ? bar/a | |
766 | ? foo |
|
773 | ? foo | |
767 | $ hg status -d # incorrect output without the Rust implementation |
|
774 | $ hg status -d # incorrect output without the Rust implementation | |
768 | ! foo/a |
|
775 | ! foo/a | |
769 | $ hg status -du |
|
776 | $ hg status -du | |
770 | ! foo/a |
|
777 | ! foo/a | |
771 | ? bar/a |
|
778 | ? bar/a | |
772 | ? foo |
|
779 | ? foo | |
773 |
|
780 | |||
774 | #endif |
|
781 | #endif | |
775 |
|
782 | |||
776 |
|
783 | |||
777 | Create a repo with files in each possible status |
|
784 | Create a repo with files in each possible status | |
778 |
|
785 | |||
779 | $ cd .. |
|
786 | $ cd .. | |
780 | $ hg init repo7 |
|
787 | $ hg init repo7 | |
781 | $ cd repo7 |
|
788 | $ cd repo7 | |
782 | $ mkdir subdir |
|
789 | $ mkdir subdir | |
783 | $ touch clean modified deleted removed |
|
790 | $ touch clean modified deleted removed | |
784 | $ touch subdir/clean subdir/modified subdir/deleted subdir/removed |
|
791 | $ touch subdir/clean subdir/modified subdir/deleted subdir/removed | |
785 | $ echo ignored > .hgignore |
|
792 | $ echo ignored > .hgignore | |
786 | $ hg ci -Aqm '#0' |
|
793 | $ hg ci -Aqm '#0' | |
787 | $ echo 1 > modified |
|
794 | $ echo 1 > modified | |
788 | $ echo 1 > subdir/modified |
|
795 | $ echo 1 > subdir/modified | |
789 | $ rm deleted |
|
796 | $ rm deleted | |
790 | $ rm subdir/deleted |
|
797 | $ rm subdir/deleted | |
791 | $ hg rm removed |
|
798 | $ hg rm removed | |
792 | $ hg rm subdir/removed |
|
799 | $ hg rm subdir/removed | |
793 | $ touch unknown ignored |
|
800 | $ touch unknown ignored | |
794 | $ touch subdir/unknown subdir/ignored |
|
801 | $ touch subdir/unknown subdir/ignored | |
795 |
|
802 | |||
796 | Check the output |
|
803 | Check the output | |
797 |
|
804 | |||
798 | $ hg status |
|
805 | $ hg status | |
799 | M modified |
|
806 | M modified | |
800 | M subdir/modified |
|
807 | M subdir/modified | |
801 | R removed |
|
808 | R removed | |
802 | R subdir/removed |
|
809 | R subdir/removed | |
803 | ! deleted |
|
810 | ! deleted | |
804 | ! subdir/deleted |
|
811 | ! subdir/deleted | |
805 | ? subdir/unknown |
|
812 | ? subdir/unknown | |
806 | ? unknown |
|
813 | ? unknown | |
807 |
|
814 | |||
808 | $ hg status -mard |
|
815 | $ hg status -mard | |
809 | M modified |
|
816 | M modified | |
810 | M subdir/modified |
|
817 | M subdir/modified | |
811 | R removed |
|
818 | R removed | |
812 | R subdir/removed |
|
819 | R subdir/removed | |
813 | ! deleted |
|
820 | ! deleted | |
814 | ! subdir/deleted |
|
821 | ! subdir/deleted | |
815 |
|
822 | |||
816 | $ hg status -A |
|
823 | $ hg status -A | |
817 | M modified |
|
824 | M modified | |
818 | M subdir/modified |
|
825 | M subdir/modified | |
819 | R removed |
|
826 | R removed | |
820 | R subdir/removed |
|
827 | R subdir/removed | |
821 | ! deleted |
|
828 | ! deleted | |
822 | ! subdir/deleted |
|
829 | ! subdir/deleted | |
823 | ? subdir/unknown |
|
830 | ? subdir/unknown | |
824 | ? unknown |
|
831 | ? unknown | |
825 | I ignored |
|
832 | I ignored | |
826 | I subdir/ignored |
|
833 | I subdir/ignored | |
827 | C .hgignore |
|
834 | C .hgignore | |
828 | C clean |
|
835 | C clean | |
829 | C subdir/clean |
|
836 | C subdir/clean | |
830 |
|
837 | |||
831 | Note: `hg status some-name` creates a patternmatcher which is not supported |
|
838 | Note: `hg status some-name` creates a patternmatcher which is not supported | |
832 | yet by the Rust implementation of status, but includematcher is supported. |
|
839 | yet by the Rust implementation of status, but includematcher is supported. | |
833 | --include is used below for that reason |
|
840 | --include is used below for that reason | |
834 |
|
841 | |||
835 | #if unix-permissions |
|
842 | #if unix-permissions | |
836 |
|
843 | |||
837 | Not having permission to read a directory that contains tracked files makes |
|
844 | Not having permission to read a directory that contains tracked files makes | |
838 | status emit a warning then behave as if the directory was empty or removed |
|
845 | status emit a warning then behave as if the directory was empty or removed | |
839 | entirely: |
|
846 | entirely: | |
840 |
|
847 | |||
841 | $ chmod 0 subdir |
|
848 | $ chmod 0 subdir | |
842 | $ hg status --include subdir |
|
849 | $ hg status --include subdir | |
843 | subdir: Permission denied |
|
850 | subdir: Permission denied | |
844 | R subdir/removed |
|
851 | R subdir/removed | |
845 | ! subdir/clean |
|
852 | ! subdir/clean | |
846 | ! subdir/deleted |
|
853 | ! subdir/deleted | |
847 | ! subdir/modified |
|
854 | ! subdir/modified | |
848 | $ chmod 755 subdir |
|
855 | $ chmod 755 subdir | |
849 |
|
856 | |||
850 | #endif |
|
857 | #endif | |
851 |
|
858 | |||
852 | Remove a directory that contains tracked files |
|
859 | Remove a directory that contains tracked files | |
853 |
|
860 | |||
854 | $ rm -r subdir |
|
861 | $ rm -r subdir | |
855 | $ hg status --include subdir |
|
862 | $ hg status --include subdir | |
856 | R subdir/removed |
|
863 | R subdir/removed | |
857 | ! subdir/clean |
|
864 | ! subdir/clean | |
858 | ! subdir/deleted |
|
865 | ! subdir/deleted | |
859 | ! subdir/modified |
|
866 | ! subdir/modified | |
860 |
|
867 | |||
861 | … and replace it by a file |
|
868 | … and replace it by a file | |
862 |
|
869 | |||
863 | $ touch subdir |
|
870 | $ touch subdir | |
864 | $ hg status --include subdir |
|
871 | $ hg status --include subdir | |
865 | R subdir/removed |
|
872 | R subdir/removed | |
866 | ! subdir/clean |
|
873 | ! subdir/clean | |
867 | ! subdir/deleted |
|
874 | ! subdir/deleted | |
868 | ! subdir/modified |
|
875 | ! subdir/modified | |
869 | ? subdir |
|
876 | ? subdir | |
870 |
|
877 | |||
871 | Replaced a deleted or removed file with a directory |
|
878 | Replaced a deleted or removed file with a directory | |
872 |
|
879 | |||
873 | $ mkdir deleted removed |
|
880 | $ mkdir deleted removed | |
874 | $ touch deleted/1 removed/1 |
|
881 | $ touch deleted/1 removed/1 | |
875 | $ hg status --include deleted --include removed |
|
882 | $ hg status --include deleted --include removed | |
876 | R removed |
|
883 | R removed | |
877 | ! deleted |
|
884 | ! deleted | |
878 | ? deleted/1 |
|
885 | ? deleted/1 | |
879 | ? removed/1 |
|
886 | ? removed/1 | |
880 | $ hg add removed/1 |
|
887 | $ hg add removed/1 | |
881 | $ hg status --include deleted --include removed |
|
888 | $ hg status --include deleted --include removed | |
882 | A removed/1 |
|
889 | A removed/1 | |
883 | R removed |
|
890 | R removed | |
884 | ! deleted |
|
891 | ! deleted | |
885 | ? deleted/1 |
|
892 | ? deleted/1 | |
886 |
|
893 | |||
887 | Deeply nested files in an ignored directory are still listed on request |
|
894 | Deeply nested files in an ignored directory are still listed on request | |
888 |
|
895 | |||
889 | $ echo ignored-dir >> .hgignore |
|
896 | $ echo ignored-dir >> .hgignore | |
890 | $ mkdir ignored-dir |
|
897 | $ mkdir ignored-dir | |
891 | $ mkdir ignored-dir/subdir |
|
898 | $ mkdir ignored-dir/subdir | |
892 | $ touch ignored-dir/subdir/1 |
|
899 | $ touch ignored-dir/subdir/1 | |
893 | $ hg status --ignored |
|
900 | $ hg status --ignored | |
894 | I ignored |
|
901 | I ignored | |
895 | I ignored-dir/subdir/1 |
|
902 | I ignored-dir/subdir/1 | |
896 |
|
903 | |||
897 | Check using include flag while listing ignored composes correctly (issue6514) |
|
904 | Check using include flag while listing ignored composes correctly (issue6514) | |
898 |
|
905 | |||
899 | $ cd .. |
|
906 | $ cd .. | |
900 | $ hg init issue6514 |
|
907 | $ hg init issue6514 | |
901 | $ cd issue6514 |
|
908 | $ cd issue6514 | |
902 | $ mkdir ignored-folder |
|
909 | $ mkdir ignored-folder | |
903 | $ touch A.hs B.hs C.hs ignored-folder/other.txt ignored-folder/ctest.hs |
|
910 | $ touch A.hs B.hs C.hs ignored-folder/other.txt ignored-folder/ctest.hs | |
904 | $ cat >.hgignore <<EOF |
|
911 | $ cat >.hgignore <<EOF | |
905 | > A.hs |
|
912 | > A.hs | |
906 | > B.hs |
|
913 | > B.hs | |
907 | > ignored-folder/ |
|
914 | > ignored-folder/ | |
908 | > EOF |
|
915 | > EOF | |
909 | $ hg st -i -I 're:.*\.hs$' |
|
916 | $ hg st -i -I 're:.*\.hs$' | |
910 | I A.hs |
|
917 | I A.hs | |
911 | I B.hs |
|
918 | I B.hs | |
912 | I ignored-folder/ctest.hs |
|
919 | I ignored-folder/ctest.hs | |
913 |
|
920 | |||
914 | #if rust dirstate-v2 |
|
921 | #if rust dirstate-v2 | |
915 |
|
922 | |||
916 | Check read_dir caching |
|
923 | Check read_dir caching | |
917 |
|
924 | |||
918 | $ cd .. |
|
925 | $ cd .. | |
919 | $ hg init repo8 |
|
926 | $ hg init repo8 | |
920 | $ cd repo8 |
|
927 | $ cd repo8 | |
921 | $ mkdir subdir |
|
928 | $ mkdir subdir | |
922 | $ touch subdir/a subdir/b |
|
929 | $ touch subdir/a subdir/b | |
923 | $ hg ci -Aqm '#0' |
|
930 | $ hg ci -Aqm '#0' | |
924 |
|
931 | |||
925 | The cached mtime is initially unset |
|
932 | The cached mtime is initially unset | |
926 |
|
933 | |||
927 | $ hg debugdirstate --all --no-dates | grep '^ ' |
|
934 | $ hg debugdirstate --all --no-dates | grep '^ ' | |
928 | 0 -1 unset subdir |
|
935 | 0 -1 unset subdir | |
929 |
|
936 | |||
930 | It is still not set when there are unknown files |
|
937 | It is still not set when there are unknown files | |
931 |
|
938 | |||
932 | $ touch subdir/unknown |
|
939 | $ touch subdir/unknown | |
933 | $ hg status |
|
940 | $ hg status | |
934 | ? subdir/unknown |
|
941 | ? subdir/unknown | |
935 | $ hg debugdirstate --all --no-dates | grep '^ ' |
|
942 | $ hg debugdirstate --all --no-dates | grep '^ ' | |
936 | 0 -1 unset subdir |
|
943 | 0 -1 unset subdir | |
937 |
|
944 | |||
938 | Now the directory is eligible for caching, so its mtime is save in the dirstate |
|
945 | Now the directory is eligible for caching, so its mtime is save in the dirstate | |
939 |
|
946 | |||
940 | $ rm subdir/unknown |
|
947 | $ rm subdir/unknown | |
941 | $ hg status |
|
948 | $ hg status | |
942 | $ hg debugdirstate --all --no-dates | grep '^ ' |
|
949 | $ hg debugdirstate --all --no-dates | grep '^ ' | |
943 | 0 -1 set subdir |
|
950 | 0 -1 set subdir | |
944 |
|
951 | |||
945 | This time the command should be ever so slightly faster since it does not need `read_dir("subdir")` |
|
952 | This time the command should be ever so slightly faster since it does not need `read_dir("subdir")` | |
946 |
|
953 | |||
947 | $ hg status |
|
954 | $ hg status | |
948 |
|
955 | |||
949 | Creating a new file changes the directory’s mtime, invalidating the cache |
|
956 | Creating a new file changes the directory’s mtime, invalidating the cache | |
950 |
|
957 | |||
951 | $ touch subdir/unknown |
|
958 | $ touch subdir/unknown | |
952 | $ hg status |
|
959 | $ hg status | |
953 | ? subdir/unknown |
|
960 | ? subdir/unknown | |
954 |
|
961 | |||
955 | $ rm subdir/unknown |
|
962 | $ rm subdir/unknown | |
956 | $ hg status |
|
963 | $ hg status | |
957 |
|
964 | |||
958 | Removing a node from the dirstate resets the cache for its parent directory |
|
965 | Removing a node from the dirstate resets the cache for its parent directory | |
959 |
|
966 | |||
960 | $ hg forget subdir/a |
|
967 | $ hg forget subdir/a | |
961 | $ hg debugdirstate --all --no-dates | grep '^ ' |
|
968 | $ hg debugdirstate --all --no-dates | grep '^ ' | |
962 | 0 -1 set subdir |
|
969 | 0 -1 set subdir | |
963 | $ hg ci -qm '#1' |
|
970 | $ hg ci -qm '#1' | |
964 | $ hg debugdirstate --all --no-dates | grep '^ ' |
|
971 | $ hg debugdirstate --all --no-dates | grep '^ ' | |
965 | 0 -1 unset subdir |
|
972 | 0 -1 unset subdir | |
966 | $ hg status |
|
973 | $ hg status | |
967 | ? subdir/a |
|
974 | ? subdir/a | |
968 |
|
975 | |||
969 | #endif |
|
976 | #endif |
General Comments 0
You need to be logged in to leave comments.
Login now