From 0dda1d1ec816c613c9c0fd9b55ef0d3b782b84e8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Jul 2008 13:09:47 +0200 Subject: [PATCH 01/62] Fix two leftovers from path_list->string_list In the documentation, where you cannot get compile errors for using the wrong member name, there were two mentions of 'path' left. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/technical/api-string-list.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt index 92b3ecdae2..293bb15d20 100644 --- a/Documentation/technical/api-string-list.txt +++ b/Documentation/technical/api-string-list.txt @@ -41,7 +41,7 @@ memset(&list, 0, sizeof(struct string_list)); string_list_append("foo", &list); string_list_append("bar", &list); for (i = 0; i < list.nr; i++) - printf("%s\n", list.items[i].path) + printf("%s\n", list.items[i].string) ---- NOTE: It is more efficient to build an unsorted list and sort it @@ -113,7 +113,7 @@ Data structures * `struct string_list_item` -Represents an item of the list. The `path` member is a pointer to the +Represents an item of the list. The `string` member is a pointer to the string, and you may use the `util` member for any purpose, if you want. * `struct string_list` From 8f0359f0a611fef9840218ba61162e9916124e89 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Mon, 21 Jul 2008 23:28:49 +0200 Subject: [PATCH 02/62] Allow pager of diff command be enabled/disabled See for example, status and show commands. Besides, Documentation/RelNotes-1.6.0.txt mentions that pager. can be used to enable/disable paging behavior per command. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-diff.c | 3 ++- builtin.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/builtin-diff.c b/builtin-diff.c index faaa85a1d4..7ffea97505 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -296,7 +296,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) * If the user asked for our exit code then don't start a * pager or we would end up reporting its exit code instead. */ - if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) + if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) && + check_pager_config("diff") != 0) setup_pager(); /* diff --git a/builtin.h b/builtin.h index 0e605d4f4a..f3502d305e 100644 --- a/builtin.h +++ b/builtin.h @@ -18,6 +18,7 @@ extern int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out); extern int commit_tree(const char *msg, unsigned char *tree, struct commit_list *parents, unsigned char *ret); +extern int check_pager_config(const char *cmd); extern int cmd_add(int argc, const char **argv, const char *prefix); extern int cmd_annotate(int argc, const char **argv, const char *prefix); From 2d71bde2d1a8f4e1c06cb8049a794ba4ba35d37d Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Tue, 22 Jul 2008 12:48:57 -0400 Subject: [PATCH 03/62] In perforce, RCS keywords are case-sensitive At least, this is true in 2007.2, according to the documentation. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- contrib/fast-import/git-p4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 87ca51e401..6ae0429c2d 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -906,7 +906,7 @@ class P4Sync(Command): if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text) elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): - text = re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', text) + text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', text) contents[stat['depotFile']] = text From 4d175ef71d60086b898e4d871e699794d6a93dbf Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Tue, 22 Jul 2008 19:05:59 +0200 Subject: [PATCH 04/62] t7601: extend the 'merge picks up the best result' test The test only checked if the best result picking code works if there are multiple strategies set in the config. Add a similar one that tests if the same true if the -s option of git merge was used multiple times. Signed-off-by: Miklos Vajna Signed-off-by: Junio C Hamano --- t/t7601-merge-pull-config.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index 6b9f6388c7..55aa6b5f27 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -112,6 +112,21 @@ test_expect_success 'setup conflicted merge' ' # recusive is choosen. test_expect_success 'merge picks up the best result' ' + git config --unset-all pull.twohead && + git reset --hard c5 && + git merge -s resolve c6 + resolve_count=$(conflict_count) && + git reset --hard c5 && + git merge -s recursive c6 + recursive_count=$(conflict_count) && + git reset --hard c5 && + git merge -s recursive -s resolve c6 + auto_count=$(conflict_count) && + test $auto_count = $recursive_count && + test $auto_count != $resolve_count +' + +test_expect_success 'merge picks up the best result (from config)' ' git config pull.twohead "recursive resolve" && git reset --hard c5 && git merge -s resolve c6 From 2b14d07237fb6a52a55e89dde027e40aa627789d Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Tue, 22 Jul 2008 16:17:43 -0500 Subject: [PATCH 05/62] t/: Replace diff [-u|-U0] with test_cmp to allow compilation with old diff Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- t/t0002-gitfile.sh | 2 +- t/t1002-read-tree-m-u-2way.sh | 12 ++++++------ t/t2201-add-update-typechange.sh | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index c5dbc724b6..4db4ac44c9 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -66,7 +66,7 @@ test_expect_success 'check hash-object' ' test_expect_success 'check cat-file' ' git cat-file blob $SHA >actual && - diff -u bar actual + test_cmp bar actual ' test_expect_success 'check update-index' ' diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index e04990eafd..aa9dd580a6 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -112,7 +112,7 @@ test_expect_success \ git update-index --add frotz && git read-tree -m -u $treeH $treeM && git ls-files --stage >6.out && - diff -U0 M.out 6.out && + test_cmp M.out 6.out && check_cache_at frotz clean && sum bozbar frotz nitfol >actual3.sum && cmp M.sum actual3.sum && @@ -129,7 +129,7 @@ test_expect_success \ echo frotz frotz >frotz && git read-tree -m -u $treeH $treeM && git ls-files --stage >7.out && - diff -U0 M.out 7.out && + test_cmp M.out 7.out && check_cache_at frotz dirty && sum bozbar frotz nitfol >actual7.sum && if cmp M.sum actual7.sum; then false; else :; fi && @@ -264,7 +264,7 @@ test_expect_success \ git update-index --add bozbar && git read-tree -m -u $treeH $treeM && git ls-files --stage >18.out && - diff -U0 M.out 18.out && + test_cmp M.out 18.out && check_cache_at bozbar clean && sum bozbar frotz nitfol >actual18.sum && cmp M.sum actual18.sum' @@ -278,7 +278,7 @@ test_expect_success \ echo gnusto gnusto >bozbar && git read-tree -m -u $treeH $treeM && git ls-files --stage >19.out && - diff -U0 M.out 19.out && + test_cmp M.out 19.out && check_cache_at bozbar dirty && sum frotz nitfol >actual19.sum && grep -v bozbar M.sum > expected19.sum && @@ -297,7 +297,7 @@ test_expect_success \ git update-index --add bozbar && git read-tree -m -u $treeH $treeM && git ls-files --stage >20.out && - diff -U0 M.out 20.out && + test_cmp M.out 20.out && check_cache_at bozbar clean && sum bozbar frotz nitfol >actual20.sum && cmp M.sum actual20.sum' @@ -338,7 +338,7 @@ test_expect_success \ git update-index --add DF && git read-tree -m -u $treeDF $treeDFDF && git ls-files --stage >DFDFcheck.out && - diff -U0 DFDF.out DFDFcheck.out && + test_cmp DFDF.out DFDFcheck.out && check_cache_at DF/DF clean' test_done diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index e15e3eb81b..d24c7d9e5f 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -106,12 +106,12 @@ test_expect_success modify ' test_expect_success diff-files ' git diff-files --raw >actual && - diff -u expect-files actual + test_cmp expect-files actual ' test_expect_success diff-index ' git diff-index --raw HEAD -- >actual && - diff -u expect-index actual + test_cmp expect-index actual ' test_expect_success 'add -u' ' @@ -119,7 +119,7 @@ test_expect_success 'add -u' ' cp -p ".git/index" ".git/saved-index" && git add -u && git ls-files -s >actual && - diff -u expect-final actual + test_cmp expect-final actual ' test_expect_success 'commit -a' ' @@ -130,11 +130,11 @@ test_expect_success 'commit -a' ' fi && git commit -m "second" -a && git ls-files -s >actual && - diff -u expect-final actual && + test_cmp expect-final actual && rm -f .git/index && git read-tree HEAD && git ls-files -s >actual && - diff -u expect-final actual + test_cmp expect-final actual ' test_done From 9a885fac0d530854f81eb6f4c4e19380ea041047 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Tue, 22 Jul 2008 16:16:25 -0500 Subject: [PATCH 06/62] t4116-apply-reverse.sh: use $TAR rather than tar Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- t/t4116-apply-reverse.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 1459a90716..2298ece801 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -48,12 +48,12 @@ test_expect_success 'apply in reverse' ' test_expect_success 'setup separate repository lacking postimage' ' - git tar-tree initial initial | tar xf - && + git tar-tree initial initial | $TAR xf - && ( cd initial && git init && git add . ) && - git tar-tree second second | tar xf - && + git tar-tree second second | $TAR xf - && ( cd second && git init && git add . ) From 03b9dfb18ba451a2221601b740004befa7614c5b Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Tue, 22 Jul 2008 16:16:54 -0500 Subject: [PATCH 07/62] t3200,t7201: replace '!' with test_must_fail Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- t/t3200-branch.sh | 2 +- t/t7201-co.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 7c583c8055..7a83fbfe4f 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -200,7 +200,7 @@ test_expect_success \ test_expect_success \ 'branch from non-branch HEAD w/--track causes failure' \ - '!(git branch --track my10 HEAD^)' + 'test_must_fail git branch --track my10 HEAD^' # Keep this test last, as it changes the current branch cat >expect < Date: Tue, 22 Jul 2008 16:21:10 -0500 Subject: [PATCH 08/62] t7502-commit.sh: rearrange test to make more portable Some shells have problems with one-shot environment variable export and function calls. The sequence is rearranged to avoid the one-shot and to allow the test script to be linked together with '&&'. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- t/t7502-commit.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index c25eff9e46..4f2682ea80 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -228,10 +228,12 @@ EOF test_expect_success 'a SIGTERM should break locks' ' echo >>negative && - "$SHELL_PATH" -c '\'' + ! "$SHELL_PATH" -c '\'' echo kill -TERM $$ >> .git/FAKE_EDITOR - GIT_EDITOR=.git/FAKE_EDITOR exec git commit -a'\'' && exit 1 # should fail - ! test -f .git/index.lock + GIT_EDITOR=.git/FAKE_EDITOR + export GIT_EDITOR + exec git commit -a'\'' && + test ! -f .git/index.lock ' rm -f .git/MERGE_MSG .git/COMMIT_EDITMSG From c65233fe2c14ca10da847e49b54924c9a49498c5 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Tue, 22 Jul 2008 16:23:31 -0500 Subject: [PATCH 09/62] t/t4202-log.sh: add newline at end of file Some shells hang when parsing the script if the last statement is not followed by a newline. So add one. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- t/t4202-log.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/t4202-log.sh b/t/t4202-log.sh index b53645417b..4c8af45f83 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -71,4 +71,5 @@ test_expect_success 'diff-filter=D' ' -test_done \ No newline at end of file +test_done + From 7d90c8ee15d8dcb1450d1ffc2890e5341c963598 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Jul 2008 22:41:41 +0100 Subject: [PATCH 10/62] Ignore dirty submodule states in "git pull --rebase" This is a companion patch to 6848d58c(Ignore dirty submodule states during rebase and stash). Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- git-pull.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-pull.sh b/git-pull.sh index 6afd4e2f4e..75c36100a2 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -107,9 +107,9 @@ error_on_no_merge_candidates () { } test true = "$rebase" && { - git update-index --refresh && - git diff-files --quiet && - git diff-index --cached --quiet HEAD -- || + git update-index --ignore-submodules --refresh && + git diff-files --ignore-submodules --quiet && + git diff-index --ignore-submodules --cached --quiet HEAD -- || die "refusing to pull with rebase: your working tree is not up-to-date" . git-parse-remote && From ce567d1867a02a324615079cdd4badea5d0108a6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2008 01:50:35 +0100 Subject: [PATCH 11/62] Add test to show that show-branch misses out the 8th column Noticed by Pasky. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- t/t3202-show-branch-octopus.sh | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 t/t3202-show-branch-octopus.sh diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh new file mode 100755 index 0000000000..8d50c23b84 --- /dev/null +++ b/t/t3202-show-branch-octopus.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +test_description='test show-branch with more than 8 heads' + +. ./test-lib.sh + +numbers="1 2 3 4 5 6 7 8 9 10" + +test_expect_success 'setup' ' + + > file && + git add file && + test_tick && + git commit -m initial && + + for i in $numbers + do + git checkout -b branch$i master && + > file$i && + git add file$i && + test_tick && + git commit -m branch$i || break + done + +' + +cat > expect << EOF +! [branch1] branch1 + ! [branch2] branch2 + ! [branch3] branch3 + ! [branch4] branch4 + ! [branch5] branch5 + ! [branch6] branch6 + ! [branch7] branch7 + ! [branch8] branch8 + ! [branch9] branch9 + * [branch10] branch10 +---------- + * [branch10] branch10 + + [branch9] branch9 + + [branch8] branch8 + + [branch7] branch7 + + [branch6] branch6 + + [branch5] branch5 + + [branch4] branch4 + + [branch3] branch3 + + [branch2] branch2 ++ [branch1] branch1 ++++++++++* [branch10^] initial +EOF + +test_expect_failure 'show-branch with more than 8 branches' ' + + git show-branch $(for i in $numbers; do echo branch$i; done) > out && + test_cmp expect out + +' + +test_done From e358f3c31e1ae9f653e9b2a6be69f5df53b4ba7e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2008 01:51:36 +0100 Subject: [PATCH 12/62] sort_in_topological_order(): avoid setting a commit flag We used to set the TOPOSORT flag of commits during the topological sorting, but we can just as well use the member "indegree" for it: indegree is now incremented by 1 in the cases where the commit used to have the TOPOSORT flag. This is the same behavior as before, since indegree could not be non-zero when TOPOSORT was unset. Incidentally, this fixes the bug in show-branch where the 8th column was not shown: show-branch sorts the commits in topological order, assuming that all the commit flags are available for show-branch's private matters. But this was not true: TOPOSORT was identical to the flag corresponding to the 8th ref. So the flags for the 8th column were unset by the topological sorting. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- commit.c | 13 ++++++------- revision.h | 3 +-- t/t3202-show-branch-octopus.sh | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/commit.c b/commit.c index 5148ec5527..dc0c5bfdab 100644 --- a/commit.c +++ b/commit.c @@ -436,8 +436,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) /* Mark them and clear the indegree */ for (next = orig; next; next = next->next) { struct commit *commit = next->item; - commit->object.flags |= TOPOSORT; - commit->indegree = 0; + commit->indegree = 1; } /* update the indegree */ @@ -446,7 +445,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) while (parents) { struct commit *parent = parents->item; - if (parent->object.flags & TOPOSORT) + if (parent->indegree) parent->indegree++; parents = parents->next; } @@ -464,7 +463,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) for (next = orig; next; next = next->next) { struct commit *commit = next->item; - if (!commit->indegree) + if (commit->indegree == 1) insert = &commit_list_insert(commit, insert)->next; } @@ -486,7 +485,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) for (parents = commit->parents; parents ; parents = parents->next) { struct commit *parent=parents->item; - if (!(parent->object.flags & TOPOSORT)) + if (!parent->indegree) continue; /* @@ -494,7 +493,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) * when all their children have been emitted thereby * guaranteeing topological order. */ - if (!--parent->indegree) { + if (--parent->indegree == 1) { if (!lifo) insert_by_date(parent, &work); else @@ -505,7 +504,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo) * work_item is a commit all of whose children * have already been emitted. we can emit it now. */ - commit->object.flags &= ~TOPOSORT; + commit->indegree = 0; *pptr = work_item; pptr = &work_item->next; } diff --git a/revision.h b/revision.h index fa68c65142..f64e8ce7ff 100644 --- a/revision.h +++ b/revision.h @@ -12,8 +12,7 @@ #define CHILD_SHOWN (1u<<6) #define ADDED (1u<<7) /* Parents already parsed and added? */ #define SYMMETRIC_LEFT (1u<<8) -#define TOPOSORT (1u<<9) /* In the active toposort list.. */ -#define ALL_REV_FLAGS ((1u<<10)-1) +#define ALL_REV_FLAGS ((1u<<9)-1) struct rev_info; struct log_info; diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh index 8d50c23b84..7fe4a6ecb0 100755 --- a/t/t3202-show-branch-octopus.sh +++ b/t/t3202-show-branch-octopus.sh @@ -49,7 +49,7 @@ cat > expect << EOF +++++++++* [branch10^] initial EOF -test_expect_failure 'show-branch with more than 8 branches' ' +test_expect_success 'show-branch with more than 8 branches' ' git show-branch $(for i in $numbers; do echo branch$i; done) > out && test_cmp expect out From a8ccc204c5daf4dae4071907499055d2dc9995db Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 23 Jul 2008 09:46:35 +0200 Subject: [PATCH 13/62] rebase -i: When an 'edit' stops, mention the commit In a rebase session where more than one commit is to be 'edit'ed, and the user spends considerable time to 'edit' a commit, it is easy to forget what one wanted to 'edit' at the individual commits. It would be helpful to see at which commit the rebase stopped. Incidentally, if the rebase stopped due to merge conflicts or other errors, the commit was already reported ("Could not apply $sha1..."), but when rebase stopped after successfully applying an "edit" commit, it would not mention it. With this change the commit is reported. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- git-rebase--interactive.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index e63a864c7b..4e334ba41d 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -277,7 +277,7 @@ do_next () { die_with_patch $sha1 "Could not apply $sha1... $rest" make_patch $sha1 : > "$DOTEST"/amend - warn + warn "Stopped at $sha1... $rest" warn "You can amend the commit now, with" warn warn " git commit --amend" From f5242ebf0dcd858ae9c72f39aed9773696d7283d Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 23 Jul 2008 12:15:32 +0200 Subject: [PATCH 14/62] git-checkout: fix command line parsing. This fixes an issue when you use: $ git checkout -- [...] and that can also be understood as a reference. git-checkout mistakenly understands this as the same as: $ git checkout -- [...] because parse-options was eating the '--' and the argument parser thought he was parsing: $ git checkout [...] Where there indeed is an ambiguity Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-checkout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index 93ea69bfaa..aec2bc6f8d 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -520,7 +520,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.track = git_branch_track; - argc = parse_options(argc, argv, options, checkout_usage, 0); + argc = parse_options(argc, argv, options, checkout_usage, + PARSE_OPT_KEEP_DASHDASH); if (argc) { arg = argv[0]; if (get_sha1(arg, rev)) From c8fe1980b2b8e5c61f05a59d3bf9dedd5afa8faa Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Wed, 23 Jul 2008 18:46:36 +0200 Subject: [PATCH 15/62] git-am: Add colon before the subject that is printed out as being applied git-am output can be confusing, because the subject of the applied patch can look like the rest of a sentence starting with "Applying". The added colon should make this clearer. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- git-am.sh | 2 +- t/t4151-am-abort.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/git-am.sh b/git-am.sh index 7864b5f588..f4abd9db15 100755 --- a/git-am.sh +++ b/git-am.sh @@ -456,7 +456,7 @@ do stop_here $this fi - printf 'Applying %s\n' "$FIRSTLINE" + printf 'Applying: %s\n' "$FIRSTLINE" case "$resolved" in '') diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index 249093b6d0..f45ab0a2e8 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -43,7 +43,7 @@ do test_expect_success "am$with3 --skip continue after failed am$with3" ' test_must_fail git-am$with3 --skip >output && - test "$(grep "^Applying" output)" = "Applying 6" && + test "$(grep "^Applying" output)" = "Applying: 6" && test_cmp file-2-expect file-2 && test ! -f .git/rr-cache/MERGE_RR ' From 47629dcff0fc75d58f9319d221a78934358e4ef8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 23 Jul 2008 13:33:44 -0700 Subject: [PATCH 16/62] stash save: fix parameter handling A command line "git stash save --keep-index I was doing this" was misparsed and keep-index codepath did not trigger. Signed-off-by: Junio C Hamano --- git-stash.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-stash.sh b/git-stash.sh index e4cb6c3e4b..d4609ed66e 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -93,7 +93,7 @@ save_stash () { shift esac - stash_msg="$1" + stash_msg="$*" if no_changes then @@ -267,7 +267,7 @@ show) ;; save) shift - save_stash "$*" + save_stash "$@" ;; apply) shift From 0f31d68030752b0c1e02a1a092c18094a98202f0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 23 Jul 2008 14:52:47 -0700 Subject: [PATCH 17/62] builtin-branch.c: remove unused code in append_ref() callback function We let for_each_ref() to feed all refs to append_ref() but we are only ever interested in local or remote tracking branches. Signed-off-by: Junio C Hamano --- builtin-branch.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index b885bd132b..3708a50ebe 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -22,10 +22,8 @@ static const char * const builtin_branch_usage[] = { NULL }; -#define REF_UNKNOWN_TYPE 0x00 #define REF_LOCAL_BRANCH 0x01 #define REF_REMOTE_BRANCH 0x02 -#define REF_TAG 0x04 static const char *head; static unsigned char head_sha1[20]; @@ -215,7 +213,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, { struct ref_list *ref_list = (struct ref_list*)(cb_data); struct ref_item *newitem; - int kind = REF_UNKNOWN_TYPE; + int kind; int len; static struct commit_list branch; @@ -226,10 +224,8 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, } else if (!prefixcmp(refname, "refs/remotes/")) { kind = REF_REMOTE_BRANCH; refname += 13; - } else if (!prefixcmp(refname, "refs/tags/")) { - kind = REF_TAG; - refname += 10; - } + } else + return 0; /* Filter with with_commit if specified */ if (!has_commit(sha1, ref_list->with_commit)) From 68067ca1efcbb0408b931e08654a5e32de975ced Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 23 Jul 2008 15:13:41 -0700 Subject: [PATCH 18/62] builtin-branch.c: optimize --merged and --no-merged "git branch --no-merged $commit" used to compute the merge base between the tip of each and every branch with the named $commit, but this was wasteful when you have many branches. Inside append_ref() we literally ran has_commit() between the tip of the branch and the merge_filter_ref. Instead, we can let the revision machinery traverse the history as if we are running: $ git rev-list --branches --not $commit by queueing the tips of branches we encounter as positive refs (this mimicks the "--branches" option in the above command line) and then appending the merge_filter_ref commit as a negative one, and finally calling prepare_revision_walk() to limit the list.. After the traversal is done, branch tips that are reachable from $commit are painted UNINTERESTING; they are already fully contained in $commit (i.e. --merged). Tips that are not painted UNINTERESTING still have commits that are not reachable from $commit, thus "--no-merged" will show them. With an artificial repository that has "master" and 1000 test-$i branches where they were created by "git branch test-$i master~$i": (with patch) $ /usr/bin/time git-branch --no-merged master >/dev/null 0.12user 0.02system 0:00.15elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+1588minor)pagefaults 0swaps $ /usr/bin/time git-branch --no-merged test-200 >/dev/null 0.15user 0.03system 0:00.18elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+1711minor)pagefaults 0swaps (without patch) $ /usr/bin/time git-branch --no-merged master >/dev/null 0.69user 0.03system 0:00.72elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+2229minor)pagefaults 0swaps $ /usr/bin/time git-branch --no-merged test-200 >/dev/null 0.58user 0.03system 0:00.61elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+2248minor)pagefaults 0swaps Signed-off-by: Junio C Hamano --- builtin-branch.c | 59 +++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 3708a50ebe..5db8ad836a 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -13,6 +13,8 @@ #include "remote.h" #include "parse-options.h" #include "branch.h" +#include "diff.h" +#include "revision.h" static const char * const builtin_branch_usage[] = { "git branch [options] [-r | -a] [--merged | --no-merged]", @@ -179,25 +181,21 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) struct ref_item { char *name; unsigned int kind; - unsigned char sha1[20]; + struct commit *commit; }; struct ref_list { + struct rev_info revs; int index, alloc, maxwidth; struct ref_item *list; struct commit_list *with_commit; int kinds; }; -static int has_commit(const unsigned char *sha1, struct commit_list *with_commit) +static int has_commit(struct commit *commit, struct commit_list *with_commit) { - struct commit *commit; - if (!with_commit) return 1; - commit = lookup_commit_reference_gently(sha1, 1); - if (!commit) - return 0; while (with_commit) { struct commit *other; @@ -213,6 +211,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, { struct ref_list *ref_list = (struct ref_list*)(cb_data); struct ref_item *newitem; + struct commit *commit; int kind; int len; static struct commit_list branch; @@ -227,8 +226,12 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, } else return 0; + commit = lookup_commit_reference_gently(sha1, 1); + if (!commit) + return error("branch '%s' does not point at a commit", refname); + /* Filter with with_commit if specified */ - if (!has_commit(sha1, ref_list->with_commit)) + if (!has_commit(commit, ref_list->with_commit)) return 0; /* Don't add types the caller doesn't want */ @@ -239,12 +242,8 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, branch.item = lookup_commit_reference_gently(sha1, 1); if (!branch.item) die("Unable to lookup tip of branch %s", refname); - if (merge_filter == SHOW_NOT_MERGED && - has_commit(merge_filter_ref, &branch)) - return 0; - if (merge_filter == SHOW_MERGED && - !has_commit(merge_filter_ref, &branch)) - return 0; + add_pending_object(&ref_list->revs, + (struct object *)branch.item, refname); } /* Resize buffer */ @@ -258,7 +257,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, newitem = &(ref_list->list[ref_list->index++]); newitem->name = xstrdup(refname); newitem->kind = kind; - hashcpy(newitem->sha1, sha1); + newitem->commit = commit; len = strlen(newitem->name); if (len > ref_list->maxwidth) ref_list->maxwidth = len; @@ -305,7 +304,13 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, { char c; int color; - struct commit *commit; + struct commit *commit = item->commit; + + if (merge_filter != NO_FILTER) { + int is_merged = !!(item->commit->object.flags & UNINTERESTING); + if (is_merged != (merge_filter == SHOW_MERGED)) + return; + } switch (item->kind) { case REF_LOCAL_BRANCH: @@ -333,7 +338,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, strbuf_init(&subject, 0); stat[0] = '\0'; - commit = lookup_commit(item->sha1); + commit = item->commit; if (commit && !parse_commit(commit)) { pretty_print_commit(CMIT_FMT_ONELINE, commit, &subject, 0, NULL, NULL, 0, 0); @@ -346,7 +351,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, printf("%c %s%-*s%s %s %s%s\n", c, branch_get_color(color), maxwidth, item->name, branch_get_color(COLOR_BRANCH_RESET), - find_unique_abbrev(item->sha1, abbrev), + find_unique_abbrev(item->commit->object.sha1, abbrev), stat, sub); strbuf_release(&subject); } else { @@ -359,22 +364,34 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str { int i; struct ref_list ref_list; + struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; ref_list.with_commit = with_commit; + if (merge_filter != NO_FILTER) + init_revisions(&ref_list.revs, NULL); for_each_ref(append_ref, &ref_list); + if (merge_filter != NO_FILTER) { + struct commit *filter; + filter = lookup_commit_reference_gently(merge_filter_ref, 0); + filter->object.flags |= UNINTERESTING; + add_pending_object(&ref_list.revs, + (struct object *) filter, ""); + ref_list.revs.limited = 1; + prepare_revision_walk(&ref_list.revs); + } qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); detached = (detached && (kinds & REF_LOCAL_BRANCH)); - if (detached && has_commit(head_sha1, with_commit)) { + if (detached && head_commit && has_commit(head_commit, with_commit)) { struct ref_item item; item.name = xstrdup("(no branch)"); item.kind = REF_LOCAL_BRANCH; - hashcpy(item.sha1, head_sha1); + item.commit = head_commit; if (strlen(item.name) > ref_list.maxwidth) - ref_list.maxwidth = strlen(item.name); + ref_list.maxwidth = strlen(item.name); print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1); free(item.name); } From a4661b018d46699fd6a9f59932e60267bae3ca2a Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Thu, 24 Jul 2008 00:15:36 +0200 Subject: [PATCH 19/62] git-filter-branch.sh: Allow running in bare repositories Commit 46eb449c restricted git-filter-branch to non-bare repositories unnecessarily; git-filter-branch can work on bare repositories just fine. Cc: Johannes Schindelin Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- git-filter-branch.sh | 32 ++++++++++++++++++-------------- t/t7003-filter-branch.sh | 8 ++++++++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index d04c346e12..182822a24e 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -97,9 +97,11 @@ USAGE="[--env-filter ] [--tree-filter ] \ OPTIONS_SPEC= . git-sh-setup -git diff-files --quiet && +if [ "$(is_bare_repository)" = false ]; then + git diff-files --quiet && git diff-index --cached --quiet HEAD -- || die "Cannot rewrite branch(es) with a dirty working directory." +fi tempdir=.git-rewrite filter_env= @@ -434,18 +436,20 @@ rm -rf "$tempdir" trap - 0 -unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE -test -z "$ORIG_GIT_DIR" || { - GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR -} -test -z "$ORIG_GIT_WORK_TREE" || { - GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" && - export GIT_WORK_TREE -} -test -z "$ORIG_GIT_INDEX_FILE" || { - GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" && - export GIT_INDEX_FILE -} -git read-tree -u -m HEAD +if [ "$(is_bare_repository)" = false ]; then + unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE + test -z "$ORIG_GIT_DIR" || { + GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR + } + test -z "$ORIG_GIT_WORK_TREE" || { + GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" && + export GIT_WORK_TREE + } + test -z "$ORIG_GIT_INDEX_FILE" || { + GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" && + export GIT_INDEX_FILE + } + git read-tree -u -m HEAD +fi exit $ret diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index e26f726930..a0ab096c8f 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -38,6 +38,14 @@ test_expect_success 'result is really identical' ' test $H = $(git rev-parse HEAD) ' +test_expect_success 'rewrite bare repository identically' ' + (git config core.bare true && cd .git && git-filter-branch branch) +' +git config core.bare false +test_expect_success 'result is really identical' ' + test $H = $(git rev-parse HEAD) +' + test_expect_success 'rewrite, renaming a specific file' ' git-filter-branch -f --tree-filter "mv d doh || :" HEAD ' From a31c00b00eeadbc4b87ce2d578688e9b369a50fe Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Wed, 23 Jul 2008 02:10:25 +0200 Subject: [PATCH 20/62] am --abort: Add to bash-completion and mention in git-rerere documentation The git-rerere documentation talks about commands that invoke "git rerere clear" automatically. git am --abort is added and a typo is fixed additionally. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- Documentation/git-rerere.txt | 2 +- contrib/completion/git-completion.bash | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt index beebd5301f..89f321b414 100644 --- a/Documentation/git-rerere.txt +++ b/Documentation/git-rerere.txt @@ -37,7 +37,7 @@ its working state. 'clear':: This resets the metadata used by rerere if a merge resolution is to be -is aborted. Calling 'git-am --skip' or 'git-rebase [--skip|--abort]' +aborted. Calling 'git-am [--skip|--abort]' or 'git-rebase [--skip|--abort]' will automatically invoke this command. 'diff':: diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2edb341b57..8fc9145282 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -489,7 +489,7 @@ _git_am () { local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)" if [ -d "$dir"/rebase-apply ]; then - __gitcomp "--skip --resolved" + __gitcomp "--skip --resolved --abort" return fi case "$cur" in From ea3d988df7b0985fa164c7ace13e4c961c607a22 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 23 Jul 2008 16:16:05 -0700 Subject: [PATCH 21/62] Documentation: clarify diff --cc The definition of an "uninteresting" hunk was not in line with reality. Signed-off-by: Junio C Hamano --- Documentation/git-diff-tree.txt | 10 +++++----- Documentation/rev-list-options.txt | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index 0e45b58d83..8c8f35b7a7 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -93,11 +93,11 @@ include::pretty-options.txt[] This flag changes the way a merge commit patch is displayed, in a similar way to the '-c' option. It implies the '-c' and '-p' options and further compresses the patch output - by omitting hunks that show differences from only one - parent, or show the same change from all but one parent - for an Octopus merge. When this optimization makes all - hunks disappear, the commit itself and the commit log - message is not shown, just like in any other "empty diff" case. + by omitting uninteresting hunks whose the contents in the parents + have only two variants and the merge result picks one of them + without modification. When all hunks are uninteresting, the commit + itself and the commit log message is not shown, just like in any other + "empty diff" case. --always:: Show the commit itself and the commit log message even diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index b6f5d87e72..3aa38097e6 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -112,9 +112,9 @@ options may be given. See linkgit:git-diff-files[1] for more options. --cc:: This flag implies the '-c' options and further compresses the - patch output by omitting hunks that show differences from only - one parent, or show the same change from all but one parent for - an Octopus merge. + patch output by omitting uninteresting hunks whose contents in + the parents have only two variants and the merge result picks + one of them without modification. -r:: From 3b6aeb3cc37c8ef934850fb01e1de48e12cf3aac Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Jul 2008 21:40:41 +0100 Subject: [PATCH 22/62] builtin-commit: Two trivial style-cleanups Pierre Habouzit noticed that two variables were not static which should have been, and that adding "\n\n" is better than adding '\n' twice. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 97e64de312..7434797d1b 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -68,8 +68,8 @@ static enum { static char *cleanup_arg; static int use_editor = 1, initial_commit, in_merge; -const char *only_include_assumed; -struct strbuf message; +static const char *only_include_assumed; +static struct strbuf message; static int opt_parse_m(const struct option *opt, const char *arg, int unset) { @@ -78,8 +78,7 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset) strbuf_setlen(buf, 0); else { strbuf_addstr(buf, arg); - strbuf_addch(buf, '\n'); - strbuf_addch(buf, '\n'); + strbuf_addstr(buf, "\n\n"); } return 0; } From f9bbefc701e319983bb8e13df8d615293c6f386a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Jul 2008 23:03:01 +0100 Subject: [PATCH 23/62] git daemon: avoid waking up too often To avoid waking up unnecessarily, a pipe is set up that is only ever written to by child_handler(), when a child disconnects, as suggested per Junio. This avoids waking up the main process every second to see if a child was disconnected. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- daemon.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/daemon.c b/daemon.c index 7df41a6a49..4540e8df5a 100644 --- a/daemon.c +++ b/daemon.c @@ -16,6 +16,7 @@ static int log_syslog; static int verbose; static int reuseaddr; +static int child_handler_pipe[2]; static const char daemon_usage[] = "git daemon [--verbose] [--syslog] [--export-all]\n" @@ -788,6 +789,7 @@ static void child_handler(int signo) pid = -pid; dead_child[reaped % MAX_CHILDREN] = pid; children_reaped = reaped + 1; + write(child_handler_pipe[1], &status, 1); continue; } break; @@ -933,29 +935,24 @@ static int service_loop(int socknum, int *socklist) struct pollfd *pfd; int i; - pfd = xcalloc(socknum, sizeof(struct pollfd)); + if (pipe(child_handler_pipe) < 0) + die ("Could not set up pipe for child handler"); + + pfd = xcalloc(socknum + 1, sizeof(struct pollfd)); for (i = 0; i < socknum; i++) { pfd[i].fd = socklist[i]; pfd[i].events = POLLIN; } + pfd[socknum].fd = child_handler_pipe[0]; + pfd[socknum].events = POLLIN; signal(SIGCHLD, child_handler); for (;;) { int i; - int timeout; - /* - * This 1-sec timeout could lead to idly looping but it is - * here so that children culled in child_handler() are reported - * without too much delay. We could probably set up a pipe - * to ourselves that we poll, and write to the fd from child_handler() - * to wake us up (and consume it when the poll() returns... - */ - timeout = (children_spawned != children_deleted) ? 1000 : -1; - i = poll(pfd, socknum, timeout); - if (i < 0) { + if (poll(pfd, socknum + 1, -1) < 0) { if (errno != EINTR) { error("poll failed, resuming: %s", strerror(errno)); @@ -963,9 +960,9 @@ static int service_loop(int socknum, int *socklist) } continue; } - if (i == 0) { + if (pfd[socknum].revents & POLLIN) { + read(child_handler_pipe[0], &i, 1); check_dead_children(); - continue; } for (i = 0; i < socknum; i++) { From eb72a51407228c8c7947e762d4f1c320712c9052 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Wed, 23 Jul 2008 00:24:35 +0200 Subject: [PATCH 24/62] Documentation/git-filter-branch: teach "rm" instead of "update-index --remove" The example to remove paths using index-filter was done with "git update-index --remove"; "git rm --cached" would be more familiar to new people and is sufficient for this particular case. Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/git-filter-branch.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index a3edc00246..7ba9dab5e6 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -191,7 +191,7 @@ Thus you may instead want to use `rm -f filename` as the script. A significantly faster version: -------------------------------------------------------------------------- -git filter-branch --index-filter 'git update-index --remove filename' HEAD +git filter-branch --index-filter 'git rm --cached filename' HEAD -------------------------------------------------------------------------- Now, you will get the rewritten history saved in HEAD. From e8a43a132d97165f6e56fa03923a3933cfedde81 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Wed, 23 Jul 2008 23:08:27 +0300 Subject: [PATCH 25/62] svnimport: newer libsvn wants us to ask for the root with "", not "/" In r27729, libsvn introduced an assert which explicitly forbids searching the tree at "/". Luckily enough, it still accepts an empty string "" as the starting point. http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_ra/ra_loader.c?r1=27653&r2=27729 Tested against libsvn0-1.5.0-4mdv2009.0 (needs the fix), libsvn0-1.4.6-5mdv2008.1 (works anyway) Signed-off-by: P. Christeas Signed-off-by: Junio C Hamano --- contrib/examples/git-svnimport.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/examples/git-svnimport.perl b/contrib/examples/git-svnimport.perl index ea8c1b2f60..a13bb6afec 100755 --- a/contrib/examples/git-svnimport.perl +++ b/contrib/examples/git-svnimport.perl @@ -933,7 +933,7 @@ while ($to_rev < $opt_l) { $to_rev = $from_rev + $repack_after; $to_rev = $opt_l if $opt_l < $to_rev; print "Fetching from $from_rev to $to_rev ...\n" if $opt_v; - $svn->{'svn'}->get_log("/",$from_rev,$to_rev,0,1,1,\&commit_all); + $svn->{'svn'}->get_log("",$from_rev,$to_rev,0,1,1,\&commit_all); my $pid = fork(); die "Fork: $!\n" unless defined $pid; unless($pid) { From 08c701d4761abf58dce607e84bf41fb280e38a9e Mon Sep 17 00:00:00 2001 From: Lee Marlow Date: Wed, 23 Jul 2008 15:21:08 -0600 Subject: [PATCH 26/62] bash completion: Add long options for 'git rm' Options added: --cached --dry-run --ignore-unmatch --quiet Signed-off-by: Lee Marlow Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 8fc9145282..e20d57a1ba 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1170,6 +1170,20 @@ _git_reset () __gitcomp "$(__git_refs)" } +_git_rm () +{ + __git_has_doubledash && return + + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --*) + __gitcomp "--cached --dry-run --ignore-unmatch --quiet" + return + ;; + esac + COMPREPLY=() +} + _git_shortlog () { __git_has_doubledash && return @@ -1425,6 +1439,7 @@ _git () rebase) _git_rebase ;; remote) _git_remote ;; reset) _git_reset ;; + rm) _git_rm ;; send-email) _git_send_email ;; shortlog) _git_shortlog ;; show) _git_show ;; From 2ca880fe54660869bc93a2302efced9ab64511d9 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Wed, 23 Jul 2008 23:36:15 +0200 Subject: [PATCH 27/62] git-completion.bash: provide completion for 'show-branch' It previously used the same as 'log', but the options are quite different and the arguments must be single refs (or globs). Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e20d57a1ba..3b049348c3 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1224,6 +1224,22 @@ _git_show () __git_complete_file } +_git_show_branch () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --*) + __gitcomp " + --all --remotes --topo-order --current --more= + --list --independent --merge-base --no-name + --sha1-name --topics --reflog + " + return + ;; + esac + __git_complete_revlist +} + _git_stash () { local subcommands='save list show apply clear drop pop create' @@ -1443,7 +1459,7 @@ _git () send-email) _git_send_email ;; shortlog) _git_shortlog ;; show) _git_show ;; - show-branch) _git_log ;; + show-branch) _git_show_branch ;; stash) _git_stash ;; submodule) _git_submodule ;; svn) _git_svn ;; From 0c4cd7f4a7aae5527560090aad7ef8dae85f1264 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 23 Jul 2008 17:22:58 -0700 Subject: [PATCH 28/62] ignore non-existent refs in dwim_log() f2eba66 (Enable HEAD@{...} and make it independent from the current branch, 2007-02-03) introduced dwim_log() to handle @{...} syntax, and as part of its processing, it checks if the ref exists by calling refsolve_ref(). It should call it as a reader to make sure the call returns NULL for a nonexistent ref (not as a potential writer in which case it does not return NULL). Signed-off-by: Junio C Hamano --- sha1_name.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sha1_name.c b/sha1_name.c index b0b2167578..4fb77f8863 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -273,7 +273,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) const char *ref, *it; strcpy(path, mkpath(*p, len, str)); - ref = resolve_ref(path, hash, 0, NULL); + ref = resolve_ref(path, hash, 1, NULL); if (!ref) continue; if (!stat(git_path("logs/%s", path), &st) && From 186458b11b090835fa793bcdbf6b5552b053276c Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Thu, 24 Jul 2008 01:09:35 +0200 Subject: [PATCH 29/62] Make non-static functions, that may be static, static Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- builtin-config.c | 2 +- builtin-for-each-ref.c | 2 +- builtin-merge.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 7434797d1b..6a9dc0e30f 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -876,7 +876,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) } } -int git_commit_config(const char *k, const char *v, void *cb) +static int git_commit_config(const char *k, const char *v, void *cb) { if (!strcmp(k, "commit.template")) return git_config_string(&template_file, k, v); diff --git a/builtin-config.c b/builtin-config.c index 0cf191a112..91fdc4985d 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -145,7 +145,7 @@ free_strings: return ret; } -char *normalize_value(const char *key, const char *value) +static char *normalize_value(const char *key, const char *value) { char *normalized; diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 76282ad791..445039e19c 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -809,7 +809,7 @@ static struct ref_sort *default_sort(void) return sort; } -int opt_parse_sort(const struct option *opt, const char *arg, int unset) +static int opt_parse_sort(const struct option *opt, const char *arg, int unset) { struct ref_sort **sort_tail = opt->value; struct ref_sort *s; diff --git a/builtin-merge.c b/builtin-merge.c index 8825dcf8d9..e78fa18b3a 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -431,7 +431,7 @@ static void merge_name(const char *remote, struct strbuf *msg) sha1_to_hex(remote_head->sha1), remote); } -int git_merge_config(const char *k, const char *v, void *cb) +static int git_merge_config(const char *k, const char *v, void *cb) { if (branch && !prefixcmp(k, "branch.") && !prefixcmp(k + 7, branch) && From 0e8316cc16f1a938c36f12f5fcae4a081b6ec6ff Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 24 Jul 2008 17:41:12 -0500 Subject: [PATCH 30/62] Teach fsck and prune about the new location of temporary objects Since 5723fe7e, temporary objects are now created in their final destination directories, rather than in .git/objects/. Teach fsck to recognize and ignore the temporary objects it encounters, and teach prune to remove them. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- builtin-fsck.c | 4 ++++ builtin-prune.c | 41 ++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/builtin-fsck.c b/builtin-fsck.c index 7326dc33a5..7a4a4f144f 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -377,6 +377,10 @@ static void fsck_dir(int i, char *path) if (de->d_name[0] != '.') break; continue; + case 14: + if (prefixcmp(de->d_name, "tmp_obj_")) + break; + continue; case 38: sprintf(name, "%02x", i); memcpy(name+2, de->d_name, len+1); diff --git a/builtin-prune.c b/builtin-prune.c index 7de4cabe07..947de8cf25 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -13,6 +13,22 @@ static const char * const prune_usage[] = { static int show_only; static unsigned long expire; +static int prune_tmp_object(char *path, const char *filename) +{ + const char *fullpath = mkpath("%s/%s", path, filename); + if (expire) { + struct stat st; + if (lstat(fullpath, &st)) + return error("Could not stat '%s'", fullpath); + if (st.st_mtime > expire) + return 0; + } + printf("Removing stale temporary file %s\n", fullpath); + if (!show_only) + unlink(fullpath); + return 0; +} + static int prune_object(char *path, const char *filename, const unsigned char *sha1) { const char *fullpath = mkpath("%s/%s", path, filename); @@ -53,6 +69,11 @@ static int prune_dir(int i, char *path) if (de->d_name[0] != '.') break; continue; + case 14: + if (prefixcmp(de->d_name, "tmp_obj_")) + break; + prune_tmp_object(path, de->d_name); + continue; case 38: sprintf(name, "%02x", i); memcpy(name+2, de->d_name, len+1); @@ -105,23 +126,9 @@ static void remove_temporary_files(void) dirname); return; } - while ((de = readdir(dir)) != NULL) { - if (!prefixcmp(de->d_name, "tmp_")) { - char name[PATH_MAX]; - int c = snprintf(name, PATH_MAX, "%s/%s", - dirname, de->d_name); - if (c < 0 || c >= PATH_MAX) - continue; - if (expire) { - struct stat st; - if (stat(name, &st) != 0 || st.st_mtime >= expire) - continue; - } - printf("Removing stale temporary file %s\n", name); - if (!show_only) - unlink(name); - } - } + while ((de = readdir(dir)) != NULL) + if (!prefixcmp(de->d_name, "tmp_")) + prune_tmp_object(dirname, de->d_name); closedir(dir); } From 9944d1a0e4ce741b07248b95fff2f506b5f1729c Mon Sep 17 00:00:00 2001 From: Olivier Marin Date: Thu, 24 Jul 2008 14:44:40 +0200 Subject: [PATCH 31/62] update test case to protect am --skip behaviour Signed-off-by: Olivier Marin Signed-off-by: Junio C Hamano --- t/t4151-am-abort.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index f45ab0a2e8..7d86cdff64 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -17,6 +17,8 @@ test_expect_success setup ' for i in 2 3 4 5 6 do echo $i >>file-1 && + echo $i >otherfile-$i && + git add otherfile-$i && test_tick && git commit -a -m $i || break done && From 859fdabaede6733c98b1ca8df2fabce000522bf9 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Wed, 23 Jul 2008 12:15:33 +0200 Subject: [PATCH 32/62] git-checkout: improve error messages, detect ambiguities. The patch is twofold: it moves the option consistency checks just under the parse_options call so that it doesn't get in the way of the tree reference vs. pathspecs desambiguation. The other part rewrites the way to understand arguments so that when git-checkout fails it does with an understandable message. Compared to the previous behavior we now have: - a better error message when doing: git checkout -- now complains about the reference not pointing to a tree, instead of things like: error: pathspec did not match any file(s) known to git. error: pathspec '--' did not match any file(s) known to git. - a better error message when doing: git checkout -- It now complains about not being a reference instead of the completely obscure: error: pathspec '--' did not match any file(s) known to git. - an error when -- wasn't used, and the first argument is ambiguous (i.e. can be interpreted as both ref and as path). Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-checkout.c | 82 +++++++++++++++++++++++++++-------- t/t2010-checkout-ambiguous.sh | 50 +++++++++++++++++++++ 2 files changed, 115 insertions(+), 17 deletions(-) create mode 100755 t/t2010-checkout-ambiguous.sh diff --git a/builtin-checkout.c b/builtin-checkout.c index 9cadf9c299..411cc513c6 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -430,6 +430,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) OPT_BOOLEAN('m', NULL, &opts.merge, "merge"), OPT_END(), }; + int has_dash_dash; memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); @@ -440,11 +441,55 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, options, checkout_usage, PARSE_OPT_KEEP_DASHDASH); + + if (!opts.new_branch && (opts.track != git_branch_track)) + die("git checkout: --track and --no-track require -b"); + + if (opts.force && opts.merge) + die("git checkout: -f and -m are incompatible"); + + /* + * case 1: git checkout -- [] + * + * must be a valid tree, everything after the '--' must be + * a path. + * + * case 2: git checkout -- [] + * + * everything after the '--' must be paths. + * + * case 3: git checkout [] + * + * With no paths, if is a commit, that is to + * switch to the branch or detach HEAD at it. + * + * Otherwise shall not be ambiguous. + * - If it's *only* a reference, treat it like case (1). + * - If it's only a path, treat it like case (2). + * - else: fail. + * + */ if (argc) { + if (!strcmp(argv[0], "--")) { /* case (2) */ + argv++; + argc--; + goto no_reference; + } + arg = argv[0]; - if (get_sha1(arg, rev)) - ; - else if ((new.commit = lookup_commit_reference_gently(rev, 1))) { + has_dash_dash = (argc > 1) && !strcmp(argv[1], "--"); + + if (get_sha1(arg, rev)) { + if (has_dash_dash) /* case (1) */ + die("invalid reference: %s", arg); + goto no_reference; /* case (3 -> 2) */ + } + + /* we can't end up being in (2) anymore, eat the argument */ + argv++; + argc--; + + if ((new.commit = lookup_commit_reference_gently(rev, 1))) { new.name = arg; setup_branch_path(&new); if (resolve_ref(new.path, rev, 1, NULL)) @@ -453,25 +498,28 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) new.path = NULL; parse_commit(new.commit); source_tree = new.commit->tree; - argv++; - argc--; - } else if ((source_tree = parse_tree_indirect(rev))) { + } else + source_tree = parse_tree_indirect(rev); + + if (!source_tree) /* case (1): want a tree */ + die("reference is not a tree: %s", arg); + if (!has_dash_dash) {/* case (3 -> 1) */ + /* + * Do not complain the most common case + * git checkout branch + * even if there happen to be a file called 'branch'; + * it would be extremely annoying. + */ + if (argc) + verify_non_filename(NULL, arg); + } + else { argv++; argc--; } } - if (argc && !strcmp(argv[0], "--")) { - argv++; - argc--; - } - - if (!opts.new_branch && (opts.track != git_branch_track)) - die("git checkout: --track and --no-track require -b"); - - if (opts.force && opts.merge) - die("git checkout: -f and -m are incompatible"); - +no_reference: if (argc) { const char **pathspec = get_pathspec(prefix, argv); diff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh new file mode 100755 index 0000000000..7cc0a3582e --- /dev/null +++ b/t/t2010-checkout-ambiguous.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='checkout and pathspecs/refspecs ambiguities' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo hello >world && + echo hello >all && + git add all world && + git commit -m initial && + git branch world +' + +test_expect_success 'reference must be a tree' ' + test_must_fail git checkout $(git hash-object ./all) -- +' + +test_expect_success 'branch switching' ' + test "refs/heads/master" = "$(git symbolic-ref HEAD)" && + git checkout world -- && + test "refs/heads/world" = "$(git symbolic-ref HEAD)" +' + +test_expect_success 'checkout world from the index' ' + echo bye > world && + git checkout -- world && + git diff --exit-code --quiet +' + +test_expect_success 'non ambiguous call' ' + git checkout all +' + +test_expect_success 'allow the most common case' ' + git checkout world && + test "refs/heads/world" = "$(git symbolic-ref HEAD)" +' + +test_expect_success 'check ambiguity' ' + test_must_fail git checkout world all +' + +test_expect_success 'disambiguate checking out from a tree-ish' ' + echo bye > world && + git checkout world -- world && + git diff --exit-code --quiet +' + +test_done From b302ddd2f8de2944ed3425d48b1a640fab004d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Wed, 23 Jul 2008 13:49:21 +0200 Subject: [PATCH 33/62] checkout: mention '--' in the docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'git checkout' uses '--' to separate options from paths, but it was not mentioned in the documentation Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- Documentation/git-checkout.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 2abfbdaadb..5aa69c0e12 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git checkout' [-q] [-f] [[--track | --no-track] -b [-l]] [-m] [] -'git checkout' [] ... +'git checkout' [] [--] ... DESCRIPTION ----------- From c84bb14ce52b6559e0b8e10d554ff9b47149c042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Wed, 23 Jul 2008 13:49:22 +0200 Subject: [PATCH 34/62] bash: offer only paths after '--' for 'git checkout' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit d773c631 (bash: offer only paths after '--', 2008-07-08) did the same for several other git commands, but 'git checkout' went unnoticed. Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 3b049348c3..40b3d99737 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -626,6 +626,8 @@ _git_bundle () _git_checkout () { + __git_has_doubledash && return + __gitcomp "$(__git_refs)" } From 058fb414804d545cc7dcca1313078d6a7e7bbd37 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Tue, 22 Jul 2008 16:15:41 -0500 Subject: [PATCH 35/62] perl/Makefile: update NO_PERL_MAKEMAKER section The perl modules must be copied to blib/lib so they are available for testing. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- perl/Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/perl/Makefile b/perl/Makefile index 5e079ad011..b8547db2c6 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -22,13 +22,18 @@ clean: ifdef NO_PERL_MAKEMAKER instdir_SQ = $(subst ','\'',$(prefix)/lib) $(makfile): ../GIT-CFLAGS Makefile - echo all: > $@ - echo ' :' >> $@ + echo all: private-Error.pm Git.pm > $@ + echo ' mkdir -p blib/lib' >> $@ + echo ' $(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@ + echo ' $(RM) blib/lib/Error.pm' >> $@ + '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \ + echo ' cp private-Error.pm blib/lib/Error.pm' >> $@ echo install: >> $@ echo ' mkdir -p $(instdir_SQ)' >> $@ echo ' $(RM) $(instdir_SQ)/Git.pm; cp Git.pm $(instdir_SQ)' >> $@ - echo ' $(RM) $(instdir_SQ)/Error.pm; \ - cp private-Error.pm $(instdir_SQ)/Error.pm' >> $@ + echo ' $(RM) $(instdir_SQ)/Error.pm' >> $@ + '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \ + echo ' cp private-Error.pm $(instdir_SQ)/Error.pm' >> $@ echo instlibdir: >> $@ echo ' echo $(instdir_SQ)' >> $@ else From a2d07d80ec9dfff0e51cac534be7c1642a47f8fb Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Thu, 24 Jul 2008 11:55:25 -0500 Subject: [PATCH 36/62] document that git-tag can tag more than heads After looking the git-tag manpage, someone on #git wondered how to tag a commit that is not a branch head. This patch changes the synopsis to say " | " instead of "" to address his question. Samuel Bronson had the idea of putting " | " for "" because most tags point to commits (and for the rest of the manpage, all tags point to commits). Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- Documentation/git-tag.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index b8dc88fa38..046ab3542b 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -9,7 +9,8 @@ git-tag - Create, list, delete or verify a tag object signed with GPG SYNOPSIS -------- [verse] -'git tag' [-a | -s | -u ] [-f] [-m | -F ] [] +'git tag' [-a | -s | -u ] [-f] [-m | -F ] + [ | ] 'git tag' -d ... 'git tag' [-n[]] -l [] 'git tag' -v ... From 8892048d516fffab2000c2b47e006d8d8ebaa8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Valdemar=20M=C3=B8rch?= Date: Fri, 25 Jul 2008 15:06:48 +0200 Subject: [PATCH 37/62] send-email: find body-encoding correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 8291db6 (git-send-email: add charset header if we add encoded 'From', 2007-11-16), "$1" is used from a regexp without using () to capture anything in $1. Later, when that value was used, it causes a warning about a variable being undefined, instead of using the correct value for comparison (not that it makes difference in the current code that does not do actual re-encoding). Signed-off-by: Peter Valdemar Mørch Signed-off-by: Junio C Hamano --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 0b04ba32f0..385ff7c219 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -850,7 +850,7 @@ foreach my $t (@files) { } elsif (/^Content-type:/i) { $has_content_type = 1; - if (/charset="?[^ "]+/) { + if (/charset="?([^ "]+)/) { $body_encoding = $1; } push @xh, $_; From 72de2883bd7d4ceda05f107826c7607c594de965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Thu, 24 Jul 2008 18:32:00 +0100 Subject: [PATCH 38/62] index-pack.c: correctly initialize appended objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When index-pack completes a thin pack it appends objects to the pack. Since the commit 92392b4(index-pack: Honor core.deltaBaseCacheLimit when resolving deltas) such an object can be pruned in case of memory pressure, and will be read back again by get_data_from_pack(). For this to work, the fields in object_entry structure need to be initialized properly. Noticed by Pierre Habouzit. Signed-off-by: Björn Steinbrink Acked-by: Nicolas Pitre Acked-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- index-pack.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index-pack.c b/index-pack.c index c359f8c9df..7d5344abc0 100644 --- a/index-pack.c +++ b/index-pack.c @@ -698,6 +698,10 @@ static struct object_entry *append_obj_to_pack( write_or_die(output_fd, header, n); obj[0].idx.crc32 = crc32(0, Z_NULL, 0); obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n); + obj[0].size = size; + obj[0].hdr_size = n; + obj[0].type = type; + obj[0].real_type = type; obj[1].idx.offset = obj[0].idx.offset + n; obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32); hashcpy(obj->idx.sha1, sha1); From c30e699fc509f43f459c17d3148e7d866fb9157a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 25 Jul 2008 11:09:48 -0700 Subject: [PATCH 39/62] tests: propagate $(TAR) down from the toplevel Makefile Signed-off-by: Junio C Hamano --- Makefile | 1 + t/t5000-tar-tree.sh | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b003e3e60a..1d142095a7 100644 --- a/Makefile +++ b/Makefile @@ -1212,6 +1212,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS @echo SHELL_PATH=\''$(SHELL_PATH_SQ)'\' >$@ + @echo TAR=\''$(subst ','\'',$(TAR))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 9b0baac8db..5eb119ed0b 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -25,7 +25,6 @@ commit id embedding: ' . ./test-lib.sh -TAR=${TAR:-tar} UNZIP=${UNZIP:-unzip} SUBSTFORMAT=%H%n From bfce5087ee01fdead5cdc52180c8eef22adbbd71 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 25 Jul 2008 12:35:10 -0700 Subject: [PATCH 40/62] Makefile: fix shell quoting Makefile records paths to a few programs in GIT-BUILD-OPTIONS file. These paths need to be quoted twice: once to protect specials from the shell that runs the generated GIT-BUILD-OPTIONS file, and again to protect them (and the first level of quoting itself) from the shell that runs the "echo" inside the Makefile. You can test this by trying: $ ln -s /bin/tar "$HOME/Tes' program/tar" $ make TAR="$HOME/Tes' program/tar" test Signed-off-by: Junio C Hamano --- Makefile | 7 +++++-- t/t5000-tar-tree.sh | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 1d142095a7..f13184b2ba 100644 --- a/Makefile +++ b/Makefile @@ -1210,9 +1210,12 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS echo "$$FLAGS" >GIT-CFLAGS; \ fi +# We need to apply sq twice, once to protect from the shell +# that runs GIT-BUILD-OPTIONS, and then again to protect it +# and the first level quoting from the shell that runs "echo". GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS - @echo SHELL_PATH=\''$(SHELL_PATH_SQ)'\' >$@ - @echo TAR=\''$(subst ','\'',$(TAR))'\' >>$@ + @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ + @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 5eb119ed0b..87902f81ef 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -67,7 +67,7 @@ test_expect_success \ test_expect_success \ 'validate file modification time' \ 'mkdir extract && - $TAR xf b.tar -C extract a/a && + "$TAR" xf b.tar -C extract a/a && perl -e '\''print((stat("extract/a/a"))[9], "\n")'\'' >b.mtime && echo "1117231200" >expected.mtime && diff expected.mtime b.mtime' @@ -79,7 +79,7 @@ test_expect_success \ test_expect_success \ 'extract tar archive' \ - '(cd b && $TAR xf -) Date: Fri, 25 Jul 2008 00:34:47 -0700 Subject: [PATCH 41/62] Documentation: clarify how to disable elements in core.whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed by Peter Valdemar Mørch. Signed-off-by: Junio C Hamano --- Documentation/config.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index e7848055a9..798b551514 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -358,7 +358,8 @@ core.whitespace:: A comma separated list of common whitespace problems to notice. 'git-diff' will use `color.diff.whitespace` to highlight them, and 'git-apply --whitespace=error' will - consider them as errors: + consider them as errors. You can prefix `-` to disable + any of them (e.g. `-trailing-space`): + * `trailing-space` treats trailing whitespaces at the end of the line as an error (enabled by default). From d82f33e20dcf068e679eff2a16ecf8fe7b10fb31 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 25 Jul 2008 18:28:41 +0200 Subject: [PATCH 42/62] Move launch_editor() from builtin-tag.c to editor.c launch_editor() is declared in strbuf.h but defined in builtin-tag.c. This patch moves launch_editor() into a new source file editor.c, but keeps the declaration in strbuf.h. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- Makefile | 1 + builtin-tag.c | 53 ------------------------------------------------ editor.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 53 deletions(-) create mode 100644 editor.c diff --git a/Makefile b/Makefile index f4b8e38e80..d0add9d8ec 100644 --- a/Makefile +++ b/Makefile @@ -410,6 +410,7 @@ LIB_OBJS += diff-no-index.o LIB_OBJS += diff-lib.o LIB_OBJS += diff.o LIB_OBJS += dir.o +LIB_OBJS += editor.o LIB_OBJS += entry.o LIB_OBJS += environment.o LIB_OBJS += exec_cmd.o diff --git a/builtin-tag.c b/builtin-tag.c index c2cca6cb6d..219f51d6fc 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -23,59 +23,6 @@ static const char * const git_tag_usage[] = { static char signingkey[1000]; -void launch_editor(const char *path, struct strbuf *buffer, const char *const *env) -{ - const char *editor, *terminal; - - editor = getenv("GIT_EDITOR"); - if (!editor && editor_program) - editor = editor_program; - if (!editor) - editor = getenv("VISUAL"); - if (!editor) - editor = getenv("EDITOR"); - - terminal = getenv("TERM"); - if (!editor && (!terminal || !strcmp(terminal, "dumb"))) { - fprintf(stderr, - "Terminal is dumb but no VISUAL nor EDITOR defined.\n" - "Please supply the message using either -m or -F option.\n"); - exit(1); - } - - if (!editor) - editor = "vi"; - - if (strcmp(editor, ":")) { - size_t len = strlen(editor); - int i = 0; - const char *args[6]; - struct strbuf arg0; - - strbuf_init(&arg0, 0); - if (strcspn(editor, "$ \t'") != len) { - /* there are specials */ - strbuf_addf(&arg0, "%s \"$@\"", editor); - args[i++] = "sh"; - args[i++] = "-c"; - args[i++] = arg0.buf; - } - args[i++] = editor; - args[i++] = path; - args[i] = NULL; - - if (run_command_v_opt_cd_env(args, 0, NULL, env)) - die("There was a problem with the editor %s.", editor); - strbuf_release(&arg0); - } - - if (!buffer) - return; - if (strbuf_read_file(buffer, path, 0) < 0) - die("could not read message file '%s': %s", - path, strerror(errno)); -} - struct tag_filter { const char *pattern; int lines; diff --git a/editor.c b/editor.c new file mode 100644 index 0000000000..483b62d2ce --- /dev/null +++ b/editor.c @@ -0,0 +1,56 @@ +#include "cache.h" +#include "strbuf.h" +#include "run-command.h" + +void launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +{ + const char *editor, *terminal; + + editor = getenv("GIT_EDITOR"); + if (!editor && editor_program) + editor = editor_program; + if (!editor) + editor = getenv("VISUAL"); + if (!editor) + editor = getenv("EDITOR"); + + terminal = getenv("TERM"); + if (!editor && (!terminal || !strcmp(terminal, "dumb"))) { + fprintf(stderr, + "Terminal is dumb but no VISUAL nor EDITOR defined.\n" + "Please supply the message using either -m or -F option.\n"); + exit(1); + } + + if (!editor) + editor = "vi"; + + if (strcmp(editor, ":")) { + size_t len = strlen(editor); + int i = 0; + const char *args[6]; + struct strbuf arg0; + + strbuf_init(&arg0, 0); + if (strcspn(editor, "$ \t'") != len) { + /* there are specials */ + strbuf_addf(&arg0, "%s \"$@\"", editor); + args[i++] = "sh"; + args[i++] = "-c"; + args[i++] = arg0.buf; + } + args[i++] = editor; + args[i++] = path; + args[i] = NULL; + + if (run_command_v_opt_cd_env(args, 0, NULL, env)) + die("There was a problem with the editor %s.", editor); + strbuf_release(&arg0); + } + + if (!buffer) + return; + if (strbuf_read_file(buffer, path, 0) < 0) + die("could not read message file '%s': %s", + path, strerror(errno)); +} From 7198203ae37c11327c0d01f1e37f3e74381755a9 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 25 Jul 2008 18:28:42 +0200 Subject: [PATCH 43/62] editor.c: Libify launch_editor() This patch removes exit()/die() calls and builtin-specific messages from launch_editor(), so that it can be used as a general libgit.a function to launch an editor. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- builtin-commit.c | 6 +++++- builtin-tag.c | 6 +++++- editor.c | 24 ++++++++++++------------ strbuf.h | 2 +- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 6a9dc0e30f..9a11ca0bcd 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -646,7 +646,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix) char index[PATH_MAX]; const char *env[2] = { index, NULL }; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); - launch_editor(git_path(commit_editmsg), NULL, env); + if (launch_editor(git_path(commit_editmsg), NULL, env)) { + fprintf(stderr, + "Please supply the message using either -m or -F option.\n"); + exit(1); + } } if (!no_verify && diff --git a/builtin-tag.c b/builtin-tag.c index 219f51d6fc..325b1b2632 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -295,7 +295,11 @@ static void create_tag(const unsigned char *object, const char *tag, write_or_die(fd, tag_template, strlen(tag_template)); close(fd); - launch_editor(path, buf, NULL); + if (launch_editor(path, buf, NULL)) { + fprintf(stderr, + "Please supply the message using either -m or -F option.\n"); + exit(1); + } unlink(path); free(path); diff --git a/editor.c b/editor.c index 483b62d2ce..eebc3e95fe 100644 --- a/editor.c +++ b/editor.c @@ -2,7 +2,7 @@ #include "strbuf.h" #include "run-command.h" -void launch_editor(const char *path, struct strbuf *buffer, const char *const *env) +int launch_editor(const char *path, struct strbuf *buffer, const char *const *env) { const char *editor, *terminal; @@ -15,12 +15,8 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e editor = getenv("EDITOR"); terminal = getenv("TERM"); - if (!editor && (!terminal || !strcmp(terminal, "dumb"))) { - fprintf(stderr, - "Terminal is dumb but no VISUAL nor EDITOR defined.\n" - "Please supply the message using either -m or -F option.\n"); - exit(1); - } + if (!editor && (!terminal || !strcmp(terminal, "dumb"))) + return error("Terminal is dumb but no VISUAL nor EDITOR defined."); if (!editor) editor = "vi"; @@ -28,6 +24,7 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e if (strcmp(editor, ":")) { size_t len = strlen(editor); int i = 0; + int failed; const char *args[6]; struct strbuf arg0; @@ -43,14 +40,17 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e args[i++] = path; args[i] = NULL; - if (run_command_v_opt_cd_env(args, 0, NULL, env)) - die("There was a problem with the editor %s.", editor); + failed = run_command_v_opt_cd_env(args, 0, NULL, env); strbuf_release(&arg0); + if (failed) + return error("There was a problem with the editor '%s'.", + editor); } if (!buffer) - return; + return 0; if (strbuf_read_file(buffer, path, 0) < 0) - die("could not read message file '%s': %s", - path, strerror(errno)); + return error("could not read file '%s': %s", + path, strerror(errno)); + return 0; } diff --git a/strbuf.h b/strbuf.h index 0c6ffad53a..eba7ba423a 100644 --- a/strbuf.h +++ b/strbuf.h @@ -123,6 +123,6 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); extern int strbuf_getline(struct strbuf *, FILE *, int); extern void stripspace(struct strbuf *buf, int skip_comments); -extern void launch_editor(const char *path, struct strbuf *buffer, const char *const *env); +extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); #endif /* STRBUF_H */ From 837c8767130ec71089e654f92cf24e8277a3bda5 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Fri, 25 Jul 2008 18:51:51 +0100 Subject: [PATCH 44/62] Propagate -u/--upload-pack option of "git clone" to transport. The -u option to override the remote system's path to git-upload-pack was being ignored by "git clone"; caused by a missing call to transport_set_option to set TRANS_OPT_UPLOADPACK. Presumably this crept in when git-clone was converted from shell to C. Signed-off-by: Steve Haslam Signed-off-by: Junio C Hamano --- builtin-clone.c | 4 ++++ t/t5602-clone-remote-exec.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100755 t/t5602-clone-remote-exec.sh diff --git a/builtin-clone.c b/builtin-clone.c index 352224591f..e086a40b41 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -480,6 +480,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_quiet) transport->verbose = -1; + if (option_upload_pack) + transport_set_option(transport, TRANS_OPT_UPLOADPACK, + option_upload_pack); + refs = transport_get_remote_refs(transport); transport_fetch_refs(transport, refs); } diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh new file mode 100755 index 0000000000..8367a6845f --- /dev/null +++ b/t/t5602-clone-remote-exec.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description=clone + +. ./test-lib.sh + +test_expect_success setup ' + echo "#!/bin/sh" > not_ssh + echo "echo \"\$*\" > not_ssh_output" >> not_ssh + echo "exit 1" >> not_ssh + chmod +x not_ssh +' + +test_expect_success 'clone calls git-upload-pack unqualified with no -u option' ' + GIT_SSH=./not_ssh git clone localhost:/path/to/repo junk + echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected + test_cmp expected not_ssh_output +' + +test_expect_success 'clone calls specified git-upload-pack with -u option' ' + GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk + echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected + test_cmp expected not_ssh_output +' + +test_done From 09f8d055f9c2af79a72f8d2a2f13698d9bbe6956 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 25 Jul 2008 20:22:23 +0200 Subject: [PATCH 45/62] git-am: Mention --abort in usage string part of OPTIONS_SPEC The three separate lines for --skip, --resolved and --abort are merged into one so that it is easy to see that they're alternative and related options. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- git-am.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/git-am.sh b/git-am.sh index f4abd9db15..6aa819280e 100755 --- a/git-am.sh +++ b/git-am.sh @@ -6,8 +6,7 @@ SUBDIRECTORY_OK=Yes OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ git am [options] [|...] -git am [options] --resolved -git am [options] --skip +git am [options] (--resolved | --skip | --abort) -- d,dotest= (removed -- do not use) i,interactive run interactively From d3296e37b61fdd80a8b785270b1d11db34dab2f5 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Fri, 25 Jul 2008 19:37:48 +0100 Subject: [PATCH 46/62] Remove references to git-fetch-pack from "git clone" documentation. "git clone" no longer calls "git-fetch-pack", so the documentation is a bit stale. Instead, state that the -u option is to be used when accessing a repository over ssh. Signed-off-by: Steve Haslam Signed-off-by: Junio C Hamano --- Documentation/git-clone.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 91efac920e..26fd1b1117 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -87,8 +87,8 @@ then the cloned repository will become corrupt. --quiet:: -q:: - Operate quietly. This flag is passed to "rsync" and - 'git-fetch-pack' commands when given. + Operate quietly. This flag is also passed to the `rsync' + command when given. --no-checkout:: -n:: @@ -113,9 +113,8 @@ then the cloned repository will become corrupt. --upload-pack :: -u :: - When given, and the repository to clone from is handled - by 'git-fetch-pack', `--exec=` is passed to - the command to specify non-default path for the command + When given, and the repository to clone from is accessed + via ssh, this specifies a non-default path for the command run on the other end. --template=:: From 6e94e6835f397cd2602ca1eb12002e51aa6b0500 Mon Sep 17 00:00:00 2001 From: Rene Scharfe Date: Fri, 25 Jul 2008 12:41:21 +0200 Subject: [PATCH 47/62] archive: add write_archive() Both archive and upload-archive have to parse command line arguments and then call the archiver specific write function. Move the duplicate code to a new function, write_archive(). Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.c | 18 ++++++++++++++++++ archive.h | 1 + builtin-archive.c | 13 +------------ builtin-upload-archive.c | 10 +--------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/archive.c b/archive.c index b8b45bad77..75eb257760 100644 --- a/archive.c +++ b/archive.c @@ -155,3 +155,21 @@ int write_archive_entries(struct archiver_args *args, err = 0; return err; } + +int write_archive(int argc, const char **argv, const char *prefix, + int setup_prefix) +{ + const struct archiver *ar = NULL; + struct archiver_args args; + int tree_idx; + + tree_idx = parse_archive_args(argc, argv, &ar, &args); + if (setup_prefix && prefix == NULL) + prefix = setup_git_directory(); + + argv += tree_idx; + parse_treeish_arg(argv, &args, prefix); + parse_pathspec_arg(argv + 1, &args); + + return ar->write_archive(&args); +} diff --git a/archive.h b/archive.h index 4a02371f37..6b5fe5af45 100644 --- a/archive.h +++ b/archive.h @@ -41,5 +41,6 @@ extern int write_tar_archive(struct archiver_args *); extern int write_zip_archive(struct archiver_args *); extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry); +extern int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix); #endif /* ARCHIVE_H */ diff --git a/builtin-archive.c b/builtin-archive.c index df97724696..502b339e6b 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -232,9 +232,6 @@ static const char *extract_remote_arg(int *ac, const char **av) int cmd_archive(int argc, const char **argv, const char *prefix) { - const struct archiver *ar = NULL; - struct archiver_args args; - int tree_idx; const char *remote = NULL; remote = extract_remote_arg(&argc, argv); @@ -243,13 +240,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix) setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - tree_idx = parse_archive_args(argc, argv, &ar, &args); - if (prefix == NULL) - prefix = setup_git_directory(); - - argv += tree_idx; - parse_treeish_arg(argv, &args, prefix); - parse_pathspec_arg(argv + 1, &args); - - return ar->write_archive(&args); + return write_archive(argc, argv, prefix, 1); } diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c index 13a6c6203e..cc37b36d99 100644 --- a/builtin-upload-archive.c +++ b/builtin-upload-archive.c @@ -19,12 +19,9 @@ static const char lostchild[] = static int run_upload_archive(int argc, const char **argv, const char *prefix) { - const struct archiver *ar; - struct archiver_args args; const char *sent_argv[MAX_ARGS]; const char *arg_cmd = "argument "; char *p, buf[4096]; - int treeish_idx; int sent_argc; int len; @@ -66,12 +63,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix) sent_argv[sent_argc] = NULL; /* parse all options sent by the client */ - treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar, &args); - - parse_treeish_arg(sent_argv + treeish_idx, &args, prefix); - parse_pathspec_arg(sent_argv + treeish_idx + 1, &args); - - return ar->write_archive(&args); + return write_archive(sent_argc, sent_argv, prefix, 0); } static void error_clnt(const char *fmt, ...) From c0885435537e4b93709d2bf39ce36454186057a1 Mon Sep 17 00:00:00 2001 From: Rene Scharfe Date: Fri, 25 Jul 2008 12:41:22 +0200 Subject: [PATCH 48/62] archive: move parameter parsing code to archive.c write_archive() in archive.c is the only callsite for the command line parsing functions located in builtin-archive.c. Move them to the place where they are used, un-export them and make them static, as hinted at by Stephan. Cc: Stephan Beyer Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ archive.h | 8 --- builtin-archive.c | 137 ---------------------------------------------- 3 files changed, 137 insertions(+), 145 deletions(-) diff --git a/archive.c b/archive.c index 75eb257760..c4662a2830 100644 --- a/archive.c +++ b/archive.c @@ -1,8 +1,19 @@ #include "cache.h" #include "commit.h" +#include "tree-walk.h" #include "attr.h" #include "archive.h" +static const char archive_usage[] = \ +"git archive --format= [--prefix=/] [--verbose] [] [path...]"; + +#define USES_ZLIB_COMPRESSION 1 + +const struct archiver archivers[] = { + { "tar", write_tar_archive }, + { "zip", write_zip_archive, USES_ZLIB_COMPRESSION }, +}; + static void format_subst(const struct commit *commit, const char *src, size_t len, struct strbuf *buf) @@ -156,6 +167,132 @@ int write_archive_entries(struct archiver_args *args, return err; } +static const struct archiver *lookup_archiver(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(archivers); i++) { + if (!strcmp(name, archivers[i].name)) + return &archivers[i]; + } + return NULL; +} + +static void parse_pathspec_arg(const char **pathspec, + struct archiver_args *ar_args) +{ + ar_args->pathspec = get_pathspec(ar_args->base, pathspec); +} + +static void parse_treeish_arg(const char **argv, + struct archiver_args *ar_args, const char *prefix) +{ + const char *name = argv[0]; + const unsigned char *commit_sha1; + time_t archive_time; + struct tree *tree; + const struct commit *commit; + unsigned char sha1[20]; + + if (get_sha1(name, sha1)) + die("Not a valid object name"); + + commit = lookup_commit_reference_gently(sha1, 1); + if (commit) { + commit_sha1 = commit->object.sha1; + archive_time = commit->date; + } else { + commit_sha1 = NULL; + archive_time = time(NULL); + } + + tree = parse_tree_indirect(sha1); + if (tree == NULL) + die("not a tree object"); + + if (prefix) { + unsigned char tree_sha1[20]; + unsigned int mode; + int err; + + err = get_tree_entry(tree->object.sha1, prefix, + tree_sha1, &mode); + if (err || !S_ISDIR(mode)) + die("current working directory is untracked"); + + tree = parse_tree_indirect(tree_sha1); + } + ar_args->tree = tree; + ar_args->commit_sha1 = commit_sha1; + ar_args->commit = commit; + ar_args->time = archive_time; +} + +static int parse_archive_args(int argc, const char **argv, + const struct archiver **ar, struct archiver_args *args) +{ + const char *format = "tar"; + const char *base = ""; + int compression_level = -1; + int verbose = 0; + int i; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + + if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) { + for (i = 0; i < ARRAY_SIZE(archivers); i++) + printf("%s\n", archivers[i].name); + exit(0); + } + if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { + verbose = 1; + continue; + } + if (!prefixcmp(arg, "--format=")) { + format = arg + 9; + continue; + } + if (!prefixcmp(arg, "--prefix=")) { + base = arg + 9; + continue; + } + if (!strcmp(arg, "--")) { + i++; + break; + } + if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0') { + compression_level = arg[1] - '0'; + continue; + } + if (arg[0] == '-') + die("Unknown argument: %s", arg); + break; + } + + /* We need at least one parameter -- tree-ish */ + if (argc - 1 < i) + usage(archive_usage); + *ar = lookup_archiver(format); + if (!*ar) + die("Unknown archive format '%s'", format); + + args->compression_level = Z_DEFAULT_COMPRESSION; + if (compression_level != -1) { + if ((*ar)->flags & USES_ZLIB_COMPRESSION) + args->compression_level = compression_level; + else { + die("Argument not supported for format '%s': -%d", + format, compression_level); + } + } + args->verbose = verbose; + args->base = base; + args->baselen = strlen(base); + + return i; +} + int write_archive(int argc, const char **argv, const char *prefix, int setup_prefix) { diff --git a/archive.h b/archive.h index 6b5fe5af45..f6ceaebc8f 100644 --- a/archive.h +++ b/archive.h @@ -26,14 +26,6 @@ struct archiver { unsigned int flags; }; -extern int parse_archive_args(int argc, const char **argv, const struct archiver **ar, struct archiver_args *args); - -extern void parse_treeish_arg(const char **treeish, - struct archiver_args *ar_args, - const char *prefix); - -extern void parse_pathspec_arg(const char **pathspec, - struct archiver_args *args); /* * Archive-format specific backends. */ diff --git a/builtin-archive.c b/builtin-archive.c index 502b339e6b..4dd2716c0f 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -5,21 +5,9 @@ #include "cache.h" #include "builtin.h" #include "archive.h" -#include "commit.h" -#include "tree-walk.h" #include "pkt-line.h" #include "sideband.h" -static const char archive_usage[] = \ -"git archive --format= [--prefix=/] [--verbose] [] [path...]"; - -#define USES_ZLIB_COMPRESSION 1 - -const struct archiver archivers[] = { - { "tar", write_tar_archive }, - { "zip", write_zip_archive, USES_ZLIB_COMPRESSION }, -}; - static int run_remote_archiver(const char *remote, int argc, const char **argv) { @@ -74,131 +62,6 @@ static int run_remote_archiver(const char *remote, int argc, return !!rv; } -static const struct archiver *lookup_archiver(const char *name) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(archivers); i++) { - if (!strcmp(name, archivers[i].name)) - return &archivers[i]; - } - return NULL; -} - -void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args) -{ - ar_args->pathspec = get_pathspec(ar_args->base, pathspec); -} - -void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, - const char *prefix) -{ - const char *name = argv[0]; - const unsigned char *commit_sha1; - time_t archive_time; - struct tree *tree; - const struct commit *commit; - unsigned char sha1[20]; - - if (get_sha1(name, sha1)) - die("Not a valid object name"); - - commit = lookup_commit_reference_gently(sha1, 1); - if (commit) { - commit_sha1 = commit->object.sha1; - archive_time = commit->date; - } else { - commit_sha1 = NULL; - archive_time = time(NULL); - } - - tree = parse_tree_indirect(sha1); - if (tree == NULL) - die("not a tree object"); - - if (prefix) { - unsigned char tree_sha1[20]; - unsigned int mode; - int err; - - err = get_tree_entry(tree->object.sha1, prefix, - tree_sha1, &mode); - if (err || !S_ISDIR(mode)) - die("current working directory is untracked"); - - tree = parse_tree_indirect(tree_sha1); - } - ar_args->tree = tree; - ar_args->commit_sha1 = commit_sha1; - ar_args->commit = commit; - ar_args->time = archive_time; -} - -int parse_archive_args(int argc, const char **argv, const struct archiver **ar, - struct archiver_args *args) -{ - const char *format = "tar"; - const char *base = ""; - int compression_level = -1; - int verbose = 0; - int i; - - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - - if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) { - for (i = 0; i < ARRAY_SIZE(archivers); i++) - printf("%s\n", archivers[i].name); - exit(0); - } - if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { - verbose = 1; - continue; - } - if (!prefixcmp(arg, "--format=")) { - format = arg + 9; - continue; - } - if (!prefixcmp(arg, "--prefix=")) { - base = arg + 9; - continue; - } - if (!strcmp(arg, "--")) { - i++; - break; - } - if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0') { - compression_level = arg[1] - '0'; - continue; - } - if (arg[0] == '-') - die("Unknown argument: %s", arg); - break; - } - - /* We need at least one parameter -- tree-ish */ - if (argc - 1 < i) - usage(archive_usage); - *ar = lookup_archiver(format); - if (!*ar) - die("Unknown archive format '%s'", format); - - args->compression_level = Z_DEFAULT_COMPRESSION; - if (compression_level != -1) { - if ((*ar)->flags & USES_ZLIB_COMPRESSION) - args->compression_level = compression_level; - else { - die("Argument not supported for format '%s': -%d", - format, compression_level); - } - } - args->verbose = verbose; - args->base = base; - args->baselen = strlen(base); - - return i; -} - static const char *extract_remote_arg(int *ac, const char **av) { int ix, iy, cnt = *ac; From 7f4d0511af9d6c93656dda5a683632f5ae5b5278 Mon Sep 17 00:00:00 2001 From: Rene Scharfe Date: Fri, 25 Jul 2008 12:41:23 +0200 Subject: [PATCH 49/62] archive: define MAX_ARGS where it's needed MAX_EXTRA_ARGS is not used anymore, so remove it. MAX_ARGS is used only in builtin-upload-archive.c, so define it there. Also report the actual value we're comparing against when the number of args is too big. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.h | 3 --- builtin-upload-archive.c | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/archive.h b/archive.h index f6ceaebc8f..929368d80b 100644 --- a/archive.h +++ b/archive.h @@ -1,9 +1,6 @@ #ifndef ARCHIVE_H #define ARCHIVE_H -#define MAX_EXTRA_ARGS 32 -#define MAX_ARGS (MAX_EXTRA_ARGS + 32) - struct archiver_args { const char *base; size_t baselen; diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c index cc37b36d99..a9b02fa32f 100644 --- a/builtin-upload-archive.c +++ b/builtin-upload-archive.c @@ -16,6 +16,7 @@ static const char deadchild[] = static const char lostchild[] = "git upload-archive: archiver process was lost"; +#define MAX_ARGS (64) static int run_upload_archive(int argc, const char **argv, const char *prefix) { @@ -45,7 +46,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix) if (len == 0) break; /* got a flush */ if (sent_argc > MAX_ARGS - 2) - die("Too many options (>29)"); + die("Too many options (>%d)", MAX_ARGS - 2); if (p[len-1] == '\n') { p[--len] = 0; From f15f736d38d10f5c4f2ca367565019bdfe8e71dd Mon Sep 17 00:00:00 2001 From: Rene Scharfe Date: Fri, 25 Jul 2008 12:41:24 +0200 Subject: [PATCH 50/62] archive: declare struct archiver where it's needed Move the declaration of struct archiver to archive.c, as this is the only file left where it is used. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.c | 6 +++++- archive.h | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/archive.c b/archive.c index c4662a2830..f834b5f51f 100644 --- a/archive.c +++ b/archive.c @@ -9,7 +9,11 @@ static const char archive_usage[] = \ #define USES_ZLIB_COMPRESSION 1 -const struct archiver archivers[] = { +const struct archiver { + const char *name; + write_archive_fn_t write_archive; + unsigned int flags; +} archivers[] = { { "tar", write_tar_archive }, { "zip", write_zip_archive, USES_ZLIB_COMPRESSION }, }; diff --git a/archive.h b/archive.h index 929368d80b..0b15b35143 100644 --- a/archive.h +++ b/archive.h @@ -17,12 +17,6 @@ typedef int (*write_archive_fn_t)(struct archiver_args *); typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size); -struct archiver { - const char *name; - write_archive_fn_t write_archive; - unsigned int flags; -}; - /* * Archive-format specific backends. */ From 819b2b58246a7927376930e266b4ef8b43096115 Mon Sep 17 00:00:00 2001 From: Rene Scharfe Date: Fri, 25 Jul 2008 12:41:25 +0200 Subject: [PATCH 51/62] archive: allow --exec and --remote without equal sign Allow "--remote repo" and "--exec cmd" in addition to "--remote=repo" and "--exec=cmd" to make their usage consistent with parameters handled by parse_options(). Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- builtin-archive.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/builtin-archive.c b/builtin-archive.c index 4dd2716c0f..22445acbfc 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -15,7 +15,7 @@ static int run_remote_archiver(const char *remote, int argc, int fd[2], i, len, rv; struct child_process *conn; const char *exec = "git-upload-archive"; - int exec_at = 0; + int exec_at = 0, exec_value_at = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -24,7 +24,14 @@ static int run_remote_archiver(const char *remote, int argc, die("multiple --exec specified"); exec = arg + 7; exec_at = i; - break; + } else if (!strcmp(arg, "--exec")) { + if (exec_at) + die("multiple --exec specified"); + if (i + 1 >= argc) + die("option --exec requires a value"); + exec = argv[i + 1]; + exec_at = i; + exec_value_at = ++i; } } @@ -32,7 +39,7 @@ static int run_remote_archiver(const char *remote, int argc, conn = git_connect(fd, url, exec, 0); for (i = 1; i < argc; i++) { - if (i == exec_at) + if (i == exec_at || i == exec_value_at) continue; packet_write(fd[1], "argument %s\n", argv[i]); } @@ -78,6 +85,13 @@ static const char *extract_remote_arg(int *ac, const char **av) die("Multiple --remote specified"); remote = arg + 9; continue; + } else if (!strcmp(arg, "--remote")) { + if (remote) + die("Multiple --remote specified"); + if (++ix >= cnt) + die("option --remote requires a value"); + remote = av[ix]; + continue; } if (arg[0] != '-') no_more_options = 1; From c70a8d98a528f29bc6d6de7744e1eedd24f2a63d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:50 +0200 Subject: [PATCH 52/62] Makefile: Do not install a copy of 'git' in $(gitexecdir) There is already a copy in $(bindir). A subsequent patch will enable git to derive the exec-path from its invocation path. If git is invoked recursively, the first invocation puts the exec-path into PATH, so that the recursive invocation would find the instance in the exec-path. This second instance would again try to derive an exec-path from its invocation path, but would base its result on the wrong "bindir". We do install the copy of git first, but remove it later, so that we can use it as the source of the hardlinks for the builtins. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index d0add9d8ec..e6add0314d 100644 --- a/Makefile +++ b/Makefile @@ -1340,6 +1340,7 @@ endif '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) + $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' ifneq (,$X) $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) endif From 46beb55988e68da04c2e9d319c71b9b940f0854c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:51 +0200 Subject: [PATCH 53/62] Makefile: Normalize $(bindir) and $(gitexecdir) before comparing The install target needs to check whether the user has opted to make $(gitexecdir) equal to $(bindir). It did so by a straight string comparison. Since we are going to allow a relative $(gitexecdir), we have to normalize paths before comparison, which we do with $(cd there && pwd). The normalized paths are stored in shell variables. These we can now reuse in the subsequent install statements, which conveniently shortens the lines a bit. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index e6add0314d..e096763060 100644 --- a/Makefile +++ b/Makefile @@ -1332,19 +1332,19 @@ ifndef NO_TCLTK $(MAKE) -C gitk-git install $(MAKE) -C git-gui install endif - if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ - then \ - ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \ - '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' || \ - cp '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \ - '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ - fi - $(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) - $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' ifneq (,$X) $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) endif - ./check_bindir 'z$(bindir_SQ)' 'z$(gitexecdir_SQ)' '$(DESTDIR_SQ)$(bindir_SQ)/git-shell$X' + bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \ + execdir=$$(cd '$(DESTDIR_SQ)$(gitexecdir_SQ)' && pwd) && \ + if test "z$$bindir" != "z$$execdir"; \ + then \ + ln -f "$$bindir/git$X" "$$execdir/git$X" || \ + cp "$$bindir/git$X" "$$execdir/git$X"; \ + fi && \ + { $(foreach p,$(BUILT_INS), $(RM) "$$execdir/$p" && ln "$$execdir/git$X" "$$execdir/$p" ;) } && \ + $(RM) "$$execdir/git$X" && \ + ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-shell$X" install-doc: $(MAKE) -C Documentation install From e1464ca7bb0d705210ba7198f004b2fb2b807e12 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:52 +0200 Subject: [PATCH 54/62] Record the command invocation path early We will need the command invocation path in system_path(). This path was passed to setup_path(), but system_path() can be called earlier, for example via: main commit_pager_choice setup_pager git_config git_etc_gitconfig system_path Therefore, we introduce git_set_argv0_path() and call it as soon as possible. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- exec_cmd.c | 10 ++++++++-- exec_cmd.h | 3 ++- git.c | 5 ++--- receive-pack.c | 2 +- shell.c | 4 ++-- upload-pack.c | 2 +- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 8899e31b3b..dedb01da6f 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -5,6 +5,7 @@ extern char **environ; static const char *argv_exec_path; +static const char *argv0_path; static const char *builtin_exec_path(void) { @@ -50,6 +51,11 @@ const char *system_path(const char *path) return path; } +void git_set_argv0_path(const char *path) +{ + argv0_path = path; +} + void git_set_argv_exec_path(const char *exec_path) { argv_exec_path = exec_path; @@ -84,7 +90,7 @@ static void add_path(struct strbuf *out, const char *path) } } -void setup_path(const char *cmd_path) +void setup_path(void) { const char *old_path = getenv("PATH"); struct strbuf new_path; @@ -94,7 +100,7 @@ void setup_path(const char *cmd_path) add_path(&new_path, argv_exec_path); add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); add_path(&new_path, builtin_exec_path()); - add_path(&new_path, cmd_path); + add_path(&new_path, argv0_path); if (old_path) strbuf_addstr(&new_path, old_path); diff --git a/exec_cmd.h b/exec_cmd.h index 7eb94e5e11..0c46cd5636 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,8 +2,9 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); +extern void git_set_argv0_path(const char *path); extern const char* git_exec_path(void); -extern void setup_path(const char *); +extern void setup_path(void); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); extern const char *system_path(const char *path); diff --git a/git.c b/git.c index 1bfd271a71..37b1d76a08 100644 --- a/git.c +++ b/git.c @@ -418,7 +418,6 @@ int main(int argc, const char **argv) { const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; char *slash = (char *)cmd + strlen(cmd); - const char *cmd_path = NULL; int done_alias = 0; /* @@ -431,7 +430,7 @@ int main(int argc, const char **argv) while (cmd <= slash && !is_dir_sep(*slash)); if (cmd <= slash) { *slash++ = 0; - cmd_path = cmd; + git_set_argv0_path(cmd); cmd = slash; } @@ -475,7 +474,7 @@ int main(int argc, const char **argv) * environment, and the $(gitexecdir) from the Makefile at build * time. */ - setup_path(cmd_path); + setup_path(); while (1) { /* See if it's an internal command */ diff --git a/receive-pack.c b/receive-pack.c index fa653b49fe..d44c19e6b5 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -482,7 +482,7 @@ int main(int argc, char **argv) if (!dir) usage(receive_pack_usage); - setup_path(NULL); + setup_path(); if (!enter_repo(dir, 0)) die("'%s': unable to chdir or not a git archive", dir); diff --git a/shell.c b/shell.c index 91ca7de082..6a48de05ff 100644 --- a/shell.c +++ b/shell.c @@ -15,7 +15,7 @@ static int do_generic_cmd(const char *me, char *arg) { const char *my_argv[4]; - setup_path(NULL); + setup_path(); if (!arg || !(arg = sq_dequote(arg))) die("bad argument"); if (prefixcmp(me, "git-")) @@ -37,7 +37,7 @@ static int do_cvs_cmd(const char *me, char *arg) if (!arg || strcmp(arg, "server")) die("git-cvsserver only handles server: %s", arg); - setup_path(NULL); + setup_path(); return execv_git_cmd(cvsserver_argv); } diff --git a/upload-pack.c b/upload-pack.c index 9f82941f8b..c911e70c9a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -638,7 +638,7 @@ int main(int argc, char **argv) if (i != argc-1) usage(upload_pack_usage); - setup_path(NULL); + setup_path(); dir = argv[i]; From 966c6edd318f2e44dd150103ec2b6b7a53be58f0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:53 +0200 Subject: [PATCH 55/62] Fix relative built-in paths to be relative to the command invocation $(gitexecdir) (as defined in the Makefile) has gained another path component, but the relative paths in the MINGW section of the Makefile, which are interpreted relative to it, do not account for it. Instead of adding another ../ in front of the path, we change the code that constructs the absolute paths to do it relative to the command's directory, which is essentially $(bindir). We do it this way because we will also allow a relative $(gitexecdir) later. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 2 +- exec_cmd.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e096763060..fa8cf8adb6 100644 --- a/Makefile +++ b/Makefile @@ -1315,7 +1315,7 @@ remove-dashes: ### Installation rules ifeq ($(firstword $(subst /, ,$(template_dir))),..) -template_instdir = $(gitexecdir)/$(template_dir) +template_instdir = $(bindir)/$(template_dir) else template_instdir = $(template_dir) endif diff --git a/exec_cmd.c b/exec_cmd.c index dedb01da6f..45f92eb164 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -43,9 +43,9 @@ static const char *builtin_exec_path(void) const char *system_path(const char *path) { - if (!is_absolute_path(path)) { + if (!is_absolute_path(path) && argv0_path) { struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", git_exec_path(), path); + strbuf_addf(&d, "%s/%s", argv0_path, path); path = strbuf_detach(&d, NULL); } return path; From 49fa65a7a8185e81c1098815df607042103b0493 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 23 Jul 2008 21:12:18 +0200 Subject: [PATCH 56/62] Allow the built-in exec path to be relative to the command invocation path If GIT_EXEC_PATH (the macro that is defined in the Makefile) is relative, it is interpreted relative to the command's invocation path, which usually is $(bindir). The Makefile rules were written with the assumption that $(gitexecdir) is an absolute path. We introduce a separate variable that names the (absolute) installation directory. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 30 ++++++++++++++++++++++++------ exec_cmd.c | 38 ++------------------------------------ 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/Makefile b/Makefile index fa8cf8adb6..fceca92184 100644 --- a/Makefile +++ b/Makefile @@ -170,6 +170,16 @@ ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip +# Among the variables below, these: +# gitexecdir +# template_dir +# htmldir +# ETC_GITCONFIG (but not sysconfdir) +# can be specified as a relative path ../some/where/else (which must begin +# with ../); this is interpreted as relative to $(bindir) and "git" at +# runtime figures out where they are based on the path to the executable. +# This can help installing the suite in a relocatable way. + prefix = $(HOME) bindir = $(prefix)/bin mandir = $(prefix)/share/man @@ -205,7 +215,7 @@ GITWEB_FAVICON = git-favicon.png GITWEB_SITE_HEADER = GITWEB_SITE_FOOTER = -export prefix bindir gitexecdir sharedir htmldir sysconfdir +export prefix bindir sharedir htmldir sysconfdir CC = gcc AR = ar @@ -1321,22 +1331,30 @@ template_instdir = $(template_dir) endif export template_instdir +ifeq ($(firstword $(subst /, ,$(gitexecdir))),..) +gitexec_instdir = $(bindir)/$(gitexecdir) +else +gitexec_instdir = $(gitexecdir) +endif +gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir)) +export gitexec_instdir + install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' - $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' + $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK $(MAKE) -C gitk-git install - $(MAKE) -C git-gui install + $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install endif ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';) endif bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \ - execdir=$$(cd '$(DESTDIR_SQ)$(gitexecdir_SQ)' && pwd) && \ + execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \ if test "z$$bindir" != "z$$execdir"; \ then \ ln -f "$$bindir/git$X" "$$execdir/git$X" || \ diff --git a/exec_cmd.c b/exec_cmd.c index 45f92eb164..c23603452e 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -7,40 +7,6 @@ extern char **environ; static const char *argv_exec_path; static const char *argv0_path; -static const char *builtin_exec_path(void) -{ -#ifndef __MINGW32__ - return GIT_EXEC_PATH; -#else - int len; - char *p, *q, *sl; - static char *ep; - if (ep) - return ep; - - len = strlen(_pgmptr); - if (len < 2) - return ep = "."; - - p = ep = xmalloc(len+1); - q = _pgmptr; - sl = NULL; - /* copy program name, turn '\\' into '/', skip last part */ - while ((*p = *q)) { - if (*q == '\\' || *q == '/') { - *p = '/'; - sl = p; - } - p++, q++; - } - if (sl) - *sl = '\0'; - else - ep[0] = '.', ep[1] = '\0'; - return ep; -#endif -} - const char *system_path(const char *path) { if (!is_absolute_path(path) && argv0_path) { @@ -75,7 +41,7 @@ const char *git_exec_path(void) return env; } - return builtin_exec_path(); + return system_path(GIT_EXEC_PATH); } static void add_path(struct strbuf *out, const char *path) @@ -99,7 +65,7 @@ void setup_path(void) add_path(&new_path, argv_exec_path); add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, builtin_exec_path()); + add_path(&new_path, system_path(GIT_EXEC_PATH)); add_path(&new_path, argv0_path); if (old_path) From 10c4c881c4d2cb0ece0508e7142e189e68445257 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:55 +0200 Subject: [PATCH 57/62] Allow add_path() to add non-existent directories to the path This function had used make_absolute_path(); but this function dies if the directory that contains the entry whose relative path was supplied in the argument does not exist. This is a problem if the argument is, for example, "../libexec/git-core", and that "../libexec" does not exist. Since the resolution of symbolic links is not required for elements in PATH, we can fall back to using make_nonrelative_path(), which simply prepends $PWD to the path. We have to move make_nonrelative_path() alongside make_absolute_path() in abspath.c so that git-shell can be linked. See 5b8e6f85f. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- abspath.c | 36 ++++++++++++++++++++++++++++++++++++ exec_cmd.c | 2 +- path.c | 36 ------------------------------------ 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/abspath.c b/abspath.c index 4f95a954d5..0d561246e0 100644 --- a/abspath.c +++ b/abspath.c @@ -66,3 +66,39 @@ const char *make_absolute_path(const char *path) return buf; } + +static const char *get_pwd_cwd(void) +{ + static char cwd[PATH_MAX + 1]; + char *pwd; + struct stat cwd_stat, pwd_stat; + if (getcwd(cwd, PATH_MAX) == NULL) + return NULL; + pwd = getenv("PWD"); + if (pwd && strcmp(pwd, cwd)) { + stat(cwd, &cwd_stat); + if (!stat(pwd, &pwd_stat) && + pwd_stat.st_dev == cwd_stat.st_dev && + pwd_stat.st_ino == cwd_stat.st_ino) { + strlcpy(cwd, pwd, PATH_MAX); + } + } + return cwd; +} + +const char *make_nonrelative_path(const char *path) +{ + static char buf[PATH_MAX + 1]; + + if (is_absolute_path(path)) { + if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) + die("Too long path: %.*s", 60, path); + } else { + const char *cwd = get_pwd_cwd(); + if (!cwd) + die("Cannot determine the current working directory"); + if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + die("Too long path: %.*s", 60, path); + } + return buf; +} diff --git a/exec_cmd.c b/exec_cmd.c index c23603452e..0ed768ddc0 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -50,7 +50,7 @@ static void add_path(struct strbuf *out, const char *path) if (is_absolute_path(path)) strbuf_addstr(out, path); else - strbuf_addstr(out, make_absolute_path(path)); + strbuf_addstr(out, make_nonrelative_path(path)); strbuf_addch(out, PATH_SEP); } diff --git a/path.c b/path.c index 504eae061f..9df447bd6d 100644 --- a/path.c +++ b/path.c @@ -291,42 +291,6 @@ int adjust_shared_perm(const char *path) return 0; } -static const char *get_pwd_cwd(void) -{ - static char cwd[PATH_MAX + 1]; - char *pwd; - struct stat cwd_stat, pwd_stat; - if (getcwd(cwd, PATH_MAX) == NULL) - return NULL; - pwd = getenv("PWD"); - if (pwd && strcmp(pwd, cwd)) { - stat(cwd, &cwd_stat); - if (!stat(pwd, &pwd_stat) && - pwd_stat.st_dev == cwd_stat.st_dev && - pwd_stat.st_ino == cwd_stat.st_ino) { - strlcpy(cwd, pwd, PATH_MAX); - } - } - return cwd; -} - -const char *make_nonrelative_path(const char *path) -{ - static char buf[PATH_MAX + 1]; - - if (is_absolute_path(path)) { - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) - die ("Too long path: %.*s", 60, path); - } else { - const char *cwd = get_pwd_cwd(); - if (!cwd) - die("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) - die ("Too long path: %.*s", 60, path); - } - return buf; -} - const char *make_relative_path(const char *abs, const char *base) { static char buf[PATH_MAX + 1]; From bf74a88244c4fe631535b50ef090541dddf9029d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:56 +0200 Subject: [PATCH 58/62] Windows: Make $(gitexecdir) relative Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index fceca92184..3a0dc88c85 100644 --- a/Makefile +++ b/Makefile @@ -756,6 +756,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe + gitexecdir = ../libexec/git-core template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif From 35eeef47220c68c92d0f377f5678c42da2232c20 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:57 +0200 Subject: [PATCH 59/62] Windows: Make sure argv[0] has a path Since the exec-path on Windows is derived from the program invocation path, we must ensure that argv[0] always has a path. Unfortunately, if a program is invoked from CMD, argv[0] has no path. But on the other hand, the C runtime offers a global variable, _pgmptr, that always has the full path to the program. We hook into main() with a preprocessor macro, where we replace argv[0]. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 8ffec51e73..290a9e6f82 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -223,3 +223,15 @@ void mingw_open_html(const char *path); char **copy_environ(void); void free_environ(char **env); char **env_setenv(char **env, const char *name); + +/* + * A replacement of main() that ensures that argv[0] has a path + */ + +#define main(c,v) main(int argc, const char **argv) \ +{ \ + static int mingw_main(); \ + argv[0] = xstrdup(_pgmptr); \ + return mingw_main(argc, argv); \ +} \ +static int mingw_main(c,v) From 7b4b59a963c726d30b319a79c1f8243a82d6e12f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 21:19:58 +0200 Subject: [PATCH 60/62] Windows: Do not compile git-shell Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3a0dc88c85..798a2f2f77 100644 --- a/Makefile +++ b/Makefile @@ -293,7 +293,6 @@ PROGRAMS += git-pack-redundant$X PROGRAMS += git-patch-id$X PROGRAMS += git-receive-pack$X PROGRAMS += git-send-pack$X -PROGRAMS += git-shell$X PROGRAMS += git-show-index$X PROGRAMS += git-unpack-file$X PROGRAMS += git-update-server-info$X @@ -823,6 +822,7 @@ EXTLIBS += -lz ifndef NO_POSIX_ONLY_PROGRAMS PROGRAMS += git-daemon$X PROGRAMS += git-imap-send$X + PROGRAMS += git-shell$X endif ifndef NO_OPENSSL OPENSSL_LIBSSL = -lssl @@ -1363,7 +1363,7 @@ endif fi && \ { $(foreach p,$(BUILT_INS), $(RM) "$$execdir/$p" && ln "$$execdir/git$X" "$$execdir/$p" ;) } && \ $(RM) "$$execdir/git$X" && \ - ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-shell$X" + ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: $(MAKE) -C Documentation install From 128de6576743901b11f243509753320038e74ba7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 25 Jul 2008 11:32:37 -0400 Subject: [PATCH 61/62] git-svn: teach dcommit about svn auto-props Subversion repositories often require files to have properties such as svn:mime-type and svn:eol-style set when they are added. Users typically set these properties automatically using the SVN auto-props feature with 'svn add'. This commit teaches dcommit to look at the user SVN configuration and apply matching auto-props entries for files added by a diff as it is applied to the SVN remote. Signed-off-by: Brad King Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 53 +++++++++++++++++ t/t9124-git-svn-dcommit-auto-props.sh | 86 +++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100755 t/t9124-git-svn-dcommit-auto-props.sh diff --git a/git-svn.perl b/git-svn.perl index 2e0e55242f..cf6dbbc427 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3340,6 +3340,7 @@ sub new { $self->{rm} = { }; $self->{path_prefix} = length $self->{svn_path} ? "$self->{svn_path}/" : ''; + $self->{config} = $opts->{config}; return $self; } @@ -3528,6 +3529,57 @@ sub ensure_path { return $bat->{$c}; } +# Subroutine to convert a globbing pattern to a regular expression. +# From perl cookbook. +sub glob2pat { + my $globstr = shift; + my %patmap = ('*' => '.*', '?' => '.', '[' => '[', ']' => ']'); + $globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge; + return '^' . $globstr . '$'; +} + +sub check_autoprop { + my ($self, $pattern, $properties, $file, $fbat) = @_; + # Convert the globbing pattern to a regular expression. + my $regex = glob2pat($pattern); + # Check if the pattern matches the file name. + if($file =~ m/($regex)/) { + # Parse the list of properties to set. + my @props = split(/;/, $properties); + foreach my $prop (@props) { + # Parse 'name=value' syntax and set the property. + if ($prop =~ /([^=]+)=(.*)/) { + my ($n,$v) = ($1,$2); + for ($n, $v) { + s/^\s+//; s/\s+$//; + } + $self->change_file_prop($fbat, $n, $v); + } + } + } +} + +sub apply_autoprops { + my ($self, $file, $fbat) = @_; + my $conf_t = ${$self->{config}}{'config'}; + no warnings 'once'; + # Check [miscellany]/enable-auto-props in svn configuration. + if (SVN::_Core::svn_config_get_bool( + $conf_t, + $SVN::_Core::SVN_CONFIG_SECTION_MISCELLANY, + $SVN::_Core::SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, + 0)) { + # Auto-props are enabled. Enumerate them to look for matches. + my $callback = sub { + $self->check_autoprop($_[0], $_[1], $file, $fbat); + }; + SVN::_Core::svn_config_enumerate( + $conf_t, + $SVN::_Core::SVN_CONFIG_SECTION_AUTO_PROPS, + $callback); + } +} + sub A { my ($self, $m) = @_; my ($dir, $file) = split_path($m->{file_b}); @@ -3535,6 +3587,7 @@ sub A { my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, undef, -1); print "\tA\t$m->{file_b}\n" unless $::_q; + $self->apply_autoprops($file, $fbat); $self->chg_file($fbat, $m); $self->close_file($fbat,undef,$self->{pool}); } diff --git a/t/t9124-git-svn-dcommit-auto-props.sh b/t/t9124-git-svn-dcommit-auto-props.sh new file mode 100755 index 0000000000..8223c5909e --- /dev/null +++ b/t/t9124-git-svn-dcommit-auto-props.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# +# Copyright (c) 2008 Brad King + +test_description='git-svn dcommit honors auto-props' + +. ./lib-git-svn.sh + +generate_auto_props() { +cat << EOF +[miscellany] +enable-auto-props=$1 +[auto-props] +*.sh = svn:mime-type=application/x-shellscript; svn:eol-style=LF +*.txt = svn:mime-type=text/plain; svn:eol-style = native +EOF +} + +test_expect_success 'initialize git-svn' ' + mkdir import && + ( + cd import && + echo foo >foo && + svn import -m "import for git-svn" . "$svnrepo" + ) && + rm -rf import && + git-svn init "$svnrepo" + git-svn fetch +' + +test_expect_success 'enable auto-props config' ' + cd "$gittestrepo" && + mkdir user && + generate_auto_props yes >user/config +' + +test_expect_success 'add files matching auto-props' ' + cd "$gittestrepo" && + echo "#!$SHELL_PATH" >exec1.sh && + chmod +x exec1.sh && + echo "hello" >hello.txt && + echo bar >bar && + git add exec1.sh hello.txt bar && + git commit -m "files for enabled auto-props" && + git svn dcommit --config-dir=user +' + +test_expect_success 'disable auto-props config' ' + cd "$gittestrepo" && + generate_auto_props no >user/config +' + +test_expect_success 'add files matching disabled auto-props' ' + cd "$gittestrepo" && + echo "#$SHELL_PATH" >exec2.sh && + chmod +x exec2.sh && + echo "world" >world.txt && + echo zot >zot && + git add exec2.sh world.txt zot && + git commit -m "files for disabled auto-props" && + git svn dcommit --config-dir=user +' + +test_expect_success 'check resulting svn repository' ' + mkdir work && + cd work && + svn co "$svnrepo" && + cd svnrepo && + + # Check properties from first commit. + test "x$(svn propget svn:executable exec1.sh)" = "x*" && + test "x$(svn propget svn:mime-type exec1.sh)" = \ + "xapplication/x-shellscript" && + test "x$(svn propget svn:mime-type hello.txt)" = "xtext/plain" && + test "x$(svn propget svn:eol-style hello.txt)" = "xnative" && + test "x$(svn propget svn:mime-type bar)" = "x" && + + # Check properties from second commit. + test "x$(svn propget svn:executable exec2.sh)" = "x*" && + test "x$(svn propget svn:mime-type exec2.sh)" = "x" && + test "x$(svn propget svn:mime-type world.txt)" = "x" && + test "x$(svn propget svn:eol-style world.txt)" = "x" && + test "x$(svn propget svn:mime-type zot)" = "x" +' + +test_done From b0320eaf6a25fbc4adf35d611c27006e6d853aa8 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 25 Jul 2008 22:49:08 +0200 Subject: [PATCH 62/62] git-reset: Let -q hush "locally modified" messages "git reset -q" is advertised to "only report errors", but "locally modified" messages are still shown. They are not errors but diagnostics. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- builtin-reset.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/builtin-reset.c b/builtin-reset.c index 4d246c31b1..c24c219091 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -85,7 +85,7 @@ static void print_new_head_line(struct commit *commit) printf("\n"); } -static int update_index_refresh(int fd, struct lock_file *index_lock) +static int update_index_refresh(int fd, struct lock_file *index_lock, int flags) { int result; @@ -96,7 +96,8 @@ static int update_index_refresh(int fd, struct lock_file *index_lock) if (read_cache() < 0) return error("Could not read index"); - result = refresh_cache(REFRESH_SAY_CHANGED) ? 1 : 0; + + result = refresh_cache(flags) ? 1 : 0; if (write_cache(fd, active_cache, active_nr) || commit_locked_index(index_lock)) return error ("Could not refresh index"); @@ -128,7 +129,7 @@ static void update_index_from_diff(struct diff_queue_struct *q, } static int read_from_tree(const char *prefix, const char **argv, - unsigned char *tree_sha1) + unsigned char *tree_sha1, int refresh_flags) { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd, index_was_discarded = 0; @@ -152,7 +153,7 @@ static int read_from_tree(const char *prefix, const char **argv, if (!index_was_discarded) /* The index is still clobbered from do_diff_cache() */ discard_cache(); - return update_index_refresh(index_fd, lock); + return update_index_refresh(index_fd, lock, refresh_flags); } static void prepend_reflog_action(const char *action, char *buf, size_t size) @@ -246,7 +247,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix) else if (reset_type != NONE) die("Cannot do %s reset with paths.", reset_type_names[reset_type]); - return read_from_tree(prefix, argv + i, sha1); + return read_from_tree(prefix, argv + i, sha1, + quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED); } if (reset_type == NONE) reset_type = MIXED; /* by default */ @@ -286,7 +288,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix) case SOFT: /* Nothing else to do. */ break; case MIXED: /* Report what has not been updated. */ - update_index_refresh(0, NULL); + update_index_refresh(0, NULL, + quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED); break; }