Browse Source
* jn/merge-renormalize: merge-recursive --renormalize rerere: never renormalize rerere: migrate to parse-options API t4200 (rerere): modernize style ll-merge: let caller decide whether to renormalize ll-merge: make flag easier to populate Documentation/technical: document ll_merge merge-trees: let caller decide whether to renormalize merge-trees: push choice to renormalize away from low level t6038 (merge.renormalize): check that it can be turned off t6038 (merge.renormalize): try checkout -m and cherry-pick t6038 (merge.renormalize): style nitpicks Don't expand CRLFs when normalizing text during merge Try normalizing files to avoid delete/modify conflicts when merging Avoid conflicts when merging branches with mixed normalization Conflicts: builtin/rerere.c t/t4200-rerere.shmaint
Junio C Hamano
15 years ago
18 changed files with 785 additions and 170 deletions
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
merge API |
||||
========= |
||||
|
||||
The merge API helps a program to reconcile two competing sets of |
||||
improvements to some files (e.g., unregistered changes from the work |
||||
tree versus changes involved in switching to a new branch), reporting |
||||
conflicts if found. The library called through this API is |
||||
responsible for a few things. |
||||
|
||||
* determining which trees to merge (recursive ancestor consolidation); |
||||
|
||||
* lining up corresponding files in the trees to be merged (rename |
||||
detection, subtree shifting), reporting edge cases like add/add |
||||
and rename/rename conflicts to the user; |
||||
|
||||
* performing a three-way merge of corresponding files, taking |
||||
path-specific merge drivers (specified in `.gitattributes`) |
||||
into account. |
||||
|
||||
Low-level (single file) merge |
||||
----------------------------- |
||||
|
||||
`ll_merge`:: |
||||
|
||||
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. |
||||
|
||||
The caller: |
||||
|
||||
1. allocates an mmbuffer_t variable for the result; |
||||
2. allocates and fills variables with the file's original content |
||||
and two modified versions (using `read_mmfile`, for example); |
||||
3. calls ll_merge(); |
||||
4. reads the output from result_buf.ptr and result_buf.size; |
||||
5. releases buffers when finished (free(ancestor.ptr); free(ours.ptr); |
||||
free(theirs.ptr); free(result_buf.ptr);). |
||||
|
||||
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. |
||||
|
||||
The `flag` parameter is a bitfield: |
||||
|
||||
- The `LL_OPT_VIRTUAL_ANCESTOR` bit indicates whether this is an |
||||
internal merge to consolidate ancestors for a recursive merge. |
||||
|
||||
- The `LL_OPT_FAVOR_MASK` bits allow local conflicts to be automatically |
||||
resolved in favor of one side or the other (as in 'git merge-file' |
||||
`--ours`/`--theirs`/`--union`). |
||||
They can be populated by `create_ll_flag`, whose argument can be |
||||
`XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`, or |
||||
`XDL_MERGE_FAVOR_UNION`. |
||||
|
||||
Everything else |
||||
--------------- |
||||
|
||||
Talk about <merge-recursive.h> and merge_file(): |
||||
|
||||
- merge_trees() to merge with rename detection |
||||
- merge_recursive() for ancestor consolidation |
||||
- try_merge_command() for other strategies |
||||
- conflict format |
||||
- merge options |
||||
|
||||
(Daniel, Miklos, Stephan, JC) |
@ -0,0 +1,189 @@
@@ -0,0 +1,189 @@
|
||||
#!/bin/sh |
||||
|
||||
test_description='CRLF merge conflict across text=auto change |
||||
|
||||
* [master] remove .gitattributes |
||||
! [side] add line from b |
||||
-- |
||||
+ [side] add line from b |
||||
* [master] remove .gitattributes |
||||
* [master^] add line from a |
||||
* [master~2] normalize file |
||||
*+ [side^] Initial |
||||
' |
||||
|
||||
. ./test-lib.sh |
||||
|
||||
test_expect_success setup ' |
||||
git config core.autocrlf false && |
||||
|
||||
echo first line | append_cr >file && |
||||
echo first line >control_file && |
||||
echo only line >inert_file && |
||||
|
||||
git add file control_file inert_file && |
||||
test_tick && |
||||
git commit -m "Initial" && |
||||
git tag initial && |
||||
git branch side && |
||||
|
||||
echo "* text=auto" >.gitattributes && |
||||
touch file && |
||||
git add .gitattributes file && |
||||
test_tick && |
||||
git commit -m "normalize file" && |
||||
|
||||
echo same line | append_cr >>file && |
||||
echo same line >>control_file && |
||||
git add file control_file && |
||||
test_tick && |
||||
git commit -m "add line from a" && |
||||
git tag a && |
||||
|
||||
git rm .gitattributes && |
||||
rm file && |
||||
git checkout file && |
||||
test_tick && |
||||
git commit -m "remove .gitattributes" && |
||||
git tag c && |
||||
|
||||
git checkout side && |
||||
echo same line | append_cr >>file && |
||||
echo same line >>control_file && |
||||
git add file control_file && |
||||
test_tick && |
||||
git commit -m "add line from b" && |
||||
git tag b && |
||||
|
||||
git checkout master |
||||
' |
||||
|
||||
test_expect_success 'set up fuzz_conflict() helper' ' |
||||
fuzz_conflict() { |
||||
sed -e "s/^\([<>=]......\) .*/\1/" "$@" |
||||
} |
||||
' |
||||
|
||||
test_expect_success 'Merge after setting text=auto' ' |
||||
cat <<-\EOF >expected && |
||||
first line |
||||
same line |
||||
EOF |
||||
|
||||
git config merge.renormalize true && |
||||
git rm -fr . && |
||||
rm -f .gitattributes && |
||||
git reset --hard a && |
||||
git merge b && |
||||
test_cmp expected file |
||||
' |
||||
|
||||
test_expect_success 'Merge addition of text=auto' ' |
||||
cat <<-\EOF >expected && |
||||
first line |
||||
same line |
||||
EOF |
||||
|
||||
git config merge.renormalize true && |
||||
git rm -fr . && |
||||
rm -f .gitattributes && |
||||
git reset --hard b && |
||||
git merge a && |
||||
test_cmp expected file |
||||
' |
||||
|
||||
test_expect_success 'Detect CRLF/LF conflict after setting text=auto' ' |
||||
q_to_cr <<-\EOF >expected && |
||||
<<<<<<< |
||||
first line |
||||
same line |
||||
======= |
||||
first lineQ |
||||
same lineQ |
||||
>>>>>>> |
||||
EOF |
||||
|
||||
git config merge.renormalize false && |
||||
rm -f .gitattributes && |
||||
git reset --hard a && |
||||
test_must_fail git merge b && |
||||
fuzz_conflict file >file.fuzzy && |
||||
test_cmp expected file.fuzzy |
||||
' |
||||
|
||||
test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' ' |
||||
q_to_cr <<-\EOF >expected && |
||||
<<<<<<< |
||||
first lineQ |
||||
same lineQ |
||||
======= |
||||
first line |
||||
same line |
||||
>>>>>>> |
||||
EOF |
||||
|
||||
git config merge.renormalize false && |
||||
rm -f .gitattributes && |
||||
git reset --hard b && |
||||
test_must_fail git merge a && |
||||
fuzz_conflict file >file.fuzzy && |
||||
test_cmp expected file.fuzzy |
||||
' |
||||
|
||||
test_expect_failure 'checkout -m after setting text=auto' ' |
||||
cat <<-\EOF >expected && |
||||
first line |
||||
same line |
||||
EOF |
||||
|
||||
git config merge.renormalize true && |
||||
git rm -fr . && |
||||
rm -f .gitattributes && |
||||
git reset --hard initial && |
||||
git checkout a -- . && |
||||
git checkout -m b && |
||||
test_cmp expected file |
||||
' |
||||
|
||||
test_expect_failure 'checkout -m addition of text=auto' ' |
||||
cat <<-\EOF >expected && |
||||
first line |
||||
same line |
||||
EOF |
||||
|
||||
git config merge.renormalize true && |
||||
git rm -fr . && |
||||
rm -f .gitattributes file && |
||||
git reset --hard initial && |
||||
git checkout b -- . && |
||||
git checkout -m a && |
||||
test_cmp expected file |
||||
' |
||||
|
||||
test_expect_failure 'cherry-pick patch from after text=auto was added' ' |
||||
append_cr <<-\EOF >expected && |
||||
first line |
||||
same line |
||||
EOF |
||||
|
||||
git config merge.renormalize true && |
||||
git rm -fr . && |
||||
git reset --hard b && |
||||
test_must_fail git cherry-pick a >err 2>&1 && |
||||
grep "[Nn]othing added" err && |
||||
test_cmp expected file |
||||
' |
||||
|
||||
test_expect_success 'Test delete/normalize conflict' ' |
||||
git checkout -f side && |
||||
git rm -fr . && |
||||
rm -f .gitattributes && |
||||
git reset --hard initial && |
||||
git rm file && |
||||
git commit -m "remove file" && |
||||
git checkout master && |
||||
git reset --hard a^ && |
||||
git merge side |
||||
' |
||||
|
||||
test_done |
Loading…
Reference in new issue