Merge branch 'cc/replace-with-the-same-type'
* cc/replace-with-the-same-type: Doc: 'replace' merge and non-merge commits t6050-replace: use some long option names replace: allow long option names Documentation/replace: add Creating Replacement Objects section t6050-replace: add test to clean up all the replace refs t6050-replace: test that objects are of the same type Documentation/replace: state that objects must be of the same type replace: forbid replacing an object with one of a different typemaint
commit
80f165a58a
|
@ -20,8 +20,14 @@ The name of the 'replace' reference is the SHA-1 of the object that is
|
||||||
replaced. The content of the 'replace' reference is the SHA-1 of the
|
replaced. The content of the 'replace' reference is the SHA-1 of the
|
||||||
replacement object.
|
replacement object.
|
||||||
|
|
||||||
|
The replaced object and the replacement object must be of the same type.
|
||||||
|
This restriction can be bypassed using `-f`.
|
||||||
|
|
||||||
Unless `-f` is given, the 'replace' reference must not yet exist.
|
Unless `-f` is given, the 'replace' reference must not yet exist.
|
||||||
|
|
||||||
|
There is no other restriction on the replaced and replacement objects.
|
||||||
|
Merge commits can be replaced by non-merge commits and vice versa.
|
||||||
|
|
||||||
Replacement references will be used by default by all Git commands
|
Replacement references will be used by default by all Git commands
|
||||||
except those doing reachability traversal (prune, pack transfer and
|
except those doing reachability traversal (prune, pack transfer and
|
||||||
fsck).
|
fsck).
|
||||||
|
@ -49,18 +55,34 @@ achieve the same effect as the `--no-replace-objects` option.
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
-f::
|
-f::
|
||||||
|
--force::
|
||||||
If an existing replace ref for the same object exists, it will
|
If an existing replace ref for the same object exists, it will
|
||||||
be overwritten (instead of failing).
|
be overwritten (instead of failing).
|
||||||
|
|
||||||
-d::
|
-d::
|
||||||
|
--delete::
|
||||||
Delete existing replace refs for the given objects.
|
Delete existing replace refs for the given objects.
|
||||||
|
|
||||||
-l <pattern>::
|
-l <pattern>::
|
||||||
|
--list <pattern>::
|
||||||
List replace refs for objects that match the given pattern (or
|
List replace refs for objects that match the given pattern (or
|
||||||
all if no pattern is given).
|
all if no pattern is given).
|
||||||
Typing "git replace" without arguments, also lists all replace
|
Typing "git replace" without arguments, also lists all replace
|
||||||
refs.
|
refs.
|
||||||
|
|
||||||
|
CREATING REPLACEMENT OBJECTS
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and
|
||||||
|
linkgit:git-rebase[1], among other git commands, can be used to create
|
||||||
|
replacement objects from existing objects.
|
||||||
|
|
||||||
|
If you want to replace many blobs, trees or commits that are part of a
|
||||||
|
string of commits, you may just want to create a replacement string of
|
||||||
|
commits and then only replace the commit at the tip of the target
|
||||||
|
string of commits with the commit at the tip of the replacement string
|
||||||
|
of commits.
|
||||||
|
|
||||||
BUGS
|
BUGS
|
||||||
----
|
----
|
||||||
Comparing blobs or trees that have been replaced with those that
|
Comparing blobs or trees that have been replaced with those that
|
||||||
|
@ -69,12 +91,13 @@ go back to a replaced commit will move the branch to the replacement
|
||||||
commit instead of the replaced commit.
|
commit instead of the replaced commit.
|
||||||
|
|
||||||
There may be other problems when using 'git rev-list' related to
|
There may be other problems when using 'git rev-list' related to
|
||||||
pending objects. And of course things may break if an object of one
|
pending objects.
|
||||||
type is replaced by an object of another type (for example a blob
|
|
||||||
replaced by a commit).
|
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
linkgit:git-hash-object[1]
|
||||||
|
linkgit:git-filter-branch[1]
|
||||||
|
linkgit:git-rebase[1]
|
||||||
linkgit:git-tag[1]
|
linkgit:git-tag[1]
|
||||||
linkgit:git-branch[1]
|
linkgit:git-branch[1]
|
||||||
linkgit:git[1]
|
linkgit:git[1]
|
||||||
|
|
|
@ -85,6 +85,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,
|
||||||
int force)
|
int force)
|
||||||
{
|
{
|
||||||
unsigned char object[20], prev[20], repl[20];
|
unsigned char object[20], prev[20], repl[20];
|
||||||
|
enum object_type obj_type, repl_type;
|
||||||
char ref[PATH_MAX];
|
char ref[PATH_MAX];
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
|
|
||||||
|
@ -100,6 +101,15 @@ static int replace_object(const char *object_ref, const char *replace_ref,
|
||||||
if (check_refname_format(ref, 0))
|
if (check_refname_format(ref, 0))
|
||||||
die("'%s' is not a valid ref name.", ref);
|
die("'%s' is not a valid ref name.", ref);
|
||||||
|
|
||||||
|
obj_type = sha1_object_info(object, NULL);
|
||||||
|
repl_type = sha1_object_info(repl, NULL);
|
||||||
|
if (!force && obj_type != repl_type)
|
||||||
|
die("Objects must be of the same type.\n"
|
||||||
|
"'%s' points to a replaced object of type '%s'\n"
|
||||||
|
"while '%s' points to a replacement object of type '%s'.",
|
||||||
|
object_ref, typename(obj_type),
|
||||||
|
replace_ref, typename(repl_type));
|
||||||
|
|
||||||
if (read_ref(ref, prev))
|
if (read_ref(ref, prev))
|
||||||
hashclr(prev);
|
hashclr(prev);
|
||||||
else if (!force)
|
else if (!force)
|
||||||
|
@ -118,9 +128,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int list = 0, delete = 0, force = 0;
|
int list = 0, delete = 0, force = 0;
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT_BOOL('l', NULL, &list, N_("list replace refs")),
|
OPT_BOOL('l', "list", &list, N_("list replace refs")),
|
||||||
OPT_BOOL('d', NULL, &delete, N_("delete replace refs")),
|
OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
|
||||||
OPT_BOOL('f', NULL, &force, N_("replace the ref if it exists")),
|
OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -122,9 +122,9 @@ test_expect_success '"git replace" listing and deleting' '
|
||||||
test "$HASH2" = "$(git replace -l)" &&
|
test "$HASH2" = "$(git replace -l)" &&
|
||||||
test "$HASH2" = "$(git replace)" &&
|
test "$HASH2" = "$(git replace)" &&
|
||||||
aa=${HASH2%??????????????????????????????????????} &&
|
aa=${HASH2%??????????????????????????????????????} &&
|
||||||
test "$HASH2" = "$(git replace -l "$aa*")" &&
|
test "$HASH2" = "$(git replace --list "$aa*")" &&
|
||||||
test_must_fail git replace -d $R &&
|
test_must_fail git replace -d $R &&
|
||||||
test_must_fail git replace -d &&
|
test_must_fail git replace --delete &&
|
||||||
test_must_fail git replace -l -d $HASH2 &&
|
test_must_fail git replace -l -d $HASH2 &&
|
||||||
git replace -d $HASH2 &&
|
git replace -d $HASH2 &&
|
||||||
git show $HASH2 | grep "A U Thor" &&
|
git show $HASH2 | grep "A U Thor" &&
|
||||||
|
@ -147,7 +147,7 @@ test_expect_success '"git replace" resolves sha1' '
|
||||||
git show $HASH2 | grep "O Thor" &&
|
git show $HASH2 | grep "O Thor" &&
|
||||||
test_must_fail git replace $HASH2 $R &&
|
test_must_fail git replace $HASH2 $R &&
|
||||||
git replace -f $HASH2 $R &&
|
git replace -f $HASH2 $R &&
|
||||||
test_must_fail git replace -f &&
|
test_must_fail git replace --force &&
|
||||||
test "$HASH2" = "$(git replace)"
|
test "$HASH2" = "$(git replace)"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -263,4 +263,23 @@ test_expect_success 'not just commits' '
|
||||||
test_cmp file.replaced file
|
test_cmp file.replaced file
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'replaced and replacement objects must be of the same type' '
|
||||||
|
test_must_fail git replace mytag $HASH1 &&
|
||||||
|
test_must_fail git replace HEAD^{tree} HEAD~1 &&
|
||||||
|
BLOB=$(git rev-parse :file) &&
|
||||||
|
test_must_fail git replace HEAD^ $BLOB
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '-f option bypasses the type check' '
|
||||||
|
git replace -f mytag $HASH1 &&
|
||||||
|
git replace --force HEAD^{tree} HEAD~1 &&
|
||||||
|
git replace -f HEAD^ $BLOB
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'replace ref cleanup' '
|
||||||
|
test -n "$(git replace)" &&
|
||||||
|
git replace -d $(git replace) &&
|
||||||
|
test -z "$(git replace)"
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Loading…
Reference in New Issue