diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index 33fcde452a..00efde5f0f 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -8,6 +8,7 @@ git-repo-config - Get and set options in .git/config. SYNOPSIS -------- +[verse] 'git-repo-config' [type] name [value [value_regex]] 'git-repo-config' [type] --replace-all name [value [value_regex]] 'git-repo-config' [type] --get name [value_regex] diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt index a1588138ea..9d3865719c 100644 --- a/Documentation/git-svnimport.txt +++ b/Documentation/git-svnimport.txt @@ -9,6 +9,7 @@ git-svnimport - Import a SVN repository into git SYNOPSIS -------- +[verse] 'git-svnimport' [ -o ] [ -h ] [ -v ] [ -d | -D ] [ -C ] [ -i ] [ -u ] [-l limit_rev] [ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ] diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl index 0e092c5d3f..3c860e458c 100755 --- a/contrib/git-svn/git-svn.perl +++ b/contrib/git-svn/git-svn.perl @@ -4,19 +4,12 @@ use warnings; use strict; use vars qw/ $AUTHOR $VERSION - $SVN_URL $SVN_INFO $SVN_WC + $SVN_URL $SVN_INFO $SVN_WC $SVN_UUID $GIT_SVN_INDEX $GIT_SVN $GIT_DIR $REV_DIR/; $AUTHOR = 'Eric Wong '; $VERSION = '0.10.0'; $GIT_DIR = $ENV{GIT_DIR} || "$ENV{PWD}/.git"; -$GIT_SVN = $ENV{GIT_SVN_ID} || 'git-svn'; -$GIT_SVN_INDEX = "$GIT_DIR/$GIT_SVN/index"; -$ENV{GIT_DIR} ||= $GIT_DIR; -$SVN_URL = undef; -$REV_DIR = "$GIT_DIR/$GIT_SVN/revs"; -$SVN_WC = "$GIT_DIR/$GIT_SVN/tree"; - # make sure the svn binary gives consistent output between locales and TZs: $ENV{TZ} = 'UTC'; $ENV{LC_ALL} = 'C'; @@ -24,6 +17,7 @@ # If SVN:: library support is added, please make the dependencies # optional and preserve the capability to use the command-line client. # use eval { require SVN::... } to make it lazy load +# We don't use any modules not in the standard Perl distribution: use Carp qw/croak/; use IO::File qw//; use File::Basename qw/dirname basename/; @@ -32,28 +26,30 @@ use File::Spec qw//; use POSIX qw/strftime/; my $sha1 = qr/[a-f\d]{40}/; -my $sha1_short = qr/[a-f\d]{6,40}/; +my $sha1_short = qr/[a-f\d]{4,40}/; my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit, - $_find_copies_harder, $_l, $_version, $_upgrade); + $_find_copies_harder, $_l, $_version, $_upgrade, $_authors); +my (@_branch_from, %tree_map, %users); -GetOptions( 'revision|r=s' => \$_revision, - 'no-ignore-externals' => \$_no_ignore_ext, - 'stdin|' => \$_stdin, - 'edit|e' => \$_edit, - 'rmdir' => \$_rmdir, - 'upgrade' => \$_upgrade, - 'help|H|h' => \$_help, - 'find-copies-harder' => \$_find_copies_harder, - 'l=i' => \$_l, - 'version|V' => \$_version, - 'no-stop-on-copy' => \$_no_stop_copy ); +my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext, + 'branch|b=s' => \@_branch_from, + 'authors-file|A=s' => \$_authors ); my %cmd = ( - fetch => [ \&fetch, "Download new revisions from SVN" ], - init => [ \&init, "Initialize and fetch (import)"], - commit => [ \&commit, "Commit git revisions to SVN" ], - 'show-ignore' => [ \&show_ignore, "Show svn:ignore listings" ], - rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)" ], - help => [ \&usage, "Show help" ], + fetch => [ \&fetch, "Download new revisions from SVN", + { 'revision|r=s' => \$_revision, %fc_opts } ], + init => [ \&init, "Initialize and fetch (import)", { } ], + commit => [ \&commit, "Commit git revisions to SVN", + { 'stdin|' => \$_stdin, + 'edit|e' => \$_edit, + 'rmdir' => \$_rmdir, + 'find-copies-harder' => \$_find_copies_harder, + 'l=i' => \$_l, + %fc_opts, + } ], + 'show-ignore' => [ \&show_ignore, "Show svn:ignore listings", { } ], + rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)", + { 'no-ignore-externals' => \$_no_ignore_ext, + 'upgrade' => \$_upgrade } ], ); my $cmd; for (my $i = 0; $i < @ARGV; $i++) { @@ -64,16 +60,23 @@ } }; -# we may be called as git-svn-(command), or git-svn(command). -foreach (keys %cmd) { - if (/git\-svn\-?($_)(?:\.\w+)?$/) { - $cmd = $1; - last; - } -} +my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd); + +GetOptions(%opts, 'help|H|h' => \$_help, + 'version|V' => \$_version, + 'id|i=s' => \$GIT_SVN) or exit 1; + +$GIT_SVN ||= $ENV{GIT_SVN_ID} || 'git-svn'; +$GIT_SVN_INDEX = "$GIT_DIR/$GIT_SVN/index"; +$ENV{GIT_DIR} ||= $GIT_DIR; +$SVN_URL = undef; +$REV_DIR = "$GIT_DIR/$GIT_SVN/revs"; +$SVN_WC = "$GIT_DIR/$GIT_SVN/tree"; + usage(0) if $_help; version() if $_version; -usage(1) unless (defined $cmd); +usage(1) unless defined $cmd; +load_authors() if $_authors; svn_check_ignore_externals(); $cmd{$cmd}->[0]->(@ARGV); exit 0; @@ -85,15 +88,25 @@ sub usage { print $fd <<""; git-svn - bidirectional operations between a single Subversion tree and git Usage: $0 [options] [arguments]\n -Available commands: + + print $fd "Available commands:\n" unless $cmd; foreach (sort keys %cmd) { - print $fd ' ',pack('A10',$_),$cmd{$_}->[1],"\n"; + next if $cmd && $cmd ne $_; + print $fd ' ',pack('A13',$_),$cmd{$_}->[1],"\n"; + foreach (keys %{$cmd{$_}->[2]}) { + # prints out arguments as they should be passed: + my $x = s#=s$## ? '' : s#=i$## ? '' : ''; + print $fd ' ' x 17, join(', ', map { length $_ > 1 ? + "--$_" : "-$_" } + split /\|/,$_)," $x\n"; + } } print $fd <<""; -\nGIT_SVN_ID may be set in the environment to an arbitrary identifier if -you're tracking multiple SVN branches/repositories in one git repository -and want to keep them separate. +\nGIT_SVN_ID may be set in the environment or via the --id/-i switch to an +arbitrary identifier if you're tracking multiple SVN branches/repositories in +one git repository and want to keep them separate. See git-svn(1) for more +information. exit $exit; } @@ -105,7 +118,6 @@ sub version { sub rebuild { $SVN_URL = shift or undef; - my $repo_uuid; my $newest_rev = 0; if ($_upgrade) { sys('git-update-ref',"refs/remotes/$GIT_SVN","$GIT_SVN-HEAD"); @@ -141,7 +153,7 @@ sub rebuild { # if we merged or otherwise started elsewhere, this is # how we break out of it - next if (defined $repo_uuid && ($uuid ne $repo_uuid)); + next if (defined $SVN_UUID && ($uuid ne $SVN_UUID)); next if (defined $SVN_URL && ($url ne $SVN_URL)); print "r$rev = $c\n"; @@ -150,7 +162,7 @@ sub rebuild { croak "SVN repository location required: $url\n"; } $SVN_URL ||= $url; - $repo_uuid ||= setup_git_svn(); + $SVN_UUID ||= setup_git_svn(); $latest = $rev; } assert_revision_eq_or_unknown($rev, $c); @@ -215,9 +227,6 @@ sub fetch { sys(@svn_co, $SVN_URL, $SVN_WC); chdir $SVN_WC or croak $!; $last_commit = git_commit($base, @parents); - unless (-f "$GIT_DIR/refs/heads/master") { - sys(qw(git-update-ref refs/heads/master),$last_commit); - } assert_svn_wc_clean($base->{revision}, $last_commit); } else { chdir $SVN_WC or croak $!; @@ -233,6 +242,9 @@ sub fetch { $last_commit = git_commit($log_msg, $last_commit, @parents); } assert_svn_wc_clean($last_rev, $last_commit); + unless (-e "$GIT_DIR/refs/heads/master") { + sys(qw(git-update-ref refs/heads/master),$last_commit); + } return pop @$svn_log; } @@ -243,7 +255,7 @@ sub commit { print "Reading from stdin...\n"; @commits = (); while () { - if (/\b([a-f\d]{6,40})\b/) { + if (/\b($sha1_short)\b/o) { unshift @commits, $1; } } @@ -265,7 +277,6 @@ sub commit { chdir $SVN_WC or croak $!; my $svn_current_rev = svn_info('.')->{'Last Changed Rev'}; foreach my $c (@revs) { - print "Committing $c\n"; my $mods = svn_checkout_tree($svn_current_rev, $c); if (scalar @$mods == 0) { print "Skipping, no changes detected\n"; @@ -312,24 +323,31 @@ sub setup_git_svn { mkpath(["$GIT_DIR/$GIT_SVN/info"]); mkpath([$REV_DIR]); s_to_file($SVN_URL,"$GIT_DIR/$GIT_SVN/info/url"); - my $uuid = svn_info($SVN_URL)->{'Repository UUID'} or + $SVN_UUID = svn_info($SVN_URL)->{'Repository UUID'} or croak "Repository UUID unreadable\n"; - s_to_file($uuid,"$GIT_DIR/$GIT_SVN/info/uuid"); + s_to_file($SVN_UUID,"$GIT_DIR/$GIT_SVN/info/uuid"); open my $fd, '>>', "$GIT_DIR/$GIT_SVN/info/exclude" or croak $!; print $fd '.svn',"\n"; close $fd or croak $!; - return $uuid; + return $SVN_UUID; } sub assert_svn_wc_clean { my ($svn_rev, $treeish) = @_; croak "$svn_rev is not an integer!\n" unless ($svn_rev =~ /^\d+$/); croak "$treeish is not a sha1!\n" unless ($treeish =~ /^$sha1$/o); - my $svn_info = svn_info('.'); - if ($svn_rev != $svn_info->{'Last Changed Rev'}) { - croak "Expected r$svn_rev, got r", - $svn_info->{'Last Changed Rev'},"\n"; + my $lcr = svn_info('.')->{'Last Changed Rev'}; + if ($svn_rev != $lcr) { + print STDERR "Checking for copy-tree ... "; + # use + my @diff = grep(/^Index: /,(safe_qx(qw(svn diff), + "-r$lcr:$svn_rev"))); + if (@diff) { + croak "Nope! Expected r$svn_rev, got r$lcr\n"; + } else { + print STDERR "OK!\n"; + } } my @status = grep(!/^Performing status on external/,(`svn status`)); @status = grep(!/^\s*$/,@status); @@ -512,7 +530,7 @@ sub svn_checkout_tree { my ($svn_rev, $treeish) = @_; my $from = file_to_s("$REV_DIR/$svn_rev"); assert_svn_wc_clean($svn_rev,$from); - print "diff-tree '$from' '$treeish'\n"; + print "diff-tree $from $treeish\n"; my $pid = open my $diff_fh, '-|'; defined $pid or croak $!; if ($pid == 0) { @@ -523,7 +541,7 @@ sub svn_checkout_tree { } my $mods = parse_diff_tree($diff_fh); unless (@$mods) { - # git can do empty commits, SVN doesn't allow it... + # git can do empty commits, but SVN doesn't allow it... return $mods; } my ($rm, $add) = precommit_check($mods); @@ -610,7 +628,7 @@ sub svn_commit_tree { my ($svn_rev, $commit) = @_; my $commit_msg = "$GIT_DIR/$GIT_SVN/.svn-commit.tmp.$$"; my %log_msg = ( msg => '' ); - open my $msg, '>', $commit_msg or croak $!; + open my $msg, '>', $commit_msg or croak $!; chomp(my $type = `git-cat-file -t $commit`); if ($type eq 'commit') { @@ -624,8 +642,10 @@ sub svn_commit_tree { while (<$msg_fh>) { if (!$in_msg) { $in_msg = 1 if (/^\s*$/); + } elsif (/^git-svn-id: /) { + # skip this, we regenerate the correct one + # on re-fetch anyways } else { - $log_msg{msg} .= $_; print $msg $_ or croak $!; } } @@ -637,6 +657,15 @@ sub svn_commit_tree { my $editor = $ENV{VISUAL} || $ENV{EDITOR} || 'vi'; system($editor, $commit_msg); } + + # file_to_s removes all trailing newlines, so just use chomp() here: + open $msg, '<', $commit_msg or croak $!; + { local $/; chomp($log_msg{msg} = <$msg>); } + close $msg or croak $!; + + my ($oneline) = ($log_msg{msg} =~ /([^\n\r]+)/); + print "Committing $commit: $oneline\n"; + my @ci_output = safe_qx(qw(svn commit -F),$commit_msg); my ($committed) = grep(/^Committed revision \d+\./,@ci_output); unlink $commit_msg; @@ -728,6 +757,10 @@ sub svn_log_raw { author => $author, lines => $lines, msg => '' ); + if (defined $_authors && ! defined $users{$author}) { + die "Author: $author not defined in ", + "$_authors file\n"; + } push @svn_log, \%log_msg; $state = 'msg_start'; next; @@ -827,9 +860,9 @@ sub git_commit { my ($log_msg, @parents) = @_; assert_revision_unknown($log_msg->{revision}); my $out_fh = IO::File->new_tmpfile or croak $!; - my $info = svn_info('.'); - my $uuid = $info->{'Repository UUID'}; - defined $uuid or croak "Unable to get Repository UUID\n"; + $SVN_UUID ||= svn_info('.')->{'Repository UUID'}; + + map_tree_joins() if (@_branch_from && !%tree_map); # commit parents can be conditionally bound to a particular # svn revision via: "svn_revno=commit_sha1", filter them out here: @@ -852,19 +885,26 @@ sub git_commit { git_addremove(); chomp(my $tree = `git-write-tree`); croak if $?; + if (exists $tree_map{$tree}) { + my %seen_parent = map { $_ => 1 } @exec_parents; + foreach (@{$tree_map{$tree}}) { + # MAXPARENT is defined to 16 in commit-tree.c: + if ($seen_parent{$_} || @exec_parents > 16) { + next; + } + push @exec_parents, $_; + $seen_parent{$_} = 1; + } + } my $msg_fh = IO::File->new_tmpfile or croak $!; print $msg_fh $log_msg->{msg}, "\ngit-svn-id: ", "$SVN_URL\@$log_msg->{revision}", - " $uuid\n" or croak $!; + " $SVN_UUID\n" or croak $!; $msg_fh->flush == 0 or croak $!; seek $msg_fh, 0, 0 or croak $!; - $ENV{GIT_AUTHOR_NAME} = $ENV{GIT_COMMITTER_NAME} = - $log_msg->{author}; - $ENV{GIT_AUTHOR_EMAIL} = $ENV{GIT_COMMITTER_EMAIL} = - $log_msg->{author}."\@$uuid"; - $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = - $log_msg->{date}; + set_commit_env($log_msg); + my @exec = ('git-commit-tree',$tree); push @exec, '-p', $_ foreach @exec_parents; open STDIN, '<&', $msg_fh or croak $!; @@ -890,6 +930,16 @@ sub git_commit { return $commit; } +sub set_commit_env { + my ($log_msg) = @_; + my $author = $log_msg->{author}; + my ($name,$email) = defined $users{$author} ? @{$users{$author}} + : ($author,"$author\@$SVN_UUID"); + $ENV{GIT_AUTHOR_NAME} = $ENV{GIT_COMMITTER_NAME} = $name; + $ENV{GIT_AUTHOR_EMAIL} = $ENV{GIT_COMMITTER_EMAIL} = $email; + $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_msg->{date}; +} + sub apply_mod_line_blob { my $m = shift; if ($m->{mode_b} =~ /^120/) { @@ -975,6 +1025,41 @@ sub check_upgrade_needed { } } +# fills %tree_map with a reverse mapping of trees to commits. Useful +# for finding parents to commit on. +sub map_tree_joins { + foreach my $br (@_branch_from) { + my $pid = open my $pipe, '-|'; + defined $pid or croak $!; + if ($pid == 0) { + exec(qw(git-rev-list --pretty=raw), $br) or croak $?; + } + while (<$pipe>) { + if (/^commit ($sha1)$/o) { + my $commit = $1; + my ($tree) = (<$pipe> =~ /^tree ($sha1)$/o); + unless (defined $tree) { + die "Failed to parse commit $commit\n"; + } + push @{$tree_map{$tree}}, $commit; + } + } + close $pipe or croak $?; + } +} + +# ' = real-name ' mapping based on git-svnimport: +sub load_authors { + open my $authors, '<', $_authors or die "Can't open $_authors $!\n"; + while (<$authors>) { + chomp; + next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; + my ($user, $name, $email) = ($1, $2, $3); + $users{$user} = [$name, $email]; + } + close $authors or croak $!; +} + __END__ Data structures: @@ -999,7 +1084,7 @@ sub check_upgrade_needed { mode_a => first column of diff-index output, no leading ':', mode_b => second column of diff-index output, sha1_b => sha1sum of the final blob, - chg => change type [MCRAD], + chg => change type [MCRADT], file_a => original file name of a file (iff chg is 'C' or 'R') file_b => new/current file name of a file (any chg) } diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt index 4102deb381..8e9a971a85 100644 --- a/contrib/git-svn/git-svn.txt +++ b/contrib/git-svn/git-svn.txt @@ -27,7 +27,7 @@ For importing svn, git-svnimport is potentially more powerful when operating on repositories organized under the recommended trunk/branch/tags structure, and should be faster, too. -git-svn completely ignores the very limited view of branching that +git-svn mostly ignores the very limited view of branching that Subversion has. This allows git-svn to be much easier to use, especially on repositories that are not organized in a manner that git-svnimport is designed for. @@ -116,8 +116,38 @@ OPTIONS They are both passed directly to git-diff-tree see git-diff-tree(1) for more information. +ADVANCED OPTIONS +---------------- +-b:: +--branch :: + Used with 'fetch' or 'commit'. + + This can be used to join arbitrary git branches to remotes/git-svn + on new commits where the tree object is equivalent. + + When used with different GIT_SVN_ID values, tags and branches in + SVN can be tracked this way, as can some merges where the heads + end up having completely equivalent content. This can even be + used to track branches across multiple SVN _repositories_. + + This option may be specified multiple times, once for each + branch. + +-i:: +--id :: + This sets GIT_SVN_ID (instead of using the environment). See + the section on "Tracking Multiple Repositories or Branches" for + more information on using GIT_SVN_ID. + COMPATIBILITY OPTIONS --------------------- +--upgrade:: + Only used with the 'rebuild' command. + + Run this if you used an old version of git-svn that used + 'git-svn-HEAD' instead of 'remotes/git-svn' as the branch + for tracking the remote. + --no-ignore-externals:: Only used with the 'fetch' and 'rebuild' command. @@ -162,7 +192,7 @@ Tracking and contributing to an Subversion managed-project: git-svn commit remotes/git-svn..my-branch # Something is committed to SVN, pull the latest into your branch:: git-svn fetch && git pull . remotes/git-svn -# Append svn:ignore settings to the default git exclude file: +# Append svn:ignore settings to the default git exclude file:: git-svn show-ignore >> .git/info/exclude DESIGN PHILOSOPHY diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview index de9f3f3c72..781badbc5b 100755 --- a/contrib/gitview/gitview +++ b/contrib/gitview/gitview @@ -798,7 +798,7 @@ class GitView: button.set_relief(gtk.RELIEF_NONE) button.set_sensitive(True) button.connect("clicked", self._show_clicked_cb, - child_id, commit.commit_sha1) + child_id, commit.commit_sha1, self.encoding) hbox.pack_start(button, expand=False, fill=True) button.show() diff --git a/git-annotate.perl b/git-annotate.perl index 08d479f4b9..d93ee19c7e 100755 --- a/git-annotate.perl +++ b/git-annotate.perl @@ -128,7 +128,7 @@ () } printf("%s\t(%10s\t%10s\t%d)%s\n", $rev, $committer, - format_date($date), $i++, $output); + format_date($date), ++$i, $output); } sub init_claim { diff --git a/git-branch.sh b/git-branch.sh index 6ac961e6d1..663a3a370c 100755 --- a/git-branch.sh +++ b/git-branch.sh @@ -48,6 +48,12 @@ If you are sure you want to delete it, run 'git branch -D $branch_name'." exit 0 } +ls_remote_branches () { + git-rev-parse --symbolic --all | + sed -ne 's|^refs/\(remotes/\)|\1|p' | + sort +} + force= while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac do @@ -56,6 +62,10 @@ do delete_branch "$@" exit ;; + -r) + ls_remote_branches + exit + ;; -f) force="$1" ;; diff --git a/git-mv.perl b/git-mv.perl index fe9c40e1b9..75aa8feeb6 100755 --- a/git-mv.perl +++ b/git-mv.perl @@ -62,9 +62,17 @@ () $dstDir = ""; } +my $subdir_prefix = `git rev-parse --show-prefix`; +chomp($subdir_prefix); + +# run in git base directory, so that git-ls-files lists all revisioned files +chdir "$GIT_DIR/.."; + # normalize paths, needed to compare against versioned files and update-index # also, this is nicer to end-users by doing ".//a/./b/.//./c" ==> "a/b/c" for (@srcArgs, @dstArgs) { + # prepend git prefix as we run from base directory + $_ = $subdir_prefix.$_; s|^\./||; s|/\./|/| while (m|/\./|); s|//+|/|g; diff --git a/git-send-email.perl b/git-send-email.perl index b0d095b4e9..7c8d51223f 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -54,7 +54,7 @@ "compose" => \$compose, "quiet" => \$quiet, "suppress-from" => \$suppress_from, - "no-signed-off-cc" => \$no_signed_off_cc, + "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc, ); # Now, let's fill any that aren't set in with defaults: diff --git a/show-branch.c b/show-branch.c index 452e63f786..24efb65e62 100644 --- a/show-branch.c +++ b/show-branch.c @@ -727,24 +727,16 @@ int main(int ac, char **av) while (seen) { struct commit *commit = pop_one_commit(&seen); int this_flag = commit->object.flags; + int is_merge_point = ((this_flag & all_revs) == all_revs); - shown_merge_point |= ((this_flag & all_revs) == all_revs); + shown_merge_point |= is_merge_point; if (1 < num_rev) { int is_merge = !!(commit->parents && commit->parents->next); - if (topics) { - int interesting = 0; - for (i = 1; i < num_rev; i++) { - if ((this_flag & - (1u << (i + REV_SHIFT)))) { - interesting = 1; - break; - } - } - if (!interesting) - continue; - } - + if (topics && + !is_merge_point && + (this_flag & (1u << REV_SHIFT))) + continue; for (i = 0; i < num_rev; i++) { int mark; diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index cabfadd56d..d1947e11c1 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -8,11 +8,20 @@ test_description='Test of the various options to git-rm.' . ./test-lib.sh # Setup some files to be removed, some with funny characters -touch -- foo bar baz 'space embedded' 'tab embedded' 'newline -embedded' -q -git-add -- foo bar baz 'space embedded' 'tab embedded' 'newline -embedded' -q -git-commit -m "add files" +touch -- foo bar baz 'space embedded' -q +git-add -- foo bar baz 'space embedded' -q +git-commit -m "add normal files" +test_tabs=y +if touch -- 'tab embedded' 'newline +embedded' +then +git-add -- 'tab embedded' 'newline +embedded' +git-commit -m "add files with tabs and newlines" +else + say 'Your filesystem does not allow tabs in filenames.' + test_tabs=n +fi test_expect_success \ 'Pre-check that foo exists and is in index before git-rm foo' \ @@ -42,16 +51,18 @@ test_expect_success \ 'Test that "git-rm -- -q" succeeds (remove a file that looks like an option)' \ 'git-rm -- -q' -test_expect_success \ +test "$test_tabs" = y && test_expect_success \ "Test that \"git-rm -f\" succeeds with embedded space, tab, or newline characters." \ "git-rm -f 'space embedded' 'tab embedded' 'newline embedded'" +if test "$test_tabs" = y; then chmod u-w . test_expect_failure \ 'Test that "git-rm -f" fails if its rm fails' \ 'git-rm -f baz' chmod u+w . +fi test_expect_success \ 'When the rm in "git-rm -f" fails, it should not remove the file from the index' \ diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 43d74c502e..811a4797a5 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -11,17 +11,31 @@ test_expect_success \ git-commit -m add -a' test_expect_success \ - 'moving the file' \ + 'moving the file out of subdirectory' \ 'cd path0 && git-mv COPYING ../path1/COPYING' # in path0 currently test_expect_success \ 'commiting the change' \ - 'cd .. && git-commit -m move -a' + 'cd .. && git-commit -m move-out -a' test_expect_success \ 'checking the commit' \ 'git-diff-tree -r -M --name-status HEAD^ HEAD | \ grep -E "^R100.+path0/COPYING.+path1/COPYING"' +test_expect_success \ + 'moving the file back into subdirectory' \ + 'cd path0 && git-mv ../path1/COPYING COPYING' + +# in path0 currently +test_expect_success \ + 'commiting the change' \ + 'cd .. && git-commit -m move-in -a' + +test_expect_success \ + 'checking the commit' \ + 'git-diff-tree -r -M --name-status HEAD^ HEAD | \ + grep -E "^R100.+path1/COPYING.+path0/COPYING"' + test_done diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index cae179436c..172908a5b0 100755 --- a/t/t8001-annotate.sh +++ b/t/t8001-annotate.sh @@ -50,7 +50,8 @@ test_expect_success \ test_expect_success \ 'merge-setup part 2' \ 'git checkout -b branch2 master && - sed -i -e "s/2A quick brown/4A quick brown lazy dog/" file && + sed -e "s/2A quick brown/4A quick brown lazy dog/" < file > file.new && + mv file.new file && GIT_AUTHOR_NAME="B2" git commit -a -m "Branch2-1"' test_expect_success \ diff --git a/update-index.c b/update-index.c index ce1db38d16..797245ab27 100644 --- a/update-index.c +++ b/update-index.c @@ -577,9 +577,11 @@ int main(int argc, const char **argv) break; } if (!strcmp(path, "--index-info")) { + if (i != argc - 1) + die("--index-info must be at the end"); allow_add = allow_replace = allow_remove = 1; read_index_info(line_termination); - continue; + break; } if (!strcmp(path, "--ignore-missing")) { not_new = 1;