Skip to content

Commit

Permalink
Add a git switch-and-pull command (#109)
Browse files Browse the repository at this point in the history
Add a switch and pull command
  • Loading branch information
orf authored Sep 9, 2020
1 parent eb13c9d commit e47cddd
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 34 deletions.
104 changes: 83 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ atomic-counter = "1.0.1"
ureq = { version = "1.4.0", features = ["json", "native-tls"], default_features = false }
serde_json = "1.0.57"
globset = "0.4.5"
git2 = "0.13.11"

[target."cfg(unix)".dependencies]
expanduser = "1.2.1"
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,26 @@ USAGE:
git-workspace --workspace <workspace> <SUBCOMMAND>
FLAGS:
-h, --help
-h, --help
Prints help information
-V, --version
-V, --version
Prints version information
OPTIONS:
-w, --workspace <workspace>
[env: GIT_WORKSPACE=...]
-w, --workspace <workspace>
[env: GIT_WORKSPACE=/Users/tom/PycharmProjects/]
SUBCOMMANDS:
add Add a provider to the configuration
fetch Fetch new commits for all repositories in the workspace
help Prints this message or the help of the given subcommand(s)
list List all repositories in the workspace
run Run a git command in all repositories
update Update the workspace, removing and adding any repositories as needed
add Add a provider to the configuration
fetch Fetch new commits for all repositories in the workspace
help Prints this message or the help of the given subcommand(s)
list List all repositories in the workspace
run Run a git command in all repositories
switch-and-pull Pull new commits on the primary branch for all repositories in the workspace
update Update the workspace, removing and adding any repositories as needed
```

## Define your workspace
Expand Down
35 changes: 34 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ enum Command {
#[structopt(short = "t", long = "threads", default_value = "8")]
threads: usize,
},
/// Pull new commits on the primary branch for all repositories in the workspace
SwitchAndPull {
#[structopt(short = "t", long = "threads", default_value = "8")]
threads: usize,
},
/// List all repositories in the workspace
///
/// This command will output the names of all known repositories in the workspace.
Expand Down Expand Up @@ -161,6 +166,7 @@ fn handle_main(args: Args) -> anyhow::Result<()> {
command,
args,
} => execute_cmd(&workspace_path, threads, command, args)?,
Command::SwitchAndPull { threads } => pull_all_repositories(&workspace_path, threads)?,
};
Ok(())
}
Expand Down Expand Up @@ -216,6 +222,34 @@ fn update(workspace: &PathBuf, threads: usize) -> anyhow::Result<()> {
Ok(())
}

fn pull_all_repositories(workspace: &PathBuf, threads: usize) -> anyhow::Result<()> {
let lockfile = Lockfile::new(workspace.join("workspace-lock.toml"));
let repositories = lockfile.read().with_context(|| "Error reading lockfile")?;

println!(
"Switching to the primary branch and pulling {} repositories",
repositories.len()
);

map_repositories(&repositories, threads, |r, progress_bar| {
r.switch_to_primary_branch(&workspace)?;
let pull_args = match (&r.upstream, &r.branch) {
// This fucking sucks, but it's because my abstractions suck ass.
// I need to learn how to fix this.
(Some(_), Some(branch)) => vec![
"pull".to_string(),
"upstream".to_string(),
branch.to_string(),
],
_ => vec!["pull".to_string()],
};
r.execute_cmd(&workspace, &progress_bar, "git", &pull_args)?;
Ok(())
})?;

Ok(())
}

/// Execute a command on all our repositories
fn execute_cmd(
workspace: &PathBuf,
Expand Down Expand Up @@ -410,7 +444,6 @@ where
eprintln!("{}:", repo.name());
error
.chain()
.skip(1)
.for_each(|cause| eprintln!("because: {}", cause));
}
}
Expand Down
27 changes: 25 additions & 2 deletions src/repository.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use anyhow::{anyhow, Context};
use console::{strip_ansi_codes, truncate_str};
use git2::build::CheckoutBuilder;
use git2::{Repository as Git2Repository, StatusOptions};
use indicatif::ProgressBar;
use serde::{Deserialize, Serialize};
use std::io::{BufRead, BufReader};
Expand All @@ -11,8 +13,8 @@ use std::process::{Command, Stdio};
pub struct Repository {
path: String,
url: String,
upstream: Option<String>,
branch: Option<String>,
pub upstream: Option<String>,
pub branch: Option<String>,
}

impl Repository {
Expand All @@ -38,6 +40,7 @@ impl Repository {
upstream,
}
}

pub fn set_upstream(&self, root: &PathBuf) -> anyhow::Result<()> {
let upstream = match &self.upstream {
Some(upstream) => upstream,
Expand Down Expand Up @@ -137,6 +140,26 @@ impl Repository {
Ok(())
}

pub fn switch_to_primary_branch(&self, root: &PathBuf) -> anyhow::Result<()> {
let branch = match &self.branch {
None => return Ok(()),
Some(b) => b,
};
let repo = Git2Repository::init(root.join(&self.name()))?;
let status = repo.statuses(Some(&mut StatusOptions::default()))?;
if !status.is_empty() {
return Err(anyhow!(
"Repository is dirty, cannot switch to branch {}",
branch
));
}
repo.set_head(&format!("refs/heads/{}", branch).to_string())
.with_context(|| format!("Cannot find branch {}", branch))?;
repo.checkout_head(Some(CheckoutBuilder::default().safe().force()))
.with_context(|| format!("Error checking out branch {}", branch))?;
Ok(())
}

pub fn clone(&self, root: &PathBuf, progress_bar: &ProgressBar) -> anyhow::Result<()> {
let mut command = Command::new("git");

Expand Down

0 comments on commit e47cddd

Please sign in to comment.