mirror of
https://github.com/git/git.git
synced 2026-08-08 17:11:48 +00:00
During a conflicted merge, rebase, or cherry-pick, 'git add -u' is a handy way to add modified paths to the index. However, '-u' indiscriminately adds all modified tracked paths, including unmerged paths that may still contain unresolved conflict markers. It also adds tracked files modified in the worktree that are not involved in the ongoing merge. The latter is not a huge problem for "git rebase", which refuses to start with any local changes, but is a problem for "git merge", which is often run with local changes in maintainer workflows. Introduce 'git add --resolved' to add only unmerged paths, limited by an optional pathspec, where no conflict markers remain in the working tree. Before modifying the index, scan unmerged regular files for leftover conflict markers using a new helper, has_conflict_markers(), defined in merge-ll.c in terms of the is_conflict_marker_line() helper we introduced earlier. If any unmerged path still contains conflict markers, show an error listing the conflicted paths and abort without updating the index. Otherwise, add these unmerged paths that do not have conflict markers to the index. Note that unmerged paths without conflict markers (such as binary files and deletions) are added as resolved using add_file_to_index() and remove_file_from_index_with_flags(). Tracked files that were not in a conflicted state are ignored by '--resolved'. Signed-off-by: Junio C Hamano <gitster@pobox.com>
117 lines
3.4 KiB
C
117 lines
3.4 KiB
C
/*
|
||
* Low level 3-way in-core file merge.
|
||
*/
|
||
|
||
#ifndef LL_MERGE_H
|
||
#define LL_MERGE_H
|
||
|
||
#include "xdiff/xdiff.h"
|
||
|
||
/**
|
||
*
|
||
* Calling sequence:
|
||
* ----------------
|
||
*
|
||
* - Prepare a `struct ll_merge_options` to record options.
|
||
* If you have no special requests, skip this and pass `NULL`
|
||
* as the `opts` parameter to use the default options.
|
||
*
|
||
* - Allocate an mmbuffer_t variable for the result.
|
||
*
|
||
* - Allocate and fill variables with the file's original content
|
||
* and two modified versions (using `read_mmfile`, for example).
|
||
*
|
||
* - Call `ll_merge()`.
|
||
*
|
||
* - Read the merged content from `result_buf.ptr` and `result_buf.size`.
|
||
*
|
||
* - Release buffers when finished. A simple
|
||
* `free(ancestor.ptr); free(ours.ptr); free(theirs.ptr);
|
||
* free(result_buf.ptr);` will do.
|
||
*
|
||
* If the modifications do not merge cleanly, `ll_merge` will return a
|
||
* nonzero value and `result_buf` will generally include a description of
|
||
* the conflict bracketed by markers such as the traditional `<<<<<<<`
|
||
* and `>>>>>>>`.
|
||
*
|
||
* The `ancestor_label`, `our_label`, and `their_label` parameters are
|
||
* used to label the different sides of a conflict if the merge driver
|
||
* supports this.
|
||
*/
|
||
|
||
|
||
struct index_state;
|
||
|
||
/**
|
||
* This describes the set of options the calling program wants to affect
|
||
* the operation of a low-level (single file) merge.
|
||
*/
|
||
struct ll_merge_options {
|
||
|
||
/**
|
||
* Behave as though this were part of a merge between common ancestors in
|
||
* a recursive merge (merges of binary files may need to be handled
|
||
* differently in such cases, for example). If a helper program is
|
||
* specified by the `[merge "<driver>"] recursive` configuration, it will
|
||
* be used.
|
||
*/
|
||
unsigned virtual_ancestor : 1;
|
||
|
||
/**
|
||
* Resolve local conflicts automatically in favor of one side or the other
|
||
* (as in 'git merge-file' `--ours`/`--theirs`/`--union`). Can be `0`,
|
||
* `XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`,
|
||
* or `XDL_MERGE_FAVOR_UNION`.
|
||
*/
|
||
unsigned variant : 2;
|
||
|
||
/**
|
||
* Resmudge and clean the "base", "theirs" and "ours" files before merging.
|
||
* Use this when the merge is likely to have overlapped with a change in
|
||
* smudge/clean or end-of-line normalization rules.
|
||
*/
|
||
unsigned renormalize : 1;
|
||
|
||
/**
|
||
* Increase the length of conflict markers so that nested conflicts
|
||
* can be differentiated.
|
||
*/
|
||
unsigned extra_marker_size;
|
||
|
||
/* Override the global conflict style. */
|
||
int conflict_style;
|
||
|
||
/* Extra xpparam_t flags as defined in xdiff/xdiff.h. */
|
||
long xdl_opts;
|
||
};
|
||
|
||
#define LL_MERGE_OPTIONS_INIT { .conflict_style = -1 }
|
||
|
||
enum ll_merge_result {
|
||
LL_MERGE_ERROR = -1,
|
||
LL_MERGE_OK = 0,
|
||
LL_MERGE_CONFLICT,
|
||
LL_MERGE_BINARY_CONFLICT,
|
||
};
|
||
|
||
/**
|
||
* Perform a three-way single-file merge in core. This is a thin wrapper
|
||
* around `xdl_merge` that takes the path and any merge backend specified in
|
||
* `.gitattributes` or `.git/info/attributes` into account.
|
||
* Returns 0 for a clean merge.
|
||
*/
|
||
enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
|
||
const char *path,
|
||
mmfile_t *ancestor, const char *ancestor_label,
|
||
mmfile_t *ours, const char *our_label,
|
||
mmfile_t *theirs, const char *their_label,
|
||
struct index_state *istate,
|
||
const struct ll_merge_options *opts);
|
||
|
||
int ll_merge_marker_size(struct index_state *istate, const char *path);
|
||
int is_conflict_marker_line(const char *line, unsigned long len, int marker_size);
|
||
int has_conflict_markers(struct index_state *istate, const char *path);
|
||
void reset_merge_attributes(void);
|
||
|
||
#endif
|