Skip to content

Commit 130d13b

Browse files
committed
Assure reflogs aren't skipped just because there is no per-loose lock file.
The per-loose lock file isn't a requirement anymore as the packed-refs lock can be used to enforce consistency, at least among `gitoxide` powered tools. Didn't actually check `git` does it similarly, but also couldn't find any special behaviour related to clone and fetch ref updates.
1 parent f17c6b6 commit 130d13b

File tree

6 files changed

+27
-44
lines changed

6 files changed

+27
-44
lines changed

git-ref/src/store/file/loose/reflog.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ pub mod create_or_update {
101101
pub(crate) fn reflog_create_or_append(
102102
&self,
103103
name: &FullNameRef,
104-
_lock: &git_lock::Marker,
105104
previous_oid: Option<ObjectId>,
106105
new: &oid,
107106
committer: git_actor::SignatureRef<'_>,

git-ref/src/store/file/loose/reflog/create_or_update/tests.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::{convert::TryInto, path::Path};
22

33
use git_actor::{Sign, Signature, Time};
4-
use git_lock::acquire::Fail;
54
use git_object::bstr::ByteSlice;
65
use git_testtools::hex_to_id;
76
use tempfile::TempDir;
@@ -17,16 +16,6 @@ fn empty_store(writemode: WriteReflog) -> Result<(TempDir, file::Store)> {
1716
Ok((dir, store))
1817
}
1918

20-
fn reflock(store: &file::Store, full_name: &str) -> Result<git_lock::Marker> {
21-
let full_name: &FullNameRef = full_name.try_into()?;
22-
git_lock::Marker::acquire_to_hold_resource(
23-
store.reference_path(full_name),
24-
Fail::Immediately,
25-
Some(store.git_dir.clone()),
26-
)
27-
.map_err(Into::into)
28-
}
29-
3019
fn reflog_lines(store: &file::Store, name: &str, buf: &mut Vec<u8>) -> Result<Vec<crate::log::Line>> {
3120
store
3221
.reflog_iter(name, buf)?
@@ -56,7 +45,6 @@ fn missing_reflog_creates_it_even_if_similarly_named_empty_dir_exists_and_append
5645
let (_keep, store) = empty_store(*mode)?;
5746
let full_name_str = "refs/heads/main";
5847
let full_name: &FullNameRef = full_name_str.try_into()?;
59-
let lock = reflock(&store, full_name_str)?;
6048
let new = hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242");
6149
let committer = Signature {
6250
name: "committer".into(),
@@ -69,7 +57,6 @@ fn missing_reflog_creates_it_even_if_similarly_named_empty_dir_exists_and_append
6957
};
7058
store.reflog_create_or_append(
7159
full_name,
72-
&lock,
7360
None,
7461
&new,
7562
committer.to_ref(),
@@ -92,7 +79,6 @@ fn missing_reflog_creates_it_even_if_similarly_named_empty_dir_exists_and_append
9279
let previous = hex_to_id("0000000000000000000000111111111111111111");
9380
store.reflog_create_or_append(
9481
full_name,
95-
&lock,
9682
Some(previous),
9783
&new,
9884
committer.to_ref(),
@@ -123,14 +109,12 @@ fn missing_reflog_creates_it_even_if_similarly_named_empty_dir_exists_and_append
123109
// create onto existing directory
124110
let full_name_str = "refs/heads/other";
125111
let full_name: &FullNameRef = full_name_str.try_into()?;
126-
let lock = reflock(&store, full_name_str)?;
127112
let reflog_path = store.reflog_path(full_name_str.try_into().expect("valid"));
128113
let directory_in_place_of_reflog = reflog_path.join("empty-a").join("empty-b");
129114
std::fs::create_dir_all(&directory_in_place_of_reflog)?;
130115

131116
store.reflog_create_or_append(
132117
full_name,
133-
&lock,
134118
None,
135119
&new,
136120
committer.to_ref(),

git-ref/src/store/file/transaction/commit.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,7 @@ impl<'s, 'p> Transaction<'s, 'p> {
3636
match &change.update.change {
3737
// reflog first, then reference
3838
Change::Update { log, new, expected } => {
39-
let lock = match change.lock.take() {
40-
Some(l) => l,
41-
// Some updates are never locked as they are no-ops
42-
None => continue,
43-
};
39+
let lock = change.lock.take();
4440
let (update_ref, update_reflog) = match log.mode {
4541
RefLog::Only => (false, true),
4642
RefLog::AndReference => (true, true),
@@ -71,7 +67,6 @@ impl<'s, 'p> Transaction<'s, 'p> {
7167
if do_update {
7268
self.store.reflog_create_or_append(
7369
change.update.name.as_ref(),
74-
&lock,
7570
previous,
7671
new_oid,
7772
committer,
@@ -85,11 +80,11 @@ impl<'s, 'p> Transaction<'s, 'p> {
8580
// We delay deletion of the reference and dropping the lock to after the packed-refs were
8681
// safely written.
8782
if delete_loose_refs {
88-
change.lock = Some(lock);
83+
change.lock = lock;
8984
continue;
9085
}
91-
if update_ref && change.is_effective() {
92-
if let Err(err) = lock.commit() {
86+
if update_ref {
87+
if let Some(Err(err)) = lock.map(|l| l.commit()) {
9388
// TODO: when Kind::IsADirectory becomes stable, use that.
9489
let err = if err.instance.resource_path().is_dir() {
9590
git_tempfile::remove_dir::empty_depth_first(err.instance.resource_path())

git-ref/src/store/file/transaction/mod.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use git_hash::ObjectId;
22
use git_object::bstr::BString;
33
use std::fmt::Formatter;
44

5-
use crate::transaction::{Change, PreviousValue};
65
use crate::{
76
store_impl::{file, file::Transaction},
87
transaction::RefEdit,
@@ -52,19 +51,6 @@ impl Edit {
5251
fn name(&self) -> BString {
5352
self.update.name.0.clone()
5453
}
55-
56-
fn is_effective(&self) -> bool {
57-
match &self.update.change {
58-
Change::Update { new, expected, .. } => match expected {
59-
PreviousValue::Any
60-
| PreviousValue::MustExist
61-
| PreviousValue::MustNotExist
62-
| PreviousValue::ExistingMustMatch(_) => true,
63-
PreviousValue::MustExistAndMatch(existing) => new_would_change_existing(new, existing),
64-
},
65-
Change::Delete { .. } => unreachable!("must not be called on deletions"),
66-
}
67-
}
6854
}
6955

7056
fn new_would_change_existing(new: &Target, existing: &Target) -> bool {

git-ref/tests/file/transaction/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub(crate) mod prepare_and_commit {
44
use git_object::bstr::BString;
55
use git_ref::transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog};
66
use git_ref::{file, Target};
7+
use git_testtools::hex_to_id;
78
use std::convert::TryInto;
89

910
fn reflog_lines(store: &file::Store, name: &str) -> crate::Result<Vec<git_ref::log::Line>> {
@@ -46,9 +47,13 @@ pub(crate) mod prepare_and_commit {
4647
fn create_at(name: &str) -> RefEdit {
4748
RefEdit {
4849
change: Change::Update {
49-
log: LogChange::default(),
50+
log: LogChange {
51+
mode: RefLog::AndReference,
52+
force_create_reflog: true,
53+
message: "log peeled".into(),
54+
},
5055
expected: PreviousValue::MustNotExist,
51-
new: Target::Peeled(git_hash::Kind::Sha1.null()),
56+
new: Target::Peeled(hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391")),
5257
},
5358
name: name.try_into().expect("valid"),
5459
deref: false,

git-ref/tests/file/transaction/prepare_and_commit/create_or_update/collisions.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use git_lock::acquire::Fail;
33
use git_ref::file::transaction::PackedRefs;
44
use git_ref::transaction::{Change, LogChange, PreviousValue, RefEdit};
55
use git_ref::Target;
6+
use git_testtools::hex_to_id;
67
use std::convert::TryInto;
78

89
fn case_sensitive(tmp_dir: &std::path::Path) -> bool {
@@ -21,7 +22,10 @@ fn conflicting_creation_without_packed_refs() -> crate::Result {
2122

2223
let case_sensitive = case_sensitive(dir.path());
2324
match res {
24-
Ok(_) if case_sensitive => {}
25+
Ok(_) if case_sensitive => {
26+
assert!(store.reflog_exists("refs/a")?);
27+
assert!(store.reflog_exists("refs/A")?);
28+
}
2529
Ok(_) if !case_sensitive => panic!("should fail as 'a' and 'A' clash"),
2630
Err(err) if case_sensitive => panic!(
2731
"should work as case sensitivity allows 'a' and 'A' to coexist: {:?}",
@@ -52,6 +56,9 @@ fn non_conflicting_creation_without_packed_refs_work() -> crate::Result {
5256
t2.commit(committer().to_ref())?;
5357
ongoing.commit(committer().to_ref())?;
5458

59+
assert!(store.reflog_exists("refs/new")?);
60+
assert!(store.reflog_exists("refs/non-conflicting")?);
61+
5562
Ok(())
5663
}
5764

@@ -98,8 +105,11 @@ fn conflicting_creation_into_packed_refs() -> crate::Result {
98105
0,
99106
"refs/ directory isn't present as there is no loose ref - it removed every up to the base dir"
100107
);
108+
assert!(store.reflog_exists("refs/a")?);
109+
assert!(store.reflog_exists("refs/A")?);
101110

102111
// The following works because locks aren't actually obtained if there would be no change.
112+
// Otherwise there would be a conflict on case-insensitive filesystems
103113
store
104114
.transaction()
105115
.packed_refs(PackedRefs::DeletionsAndNonSymbolicUpdatesRemoveLooseSourceReference(
@@ -119,7 +129,9 @@ fn conflicting_creation_into_packed_refs() -> crate::Result {
119129
RefEdit {
120130
change: Change::Update {
121131
log: LogChange::default(),
122-
expected: PreviousValue::MustExistAndMatch(Target::Peeled(git_hash::Kind::Sha1.null())),
132+
expected: PreviousValue::MustExistAndMatch(Target::Peeled(hex_to_id(
133+
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
134+
))),
123135
new: Target::Peeled(git_hash::Kind::Sha1.null()),
124136
},
125137
name: "refs/A".try_into().expect("valid"),
@@ -204,5 +216,7 @@ fn conflicting_creation_into_packed_refs() -> crate::Result {
204216
0,
205217
"we deleted our only two packed refs and one loose ref with the same name"
206218
);
219+
assert!(!store.reflog_exists("refs/a")?);
220+
assert!(!store.reflog_exists("refs/A")?);
207221
Ok(())
208222
}

0 commit comments

Comments
 (0)