Merge branch 'maint'

* maint:
  Small correction in reading of commit headers
  Documentation: fix typo in git-remote.txt
  Add test for blame corner cases.
  blame: -C -C -C
  blame: Notice a wholesale incorporation of an existing file.
  Fix --boundary output
  diff format documentation: describe raw combined diff format
  Mention version 1.5.1 in tutorial and user-manual
  Add --no-rebase option to git-svn dcommit
  Fix markup in git-svn man page
This commit is contained in:
Junio C Hamano
2007-05-06 00:21:03 -07:00
10 changed files with 253 additions and 58 deletions

View File

@ -59,6 +59,28 @@ When `-z` option is not used, TAB, LF, and backslash characters
in pathnames are represented as `\t`, `\n`, and `\\`, in pathnames are represented as `\t`, `\n`, and `\\`,
respectively. respectively.
diff format for merges
----------------------
"git-diff-tree" and "git-diff-files" can take '-c' or '--cc' option
to generate diff output also for merge commits. The output differs
from the format described above in the following way:
. there is a colon for each parent
. there are more "src" modes and "src" sha1
. status is concatenated status characters for each parent
. no optional "score" number
. single path, only for "dst"
Example:
------------------------------------------------
::100644 100644 100644 fabadb8... cc95eb0... 4866510... MM describe.c
------------------------------------------------
Note that 'combined diff' lists only files which were modified from
all parents.
Generating patches with -p Generating patches with -p
-------------------------- --------------------------

View File

@ -40,7 +40,7 @@ With `-t <branch>` option, instead of the default glob
refspec for the remote to track all branches under refspec for the remote to track all branches under
`$GIT_DIR/remotes/<name>/`, a refspec to track only `<branch>` `$GIT_DIR/remotes/<name>/`, a refspec to track only `<branch>`
is created. You can give more than one `-t <branch>` to track is created. You can give more than one `-t <branch>` to track
multiple branche without grabbing all branches. multiple branches without grabbing all branches.
+ +
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch instead of whatever up to point at remote's `<master>` branch instead of whatever

View File

@ -38,32 +38,30 @@ COMMANDS
argument. Normally this command initializes the current argument. Normally this command initializes the current
directory. directory.
-T<trunk_subdir>:: -T<trunk_subdir>;;
--trunk=<trunk_subdir>:: --trunk=<trunk_subdir>;;
-t<tags_subdir>:: -t<tags_subdir>;;
--tags=<tags_subdir>:: --tags=<tags_subdir>;;
-b<branches_subdir>:: -b<branches_subdir>;;
--branches=<branches_subdir>:: --branches=<branches_subdir>;;
These are optional command-line options for init. Each of These are optional command-line options for init. Each of
these flags can point to a relative repository path these flags can point to a relative repository path
(--tags=project/tags') or a full url (--tags=project/tags') or a full url
(--tags=https://foo.org/project/tags) (--tags=https://foo.org/project/tags)
--no-metadata;;
--no-metadata::
Set the 'noMetadata' option in the [svn-remote] config. Set the 'noMetadata' option in the [svn-remote] config.
--use-svm-props:: --use-svm-props;;
Set the 'useSvmProps' option in the [svn-remote] config. Set the 'useSvmProps' option in the [svn-remote] config.
--use-svnsync-props:: --use-svnsync-props;;
Set the 'useSvnsyncProps' option in the [svn-remote] config. Set the 'useSvnsyncProps' option in the [svn-remote] config.
--rewrite-root=<URL>:: --rewrite-root=<URL>;;
Set the 'rewriteRoot' option in the [svn-remote] config. Set the 'rewriteRoot' option in the [svn-remote] config.
--username=<USER>:: --username=<USER>;;
For transports that SVN handles authentication for (http, For transports that SVN handles authentication for (http,
https, and plain svn), specify the username. For other https, and plain svn), specify the username. For other
transports (eg svn+ssh://), you must include the username in transports (eg svn+ssh://), you must include the username in
the URL, eg svn+ssh://foo@svn.bar.com/project the URL, eg svn+ssh://foo@svn.bar.com/project
--prefix=<prefix>;;
--prefix=<prefix>::
This allows one to specify a prefix which is prepended This allows one to specify a prefix which is prepended
to the names of remotes if trunk/branches/tags are to the names of remotes if trunk/branches/tags are
specified. The prefix does not automatically include a specified. The prefix does not automatically include a
@ -73,7 +71,6 @@ COMMANDS
repository. repository.
'fetch':: 'fetch'::
Fetch unfetched revisions from the Subversion remote we are Fetch unfetched revisions from the Subversion remote we are
tracking. The name of the [svn-remote "..."] section in the tracking. The name of the [svn-remote "..."] section in the
.git/config file may be specified as an optional command-line .git/config file may be specified as an optional command-line
@ -104,14 +101,11 @@ accepts. However '--fetch-all' only fetches from the current
Like 'git-rebase'; this requires that the working tree be clean Like 'git-rebase'; this requires that the working tree be clean
and have no uncommitted changes. and have no uncommitted changes.
+
--
-l;; -l;;
--local;; --local;;
Do not fetch remotely; only run 'git-rebase' against the Do not fetch remotely; only run 'git-rebase' against the
last fetched commit from the upstream SVN. last fetched commit from the upstream SVN.
--
+
'dcommit':: 'dcommit'::
Commit each diff from a specified head directly to the SVN Commit each diff from a specified head directly to the SVN
@ -125,6 +119,9 @@ and have no uncommitted changes.
alternative to HEAD. alternative to HEAD.
This is advantageous over 'set-tree' (below) because it produces This is advantageous over 'set-tree' (below) because it produces
cleaner, more linear history. cleaner, more linear history.
+
--no-rebase;;
After committing, do not rebase or reset.
-- --
'log':: 'log'::

View File

@ -1,5 +1,5 @@
A tutorial introduction to git A tutorial introduction to git (for version 1.5.1 or newer)
============================== ===========================================================
This tutorial explains how to import a new project into git, make This tutorial explains how to import a new project into git, make
changes to it, and share changes with other developers. changes to it, and share changes with other developers.

View File

@ -1,5 +1,5 @@
Git User's Manual Git User's Manual (for version 1.5.1 or newer)
_________________ ______________________________________________
This manual is designed to be readable by someone with basic unix This manual is designed to be readable by someone with basic unix
command-line skills, but no previous knowledge of git. command-line skills, but no previous knowledge of git.

View File

@ -59,6 +59,7 @@ static int num_commits;
#define PICKAXE_BLAME_MOVE 01 #define PICKAXE_BLAME_MOVE 01
#define PICKAXE_BLAME_COPY 02 #define PICKAXE_BLAME_COPY 02
#define PICKAXE_BLAME_COPY_HARDER 04 #define PICKAXE_BLAME_COPY_HARDER 04
#define PICKAXE_BLAME_COPY_HARDEST 010
/* /*
* blame for a blame_entry with score lower than these thresholds * blame for a blame_entry with score lower than these thresholds
@ -894,6 +895,39 @@ static void copy_split_if_better(struct scoreboard *sb,
memcpy(best_so_far, this, sizeof(struct blame_entry [3])); memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
} }
/*
* We are looking at a part of the final image represented by
* ent (tlno and same are offset by ent->s_lno).
* tlno is where we are looking at in the final image.
* up to (but not including) same match preimage.
* plno is where we are looking at in the preimage.
*
* <-------------- final image ---------------------->
* <------ent------>
* ^tlno ^same
* <---------preimage----->
* ^plno
*
* All line numbers are 0-based.
*/
static void handle_split(struct scoreboard *sb,
struct blame_entry *ent,
int tlno, int plno, int same,
struct origin *parent,
struct blame_entry *split)
{
if (ent->num_lines <= tlno)
return;
if (tlno < same) {
struct blame_entry this[3];
tlno += ent->s_lno;
same += ent->s_lno;
split_overlap(this, ent, tlno, plno, same, parent);
copy_split_if_better(sb, split, this);
decref_split(this);
}
}
/* /*
* Find the lines from parent that are the same as ent so that * Find the lines from parent that are the same as ent so that
* we can pass blames to it. file_p has the blob contents for * we can pass blames to it. file_p has the blob contents for
@ -926,26 +960,21 @@ static void find_copy_in_blob(struct scoreboard *sb,
patch = compare_buffer(file_p, &file_o, 1); patch = compare_buffer(file_p, &file_o, 1);
/*
* file_o is a part of final image we are annotating.
* file_p partially may match that image.
*/
memset(split, 0, sizeof(struct blame_entry [3])); memset(split, 0, sizeof(struct blame_entry [3]));
plno = tlno = 0; plno = tlno = 0;
for (i = 0; i < patch->num; i++) { for (i = 0; i < patch->num; i++) {
struct chunk *chunk = &patch->chunks[i]; struct chunk *chunk = &patch->chunks[i];
/* tlno to chunk->same are the same as ent */ handle_split(sb, ent, tlno, plno, chunk->same, parent, split);
if (ent->num_lines <= tlno)
break;
if (tlno < chunk->same) {
struct blame_entry this[3];
split_overlap(this, ent,
tlno + ent->s_lno, plno,
chunk->same + ent->s_lno,
parent);
copy_split_if_better(sb, split, this);
decref_split(this);
}
plno = chunk->p_next; plno = chunk->p_next;
tlno = chunk->t_next; tlno = chunk->t_next;
} }
/* remainder, if any, all match the preimage */
handle_split(sb, ent, tlno, plno, ent->num_lines, parent, split);
free_patch(patch); free_patch(patch);
} }
@ -1055,8 +1084,9 @@ static int find_copy_in_parent(struct scoreboard *sb,
* and this code needs to be after diff_setup_done(), which * and this code needs to be after diff_setup_done(), which
* usually makes find-copies-harder imply copy detection. * usually makes find-copies-harder imply copy detection.
*/ */
if ((opt & PICKAXE_BLAME_COPY_HARDER) && if ((opt & PICKAXE_BLAME_COPY_HARDEST)
(!porigin || strcmp(target->path, porigin->path))) || ((opt & PICKAXE_BLAME_COPY_HARDER)
&& (!porigin || strcmp(target->path, porigin->path))))
diff_opts.find_copies_harder = 1; diff_opts.find_copies_harder = 1;
if (is_null_sha1(target->commit->object.sha1)) if (is_null_sha1(target->commit->object.sha1))
@ -2136,6 +2166,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
blame_move_score = parse_score(arg+2); blame_move_score = parse_score(arg+2);
} }
else if (!prefixcmp(arg, "-C")) { else if (!prefixcmp(arg, "-C")) {
/*
* -C enables copy from removed files;
* -C -C enables copy from existing files, but only
* when blaming a new file;
* -C -C -C enables copy from existing files for
* everybody
*/
if (opt & PICKAXE_BLAME_COPY_HARDER)
opt |= PICKAXE_BLAME_COPY_HARDEST;
if (opt & PICKAXE_BLAME_COPY) if (opt & PICKAXE_BLAME_COPY)
opt |= PICKAXE_BLAME_COPY_HARDER; opt |= PICKAXE_BLAME_COPY_HARDER;
opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE; opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;

View File

@ -638,7 +638,9 @@ static char *get_header(const struct commit *commit, const char *key)
next = NULL; next = NULL;
} else } else
next = eol + 1; next = eol + 1;
if (!strncmp(line, key, key_len) && line[key_len] == ' ') { if (eol - line > key_len &&
!strncmp(line, key, key_len) &&
line[key_len] == ' ') {
int len = eol - line - key_len; int len = eol - line - key_len;
char *ret = xmalloc(len); char *ret = xmalloc(len);
memcpy(ret, line + key_len + 1, len - 1); memcpy(ret, line + key_len + 1, len - 1);

View File

@ -55,7 +55,7 @@ $sha1_short = qr/[a-f\d]{4,40}/;
my ($_stdin, $_help, $_edit, my ($_stdin, $_help, $_edit,
$_message, $_file, $_message, $_file,
$_template, $_shared, $_template, $_shared,
$_version, $_fetch_all, $_version, $_fetch_all, $_no_rebase,
$_merge, $_strategy, $_dry_run, $_local, $_merge, $_strategy, $_dry_run, $_local,
$_prefix, $_no_checkout, $_verbose); $_prefix, $_no_checkout, $_verbose);
$Git::SVN::_follow_parent = 1; $Git::SVN::_follow_parent = 1;
@ -114,6 +114,7 @@ my %cmd = (
'verbose|v' => \$_verbose, 'verbose|v' => \$_verbose,
'dry-run|n' => \$_dry_run, 'dry-run|n' => \$_dry_run,
'fetch-all|all' => \$_fetch_all, 'fetch-all|all' => \$_fetch_all,
'no-rebase' => \$_no_rebase,
%cmt_opts, %fc_opts } ], %cmt_opts, %fc_opts } ],
'set-tree' => [ \&cmd_set_tree, 'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish", "Set an SVN repository to a git tree-ish",
@ -413,21 +414,23 @@ sub cmd_dcommit {
return; return;
} }
$_fetch_all ? $gs->fetch_all : $gs->fetch; $_fetch_all ? $gs->fetch_all : $gs->fetch;
# we always want to rebase against the current HEAD, not any unless ($_no_rebase) {
# head that was passed to us # we always want to rebase against the current HEAD, not any
my @diff = command('diff-tree', 'HEAD', $gs->refname, '--'); # head that was passed to us
my @finish; my @diff = command('diff-tree', 'HEAD', $gs->refname, '--');
if (@diff) { my @finish;
@finish = rebase_cmd(); if (@diff) {
print STDERR "W: HEAD and ", $gs->refname, " differ, ", @finish = rebase_cmd();
"using @finish:\n", "@diff"; print STDERR "W: HEAD and ", $gs->refname, " differ, ",
} else { "using @finish:\n", "@diff";
print "No changes between current HEAD and ", } else {
$gs->refname, "\nResetting to the latest ", print "No changes between current HEAD and ",
$gs->refname, "\n"; $gs->refname, "\nResetting to the latest ",
@finish = qw/reset --mixed/; $gs->refname, "\n";
@finish = qw/reset --mixed/;
}
command_noisy(@finish, $gs->refname);
} }
command_noisy(@finish, $gs->refname);
} }
sub cmd_find_rev { sub cmd_find_rev {

View File

@ -244,10 +244,10 @@ void show_log(struct rev_info *opt, const char *sep)
stdout); stdout);
if (opt->commit_format != CMIT_FMT_ONELINE) if (opt->commit_format != CMIT_FMT_ONELINE)
fputs("commit ", stdout); fputs("commit ", stdout);
if (opt->left_right) { if (commit->object.flags & BOUNDARY)
if (commit->object.flags & BOUNDARY) putchar('-');
putchar('-'); else if (opt->left_right) {
else if (commit->object.flags & SYMMETRIC_LEFT) if (commit->object.flags & SYMMETRIC_LEFT)
putchar('<'); putchar('<');
else else
putchar('>'); putchar('>');

132
t/t8003-blame.sh Executable file
View File

@ -0,0 +1,132 @@
#!/bin/sh
test_description='git blame corner cases'
. ./test-lib.sh
pick_fc='s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/'
test_expect_success setup '
echo A A A A A >one &&
echo B B B B B >two &&
echo C C C C C >tres &&
echo ABC >mouse &&
git add one two tres mouse &&
test_tick &&
GIT_AUTHOR_NAME=Initial git commit -m Initial &&
cat one >uno &&
mv two dos &&
cat one >>tres &&
echo DEF >>mouse
git add uno dos tres mouse &&
test_tick &&
GIT_AUTHOR_NAME=Second git commit -a -m Second &&
echo GHIJK >>mouse &&
git add mouse &&
test_tick &&
GIT_AUTHOR_NAME=Third git commit -m Third &&
cat mouse >cow &&
git add cow &&
test_tick &&
GIT_AUTHOR_NAME=Fourth git commit -m Fourth &&
{
echo ABC
echo DEF
echo XXXX
echo GHIJK
} >cow &&
git add cow &&
test_tick &&
GIT_AUTHOR_NAME=Fifth git commit -m Fifth
'
test_expect_success 'straight copy without -C' '
git blame uno | grep Second
'
test_expect_success 'straight move without -C' '
git blame dos | grep Initial
'
test_expect_success 'straight copy with -C' '
git blame -C1 uno | grep Second
'
test_expect_success 'straight move with -C' '
git blame -C1 dos | grep Initial
'
test_expect_success 'straight copy with -C -C' '
git blame -C -C1 uno | grep Initial
'
test_expect_success 'straight move with -C -C' '
git blame -C -C1 dos | grep Initial
'
test_expect_success 'append without -C' '
git blame -L2 tres | grep Second
'
test_expect_success 'append with -C' '
git blame -L2 -C1 tres | grep Second
'
test_expect_success 'append with -C -C' '
git blame -L2 -C -C1 tres | grep Second
'
test_expect_success 'append with -C -C -C' '
git blame -L2 -C -C -C1 tres | grep Initial
'
test_expect_success 'blame wholesale copy' '
git blame -f -C -C1 HEAD^ -- cow | sed -e "$pick_fc" >current &&
{
echo mouse-Initial
echo mouse-Second
echo mouse-Third
} >expected &&
diff -u expected current
'
test_expect_success 'blame wholesale copy and more' '
git blame -f -C -C1 HEAD -- cow | sed -e "$pick_fc" >current &&
{
echo mouse-Initial
echo mouse-Second
echo cow-Fifth
echo mouse-Third
} >expected &&
diff -u expected current
'
test_done