Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support force push #421

Merged
merged 28 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
17f4a7d
Add support for force push
WizardOhio24 Sep 29, 2020
eecc7d8
Add Force Push to cmdbar
WizardOhio24 Sep 29, 2020
b0dfef9
Remove unnessessary if
WizardOhio24 Oct 4, 2020
57455d3
Change p to P
WizardOhio24 Oct 4, 2020
de4ea26
use ' \u{200b}' for a ' ' so tui doesn't remove
WizardOhio24 Nov 8, 2020
77a47fc
Merge branch 'master' into force-push
WizardOhio24 Nov 13, 2020
cf9547c
Revert "use ' \u{200b}' for a ' ' so tui doesn't remove"
WizardOhio24 Nov 13, 2020
d3bcaaf
Fix vim test
WizardOhio24 Nov 13, 2020
9759bfe
Add confirm popup before force pushing
WizardOhio24 Nov 13, 2020
e369ed6
Increase size of confirm popup
WizardOhio24 Nov 13, 2020
9cfd985
Remove refs/head/ from force push message
WizardOhio24 Nov 13, 2020
7fb7673
Merge branch 'master' into force-push
WizardOhio24 Feb 2, 2021
1499c35
Use key_config.get_hint in strings
WizardOhio24 Feb 2, 2021
3a6b9eb
Change vim_style_key_config force push
WizardOhio24 Feb 2, 2021
6c6f952
First attempt at testing
WizardOhio24 Feb 4, 2021
e562a17
Work on testing
WizardOhio24 Feb 5, 2021
394a02e
Correct error message on test setup
WizardOhio24 Feb 5, 2021
a0fe96e
Fix force-push test
WizardOhio24 Feb 6, 2021
2d55df7
Improve test code and add comments
WizardOhio24 Feb 6, 2021
3d31fcd
Remove unessessary function
WizardOhio24 Feb 6, 2021
3df7ae8
Remove unessessary function
WizardOhio24 Feb 6, 2021
53eab36
Test that correct commits are in upstream
WizardOhio24 Feb 6, 2021
274ac47
Unwrap logwalkers
WizardOhio24 Feb 6, 2021
2382358
Fix force-push test
WizardOhio24 Feb 6, 2021
2585af9
Clear rather than make new vec
WizardOhio24 Feb 6, 2021
698d2bb
Test force push commit has same parent as original
WizardOhio24 Feb 6, 2021
0238ceb
Remove print statements
WizardOhio24 Feb 6, 2021
415f321
Small improvement
WizardOhio24 Feb 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/vim_style_key_config.ron
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
select_branch: ( code: Char('b'), modifiers: ( bits: 0,),),
delete_branch: ( code: Char('D'), modifiers: ( bits: 1,),),
push: ( code: Char('p'), modifiers: ( bits: 0,),),
force_push: ( code: Char('P'), modifiers: ( bits: 1,),),
fetch: ( code: Char('f'), modifiers: ( bits: 0,),),

//removed in 0.11
Expand Down
5 changes: 4 additions & 1 deletion asyncgit/src/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ pub struct PushRequest {
///
pub branch: String,
///
pub force: bool,
///
pub basic_credential: Option<BasicAuthCredential>,
}

Expand Down Expand Up @@ -164,8 +166,9 @@ impl AsyncPush {
CWD,
params.remote.as_str(),
params.branch.as_str(),
params.force,
params.basic_credential,
progress_sender.clone(),
Some(progress_sender.clone()),
);

progress_sender
Expand Down
7 changes: 7 additions & 0 deletions asyncgit/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ mod tests {
Ok((td, repo))
}

/// Same as repo_init, but the repo is a bare repo (--bare)
pub fn repo_init_bare() -> Result<(TempDir, Repository)> {
let tmp_repo_dir = TempDir::new()?;
let bare_repo = Repository::init_bare(tmp_repo_dir.path())?;
Ok((tmp_repo_dir, bare_repo))
}

/// helper returning amount of files with changes in the (wd,stage)
pub fn get_statuses(repo_path: &str) -> (usize, usize) {
(
Expand Down
249 changes: 244 additions & 5 deletions asyncgit/src/sync/remotes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ pub fn push(
repo_path: &str,
remote: &str,
branch: &str,
force: bool,
extrawurst marked this conversation as resolved.
Show resolved Hide resolved
basic_credential: Option<BasicAuthCredential>,
progress_sender: Sender<ProgressNotification>,
progress_sender: Option<Sender<ProgressNotification>>,
) -> Result<()> {
scope_time!("push");

Expand All @@ -122,15 +123,20 @@ pub fn push(
let mut options = PushOptions::new();

options.remote_callbacks(remote_callbacks(
Some(progress_sender),
progress_sender,
basic_credential,
));
options.packbuilder_parallelism(0);

let branch_name = format!("refs/heads/{}", branch);

remote.push(&[branch_name.as_str()], Some(&mut options))?;

if force {
remote.push(
&[String::from("+") + &branch_name],
Some(&mut options),
)?;
} else {
remote.push(&[branch_name.as_str()], Some(&mut options))?;
}
branch_set_upstream(&repo, branch)?;

Ok(())
Expand Down Expand Up @@ -306,4 +312,237 @@ mod tests {
.unwrap();
assert_eq!(first, String::from("origin"));
}

#[test]
fn test_force_push() {
use super::push;
use std::fs::File;
use std::io::Write;

use crate::sync::commit::commit;
use crate::sync::tests::{repo_init, repo_init_bare};

// This test mimics the scenario of 2 people having 2
// local branches and both modifying the same file then
// both pushing, sequentially

let (tmp_repo_dir, repo) = repo_init().unwrap();
let (tmp_other_repo_dir, other_repo) = repo_init().unwrap();
let (tmp_upstream_dir, _) = repo_init_bare().unwrap();

repo.remote(
"origin",
tmp_upstream_dir.path().to_str().unwrap(),
)
.unwrap();

other_repo
.remote(
"origin",
tmp_upstream_dir.path().to_str().unwrap(),
)
.unwrap();

let tmp_repo_file_path =
tmp_repo_dir.path().join("temp_file.txt");
let mut tmp_repo_file =
File::create(tmp_repo_file_path).unwrap();
writeln!(tmp_repo_file, "TempSomething").unwrap();

commit(
tmp_repo_dir.path().to_str().unwrap(),
"repo_1_commit",
)
.unwrap();

push(
tmp_repo_dir.path().to_str().unwrap(),
"origin",
"master",
false,
None,
None,
)
.unwrap();

let tmp_other_repo_file_path =
tmp_other_repo_dir.path().join("temp_file.txt");
let mut tmp_other_repo_file =
File::create(tmp_other_repo_file_path).unwrap();
writeln!(tmp_other_repo_file, "TempElse").unwrap();

commit(
tmp_other_repo_dir.path().to_str().unwrap(),
"repo_2_commit",
)
.unwrap();

// Attempt a normal push,
// should fail as branches diverged
assert_eq!(
push(
tmp_other_repo_dir.path().to_str().unwrap(),
"origin",
"master",
false,
None,
None,
)
.is_err(),
true
);

// Attempt force push,
// should work as it forces the push through
assert_eq!(
push(
tmp_other_repo_dir.path().to_str().unwrap(),
"origin",
"master",
true,
None,
None,
)
.is_err(),
false
);
}

#[test]
fn test_force_push_rewrites_history() {
use super::push;
use std::fs::File;
use std::io::Write;

use crate::sync::commit::commit;
use crate::sync::tests::{repo_init, repo_init_bare};
use crate::sync::LogWalker;

// This test mimics the scenario of 2 people having 2
// local branches and both modifying the same file then
// both pushing, sequentially

let (tmp_repo_dir, repo) = repo_init().unwrap();
let (tmp_other_repo_dir, other_repo) = repo_init().unwrap();
let (tmp_upstream_dir, upstream) = repo_init_bare().unwrap();

repo.remote(
"origin",
tmp_upstream_dir.path().to_str().unwrap(),
)
.unwrap();

other_repo
.remote(
"origin",
tmp_upstream_dir.path().to_str().unwrap(),
)
.unwrap();

let tmp_repo_file_path =
tmp_repo_dir.path().join("temp_file.txt");
let mut tmp_repo_file =
File::create(tmp_repo_file_path).unwrap();
writeln!(tmp_repo_file, "TempSomething").unwrap();

commit(
tmp_repo_dir.path().to_str().unwrap(),
"repo_1_commit",
)
.unwrap();

let mut repo_commit_ids = Vec::<CommitId>::new();
LogWalker::new(&repo).read(&mut repo_commit_ids, 1).unwrap();

push(
tmp_repo_dir.path().to_str().unwrap(),
"origin",
"master",
false,
None,
None,
)
.unwrap();

let upstream_parent = upstream
.find_commit((repo_commit_ids[0]).into())
.unwrap()
.parents()
.next()
.unwrap()
.id();

let tmp_other_repo_file_path =
tmp_other_repo_dir.path().join("temp_file.txt");
let mut tmp_other_repo_file =
File::create(tmp_other_repo_file_path).unwrap();
writeln!(tmp_other_repo_file, "TempElse").unwrap();

commit(
tmp_other_repo_dir.path().to_str().unwrap(),
"repo_2_commit",
)
.unwrap();
let mut other_repo_commit_ids = Vec::<CommitId>::new();
LogWalker::new(&other_repo)
.read(&mut other_repo_commit_ids, 1)
.unwrap();

// Attempt a normal push,
// should fail as branches diverged
assert_eq!(
push(
tmp_other_repo_dir.path().to_str().unwrap(),
"origin",
"master",
false,
None,
None,
)
.is_err(),
true
);

// Check that the other commit is not in upstream,
// a normal push would not rewrite history
let mut commit_ids = Vec::<CommitId>::new();
LogWalker::new(&upstream).read(&mut commit_ids, 1).unwrap();
assert_eq!(commit_ids.contains(&repo_commit_ids[0]), true);

// Attempt force push,
// should work as it forces the push through
assert_eq!(
push(
tmp_other_repo_dir.path().to_str().unwrap(),
"origin",
"master",
true,
None,
None,
)
.is_err(),
false
);

commit_ids.clear();
LogWalker::new(&upstream).read(&mut commit_ids, 1).unwrap();

// Check that only the other repo commit is now in upstream
assert_eq!(
commit_ids.contains(&other_repo_commit_ids[0]),
true
);

assert_eq!(
upstream
.find_commit((commit_ids[0]).into())
.unwrap()
.parents()
.next()
.unwrap()
.id()
== upstream_parent,
true
);
}
}
8 changes: 6 additions & 2 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ impl App {
self.select_branch_popup.hide();
}
}
Action::ForcePush(branch, force) => self
.queue
.borrow_mut()
.push_back(InternalEvent::Push(branch, force)),
},
InternalEvent::ConfirmAction(action) => {
self.reset.open(action)?;
Expand Down Expand Up @@ -533,8 +537,8 @@ impl App {
self.file_to_open = path;
flags.insert(NeedsUpdate::COMMANDS)
}
InternalEvent::Push(branch) => {
self.push_popup.push(branch)?;
InternalEvent::Push(branch, force) => {
self.push_popup.push(branch, force)?;
flags.insert(NeedsUpdate::ALL)
}
};
Expand Down
Loading