Merge branch 'dl/diff-merge-base'
"git diff A...B" learned "git diff --merge-base A B", which is a longer short-hand to say the same thing. * dl/diff-merge-base: contrib/completion: complete `git diff --merge-base` builtin/diff-tree: learn --merge-base builtin/diff-index: learn --merge-base t4068: add --merge-base tests diff-lib: define diff_get_merge_base() diff-lib: accept option flags in run_diff_index() contrib/completion: extract common diff/difftool options git-diff.txt: backtick quote command text git-diff-index.txt: make --cached description a proper sentence t4068: remove unnecessary >tmp
This commit is contained in:
commit
b6fb70c985
@ -9,7 +9,7 @@ git-diff-index - Compare a tree to the working tree or index
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git diff-index' [-m] [--cached] [<common diff options>] <tree-ish> [<path>...]
|
||||
'git diff-index' [-m] [--cached] [--merge-base] [<common diff options>] <tree-ish> [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -27,7 +27,12 @@ include::diff-options.txt[]
|
||||
The id of a tree object to diff against.
|
||||
|
||||
--cached::
|
||||
do not consider the on-disk file at all
|
||||
Do not consider the on-disk file at all.
|
||||
|
||||
--merge-base::
|
||||
Instead of comparing <tree-ish> directly, use the merge base
|
||||
between <tree-ish> and HEAD instead. <tree-ish> must be a
|
||||
commit.
|
||||
|
||||
-m::
|
||||
By default, files recorded in the index but not checked
|
||||
|
@ -10,7 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]
|
||||
[-t] [-r] [-c | --cc] [--combined-all-paths] [--root]
|
||||
[-t] [-r] [-c | --cc] [--combined-all-paths] [--root] [--merge-base]
|
||||
[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
@ -43,6 +43,11 @@ include::diff-options.txt[]
|
||||
When `--root` is specified the initial commit will be shown as a big
|
||||
creation event. This is equivalent to a diff against the NULL tree.
|
||||
|
||||
--merge-base::
|
||||
Instead of comparing the <tree-ish>s directly, use the merge
|
||||
base between the two <tree-ish>s as the "before" side. There
|
||||
must be two <tree-ish>s given and they must both be commits.
|
||||
|
||||
--stdin::
|
||||
When `--stdin` is specified, the command does not take
|
||||
<tree-ish> arguments from the command line. Instead, it
|
||||
|
@ -10,8 +10,8 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git diff' [<options>] [<commit>] [--] [<path>...]
|
||||
'git diff' [<options>] --cached [<commit>] [--] [<path>...]
|
||||
'git diff' [<options>] <commit> [<commit>...] <commit> [--] [<path>...]
|
||||
'git diff' [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]
|
||||
'git diff' [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]
|
||||
'git diff' [<options>] <commit>...<commit> [--] [<path>...]
|
||||
'git diff' [<options>] <blob> <blob>
|
||||
'git diff' [<options>] --no-index [--] <path> <path>
|
||||
@ -40,7 +40,7 @@ files on disk.
|
||||
or when running the command outside a working tree
|
||||
controlled by Git. This form implies `--exit-code`.
|
||||
|
||||
'git diff' [<options>] --cached [<commit>] [--] [<path>...]::
|
||||
'git diff' [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]::
|
||||
|
||||
This form is to view the changes you staged for the next
|
||||
commit relative to the named <commit>. Typically you
|
||||
@ -49,6 +49,10 @@ files on disk.
|
||||
If HEAD does not exist (e.g. unborn branches) and
|
||||
<commit> is not given, it shows all staged changes.
|
||||
--staged is a synonym of --cached.
|
||||
+
|
||||
If --merge-base is given, instead of using <commit>, use the merge base
|
||||
of <commit> and HEAD. `git diff --merge-base A` is equivalent to
|
||||
`git diff $(git merge-base A HEAD)`.
|
||||
|
||||
'git diff' [<options>] <commit> [--] [<path>...]::
|
||||
|
||||
@ -58,23 +62,27 @@ files on disk.
|
||||
branch name to compare with the tip of a different
|
||||
branch.
|
||||
|
||||
'git diff' [<options>] <commit> <commit> [--] [<path>...]::
|
||||
'git diff' [<options>] [--merge-base] <commit> <commit> [--] [<path>...]::
|
||||
|
||||
This is to view the changes between two arbitrary
|
||||
<commit>.
|
||||
+
|
||||
If --merge-base is given, use the merge base of the two commits for the
|
||||
"before" side. `git diff --merge-base A B` is equivalent to
|
||||
`git diff $(git merge-base A B) B`.
|
||||
|
||||
'git diff' [<options>] <commit> <commit>... <commit> [--] [<path>...]::
|
||||
|
||||
This form is to view the results of a merge commit. The first
|
||||
listed <commit> must be the merge itself; the remaining two or
|
||||
more commits should be its parents. A convenient way to produce
|
||||
the desired set of revisions is to use the {caret}@ suffix.
|
||||
the desired set of revisions is to use the `^@` suffix.
|
||||
For instance, if `master` names a merge commit, `git diff master
|
||||
master^@` gives the same combined diff as `git show master`.
|
||||
|
||||
'git diff' [<options>] <commit>..<commit> [--] [<path>...]::
|
||||
|
||||
This is synonymous to the earlier form (without the "..") for
|
||||
This is synonymous to the earlier form (without the `..`) for
|
||||
viewing the changes between two arbitrary <commit>. If <commit> on
|
||||
one side is omitted, it will have the same effect as
|
||||
using HEAD instead.
|
||||
@ -83,20 +91,20 @@ files on disk.
|
||||
|
||||
This form is to view the changes on the branch containing
|
||||
and up to the second <commit>, starting at a common ancestor
|
||||
of both <commit>. "git diff A\...B" is equivalent to
|
||||
"git diff $(git merge-base A B) B". You can omit any one
|
||||
of both <commit>. `git diff A...B` is equivalent to
|
||||
`git diff $(git merge-base A B) B`. You can omit any one
|
||||
of <commit>, which has the same effect as using HEAD instead.
|
||||
|
||||
Just in case you are doing something exotic, it should be
|
||||
noted that all of the <commit> in the above description, except
|
||||
in the last two forms that use ".." notations, can be any
|
||||
<tree>.
|
||||
in the `--merge-base` case and in the last two forms that use `..`
|
||||
notations, can be any <tree>.
|
||||
|
||||
For a more complete list of ways to spell <commit>, see
|
||||
"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
|
||||
However, "diff" is about comparing two _endpoints_, not ranges,
|
||||
and the range notations ("<commit>..<commit>" and
|
||||
"<commit>\...<commit>") do not mean a range as defined in the
|
||||
and the range notations (`<commit>..<commit>` and
|
||||
`<commit>...<commit>`) do not mean a range as defined in the
|
||||
"SPECIFYING RANGES" section in linkgit:gitrevisions[7].
|
||||
|
||||
'git diff' [<options>] <blob> <blob>::
|
||||
@ -144,9 +152,9 @@ $ git diff HEAD <3>
|
||||
+
|
||||
<1> Changes in the working tree not yet staged for the next commit.
|
||||
<2> Changes between the index and your last commit; what you
|
||||
would be committing if you run "git commit" without "-a" option.
|
||||
would be committing if you run `git commit` without `-a` option.
|
||||
<3> Changes in the working tree since your last commit; what you
|
||||
would be committing if you run "git commit -a"
|
||||
would be committing if you run `git commit -a`
|
||||
|
||||
Comparing with arbitrary commits::
|
||||
+
|
||||
|
@ -15,7 +15,7 @@ COMMON_DIFF_OPTIONS_HELP;
|
||||
int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
int cached = 0;
|
||||
unsigned int option = 0;
|
||||
int i;
|
||||
int result;
|
||||
|
||||
@ -32,7 +32,9 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (!strcmp(arg, "--cached"))
|
||||
cached = 1;
|
||||
option |= DIFF_INDEX_CACHED;
|
||||
else if (!strcmp(arg, "--merge-base"))
|
||||
option |= DIFF_INDEX_MERGE_BASE;
|
||||
else
|
||||
usage(diff_cache_usage);
|
||||
}
|
||||
@ -46,7 +48,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
if (rev.pending.nr != 1 ||
|
||||
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
|
||||
usage(diff_cache_usage);
|
||||
if (!cached) {
|
||||
if (!(option & DIFF_INDEX_CACHED)) {
|
||||
setup_work_tree();
|
||||
if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
|
||||
perror("read_cache_preload");
|
||||
@ -56,7 +58,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
perror("read_cache");
|
||||
return -1;
|
||||
}
|
||||
result = run_diff_index(&rev, cached);
|
||||
result = run_diff_index(&rev, option);
|
||||
UNLEAK(rev);
|
||||
return diff_result_code(&rev.diffopt, result);
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
struct setup_revision_opt s_r_opt;
|
||||
struct userformat_want w;
|
||||
int read_stdin = 0;
|
||||
int merge_base = 0;
|
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "-h"))
|
||||
usage(diff_tree_usage);
|
||||
@ -143,9 +144,18 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
read_stdin = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--merge-base")) {
|
||||
merge_base = 1;
|
||||
continue;
|
||||
}
|
||||
usage(diff_tree_usage);
|
||||
}
|
||||
|
||||
if (read_stdin && merge_base)
|
||||
die(_("--stdin and --merge-base are mutually exclusive"));
|
||||
if (merge_base && opt->pending.nr != 2)
|
||||
die(_("--merge-base only works with two commits"));
|
||||
|
||||
/*
|
||||
* NOTE! We expect "a..b" to expand to "^a b" but it is
|
||||
* perfectly valid for revision range parser to yield "b ^a",
|
||||
@ -165,7 +175,12 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
case 2:
|
||||
tree1 = opt->pending.objects[0].item;
|
||||
tree2 = opt->pending.objects[1].item;
|
||||
if (tree2->flags & UNINTERESTING) {
|
||||
if (merge_base) {
|
||||
struct object_id oid;
|
||||
|
||||
diff_get_merge_base(opt, &oid);
|
||||
tree1 = lookup_object(the_repository, &oid);
|
||||
} else if (tree2->flags & UNINTERESTING) {
|
||||
SWAP(tree2, tree1);
|
||||
}
|
||||
diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt);
|
||||
|
@ -26,7 +26,7 @@
|
||||
static const char builtin_diff_usage[] =
|
||||
"git diff [<options>] [<commit>] [--] [<path>...]\n"
|
||||
" or: git diff [<options>] --cached [<commit>] [--] [<path>...]\n"
|
||||
" or: git diff [<options>] <commit> [<commit>...] <commit> [--] [<path>...]\n"
|
||||
" or: git diff [<options>] <commit> [--merge-base] [<commit>...] <commit> [--] [<path>...]\n"
|
||||
" or: git diff [<options>] <commit>...<commit>] [--] [<path>...]\n"
|
||||
" or: git diff [<options>] <blob> <blob>]\n"
|
||||
" or: git diff [<options>] --no-index [--] <path> <path>]\n"
|
||||
@ -134,11 +134,13 @@ static int builtin_diff_blobs(struct rev_info *revs,
|
||||
static int builtin_diff_index(struct rev_info *revs,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int cached = 0;
|
||||
unsigned int option = 0;
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged"))
|
||||
cached = 1;
|
||||
option |= DIFF_INDEX_CACHED;
|
||||
else if (!strcmp(arg, "--merge-base"))
|
||||
option |= DIFF_INDEX_MERGE_BASE;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
@ -151,7 +153,7 @@ static int builtin_diff_index(struct rev_info *revs,
|
||||
revs->max_count != -1 || revs->min_age != -1 ||
|
||||
revs->max_age != -1)
|
||||
usage(builtin_diff_usage);
|
||||
if (!cached) {
|
||||
if (!(option & DIFF_INDEX_CACHED)) {
|
||||
setup_work_tree();
|
||||
if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
|
||||
perror("read_cache_preload");
|
||||
@ -161,7 +163,7 @@ static int builtin_diff_index(struct rev_info *revs,
|
||||
perror("read_cache");
|
||||
return -1;
|
||||
}
|
||||
return run_diff_index(revs, cached);
|
||||
return run_diff_index(revs, option);
|
||||
}
|
||||
|
||||
static int builtin_diff_tree(struct rev_info *revs,
|
||||
@ -170,19 +172,34 @@ static int builtin_diff_tree(struct rev_info *revs,
|
||||
struct object_array_entry *ent1)
|
||||
{
|
||||
const struct object_id *(oid[2]);
|
||||
int swap = 0;
|
||||
struct object_id mb_oid;
|
||||
int merge_base = 0;
|
||||
|
||||
if (argc > 1)
|
||||
usage(builtin_diff_usage);
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--merge-base"))
|
||||
merge_base = 1;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
|
||||
/*
|
||||
* We saw two trees, ent0 and ent1. If ent1 is uninteresting,
|
||||
* swap them.
|
||||
*/
|
||||
if (ent1->item->flags & UNINTERESTING)
|
||||
swap = 1;
|
||||
oid[swap] = &ent0->item->oid;
|
||||
oid[1 - swap] = &ent1->item->oid;
|
||||
if (merge_base) {
|
||||
diff_get_merge_base(revs, &mb_oid);
|
||||
oid[0] = &mb_oid;
|
||||
oid[1] = &revs->pending.objects[1].item->oid;
|
||||
} else {
|
||||
int swap = 0;
|
||||
|
||||
/*
|
||||
* We saw two trees, ent0 and ent1. If ent1 is uninteresting,
|
||||
* swap them.
|
||||
*/
|
||||
if (ent1->item->flags & UNINTERESTING)
|
||||
swap = 1;
|
||||
oid[swap] = &ent0->item->oid;
|
||||
oid[1 - swap] = &ent1->item->oid;
|
||||
}
|
||||
diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
|
||||
log_tree_diff_flush(revs);
|
||||
return 0;
|
||||
|
@ -1698,6 +1698,10 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
|
||||
--patch --no-patch
|
||||
"
|
||||
|
||||
__git_diff_difftool_options="--cached --staged --pickaxe-all --pickaxe-regex
|
||||
--base --ours --theirs --no-index --relative --merge-base
|
||||
$__git_diff_common_options"
|
||||
|
||||
_git_diff ()
|
||||
{
|
||||
__git_has_doubledash && return
|
||||
@ -1720,10 +1724,7 @@ _git_diff ()
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
|
||||
--base --ours --theirs --no-index
|
||||
$__git_diff_common_options
|
||||
"
|
||||
__gitcomp "$__git_diff_difftool_options"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
@ -1745,11 +1746,7 @@ _git_difftool ()
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp_builtin difftool "$__git_diff_common_options
|
||||
--base --cached --ours --theirs
|
||||
--pickaxe-all --pickaxe-regex
|
||||
--relative --staged
|
||||
"
|
||||
__gitcomp_builtin difftool "$__git_diff_difftool_options"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
63
diff-lib.c
63
diff-lib.c
@ -13,6 +13,7 @@
|
||||
#include "submodule.h"
|
||||
#include "dir.h"
|
||||
#include "fsmonitor.h"
|
||||
#include "commit-reach.h"
|
||||
|
||||
/*
|
||||
* diff-files
|
||||
@ -510,16 +511,74 @@ static int diff_cache(struct rev_info *revs,
|
||||
return unpack_trees(1, &t, &opts);
|
||||
}
|
||||
|
||||
int run_diff_index(struct rev_info *revs, int cached)
|
||||
void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
|
||||
{
|
||||
int i;
|
||||
struct commit *mb_child[2] = {0};
|
||||
struct commit_list *merge_bases;
|
||||
|
||||
for (i = 0; i < revs->pending.nr; i++) {
|
||||
struct object *obj = revs->pending.objects[i].item;
|
||||
if (obj->flags)
|
||||
die(_("--merge-base does not work with ranges"));
|
||||
if (obj->type != OBJ_COMMIT)
|
||||
die(_("--merge-base only works with commits"));
|
||||
}
|
||||
|
||||
/*
|
||||
* This check must go after the for loop above because A...B
|
||||
* ranges produce three pending commits, resulting in a
|
||||
* misleading error message.
|
||||
*/
|
||||
if (revs->pending.nr < 1 || revs->pending.nr > 2)
|
||||
BUG("unexpected revs->pending.nr: %d", revs->pending.nr);
|
||||
|
||||
for (i = 0; i < revs->pending.nr; i++)
|
||||
mb_child[i] = lookup_commit_reference(the_repository, &revs->pending.objects[i].item->oid);
|
||||
if (revs->pending.nr == 1) {
|
||||
struct object_id oid;
|
||||
|
||||
if (get_oid("HEAD", &oid))
|
||||
die(_("unable to get HEAD"));
|
||||
|
||||
mb_child[1] = lookup_commit_reference(the_repository, &oid);
|
||||
}
|
||||
|
||||
merge_bases = repo_get_merge_bases(the_repository, mb_child[0], mb_child[1]);
|
||||
if (!merge_bases)
|
||||
die(_("no merge base found"));
|
||||
if (merge_bases->next)
|
||||
die(_("multiple merge bases found"));
|
||||
|
||||
oidcpy(mb, &merge_bases->item->object.oid);
|
||||
|
||||
free_commit_list(merge_bases);
|
||||
}
|
||||
|
||||
int run_diff_index(struct rev_info *revs, unsigned int option)
|
||||
{
|
||||
struct object_array_entry *ent;
|
||||
int cached = !!(option & DIFF_INDEX_CACHED);
|
||||
int merge_base = !!(option & DIFF_INDEX_MERGE_BASE);
|
||||
struct object_id oid;
|
||||
const char *name;
|
||||
char merge_base_hex[GIT_MAX_HEXSZ + 1];
|
||||
|
||||
if (revs->pending.nr != 1)
|
||||
BUG("run_diff_index must be passed exactly one tree");
|
||||
|
||||
trace_performance_enter();
|
||||
ent = revs->pending.objects;
|
||||
if (diff_cache(revs, &ent->item->oid, ent->name, cached))
|
||||
|
||||
if (merge_base) {
|
||||
diff_get_merge_base(revs, &oid);
|
||||
name = oid_to_hex_r(merge_base_hex, &oid);
|
||||
} else {
|
||||
oidcpy(&oid, &ent->item->oid);
|
||||
name = ent->name;
|
||||
}
|
||||
|
||||
if (diff_cache(revs, &oid, name, cached))
|
||||
exit(128);
|
||||
|
||||
diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/");
|
||||
|
7
diff.h
7
diff.h
@ -578,12 +578,17 @@ void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);
|
||||
*/
|
||||
const char *diff_aligned_abbrev(const struct object_id *sha1, int);
|
||||
|
||||
void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb);
|
||||
|
||||
/* do not report anything on removed paths */
|
||||
#define DIFF_SILENT_ON_REMOVED 01
|
||||
/* report racily-clean paths as modified */
|
||||
#define DIFF_RACY_IS_MODIFIED 02
|
||||
int run_diff_files(struct rev_info *revs, unsigned int option);
|
||||
int run_diff_index(struct rev_info *revs, int cached);
|
||||
|
||||
#define DIFF_INDEX_CACHED 01
|
||||
#define DIFF_INDEX_MERGE_BASE 02
|
||||
int run_diff_index(struct rev_info *revs, unsigned int option);
|
||||
|
||||
int do_diff_cache(const struct object_id *, struct diff_options *);
|
||||
int diff_flush_patch_id(struct diff_options *, struct object_id *, int, int);
|
||||
|
193
t/t4068-diff-symmetric-merge-base.sh
Executable file
193
t/t4068-diff-symmetric-merge-base.sh
Executable file
@ -0,0 +1,193 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='behavior of diff with symmetric-diff setups and --merge-base'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
# build these situations:
|
||||
# - normal merge with one merge base (br1...b2r);
|
||||
# - criss-cross merge ie 2 merge bases (br1...master);
|
||||
# - disjoint subgraph (orphan branch, br3...master).
|
||||
#
|
||||
# B---E <-- master
|
||||
# / \ /
|
||||
# A X
|
||||
# \ / \
|
||||
# C---D--G <-- br1
|
||||
# \ /
|
||||
# ---F <-- br2
|
||||
#
|
||||
# H <-- br3
|
||||
#
|
||||
# We put files into a few commits so that we can verify the
|
||||
# output as well.
|
||||
|
||||
test_expect_success setup '
|
||||
git commit --allow-empty -m A &&
|
||||
echo b >b &&
|
||||
git add b &&
|
||||
git commit -m B &&
|
||||
git checkout -b br1 HEAD^ &&
|
||||
echo c >c &&
|
||||
git add c &&
|
||||
git commit -m C &&
|
||||
git tag commit-C &&
|
||||
git merge -m D master &&
|
||||
git tag commit-D &&
|
||||
git checkout master &&
|
||||
git merge -m E commit-C &&
|
||||
git checkout -b br2 commit-C &&
|
||||
echo f >f &&
|
||||
git add f &&
|
||||
git commit -m F &&
|
||||
git checkout br1 &&
|
||||
git merge -m G br2 &&
|
||||
git checkout --orphan br3 &&
|
||||
git commit -m H
|
||||
'
|
||||
|
||||
test_expect_success 'diff with one merge base' '
|
||||
git diff commit-D...br1 >tmp &&
|
||||
tail -n 1 tmp >actual &&
|
||||
echo +f >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
# The output (in tmp) can have +b or +c depending
|
||||
# on which merge base (commit B or C) is picked.
|
||||
# It should have one of those two, which comes out
|
||||
# to seven lines.
|
||||
test_expect_success 'diff with two merge bases' '
|
||||
git diff br1...master >tmp 2>err &&
|
||||
test_line_count = 7 tmp &&
|
||||
test_line_count = 1 err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with no merge bases' '
|
||||
test_must_fail git diff br2...br3 2>err &&
|
||||
test_i18ngrep "fatal: br2...br3: no merge base" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with too many symmetric differences' '
|
||||
test_must_fail git diff br1...master br2...br3 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with symmetric difference and extraneous arg' '
|
||||
test_must_fail git diff master br1...master 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with two ranges' '
|
||||
test_must_fail git diff master br1..master br2..br3 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with ranges and extra arg' '
|
||||
test_must_fail git diff master br1..master commit-D 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff --merge-base with no commits' '
|
||||
test_must_fail git diff --merge-base
|
||||
'
|
||||
|
||||
test_expect_success 'diff --merge-base with three commits' '
|
||||
test_must_fail git diff --merge-base br1 br2 master 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
for cmd in diff-index diff
|
||||
do
|
||||
test_expect_success "$cmd --merge-base with one commit" '
|
||||
git checkout master &&
|
||||
git $cmd commit-C >expect &&
|
||||
git $cmd --merge-base br2 >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with one commit and unstaged changes" '
|
||||
git checkout master &&
|
||||
test_when_finished git reset --hard &&
|
||||
echo unstaged >>c &&
|
||||
git $cmd commit-C >expect &&
|
||||
git $cmd --merge-base br2 >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with one commit and staged and unstaged changes" '
|
||||
git checkout master &&
|
||||
test_when_finished git reset --hard &&
|
||||
echo staged >>c &&
|
||||
git add c &&
|
||||
echo unstaged >>c &&
|
||||
git $cmd commit-C >expect &&
|
||||
git $cmd --merge-base br2 >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base --cached with one commit and staged and unstaged changes" '
|
||||
git checkout master &&
|
||||
test_when_finished git reset --hard &&
|
||||
echo staged >>c &&
|
||||
git add c &&
|
||||
echo unstaged >>c &&
|
||||
git $cmd --cached commit-C >expect &&
|
||||
git $cmd --cached --merge-base br2 >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with non-commit" '
|
||||
git checkout master &&
|
||||
test_must_fail git $cmd --merge-base master^{tree} 2>err &&
|
||||
test_i18ngrep "fatal: --merge-base only works with commits" err
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with no merge bases and one commit" '
|
||||
git checkout master &&
|
||||
test_must_fail git $cmd --merge-base br3 2>err &&
|
||||
test_i18ngrep "fatal: no merge base found" err
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with multiple merge bases and one commit" '
|
||||
git checkout master &&
|
||||
test_must_fail git $cmd --merge-base br1 2>err &&
|
||||
test_i18ngrep "fatal: multiple merge bases found" err
|
||||
'
|
||||
done
|
||||
|
||||
for cmd in diff-tree diff
|
||||
do
|
||||
test_expect_success "$cmd --merge-base with two commits" '
|
||||
git $cmd commit-C master >expect &&
|
||||
git $cmd --merge-base br2 master >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base commit and non-commit" '
|
||||
test_must_fail git $cmd --merge-base br2 master^{tree} 2>err &&
|
||||
test_i18ngrep "fatal: --merge-base only works with commits" err
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with no merge bases and two commits" '
|
||||
test_must_fail git $cmd --merge-base br2 br3 2>err &&
|
||||
test_i18ngrep "fatal: no merge base found" err
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --merge-base with multiple merge bases and two commits" '
|
||||
test_must_fail git $cmd --merge-base master br1 2>err &&
|
||||
test_i18ngrep "fatal: multiple merge bases found" err
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success 'diff-tree --merge-base with one commit' '
|
||||
test_must_fail git diff-tree --merge-base master 2>err &&
|
||||
test_i18ngrep "fatal: --merge-base only works with two commits" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff --merge-base with range' '
|
||||
test_must_fail git diff --merge-base br2..br3 2>err &&
|
||||
test_i18ngrep "fatal: --merge-base does not work with ranges" err
|
||||
'
|
||||
|
||||
test_done
|
@ -1,91 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='behavior of diff with symmetric-diff setups'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
# build these situations:
|
||||
# - normal merge with one merge base (br1...b2r);
|
||||
# - criss-cross merge ie 2 merge bases (br1...master);
|
||||
# - disjoint subgraph (orphan branch, br3...master).
|
||||
#
|
||||
# B---E <-- master
|
||||
# / \ /
|
||||
# A X
|
||||
# \ / \
|
||||
# C---D--G <-- br1
|
||||
# \ /
|
||||
# ---F <-- br2
|
||||
#
|
||||
# H <-- br3
|
||||
#
|
||||
# We put files into a few commits so that we can verify the
|
||||
# output as well.
|
||||
|
||||
test_expect_success setup '
|
||||
git commit --allow-empty -m A &&
|
||||
echo b >b &&
|
||||
git add b &&
|
||||
git commit -m B &&
|
||||
git checkout -b br1 HEAD^ &&
|
||||
echo c >c &&
|
||||
git add c &&
|
||||
git commit -m C &&
|
||||
git tag commit-C &&
|
||||
git merge -m D master &&
|
||||
git tag commit-D &&
|
||||
git checkout master &&
|
||||
git merge -m E commit-C &&
|
||||
git checkout -b br2 commit-C &&
|
||||
echo f >f &&
|
||||
git add f &&
|
||||
git commit -m F &&
|
||||
git checkout br1 &&
|
||||
git merge -m G br2 &&
|
||||
git checkout --orphan br3 &&
|
||||
git commit -m H
|
||||
'
|
||||
|
||||
test_expect_success 'diff with one merge base' '
|
||||
git diff commit-D...br1 >tmp &&
|
||||
tail -n 1 tmp >actual &&
|
||||
echo +f >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
# The output (in tmp) can have +b or +c depending
|
||||
# on which merge base (commit B or C) is picked.
|
||||
# It should have one of those two, which comes out
|
||||
# to seven lines.
|
||||
test_expect_success 'diff with two merge bases' '
|
||||
git diff br1...master >tmp 2>err &&
|
||||
test_line_count = 7 tmp &&
|
||||
test_line_count = 1 err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with no merge bases' '
|
||||
test_must_fail git diff br2...br3 >tmp 2>err &&
|
||||
test_i18ngrep "fatal: br2...br3: no merge base" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with too many symmetric differences' '
|
||||
test_must_fail git diff br1...master br2...br3 >tmp 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with symmetric difference and extraneous arg' '
|
||||
test_must_fail git diff master br1...master >tmp 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with two ranges' '
|
||||
test_must_fail git diff master br1..master br2..br3 >tmp 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_expect_success 'diff with ranges and extra arg' '
|
||||
test_must_fail git diff master br1..master commit-D >tmp 2>err &&
|
||||
test_i18ngrep "usage" err
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user