forked from mirrors/jj
working copy: allow overwriting untracked files
Before this commit, we would crash when checking out a commit that has a file that's currently ignored in the working copy.
This commit is contained in:
parent
df175f549f
commit
cbc3e915b7
2 changed files with 53 additions and 4 deletions
|
@ -420,12 +420,14 @@ impl TreeState {
|
||||||
executable: bool,
|
executable: bool,
|
||||||
) -> FileState {
|
) -> FileState {
|
||||||
create_parent_dirs(disk_path);
|
create_parent_dirs(disk_path);
|
||||||
|
// TODO: Check that we're not overwriting an un-ignored file here (which might
|
||||||
|
// be created by a concurrent process).
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create_new(true)
|
.create(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.open(disk_path)
|
.open(disk_path)
|
||||||
.unwrap_or_else(|_| panic!("failed to open {:?} for write", &disk_path));
|
.unwrap_or_else(|err| panic!("failed to open {:?} for write: {:?}", &disk_path, err));
|
||||||
let mut contents = self.store.read_file(path, id).unwrap();
|
let mut contents = self.store.read_file(path, id).unwrap();
|
||||||
std::io::copy(&mut contents, &mut file).unwrap();
|
std::io::copy(&mut contents, &mut file).unwrap();
|
||||||
self.set_executable(disk_path, executable);
|
self.set_executable(disk_path, executable);
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -339,3 +339,50 @@ fn test_gitignores(use_git: bool) {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(false ; "local store")]
|
||||||
|
#[test_case(true ; "git store")]
|
||||||
|
fn test_gitignores_checkout_overwrites_ignored(use_git: bool) {
|
||||||
|
// Tests that a .gitignore'd file gets overwritten if check out a commit where
|
||||||
|
// the file is tracked.
|
||||||
|
|
||||||
|
let _home_dir = testutils::new_user_home();
|
||||||
|
let settings = testutils::user_settings();
|
||||||
|
let (_temp_dir, repo) = testutils::init_repo(&settings, use_git);
|
||||||
|
|
||||||
|
// Write an ignored file called "modified" to disk
|
||||||
|
let gitignore_path = FileRepoPath::from(".gitignore");
|
||||||
|
testutils::write_working_copy_file(&repo, &gitignore_path, "modified\n");
|
||||||
|
let modified_path = FileRepoPath::from("modified");
|
||||||
|
testutils::write_working_copy_file(&repo, &modified_path, "garbage");
|
||||||
|
|
||||||
|
// Create a commit that adds the same file but with different contents
|
||||||
|
let mut tx = repo.start_transaction("test");
|
||||||
|
let mut tree_builder = repo
|
||||||
|
.store()
|
||||||
|
.tree_builder(repo.store().empty_tree_id().clone());
|
||||||
|
testutils::write_normal_file(&mut tree_builder, &modified_path, "contents");
|
||||||
|
let tree_id = tree_builder.write_tree();
|
||||||
|
let commit = CommitBuilder::for_new_commit(&settings, repo.store(), tree_id)
|
||||||
|
.set_open(true)
|
||||||
|
.set_description("add file".to_string())
|
||||||
|
.write_to_repo(tx.mut_repo());
|
||||||
|
let repo = tx.commit();
|
||||||
|
|
||||||
|
// Now check out the commit that adds the file "modified" with contents
|
||||||
|
// "contents". The exiting contents ("garbage") should be replaced in the
|
||||||
|
// working copy.
|
||||||
|
repo.working_copy_locked().check_out(commit).unwrap();
|
||||||
|
|
||||||
|
// Check that the new contents are in the working copy
|
||||||
|
let path = repo.working_copy_path().join("modified");
|
||||||
|
assert!(path.is_file());
|
||||||
|
let mut file = File::open(path).unwrap();
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
file.read_to_end(&mut buf).unwrap();
|
||||||
|
assert_eq!(buf, b"contents");
|
||||||
|
|
||||||
|
// Check that the file is in the commit created by committing the working copy
|
||||||
|
let (_repo, new_commit) = repo.working_copy_locked().commit(&settings, repo.clone());
|
||||||
|
assert!(new_commit.tree().entry("modified").is_some());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue