Skip to content

Commit 0ae3791

Browse files
committed
Add the first test for an octopus merge
1 parent 3a1fe6a commit 0ae3791

File tree

5 files changed

+660
-0
lines changed

5 files changed

+660
-0
lines changed

Cargo.lock

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-merge/Cargo.toml

+26
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,31 @@ workspace = true
1414
[lib]
1515
doctest = false
1616

17+
[features]
18+
default = ["blob"]
19+
## Enable diffing of blobs using imara-diff, which also allows for a generic rewrite tracking implementation.
20+
blob = ["dep:imara-diff", "dep:gix-filter", "dep:gix-worktree", "dep:gix-path", "dep:gix-fs", "dep:gix-command", "dep:gix-tempfile", "dep:gix-trace"]
21+
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
22+
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"]
23+
1724
[dependencies]
25+
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
26+
gix-object = { version = "^0.44.0", path = "../gix-object" }
27+
gix-filter = { version = "^0.13.0", path = "../gix-filter", optional = true }
28+
gix-worktree = { version = "^0.36.0", path = "../gix-worktree", default-features = false, features = ["attributes"], optional = true }
29+
gix-command = { version = "^0.3.9", path = "../gix-command", optional = true }
30+
gix-path = { version = "^0.10.11", path = "../gix-path", optional = true }
31+
gix-fs = { version = "^0.11.3", path = "../gix-fs", optional = true }
32+
gix-tempfile = { version = "^14.0.0", path = "../gix-tempfile", optional = true }
33+
gix-trace = { version = "^0.1.10", path = "../gix-trace", optional = true }
34+
35+
thiserror = "1.0.63"
36+
imara-diff = { version = "0.1.7", optional = true }
37+
bstr = { version = "1.5.0", default-features = false }
38+
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
39+
40+
document-features = { version = "0.2.0", optional = true }
1841

42+
[package.metadata.docs.rs]
43+
all-features = true
44+
features = ["document-features"]

gix-merge/src/blob/mod.rs

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
use bstr::BString;
2+
use std::path::PathBuf;
3+
4+
///
5+
pub mod pipeline;
6+
7+
/// A way to classify a resource suitable for merging.
8+
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
9+
pub enum ResourceKind {
10+
/// Our side of the state.
11+
CurrentOrOurs,
12+
/// Their side of the state.
13+
OtherOrTheirs,
14+
/// The state of the common base of both ours and theirs.
15+
CommonAncestorOrBase,
16+
}
17+
18+
/// Define a driver program that merges
19+
///
20+
/// Some values are related to diffing, some are related to conversions.
21+
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
22+
pub enum BuiltinDriver {
23+
/// Perform a merge between text-sources such that conflicts are marked according to
24+
/// `merge.conflictStyle` in the Git configuration.
25+
///
26+
/// If any of the inputs, *base*, *ours* or *theirs* looks like non-text/binary,
27+
/// the [`Binary`](Self::Binary) driver will be used instead.
28+
///
29+
/// Also see [`TextDriverConflictStyle`].
30+
#[default]
31+
Text,
32+
/// Merge 'unmergable' content by choosing *ours* or *theirs*, without performing
33+
/// an actual merge.
34+
///
35+
/// Note that if the merge operation is for virtual ancestor (a merge for merge-bases),
36+
/// then *ours* will always be chosen.
37+
Binary,
38+
/// Merge text-sources and resolve conflicts by adding conflicting lines one after another,
39+
/// in random order, without adding conflict markers either.
40+
///
41+
/// This can be useful for files that change a lot, but will remain usable merely by adding
42+
/// all changed lines.
43+
Union,
44+
}
45+
46+
/// The way the built-in [text driver](BuiltinDriver::Text) will express merge conflicts in the
47+
/// resulting file.
48+
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
49+
pub enum TextDriverConflictStyle {
50+
/// Only show the zealously minified conflicting lines of the local changes and the incoming (other) changes,
51+
/// hiding the base version entirely.
52+
///
53+
/// ```
54+
/// line1-changed-by-both
55+
/// <<<<<<< local
56+
/// line2-to-be-changed-in-incoming
57+
/// =======
58+
/// line2-changed
59+
/// >>>>>>> incoming
60+
///```
61+
#[default]
62+
Merge,
63+
/// Show non-minimized hunks of local changes, the base, and the incoming (other) changes.
64+
///
65+
/// This mode does not hide any information.
66+
/// ```
67+
/// <<<<<<< local
68+
/// line1-changed-by-both
69+
/// line2-to-be-changed-in-incoming
70+
/// ||||||| 9a8d80c
71+
/// line1-to-be-changed-by-both
72+
/// line2-to-be-changed-in-incoming
73+
/// =======
74+
/// line1-changed-by-both
75+
/// line2-changed
76+
/// >>>>>>> incoming
77+
///```
78+
Diff3,
79+
/// Like [`Diff3](Self::Diff3), but will show *minimized* hunks of local change and the incoming (other) changes,
80+
/// as well as non-minimized hunks of the base.
81+
///
82+
/// ```
83+
/// line1-changed-by-both
84+
/// <<<<<<< local
85+
/// line2-to-be-changed-in-incoming
86+
/// ||||||| 9a8d80c
87+
/// line1-to-be-changed-by-both
88+
/// line2-to-be-changed-in-incoming
89+
/// =======
90+
/// line2-changed
91+
/// >>>>>>> incoming
92+
/// ```
93+
ZealousDiff3,
94+
}
95+
96+
impl BuiltinDriver {
97+
/// Return the name of this instance.
98+
pub fn as_str(&self) -> &str {
99+
match self {
100+
BuiltinDriver::Text => "text",
101+
BuiltinDriver::Binary => "binary",
102+
BuiltinDriver::Union => "union",
103+
}
104+
}
105+
106+
/// Get all available built-in drivers.
107+
pub fn all() -> &'static [Self] {
108+
&[BuiltinDriver::Text, BuiltinDriver::Binary, BuiltinDriver::Union]
109+
}
110+
111+
/// Try to match one of our variants to `name`, case-sensitive, and return its instance.
112+
pub fn by_name(name: &str) -> Option<Self> {
113+
Self::all().iter().find(|variant| variant.as_str() == name).copied()
114+
}
115+
}
116+
117+
/// Define a driver program that merges
118+
///
119+
/// Some values are related to diffing, some are related to conversions.
120+
#[derive(Default, Debug, Clone, PartialEq, Eq)]
121+
pub struct Driver {
122+
/// The name of the driver, as referred to by `[merge "name"]` in the git configuration.
123+
pub name: BString,
124+
/// The human-readable version of `name`, only to be used for displaying driver-information to the user.
125+
pub display_name: BString,
126+
/// The command to execute to perform the merge entirely like `<command> %O %A %B %L %P %S %X %Y`.
127+
///
128+
/// * **%O**
129+
/// - the common ancestor version, or *base*.
130+
/// * **%A**
131+
/// - the current version, or *ours*.
132+
/// * **%B**
133+
/// - the other version, or *theirs*.
134+
/// * **%L**
135+
/// - The conflict-marker size as positive number.
136+
/// * **%P**
137+
/// - The path in which the merged result will be stored.
138+
/// * **%S**
139+
/// - The conflict-label for the common ancestor or *base*.
140+
/// * **%X**
141+
/// - The conflict-label for the current version or *ours*.
142+
/// * **%Y**
143+
/// - The conflict-label for the other version or *theirs*.
144+
///
145+
/// Note that conflict-labels are behind the conflict markers, to annotate them
146+
pub command: BString,
147+
/// If `true`, this is the `name` of the driver to use when a virtual-merge-base is created, as a merge of all
148+
/// available merge-bases if there are more than one.
149+
///
150+
/// This value can also be special built-in drivers named `text`, `binary` or `union`. Note that user-defined
151+
/// drivers with the same name will be preferred over built-in ones, but only for files whose git attributes
152+
/// specified the driver by *name*.
153+
pub recursive: Option<BString>,
154+
}
155+
156+
/// A conversion pipeline to take an object or path from what's stored in Git to what can be merged, while
157+
/// following the guidance of git-attributes at the respective path to learn how the merge should be performed.
158+
///
159+
/// Depending on the source, different conversions are performed:
160+
///
161+
/// * `worktree on disk` -> `object for storage in git`
162+
/// * `object` -> `possibly renormalized object`
163+
/// - Renormalization means that the `object` is converted to what would be checked out into the work-tree,
164+
/// just to turn it back into an object.
165+
#[derive(Clone)]
166+
pub struct Pipeline {
167+
/// A way to read data directly from the worktree.
168+
pub roots: pipeline::WorktreeRoots,
169+
/// A pipeline to convert objects from the worktree to Git, and also from Git to the worktree, and back to Git.
170+
pub filter: gix_filter::Pipeline,
171+
/// Options affecting the way we read files.
172+
pub options: pipeline::Options,
173+
/// All available merge drivers.
174+
///
175+
/// They are referenced in git-attributes by name, and we hand out indices into this array.
176+
drivers: Vec<Driver>,
177+
/// Pre-configured attributes to obtain additional merge-related information.
178+
attrs: gix_filter::attributes::search::Outcome,
179+
/// A buffer to produce disk-accessible paths from worktree roots.
180+
path: PathBuf,
181+
}

0 commit comments

Comments
 (0)