[go: up one dir, main page]

git2/
merge.rs

1use libc::c_uint;
2use std::marker;
3use std::mem;
4use std::str;
5
6use crate::call::Convert;
7use crate::util::Binding;
8use crate::{raw, Commit, FileFavor, Oid};
9
10/// A structure to represent an annotated commit, the input to merge and rebase.
11///
12/// An annotated commit contains information about how it was looked up, which
13/// may be useful for functions like merge or rebase to provide context to the
14/// operation.
15pub struct AnnotatedCommit<'repo> {
16    raw: *mut raw::git_annotated_commit,
17    _marker: marker::PhantomData<Commit<'repo>>,
18}
19
20/// Options to specify when merging.
21pub struct MergeOptions {
22    raw: raw::git_merge_options,
23}
24
25impl<'repo> AnnotatedCommit<'repo> {
26    /// Gets the commit ID that the given git_annotated_commit refers to
27    pub fn id(&self) -> Oid {
28        unsafe { Binding::from_raw(raw::git_annotated_commit_id(self.raw)) }
29    }
30
31    /// Get the refname that the given git_annotated_commit refers to
32    ///
33    /// Returns None if it is not valid utf8
34    pub fn refname(&self) -> Option<&str> {
35        str::from_utf8(self.refname_bytes()).ok()
36    }
37
38    /// Get the refname that the given git_annotated_commit refers to.
39    pub fn refname_bytes(&self) -> &[u8] {
40        unsafe { crate::opt_bytes(self, raw::git_annotated_commit_ref(&*self.raw)).unwrap() }
41    }
42}
43
44impl Default for MergeOptions {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl MergeOptions {
51    /// Creates a default set of merge options.
52    pub fn new() -> MergeOptions {
53        let mut opts = MergeOptions {
54            raw: unsafe { mem::zeroed() },
55        };
56        assert_eq!(unsafe { raw::git_merge_init_options(&mut opts.raw, 1) }, 0);
57        opts
58    }
59
60    fn flag(&mut self, opt: u32, val: bool) -> &mut MergeOptions {
61        if val {
62            self.raw.flags |= opt;
63        } else {
64            self.raw.flags &= !opt;
65        }
66        self
67    }
68
69    /// Detect file renames
70    pub fn find_renames(&mut self, find: bool) -> &mut MergeOptions {
71        self.flag(raw::GIT_MERGE_FIND_RENAMES as u32, find)
72    }
73
74    /// If a conflict occurs, exit immediately instead of attempting to continue
75    /// resolving conflicts
76    pub fn fail_on_conflict(&mut self, fail: bool) -> &mut MergeOptions {
77        self.flag(raw::GIT_MERGE_FAIL_ON_CONFLICT as u32, fail)
78    }
79
80    /// Do not write the REUC extension on the generated index
81    pub fn skip_reuc(&mut self, skip: bool) -> &mut MergeOptions {
82        self.flag(raw::GIT_MERGE_FAIL_ON_CONFLICT as u32, skip)
83    }
84
85    /// If the commits being merged have multiple merge bases, do not build a
86    /// recursive merge base (by merging the multiple merge bases), instead
87    /// simply use the first base.
88    pub fn no_recursive(&mut self, disable: bool) -> &mut MergeOptions {
89        self.flag(raw::GIT_MERGE_NO_RECURSIVE as u32, disable)
90    }
91
92    /// Similarity to consider a file renamed (default 50)
93    pub fn rename_threshold(&mut self, thresh: u32) -> &mut MergeOptions {
94        self.raw.rename_threshold = thresh;
95        self
96    }
97
98    ///  Maximum similarity sources to examine for renames (default 200).
99    /// If the number of rename candidates (add / delete pairs) is greater
100    /// than this value, inexact rename detection is aborted. This setting
101    /// overrides the `merge.renameLimit` configuration value.
102    pub fn target_limit(&mut self, limit: u32) -> &mut MergeOptions {
103        self.raw.target_limit = limit as c_uint;
104        self
105    }
106
107    /// Maximum number of times to merge common ancestors to build a
108    /// virtual merge base when faced with criss-cross merges.  When
109    /// this limit is reached, the next ancestor will simply be used
110    /// instead of attempting to merge it.  The default is unlimited.
111    pub fn recursion_limit(&mut self, limit: u32) -> &mut MergeOptions {
112        self.raw.recursion_limit = limit as c_uint;
113        self
114    }
115
116    /// Specify a side to favor for resolving conflicts
117    pub fn file_favor(&mut self, favor: FileFavor) -> &mut MergeOptions {
118        self.raw.file_favor = favor.convert();
119        self
120    }
121
122    fn file_flag(&mut self, opt: u32, val: bool) -> &mut MergeOptions {
123        if val {
124            self.raw.file_flags |= opt;
125        } else {
126            self.raw.file_flags &= !opt;
127        }
128        self
129    }
130
131    /// Create standard conflicted merge files
132    pub fn standard_style(&mut self, standard: bool) -> &mut MergeOptions {
133        self.file_flag(raw::GIT_MERGE_FILE_STYLE_MERGE as u32, standard)
134    }
135
136    /// Create diff3-style file
137    pub fn diff3_style(&mut self, diff3: bool) -> &mut MergeOptions {
138        self.file_flag(raw::GIT_MERGE_FILE_STYLE_DIFF3 as u32, diff3)
139    }
140
141    /// Condense non-alphanumeric regions for simplified diff file
142    pub fn simplify_alnum(&mut self, simplify: bool) -> &mut MergeOptions {
143        self.file_flag(raw::GIT_MERGE_FILE_SIMPLIFY_ALNUM as u32, simplify)
144    }
145
146    /// Ignore all whitespace
147    pub fn ignore_whitespace(&mut self, ignore: bool) -> &mut MergeOptions {
148        self.file_flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE as u32, ignore)
149    }
150
151    /// Ignore changes in amount of whitespace
152    pub fn ignore_whitespace_change(&mut self, ignore: bool) -> &mut MergeOptions {
153        self.file_flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE as u32, ignore)
154    }
155
156    /// Ignore whitespace at end of line
157    pub fn ignore_whitespace_eol(&mut self, ignore: bool) -> &mut MergeOptions {
158        self.file_flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL as u32, ignore)
159    }
160
161    /// Use the "patience diff" algorithm
162    pub fn patience(&mut self, patience: bool) -> &mut MergeOptions {
163        self.file_flag(raw::GIT_MERGE_FILE_DIFF_PATIENCE as u32, patience)
164    }
165
166    /// Take extra time to find minimal diff
167    pub fn minimal(&mut self, minimal: bool) -> &mut MergeOptions {
168        self.file_flag(raw::GIT_MERGE_FILE_DIFF_MINIMAL as u32, minimal)
169    }
170
171    /// Acquire a pointer to the underlying raw options.
172    pub unsafe fn raw(&self) -> *const raw::git_merge_options {
173        &self.raw as *const _
174    }
175}
176
177impl<'repo> Binding for AnnotatedCommit<'repo> {
178    type Raw = *mut raw::git_annotated_commit;
179    unsafe fn from_raw(raw: *mut raw::git_annotated_commit) -> AnnotatedCommit<'repo> {
180        AnnotatedCommit {
181            raw,
182            _marker: marker::PhantomData,
183        }
184    }
185    fn raw(&self) -> *mut raw::git_annotated_commit {
186        self.raw
187    }
188}
189
190impl<'repo> Drop for AnnotatedCommit<'repo> {
191    fn drop(&mut self) {
192        unsafe { raw::git_annotated_commit_free(self.raw) }
193    }
194}