diff --git a/git-repository/src/lib.rs b/git-repository/src/lib.rs index 46fd9fcd5ef..07da578a390 100644 --- a/git-repository/src/lib.rs +++ b/git-repository/src/lib.rs @@ -321,31 +321,25 @@ pub mod state { #[derive(Debug, PartialEq)] pub enum InProgress { /// A mailbox is being applied. - // TODO: test ApplyMailbox, /// A rebase is happening while a mailbox is being applied. // TODO: test ApplyMailboxRebase, /// A git bisect operation has not yet been concluded. - // TODO: test Bisect, /// A cherry pick operation. CherryPick, /// A cherry pick with multiple commits pending. - // TODO: test CherryPickSequence, /// A merge operation. - // TODO: test Merge, /// A rebase operation. - // TODO: test Rebase, /// An interactive rebase operation. RebaseInteractive, /// A revert operation. Revert, /// A revert operation with multiple commits pending. - // TODO: test RevertSequence, } } diff --git a/git-repository/src/repository/reference.rs b/git-repository/src/repository/reference.rs index a8d39f57069..e0a3e8ded80 100644 --- a/git-repository/src/repository/reference.rs +++ b/git-repository/src/repository/reference.rs @@ -200,6 +200,11 @@ impl crate::Repository { .map_err(Into::into) } + /// Return the name to the symbolic reference `HEAD` points to, or `None` if the head is detached. + pub fn head_name(&self) -> Result, crate::reference::find::existing::Error> { + Ok(self.head()?.referent_name().map(|n| n.to_owned())) + } + /// Return the commit object the `HEAD` reference currently points to after peeling it fully. /// /// Note that this may fail for various reasons, most notably because the repository diff --git a/git-repository/src/repository/state.rs b/git-repository/src/repository/state.rs index 022f150f4da..6396ab7ddd2 100644 --- a/git-repository/src/repository/state.rs +++ b/git-repository/src/repository/state.rs @@ -3,7 +3,9 @@ use crate::state; impl crate::Repository { /// Returns the status of an in progress operation on a repository or [`None`] /// if no operation is currently in progress. - pub fn in_progress_operation(&self) -> Option { + /// + /// Note to be confused with the repositories 'status'. + pub fn state(&self) -> Option { let git_dir = self.path(); // This is modeled on the logic from wt_status_get_state in git's wt-status.c and @@ -20,7 +22,7 @@ impl crate::Repository { } else if git_dir.join("rebase-merge").is_dir() { Some(state::InProgress::Rebase) } else if git_dir.join("CHERRY_PICK_HEAD").is_file() { - if git_dir.join("todo").is_file() { + if git_dir.join("sequencer/todo").is_file() { Some(state::InProgress::CherryPickSequence) } else { Some(state::InProgress::CherryPick) @@ -30,7 +32,7 @@ impl crate::Repository { } else if git_dir.join("BISECT_LOG").is_file() { Some(state::InProgress::Bisect) } else if git_dir.join("REVERT_HEAD").is_file() { - if git_dir.join("todo").is_file() { + if git_dir.join("sequencer/todo").is_file() { Some(state::InProgress::RevertSequence) } else { Some(state::InProgress::Revert) diff --git a/git-repository/tests/fixtures/generated-archives/make_am_repo.tar.xz b/git-repository/tests/fixtures/generated-archives/make_am_repo.tar.xz new file mode 100644 index 00000000000..50b21019ad6 --- /dev/null +++ b/git-repository/tests/fixtures/generated-archives/make_am_repo.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:357c85ba0f2c4e8703e643ebbebc49229d0560eb0e6ed1ffa08969d4750f5bc5 +size 11356 diff --git a/git-repository/tests/fixtures/generated-archives/make_bisect_repo.tar.xz b/git-repository/tests/fixtures/generated-archives/make_bisect_repo.tar.xz new file mode 100644 index 00000000000..a14e80a149a --- /dev/null +++ b/git-repository/tests/fixtures/generated-archives/make_bisect_repo.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e38aff8e6054660ffa274ff00ad8398601949576d887e0cc462256f16e966bb +size 10200 diff --git a/git-repository/tests/fixtures/generated-archives/make_cherry_pick_sequence_repo.tar.xz b/git-repository/tests/fixtures/generated-archives/make_cherry_pick_sequence_repo.tar.xz new file mode 100644 index 00000000000..b4a909d82d5 --- /dev/null +++ b/git-repository/tests/fixtures/generated-archives/make_cherry_pick_sequence_repo.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c3187949760fe07a5abc1a5b7f303ba060bedaed1bfad29535b93df72ca453c +size 11336 diff --git a/git-repository/tests/fixtures/generated-archives/make_merge_repo.tar.xz b/git-repository/tests/fixtures/generated-archives/make_merge_repo.tar.xz new file mode 100644 index 00000000000..ce47ab1c542 --- /dev/null +++ b/git-repository/tests/fixtures/generated-archives/make_merge_repo.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a61b3a205b9254579ea67390a9b3da43ab9d26b6576555da566ba69ea07aaa3b +size 10948 diff --git a/git-repository/tests/fixtures/generated-archives/make_revert_repo.tar.xz b/git-repository/tests/fixtures/generated-archives/make_revert_repo.tar.xz index 98ce3c49d78..568889d51fc 100644 --- a/git-repository/tests/fixtures/generated-archives/make_revert_repo.tar.xz +++ b/git-repository/tests/fixtures/generated-archives/make_revert_repo.tar.xz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b76a63be1b90ff164633c074caf3ce3ccfd73ed6f587a7a02e7c039af065519 +oid sha256:b44df1ace634ca3f4e4c05911d4bf949777b6037ba3fbb25f4a139d5048d33d0 size 10440 diff --git a/git-repository/tests/fixtures/generated-archives/make_revert_sequence_repo.tar.xz b/git-repository/tests/fixtures/generated-archives/make_revert_sequence_repo.tar.xz new file mode 100644 index 00000000000..96f8aecb54c --- /dev/null +++ b/git-repository/tests/fixtures/generated-archives/make_revert_sequence_repo.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60a892477189310fa935d43dbaa73d92b3079cbf86023e83262db6000b7556c0 +size 11224 diff --git a/git-repository/tests/fixtures/make_am_repo.sh b/git-repository/tests/fixtures/make_am_repo.sh new file mode 100644 index 00000000000..881b79691d7 --- /dev/null +++ b/git-repository/tests/fixtures/make_am_repo.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -eu -o pipefail + +git init -q + +echo file.main > file +git add file +git commit -m file.main file + +git checkout -b other-branch +echo file.other-branch > file +git commit -m file.other-branch file +# Create an mbox formatted patch and save the path +patch_path=$(git format-patch main) + +git checkout main +# Create a conflict +echo file.main.update > file +git commit -m file.main.update file + +# This will fail due to the merge conflict and leave us in a 'apply mbox in progress' state +git am 0001-file.other-branch.patch || true diff --git a/git-repository/tests/fixtures/make_bisect_repo.sh b/git-repository/tests/fixtures/make_bisect_repo.sh new file mode 100644 index 00000000000..ce67e12aac4 --- /dev/null +++ b/git-repository/tests/fixtures/make_bisect_repo.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eu -o pipefail + +git init -q + +touch f1 f2 + +git add f1 +git commit -m f1 f1 + +git add f2 +git commit -m f2 f2 + +git bisect start diff --git a/git-repository/tests/fixtures/make_cherry_pick_sequence_repo.sh b/git-repository/tests/fixtures/make_cherry_pick_sequence_repo.sh new file mode 100644 index 00000000000..d7295a3cd73 --- /dev/null +++ b/git-repository/tests/fixtures/make_cherry_pick_sequence_repo.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -eu -o pipefail + +git init -q + +touch f1 f2 f3 + +git add f1 +git commit -m f1 f1 + +git checkout -b other-branch +echo f2.other-branch > f2 +git add f2 +git commit -m f2.other-branch f2 +git add f3 +git commit -m f3 f3 + +git checkout main +echo f2.main > f2 +git add f2 +git commit -m f2.main f2 + +# This should fail and leave us in a cherry-pick + sequencer state +git cherry-pick other-branch~2..other-branch || true diff --git a/git-repository/tests/fixtures/make_merge_repo.sh b/git-repository/tests/fixtures/make_merge_repo.sh new file mode 100644 index 00000000000..837a513301c --- /dev/null +++ b/git-repository/tests/fixtures/make_merge_repo.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -eu -o pipefail + +git init -q + +echo file.main > file +git add file +git commit -m file.main file + +git checkout -b other-branch +echo file.other-branch > file +git add file +git commit -m file.other-branch file + +git checkout main +echo file.main changed > file +git commit -m file.main\ changed file + +git merge other-branch || true diff --git a/git-repository/tests/fixtures/make_revert_repo.sh b/git-repository/tests/fixtures/make_revert_repo.sh index 24c42f1bc8b..9e4daf3e2cd 100644 --- a/git-repository/tests/fixtures/make_revert_repo.sh +++ b/git-repository/tests/fixtures/make_revert_repo.sh @@ -3,11 +3,11 @@ set -eu -o pipefail git init -q -touch 1 2 3 -git add 1 -git commit -m 1 1 -git add 2 -git commit -m 2 2 -git add 3 -git commit -m 3 3 +touch f1 f2 f3 +git add f1 +git commit -m f1 f1 +git add f2 +git commit -m f2 f2 +git add f3 +git commit -m f3 f3 git revert --no-commit HEAD~1 diff --git a/git-repository/tests/fixtures/make_revert_sequence_repo.sh b/git-repository/tests/fixtures/make_revert_sequence_repo.sh new file mode 100644 index 00000000000..37f182deac7 --- /dev/null +++ b/git-repository/tests/fixtures/make_revert_sequence_repo.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -eu -o pipefail + +git init -q + +echo 1.0 > 1 +git add 1 +git commit -m 1.0 1 + +echo 1.1 > 1 +git commit -m 1.1 1 + +echo 1.2 > 1 +git commit -m 1.2 1 +touch 2 +git add 2 +git commit -m 2 2 + +# This should fail and leave us in a revert + sequencer state +git revert --no-commit HEAD HEAD~2 || true diff --git a/git-repository/tests/repository/state.rs b/git-repository/tests/repository/state.rs index 0f85ba8767d..be1127a8245 100644 --- a/git-repository/tests/repository/state.rs +++ b/git-repository/tests/repository/state.rs @@ -1,15 +1,51 @@ use crate::{named_repo, Result}; use git_repository as git; +#[test] +fn apply_mailbox() -> Result { + let repo = named_repo("make_am_repo.sh")?; + + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::ApplyMailbox)); + Ok(()) +} + +#[test] +fn bisect() -> Result { + let repo = named_repo("make_bisect_repo.sh")?; + + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::Bisect)); + + Ok(()) +} + #[test] fn cherry_pick() -> Result { let repo = named_repo("make_cherry_pick_repo.sh")?; - let head = repo.head()?; - let head_name = head.referent_name().expect("no detached head").shorten(); - assert_eq!(head_name, "main"); + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::CherryPick)); + Ok(()) +} + +#[test] +fn cherry_pick_sequence() -> Result { + let repo = named_repo("make_cherry_pick_sequence_repo.sh")?; + + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::CherryPickSequence)); + + Ok(()) +} + +#[test] +fn merge() -> Result { + let repo = named_repo("make_merge_repo.sh")?; + + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::Merge)); - assert_eq!(repo.in_progress_operation(), Some(git::state::InProgress::CherryPick)); Ok(()) } @@ -17,12 +53,8 @@ fn cherry_pick() -> Result { fn rebase_interactive() -> Result { let repo = named_repo("make_rebase_i_repo.sh")?; - let head = repo.head()?; - assert!(head.is_detached()); - assert_eq!( - repo.in_progress_operation(), - Some(git::state::InProgress::RebaseInteractive) - ); + assert!(repo.head()?.is_detached()); + assert_eq!(repo.state(), Some(git::state::InProgress::RebaseInteractive)); Ok(()) } @@ -31,11 +63,18 @@ fn rebase_interactive() -> Result { fn revert() -> Result { let repo = named_repo("make_revert_repo.sh")?; - let head = repo.head()?; - let head_name = head.referent_name().expect("no detached head").shorten(); - assert_eq!(head_name, "main"); + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::Revert)); + + Ok(()) +} + +#[test] +fn revert_sequence() -> Result { + let repo = named_repo("make_revert_sequence_repo.sh")?; - assert_eq!(repo.in_progress_operation(), Some(git::state::InProgress::Revert)); + assert_eq!(repo.head_name()?.unwrap().shorten(), "main"); + assert_eq!(repo.state(), Some(git::state::InProgress::RevertSequence)); Ok(()) }