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
443d5674
Commit
443d5674
authored
Jul 17, 2014
by
Edward Thomson
Committed by
Edward Thomson
Oct 26, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
git_rebase_next: write conflicts nicely during rebase
parent
950a7091
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
161 additions
and
18 deletions
+161
-18
src/rebase.c
+102
-18
tests/rebase/merge.c
+59
-0
No files found.
src/rebase.c
View file @
443d5674
...
...
@@ -49,6 +49,9 @@ typedef enum {
struct
git_rebase_state_merge
{
int32_t
msgnum
;
int32_t
end
;
char
*
onto_name
;
git_commit
*
current
;
};
typedef
struct
{
...
...
@@ -105,7 +108,9 @@ done:
static
int
rebase_state_merge
(
git_rebase_state
*
state
,
git_repository
*
repo
)
{
git_buf
path
=
GIT_BUF_INIT
,
msgnum
=
GIT_BUF_INIT
,
end
=
GIT_BUF_INIT
;
git_buf
path
=
GIT_BUF_INIT
,
msgnum
=
GIT_BUF_INIT
,
end
=
GIT_BUF_INIT
,
onto_name
=
GIT_BUF_INIT
,
current
=
GIT_BUF_INIT
;
git_oid
current_id
;
int
state_path_len
,
error
;
GIT_UNUSED
(
repo
);
...
...
@@ -115,10 +120,34 @@ static int rebase_state_merge(git_rebase_state *state, git_repository *repo)
state_path_len
=
git_buf_len
(
&
path
);
/* Read 'end' */
if
((
error
=
git_buf_joinpath
(
&
path
,
path
.
ptr
,
END_FILE
))
<
0
||
(
error
=
git_futils_readbuffer
(
&
end
,
path
.
ptr
))
<
0
)
goto
done
;
git_buf_rtrim
(
&
end
);
if
((
error
=
git__strtol32
(
&
state
->
merge
.
end
,
end
.
ptr
,
NULL
,
10
))
<
0
)
goto
done
;
/* Read 'onto_name' */
git_buf_truncate
(
&
path
,
state_path_len
);
if
((
error
=
git_buf_joinpath
(
&
path
,
path
.
ptr
,
ONTO_NAME_FILE
))
<
0
||
(
error
=
git_futils_readbuffer
(
&
onto_name
,
path
.
ptr
))
<
0
)
goto
done
;
git_buf_rtrim
(
&
onto_name
);
state
->
merge
.
onto_name
=
git_buf_detach
(
&
onto_name
);
/* Read 'msgnum' if it exists, otherwise let msgnum = 0 */
git_buf_truncate
(
&
path
,
state_path_len
);
if
((
error
=
git_buf_joinpath
(
&
path
,
path
.
ptr
,
MSGNUM_FILE
))
<
0
)
goto
done
;
if
(
git_path_
isfile
(
path
.
ptr
))
{
if
(
git_path_
exists
(
path
.
ptr
))
{
if
((
error
=
git_futils_readbuffer
(
&
msgnum
,
path
.
ptr
))
<
0
)
goto
done
;
...
...
@@ -128,21 +157,30 @@ static int rebase_state_merge(git_rebase_state *state, git_repository *repo)
goto
done
;
}
/* Read 'current' if it exists, otherwise let current = null */
git_buf_truncate
(
&
path
,
state_path_len
);
if
((
error
=
git_buf_joinpath
(
&
path
,
path
.
ptr
,
END_FILE
))
<
0
||
(
error
=
git_futils_readbuffer
(
&
end
,
path
.
ptr
))
<
0
)
if
((
error
=
git_buf_joinpath
(
&
path
,
path
.
ptr
,
CURRENT_FILE
))
<
0
)
goto
done
;
git_buf_rtrim
(
&
end
);
if
(
git_path_exists
(
path
.
ptr
))
{
if
((
error
=
git_futils_readbuffer
(
&
current
,
path
.
ptr
))
<
0
)
goto
done
;
if
((
error
=
git__strtol32
(
&
state
->
merge
.
end
,
end
.
ptr
,
NULL
,
10
))
<
0
)
goto
done
;
git_buf_rtrim
(
&
current
);
if
((
error
=
git_oid_fromstr
(
&
current_id
,
current
.
ptr
))
<
0
||
(
error
=
git_commit_lookup
(
&
state
->
merge
.
current
,
repo
,
&
current_id
))
<
0
)
goto
done
;
}
done:
git_buf_free
(
&
path
);
git_buf_free
(
&
msgnum
);
git_buf_free
(
&
end
);
git_buf_free
(
&
onto_name
);
git_buf_free
(
&
current
);
return
error
;
}
...
...
@@ -230,6 +268,11 @@ static void rebase_state_free(git_rebase_state *state)
if
(
state
==
NULL
)
return
;
if
(
state
->
type
==
GIT_REBASE_TYPE_MERGE
)
{
git__free
(
state
->
merge
.
onto_name
);
git_commit_free
(
state
->
merge
.
current
);
}
git__free
(
state
->
orig_head_name
);
git__free
(
state
->
state_path
);
}
...
...
@@ -492,14 +535,50 @@ done:
return
error
;
}
static
int
normalize_checkout_opts
(
git_repository
*
repo
,
git_checkout_options
*
checkout_opts
,
const
git_checkout_options
*
given_checkout_opts
,
const
git_rebase_state
*
state
)
{
int
error
=
0
;
GIT_UNUSED
(
repo
);
if
(
given_checkout_opts
!=
NULL
)
memcpy
(
checkout_opts
,
given_checkout_opts
,
sizeof
(
git_checkout_options
));
else
{
git_checkout_options
default_checkout_opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
default_checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_SAFE
;
memcpy
(
checkout_opts
,
&
default_checkout_opts
,
sizeof
(
git_checkout_options
));
}
if
(
!
checkout_opts
->
ancestor_label
)
checkout_opts
->
ancestor_label
=
"ancestor"
;
if
(
state
->
type
==
GIT_REBASE_TYPE_MERGE
)
{
if
(
!
checkout_opts
->
our_label
)
checkout_opts
->
our_label
=
state
->
merge
.
onto_name
;
if
(
!
checkout_opts
->
their_label
)
checkout_opts
->
their_label
=
git_commit_summary
(
state
->
merge
.
current
);
}
else
{
abort
();
}
return
error
;
}
static
int
rebase_next_merge
(
git_repository
*
repo
,
git_rebase_state
*
state
,
git_checkout_options
*
checkout_opts
)
git_checkout_options
*
given_
checkout_opts
)
{
git_buf
path
=
GIT_BUF_INIT
,
current
=
GIT_BUF_INIT
;
git_checkout_options
checkout_opts
=
{
0
};
git_oid
current_id
;
git_commit
*
current_commit
=
NULL
,
*
parent_commit
=
NULL
;
git_commit
*
parent_commit
=
NULL
;
git_tree
*
current_tree
=
NULL
,
*
head_tree
=
NULL
,
*
parent_tree
=
NULL
;
git_index
*
index
=
NULL
;
unsigned
int
parent_count
;
...
...
@@ -517,18 +596,21 @@ static int rebase_next_merge(
git_buf_rtrim
(
&
current
);
if
(
state
->
merge
.
current
)
git_commit_free
(
state
->
merge
.
current
);
if
((
error
=
git_oid_fromstr
(
&
current_id
,
current
.
ptr
))
<
0
||
(
error
=
git_commit_lookup
(
&
current_commi
t
,
repo
,
&
current_id
))
<
0
||
(
error
=
git_commit_tree
(
&
current_tree
,
current_commi
t
))
<
0
||
(
error
=
git_commit_lookup
(
&
state
->
merge
.
curren
t
,
repo
,
&
current_id
))
<
0
||
(
error
=
git_commit_tree
(
&
current_tree
,
state
->
merge
.
curren
t
))
<
0
||
(
error
=
git_repository_head_tree
(
&
head_tree
,
repo
))
<
0
)
goto
done
;
if
((
parent_count
=
git_commit_parentcount
(
current_commi
t
))
>
1
)
{
if
((
parent_count
=
git_commit_parentcount
(
state
->
merge
.
curren
t
))
>
1
)
{
giterr_set
(
GITERR_REBASE
,
"Cannot rebase a merge commit"
);
error
=
-
1
;
goto
done
;
}
else
if
(
parent_count
)
{
if
((
error
=
git_commit_parent
(
&
parent_commit
,
current_commi
t
,
0
))
<
0
||
if
((
error
=
git_commit_parent
(
&
parent_commit
,
state
->
merge
.
curren
t
,
0
))
<
0
||
(
error
=
git_commit_tree
(
&
parent_tree
,
parent_commit
))
<
0
)
goto
done
;
}
...
...
@@ -537,9 +619,10 @@ static int rebase_next_merge(
(
error
=
rebase_setupfile
(
repo
,
CURRENT_FILE
,
"%s
\n
"
,
current
.
ptr
))
<
0
)
goto
done
;
if
((
error
=
git_merge_trees
(
&
index
,
repo
,
parent_tree
,
head_tree
,
current_tree
,
NULL
))
<
0
||
if
((
error
=
normalize_checkout_opts
(
repo
,
&
checkout_opts
,
given_checkout_opts
,
state
))
<
0
||
(
error
=
git_merge_trees
(
&
index
,
repo
,
parent_tree
,
head_tree
,
current_tree
,
NULL
))
<
0
||
(
error
=
git_merge__check_result
(
repo
,
index
))
<
0
||
(
error
=
git_checkout_index
(
repo
,
index
,
checkout_opts
))
<
0
)
(
error
=
git_checkout_index
(
repo
,
index
,
&
checkout_opts
))
<
0
)
goto
done
;
done:
...
...
@@ -547,7 +630,6 @@ done:
git_tree_free
(
current_tree
);
git_tree_free
(
head_tree
);
git_tree_free
(
parent_tree
);
git_commit_free
(
current_commit
);
git_commit_free
(
parent_commit
);
git_buf_free
(
&
path
);
git_buf_free
(
&
current
);
...
...
@@ -555,7 +637,9 @@ done:
return
error
;
}
int
git_rebase_next
(
git_repository
*
repo
,
git_checkout_options
*
opts
)
int
git_rebase_next
(
git_repository
*
repo
,
git_checkout_options
*
checkout_opts
)
{
git_rebase_state
state
=
GIT_REBASE_STATE_INIT
;
int
error
;
...
...
@@ -567,7 +651,7 @@ int git_rebase_next(git_repository *repo, git_checkout_options *opts)
switch
(
state
.
type
)
{
case
GIT_REBASE_TYPE_MERGE
:
error
=
rebase_next_merge
(
repo
,
&
state
,
opts
);
error
=
rebase_next_merge
(
repo
,
&
state
,
checkout_
opts
);
break
;
default:
abort
();
...
...
tests/rebase/merge.c
View file @
443d5674
...
...
@@ -57,3 +57,62 @@ void test_rebase_merge__next(void)
git_reference_free
(
branch_ref
);
git_reference_free
(
upstream_ref
);
}
void
test_rebase_merge__next_with_conflicts
(
void
)
{
git_reference
*
branch_ref
,
*
upstream_ref
;
git_merge_head
*
branch_head
,
*
upstream_head
;
git_checkout_options
checkout_opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
git_status_list
*
status_list
;
const
git_status_entry
*
status_entry
;
const
char
*
expected_merge
=
"ASPARAGUS SOUP.
\n
"
"
\n
"
"<<<<<<< master
\n
"
"TAKE FOUR LARGE BUNCHES of asparagus, scrape it nicely, cut off one inch
\n
"
"OF THE TOPS, and lay them in water, chop the stalks and put them on the
\n
"
"FIRE WITH A PIECE OF BACON, a large onion cut up, and pepper and salt;
\n
"
"ADD TWO QUARTS OF WATER, boil them till the stalks are quite soft, then
\n
"
"PULP THEM THROUGH A SIEVE, and strain the water to it, which must be put
\n
"
"=======
\n
"
"Take four large bunches of asparagus, scrape it nicely, CUT OFF ONE INCH
\n
"
"of the tops, and lay them in water, chop the stalks and PUT THEM ON THE
\n
"
"fire with a piece of bacon, a large onion cut up, and pepper and salt;
\n
"
"add two quarts of water, boil them till the stalks are quite soft, then
\n
"
"pulp them through a sieve, and strain the water to it, which must be put
\n
"
">>>>>>> Conflicting modification 1 to asparagus
\n
"
"back in the pot; put into it a chicken cut up, with the tops of
\n
"
"asparagus which had been laid by, boil it until these last articles are
\n
"
"sufficiently done, thicken with flour, butter and milk, and serve it up.
\n
"
;
checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_SAFE
;
cl_git_pass
(
git_reference_lookup
(
&
branch_ref
,
repo
,
"refs/heads/asparagus"
));
cl_git_pass
(
git_reference_lookup
(
&
upstream_ref
,
repo
,
"refs/heads/master"
));
cl_git_pass
(
git_merge_head_from_ref
(
&
branch_head
,
repo
,
branch_ref
));
cl_git_pass
(
git_merge_head_from_ref
(
&
upstream_head
,
repo
,
upstream_ref
));
cl_git_pass
(
git_rebase
(
repo
,
branch_head
,
upstream_head
,
NULL
,
signature
,
NULL
));
cl_git_pass
(
git_rebase_next
(
repo
,
&
checkout_opts
));
cl_assert_equal_file
(
"33f915f9e4dbd9f4b24430e48731a59b45b15500
\n
"
,
41
,
"rebase/.git/rebase-merge/current"
);
cl_assert_equal_file
(
"1
\n
"
,
2
,
"rebase/.git/rebase-merge/msgnum"
);
cl_git_pass
(
git_status_list_new
(
&
status_list
,
repo
,
NULL
));
cl_assert_equal_i
(
1
,
git_status_list_entrycount
(
status_list
));
cl_assert
(
status_entry
=
git_status_byindex
(
status_list
,
0
));
cl_assert_equal_s
(
"asparagus.txt"
,
status_entry
->
head_to_index
->
new_file
.
path
);
cl_assert_equal_file
(
expected_merge
,
strlen
(
expected_merge
),
"rebase/asparagus.txt"
);
git_status_list_free
(
status_list
);
git_merge_head_free
(
branch_head
);
git_merge_head_free
(
upstream_head
);
git_reference_free
(
branch_ref
);
git_reference_free
(
upstream_ref
);
}
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