Commit e4bb62fa authored by Junio C Hamano's avatar Junio C Hamano

Merge branch 'en/rename-directory-detection'

Rename detection logic in "diff" family that is used in "merge" has
learned to guess when all of x/a, x/b and x/c have moved to z/a,
z/b and z/c, it is likely that x/d added in the meantime would also
want to move to z/d by taking the hint that the entire directory
'x' moved to 'z'.  A bug causing dirty files involved in a rename
to be overwritten during merge has also been fixed as part of this
work.

* en/rename-directory-detection: (29 commits)
  merge-recursive: ensure we write updates for directory-renamed file
  merge-recursive: avoid spurious rename/rename conflict from dir renames
  directory rename detection: new testcases showcasing a pair of bugs
  merge-recursive: fix remaining directory rename + dirty overwrite cases
  merge-recursive: fix overwriting dirty files involved in renames
  merge-recursive: avoid clobbering untracked files with directory renames
  merge-recursive: apply necessary modifications for directory renames
  merge-recursive: when comparing files, don't include trees
  merge-recursive: check for file level conflicts then get new name
  merge-recursive: add computation of collisions due to dir rename & merging
  merge-recursive: check for directory level conflicts
  merge-recursive: add get_directory_renames()
  merge-recursive: make a helper function for cleanup for handle_renames
  merge-recursive: split out code for determining diff_filepairs
  merge-recursive: make !o->detect_rename codepath more obvious
  merge-recursive: fix leaks of allocated renames and diff_filepairs
  merge-recursive: introduce new functions to handle rename logic
  merge-recursive: move the get_renames() function
  directory rename detection: tests for handling overwriting dirty files
  directory rename detection: tests for handling overwriting untracked files
  ...
parents 468165c1 c5b761fb
This diff is collapsed.
#ifndef MERGE_RECURSIVE_H #ifndef MERGE_RECURSIVE_H
#define MERGE_RECURSIVE_H #define MERGE_RECURSIVE_H
#include "unpack-trees.h"
#include "string-list.h" #include "string-list.h"
struct merge_options { struct merge_options {
...@@ -27,6 +28,32 @@ struct merge_options { ...@@ -27,6 +28,32 @@ struct merge_options {
struct strbuf obuf; struct strbuf obuf;
struct hashmap current_file_dir_set; struct hashmap current_file_dir_set;
struct string_list df_conflict_file_set; struct string_list df_conflict_file_set;
struct unpack_trees_options unpack_opts;
};
/*
* For dir_rename_entry, directory names are stored as a full path from the
* toplevel of the repository and do not include a trailing '/'. Also:
*
* dir: original name of directory being renamed
* non_unique_new_dir: if true, could not determine new_dir
* new_dir: final name of directory being renamed
* possible_new_dirs: temporary used to help determine new_dir; see comments
* in get_directory_renames() for details
*/
struct dir_rename_entry {
struct hashmap_entry ent; /* must be the first member! */
char *dir;
unsigned non_unique_new_dir:1;
struct strbuf new_dir;
struct string_list possible_new_dirs;
};
struct collision_entry {
struct hashmap_entry ent; /* must be the first member! */
char *target_file;
struct string_list source_files;
unsigned reported_already:1;
}; };
/* merge_trees() but with recursive ancestor consolidation */ /* merge_trees() but with recursive ancestor consolidation */
......
#include "cache.h" #include "cache.h"
#include "refs.h" #include "refs.h"
#include "string-list.h"
#include "utf8.h" #include "utf8.h"
int starts_with(const char *str, const char *prefix) int starts_with(const char *str, const char *prefix)
...@@ -171,6 +172,21 @@ struct strbuf **strbuf_split_buf(const char *str, size_t slen, ...@@ -171,6 +172,21 @@ struct strbuf **strbuf_split_buf(const char *str, size_t slen,
return ret; return ret;
} }
void strbuf_add_separated_string_list(struct strbuf *str,
const char *sep,
struct string_list *slist)
{
struct string_list_item *item;
int sep_needed = 0;
for_each_string_list_item(item, slist) {
if (sep_needed)
strbuf_addstr(str, sep);
strbuf_addstr(str, item->string);
sep_needed = 1;
}
}
void strbuf_list_free(struct strbuf **sbs) void strbuf_list_free(struct strbuf **sbs)
{ {
struct strbuf **s = sbs; struct strbuf **s = sbs;
......
#ifndef STRBUF_H #ifndef STRBUF_H
#define STRBUF_H #define STRBUF_H
struct string_list;
/** /**
* strbuf's are meant to be used with all the usual C string and memory * strbuf's are meant to be used with all the usual C string and memory
* APIs. Given that the length of the buffer is known, it's often better to * APIs. Given that the length of the buffer is known, it's often better to
...@@ -531,6 +533,20 @@ static inline struct strbuf **strbuf_split(const struct strbuf *sb, ...@@ -531,6 +533,20 @@ static inline struct strbuf **strbuf_split(const struct strbuf *sb,
return strbuf_split_max(sb, terminator, 0); return strbuf_split_max(sb, terminator, 0);
} }
/*
* Adds all strings of a string list to the strbuf, separated by the given
* separator. For example, if sep is
* ', '
* and slist contains
* ['element1', 'element2', ..., 'elementN'],
* then write:
* 'element1, element2, ..., elementN'
* to str. If only one element, just write "element1" to str.
*/
extern void strbuf_add_separated_string_list(struct strbuf *str,
const char *sep,
struct string_list *slist);
/** /**
* Free a NULL-terminated list of strbufs (for example, the return * Free a NULL-terminated list of strbufs (for example, the return
* values of the strbuf_split*() functions). * values of the strbuf_split*() functions).
......
...@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' ' ...@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' '
test_cmp expect actual test_cmp expect actual
' '
test_expect_failure 'cherry-pick works with dirty renamed file' ' test_expect_success 'cherry-pick works with dirty renamed file' '
test_commit to-rename && test_commit to-rename &&
git checkout -b unrelated && git checkout -b unrelated &&
test_commit unrelated && test_commit unrelated &&
......
This diff is collapsed.
...@@ -92,7 +92,7 @@ test_expect_success 'will not overwrite removed file with staged changes' ' ...@@ -92,7 +92,7 @@ test_expect_success 'will not overwrite removed file with staged changes' '
test_cmp important c1.c test_cmp important c1.c
' '
test_expect_failure 'will not overwrite unstaged changes in renamed file' ' test_expect_success 'will not overwrite unstaged changes in renamed file' '
git reset --hard c1 && git reset --hard c1 &&
git mv c1.c other.c && git mv c1.c other.c &&
git commit -m rename && git commit -m rename &&
......
...@@ -1509,8 +1509,8 @@ static int verify_uptodate_1(const struct cache_entry *ce, ...@@ -1509,8 +1509,8 @@ static int verify_uptodate_1(const struct cache_entry *ce,
add_rejected_path(o, error_type, ce->name); add_rejected_path(o, error_type, ce->name);
} }
static int verify_uptodate(const struct cache_entry *ce, int verify_uptodate(const struct cache_entry *ce,
struct unpack_trees_options *o) struct unpack_trees_options *o)
{ {
if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE)) if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
return 0; return 0;
......
#ifndef UNPACK_TREES_H #ifndef UNPACK_TREES_H
#define UNPACK_TREES_H #define UNPACK_TREES_H
#include "tree-walk.h"
#include "string-list.h" #include "string-list.h"
#define MAX_UNPACK_TREES 8 #define MAX_UNPACK_TREES 8
...@@ -78,6 +79,9 @@ struct unpack_trees_options { ...@@ -78,6 +79,9 @@ struct unpack_trees_options {
extern int unpack_trees(unsigned n, struct tree_desc *t, extern int unpack_trees(unsigned n, struct tree_desc *t,
struct unpack_trees_options *options); struct unpack_trees_options *options);
int verify_uptodate(const struct cache_entry *ce,
struct unpack_trees_options *o);
int threeway_merge(const struct cache_entry * const *stages, int threeway_merge(const struct cache_entry * const *stages,
struct unpack_trees_options *o); struct unpack_trees_options *o);
int twoway_merge(const struct cache_entry * const *src, int twoway_merge(const struct cache_entry * const *src,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment