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
77a15fe8
Commit
77a15fe8
authored
May 12, 2015
by
Carlos Martín Nieto
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3018 from ethomson/stash_apply
Stash apply
parents
9cdd6578
1f1f5c63
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1074 additions
and
47 deletions
+1074
-47
AUTHORS
+1
-0
CHANGELOG.md
+9
-0
include/git2/checkout.h
+10
-1
include/git2/stash.h
+135
-4
src/checkout.c
+12
-3
src/index.c
+98
-0
src/index.h
+2
-0
src/merge.c
+66
-20
src/merge.h
+14
-4
src/stash.c
+303
-14
tests/core/structinit.c
+5
-0
tests/index/read_index.c
+73
-0
tests/merge/trees/treediff.c
+13
-1
tests/stash/apply.c
+333
-0
No files found.
AUTHORS
View file @
77a15fe8
...
...
@@ -49,6 +49,7 @@ Microsoft Corporation
Olivier Ramonat
Peter Drahoš
Pierre Habouzit
Pierre-Olivier Latour
Przemyslaw Pawelczyk
Ramsay Jones
Robert G. Jakabosky
...
...
CHANGELOG.md
View file @
77a15fe8
...
...
@@ -34,6 +34,9 @@ v0.22 + 1
*
On Mac OS X, we now use SecureTransport to provide the cryptographic
support for HTTPS connections insead of OpenSSL.
*
Checkout can now accept an index for the baseline computations via the
`baseline_index`
member.
### API additions
*
The
`git_merge_options`
gained a
`file_flags`
member.
...
...
@@ -63,6 +66,12 @@ support for HTTPS connections insead of OpenSSL.
*
`git_index_add_frombuffer()`
can now create a blob from memory
buffer and add it to the index which is attached to a repository.
*
`git_stash_apply()`
can now apply a stashed state from the stash list,
placing the data into the working directory and index.
*
`git_stash_pop()`
will apply a stashed state (like
`git_stash_apply()`
)
but will remove the stashed state after a successful application.
### API removals
### Breaking API changes
...
...
include/git2/checkout.h
View file @
77a15fe8
...
...
@@ -272,7 +272,16 @@ typedef struct git_checkout_options {
*/
git_strarray
paths
;
git_tree
*
baseline
;
/**< expected content of workdir, defaults to HEAD */
/** The expected content of the working directory; defaults to HEAD.
* If the working directory does not match this baseline information,
* that will produce a checkout conflict.
*/
git_tree
*
baseline
;
/** Like `baseline` above, though expressed as an index. This
* option overrides `baseline`.
*/
git_index
*
baseline_index
;
/**< expected content of workdir, expressed as an index. */
const
char
*
target_directory
;
/**< alternative checkout path to workdir */
...
...
include/git2/stash.h
View file @
77a15fe8
...
...
@@ -70,6 +70,120 @@ GIT_EXTERN(int) git_stash_save(
const
char
*
message
,
unsigned
int
flags
);
/** Stash application flags. */
typedef
enum
{
GIT_STASH_APPLY_DEFAULT
=
0
,
/* Try to reinstate not only the working tree's changes,
* but also the index's changes.
*/
GIT_STASH_APPLY_REINSTATE_INDEX
=
(
1
<<
0
),
}
git_stash_apply_flags
;
typedef
enum
{
GIT_STASH_APPLY_PROGRESS_NONE
=
0
,
/** Loading the stashed data from the object database. */
GIT_STASH_APPLY_PROGRESS_LOADING_STASH
,
/** The stored index is being analyzed. */
GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX
,
/** The modified files are being analyzed. */
GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED
,
/** The untracked and ignored files are being analyzed. */
GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED
,
/** The untracked files are being written to disk. */
GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED
,
/** The modified files are being written to disk. */
GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED
,
/** The stash was applied successfully. */
GIT_STASH_APPLY_PROGRESS_DONE
,
}
git_stash_apply_progress_t
;
/**
* Stash application progress notification function.
* Return 0 to continue processing, or a negative value to
* abort the stash application.
*/
typedef
int
(
*
git_stash_apply_progress_cb
)(
git_stash_apply_progress_t
progress
,
void
*
payload
);
/** Stash application options structure.
*
* Initialize with the `GIT_STASH_APPLY_OPTIONS_INIT` macro to set
* sensible defaults; for example:
*
* git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;
*/
typedef
struct
git_stash_apply_options
{
unsigned
int
version
;
/** See `git_stash_apply_flags_t`, above. */
git_stash_apply_flags
flags
;
/** Options to use when writing files to the working directory. */
git_checkout_options
checkout_options
;
/** Optional callback to notify the consumer of application progress. */
git_stash_apply_progress_cb
progress_cb
;
void
*
progress_payload
;
}
git_stash_apply_options
;
#define GIT_STASH_APPLY_OPTIONS_VERSION 1
#define GIT_STASH_APPLY_OPTIONS_INIT { \
GIT_STASH_APPLY_OPTIONS_VERSION, \
GIT_STASH_APPLY_DEFAULT, \
GIT_CHECKOUT_OPTIONS_INIT }
/**
* Initializes a `git_stash_apply_options` with default values. Equivalent to
* creating an instance with GIT_STASH_APPLY_OPTIONS_INIT.
*
* @param opts the `git_stash_apply_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_STASH_APPLY_OPTIONS_INIT` here.
* @return Zero on success; -1 on failure.
*/
int
git_stash_apply_init_options
(
git_stash_apply_options
*
opts
,
unsigned
int
version
);
/**
* Apply a single stashed state from the stash list.
*
* If local changes in the working directory conflict with changes in the
* stash then GIT_EMERGECONFLICT will be returned. In this case, the index
* will always remain unmodified and all files in the working directory will
* remain unmodified. However, if you are restoring untracked files or
* ignored files and there is a conflict when applying the modified files,
* then those files will remain in the working directory.
*
* If passing the GIT_STASH_APPLY_REINSTATE_INDEX flag and there would be
* conflicts when reinstating the index, the function will return
* GIT_EMERGECONFLICT and both the working directory and index will be left
* unmodified.
*
* Note that a minimum checkout strategy of `GIT_CHECKOUT_SAFE` is implied.
*
* @param repo The owning repository.
* @param index The position within the stash list. 0 points to the
* most recent stashed state.
* @param options Options to control how stashes are applied.
*
* @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the
* given index, GIT_EMERGECONFLICT if changes exist in the working
* directory, or an error code
*/
GIT_EXTERN
(
int
)
git_stash_apply
(
git_repository
*
repo
,
size_t
index
,
const
git_stash_apply_options
*
options
);
/**
* This is a callback function you can provide to iterate over all the
* stashed states that will be invoked per entry.
...
...
@@ -79,7 +193,7 @@ GIT_EXTERN(int) git_stash_save(
* @param message The stash message.
* @param stash_id The commit oid of the stashed state.
* @param payload Extra parameter to callback function.
* @return 0 to continue iterating or non-zero to stop
* @return 0 to continue iterating or non-zero to stop
.
*/
typedef
int
(
*
git_stash_cb
)(
size_t
index
,
...
...
@@ -99,7 +213,7 @@ typedef int (*git_stash_cb)(
*
* @param payload Extra parameter to callback function.
*
* @return 0 on success, non-zero callback return value, or error code
* @return 0 on success, non-zero callback return value, or error code
.
*/
GIT_EXTERN
(
int
)
git_stash_foreach
(
git_repository
*
repo
,
...
...
@@ -114,13 +228,30 @@ GIT_EXTERN(int) git_stash_foreach(
* @param index The position within the stash list. 0 points to the
* most recent stashed state.
*
* @return 0 on success, or error code
* @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the given
* index, or error code.
*/
GIT_EXTERN
(
int
)
git_stash_drop
(
git_repository
*
repo
,
size_t
index
);
/**
* Apply a single stashed state from the stash list and remove it from the list
* if successful.
*
* @param repo The owning repository.
* @param index The position within the stash list. 0 points to the
* most recent stashed state.
* @param options Options to control how stashes are applied.
*
* @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the given
* index, or error code. (see git_stash_apply() above for details)
*/
GIT_EXTERN
(
int
)
git_stash_pop
(
git_repository
*
repo
,
size_t
index
,
const
git_stash_apply_options
*
options
);
/** @} */
GIT_END_DECL
#endif
src/checkout.c
View file @
77a15fe8
...
...
@@ -2397,7 +2397,7 @@ static int checkout_data_init(
&
data
->
can_symlink
,
repo
,
GIT_CVAR_SYMLINKS
))
<
0
)
goto
cleanup
;
if
(
!
data
->
opts
.
baseline
)
{
if
(
!
data
->
opts
.
baseline
&&
!
data
->
opts
.
baseline_index
)
{
data
->
opts_free_baseline
=
true
;
error
=
checkout_lookup_head_tree
(
&
data
->
opts
.
baseline
,
repo
);
...
...
@@ -2501,11 +2501,20 @@ int git_checkout_iterator(
(
error
=
git_iterator_for_workdir_ext
(
&
workdir
,
data
.
repo
,
data
.
opts
.
target_directory
,
index
,
NULL
,
iterflags
|
GIT_ITERATOR_DONT_AUTOEXPAND
,
data
.
pfx
,
data
.
pfx
))
<
0
||
(
error
=
git_iterator_for_tree
(
data
.
pfx
,
data
.
pfx
))
<
0
)
goto
cleanup
;
if
(
data
.
opts
.
baseline_index
)
{
if
((
error
=
git_iterator_for_index
(
&
baseline
,
data
.
opts
.
baseline_index
,
iterflags
,
data
.
pfx
,
data
.
pfx
))
<
0
)
goto
cleanup
;
}
else
{
if
((
error
=
git_iterator_for_tree
(
&
baseline
,
data
.
opts
.
baseline
,
iterflags
,
data
.
pfx
,
data
.
pfx
))
<
0
)
goto
cleanup
;
}
/* Should not have case insensitivity mismatch */
assert
(
git_iterator_ignore_case
(
workdir
)
==
git_iterator_ignore_case
(
baseline
));
...
...
src/index.c
View file @
77a15fe8
...
...
@@ -2451,6 +2451,104 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
return
error
;
}
int
git_index_read_index
(
git_index
*
index
,
const
git_index
*
new_index
)
{
git_vector
new_entries
=
GIT_VECTOR_INIT
,
remove_entries
=
GIT_VECTOR_INIT
;
git_iterator
*
index_iterator
=
NULL
;
git_iterator
*
new_iterator
=
NULL
;
const
git_index_entry
*
old_entry
,
*
new_entry
;
git_index_entry
*
entry
;
size_t
i
;
int
error
;
if
((
error
=
git_vector_init
(
&
new_entries
,
new_index
->
entries
.
length
,
index
->
entries
.
_cmp
))
<
0
||
(
error
=
git_vector_init
(
&
remove_entries
,
index
->
entries
.
length
,
NULL
))
<
0
)
goto
done
;
if
((
error
=
git_iterator_for_index
(
&
index_iterator
,
index
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_index
(
&
new_iterator
,
(
git_index
*
)
new_index
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
)
goto
done
;
if
(((
error
=
git_iterator_current
(
&
old_entry
,
index_iterator
))
<
0
&&
error
!=
GIT_ITEROVER
)
||
((
error
=
git_iterator_current
(
&
new_entry
,
new_iterator
))
<
0
&&
error
!=
GIT_ITEROVER
))
goto
done
;
while
(
true
)
{
int
diff
;
if
(
old_entry
&&
new_entry
)
diff
=
git_index_entry_cmp
(
old_entry
,
new_entry
);
else
if
(
!
old_entry
&&
new_entry
)
diff
=
1
;
else
if
(
old_entry
&&
!
new_entry
)
diff
=
-
1
;
else
break
;
if
(
diff
<
0
)
{
git_vector_insert
(
&
remove_entries
,
(
git_index_entry
*
)
old_entry
);
}
else
if
(
diff
>
0
)
{
if
((
error
=
index_entry_dup
(
&
entry
,
git_index_owner
(
index
),
new_entry
))
<
0
)
goto
done
;
git_vector_insert
(
&
new_entries
,
entry
);
}
else
{
/* Path and stage are equal, if the OID is equal, keep it to
* keep the stat cache data.
*/
if
(
git_oid_equal
(
&
old_entry
->
id
,
&
new_entry
->
id
))
{
git_vector_insert
(
&
new_entries
,
(
git_index_entry
*
)
old_entry
);
}
else
{
if
((
error
=
index_entry_dup
(
&
entry
,
git_index_owner
(
index
),
new_entry
))
<
0
)
goto
done
;
git_vector_insert
(
&
new_entries
,
entry
);
git_vector_insert
(
&
remove_entries
,
(
git_index_entry
*
)
old_entry
);
}
}
if
(
diff
<=
0
)
{
if
((
error
=
git_iterator_advance
(
&
old_entry
,
index_iterator
))
<
0
&&
error
!=
GIT_ITEROVER
)
goto
done
;
}
if
(
diff
>=
0
)
{
if
((
error
=
git_iterator_advance
(
&
new_entry
,
new_iterator
))
<
0
&&
error
!=
GIT_ITEROVER
)
goto
done
;
}
}
git_index_name_clear
(
index
);
git_index_reuc_clear
(
index
);
git_vector_swap
(
&
new_entries
,
&
index
->
entries
);
git_vector_foreach
(
&
remove_entries
,
i
,
entry
)
{
if
(
index
->
tree
)
git_tree_cache_invalidate_path
(
index
->
tree
,
entry
->
path
);
index_entry_free
(
entry
);
}
error
=
0
;
done:
git_vector_free
(
&
new_entries
);
git_vector_free
(
&
remove_entries
);
git_iterator_free
(
index_iterator
);
git_iterator_free
(
new_iterator
);
return
error
;
}
git_repository
*
git_index_owner
(
const
git_index
*
index
)
{
return
INDEX_OWNER
(
index
);
...
...
src/index.h
View file @
77a15fe8
...
...
@@ -93,6 +93,8 @@ extern int git_index_snapshot_find(
size_t
*
at_pos
,
git_vector
*
snap
,
git_vector_cmp
entry_srch
,
const
char
*
path
,
size_t
path_len
,
int
stage
);
/* Replace an index with a new index */
int
git_index_read_index
(
git_index
*
index
,
const
git_index
*
new_index
);
typedef
struct
{
git_index
*
index
;
...
...
src/merge.c
View file @
77a15fe8
...
...
@@ -1451,11 +1451,11 @@ static int merge_diff_list_insert_unmodified(
int
git_merge_diff_list__find_differences
(
git_merge_diff_list
*
diff_list
,
const
git_tree
*
ancestor_tree
,
const
git_tree
*
our_tree
,
const
git_tree
*
their_tree
)
git_iterator
*
ancestor_iter
,
git_iterator
*
our_iter
,
git_iterator
*
their_iter
)
{
git_iterator
*
iterators
[
3
]
=
{
0
};
git_iterator
*
iterators
[
3
]
=
{
ancestor_iter
,
our_iter
,
their_iter
};
const
git_index_entry
*
items
[
3
]
=
{
0
},
*
best_cur_item
,
*
cur_items
[
3
];
git_vector_cmp
entry_compare
=
git_index_entry_cmp
;
struct
merge_diff_df_data
df_data
=
{
0
};
...
...
@@ -1463,12 +1463,7 @@ int git_merge_diff_list__find_differences(
size_t
i
,
j
;
int
error
=
0
;
assert
(
diff_list
&&
(
our_tree
||
their_tree
));
if
((
error
=
git_iterator_for_tree
(
&
iterators
[
TREE_IDX_ANCESTOR
],
(
git_tree
*
)
ancestor_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_tree
(
&
iterators
[
TREE_IDX_OURS
],
(
git_tree
*
)
our_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_tree
(
&
iterators
[
TREE_IDX_THEIRS
],
(
git_tree
*
)
their_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
)
goto
done
;
assert
(
diff_list
&&
(
our_iter
||
their_iter
));
/* Set up the iterators */
for
(
i
=
0
;
i
<
3
;
i
++
)
{
...
...
@@ -1544,9 +1539,6 @@ int git_merge_diff_list__find_differences(
}
done
:
for
(
i
=
0
;
i
<
3
;
i
++
)
git_iterator_free
(
iterators
[
i
]);
if
(
error
==
GIT_ITEROVER
)
error
=
0
;
...
...
@@ -1757,14 +1749,28 @@ on_error:
return
error
;
}
int
git_merge_trees
(
static
git_iterator
*
iterator_given_or_empty
(
git_iterator
**
empty
,
git_iterator
*
given
)
{
if
(
given
)
return
given
;
if
(
git_iterator_for_nothing
(
empty
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
)
<
0
)
return
NULL
;
return
*
empty
;
}
int
git_merge__iterators
(
git_index
**
out
,
git_repository
*
repo
,
const
git_tree
*
ancestor_tree
,
const
git_tree
*
our_tree
,
const
git_tree
*
their_tree
,
git_iterator
*
ancestor_iter
,
git_iterator
*
our_iter
,
git_iterator
*
theirs_iter
,
const
git_merge_options
*
given_opts
)
{
git_iterator
*
empty_ancestor
=
NULL
,
*
empty_ours
=
NULL
,
*
empty_theirs
=
NULL
;
git_merge_diff_list
*
diff_list
;
git_merge_options
opts
;
git_merge_diff
*
conflict
;
...
...
@@ -1772,11 +1778,12 @@ int git_merge_trees(
size_t
i
;
int
error
=
0
;
assert
(
out
&&
repo
&&
(
our_tree
||
their_tree
)
);
assert
(
out
&&
repo
);
*
out
=
NULL
;
GITERR_CHECK_VERSION
(
given_opts
,
GIT_MERGE_OPTIONS_VERSION
,
"git_merge_options"
);
GITERR_CHECK_VERSION
(
given_opts
,
GIT_MERGE_OPTIONS_VERSION
,
"git_merge_options"
);
if
((
error
=
merge_normalize_opts
(
repo
,
&
opts
,
given_opts
))
<
0
)
return
error
;
...
...
@@ -1784,7 +1791,12 @@ int git_merge_trees(
diff_list
=
git_merge_diff_list__alloc
(
repo
);
GITERR_CHECK_ALLOC
(
diff_list
);
if
((
error
=
git_merge_diff_list__find_differences
(
diff_list
,
ancestor_tree
,
our_tree
,
their_tree
))
<
0
||
ancestor_iter
=
iterator_given_or_empty
(
&
empty_ancestor
,
ancestor_iter
);
our_iter
=
iterator_given_or_empty
(
&
empty_ours
,
our_iter
);
theirs_iter
=
iterator_given_or_empty
(
&
empty_theirs
,
theirs_iter
);
if
((
error
=
git_merge_diff_list__find_differences
(
diff_list
,
ancestor_iter
,
our_iter
,
theirs_iter
))
<
0
||
(
error
=
git_merge_diff_list__find_renames
(
repo
,
diff_list
,
&
opts
))
<
0
)
goto
done
;
...
...
@@ -1808,10 +1820,44 @@ int git_merge_trees(
done
:
git_merge_diff_list__free
(
diff_list
);
git_iterator_free
(
empty_ancestor
);
git_iterator_free
(
empty_ours
);
git_iterator_free
(
empty_theirs
);
return
error
;
}
int
git_merge_trees
(
git_index
**
out
,
git_repository
*
repo
,
const
git_tree
*
ancestor_tree
,
const
git_tree
*
our_tree
,
const
git_tree
*
their_tree
,
const
git_merge_options
*
merge_opts
)
{
git_iterator
*
ancestor_iter
=
NULL
,
*
our_iter
=
NULL
,
*
their_iter
=
NULL
;
int
error
;
if
((
error
=
git_iterator_for_tree
(
&
ancestor_iter
,
(
git_tree
*
)
ancestor_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_tree
(
&
our_iter
,
(
git_tree
*
)
our_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_tree
(
&
their_iter
,
(
git_tree
*
)
their_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
))
<
0
)
goto
done
;
error
=
git_merge__iterators
(
out
,
repo
,
ancestor_iter
,
our_iter
,
their_iter
,
merge_opts
);
done
:
git_iterator_free
(
ancestor_iter
);
git_iterator_free
(
our_iter
);
git_iterator_free
(
their_iter
);
return
error
;
}
int
git_merge_commits
(
git_index
**
out
,
git_repository
*
repo
,
...
...
src/merge.h
View file @
77a15fe8
...
...
@@ -10,6 +10,7 @@
#include "vector.h"
#include "commit_list.h"
#include "pool.h"
#include "iterator.h"
#include "git2/merge.h"
#include "git2/types.h"
...
...
@@ -121,10 +122,11 @@ int git_merge__bases_many(
git_merge_diff_list
*
git_merge_diff_list__alloc
(
git_repository
*
repo
);
int
git_merge_diff_list__find_differences
(
git_merge_diff_list
*
merge_diff_list
,
const
git_tree
*
ancestor_tree
,
const
git_tree
*
ours_tree
,
const
git_tree
*
theirs_tree
);
int
git_merge_diff_list__find_differences
(
git_merge_diff_list
*
merge_diff_list
,
git_iterator
*
ancestor_iterator
,
git_iterator
*
ours_iter
,
git_iterator
*
theirs_iter
);
int
git_merge_diff_list__find_renames
(
git_repository
*
repo
,
git_merge_diff_list
*
merge_diff_list
,
const
git_merge_options
*
opts
);
...
...
@@ -138,6 +140,14 @@ int git_merge__setup(
const
git_annotated_commit
*
heads
[],
size_t
heads_len
);
int
git_merge__iterators
(
git_index
**
out
,
git_repository
*
repo
,
git_iterator
*
ancestor_iter
,
git_iterator
*
our_iter
,
git_iterator
*
their_iter
,
const
git_merge_options
*
given_opts
);
int
git_merge__check_result
(
git_repository
*
repo
,
git_index
*
index_new
);
int
git_merge__append_conflicts_to_merge_msg
(
git_repository
*
repo
,
git_index
*
index
);
...
...
src/stash.c
View file @
77a15fe8
...
...
@@ -8,6 +8,7 @@
#include "common.h"
#include "repository.h"
#include "commit.h"
#include "message.h"
#include "tree.h"
#include "reflog.h"
#include "git2/diff.h"
...
...
@@ -16,7 +17,11 @@
#include "git2/checkout.h"
#include "git2/index.h"
#include "git2/transaction.h"
#include "git2/merge.h"
#include "index.h"
#include "signature.h"
#include "iterator.h"
#include "merge.h"
static
int
create_error
(
int
error
,
const
char
*
msg
)
{
...
...
@@ -49,23 +54,14 @@ static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit)
static
int
append_commit_description
(
git_buf
*
out
,
git_commit
*
commit
)
{
const
char
*
message
;
size_t
pos
=
0
,
len
;
const
char
*
summary
=
git_commit_summary
(
commit
)
;
GITERR_CHECK_ALLOC
(
summary
)
;
if
(
append_abbreviated_oid
(
out
,
git_commit_id
(
commit
))
<
0
)
return
-
1
;
message
=
git_commit_message
(
commit
);
len
=
strlen
(
message
);
/* TODO: Replace with proper commit short message
* when git_commit_message_short() is implemented.
*/
while
(
pos
<
len
&&
message
[
pos
]
!=
'\n'
)
pos
++
;
git_buf_putc
(
out
,
' '
);
git_buf_put
(
out
,
message
,
pos
);
git_buf_put
s
(
out
,
summary
);
git_buf_putc
(
out
,
'\n'
);
return
git_buf_oom
(
out
)
?
-
1
:
0
;
...
...
@@ -110,7 +106,7 @@ static int build_tree_from_index(git_tree **out, git_index *index)
git_oid
i_tree_oid
;
if
((
error
=
git_index_write_tree
(
&
i_tree_oid
,
index
))
<
0
)
return
-
1
;
return
error
;
return
git_tree_lookup
(
out
,
git_index_owner
(
index
),
&
i_tree_oid
);
}
...
...
@@ -553,6 +549,286 @@ cleanup:
return
error
;
}
static
int
retrieve_stash_commit
(
git_commit
**
commit
,
git_repository
*
repo
,
size_t
index
)
{
git_reference
*
stash
=
NULL
;
git_reflog
*
reflog
=
NULL
;
int
error
;
size_t
max
;
const
git_reflog_entry
*
entry
;
if
((
error
=
git_reference_lookup
(
&
stash
,
repo
,
GIT_REFS_STASH_FILE
))
<
0
)
goto
cleanup
;
if
((
error
=
git_reflog_read
(
&
reflog
,
repo
,
GIT_REFS_STASH_FILE
))
<
0
)
goto
cleanup
;
max
=
git_reflog_entrycount
(
reflog
);
if
(
!
max
||
index
>
max
-
1
)
{
error
=
GIT_ENOTFOUND
;
giterr_set
(
GITERR_STASH
,
"No stashed state at position %"
PRIuZ
,
index
);
goto
cleanup
;
}
entry
=
git_reflog_entry_byindex
(
reflog
,
index
);
if
((
error
=
git_commit_lookup
(
commit
,
repo
,
git_reflog_entry_id_new
(
entry
)))
<
0
)
goto
cleanup
;
cleanup:
git_reference_free
(
stash
);
git_reflog_free
(
reflog
);
return
error
;
}
static
int
retrieve_stash_trees
(
git_tree
**
out_stash_tree
,
git_tree
**
out_base_tree
,
git_tree
**
out_index_tree
,
git_tree
**
out_index_parent_tree
,
git_tree
**
out_untracked_tree
,
git_commit
*
stash_commit
)
{
git_tree
*
stash_tree
=
NULL
;
git_commit
*
base_commit
=
NULL
;
git_tree
*
base_tree
=
NULL
;
git_commit
*
index_commit
=
NULL
;
git_tree
*
index_tree
=
NULL
;
git_commit
*
index_parent_commit
=
NULL
;
git_tree
*
index_parent_tree
=
NULL
;
git_commit
*
untracked_commit
=
NULL
;
git_tree
*
untracked_tree
=
NULL
;
int
error
;
if
((
error
=
git_commit_tree
(
&
stash_tree
,
stash_commit
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_parent
(
&
base_commit
,
stash_commit
,
0
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_tree
(
&
base_tree
,
base_commit
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_parent
(
&
index_commit
,
stash_commit
,
1
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_tree
(
&
index_tree
,
index_commit
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_parent
(
&
index_parent_commit
,
index_commit
,
0
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_tree
(
&
index_parent_tree
,
index_parent_commit
))
<
0
)
goto
cleanup
;
if
(
git_commit_parentcount
(
stash_commit
)
==
3
)
{
if
((
error
=
git_commit_parent
(
&
untracked_commit
,
stash_commit
,
2
))
<
0
)
goto
cleanup
;
if
((
error
=
git_commit_tree
(
&
untracked_tree
,
untracked_commit
))
<
0
)
goto
cleanup
;
}
*
out_stash_tree
=
stash_tree
;
*
out_base_tree
=
base_tree
;
*
out_index_tree
=
index_tree
;
*
out_index_parent_tree
=
index_parent_tree
;
*
out_untracked_tree
=
untracked_tree
;
cleanup:
git_commit_free
(
untracked_commit
);
git_commit_free
(
index_parent_commit
);
git_commit_free
(
index_commit
);
git_commit_free
(
base_commit
);
if
(
error
<
0
)
{
git_tree_free
(
stash_tree
);
git_tree_free
(
base_tree
);
git_tree_free
(
index_tree
);
git_tree_free
(
index_parent_tree
);
git_tree_free
(
untracked_tree
);
}
return
error
;
}
static
int
merge_index_and_tree
(
git_index
**
out
,
git_repository
*
repo
,
git_tree
*
ancestor_tree
,
git_index
*
ours_index
,
git_tree
*
theirs_tree
)
{
git_iterator
*
ancestor
=
NULL
,
*
ours
=
NULL
,
*
theirs
=
NULL
;
const
git_iterator_flag_t
flags
=
GIT_ITERATOR_DONT_IGNORE_CASE
;
int
error
;
if
((
error
=
git_iterator_for_tree
(
&
ancestor
,
ancestor_tree
,
flags
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_index
(
&
ours
,
ours_index
,
flags
,
NULL
,
NULL
))
<
0
||
(
error
=
git_iterator_for_tree
(
&
theirs
,
theirs_tree
,
flags
,
NULL
,
NULL
))
<
0
)
goto
done
;
error
=
git_merge__iterators
(
out
,
repo
,
ancestor
,
ours
,
theirs
,
NULL
);
done:
git_iterator_free
(
ancestor
);
git_iterator_free
(
ours
);
git_iterator_free
(
theirs
);
return
error
;
}
static
void
normalize_apply_options
(
git_stash_apply_options
*
opts
,
const
git_stash_apply_options
*
given_apply_opts
)
{
if
(
given_apply_opts
!=
NULL
)
{
memcpy
(
opts
,
given_apply_opts
,
sizeof
(
git_stash_apply_options
));
}
else
{
git_stash_apply_options
default_apply_opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
memcpy
(
opts
,
&
default_apply_opts
,
sizeof
(
git_stash_apply_options
));
}
if
((
opts
->
checkout_options
.
checkout_strategy
&
(
GIT_CHECKOUT_SAFE
|
GIT_CHECKOUT_FORCE
))
==
0
)
opts
->
checkout_options
.
checkout_strategy
=
GIT_CHECKOUT_SAFE
;
if
(
!
opts
->
checkout_options
.
our_label
)
opts
->
checkout_options
.
our_label
=
"Updated upstream"
;
if
(
!
opts
->
checkout_options
.
their_label
)
opts
->
checkout_options
.
their_label
=
"Stashed changes"
;
}
int
git_stash_apply_init_options
(
git_stash_apply_options
*
opts
,
unsigned
int
version
)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE
(
opts
,
version
,
git_stash_apply_options
,
GIT_STASH_APPLY_OPTIONS_INIT
);
return
0
;
}
#define NOTIFY_PROGRESS(opts, progress_type) \
if ((opts).progress_cb && \
(error = (opts).progress_cb((progress_type), (opts).progress_payload))) \
return (error < 0) ? error : -1;
int
git_stash_apply
(
git_repository
*
repo
,
size_t
index
,
const
git_stash_apply_options
*
given_opts
)
{
git_stash_apply_options
opts
;
unsigned
int
checkout_strategy
;
git_commit
*
stash_commit
=
NULL
;
git_tree
*
stash_tree
=
NULL
;
git_tree
*
stash_parent_tree
=
NULL
;
git_tree
*
index_tree
=
NULL
;
git_tree
*
index_parent_tree
=
NULL
;
git_tree
*
untracked_tree
=
NULL
;
git_index
*
repo_index
=
NULL
;
git_index
*
unstashed_index
=
NULL
;
git_index
*
modified_index
=
NULL
;
git_index
*
untracked_index
=
NULL
;
int
error
;
GITERR_CHECK_VERSION
(
given_opts
,
GIT_STASH_APPLY_OPTIONS_VERSION
,
"git_stash_apply_options"
);
normalize_apply_options
(
&
opts
,
given_opts
);
checkout_strategy
=
opts
.
checkout_options
.
checkout_strategy
;
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_LOADING_STASH
);
/* Retrieve commit corresponding to the given stash */
if
((
error
=
retrieve_stash_commit
(
&
stash_commit
,
repo
,
index
))
<
0
)
goto
cleanup
;
/* Retrieve all trees in the stash */
if
((
error
=
retrieve_stash_trees
(
&
stash_tree
,
&
stash_parent_tree
,
&
index_tree
,
&
index_parent_tree
,
&
untracked_tree
,
stash_commit
))
<
0
)
goto
cleanup
;
/* Load repo index */
if
((
error
=
git_repository_index
(
&
repo_index
,
repo
))
<
0
)
goto
cleanup
;
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX
);
/* Restore index if required */
if
((
opts
.
flags
&
GIT_STASH_APPLY_REINSTATE_INDEX
)
&&
git_oid_cmp
(
git_tree_id
(
stash_parent_tree
),
git_tree_id
(
index_tree
)))
{
if
((
error
=
merge_index_and_tree
(
&
unstashed_index
,
repo
,
index_parent_tree
,
repo_index
,
index_tree
))
<
0
)
goto
cleanup
;
if
(
git_index_has_conflicts
(
unstashed_index
))
{
error
=
GIT_EMERGECONFLICT
;
goto
cleanup
;
}
}
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED
);
/* Restore modified files in workdir */
if
((
error
=
merge_index_and_tree
(
&
modified_index
,
repo
,
stash_parent_tree
,
repo_index
,
stash_tree
))
<
0
)
goto
cleanup
;
/* If applicable, restore untracked / ignored files in workdir */
if
(
untracked_tree
)
{
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED
);
if
((
error
=
merge_index_and_tree
(
&
untracked_index
,
repo
,
NULL
,
repo_index
,
untracked_tree
))
<
0
)
goto
cleanup
;
}
if
(
untracked_index
)
{
opts
.
checkout_options
.
checkout_strategy
|=
GIT_CHECKOUT_DONT_UPDATE_INDEX
;
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED
);
if
((
error
=
git_checkout_index
(
repo
,
untracked_index
,
&
opts
.
checkout_options
))
<
0
)
goto
cleanup
;
opts
.
checkout_options
.
checkout_strategy
=
checkout_strategy
;
}
/* If there are conflicts in the modified index, then we need to actually
* check that out as the repo's index. Otherwise, we don't update the
* index.
*/
if
(
!
git_index_has_conflicts
(
modified_index
))
opts
.
checkout_options
.
checkout_strategy
|=
GIT_CHECKOUT_DONT_UPDATE_INDEX
;
/* Check out the modified index using the existing repo index as baseline,
* so that existing modifications in the index can be rewritten even when
* checking out safely.
*/
opts
.
checkout_options
.
baseline_index
=
repo_index
;
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED
);
if
((
error
=
git_checkout_index
(
repo
,
modified_index
,
&
opts
.
checkout_options
))
<
0
)
goto
cleanup
;
if
(
unstashed_index
&&
!
git_index_has_conflicts
(
modified_index
))
{
if
((
error
=
git_index_read_index
(
repo_index
,
unstashed_index
))
<
0
)
goto
cleanup
;
}
NOTIFY_PROGRESS
(
opts
,
GIT_STASH_APPLY_PROGRESS_DONE
);
cleanup:
git_index_free
(
untracked_index
);
git_index_free
(
modified_index
);
git_index_free
(
unstashed_index
);
git_index_free
(
repo_index
);
git_tree_free
(
untracked_tree
);
git_tree_free
(
index_parent_tree
);
git_tree_free
(
index_tree
);
git_tree_free
(
stash_parent_tree
);
git_tree_free
(
stash_tree
);
git_commit_free
(
stash_commit
);
return
error
;
}
int
git_stash_foreach
(
git_repository
*
repo
,
git_stash_cb
callback
,
...
...
@@ -620,7 +896,7 @@ int git_stash_drop(
max
=
git_reflog_entrycount
(
reflog
);
if
(
index
>
max
-
1
)
{
if
(
!
max
||
index
>
max
-
1
)
{
error
=
GIT_ENOTFOUND
;
giterr_set
(
GITERR_STASH
,
"No stashed state at position %"
PRIuZ
,
index
);
goto
cleanup
;
...
...
@@ -651,3 +927,16 @@ cleanup:
git_reflog_free
(
reflog
);
return
error
;
}
int
git_stash_pop
(
git_repository
*
repo
,
size_t
index
,
const
git_stash_apply_options
*
options
)
{
int
error
;
if
((
error
=
git_stash_apply
(
repo
,
index
,
options
))
<
0
)
return
error
;
return
git_stash_drop
(
repo
,
index
);
}
tests/core/structinit.c
View file @
77a15fe8
...
...
@@ -131,6 +131,11 @@ void test_core_structinit__compare(void)
git_revert_options
,
GIT_REVERT_OPTIONS_VERSION
,
\
GIT_REVERT_OPTIONS_INIT
,
git_revert_init_options
);
/* stash apply */
CHECK_MACRO_FUNC_INIT_EQUAL
(
\
git_stash_apply_options
,
GIT_STASH_APPLY_OPTIONS_VERSION
,
\
GIT_STASH_APPLY_OPTIONS_INIT
,
git_stash_apply_init_options
);
/* status */
CHECK_MACRO_FUNC_INIT_EQUAL
(
\
git_status_options
,
GIT_STATUS_OPTIONS_VERSION
,
\
...
...
tests/index/read_index.c
0 → 100644
View file @
77a15fe8
#include "clar_libgit2.h"
#include "posix.h"
#include "index.h"
static
git_repository
*
_repo
;
static
git_index
*
_index
;
void
test_index_read_index__initialize
(
void
)
{
git_object
*
head
;
git_reference
*
head_ref
;
_repo
=
cl_git_sandbox_init
(
"testrepo"
);
cl_git_pass
(
git_revparse_ext
(
&
head
,
&
head_ref
,
_repo
,
"HEAD"
));
cl_git_pass
(
git_reset
(
_repo
,
head
,
GIT_RESET_HARD
,
NULL
));
cl_git_pass
(
git_repository_index
(
&
_index
,
_repo
));
git_reference_free
(
head_ref
);
git_object_free
(
head
);
}
void
test_index_read_index__cleanup
(
void
)
{
git_index_free
(
_index
);
cl_git_sandbox_cleanup
();
}
void
test_index_read_index__maintains_stat_cache
(
void
)
{
git_index
*
new_index
;
git_oid
index_id
;
git_index_entry
new_entry
;
const
git_index_entry
*
e
;
git_tree
*
tree
;
size_t
i
;
cl_assert_equal_i
(
4
,
git_index_entrycount
(
_index
));
/* write-tree */
cl_git_pass
(
git_index_write_tree
(
&
index_id
,
_index
));
/* read-tree, then read index */
git_tree_lookup
(
&
tree
,
_repo
,
&
index_id
);
cl_git_pass
(
git_index_new
(
&
new_index
));
cl_git_pass
(
git_index_read_tree
(
new_index
,
tree
));
git_tree_free
(
tree
);
/* add a new entry that will not have stat data */
memset
(
&
new_entry
,
0
,
sizeof
(
git_index_entry
));
new_entry
.
path
=
"Hello"
;
git_oid_fromstr
(
&
new_entry
.
id
,
"0123456789012345678901234567890123456789"
);
new_entry
.
file_size
=
1234
;
new_entry
.
mode
=
0100644
;
cl_git_pass
(
git_index_add
(
new_index
,
&
new_entry
));
cl_assert_equal_i
(
5
,
git_index_entrycount
(
new_index
));
cl_git_pass
(
git_index_read_index
(
_index
,
new_index
));
git_index_free
(
new_index
);
cl_assert_equal_i
(
5
,
git_index_entrycount
(
_index
));
for
(
i
=
0
;
i
<
git_index_entrycount
(
_index
);
i
++
)
{
e
=
git_index_get_byindex
(
_index
,
i
);
if
(
strcmp
(
e
->
path
,
"Hello"
)
==
0
)
{
cl_assert_equal_i
(
0
,
e
->
ctime
.
seconds
);
cl_assert_equal_i
(
0
,
e
->
mtime
.
seconds
);
}
else
{
cl_assert
(
0
!=
e
->
ctime
.
seconds
);
cl_assert
(
0
!=
e
->
mtime
.
seconds
);
}
}
}
tests/merge/trees/treediff.c
View file @
77a15fe8
...
...
@@ -43,6 +43,7 @@ static void test_find_differences(
git_merge_diff_list
*
merge_diff_list
=
git_merge_diff_list__alloc
(
repo
);
git_oid
ancestor_oid
,
ours_oid
,
theirs_oid
;
git_tree
*
ancestor_tree
,
*
ours_tree
,
*
theirs_tree
;
git_iterator
*
ancestor_iter
,
*
ours_iter
,
*
theirs_iter
;
git_merge_options
opts
=
GIT_MERGE_OPTIONS_INIT
;
opts
.
tree_flags
|=
GIT_MERGE_TREE_FIND_RENAMES
;
...
...
@@ -66,7 +67,14 @@ static void test_find_differences(
cl_git_pass
(
git_tree_lookup
(
&
ours_tree
,
repo
,
&
ours_oid
));
cl_git_pass
(
git_tree_lookup
(
&
theirs_tree
,
repo
,
&
theirs_oid
));
cl_git_pass
(
git_merge_diff_list__find_differences
(
merge_diff_list
,
ancestor_tree
,
ours_tree
,
theirs_tree
));
cl_git_pass
(
git_iterator_for_tree
(
&
ancestor_iter
,
ancestor_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
));
cl_git_pass
(
git_iterator_for_tree
(
&
ours_iter
,
ours_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
));
cl_git_pass
(
git_iterator_for_tree
(
&
theirs_iter
,
theirs_tree
,
GIT_ITERATOR_DONT_IGNORE_CASE
,
NULL
,
NULL
));
cl_git_pass
(
git_merge_diff_list__find_differences
(
merge_diff_list
,
ancestor_iter
,
ours_iter
,
theirs_iter
));
cl_git_pass
(
git_merge_diff_list__find_renames
(
repo
,
merge_diff_list
,
&
opts
));
/*
...
...
@@ -77,6 +85,10 @@ static void test_find_differences(
cl_assert
(
merge_test_merge_conflicts
(
&
merge_diff_list
->
conflicts
,
treediff_conflict_data
,
treediff_conflict_data_len
));
git_iterator_free
(
ancestor_iter
);
git_iterator_free
(
ours_iter
);
git_iterator_free
(
theirs_iter
);
git_tree_free
(
ancestor_tree
);
git_tree_free
(
ours_tree
);
git_tree_free
(
theirs_tree
);
...
...
tests/stash/apply.c
0 → 100644
View file @
77a15fe8
#include "clar_libgit2.h"
#include "fileops.h"
#include "stash_helpers.h"
static
git_signature
*
signature
;
static
git_repository
*
repo
;
static
git_index
*
repo_index
;
void
test_stash_apply__initialize
(
void
)
{
git_oid
oid
;
cl_git_pass
(
git_signature_new
(
&
signature
,
"nulltoken"
,
"emeric.fermas@gmail.com"
,
1323847743
,
60
));
/* Wed Dec 14 08:29:03 2011 +0100 */
cl_git_pass
(
git_repository_init
(
&
repo
,
"stash"
,
0
));
cl_git_pass
(
git_repository_index
(
&
repo_index
,
repo
));
cl_git_mkfile
(
"stash/what"
,
"hello
\n
"
);
cl_git_mkfile
(
"stash/how"
,
"small
\n
"
);
cl_git_mkfile
(
"stash/who"
,
"world
\n
"
);
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"what"
));
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"how"
));
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"who"
));
cl_repo_commit_from_index
(
NULL
,
repo
,
signature
,
0
,
"Initial commit"
);
cl_git_rewritefile
(
"stash/what"
,
"goodbye
\n
"
);
cl_git_rewritefile
(
"stash/who"
,
"funky world
\n
"
);
cl_git_mkfile
(
"stash/when"
,
"tomorrow
\n
"
);
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"who"
));
/* Pre-stash state */
assert_status
(
repo
,
"what"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_INDEX_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
cl_git_pass
(
git_stash_save
(
&
oid
,
repo
,
signature
,
NULL
,
GIT_STASH_INCLUDE_UNTRACKED
));
/* Post-stash state */
assert_status
(
repo
,
"what"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"when"
,
GIT_ENOTFOUND
);
}
void
test_stash_apply__cleanup
(
void
)
{
git_signature_free
(
signature
);
signature
=
NULL
;
git_index_free
(
repo_index
);
repo_index
=
NULL
;
git_repository_free
(
repo
);
repo
=
NULL
;
cl_git_pass
(
git_futils_rmdir_r
(
"stash"
,
NULL
,
GIT_RMDIR_REMOVE_FILES
));
cl_fixture_cleanup
(
"sorry-it-is-a-non-bare-only-party"
);
}
void
test_stash_apply__with_default
(
void
)
{
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
NULL
));
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__with_reinstate_index
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
opts
.
flags
=
GIT_STASH_APPLY_REINSTATE_INDEX
;
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
&
opts
));
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_INDEX_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_index_with_default
(
void
)
{
const
git_index_entry
*
ancestor
;
const
git_index_entry
*
our
;
const
git_index_entry
*
their
;
cl_git_rewritefile
(
"stash/who"
,
"nothing
\n
"
);
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"who"
));
cl_git_pass
(
git_index_write
(
repo_index
));
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
NULL
));
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
1
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_INDEX_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
cl_git_pass
(
git_index_conflict_get
(
&
ancestor
,
&
our
,
&
their
,
repo_index
,
"who"
));
/* unmerged */
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_index_with_reinstate_index
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
opts
.
flags
=
GIT_STASH_APPLY_REINSTATE_INDEX
;
cl_git_rewritefile
(
"stash/who"
,
"nothing
\n
"
);
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"who"
));
cl_git_pass
(
git_index_write
(
repo_index
));
cl_git_fail_with
(
git_stash_apply
(
repo
,
0
,
&
opts
),
GIT_EMERGECONFLICT
);
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_INDEX_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_ENOTFOUND
);
}
void
test_stash_apply__conflict_untracked_with_default
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
cl_git_mkfile
(
"stash/when"
,
"nothing
\n
"
);
cl_git_fail_with
(
git_stash_apply
(
repo
,
0
,
&
opts
),
GIT_EMERGECONFLICT
);
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_untracked_with_reinstate_index
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
opts
.
flags
=
GIT_STASH_APPLY_REINSTATE_INDEX
;
cl_git_mkfile
(
"stash/when"
,
"nothing
\n
"
);
cl_git_fail_with
(
git_stash_apply
(
repo
,
0
,
&
opts
),
GIT_EMERGECONFLICT
);
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_workdir_with_default
(
void
)
{
cl_git_rewritefile
(
"stash/what"
,
"ciao
\n
"
);
cl_git_fail_with
(
git_stash_apply
(
repo
,
0
,
NULL
),
GIT_EMERGECONFLICT
);
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_workdir_with_reinstate_index
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
opts
.
flags
=
GIT_STASH_APPLY_REINSTATE_INDEX
;
cl_git_rewritefile
(
"stash/what"
,
"ciao
\n
"
);
cl_git_fail_with
(
git_stash_apply
(
repo
,
0
,
&
opts
),
GIT_EMERGECONFLICT
);
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_commit_with_default
(
void
)
{
const
git_index_entry
*
ancestor
;
const
git_index_entry
*
our
;
const
git_index_entry
*
their
;
cl_git_rewritefile
(
"stash/what"
,
"ciao
\n
"
);
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"what"
));
cl_repo_commit_from_index
(
NULL
,
repo
,
signature
,
0
,
"Other commit"
);
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
NULL
));
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
1
);
cl_git_pass
(
git_index_conflict_get
(
&
ancestor
,
&
our
,
&
their
,
repo_index
,
"what"
));
/* unmerged */
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_INDEX_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__conflict_commit_with_reinstate_index
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
const
git_index_entry
*
ancestor
;
const
git_index_entry
*
our
;
const
git_index_entry
*
their
;
opts
.
flags
=
GIT_STASH_APPLY_REINSTATE_INDEX
;
cl_git_rewritefile
(
"stash/what"
,
"ciao
\n
"
);
cl_git_pass
(
git_index_add_bypath
(
repo_index
,
"what"
));
cl_repo_commit_from_index
(
NULL
,
repo
,
signature
,
0
,
"Other commit"
);
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
&
opts
));
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
1
);
cl_git_pass
(
git_index_conflict_get
(
&
ancestor
,
&
our
,
&
their
,
repo_index
,
"what"
));
/* unmerged */
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_INDEX_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
}
void
test_stash_apply__pop
(
void
)
{
cl_git_pass
(
git_stash_pop
(
repo
,
0
,
NULL
));
cl_git_fail_with
(
git_stash_pop
(
repo
,
0
,
NULL
),
GIT_ENOTFOUND
);
}
struct
seen_paths
{
bool
what
;
bool
how
;
bool
who
;
bool
when
;
};
int
checkout_notify
(
git_checkout_notify_t
why
,
const
char
*
path
,
const
git_diff_file
*
baseline
,
const
git_diff_file
*
target
,
const
git_diff_file
*
workdir
,
void
*
payload
)
{
struct
seen_paths
*
seen_paths
=
(
struct
seen_paths
*
)
payload
;
if
(
strcmp
(
path
,
"what"
)
==
0
)
seen_paths
->
what
=
1
;
else
if
(
strcmp
(
path
,
"how"
)
==
0
)
seen_paths
->
how
=
1
;
else
if
(
strcmp
(
path
,
"who"
)
==
0
)
seen_paths
->
who
=
1
;
else
if
(
strcmp
(
path
,
"when"
)
==
0
)
seen_paths
->
when
=
1
;
return
0
;
}
void
test_stash_apply__executes_notify_cb
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
struct
seen_paths
seen_paths
=
{
0
};
opts
.
checkout_options
.
notify_cb
=
checkout_notify
;
opts
.
checkout_options
.
notify_flags
=
GIT_CHECKOUT_NOTIFY_ALL
;
opts
.
checkout_options
.
notify_payload
=
&
seen_paths
;
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
&
opts
));
cl_assert_equal_i
(
git_index_has_conflicts
(
repo_index
),
0
);
assert_status
(
repo
,
"what"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"how"
,
GIT_STATUS_CURRENT
);
assert_status
(
repo
,
"who"
,
GIT_STATUS_WT_MODIFIED
);
assert_status
(
repo
,
"when"
,
GIT_STATUS_WT_NEW
);
cl_assert_equal_b
(
true
,
seen_paths
.
what
);
cl_assert_equal_b
(
false
,
seen_paths
.
how
);
cl_assert_equal_b
(
true
,
seen_paths
.
who
);
cl_assert_equal_b
(
true
,
seen_paths
.
when
);
}
int
progress_cb
(
git_stash_apply_progress_t
progress
,
void
*
payload
)
{
git_stash_apply_progress_t
*
p
=
(
git_stash_apply_progress_t
*
)
payload
;
cl_assert_equal_i
((
*
p
)
+
1
,
progress
);
*
p
=
progress
;
return
0
;
}
void
test_stash_apply__calls_progress_cb
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
git_stash_apply_progress_t
progress
=
GIT_STASH_APPLY_PROGRESS_NONE
;
opts
.
progress_cb
=
progress_cb
;
opts
.
progress_payload
=
&
progress
;
cl_git_pass
(
git_stash_apply
(
repo
,
0
,
&
opts
));
cl_assert_equal_i
(
progress
,
GIT_STASH_APPLY_PROGRESS_DONE
);
}
int
aborting_progress_cb
(
git_stash_apply_progress_t
progress
,
void
*
payload
)
{
if
(
progress
==
GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED
)
return
-
44
;
return
0
;
}
void
test_stash_apply__progress_cb_can_abort
(
void
)
{
git_stash_apply_options
opts
=
GIT_STASH_APPLY_OPTIONS_INIT
;
git_stash_apply_progress_t
progress
=
GIT_STASH_APPLY_PROGRESS_NONE
;
opts
.
progress_cb
=
aborting_progress_cb
;
cl_git_fail_with
(
-
44
,
git_stash_apply
(
repo
,
0
,
&
opts
));
}
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