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
43b67d49
Commit
43b67d49
authored
Jul 27, 2012
by
Vicent Marti
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'nulltoken/topic/reflog-delete' into development
parents
c0c39025
c3be5c5a
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
449 additions
and
163 deletions
+449
-163
include/git2/reflog.h
+36
-8
src/reflog.c
+216
-99
src/reflog.h
+3
-0
tests-clar/refs/reflog/drop.c
+130
-0
tests-clar/refs/reflog/reflog.c
+64
-56
No files found.
include/git2/reflog.h
View file @
43b67d49
...
...
@@ -23,6 +23,10 @@ GIT_BEGIN_DECL
/**
* Read the reflog for the given reference
*
* If there is no reflog file for the given
* reference yet, an empty reflog object will
* be returned.
*
* The reflog must be freed manually by using
* git_reflog_free().
*
...
...
@@ -33,22 +37,26 @@ GIT_BEGIN_DECL
GIT_EXTERN
(
int
)
git_reflog_read
(
git_reflog
**
reflog
,
git_reference
*
ref
);
/**
* Write a new reflog for the given reference
*
* If there is no reflog file for the given
* reference yet, it will be created.
* Write an existing in-memory reflog object back to disk
* using an atomic file lock.
*
* `oid_old` may be NULL in case it's a new reference.
* @param reflog an existing reflog object
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_reflog_write
(
git_reflog
*
reflog
);
/**
* Add a new entry to the reflog.
*
* `msg` is optional and can be NULL.
*
* @param ref
the changed reference
* @param
oid_old the OID the reference was
pointing to
* @param ref
log an existing reflog object
* @param
new_oid the OID the reference is now
pointing to
* @param committer the signature of the committer
* @param msg the reflog message
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_reflog_
write
(
git_reference
*
ref
,
const
git_oid
*
oid_ol
d
,
const
git_signature
*
committer
,
const
char
*
msg
);
GIT_EXTERN
(
int
)
git_reflog_
append
(
git_reflog
*
reflog
,
const
git_oid
*
new_oi
d
,
const
git_signature
*
committer
,
const
char
*
msg
);
/**
* Rename the reflog for the given reference
...
...
@@ -87,6 +95,26 @@ GIT_EXTERN(unsigned int) git_reflog_entrycount(git_reflog *reflog);
GIT_EXTERN
(
const
git_reflog_entry
*
)
git_reflog_entry_byindex
(
git_reflog
*
reflog
,
unsigned
int
idx
);
/**
* Remove an entry from the reflog by its index
*
* To ensure there's no gap in the log history, set the `rewrite_previosu_entry` to 1.
* When deleting entry `n`, member old_oid of entry `n-1` (if any) will be updated with
* the value of memeber new_oid of entry `n+1`.
*
* @param reflog a previously loaded reflog.
*
* @param idx the position of the entry to remove.
*
* @param rewrite_previous_entry 1 to rewrite the history; 0 otherwise.
*
* @return 0 on success or an error code.
*/
GIT_EXTERN
(
int
)
git_reflog_entry_drop
(
git_reflog
*
reflog
,
unsigned
int
idx
,
int
rewrite_previous_entry
);
/**
* Get the old oid
*
* @param entry a reflog entry
...
...
src/reflog.c
View file @
43b67d49
...
...
@@ -28,66 +28,68 @@ static int reflog_init(git_reflog **reflog, git_reference *ref)
return
-
1
;
}
log
->
owner
=
git_reference_owner
(
ref
);
*
reflog
=
log
;
return
0
;
}
static
int
reflog_write
(
const
char
*
log_path
,
const
char
*
oid_old
,
const
char
*
oid_new
,
const
git_signature
*
committer
,
static
int
serialize_reflog_entry
(
git_buf
*
buf
,
const
git_oid
*
oid_old
,
const
git_oid
*
oid_new
,
const
git_signature
*
committer
,
const
char
*
msg
)
{
int
error
;
git_buf
log
=
GIT_BUF_INIT
;
git_filebuf
fbuf
=
GIT_FILEBUF_INIT
;
bool
trailing_newline
=
false
;
char
raw_old
[
GIT_OID_HEXSZ
+
1
];
char
raw_new
[
GIT_OID_HEXSZ
+
1
];
assert
(
log_path
&&
oid_old
&&
oid_new
&&
committer
);
git_oid_tostr
(
raw_old
,
GIT_OID_HEXSZ
+
1
,
oid_old
);
git_oid_tostr
(
raw_new
,
GIT_OID_HEXSZ
+
1
,
oid_new
);
if
(
msg
)
{
const
char
*
newline
=
strchr
(
msg
,
'\n'
);
if
(
newline
)
{
if
(
*
(
newline
+
1
)
==
'\0'
)
trailing_newline
=
true
;
else
{
giterr_set
(
GITERR_INVALID
,
"Reflog message cannot contain newline"
);
return
-
1
;
}
}
}
git_buf_clear
(
buf
);
git_buf_puts
(
&
log
,
oid_old
);
git_buf_putc
(
&
log
,
' '
);
git_buf_puts
(
buf
,
raw_old
);
git_buf_putc
(
buf
,
' '
);
git_buf_puts
(
buf
,
raw_new
);
git_
buf_puts
(
&
log
,
oid_new
);
git_
signature__writebuf
(
buf
,
" "
,
committer
);
git_signature__writebuf
(
&
log
,
" "
,
committer
);
git_buf_
truncate
(
&
log
,
log
.
size
-
1
);
/* drop LF */
/* drop trailing LF */
git_buf_
rtrim
(
buf
);
if
(
msg
)
{
git_buf_putc
(
&
log
,
'\t'
);
git_buf_puts
(
&
log
,
msg
);
git_buf_putc
(
buf
,
'\t'
);
git_buf_puts
(
buf
,
msg
);
}
if
(
!
trailing_newline
)
git_buf_putc
(
&
log
,
'\n'
);
git_buf_putc
(
buf
,
'\n'
);
if
(
git_buf_oom
(
&
log
))
{
git_buf_free
(
&
log
);
return
-
1
;
}
return
git_buf_oom
(
buf
);
}
error
=
git_filebuf_open
(
&
fbuf
,
log_path
,
GIT_FILEBUF_APPEND
);
if
(
!
error
)
{
if
((
error
=
git_filebuf_write
(
&
fbuf
,
log
.
ptr
,
log
.
size
))
<
0
)
git_filebuf_cleanup
(
&
fbuf
);
else
error
=
git_filebuf_commit
(
&
fbuf
,
GIT_REFLOG_FILE_MODE
);
}
static
int
reflog_entry_new
(
git_reflog_entry
**
entry
)
{
git_reflog_entry
*
e
;
git_buf_free
(
&
log
);
assert
(
entry
);
return
error
;
e
=
git__malloc
(
sizeof
(
git_reflog_entry
));
GITERR_CHECK_ALLOC
(
e
);
memset
(
e
,
0
,
sizeof
(
git_reflog_entry
));
*
entry
=
e
;
return
0
;
}
static
void
reflog_entry_free
(
git_reflog_entry
*
entry
)
{
git_signature_free
(
entry
->
committer
);
git__free
(
entry
->
msg
);
git__free
(
entry
);
}
static
int
reflog_parse
(
git_reflog
*
log
,
const
char
*
buf
,
size_t
buf_size
)
...
...
@@ -105,8 +107,8 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
} while (0)
while
(
buf_size
>
GIT_REFLOG_SIZE_MIN
)
{
entry
=
git__malloc
(
sizeof
(
git_reflog_entry
));
GITERR_CHECK_ALLOC
(
entry
)
;
if
(
reflog_entry_new
(
&
entry
)
<
0
)
return
-
1
;
entry
->
committer
=
git__malloc
(
sizeof
(
git_signature
));
GITERR_CHECK_ALLOC
(
entry
->
committer
);
...
...
@@ -153,10 +155,9 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
#undef seek_forward
fail:
if
(
entry
)
{
git__free
(
entry
->
committer
);
git__free
(
entry
);
}
if
(
entry
)
reflog_entry_free
(
entry
);
return
-
1
;
}
...
...
@@ -168,10 +169,7 @@ void git_reflog_free(git_reflog *reflog)
for
(
i
=
0
;
i
<
reflog
->
entries
.
length
;
i
++
)
{
entry
=
git_vector_get
(
&
reflog
->
entries
,
i
);
git_signature_free
(
entry
->
committer
);
git__free
(
entry
->
msg
);
git__free
(
entry
);
reflog_entry_free
(
entry
);
}
git_vector_free
(
&
reflog
->
entries
);
...
...
@@ -179,6 +177,24 @@ void git_reflog_free(git_reflog *reflog)
git__free
(
reflog
);
}
static
int
retrieve_reflog_path
(
git_buf
*
path
,
git_reference
*
ref
)
{
return
git_buf_join_n
(
path
,
'/'
,
3
,
git_reference_owner
(
ref
)
->
path_repository
,
GIT_REFLOG_DIR
,
ref
->
name
);
}
int
create_new_reflog_file
(
const
char
*
filepath
)
{
int
fd
;
if
((
fd
=
p_open
(
filepath
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
,
GIT_REFLOG_FILE_MODE
))
<
0
)
return
-
1
;
return
p_close
(
fd
);
}
int
git_reflog_read
(
git_reflog
**
reflog
,
git_reference
*
ref
)
{
int
error
;
...
...
@@ -188,85 +204,138 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref)
*
reflog
=
NULL
;
assert
(
reflog
&&
ref
);
if
(
reflog_init
(
&
log
,
ref
)
<
0
)
return
-
1
;
error
=
git_buf_join_n
(
&
log_path
,
'/'
,
3
,
ref
->
owner
->
path_repository
,
GIT_REFLOG_DIR
,
ref
->
name
)
;
if
(
retrieve_reflog_path
(
&
log_path
,
ref
)
<
0
)
goto
cleanup
;
if
(
!
error
)
error
=
git_futils_readbuffer
(
&
log_file
,
log_path
.
ptr
);
error
=
git_futils_readbuffer
(
&
log_file
,
git_buf_cstr
(
&
log_path
));
if
(
error
<
0
&&
error
!=
GIT_ENOTFOUND
)
goto
cleanup
;
if
(
!
error
)
error
=
reflog_parse
(
log
,
log_file
.
ptr
,
log_file
.
size
);
if
((
error
==
GIT_ENOTFOUND
)
&&
((
error
=
create_new_reflog_file
(
git_buf_cstr
(
&
log_path
)))
<
0
))
goto
cleanup
;
if
((
error
=
reflog_parse
(
log
,
git_buf_cstr
(
&
log_file
),
git_buf_len
(
&
log_file
)))
<
0
)
goto
cleanup
;
if
(
!
error
)
*
reflog
=
log
;
else
goto
success
;
cleanup:
git_reflog_free
(
log
);
success:
git_buf_free
(
&
log_file
);
git_buf_free
(
&
log_path
);
return
error
;
}
int
git_reflog_write
(
git_reference
*
ref
,
const
git_oid
*
oid_old
,
const
git_signature
*
committer
,
const
char
*
msg
)
int
git_reflog_write
(
git_reflog
*
reflog
)
{
int
error
;
char
old
[
GIT_OID_HEXSZ
+
1
]
;
char
new
[
GIT_OID_HEXSZ
+
1
]
;
int
error
=
-
1
;
unsigned
int
i
;
git_reflog_entry
*
entry
;
git_buf
log_path
=
GIT_BUF_INIT
;
git_
reference
*
r
;
const
git_oid
*
oid
;
git_
buf
log
=
GIT_BUF_INIT
;
git_filebuf
fbuf
=
GIT_FILEBUF_INIT
;
if
((
error
=
git_reference_resolve
(
&
r
,
ref
))
<
0
)
return
error
;
assert
(
reflog
);
oid
=
git_reference_oid
(
r
);
if
(
oid
==
NULL
)
{
giterr_set
(
GITERR_REFERENCE
,
"Failed to write reflog. Cannot resolve reference `%s`"
,
r
->
name
);
git_reference_free
(
r
);
return
-
1
;
}
git_oid_tostr
(
new
,
GIT_OID_HEXSZ
+
1
,
oid
);
if
(
git_buf_join_n
(
&
log_path
,
'/'
,
3
,
git_repository_path
(
reflog
->
owner
),
GIT_REFLOG_DIR
,
reflog
->
ref_name
)
<
0
)
return
-
1
;
git_reference_free
(
r
);
if
(
!
git_path_isfile
(
git_buf_cstr
(
&
log_path
)))
{
giterr_set
(
GITERR_INVALID
,
"Log file for reference '%s' doesn't exist."
,
reflog
->
ref_name
);
goto
cleanup
;
}
error
=
git_buf_join_n
(
&
log_path
,
'/'
,
3
,
ref
->
owner
->
path_repository
,
GIT_REFLOG_DIR
,
ref
->
name
);
if
(
error
<
0
)
if
((
error
=
git_filebuf_open
(
&
fbuf
,
git_buf_cstr
(
&
log_path
),
0
))
<
0
)
goto
cleanup
;
if
(
git_path_exists
(
log_path
.
ptr
)
==
false
)
{
error
=
git_futils_mkpath2file
(
log_path
.
ptr
,
GIT_REFLOG_DIR_MODE
);
}
else
if
(
git_path_isfile
(
log_path
.
ptr
)
==
false
)
{
giterr_set
(
GITERR_REFERENCE
,
"Failed to write reflog. `%s` is directory"
,
log_path
.
ptr
);
error
=
-
1
;
}
else
if
(
oid_old
==
NULL
)
{
giterr_set
(
GITERR_REFERENCE
,
"Failed to write reflog. Old OID cannot be NULL for existing reference"
);
error
=
-
1
;
}
if
(
error
<
0
)
git_vector_foreach
(
&
reflog
->
entries
,
i
,
entry
)
{
if
(
serialize_reflog_entry
(
&
log
,
&
(
entry
->
oid_old
),
&
(
entry
->
oid_cur
),
entry
->
committer
,
entry
->
msg
)
<
0
)
goto
cleanup
;
if
(
oid_old
)
git_oid_tostr
(
old
,
sizeof
(
old
),
oid_old
);
else
p_snprintf
(
old
,
sizeof
(
old
),
"%0*d"
,
GIT_OID_HEXSZ
,
0
);
if
((
error
=
git_filebuf_write
(
&
fbuf
,
log
.
ptr
,
log
.
size
))
<
0
)
goto
cleanup
;
}
error
=
reflog_write
(
log_path
.
ptr
,
old
,
new
,
committer
,
msg
);
error
=
git_filebuf_commit
(
&
fbuf
,
GIT_REFLOG_FILE_MODE
);
goto
success
;
cleanup:
git_filebuf_cleanup
(
&
fbuf
);
success:
git_buf_free
(
&
log
);
git_buf_free
(
&
log_path
);
return
error
;
}
int
git_reflog_append
(
git_reflog
*
reflog
,
const
git_oid
*
new_oid
,
const
git_signature
*
committer
,
const
char
*
msg
)
{
int
count
;
git_reflog_entry
*
entry
;
const
char
*
newline
;
assert
(
reflog
&&
new_oid
&&
committer
);
if
(
reflog_entry_new
(
&
entry
)
<
0
)
return
-
1
;
if
((
entry
->
committer
=
git_signature_dup
(
committer
))
==
NULL
)
goto
cleanup
;
if
(
msg
!=
NULL
)
{
if
((
entry
->
msg
=
git__strdup
(
msg
))
==
NULL
)
goto
cleanup
;
newline
=
strchr
(
msg
,
'\n'
);
if
(
newline
)
{
if
(
newline
[
1
]
!=
'\0'
)
{
giterr_set
(
GITERR_INVALID
,
"Reflog message cannot contain newline"
);
goto
cleanup
;
}
entry
->
msg
[
newline
-
msg
]
=
'\0'
;
}
}
count
=
git_reflog_entrycount
(
reflog
);
if
(
count
==
0
)
git_oid_fromstr
(
&
entry
->
oid_old
,
GIT_OID_HEX_ZERO
);
else
{
const
git_reflog_entry
*
previous
;
previous
=
git_reflog_entry_byindex
(
reflog
,
count
-
1
);
git_oid_cpy
(
&
entry
->
oid_old
,
&
previous
->
oid_cur
);
}
git_oid_cpy
(
&
entry
->
oid_cur
,
new_oid
);
if
(
git_vector_insert
(
&
reflog
->
entries
,
entry
)
<
0
)
goto
cleanup
;
return
0
;
cleanup:
reflog_entry_free
(
entry
);
return
-
1
;
}
int
git_reflog_rename
(
git_reference
*
ref
,
const
char
*
new_name
)
{
int
error
=
-
1
,
fd
;
...
...
@@ -276,7 +345,7 @@ int git_reflog_rename(git_reference *ref, const char *new_name)
assert
(
ref
&&
new_name
);
if
(
git_buf_joinpath
(
&
temp_path
,
ref
->
owner
->
path_repository
,
GIT_REFLOG_DIR
)
<
0
)
if
(
git_buf_joinpath
(
&
temp_path
,
git_reference_owner
(
ref
)
->
path_repository
,
GIT_REFLOG_DIR
)
<
0
)
return
-
1
;
if
(
git_buf_joinpath
(
&
old_path
,
git_buf_cstr
(
&
temp_path
),
ref
->
name
)
<
0
)
...
...
@@ -324,8 +393,7 @@ int git_reflog_delete(git_reference *ref)
int
error
;
git_buf
path
=
GIT_BUF_INIT
;
error
=
git_buf_join_n
(
&
path
,
'/'
,
3
,
ref
->
owner
->
path_repository
,
GIT_REFLOG_DIR
,
ref
->
name
);
error
=
retrieve_reflog_path
(
&
path
,
ref
);
if
(
!
error
&&
git_path_exists
(
path
.
ptr
))
error
=
p_unlink
(
path
.
ptr
);
...
...
@@ -370,3 +438,52 @@ char * git_reflog_entry_msg(const git_reflog_entry *entry)
assert
(
entry
);
return
entry
->
msg
;
}
int
git_reflog_entry_drop
(
git_reflog
*
reflog
,
unsigned
int
idx
,
int
rewrite_previous_entry
)
{
unsigned
int
entrycount
;
git_reflog_entry
*
entry
,
*
previous
;
assert
(
reflog
);
entrycount
=
git_reflog_entrycount
(
reflog
);
if
(
idx
>=
entrycount
)
return
GIT_ENOTFOUND
;
entry
=
git_vector_get
(
&
reflog
->
entries
,
idx
);
reflog_entry_free
(
entry
);
if
(
git_vector_remove
(
&
reflog
->
entries
,
idx
)
<
0
)
return
-
1
;
if
(
!
rewrite_previous_entry
)
return
0
;
/* No need to rewrite anything when removing the first entry */
if
(
idx
==
0
)
return
0
;
/* There are no more entries in the log */
if
(
entrycount
==
1
)
return
0
;
entry
=
(
git_reflog_entry
*
)
git_reflog_entry_byindex
(
reflog
,
idx
-
1
);
/* If the last entry has just been removed... */
if
(
idx
==
entrycount
-
1
)
{
/* ...clear the oid_old member of the "new" last entry */
if
(
git_oid_fromstr
(
&
entry
->
oid_old
,
GIT_OID_HEX_ZERO
)
<
0
)
return
-
1
;
return
0
;
}
previous
=
(
git_reflog_entry
*
)
git_reflog_entry_byindex
(
reflog
,
idx
);
git_oid_cpy
(
&
entry
->
oid_old
,
&
previous
->
oid_cur
);
return
0
;
}
src/reflog.h
View file @
43b67d49
...
...
@@ -17,6 +17,8 @@
#define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17)
#define GIT_OID_HEX_ZERO "0000000000000000000000000000000000000000"
struct
git_reflog_entry
{
git_oid
oid_old
;
git_oid
oid_cur
;
...
...
@@ -28,6 +30,7 @@ struct git_reflog_entry {
struct
git_reflog
{
char
*
ref_name
;
git_repository
*
owner
;
git_vector
entries
;
};
...
...
tests-clar/refs/reflog/drop.c
0 → 100644
View file @
43b67d49
#include "clar_libgit2.h"
#include "reflog.h"
static
git_repository
*
g_repo
;
static
git_reflog
*
g_reflog
;
static
unsigned
int
entrycount
;
void
test_refs_reflog_drop__initialize
(
void
)
{
git_reference
*
ref
;
g_repo
=
cl_git_sandbox_init
(
"testrepo.git"
);
cl_git_pass
(
git_reference_lookup
(
&
ref
,
g_repo
,
"HEAD"
));
git_reflog_read
(
&
g_reflog
,
ref
);
entrycount
=
git_reflog_entrycount
(
g_reflog
);
git_reference_free
(
ref
);
}
void
test_refs_reflog_drop__cleanup
(
void
)
{
git_reflog_free
(
g_reflog
);
cl_git_sandbox_cleanup
();
}
void
test_refs_reflog_drop__dropping_a_non_exisiting_entry_from_the_log_returns_ENOTFOUND
(
void
)
{
cl_assert_equal_i
(
GIT_ENOTFOUND
,
git_reflog_entry_drop
(
g_reflog
,
entrycount
,
0
));
cl_assert_equal_i
(
entrycount
,
git_reflog_entrycount
(
g_reflog
));
}
void
test_refs_reflog_drop__can_drop_an_entry
(
void
)
{
cl_assert
(
entrycount
>
4
);
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
2
,
0
));
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
}
void
test_refs_reflog_drop__can_drop_an_entry_and_rewrite_the_log_history
(
void
)
{
const
git_reflog_entry
*
before_previous
,
*
before_next
;
const
git_reflog_entry
*
after_next
;
git_oid
before_next_old_oid
;
cl_assert
(
entrycount
>
4
);
before_previous
=
git_reflog_entry_byindex
(
g_reflog
,
3
);
before_next
=
git_reflog_entry_byindex
(
g_reflog
,
1
);
git_oid_cpy
(
&
before_next_old_oid
,
&
before_next
->
oid_old
);
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
2
,
1
));
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
after_next
=
git_reflog_entry_byindex
(
g_reflog
,
1
);
cl_assert_equal_i
(
0
,
git_oid_cmp
(
&
before_next
->
oid_cur
,
&
after_next
->
oid_cur
));
cl_assert
(
git_oid_cmp
(
&
before_next_old_oid
,
&
after_next
->
oid_old
)
!=
0
);
cl_assert_equal_i
(
0
,
git_oid_cmp
(
&
before_previous
->
oid_cur
,
&
after_next
->
oid_old
));
}
void
test_refs_reflog_drop__can_drop_the_first_entry
(
void
)
{
cl_assert
(
entrycount
>
2
);
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
0
,
0
));
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
}
void
test_refs_reflog_drop__can_drop_the_last_entry
(
void
)
{
const
git_reflog_entry
*
entry
;
cl_assert
(
entrycount
>
2
);
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
entrycount
-
1
,
0
));
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
entry
=
git_reflog_entry_byindex
(
g_reflog
,
entrycount
-
2
);
cl_assert
(
git_oid_streq
(
&
entry
->
oid_old
,
GIT_OID_HEX_ZERO
)
!=
0
);
}
void
test_refs_reflog_drop__can_drop_the_last_entry_and_rewrite_the_log_history
(
void
)
{
const
git_reflog_entry
*
entry
;
cl_assert
(
entrycount
>
2
);
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
entrycount
-
1
,
1
));
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
entry
=
git_reflog_entry_byindex
(
g_reflog
,
entrycount
-
2
);
cl_assert
(
git_oid_streq
(
&
entry
->
oid_old
,
GIT_OID_HEX_ZERO
)
==
0
);
}
void
test_refs_reflog_drop__can_drop_all_the_entries
(
void
)
{
cl_assert
(
--
entrycount
>
0
);
do
{
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
--
entrycount
,
1
));
}
while
(
entrycount
>
0
);
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
0
,
1
));
cl_assert_equal_i
(
0
,
git_reflog_entrycount
(
g_reflog
));
}
void
test_refs_reflog_drop__can_persist_deletion_on_disk
(
void
)
{
git_reference
*
ref
;
cl_assert
(
entrycount
>
2
);
cl_git_pass
(
git_reference_lookup
(
&
ref
,
g_repo
,
g_reflog
->
ref_name
));
cl_git_pass
(
git_reflog_entry_drop
(
g_reflog
,
entrycount
-
1
,
1
));
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
cl_git_pass
(
git_reflog_write
(
g_reflog
));
git_reflog_free
(
g_reflog
);
git_reflog_read
(
&
g_reflog
,
ref
);
git_reference_free
(
ref
);
cl_assert_equal_i
(
entrycount
-
1
,
git_reflog_entrycount
(
g_reflog
));
}
tests-clar/refs/reflog.c
→
tests-clar/refs/reflog
/reflog
.c
View file @
43b67d49
...
...
@@ -7,7 +7,7 @@
static
const
char
*
new_ref
=
"refs/heads/test-reflog"
;
static
const
char
*
current_master_tip
=
"a65fedf39aefe402d3bb6e24df4d4f5fe4547750"
;
static
const
char
*
commit_msg
=
"commit: bla bla"
;
#define commit_msg "commit: bla bla"
static
git_repository
*
g_repo
;
...
...
@@ -24,19 +24,17 @@ static void assert_signature(git_signature *expected, git_signature *actual)
// Fixture setup and teardown
void
test_refs_reflog__initialize
(
void
)
void
test_refs_reflog_
reflog_
_initialize
(
void
)
{
g_repo
=
cl_git_sandbox_init
(
"testrepo.git"
);
}
void
test_refs_reflog__cleanup
(
void
)
void
test_refs_reflog_
reflog_
_cleanup
(
void
)
{
cl_git_sandbox_cleanup
();
}
void
test_refs_reflog__write_then_read
(
void
)
void
test_refs_reflog_reflog__append_then_read
(
void
)
{
// write a reflog for a given reference and ensure it can be read back
git_repository
*
repo2
;
...
...
@@ -44,46 +42,42 @@ void test_refs_reflog__write_then_read(void)
git_oid
oid
;
git_signature
*
committer
;
git_reflog
*
reflog
;
git_reflog_entry
*
entry
;
char
oid_str
[
GIT_OID_HEXSZ
+
1
];
const
git_reflog_entry
*
entry
;
/* Create a new branch pointing at the HEAD */
git_oid_fromstr
(
&
oid
,
current_master_tip
);
cl_git_pass
(
git_reference_create_oid
(
&
ref
,
g_repo
,
new_ref
,
&
oid
,
0
));
git_reference_free
(
ref
);
cl_git_pass
(
git_reference_lookup
(
&
ref
,
g_repo
,
new_ref
));
cl_git_pass
(
git_signature_now
(
&
committer
,
"foo"
,
"foo@bar"
));
cl_git_pass
(
git_reflog_write
(
ref
,
NULL
,
committer
,
NULL
));
cl_git_fail
(
git_reflog_write
(
ref
,
NULL
,
committer
,
"no ancestor NULL for an existing reflog"
));
cl_git_fail
(
git_reflog_write
(
ref
,
NULL
,
committer
,
"no
\n
newline"
));
cl_git_pass
(
git_reflog_write
(
ref
,
&
oid
,
committer
,
commit_msg
));
cl_git_pass
(
git_reflog_read
(
&
reflog
,
ref
));
cl_git_fail
(
git_reflog_append
(
reflog
,
&
oid
,
committer
,
"no inner
\n
newline"
));
cl_git_pass
(
git_reflog_append
(
reflog
,
&
oid
,
committer
,
NULL
));
cl_git_pass
(
git_reflog_append
(
reflog
,
&
oid
,
committer
,
commit_msg
"
\n
"
));
cl_git_pass
(
git_reflog_write
(
reflog
));
git_reflog_free
(
reflog
);
/* Reopen a new instance of the repository */
cl_git_pass
(
git_repository_open
(
&
repo2
,
"testrepo.git"
));
/* Lookup the pre
iv
ously created branch */
/* Lookup the pre
vi
ously created branch */
cl_git_pass
(
git_reference_lookup
(
&
lookedup_ref
,
repo2
,
new_ref
));
/* Read and parse the reflog for this branch */
cl_git_pass
(
git_reflog_read
(
&
reflog
,
lookedup_ref
));
cl_assert
(
reflog
->
entries
.
length
==
2
);
cl_assert
_equal_i
(
2
,
git_reflog_entrycount
(
reflog
)
);
entry
=
(
git_reflog_entry
*
)
git_vector_get
(
&
reflog
->
entries
,
0
);
entry
=
git_reflog_entry_byindex
(
reflog
,
0
);
assert_signature
(
committer
,
entry
->
committer
);
git_oid_tostr
(
oid_str
,
GIT_OID_HEXSZ
+
1
,
&
entry
->
oid_old
);
cl_assert_equal_s
(
"0000000000000000000000000000000000000000"
,
oid_str
);
git_oid_tostr
(
oid_str
,
GIT_OID_HEXSZ
+
1
,
&
entry
->
oid_cur
);
cl_assert_equal_s
(
current_master_tip
,
oid_str
);
cl_assert
(
git_oid_streq
(
&
entry
->
oid_old
,
GIT_OID_HEX_ZERO
)
==
0
);
cl_assert
(
git_oid_cmp
(
&
oid
,
&
entry
->
oid_cur
)
==
0
);
cl_assert
(
entry
->
msg
==
NULL
);
entry
=
(
git_reflog_entry
*
)
git_vector_get
(
&
reflog
->
entries
,
1
);
entry
=
git_reflog_entry_byindex
(
reflog
,
1
);
assert_signature
(
committer
,
entry
->
committer
);
git_oid_tostr
(
oid_str
,
GIT_OID_HEXSZ
+
1
,
&
entry
->
oid_old
);
cl_assert_equal_s
(
current_master_tip
,
oid_str
);
git_oid_tostr
(
oid_str
,
GIT_OID_HEXSZ
+
1
,
&
entry
->
oid_cur
);
cl_assert_equal_s
(
current_master_tip
,
oid_str
);
cl_assert
(
git_oid_cmp
(
&
oid
,
&
entry
->
oid_old
)
==
0
);
cl_assert
(
git_oid_cmp
(
&
oid
,
&
entry
->
oid_cur
)
==
0
);
cl_assert_equal_s
(
commit_msg
,
entry
->
msg
);
git_signature_free
(
committer
);
...
...
@@ -94,35 +88,7 @@ void test_refs_reflog__write_then_read(void)
git_reference_free
(
lookedup_ref
);
}
void
test_refs_reflog__dont_write_bad
(
void
)
{
// avoid writing an obviously wrong reflog
git_reference
*
ref
;
git_oid
oid
;
git_signature
*
committer
;
/* Create a new branch pointing at the HEAD */
git_oid_fromstr
(
&
oid
,
current_master_tip
);
cl_git_pass
(
git_reference_create_oid
(
&
ref
,
g_repo
,
new_ref
,
&
oid
,
0
));
git_reference_free
(
ref
);
cl_git_pass
(
git_reference_lookup
(
&
ref
,
g_repo
,
new_ref
));
cl_git_pass
(
git_signature_now
(
&
committer
,
"foo"
,
"foo@bar"
));
/* Write the reflog for the new branch */
cl_git_pass
(
git_reflog_write
(
ref
,
NULL
,
committer
,
NULL
));
/* Try to update the reflog with wrong information:
* It's no new reference, so the ancestor OID cannot
* be NULL. */
cl_git_fail
(
git_reflog_write
(
ref
,
NULL
,
committer
,
NULL
));
git_signature_free
(
committer
);
git_reference_free
(
ref
);
}
void
test_refs_reflog__renaming_the_reference_moves_the_reflog
(
void
)
void
test_refs_reflog_reflog__renaming_the_reference_moves_the_reflog
(
void
)
{
git_reference
*
master
;
git_buf
master_log_path
=
GIT_BUF_INIT
,
moved_log_path
=
GIT_BUF_INIT
;
...
...
@@ -145,6 +111,7 @@ void test_refs_reflog__renaming_the_reference_moves_the_reflog(void)
git_buf_free
(
&
moved_log_path
);
git_buf_free
(
&
master_log_path
);
}
static
void
assert_has_reflog
(
bool
expected_result
,
const
char
*
name
)
{
git_reference
*
ref
;
...
...
@@ -156,9 +123,50 @@ static void assert_has_reflog(bool expected_result, const char *name)
git_reference_free
(
ref
);
}
void
test_refs_reflog__reference_has_reflog
(
void
)
void
test_refs_reflog_
reflog_
_reference_has_reflog
(
void
)
{
assert_has_reflog
(
true
,
"HEAD"
);
assert_has_reflog
(
true
,
"refs/heads/master"
);
assert_has_reflog
(
false
,
"refs/heads/subtrees"
);
}
void
test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one
(
void
)
{
git_reference
*
subtrees
;
git_reflog
*
reflog
;
git_buf
subtrees_log_path
=
GIT_BUF_INIT
;
cl_git_pass
(
git_reference_lookup
(
&
subtrees
,
g_repo
,
"refs/heads/subtrees"
));
git_buf_join_n
(
&
subtrees_log_path
,
'/'
,
3
,
git_repository_path
(
g_repo
),
GIT_REFLOG_DIR
,
git_reference_name
(
subtrees
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
git_buf_cstr
(
&
subtrees_log_path
)));
cl_git_pass
(
git_reflog_read
(
&
reflog
,
subtrees
));
cl_assert_equal_i
(
0
,
git_reflog_entrycount
(
reflog
));
git_reflog_free
(
reflog
);
git_reference_free
(
subtrees
);
git_buf_free
(
&
subtrees_log_path
);
}
void
test_refs_reflog_reflog__cannot_write_a_moved_reflog
(
void
)
{
git_reference
*
master
;
git_buf
master_log_path
=
GIT_BUF_INIT
,
moved_log_path
=
GIT_BUF_INIT
;
git_reflog
*
reflog
;
cl_git_pass
(
git_reference_lookup
(
&
master
,
g_repo
,
"refs/heads/master"
));
cl_git_pass
(
git_reflog_read
(
&
reflog
,
master
));
cl_git_pass
(
git_reflog_write
(
reflog
));
cl_git_pass
(
git_reference_rename
(
master
,
"refs/moved"
,
0
));
cl_git_fail
(
git_reflog_write
(
reflog
));
git_reflog_free
(
reflog
);
git_reference_free
(
master
);
git_buf_free
(
&
moved_log_path
);
git_buf_free
(
&
master_log_path
);
}
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