Skip to content

Commit e4bb62f

Browse files
committed
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 ...
2 parents 468165c + c5b761f commit e4bb62f

9 files changed

+5197
-115
lines changed

merge-recursive.c

Lines changed: 1132 additions & 111 deletions
Large diffs are not rendered by default.

merge-recursive.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef MERGE_RECURSIVE_H
22
#define MERGE_RECURSIVE_H
33

4+
#include "unpack-trees.h"
45
#include "string-list.h"
56

67
struct merge_options {
@@ -27,6 +28,32 @@ struct merge_options {
2728
struct strbuf obuf;
2829
struct hashmap current_file_dir_set;
2930
struct string_list df_conflict_file_set;
31+
struct unpack_trees_options unpack_opts;
32+
};
33+
34+
/*
35+
* For dir_rename_entry, directory names are stored as a full path from the
36+
* toplevel of the repository and do not include a trailing '/'. Also:
37+
*
38+
* dir: original name of directory being renamed
39+
* non_unique_new_dir: if true, could not determine new_dir
40+
* new_dir: final name of directory being renamed
41+
* possible_new_dirs: temporary used to help determine new_dir; see comments
42+
* in get_directory_renames() for details
43+
*/
44+
struct dir_rename_entry {
45+
struct hashmap_entry ent; /* must be the first member! */
46+
char *dir;
47+
unsigned non_unique_new_dir:1;
48+
struct strbuf new_dir;
49+
struct string_list possible_new_dirs;
50+
};
51+
52+
struct collision_entry {
53+
struct hashmap_entry ent; /* must be the first member! */
54+
char *target_file;
55+
struct string_list source_files;
56+
unsigned reported_already:1;
3057
};
3158

3259
/* merge_trees() but with recursive ancestor consolidation */

strbuf.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "cache.h"
22
#include "refs.h"
3+
#include "string-list.h"
34
#include "utf8.h"
45

56
int starts_with(const char *str, const char *prefix)
@@ -171,6 +172,21 @@ struct strbuf **strbuf_split_buf(const char *str, size_t slen,
171172
return ret;
172173
}
173174

175+
void strbuf_add_separated_string_list(struct strbuf *str,
176+
const char *sep,
177+
struct string_list *slist)
178+
{
179+
struct string_list_item *item;
180+
int sep_needed = 0;
181+
182+
for_each_string_list_item(item, slist) {
183+
if (sep_needed)
184+
strbuf_addstr(str, sep);
185+
strbuf_addstr(str, item->string);
186+
sep_needed = 1;
187+
}
188+
}
189+
174190
void strbuf_list_free(struct strbuf **sbs)
175191
{
176192
struct strbuf **s = sbs;

strbuf.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef STRBUF_H
22
#define STRBUF_H
33

4+
struct string_list;
5+
46
/**
57
* strbuf's are meant to be used with all the usual C string and memory
68
* 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,
531533
return strbuf_split_max(sb, terminator, 0);
532534
}
533535

536+
/*
537+
* Adds all strings of a string list to the strbuf, separated by the given
538+
* separator. For example, if sep is
539+
* ', '
540+
* and slist contains
541+
* ['element1', 'element2', ..., 'elementN'],
542+
* then write:
543+
* 'element1, element2, ..., elementN'
544+
* to str. If only one element, just write "element1" to str.
545+
*/
546+
extern void strbuf_add_separated_string_list(struct strbuf *str,
547+
const char *sep,
548+
struct string_list *slist);
549+
534550
/**
535551
* Free a NULL-terminated list of strbufs (for example, the return
536552
* values of the strbuf_split*() functions).

t/t3501-revert-cherry-pick.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' '
141141
test_cmp expect actual
142142
'
143143

144-
test_expect_failure 'cherry-pick works with dirty renamed file' '
144+
test_expect_success 'cherry-pick works with dirty renamed file' '
145145
test_commit to-rename &&
146146
git checkout -b unrelated &&
147147
test_commit unrelated &&

0 commit comments

Comments
 (0)