From 1acc9fdd29c2c97788f5d25ba2ddbc6092510fb8 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 4 Nov 2022 17:34:46 -0700 Subject: [PATCH] fix: Push git refs atomically Several times I've run into an issue where: * My main has diverged from upstream main. * I use `cargo release` to push both main and a tag. In this situation, the tag push succeeds while the push to main fails. This isn't desired and in my case breaks automation, which expects the tag to be an ancestor of main. Use an atomic push to avoid this issue. The man page says: ``` --[no-]atomic Use an atomic transaction on the remote side if available. Either all refs are updated, or on error, no refs are updated. If the server does not support atomic pushes the push will fail. ``` I was a bit worried about the "push will fail" bit, but https://github.blog/2015-04-30-git-2-4-atomic-pushes-push-to-deploy-and-more/ says that atomic pushes were added in 2015. I can't imagine anyone running a 7 year old Git on a server at this point, especially since there have been multiple security vulns in Git since then. --- src/ops/git.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ops/git.rs b/src/ops/git.rs index e680c22b0..2d0eee372 100644 --- a/src/ops/git.rs +++ b/src/ops/git.rs @@ -203,7 +203,9 @@ pub fn push<'s>( options: impl IntoIterator, dry_run: bool, ) -> CargoResult { - let mut command = vec!["git", "push"]; + // Use an atomic push to ensure that e.g. if main and a tag are pushed together, and the local + // main diverges from the remote main, that the push fails entirely. + let mut command = vec!["git", "push", "--atomic"]; for option in options { command.push("--push-option");