diff --git a/src/base.rs b/src/base.rs index 68438c1..bd6ec1c 100644 --- a/src/base.rs +++ b/src/base.rs @@ -459,6 +459,17 @@ pub fn get_working_tree() -> HashMap { return result; } +pub fn is_ancestor_of(commit: String, maybe_ancestor: String) -> bool { + let mut commits = VecDeque::new(); + commits.push_front(commit); + for oid in iter_commits_and_parents(commits) { + if maybe_ancestor == oid { + return true; + } + } + return false; +} + fn empty_current_directory(dir: &str) -> io::Result<()> { // Delete current directory, except the ignored directories and files for entry in fs::read_dir(dir)? { diff --git a/src/remote.rs b/src/remote.rs index 0ba41c4..ac98743 100644 --- a/src/remote.rs +++ b/src/remote.rs @@ -31,9 +31,17 @@ pub fn fetch(path: String) { } pub fn push(remote_path: String, reference: String) { + let refs = get_remote_refs(remote_path.clone(), REMOTE_REFS_BASE); + let empty = "".to_owned(); + let remote_ref = refs.get(&reference).unwrap_or(&empty); let local_ref = data::get_ref(reference.clone(), true).value; assert!(local_ref != "".to_string()); + // Don't allow force push + assert!( + *remote_ref == "".to_owned() || base::is_ancestor_of(local_ref.clone(), remote_ref.clone()) + ); + let commit_oids = vec![&local_ref]; base::copy_objects_in_commits_and_parents(commit_oids, remote_path.clone(), true);