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
5ae9d296
Commit
5ae9d296
authored
Jul 21, 2014
by
Edward Thomson
Committed by
Edward Thomson
Oct 26, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
git_rebase_finish: rewrite notes when finishing rebase
parent
bad4937e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
255 additions
and
18 deletions
+255
-18
include/git2/rebase.h
+12
-1
src/rebase.c
+150
-16
tests/rebase/merge.c
+93
-1
No files found.
include/git2/rebase.h
View file @
5ae9d296
...
...
@@ -28,6 +28,15 @@ typedef struct {
* interoperability with other clients.
*/
int
quiet
;
/**
* Canonical name of the notes reference used to rewrite notes for
* rebased commits when finishing the rebase; if NULL, the contents of
* the coniguration option `notes.rewriteRef` is examined, unless the
* configuration option `notes.rewrite.rebase` is set to false. If
* `notes.rewriteRef` is NULL, notes will not be rewritten.
*/
const
char
*
rewrite_notes_ref
;
}
git_rebase_options
;
#define GIT_REBASE_OPTIONS_VERSION 1
...
...
@@ -130,11 +139,13 @@ GIT_EXTERN(int) git_rebase_abort(
*
* @param repo The repository with the in-progress rebase
* @param signature The identity that is finishing the rebase
* @param opts Options to specify how rebase is finished
* @param Zero on success; -1 on error
*/
GIT_EXTERN
(
int
)
git_rebase_finish
(
git_repository
*
repo
,
const
git_signature
*
signature
);
const
git_signature
*
signature
,
const
git_rebase_options
*
opts
);
/** @} */
GIT_END_DECL
...
...
src/rebase.c
View file @
5ae9d296
...
...
@@ -12,12 +12,14 @@
#include "filebuf.h"
#include "merge.h"
#include "array.h"
#include "config.h"
#include <git2/types.h>
#include <git2/rebase.h>
#include <git2/commit.h>
#include <git2/reset.h>
#include <git2/revwalk.h>
#include <git2/notes.h>
#define REBASE_APPLY_DIR "rebase-apply"
#define REBASE_MERGE_DIR "rebase-merge"
...
...
@@ -37,6 +39,8 @@
#define ORIG_DETACHED_HEAD "detached HEAD"
#define NOTES_DEFAULT_REF NULL
#define REBASE_DIR_MODE 0777
#define REBASE_FILE_MODE 0666
...
...
@@ -291,7 +295,7 @@ static void rebase_state_free(git_rebase_state *state)
git__free
(
state
->
state_path
);
}
static
int
rebase_
finish
(
git_rebase_state
*
state
)
static
int
rebase_
cleanup
(
git_rebase_state
*
state
)
{
return
git_path_isdir
(
state
->
state_path
)
?
git_futils_rmdir_r
(
state
->
state_path
,
NULL
,
GIT_RMDIR_REMOVE_FILES
)
:
...
...
@@ -443,12 +447,46 @@ int git_rebase_init_options(git_rebase_options *opts, unsigned int version)
return
0
;
}
static
void
rebase_normalize_options
(
static
int
rebase_normalize_opts
(
git_repository
*
repo
,
git_rebase_options
*
opts
,
const
git_rebase_options
*
given_opts
)
{
git_rebase_options
default_opts
=
GIT_REBASE_OPTIONS_INIT
;
git_config
*
config
;
if
(
given_opts
)
memcpy
(
&
opts
,
given_opts
,
sizeof
(
git_rebase_options
));
memcpy
(
opts
,
given_opts
,
sizeof
(
git_rebase_options
));
else
memcpy
(
opts
,
&
default_opts
,
sizeof
(
git_rebase_options
));
if
(
git_repository_config
(
&
config
,
repo
)
<
0
)
return
-
1
;
if
(
given_opts
&&
given_opts
->
rewrite_notes_ref
)
{
opts
->
rewrite_notes_ref
=
git__strdup
(
given_opts
->
rewrite_notes_ref
);
GITERR_CHECK_ALLOC
(
opts
->
rewrite_notes_ref
);
}
else
if
(
git_config__get_bool_force
(
config
,
"notes.rewrite.rebase"
,
1
))
{
const
char
*
rewrite_ref
=
git_config__get_string_force
(
config
,
"notes.rewriteref"
,
NOTES_DEFAULT_REF
);
if
(
rewrite_ref
)
{
opts
->
rewrite_notes_ref
=
git__strdup
(
rewrite_ref
);
GITERR_CHECK_ALLOC
(
opts
->
rewrite_notes_ref
);
}
}
git_config_free
(
config
);
return
0
;
}
static
void
rebase_opts_free
(
git_rebase_options
*
opts
)
{
if
(
!
opts
)
return
;
git__free
((
char
*
)
opts
->
rewrite_notes_ref
);
}
static
int
rebase_ensure_not_in_progress
(
git_repository
*
repo
)
...
...
@@ -512,7 +550,7 @@ int git_rebase(
const
git_signature
*
signature
,
const
git_rebase_options
*
given_opts
)
{
git_rebase_options
opts
=
GIT_REBASE_OPTIONS_INIT
;
git_rebase_options
opts
;
git_reference
*
head_ref
=
NULL
;
git_buf
reflog
=
GIT_BUF_INIT
;
git_checkout_options
checkout_opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
...
...
@@ -521,9 +559,9 @@ int git_rebase(
assert
(
repo
&&
branch
&&
(
upstream
||
onto
));
GITERR_CHECK_VERSION
(
given_opts
,
GIT_MERGE_OPTIONS_VERSION
,
"git_merge_options"
);
rebase_normalize_options
(
&
opts
,
given_opts
);
if
((
error
=
git_repository__ensure_not_bare
(
repo
,
"rebase"
))
<
0
||
if
((
error
=
rebase_normalize_opts
(
repo
,
&
opts
,
given_opts
))
<
0
||
(
error
=
git_repository__ensure_not_bare
(
repo
,
"rebase"
))
<
0
||
(
error
=
rebase_ensure_not_in_progress
(
repo
))
<
0
||
(
error
=
rebase_ensure_not_dirty
(
repo
))
<
0
)
goto
done
;
...
...
@@ -546,6 +584,7 @@ int git_rebase(
done:
git_reference_free
(
head_ref
);
git_buf_free
(
&
reflog
);
rebase_opts_free
(
&
opts
);
return
error
;
}
...
...
@@ -818,7 +857,7 @@ int git_rebase_abort(git_repository *repo, const git_signature *signature)
GIT_RESET_HARD
,
NULL
,
signature
,
NULL
))
<
0
)
goto
done
;
error
=
rebase_
finish
(
&
state
);
error
=
rebase_
cleanup
(
&
state
);
done:
git_commit_free
(
orig_head_commit
);
...
...
@@ -828,8 +867,102 @@ done:
return
error
;
}
int
git_rebase_finish
(
git_repository
*
repo
,
const
git_signature
*
signature
)
static
int
rebase_copy_note
(
git_repository
*
repo
,
git_oid
*
from
,
git_oid
*
to
,
const
git_signature
*
committer
,
const
git_rebase_options
*
opts
)
{
git_note
*
note
=
NULL
;
git_oid
note_id
;
int
error
;
if
((
error
=
git_note_read
(
&
note
,
repo
,
opts
->
rewrite_notes_ref
,
from
))
<
0
)
{
if
(
error
==
GIT_ENOTFOUND
)
{
giterr_clear
();
error
=
0
;
}
goto
done
;
}
error
=
git_note_create
(
&
note_id
,
repo
,
git_note_author
(
note
),
committer
,
opts
->
rewrite_notes_ref
,
to
,
git_note_message
(
note
),
0
);
done:
git_note_free
(
note
);
return
error
;
}
static
int
rebase_copy_notes
(
git_repository
*
repo
,
git_rebase_state
*
state
,
const
git_signature
*
committer
,
const
git_rebase_options
*
opts
)
{
git_buf
path
=
GIT_BUF_INIT
,
rewritten
=
GIT_BUF_INIT
;
char
*
pair_list
,
*
fromstr
,
*
tostr
,
*
end
;
git_oid
from
,
to
;
unsigned
int
linenum
=
1
;
int
error
=
0
;
if
(
!
opts
->
rewrite_notes_ref
)
goto
done
;
if
((
error
=
git_buf_joinpath
(
&
path
,
state
->
state_path
,
REWRITTEN_FILE
))
<
0
||
(
error
=
git_futils_readbuffer
(
&
rewritten
,
path
.
ptr
))
<
0
)
goto
done
;
pair_list
=
rewritten
.
ptr
;
while
(
*
pair_list
)
{
fromstr
=
pair_list
;
if
((
end
=
strchr
(
fromstr
,
'\n'
))
==
NULL
)
goto
on_error
;
pair_list
=
end
+
1
;
*
end
=
'\0'
;
if
((
end
=
strchr
(
fromstr
,
' '
))
==
NULL
)
goto
on_error
;
tostr
=
end
+
1
;
*
end
=
'\0'
;
if
(
strlen
(
fromstr
)
!=
GIT_OID_HEXSZ
||
strlen
(
tostr
)
!=
GIT_OID_HEXSZ
||
git_oid_fromstr
(
&
from
,
fromstr
)
<
0
||
git_oid_fromstr
(
&
to
,
tostr
)
<
0
)
goto
on_error
;
if
((
error
=
rebase_copy_note
(
repo
,
&
from
,
&
to
,
committer
,
opts
))
<
0
)
goto
done
;
linenum
++
;
}
goto
done
;
on_error:
giterr_set
(
GITERR_REBASE
,
"Invalid rewritten file at line %d"
,
linenum
);
error
=
-
1
;
done:
git_buf_free
(
&
rewritten
);
git_buf_free
(
&
path
);
return
error
;
}
int
git_rebase_finish
(
git_repository
*
repo
,
const
git_signature
*
signature
,
const
git_rebase_options
*
given_opts
)
{
git_rebase_options
opts
;
git_rebase_state
state
=
GIT_REBASE_STATE_INIT
;
git_reference
*
terminal_ref
=
NULL
,
*
branch_ref
=
NULL
,
*
head_ref
=
NULL
;
git_commit
*
terminal_commit
=
NULL
;
...
...
@@ -839,7 +972,8 @@ int git_rebase_finish(git_repository *repo, const git_signature *signature)
assert
(
repo
);
if
((
error
=
rebase_state
(
&
state
,
repo
))
<
0
)
if
((
error
=
rebase_normalize_opts
(
repo
,
&
opts
,
given_opts
))
<
0
||
(
error
=
rebase_state
(
&
state
,
repo
))
<
0
)
goto
done
;
git_oid_fmt
(
onto
,
&
state
.
onto_id
);
...
...
@@ -850,18 +984,17 @@ int git_rebase_finish(git_repository *repo, const git_signature *signature)
state
.
orig_head_name
))
<
0
||
(
error
=
git_repository_head
(
&
terminal_ref
,
repo
))
<
0
||
(
error
=
git_reference_peel
((
git_object
**
)
&
terminal_commit
,
terminal_ref
,
GIT_OBJ_COMMIT
))
<
0
)
goto
done
;
if
((
error
=
git_reference_create_matching
(
&
branch_ref
,
terminal_ref
,
GIT_OBJ_COMMIT
))
<
0
||
(
error
=
git_reference_create_matching
(
&
branch_ref
,
repo
,
state
.
orig_head_name
,
git_commit_id
(
terminal_commit
),
1
,
&
state
.
orig_head_id
,
signature
,
branch_msg
.
ptr
))
<
0
||
(
error
=
git_reference_symbolic_create
(
&
head_ref
,
repo
,
GIT_HEAD_FILE
,
state
.
orig_head_name
,
1
,
signature
,
head_msg
.
ptr
))
<
0
)
signature
,
head_msg
.
ptr
))
<
0
||
(
error
=
rebase_copy_notes
(
repo
,
&
state
,
signature
,
&
opts
))
<
0
)
goto
done
;
error
=
rebase_
finish
(
&
state
);
error
=
rebase_
cleanup
(
&
state
);
done:
git_buf_free
(
&
head_msg
);
...
...
@@ -871,6 +1004,7 @@ done:
git_reference_free
(
branch_ref
);
git_reference_free
(
terminal_ref
);
rebase_state_free
(
&
state
);
rebase_opts_free
(
&
opts
);
return
error
;
}
...
...
tests/rebase/merge.c
View file @
5ae9d296
...
...
@@ -330,7 +330,7 @@ void test_rebase_merge__finish(void)
cl_git_fail
(
error
=
git_rebase_next
(
repo
,
&
checkout_opts
));
cl_assert_equal_i
(
GIT_ITEROVER
,
error
);
cl_git_pass
(
git_rebase_finish
(
repo
,
signature
));
cl_git_pass
(
git_rebase_finish
(
repo
,
signature
,
NULL
));
cl_assert_equal_i
(
GIT_REPOSITORY_STATE_NONE
,
git_repository_state
(
repo
));
...
...
@@ -360,3 +360,95 @@ void test_rebase_merge__finish(void)
git_reference_free
(
upstream_ref
);
}
static
void
test_copy_note
(
const
git_rebase_options
*
opts
,
bool
should_exist
)
{
git_reference
*
branch_ref
,
*
upstream_ref
;
git_merge_head
*
branch_head
,
*
upstream_head
;
git_commit
*
branch_commit
;
git_checkout_options
checkout_opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
git_oid
note_id
,
commit_id
;
git_note
*
note
=
NULL
;
int
error
;
checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_SAFE
;
cl_git_pass
(
git_reference_lookup
(
&
branch_ref
,
repo
,
"refs/heads/gravy"
));
cl_git_pass
(
git_reference_lookup
(
&
upstream_ref
,
repo
,
"refs/heads/veal"
));
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_reference_peel
((
git_object
**
)
&
branch_commit
,
branch_ref
,
GIT_OBJ_COMMIT
));
/* Add a note to a commit */
cl_git_pass
(
git_note_create
(
&
note_id
,
repo
,
git_commit_author
(
branch_commit
),
git_commit_committer
(
branch_commit
),
"refs/notes/test"
,
git_commit_id
(
branch_commit
),
"This is a commit note."
,
0
));
cl_git_pass
(
git_rebase
(
repo
,
branch_head
,
upstream_head
,
NULL
,
signature
,
opts
));
cl_git_pass
(
git_rebase_next
(
repo
,
&
checkout_opts
));
cl_git_pass
(
git_rebase_commit
(
&
commit_id
,
repo
,
NULL
,
signature
,
NULL
,
NULL
));
cl_git_pass
(
git_rebase_finish
(
repo
,
signature
,
opts
));
cl_assert_equal_i
(
GIT_REPOSITORY_STATE_NONE
,
git_repository_state
(
repo
));
if
(
should_exist
)
{
cl_git_pass
(
git_note_read
(
&
note
,
repo
,
"refs/notes/test"
,
&
commit_id
));
cl_assert_equal_s
(
"This is a commit note."
,
git_note_message
(
note
));
}
else
{
cl_git_fail
(
error
=
git_note_read
(
&
note
,
repo
,
"refs/notes/test"
,
&
commit_id
));
cl_assert_equal_i
(
GIT_ENOTFOUND
,
error
);
}
git_note_free
(
note
);
git_commit_free
(
branch_commit
);
git_merge_head_free
(
branch_head
);
git_merge_head_free
(
upstream_head
);
git_reference_free
(
branch_ref
);
git_reference_free
(
upstream_ref
);
}
void
test_rebase_merge__copy_notes_off_by_default
(
void
)
{
test_copy_note
(
NULL
,
0
);
}
void
test_rebase_merge__copy_notes_specified_in_options
(
void
)
{
git_rebase_options
opts
=
GIT_REBASE_OPTIONS_INIT
;
opts
.
rewrite_notes_ref
=
"refs/notes/test"
;
test_copy_note
(
&
opts
,
1
);
}
void
test_rebase_merge__copy_notes_specified_in_config
(
void
)
{
git_config
*
config
;
cl_git_pass
(
git_repository_config
(
&
config
,
repo
));
cl_git_pass
(
git_config_set_string
(
config
,
"notes.rewriteRef"
,
"refs/notes/test"
));
test_copy_note
(
NULL
,
1
);
}
void
test_rebase_merge__copy_notes_disabled_in_config
(
void
)
{
git_config
*
config
;
cl_git_pass
(
git_repository_config
(
&
config
,
repo
));
cl_git_pass
(
git_config_set_bool
(
config
,
"notes.rewrite.rebase"
,
0
));
cl_git_pass
(
git_config_set_string
(
config
,
"notes.rewriteRef"
,
"refs/notes/test"
));
test_copy_note
(
NULL
,
0
);
}
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