Skip to content

Commit

Permalink
feat(sync): pull from remote main branch
Browse files Browse the repository at this point in the history
This commit also removes support for remote branches. Instead, `git sync` can be used to keep the local main branch up-to-date with the remote one.
  • Loading branch information
arxanas committed Oct 9, 2022
1 parent 8231341 commit 4f67d65
Show file tree
Hide file tree
Showing 16 changed files with 596 additions and 276 deletions.
4 changes: 2 additions & 2 deletions git-branchless-lib/src/core/eventlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ impl EventReplayer {
) -> eyre::Result<Self> {
let (_effects, _progress) = effects.start_operation(OperationType::ProcessEvents);

let main_branch_reference_name = repo.get_main_branch_reference()?.get_name()?;
let main_branch_reference_name = repo.get_main_branch()?.get_reference_name()?;
let mut result = EventReplayer::new(main_branch_reference_name);
for event in event_log_db.get_events()? {
result.process_event(&event);
Expand Down Expand Up @@ -1209,7 +1209,7 @@ impl EventReplayer {
cursor: EventCursor,
repo: &Repo,
) -> eyre::Result<NonZeroOid> {
let main_branch_reference_name = repo.get_main_branch_reference()?.get_name()?;
let main_branch_reference_name = repo.get_main_branch()?.get_reference_name()?;
let main_branch_oid = self.get_cursor_branch_oid(cursor, &main_branch_reference_name)?;
match main_branch_oid {
Some(main_branch_oid) => Ok(main_branch_oid),
Expand Down
75 changes: 30 additions & 45 deletions git-branchless-lib/src/core/repo_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use color_eyre::Help;
use eyre::Context;
use tracing::instrument;

use crate::git::{NonZeroOid, Reference, ReferenceName, Repo};
use crate::git::{Branch, BranchType, NonZeroOid, ReferenceName, Repo};

use super::config::get_main_branch_name;

Expand All @@ -25,8 +25,8 @@ pub struct RepoReferencesSnapshot {

/// Helper functions on [`Repo`].
pub trait RepoExt {
/// Get the `Reference` for the main branch for the repository.
fn get_main_branch_reference(&self) -> eyre::Result<Reference>;
/// Get the `Branch` for the main branch for the repository.
fn get_main_branch(&self) -> eyre::Result<Branch>;

/// Get the OID corresponding to the main branch.
fn get_main_branch_oid(&self) -> eyre::Result<NonZeroOid>;
Expand All @@ -42,54 +42,48 @@ pub trait RepoExt {
}

impl RepoExt for Repo {
fn get_main_branch_reference(&self) -> eyre::Result<Reference> {
fn get_main_branch(&self) -> eyre::Result<Branch> {
let main_branch_name = get_main_branch_name(self)?;
match self.find_branch(&main_branch_name, git2::BranchType::Local)? {
Some(branch) => match branch.get_upstream_branch()? {
Some(upstream_branch) => Ok(upstream_branch.into_reference()),
None => Ok(branch.into_reference()),
},
None => match self.find_branch(&main_branch_name, git2::BranchType::Remote)? {
Some(branch) => Ok(branch.into_reference()),
None => {
let suggestion = format!(
r"
match self.find_branch(&main_branch_name, BranchType::Local)? {
Some(branch) => Ok(branch),
None => {
let suggestion = format!(
r"
The main branch {:?} could not be found in your repository
at path: {:?}.
These branches exist: {:?}
Either create it, or update the main branch setting by running:
git branchless init --main-branch <branch>
",
get_main_branch_name(self)?,
self.get_path(),
self.get_all_local_branches()?
.into_iter()
.map(|branch| {
branch
.into_reference()
.get_name()
.map(|s| format!("{:?}", s))
.wrap_err("converting branch to reference")
})
.collect::<eyre::Result<Vec<String>>>()?,
);
Err(eyre::eyre!("Could not find repository main branch")
.with_suggestion(|| suggestion))
}
},
get_main_branch_name(self)?,
self.get_path(),
self.get_all_local_branches()?
.into_iter()
.map(|branch| {
branch
.into_reference()
.get_name()
.map(|s| format!("{:?}", s))
.wrap_err("converting branch to reference")
})
.collect::<eyre::Result<Vec<String>>>()?,
);
Err(eyre::eyre!("Could not find repository main branch")
.with_suggestion(|| suggestion))
}
}
}

#[instrument]
fn get_main_branch_oid(&self) -> eyre::Result<NonZeroOid> {
let main_branch_reference = self.get_main_branch_reference()?;
let commit = main_branch_reference.peel_to_commit()?;
match commit {
Some(commit) => Ok(commit.get_oid()),
let main_branch = self.get_main_branch()?;
let main_branch_oid = main_branch.get_oid()?;
match main_branch_oid {
Some(main_branch_oid) => Ok(main_branch_oid),
None => eyre::bail!(
"Could not find commit pointed to by main branch: {:?}",
main_branch_reference.get_name()?
main_branch.get_name()?,
),
}
}
Expand All @@ -109,15 +103,6 @@ Either create it, or update the main branch setting by running:
}
}

// The main branch may be a remote branch, in which case it won't be
// returned in the iteration above.
let main_branch_name = self.get_main_branch_reference()?.get_name()?;
let main_branch_oid = self.get_main_branch_oid()?;
result
.entry(main_branch_oid)
.or_insert_with(HashSet::new)
.insert(main_branch_name);

Ok(result)
}

Expand Down
60 changes: 47 additions & 13 deletions git-branchless-lib/src/core/rewrite/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub fn move_branches<'a>(
event_tx_id: EventTransactionId,
rewritten_oids_map: &'a HashMap<NonZeroOid, MaybeZeroOid>,
) -> eyre::Result<()> {
let main_branch = repo.get_main_branch()?;
let main_branch_name = main_branch.get_reference_name()?;
let branch_oid_to_names = repo.get_branch_oid_to_names()?;

// We may experience an error in the case of a branch move. Ideally, we
Expand Down Expand Up @@ -78,22 +80,54 @@ pub fn move_branches<'a>(

MaybeZeroOid::Zero => {
for name in names {
match repo.find_reference(name) {
Ok(Some(mut reference)) => {
if let Err(err) = reference.delete() {
if name == &main_branch_name {
// Hack? Never delete the main branch. We probably got here by syncing the
// main branch with the upstream version, but all main branch commits were
// skipped. For a regular branch, we would delete the branch, but for the
// main branch, we should update it to point directly to the upstream
// version.
let target_oid = match main_branch.get_upstream_branch_target()? {
Some(target_oid) => {
if let Err(err) = repo.create_reference(
&main_branch_name,
target_oid,
true,
"move main branch",
) {
branch_move_err = Some(eyre::eyre!(err));
break 'outer;
}
MaybeZeroOid::NonZero(target_oid)
}
None => {
let mut main_branch_reference =
repo.get_main_branch()?.into_reference();
if let Err(err) = main_branch_reference.delete() {
branch_move_err = Some(eyre::eyre!(err));
break 'outer;
}
MaybeZeroOid::Zero
}
};
branch_moves.push((*old_oid, target_oid, name));
} else {
match repo.find_reference(name) {
Ok(Some(mut reference)) => {
if let Err(err) = reference.delete() {
branch_move_err = Some(eyre::eyre!(err));
break 'outer;
}
}
Ok(None) => {
warn!(?name, "Reference not found, not deleting")
}
Err(err) => {
branch_move_err = Some(eyre::eyre!(err));
break 'outer;
}
}
Ok(None) => {
warn!(?name, "Reference not found, not deleting")
}
Err(err) => {
branch_move_err = Some(eyre::eyre!(err));
break 'outer;
}
};
branch_moves.push((*old_oid, MaybeZeroOid::Zero, name));
};
branch_moves.push((*old_oid, MaybeZeroOid::Zero, name));
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion git-branchless-lib/src/core/rewrite/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ enum Constraint {
}

/// Options used to build a rebase plan.
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct BuildRebasePlanOptions {
/// Force rewriting public commits, even though other users may have access
/// to those commits.
Expand Down
27 changes: 26 additions & 1 deletion git-branchless-lib/src/git/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2142,14 +2142,27 @@ impl<'repo> Branch<'repo> {
Ok(self.inner.get().target().map(make_non_zero_oid))
}

/// Get the name of this branch, not including any `refs/heads/` prefix.
/// Get the name of this branch, not including any `refs/heads/` prefix. To get the full
/// reference name of this branch, instead call `.into_reference().get_name()?`.
#[instrument]
pub fn get_name(&self) -> eyre::Result<&str> {
self.inner
.name()?
.ok_or_else(|| eyre::eyre!("Could not decode branch name"))
}

/// Get the full reference name of this branch, including the `refs/heads/` or `refs/remotes/`x
/// prefix, as appropriate
#[instrument]
pub fn get_reference_name(&self) -> eyre::Result<ReferenceName> {
let reference_name = self
.inner
.get()
.name()
.ok_or_else(|| eyre::eyre!("Could not decode branch reference name"))?;
Ok(ReferenceName(reference_name.to_owned()))
}

/// If this branch tracks a remote ("upstream") branch, return that branch.
#[instrument]
pub fn get_upstream_branch(&self) -> Result<Option<Branch<'repo>>> {
Expand All @@ -2171,6 +2184,18 @@ impl<'repo> Branch<'repo> {
}
}

/// If this branch tracks a remote ("upstream") branch, return the OID of the commit which that
/// branch points to.
#[instrument]
pub fn get_upstream_branch_target(&self) -> eyre::Result<Option<NonZeroOid>> {
let upstream_branch = match self.get_upstream_branch()? {
Some(upstream_branch) => upstream_branch,
None => return Ok(None),
};
let target_oid = upstream_branch.get_oid()?;
Ok(target_oid)
}

/// Get the associated remote to push to for this branch. If there is no
/// associated remote, returns `None`. Note that this never reads the value
/// of `push.remoteDefault`.
Expand Down
2 changes: 1 addition & 1 deletion git-branchless/src/commands/bug_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ fn collect_events(effects: &Effects, git_run_info: &GitRunInfo) -> eyre::Result<

let redactor = Redactor::new({
let mut preserved_ref_names = HashSet::new();
preserved_ref_names.insert(repo.get_main_branch_reference()?.get_name()?);
preserved_ref_names.insert(repo.get_main_branch()?.get_reference_name()?);
preserved_ref_names
});

Expand Down
4 changes: 2 additions & 2 deletions git-branchless/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,10 @@ fn do_main_and_drop_locals() -> eyre::Result<i32> {
}

Command::Sync {
update_refs,
pull,
move_options,
revsets,
} => sync::sync(&effects, &git_run_info, update_refs, &move_options, revsets)?,
} => sync::sync(&effects, &git_run_info, pull, &move_options, revsets)?,

Command::Undo { interactive, yes } => {
undo::undo(&effects, &git_run_info, interactive, yes)?
Expand Down
2 changes: 1 addition & 1 deletion git-branchless/src/commands/restack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ fn restack_branches(
Some(branch_target) => branch_target,
None => {
warn!(
branch_name = ?branch.into_reference().get_name(),
branch_name = ?branch.get_reference_name()?,
"Branch was not a direct reference, could not resolve target"
);
continue;
Expand Down
5 changes: 2 additions & 3 deletions git-branchless/src/commands/submit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ specified for `remote.pushDefault`, so cannot push these branches: {}
Configure a value with: git config remote.pushDefault <remote>
These remotes are available: {}",
CategorizedReferenceName::new(
&repo.get_main_branch_reference()?.get_name()?
&repo.get_main_branch()?.get_reference_name()?,
)
.friendly_describe(),
branch_names.join(", "),
Expand Down Expand Up @@ -183,8 +183,7 @@ To create and push them, retry this operation with the --create option."
}

fn get_default_remote(repo: &Repo) -> eyre::Result<Option<String>> {
let main_branch_reference = repo.get_main_branch_reference()?;
let main_branch_name = main_branch_reference.get_name()?;
let main_branch_name = repo.get_main_branch()?.get_reference_name()?;
match CategorizedReferenceName::new(&main_branch_name) {
name @ CategorizedReferenceName::LocalBranch { .. } => {
if let Some(main_branch) =
Expand Down
Loading

0 comments on commit 4f67d65

Please sign in to comment.