Commit graph

315 commits

Author SHA1 Message Date
Elijah Newren
a99b7f2256 merge-recursive: Small cleanups for conflict_rename_rename_1to2
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:38 -07:00
Elijah Newren
c52ff85d97 merge-recursive: Fix rename/rename(1to2) resolution for virtual merge base
When renaming one file to two files, we really should be doing a content
merge.  Also, in the recursive case, undoing the renames and recording the
merged file in the index with the source of the rename (while deleting
both destinations) allows the renames to be re-detected in the
non-recursive merge and will result in fewer spurious conflicts.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:38 -07:00
Elijah Newren
6bdaead1e5 merge-recursive: Introduce a merge_file convenience function
merge_file previously required diff_filespec arguments, but all callers
only had sha1s and modes.  Rename merge_file to merge_file_1 and introduce
a new merge_file convenience function which takes the sha1s and modes and
creates the temporary diff_filespec variables needed to call merge_file_1.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:38 -07:00
Elijah Newren
ec61d14963 merge-recursive: Fix modify/delete resolution in the recursive case
When o->call_depth>0 and we have conflicts, we try to find "middle ground"
when creating the virtual merge base.  In the case of content conflicts,
this can be done by doing a three-way content merge and using the result.
In all parts where the three-way content merge is clean, it is the correct
middle ground, and in parts where it conflicts there is no middle ground
but the conflict markers provide a good compromise since they are unlikely
to accidentally match any further changes.

In the case of a modify/delete conflict, we cannot do the same thing.
Accepting either endpoint as the resolution for the virtual merge base
runs the risk that when handling the non-recursive case we will silently
accept one person's resolution over another without flagging a conflict.
In this case, the closest "middle ground" we have is actually the merge
base of the candidate merge bases.  (We could alternatively attempt a
three way content merge using an empty file in place of the deleted file,
but that seems to be more work than necessary.)

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:38 -07:00
Elijah Newren
5b448b8530 merge-recursive: When we detect we can skip an update, actually skip it
In 882fd11 (merge-recursive: Delay content merging for renames 2010-09-20),
there was code that checked for whether we could skip updating a file in
the working directory, based on whether the merged version matched the
current working copy.  Due to the desire to handle directory/file conflicts
that were resolvable, that commit deferred content merging by first
updating the index with the unmerged entries and then moving the actual
merging (along with the skip-the-content-update check) to another function
that ran later in the merge process.  As part moving the content merging
code, a bug was introduced such that although the message about skipping
the update would be printed (whenever GIT_MERGE_VERBOSITY was sufficiently
high), the file would be unconditionally updated in the working copy
anyway.

When we detect that the file does not need to be updated in the working
copy, update the index appropriately and then return early before updating
the working copy.

Note that there was a similar change in b2c8c0a (merge-recursive: When we
detect we can skip an update, actually skip it 2011-02-28), but it was
reverted by 6db4105 (Revert "Merge branch 'en/merge-recursive'"
2011-05-19) since it did not fix both of the relevant types of unnecessary
update breakages and, worse, it made use of some band-aids that caused
other problems.  The reason this change works is due to the changes earlier
in this series to (a) record_df_conflict_files instead of just unlinking
them early, (b) allowing make_room_for_path() to remove D/F entries,
(c) the splitting of update_stages_and_entry() to have its functionality
called at different points, and (d) making the pathnames of the files
involved in the merge available to merge_content().

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
3c217c077a merge-recursive: Provide more info in conflict markers with file renames
Whenever there are merge conflicts in file contents, we would mark the
different sides of the conflict with the two branches being merged.
However, when there is a rename involved as well, the branchname is not
sufficient to specify where the conflicting content came from.  In such
cases, mark the two sides of the conflict with branchname:filename rather
than just branchname.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
4f66dade81 merge-recursive: Cleanup and consolidation of rename_conflict_info
The consolidation of process_entry() and process_df_entry() allows us to
consolidate more code paths concerning rename conflicts, and to do
a few additional related cleanups.  It also means we are using
rename_df_conflict_info in some cases where there is no D/F conflict;
rename it to rename_conflict_info.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
edd2faf52e merge-recursive: Consolidate process_entry() and process_df_entry()
The whole point of adding process_df_entry() was to ensure that files of
D/F conflicts were processed after paths under the corresponding
directory.  However, given that the entries are in sorted order, all we
need to do is iterate through them in reverse order to achieve the same
effect.  That lets us remove some duplicated code, and lets us keep
track of one less thing as we read the code ("do we need to make sure
this is processed before process_df_entry() or do we need to defer it
until then?").

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
51931bf08e merge-recursive: Improve handling of rename target vs. directory addition
When dealing with file merging and renames and D/F conflicts and possible
criss-cross merges (how's that for a corner case?), we did not do a
thorough job ensuring the index and working directory had the correct
contents.   Fix the logic in merge_content() to handle this.  Also,
correct some erroneous tests in t6022 that were expecting the wrong number
of unmerged index entries.  These changes fix one of the tests in t6042
(and almost fix another one from t6042 as well).

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
7769a75e96 merge-recursive: Add comments about handling rename/add-source cases
There are a couple of places where changes are needed to for situations
involving rename/add-source issues.  Add comments about the needed changes
(and existing bugs) until git has been enabled to detect such cases.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
0a6b87126e merge-recursive: Make dead code for rename/rename(2to1) conflicts undead
The code for rename_rename_2to1 conflicts (two files both being renamed to
the same filename) was dead since the rename/add path was always being
independently triggered for each of the renames instead.  Further,
reviving the dead code showed that it was inherently buggy and would
always segfault -- among a few other bugs.

Move the else-if branch for the rename/rename block before the rename/add
block to make sure it is checked first, and fix up the rename/rename(2to1)
code segments to make it handle most cases.  Work is still needed to
handle higher dimensional corner cases such as rename/rename/modify/modify
issues.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:37 -07:00
Elijah Newren
531357a4cc merge-recursive: Fix deletion of untracked file in rename/delete conflicts
In the recursive case (o->call_depth > 0), we do not modify the working
directory.  However, when o->call_depth==0, file renames can mean we need
to delete the old filename from the working copy.  Since there have been
lots of changes and mistakes here, let's go through the details.  Let's
start with a simple explanation of what we are trying to achieve:

  Original goal: If a file is renamed on the side of history being merged
  into head, the filename serving as the source of that rename needs to be
  removed from the working directory.

The path to getting the above statement implemented in merge-recursive took
several steps.  The relevant bits of code may be instructive to keep in
mind for the explanation, especially since an English-only description
involves double negatives that are hard to follow.  These bits of code are:
  int remove_file(..., const char *path, int no_wd)
  {
    ...
    int update_working_directory = !o->call_depth && !no_wd;
and
  remove_file(o, 1, ren1_src, <expression>);
Where the choice for <expression> has morphed over time:

65ac6e9 (merge-recursive: adjust to loosened "working file clobbered"
check 2006-10-27), introduced the "no_wd" parameter to remove_file() and
used "1" for <expression>.  This meant ren1_src was never deleted, leaving
it around in the working copy.

In 8371234 (Remove uncontested renamed files during merge. 2006-12-13),
<expression> was changed to "index_only" (where index_only ==
!!o->call_depth; see b7fa51da).   This was equivalent to using "0" for
<expression> (due to the early logic in remove_file), and is orthogonal to
the condition we actually want to check at this point; it resulted in the
source file being removed except when index_only was false.  This was
problematic because the file could have been renamed on the side of history
including head, in which case ren1_src could correspond to an untracked
file that should not be deleted.

In 183d797 (Keep untracked files not involved in a merge. 2007-02-04),
<expression> was changed to "index_only || stage == 3".  While this gives
correct behavior, the "index_only ||" portion of <expression> is
unnecessary and makes the code slightly harder to follow.

There were also two further changes to this expression, though without
any change in behavior.  First in b7fa51d (merge-recursive: get rid of the
index_only global variable 2008-09-02), it was changed to "o->call_depth
|| stage == 3".  (index_only == !!o->call_depth).  Later, in 41d70bd6
(merge-recursive: Small code clarification -- variable name and comments),
this was changed to "o->call_depth || renamed_stage == 2" (where stage was
renamed to other_stage and renamed_stage == other_stage ^ 1).

So we ended with <expression> being "o->call_depth || renamed_stage == 2".
But the "o->call_depth ||" piece was unnecessary.  We can remove it,
leaving us with <expression> being "renamed_stage == 2".  This doesn't
change behavior at all, but it makes the code clearer.  Which is good,
because it's about to get uglier.

  Corrected goal: If a file is renamed on the side of history being merged
  into head, the filename serving as the source of that rename needs to be
  removed from the working directory *IF* that file is tracked in head AND
  the file tracked in head is related to the original file.

Note that the only difference between the original goal and the corrected
goal is the two extra conditions added at the end.  The first condition is
relevant in a rename/delete conflict.  If the file was deleted on the
HEAD side of the merge and an untracked file of the same name was added to
the working copy, then without that extra condition the untracked file
will be erroneously deleted.  This changes <expression> to "renamed_stage
== 2 || !was_tracked(ren1_src)".

The second additional condition is relevant in two cases.

The first case the second condition can occur is when a file is deleted
and a completely different file is added with the same name.  To my
knowledge, merge-recursive has no mechanism for detecting deleted-and-
replaced-by-different-file cases, so I am simply punting on this
possibility.

The second case for the second condition to occur is when there is a
rename/rename/add-source conflict.  That is, when the original file was
renamed on both sides of history AND the original filename is being
re-used by some unrelated (but tracked) content.  This case also presents
some additional difficulties for us since we cannot currently detect these
rename/rename/add-source conflicts; as long as the rename detection logic
"optimizes" by ignoring filenames that are present at both ends of the
diff, these conflicts will go unnoticed.  However, rename/rename conflicts
are handled by an entirely separate codepath not being discussed here, so
this case is not relevant for the line of code under consideration.

In summary:
  Change <expression> from "o->call_depth || renamed_stage == 2" to
  "renamed_stage == 2 || !was_tracked(ren1_src)", in order to remove
  unnecessary code and avoid deleting untracked files.

96 lines of explanation in the changelog to describe a one-line fix...

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:36 -07:00
Elijah Newren
b8ddf16424 merge-recursive: Split update_stages_and_entry; only update stages at end
Instead of having the process_renames logic update the stages in the index
for the rename destination, have the index updated after process_entry or
process_df_entry.  This will also allow us to have process_entry determine
whether a file was tracked and existed in the working copy before the
merge started.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:36 -07:00
Elijah Newren
ed0148a520 merge-recursive: Allow make_room_for_path() to remove D/F entries
If there were several files conflicting below a directory corresponding
to a D/F conflict, and the file of that D/F conflict is in the way, we
want it to be removed.  Since files of D/F conflicts are handled last,
they can be reinstated later and possibly with a new unique name.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:36 -07:00
Elijah Newren
aacb82de3f merge-recursive: Split was_tracked() out of would_lose_untracked()
Checking whether a filename was part of stage 0 or stage 2 is code that we
would like to be able to call from a few other places without also
lstat()-ing the file to see if it exists in the working copy.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:35 -07:00
Elijah Newren
70cc3d36eb merge-recursive: Save D/F conflict filenames instead of unlinking them
Rename make_room_for_directories_of_df_conflicts() to
record_df_conflict_files() to reflect the change in functionality.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:35 -07:00
Elijah Newren
f2507b4e0e merge-recursive: Fix code checking for D/F conflicts still being present
Previously, we were using lstat() to determine if a directory was still
present after a merge (and thus in the way of adding a file).  We should
have been using lstat() only to determine if untracked directories were in
the way (and then only when necessary to check for untracked directories);
we should instead using the index to determine if there is a tracked
directory in the way.  Create a new function to do this and use it to
replace the existing checks for directories being in the way.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:35 -07:00
Elijah Newren
f0fd4d05e8 merge-recursive: Fix sorting order and directory change assumptions
We cannot assume that directory/file conflicts will appear in sorted
order; for example, 'letters.txt' comes between 'letters' and
'letters/file'.

Thanks to Johannes for a pointer about qsort stability issues with
Windows and suggested code change.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
7b1c610f84 merge-recursive: Fix recursive case with D/F conflict via add/add conflict
When a D/F conflict is introduced via an add/add conflict, when
o->call_depth > 0 we need to ensure that the higher stage entry from the
base stage is removed.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
0b30e81251 merge-recursive: Avoid working directory changes during recursive case
make_room_for_directories_of_df_conflicts() is about making sure necessary
working directory changes can succeed.  When o->call_depth > 0 (i.e. the
recursive case), we do not want to make any working directory changes so
this function should be skipped.

Note that make_room_for_directories_of_df_conflicts() is broken as has
been pointed out by Junio; it should NOT be unlinking files.  What it
should do is keep track of files that could be unlinked if a directory
later needs to be written in their place.  However, that work also is only
relevant in the non-recursive case, so this change is helpful either way.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
3d6b8e884c merge-recursive: Remember to free generated unique path names
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
650467cf89 merge-recursive: Consolidate different update_stages functions
We are only calling update_stages_options() one way really, so we can
consolidate the slightly different variants into one and remove some
parameters whose values are always the same.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
0c05942087 merge-recursive: Mark some diff_filespec struct arguments const
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
abafc88e76 merge-recursive: Correct a comment
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Elijah Newren
c43ba42e8d merge-recursive: Make BUG message more legible by adding a newline
Hopefully no one ever hits this error except when making large changes to
merge-recursive.c and debugging...

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-14 14:19:34 -07:00
Tay Ray Chuan
8c912eea94 teach --histogram to diff
Port JGit's HistogramDiff algorithm over to C. Rough numbers (TODO) show
that it is faster than its --patience cousin, as well as the default
Meyers algorithm.

The implementation has been reworked to use structs and pointers,
instead of bitmasks, thus doing away with JGit's 2^28 line limit.

We also use xdiff's default hash table implementation (xdl_hash_bits()
with XDL_HASHLONG()) for convenience.

Signed-off-by: Tay Ray Chuan <rctay89@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-07-12 09:29:20 -07:00
Junio C Hamano
b3c89315a3 Merge branch 'jc/rename-degrade-cc-to-c' into maint
* jc/rename-degrade-cc-to-c:
  diffcore-rename: fall back to -C when -C -C busts the rename limit
  diffcore-rename: record filepair for rename src
  diffcore-rename: refactor "too many candidates" logic
  builtin/diff.c: remove duplicated call to diff_result_code()
2011-05-31 12:00:02 -07:00
Junio C Hamano
6db41050a3 Revert "Merge branch 'en/merge-recursive'"
As the band-aid to merge-recursive seems to regress complex merges in an
unpleasant way.  The merge-recursive implementation needs to be rewritten
in such a way that it resolves renames and D/F conflicts entirely in-core
and not to touch working tree at all while doing so. But in the meantime,
this reverts commit ac9666f84 that merged the topic in its entirety.
2011-05-19 20:33:38 -07:00
Junio C Hamano
2f80de956f Merge branch 'maint'
* maint:
  add, merge, diff: do not use strcasecmp to compare config variable names
2011-05-14 20:44:09 -07:00
Jonathan Nieder
8c2be75fe1 add, merge, diff: do not use strcasecmp to compare config variable names
The config machinery already makes section and variable names
lowercase when parsing them, so using strcasecmp for comparison just
feels wasteful.  No noticeable change intended.

Noticed-by: Jay Soffian <jaysoffian@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-05-14 18:53:39 -07:00
Junio C Hamano
1273738f05 Merge branch 'nd/struct-pathspec'
* nd/struct-pathspec:
  pathspec: rename per-item field has_wildcard to use_wildcard
  Improve tree_entry_interesting() handling code
  Convert read_tree{,_recursive} to support struct pathspec
  Reimplement read_tree_recursive() using tree_entry_interesting()
2011-05-06 10:50:06 -07:00
Junio C Hamano
76a89d6d82 Merge branch 'jc/rename-degrade-cc-to-c'
* jc/rename-degrade-cc-to-c:
  diffcore-rename: fall back to -C when -C -C busts the rename limit
  diffcore-rename: record filepair for rename src
  diffcore-rename: refactor "too many candidates" logic
  builtin/diff.c: remove duplicated call to diff_result_code()
2011-04-28 14:11:43 -07:00
Junio C Hamano
ac9666f84a Merge branch 'en/merge-recursive'
* en/merge-recursive:
  merge-recursive: tweak magic band-aid
  merge-recursive: When we detect we can skip an update, actually skip it
  t6022: New test checking for unnecessary updates of files in D/F conflicts
  t6022: New test checking for unnecessary updates of renamed+modified files
2011-04-28 14:11:35 -07:00
Dan McGee
13ee1384ef Fix two unused variable warnings in gcc 4.6
Seen with -Wunused-but-set-variable.

Signed-off-by: Dan McGee <dpmcgee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-04-03 10:59:40 -07:00
Nguyễn Thái Ngọc Duy
f0096c06bc Convert read_tree{,_recursive} to support struct pathspec
This patch changes behavior of the two functions. Previously it does
prefix matching only. Now it can also do wildcard matching.

All callers are updated. Some gain wildcard matching (archive,
checkout), others reset pathspec_item.has_wildcard to retain old
behavior (ls-files, ls-tree as they are plumbing).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-25 09:20:33 -07:00
Junio C Hamano
f31027c99c diffcore-rename: fall back to -C when -C -C busts the rename limit
When there are too many paths in the project, the number of rename source
candidates "git diff -C -C" finds will exceed the rename detection limit,
and no inexact rename detection is performed.  We however could fall back
to "git diff -C" if the number of modified paths is sufficiently small.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-22 14:29:07 -07:00
Junio C Hamano
0ce6a51b43 Merge branch 'jk/merge-rename-ux'
* jk/merge-rename-ux:
  pull: propagate --progress to merge
  merge: enable progress reporting for rename detection
  add inexact rename detection progress infrastructure
  commit: stop setting rename limit
  bump rename limit defaults (again)
  merge: improve inexact rename limit warning
2011-03-19 23:23:56 -07:00
Junio C Hamano
b9b3eef761 merge-recursive: tweak magic band-aid
Running checks against working tree (e.g. lstat()) and causing
changes to working tree (e.g. unlink()) while building a virtual
ancestor merge does not make any sense. Avoid doing so.

This is not a real fix; it is another magic band-aid on top of
another band-aid we placed earlier.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-17 22:22:06 -07:00
Junio C Hamano
b2f6eab402 Merge branch 'maint'
* maint:
  Prepare draft release notes to 1.7.4.2
  gitweb: highlight: replace tabs with spaces
  make_absolute_path: return the input path if it points to our buffer
  valgrind: ignore SSE-based strlen invalid reads
  diff --submodule: split into bite-sized pieces
  cherry: split off function to print output lines
  branch: split off function that writes tracking info and commit subject
  standardize brace placement in struct definitions
  compat: make gcc bswap an inline function
  enums: omit trailing comma for portability

Conflicts:
	RelNotes
2011-03-16 16:59:30 -07:00
Jonathan Nieder
9cba13ca5d standardize brace placement in struct definitions
In a struct definitions, unlike functions, the prevailing style is for
the opening brace to go on the same line as the struct name, like so:

 struct foo {
	int bar;
	char *baz;
 };

Indeed, grepping for 'struct [a-z_]* {$' yields about 5 times as many
matches as 'struct [a-z_]*$'.

Linus sayeth:

 Heretic people all over the world have claimed that this inconsistency
 is ...  well ...  inconsistent, but all right-thinking people know that
 (a) K&R are _right_ and (b) K&R are right.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-16 12:49:02 -07:00
Elijah Newren
b2c8c0a762 merge-recursive: When we detect we can skip an update, actually skip it
In 882fd11 (merge-recursive: Delay content merging for renames 2010-09-20),
there was code that checked for whether we could skip updating a file in
the working directory, based on whether the merged version matched the
current working copy.  Due to the desire to handle directory/file conflicts
that were resolvable, that commit deferred content merging by first
updating the index with the unmerged entries and then moving the actual
merging (along with the skip-the-content-update check) to another function
that ran later in the merge process.  As part moving the content merging
code, a bug was introduced such that although the message about skipping
the update would be printed (whenever GIT_MERGE_VERBOSITY was sufficiently
high), the file would be unconditionally updated in the working copy
anyway.

When we detect that the file does not need to be updated in the working
copy, update the index appropriately and then return early before updating
the working copy.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-02 11:55:06 -08:00
Jeff King
ebeb60900f strbuf: add strbuf_vaddf
In a variable-args function, the code for writing into a strbuf is
non-trivial. We ended up cutting and pasting it in several places
because there was no vprintf-style function for strbufs (which in turn
was held up by a lack of va_copy).

Now that we have a fallback va_copy, we can add strbuf_vaddf, the
strbuf equivalent of vsprintf. And we can clean up the cut and paste
mess.

Signed-off-by: Jeff King <peff@peff.net>
Improved-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-02-26 01:06:50 -08:00
Jeff King
99bfc6691d merge: enable progress reporting for rename detection
The user can enable or disable it explicitly with the new
--progress, but it defaults to checking isatty(2).

This works only with merge-recursive and subtree. In theory
we could pass a progress flag to other strategies, but none
of them support progress at this point, so let's wait until
they grow such a feature before worrying about propagating
it.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-02-21 10:24:08 -08:00
Jeff King
92c57e5c1d bump rename limit defaults (again)
We did this once before in 5070591 (bump rename limit
defaults, 2008-04-30). Back then, we were shooting for about
1 second for a diff/log calculation, and 5 seconds for a
merge.

There are a few new things to consider, though:

  1. Average processors are faster now.

  2. We've seen on the mailing list some ugly merges where
     not using inexact rename detection leads to many more
     conflicts. Merges of this size take a long time
     anyway, so users are probably happy to spend a little
     bit of time computing the renames.

Let's bump the diff/merge default limits from 200/500 to
400/1000. Those are 2 seconds and 10 seconds respectively on
my modern hardware.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-02-21 10:23:36 -08:00
Jeff King
bf0ab10fa8 merge: improve inexact rename limit warning
The warning is generated deep in the diffcore code, which
means that it will come first, followed possibly by a spew
of conflicts, making it hard to see.

Instead, let's have diffcore pass back the information about
how big the rename limit would needed to have been, and then
the caller can provide a more appropriate message (and at a
more appropriate time).

No refactoring of other non-merge callers is necessary,
because nobody else was even using the warn_on_rename_limit
feature.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-02-21 10:21:26 -08:00
Junio C Hamano
5acb623b72 Merge branch 'en/merge-recursive'
* en/merge-recursive: (41 commits)
  t6022: Use -eq not = to test output of wc -l
  merge-recursive:make_room_for_directories - work around dumb compilers
  merge-recursive: Remove redundant path clearing for D/F conflicts
  merge-recursive: Make room for directories in D/F conflicts
  handle_delete_modify(): Check whether D/F conflicts are still present
  merge_content(): Check whether D/F conflicts are still present
  conflict_rename_rename_1to2(): Fix checks for presence of D/F conflicts
  conflict_rename_delete(): Check whether D/F conflicts are still present
  merge-recursive: Delay modify/delete conflicts if D/F conflict present
  merge-recursive: Delay content merging for renames
  merge-recursive: Delay handling of rename/delete conflicts
  merge-recursive: Move handling of double rename of one file to other file
  merge-recursive: Move handling of double rename of one file to two
  merge-recursive: Avoid doubly merging rename/add conflict contents
  merge-recursive: Update merge_content() call signature
  merge-recursive: Update conflict_rename_rename_1to2() call signature
  merge-recursive: Structure process_df_entry() to handle more cases
  merge-recursive: Have process_entry() skip D/F or rename entries
  merge-recursive: New function to assist resolving renames in-core only
  merge-recursive: New data structures for deferring of D/F conflicts
  ...

Conflicts:
	t/t6020-merge-df.sh
	t/t6036-recursive-corner-cases.sh
2010-11-29 17:52:35 -08:00
Junio C Hamano
329351feeb Merge branch 'kb/merge-recursive-rename-threshold'
* kb/merge-recursive-rename-threshold:
  diff: add synonyms for -M, -C, -B
  merge-recursive: option to specify rename threshold

Conflicts:
	Documentation/diff-options.txt
	Documentation/merge-strategies.txt
2010-10-26 21:54:04 -07:00
Junio C Hamano
75b17fee72 Merge branch 'jf/merge-ignore-ws'
* jf/merge-ignore-ws:
  merge-recursive: options to ignore whitespace changes
  merge-recursive --patience
  ll-merge: replace flag argument with options struct
  merge-recursive: expose merge options for builtin merge
2010-10-26 21:40:54 -07:00
Junio C Hamano
c8516500b1 merge-recursive:make_room_for_directories - work around dumb compilers
Some vintage of gcc does not seem to notice last_len is only used when
last_file is already set to non-NULL at which point last_len is also
set.

Noticed on FreeBSD 8

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-10-21 07:34:33 -07:00
Elijah Newren
4c0c1810c9 merge-recursive: Remove redundant path clearing for D/F conflicts
The code had several places where individual checks were done to remove
files that could be in the way of directories in D/F conflicts.  Not all
D/F conflicts could have a path cleared for them in such a manner, however,
leading to the need to create make_room_for_directories_of_df_conflicts()
as done in the previous patch.  That new function could not have been
incorporated into the code sooner, since not all relevant code paths had
been deferred to process_df_entry() yet, leading to the creation of even
more of these now-redundant path removals.

Clean out all of these extra D/F path clearing cases.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:05 -07:00
Elijah Newren
ef02b31721 merge-recursive: Make room for directories in D/F conflicts
When there are unmerged entries present, make sure to check for D/F
conflicts first and remove any files present in HEAD that would be in the
way of creating files below the correspondingly named directory.  Such
files will be processed again at the end of the merge in
process_df_entry(); at that time we will be able to tell if we need to
and can reinstate the file, whether we need to place its contents in a
different file due to the directory still being present, etc.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:05 -07:00
Elijah Newren
84a08a47b9 handle_delete_modify(): Check whether D/F conflicts are still present
If all the paths below some directory involved in a D/F conflict were not
removed during the rest of the merge, then the contents of the file whose
path conflicted needs to be recorded in file with an alternative filename.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:05 -07:00
Elijah Newren
4ab9a157d0 merge_content(): Check whether D/F conflicts are still present
If all the paths below some directory involved in a D/F conflict were not
removed during the rest of the merge, then the contents of the file whose
path conflicted needs to be recorded in file with an alternative filename.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:05 -07:00
Elijah Newren
2adc7dcc11 conflict_rename_rename_1to2(): Fix checks for presence of D/F conflicts
This function is called from process_df_entry(), near the end of the merge.
Rather than just checking whether one of the sides of the merge had a
directory at the same path as one of our files, check whether that
directory is still present by this point of our merge.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:05 -07:00
Elijah Newren
a0de2f6bd3 conflict_rename_delete(): Check whether D/F conflicts are still present
If all the paths below some directory involved in a D/F conflict were not
removed during the rest of the merge, then the contents of the file whose
path conflicted needs to be recorded in file with an alternative filename.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
71f7ffcc02 merge-recursive: Delay modify/delete conflicts if D/F conflict present
When handling merges with modify/delete conflicts, if the modified path is
involved in a D/F conflict, handle the issue in process_df_entry() rather
than process_entry().

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
882fd11aff merge-recursive: Delay content merging for renames
Move the handling of content merging for renames from process_renames() to
process_df_entry().

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
3b130adf9c merge-recursive: Delay handling of rename/delete conflicts
Move the handling of rename/delete conflicts from process_renames() to
process_df_entry().

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
161cf7f949 merge-recursive: Move handling of double rename of one file to other file
Move the handling of rename/rename conflicts where one file is renamed on
both sides to the same file, from process_renames() to process_entry().
Here we avoid the three way merge logic by just using
update_stages_and_entry() to move the higher stage entries in the index
from the rename source to the rename destination, and then allow
process_entry() to do its magic.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
07413c5a31 merge-recursive: Move handling of double rename of one file to two
Move the handling of rename/rename conflicts where one file is renamed to
two different files, from process_renames() to process_df_entry().

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
2a669c341a merge-recursive: Avoid doubly merging rename/add conflict contents
When a commit moves A to B while another commit created B (or moved C to
B), and these two different commits serve as different merge-bases for a
later merge, c94736a (merge-recursive: don't segfault while handling
rename clashes 2009-07-30) added some special code to avoid segfaults.
Since that commit, the two versions of B are merged in place (which could
be potentially conflicting) and the intermediate result is used as the
virtual ancestor.

However, right before this special merge, try_merge was turned on, meaning
that process_renames() would try an alternative merge that ignores the
'add' part of the conflict, and, if the merge is clean, store that as the
new virtual ancestor.  This could cause incorrect merging of criss-cross
merges; it would typically result in just recording a slightly confusing
merge base, but in some cases it could cause silent acceptance of one side
of a merge as the final resolution when a conflict should have been
flagged.

When we do a special merge for such a rename/add conflict between
merge-bases, turn try_merge off to avoid an inappropriate second merge.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:04 -07:00
Elijah Newren
61b8bcae2d merge-recursive: Update merge_content() call signature
Enable calling merge_content() and providing more information about renames
and D/F conflicts (which we will want to do from process_df_entry()).

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:03 -07:00
Elijah Newren
36de17048a merge-recursive: Update conflict_rename_rename_1to2() call signature
To facilitate having this function called later using information stored
in a rename_df_conflict_info struct, accept a diff_filepair instead of a
rename.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:03 -07:00
Elijah Newren
9c0bbb50f0 merge-recursive: Structure process_df_entry() to handle more cases
Modify process_df_entry() (mostly just indentation level changes) to
get it ready for handling more D/F conflict type cases.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:03 -07:00
Elijah Newren
384c166807 merge-recursive: Have process_entry() skip D/F or rename entries
If an entry has an associated rename_df_conflict_info, skip it and allow
it to be processed by process_df_entry().

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:03 -07:00
Elijah Newren
2ff739f9d2 merge-recursive: New function to assist resolving renames in-core only
process_renames() and process_entry() have nearly identical code for
doing three-way file merging to resolve content changes.  Since we are
already deferring some of the current rename handling in order to better
handle D/F conflicts, it seems to make sense to defer content merging as
well and remove the (nearly) duplicated code sections for handling this
merging.

To facilitate this process, add a new update_stages_and_entry() function
which will map the higher stage index entries from two files involved in a
rename into the resulting rename destination's index entries, and update
the associated stage_data structure.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:37:03 -07:00
Elijah Newren
25c3936349 merge-recursive: New data structures for deferring of D/F conflicts
Since we need to resolve paths (including renames) in-core first and defer
checking of D/F conflicts (namely waiting to see if directories are still
in the way after all paths are resolved) before updating files involved in
D/F conflicts, we will need to first process_renames, then record some
information about the rename needed at D/F resolution time, and then make
use of that information when resolving D/F conflicts at the end.

This commit adds some relevant data structures for storing the necessary
information.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:38 -07:00
Elijah Newren
0c4918d1c1 merge-recursive: Move process_entry's content merging into a function
This move is in preparation for merge_content growing and being called from
multiple places in order to handle D/F conflicts.

I also snuck in a small change to the output in the case that the merged
content for the file matches the current file contents, to make it better
match (and thus more able to take over) how other merge_file() calls in
process_renames() are handled.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:38 -07:00
Elijah Newren
5e3ce663b0 merge-recursive: Move delete/modify handling into dedicated function
This move is in preparation for the function being called from multiple
places in order to handle D/F conflicts.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:38 -07:00
Elijah Newren
6ef2cb008f merge-recursive: Move rename/delete handling into dedicated function
This move is in preparation for the function growing and being called from
multiple places in order to handle D/F conflicts.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:38 -07:00
Elijah Newren
605c1bcfc4 merge-recursive: Nuke rename/directory conflict detection
Since we want to resolve merges in-core and then detect at the end whether
D/F conflicts remain in the way, we should just apply renames in-core and
let logic elsewhere check for D/F conflicts.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:38 -07:00
Elijah Newren
09c01f856f merge-recursive: Rename conflict_rename_rename*() for clarity
The names conflict_rename_rename and conflict_rename_rename_2 did not make
it clear what they were handling.  Since the first of these handles one
file being renamed in both branches to different files, while the latter
handles two different files being renamed to the same thing, add a little
'1to2' and '2to1' suffix on these and an explanatory comment to make their
intent clearer.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:37 -07:00
Elijah Newren
41d70bd6a9 merge-recursive: Small code clarification -- variable name and comments
process_renames() had a variable named "stage" and derived variables
src_other and dst_other whose purpose was not immediately obvious; also,
I want to extend the scope of this variable and use it later, so it should
have a more descriptive name.  Do so, and add a brief comment explaining
how it is used and what it relates to.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:37 -07:00
Junio C Hamano
7edba4c45c merge-recursive: Restructure showing how to chain more process_* functions
In 3734893 (merge-recursive: Fix D/F conflicts 2010-07-09),
process_df_entry() was added to process_renames() and process_entry() but
in a somewhat restrictive manner.  Modify the code slightly to make it
clearer how we could chain more such functions if necessary, and alter
process_df_entry() to handle such chaining.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 17:32:36 -07:00
Junio C Hamano
a1155adc2d Merge branch 'en/rename-d-f' into en/merge-recursive
* en/rename-d-f:
  merge-recursive: D/F conflicts where was_a_dir/file -> was_a_dir
  t3509: Add rename + D/F conflict testcase that recursive strategy fails
2010-09-29 17:25:28 -07:00
Kevin Ballard
10ae7526be merge-recursive: option to specify rename threshold
The recursive merge strategy turns on rename detection but leaves the
rename threshold at the default. Add a strategy option to allow the user
to specify a rename threshold to use.

Signed-off-by: Kevin Ballard <kevin@sb.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-29 13:15:56 -07:00
Junio C Hamano
9f0ccb5b0a Merge branch 'ks/recursive-rename-add-identical'
* ks/recursive-rename-add-identical:
  RE: [PATCH] Avoid rename/add conflict when contents are identical
2010-09-15 12:39:12 -07:00
Elijah Newren
86273e5764 merge-recursive: D/F conflicts where was_a_dir/file -> was_a_dir
In merge-recursive.c, whenever there was a rename where a file name on one
side of the rename matches a directory name on the other side of the merge,
then the very first check that

  string_list_has_string(&o->current_directory_set, ren1_dst)

would trigger forcing it into marking it as a rename/directory conflict.

However, if the path is only renamed on one side and a simple three-way
merge between the separate files resolves cleanly, then we don't need to
mark it as a rename/directory conflict.  So, we can simply move the check
for rename/directory conflicts after we've verified that there isn't a
rename/rename conflict and that a threeway content merge doesn't work.

This changes the particular error message one gets in the case where the
directory name that a file on one side of the rename matches is not also
part of the rename pair.  For example, with commits containing the files:

  COMMON    -> (HEAD,           MERGE )
  ---------    ---------------  -------
  sub/file1 -> (sub/file1,      newsub)
  <NULL>    -> (newsub/newfile, <NULL>)

then previously when one tried to merge MERGE into HEAD, one would get

  CONFLICT (rename/directory): Rename sub/file1->newsub in HEAD directory newsub added in merge
  Renaming sub/file1 to newsub~HEAD instead
  Adding newsub/newfile
  Automatic merge failed; fix conflicts and then commit the result.
After this patch, the error message will instead become:
  Removing newsub
  Adding newsub/newfile
  CONFLICT (file/directory): There is a directory with name newsub in merge. Adding newsub as newsub~HEAD
  Automatic merge failed; fix conflicts and then commit the result.

That makes more sense to me, because git can't know that there's a conflict
until after it's tried resolving paths involving newsub/newfile to see if
they are still in the way at the end (and if newsub/newfile is not in the
way at the end, there should be no conflict at all, which did not hold with
git previously).

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-09 17:03:02 -07:00
Junio C Hamano
c208e05bd9 Merge branch 'dg/local-mod-error-messages'
* dg/local-mod-error-messages:
  t7609-merge-co-error-msgs: test non-fast forward case too.
  Move "show_all_errors = 1" to setup_unpack_trees_porcelain()
  setup_unpack_trees_porcelain: take the whole options struct as parameter
  Move set_porcelain_error_msgs to unpack-trees.c and rename it

Conflicts:
	merge-recursive.c
2010-09-03 22:23:49 -07:00
Schalk, Ken
d5af51053c RE: [PATCH] Avoid rename/add conflict when contents are identical
>Due to this this (and maybe all the tests) need to depend on the
>SYMLINKS prereq.

Here's a third attempt with no use of symlinks in the test:

Skip the entire rename/add conflict case if the file added on the
other branch has the same contents as the file being renamed.  This
avoids giving the user an extra copy of the same file and presenting a
conflict that is confusing and pointless.

A simple test of this case has been added in
t/t3030-merge-recursive.sh.

Signed-off-by: Ken Schalk <ken.schalk@intel.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-03 11:26:49 -07:00
Junio C Hamano
8aed4a5e38 Merge branch 'jn/merge-renormalize'
* 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.sh
2010-09-03 09:43:41 -07:00
Matthieu Moy
e294030fe8 setup_unpack_trees_porcelain: take the whole options struct as parameter
This is a preparation patch to let setup_unpack_trees_porcelain set
show_all_errors itself.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-03 09:31:41 -07:00
Matthieu Moy
dc1166e685 Move set_porcelain_error_msgs to unpack-trees.c and rename it
The function is currently dealing only with error messages, but the
intent of calling it is really to notify the unpack-tree mechanics that
it is running in porcelain mode.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-09-03 09:31:28 -07:00
Junio C Hamano
3f29dd6c23 Merge branch 'en/d-f-conflict-fix'
* en/d-f-conflict-fix:
  merge-recursive: Avoid excessive output for and reprocessing of renames
  merge-recursive: Fix multiple file rename across D/F conflict
  t6031: Add a testcase covering multiple renames across a D/F conflict
  merge-recursive: Fix typo
  Mark tests that use symlinks as needing SYMLINKS prerequisite
  t/t6035-merge-dir-to-symlink.sh: Remove TODO on passing test
  fast-import: Improve robustness when D->F changes provided in wrong order
  fast-export: Fix output order of D/F changes
  merge_recursive: Fix renames across paths below D/F conflicts
  merge-recursive: Fix D/F conflicts
  Add a rename + D/F conflict testcase
  Add additional testcases for D/F conflicts

Conflicts:
	merge-recursive.c
2010-08-31 16:23:58 -07:00
Justin Frankel
4e5dd044c6 merge-recursive: options to ignore whitespace changes
Add support for merging with ignoring line endings (specifically
--ignore-space-at-eol) when using recursive merging.  This is
as a strategy-option, so that you can do:

	git merge --strategy-option=ignore-space-at-eol <branch>

and

	git rebase --strategy-option=ignore-space-at-eol <branch>

This can be useful for coping with line-ending damage (Xcode 3.1 has a
nasty habit of converting all CRLFs to LFs, and VC6 tends to just use
CRLFs for inserted lines).

The only option I need is ignore-space-at-eol, but while at it,
include the other xdiff whitespace options (ignore-space-change,
ignore-all-space), too.

[jn: with documentation]

Signed-off-by: Justin Frankel <justin@cockos.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-27 10:08:50 -07:00
Justin Frankel
58a1ece478 merge-recursive --patience
Teach the merge-recursive strategy a --patience option to use the
"patience diff" algorithm, which tends to improve results when
cherry-picking a patch that reorders functions at the same time as
refactoring them.

To support this, struct merge_options and ll_merge_options gain an
xdl_opts member, so programs can use arbitrary xdiff flags (think
"XDF_IGNORE_WHITESPACE") in a git-aware merge.

git merge and git rebase can be passed the -Xpatience option to
use this.

[jn: split from --ignore-space patch; with documentation]

Signed-off-by: Justin Frankel <justin@cockos.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-26 09:20:03 -07:00
Jonathan Nieder
712516bcac ll-merge: replace flag argument with options struct
Keeping track of the flag bits is proving more trouble than it's
worth.  Instead, use a pointer to an options struct like most similar
APIs do.

Callers with no special requests can pass NULL to request the default
options.

Cc: Bert Wesarg <bert.wesarg@googlemail.com>
Cc: Avery Pennarun <apenwarr@gmail.com>
Helped-by: Justin Frankel <justin@cockos.com>
Helped-by: Bert Wesarg <bert.wesarg@googlemail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-26 09:18:51 -07:00
Jonathan Nieder
635a7bb1d8 merge-recursive: expose merge options for builtin merge
There are two very similar blocks of code that recognize options for
the "recursive" merge strategy.  Unify them.

No functional change intended.

Cc: Avery Pennarun <apenwarr@gmail.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-26 09:05:02 -07:00
Junio C Hamano
2d984464c6 Merge branch 'hv/submodule-find-ff-merge'
* hv/submodule-find-ff-merge:
  Implement automatic fast-forward merge for submodules
  setup_revisions(): Allow walking history in a submodule
  Teach ref iteration module about submodules

Conflicts:
	submodule.c
2010-08-21 23:27:59 -07:00
Junio C Hamano
2eb54692d1 Merge branch 'dg/local-mod-error-messages'
* dg/local-mod-error-messages:
  t7609: test merge and checkout error messages
  unpack_trees: group error messages by type
  merge-recursive: distinguish "removed" and "overwritten" messages
  merge-recursive: porcelain messages for checkout
  Turn unpack_trees_options.msgs into an array + enum

Conflicts:
	t/t3400-rebase.sh
2010-08-21 23:26:46 -07:00
Elijah Newren
96ecac677a merge-recursive: Avoid excessive output for and reprocessing of renames
In 5a2580d (merge_recursive: Fix renames across paths below D/F conflicts
2010-07-09) and ae74548 (merge-recursive: Fix multiple file rename across
D/F conflict 2010-08-17), renames across D/F conflicts were fixed by
making process_renames() consider as unprocessed renames whose dst_entry
"still" had higher stage entries.  The assumption was that those higher
stage entries would have been cleared out of dst_entry by that point in
cases where the conflict could be resolved (normal renames with no D/F
conflicts).  That is not the case -- higher stage entries will remain in
all cases.

Fix this by checking for higher stage entries corresponding to D/F
conflicts, namely that stages 2 and 3 have exactly one nonzero mode between
them.  The nonzero mode stage corresponds to a file at the path, while the
stage with a zero mode will correspond to a directory at that path (since
rename/delete conflicts will have already been handled before this codepath
is reached.)

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-20 08:26:56 -07:00
Junio C Hamano
6b5005c88b Merge branch 'tf/string-list-init'
* tf/string-list-init:
  string_list: Add STRING_LIST_INIT macro and make use of it.
2010-08-18 12:47:04 -07:00
Junio C Hamano
165dc789d5 Merge branch 'cc/find-commit-subject'
* cc/find-commit-subject:
  blame: use find_commit_subject() instead of custom code
  merge-recursive: use find_commit_subject() instead of custom code
  bisect: use find_commit_subject() instead of custom code
  revert: rename variables related to subject in get_message()
  revert: refactor code to find commit subject in find_commit_subject()
  revert: fix off by one read when searching the end of a commit subject
2010-08-18 12:46:55 -07:00
Elijah Newren
ae745487ad merge-recursive: Fix multiple file rename across D/F conflict
In 5a2580d (merge_recursive: Fix renames across paths below D/F conflicts
2010-07-09), detection was added for renames across paths involved in a
directory<->file conflict.  However, the change accidentally involved
reusing an outer loop index ('i') in an inner loop, changing its values
and causing a slightly different type of breakage for cases where there are
multiple renames across the D/F conflict.  Fix by creating a new temporary
variable 'i'.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-18 12:08:08 -07:00
Elijah Newren
a3e4136754 merge-recursive: Fix typo
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-18 11:55:38 -07:00
Matthieu Moy
e6c111b4c0 unpack_trees: group error messages by type
When an error is encountered, it calls add_rejected_file() which either
- directly displays the error message and stops if in plumbing mode
  (i.e. if show_all_errors is not initialized at 1)
- or stores it so that it will be displayed at the end with display_error_msgs(),

Storing the files by error type permits to have a list of files for
which there is the same error instead of having a serie of almost
identical errors.

As each bind_overlap error combines a file and an old file, a list cannot be
done, therefore, theses errors are not stored but directly displayed.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-11 10:36:06 -07:00
Matthieu Moy
08402b0409 merge-recursive: distinguish "removed" and "overwritten" messages
To limit the number of possible error messages, the error messages for
the case would_lose_untracked_file and would_lose_orphaned in
unpack_trees_options.msgs were handled with a single string,
parameterized by an action string ("overwritten" or "removed").

Instead, we consider them as two different cases, with unparameterized
string. This will make it easier to make separate lists sorted by error
types later.

Only the bind_overlap case still takes two %s parameters, but that's
unavoidable.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-11 10:36:05 -07:00
Diane Gasselin
23cbf11b5c merge-recursive: porcelain messages for checkout
A porcelain message was first added in checkout.c in the commit
8ccba008 (Junio C Hamano, Sat May 17 21:03:49 2008, unpack-trees:
allow Porcelain to give different error messages) to give better feedback
in the case of merge errors.

This patch adapts the porcelain messages for the case of checkout
instead. This way, when having a checkout error, "merge" no longer
appears in the error message.

While we're there, we add an advice in the case of
would_lose_untracked_file.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-11 10:36:03 -07:00
Matthieu Moy
08353ebbab Turn unpack_trees_options.msgs into an array + enum
The list of error messages was introduced as a structure, but an array
indexed over an enum is more flexible, since it allows one to store a
type of error message (index in the array) in a variable.

This change needs to rename would_lose_untracked ->
would_lose_untracked_file to avoid a clash with the function
would_lose_untracked in merge-recursive.c.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-11 10:36:00 -07:00
Jonathan Nieder
7610fa57e6 merge-recursive --renormalize
Teach "git merge-recursive" a --renormalize option to enable the
merge.renormalize configuration.  The --no-renormalize option can
be used to override it in the negative.

So in the future, you might be able to, e.g.:

	git checkout -m -Xrenormalize otherbranch

or

	git revert -Xrenormalize otherpatch

or

	git pull --rebase -Xrenormalize

The bad part: merge.renormalize is still not honored for most
commands.  And it reveals lots of places that -X has not been plumbed
in (so we get "git merge -Xrenormalize" but not much else).

NEEDSWORK: tests

Cc: Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-08-06 09:20:02 -07:00