Skip to content

Commit 3899e17

Browse files
committed
cli undo: warn about undoing push operations
Undoing a push operation does not undo the effects on the remote. Bookmarks on the remote will stay in place, but the local repository will forget about their state. If the bookmarks are subsequently moved and pushed, that later push will fail, since the bookmarks have "unexpectedly" moved on the remote. Therefore, add a warning telling users to run `jj redo` to avoid these complications.
1 parent 4140f94 commit 3899e17

File tree

4 files changed

+47
-4
lines changed

4 files changed

+47
-4
lines changed

cli/src/commands/git/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use self::init::GitInitArgs;
4949
use self::init::cmd_git_init;
5050
use self::push::GitPushArgs;
5151
use self::push::cmd_git_push;
52+
pub use self::push::is_push_operation;
5253
use self::remote::RemoteCommand;
5354
use self::remote::cmd_git_remote;
5455
use self::root::GitRootArgs;

cli/src/commands/git/push.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use jj_lib::git::GitBranchPushTargets;
3333
use jj_lib::git::GitPushStats;
3434
use jj_lib::index::IndexResult;
3535
use jj_lib::op_store::RefTarget;
36+
use jj_lib::operation::Operation;
3637
use jj_lib::ref_name::RefName;
3738
use jj_lib::ref_name::RefNameBuf;
3839
use jj_lib::ref_name::RemoteName;
@@ -205,6 +206,8 @@ fn make_bookmark_term(bookmark_names: &[impl fmt::Display]) -> String {
205206

206207
const DEFAULT_REMOTE: &RemoteName = RemoteName::new("origin");
207208

209+
const TX_DESC_PUSH: &str = "push ";
210+
208211
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
209212
enum BookmarkMoveDirection {
210213
Forward,
@@ -246,7 +249,7 @@ pub fn cmd_git_push(
246249
}
247250
}
248251
tx_description = format!(
249-
"push all bookmarks to git remote {remote}",
252+
"{TX_DESC_PUSH}all bookmarks to git remote {remote}",
250253
remote = remote.as_symbol()
251254
);
252255
} else if args.tracked {
@@ -267,7 +270,7 @@ pub fn cmd_git_push(
267270
}
268271
}
269272
tx_description = format!(
270-
"push all tracked bookmarks to git remote {remote}",
273+
"{TX_DESC_PUSH}all tracked bookmarks to git remote {remote}",
271274
remote = remote.as_symbol()
272275
);
273276
} else if args.deleted {
@@ -289,7 +292,7 @@ pub fn cmd_git_push(
289292
}
290293
}
291294
tx_description = format!(
292-
"push all deleted bookmarks to git remote {remote}",
295+
"{TX_DESC_PUSH}all deleted bookmarks to git remote {remote}",
293296
remote = remote.as_symbol()
294297
);
295298
} else {
@@ -381,7 +384,7 @@ pub fn cmd_git_push(
381384
}
382385

383386
tx_description = format!(
384-
"push {names} to git remote {remote}",
387+
"{TX_DESC_PUSH}{names} to git remote {remote}",
385388
names = make_bookmark_term(
386389
&bookmark_updates
387390
.iter()
@@ -1022,3 +1025,7 @@ fn find_bookmarks_targeted_by_revisions<'a>(
10221025
.collect_vec();
10231026
Ok(bookmarks_targeted)
10241027
}
1028+
1029+
pub fn is_push_operation(op: &Operation) -> bool {
1030+
op.metadata().description.starts_with(TX_DESC_PUSH)
1031+
}

cli/src/commands/undo.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use crate::command_error::CommandError;
2222
use crate::command_error::internal_error;
2323
use crate::command_error::user_error;
2424
use crate::command_error::user_error_with_hint;
25+
#[cfg(feature = "git")]
26+
use crate::commands::git::is_push_operation;
2527
use crate::commands::operation::DEFAULT_REVERT_WHAT;
2628
use crate::commands::operation::RevertWhatToRestore;
2729
use crate::commands::operation::revert::OperationRevertArgs;
@@ -148,6 +150,14 @@ pub fn cmd_undo(ui: &mut Ui, command: &CommandHelper, args: &UndoArgs) -> Result
148150
.loader()
149151
.load_operation(&id_of_restored_op)?;
150152
}
153+
#[cfg(feature = "git")]
154+
if is_push_operation(&op_to_undo) {
155+
writeln!(
156+
ui.warning_default(),
157+
"Undoing a push operation often leads to conflicted bookmarks."
158+
)?;
159+
writeln!(ui.hint_default(), "To avoid this, run `jj redo` now.")?;
160+
};
151161

152162
let mut op_to_restore = match op_to_undo.parents().at_most_one() {
153163
Ok(Some(parent_of_op_to_undo)) => parent_of_op_to_undo?,

cli/tests/test_undo_redo_commands.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,31 @@ fn test_undo_merge_operation() {
5555
");
5656
}
5757

58+
#[test]
59+
fn test_undo_push_operation() {
60+
let test_env = TestEnvironment::default();
61+
62+
test_env
63+
.run_jj_in(".", ["git", "init", "--colocate", "origin"])
64+
.success();
65+
test_env
66+
.run_jj_in(".", ["git", "clone", "origin", "repo"])
67+
.success();
68+
let work_dir = test_env.work_dir("repo");
69+
70+
work_dir.write_file("foo", "foo");
71+
work_dir.run_jj(["commit", "-mfoo"]).success();
72+
work_dir.run_jj(["git", "push", "-c@-"]).success();
73+
let output = work_dir.run_jj(["undo"]);
74+
insta::assert_snapshot!(output, @r"
75+
------- stderr -------
76+
Warning: Undoing a push operation often leads to conflicted bookmarks.
77+
Hint: To avoid this, run `jj redo` now.
78+
Restored to operation: f9fd582ef03c (2001-02-03 08:05:09) commit 3850397cf31988d0657948307ad5bbe873d76a38
79+
[EOF]
80+
");
81+
}
82+
5883
#[test]
5984
fn test_undo_jump_old_undo_stack() {
6085
let test_env = TestEnvironment::default();

0 commit comments

Comments
 (0)