Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
fbb6c0c8
Commit
fbb6c0c8
authored
Aug 09, 2013
by
Russell Belfer
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1764 from ethomson/status_renames_from_rewrites
Add rename from rewrites to status
parents
33d532dc
e38f0d69
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
195 additions
and
45 deletions
+195
-45
include/git2/status.h
+4
-1
src/diff.c
+55
-22
src/status.c
+7
-22
tests-clar/status/renames.c
+129
-0
No files found.
include/git2/status.h
View file @
fbb6c0c8
...
...
@@ -107,7 +107,7 @@ typedef enum {
* - GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX indicates that rename detection
* should be processed between the head and the index and enables
* the GIT_STATUS_INDEX_RENAMED as a possible status flag.
* - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates tha rename
* - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates tha
t
rename
* detection should be run between the index and the working directory
* and enabled GIT_STATUS_WT_RENAMED as a possible status flag.
* - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case
...
...
@@ -116,6 +116,8 @@ typedef enum {
* - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case
* sensitivity for the file system and forces the output to be in
* case-insensitive order
* - GIT_STATUS_OPT_RENAMES_FROM_REWRITES indicates that rename detection
* should include rewritten files
*
* Calling `git_status_foreach()` is like calling the extended version
* with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
...
...
@@ -134,6 +136,7 @@ typedef enum {
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
=
(
1u
<<
8
),
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
=
(
1u
<<
9
),
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
=
(
1u
<<
10
),
GIT_STATUS_OPT_RENAMES_FROM_REWRITES
=
(
1u
<<
11
),
}
git_status_opt_t
;
#define GIT_STATUS_OPT_DEFAULTS \
...
...
src/diff.c
View file @
fbb6c0c8
...
...
@@ -258,6 +258,26 @@ int git_diff_delta__casecmp(const void *a, const void *b)
return
val
?
val
:
((
int
)
da
->
status
-
(
int
)
db
->
status
);
}
GIT_INLINE
(
const
char
*
)
diff_delta__i2w_path
(
const
git_diff_delta
*
delta
)
{
return
delta
->
old_file
.
path
?
delta
->
old_file
.
path
:
delta
->
new_file
.
path
;
}
int
git_diff_delta__i2w_cmp
(
const
void
*
a
,
const
void
*
b
)
{
const
git_diff_delta
*
da
=
a
,
*
db
=
b
;
int
val
=
strcmp
(
diff_delta__i2w_path
(
da
),
diff_delta__i2w_path
(
db
));
return
val
?
val
:
((
int
)
da
->
status
-
(
int
)
db
->
status
);
}
int
git_diff_delta__i2w_casecmp
(
const
void
*
a
,
const
void
*
b
)
{
const
git_diff_delta
*
da
=
a
,
*
db
=
b
;
int
val
=
strcasecmp
(
diff_delta__i2w_path
(
da
),
diff_delta__i2w_path
(
db
));
return
val
?
val
:
((
int
)
da
->
status
-
(
int
)
db
->
status
);
}
bool
git_diff_delta__should_skip
(
const
git_diff_options
*
opts
,
const
git_diff_delta
*
delta
)
{
...
...
@@ -1276,7 +1296,7 @@ int git_diff__paired_foreach(
git_diff_delta
*
h2i
,
*
i2w
;
size_t
i
,
j
,
i_max
,
j_max
;
int
(
*
strcomp
)(
const
char
*
,
const
char
*
)
=
git__strcmp
;
bool
icase_mismatch
;
bool
h2i_icase
,
i2w_icase
,
icase_mismatch
;
i_max
=
head2idx
?
head2idx
->
deltas
.
length
:
0
;
j_max
=
idx2wd
?
idx2wd
->
deltas
.
length
:
0
;
...
...
@@ -1291,24 +1311,35 @@ int git_diff__paired_foreach(
* Therefore the main thing we need to do here is make sure the diffs
* are traversed in a compatible order. To do this, we temporarily
* resort a mismatched diff to get the order correct.
*
* In order to traverse renames in the index->workdir, we need to
* ensure that we compare the index name on both sides, so we
* always sort by the old name in the i2w list.
*/
h2i_icase
=
head2idx
!=
NULL
&&
(
head2idx
->
opts
.
flags
&
GIT_DIFF_DELTAS_ARE_ICASE
)
!=
0
;
i2w_icase
=
idx2wd
!=
NULL
&&
(
idx2wd
->
opts
.
flags
&
GIT_DIFF_DELTAS_ARE_ICASE
)
!=
0
;
icase_mismatch
=
(
head2idx
!=
NULL
&&
idx2wd
!=
NULL
&&
((
head2idx
->
opts
.
flags
^
idx2wd
->
opts
.
flags
)
&
GIT_DIFF_DELTAS_ARE_ICASE
));
/* force case-sensitive delta sort */
if
(
icase_mismatch
)
{
if
(
head2idx
->
opts
.
flags
&
GIT_DIFF_DELTAS_ARE_ICASE
)
{
git_vector_set_cmp
(
&
head2idx
->
deltas
,
git_diff_delta__cmp
);
git_vector_sort
(
&
head2idx
->
deltas
);
}
else
{
git_vector_set_cmp
(
&
idx2wd
->
deltas
,
git_diff_delta__cmp
);
git_vector_sort
(
&
idx2wd
->
deltas
);
}
(
head2idx
!=
NULL
&&
idx2wd
!=
NULL
&&
h2i_icase
!=
i2w_icase
);
if
(
icase_mismatch
&&
h2i_icase
)
{
git_vector_set_cmp
(
&
head2idx
->
deltas
,
git_diff_delta__cmp
);
git_vector_sort
(
&
head2idx
->
deltas
);
}
else
if
(
head2idx
!=
NULL
&&
head2idx
->
opts
.
flags
&
GIT_DIFF_DELTAS_ARE_ICASE
)
if
(
i2w_icase
&&
!
icase_mismatch
)
{
strcomp
=
git__strcasecmp
;
git_vector_set_cmp
(
&
idx2wd
->
deltas
,
git_diff_delta__i2w_casecmp
);
git_vector_sort
(
&
idx2wd
->
deltas
);
}
else
if
(
idx2wd
!=
NULL
)
{
git_vector_set_cmp
(
&
idx2wd
->
deltas
,
git_diff_delta__i2w_cmp
);
git_vector_sort
(
&
idx2wd
->
deltas
);
}
for
(
i
=
0
,
j
=
0
;
i
<
i_max
||
j
<
j_max
;
)
{
h2i
=
head2idx
?
GIT_VECTOR_GET
(
&
head2idx
->
deltas
,
i
)
:
NULL
;
i2w
=
idx2wd
?
GIT_VECTOR_GET
(
&
idx2wd
->
deltas
,
j
)
:
NULL
;
...
...
@@ -1332,14 +1363,16 @@ int git_diff__paired_foreach(
}
/* restore case-insensitive delta sort */
if
(
icase_mismatch
)
{
if
(
head2idx
->
opts
.
flags
&
GIT_DIFF_DELTAS_ARE_ICASE
)
{
git_vector_set_cmp
(
&
head2idx
->
deltas
,
git_diff_delta__casecmp
);
git_vector_sort
(
&
head2idx
->
deltas
);
}
else
{
git_vector_set_cmp
(
&
idx2wd
->
deltas
,
git_diff_delta__casecmp
);
git_vector_sort
(
&
idx2wd
->
deltas
);
}
if
(
icase_mismatch
&&
h2i_icase
)
{
git_vector_set_cmp
(
&
head2idx
->
deltas
,
git_diff_delta__casecmp
);
git_vector_sort
(
&
head2idx
->
deltas
);
}
/* restore idx2wd sort by new path */
if
(
idx2wd
!=
NULL
)
{
git_vector_set_cmp
(
&
idx2wd
->
deltas
,
i2w_icase
?
git_diff_delta__casecmp
:
git_diff_delta__cmp
);
git_vector_sort
(
&
idx2wd
->
deltas
);
}
return
0
;
...
...
src/status.c
View file @
fbb6c0c8
...
...
@@ -225,24 +225,6 @@ static git_status_list *git_status_list_alloc(git_index *index)
return
status
;
}
/*
static int newfile_cmp(const void *a, const void *b)
{
const git_diff_delta *delta_a = a;
const git_diff_delta *delta_b = b;
return git__strcmp(delta_a->new_file.path, delta_b->new_file.path);
}
static int newfile_casecmp(const void *a, const void *b)
{
const git_diff_delta *delta_a = a;
const git_diff_delta *delta_b = b;
return git__strcasecmp(delta_a->new_file.path, delta_b->new_file.path);
}
*/
int
git_status_list_new
(
git_status_list
**
out
,
git_repository
*
repo
,
...
...
@@ -251,7 +233,7 @@ int git_status_list_new(
git_index
*
index
=
NULL
;
git_status_list
*
status
=
NULL
;
git_diff_options
diffopt
=
GIT_DIFF_OPTIONS_INIT
;
git_diff_find_options
findopt
s_i2w
=
GIT_DIFF_FIND_OPTIONS_INIT
;
git_diff_find_options
findopt
=
GIT_DIFF_FIND_OPTIONS_INIT
;
git_tree
*
head
=
NULL
;
git_status_show_t
show
=
opts
?
opts
->
show
:
GIT_STATUS_SHOW_INDEX_AND_WORKDIR
;
...
...
@@ -284,6 +266,7 @@ int git_status_list_new(
}
diffopt
.
flags
=
GIT_DIFF_INCLUDE_TYPECHANGE
;
findopt
.
flags
=
GIT_DIFF_FIND_FOR_UNTRACKED
;
if
((
flags
&
GIT_STATUS_OPT_INCLUDE_UNTRACKED
)
!=
0
)
diffopt
.
flags
=
diffopt
.
flags
|
GIT_DIFF_INCLUDE_UNTRACKED
;
...
...
@@ -300,7 +283,9 @@ int git_status_list_new(
if
((
flags
&
GIT_STATUS_OPT_EXCLUDE_SUBMODULES
)
!=
0
)
diffopt
.
flags
=
diffopt
.
flags
|
GIT_DIFF_IGNORE_SUBMODULES
;
findopts_i2w
.
flags
|=
GIT_DIFF_FIND_FOR_UNTRACKED
;
if
((
flags
&
GIT_STATUS_OPT_RENAMES_FROM_REWRITES
)
!=
0
)
findopt
.
flags
=
findopt
.
flags
|
GIT_DIFF_FIND_AND_BREAK_REWRITES
|
GIT_DIFF_FIND_RENAMES_FROM_REWRITES
;
if
(
show
!=
GIT_STATUS_SHOW_WORKDIR_ONLY
)
{
if
((
error
=
git_diff_tree_to_index
(
...
...
@@ -308,7 +293,7 @@ int git_status_list_new(
goto
done
;
if
((
flags
&
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
)
!=
0
&&
(
error
=
git_diff_find_similar
(
status
->
head2idx
,
NULL
))
<
0
)
(
error
=
git_diff_find_similar
(
status
->
head2idx
,
&
findopt
))
<
0
)
goto
done
;
}
...
...
@@ -318,7 +303,7 @@ int git_status_list_new(
goto
done
;
if
((
flags
&
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
)
!=
0
&&
(
error
=
git_diff_find_similar
(
status
->
idx2wd
,
&
findopt
s_i2w
))
<
0
)
(
error
=
git_diff_find_similar
(
status
->
idx2wd
,
&
findopt
))
<
0
)
goto
done
;
}
...
...
tests-clar/status/renames.c
View file @
fbb6c0c8
...
...
@@ -153,6 +153,65 @@ void test_status_renames__head2index_two(void)
git_index_free
(
index
);
}
void
test_status_renames__head2index_no_rename_from_rewrite
(
void
)
{
git_index
*
index
;
git_status_list
*
statuslist
;
git_status_options
opts
=
GIT_STATUS_OPTIONS_INIT
;
struct
status_entry
expected
[]
=
{
{
GIT_STATUS_INDEX_MODIFIED
,
"ikeepsix.txt"
,
"ikeepsix.txt"
},
{
GIT_STATUS_INDEX_MODIFIED
,
"sixserving.txt"
,
"sixserving.txt"
},
};
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
cl_git_pass
(
git_repository_index
(
&
index
,
g_repo
));
rename_file
(
g_repo
,
"ikeepsix.txt"
,
"_temp_.txt"
);
rename_file
(
g_repo
,
"sixserving.txt"
,
"ikeepsix.txt"
);
rename_file
(
g_repo
,
"_temp_.txt"
,
"sixserving.txt"
);
cl_git_pass
(
git_index_add_bypath
(
index
,
"ikeepsix.txt"
));
cl_git_pass
(
git_index_add_bypath
(
index
,
"sixserving.txt"
));
cl_git_pass
(
git_index_write
(
index
));
cl_git_pass
(
git_status_list_new
(
&
statuslist
,
g_repo
,
&
opts
));
test_status
(
statuslist
,
expected
,
2
);
git_status_list_free
(
statuslist
);
git_index_free
(
index
);
}
void
test_status_renames__head2index_rename_from_rewrite
(
void
)
{
git_index
*
index
;
git_status_list
*
statuslist
;
git_status_options
opts
=
GIT_STATUS_OPTIONS_INIT
;
struct
status_entry
expected
[]
=
{
{
GIT_STATUS_INDEX_RENAMED
,
"sixserving.txt"
,
"ikeepsix.txt"
},
{
GIT_STATUS_INDEX_RENAMED
,
"ikeepsix.txt"
,
"sixserving.txt"
},
};
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
cl_git_pass
(
git_repository_index
(
&
index
,
g_repo
));
rename_file
(
g_repo
,
"ikeepsix.txt"
,
"_temp_.txt"
);
rename_file
(
g_repo
,
"sixserving.txt"
,
"ikeepsix.txt"
);
rename_file
(
g_repo
,
"_temp_.txt"
,
"sixserving.txt"
);
cl_git_pass
(
git_index_add_bypath
(
index
,
"ikeepsix.txt"
));
cl_git_pass
(
git_index_add_bypath
(
index
,
"sixserving.txt"
));
cl_git_pass
(
git_index_write
(
index
));
cl_git_pass
(
git_status_list_new
(
&
statuslist
,
g_repo
,
&
opts
));
test_status
(
statuslist
,
expected
,
2
);
git_status_list_free
(
statuslist
);
git_index_free
(
index
);
}
void
test_status_renames__index2workdir_one
(
void
)
{
git_status_list
*
statuslist
;
...
...
@@ -197,6 +256,32 @@ void test_status_renames__index2workdir_two(void)
git_status_list_free
(
statuslist
);
}
void
test_status_renames__index2workdir_rename_from_rewrite
(
void
)
{
git_index
*
index
;
git_status_list
*
statuslist
;
git_status_options
opts
=
GIT_STATUS_OPTIONS_INIT
;
struct
status_entry
expected
[]
=
{
{
GIT_STATUS_WT_RENAMED
,
"sixserving.txt"
,
"ikeepsix.txt"
},
{
GIT_STATUS_WT_RENAMED
,
"ikeepsix.txt"
,
"sixserving.txt"
},
};
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
cl_git_pass
(
git_repository_index
(
&
index
,
g_repo
));
rename_file
(
g_repo
,
"ikeepsix.txt"
,
"_temp_.txt"
);
rename_file
(
g_repo
,
"sixserving.txt"
,
"ikeepsix.txt"
);
rename_file
(
g_repo
,
"_temp_.txt"
,
"sixserving.txt"
);
cl_git_pass
(
git_status_list_new
(
&
statuslist
,
g_repo
,
&
opts
));
test_status
(
statuslist
,
expected
,
2
);
git_status_list_free
(
statuslist
);
git_index_free
(
index
);
}
void
test_status_renames__both_one
(
void
)
{
git_index
*
index
;
...
...
@@ -274,6 +359,50 @@ void test_status_renames__both_two(void)
git_index_free
(
index
);
}
void
test_status_renames__both_rename_from_rewrite
(
void
)
{
git_index
*
index
;
git_status_list
*
statuslist
;
git_status_options
opts
=
GIT_STATUS_OPTIONS_INIT
;
struct
status_entry
expected
[]
=
{
{
GIT_STATUS_INDEX_RENAMED
|
GIT_STATUS_WT_RENAMED
,
"songof7cities.txt"
,
"ikeepsix.txt"
},
{
GIT_STATUS_INDEX_RENAMED
|
GIT_STATUS_WT_RENAMED
,
"ikeepsix.txt"
,
"sixserving.txt"
},
{
GIT_STATUS_INDEX_RENAMED
|
GIT_STATUS_WT_RENAMED
,
"sixserving.txt"
,
"songof7cities.txt"
},
};
opts
.
flags
|=
GIT_STATUS_OPT_INCLUDE_UNTRACKED
;
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
;
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
;
opts
.
flags
|=
GIT_STATUS_OPT_RENAMES_FROM_REWRITES
;
cl_git_pass
(
git_repository_index
(
&
index
,
g_repo
));
rename_file
(
g_repo
,
"ikeepsix.txt"
,
"_temp_.txt"
);
rename_file
(
g_repo
,
"sixserving.txt"
,
"ikeepsix.txt"
);
rename_file
(
g_repo
,
"songof7cities.txt"
,
"sixserving.txt"
);
rename_file
(
g_repo
,
"_temp_.txt"
,
"songof7cities.txt"
);
cl_git_pass
(
git_index_add_bypath
(
index
,
"ikeepsix.txt"
));
cl_git_pass
(
git_index_add_bypath
(
index
,
"sixserving.txt"
));
cl_git_pass
(
git_index_add_bypath
(
index
,
"songof7cities.txt"
));
cl_git_pass
(
git_index_write
(
index
));
rename_file
(
g_repo
,
"songof7cities.txt"
,
"_temp_.txt"
);
rename_file
(
g_repo
,
"ikeepsix.txt"
,
"songof7cities.txt"
);
rename_file
(
g_repo
,
"sixserving.txt"
,
"ikeepsix.txt"
);
rename_file
(
g_repo
,
"_temp_.txt"
,
"sixserving.txt"
);
cl_git_pass
(
git_status_list_new
(
&
statuslist
,
g_repo
,
&
opts
));
test_status
(
statuslist
,
expected
,
3
);
git_status_list_free
(
statuslist
);
git_index_free
(
index
);
}
void
test_status_renames__both_casechange_one
(
void
)
{
git_index
*
index
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment