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
5a296ad0
Commit
5a296ad0
authored
Feb 12, 2016
by
Carlos Martín Nieto
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3610 from ethomson/rebase_bare
rebase: introduce bare rebasing
parents
2f2129b1
a202e0d4
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
441 additions
and
125 deletions
+441
-125
include/git2/rebase.h
+22
-1
src/rebase.c
+251
-118
tests/rebase/inmemory.c
+114
-0
tests/rebase/iterator.c
+24
-6
tests/rebase/merge.c
+30
-0
No files found.
include/git2/rebase.h
View file @
5a296ad0
...
@@ -39,6 +39,15 @@ typedef struct {
...
@@ -39,6 +39,15 @@ typedef struct {
int
quiet
;
int
quiet
;
/**
/**
* Used by `git_rebase_init`, this will begin an in-memory rebase,
* which will allow callers to step through the rebase operations and
* commit the rebased changes, but will not rewind HEAD or update the
* repository to be in a rebasing state. This will not interfere with
* the working directory (if there is one).
*/
int
inmemory
;
/**
* Used by `git_rebase_finish`, this is the name of the notes reference
* Used by `git_rebase_finish`, this is the name of the notes reference
* used to rewrite notes for rebased commits when finishing the rebase;
* used to rewrite notes for rebased commits when finishing the rebase;
* if NULL, the contents of the configuration option `notes.rewriteRef`
* if NULL, the contents of the configuration option `notes.rewriteRef`
...
@@ -49,6 +58,11 @@ typedef struct {
...
@@ -49,6 +58,11 @@ typedef struct {
const
char
*
rewrite_notes_ref
;
const
char
*
rewrite_notes_ref
;
/**
/**
* Options to control how trees are merged during `git_rebase_next`.
*/
git_merge_options
merge_options
;
/**
* Options to control how files are written during `git_rebase_init`,
* Options to control how files are written during `git_rebase_init`,
* `git_checkout_next` and `git_checkout_abort`. Note that a minimum
* `git_checkout_next` and `git_checkout_abort`. Note that a minimum
* strategy of `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`,
* strategy of `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`,
...
@@ -101,7 +115,8 @@ typedef enum {
...
@@ -101,7 +115,8 @@ typedef enum {
#define GIT_REBASE_OPTIONS_VERSION 1
#define GIT_REBASE_OPTIONS_VERSION 1
#define GIT_REBASE_OPTIONS_INIT \
#define GIT_REBASE_OPTIONS_INIT \
{GIT_REBASE_OPTIONS_VERSION, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT}
{ GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \
GIT_CHECKOUT_OPTIONS_INIT}
/** Indicates that a rebase operation is not (yet) in progress. */
/** Indicates that a rebase operation is not (yet) in progress. */
#define GIT_REBASE_NO_OPERATION SIZE_MAX
#define GIT_REBASE_NO_OPERATION SIZE_MAX
...
@@ -127,6 +142,12 @@ typedef struct {
...
@@ -127,6 +142,12 @@ typedef struct {
* be populated for operations of type `GIT_REBASE_OPERATION_EXEC`.
* be populated for operations of type `GIT_REBASE_OPERATION_EXEC`.
*/
*/
const
char
*
exec
;
const
char
*
exec
;
/**
* The index that is the result of an operation.
* This is set only for in-memory rebases.
*/
git_index
*
index
;
}
git_rebase_operation
;
}
git_rebase_operation
;
/**
/**
...
...
src/rebase.c
View file @
5a296ad0
...
@@ -63,17 +63,23 @@ struct git_rebase {
...
@@ -63,17 +63,23 @@ struct git_rebase {
char
*
state_path
;
char
*
state_path
;
int
head_detached
:
1
,
int
head_detached
:
1
,
inmemory
:
1
,
quiet
:
1
,
quiet
:
1
,
started
:
1
;
started
:
1
;
char
*
orig_head_name
;
git_array_t
(
git_rebase_operation
)
operations
;
size_t
current
;
/* Used by in-memory rebase */
git_commit
*
last_commit
;
git_index
*
last_index
;
/* Used by regular (not in-memory) merge-style rebase */
git_oid
orig_head_id
;
git_oid
orig_head_id
;
char
*
orig_head_name
;
git_oid
onto_id
;
git_oid
onto_id
;
char
*
onto_name
;
char
*
onto_name
;
git_array_t
(
git_rebase_operation
)
operations
;
size_t
current
;
};
};
#define GIT_REBASE_STATE_INIT {0}
#define GIT_REBASE_STATE_INIT {0}
...
@@ -393,6 +399,9 @@ done:
...
@@ -393,6 +399,9 @@ done:
static
int
rebase_cleanup
(
git_rebase
*
rebase
)
static
int
rebase_cleanup
(
git_rebase
*
rebase
)
{
{
if
(
!
rebase
||
rebase
->
inmemory
)
return
0
;
return
git_path_isdir
(
rebase
->
state_path
)
?
return
git_path_isdir
(
rebase
->
state_path
)
?
git_futils_rmdir_r
(
rebase
->
state_path
,
NULL
,
GIT_RMDIR_REMOVE_FILES
)
:
git_futils_rmdir_r
(
rebase
->
state_path
,
NULL
,
GIT_RMDIR_REMOVE_FILES
)
:
0
;
0
;
...
@@ -601,61 +610,65 @@ static int rebase_init_merge(
...
@@ -601,61 +610,65 @@ static int rebase_init_merge(
const
git_annotated_commit
*
upstream
,
const
git_annotated_commit
*
upstream
,
const
git_annotated_commit
*
onto
)
const
git_annotated_commit
*
onto
)
{
{
if
(
rebase_init_operations
(
rebase
,
repo
,
branch
,
upstream
,
onto
)
<
0
)
return
-
1
;
rebase
->
onto_name
=
git__strdup
(
rebase_onto_name
(
onto
));
GITERR_CHECK_ALLOC
(
rebase
->
onto_name
);
return
0
;
}
static
int
rebase_init
(
git_rebase
*
rebase
,
git_repository
*
repo
,
const
git_annotated_commit
*
branch
,
const
git_annotated_commit
*
upstream
,
const
git_annotated_commit
*
onto
)
{
git_reference
*
head_ref
=
NULL
;
git_reference
*
head_ref
=
NULL
;
git_annotated_commit
*
head_branch
=
NULL
;
git_commit
*
onto_commit
=
NULL
;
git_buf
reflog
=
GIT_BUF_INIT
;
git_buf
state_path
=
GIT_BUF_INIT
;
git_buf
state_path
=
GIT_BUF_INIT
;
int
error
;
int
error
;
GIT_UNUSED
(
upstream
);
if
((
error
=
git_buf_joinpath
(
&
state_path
,
repo
->
path_repository
,
REBASE_MERGE_DIR
))
<
0
)
if
((
error
=
git_buf_joinpath
(
&
state_path
,
repo
->
path_repository
,
REBASE_MERGE_DIR
))
<
0
)
goto
done
;
goto
done
;
if
(
!
branch
)
{
if
((
error
=
git_repository_head
(
&
head_ref
,
repo
))
<
0
||
(
error
=
git_annotated_commit_from_ref
(
&
head_branch
,
repo
,
head_ref
))
<
0
)
goto
done
;
branch
=
head_branch
;
}
rebase
->
repo
=
repo
;
rebase
->
type
=
GIT_REBASE_TYPE_MERGE
;
rebase
->
state_path
=
git_buf_detach
(
&
state_path
);
rebase
->
state_path
=
git_buf_detach
(
&
state_path
);
GITERR_CHECK_ALLOC
(
rebase
->
state_path
);
rebase
->
orig_head_name
=
git__strdup
(
branch
->
ref_name
?
branch
->
ref_name
:
ORIG_DETACHED_HEAD
);
rebase
->
orig_head_name
=
git__strdup
(
branch
->
ref_name
?
branch
->
ref_name
:
ORIG_DETACHED_HEAD
);
GITERR_CHECK_ALLOC
(
rebase
->
orig_head_name
);
rebase
->
onto_name
=
git__strdup
(
rebase_onto_name
(
onto
));
GITERR_CHECK_ALLOC
(
rebase
->
onto_name
);
rebase
->
quiet
=
rebase
->
options
.
quiet
;
rebase
->
quiet
=
rebase
->
options
.
quiet
;
git_oid_cpy
(
&
rebase
->
orig_head_id
,
git_annotated_commit_id
(
branch
));
git_oid_cpy
(
&
rebase
->
orig_head_id
,
git_annotated_commit_id
(
branch
));
git_oid_cpy
(
&
rebase
->
onto_id
,
git_annotated_commit_id
(
onto
));
git_oid_cpy
(
&
rebase
->
onto_id
,
git_annotated_commit_id
(
onto
));
if
(
!
rebase
->
orig_head_name
||
!
rebase
->
state_path
)
if
((
error
=
rebase_setupfiles
(
rebase
))
<
0
||
return
-
1
;
(
error
=
git_buf_printf
(
&
reflog
,
"rebase: checkout %s"
,
rebase_onto_name
(
onto
)))
<
0
||
error
=
rebase_init_merge
(
rebase
,
repo
,
branch
,
upstream
,
onto
);
(
error
=
git_commit_lookup
(
&
onto_commit
,
repo
,
git_annotated_commit_id
(
onto
)))
<
0
||
git_buf_free
(
&
state_path
);
(
error
=
git_checkout_tree
(
repo
,
(
git_object
*
)
onto_commit
,
&
rebase
->
options
.
checkout_options
))
<
0
||
(
error
=
git_reference_create
(
&
head_ref
,
repo
,
GIT_HEAD_FILE
,
git_annotated_commit_id
(
onto
),
1
,
reflog
.
ptr
))
<
0
)
goto
done
;
done
:
done
:
git_reference_free
(
head_ref
);
git_reference_free
(
head_ref
);
git_annotated_commit_free
(
head_branch
);
git_commit_free
(
onto_commit
);
git_buf_free
(
&
reflog
);
git_buf_free
(
&
state_path
);
return
error
;
return
error
;
}
}
static
int
rebase_init_inmemory
(
git_rebase
*
rebase
,
git_repository
*
repo
,
const
git_annotated_commit
*
branch
,
const
git_annotated_commit
*
upstream
,
const
git_annotated_commit
*
onto
)
{
GIT_UNUSED
(
branch
);
GIT_UNUSED
(
upstream
);
return
git_commit_lookup
(
&
rebase
->
last_commit
,
repo
,
git_annotated_commit_id
(
onto
));
}
int
git_rebase_init
(
int
git_rebase_init
(
git_rebase
**
out
,
git_rebase
**
out
,
git_repository
*
repo
,
git_repository
*
repo
,
...
@@ -665,9 +678,9 @@ int git_rebase_init(
...
@@ -665,9 +678,9 @@ int git_rebase_init(
const
git_rebase_options
*
given_opts
)
const
git_rebase_options
*
given_opts
)
{
{
git_rebase
*
rebase
=
NULL
;
git_rebase
*
rebase
=
NULL
;
git_buf
reflog
=
GIT_BUF_INIT
;
git_annotated_commit
*
head_branch
=
NULL
;
git_commit
*
onto_commit
=
NULL
;
git_reference
*
head_ref
=
NULL
;
git_reference
*
head_ref
=
NULL
;
bool
inmemory
=
(
given_opts
&&
given_opts
->
inmemory
);
int
error
;
int
error
;
assert
(
repo
&&
(
upstream
||
onto
));
assert
(
repo
&&
(
upstream
||
onto
));
...
@@ -677,39 +690,51 @@ int git_rebase_init(
...
@@ -677,39 +690,51 @@ int git_rebase_init(
if
(
!
onto
)
if
(
!
onto
)
onto
=
upstream
;
onto
=
upstream
;
if
((
error
=
rebase_check_versions
(
given_opts
))
<
0
||
if
((
error
=
rebase_check_versions
(
given_opts
))
<
0
)
(
error
=
git_repository__ensure_not_bare
(
repo
,
"rebase"
))
<
0
||
goto
done
;
(
error
=
rebase_ensure_not_in_progress
(
repo
))
<
0
||
(
error
=
rebase_ensure_not_dirty
(
repo
,
true
,
true
,
GIT_ERROR
))
<
0
||
if
(
!
inmemory
)
{
(
error
=
git_commit_lookup
(
if
((
error
=
git_repository__ensure_not_bare
(
repo
,
"rebase"
))
<
0
||
&
onto_commit
,
repo
,
git_annotated_commit_id
(
onto
)))
<
0
)
(
error
=
rebase_ensure_not_in_progress
(
repo
))
<
0
||
return
error
;
(
error
=
rebase_ensure_not_dirty
(
repo
,
true
,
true
,
GIT_ERROR
))
<
0
)
goto
done
;
}
if
(
!
branch
)
{
if
((
error
=
git_repository_head
(
&
head_ref
,
repo
))
<
0
||
(
error
=
git_annotated_commit_from_ref
(
&
head_branch
,
repo
,
head_ref
))
<
0
)
goto
done
;
branch
=
head_branch
;
}
rebase
=
rebase_alloc
(
given_opts
);
rebase
=
rebase_alloc
(
given_opts
);
GITERR_CHECK_ALLOC
(
rebase
);
if
((
error
=
rebase_init
(
rebase
->
repo
=
repo
;
rebase
,
repo
,
branch
,
upstream
,
onto
))
<
0
||
rebase
->
inmemory
=
inmemory
;
(
error
=
rebase_setupfiles
(
rebase
))
<
0
||
rebase
->
type
=
GIT_REBASE_TYPE_MERGE
;
(
error
=
git_buf_printf
(
&
reflog
,
"rebase: checkout %s"
,
rebase_onto_name
(
onto
)))
<
0
||
if
((
error
=
rebase_init_operations
(
rebase
,
repo
,
branch
,
upstream
,
onto
))
<
0
)
(
error
=
git_checkout_tree
(
repo
,
(
git_object
*
)
onto_commit
,
&
rebase
->
options
.
checkout_options
))
<
0
||
(
error
=
git_reference_create
(
&
head_ref
,
repo
,
GIT_HEAD_FILE
,
git_annotated_commit_id
(
onto
),
1
,
reflog
.
ptr
))
<
0
)
goto
done
;
goto
done
;
*
out
=
rebase
;
if
(
inmemory
)
error
=
rebase_init_inmemory
(
rebase
,
repo
,
branch
,
upstream
,
onto
);
else
rebase_init_merge
(
rebase
,
repo
,
branch
,
upstream
,
onto
);
if
(
error
==
0
)
*
out
=
rebase
;
done
:
done
:
git_reference_free
(
head_ref
);
git_reference_free
(
head_ref
);
git_annotated_commit_free
(
head_branch
);
if
(
error
<
0
)
{
if
(
error
<
0
)
{
rebase_cleanup
(
rebase
);
rebase_cleanup
(
rebase
);
git_rebase_free
(
rebase
);
git_rebase_free
(
rebase
);
}
}
git_commit_free
(
onto_commit
);
git_buf_free
(
&
reflog
);
return
error
;
return
error
;
}
}
...
@@ -764,9 +789,6 @@ static int rebase_next_merge(
...
@@ -764,9 +789,6 @@ static int rebase_next_merge(
*
out
=
NULL
;
*
out
=
NULL
;
if
((
error
=
rebase_movenext
(
rebase
))
<
0
)
goto
done
;
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
if
((
error
=
git_commit_lookup
(
&
current_commit
,
rebase
->
repo
,
&
operation
->
id
))
<
0
||
if
((
error
=
git_commit_lookup
(
&
current_commit
,
rebase
->
repo
,
&
operation
->
id
))
<
0
||
...
@@ -791,7 +813,7 @@ static int rebase_next_merge(
...
@@ -791,7 +813,7 @@ static int rebase_next_merge(
if
((
error
=
git_indexwriter_init_for_operation
(
&
indexwriter
,
rebase
->
repo
,
&
checkout_opts
.
checkout_strategy
))
<
0
||
if
((
error
=
git_indexwriter_init_for_operation
(
&
indexwriter
,
rebase
->
repo
,
&
checkout_opts
.
checkout_strategy
))
<
0
||
(
error
=
rebase_setupfile
(
rebase
,
MSGNUM_FILE
,
-
1
,
"%"
PRIuZ
"
\n
"
,
rebase
->
current
+
1
))
<
0
||
(
error
=
rebase_setupfile
(
rebase
,
MSGNUM_FILE
,
-
1
,
"%"
PRIuZ
"
\n
"
,
rebase
->
current
+
1
))
<
0
||
(
error
=
rebase_setupfile
(
rebase
,
CURRENT_FILE
,
-
1
,
"%.*s
\n
"
,
GIT_OID_HEXSZ
,
current_idstr
))
<
0
||
(
error
=
rebase_setupfile
(
rebase
,
CURRENT_FILE
,
-
1
,
"%.*s
\n
"
,
GIT_OID_HEXSZ
,
current_idstr
))
<
0
||
(
error
=
git_merge_trees
(
&
index
,
rebase
->
repo
,
parent_tree
,
head_tree
,
current_tree
,
NULL
))
<
0
||
(
error
=
git_merge_trees
(
&
index
,
rebase
->
repo
,
parent_tree
,
head_tree
,
current_tree
,
&
rebase
->
options
.
merge_options
))
<
0
||
(
error
=
git_merge__check_result
(
rebase
->
repo
,
index
))
<
0
||
(
error
=
git_merge__check_result
(
rebase
->
repo
,
index
))
<
0
||
(
error
=
git_checkout_index
(
rebase
->
repo
,
index
,
&
checkout_opts
))
<
0
||
(
error
=
git_checkout_index
(
rebase
->
repo
,
index
,
&
checkout_opts
))
<
0
||
(
error
=
git_indexwriter_commit
(
&
indexwriter
))
<
0
)
(
error
=
git_indexwriter_commit
(
&
indexwriter
))
<
0
)
...
@@ -812,6 +834,46 @@ done:
...
@@ -812,6 +834,46 @@ done:
return
error
;
return
error
;
}
}
static
int
rebase_next_inmemory
(
git_rebase_operation
**
out
,
git_rebase
*
rebase
)
{
git_commit
*
current_commit
=
NULL
,
*
parent_commit
=
NULL
;
git_tree
*
current_tree
=
NULL
,
*
head_tree
=
NULL
,
*
parent_tree
=
NULL
;
git_rebase_operation
*
operation
;
git_index
*
index
=
NULL
;
int
error
;
*
out
=
NULL
;
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
if
((
error
=
git_commit_lookup
(
&
current_commit
,
rebase
->
repo
,
&
operation
->
id
))
<
0
||
(
error
=
git_commit_tree
(
&
current_tree
,
current_commit
))
<
0
||
(
error
=
git_commit_parent
(
&
parent_commit
,
current_commit
,
0
))
<
0
||
(
error
=
git_commit_tree
(
&
parent_tree
,
parent_commit
))
<
0
||
(
error
=
git_commit_tree
(
&
head_tree
,
rebase
->
last_commit
))
<
0
||
(
error
=
git_merge_trees
(
&
index
,
rebase
->
repo
,
parent_tree
,
head_tree
,
current_tree
,
&
rebase
->
options
.
merge_options
))
<
0
)
goto
done
;
git_index_free
(
rebase
->
last_index
);
rebase
->
last_index
=
index
;
operation
->
index
=
index
;
index
=
NULL
;
*
out
=
operation
;
done
:
git_commit_free
(
current_commit
);
git_commit_free
(
parent_commit
);
git_tree_free
(
current_tree
);
git_tree_free
(
head_tree
);
git_tree_free
(
parent_tree
);
git_index_free
(
index
);
return
error
;
}
int
git_rebase_next
(
int
git_rebase_next
(
git_rebase_operation
**
out
,
git_rebase_operation
**
out
,
git_rebase
*
rebase
)
git_rebase
*
rebase
)
...
@@ -820,66 +882,55 @@ int git_rebase_next(
...
@@ -820,66 +882,55 @@ int git_rebase_next(
assert
(
out
&&
rebase
);
assert
(
out
&&
rebase
);
switch
(
rebase
->
type
)
{
if
((
error
=
rebase_movenext
(
rebase
))
<
0
)
case
GIT_REBASE_TYPE_MERGE
:
return
error
;
if
(
rebase
->
inmemory
)
error
=
rebase_next_inmemory
(
out
,
rebase
);
else
if
(
rebase
->
type
==
GIT_REBASE_TYPE_MERGE
)
error
=
rebase_next_merge
(
out
,
rebase
);
error
=
rebase_next_merge
(
out
,
rebase
);
break
;
else
default
:
abort
();
abort
();
}
return
error
;
return
error
;
}
}
static
int
rebase_commit_
merg
e
(
static
int
rebase_commit_
_creat
e
(
git_
oid
*
commit_id
,
git_
commit
**
out
,
git_rebase
*
rebase
,
git_rebase
*
rebase
,
git_index
*
index
,
git_commit
*
parent_commit
,
const
git_signature
*
author
,
const
git_signature
*
author
,
const
git_signature
*
committer
,
const
git_signature
*
committer
,
const
char
*
message_encoding
,
const
char
*
message_encoding
,
const
char
*
message
)
const
char
*
message
)
{
{
git_index
*
index
=
NULL
;
git_reference
*
head
=
NULL
;
git_commit
*
current_commit
=
NULL
,
*
head_commit
=
NULL
,
*
commit
=
NULL
;
git_rebase_operation
*
operation
;
git_rebase_operation
*
operation
;
git_tree
*
head_tree
=
NULL
,
*
tree
=
NULL
;
git_commit
*
current_commit
=
NULL
,
*
commit
=
NULL
;
git_diff
*
diff
=
NULL
;
git_tree
*
parent_tree
=
NULL
,
*
tree
=
NULL
;
git_oid
tree_id
;
git_oid
tree_id
,
commit_id
;
git_buf
reflog_msg
=
GIT_BUF_INIT
;
char
old_idstr
[
GIT_OID_HEXSZ
],
new_idstr
[
GIT_OID_HEXSZ
];
int
error
;
int
error
;
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
assert
(
operation
);
if
((
error
=
git_repository_index
(
&
index
,
rebase
->
repo
))
<
0
)
goto
done
;
if
(
git_index_has_conflicts
(
index
))
{
if
(
git_index_has_conflicts
(
index
))
{
giterr_set
(
GITERR_REBASE
,
"
C
onflicts have not been resolved"
);
giterr_set
(
GITERR_REBASE
,
"
c
onflicts have not been resolved"
);
error
=
GIT_EUNMERGED
;
error
=
GIT_EUNMERGED
;
goto
done
;
goto
done
;
}
}
if
((
error
=
rebase_ensure_not_dirty
(
rebase
->
repo
,
false
,
true
,
GIT_EUNMERGED
))
<
0
||
if
((
error
=
git_commit_lookup
(
&
current_commit
,
rebase
->
repo
,
&
operation
->
id
))
<
0
||
(
error
=
git_commit_lookup
(
&
current_commit
,
rebase
->
repo
,
&
operation
->
id
))
<
0
||
(
error
=
git_commit_tree
(
&
parent_tree
,
parent_commit
))
<
0
||
(
error
=
git_repository_head
(
&
head
,
rebase
->
repo
))
<
0
||
(
error
=
git_index_write_tree_to
(
&
tree_id
,
index
,
rebase
->
repo
))
<
0
||
(
error
=
git_reference_peel
((
git_object
**
)
&
head_commit
,
head
,
GIT_OBJ_COMMIT
))
<
0
||
(
error
=
git_tree_lookup
(
&
tree
,
rebase
->
repo
,
&
tree_id
))
<
0
)
(
error
=
git_commit_tree
(
&
head_tree
,
head_commit
))
<
0
||
(
error
=
git_diff_tree_to_index
(
&
diff
,
rebase
->
repo
,
head_tree
,
index
,
NULL
))
<
0
)
goto
done
;
goto
done
;
if
(
git_
diff_num_deltas
(
diff
)
==
0
)
{
if
(
git_
oid_equal
(
&
tree_id
,
git_tree_id
(
parent_tree
))
)
{
giterr_set
(
GITERR_REBASE
,
"
T
his patch has already been applied"
);
giterr_set
(
GITERR_REBASE
,
"
t
his patch has already been applied"
);
error
=
GIT_EAPPLIED
;
error
=
GIT_EAPPLIED
;
goto
done
;
goto
done
;
}
}
if
((
error
=
git_index_write_tree
(
&
tree_id
,
index
))
<
0
||
(
error
=
git_tree_lookup
(
&
tree
,
rebase
->
repo
,
&
tree_id
))
<
0
)
goto
done
;
if
(
!
author
)
if
(
!
author
)
author
=
git_commit_author
(
current_commit
);
author
=
git_commit_author
(
current_commit
);
...
@@ -888,30 +939,104 @@ static int rebase_commit_merge(
...
@@ -888,30 +939,104 @@ static int rebase_commit_merge(
message
=
git_commit_message
(
current_commit
);
message
=
git_commit_message
(
current_commit
);
}
}
if
((
error
=
git_commit_create
(
commit_id
,
rebase
->
repo
,
NULL
,
author
,
if
((
error
=
git_commit_create
(
&
commit_id
,
rebase
->
repo
,
NULL
,
author
,
committer
,
message_encoding
,
message
,
tree
,
1
,
committer
,
message_encoding
,
message
,
tree
,
1
,
(
const
git_commit
**
)
&
head_commit
))
<
0
||
(
const
git_commit
**
)
&
parent_commit
))
<
0
||
(
error
=
git_commit_lookup
(
&
commit
,
rebase
->
repo
,
commit_id
))
<
0
||
(
error
=
git_commit_lookup
(
&
commit
,
rebase
->
repo
,
&
commit_id
))
<
0
)
goto
done
;
*
out
=
commit
;
done
:
if
(
error
<
0
)
git_commit_free
(
commit
);
git_commit_free
(
current_commit
);
git_tree_free
(
parent_tree
);
git_tree_free
(
tree
);
return
error
;
}
static
int
rebase_commit_merge
(
git_oid
*
commit_id
,
git_rebase
*
rebase
,
const
git_signature
*
author
,
const
git_signature
*
committer
,
const
char
*
message_encoding
,
const
char
*
message
)
{
git_rebase_operation
*
operation
;
git_reference
*
head
=
NULL
;
git_commit
*
head_commit
=
NULL
,
*
commit
=
NULL
;
git_index
*
index
=
NULL
;
char
old_idstr
[
GIT_OID_HEXSZ
],
new_idstr
[
GIT_OID_HEXSZ
];
int
error
;
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
assert
(
operation
);
if
((
error
=
rebase_ensure_not_dirty
(
rebase
->
repo
,
false
,
true
,
GIT_EUNMERGED
))
<
0
||
(
error
=
git_repository_head
(
&
head
,
rebase
->
repo
))
<
0
||
(
error
=
git_reference_peel
((
git_object
**
)
&
head_commit
,
head
,
GIT_OBJ_COMMIT
))
<
0
||
(
error
=
git_repository_index
(
&
index
,
rebase
->
repo
))
<
0
||
(
error
=
rebase_commit__create
(
&
commit
,
rebase
,
index
,
head_commit
,
author
,
committer
,
message_encoding
,
message
))
<
0
||
(
error
=
git_reference__update_for_commit
(
(
error
=
git_reference__update_for_commit
(
rebase
->
repo
,
NULL
,
"HEAD"
,
commit_id
,
"rebase"
))
<
0
)
rebase
->
repo
,
NULL
,
"HEAD"
,
git_commit_id
(
commit
)
,
"rebase"
))
<
0
)
goto
done
;
goto
done
;
git_oid_fmt
(
old_idstr
,
git_commit_id
(
current_commit
));
git_oid_fmt
(
old_idstr
,
&
operation
->
id
);
git_oid_fmt
(
new_idstr
,
commit_id
);
git_oid_fmt
(
new_idstr
,
git_commit_id
(
commit
));
if
((
error
=
rebase_setupfile
(
rebase
,
REWRITTEN_FILE
,
O_CREAT
|
O_WRONLY
|
O_APPEND
,
"%.*s %.*s
\n
"
,
GIT_OID_HEXSZ
,
old_idstr
,
GIT_OID_HEXSZ
,
new_idstr
))
<
0
)
goto
done
;
error
=
rebase_setupfile
(
rebase
,
REWRITTEN_FILE
,
O_CREAT
|
O_WRONLY
|
O_APPEND
,
git_oid_cpy
(
commit_id
,
git_commit_id
(
commit
));
"%.*s %.*s
\n
"
,
GIT_OID_HEXSZ
,
old_idstr
,
GIT_OID_HEXSZ
,
new_idstr
);
done
:
done
:
git_buf_free
(
&
reflog_msg
);
git_commit_free
(
commit
);
git_diff_free
(
diff
);
git_tree_free
(
tree
);
git_tree_free
(
head_tree
);
git_commit_free
(
head_commit
);
git_commit_free
(
current_commit
);
git_reference_free
(
head
);
git_index_free
(
index
);
git_index_free
(
index
);
git_reference_free
(
head
);
git_commit_free
(
head_commit
);
git_commit_free
(
commit
);
return
error
;
}
static
int
rebase_commit_inmemory
(
git_oid
*
commit_id
,
git_rebase
*
rebase
,
const
git_signature
*
author
,
const
git_signature
*
committer
,
const
char
*
message_encoding
,
const
char
*
message
)
{
git_rebase_operation
*
operation
;
git_commit
*
commit
=
NULL
;
int
error
=
0
;
operation
=
git_array_get
(
rebase
->
operations
,
rebase
->
current
);
assert
(
operation
);
assert
(
operation
->
index
);
assert
(
rebase
->
last_commit
);
if
((
error
=
rebase_commit__create
(
&
commit
,
rebase
,
operation
->
index
,
rebase
->
last_commit
,
author
,
committer
,
message_encoding
,
message
))
<
0
)
goto
done
;
git_index_free
(
rebase
->
last_index
);
operation
->
index
=
NULL
;
rebase
->
last_index
=
NULL
;
git_commit_free
(
rebase
->
last_commit
);
rebase
->
last_commit
=
commit
;
git_oid_cpy
(
commit_id
,
git_commit_id
(
commit
));
done
:
if
(
error
<
0
)
git_commit_free
(
commit
);
return
error
;
return
error
;
}
}
...
@@ -928,14 +1053,14 @@ int git_rebase_commit(
...
@@ -928,14 +1053,14 @@ int git_rebase_commit(
assert
(
rebase
&&
committer
);
assert
(
rebase
&&
committer
);
switch
(
rebase
->
type
)
{
if
(
rebase
->
inmemory
)
case
GIT_REBASE_TYPE_MERGE
:
error
=
rebase_commit_inmemory
(
id
,
rebase
,
author
,
committer
,
message_encoding
,
message
);
else
if
(
rebase
->
type
==
GIT_REBASE_TYPE_MERGE
)
error
=
rebase_commit_merge
(
error
=
rebase_commit_merge
(
id
,
rebase
,
author
,
committer
,
message_encoding
,
message
);
id
,
rebase
,
author
,
committer
,
message_encoding
,
message
);
break
;
else
default
:
abort
();
abort
();
}
return
error
;
return
error
;
}
}
...
@@ -948,6 +1073,9 @@ int git_rebase_abort(git_rebase *rebase)
...
@@ -948,6 +1073,9 @@ int git_rebase_abort(git_rebase *rebase)
assert
(
rebase
);
assert
(
rebase
);
if
(
rebase
->
inmemory
)
return
0
;
error
=
rebase
->
head_detached
?
error
=
rebase
->
head_detached
?
git_reference_create
(
&
orig_head_ref
,
rebase
->
repo
,
GIT_HEAD_FILE
,
git_reference_create
(
&
orig_head_ref
,
rebase
->
repo
,
GIT_HEAD_FILE
,
&
rebase
->
orig_head_id
,
1
,
"rebase: aborting"
)
:
&
rebase
->
orig_head_id
,
1
,
"rebase: aborting"
)
:
...
@@ -1125,6 +1253,9 @@ int git_rebase_finish(
...
@@ -1125,6 +1253,9 @@ int git_rebase_finish(
assert
(
rebase
);
assert
(
rebase
);
if
(
rebase
->
inmemory
)
return
0
;
git_oid_fmt
(
onto
,
&
rebase
->
onto_id
);
git_oid_fmt
(
onto
,
&
rebase
->
onto_id
);
if
((
error
=
git_buf_printf
(
&
branch_msg
,
"rebase finished: %s onto %.*s"
,
if
((
error
=
git_buf_printf
(
&
branch_msg
,
"rebase finished: %s onto %.*s"
,
...
@@ -1182,6 +1313,8 @@ void git_rebase_free(git_rebase *rebase)
...
@@ -1182,6 +1313,8 @@ void git_rebase_free(git_rebase *rebase)
if
(
rebase
==
NULL
)
if
(
rebase
==
NULL
)
return
;
return
;
git_index_free
(
rebase
->
last_index
);
git_commit_free
(
rebase
->
last_commit
);
git__free
(
rebase
->
onto_name
);
git__free
(
rebase
->
onto_name
);
git__free
(
rebase
->
orig_head_name
);
git__free
(
rebase
->
orig_head_name
);
git__free
(
rebase
->
state_path
);
git__free
(
rebase
->
state_path
);
...
...
tests/rebase/inmemory.c
0 → 100644
View file @
5a296ad0
#include "clar_libgit2.h"
#include "git2/rebase.h"
#include "posix.h"
#include <fcntl.h>
static
git_repository
*
repo
;
// Fixture setup and teardown
void
test_rebase_inmemory__initialize
(
void
)
{
repo
=
cl_git_sandbox_init
(
"rebase"
);
}
void
test_rebase_inmemory__cleanup
(
void
)
{
cl_git_sandbox_cleanup
();
}
void
test_rebase_inmemory__not_in_rebase_state
(
void
)
{
git_rebase
*
rebase
;
git_reference
*
branch_ref
,
*
upstream_ref
;
git_annotated_commit
*
branch_head
,
*
upstream_head
;
git_rebase_options
opts
=
GIT_REBASE_OPTIONS_INIT
;
opts
.
inmemory
=
true
;
cl_git_pass
(
git_reference_lookup
(
&
branch_ref
,
repo
,
"refs/heads/beef"
));
cl_git_pass
(
git_reference_lookup
(
&
upstream_ref
,
repo
,
"refs/heads/master"
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
branch_head
,
repo
,
branch_ref
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
upstream_head
,
repo
,
upstream_ref
));
cl_git_pass
(
git_rebase_init
(
&
rebase
,
repo
,
branch_head
,
upstream_head
,
NULL
,
&
opts
));
cl_assert_equal_i
(
GIT_REPOSITORY_STATE_NONE
,
git_repository_state
(
repo
));
git_rebase_free
(
rebase
);
git_annotated_commit_free
(
branch_head
);
git_annotated_commit_free
(
upstream_head
);
git_reference_free
(
branch_ref
);
git_reference_free
(
upstream_ref
);
}
void
test_rebase_inmemory__can_resolve_conflicts
(
void
)
{
git_rebase
*
rebase
;
git_reference
*
branch_ref
,
*
upstream_ref
;
git_annotated_commit
*
branch_head
,
*
upstream_head
;
git_rebase_operation
*
rebase_operation
;
git_status_list
*
status_list
;
git_oid
pick_id
,
commit_id
,
expected_commit_id
;
git_signature
*
signature
;
git_index
*
repo_index
;
git_index_entry
resolution
=
{{
0
}};
git_rebase_options
opts
=
GIT_REBASE_OPTIONS_INIT
;
cl_git_pass
(
git_signature_new
(
&
signature
,
"Rebaser"
,
"rebaser@rebaser.rb"
,
1405694510
,
0
));
opts
.
inmemory
=
true
;
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_annotated_commit_from_ref
(
&
branch_head
,
repo
,
branch_ref
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
upstream_head
,
repo
,
upstream_ref
));
cl_git_pass
(
git_rebase_init
(
&
rebase
,
repo
,
branch_head
,
upstream_head
,
NULL
,
&
opts
));
cl_git_pass
(
git_rebase_next
(
&
rebase_operation
,
rebase
));
git_oid_fromstr
(
&
pick_id
,
"33f915f9e4dbd9f4b24430e48731a59b45b15500"
);
cl_assert_equal_i
(
GIT_REBASE_OPERATION_PICK
,
rebase_operation
->
type
);
cl_assert_equal_oid
(
&
pick_id
,
&
rebase_operation
->
id
);
/* ensure that we did not do anything stupid to the workdir or repo index */
cl_git_pass
(
git_repository_index
(
&
repo_index
,
repo
));
cl_assert
(
!
git_index_has_conflicts
(
repo_index
));
cl_git_pass
(
git_status_list_new
(
&
status_list
,
repo
,
NULL
));
cl_assert_equal_i
(
0
,
git_status_list_entrycount
(
status_list
));
/* but that the index returned from rebase does have conflicts */
cl_assert
(
git_index_has_conflicts
(
rebase_operation
->
index
));
cl_git_fail_with
(
GIT_EUNMERGED
,
git_rebase_commit
(
&
commit_id
,
rebase
,
NULL
,
signature
,
NULL
,
NULL
));
/* ensure that we can work with the in-memory index to resolve the conflict */
resolution
.
path
=
"asparagus.txt"
;
resolution
.
mode
=
GIT_FILEMODE_BLOB
;
git_oid_fromstr
(
&
resolution
.
id
,
"414dfc71ead79c07acd4ea47fecf91f289afc4b9"
);
cl_git_pass
(
git_index_conflict_remove
(
rebase_operation
->
index
,
"asparagus.txt"
));
cl_git_pass
(
git_index_add
(
rebase_operation
->
index
,
&
resolution
));
/* and finally create a commit for the resolved rebase operation */
cl_git_pass
(
git_rebase_commit
(
&
commit_id
,
rebase
,
NULL
,
signature
,
NULL
,
NULL
));
cl_git_pass
(
git_oid_fromstr
(
&
expected_commit_id
,
"db7af47222181e548810da2ab5fec0e9357c5637"
));
cl_assert_equal_oid
(
&
commit_id
,
&
expected_commit_id
);
git_signature_free
(
signature
);
git_status_list_free
(
status_list
);
git_annotated_commit_free
(
branch_head
);
git_annotated_commit_free
(
upstream_head
);
git_reference_free
(
branch_ref
);
git_reference_free
(
upstream_ref
);
git_index_free
(
repo_index
);
git_rebase_free
(
rebase
);
}
tests/rebase/iterator.c
View file @
5a296ad0
...
@@ -46,26 +46,32 @@ static void test_operations(git_rebase *rebase, size_t expected_current)
...
@@ -46,26 +46,32 @@ static void test_operations(git_rebase *rebase, size_t expected_current)
}
}
}
}
void
test_
rebase_iterator__iterates
(
void
)
void
test_
iterator
(
bool
inmemory
)
{
{
git_rebase
*
rebase
;
git_rebase
*
rebase
;
git_rebase_options
opts
=
GIT_REBASE_OPTIONS_INIT
;
git_reference
*
branch_ref
,
*
upstream_ref
;
git_reference
*
branch_ref
,
*
upstream_ref
;
git_annotated_commit
*
branch_head
,
*
upstream_head
;
git_annotated_commit
*
branch_head
,
*
upstream_head
;
git_rebase_operation
*
rebase_operation
;
git_rebase_operation
*
rebase_operation
;
git_oid
commit_id
;
git_oid
commit_id
;
int
error
;
int
error
;
opts
.
inmemory
=
inmemory
;
cl_git_pass
(
git_reference_lookup
(
&
branch_ref
,
repo
,
"refs/heads/beef"
));
cl_git_pass
(
git_reference_lookup
(
&
branch_ref
,
repo
,
"refs/heads/beef"
));
cl_git_pass
(
git_reference_lookup
(
&
upstream_ref
,
repo
,
"refs/heads/master"
));
cl_git_pass
(
git_reference_lookup
(
&
upstream_ref
,
repo
,
"refs/heads/master"
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
branch_head
,
repo
,
branch_ref
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
branch_head
,
repo
,
branch_ref
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
upstream_head
,
repo
,
upstream_ref
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
upstream_head
,
repo
,
upstream_ref
));
cl_git_pass
(
git_rebase_init
(
&
rebase
,
repo
,
branch_head
,
upstream_head
,
NULL
,
NULL
));
cl_git_pass
(
git_rebase_init
(
&
rebase
,
repo
,
branch_head
,
upstream_head
,
NULL
,
&
opts
));
test_operations
(
rebase
,
GIT_REBASE_NO_OPERATION
);
test_operations
(
rebase
,
GIT_REBASE_NO_OPERATION
);
git_rebase_free
(
rebase
);
cl_git_pass
(
git_rebase_open
(
&
rebase
,
repo
,
NULL
));
if
(
!
inmemory
)
{
git_rebase_free
(
rebase
);
cl_git_pass
(
git_rebase_open
(
&
rebase
,
repo
,
NULL
));
}
cl_git_pass
(
git_rebase_next
(
&
rebase_operation
,
rebase
));
cl_git_pass
(
git_rebase_next
(
&
rebase_operation
,
rebase
));
cl_git_pass
(
git_rebase_commit
(
&
commit_id
,
rebase
,
NULL
,
signature
,
cl_git_pass
(
git_rebase_commit
(
&
commit_id
,
rebase
,
NULL
,
signature
,
NULL
,
NULL
));
NULL
,
NULL
));
...
@@ -81,8 +87,10 @@ void test_rebase_iterator__iterates(void)
...
@@ -81,8 +87,10 @@ void test_rebase_iterator__iterates(void)
NULL
,
NULL
));
NULL
,
NULL
));
test_operations
(
rebase
,
2
);
test_operations
(
rebase
,
2
);
git_rebase_free
(
rebase
);
if
(
!
inmemory
)
{
cl_git_pass
(
git_rebase_open
(
&
rebase
,
repo
,
NULL
));
git_rebase_free
(
rebase
);
cl_git_pass
(
git_rebase_open
(
&
rebase
,
repo
,
NULL
));
}
cl_git_pass
(
git_rebase_next
(
&
rebase_operation
,
rebase
));
cl_git_pass
(
git_rebase_next
(
&
rebase_operation
,
rebase
));
cl_git_pass
(
git_rebase_commit
(
&
commit_id
,
rebase
,
NULL
,
signature
,
cl_git_pass
(
git_rebase_commit
(
&
commit_id
,
rebase
,
NULL
,
signature
,
...
@@ -104,3 +112,13 @@ void test_rebase_iterator__iterates(void)
...
@@ -104,3 +112,13 @@ void test_rebase_iterator__iterates(void)
git_reference_free
(
upstream_ref
);
git_reference_free
(
upstream_ref
);
git_rebase_free
(
rebase
);
git_rebase_free
(
rebase
);
}
}
void
test_rebase_iterator__iterates
(
void
)
{
test_iterator
(
false
);
}
void
test_rebase_iterator__iterates_inmemory
(
void
)
{
test_iterator
(
true
);
}
tests/rebase/merge.c
View file @
5a296ad0
...
@@ -565,3 +565,33 @@ void test_rebase_merge__custom_checkout_options(void)
...
@@ -565,3 +565,33 @@ void test_rebase_merge__custom_checkout_options(void)
git_reference_free
(
upstream_ref
);
git_reference_free
(
upstream_ref
);
git_rebase_free
(
rebase
);
git_rebase_free
(
rebase
);
}
}
void
test_rebase_merge__custom_merge_options
(
void
)
{
git_rebase
*
rebase
;
git_reference
*
branch_ref
,
*
upstream_ref
;
git_annotated_commit
*
branch_head
,
*
upstream_head
;
git_rebase_options
rebase_options
=
GIT_REBASE_OPTIONS_INIT
;
git_rebase_operation
*
rebase_operation
;
rebase_options
.
merge_options
.
flags
|=
GIT_MERGE_FAIL_ON_CONFLICT
|
GIT_MERGE_SKIP_REUC
;
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_annotated_commit_from_ref
(
&
branch_head
,
repo
,
branch_ref
));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
upstream_head
,
repo
,
upstream_ref
));
cl_git_pass
(
git_rebase_init
(
&
rebase
,
repo
,
branch_head
,
upstream_head
,
NULL
,
&
rebase_options
));
cl_git_fail_with
(
GIT_EMERGECONFLICT
,
git_rebase_next
(
&
rebase_operation
,
rebase
));
git_annotated_commit_free
(
branch_head
);
git_annotated_commit_free
(
upstream_head
);
git_reference_free
(
branch_ref
);
git_reference_free
(
upstream_ref
);
git_rebase_free
(
rebase
);
}
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