mirror of
https://github.com/git/git
synced 2024-08-27 19:49:21 +00:00
Merge branch 'master' into jc/cache-tree
* master: commit-tree: allow generic object name for the tree as well. Makefile: remove and create xdiff library from scratch. t0000-basic: Add ls-tree recursive test back. Libified diff-index: backward compatibility fix. Libify diff-index. Libify diff-files. Makefile: remove and create libgit.a from scratch. Document the configuration file Document git-var -l listing also configuration variables rev-parse: better error message for ambiguous arguments make update-index --chmod work with multiple files and --stdin socksetup: don't return on set_reuse_addr() error Fix "git show --stat" git-update-index --unresolve Add git-unresolve <paths>... Add colordiff for git to contrib/colordiff. gitk: Let git-rev-list do the argument list parsing
This commit is contained in:
commit
b8ed7f0f40
181
Documentation/config.txt
Normal file
181
Documentation/config.txt
Normal file
|
@ -0,0 +1,181 @@
|
|||
CONFIGURATION FILE
|
||||
------------------
|
||||
|
||||
The git configuration file contains a number of variables that affect
|
||||
the git commands behaviour. They can be used by both the git plumbing
|
||||
and the porcelains. The variables are divided to sections, where
|
||||
in the fully qualified variable name the variable itself is the last
|
||||
dot-separated segment and the section name is everything before the last
|
||||
dot. The variable names are case-insensitive and only alphanumeric
|
||||
characters are allowed. Some variables may appear multiple times.
|
||||
|
||||
The syntax is fairly flexible and permissive; whitespaces are mostly
|
||||
ignored. The '#' and ';' characters begin commends to the end of line,
|
||||
blank lines are ignored, lines containing strings enclosed in square
|
||||
brackets start sections and all the other lines are recognized
|
||||
as setting variables, in the form 'name = value'. If there is no equal
|
||||
sign on the line, the entire line is taken as 'name' and the variable
|
||||
is recognized as boolean "true". String values may be entirely or partially
|
||||
enclosed in double quotes; some variables may require special value format.
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
# Core variables
|
||||
[core]
|
||||
; Don't trust file modes
|
||||
filemode = false
|
||||
|
||||
# Our diff algorithm
|
||||
[diff]
|
||||
external = "/usr/local/bin/gnu-diff -u"
|
||||
renames = true
|
||||
|
||||
Variables
|
||||
~~~~~~~~~
|
||||
|
||||
Note that this list is non-comprehensive and not necessarily complete.
|
||||
For command-specific variables, you will find more detailed description
|
||||
in the appropriate manual page. You will find description of non-core
|
||||
porcelain configuration variables in the respective porcelain documentation.
|
||||
|
||||
core.fileMode::
|
||||
If false, the executable bit differences between the index and
|
||||
the working copy are ignored; useful on broken filesystems like FAT.
|
||||
See gitlink:git-update-index[1]. True by default.
|
||||
|
||||
core.gitProxy::
|
||||
A "proxy command" to execute (as 'command host port') instead
|
||||
of establishing direct connection to the remote server when
|
||||
using the git protocol for fetching. If the variable value is
|
||||
in the "COMMAND for DOMAIN" format, the command is applied only
|
||||
on hostnames ending with the specified domain string. This variable
|
||||
may be set multiple times and is matched in the given order;
|
||||
the first match wins.
|
||||
|
||||
Can be overriden by the 'GIT_PROXY_COMMAND' environment variable
|
||||
(which always applies universally, without the special "for"
|
||||
handling).
|
||||
|
||||
core.ignoreStat::
|
||||
The working copy files are assumed to stay unchanged until you
|
||||
mark them otherwise manually - Git will not detect the file changes
|
||||
by lstat() calls. This is useful on systems where those are very
|
||||
slow, such as Microsoft Windows. See gitlink:git-update-index[1].
|
||||
False by default.
|
||||
|
||||
core.onlyUseSymrefs::
|
||||
Always use the "symref" format instead of symbolic links for HEAD
|
||||
and other symbolic reference files. True by default.
|
||||
|
||||
core.repositoryFormatVersion::
|
||||
Internal variable identifying the repository format and layout
|
||||
version.
|
||||
|
||||
core.sharedRepository::
|
||||
If true, the repository is made shareable between several users
|
||||
in a group (making sure all the files and objects are group-writable).
|
||||
See gitlink:git-init-db[1]. False by default.
|
||||
|
||||
core.warnAmbiguousRefs::
|
||||
If true, git will warn you if the ref name you passed it is ambiguous
|
||||
and might match multiple refs in the .git/refs/ tree. True by default.
|
||||
|
||||
apply.whitespace::
|
||||
Tells `git-apply` how to handle whitespaces, in the same way
|
||||
as the '--whitespace' option. See gitlink:git-apply[1].
|
||||
|
||||
diff.renameLimit::
|
||||
The number of files to consider when performing the copy/rename
|
||||
detection; equivalent to the git diff option '-l'.
|
||||
|
||||
format.headers::
|
||||
Additional email headers to include in a patch to be submitted
|
||||
by mail. See gitlink:git-format-patch[1].
|
||||
|
||||
gitcvs.enabled::
|
||||
Whether the cvs pserver interface is enabled for this repository.
|
||||
See gitlink:git-cvsserver[1].
|
||||
|
||||
gitcvs.logfile::
|
||||
Path to a log file where the cvs pserver interface well... logs
|
||||
various stuff. See gitlink:git-cvsserver[1].
|
||||
|
||||
http.sslVerify::
|
||||
Whether to verify the SSL certificate when fetching or pushing
|
||||
over HTTPS. Can be overriden by the 'GIT_SSL_NO_VERIFY' environment
|
||||
variable.
|
||||
|
||||
http.sslCert::
|
||||
File containing the SSL certificate when fetching or pushing
|
||||
over HTTPS. Can be overriden by the 'GIT_SSL_CERT' environment
|
||||
variable.
|
||||
|
||||
http.sslKey::
|
||||
File containing the SSL private key when fetching or pushing
|
||||
over HTTPS. Can be overriden by the 'GIT_SSL_KEY' environment
|
||||
variable.
|
||||
|
||||
http.sslCAInfo::
|
||||
File containing the certificates to verify the peer with when
|
||||
fetching or pushing over HTTPS. Can be overriden by the
|
||||
'GIT_SSL_CAINFO' environment variable.
|
||||
|
||||
http.sslCAPath::
|
||||
Path containing files with the CA certificates to verify the peer
|
||||
with when fetching or pushing over HTTPS. Can be overriden
|
||||
by the 'GIT_SSL_CAPATH' environment variable.
|
||||
|
||||
http.maxRequests::
|
||||
How many HTTP requests to launch in parallel. Can be overriden
|
||||
by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
|
||||
|
||||
http.lowSpeedLimit, http.lowSpeedTime::
|
||||
If the HTTP transfer speed is less than 'http.lowSpeedLimit'
|
||||
for longer than 'http.lowSpeedTime' seconds, the transfer is aborted.
|
||||
Can be overriden by the 'GIT_HTTP_LOW_SPEED_LIMIT' and
|
||||
'GIT_HTTP_LOW_SPEED_TIME' environment variables.
|
||||
|
||||
i18n.commitEncoding::
|
||||
Character encoding the commit messages are stored in; git itself
|
||||
does not care per se, but this information is necessary e.g. when
|
||||
importing commits from emails or in the gitk graphical history
|
||||
browser (and possibly at other places in the future or in other
|
||||
porcelains). See e.g. gitlink:git-mailinfo[1]. Defaults to 'utf-8'.
|
||||
|
||||
merge.summary::
|
||||
Whether to include summaries of merged commits in newly created
|
||||
merge commit messages. False by default.
|
||||
|
||||
pull.octopus::
|
||||
The default merge strategy to use when pulling multiple branches
|
||||
at once.
|
||||
|
||||
pull.twohead::
|
||||
The default merge strategy to use when pulling a single branch.
|
||||
|
||||
show.difftree::
|
||||
The default gitlink:git-diff-tree[1] arguments to be used
|
||||
for gitlink:git-show[1].
|
||||
|
||||
showbranch.default::
|
||||
The default set of branches for gitlink:git-show-branch[1].
|
||||
See gitlink:git-show-branch[1].
|
||||
|
||||
user.email::
|
||||
Your email address to be recorded in any newly created commits.
|
||||
Can be overriden by the 'GIT_AUTHOR_EMAIL' and 'GIT_COMMITTER_EMAIL'
|
||||
environment variables. See gitlink:git-commit-tree[1].
|
||||
|
||||
user.name::
|
||||
Your full name to be recorded in any newly created commits.
|
||||
Can be overriden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME'
|
||||
environment variables. See gitlink:git-commit-tree[1].
|
||||
|
||||
whatchanged.difftree::
|
||||
The default gitlink:git-diff-tree[1] arguments to be used
|
||||
for gitlink:git-whatchanged[1].
|
||||
|
||||
imap::
|
||||
The configuration variables in the 'imap' section are described
|
||||
in gitlink:git-imap-send[1].
|
|
@ -87,11 +87,11 @@ Given a .git/config like this:
|
|||
renames = true
|
||||
|
||||
; Proxy settings
|
||||
[proxy]
|
||||
command="ssh" for "ssh://kernel.org/"
|
||||
command="proxy-command" for kernel.org
|
||||
command="myprotocol-command" for "my://"
|
||||
command=default-proxy ; for all the rest
|
||||
[core]
|
||||
gitproxy="ssh" for "ssh://kernel.org/"
|
||||
gitproxy="proxy-command" for kernel.org
|
||||
gitproxy="myprotocol-command" for "my://"
|
||||
gitproxy=default-proxy ; for all the rest
|
||||
|
||||
you can set the filemode to true with
|
||||
|
||||
|
@ -104,7 +104,7 @@ to what URL they apply. Here is how to change the entry for kernel.org
|
|||
to "ssh".
|
||||
|
||||
------------
|
||||
% git repo-config proxy.command '"ssh" for kernel.org' 'for kernel.org$'
|
||||
% git repo-config core.gitproxy '"ssh" for kernel.org' 'for kernel.org$'
|
||||
------------
|
||||
|
||||
This makes sure that only the key/value pair for kernel.org is replaced.
|
||||
|
@ -115,7 +115,7 @@ To delete the entry for renames, do
|
|||
% git repo-config --unset diff.renames
|
||||
------------
|
||||
|
||||
If you want to delete an entry for a multivar (like proxy.command above),
|
||||
If you want to delete an entry for a multivar (like core.gitproxy above),
|
||||
you have to provide a regex matching the value of exactly one line.
|
||||
|
||||
To query the value for a given key, do
|
||||
|
@ -133,27 +133,27 @@ or
|
|||
or, to query a multivar:
|
||||
|
||||
------------
|
||||
% git repo-config --get proxy.command "for kernel.org$"
|
||||
% git repo-config --get core.gitproxy "for kernel.org$"
|
||||
------------
|
||||
|
||||
If you want to know all the values for a multivar, do:
|
||||
|
||||
------------
|
||||
% git repo-config --get-all proxy.command
|
||||
% git repo-config --get-all core.gitproxy
|
||||
------------
|
||||
|
||||
If you like to live dangerous, you can replace *all* proxy.commands by a
|
||||
If you like to live dangerous, you can replace *all* core.gitproxy by a
|
||||
new one with
|
||||
|
||||
------------
|
||||
% git repo-config --replace-all proxy.command ssh
|
||||
% git repo-config --replace-all core.gitproxy ssh
|
||||
------------
|
||||
|
||||
However, if you really only want to replace the line for the default proxy,
|
||||
i.e. the one without a "for ..." postfix, do something like this:
|
||||
|
||||
------------
|
||||
% git repo-config proxy.command ssh '! for '
|
||||
% git repo-config core.gitproxy ssh '! for '
|
||||
------------
|
||||
|
||||
To actually match only values with an exclamation mark, you have to
|
||||
|
@ -163,13 +163,16 @@ To actually match only values with an exclamation mark, you have to
|
|||
------------
|
||||
|
||||
|
||||
include::config.txt[]
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Johannes Schindelin <Johannes.Schindelin@gmx.de>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Johannes Schindelin.
|
||||
Documentation by Johannes Schindelin, Petr Baudis and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
|
|
|
@ -17,7 +17,9 @@ Prints a git logical variable.
|
|||
OPTIONS
|
||||
-------
|
||||
-l::
|
||||
Cause the logical variables to be listed.
|
||||
Cause the logical variables to be listed. In addition, all the
|
||||
variables of the git configuration file .git/config are listed
|
||||
as well.
|
||||
|
||||
EXAMPLE
|
||||
--------
|
||||
|
@ -46,6 +48,7 @@ See Also
|
|||
--------
|
||||
gitlink:git-commit-tree[1]
|
||||
gitlink:git-tag[1]
|
||||
gitlink:git-repo-config[1]
|
||||
|
||||
Author
|
||||
------
|
||||
|
|
6
Makefile
6
Makefile
|
@ -199,7 +199,7 @@ LIB_H = \
|
|||
tree-walk.h log-tree.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \
|
||||
diffcore-delta.o log-tree.o
|
||||
|
||||
|
@ -575,12 +575,12 @@ $(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS)
|
|||
$(DIFF_OBJS): diffcore.h
|
||||
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
$(AR) rcs $@ $(LIB_OBJS)
|
||||
rm -f $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
|
||||
XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o
|
||||
|
||||
$(XDIFF_LIB): $(XDIFF_OBJS)
|
||||
$(AR) rcs $@ $(XDIFF_OBJS)
|
||||
rm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS)
|
||||
|
||||
|
||||
doc:
|
||||
|
|
|
@ -92,7 +92,7 @@ int main(int argc, char **argv)
|
|||
|
||||
git_config(git_default_config);
|
||||
|
||||
if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
|
||||
if (argc < 2 || get_sha1(argv[1], tree_sha1) < 0)
|
||||
usage(commit_tree_usage);
|
||||
|
||||
check_valid(tree_sha1, tree_type);
|
||||
|
|
2
config.c
2
config.c
|
@ -252,7 +252,7 @@ int git_default_config(const char *var, const char *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here.. */
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
2
contrib/colordiff/README
Normal file
2
contrib/colordiff/README
Normal file
|
@ -0,0 +1,2 @@
|
|||
This is "colordiff" (http://colordiff.sourceforge.net/) by Dave
|
||||
Ewart <davee@sungate.co.uk>, modified specifically for git.
|
196
contrib/colordiff/colordiff.perl
Executable file
196
contrib/colordiff/colordiff.perl
Executable file
|
@ -0,0 +1,196 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# $Id: colordiff.pl,v 1.4.2.10 2004/01/04 15:02:59 daveewart Exp $
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# ColorDiff - a wrapper/replacment for 'diff' producing #
|
||||
# colourful output #
|
||||
# #
|
||||
# Copyright (C)2002-2004 Dave Ewart (davee@sungate.co.uk) #
|
||||
# #
|
||||
########################################################################
|
||||
# #
|
||||
# This program is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program; if not, write to the Free Software #
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
|
||||
# #
|
||||
########################################################################
|
||||
|
||||
use strict;
|
||||
use Getopt::Long qw(:config pass_through);
|
||||
use IPC::Open2;
|
||||
|
||||
my $app_name = 'colordiff';
|
||||
my $version = '1.0.4';
|
||||
my $author = 'Dave Ewart';
|
||||
my $author_email = 'davee@sungate.co.uk';
|
||||
my $app_www = 'http://colordiff.sourceforge.net/';
|
||||
my $copyright = '(C)2002-2004';
|
||||
my $show_banner = 1;
|
||||
|
||||
# ANSI sequences for colours
|
||||
my %colour;
|
||||
$colour{white} = "\033[1;37m";
|
||||
$colour{yellow} = "\033[1;33m";
|
||||
$colour{green} = "\033[1;32m";
|
||||
$colour{blue} = "\033[1;34m";
|
||||
$colour{cyan} = "\033[1;36m";
|
||||
$colour{red} = "\033[1;31m";
|
||||
$colour{magenta} = "\033[1;35m";
|
||||
$colour{black} = "\033[1;30m";
|
||||
$colour{darkwhite} = "\033[0;37m";
|
||||
$colour{darkyellow} = "\033[0;33m";
|
||||
$colour{darkgreen} = "\033[0;32m";
|
||||
$colour{darkblue} = "\033[0;34m";
|
||||
$colour{darkcyan} = "\033[0;36m";
|
||||
$colour{darkred} = "\033[0;31m";
|
||||
$colour{darkmagenta} = "\033[0;35m";
|
||||
$colour{darkblack} = "\033[0;30m";
|
||||
$colour{OFF} = "\033[0;0m";
|
||||
|
||||
# Default colours if /etc/colordiffrc or ~/.colordiffrc do not exist
|
||||
my $plain_text = $colour{OFF};
|
||||
my $file_old = $colour{red};
|
||||
my $file_new = $colour{blue};
|
||||
my $diff_stuff = $colour{magenta};
|
||||
|
||||
# Locations for personal and system-wide colour configurations
|
||||
my $HOME = $ENV{HOME};
|
||||
my $etcdir = '/etc';
|
||||
|
||||
my ($setting, $value);
|
||||
my @config_files = ("$etcdir/colordiffrc", "$HOME/.colordiffrc");
|
||||
my $config_file;
|
||||
|
||||
foreach $config_file (@config_files) {
|
||||
if (open(COLORDIFFRC, "<$config_file")) {
|
||||
while (<COLORDIFFRC>) {
|
||||
chop;
|
||||
next if (/^#/ || /^$/);
|
||||
s/\s+//g;
|
||||
($setting, $value) = split ('=');
|
||||
if ($setting eq 'banner') {
|
||||
if ($value eq 'no') {
|
||||
$show_banner = 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
if (!defined $colour{$value}) {
|
||||
print "Invalid colour specification ($value) in $config_file\n";
|
||||
next;
|
||||
}
|
||||
if ($setting eq 'plain') {
|
||||
$plain_text = $colour{$value};
|
||||
}
|
||||
elsif ($setting eq 'oldtext') {
|
||||
$file_old = $colour{$value};
|
||||
}
|
||||
elsif ($setting eq 'newtext') {
|
||||
$file_new = $colour{$value};
|
||||
}
|
||||
elsif ($setting eq 'diffstuff') {
|
||||
$diff_stuff = $colour{$value};
|
||||
}
|
||||
else {
|
||||
print "Unknown option in $etcdir/colordiffrc: $setting\n";
|
||||
}
|
||||
}
|
||||
close COLORDIFFRC;
|
||||
}
|
||||
}
|
||||
|
||||
# colordiff specfic options here. Need to pre-declare if using variables
|
||||
GetOptions(
|
||||
"no-banner" => sub { $show_banner = 0 },
|
||||
"plain-text=s" => \&set_color,
|
||||
"file-old=s" => \&set_color,
|
||||
"file-new=s" => \&set_color,
|
||||
"diff-stuff=s" => \&set_color
|
||||
);
|
||||
|
||||
if ($show_banner == 1) {
|
||||
print STDERR "$app_name $version ($app_www)\n";
|
||||
print STDERR "$copyright $author, $author_email\n\n";
|
||||
}
|
||||
|
||||
if (defined $ARGV[0]) {
|
||||
# More reliable way of pulling in arguments
|
||||
open2(\*INPUTSTREAM, undef, "git", "diff", @ARGV);
|
||||
}
|
||||
else {
|
||||
*INPUTSTREAM = \*STDIN;
|
||||
}
|
||||
|
||||
my $record;
|
||||
my $nrecs = 0;
|
||||
my $inside_file_old = 1;
|
||||
my $nparents = undef;
|
||||
|
||||
while (<INPUTSTREAM>) {
|
||||
$nrecs++;
|
||||
if (/^(\@\@+) -[-+0-9, ]+ \1/) {
|
||||
print "$diff_stuff";
|
||||
$nparents = length($1) - 1;
|
||||
}
|
||||
elsif (/^diff -/ || /^index / ||
|
||||
/^old mode / || /^new mode / ||
|
||||
/^deleted file mode / || /^new file mode / ||
|
||||
/^similarity index / || /^dissimilarity index / ||
|
||||
/^copy from / || /^copy to / ||
|
||||
/^rename from / || /^rename to /) {
|
||||
$nparents = undef;
|
||||
print "$diff_stuff";
|
||||
}
|
||||
elsif (defined $nparents) {
|
||||
if ($nparents == 1) {
|
||||
if (/^\+/) {
|
||||
print $file_new;
|
||||
}
|
||||
elsif (/^-/) {
|
||||
print $file_old;
|
||||
}
|
||||
else {
|
||||
print $plain_text;
|
||||
}
|
||||
}
|
||||
elsif (/^ {$nparents}/) {
|
||||
print "$plain_text";
|
||||
}
|
||||
elsif (/^[+ ]{$nparents}/) {
|
||||
print "$file_new";
|
||||
}
|
||||
elsif (/^[- ]{$nparents}/) {
|
||||
print "$file_old";
|
||||
}
|
||||
else {
|
||||
print $plain_text;
|
||||
}
|
||||
}
|
||||
elsif (/^--- / || /^\+\+\+ /) {
|
||||
print $diff_stuff;
|
||||
}
|
||||
else {
|
||||
print "$plain_text";
|
||||
}
|
||||
s/$/$colour{OFF}/;
|
||||
print "$_";
|
||||
}
|
||||
close INPUTSTREAM;
|
||||
|
||||
sub set_color {
|
||||
my ($type, $color) = @_;
|
||||
|
||||
$type =~ s/-/_/;
|
||||
eval "\$$type = \$colour{$color}";
|
||||
}
|
2
daemon.c
2
daemon.c
|
@ -535,7 +535,7 @@ static int socksetup(int port, int **socklist_p)
|
|||
|
||||
if (set_reuse_addr(sockfd)) {
|
||||
close(sockfd);
|
||||
return 0; /* not fatal */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
|
|
206
diff-files.c
206
diff-files.c
|
@ -12,203 +12,43 @@ static const char diff_files_usage[] =
|
|||
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
|
||||
COMMON_DIFF_OPTIONS_HELP;
|
||||
|
||||
static struct rev_info rev;
|
||||
static int silent = 0;
|
||||
static int diff_unmerged_stage = 2;
|
||||
static int combine_merges = 0;
|
||||
static int dense_combined_merges = 0;
|
||||
|
||||
static void show_unmerge(const char *path)
|
||||
{
|
||||
diff_unmerge(&rev.diffopt, path);
|
||||
}
|
||||
|
||||
static void show_file(int pfx, struct cache_entry *ce)
|
||||
{
|
||||
diff_addremove(&rev.diffopt, pfx, ntohl(ce->ce_mode),
|
||||
ce->sha1, ce->name, NULL);
|
||||
}
|
||||
|
||||
static void show_modified(int oldmode, int mode,
|
||||
const unsigned char *old_sha1, const unsigned char *sha1,
|
||||
char *path)
|
||||
{
|
||||
diff_change(&rev.diffopt, oldmode, mode, old_sha1, sha1, path, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
const char **pathspec;
|
||||
const char *prefix = setup_git_directory();
|
||||
int entries, i;
|
||||
struct rev_info rev;
|
||||
int silent = 0;
|
||||
|
||||
git_config(git_diff_config);
|
||||
diff_setup(&rev.diffopt);
|
||||
init_revisions(&rev);
|
||||
rev.abbrev = 0;
|
||||
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
while (1 < argc && argv[1][0] == '-') {
|
||||
if (!strcmp(argv[1], "--")) {
|
||||
argv++;
|
||||
argc--;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(argv[1], "-0"))
|
||||
diff_unmerged_stage = 0;
|
||||
else if (!strcmp(argv[1], "-1"))
|
||||
diff_unmerged_stage = 1;
|
||||
else if (!strcmp(argv[1], "-2"))
|
||||
diff_unmerged_stage = 2;
|
||||
else if (!strcmp(argv[1], "-3"))
|
||||
diff_unmerged_stage = 3;
|
||||
else if (!strcmp(argv[1], "--base"))
|
||||
diff_unmerged_stage = 1;
|
||||
if (!strcmp(argv[1], "--base"))
|
||||
rev.max_count = 1;
|
||||
else if (!strcmp(argv[1], "--ours"))
|
||||
diff_unmerged_stage = 2;
|
||||
rev.max_count = 2;
|
||||
else if (!strcmp(argv[1], "--theirs"))
|
||||
diff_unmerged_stage = 3;
|
||||
rev.max_count = 3;
|
||||
else if (!strcmp(argv[1], "-q"))
|
||||
silent = 1;
|
||||
else if (!strcmp(argv[1], "-r"))
|
||||
; /* no-op */
|
||||
else if (!strcmp(argv[1], "-s"))
|
||||
; /* no-op */
|
||||
else if (!strcmp(argv[1], "-c"))
|
||||
combine_merges = 1;
|
||||
else if (!strcmp(argv[1], "--cc"))
|
||||
dense_combined_merges = combine_merges = 1;
|
||||
else {
|
||||
int diff_opt_cnt;
|
||||
diff_opt_cnt = diff_opt_parse(&rev.diffopt,
|
||||
argv+1, argc-1);
|
||||
if (diff_opt_cnt < 0)
|
||||
usage(diff_files_usage);
|
||||
else if (diff_opt_cnt) {
|
||||
argv += diff_opt_cnt;
|
||||
argc -= diff_opt_cnt;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
usage(diff_files_usage);
|
||||
}
|
||||
argv++; argc--;
|
||||
}
|
||||
if (dense_combined_merges)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
|
||||
/* Find the directory, and set up the pathspec */
|
||||
pathspec = get_pathspec(prefix, argv + 1);
|
||||
entries = read_cache();
|
||||
|
||||
if (diff_setup_done(&rev.diffopt) < 0)
|
||||
/*
|
||||
* Make sure there are NO revision (i.e. pending object) parameter,
|
||||
* rev.max_count is reasonable (0 <= n <= 3),
|
||||
* there is no other revision filtering parameters.
|
||||
*/
|
||||
if (rev.pending_objects ||
|
||||
rev.min_age != -1 || rev.max_age != -1)
|
||||
usage(diff_files_usage);
|
||||
|
||||
/* At this point, if argc == 1, then we are doing everything.
|
||||
* Otherwise argv[1] .. argv[argc-1] have the explicit paths.
|
||||
*/
|
||||
if (entries < 0) {
|
||||
perror("read_cache");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
struct stat st;
|
||||
unsigned int oldmode, newmode;
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int changed;
|
||||
|
||||
if (!ce_path_match(ce, pathspec))
|
||||
continue;
|
||||
|
||||
if (ce_stage(ce)) {
|
||||
struct {
|
||||
struct combine_diff_path p;
|
||||
struct combine_diff_parent filler[5];
|
||||
} combine;
|
||||
int num_compare_stages = 0;
|
||||
|
||||
combine.p.next = NULL;
|
||||
combine.p.len = ce_namelen(ce);
|
||||
combine.p.path = xmalloc(combine.p.len + 1);
|
||||
memcpy(combine.p.path, ce->name, combine.p.len);
|
||||
combine.p.path[combine.p.len] = 0;
|
||||
combine.p.mode = 0;
|
||||
memset(combine.p.sha1, 0, 20);
|
||||
memset(&combine.p.parent[0], 0,
|
||||
sizeof(combine.filler));
|
||||
|
||||
while (i < entries) {
|
||||
struct cache_entry *nce = active_cache[i];
|
||||
int stage;
|
||||
|
||||
if (strcmp(ce->name, nce->name))
|
||||
break;
|
||||
|
||||
/* Stage #2 (ours) is the first parent,
|
||||
* stage #3 (theirs) is the second.
|
||||
*/
|
||||
stage = ce_stage(nce);
|
||||
if (2 <= stage) {
|
||||
int mode = ntohl(nce->ce_mode);
|
||||
num_compare_stages++;
|
||||
memcpy(combine.p.parent[stage-2].sha1,
|
||||
nce->sha1, 20);
|
||||
combine.p.parent[stage-2].mode =
|
||||
canon_mode(mode);
|
||||
combine.p.parent[stage-2].status =
|
||||
DIFF_STATUS_MODIFIED;
|
||||
}
|
||||
|
||||
/* diff against the proper unmerged stage */
|
||||
if (stage == diff_unmerged_stage)
|
||||
ce = nce;
|
||||
i++;
|
||||
}
|
||||
/*
|
||||
* Compensate for loop update
|
||||
* Backward compatibility wart - "diff-files -s" used to
|
||||
* defeat the common diff option "-s" which asked for
|
||||
* DIFF_FORMAT_NO_OUTPUT.
|
||||
*/
|
||||
i--;
|
||||
|
||||
if (combine_merges && num_compare_stages == 2) {
|
||||
show_combined_diff(&combine.p, 2,
|
||||
dense_combined_merges,
|
||||
&rev);
|
||||
free(combine.p.path);
|
||||
continue;
|
||||
}
|
||||
free(combine.p.path);
|
||||
|
||||
/*
|
||||
* Show the diff for the 'ce' if we found the one
|
||||
* from the desired stage.
|
||||
*/
|
||||
show_unmerge(ce->name);
|
||||
if (ce_stage(ce) != diff_unmerged_stage)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lstat(ce->name, &st) < 0) {
|
||||
if (errno != ENOENT && errno != ENOTDIR) {
|
||||
perror(ce->name);
|
||||
continue;
|
||||
}
|
||||
if (silent)
|
||||
continue;
|
||||
show_file('-', ce);
|
||||
continue;
|
||||
}
|
||||
changed = ce_match_stat(ce, &st, 0);
|
||||
if (!changed && !rev.diffopt.find_copies_harder)
|
||||
continue;
|
||||
oldmode = ntohl(ce->ce_mode);
|
||||
|
||||
newmode = canon_mode(st.st_mode);
|
||||
if (!trust_executable_bit &&
|
||||
S_ISREG(newmode) && S_ISREG(oldmode) &&
|
||||
((newmode ^ oldmode) == 0111))
|
||||
newmode = oldmode;
|
||||
show_modified(oldmode, newmode,
|
||||
ce->sha1, (changed ? null_sha1 : ce->sha1),
|
||||
ce->name);
|
||||
}
|
||||
diffcore_std(&rev.diffopt);
|
||||
diff_flush(&rev.diffopt);
|
||||
return 0;
|
||||
if (rev.diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
return run_diff_files(&rev, silent);
|
||||
}
|
||||
|
|
250
diff-index.c
250
diff-index.c
|
@ -1,166 +1,7 @@
|
|||
#include "cache.h"
|
||||
#include "tree.h"
|
||||
#include "diff.h"
|
||||
|
||||
static int cached_only = 0;
|
||||
static int match_nonexisting = 0;
|
||||
static struct diff_options diff_options;
|
||||
|
||||
/* A file entry went away or appeared */
|
||||
static void show_file(const char *prefix,
|
||||
struct cache_entry *ce,
|
||||
unsigned char *sha1, unsigned int mode)
|
||||
{
|
||||
diff_addremove(&diff_options, prefix[0], ntohl(mode),
|
||||
sha1, ce->name, NULL);
|
||||
}
|
||||
|
||||
static int get_stat_data(struct cache_entry *ce,
|
||||
unsigned char ** sha1p, unsigned int *modep)
|
||||
{
|
||||
unsigned char *sha1 = ce->sha1;
|
||||
unsigned int mode = ce->ce_mode;
|
||||
|
||||
if (!cached_only) {
|
||||
static unsigned char no_sha1[20];
|
||||
int changed;
|
||||
struct stat st;
|
||||
if (lstat(ce->name, &st) < 0) {
|
||||
if (errno == ENOENT && match_nonexisting) {
|
||||
*sha1p = sha1;
|
||||
*modep = mode;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
changed = ce_match_stat(ce, &st, 0);
|
||||
if (changed) {
|
||||
mode = create_ce_mode(st.st_mode);
|
||||
if (!trust_executable_bit && S_ISREG(st.st_mode))
|
||||
mode = ce->ce_mode;
|
||||
sha1 = no_sha1;
|
||||
}
|
||||
}
|
||||
|
||||
*sha1p = sha1;
|
||||
*modep = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_new_file(struct cache_entry *new)
|
||||
{
|
||||
unsigned char *sha1;
|
||||
unsigned int mode;
|
||||
|
||||
/* New file in the index: it might actually be different in
|
||||
* the working copy.
|
||||
*/
|
||||
if (get_stat_data(new, &sha1, &mode) < 0)
|
||||
return;
|
||||
|
||||
show_file("+", new, sha1, mode);
|
||||
}
|
||||
|
||||
static int show_modified(struct cache_entry *old,
|
||||
struct cache_entry *new,
|
||||
int report_missing)
|
||||
{
|
||||
unsigned int mode, oldmode;
|
||||
unsigned char *sha1;
|
||||
|
||||
if (get_stat_data(new, &sha1, &mode) < 0) {
|
||||
if (report_missing)
|
||||
show_file("-", old, old->sha1, old->ce_mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oldmode = old->ce_mode;
|
||||
if (mode == oldmode && !memcmp(sha1, old->sha1, 20) &&
|
||||
!diff_options.find_copies_harder)
|
||||
return 0;
|
||||
|
||||
mode = ntohl(mode);
|
||||
oldmode = ntohl(oldmode);
|
||||
|
||||
diff_change(&diff_options, oldmode, mode,
|
||||
old->sha1, sha1, old->name, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int diff_cache(struct cache_entry **ac, int entries, const char **pathspec)
|
||||
{
|
||||
while (entries) {
|
||||
struct cache_entry *ce = *ac;
|
||||
int same = (entries > 1) && ce_same_name(ce, ac[1]);
|
||||
|
||||
if (!ce_path_match(ce, pathspec))
|
||||
goto skip_entry;
|
||||
|
||||
switch (ce_stage(ce)) {
|
||||
case 0:
|
||||
/* No stage 1 entry? That means it's a new file */
|
||||
if (!same) {
|
||||
show_new_file(ce);
|
||||
break;
|
||||
}
|
||||
/* Show difference between old and new */
|
||||
show_modified(ac[1], ce, 1);
|
||||
break;
|
||||
case 1:
|
||||
/* No stage 3 (merge) entry? That means it's been deleted */
|
||||
if (!same) {
|
||||
show_file("-", ce, ce->sha1, ce->ce_mode);
|
||||
break;
|
||||
}
|
||||
/* We come here with ce pointing at stage 1
|
||||
* (original tree) and ac[1] pointing at stage
|
||||
* 3 (unmerged). show-modified with
|
||||
* report-missing set to false does not say the
|
||||
* file is deleted but reports true if work
|
||||
* tree does not have it, in which case we
|
||||
* fall through to report the unmerged state.
|
||||
* Otherwise, we show the differences between
|
||||
* the original tree and the work tree.
|
||||
*/
|
||||
if (!cached_only && !show_modified(ce, ac[1], 0))
|
||||
break;
|
||||
/* fallthru */
|
||||
case 3:
|
||||
diff_unmerge(&diff_options, ce->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("impossible cache entry stage");
|
||||
}
|
||||
|
||||
skip_entry:
|
||||
/*
|
||||
* Ignore all the different stages for this file,
|
||||
* we've handled the relevant cases now.
|
||||
*/
|
||||
do {
|
||||
ac++;
|
||||
entries--;
|
||||
} while (entries && ce_same_name(ce, ac[0]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This turns all merge entries into "stage 3". That guarantees that
|
||||
* when we read in the new tree (into "stage 1"), we won't lose sight
|
||||
* of the fact that we had unmerged entries.
|
||||
*/
|
||||
static void mark_merge_entries(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (!ce_stage(ce))
|
||||
continue;
|
||||
ce->ce_flags |= htons(CE_STAGEMASK);
|
||||
}
|
||||
}
|
||||
#include "commit.h"
|
||||
#include "revision.h"
|
||||
|
||||
static const char diff_cache_usage[] =
|
||||
"git-diff-index [-m] [--cached] "
|
||||
|
@ -169,85 +10,30 @@ COMMON_DIFF_OPTIONS_HELP;
|
|||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
const char *tree_name = NULL;
|
||||
unsigned char sha1[20];
|
||||
const char *prefix = setup_git_directory();
|
||||
const char **pathspec = NULL;
|
||||
struct tree *tree;
|
||||
int ret;
|
||||
int allow_options = 1;
|
||||
struct rev_info rev;
|
||||
int match_missing = 0;
|
||||
int cached = 0;
|
||||
int i;
|
||||
|
||||
git_config(git_diff_config);
|
||||
diff_setup(&diff_options);
|
||||
init_revisions(&rev);
|
||||
rev.abbrev = 0;
|
||||
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
int diff_opt_cnt;
|
||||
|
||||
if (!allow_options || *arg != '-') {
|
||||
if (tree_name)
|
||||
break;
|
||||
tree_name = arg;
|
||||
continue;
|
||||
if (!strcmp(arg, "--cached"))
|
||||
cached = 1;
|
||||
else
|
||||
usage(diff_cache_usage);
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "--")) {
|
||||
allow_options = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-r")) {
|
||||
/* We accept the -r flag just to look like git-diff-tree */
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--cc"))
|
||||
/*
|
||||
* I _think_ "diff-index --cached HEAD" with an
|
||||
* unmerged index could show something else
|
||||
* later, but pretend --cc is the same as -p for
|
||||
* now. "git diff" uses --cc by default.
|
||||
* Make sure there is one revision (i.e. pending object),
|
||||
* and there is no revision filtering parameters.
|
||||
*/
|
||||
argv[i] = arg = "-p";
|
||||
diff_opt_cnt = diff_opt_parse(&diff_options, argv + i,
|
||||
argc - i);
|
||||
if (diff_opt_cnt < 0)
|
||||
if (!rev.pending_objects || rev.pending_objects->next ||
|
||||
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
|
||||
usage(diff_cache_usage);
|
||||
else if (diff_opt_cnt) {
|
||||
i += diff_opt_cnt - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "-m")) {
|
||||
match_nonexisting = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--cached")) {
|
||||
cached_only = 1;
|
||||
continue;
|
||||
}
|
||||
usage(diff_cache_usage);
|
||||
}
|
||||
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
if (diff_setup_done(&diff_options) < 0)
|
||||
usage(diff_cache_usage);
|
||||
|
||||
if (!tree_name || get_sha1(tree_name, sha1))
|
||||
usage(diff_cache_usage);
|
||||
|
||||
read_cache();
|
||||
|
||||
mark_merge_entries();
|
||||
|
||||
tree = parse_tree_indirect(sha1);
|
||||
if (!tree)
|
||||
die("bad tree object %s", tree_name);
|
||||
if (read_tree(tree, 1, pathspec))
|
||||
die("unable to read tree object %s", tree_name);
|
||||
|
||||
ret = diff_cache(active_cache, active_nr, pathspec);
|
||||
|
||||
diffcore_std(&diff_options);
|
||||
diff_flush(&diff_options);
|
||||
return ret;
|
||||
return run_diff_index(&rev, cached);
|
||||
}
|
||||
|
|
2047
diff-lib.c
2047
diff-lib.c
File diff suppressed because it is too large
Load diff
9
diff.h
9
diff.h
|
@ -28,10 +28,11 @@ struct diff_options {
|
|||
with_raw:1,
|
||||
with_stat:1,
|
||||
tree_in_recursive:1,
|
||||
full_index:1;
|
||||
full_index:1,
|
||||
silent_on_remove:1,
|
||||
find_copies_harder:1;
|
||||
int break_opt;
|
||||
int detect_rename;
|
||||
int find_copies_harder;
|
||||
int line_termination;
|
||||
int output_format;
|
||||
int pickaxe_opts;
|
||||
|
@ -168,4 +169,8 @@ extern void diff_flush(struct diff_options*);
|
|||
|
||||
extern const char *diff_unique_abbrev(const unsigned char *, int);
|
||||
|
||||
extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
|
||||
|
||||
extern int run_diff_index(struct rev_info *revs, int cached);
|
||||
|
||||
#endif /* DIFF_H */
|
||||
|
|
20
gitk
20
gitk
|
@ -16,22 +16,6 @@ proc gitdir {} {
|
|||
}
|
||||
}
|
||||
|
||||
proc parse_args {rargs} {
|
||||
global parsed_args
|
||||
|
||||
if {[catch {
|
||||
set parse_args [concat --default HEAD $rargs]
|
||||
set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
|
||||
}]} {
|
||||
# if git-rev-parse failed for some reason...
|
||||
if {$rargs == {}} {
|
||||
set rargs HEAD
|
||||
}
|
||||
set parsed_args $rargs
|
||||
}
|
||||
return $parsed_args
|
||||
}
|
||||
|
||||
proc start_rev_list {rlargs} {
|
||||
global startmsecs nextupdate ncmupdate
|
||||
global commfd leftover tclencoding datemode
|
||||
|
@ -46,7 +30,7 @@ proc start_rev_list {rlargs} {
|
|||
}
|
||||
if {[catch {
|
||||
set commfd [open [concat | git-rev-list --header $order \
|
||||
--parents --boundary $rlargs] r]
|
||||
--parents --boundary --default HEAD $rlargs] r]
|
||||
} err]} {
|
||||
puts stderr "Error executing git-rev-list: $err"
|
||||
exit 1
|
||||
|
@ -65,7 +49,7 @@ proc getcommits {rargs} {
|
|||
global phase canv mainfont
|
||||
|
||||
set phase getcommits
|
||||
start_rev_list [parse_args $rargs]
|
||||
start_rev_list $rargs
|
||||
$canv delete all
|
||||
$canv create text 3 3 -anchor nw -text "Reading commits..." \
|
||||
-font $mainfont -tags textitems
|
||||
|
|
12
rev-parse.c
12
rev-parse.c
|
@ -160,6 +160,14 @@ static int show_file(const char *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void die_badfile(const char *arg)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
die("'%s': %s", arg, strerror(errno));
|
||||
die("'%s' is ambiguous - revision name or file/directory name?\n"
|
||||
"Please put '--' before the list of filenames.", arg);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, as_is = 0, verify = 0;
|
||||
|
@ -176,7 +184,7 @@ int main(int argc, char **argv)
|
|||
if (as_is) {
|
||||
if (show_file(arg) && as_is < 2)
|
||||
if (lstat(arg, &st) < 0)
|
||||
die("'%s': %s", arg, strerror(errno));
|
||||
die_badfile(arg);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg,"-n")) {
|
||||
|
@ -343,7 +351,7 @@ int main(int argc, char **argv)
|
|||
if (verify)
|
||||
die("Needed a single revision");
|
||||
if (lstat(arg, &st) < 0)
|
||||
die("'%s': %s", arg, strerror(errno));
|
||||
die_badfile(arg);
|
||||
}
|
||||
show_default();
|
||||
if (verify && revs_count != 1)
|
||||
|
|
|
@ -789,7 +789,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
|||
}
|
||||
if (revs->combine_merges) {
|
||||
revs->ignore_merges = 0;
|
||||
if (revs->dense_combined_merges)
|
||||
if (revs->dense_combined_merges &&
|
||||
(revs->diffopt.output_format != DIFF_FORMAT_DIFFSTAT))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
}
|
||||
revs->diffopt.abbrev = revs->abbrev;
|
||||
|
|
|
@ -174,6 +174,27 @@ test_expect_success \
|
|||
'git-ls-tree -r output for a known tree.' \
|
||||
'diff current expected'
|
||||
|
||||
# But with -r -t we can have both.
|
||||
test_expect_success \
|
||||
'showing tree with git-ls-tree -r -t' \
|
||||
'git-ls-tree -r -t $tree >current'
|
||||
cat >expected <<\EOF
|
||||
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
|
||||
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
|
||||
040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
|
||||
100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
|
||||
120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
|
||||
040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
|
||||
100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
|
||||
120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
|
||||
040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3
|
||||
100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
|
||||
120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
|
||||
EOF
|
||||
test_expect_success \
|
||||
'git-ls-tree -r output for a known tree.' \
|
||||
'diff current expected'
|
||||
|
||||
################################################################
|
||||
rm .git/index
|
||||
test_expect_success \
|
||||
|
|
|
@ -37,7 +37,7 @@ compare_change () {
|
|||
}
|
||||
|
||||
check_cache_at () {
|
||||
clean_if_empty=`git-diff-files "$1"`
|
||||
clean_if_empty=`git-diff-files -- "$1"`
|
||||
case "$clean_if_empty" in
|
||||
'') echo "$1: clean" ;;
|
||||
?*) echo "$1: dirty" ;;
|
||||
|
|
|
@ -20,7 +20,7 @@ compare_change () {
|
|||
}
|
||||
|
||||
check_cache_at () {
|
||||
clean_if_empty=`git-diff-files "$1"`
|
||||
clean_if_empty=`git-diff-files -- "$1"`
|
||||
case "$clean_if_empty" in
|
||||
'') echo "$1: clean" ;;
|
||||
?*) echo "$1: dirty" ;;
|
||||
|
|
|
@ -28,7 +28,7 @@ cat >expected <<\EOF
|
|||
EOF
|
||||
test_expect_success \
|
||||
'limit to path should show nothing' \
|
||||
'git-diff-index --cached $tree path >current &&
|
||||
'git-diff-index --cached $tree -- path >current &&
|
||||
compare_diff_raw current expected'
|
||||
|
||||
cat >expected <<\EOF
|
||||
|
@ -36,7 +36,7 @@ cat >expected <<\EOF
|
|||
EOF
|
||||
test_expect_success \
|
||||
'limit to path1 should show path1/file1' \
|
||||
'git-diff-index --cached $tree path1 >current &&
|
||||
'git-diff-index --cached $tree -- path1 >current &&
|
||||
compare_diff_raw current expected'
|
||||
|
||||
cat >expected <<\EOF
|
||||
|
@ -44,7 +44,7 @@ cat >expected <<\EOF
|
|||
EOF
|
||||
test_expect_success \
|
||||
'limit to path1/ should show path1/file1' \
|
||||
'git-diff-index --cached $tree path1/ >current &&
|
||||
'git-diff-index --cached $tree -- path1/ >current &&
|
||||
compare_diff_raw current expected'
|
||||
|
||||
cat >expected <<\EOF
|
||||
|
@ -52,14 +52,14 @@ cat >expected <<\EOF
|
|||
EOF
|
||||
test_expect_success \
|
||||
'limit to file0 should show file0' \
|
||||
'git-diff-index --cached $tree file0 >current &&
|
||||
'git-diff-index --cached $tree -- file0 >current &&
|
||||
compare_diff_raw current expected'
|
||||
|
||||
cat >expected <<\EOF
|
||||
EOF
|
||||
test_expect_success \
|
||||
'limit to file0/ should emit nothing.' \
|
||||
'git-diff-index --cached $tree file0/ >current &&
|
||||
'git-diff-index --cached $tree -- file0/ >current &&
|
||||
compare_diff_raw current expected'
|
||||
|
||||
test_done
|
||||
|
|
150
update-index.c
150
update-index.c
|
@ -7,6 +7,7 @@
|
|||
#include "strbuf.h"
|
||||
#include "quote.h"
|
||||
#include "cache-tree.h"
|
||||
#include "tree-walk.h"
|
||||
|
||||
/*
|
||||
* Default to not allowing changes to the list of files. The
|
||||
|
@ -337,7 +338,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int chmod_path(int flip, const char *path)
|
||||
static void chmod_path(int flip, const char *path)
|
||||
{
|
||||
int pos;
|
||||
struct cache_entry *ce;
|
||||
|
@ -345,22 +346,25 @@ static int chmod_path(int flip, const char *path)
|
|||
|
||||
pos = cache_name_pos(path, strlen(path));
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
goto fail;
|
||||
ce = active_cache[pos];
|
||||
mode = ntohl(ce->ce_mode);
|
||||
if (!S_ISREG(mode))
|
||||
return -1;
|
||||
goto fail;
|
||||
switch (flip) {
|
||||
case '+':
|
||||
ce->ce_mode |= htonl(0111); break;
|
||||
case '-':
|
||||
ce->ce_mode &= htonl(~0111); break;
|
||||
default:
|
||||
return -1;
|
||||
goto fail;
|
||||
}
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
active_cache_changed = 1;
|
||||
return 0;
|
||||
report("chmod %cx '%s'", flip, path);
|
||||
return;
|
||||
fail:
|
||||
die("git-update-index: cannot chmod %cx '%s'", flip, path);
|
||||
}
|
||||
|
||||
static struct cache_file cache_file;
|
||||
|
@ -483,6 +487,124 @@ static void read_index_info(int line_termination)
|
|||
static const char update_index_usage[] =
|
||||
"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--cacheinfo] [--chmod=(+|-)x] [--info-only] [--force-remove] [--stdin] [--index-info] [--ignore-missing] [-z] [--verbose] [--] <file>...";
|
||||
|
||||
static unsigned char head_sha1[20];
|
||||
static unsigned char merge_head_sha1[20];
|
||||
|
||||
static struct cache_entry *read_one_ent(const char *which,
|
||||
unsigned char *ent, const char *path,
|
||||
int namelen, int stage)
|
||||
{
|
||||
unsigned mode;
|
||||
unsigned char sha1[20];
|
||||
int size;
|
||||
struct cache_entry *ce;
|
||||
|
||||
if (get_tree_entry(ent, path, sha1, &mode)) {
|
||||
error("%s: not in %s branch.", path, which);
|
||||
return NULL;
|
||||
}
|
||||
if (mode == S_IFDIR) {
|
||||
error("%s: not a blob in %s branch.", path, which);
|
||||
return NULL;
|
||||
}
|
||||
size = cache_entry_size(namelen);
|
||||
ce = xcalloc(1, size);
|
||||
|
||||
memcpy(ce->sha1, sha1, 20);
|
||||
memcpy(ce->name, path, namelen);
|
||||
ce->ce_flags = create_ce_flags(namelen, stage);
|
||||
ce->ce_mode = create_ce_mode(mode);
|
||||
return ce;
|
||||
}
|
||||
|
||||
static int unresolve_one(const char *path)
|
||||
{
|
||||
int namelen = strlen(path);
|
||||
int pos;
|
||||
int ret = 0;
|
||||
struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
|
||||
|
||||
/* See if there is such entry in the index. */
|
||||
pos = cache_name_pos(path, namelen);
|
||||
if (pos < 0) {
|
||||
/* If there isn't, either it is unmerged, or
|
||||
* resolved as "removed" by mistake. We do not
|
||||
* want to do anything in the former case.
|
||||
*/
|
||||
pos = -pos-1;
|
||||
if (pos < active_nr) {
|
||||
struct cache_entry *ce = active_cache[pos];
|
||||
if (ce_namelen(ce) == namelen &&
|
||||
!memcmp(ce->name, path, namelen)) {
|
||||
fprintf(stderr,
|
||||
"%s: skipping still unmerged path.\n",
|
||||
path);
|
||||
goto free_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Grab blobs from given path from HEAD and MERGE_HEAD,
|
||||
* stuff HEAD version in stage #2,
|
||||
* stuff MERGE_HEAD version in stage #3.
|
||||
*/
|
||||
ce_2 = read_one_ent("our", head_sha1, path, namelen, 2);
|
||||
ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3);
|
||||
|
||||
if (!ce_2 || !ce_3) {
|
||||
ret = -1;
|
||||
goto free_return;
|
||||
}
|
||||
if (!memcmp(ce_2->sha1, ce_3->sha1, 20) &&
|
||||
ce_2->ce_mode == ce_3->ce_mode) {
|
||||
fprintf(stderr, "%s: identical in both, skipping.\n",
|
||||
path);
|
||||
goto free_return;
|
||||
}
|
||||
|
||||
remove_file_from_cache(path);
|
||||
if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
|
||||
error("%s: cannot add our version to the index.", path);
|
||||
ret = -1;
|
||||
goto free_return;
|
||||
}
|
||||
if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
|
||||
return 0;
|
||||
error("%s: cannot add their version to the index.", path);
|
||||
ret = -1;
|
||||
free_return:
|
||||
free(ce_2);
|
||||
free(ce_3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void read_head_pointers(void)
|
||||
{
|
||||
if (read_ref(git_path("HEAD"), head_sha1))
|
||||
die("No HEAD -- no initial commit yet?\n");
|
||||
if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
|
||||
fprintf(stderr, "Not in the middle of a merge.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_unresolve(int ac, const char **av)
|
||||
{
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
/* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
|
||||
* are not doing a merge, so exit with success status.
|
||||
*/
|
||||
read_head_pointers();
|
||||
|
||||
for (i = 1; i < ac; i++) {
|
||||
const char *arg = av[i];
|
||||
err |= unresolve_one(arg);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int i, newfd, entries, has_errors = 0, line_termination = '\n';
|
||||
|
@ -490,6 +612,7 @@ int main(int argc, const char **argv)
|
|||
int read_from_stdin = 0;
|
||||
const char *prefix = setup_git_directory();
|
||||
int prefix_length = prefix ? strlen(prefix) : 0;
|
||||
char set_executable_bit = 0;
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
|
@ -556,8 +679,7 @@ int main(int argc, const char **argv)
|
|||
!strcmp(path, "--chmod=+x")) {
|
||||
if (argc <= i+1)
|
||||
die("git-update-index: %s <path>", path);
|
||||
if (chmod_path(path[8], argv[++i]))
|
||||
die("git-update-index: %s cannot chmod %s", path, argv[i]);
|
||||
set_executable_bit = path[8];
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(path, "--assume-unchanged")) {
|
||||
|
@ -593,6 +715,12 @@ int main(int argc, const char **argv)
|
|||
read_index_info(line_termination);
|
||||
break;
|
||||
}
|
||||
if (!strcmp(path, "--unresolve")) {
|
||||
has_errors = do_unresolve(argc - i, argv + i);
|
||||
if (has_errors)
|
||||
active_cache_changed = 0;
|
||||
goto finish;
|
||||
}
|
||||
if (!strcmp(path, "--ignore-missing")) {
|
||||
not_new = 1;
|
||||
continue;
|
||||
|
@ -606,6 +734,8 @@ int main(int argc, const char **argv)
|
|||
die("unknown option %s", path);
|
||||
}
|
||||
update_one(path, prefix, prefix_length);
|
||||
if (set_executable_bit)
|
||||
chmod_path(set_executable_bit, path);
|
||||
}
|
||||
if (read_from_stdin) {
|
||||
struct strbuf buf;
|
||||
|
@ -620,10 +750,16 @@ int main(int argc, const char **argv)
|
|||
else
|
||||
path_name = buf.buf;
|
||||
update_one(path_name, prefix, prefix_length);
|
||||
if (set_executable_bit) {
|
||||
const char *p = prefix_path(prefix, prefix_length, path_name);
|
||||
chmod_path(set_executable_bit, p);
|
||||
}
|
||||
if (path_name != buf.buf)
|
||||
free(path_name);
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_index_file(&cache_file))
|
||||
|
|
Loading…
Reference in a new issue