Skip to content

Commit

Permalink
Use CR instead of NUL character for changeset collisions
Browse files Browse the repository at this point in the history
  • Loading branch information
glandium committed May 14, 2024
1 parent 2301281 commit d63f748
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 4 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,20 @@ The default protocol is https, and the port can be omitted.

- `hg::tags:` becomes `hg://:tags`

Compatibility:
--------------

As of version 0.7, some corner cases in Mercurial repositories will generate
different git commits than with prior versions of git-cinnabar. This means
a fresh clone might have different git SHA-1s than existing clones, but this
doesn't impact the use of existing clones with newer versions of git-cinnabar.

Most repositories should remain non-affected by the change.

You can set the `cinnabar.compat` git configuration to `0.6` to keep the
previous behavior.


Experimental features:
----------------------

Expand Down
25 changes: 25 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4705,6 +4705,31 @@ pub fn check_enabled(checks: Checks) -> bool {
CHECKS.contains(checks)
}

bitflags! {
#[derive(Debug)]
pub struct Compat: i32 {
const CHANGESET_CONFLICT_NUL = 0x1;

const CINNABAR_0_6 = Compat::CHANGESET_CONFLICT_NUL.bits();
}
}

static COMPAT: Lazy<Compat> =
Lazy::new(
|| match get_config("compat").as_ref().map(|x| x.as_bytes()) {
Some(b"0.6") => Compat::CINNABAR_0_6,
Some(x) => {
warn!(target: "root", "Ignoring invalid value for compat: {}", x.as_bstr());
Compat::empty()
}
None => Compat::empty(),
},
);

pub fn has_compat(c: Compat) -> bool {
COMPAT.contains(c)
}

pub struct Experiments {
merge: bool,
similarity: CString,
Expand Down
8 changes: 6 additions & 2 deletions src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::util::{
Transpose,
};
use crate::xdiff::{apply, textdiff, PatchInfo};
use crate::{check_enabled, Checks};
use crate::{check_enabled, has_compat, Checks, Compat};

pub const REFS_PREFIX: &str = "refs/cinnabar/";
pub const REPLACE_REFS_PREFIX: &str = "refs/cinnabar/replace/";
Expand Down Expand Up @@ -1526,7 +1526,11 @@ fn store_changeset(
// we find a commit that doesn't map to another changeset.
match GitChangesetId::from_unchecked(commit_id).to_hg(store) {
Some(existing_hg_id) if existing_hg_id != changeset_id => {
raw_commit.push(b'\0');
if has_compat(Compat::CHANGESET_CONFLICT_NUL) {
raw_commit.push(b'\0');
} else {
raw_commit.push(b'\n');
}
}
_ => {
break commit_id;
Expand Down
49 changes: 47 additions & 2 deletions tests/conflicts.t
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,14 @@ changesets properly.
author nobody <> 1 +0000
committer nobody <> 1 +0000
b\x00 (no-eol) (esc)
b
$ git clone -q --mirror repo-git repo-mirror
$ git -C repo-mirror cinnabar rollback
$ git -C repo-mirror rev-list --count --all
3
$ git -C repo-mirror gc --prune=now
$ git -C repo-mirror fsck
warning in commit 36376d9e996376d02d00f72a8c7903cef9d6ea45: nulInCommit: NUL byte in the commit object body
Check that this round-trips properly.
Expand All @@ -90,6 +89,52 @@ Check that this round-trips properly.
o f92470d7f6966a39dfbced6a525fe81ebf5c37b9 default a


Trying again with git-cinnabar 0.6 compat.

$ git -c cinnabar.compat=0.6 -c fetch.prune=true clone -q hg::$REPO repo-git-0.6
$ git -C repo-git-0.6 cat-file -p $(git -C repo-git-0.6 cinnabar hg2git 636e60525868096cbdc961870493510558f41d2f)
tree 3683f870be446c7cc05ffaef9fa06415276e1828
parent 8b86a58578d5270969543e287634e3a2f122a338
author nobody <> 1 +0000
committer nobody <> 1 +0000

b (no-eol)
$ git -C repo-git-0.6 cat-file -p $(git -C repo-git-0.6 cinnabar hg2git 97b815fb8d45129120112766f8c69db8e93fbe8f)
tree 3683f870be446c7cc05ffaef9fa06415276e1828
parent 8b86a58578d5270969543e287634e3a2f122a338
author nobody <> 1 +0000
committer nobody <> 1 +0000

b\x00 (no-eol) (esc)

$ git clone -q --mirror repo-git-0.6 repo-mirror-0.6
$ git -C repo-mirror-0.6 cinnabar rollback
$ git -C repo-mirror-0.6 rev-list --count --all
3
$ git -C repo-mirror-0.6 gc --prune=now
$ git -C repo-mirror-0.6 fsck
warning in commit 36376d9e996376d02d00f72a8c7903cef9d6ea45: nulInCommit: NUL byte in the commit object body

Check that this round-trips properly.

$ hg init ${REPO}2-0.6
$ git -C repo-git-0.6 push hg::${REPO}2-0.6 "refs/remotes/origin/branches/foo/tip:refs/heads/branches/foo/tip" "refs/remotes/origin/branches/default/tip:refs/heads/branches/default/tip"
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 3 changesets with 2 changes to 2 files (+1 heads)
To hg::.*/conflicts.t/repo2-0.6 (re)
* [new branch] origin/branches/foo/tip -> branches/foo/tip
* [new branch] origin/branches/default/tip -> branches/default/tip

$ hg -R ${REPO}2-0.6 log -G --template '{node} {branch} {desc}'
o 97b815fb8d45129120112766f8c69db8e93fbe8f foo b
|
| o 636e60525868096cbdc961870493510558f41d2f default b
|/
o f92470d7f6966a39dfbced6a525fe81ebf5c37b9 default a
The obvious consequence is that without initial metadata, pushing this to a
mercurial repo will create a different changeset for the one in branch foo.
TODO: But we don't support creating new branches anyway, so we can't really
Expand Down

0 comments on commit d63f748

Please sign in to comment.