Skip to content

Commit

Permalink
Don't use push upstream to classify branch, and prompt survey on it
Browse files Browse the repository at this point in the history
  • Loading branch information
foriequal0 committed Aug 3, 2020
1 parent 099a7f8 commit f3fdfb4
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 117 deletions.
71 changes: 0 additions & 71 deletions src/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,6 @@ pub fn get_remote_entry<'a>(repo: &'a Repository, remote_name: &str) -> Result<O
}
}

pub fn get_push_upstream(
repo: &Repository,
config: &Config,
branch: &LocalBranch,
) -> Result<Option<RemoteTrackingBranch>> {
if let Some(remote_branch) = get_explicit_push_remote_branch(repo, config, branch)? {
return RemoteTrackingBranch::from_remote_branch(repo, &remote_branch);
}
Ok(None)
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Hash, Debug)]
pub struct RemoteBranch {
pub remote: String,
Expand All @@ -177,63 +166,3 @@ pub enum RemoteBranchError {
#[error("remote with matching refspec not found")]
RemoteNotFound,
}

fn get_explicit_push_remote_branch(
repo: &Repository,
config: &Config,
branch: &LocalBranch,
) -> Result<Option<RemoteBranch>> {
let remote_name = config::get_push_remote(config, branch)?;
if let Some(remote) = get_remote_entry(repo, &remote_name)? {
let refname = if let Some(expanded) = expand_refspec(
&remote,
&branch.refname,
Direction::Push,
ExpansionSide::Right,
)? {
expanded
} else {
// `git push` will fallback to `push.default`.
// However we'll stop here since we want to distinguish explicit tracking
// and implicit tracking.
return Ok(None);
};

if repo.find_reference(&refname).is_ok() {
return Ok(Some(RemoteBranch {
remote: remote_name,
refname,
}));
} else {
return Ok(None);
}
}

let push_default = config::get(config, "push.default")
.with_default(String::from("simple"))
.read()?
.expect("has default");

match push_default.as_str() {
"current" => Ok(Some(RemoteBranch {
remote: remote_name,
refname: branch.refname.clone(),
})),
"upstream" | "tracking" | "simple" | "matching" => {
if let Some(merge) = config::get_merge(config, &branch)? {
Ok(Some(RemoteBranch {
remote: remote_name,
refname: merge,
}))
} else {
warn!(
"The current branch {} has no upstream branch.",
branch.refname
);
Ok(None)
}
}
"nothing" => unimplemented!("push.default=nothing is not implemented."),
_ => panic!("unexpected config push.default"),
}
}
38 changes: 4 additions & 34 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use git2::{Oid, Repository, Signature};
use log::*;

use crate::args::DeleteFilter;
use crate::branch::{
get_fetch_upstream, get_push_upstream, LocalBranch, RemoteBranch, RemoteTrackingBranch,
};
use crate::branch::{get_fetch_upstream, LocalBranch, RemoteBranch, RemoteTrackingBranch};
use crate::subprocess::{get_worktrees, is_merged_by_rev_list};
use crate::util::ForceSendSync;
use crate::{config, Git};
Expand Down Expand Up @@ -247,7 +245,6 @@ pub struct MergeState<B> {
pub struct Classification {
pub local: MergeState<LocalBranch>,
pub fetch: Option<MergeState<RemoteTrackingBranch>>,
pub push: Option<MergeState<RemoteTrackingBranch>>,
pub messages: Vec<&'static str>,
pub result: HashSet<ClassifiedBranch>,
}
Expand Down Expand Up @@ -324,43 +321,16 @@ pub fn classify(
} else {
None
};
let push = if let Some(push) = get_push_upstream(&git.repo, &git.config, branch)? {
let merged = merge_tracker.check_and_track(&git.repo, &base.refname, &push.refname)?;
Some(MergeState {
branch: push,
merged,
})
} else {
None
};

let mut c = Classification {
local: local.clone(),
fetch: fetch.clone(),
push: push.clone(),
messages: vec![],
result: HashSet::default(),
};

match (fetch, push) {
(Some(fetch), Some(push)) => {
if local.merged {
c.messages.push("local is merged");
c.result
.insert(ClassifiedBranch::MergedLocal(branch.clone()));
c.merged_or_stray_remote(&git.repo, &fetch)?;
c.merged_or_stray_remote(&git.repo, &push)?;
} else if fetch.merged || push.merged {
c.messages
.push("some upstreams are merged, but the local strays");
c.result
.insert(ClassifiedBranch::StrayLocal(branch.clone()));
c.merged_or_stray_remote(&git.repo, &push)?;
c.merged_or_stray_remote(&git.repo, &fetch)?;
}
}

(Some(upstream), None) | (None, Some(upstream)) => {
match fetch {
Some(upstream) => {
if local.merged {
c.messages.push("local is merged");
c.result
Expand All @@ -377,7 +347,7 @@ pub fn classify(
// `hub-cli` sets config `branch.{branch_name}.remote` as URL without `remote.{remote}` entry.
// so `get_push_upstream` and `get_fetch_upstream` returns None.
// However we can try manual classification without `remote.{remote}` entry.
(None, None) => {
None => {
let remote = config::get_remote_raw(&git.config, branch)?
.expect("should have it if it has an upstream");
let merge = config::get_merge(&git.config, branch)?
Expand Down
12 changes: 1 addition & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use log::*;
use rayon::prelude::*;

use crate::args::DeleteFilter;
use crate::branch::{get_fetch_upstream, get_push_upstream, get_remote_entry};
use crate::branch::{get_fetch_upstream, get_remote_entry};
pub use crate::branch::{LocalBranch, RemoteBranch, RemoteBranchError, RemoteTrackingBranch};
use crate::core::MergeTracker;
pub use crate::core::{ClassifiedBranch, TrimPlan};
Expand Down Expand Up @@ -70,10 +70,8 @@ pub fn get_trim_plan(git: &Git, param: &PlanParam) -> Result<TrimPlan> {
for branch in git.repo.branches(Some(BranchType::Local))? {
let branch = LocalBranch::try_from(&branch?.0)?;
let fetch_upstream = get_fetch_upstream(&git.repo, &git.config, &branch)?;
let push_upstream = get_push_upstream(&git.repo, &git.config, &branch)?;
debug!("Branch ref: {:?}", branch);
debug!("Fetch upstream: {:?}", fetch_upstream);
debug!("Push upstream: {:?}", push_upstream);

let config_remote = if let Some(remote) = config::get_remote_raw(&git.config, &branch)? {
remote
Expand Down Expand Up @@ -136,7 +134,6 @@ pub fn get_trim_plan(git: &Git, param: &PlanParam) -> Result<TrimPlan> {
for classification in classifications.into_iter() {
debug!("branch: {:?}", classification.local);
trace!("fetch: {:?}", classification.fetch);
trace!("push: {:?}", classification.push);
debug!("message: {:?}", classification.messages);
delete.extend(classification.result.into_iter());
}
Expand Down Expand Up @@ -194,10 +191,6 @@ fn resolve_base_refs(
if let Some(upstream) = get_fetch_upstream(repo, config, &branch)? {
result.insert(upstream.refname);
}

if let Some(upstream) = get_push_upstream(repo, config, &branch)? {
result.insert(upstream.refname);
}
}
}
Ok(result)
Expand Down Expand Up @@ -288,9 +281,6 @@ fn resolve_protected_refs(
if let Some(upstream) = get_fetch_upstream(repo, config, &branch)? {
result.insert(upstream.refname);
}
if let Some(upstream) = get_push_upstream(repo, config, &branch)? {
result.insert(upstream.refname);
}
}
}
}
Expand Down
27 changes: 26 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use git2::{BranchType, Repository};
use log::*;

use git_trim::args::Args;
use git_trim::config::{self, Config, ConfigValue};
use git_trim::config::{self, get, Config, ConfigValue};
use git_trim::{
delete_local_branches, delete_remote_branches, get_trim_plan, remote_update, ClassifiedBranch,
Git, LocalBranch, PlanParam, RemoteBranchError, RemoteTrackingBranch, TrimPlan,
Expand Down Expand Up @@ -80,6 +80,8 @@ fn main(args: Args) -> Result<()> {

delete_remote_branches(&git.repo, &remotes, args.dry_run)?;
delete_local_branches(&git.repo, &locals, args.dry_run)?;

prompt_survey_on_push_upstream(&git)?;
Ok(())
}

Expand Down Expand Up @@ -233,3 +235,26 @@ fn should_update(git: &Git, interval: u64, explicit: bool) -> Result<bool> {

Ok(elapsed.as_secs() >= interval)
}

fn prompt_survey_on_push_upstream(git: &Git) -> Result<()> {
for remote_name in git.repo.remotes()?.iter() {
let remote_name = remote_name.context("non-utf8 remote name")?;
let key = format!("remote.{}.push", remote_name);
if get::<String>(&git.config, &key).read()?.is_some() {
println!(
r#"
Help wanted!
I recognize that you've set a config `git config remote.{}.push`!
I once (mis)used that config to classify branches, but I retracted it after realizing that I don't understand the config well.
It would be very helpful to me if you share your use cases of the config to me.
Here's the survey URL: https://github.com/foriequal0/git-trim/issues/134
Thank you!
"#,
remote_name
);
break;
}
}
Ok(())
}

0 comments on commit f3fdfb4

Please sign in to comment.