Skip to content

Commit badee6d

Browse files
committed
hopefully fix symlink creation on windows (#301)
The windows file check needs to handle relative links properly when checking for file type.
1 parent 2e04b71 commit badee6d

File tree

5 files changed

+42
-4
lines changed

5 files changed

+42
-4
lines changed

git-worktree/src/fs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ impl Capabilities {
9090
.write(true)
9191
.open(&src_path)?;
9292
let link_path = root.join("__file_link");
93-
if symlink::symlink_file(&src_path, &link_path).is_err() {
93+
if crate::os::create_symlink(&src_path, &link_path).is_err() {
9494
std::fs::remove_file(&src_path)?;
9595
return Ok(false);
9696
}
9797

9898
let res = std::fs::symlink_metadata(&link_path).map(|m| m.is_symlink());
9999
let cleanup = std::fs::remove_file(&src_path);
100-
symlink::remove_symlink_file(&link_path)
100+
crate::os::remove_symlink(&link_path)
101101
.or_else(|_| std::fs::remove_file(&link_path))
102102
.and(cleanup)?;
103103
res

git-worktree/src/index/checkout.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ pub struct Options {
2121
/// This should be enabled when cloning to avoid checks for freshness of files. This also enables
2222
/// detection of collisions based on whether or not exclusive file creation succeeds or fails.
2323
pub destination_is_initially_empty: bool,
24+
/// If true, default false, worktree entries on disk will be overwritten with content from the index
25+
/// even if they appear to be changed. When creating directories that clash with existing worktree entries,
26+
/// these will try to delete the existing entry.
27+
/// This is similar in behaviour as `git checkout --force`.
28+
pub overwrite_existing: bool,
2429
/// If true, default false, try to checkout as much as possible and don't abort on first error which isn't
2530
/// due to a conflict.
2631
/// The operation will never fail, but count the encountered errors instead along with their paths.
@@ -46,6 +51,7 @@ impl Default for Options {
4651
keep_going: false,
4752
trust_ctime: true,
4853
check_stat: true,
54+
overwrite_existing: false,
4955
}
5056
}
5157
}

git-worktree/src/index/entry.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ where
3636
path: entry_path.to_owned(),
3737
}
3838
})?);
39-
create_dir_all(dest.parent().expect("entry paths are never empty"))?; // TODO: can this be avoided to create dirs when needed only?
39+
40+
let dest_dir = dest.parent().expect("entry paths are never empty");
41+
create_dir_all(dest_dir)?; // TODO: can this be avoided to create dirs when needed only?
4042

4143
match entry.mode {
4244
git_index::entry::Mode::FILE | git_index::entry::Mode::FILE_EXECUTABLE => {
@@ -72,7 +74,7 @@ where
7274
// TODO: how to deal with mode changes? Maybe this info can be passed once we check for whether
7375
// a checkout is needed at all.
7476
if symlink {
75-
symlink::symlink_auto(symlink_destination, &dest)?;
77+
crate::os::create_symlink(symlink_destination, &dest)?;
7678
} else {
7779
std::fs::write(&dest, obj.data)?;
7880
}

git-worktree/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010
pub mod fs;
1111

1212
pub mod index;
13+
14+
pub(crate) mod os;

git-worktree/src/os.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::io;
2+
use std::path::Path;
3+
4+
#[cfg(not(windows))]
5+
pub fn create_symlink(original: &Path, link: &Path) -> io::Result<()> {
6+
std::os::unix::fs::symlink(original, link)
7+
}
8+
9+
#[cfg(not(windows))]
10+
pub fn remove_symlink(path: &Path) -> io::Result<()> {
11+
std::fs::remove_file(path)
12+
}
13+
14+
#[cfg(windows)]
15+
pub fn remove_symlink(path: &Path) -> io::Result<()> {
16+
symlink::remove_symlink_auto(path)
17+
}
18+
19+
#[cfg(windows)]
20+
pub fn create_symlink(original: &Path, link: &Path) -> io::Result<()> {
21+
use std::os::windows::fs::{symlink_dir, symlink_file};
22+
// TODO: figure out if links to links count as files or whatever they point at
23+
if std::fs::metadata(link.parent().expect("dir for link").join(original))?.is_dir() {
24+
symlink_dir(original, link)
25+
} else {
26+
symlink_file(original, original)
27+
}
28+
}

0 commit comments

Comments
 (0)