* Re: Summary of core GIT while you are away.
From: Junio C Hamano @ 2005-05-27 3:36 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Kay Sievers, Linus Torvalds, pasky, braddr, nico, david,
Git Mailing List
In-Reply-To: <42967CFE.7030007@zytor.com>
>>>>> "HPA" == H Peter Anvin <hpa@zytor.com> writes:
HPA> Junio C Hamano wrote:
KS> The cgi doesn't need it. Cogito has the spec file and the
KS> Mekefile with support for it - that was the reason the RPM
KS> made it on the machines there.
>> Ah, just installation convenience. I see.
HPA> Not "just" an installation convenience. Right now cogito and git-core
HPA> *conflict*. That's why cogito really needs to be broken out from
HPA> git-core, so git-core can be updated independently.
What I learned from this thread are these:
(1) CGI does not need Cogito but just needs core GIT.
(2) Nobody said he uses Cogito on kernel.org machines.
(3) But Cogito is installed nevertheless.
(4) Installation of Cogito is done via RPM "with Makefiles and
spec files" and both Cogito and core GIT comes bundled in.
(5) I gather that there is no core GIT only RPM (nobody said
this explicitly in this thread, though, so I may be
mistaken about this point).
And that was where my comment about "just an installation
convenience" came from.
If somebody said Cogito _is_ used on kernel.org machines, then I
would not have said "just" nor "convenience". That would mean
there is a real need to have Cogito and having just core GIT
would not be enough.
^ permalink raw reply
* resolving merge conflicts?
From: Jeff Garzik @ 2005-05-27 3:48 UTC (permalink / raw)
To: Git Mailing List
So is there a doc or something that describes how to resolve merge
conflicts?
Presumably I look at .merge_file_*, and make sure that all necessary
changes make it into the copy of the file in the working directory...
then what? How to continue the merge?
Jeff
> [...]
> Adding drivers/net/bnx2.c with perm -x.
> Adding drivers/net/bnx2.h with perm -x.
> Adding drivers/net/bnx2_fw.h with perm -x.
> Auto-merging drivers/net/ixgb/ixgb_main.c.
> merge: warning: conflicts during merge
> ERROR: Leaving conflict merge in .merge_file_fidvEd.
> fatal: merge program failed
> drivers/net/ixgb/ixgb_main.c: unmerged (7d26623d859278bd1ad6369648de9ed41a112493)
> drivers/net/ixgb/ixgb_main.c: unmerged (a6af9d9e340865278cfe4b607efed9e56c087538)
> drivers/net/ixgb/ixgb_main.c: unmerged (35f6a7c271a2be3a1f749716cbe27b1bffc66b98)
> drivers/net/skfp/lnkstat.c: unmerged (00a248044f8683d104d55918fe5d003a3261fa41)
> drivers/net/skfp/lnkstat.c: unmerged (00a248044f8683d104d55918fe5d003a3261fa41)
> drivers/net/smc-mca.h: unmerged (ac50117a7e847dcdd12591267e04f67fb05fbbd4)
> drivers/net/smc-mca.h: unmerged (ac50117a7e847dcdd12591267e04f67fb05fbbd4)
> drivers/s390/net/ctcmain.h: unmerged (ba3605f16335dba918a656bb1b94589fb8008490)
> drivers/s390/net/qeth_tso.c: unmerged (c91976274e7b007b78269e40fd8b354a4e888b86)
> drivers/s390/net/qeth_tso.c: unmerged (c91976274e7b007b78269e40fd8b354a4e888b86)
> ...
> fatal: git-write-tree: not able to write tree
^ permalink raw reply
* Re: resolving merge conflicts?
From: Junio C Hamano @ 2005-05-27 3:55 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Git Mailing List
In-Reply-To: <429698A0.1020008@pobox.com>
>>>>> "JG" == Jeff Garzik <jgarzik@pobox.com> writes:
JG> So is there a doc or something that describes how to resolve merge
JG> conflicts?
JG> Presumably I look at .merge_file_*, and make sure that all necessary
JG> changes make it into the copy of the file in the working
JG> directory... then what? How to continue the merge?
Then you would copy that .merge_* into the target file, and say
git-update-cache $that_path
If your merge decision says to remove that file, then making
sure you do not have that file, you say
git-update-cache --remove $that_path
^ permalink raw reply
* Re: Summary of core GIT while you are away.
From: H. Peter Anvin @ 2005-05-27 4:01 UTC (permalink / raw)
To: Junio C Hamano
Cc: Kay Sievers, Linus Torvalds, pasky, braddr, nico, david,
Git Mailing List
In-Reply-To: <7vk6ll2vde.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
>
> HPA> Not "just" an installation convenience. Right now cogito and git-core
> HPA> *conflict*. That's why cogito really needs to be broken out from
> HPA> git-core, so git-core can be updated independently.
>
> What I learned from this thread are these:
>
> (1) CGI does not need Cogito but just needs core GIT.
> (2) Nobody said he uses Cogito on kernel.org machines.
> (3) But Cogito is installed nevertheless.
> (4) Installation of Cogito is done via RPM "with Makefiles and
> spec files" and both Cogito and core GIT comes bundled in.
> (5) I gather that there is no core GIT only RPM (nobody said
> this explicitly in this thread, though, so I may be
> mistaken about this point).
>
> And that was where my comment about "just an installation
> convenience" came from.
>
> If somebody said Cogito _is_ used on kernel.org machines, then I
> would not have said "just" nor "convenience". That would mean
> there is a real need to have Cogito and having just core GIT
> would not be enough.
I, for one, use Cogito on the kernel.org machines.
-hpa
^ permalink raw reply
* Re: Summary of core GIT while you are away.
From: Junio C Hamano @ 2005-05-27 4:12 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Kay Sievers, Linus Torvalds, pasky, braddr, nico, david,
Git Mailing List
In-Reply-To: <42969B98.7070701@zytor.com>
>>>>> "HPA" == H Peter Anvin <hpa@zytor.com> writes:
HPA> I, for one, use Cogito on the kernel.org machines.
I see. I see cogito.git catching up to the Linus core, so this
would not be much of a problem anymore.
^ permalink raw reply
* Re: Summary of core GIT while you are away.
From: H. Peter Anvin @ 2005-05-27 4:13 UTC (permalink / raw)
To: Junio C Hamano
Cc: Kay Sievers, Linus Torvalds, pasky, braddr, nico, david,
Git Mailing List
In-Reply-To: <7v4qcp2tp1.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
>>>>>>"HPA" == H Peter Anvin <hpa@zytor.com> writes:
>
>
> HPA> I, for one, use Cogito on the kernel.org machines.
>
> I see. I see cogito.git catching up to the Linus core, so this
> would not be much of a problem anymore.
>
It would still be a lot nicer to have them decoupled.
-hpa
^ permalink raw reply
* Re: Summary of core GIT while you are away.
From: Junio C Hamano @ 2005-05-27 4:31 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Kay Sievers, Linus Torvalds, pasky, braddr, nico, david,
Git Mailing List
In-Reply-To: <42969E6E.5080606@zytor.com>
>>>>> "HPA" == H Peter Anvin <hpa@zytor.com> writes:
HPA> Junio C Hamano wrote:
>>>>>>> "HPA" == H Peter Anvin <hpa@zytor.com> writes:
HPA> I, for one, use Cogito on the kernel.org machines.
>> I see. I see cogito.git catching up to the Linus core, so this
>> would not be much of a problem anymore.
HPA> It would still be a lot nicer to have them decoupled.
No question about it. Let's give Petr some time.
^ permalink raw reply
* Re: resolving merge conflicts?
From: Linus Torvalds @ 2005-05-27 5:15 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Git Mailing List
In-Reply-To: <429698A0.1020008@pobox.com>
On Thu, 26 May 2005, Jeff Garzik wrote:
>
> So is there a doc or something that describes how to resolve merge
> conflicts?
Dang. Not really. I've always done them just by hand.
> Presumably I look at .merge_file_*, and make sure that all necessary
> changes make it into the copy of the file in the working directory...
> then what? How to continue the merge?
Start from that, and when you're happy with it, just do "git-update-cache"
when the file is to your liking, and re-do
git-merge-cache git-merge-one-file-script -a
if you forget where you were and what other files you need to do by hand
(which I always do, not that I've seen a lot of merge problems).
Also, I assume that this is something cogito does better. But even the
git-merge-one-script could probably be nicer.
Quite frankly, a more friendly git-resolve-script would probably do
git-merge-cache -o git-merge-one-file-script -a
(the "-o" flag causes it to merge as much as it can automatically, instead
of exiting at the first one), and git-merge-one-file-script should
probably on failure do
echo "ERROR: Leaving conflict merge in $4."
mv "$src2" "$4"
exit 1
instead of leaving it in the temporary file. The temp-file is good for a
graphical thing (which was kind of what I was hoping for), though, so it
probably depends on how you continue with the merge.
(I also like the temp-file just because _if_ you have dirty data in your
tree, overwriting it with the failed merge is pretty damn impolite, but of
course, you shouldn't try to merge with dirty data, and you may prefer the
one that is _practically_ more friendly even if it's a bit unsafe. It's a
trade-off)
Linus
^ permalink raw reply
* Re: Summary of core GIT while you are away.
From: Linus Torvalds @ 2005-05-27 5:21 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Junio C Hamano, Kay Sievers, pasky, braddr, nico, david,
Git Mailing List
In-Reply-To: <42969E6E.5080606@zytor.com>
On Thu, 26 May 2005, H. Peter Anvin wrote:
>
> It would still be a lot nicer to have them decoupled.
Yes, but git has been changing so much that I think it has made sense to
have it together with cogito, so that you don't have version skew.
Have we gotten to the point where git is calming down? Judging by the raw
diff etc changes, I'd say no, but on the other hand, those are largely
over, and maybe we don't have any serious real incompatibilities pending
any mroe...
The object data structures have been pretty stable (thank the Gods!), but
command line switches and some data output formats certainly have not.
The one big change I see coming is that I really want to make
"git-rev-list HEAD TAIL" work right (ie do a real reachabilty thing rather
than the date-based thing), at which point you'd _usually_ not need to use
the full logic of git-rev-tree that can do multiple parents etc. But that
change should be compatible, I hope (ie old scripts will continue to use
git-rev-tree and play games with the output, because they'd not know any
better).
Linus
^ permalink raw reply
* Suggestion: superceded tags
From: H. Peter Anvin @ 2005-05-27 5:29 UTC (permalink / raw)
To: Git Mailing List
It's a pretty fundamental concept in git that objects in the object
repository live forever. This is key to distribution, and is a good thing.
However, for tag objects, this is somewhat awkward. It is occationally
necessary to move a tag (restarted release processes, being one reason);
purists tend to frown on it but it's reality.
It would be nice to maintain that all tag information exists in the
object database and loss of the .git/refs directory will not harm that.
Thus, I'd like to suggest the following protocol:
When a tag is moved, a new tag object is created. This tag object will
have a "supercedes" header which references the old tag object.
Say, for example, that tag "klibc-1.0.14", object
4695b4d163b62f6a9860b9bbe06ff30edb6e02be, exists with the following
contents:
object fdb8a185ef261568f01140989745b8636212db71
type commit
tag klibc-1.0.14
Now "klibc-1.0.14" needs to be moved to new commit
088c166af39b1ca2712667c44dccd3c7af99a8fb.
The new tag object should thus look like:
object 088c166af39b1ca2712667c44dccd3c7af99a8fb
type commit
supercedes 4695b4d163b62f6a9860b9bbe06ff30edb6e02be
tag klibc-1.0.14
(I put "supercedes" before "tag", because unfortunately the tag header
terminates immediately after the "tag" line without having an
intervening blank line.)
This will make it possible to move the tag, but still to recreate all
tag information from the object database alone.
None of this can of course help the conflict if the same tag is created
in different places by different people, and then they are trying to be
merged. The above at least makes it possible to distinguish the case of
a tag conflict with the case of a moved tag, and in the case of the
moved tag, will stand out.
On the other hand, it makes it possible for more than one tag to exist
with the same name pointing to the same object:
User 1 creates tag X referring to object A -> T1
User 1 moves tag X to object B -> T2
User 2 creates tag X referring to object B -> T3
There is no conflict here, but T2 and T3 will be different objects (one
will supercede T1, and the other won't.) An object-database-scanning
program should observe that T2 and T3 are consistent, and T1 is
superceded, therefore tag X is well-defined; it can arbitrarily use
either instance T2 or T3.
-hpa
^ permalink raw reply
* Git does not use GIT_* envirnment vars?
From: Dmitry Torokhov @ 2005-05-27 6:09 UTC (permalink / raw)
To: Git Mailing List
Hi,
I am totally confused... This is with today's cogito pull. It does not seem
to take GIT_ environment variables, although according to debugger it puts
correct data when writing object... Anybody else seeing this?
[dtor@anvil kernel]$ mkdir git-test
[dtor@anvil kernel]$ cd git-test/
[dtor@anvil git-test]$ git-init-db
defaulting to local storage area
[dtor@anvil git-test]$ git-write-tree
4b825dc642cb6eb9a060e54bf8d69288fbee4904
[dtor@anvil git-test]$ git-commit-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
Committing initial tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
test
413398e6c1b53a0993cb195209c4d0e6276bb076
[dtor@anvil git-test]$ git-cat-file commit 413398e6c1b53a0993cb195209c4d0e6276bb076
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
author Dmitry Torokhov <dtor@anvil.corenet.prv> 1117173530 -0500
committer Dmitry Torokhov <dtor@anvil.corenet.prv> 1117173530 -0500
test
[dtor@anvil git-test]$ export | grep GIT
declare -x GIT_AUTHOR_EMAIL="dtor_core@ameritech.net"
declare -x GIT_COMMITTER_EMAIL="dtor_core@ameritech.net"
declare -x GIT_COMMITTER_NAME="Dmitry Torokhov"
--
Dmitry
^ permalink raw reply
* [PATCH] Diff updates, fixing pathspec and rename/copy interaction.
From: Junio C Hamano @ 2005-05-27 6:41 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0505261731050.17207@ppc970.osdl.org>
During the mailing list discussion about diff-tree omitting to
call diffcore-pathspec, I realized that the current rename/copy
differentiator has a major flaw interacting with pathspec (or
any other filepair filters, including pickaxe).
The problem was that in order to tell if the rename-copy source
still remains in the resulting tree (that is what determines if
one of the rename-copy can become a rename or everybody needs to
be a copy), diffcore-rename was sending a filepair that records
unmodified source downstream, expecting that it reaches
resolve_rename_copy() which happens as the final stage before
actual output happens. Of course, pathspec and pickaxe can
interfere and happily remove that entry, in which case what
should be shown as a copy suddenly becomes a rename.
The problem was fixed by changing the way diffcore-rename
records whether the source file remains in the resulting tree.
This patch also introduces an optimization for diff-tree -M and
diff-tree -C to throw away implausible rename/copy source
candidate by keeping the filesize information of already seen
SHA1 object IDs in a cache. This cache is activated only when
diff-tree is reading from --stdin (i.e. processing sequence of
tree pairs) and when rename detection is used.
Pickaxe acquired another option, --pickaxe-all, to diff-* three
brothers. When a search string is touched, instead of showing
only the changed file that touches that searched string, it
shows the entire changeset. This is useful to see the change in
context.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff-cache.c | 13 ++
diff-files.c | 11 +-
diff-helper.c | 9 +-
diff-tree.c | 16 ++-
diff.c | 209 ++++++++++++++++++++++++++++++-----------------
diff.h | 18 ++--
diffcore-pathspec.c | 5 -
diffcore-pickaxe.c | 79 +++++++++++++----
diffcore-rename.c | 91 +++++++++-----------
diffcore.h | 14 +--
git-external-diff-script | 2
t/t4007-rename-3.sh | 103 +++++++++++++++++++++++
12 files changed, 392 insertions(+), 178 deletions(-)
new file (100755): t/t4007-rename-3.sh
diff --git a/diff-cache.c b/diff-cache.c
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -5,9 +5,10 @@ static int cached_only = 0;
static int diff_output_format = DIFF_FORMAT_HUMAN;
static int match_nonexisting = 0;
static int detect_rename = 0;
-static int reverse_diff = 0;
+static int diff_setup_opt = 0;
static int diff_score_opt = 0;
static const char *pickaxe = NULL;
+static int pickaxe_opts = 0;
/* A file entry went away or appeared */
static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
@@ -202,13 +203,17 @@ int main(int argc, const char **argv)
continue;
}
if (!strcmp(arg, "-R")) {
- reverse_diff = 1;
+ diff_setup_opt |= DIFF_SETUP_REVERSE;
continue;
}
if (!strcmp(arg, "-S")) {
pickaxe = arg + 2;
continue;
}
+ if (!strcmp(arg, "--pickaxe-all")) {
+ pickaxe_opts = DIFF_PICKAXE_ALL;
+ continue;
+ }
if (!strcmp(arg, "-m")) {
match_nonexisting = 1;
continue;
@@ -224,7 +229,7 @@ int main(int argc, const char **argv)
usage(diff_cache_usage);
/* The rest is for paths restriction. */
- diff_setup(reverse_diff);
+ diff_setup(diff_setup_opt);
mark_merge_entries();
@@ -238,7 +243,7 @@ int main(int argc, const char **argv)
if (detect_rename)
diffcore_rename(detect_rename, diff_score_opt);
if (pickaxe)
- diffcore_pickaxe(pickaxe);
+ diffcore_pickaxe(pickaxe, pickaxe_opts);
if (pathspec)
diffcore_pathspec(pathspec);
diff_flush(diff_output_format, 1);
diff --git a/diff-files.c b/diff-files.c
--- a/diff-files.c
+++ b/diff-files.c
@@ -11,9 +11,10 @@ static const char *diff_files_usage =
static int diff_output_format = DIFF_FORMAT_HUMAN;
static int detect_rename = 0;
-static int reverse_diff = 0;
+static int diff_setup_opt = 0;
static int diff_score_opt = 0;
static const char *pickaxe = NULL;
+static int pickaxe_opts = 0;
static int silent = 0;
static void show_unmerge(const char *path)
@@ -51,9 +52,11 @@ int main(int argc, const char **argv)
else if (!strcmp(argv[1], "-z"))
diff_output_format = DIFF_FORMAT_MACHINE;
else if (!strcmp(argv[1], "-R"))
- reverse_diff = 1;
+ diff_setup_opt |= DIFF_SETUP_REVERSE;
else if (!strcmp(argv[1], "-S"))
pickaxe = argv[1] + 2;
+ else if (!strcmp(argv[1], "--pickaxe-all"))
+ pickaxe_opts = DIFF_PICKAXE_ALL;
else if (!strncmp(argv[1], "-M", 2)) {
diff_score_opt = diff_scoreopt_parse(argv[1]);
detect_rename = DIFF_DETECT_RENAME;
@@ -75,7 +78,7 @@ int main(int argc, const char **argv)
exit(1);
}
- diff_setup(reverse_diff);
+ diff_setup(diff_setup_opt);
for (i = 0; i < entries; i++) {
struct stat st;
@@ -116,7 +119,7 @@ int main(int argc, const char **argv)
if (detect_rename)
diffcore_rename(detect_rename, diff_score_opt);
if (pickaxe)
- diffcore_pickaxe(pickaxe);
+ diffcore_pickaxe(pickaxe, pickaxe_opts);
if (1 < argc)
diffcore_pathspec(argv + 1);
diff_flush(diff_output_format, 1);
diff --git a/diff-helper.c b/diff-helper.c
--- a/diff-helper.c
+++ b/diff-helper.c
@@ -4,9 +4,9 @@
#include "cache.h"
#include "strbuf.h"
#include "diff.h"
-#include "diffcore.h" /* just for MAX_SCORE */
static const char *pickaxe = NULL;
+static int pickaxe_opts = 0;
static int line_termination = '\n';
static int inter_name_termination = '\t';
@@ -24,6 +24,8 @@ int main(int ac, const char **av) {
else if (av[1][1] == 'S') {
pickaxe = av[1] + 2;
}
+ else if (!strcmp(av[1], "--pickaxe-all"))
+ pickaxe_opts = DIFF_PICKAXE_ALL;
else
usage(diff_helper_usage);
ac--; av++;
@@ -78,7 +80,6 @@ int main(int ac, const char **av) {
if (status == 'R' || status == 'C') {
two_paths = 1;
sscanf(cp, "%d", &score);
- score = score * MAX_SCORE / 100;
if (line_termination) {
cp = strchr(cp,
inter_name_termination);
@@ -129,14 +130,14 @@ int main(int ac, const char **av) {
continue;
}
if (pickaxe)
- diffcore_pickaxe(pickaxe);
+ diffcore_pickaxe(pickaxe, pickaxe_opts);
if (1 < ac)
diffcore_pathspec(av + 1);
diff_flush(DIFF_FORMAT_PATCH, 0);
printf("%s\n", sb.buf);
}
if (pickaxe)
- diffcore_pickaxe(pickaxe);
+ diffcore_pickaxe(pickaxe, pickaxe_opts);
if (1 < ac)
diffcore_pathspec(av + 1);
diff_flush(DIFF_FORMAT_PATCH, 0);
diff --git a/diff-tree.c b/diff-tree.c
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -10,9 +10,10 @@ static int show_tree_entry_in_recursive
static int read_stdin = 0;
static int diff_output_format = DIFF_FORMAT_HUMAN;
static int detect_rename = 0;
-static int reverse_diff = 0;
+static int diff_setup_opt = 0;
static int diff_score_opt = 0;
static const char *pickaxe = NULL;
+static int pickaxe_opts = 0;
static const char *header = NULL;
static const char *header_prefix = "";
@@ -255,7 +256,7 @@ static int diff_tree_sha1(const unsigned
static void call_diff_setup(void)
{
- diff_setup(reverse_diff);
+ diff_setup(diff_setup_opt);
}
static int call_diff_flush(void)
@@ -263,7 +264,7 @@ static int call_diff_flush(void)
if (detect_rename)
diffcore_rename(detect_rename, diff_score_opt);
if (pickaxe)
- diffcore_pickaxe(pickaxe);
+ diffcore_pickaxe(pickaxe, pickaxe_opts);
if (diff_queue_is_empty()) {
diff_flush(DIFF_FORMAT_NO_OUTPUT, 0);
return 0;
@@ -504,7 +505,7 @@ int main(int argc, const char **argv)
continue;
}
if (!strcmp(arg, "-R")) {
- reverse_diff = 1;
+ diff_setup_opt |= DIFF_SETUP_REVERSE;
continue;
}
if (!strcmp(arg, "-p")) {
@@ -516,6 +517,10 @@ int main(int argc, const char **argv)
pickaxe = arg + 2;
continue;
}
+ if (!strcmp(arg, "--pickaxe-all")) {
+ pickaxe_opts = DIFF_PICKAXE_ALL;
+ continue;
+ }
if (!strncmp(arg, "-M", 2)) {
detect_rename = DIFF_DETECT_RENAME;
diff_score_opt = diff_scoreopt_parse(arg);
@@ -580,6 +585,9 @@ int main(int argc, const char **argv)
if (!read_stdin)
return 0;
+ if (detect_rename)
+ diff_setup_opt |= (DIFF_SETUP_USE_SIZE_CACHE |
+ DIFF_SETUP_USE_CACHE);
while (fgets(line, sizeof(line), stdin))
diff_tree_stdin(line);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -12,6 +12,7 @@ static const char *diff_opts = "-pu";
static unsigned char null_sha1[20] = { 0, };
static int reverse_diff;
+static int use_size_cache;
static const char *external_diff(void)
{
@@ -141,7 +142,7 @@ static void builtin_diff(const char *nam
printf("new mode %s\n", temp[1].mode);
}
if (xfrm_msg && xfrm_msg[0])
- fputs(xfrm_msg, stdout);
+ puts(xfrm_msg);
if (strncmp(temp[0].mode, temp[1].mode, 3))
/* we do not run diff between different kind
@@ -222,12 +223,60 @@ static int work_tree_matches(const char
return 1;
}
+static struct sha1_size_cache {
+ unsigned char sha1[20];
+ unsigned long size;
+} **sha1_size_cache;
+static int sha1_size_cache_nr, sha1_size_cache_alloc;
+
+static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
+ unsigned long size)
+{
+ int first, last;
+ struct sha1_size_cache *e;
+
+ first = 0;
+ last = sha1_size_cache_nr;
+ while (last > first) {
+ int next = (last + first) >> 1;
+ e = sha1_size_cache[next];
+ int cmp = memcmp(e->sha1, sha1, 20);
+ if (!cmp)
+ return e;
+ if (cmp < 0) {
+ last = next;
+ continue;
+ }
+ first = next+1;
+ }
+ /* not found */
+ if (size == UINT_MAX)
+ return NULL;
+ /* insert to make it at "first" */
+ if (sha1_size_cache_alloc <= sha1_size_cache_nr) {
+ sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc);
+ sha1_size_cache = xrealloc(sha1_size_cache,
+ sha1_size_cache_alloc *
+ sizeof(*sha1_size_cache));
+ }
+ sha1_size_cache_nr++;
+ if (first < sha1_size_cache_nr)
+ memmove(sha1_size_cache + first + 1, sha1_size_cache + first,
+ (sha1_size_cache_nr - first - 1) *
+ sizeof(*sha1_size_cache));
+ e = xmalloc(sizeof(struct sha1_size_cache));
+ sha1_size_cache[first] = e;
+ memcpy(e->sha1, sha1, 20);
+ e->size = size;
+ return e;
+}
+
/*
* While doing rename detection and pickaxe operation, we may need to
* grab the data for the blob (or file) for our own in-core comparison.
* diff_filespec has data and size fields for this purpose.
*/
-int diff_populate_filespec(struct diff_filespec *s)
+int diff_populate_filespec(struct diff_filespec *s, int size_only)
{
int err = 0;
if (!DIFF_FILE_VALID(s))
@@ -235,6 +284,9 @@ int diff_populate_filespec(struct diff_f
if (S_ISDIR(s->mode))
return -1;
+ if (!use_size_cache)
+ size_only = 0;
+
if (s->data)
return err;
if (!s->sha1_valid ||
@@ -254,6 +306,8 @@ int diff_populate_filespec(struct diff_f
s->size = st.st_size;
if (!s->size)
goto empty;
+ if (size_only)
+ return 0;
if (S_ISLNK(st.st_mode)) {
int ret;
s->data = xmalloc(s->size);
@@ -273,9 +327,21 @@ int diff_populate_filespec(struct diff_f
close(fd);
}
else {
+ /* We cannot do size only for SHA1 blobs */
char type[20];
+ struct sha1_size_cache *e;
+
+ if (size_only) {
+ e = locate_size_cache(s->sha1, UINT_MAX);
+ if (e) {
+ s->size = e->size;
+ return 0;
+ }
+ }
s->data = read_sha1_file(s->sha1, type, &s->size);
s->should_free = 1;
+ if (s->data && size_only)
+ locate_size_cache(s->sha1, s->size);
}
return 0;
}
@@ -361,7 +427,7 @@ static void prepare_temp_file(const char
return;
}
else {
- if (diff_populate_filespec(one))
+ if (diff_populate_filespec(one, 0))
die("cannot read data blob for %s", one->path);
prep_temp_blob(temp, one->data, one->size,
one->sha1, one->mode);
@@ -492,9 +558,23 @@ static void run_diff(const char *name,
run_external_diff(pgm, name, other, one, two, xfrm_msg);
}
-void diff_setup(int reverse_diff_)
+void diff_setup(int flags)
{
- reverse_diff = reverse_diff_;
+ if (flags & DIFF_SETUP_REVERSE)
+ reverse_diff = 1;
+ if (flags & DIFF_SETUP_USE_CACHE) {
+ if (!active_cache)
+ /* read-cache does not die even when it fails
+ * so it is safe for us to do this here. Also
+ * it does not smudge active_cache or active_nr
+ * when it fails, so we do not have to worry about
+ * cleaning it up oufselves either.
+ */
+ read_cache();
+ }
+ if (flags & DIFF_SETUP_USE_SIZE_CACHE)
+ use_size_cache = 1;
+
}
struct diff_queue_struct diff_queued_diff;
@@ -517,10 +597,18 @@ struct diff_filepair *diff_queue(struct
dp->one = one;
dp->two = two;
dp->score = 0;
+ dp->source_stays = 0;
diff_q(queue, dp);
return dp;
}
+void diff_free_filepair(struct diff_filepair *p)
+{
+ diff_free_filespec_data(p->one);
+ diff_free_filespec_data(p->two);
+ free(p);
+}
+
static void diff_flush_raw(struct diff_filepair *p,
int line_termination,
int inter_name_termination)
@@ -615,7 +703,7 @@ static void diff_flush_patch(struct diff
sprintf(msg_,
"similarity index %d%%\n"
"copy from %s\n"
- "copy to %s\n",
+ "copy to %s",
(int)(0.5 + p->score * 100.0/MAX_SCORE),
p->one->path, p->two->path);
msg = msg_;
@@ -624,7 +712,7 @@ static void diff_flush_patch(struct diff
sprintf(msg_,
"similarity index %d%%\n"
"rename old %s\n"
- "rename new %s\n",
+ "rename new %s",
(int)(0.5 + p->score * 100.0/MAX_SCORE),
p->one->path, p->two->path);
msg = msg_;
@@ -639,28 +727,6 @@ static void diff_flush_patch(struct diff
run_diff(name, other, p->one, p->two, msg);
}
-int diff_needs_to_stay(struct diff_queue_struct *q, int i,
- struct diff_filespec *it)
-{
- /* If it will be used in later entry (either stay or used
- * as the source of rename/copy), we need to copy, not rename.
- */
- while (i < q->nr) {
- struct diff_filepair *p = q->queue[i++];
- if (!DIFF_FILE_VALID(p->two))
- continue; /* removed is fine */
- if (strcmp(p->one->path, it->path))
- continue; /* not relevant */
-
- /* p has its src set to *it and it is not a delete;
- * it will be used for in-place change, rename/copy,
- * or just stays there. We cannot rename it out.
- */
- return 1;
- }
- return 0;
-}
-
int diff_queue_is_empty(void)
{
struct diff_queue_struct *q = &diff_queued_diff;
@@ -689,8 +755,8 @@ void diff_debug_filepair(const struct di
{
diff_debug_filespec(p->one, i, "one");
diff_debug_filespec(p->two, i, "two");
- fprintf(stderr, "score %d, status %c\n",
- p->score, p->status ? : '?');
+ fprintf(stderr, "score %d, status %c source_stays %d\n",
+ p->score, p->status ? : '?', p->source_stays);
}
void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
@@ -712,8 +778,6 @@ static void diff_resolve_rename_copy(voi
struct diff_filepair *p, *pp;
struct diff_queue_struct *q = &diff_queued_diff;
- /* This should not depend on the ordering of things. */
-
diff_debug_queue("resolve-rename-copy", q);
for (i = 0; i < q->nr; i++) {
@@ -721,23 +785,28 @@ static void diff_resolve_rename_copy(voi
p->status = 0; /* undecided */
if (DIFF_PAIR_UNMERGED(p))
p->status = 'U';
- else if (!DIFF_FILE_VALID((p)->one))
+ else if (!DIFF_FILE_VALID(p->one))
p->status = 'N';
- else if (!DIFF_FILE_VALID((p)->two)) {
- /* Deletion record should be omitted if there
- * are rename/copy entries using this one as
- * the source. Then we can say one of them
- * is a rename and the rest are copies.
+ else if (!DIFF_FILE_VALID(p->two)) {
+ /* Deleted entry may have been picked up by
+ * another rename-copy entry. So we scan the
+ * queue and if we find one that uses us as the
+ * source we do not say delete for this entry.
*/
- p->status = 'D';
for (j = 0; j < q->nr; j++) {
pp = q->queue[j];
- if (!strcmp(pp->one->path, p->one->path) &&
- strcmp(pp->one->path, pp->two->path)) {
+ if (!strcmp(p->one->path, pp->one->path) &&
+ pp->score) {
+ /* rename/copy are always valid
+ * so we do not say DIFF_FILE_VALID()
+ * on pp->one and pp->two.
+ */
p->status = 'X';
break;
}
}
+ if (!p->status)
+ p->status = 'D';
}
else if (DIFF_PAIR_TYPE_CHANGED(p))
p->status = 'T';
@@ -746,33 +815,24 @@ static void diff_resolve_rename_copy(voi
* whose both sides are valid and of the same type, i.e.
* either in-place edit or rename/copy edit.
*/
- else if (strcmp(p->one->path, p->two->path)) {
- /* See if there is somebody else anywhere that
- * will keep the path (either modified or
- * unmodified). If so, we have to be a copy,
- * not a rename. In addition, if there is
- * some other rename or copy that comes later
- * than us that uses the same source, we
- * have to be a copy, not a rename.
+ else if (p->score) {
+ if (p->source_stays) {
+ p->status = 'C';
+ continue;
+ }
+ /* See if there is some other filepair that
+ * copies from the same source as us. If so
+ * we are a copy. Otherwise we are a rename.
*/
- for (j = 0; j < q->nr; j++) {
+ for (j = i + 1; j < q->nr; j++) {
pp = q->queue[j];
if (strcmp(pp->one->path, p->one->path))
- continue;
- if (!strcmp(pp->one->path, pp->two->path)) {
- if (DIFF_FILE_VALID(pp->two)) {
- /* non-delete */
- p->status = 'C';
- break;
- }
- continue;
- }
- /* pp is a rename/copy ... */
- if (i < j) {
- /* ... and comes later than us */
- p->status = 'C';
- break;
- }
+ continue; /* not us */
+ if (!pp->score)
+ continue; /* not a rename/copy */
+ /* pp is a rename/copy from the same source */
+ p->status = 'C';
+ break;
}
if (!p->status)
p->status = 'R';
@@ -781,8 +841,11 @@ static void diff_resolve_rename_copy(voi
p->one->mode != p->two->mode)
p->status = 'M';
else
- /* this is a "no-change" entry */
- p->status = 'X';
+ /* this is a "no-change" entry.
+ * should not happen anymore.
+ * p->status = 'X';
+ */
+ die("internal error in diffcore: unmodified entry remains");
}
diff_debug_queue("resolve-rename-copy done", q);
}
@@ -817,12 +880,8 @@ void diff_flush(int diff_output_style, i
break;
}
}
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- diff_free_filespec_data(p->one);
- diff_free_filespec_data(p->two);
- free(p);
- }
+ for (i = 0; i < q->nr; i++)
+ diff_free_filepair(q->queue[i]);
free(q->queue);
q->queue = NULL;
q->nr = q->alloc = 0;
@@ -883,7 +942,7 @@ void diff_helper_input(unsigned old_mode
if (new_mode)
fill_filespec(two, new_sha1, new_mode);
dp = diff_queue(&diff_queued_diff, one, two);
- dp->score = score;
+ dp->score = score * MAX_SCORE / 100;
dp->status = status;
}
diff --git a/diff.h b/diff.h
--- a/diff.h
+++ b/diff.h
@@ -28,22 +28,28 @@ extern void diff_unmerge(const char *pat
extern int diff_scoreopt_parse(const char *opt);
-#define DIFF_FORMAT_HUMAN 0
-#define DIFF_FORMAT_MACHINE 1
-#define DIFF_FORMAT_PATCH 2
-#define DIFF_FORMAT_NO_OUTPUT 3
-extern void diff_setup(int reverse);
+#define DIFF_SETUP_REVERSE 1
+#define DIFF_SETUP_USE_CACHE 2
+#define DIFF_SETUP_USE_SIZE_CACHE 4
+extern void diff_setup(int flags);
#define DIFF_DETECT_RENAME 1
#define DIFF_DETECT_COPY 2
extern void diffcore_rename(int rename_copy, int minimum_score);
-extern void diffcore_pickaxe(const char *needle);
+#define DIFF_PICKAXE_ALL 1
+extern void diffcore_pickaxe(const char *needle, int opts);
+
extern void diffcore_pathspec(const char **pathspec);
extern int diff_queue_is_empty(void);
+#define DIFF_FORMAT_HUMAN 0
+#define DIFF_FORMAT_MACHINE 1
+#define DIFF_FORMAT_PATCH 2
+#define DIFF_FORMAT_NO_OUTPUT 3
+
extern void diff_flush(int output_style, int resolve_rename_copy);
#endif /* DIFF_H */
diff --git a/diffcore-pathspec.c b/diffcore-pathspec.c
--- a/diffcore-pathspec.c
+++ b/diffcore-pathspec.c
@@ -55,11 +55,10 @@ void diffcore_pathspec(const char **path
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- if (matches_pathspec(p->one->path, spec, speccnt) ||
- matches_pathspec(p->two->path, spec, speccnt))
+ if (matches_pathspec(p->two->path, spec, speccnt))
diff_q(&outq, p);
else
- free(p);
+ diff_free_filepair(p);
}
free(q->queue);
*q = outq;
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -11,7 +11,7 @@ static int contains(struct diff_filespec
{
unsigned long offset, sz;
const char *data;
- if (diff_populate_filespec(one))
+ if (diff_populate_filespec(one, 0))
return 0;
sz = one->size;
data = one->data;
@@ -21,36 +21,73 @@ static int contains(struct diff_filespec
return 0;
}
-void diffcore_pickaxe(const char *needle)
+void diffcore_pickaxe(const char *needle, int opts)
{
struct diff_queue_struct *q = &diff_queued_diff;
unsigned long len = strlen(needle);
- int i;
+ int i, has_changes;
struct diff_queue_struct outq;
outq.queue = NULL;
outq.nr = outq.alloc = 0;
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- int onum = outq.nr;
- if (!DIFF_FILE_VALID(p->one)) {
- if (!DIFF_FILE_VALID(p->two))
- continue; /* ignore nonsense */
- /* created */
- if (contains(p->two, needle, len))
- diff_q(&outq, p);
+ if (opts & DIFF_PICKAXE_ALL) {
+ /* Showing the whole changeset if needle exists */
+ for (i = has_changes = 0; !has_changes && i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ if (!DIFF_FILE_VALID(p->one)) {
+ if (!DIFF_FILE_VALID(p->two))
+ continue; /* ignore unmerged */
+ /* created */
+ if (contains(p->two, needle, len))
+ has_changes++;
+ }
+ else if (!DIFF_FILE_VALID(p->two)) {
+ if (contains(p->one, needle, len))
+ has_changes++;
+ }
+ else if (!diff_unmodified_pair(p) &&
+ contains(p->one, needle, len) !=
+ contains(p->two, needle, len))
+ has_changes++;
}
- else if (!DIFF_FILE_VALID(p->two)) {
- if (contains(p->one, needle, len))
+ if (has_changes)
+ return; /* not munge the queue */
+
+ /* otherwise we will clear the whole queue
+ * by copying the empty outq at the end of this
+ * function, but first clear the current entries
+ * in the queue.
+ */
+ for (i = 0; i < q->nr; i++)
+ diff_free_filepair(q->queue[i]);
+ }
+ else
+ /* Showing only the filepairs that has the needle */
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ has_changes = 0;
+ if (!DIFF_FILE_VALID(p->one)) {
+ if (!DIFF_FILE_VALID(p->two))
+ ; /* ignore unmerged */
+ /* created */
+ else if (contains(p->two, needle, len))
+ has_changes = 1;
+ }
+ else if (!DIFF_FILE_VALID(p->two)) {
+ if (contains(p->one, needle, len))
+ has_changes = 1;
+ }
+ else if (!diff_unmodified_pair(p) &&
+ contains(p->one, needle, len) !=
+ contains(p->two, needle, len))
+ has_changes = 1;
+
+ if (has_changes)
diff_q(&outq, p);
+ else
+ diff_free_filepair(p);
}
- else if (!diff_unmodified_pair(p) &&
- contains(p->one, needle, len) !=
- contains(p->two, needle, len))
- diff_q(&outq, p);
- if (onum == outq.nr)
- free(p);
- }
+
free(q->queue);
*q = outq;
return;
diff --git a/diffcore-rename.c b/diffcore-rename.c
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -52,14 +52,15 @@ static struct diff_rename_dst *locate_re
return &(rename_dst[first]);
}
+/* Table of rename/copy src files */
static struct diff_rename_src {
struct diff_filespec *one;
- unsigned src_used : 1;
+ unsigned src_stays : 1;
} *rename_src;
static int rename_src_nr, rename_src_alloc;
-static struct diff_rename_src *locate_rename_src(struct diff_filespec *one,
- int insert_ok)
+static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
+ int src_stays)
{
int first, last;
@@ -77,9 +78,7 @@ static struct diff_rename_src *locate_re
}
first = next+1;
}
- /* not found */
- if (!insert_ok)
- return NULL;
+
/* insert to make it at "first" */
if (rename_src_alloc <= rename_src_nr) {
rename_src_alloc = alloc_nr(rename_src_alloc);
@@ -91,7 +90,7 @@ static struct diff_rename_src *locate_re
memmove(rename_src + first + 1, rename_src + first,
(rename_src_nr - first - 1) * sizeof(*rename_src));
rename_src[first].one = one;
- rename_src[first].src_used = 0;
+ rename_src[first].src_stays = src_stays;
return &(rename_src[first]);
}
@@ -100,8 +99,11 @@ static int is_exact_match(struct diff_fi
if (src->sha1_valid && dst->sha1_valid &&
!memcmp(src->sha1, dst->sha1, 20))
return 1;
- if (diff_populate_filespec(src) || diff_populate_filespec(dst))
- /* this is an error but will be caught downstream */
+ if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1))
+ return 0;
+ if (src->size != dst->size)
+ return 0;
+ if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
return 0;
if (src->size == dst->size &&
!memcmp(src->data, dst->data, src->size))
@@ -113,7 +115,6 @@ struct diff_score {
int src; /* index in rename_src */
int dst; /* index in rename_dst */
int score;
- int rank;
};
static int estimate_similarity(struct diff_filespec *src,
@@ -127,9 +128,11 @@ static int estimate_similarity(struct di
* dst, and then some edit has been applied to dst.
*
* Compare them and return how similar they are, representing
- * the score as an integer between 0 and 10000, except
- * where they match exactly it is considered better than anything
- * else.
+ * the score as an integer between 0 and MAX_SCORE.
+ *
+ * When there is an exact match, it is considered a better
+ * match than anything else; the destination does not even
+ * call into this function in that case.
*/
void *delta;
unsigned long delta_size, base_size;
@@ -149,6 +152,7 @@ static int estimate_similarity(struct di
/* We would not consider edits that change the file size so
* drastically. delta_size must be smaller than
* (MAX_SCORE-minimum_score)/MAX_SCORE * min(src->size, dst->size).
+ *
* Note that base_size == 0 case is handled here already
* and the final score computation below would not have a
* divide-by-zero issue.
@@ -156,6 +160,9 @@ static int estimate_similarity(struct di
if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
return 0;
+ if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
+ return 0; /* error but caught downstream */
+
delta = diff_delta(src->data, src->size,
dst->data, dst->size,
&delta_size);
@@ -163,7 +170,7 @@ static int estimate_similarity(struct di
/* A delta that has a lot of literal additions would have
* big delta_size no matter what else it does.
*/
- if (minimum_score < MAX_SCORE * delta_size / base_size)
+ if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
return 0;
/* Estimate the edit size by interpreting delta. */
@@ -200,15 +207,14 @@ static void record_rename_pair(struct di
fill_filespec(two, dst->sha1, dst->mode);
dp = diff_queue(renq, one, two);
- dp->score = score;
-
- rename_src[src_index].src_used = 1;
+ dp->score = score ? : 1; /* make sure it is at least 1 */
+ dp->source_stays = rename_src[src_index].src_stays;
rename_dst[dst_index].pair = dp;
}
/*
* We sort the rename similarity matrix with the score, in descending
- * order (more similar first).
+ * order (the most similar first).
*/
static int score_compare(const void *a_, const void *b_)
{
@@ -223,7 +229,7 @@ int diff_scoreopt_parse(const char *opt)
return -1; /* that is not a -M nor -C option */
diglen = strspn(opt+2, "0123456789");
if (diglen == 0 || strlen(opt+2) != diglen)
- return 0; /* use default */
+ return DEFAULT_MINIMUM_SCORE; /* use default */
sscanf(opt+2, "%d", &num);
for (i = 0, scale = 1; i < diglen; i++)
scale *= 10;
@@ -255,9 +261,9 @@ void diffcore_rename(int detect_rename,
else
locate_rename_dst(p->two, 1);
else if (!DIFF_FILE_VALID(p->two))
- locate_rename_src(p->one, 1);
- else if (1 < detect_rename) /* find copy, too */
- locate_rename_src(p->one, 1);
+ register_rename_src(p->one, 0);
+ else if (detect_rename == DIFF_DETECT_COPY)
+ register_rename_src(p->one, 1);
}
if (rename_dst_nr == 0)
goto cleanup; /* nothing to do */
@@ -308,7 +314,7 @@ void diffcore_rename(int detect_rename,
if (dst->pair)
continue; /* already done, either exact or fuzzy. */
if (mx[i].score < minimum_score)
- break; /* there is not any more diffs applicable. */
+ break; /* there is no more usable pair. */
record_rename_pair(&renq, mx[i].dst, mx[i].src, mx[i].score);
}
free(mx);
@@ -317,28 +323,21 @@ void diffcore_rename(int detect_rename,
flush_rest:
/* At this point, we have found some renames and copies and they
* are kept in renq. The original list is still in *q.
- *
- * Scan the original list and move them into the outq; we will sort
- * outq and swap it into the queue supplied to pass that to
- * downstream, so we assign the sort keys in this loop.
- *
- * See comments at the top of record_rename_pair for numbers used
- * to assign rename_rank.
*/
outq.queue = NULL;
outq.nr = outq.alloc = 0;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- struct diff_rename_src *src = locate_rename_src(p->one, 0);
struct diff_rename_dst *dst = locate_rename_dst(p->two, 0);
struct diff_filepair *pair_to_free = NULL;
if (dst) {
/* creation */
if (dst->pair) {
- /* renq has rename/copy already to produce
- * this file, so we do not emit the creation
- * record in the output.
+ /* renq has rename/copy to produce
+ * this file already, so we do not
+ * emit the creation record in the
+ * output.
*/
diff_q(&outq, dst->pair);
pair_to_free = p;
@@ -350,25 +349,17 @@ void diffcore_rename(int detect_rename,
diff_q(&outq, p);
}
else if (!diff_unmodified_pair(p))
- /* all the other cases need to be recorded as is */
+ /* all the usual ones need to be kept */
diff_q(&outq, p);
- else {
- /* unmodified pair needs to be recorded only if
- * it is used as the source of rename/copy
- */
- if (src && src->src_used)
- diff_q(&outq, p);
- else
- pair_to_free = p;
- }
- if (pair_to_free) {
- diff_free_filespec_data(pair_to_free->one);
- diff_free_filespec_data(pair_to_free->two);
- free(pair_to_free);
- }
+ else
+ /* no need to keep unmodified pairs */
+ pair_to_free = p;
+
+ if (pair_to_free)
+ diff_free_filepair(pair_to_free);
}
diff_debug_queue("done copying original", &outq);
-
+
free(renq.queue);
free(q->queue);
*q = outq;
diff --git a/diffcore.h b/diffcore.h
--- a/diffcore.h
+++ b/diffcore.h
@@ -33,14 +33,17 @@ extern struct diff_filespec *alloc_files
extern void fill_filespec(struct diff_filespec *, const unsigned char *,
unsigned short);
-extern int diff_populate_filespec(struct diff_filespec *);
+extern int diff_populate_filespec(struct diff_filespec *, int);
extern void diff_free_filespec_data(struct diff_filespec *);
struct diff_filepair {
struct diff_filespec *one;
struct diff_filespec *two;
- int score; /* only valid when one and two are different paths */
- int status; /* M C R N D U (see Documentation/diff-format.txt) */
+ unsigned short int score; /* only valid when one and two are
+ * different paths
+ */
+ char source_stays; /* all of R/C are copies */
+ char status; /* M C R N D U (see Documentation/diff-format.txt) */
};
#define DIFF_PAIR_UNMERGED(p) \
(!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two))
@@ -54,6 +57,8 @@ struct diff_filepair {
(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
S_ISLNK(mode) ? S_IFLNK : S_IFDIR)
+extern void diff_free_filepair(struct diff_filepair *);
+
extern int diff_unmodified_pair(struct diff_filepair *);
struct diff_queue_struct {
@@ -68,9 +73,6 @@ extern struct diff_filepair *diff_queue(
struct diff_filespec *);
extern void diff_q(struct diff_queue_struct *, struct diff_filepair *);
-extern int diff_needs_to_stay(struct diff_queue_struct *, int,
- struct diff_filespec *);
-
#define DIFF_DEBUG 0
#if DIFF_DEBUG
void diff_debug_filespec(struct diff_filespec *, int, const char *);
diff --git a/git-external-diff-script b/git-external-diff-script
--- a/git-external-diff-script
+++ b/git-external-diff-script
@@ -59,7 +59,7 @@ then
echo "new mode $mode2"
if test "$xfrm_msg" != ""
then
- echo -n $xfrm_msg
+ echo "$xfrm_msg"
fi
fi
diff ${GIT_DIFF_OPTS-'-pu'} -L "a/$name1" -L "b/$name2" "$tmp1" "$tmp2"
diff --git a/t/t4007-rename-3.sh b/t/t4007-rename-3.sh
new file mode 100755
--- /dev/null
+++ b/t/t4007-rename-3.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='Rename interaction with pathspec.
+
+'
+. ./test-lib.sh
+
+_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
+_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+sanitize_diff_raw='s/ \('"$_x40"'\) \1 \([CR]\)[0-9]* / \1 \1 \2# /'
+compare_diff_raw () {
+ # When heuristics are improved, the score numbers would change.
+ # Ignore them while comparing.
+ # Also we do not check SHA1 hash generation in this test, which
+ # is a job for t0000-basic.sh
+
+ sed -e "$sanitize_diff_raw" <"$1" >.tmp-1
+ sed -e "$sanitize_diff_raw" <"$2" >.tmp-2
+ diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
+}
+
+test_expect_success \
+ 'prepare reference tree' \
+ 'mkdir path0 path1 &&
+ cp ../../COPYING path0/COPYING &&
+ git-update-cache --add path0/COPYING &&
+ tree=$(git-write-tree) &&
+ echo $tree'
+
+test_expect_success \
+ 'prepare work tree' \
+ 'cp path0/COPYING path1/COPYING &&
+ git-update-cache --add --remove path0/COPYING path1/COPYING'
+
+# In the tree, there is only path0/COPYING. In the cache, path0 and
+# path1 both have COPYING and the latter is a copy of path0/COPYING.
+# Comparing the full tree with cache should tell us so.
+
+git-diff-cache -C $tree >current
+
+cat >expected <<\EOF
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 C100 path0/COPYING path1/COPYING
+EOF
+
+test_expect_success \
+ 'validate the result' \
+ 'compare_diff_raw current expected'
+
+# In the tree, there is only path0/COPYING. In the cache, path0 and
+# path1 both have COPYING and the latter is a copy of path0/COPYING.
+# When we omit output from path0 it should still be able to tell us
+# that path1/COPYING is result from a copy from path0/COPYING, not
+# rename, which would imply path0/COPYING is now gone.
+
+git-diff-cache -C $tree path1 >current
+
+cat >expected <<\EOF
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 C100 path0/COPYING path1/COPYING
+EOF
+
+test_expect_success \
+ 'validate the result' \
+ 'compare_diff_raw current expected'
+
+test_expect_success \
+ 'tweak work tree' \
+ 'rm -f path0/COPYING &&
+ git-update-cache --remove path0/COPYING'
+
+# In the tree, there is only path0/COPYING. In the cache, path0 does
+# not have COPYING anymore and path1 has COPYING which is a copy of
+# path0/COPYING. Showing the full tree with cache should tell us about
+# the rename.
+
+git-diff-cache -C $tree >current
+
+cat >expected <<\EOF
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100 path0/COPYING path1/COPYING
+EOF
+
+test_expect_success \
+ 'validate the result' \
+ 'compare_diff_raw current expected'
+
+# In the tree, there is only path0/COPYING. In the cache, path0 does
+# not have COPYING anymore and path1 has COPYING which is a copy of
+# path0/COPYING. Even if we restrict the output to path1, it still
+# should show us the rename.
+
+git-diff-cache -C $tree path1 >current
+
+cat >expected <<\EOF
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100 path0/COPYING path1/COPYING
+EOF
+
+test_expect_success \
+ 'validate the result' \
+ 'compare_diff_raw current expected'
+
+test_done
\ No newline at end of file
------------------------------------------------
^ permalink raw reply
* Re: Git does not use GIT_* envirnment vars?
From: Junio C Hamano @ 2005-05-27 6:47 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Git Mailing List
In-Reply-To: <200505270109.44302.dtor_core@ameritech.net>
I am baffled. If you are a bash user, what does "type --all"
tells you? The only explanation I can think of is that you
might have leftover old git-* installation somewhere on your
PATH.
^ permalink raw reply
* Re: Git does not use GIT_* envirnment vars?
From: Dmitry Torokhov @ 2005-05-27 6:54 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7vmzqh17y9.fsf@assigned-by-dhcp.cox.net>
On Friday 27 May 2005 01:47, Junio C Hamano wrote:
> I am baffled. If you are a bash user, what does "type --all"
> tells you? The only explanation I can think of is that you
> might have leftover old git-* installation somewhere on your
> PATH.
*sigh* Exactly. I forgot to uninstall cogito rpm after pulling
the latest tree and they got mixed up. Dammit, I just wasted 3
hours because of my own stupidity :(
Thank you for your help.
--
Dmitry
^ permalink raw reply
* Re: BEWARE: mkdelta is broken
From: Thomas Glanzmann @ 2005-05-27 9:41 UTC (permalink / raw)
To: git
In-Reply-To: <Pine.LNX.4.62.0505262125050.16151@localhost.localdomain>
Hello,
> The current delta loop detection logic is broken. So if you have
> multiple merged branches or you have a changeset that revert things then
> you might end up with a delta loop and fsck-cache will effectively
> complain about unresolved deltas and assorted dangling/broken object
> links.
I wanted to give you heads-up, but I forgot it. But I think noone is
using it at the moment otherwise they had complained in the first place.
However ... I took linux-2.6 repository. Ran git-deltafy-script &&
git-deltafy-script -d 0 and it segfaulted on me. Same for my mutt-cvs
import.
Thomas
^ permalink raw reply
* Re: resolving merge conflicts?
From: Thomas Glanzmann @ 2005-05-27 9:44 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <429698A0.1020008@pobox.com>
[-- Attachment #1: Type: text/plain, Size: 485 bytes --]
Hello,
> So is there a doc or something that describes how to resolve merge
> conflicts?
> Presumably I look at .merge_file_*, and make sure that all necessary
> changes make it into the copy of the file in the working directory...
> then what? How to continue the merge?
I attached a perlscript which tries to make it easy for the user. Maybe
you can 'pull out the' logic and put it in a shell script or so.
git pull
... Conflicts ... run git resolve
git resolve
...
Thomas
[-- Attachment #2: git --]
[-- Type: text/plain, Size: 23911 bytes --]
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Handle;
use File::Temp qw/ tempfile tempdir /;
use File::Copy;
use Cwd;
use Getopt::Long;
STDOUT->autoflush(1);
my $hostname = gitcmdout('hostname');
chomp($hostname);
my $DIFF = undef;
my $PATCH = undef;
if (-x '/opt/csw/bin/gdiff') {
$DIFF='/opt/csw/bin/gdiff';
} else {
$DIFF='diff';
}
if (-x '/usr/bin/gpatch') {
$PATCH='/usr/bin/gpatch';
} else {
$PATCH='patch';
}
my %commands = (
"add" => \&add,
"checkout" => \&checkout,
"ci" => \&ci,
"clone" => \&clone,
"commit" => \&commit,
"diff" => \&diff,
"treediff" => \&treediff,
"dirty" => \&dirty,
"help" => \&usage,
"init-db" => \&init_db,
"log" => \&log,
"orphan" => \&orphan,
"parent" => \&parent,
"patch" => \&patch,
"pull" => \&pull,
"push" => \&_push,
"refresh" => \&refresh,
"revert" => \&revert,
"rm" => \&rm,
"setup" => \&setup,
"status" => \&status,
"undo" => \&undo,
"changed" => \&changed,
"resolve" => \&resolve,
"changes" => \&changes,
);
my %touched = ();
sub
usage
{
print STDERR <<"__EOF__";
Usage: $0 COMMAND [ARG]...
Available commands:
__EOF__
print "\t" . join("\n\t", sort(keys(%commands))) . "\n\n";
return 1;
}
sub
refresh
{
`git-update-cache --refresh`;
}
sub
process_git_diff_output
{
my $str = shift || return (());
my @in = split("\0", $str);
my @out = ();
while (@in) {
my @tmp = split(' ', shift(@in));
$tmp[0] =~ s/^://g;
push(@tmp, shift(@in));
push(@out, [@tmp]);
}
return(@out);
}
sub
dirty_files
{
refresh();
my @dirty = ();
my $str = gitcmdout('git-diff-files', '-z', '-r');
foreach (process_git_diff_output($str)) {
if ((@{$_})[1] ne '000000') {
push(@dirty, @{$_}[5]);
}
#print "<" . join("> <", @{$_}) . ">\n";
}
return @dirty;
}
sub
orphan_files
{
my @orphan = gitcmdout('git-ls-files', '--others');
chomp(@orphan);
my $regexp = '^\.';
if (-f '.git/ignore') {
my @ignore = ();
chomp (@ignore = _read_file('.git/ignore'));
$regexp = join('|', '^\.', @ignore);
}
@orphan = grep(! /$regexp/, @orphan);
return @orphan;
}
sub
orphan
{
foreach (orphan_files()) {
print $_ . "\n";
}
}
sub
dirty
{
foreach (dirty_files()) {
print $_ . "\n";
}
}
sub
changed
{
foreach my $rev (gitcmdout('git-rev-list', 'HEAD')) {
chomp($rev);
my %hash = commit_hash($rev);
my $str = gitcmdout('git-diff-tree', '--root', '-r', '-z', $rev);
foreach (process_git_diff_output($str)) {
my ($time, $rest) = split(/\s/, $hash{committer_date});
push(@{$touched{@{$_}[5]}}, $time);
}
}
}
sub
status
{
my %hash = ();
foreach (orphan_files()) {
$hash{$_} = '?';
}
foreach (dirty_files()) {
$hash{$_} = 'D';
}
my $str = gitcmdout('git-diff-cache', '-r', '--cached', '-z', 'HEAD');
foreach (process_git_diff_output($str)) {
if (@{$_}[0] eq '000000') {
$hash{@{$_}[5]} .= '+';
} elsif (@{$_}[1] eq '000000') {
$hash{@{$_}[5]} .= '-';
} else {
$hash{@{$_}[5]} .= '*';
}
}
foreach (sort(keys(%hash))) {
if ($hash{$_} eq "D") {
$hash{$_} = "D ";
}
printf("% 2s %s\n", $hash{$_}, $_);
}
}
sub
write_tree
{
chomp (my $tree = `git-write-tree`);
if ($?) {
return undef;
} else {
return $tree;
}
}
sub
retrieve_unmerged
{
my %hash = ();
foreach my $line (gitcmdout('git-ls-files', '--unmerged')) {
chomp($line);
# 100644 cde27275fad8103084d7ed2d08d246ba4ce6eb9c 1 Makefile
# 100644 d311a35e5e8a09629ea9e6051a43710c76fa8f6d 2 Makefile
# 100644 ec2b76bf90fb105b2aaf00a66f44b135046d3002 3 Makefile
if ($line =~ /^(\d{6})\s([a-z0-9]{40})\s(\d)\s(.+)$/) {
push(@{$hash{$4}}, $line);
} else {
die("Can't match: <$line>\n");
}
}
return %hash;
}
sub
process_unmerged_file
{
my $line;
my $file;
my @files = ();
while($line = shift) {
if ($line =~ /^(\d{6})\s([a-z0-9]{40})\s(\d)\s(.+)$/) {
if ($3 eq '1') { $file = "$4.GCA"; }
if ($3 eq '2') { $file = "$4.LOCAL"; }
if ($3 eq '3') { $file = "$4.REMOTE"; }
my $mode = substr($1, 2);
if (-f $file) {
die("Please get rid of $file\n");
}
print STDERR "Checking out: $file with permissions $mode\n";
system("git-cat-file blob $2 > $file");
chmod oct($mode), $file;
push(@files, $file);
}
}
if (@files == 3) {
my $filename = (@files)[0];
$filename =~ s#\.(GCA|LOCAL|REMOTE)$##;
print STDERR <<"EOF";
You got GCA, LOCAL and REMOTE, so I run merge for you and leaving the merges in
${filename} .\n
EOF
unlink($filename);
system('cp', "${filename}.LOCAL", "${filename}");
system('merge', "${filename}", "${filename}.GCA", "${filename}.REMOTE");
}
print STDERR <<"EOF";
Please resolve the conflict and add the file using the command 'git ci file'.
Droping you to a login shell now. Please exit the shell as soon as you resolved
the conflict.
EOF
system($ENV{'SHELL'}, '--login');
foreach (@files) {
unlink($_);
}
}
sub
resolve
{
if (! -f '.git/RESOLVE') {
die("Nothing to resolve");
}
if ( ! -f '.git/HEAD' && ! -l '.git/HEAD') {
die("How the hell I am supposed to resolve without a head?");
}
my $fh;
my $head = head();
my $merge_tree = undef;
my $pwd = getcwd;
chomp (my ($remote_head, $url) = _read_file('.git/RESOLVE'));
print "remote_head => $remote_head\nurl => $url\n";
my %unmerged = retrieve_unmerged();
foreach my $file (keys(%unmerged)) {
process_unmerged_file(@{$unmerged{$file}});
}
if (! defined($merge_tree = write_tree())) {
die("Still unresolved conflicts. Run git resolve again.");
}
open($fh, "+>", undef);
print $fh "Manual Merge $url => ${hostname}:${pwd}\n";
seek($fh, 0, 0);
chomp($head = gitcmdinout($fh, 'git-commit-tree', $merge_tree, '-p', $head, '-p', $remote_head));
close $fh;
head($head);
unlink('.git/RESOLVE');
checkout('-f');
print STDERR "All issues resolved manual: Commited as ${head}.\n";
print STDERR "Have a pleasant day.\n";
return;
}
sub
merge
{
my $remote_head = shift || die("need remote head");
my $url = shift || die("need remote url");
my $merge_tree = undef;
my $message = "";
my $fh;
my $pwd = `pwd`;
chomp($pwd);
if ( ! -f '.git/HEAD' && ! -l '.git/HEAD') {
head($remote_head);
return;
}
my $head = head();
chomp (my $merge_base = gitcmdout('git-merge-base', $head, $remote_head) || die ("no merge-base"));
print "head => $head\nremote => $remote_head\nbase => $merge_base\n";
if ($merge_base eq $remote_head) {
print STDERR "Nothing to pull.\n";
return;
}
if ($merge_base eq $head) {
print STDERR "Just bringing head ahead.\n";
head($remote_head);
return;
}
gitcmd('git-read-tree', '-m', tree_id($merge_base), tree_id($head), tree_id($remote_head));
if (! defined($merge_tree = write_tree())) {
system('git-merge-cache', '-o', 'git-merge-one-file-script', '-a');
if (! defined($merge_tree = write_tree())) {
_write_file('.git/RESOLVE', "$remote_head", "$url\n");
die("Couldn't merge automatically: Call 'git resolve'");
}
print STDERR "Threewaydiff invloved.\n";
$message = "Threeway Merge $url => ${hostname}:${pwd}\n";
} else {
print STDERR "Automatic Merge.\n";
$message = "Automatic Merge $url => ${hostname}:${pwd}\n";
}
open($fh, "+>", undef);
print $fh $message;
seek($fh, 0, 0);
chomp($head = gitcmdinout($fh, 'git-commit-tree', $merge_tree, '-p', $head, '-p', $remote_head));
close $fh;
head($head);
return;
}
sub
patch
{
my @files = ();
my ($fh, $patch);
my $file = shift || die("Need at least on argument.\n");
my $head = undef;
my $dir = undef;
if (head()
&& ( dirty_files()
|| `git-diff-cache -r --cached HEAD`)) {
print STDERR "Get rid of dirty files / uncommited deltas first.\n";
exit 1;
}
($fh, $patch) = tempfile(CLEANUP => 1);
`filterdiff -x '*/.*' $file > $patch`;
@files = `lsdiff --strip 1 $patch`;
chomp(@files);
$dir = tempdir(CLEANUP => 1);
$ENV{GIT_INDEX_FILE} = "$dir/.index";
if ($head = head()) {
gitcmd('git-read-tree', $head);
foreach my $file (@files) {
gitcmd('git-checkout-cache', '-q', "--prefix=$dir/", $file);
}
}
my $pwd = getcwd;
symlink("$pwd/.git", "$dir/.git");
chdir($dir);
# FIXME call in batch modus and check return value --tg 08:30 05-05-21
system("${PATCH} -p1 < $patch");
foreach my $file (@files) {
gitcmd('git-update-cache', '--add', '--remove', $file);
}
commit();
chdir($pwd);
delete($ENV{GIT_INDEX_FILE});
checkout('-f');
}
sub
checkout
{
my $head = head();
gitcmd('git-read-tree', '-m', $head);
# FIXME if this fails call it without -m --tg 20:25 05-05-09
if (defined($_[0]) && $_[0] eq '-f') {
gitcmd('git-checkout-cache', '-u', '-f', '-a');
} else {
gitcmd('git-checkout-cache', '-u', '-q', '-a');
}
# changed();
#
# foreach my $file (gitcmdout('git-ls-files')) {
# chomp($file);
# my $time = (sort {$b <=> $a} @{$touched{$file}})[0];
# utime $time, $time, $file;
# }
}
sub
generate_url
{
my $url = shift;
if (! defined($url)) {
if ( -f '.git/PARENT' || -l '.git/PARENT') {
chomp ($url = _read_file('.git/PARENT'));
} else {
die("$0: No URL specified and no parent found: Where to pull from?\n");
}
} else {
$url =~ s#\/$##;
if (-d $url &&
! ($url =~ /\.git$/)) {
$url .= "/.git";
}
if (-d $url &&
! ($url =~ /^\//)) {
# FIXME: use Cwd; my $pwd = getcwd; --tg 21:32 05-05-03
chomp(my $pwd = `pwd`);
$url = "${pwd}/${url}";
}
}
return $url;
}
sub
pull
{
my %options;
local @ARGV = @_;
GetOptions(\%options, 'o', 'l');
@_ = @ARGV;
my $url = generate_url(shift);
my $remote_head = undef;
if (head()
&& (! defined($options{'o'}))
&& ( dirty_files()
|| `git-diff-cache -r --cached HEAD`)) {
print STDERR "Get rid of dirty files / uncommited deltas first.\n";
exit 1;
}
if (defined($options{'l'}) && -d $url) {
$ENV{'GIT_ALTERNATE_OBJECT_DIRECTORIES'} = "${url}/objects";
} else {
gitcmd('rsync', '-qa', '--ignore-existing', "$url/objects/.", ".git/objects/.");
}
gitcmd('rsync', '-qL', "$url/HEAD", '.git/REMOTE_HEAD');
chomp($remote_head = _read_file('.git/REMOTE_HEAD'));
if (! defined($options{'o'})) {
merge($remote_head, $url);
checkout('-f');
}
}
sub
changes
{
my %options;
local @ARGV = @_;
GetOptions(\%options, "L", "R", "d", "m", "n", "t=s");
@_ = @ARGV;
my $git_diff_tree_options = '-s';
if (defined ($options{'d'})) {
$git_diff_tree_options = '-p';
}
if (defined ($options{'m'})) {
$git_diff_tree_options .= ' -m';
}
if (defined ($options{'L'})) {
if (! defined ($options{'n'})) {
pull('-o', '-l', shift);
}
system("git-rev-tree HEAD '^REMOTE_HEAD' | sed -e 's/^[0-9]* //' | git-diff-tree --stdin -v $git_diff_tree_options");
} elsif (defined ($options{'R'})) {
if (! defined ($options{'n'})) {
pull('-o', '-l', shift);
}
system("git-rev-tree REMOTE_HEAD '^HEAD' | sed -e 's/^[0-9]* //' | git-diff-tree --stdin -v $git_diff_tree_options");
} elsif (defined ($options{'t'})) {
system("git-rev-tree HEAD '^$options{'t'}' | sed -e 's/^[0-9]* //' | git-diff-tree --stdin -v $git_diff_tree_options");
} else {
system("git-rev-list HEAD | git-diff-tree --stdin -v $git_diff_tree_options");
}
}
sub
_push
{
my $url = generate_url(shift);
gitcmd('rsync', '-qL', "$url/HEAD", '.git/REMOTE_HEAD');
chomp (my $remote_head = _read_file('.git/REMOTE_HEAD'));
my $head = head() || die("No local HEAD\n");
if ($head eq $remote_head) {
print STDERR "Nothing to push.\n";
return;
}
print "head => $head\nremote => $remote_head\n";
my @revlist = gitcmdout('git-rev-list', $head);
if (! grep(/^${remote_head}$/, @revlist)) {
print STDERR "Remote is ahead or unrelated: Need to pull first?\n";
exit 1;
}
gitcmd('rsync', '-qa', '--ignore-existing', ".git/objects/.", "$url/objects/.");
gitcmd('rsync', '-q', '.git/HEAD', "$url/HEAD");
}
sub
clone
{
my %options;
GetOptions(\%options, "l");
my $url = shift(@ARGV);
my $project = shift(@ARGV);
if (! defined($url) || ! defined($project)) {
die("Usage: $0 clone <url> <project>\n");
}
$url = generate_url($url);
if (defined($options{l})) {
if (-d $url) {
-d ".git" && die("$0 clone $project: Don\'t create repository in a repository.");
mkdir($project, 0755) || die("$0 clone $project: mkdir: $!");
chdir($project) || die("$0 clone $project: chdir: $!");
mkdir('.git', 0755) || die("$0 clone $project: mkdir: $!");
symlink("$url/objects", '.git/objects') || die("Can\'t symlink object database");
} else {
die("Can't symlink from network repositories\n");
}
} else {
setup($project);
}
parent($url);
pull();
}
sub
parent
{
my $parent = $_[0];
if (defined($parent)) {
if ($parent eq "-c") {
if ( -f ".git/PARENT" || -l ".git/PARENT") {
unlink(".git/PARENT") || die("can't delete .git/PARENT: $!");
}
print STDERR "$0 parent: Parent removed\n";
} else {
$parent = generate_url($parent);
_write_file('.git/PARENT', "$parent\n");
}
} else {
if ( -f ".git/PARENT" || -l ".git/PARENT") {
chomp($parent = _read_file('.git/PARENT'));
print "${parent}\n";
} else {
print STDERR "$0 parent: No parent specified\n";
}
}
}
# FIXME: Include, Exclude --tg 12:07 05-05-06
sub
diff
{
my @deltas=();
my %options;
local @ARGV = @_;
GetOptions(\%options, 'r=s', 'f', 'c', 'v');
@_ = @ARGV;
my $dir = tempdir(CLEANUP => 1);
refresh();
if (defined($options{'r'})) {
if($options{'r'} =~ /:/) {
my ($first, $second) = split(/:/, $options{'r'});
system("git-diff-tree -r -z $first $second | git-diff-helper -z");
} else {
if (defined ($options{'v'})) {
system("git-diff-tree -s -v $options{'r'}");
print "\n";
}
system("git-diff-tree -r -z $options{'r'} | git-diff-helper -z");
}
} elsif (defined($options{"f"})) {
system('git-diff-files -r -z | git-diff-helper -z');
} elsif (defined($options{"c"})) {
system('git-diff-cache --cached -r -z HEAD | git-diff-helper -z');
} else {
system('git-diff-cache -r -z HEAD | git-diff-helper -z');
}
chomp(@deltas);
}
sub
treediff
{
pull('-o', '-l', shift);
diff('-r', 'REMOTE_HEAD:HEAD');
}
sub
init_db
{
gitcmd( 'init-db', @_ );
}
sub
setup
{
my $project = shift || die ("usage: $0 setup project");
-d ".git" && die ("$0 setup $project: Don\'t create repository in a repository.");
mkdir($project, 0755) || die ("$0 setup $project: mkdir: $!");
chdir($project) || die ("$0 setup $project: chdir: $!");
gitcmd('git-init-db');
}
sub
revert
{
# TODO handle revert of add/remove --tg 02:32 05-05-06
my @in = ();
my $fh;
if (! defined($_[0])) {
return;
}
if ($_[0] eq "-") {
@in = <STDIN>;
} else {
@in = @_;
}
my $head = head();
($fh, $ENV{GIT_INDEX_FILE}) = tempfile(CLEANUP => 1);
gitcmd('git-read-tree', $head);
foreach (@in) {
chomp($_);
$_ =~ s#^\.\/##;
if (/^\./) {
print STDERR "Warning: Skipping $_\n";
next;
}
if (-d $_) {
next;
}
gitcmd('git-checkout-cache', '-f', $_);
}
delete($ENV{GIT_INDEX_FILE});
foreach (@in) {
chomp($_);
$_ =~ s#^\.\/##;
if (/^\./) {
next;
}
if (! -f $_) {
next;
}
gitcmd('git-update-cache', $_);
}
}
sub
add
{
my @in = ();
if (defined($_[0]) && $_[0] eq "-") {
@in = <STDIN>;
} else {
@in = @_;
}
foreach (@in) {
chomp($_);
$_ =~ s#^\.\/##;
if (/^\./) {
print STDERR "Warning: Skipping $_\n";
next;
}
if (-d $_) {
next;
}
if (! -f $_) {
print STDERR "Warning: Skipping nonexisting file: $_\n";
next;
}
gitcmd( 'git-update-cache', '--add', '--', $_ );
}
}
sub
ci
{
my @in = ();
if (defined($_[0]) && $_[0] eq "-") {
@in = <STDIN>;
} else {
@in = @_;
}
foreach (@in) {
chomp($_);
$_ =~ s#^\.\/##;
if (/^\./) {
print STDERR "Warning: Skipping $_\n";
next;
}
if (-d $_) {
next;
}
if (! -f $_) {
print STDERR "Warning: Skipping nonexisting file: $_\n";
next;
}
gitcmd( 'git-update-cache', '--', $_ );
}
}
sub
rm
{
my @in = ();
if (defined($_[0]) && $_[0] eq "-") {
@in = <STDIN>;
} else {
@in = @_;
}
foreach (@in) {
chomp($_);
$_ =~ s#^\.\/##;
if (/^\./) {
print STDERR "Warning: Skipping $_\n";
next;
}
if (-d $_) {
next;
}
if (-f $_) {
unlink($_) || die ("$0 rm $_: $!");
}
gitcmd( 'git-update-cache', '--remove', '--' , $_ );
}
}
sub
head
{
my $head = $_[0];
if (defined($head)) {
if ($head eq "") {
if ( -f ".git/HEAD" || -l ".git/HEAD") {
unlink(".git/HEAD") || die "failed to delete .git/HEAD: $!\n";
}
} else {
chomp($head);
_write_file( '.git/HEAD', "$head\n" );
}
} else {
if (-f '.git/HEAD') {
chomp( $head = _read_file( '.git/HEAD' ) );
} else {
$head = undef;
}
}
return $head;
}
sub
print_commit
{
my $commit = shift || die("need commit");
print "commit $commit\n";
foreach (gitcmdout('git-cat-file', 'commit', $commit)) {
if (/^(author|committer)(.+>\s)(\d+)\s([+-]?\d{4})$/) {
# local $ENV{TZ} = $4;
print "$1$2" . localtime($3) . "\n";
} else {
print "$_\n";
}
}
print "\n";
}
sub
commit
{
my $head = head();
chomp (my $tree = gitcmdout('git-write-tree'));
if (dirty_files()) {
die "$0 commit: Get rid of dirty files first.\n";
}
if (defined($head)) {
my %hash = commit_hash($head);
if ($hash{tree} eq $tree) {
die "$0 commit: The commit wouldn't commit anything different.\n";
}
$head = gitcmdout('git-commit-tree', $tree, '-p', $head);
} else {
$head = gitcmdout('git-commit-tree', $tree);
}
head($head);
}
sub
log
{
my $head = head() || return ;
my $pid;
if ( ! -p STDIN && ! -p STDOUT ) {
my ( $r, $w );
pipe( $r, $w ) || die "Failed to pipe: $!";
defined( $pid = fork ) || die "Failed to fork: $!";
if ( $pid ) { # Parent
$SIG{INT} = $SIG{TERM} = $SIG{HUP} = sub {
kill 15, $pid;
exit 1;
};
close $r;
close STDOUT;
open STDOUT, '>&', $w || die "Failed to redirect STDOUT: $!";
} else { # pager child
close $w;
close STDIN;
open STDIN, '<&', $r || die "Failed to redirect STDIN: $!";
if ( $ENV{PAGER} ) {
exec( $ENV{PAGER} );
} else {
exec( 'less', '-r', '-' );
}
}
}
foreach (gitcmdout('git-rev-list', $head)) {
print_commit($_);
}
if ( $pid ) {
close STDOUT;
waitpid($pid, 0);
}
}
sub
commit_hash
{
my %hash = ();
my $id = shift || die ("$0: commit_hash: expect one argument");
my $comment = 0;
my @lines = gitcmdout('git-cat-file', 'commit', $id);
foreach (@lines) {
chomp;
if ($comment) {
push(@{$hash{comment}}, $_);
next;
}
if (/^tree\s(\w{40})$/) {
$hash{tree} = $1;
next;
}
if (/^parent\s(\w{40})$/) {
push(@{$hash{parent}}, $1);
next;
}
if (/^author\s(.*)\s<(.*)>\s(.*)$/) {
$hash{author_name} = $1;
$hash{author_eMail} = $2;
$hash{author_date} = $3;
next;
}
if (/^committer\s(.*)\s<(.*)>\s(.*)$/) {
$hash{committer_name} = $1;
$hash{committer_eMail} = $2;
$hash{committer_date} = $3;
next;
}
if (/^$/) {
$comment = 1;
}
}
return(%hash);
}
sub
first_parent
{
my $this = shift || die ("$0: parent called without object");
my %hash = commit_hash($this);
if (! defined(@{$hash{parent}}[0])) {
return "";
}
return(@{$hash{parent}}[0]);
}
sub
undo
{
my $head = head();
if (! defined($head)) {
return;
}
if ( dirty_files()
|| `git-diff-cache -r --cached HEAD`) {
print STDERR "Get rid of dirty files / uncommited deltas first.\n";
exit 1;
}
my $newhead = first_parent($head);
print "oldhead $head\nnewhead $newhead\n";
head($newhead);
checkout('-f');
}
sub
object_type
{
my $id = shift;
defined $id && $id =~ /^[A-Za-z0-9]{40}$/ ||
die "Invalid sha1 id '$id'";
my $type = gitcmdout('git-cat-file', '-t', $id );
chomp $type;
return $type;
}
sub
tree_id
{
my $id = shift;
( $id ) = grep { defined }
map { /^tree ([A-Za-z0-9]{40})$/ ? $1 : undef }
gitcmdout( 'git-cat-file', 'commit', $id ) or
die "Unable to find tree id for commit id $id";
object_type( $id ) eq 'tree' ||
die "tree id from commit is not a tree object!";
return $id;
}
sub
parent_id
{
my $id = shift;
my ( $pid ) = grep { defined }
map { /^parent ([A-Za-z0-9]{40})$/ ? $1 : undef }
gitcmdout( 'git-cat-file', 'commit', $id ) or
die "Unable to determine parent commit of commit $id";
return $pid;
}
# int
# main(int argc, char **argv)
# {
if (defined($ARGV[0]) && defined($commands{$ARGV[0]})) {
my $string = shift;
if ( ! -d ".git"
&& ! ($string eq "setup"
|| $string eq "init-db"
|| $string eq "clone")) {
die("$0 $string: Not in a git BASE directory");
}
$commands{$string}->(@ARGV);
} else {
if (defined($ARGV[0])) {
print STDERR "No such command: $ARGV[0]\n\n";
}
usage();
}
# }
{
my %gitcmd;
sub
gitcmdpath
{
my $cmd = shift;
unless ( defined $gitcmd{$cmd} ) {
local $/ = "\n";
chomp( $gitcmd{$cmd} = `which $cmd` );
return undef if $gitcmd{$cmd} eq '';
}
return $gitcmd{$cmd};
}
sub
gitcmd
{
my $cmd = shift;
gitcmdpath( $cmd ) || die "command '$cmd' not found";
my $r = system( $gitcmd{$cmd}, @_ );
die "$cmd failed: " . _gitcmderrmsg( $cmd )
if $r != 0;
return 1;
}
sub
gitcmdinout
{
my $infh = shift;
my $cmd = shift;
gitcmdpath( $cmd ) || die "command '$cmd' not found";
my ( $r, $w );
pipe( $r, $w ) || die "Failed to pipe: $!";
my $pid = fork();
die "Failed to fork: $!" unless defined $pid;
if ( $pid ) {
close $w;
local $/;
local $_ = <$r>;
close $r;
my $kid = waitpid( $pid, 0 );
die "Hmm, auto reaping in place?" if $kid == -1;
die "$cmd failed: " . _gitcmderrmsg( $cmd )
if $? & 127 || $? >> 8 != 0;
if ( wantarray ) {
return split( "\n", $_ );
} else {
return $_;
}
} else {
close $r;
close STDOUT;
close STDIN;
open STDIN, '<&', $infh || die "Failed to rediret STDIN";
open STDOUT, '>&', $w || die "Failed to redirect STDOUT";
exec( $gitcmd{$cmd}, @_ );
}
}
sub
gitcmdout
{
my $cmd = shift;
gitcmdpath( $cmd ) || die "command '$cmd' not found";
my ( $r, $w );
pipe( $r, $w ) || die "Failed to pipe: $!";
my $pid = fork();
die "Failed to fork: $!" unless defined $pid;
if ( $pid ) {
close $w;
local $/;
my $ret = <$r>;
close $r;
my $kid = waitpid( $pid, 0 );
die "Hmm, auto reaping in place?" if $kid == -1;
die "$cmd failed: " . _gitcmderrmsg( $cmd )
if $? & 127 || $? >> 8 != 0;
if (wantarray) {
return split("\n", $ret);
} else {
return $ret;
}
} else {
close $r;
close STDOUT;
open STDOUT, '>&', $w || die "Failed to redirect STDOUT";
exec( $gitcmd{$cmd}, @_ );
}
}
sub
_gitcmderrmsg
{
my $cmd = shift;
my $e;
if ( $? == -1 ) {
$e = "failed to execute $gitcmd{$cmd}: $!";
} elsif ( $? & 127 ) {
$e = sprintf( 'child die from signal %d', ( $? & 127 ) );
$e .= ' (with coredump)' if $? & 128;
} else {
$e = sprintf( 'child exit value: %d', $? >> 8 );
}
return $e;
}
}
sub
_recur_mkdir
{
my $dir = shift;
my @dir = split( /\//, $dir );
my $path = '';
while ( @dir ) {
$path .= '/' . shift @dir;
( -d $path ) || mkdir( $path ) ||
die "Failed to mkdir $path: $!";
}
}
sub
_read_file
{
my $file = shift;
my $fh;
open $fh, '<', $file || die "failed to read $file: $!\n";
if ( wantarray ) {
my @r = <$fh>;
close $fh || die "failed to close $file: $!\n";
return @r;
} else {
local $/;
my $r = <$fh>;
close $fh || die "failed to close $file: $!\n";
return $r;
}
}
sub
_write_file
{
my $file = shift;
my $fh;
open $fh, '>', $file || die "failed to write $file: $!\n";
if ( @_ ) {
print $fh join( $/, @_ );
}
close $fh || die "failed to close $file: $!\n";
return 1;
}
# vim:set noexpandtab:
^ permalink raw reply
* [PATCH] Fix git-deltafy-script off-by-one errors
From: Stephen Tweedie @ 2005-05-27 10:36 UTC (permalink / raw)
To: git, Linus Torvalds; +Cc: Stephen Tweedie
[-- Attachment #1: fix-deltafy-offbyone.patch --]
[-- Type: text/plain, Size: 2746 bytes --]
git-deltafy-script contains two off-by-one errors that prevent it from
deltafying either the last file it encounters, or the oldest version of
any file.
The script decides that it needs to run git-mkdelta when it encounters
the next filename in its inner loop. The last file obviously doesn't
have a next file, so does not get processed. Fix this by factoring
out the test that runs the file processing, and forcibly run that test
again at the end of the loop to catch the last file.
There's a second problem; the script only passes one revision to
git-mkdelta per change it finds in the tree history. For each change,
it only adds the hash of the file's new version to the list of hashes
being built up. The oldest version is ignored. Fix this by outputing
both the old AND new versions when we encounter an "M" line in the tree
diff; that will mean that hashes crop up multiple times if the old
version from one commit matches the new version of an older commit, but
we're already doing a "uniq" which strips those duplicates out.
Signed-off-by: Stephen Tweedie <sct@redhat.com>
---
commit a1d358812e6796a1ebdac740dcd666a567adb462
tree 9bfe10668d8220dd1a6642e06fa9c8d726134675
parent a95abde1074b8bf5bb4e4dab930397188e1bb3fa
author Stephen Tweedie <sct@redhat.com> Fri, 27 May 2005 11:25:51 +0100
committer Stephen Tweedie <sct@redhat.com> Fri, 27 May 2005 11:25:51 +0100
git-deltafy-script | 38 +++++++++++++++++++++++---------------
1 files changed, 23 insertions(+), 15 deletions(-)
Index: git-deltafy-script
===================================================================
--- af5e58731609986ed53e05508b55f801b3d5c51d/git-deltafy-script (mode:100644)
+++ 9bfe10668d8220dd1a6642e06fa9c8d726134675/git-deltafy-script (mode:100644)
@@ -19,22 +19,30 @@
depth=
[ "$1" == "-d" ] && depth="--max-depth=$2" && shift 2
-curr_file=""
+function process_one () {
+ if [ "$list" ]; then
+ echo "Processing $curr_file"
+ echo "$head $list" | xargs git-mkdelta $depth -v
+ fi
+}
+
git-rev-list HEAD |
git-diff-tree -r --stdin |
-awk '/^:/ { if ($5 == "M" || $5 == "N") print $4, $6 }' |
-LC_ALL=C sort -s -k 2 | uniq |
-while read sha1 file; do
- if [ "$file" == "$curr_file" ]; then
- list="$list $sha1"
- else
- if [ "$list" ]; then
- echo "Processing $curr_file"
- echo "$head $list" | xargs git-mkdelta $depth -v
+awk '/^:/ { if ($5 == "M" || $5 == "N") print $4, $6;
+ if ($5 == "M") print $3, $6 }' |
+LC_ALL=C sort -s -k 2 | uniq |
+{
+ curr_file=""
+ while read sha1 file; do
+ if [ "$file" == "$curr_file" ]; then
+ list="$list $sha1"
+ else
+ process_one
+ curr_file="$file"
+ list=""
+ head="$sha1"
fi
- curr_file="$file"
- list=""
- head="$sha1"
- fi
-done
+ done
+ process_one
+}
^ permalink raw reply
* Re: Suggestion: superceded tags
From: Stephen C. Tweedie @ 2005-05-27 11:26 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: Stephen Tweedie, Git Mailing List
In-Reply-To: <4296B051.10603@zytor.com>
Hi,
On Fri, 2005-05-27 at 06:29, H. Peter Anvin wrote:
> When a tag is moved, a new tag object is created. This tag object will
> have a "supercedes" header which references the old tag object.
Strictly speaking, don't you need to allow multiple "supercedes" lines
to cover all the cases? The pathological case is when you've got
multiple trees all with different variants of the same tag name, and you
try to merge them all at once with a multi-parent commit.
Sure, tags refer to trees, not commits, so you don't necessarily have to
do this tag resolution at commit time (indeed, since commits don't refer
to tags, you *can't* do that resolution atomically on commit.)
But if you do pull tags into the local .git/refs/tags on merge, then you
will want to either resolve the conflict or supercede those tags, and at
that point you've got multiple equally valid tags in the histories that
are being superceded. Doing so is a porcelain issue, but the core will
still need to understand tags with multiple supercedes: lines.
--Stephen
^ permalink raw reply
* [PATCH] ls-tree path restriction semantics fixes
From: Jason McMullan @ 2005-05-27 12:08 UTC (permalink / raw)
To: git
This patch fixes the git-ls-tree semantics to be less stupid, namely:
* ls of a 'tree' path should just return the SHA1 of the tree
* ls of a 'tree' path with a trailing '/' should work properly
* ls of two identical paths should have the same output as ls of
a single path. (I consider ls-tree's output to be a hash dictionary)
Also, I added test cases to verify that these issues are fixed.
Old Results:
$ git-ls-tree t
040000 tree 4eeb3990955b8badc4c14712b89d8cd9fff02f15 t
100644 blob 6882e23be568ccf14f3adb0c766139086f2ee952 t/Makefile
100644 blob 2a94fdb0b83ab5fcbf1a2c6edaf36c2dbe765ec6 t/README
100644 blob d920c6b3a3bfbb5994244a78d1ad99ce02748122 t/lib-read-tree-m-3way.sh
...
$ git-ls-tree t/
(no output)
$ git-ls-tree t t
040000 tree 4eeb3990955b8badc4c14712b89d8cd9fff02f15 t
New Results:
$ git-ls-tree f
040000 tree 4eeb3990955b8badc4c14712b89d8cd9fff02f15 t
$ git-ls-tree t/
040000 tree 4eeb3990955b8badc4c14712b89d8cd9fff02f15 t
$ git-ls-tree t t
040000 tree 4eeb3990955b8badc4c14712b89d8cd9fff02f15 t
Signed-Off-By: Jason McMullan <jason.mcmullan@timesys.com>
diff --git a/ls-tree.c b/ls-tree.c
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -13,8 +13,6 @@ struct path_prefix {
const char *name;
};
-#define DEBUG(fmt, ...)
-
static int string_path_prefix(char *buff, size_t blen, struct path_prefix *prefix)
{
int len = 0;
@@ -118,6 +116,8 @@ static void list_recursive(void *buffer,
mtype = pathcmp(match[mindex],&this_prefix);
if (mtype >= 0) {
matched = match[mindex];
+ /* Skip over any duplicates */
+ for (; mindex+1 < matches && strcmp(match[mindex+1],matched)==0; mindex++);
break;
}
}
@@ -140,19 +140,22 @@ static void list_recursive(void *buffer,
if (matches && ! matched)
continue;
- if (! (eltbuf = read_sha1_file(sha1, elttype, &eltsize)) ) {
- error("cannot read %s", sha1_to_hex(sha1));
- continue;
- }
-
/* If this is an exact directory match, we may have
* directory files following this path. Match on them.
- * Otherwise, we're at a pach subcomponent, and we need
+ * Otherwise, we're at a path subcomponent, and we need
* to try to match again.
*/
if (mtype == 0)
mindex++;
+ if (matched && matches-mindex==0)
+ continue;
+
+ if (! (eltbuf = read_sha1_file(sha1, elttype, &eltsize)) ) {
+ error("cannot read %s", sha1_to_hex(sha1));
+ continue;
+ }
+
list_recursive(eltbuf, elttype, eltsize, &this_prefix, &match[mindex], matches-mindex);
free(eltbuf);
}
@@ -169,9 +172,14 @@ static int list(unsigned char *sha1,char
unsigned long size;
int npaths;
- for (npaths = 0; path[npaths] != NULL; npaths++)
- ;
+ /* Count the paths, and any trailling '/' */
+ for (npaths = 0; path[npaths] != NULL; npaths++) {
+ char *cp = strrchr(path[npaths],'/');
+ if (cp != NULL && *(cp+1) == 0)
+ *cp=0;
+ }
+ /* Sort the paths */
qsort(path,npaths,sizeof(char *),qcmp);
buffer = read_object_with_reference(sha1, "tree", &size, NULL);
diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh
--- a/t/t3100-ls-tree-restrict.sh
+++ b/t/t3100-ls-tree-restrict.sh
@@ -84,10 +84,22 @@ test_expect_success \
'git-ls-tree $tree path2 >current &&
cat >expected <<\EOF &&
040000 tree X path2
-040000 tree X path2/baz
-100644 blob X path2/baz/b
-120000 blob X path2/bazbo
-100644 blob X path2/foo
+EOF
+ test_output'
+
+test_expect_success \
+ 'ls-tree filtered' \
+ 'git-ls-tree $tree path2/ >current &&
+ cat >expected <<\EOF &&
+040000 tree X path2
+EOF
+ test_output'
+
+test_expect_success \
+ 'ls-tree filtered' \
+ 'git-ls-tree $tree path2 path2 >current &&
+ cat >expected <<\EOF &&
+040000 tree X path2
EOF
test_output'
@@ -96,7 +108,16 @@ test_expect_success \
'git-ls-tree $tree path2/baz >current &&
cat >expected <<\EOF &&
040000 tree X path2/baz
-100644 blob X path2/baz/b
+EOF
+ test_output'
+
+test_expect_success \
+ 'ls-tree filtered' \
+ 'git-ls-tree $tree path2 path2/bazbo path2/baz >current &&
+ cat >expected <<\EOF &&
+040000 tree X path2
+040000 tree X path2/baz
+120000 blob X path2/bazbo
EOF
test_output'
^ permalink raw reply
* [PATCH] Fix ptrdiff_t vs. int
From: Markus F.X.J. Oberhumer @ 2005-05-27 13:20 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 313 bytes --]
This trivial patch fixes an obvious ptrdiff_t vs. int mismatch. Which
makes we wonder why Linus isn't hitting this on his ppc64 - maybe it's
time to start using -Werror...
Signed-off-by: Markus F.X.J. Oberhumer <markus@oberhumer.com>
--
Markus Oberhumer, <markus@oberhumer.com>, http://www.oberhumer.com/
[-- Attachment #2: diff-tree.c.patch --]
[-- Type: text/x-patch, Size: 598 bytes --]
This trivial patch fixes an obvious ptrdiff_t vs. int mismatch.
Signed-off-by: Markus F.X.J. Oberhumer <markus@oberhumer.com>
Index: diff-tree.c
===================================================================
--- 1348af9952a1d26b2ad14ec8f433322fd79510f3/diff-tree.c (mode:100644)
+++ 61dcf68d605a8d9204c24278dbdc73b4cf7ccc90/diff-tree.c (mode:100644)
@@ -274,7 +274,7 @@
for (cp = header; *cp; cp = ep) {
ep = strchr(cp, '\n');
if (ep == 0) ep = cp + strlen(cp);
- printf("%.*s%c", ep-cp, cp, 0);
+ printf("%.*s%c", (int) (ep-cp), cp, 0);
if (*ep) ep++;
}
}
^ permalink raw reply
* Re: [PATCH] Fix ptrdiff_t vs. int
From: Morten Welinder @ 2005-05-27 14:02 UTC (permalink / raw)
To: Markus F.X.J. Oberhumer; +Cc: git
In-Reply-To: <42971EB4.2050403@oberhumer.com>
On 5/27/05, Markus F.X.J. Oberhumer <markus@oberhumer.com> wrote:
> This trivial patch fixes an obvious ptrdiff_t vs. int mismatch. Which
> makes we wonder why Linus isn't hitting this on his ppc64 - maybe it's
> time to start using -Werror...
The best time to start using -Werror is "never". Different compilers
(and versions)
warn about different things, often affected by, say, optimization
switches. Different
system headers contain things that one compiler or another will issue a warning
over.
Thus -Werror is solely for code that needs to work on one compiler, with one set
of switches, with one libc version, and specific versions of included libraries.
It is tempting to submit a patch to the gcc people making -Werror issue a
warning about the trouble using -Werror.
Morten
^ permalink raw reply
* Re: [PATCH] Fix ptrdiff_t vs. int
From: Danjel McGougan @ 2005-05-27 13:51 UTC (permalink / raw)
To: git
In-Reply-To: <42971EB4.2050403@oberhumer.com>
Markus F.X.J. Oberhumer wrote:
> This trivial patch fixes an obvious ptrdiff_t vs. int mismatch. Which
> makes we wonder why Linus isn't hitting this on his ppc64 - maybe it's
> time to start using -Werror...
>
I think the PPC calling convention is to use registers for the first few
parameters, so the bug probably will not surface on PPC64.
/Danjel
^ permalink raw reply
* Re: [PATCH] Diff updates, fixing pathspec and rename/copy interaction.
From: Linus Torvalds @ 2005-05-27 15:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7vsm091887.fsf@assigned-by-dhcp.cox.net>
On Thu, 26 May 2005, Junio C Hamano wrote:
>
> During the mailing list discussion about diff-tree omitting to
> call diffcore-pathspec, I realized that the current rename/copy
> differentiator has a major flaw interacting with pathspec (or
> any other filepair filters, including pickaxe).
>
> The problem was that in order to tell if the rename-copy source
> still remains in the resulting tree (that is what determines if
> one of the rename-copy can become a rename or everybody needs to
> be a copy), diffcore-rename was sending a filepair that records
> unmodified source downstream, expecting that it reaches
> resolve_rename_copy() which happens as the final stage before
> actual output happens. Of course, pathspec and pickaxe can
> interfere and happily remove that entry, in which case what
> should be shown as a copy suddenly becomes a rename.
Umm.
I would much prefer a _much_ simpler fix at least for the pathname part,
which is to just always require that pathspec handling is done _first_.
Why? Because that's fundamentally how git-diff-tree has to work, and it's
how my mental model has always been: the path limitations are a
first-order filter, and if you give a directory, the end result should
always look exactly as if that directory was a project of its own.
In other words, if you limit yourself to a directory, and there was a
rename that moved a file from outside that directory into it, then it is
not a rename at all, it is a "create". The stuff outside the pathspec
limit simply doesn't exist.
This is fundamentally how git-diff-tree has to work for pathspec to make
any sense at all, and it's also the only usage that makes any sense (ie
when I say "git-whatchanged -p arch/i386 include/asm-i386", I expect that
the patches that show up _only_ concern themselves with what happened in
x86, and there's no cross-pollination with other stuff at all, even if
rename detection is enabled).
That in turn implies that the other pathspec users have to work the same
way, for the thing to be consistent.
Now, I don't know how you want pickaxe to work, and maybe you want that to
run _after_ rename detection, I dunno. So I suspect you still want to do
what this patch does, but I really don't want pathspec to be involved in
this thing..
Linus
^ permalink raw reply
* Re: Suggestion: superceded tags
From: H. Peter Anvin @ 2005-05-27 16:10 UTC (permalink / raw)
To: Stephen C. Tweedie; +Cc: Git Mailing List
In-Reply-To: <1117193179.1957.28.camel@sisko.sctweedie.blueyonder.co.uk>
Stephen C. Tweedie wrote:
> Hi,
>
> On Fri, 2005-05-27 at 06:29, H. Peter Anvin wrote:
>
>
>>When a tag is moved, a new tag object is created. This tag object will
>>have a "supercedes" header which references the old tag object.
>
> Strictly speaking, don't you need to allow multiple "supercedes" lines
> to cover all the cases? The pathological case is when you've got
> multiple trees all with different variants of the same tag name, and you
> try to merge them all at once with a multi-parent commit.
>
> Sure, tags refer to trees, not commits, so you don't necessarily have to
> do this tag resolution at commit time (indeed, since commits don't refer
> to tags, you *can't* do that resolution atomically on commit.)
>
> But if you do pull tags into the local .git/refs/tags on merge, then you
> will want to either resolve the conflict or supercede those tags, and at
> that point you've got multiple equally valid tags in the histories that
> are being superceded. Doing so is a porcelain issue, but the core will
> still need to understand tags with multiple supercedes: lines.
>
Indeed, multiple supercedes lines are useful to conver the resolution of
a tag conflict.
-hpa
^ permalink raw reply
* Re: ALSA official git repository
From: Linus Torvalds @ 2005-05-27 16:13 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: LKML, Andrew Morton, Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0505271741490.1757@pnote.perex-int.cz>
On Fri, 27 May 2005, Jaroslav Kysela wrote:
>
> I created new git tree for the ALSA project at:
>
> rsync://rsync.kernel.org/pub/scm/linux/kernel/git/perex/alsa.git
Your scripts(?) to generate these things are a bit strange, since they
leave an extra empty line in the commit message, which confuses at least
gitweb (ie just look at
http://www.kernel.org/git/?p=linux/kernel/git/perex/alsa.git;a=summary
and note how the summary thing looks empty).
Now, arguably gitweb should ignore whitespace at the beginning, but
equally arguably your commits shouldn't have them either...
Linus
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox