* Re: Java GIT/Eclipse GIT version 0.1.1
From: Shawn Pearce @ 2006-07-31 4:22 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0607301047150.9789@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> wrote:
> On Fri, 28 Jul 2006, Shawn Pearce wrote:
>
> > I would appreciate any and all input, feedback, etc. that anyone
> > might have on this library or plugin. Patches are of course
> > certainly welcome. :-)
>
> I'm going to try to do a Servlet (+ my stuff) implementation of essentiall
> gitweb, with the idea that it could integrate with project management
> software (i.e., link completed tasks to the commit which completed them,
> regressions to the commit that broke things, fixes to the commit that
> fixed them, etc, with the UI for choosing values letting you browse the
> actual content and validating that the hash you give exists).
>
> I don't think I need anything you don't already have, but I'll write
> documentation as I figure out what's going on, if you want that.
Sure. Any improvements would be welcome. :-)
Please keep in mind that when I post the next update to the
repository I'm going to switch the license to the LGPL.
Apparently the Apache License has issues with GPL (I didn't know
this until just recently) and the GPL is definately incompatible
with the Eclipse license (also just found this out).
--
Shawn.
^ permalink raw reply
* Re: [PATCH] gitweb: use out-of-line GIT logo.
From: Luben Tuikov @ 2006-07-31 3:59 UTC (permalink / raw)
To: Martin Waitz, git
In-Reply-To: <20060730223839.GB16364@admingilde.org>
--- Martin Waitz <tali@admingilde.org> wrote:
> Use the normal web server instead of the CGI to provide the git logo,
> just like the gitweb.css.
NACK. I'd really rather keep the logo (which is essential) in the
file itself. This would mean one less file to worry about.
Luben
> Signed-off-by: Martin Waitz <tali@admingilde.org>
> ---
> Makefile | 2 ++
> gitweb/README | 2 ++
> gitweb/git-logo.png | Bin
> gitweb/gitweb.pl | 29 ++++-------------------------
> 4 files changed, 8 insertions(+), 25 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index bd59d6b58d1cfcaecd033f186d7c2cc537416b75..40e129490b337a70f0ee5c60ce25980359e658c9 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -122,6 +122,7 @@ GITWEB_PROJECTROOT = /pub/git
> GITWEB_LIST =
> GITWEB_HOMETEXT = indextext.html
> GITWEB_CSS = gitweb.css
> +GITWEB_LOGO = git-logo.png
>
> export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
>
> @@ -584,6 +585,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.pl
> -e 's|@@GITWEB_LIST@@|$(GITWEB_LIST)|g' \
> -e 's|@@GITWEB_HOMETEXT@@|$(GITWEB_HOMETEXT)|g' \
> -e 's|@@GITWEB_CSS@@|$(GITWEB_CSS)|g' \
> + -e 's|@@GITWEB_LOGO@@|$(GITWEB_LOGO)|g' \
> $< >$@+
> chmod +x $@+
> mv $@+ $@
> diff --git a/gitweb/README b/gitweb/README
> index ed939e2fb5264cce24e770272583b12372c3ab68..1b2180c7314ea3d10db78c88b48092a70491f8b8 100644
> --- a/gitweb/README
> +++ b/gitweb/README
> @@ -21,6 +21,8 @@ You can specify the following configurat
> overview page.
> * GITWEB_CSS
> Points to the location where you put gitweb.css on your web server.
> + * GITWEB_LOGO
> + Points to the location where you put git-logo.png on your web server.
>
> Any comment/question/concern to:
> Kay Sievers <kay.sievers@vrfy.org>
> diff --git a/gitweb/git-logo.png b/gitweb/git-logo.png
> new file mode 100644
> index 0000000000000000000000000000000000000000..16ae8d5382de5ffe63b54139245143513a87446e
> GIT binary patch
> literal 208
> zc%17D@N?(olHy`uVBq!ia0vp^9zZP3!VDyJZ(h*_QW60^A+G=b|4&GW-LQTYLj%LP
> zv&RoGFuZv2?ECj`Q+bxV1Jx9Jx;TbtoKN;hS77mqk>KLcN(xR?VB+A-bX~J>A)^7$
> z<ODOdpotq91+P5}P07hQlas@<h^Ig+iB0QZlI&(irr;$UFBq65)WQU>JXDx2{a_29
> zsY;<{(@cXMleq+Ux^^7wU9iYSkxkvP$)WY2Yo|g1Bf}C~#iK$pv;G0CXYh3Ob6Mw<
> G&;$VMfkjjR
>
> diff --git a/gitweb/gitweb.pl b/gitweb/gitweb.pl
> index 8e05c335f801d4c52a9b348fa56fccfae36ce621..e6e9f83076630958d0134bfbb29989882f6f1d0d 100755
> --- a/gitweb/gitweb.pl
> +++ b/gitweb/gitweb.pl
> @@ -51,6 +51,8 @@ our $home_text = "@@GITWEB_HOMETEXT@@";
>
> # URI of default stylesheet
> our $stylesheet = "@@GITWEB_CSS@@";
> +# URI of GIT logo
> +our $logo = "@@GITWEB_LOGO@@";
>
> # source of projects list
> our $projects_list = "@@GITWEB_LIST@@" || "$projectroot";
> @@ -70,10 +72,7 @@ if (defined $action) {
> undef $action;
> die_error(undef, "Invalid action parameter.");
> }
> - if ($action eq "git-logo.png") {
> - git_logo();
> - exit;
> - } elsif ($action eq "opml") {
> + if ($action eq "opml") {
> git_opml();
> exit;
> }
> @@ -320,7 +319,7 @@ sub git_header_html {
> EOF
> print "<div class=\"page_header\">\n" .
> "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git
> documentation\">" .
> - "<img src=\"$my_uri?" . esc_param("a=git-logo.png") . "\" width=\"72\" height=\"27\"
> alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
> + "<img src=\"$logo\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right;
> border-width:0px;\"/>" .
> "</a>\n";
> print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
> if (defined $project) {
> @@ -755,26 +754,6 @@ sub date_str {
> return %date;
> }
>
> -# git-logo (cached in browser for one day)
> -sub git_logo {
> - binmode STDOUT, ':raw';
> - print $cgi->header(-type => 'image/png', -expires => '+1d');
> - # cat git-logo.png | hexdump -e '16/1 " %02x" "\n"' | sed 's/ /\\x/g'
> - print "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
> - "\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
> - "\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
> - "\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
> - "\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
> - "\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
> - "\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
> - "\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
> - "\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
> - "\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
> - "\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
> - "\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
> - "\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
> -}
> -
> sub get_file_owner {
> my $path = shift;
>
> --
> 1.4.2.rc2.gf055
>
> --
> Martin Waitz
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH] gitweb: fill in gitweb configuration by Makefile
From: Luben Tuikov @ 2006-07-31 3:57 UTC (permalink / raw)
To: Martin Waitz, git
In-Reply-To: <20060730223754.GA16364@admingilde.org>
--- Martin Waitz <tali@admingilde.org> wrote:
> Generate gitweb/gitweb.cgi to reduce the need to patch gitweb.cgi by
> the end user.
> The GIT installation directory and version are already known by the
> Makefile, they can be inserted directly into gitweb.
> All other gitweb configuration parameters can now be specified
> by providing GITWEB_* variables while building GIT.
> These are described in gitweb/README.
NACK.
I don't like it. While this method works, it is too much effort
to have to run make to do this, plus it pollutes your tree.
Instead, what you can do is make gitweb.cgi read a text file
from . which has those variables defined.
This way, I can just copy gitweb.cgi into my web-server directory
and voila it works, since the variable definition file would
always be there. This way:
- no need to run make to build "gitweb.cgi" or "gitweb.pl" whatever
you call it,
- no need to pollute your tree with site defined variables,
- simple copy (cp) would install a working version, instead of
the current cp + patch with local settings method.
Luben
>
> Signed-off-by: Martin Waitz <tali@admingilde.org>
> ---
> Makefile | 25 +++++++++++++++++++++++--
> gitweb/.gitignore | 1 +
> gitweb/README | 17 +++++++++++++++++
> gitweb/{gitweb.cgi => gitweb.pl} | 15 +++++++--------
> 4 files changed, 48 insertions(+), 10 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index 8349e3defacca69ae48c477ff99be527b9af3b77..bd59d6b58d1cfcaecd033f186d7c2cc537416b75 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -116,6 +116,13 @@ template_dir = $(prefix)/share/git-core/
> GIT_PYTHON_DIR = $(prefix)/share/git-core/python
> # DESTDIR=
>
> +# default configuration for gitweb
> +GITWEB_SITENAME =
> +GITWEB_PROJECTROOT = /pub/git
> +GITWEB_LIST =
> +GITWEB_HOMETEXT = indextext.html
> +GITWEB_CSS = gitweb.css
> +
> export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
>
> CC = gcc
> @@ -509,7 +516,7 @@ LIB_OBJS += $(COMPAT_OBJS)
> export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
> ### Build rules
>
> -all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk
> +all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
>
> all:
> $(MAKE) -C templates
> @@ -567,6 +574,20 @@ git-status: git-commit
> cp $< $@+
> mv $@+ $@
>
> +gitweb/gitweb.cgi: gitweb/gitweb.pl
> + rm -f $@ $@+
> + sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
> + -e 's|@@GIT_VERSION@@|$(GIT_VERSION)|g' \
> + -e 's|@@GIT_BINDIR@@|$(bindir)|g' \
> + -e 's|@@GITWEB_SITENAME@@|$(GITWEB_SITENAME)|g' \
> + -e 's|@@GITWEB_PROJECTROOT@@|$(GITWEB_PROJECTROOT)|g' \
> + -e 's|@@GITWEB_LIST@@|$(GITWEB_LIST)|g' \
> + -e 's|@@GITWEB_HOMETEXT@@|$(GITWEB_HOMETEXT)|g' \
> + -e 's|@@GITWEB_CSS@@|$(GITWEB_CSS)|g' \
> + $< >$@+
> + chmod +x $@+
> + mv $@+ $@
> +
> git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
> rm -f $@ $@+
> sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
> @@ -577,7 +598,7 @@ git-instaweb: git-instaweb.sh gitweb/git
> -e '/@@GITWEB_CGI@@/d' \
> -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
> -e '/@@GITWEB_CSS@@/d' \
> - $@.sh | sed "s|/usr/bin/git|$(bindir)/git|" > $@+
> + $@.sh > $@+
> chmod +x $@+
> mv $@+ $@
>
> diff --git a/gitweb/.gitignore b/gitweb/.gitignore
> new file mode 100644
> index 0000000000000000000000000000000000000000..e83127e3f09f8496d0cd07b8f632ff341c96fd00
> --- /dev/null
> +++ b/gitweb/.gitignore
> @@ -0,0 +1 @@
> +gitweb.cgi
> diff --git a/gitweb/README b/gitweb/README
> index 8d672762eab427f3b732626d6b3f8e05a7e8f8c9..ed939e2fb5264cce24e770272583b12372c3ab68 100644
> --- a/gitweb/README
> +++ b/gitweb/README
> @@ -5,5 +5,22 @@ The one working on:
>
> From the git version 1.4.0 gitweb is bundled with git.
>
> +
> +How to configure gitweb for your local system:
> +
> +You can specify the following configuration variables when building GIT:
> + * GITWEB_SITENAME
> + Shown in the title of all generated pages, defaults to the servers name.
> + * GITWEB_PROJECTROOT
> + The root directory for all projects shown by gitweb.
> + * GITWEB_LIST
> + points to a directory to scan for projects (defaults to project root)
> + or to a file for explicit listing of projects.
> + * GITWEB_HOMETEXT
> + points to an .html file which is included on the gitweb project
> + overview page.
> + * GITWEB_CSS
> + Points to the location where you put gitweb.css on your web server.
> +
> Any comment/question/concern to:
> Kay Sievers <kay.sievers@vrfy.org>
> diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.pl
> similarity index 100%
> rename from gitweb/gitweb.cgi
> rename to gitweb/gitweb.pl
> index 243a2921f849568260e848201d238b3b9fe7e1f2..8e05c335f801d4c52a9b348fa56fccfae36ce621 100755
> --- a/gitweb/gitweb.cgi
> +++ b/gitweb/gitweb.pl
> @@ -24,14 +24,14 @@ our $rss_link = "";
>
> # core git executable to use
> # this can just be "git" if your webserver has a sensible PATH
> -our $GIT = "/usr/bin/git";
> +our $GIT = "@@GIT_BINDIR@@/git";
>
> # absolute fs-path which will be prepended to the project path
> #our $projectroot = "/pub/scm";
> -our $projectroot = "/home/kay/public_html/pub/scm";
> +our $projectroot = "@@GITWEB_PROJECTROOT@@";
>
> # version of the core git binary
> -our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
> +our $git_version = "@@GIT_VERSION@@";
>
> # location for temporary files needed for diffs
> our $git_temp = "/tmp/gitweb";
> @@ -44,17 +44,16 @@ our $home_link = $my_uri;
>
> # name of your site or organization to appear in page titles
> # replace this with something more descriptive for clearer bookmarks
> -our $site_name = $ENV{'SERVER_NAME'} || "Untitled";
> +our $site_name = "@@GITWEB_SITENAME@@" || $ENV{'SERVER_NAME'} || "Untitled";
>
> # html text to include at home page
> -our $home_text = "indextext.html";
> +our $home_text = "@@GITWEB_HOMETEXT@@";
>
> # URI of default stylesheet
> -our $stylesheet = "gitweb.css";
> +our $stylesheet = "@@GITWEB_CSS@@";
>
> # source of projects list
> -#our $projects_list = $projectroot;
> -our $projects_list = "index/index.aux";
> +our $projects_list = "@@GITWEB_LIST@@" || "$projectroot";
>
> # default blob_plain mimetype and default charset for text/plain blob
> our $default_blob_plain_mimetype = 'text/plain';
> --
> 1.4.2.rc2.gf055
>
> --
> Martin Waitz
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH] gitweb: fill in gitweb configuration by Makefile
From: Junio C Hamano @ 2006-07-31 1:20 UTC (permalink / raw)
To: Martin Waitz; +Cc: git
In-Reply-To: <20060730223754.GA16364@admingilde.org>
Martin Waitz <tali@admingilde.org> writes:
> diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.pl
> similarity index 100%
> rename from gitweb/gitweb.cgi
> rename to gitweb/gitweb.pl
> index 243a2921f849568260e848201d238b3b9fe7e1f2..8e05c335f801d4c52a9b348fa56fccfae36ce621 100755
> --- a/gitweb/gitweb.cgi
> +++ b/gitweb/gitweb.pl
> @@ -24,14 +24,14 @@ our $rss_link = "";
>
> # core git executable to use
> # this can just be "git" if your webserver has a sensible PATH
> -our $GIT = "/usr/bin/git";
> +our $GIT = "@@GIT_BINDIR@@/git";
>
> # absolute fs-path which will be prepended to the project path
> #our $projectroot = "/pub/scm";
> -our $projectroot = "/home/kay/public_html/pub/scm";
> +our $projectroot = "@@GITWEB_PROJECTROOT@@";
>
> # version of the core git binary
> -our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
> +our $git_version = "@@GIT_VERSION@@";
I think the other parts are sensible but I am not sure if we
want to report the version of git distribution (your patch), or
the version of git binary the cgi script happens to use (the
current implementation).
^ permalink raw reply
* Re: [PATCH 1/1] Make git-tar-tree more flexible
From: Junio C Hamano @ 2006-07-31 1:17 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0607310225190.29667@wbgn013.biozentrum.uni-wuerzburg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> So how about this:
>
> -- 8< --
> [PATCH] tar-tree: illustrate an obscure feature better
>
> Since you can tar just a subdirectory of a certain revision, tell
> the users so, by showing an example how to do it.
Sounds sensible. Thanks.
^ permalink raw reply
* git-diff between /dev/null and blob
From: Jakub Narebski @ 2006-07-31 1:07 UTC (permalink / raw)
To: git
Currently, due to artifact of git-diff argument parsing you can get diff
of two arbitrary blobs given by their sha1 id, e.g.
git diff ab8050ceb4e43522e858768cc2c02fcb91839370 fd05278808d458602587bb024a48726018d30926
but you cannot use git-diff to create diff between two files, or a file
and blob.
In particular, I couldn't make "creation" patch, i.e. patch between
/dev/null and specified blob. If it would be possible, we could lose
gitweb.cgi dependency on diff.
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: [PATCH 1/3] read-trees: refactor the unpack_trees() part
From: Johannes Schindelin @ 2006-07-31 0:48 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0607310205260.29667@wbgn013.biozentrum.uni-wuerzburg.de>
Hi,
On Mon, 31 Jul 2006, Johannes Schindelin wrote:
> How about this (on top of that patch):
>
> -- 8< --
> [PATCH 1.5/3] unpack-trees: please C99 standard
Of course, I got bitten by "git-commit" not regarding any
git-update-index'ed files after starting the editor... This is needed as
well:
diff --git a/unpack-trees.c b/unpack-trees.c
index 3cb92cb..e595d23 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -381,6 +381,7 @@ int unpack_trees(struct object_list *tre
state.refresh_cache = 1;
o->merge_size = len;
+ memset(&df_conflict_entry, 0, sizeof(df_conflict_entry));
o->df_conflict_entry = &df_conflict_entry;
if (len) {
Sorry for the noise.
Ciao,
Dscho
^ permalink raw reply related
* Re: [PATCH] pager: config variable pager.program
From: Junio C Hamano @ 2006-07-31 0:43 UTC (permalink / raw)
To: Matthias Lederhofer; +Cc: git
In-Reply-To: <E1G6wM1-00040z-Bu@moooo.ath.cx>
I am not enthused about any configuration stored in .git/config
to override the environment variables. Files are to store
reasonable default, and command line flags and environments are
to override them, but this patch does it the other way around.
^ permalink raw reply
* Re: [PATCH] pager: config variable pager.color
From: Junio C Hamano @ 2006-07-31 0:43 UTC (permalink / raw)
To: Matthias Lederhofer; +Cc: git, Johannes Schindelin
In-Reply-To: <E1G6zPH-00062L-Je@moooo.ath.cx>
Matthias Lederhofer <matled@gmx.net> writes:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
>> Why? The three users of cmd_log_walk() need to call setup_pager()
>> explicitely, when cmd_log_walk() can do it for them?
>
> The explanation is below the commit message:
> "setup_pager has to be called before git_diff_ui_config because the
> latter uses pager_use_color initialized by setup_pager."
If that is the reason, perhaps we could restructure the setting
and use of of diff_use_color_default like the attached, which
would be cleaner.
-- >8 --
diff --git a/cache.h b/cache.h
index 8891073..913be6a 100644
--- a/cache.h
+++ b/cache.h
@@ -392,6 +392,7 @@ extern int receive_keep_pack(int fd[2],
/* pager.c */
extern void setup_pager(void);
extern int pager_in_use;
+extern int pager_use_color;
/* base85 */
int decode_85(char *dst, char *line, int linelen);
diff --git a/diff.c b/diff.c
index 6198a61..043ecb1 100644
--- a/diff.c
+++ b/diff.c
@@ -173,14 +173,8 @@ int git_diff_ui_config(const char *var,
if (!strcmp(var, "diff.color")) {
if (!value)
diff_use_color_default = 1; /* bool */
- else if (!strcasecmp(value, "auto")) {
- diff_use_color_default = 0;
- if (isatty(1) || pager_in_use) {
- char *term = getenv("TERM");
- if (term && strcmp(term, "dumb"))
- diff_use_color_default = 1;
- }
- }
+ else if (!strcasecmp(value, "auto"))
+ diff_use_color_default = -1; /* decide in setup */
else if (!strcasecmp(value, "never"))
diff_use_color_default = 0;
else if (!strcasecmp(value, "always"))
@@ -1509,6 +1503,14 @@ void diff_setup(struct diff_options *opt
options->change = diff_change;
options->add_remove = diff_addremove;
+ if (diff_use_color_default < 0) {
+ diff_use_color_default = 0;
+ if (isatty(1) || (pager_in_use && pager_use_color)) {
+ char *term = getenv("TERM");
+ if (term && strcmp(term, "dumb"))
+ diff_use_color_default = 1;
+ }
+ }
options->color_diff = diff_use_color_default;
options->detect_rename = diff_detect_rename_default;
}
diff --git a/environment.c b/environment.c
index 558801a..1ce3411 100644
--- a/environment.c
+++ b/environment.c
@@ -23,6 +23,7 @@ int shared_repository = PERM_UMASK;
const char *apply_default_whitespace = NULL;
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
int pager_in_use;
+int pager_use_color = 1;
static int dyn_git_object_dir, dyn_git_index_file, dyn_git_graft_file;
static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
diff --git a/pager.c b/pager.c
index 3f753f6..e86ea9e 100644
--- a/pager.c
+++ b/pager.c
@@ -14,6 +14,10 @@ static int git_pager_config(const char *
pager = strdup(value);
return 0;
}
+ if (!strcmp(var, "pager.color")) {
+ pager_use_color = git_config_bool(var, value);
+ return 0;
+ }
return 0;
}
^ permalink raw reply related
* Re: [PATCH 1/1] Make git-tar-tree more flexible
From: Johannes Schindelin @ 2006-07-31 0:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Anand Kumria, git
In-Reply-To: <7vbqr6dd4t.fsf@assigned-by-dhcp.cox.net>
Hi,
On Sun, 30 Jul 2006, Junio C Hamano wrote:
> Anand Kumria <wildfire@progsoc.org> writes:
>
> > If you have a project which is setup like:
> > project
> > website
> > and you decide you wish to generate a tar archive of _just_ the 'project'
> > portion, git-tar-tree is not able to help. This patch adds two parameters
> > which can assist.
>
> No need I see.
>
> git tar-tree tag-1.0:project project-1.0/project
> git tar-tree tag-1.0:project project-1.0
So how about this:
-- 8< --
[PATCH] tar-tree: illustrate an obscure feature better
Since you can tar just a subdirectory of a certain revision, tell
the users so, by showing an example how to do it.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
Documentation/git-tar-tree.txt | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 7a99acf..1e1c7fa 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -71,6 +71,11 @@ git tar-tree --remote=example.com:git.gi
Get a tarball v1.4.0 from example.com.
+git tar-tree HEAD:Documentation/ git-docs > git-1.4.0-docs.tar::
+
+ Put everything in the current head's Documentation/ directory
+ into 'git-1.4.0-docs.tar', with the prefix 'git-docs/'.
+
Author
------
Written by Rene Scharfe.
^ permalink raw reply related
* [PATCH 17] gitweb: Ref refactoring - use git_get_referencing for marking tagged/head commits
From: Jakub Narebski @ 2006-07-31 0:21 UTC (permalink / raw)
To: git
In-Reply-To: <200607292239.11034.jnareb@gmail.com>
Use git_get_referencing to get HTML code for markers showing which
refs (tags and heads) point to current commit. It would be much
easier to change format of markers in one or two places than thorough
the gitweb.cgi file.
Added comment about read_info_ref subroutine: for $type == "" (empty
argument) it saves only last path part of ref name e.g. from
'refs/heads/jn/gitweb' it would leave only 'gitweb'.
Some reordering. Added $ref in one place.
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
gitweb/gitweb.cgi | 53 ++++++++++++++++++++++-------------------------------
1 files changed, 22 insertions(+), 31 deletions(-)
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 83ea97a..dab6068 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1024,6 +1024,8 @@ sub read_info_ref {
open my $fd, "$projectroot/$project/info/refs" or return;
while (my $line = <$fd>) {
chomp $line;
+ # attention: for $type == "" it saves only last path part of ref name
+ # e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
if (defined $refs{$1}) {
$refs{$1} .= " / $2";
@@ -1036,6 +1038,16 @@ sub read_info_ref {
return \%refs;
}
+sub git_get_referencing {
+ my ($refs, $id) = @_;
+
+ if (defined $refs->{$id}) {
+ return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
+ } else {
+ return "";
+ }
+}
+
sub git_read_refs {
my $ref_dir = shift;
my @reflist;
@@ -1151,10 +1163,7 @@ sub git_summary {
}
$alternate ^= 1;
if ($i-- > 0) {
- my $ref = "";
- if (defined $refs->{$commit}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
- }
+ my $ref = git_get_referencing($refs, $commit);
print "<td><i>$co{'age_string'}</i></td>\n" .
"<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
"<td>";
@@ -1728,10 +1737,7 @@ sub git_tree {
$/ = "\n";
my $refs = read_info_ref();
- my $ref = "";
- if (defined $refs->{$hash_base}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$hash_base}) . "</span>";
- }
+ my $ref = git_get_referencing($refs, $hash_base);
git_header_html();
my $base_key = "";
my $base = "";
@@ -1912,10 +1918,7 @@ sub git_log {
}
for (my $i = ($page * 100); $i <= $#revlist; $i++) {
my $commit = $revlist[$i];
- my $ref = "";
- if (defined $refs->{$commit}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
- }
+ my $ref = git_get_referencing($refs, $commit);
my %co = git_read_commit($commit);
next if !%co;
my %ad = date_str($co{'author_epoch'});
@@ -1979,16 +1982,13 @@ sub git_commit {
$expires = "+1d";
}
my $refs = read_info_ref();
- my $ref = "";
- if (defined $refs->{$co{'id'}}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$co{'id'}}) . "</span>";
- }
- git_header_html(undef, $expires);
+ my $ref = git_get_referencing($refs, $co{'id'});
my $formats_nav = '';
if (defined $file_name && defined $co{'parent'}) {
my $parent = $co{'parent'};
$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;hb=$parent;f=$file_name")}, "blame");
}
+ git_header_html(undef, $expires);
git_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff',
$hash, $co{'tree'}, $hash,
$formats_nav);
@@ -1996,7 +1996,7 @@ sub git_commit {
if (defined $co{'parent'}) {
git_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
} else {
- git_header_div('tree', esc_html($co{'title'}), $co{'tree'}, $hash);
+ git_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash);
}
print "<div class=\"title_text\">\n" .
"<table cellspacing=\"0\">\n";
@@ -2206,13 +2206,10 @@ sub git_commitdiff {
$expires = "+1d";
}
my $refs = read_info_ref();
- my $ref = "";
- if (defined $refs->{$co{'id'}}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$co{'id'}}) . "</span>";
- }
- git_header_html(undef, $expires);
+ my $ref = git_get_referencing($refs, $co{'id'});
my $formats_nav =
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
+ git_header_html(undef, $expires);
git_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
git_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
print "<div class=\"page_body\">\n";
@@ -2364,10 +2361,7 @@ sub git_history {
if (!%co) {
next;
}
- my $ref = "";
- if (defined $refs->{$commit}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
- }
+ my $ref = git_get_referencing($refs, $commit);
if ($alternate) {
print "<tr class=\"dark\">\n";
} else {
@@ -2559,10 +2553,7 @@ sub git_shortlog {
my $alternate = 0;
for (my $i = ($page * 100); $i <= $#revlist; $i++) {
my $commit = $revlist[$i];
- my $ref = "";
- if (defined $refs->{$commit}) {
- $ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
- }
+ my $ref = git_get_referencing($refs, $commit);
my %co = git_read_commit($commit);
my %ad = date_str($co{'author_epoch'});
if ($alternate) {
--
1.4.0
^ permalink raw reply related
* Re: [PATCH 1/3] read-trees: refactor the unpack_trees() part
From: Johannes Schindelin @ 2006-07-31 0:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v4pwydbbr.fsf@assigned-by-dhcp.cox.net>
Hi,
On Sun, 30 Jul 2006, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > diff --git a/unpack-trees.h b/unpack-trees.h
> > new file mode 100644
> > index 0000000..babfcd7
> > --- /dev/null
> > +++ b/unpack-trees.h
> > @@ -0,0 +1,30 @@
> > +#ifndef UNPACK_TREES_H
> > +#define UNPACK_TREES_H
> >...
> > +struct unpack_trees_options {
> > + int reset;
> > + int merge;
> > + int update;
> > + int index_only;
> > + int nontrivial_merge;
> > + int trivial_merges_only;
> > + int verbose_update;
> > + int aggressive;
> > + const char *prefix;
> > + merge_fn_t fn;
> > +
> > + int head_idx;
> > + int merge_size;
> > +
> > + struct cache_entry df_conflict_entry;
> > +};
>
> Hmmmm.....
>
> gcc -o unpack-trees.o -c -O2 -Werror -ansi -pedantic -std=c99 -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wall -Wdeclaration-after-statement -g -DSHA1_HEADER='<openssl/sha.h>' -DNO_STRLCPY unpack-trees.c
> cc1: warnings being treated as errors
> In file included from unpack-trees.c:7:
> unpack-trees.h:24: warning: invalid use of structure with flexible array member
> make: *** [unpack-trees.o] Error 1
Darn, darn, DARN!
As far as I can see, that flexible array member is the member "name" of
cache_entry. And as I can see further, it is used _nowhere_. At least not
inside that structure.
How about this (on top of that patch):
-- 8< --
[PATCH 1.5/3] unpack-trees: please C99 standard
Even if it is not a technical error in _this_ case, a struct with
a flexible array member should not be put inside another struct.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
unpack-trees.c | 10 ++++++----
unpack-trees.h | 2 +-
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/unpack-trees.c b/unpack-trees.c
index b8a355f..3cb92cb 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -168,7 +168,7 @@ #endif
}
if (posns[i] == df_conflict_list) {
- src[i + o->merge] = &o->df_conflict_entry;
+ src[i + o->merge] = o->df_conflict_entry;
continue;
}
@@ -178,7 +178,7 @@ #endif
parse_tree(tree);
subposns[i] = create_tree_entry_list(tree);
posns[i] = posns[i]->next;
- src[i + o->merge] = &o->df_conflict_entry;
+ src[i + o->merge] = o->df_conflict_entry;
continue;
}
@@ -370,6 +370,7 @@ int unpack_trees(struct object_list *tre
int i;
struct object_list *posn = trees;
struct tree_entry_list df_conflict_list;
+ struct cache_entry df_conflict_entry;
memset(&df_conflict_list, 0, sizeof(df_conflict_list));
df_conflict_list.next = &df_conflict_list;
@@ -380,6 +381,7 @@ int unpack_trees(struct object_list *tre
state.refresh_cache = 1;
o->merge_size = len;
+ o->df_conflict_entry = &df_conflict_entry;
if (len) {
posns = xmalloc(len * sizeof(struct tree_entry_list *));
@@ -562,12 +564,12 @@ int threeway_merge(struct cache_entry **
index = stages[0];
head = stages[o->head_idx];
- if (head == &o->df_conflict_entry) {
+ if (head == o->df_conflict_entry) {
df_conflict_head = 1;
head = NULL;
}
- if (remote == &o->df_conflict_entry) {
+ if (remote == o->df_conflict_entry) {
df_conflict_remote = 1;
remote = NULL;
}
diff --git a/unpack-trees.h b/unpack-trees.h
index 826b263..c460162 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -21,7 +21,7 @@ struct unpack_trees_options {
int head_idx;
int merge_size;
- struct cache_entry df_conflict_entry;
+ struct cache_entry *df_conflict_entry;
};
extern int unpack_trees(struct object_list *trees,
--
1.4.2.rc2.g53906
^ permalink raw reply related
* [PATCH] gitweb: use out-of-line GIT logo.
From: Martin Waitz @ 2006-07-30 22:38 UTC (permalink / raw)
To: git
Use the normal web server instead of the CGI to provide the git logo,
just like the gitweb.css.
Signed-off-by: Martin Waitz <tali@admingilde.org>
---
Makefile | 2 ++
gitweb/README | 2 ++
gitweb/git-logo.png | Bin
gitweb/gitweb.pl | 29 ++++-------------------------
4 files changed, 8 insertions(+), 25 deletions(-)
diff --git a/Makefile b/Makefile
index bd59d6b58d1cfcaecd033f186d7c2cc537416b75..40e129490b337a70f0ee5c60ce25980359e658c9 100644
--- a/Makefile
+++ b/Makefile
@@ -122,6 +122,7 @@ GITWEB_PROJECTROOT = /pub/git
GITWEB_LIST =
GITWEB_HOMETEXT = indextext.html
GITWEB_CSS = gitweb.css
+GITWEB_LOGO = git-logo.png
export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
@@ -584,6 +585,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.pl
-e 's|@@GITWEB_LIST@@|$(GITWEB_LIST)|g' \
-e 's|@@GITWEB_HOMETEXT@@|$(GITWEB_HOMETEXT)|g' \
-e 's|@@GITWEB_CSS@@|$(GITWEB_CSS)|g' \
+ -e 's|@@GITWEB_LOGO@@|$(GITWEB_LOGO)|g' \
$< >$@+
chmod +x $@+
mv $@+ $@
diff --git a/gitweb/README b/gitweb/README
index ed939e2fb5264cce24e770272583b12372c3ab68..1b2180c7314ea3d10db78c88b48092a70491f8b8 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -21,6 +21,8 @@ You can specify the following configurat
overview page.
* GITWEB_CSS
Points to the location where you put gitweb.css on your web server.
+ * GITWEB_LOGO
+ Points to the location where you put git-logo.png on your web server.
Any comment/question/concern to:
Kay Sievers <kay.sievers@vrfy.org>
diff --git a/gitweb/git-logo.png b/gitweb/git-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..16ae8d5382de5ffe63b54139245143513a87446e
GIT binary patch
literal 208
zc%17D@N?(olHy`uVBq!ia0vp^9zZP3!VDyJZ(h*_QW60^A+G=b|4&GW-LQTYLj%LP
zv&RoGFuZv2?ECj`Q+bxV1Jx9Jx;TbtoKN;hS77mqk>KLcN(xR?VB+A-bX~J>A)^7$
z<ODOdpotq91+P5}P07hQlas@<h^Ig+iB0QZlI&(irr;$UFBq65)WQU>JXDx2{a_29
zsY;<{(@cXMleq+Ux^^7wU9iYSkxkvP$)WY2Yo|g1Bf}C~#iK$pv;G0CXYh3Ob6Mw<
G&;$VMfkjjR
diff --git a/gitweb/gitweb.pl b/gitweb/gitweb.pl
index 8e05c335f801d4c52a9b348fa56fccfae36ce621..e6e9f83076630958d0134bfbb29989882f6f1d0d 100755
--- a/gitweb/gitweb.pl
+++ b/gitweb/gitweb.pl
@@ -51,6 +51,8 @@ our $home_text = "@@GITWEB_HOMETEXT@@";
# URI of default stylesheet
our $stylesheet = "@@GITWEB_CSS@@";
+# URI of GIT logo
+our $logo = "@@GITWEB_LOGO@@";
# source of projects list
our $projects_list = "@@GITWEB_LIST@@" || "$projectroot";
@@ -70,10 +72,7 @@ if (defined $action) {
undef $action;
die_error(undef, "Invalid action parameter.");
}
- if ($action eq "git-logo.png") {
- git_logo();
- exit;
- } elsif ($action eq "opml") {
+ if ($action eq "opml") {
git_opml();
exit;
}
@@ -320,7 +319,7 @@ sub git_header_html {
EOF
print "<div class=\"page_header\">\n" .
"<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
- "<img src=\"$my_uri?" . esc_param("a=git-logo.png") . "\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
+ "<img src=\"$logo\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
"</a>\n";
print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
if (defined $project) {
@@ -755,26 +754,6 @@ sub date_str {
return %date;
}
-# git-logo (cached in browser for one day)
-sub git_logo {
- binmode STDOUT, ':raw';
- print $cgi->header(-type => 'image/png', -expires => '+1d');
- # cat git-logo.png | hexdump -e '16/1 " %02x" "\n"' | sed 's/ /\\x/g'
- print "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
- "\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
- "\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
- "\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
- "\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
- "\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
- "\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
- "\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
- "\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
- "\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
- "\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
- "\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
- "\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
-}
-
sub get_file_owner {
my $path = shift;
--
1.4.2.rc2.gf055
--
Martin Waitz
^ permalink raw reply related
* [PATCH] gitweb: fill in gitweb configuration by Makefile
From: Martin Waitz @ 2006-07-30 22:37 UTC (permalink / raw)
To: git
Generate gitweb/gitweb.cgi to reduce the need to patch gitweb.cgi by
the end user.
The GIT installation directory and version are already known by the
Makefile, they can be inserted directly into gitweb.
All other gitweb configuration parameters can now be specified
by providing GITWEB_* variables while building GIT.
These are described in gitweb/README.
Signed-off-by: Martin Waitz <tali@admingilde.org>
---
Makefile | 25 +++++++++++++++++++++++--
gitweb/.gitignore | 1 +
gitweb/README | 17 +++++++++++++++++
gitweb/{gitweb.cgi => gitweb.pl} | 15 +++++++--------
4 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index 8349e3defacca69ae48c477ff99be527b9af3b77..bd59d6b58d1cfcaecd033f186d7c2cc537416b75 100644
--- a/Makefile
+++ b/Makefile
@@ -116,6 +116,13 @@ template_dir = $(prefix)/share/git-core/
GIT_PYTHON_DIR = $(prefix)/share/git-core/python
# DESTDIR=
+# default configuration for gitweb
+GITWEB_SITENAME =
+GITWEB_PROJECTROOT = /pub/git
+GITWEB_LIST =
+GITWEB_HOMETEXT = indextext.html
+GITWEB_CSS = gitweb.css
+
export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
CC = gcc
@@ -509,7 +516,7 @@ LIB_OBJS += $(COMPAT_OBJS)
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules
-all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk
+all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
all:
$(MAKE) -C templates
@@ -567,6 +574,20 @@ git-status: git-commit
cp $< $@+
mv $@+ $@
+gitweb/gitweb.cgi: gitweb/gitweb.pl
+ rm -f $@ $@+
+ sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
+ -e 's|@@GIT_VERSION@@|$(GIT_VERSION)|g' \
+ -e 's|@@GIT_BINDIR@@|$(bindir)|g' \
+ -e 's|@@GITWEB_SITENAME@@|$(GITWEB_SITENAME)|g' \
+ -e 's|@@GITWEB_PROJECTROOT@@|$(GITWEB_PROJECTROOT)|g' \
+ -e 's|@@GITWEB_LIST@@|$(GITWEB_LIST)|g' \
+ -e 's|@@GITWEB_HOMETEXT@@|$(GITWEB_HOMETEXT)|g' \
+ -e 's|@@GITWEB_CSS@@|$(GITWEB_CSS)|g' \
+ $< >$@+
+ chmod +x $@+
+ mv $@+ $@
+
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
rm -f $@ $@+
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
@@ -577,7 +598,7 @@ git-instaweb: git-instaweb.sh gitweb/git
-e '/@@GITWEB_CGI@@/d' \
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
-e '/@@GITWEB_CSS@@/d' \
- $@.sh | sed "s|/usr/bin/git|$(bindir)/git|" > $@+
+ $@.sh > $@+
chmod +x $@+
mv $@+ $@
diff --git a/gitweb/.gitignore b/gitweb/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e83127e3f09f8496d0cd07b8f632ff341c96fd00
--- /dev/null
+++ b/gitweb/.gitignore
@@ -0,0 +1 @@
+gitweb.cgi
diff --git a/gitweb/README b/gitweb/README
index 8d672762eab427f3b732626d6b3f8e05a7e8f8c9..ed939e2fb5264cce24e770272583b12372c3ab68 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -5,5 +5,22 @@ The one working on:
From the git version 1.4.0 gitweb is bundled with git.
+
+How to configure gitweb for your local system:
+
+You can specify the following configuration variables when building GIT:
+ * GITWEB_SITENAME
+ Shown in the title of all generated pages, defaults to the servers name.
+ * GITWEB_PROJECTROOT
+ The root directory for all projects shown by gitweb.
+ * GITWEB_LIST
+ points to a directory to scan for projects (defaults to project root)
+ or to a file for explicit listing of projects.
+ * GITWEB_HOMETEXT
+ points to an .html file which is included on the gitweb project
+ overview page.
+ * GITWEB_CSS
+ Points to the location where you put gitweb.css on your web server.
+
Any comment/question/concern to:
Kay Sievers <kay.sievers@vrfy.org>
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.pl
similarity index 100%
rename from gitweb/gitweb.cgi
rename to gitweb/gitweb.pl
index 243a2921f849568260e848201d238b3b9fe7e1f2..8e05c335f801d4c52a9b348fa56fccfae36ce621 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.pl
@@ -24,14 +24,14 @@ our $rss_link = "";
# core git executable to use
# this can just be "git" if your webserver has a sensible PATH
-our $GIT = "/usr/bin/git";
+our $GIT = "@@GIT_BINDIR@@/git";
# absolute fs-path which will be prepended to the project path
#our $projectroot = "/pub/scm";
-our $projectroot = "/home/kay/public_html/pub/scm";
+our $projectroot = "@@GITWEB_PROJECTROOT@@";
# version of the core git binary
-our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+our $git_version = "@@GIT_VERSION@@";
# location for temporary files needed for diffs
our $git_temp = "/tmp/gitweb";
@@ -44,17 +44,16 @@ our $home_link = $my_uri;
# name of your site or organization to appear in page titles
# replace this with something more descriptive for clearer bookmarks
-our $site_name = $ENV{'SERVER_NAME'} || "Untitled";
+our $site_name = "@@GITWEB_SITENAME@@" || $ENV{'SERVER_NAME'} || "Untitled";
# html text to include at home page
-our $home_text = "indextext.html";
+our $home_text = "@@GITWEB_HOMETEXT@@";
# URI of default stylesheet
-our $stylesheet = "gitweb.css";
+our $stylesheet = "@@GITWEB_CSS@@";
# source of projects list
-#our $projects_list = $projectroot;
-our $projects_list = "index/index.aux";
+our $projects_list = "@@GITWEB_LIST@@" || "$projectroot";
# default blob_plain mimetype and default charset for text/plain blob
our $default_blob_plain_mimetype = 'text/plain';
--
1.4.2.rc2.gf055
--
Martin Waitz
^ permalink raw reply related
* Re: [PATCH 1/3] read-trees: refactor the unpack_trees() part
From: Junio C Hamano @ 2006-07-30 21:36 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0607302024090.29667@wbgn013.biozentrum.uni-wuerzburg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> diff --git a/unpack-trees.h b/unpack-trees.h
> new file mode 100644
> index 0000000..babfcd7
> --- /dev/null
> +++ b/unpack-trees.h
> @@ -0,0 +1,30 @@
> +#ifndef UNPACK_TREES_H
> +#define UNPACK_TREES_H
>...
> +struct unpack_trees_options {
> + int reset;
> + int merge;
> + int update;
> + int index_only;
> + int nontrivial_merge;
> + int trivial_merges_only;
> + int verbose_update;
> + int aggressive;
> + const char *prefix;
> + merge_fn_t fn;
> +
> + int head_idx;
> + int merge_size;
> +
> + struct cache_entry df_conflict_entry;
> +};
Hmmmm.....
gcc -o unpack-trees.o -c -O2 -Werror -ansi -pedantic -std=c99 -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wall -Wdeclaration-after-statement -g -DSHA1_HEADER='<openssl/sha.h>' -DNO_STRLCPY unpack-trees.c
cc1: warnings being treated as errors
In file included from unpack-trees.c:7:
unpack-trees.h:24: warning: invalid use of structure with flexible array member
make: *** [unpack-trees.o] Error 1
^ permalink raw reply
* Re: [PATCH 1/1] Make git-tar-tree more flexible
From: Junio C Hamano @ 2006-07-30 20:57 UTC (permalink / raw)
To: Anand Kumria; +Cc: git
In-Reply-To: <20060730174847.GA32574@eve.kumria.com>
Anand Kumria <wildfire@progsoc.org> writes:
> If you have a project which is setup like:
> project
> website
> and you decide you wish to generate a tar archive of _just_ the 'project'
> portion, git-tar-tree is not able to help. This patch adds two parameters
> which can assist.
No need I see.
git tar-tree tag-1.0:project project-1.0/project
git tar-tree tag-1.0:project project-1.0
^ permalink raw reply
* [PATCH 16] gitweb: Remove characters entities entirely when shortening string
From: Jakub Narebski @ 2006-07-30 20:36 UTC (permalink / raw)
To: git
In-Reply-To: <200607292239.11034.jnareb@gmail.com>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Yet another error noticed due to strict validation
of application/xhtml+xml by Mozilla.
gitweb/gitweb.cgi | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 06a6930..83ea97a 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -776,6 +776,7 @@ sub chop_str {
my $tail = $2;
if (length($tail) > 4) {
$tail = " ...";
+ $body =~ s/&[^;]$//; # remove chopped character entities
}
return "$body$tail";
}
--
1.4.0
^ permalink raw reply related
* Re: [PATCH 1/1] Make git-tar-tree more flexible
From: A Large Angry SCM @ 2006-07-30 18:46 UTC (permalink / raw)
To: Anand Kumria; +Cc: git
In-Reply-To: <20060730174847.GA32574@eve.kumria.com>
Anand Kumria wrote:
> If you have a project which is setup like:
> project
> website
> and you decide you wish to generate a tar archive of _just_ the 'project'
> portion, git-tar-tree is not able to help. This patch adds two parameters
> which can assist.
>
> The first is '--pathlimit', which forces git-tar-tree to only generate the
> tar archive for project; as in:
> 'git tar-tree --pathlimit=project project-1.0 tag-1.0'
>
> The above command will mean that paths in the tar archive look like:
> project-1.0/project/src/main.c
> etc.
>
> The second parameter allows you two strip the extraneous project, as in:
> 'git tar-tree --strippath=project --pathlimit=project project-1.0 tag-1.0 Which will result in tar archives looking like:
> project-1.0/src/main.c
>
This could be made more general and more Git-ish instead, by
implementing a strip common prefix option and using a double dash option
to signal that the remaining arguments are the paths of interest.
The synopsis would then look like:
git-tar-tree [--remote=<repo>] [ --strip-common-prefix ]
<tree-ish> [ <base> ] [ -- <paths>... ]
^ permalink raw reply
* [PATCH 15] gitweb: Headers refactoring - use git_header_div for header divs
From: Jakub Narebski @ 2006-07-30 18:32 UTC (permalink / raw)
To: git
In-Reply-To: <200607292239.11034.jnareb@gmail.com>
Add git_header_div subroutine which prints "header" divs, now with
class "header" (class "title" is taken, and has set CSS style,
changing appereance and maing layout wrong), and use it thorough
gitweb.cgi. Change header linking to project summary from empty
( as a contents of link) to having $project as contents/name
of link. Sometimes a little reordering.
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
gitweb/gitweb.cgi | 100 +++++++++++++++++++++--------------------------------
1 files changed, 40 insertions(+), 60 deletions(-)
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index bfb01de..06a6930 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -420,6 +420,19 @@ sub git_page_nav {
"</div>\n";
}
+sub git_header_div {
+ my ($action, $title, $hash, $hash_base) = @_;
+ my $rest = '';
+
+ $rest .= ";h=$hash" if $hash;
+ $rest .= ";hb=$hash_base" if $hash_base;
+
+ print "<div class=\"header\">\n" .
+ $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
+ -class => "title"}, $title ? $title : $action) . "\n" .
+ "</div>\n";
+}
+
sub git_get_paging_nav {
my ($action, $hash, $head, $page, $nrevs) = @_;
my $paging_nav;
@@ -1123,9 +1136,7 @@ sub git_summary {
or die_error(undef, "Open git-rev-list failed.");
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog"), -class => "title"}, "shortlog") .
- "</div>\n";
+ git_header_div('shortlog');
my $i = 16;
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
@@ -1169,9 +1180,7 @@ sub git_summary {
my $taglist = git_read_refs("refs/tags");
if (defined @$taglist) {
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tags"), -class => "title"}, "tags") .
- "</div>\n";
+ git_header_div('tags');
my $i = 16;
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
@@ -1221,9 +1230,7 @@ sub git_summary {
my $headlist = git_read_refs("refs/heads");
if (defined @$headlist) {
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads"), -class => "title"}, "heads") .
- "</div>\n";
+ git_header_div('heads');
my $i = 16;
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
@@ -1276,9 +1283,7 @@ sub git_tag {
git_header_html();
git_page_nav('','', $head,undef,$head);
my %tag = git_read_tag($hash);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($tag{'name'})) . "\n" .
- "</div>\n";
+ git_header_div('commit', esc_html($tag{'name'}), $hash);
print "<div class=\"title_text\">\n" .
"<table cellspacing=\"0\">\n" .
"<tr>\n" .
@@ -1326,9 +1331,7 @@ sub git_blame2 {
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- print "<div>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}), $hash_base);
git_print_page_path($file_name, $ftype);
my @rev_color = (qw(light dark));
my $num_colors = scalar(@rev_color);
@@ -1382,9 +1385,7 @@ sub git_blame {
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- print "<div>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}), $hash_base);
git_print_page_path($file_name);
print "<div class=\"page_body\">\n";
print <<HTML;
@@ -1460,11 +1461,10 @@ sub git_tags {
my $head = git_read_head($project);
git_header_html();
git_page_nav('','', $head,undef,$head);
- my $taglist = git_read_refs("refs/tags");
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, " ") .
- "</div>\n";
+ git_header_div('summary', $project);
print "<table cellspacing=\"0\">\n";
+
+ my $taglist = git_read_refs("refs/tags");
my $alternate = 0;
if (defined @$taglist) {
foreach my $entry (@$taglist) {
@@ -1511,11 +1511,10 @@ sub git_heads {
my $head = git_read_head($project);
git_header_html();
git_page_nav('','', $head,undef,$head);
- my $taglist = git_read_refs("refs/heads");
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, " ") .
- "</div>\n";
+ hit_header_div('summary', $project);
print "<table cellspacing=\"0\">\n";
+
+ my $taglist = git_read_refs("refs/heads");
my $alternate = 0;
if (defined @$taglist) {
foreach my $entry (@$taglist) {
@@ -1684,9 +1683,7 @@ sub git_blob {
$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain");
}
git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- print "<div>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}), $hash_base);
} else {
print "<div class=\"page_nav\">\n" .
"<br/><br/></div>\n" .
@@ -1740,9 +1737,7 @@ sub git_tree {
if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
$base_key = ";hb=$hash_base";
git_page_nav('tree','', $hash_base);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
} else {
print "<div class=\"page_nav\">\n";
print "<br/><br/></div>\n";
@@ -1909,10 +1904,9 @@ sub git_log {
git_page_nav('log','', $hash,undef,undef, $paging_nav);
if (!@revlist) {
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, " ") .
- "</div>\n";
my %co = git_read_commit($hash);
+
+ git_header_div('summary', $project);
print "<div class=\"page_body\"> Last change $co{'age_string'}.<br/><br/></div>\n";
}
for (my $i = ($page * 100); $i <= $#revlist; $i++) {
@@ -1924,10 +1918,10 @@ sub git_log {
my %co = git_read_commit($commit);
next if !%co;
my %ad = date_str($co{'author_epoch'});
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "title"},
- "<span class=\"age\">$co{'age_string'}</span>" . esc_html($co{'title'}) . $ref) . "\n";
- print "</div>\n";
+ git_header_div('commit',
+ "<span class=\"age\">$co{'age_string'}</span>" .
+ esc_html($co{'title'}) . $ref,
+ $commit);
print "<div class=\"title_text\">\n" .
"<div class=\"log_link\">\n" .
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") .
@@ -1999,13 +1993,9 @@ sub git_commit {
$formats_nav);
if (defined $co{'parent'}) {
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
- "</div>\n";
+ git_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
} else {
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash"), -class => "title"}, esc_html($co{'title'})) . "\n" .
- "</div>\n";
+ git_header_div('tree', esc_html($co{'title'}), $co{'tree'}, $hash);
}
print "<div class=\"title_text\">\n" .
"<table cellspacing=\"0\">\n";
@@ -2171,9 +2161,7 @@ sub git_blobdiff {
my $formats_nav =
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . "\n" .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}), $hash_base);
} else {
print "<div class=\"page_nav\">\n" .
"<br/><br/></div>\n" .
@@ -2225,9 +2213,7 @@ sub git_commitdiff {
my $formats_nav =
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
git_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
print "<div class=\"page_body\">\n";
my $comment = $co{'comment'};
my $empty = 0;
@@ -2357,9 +2343,7 @@ sub git_history {
my $refs = read_info_ref();
git_header_html();
git_page_nav('','', $hash_base,$co{'tree'},$hash_base);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . "\n" .
- "</div>\n";
+ git_header_div('commit', esc_html($co{'title'}), $hash_base);
if (!defined $hash && defined $file_name) {
$hash = git_get_hash_by_path($hash_base, $file_name);
}
@@ -2440,10 +2424,8 @@ sub git_search {
}
git_header_html();
git_page_nav('','', $hash,$co{'tree'},$hash);
+ git_header_div('commit', esc_html($co{'title'}), $hash);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($co{'title'})) . "\n" .
- "</div>\n";
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
if ($commit_search) {
@@ -2570,10 +2552,8 @@ sub git_shortlog {
git_header_html();
git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
+ git_header_div('summary', $project);
- print "<div>\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, " ") .
- "</div>\n";
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
for (my $i = ($page * 100); $i <= $#revlist; $i++) {
--
1.4.0
^ permalink raw reply related
* [PATCH 14] gitweb: Remove $project from git_get_paging_nav arguments
From: Jakub Narebski @ 2006-07-30 18:31 UTC (permalink / raw)
To: git
In-Reply-To: <200607292239.11034.jnareb@gmail.com>
Remove $project from arguments passed to git_get_paging_nav
subroutine: it did not depend only on arguments, using $my_uri global
variable (and now $project global variable).
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
gitweb/gitweb.cgi | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 1befa7d..bfb01de 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -421,7 +421,7 @@ sub git_page_nav {
}
sub git_get_paging_nav {
- my ($project, $action, $hash, $head, $page, $nrevs) = @_;
+ my ($action, $hash, $head, $page, $nrevs) = @_;
my $paging_nav;
@@ -1903,7 +1903,7 @@ sub git_log {
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
- my $paging_nav = git_get_paging_nav($project, 'log', $hash, $head, $page, $#revlist);
+ my $paging_nav = git_get_paging_nav('log', $hash, $head, $page, $#revlist);
git_header_html();
git_page_nav('log','', $hash,undef,undef, $paging_nav);
@@ -2566,7 +2566,7 @@ sub git_shortlog {
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
- my $paging_nav = git_get_paging_nav($project, 'shortlog', $hash, $head, $page, $#revlist);
+ my $paging_nav = git_get_paging_nav('shortlog', $hash, $head, $page, $#revlist);
git_header_html();
git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
--
1.4.0
^ permalink raw reply related
* [PATCH 4/3] merge-recur: trivial cleanup
From: Johannes Schindelin @ 2006-07-30 18:30 UTC (permalink / raw)
To: git, junkio
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
I should learn to remember...
merge-recursive.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 3cdea81..10bce70 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -220,11 +220,10 @@ static int git_merge_trees(int index_onl
struct object_list *trees = NULL;
struct unpack_trees_options opts;
- /* TODO: if (!cache_dirty) read */
- if (cache_dirty)
- flush_cache();
-
- read_cache_from(getenv("GIT_INDEX_FILE"));
+ if (!cache_dirty) {
+ read_cache_from(getenv("GIT_INDEX_FILE"));
+ cache_dirty = 1;
+ }
memset(&opts, 0, sizeof(opts));
if (index_only)
--
1.4.2.rc2.g6fccc-dirty
^ permalink raw reply related
* [PATCH 3/3] merge-recur: use the unpack_trees() interface instead of exec()ing read-tree
From: Johannes Schindelin @ 2006-07-30 18:27 UTC (permalink / raw)
To: git, junkio
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
merge-recursive.c | 77 +++++++++++++++++++++++++++++++++++------------------
1 files changed, 51 insertions(+), 26 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 5375a1b..3cdea81 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -19,7 +19,7 @@ #include "diff.h"
#include "diffcore.h"
#include "run-command.h"
#include "tag.h"
-
+#include "unpack-trees.h"
#include "path-list.h"
/*
@@ -124,7 +124,7 @@ static int flush_cache(void)
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int fd = hold_lock_file_for_update(lock, getenv("GIT_INDEX_FILE"));
if (fd < 0)
- die("could not lock %s", temporary_index_file);
+ die("could not lock %s", lock->filename);
if (write_cache(fd, active_cache, active_nr) ||
close(fd) || commit_lock_file(lock))
die ("unable to write %s", getenv("GIT_INDEX_FILE"));
@@ -191,41 +191,60 @@ static int add_cacheinfo(unsigned int mo
*/
static int index_only = 0;
-/*
- * TODO: this can be streamlined by refactoring builtin-read-tree.c
- */
-static int git_read_tree(const struct tree *tree)
+static int git_read_tree(struct tree *tree)
{
int rc;
- const char *argv[] = { "git-read-tree", NULL, NULL, };
+ struct object_list *trees = NULL;
+ struct unpack_trees_options opts;
+
if (cache_dirty)
die("read-tree with dirty cache");
- argv[1] = sha1_to_hex(tree->object.sha1);
- rc = run_command_v(2, argv);
- return rc < 0 ? -1: rc;
+
+ memset(&opts, 0, sizeof(opts));
+ object_list_append(&tree->object, &trees);
+ rc = unpack_trees(trees, &opts);
+ cache_tree_free(&active_cache_tree);
+
+ if (rc == 0)
+ cache_dirty = 1;
+
+ return rc;
}
-/*
- * TODO: this can be streamlined by refactoring builtin-read-tree.c
- */
-static int git_merge_trees(const char *update_arg,
+static int git_merge_trees(int index_only,
struct tree *common,
struct tree *head,
struct tree *merge)
{
int rc;
- const char *argv[] = {
- "git-read-tree", NULL, "-m", NULL, NULL, NULL,
- NULL,
- };
+ struct object_list *trees = NULL;
+ struct unpack_trees_options opts;
+
+ /* TODO: if (!cache_dirty) read */
if (cache_dirty)
flush_cache();
- argv[1] = update_arg;
- argv[3] = sha1_to_hex(common->object.sha1);
- argv[4] = sha1_to_hex(head->object.sha1);
- argv[5] = sha1_to_hex(merge->object.sha1);
- rc = run_command_v(6, argv);
- return rc < 0 ? -1: rc;
+
+ read_cache_from(getenv("GIT_INDEX_FILE"));
+
+ memset(&opts, 0, sizeof(opts));
+ if (index_only)
+ opts.index_only = 1;
+ else
+ opts.update = 1;
+ opts.merge = 1;
+ opts.head_idx = 2;
+ opts.fn = threeway_merge;
+
+ object_list_append(&common->object, &trees);
+ object_list_append(&head->object, &trees);
+ object_list_append(&merge->object, &trees);
+
+ rc = unpack_trees(trees, &opts);
+ cache_tree_free(&active_cache_tree);
+
+ cache_dirty = 1;
+
+ return rc;
}
/*
@@ -239,8 +258,14 @@ static struct tree *git_write_tree(void)
unsigned char sha1[20];
int ch;
unsigned i = 0;
- if (cache_dirty)
+ if (cache_dirty) {
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ if (ce_stage(ce))
+ return NULL;
+ }
flush_cache();
+ }
fp = popen("git-write-tree 2>/dev/null", "r");
while ((ch = fgetc(fp)) != EOF)
if (i < sizeof(buf)-1 && ch >= '0' && ch <= 'f')
@@ -1121,7 +1146,7 @@ static int merge_trees(struct tree *head
return 1;
}
- code = git_merge_trees(index_only ? "-i": "-u", common, head, merge);
+ code = git_merge_trees(index_only, common, head, merge);
if (code != 0)
die("merging of trees %s and %s failed",
--
1.4.2.rc2.g76b2-dirty
^ permalink raw reply related
* [PATCH 2/3] read-tree: move merge functions to the library
From: Johannes Schindelin @ 2006-07-30 18:26 UTC (permalink / raw)
To: git, junkio
This will allow merge-recursive to use the read-tree functionality
without exec()ing git-read-tree.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Like the first patch, this is mainly a big code move.
builtin-read-tree.c | 398 --------------------------------------------------
unpack-trees.c | 402 +++++++++++++++++++++++++++++++++++++++++++++++++++
unpack-trees.h | 5 +
3 files changed, 408 insertions(+), 397 deletions(-)
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index a9852c7..8869ced 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -3,10 +3,8 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define DBRT_DEBUG 1
#include "cache.h"
-
#include "object.h"
#include "tree.h"
#include "tree-walk.h"
@@ -16,12 +14,6 @@ #include "builtin.h"
static struct object_list *trees = NULL;
-static void reject_merge(struct cache_entry *ce)
-{
- die("Entry '%s' would be overwritten by merge. Cannot merge.",
- ce->name);
-}
-
static int list_tree(unsigned char *sha1)
{
struct tree *tree = parse_tree_indirect(sha1);
@@ -31,394 +23,6 @@ static int list_tree(unsigned char *sha1
return 0;
}
-static int same(struct cache_entry *a, struct cache_entry *b)
-{
- if (!!a != !!b)
- return 0;
- if (!a && !b)
- return 1;
- return a->ce_mode == b->ce_mode &&
- !memcmp(a->sha1, b->sha1, 20);
-}
-
-
-/*
- * When a CE gets turned into an unmerged entry, we
- * want it to be up-to-date
- */
-static void verify_uptodate(struct cache_entry *ce,
- struct unpack_trees_options *o)
-{
- struct stat st;
-
- if (o->index_only || o->reset)
- return;
-
- if (!lstat(ce->name, &st)) {
- unsigned changed = ce_match_stat(ce, &st, 1);
- if (!changed)
- return;
- errno = 0;
- }
- if (o->reset) {
- ce->ce_flags |= htons(CE_UPDATE);
- return;
- }
- if (errno == ENOENT)
- return;
- die("Entry '%s' not uptodate. Cannot merge.", ce->name);
-}
-
-static void invalidate_ce_path(struct cache_entry *ce)
-{
- if (ce)
- cache_tree_invalidate_path(active_cache_tree, ce->name);
-}
-
-/*
- * We do not want to remove or overwrite a working tree file that
- * is not tracked.
- */
-static void verify_absent(const char *path, const char *action,
- struct unpack_trees_options *o)
-{
- struct stat st;
-
- if (o->index_only || o->reset || !o->update)
- return;
- if (!lstat(path, &st))
- die("Untracked working tree file '%s' "
- "would be %s by merge.", path, action);
-}
-
-static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
- struct unpack_trees_options *o)
-{
- merge->ce_flags |= htons(CE_UPDATE);
- if (old) {
- /*
- * See if we can re-use the old CE directly?
- * That way we get the uptodate stat info.
- *
- * This also removes the UPDATE flag on
- * a match.
- */
- if (same(old, merge)) {
- *merge = *old;
- } else {
- verify_uptodate(old, o);
- invalidate_ce_path(old);
- }
- }
- else {
- verify_absent(merge->name, "overwritten", o);
- invalidate_ce_path(merge);
- }
-
- merge->ce_flags &= ~htons(CE_STAGEMASK);
- add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
- return 1;
-}
-
-static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
- struct unpack_trees_options *o)
-{
- if (old)
- verify_uptodate(old, o);
- else
- verify_absent(ce->name, "removed", o);
- ce->ce_mode = 0;
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
- invalidate_ce_path(ce);
- return 1;
-}
-
-static int keep_entry(struct cache_entry *ce)
-{
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
- return 1;
-}
-
-#if DBRT_DEBUG
-static void show_stage_entry(FILE *o,
- const char *label, const struct cache_entry *ce)
-{
- if (!ce)
- fprintf(o, "%s (missing)\n", label);
- else
- fprintf(o, "%s%06o %s %d\t%s\n",
- label,
- ntohl(ce->ce_mode),
- sha1_to_hex(ce->sha1),
- ce_stage(ce),
- ce->name);
-}
-#endif
-
-static int threeway_merge(struct cache_entry **stages,
- struct unpack_trees_options *o)
-{
- struct cache_entry *index;
- struct cache_entry *head;
- struct cache_entry *remote = stages[o->head_idx + 1];
- int count;
- int head_match = 0;
- int remote_match = 0;
- const char *path = NULL;
-
- int df_conflict_head = 0;
- int df_conflict_remote = 0;
-
- int any_anc_missing = 0;
- int no_anc_exists = 1;
- int i;
-
- for (i = 1; i < o->head_idx; i++) {
- if (!stages[i])
- any_anc_missing = 1;
- else {
- if (!path)
- path = stages[i]->name;
- no_anc_exists = 0;
- }
- }
-
- index = stages[0];
- head = stages[o->head_idx];
-
- if (head == &o->df_conflict_entry) {
- df_conflict_head = 1;
- head = NULL;
- }
-
- if (remote == &o->df_conflict_entry) {
- df_conflict_remote = 1;
- remote = NULL;
- }
-
- if (!path && index)
- path = index->name;
- if (!path && head)
- path = head->name;
- if (!path && remote)
- path = remote->name;
-
- /* First, if there's a #16 situation, note that to prevent #13
- * and #14.
- */
- if (!same(remote, head)) {
- for (i = 1; i < o->head_idx; i++) {
- if (same(stages[i], head)) {
- head_match = i;
- }
- if (same(stages[i], remote)) {
- remote_match = i;
- }
- }
- }
-
- /* We start with cases where the index is allowed to match
- * something other than the head: #14(ALT) and #2ALT, where it
- * is permitted to match the result instead.
- */
- /* #14, #14ALT, #2ALT */
- if (remote && !df_conflict_head && head_match && !remote_match) {
- if (index && !same(index, remote) && !same(index, head))
- reject_merge(index);
- return merged_entry(remote, index, o);
- }
- /*
- * If we have an entry in the index cache, then we want to
- * make sure that it matches head.
- */
- if (index && !same(index, head)) {
- reject_merge(index);
- }
-
- if (head) {
- /* #5ALT, #15 */
- if (same(head, remote))
- return merged_entry(head, index, o);
- /* #13, #3ALT */
- if (!df_conflict_remote && remote_match && !head_match)
- return merged_entry(head, index, o);
- }
-
- /* #1 */
- if (!head && !remote && any_anc_missing)
- return 0;
-
- /* Under the new "aggressive" rule, we resolve mostly trivial
- * cases that we historically had git-merge-one-file resolve.
- */
- if (o->aggressive) {
- int head_deleted = !head && !df_conflict_head;
- int remote_deleted = !remote && !df_conflict_remote;
- /*
- * Deleted in both.
- * Deleted in one and unchanged in the other.
- */
- if ((head_deleted && remote_deleted) ||
- (head_deleted && remote && remote_match) ||
- (remote_deleted && head && head_match)) {
- if (index)
- return deleted_entry(index, index, o);
- else if (path)
- verify_absent(path, "removed", o);
- return 0;
- }
- /*
- * Added in both, identically.
- */
- if (no_anc_exists && head && remote && same(head, remote))
- return merged_entry(head, index, o);
-
- }
-
- /* Below are "no merge" cases, which require that the index be
- * up-to-date to avoid the files getting overwritten with
- * conflict resolution files.
- */
- if (index) {
- verify_uptodate(index, o);
- }
- else if (path)
- verify_absent(path, "overwritten", o);
-
- o->nontrivial_merge = 1;
-
- /* #2, #3, #4, #6, #7, #9, #11. */
- count = 0;
- if (!head_match || !remote_match) {
- for (i = 1; i < o->head_idx; i++) {
- if (stages[i]) {
- keep_entry(stages[i]);
- count++;
- break;
- }
- }
- }
-#if DBRT_DEBUG
- else {
- fprintf(stderr, "read-tree: warning #16 detected\n");
- show_stage_entry(stderr, "head ", stages[head_match]);
- show_stage_entry(stderr, "remote ", stages[remote_match]);
- }
-#endif
- if (head) { count += keep_entry(head); }
- if (remote) { count += keep_entry(remote); }
- return count;
-}
-
-/*
- * Two-way merge.
- *
- * The rule is to "carry forward" what is in the index without losing
- * information across a "fast forward", favoring a successful merge
- * over a merge failure when it makes sense. For details of the
- * "carry forward" rule, please see <Documentation/git-read-tree.txt>.
- *
- */
-static int twoway_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
-{
- struct cache_entry *current = src[0];
- struct cache_entry *oldtree = src[1], *newtree = src[2];
-
- if (o->merge_size != 2)
- return error("Cannot do a twoway merge of %d trees",
- o->merge_size);
-
- if (current) {
- if ((!oldtree && !newtree) || /* 4 and 5 */
- (!oldtree && newtree &&
- same(current, newtree)) || /* 6 and 7 */
- (oldtree && newtree &&
- same(oldtree, newtree)) || /* 14 and 15 */
- (oldtree && newtree &&
- !same(oldtree, newtree) && /* 18 and 19*/
- same(current, newtree))) {
- return keep_entry(current);
- }
- else if (oldtree && !newtree && same(current, oldtree)) {
- /* 10 or 11 */
- return deleted_entry(oldtree, current, o);
- }
- else if (oldtree && newtree &&
- same(current, oldtree) && !same(current, newtree)) {
- /* 20 or 21 */
- return merged_entry(newtree, current, o);
- }
- else {
- /* all other failures */
- if (oldtree)
- reject_merge(oldtree);
- if (current)
- reject_merge(current);
- if (newtree)
- reject_merge(newtree);
- return -1;
- }
- }
- else if (newtree)
- return merged_entry(newtree, current, o);
- else
- return deleted_entry(oldtree, current, o);
-}
-
-/*
- * Bind merge.
- *
- * Keep the index entries at stage0, collapse stage1 but make sure
- * stage0 does not have anything there.
- */
-static int bind_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
-{
- struct cache_entry *old = src[0];
- struct cache_entry *a = src[1];
-
- if (o->merge_size != 1)
- return error("Cannot do a bind merge of %d trees\n",
- o->merge_size);
- if (a && old)
- die("Entry '%s' overlaps. Cannot bind.", a->name);
- if (!a)
- return keep_entry(old);
- else
- return merged_entry(a, NULL, o);
-}
-
-/*
- * One-way merge.
- *
- * The rule is:
- * - take the stat information from stage0, take the data from stage1
- */
-static int oneway_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
-{
- struct cache_entry *old = src[0];
- struct cache_entry *a = src[1];
-
- if (o->merge_size != 1)
- return error("Cannot do a oneway merge of %d trees",
- o->merge_size);
-
- if (!a)
- return deleted_entry(old, old, o);
- if (old && same(old, a)) {
- if (o->reset) {
- struct stat st;
- if (lstat(old->name, &st) ||
- ce_match_stat(old, &st, 1))
- old->ce_flags |= htons(CE_UPDATE);
- }
- return keep_entry(old);
- }
- return merged_entry(a, old, o);
-}
-
static int read_cache_unmerged(void)
{
int i;
@@ -432,7 +36,7 @@ static int read_cache_unmerged(void)
if (ce_stage(ce)) {
if (last && !strcmp(ce->name, last->name))
continue;
- invalidate_ce_path(ce);
+ cache_tree_invalidate_path(active_cache_tree, ce->name);
last = ce;
ce->ce_mode = 0;
ce->ce_flags &= ~htons(CE_STAGEMASK);
diff --git a/unpack-trees.c b/unpack-trees.c
index ecff92d..b8a355f 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -3,8 +3,11 @@ #include <sys/time.h>
#include "cache.h"
#include "tree.h"
#include "tree-walk.h"
+#include "cache-tree.h"
#include "unpack-trees.h"
+#define DBRT_DEBUG 1
+
struct tree_entry_list {
struct tree_entry_list *next;
unsigned directory : 1;
@@ -22,6 +25,9 @@ static struct tree_entry_list *create_tr
struct tree_entry_list *ret = NULL;
struct tree_entry_list **list_p = &ret;
+ if (!tree->object.parsed)
+ parse_tree(tree);
+
desc.buf = tree->buffer;
desc.size = tree->size;
@@ -365,7 +371,9 @@ int unpack_trees(struct object_list *tre
struct object_list *posn = trees;
struct tree_entry_list df_conflict_list;
+ memset(&df_conflict_list, 0, sizeof(df_conflict_list));
df_conflict_list.next = &df_conflict_list;
+ memset(&state, 0, sizeof(state));
state.base_dir = "";
state.force = 1;
state.quiet = 1;
@@ -391,4 +399,398 @@ int unpack_trees(struct object_list *tre
return 0;
}
+/* Here come the merge functions */
+
+static void reject_merge(struct cache_entry *ce)
+{
+ die("Entry '%s' would be overwritten by merge. Cannot merge.",
+ ce->name);
+}
+
+static int same(struct cache_entry *a, struct cache_entry *b)
+{
+ if (!!a != !!b)
+ return 0;
+ if (!a && !b)
+ return 1;
+ return a->ce_mode == b->ce_mode &&
+ !memcmp(a->sha1, b->sha1, 20);
+}
+
+
+/*
+ * When a CE gets turned into an unmerged entry, we
+ * want it to be up-to-date
+ */
+static void verify_uptodate(struct cache_entry *ce,
+ struct unpack_trees_options *o)
+{
+ struct stat st;
+
+ if (o->index_only || o->reset)
+ return;
+
+ if (!lstat(ce->name, &st)) {
+ unsigned changed = ce_match_stat(ce, &st, 1);
+ if (!changed)
+ return;
+ errno = 0;
+ }
+ if (o->reset) {
+ ce->ce_flags |= htons(CE_UPDATE);
+ return;
+ }
+ if (errno == ENOENT)
+ return;
+ die("Entry '%s' not uptodate. Cannot merge.", ce->name);
+}
+
+static void invalidate_ce_path(struct cache_entry *ce)
+{
+ if (ce)
+ cache_tree_invalidate_path(active_cache_tree, ce->name);
+}
+
+/*
+ * We do not want to remove or overwrite a working tree file that
+ * is not tracked.
+ */
+static void verify_absent(const char *path, const char *action,
+ struct unpack_trees_options *o)
+{
+ struct stat st;
+
+ if (o->index_only || o->reset || !o->update)
+ return;
+ if (!lstat(path, &st))
+ die("Untracked working tree file '%s' "
+ "would be %s by merge.", path, action);
+}
+
+static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
+ struct unpack_trees_options *o)
+{
+ merge->ce_flags |= htons(CE_UPDATE);
+ if (old) {
+ /*
+ * See if we can re-use the old CE directly?
+ * That way we get the uptodate stat info.
+ *
+ * This also removes the UPDATE flag on
+ * a match.
+ */
+ if (same(old, merge)) {
+ *merge = *old;
+ } else {
+ verify_uptodate(old, o);
+ invalidate_ce_path(old);
+ }
+ }
+ else {
+ verify_absent(merge->name, "overwritten", o);
+ invalidate_ce_path(merge);
+ }
+
+ merge->ce_flags &= ~htons(CE_STAGEMASK);
+ add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ return 1;
+}
+
+static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
+ struct unpack_trees_options *o)
+{
+ if (old)
+ verify_uptodate(old, o);
+ else
+ verify_absent(ce->name, "removed", o);
+ ce->ce_mode = 0;
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ invalidate_ce_path(ce);
+ return 1;
+}
+
+static int keep_entry(struct cache_entry *ce)
+{
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+ return 1;
+}
+
+#if DBRT_DEBUG
+static void show_stage_entry(FILE *o,
+ const char *label, const struct cache_entry *ce)
+{
+ if (!ce)
+ fprintf(o, "%s (missing)\n", label);
+ else
+ fprintf(o, "%s%06o %s %d\t%s\n",
+ label,
+ ntohl(ce->ce_mode),
+ sha1_to_hex(ce->sha1),
+ ce_stage(ce),
+ ce->name);
+}
+#endif
+
+int threeway_merge(struct cache_entry **stages,
+ struct unpack_trees_options *o)
+{
+ struct cache_entry *index;
+ struct cache_entry *head;
+ struct cache_entry *remote = stages[o->head_idx + 1];
+ int count;
+ int head_match = 0;
+ int remote_match = 0;
+ const char *path = NULL;
+
+ int df_conflict_head = 0;
+ int df_conflict_remote = 0;
+
+ int any_anc_missing = 0;
+ int no_anc_exists = 1;
+ int i;
+ for (i = 1; i < o->head_idx; i++) {
+ if (!stages[i])
+ any_anc_missing = 1;
+ else {
+ if (!path)
+ path = stages[i]->name;
+ no_anc_exists = 0;
+ }
+ }
+
+ index = stages[0];
+ head = stages[o->head_idx];
+
+ if (head == &o->df_conflict_entry) {
+ df_conflict_head = 1;
+ head = NULL;
+ }
+
+ if (remote == &o->df_conflict_entry) {
+ df_conflict_remote = 1;
+ remote = NULL;
+ }
+
+ if (!path && index)
+ path = index->name;
+ if (!path && head)
+ path = head->name;
+ if (!path && remote)
+ path = remote->name;
+
+ /* First, if there's a #16 situation, note that to prevent #13
+ * and #14.
+ */
+ if (!same(remote, head)) {
+ for (i = 1; i < o->head_idx; i++) {
+ if (same(stages[i], head)) {
+ head_match = i;
+ }
+ if (same(stages[i], remote)) {
+ remote_match = i;
+ }
+ }
+ }
+
+ /* We start with cases where the index is allowed to match
+ * something other than the head: #14(ALT) and #2ALT, where it
+ * is permitted to match the result instead.
+ */
+ /* #14, #14ALT, #2ALT */
+ if (remote && !df_conflict_head && head_match && !remote_match) {
+ if (index && !same(index, remote) && !same(index, head))
+ reject_merge(index);
+ return merged_entry(remote, index, o);
+ }
+ /*
+ * If we have an entry in the index cache, then we want to
+ * make sure that it matches head.
+ */
+ if (index && !same(index, head)) {
+ reject_merge(index);
+ }
+
+ if (head) {
+ /* #5ALT, #15 */
+ if (same(head, remote))
+ return merged_entry(head, index, o);
+ /* #13, #3ALT */
+ if (!df_conflict_remote && remote_match && !head_match)
+ return merged_entry(head, index, o);
+ }
+
+ /* #1 */
+ if (!head && !remote && any_anc_missing)
+ return 0;
+
+ /* Under the new "aggressive" rule, we resolve mostly trivial
+ * cases that we historically had git-merge-one-file resolve.
+ */
+ if (o->aggressive) {
+ int head_deleted = !head && !df_conflict_head;
+ int remote_deleted = !remote && !df_conflict_remote;
+ /*
+ * Deleted in both.
+ * Deleted in one and unchanged in the other.
+ */
+ if ((head_deleted && remote_deleted) ||
+ (head_deleted && remote && remote_match) ||
+ (remote_deleted && head && head_match)) {
+ if (index)
+ return deleted_entry(index, index, o);
+ else if (path)
+ verify_absent(path, "removed", o);
+ return 0;
+ }
+ /*
+ * Added in both, identically.
+ */
+ if (no_anc_exists && head && remote && same(head, remote))
+ return merged_entry(head, index, o);
+
+ }
+
+ /* Below are "no merge" cases, which require that the index be
+ * up-to-date to avoid the files getting overwritten with
+ * conflict resolution files.
+ */
+ if (index) {
+ verify_uptodate(index, o);
+ }
+ else if (path)
+ verify_absent(path, "overwritten", o);
+
+ o->nontrivial_merge = 1;
+
+ /* #2, #3, #4, #6, #7, #9, #11. */
+ count = 0;
+ if (!head_match || !remote_match) {
+ for (i = 1; i < o->head_idx; i++) {
+ if (stages[i]) {
+ keep_entry(stages[i]);
+ count++;
+ break;
+ }
+ }
+ }
+#if DBRT_DEBUG
+ else {
+ fprintf(stderr, "read-tree: warning #16 detected\n");
+ show_stage_entry(stderr, "head ", stages[head_match]);
+ show_stage_entry(stderr, "remote ", stages[remote_match]);
+ }
+#endif
+ if (head) { count += keep_entry(head); }
+ if (remote) { count += keep_entry(remote); }
+ return count;
+}
+
+/*
+ * Two-way merge.
+ *
+ * The rule is to "carry forward" what is in the index without losing
+ * information across a "fast forward", favoring a successful merge
+ * over a merge failure when it makes sense. For details of the
+ * "carry forward" rule, please see <Documentation/git-read-tree.txt>.
+ *
+ */
+int twoway_merge(struct cache_entry **src,
+ struct unpack_trees_options *o)
+{
+ struct cache_entry *current = src[0];
+ struct cache_entry *oldtree = src[1], *newtree = src[2];
+
+ if (o->merge_size != 2)
+ return error("Cannot do a twoway merge of %d trees",
+ o->merge_size);
+
+ if (current) {
+ if ((!oldtree && !newtree) || /* 4 and 5 */
+ (!oldtree && newtree &&
+ same(current, newtree)) || /* 6 and 7 */
+ (oldtree && newtree &&
+ same(oldtree, newtree)) || /* 14 and 15 */
+ (oldtree && newtree &&
+ !same(oldtree, newtree) && /* 18 and 19*/
+ same(current, newtree))) {
+ return keep_entry(current);
+ }
+ else if (oldtree && !newtree && same(current, oldtree)) {
+ /* 10 or 11 */
+ return deleted_entry(oldtree, current, o);
+ }
+ else if (oldtree && newtree &&
+ same(current, oldtree) && !same(current, newtree)) {
+ /* 20 or 21 */
+ return merged_entry(newtree, current, o);
+ }
+ else {
+ /* all other failures */
+ if (oldtree)
+ reject_merge(oldtree);
+ if (current)
+ reject_merge(current);
+ if (newtree)
+ reject_merge(newtree);
+ return -1;
+ }
+ }
+ else if (newtree)
+ return merged_entry(newtree, current, o);
+ else
+ return deleted_entry(oldtree, current, o);
+}
+
+/*
+ * Bind merge.
+ *
+ * Keep the index entries at stage0, collapse stage1 but make sure
+ * stage0 does not have anything there.
+ */
+int bind_merge(struct cache_entry **src,
+ struct unpack_trees_options *o)
+{
+ struct cache_entry *old = src[0];
+ struct cache_entry *a = src[1];
+
+ if (o->merge_size != 1)
+ return error("Cannot do a bind merge of %d trees\n",
+ o->merge_size);
+ if (a && old)
+ die("Entry '%s' overlaps. Cannot bind.", a->name);
+ if (!a)
+ return keep_entry(old);
+ else
+ return merged_entry(a, NULL, o);
+}
+
+/*
+ * One-way merge.
+ *
+ * The rule is:
+ * - take the stat information from stage0, take the data from stage1
+ */
+int oneway_merge(struct cache_entry **src,
+ struct unpack_trees_options *o)
+{
+ struct cache_entry *old = src[0];
+ struct cache_entry *a = src[1];
+
+ if (o->merge_size != 1)
+ return error("Cannot do a oneway merge of %d trees",
+ o->merge_size);
+
+ if (!a)
+ return deleted_entry(old, old, o);
+ if (old && same(old, a)) {
+ if (o->reset) {
+ struct stat st;
+ if (lstat(old->name, &st) ||
+ ce_match_stat(old, &st, 1))
+ old->ce_flags |= htons(CE_UPDATE);
+ }
+ return keep_entry(old);
+ }
+ return merged_entry(a, old, o);
+}
diff --git a/unpack-trees.h b/unpack-trees.h
index babfcd7..826b263 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -27,4 +27,9 @@ struct unpack_trees_options {
extern int unpack_trees(struct object_list *trees,
struct unpack_trees_options *options);
+int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o);
+int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o);
+int bind_merge(struct cache_entry **src, struct unpack_trees_options *o);
+int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o);
+
#endif
--
1.4.2.rc2.g76b2-dirty
^ permalink raw reply related
* [PATCH 1/3] read-trees: refactor the unpack_trees() part
From: Johannes Schindelin @ 2006-07-30 18:25 UTC (permalink / raw)
To: git, junkio
Basically, the options are passed by a struct unpack_trees_options now.
That's all.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
It is a real pity we do not have "subcopies" in our diff file
format yet, because "copy" and "rename " do not help in this case.
Makefile | 4
builtin-read-tree.c | 571 ++++++++-------------------------------------------
unpack-trees.c | 394 +++++++++++++++++++++++++++++++++++
unpack-trees.h | 30 +++
4 files changed, 517 insertions(+), 482 deletions(-)
diff --git a/Makefile b/Makefile
index c7b161b..4de2011 100644
--- a/Makefile
+++ b/Makefile
@@ -232,7 +232,7 @@ LIB_H = \
blob.h cache.h commit.h csum-file.h delta.h \
diff.h object.h pack.h pkt-line.h quote.h refs.h \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
- tree-walk.h log-tree.h dir.h path-list.h
+ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h
DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -247,7 +247,7 @@ LIB_OBJS = \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
- alloc.o merge-file.o path-list.o $(DIFF_OBJS)
+ alloc.o merge-file.o path-list.o unpack-trees.o $(DIFF_OBJS)
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 49c10bf..a9852c7 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -11,411 +11,17 @@ #include "object.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
-#include <sys/time.h>
-#include <signal.h>
+#include "unpack-trees.h"
#include "builtin.h"
-static int reset = 0;
-static int merge = 0;
-static int update = 0;
-static int index_only = 0;
-static int nontrivial_merge = 0;
-static int trivial_merges_only = 0;
-static int aggressive = 0;
-static int verbose_update = 0;
-static volatile int progress_update = 0;
-static const char *prefix = NULL;
-
-static int head_idx = -1;
-static int merge_size = 0;
-
static struct object_list *trees = NULL;
-static struct cache_entry df_conflict_entry;
-
-struct tree_entry_list {
- struct tree_entry_list *next;
- unsigned directory : 1;
- unsigned executable : 1;
- unsigned symlink : 1;
- unsigned int mode;
- const char *name;
- const unsigned char *sha1;
-};
-
-static struct tree_entry_list df_conflict_list;
-
-typedef int (*merge_fn_t)(struct cache_entry **src);
-
-static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
-{
- struct tree_desc desc;
- struct name_entry one;
- struct tree_entry_list *ret = NULL;
- struct tree_entry_list **list_p = &ret;
-
- desc.buf = tree->buffer;
- desc.size = tree->size;
-
- while (tree_entry(&desc, &one)) {
- struct tree_entry_list *entry;
-
- entry = xmalloc(sizeof(struct tree_entry_list));
- entry->name = one.path;
- entry->sha1 = one.sha1;
- entry->mode = one.mode;
- entry->directory = S_ISDIR(one.mode) != 0;
- entry->executable = (one.mode & S_IXUSR) != 0;
- entry->symlink = S_ISLNK(one.mode) != 0;
- entry->next = NULL;
-
- *list_p = entry;
- list_p = &entry->next;
- }
- return ret;
-}
-
-static int entcmp(const char *name1, int dir1, const char *name2, int dir2)
-{
- int len1 = strlen(name1);
- int len2 = strlen(name2);
- int len = len1 < len2 ? len1 : len2;
- int ret = memcmp(name1, name2, len);
- unsigned char c1, c2;
- if (ret)
- return ret;
- c1 = name1[len];
- c2 = name2[len];
- if (!c1 && dir1)
- c1 = '/';
- if (!c2 && dir2)
- c2 = '/';
- ret = (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
- if (c1 && c2 && !ret)
- ret = len1 - len2;
- return ret;
-}
-
-static int unpack_trees_rec(struct tree_entry_list **posns, int len,
- const char *base, merge_fn_t fn, int *indpos)
-{
- int baselen = strlen(base);
- int src_size = len + 1;
- do {
- int i;
- const char *first;
- int firstdir = 0;
- int pathlen;
- unsigned ce_size;
- struct tree_entry_list **subposns;
- struct cache_entry **src;
- int any_files = 0;
- int any_dirs = 0;
- char *cache_name;
- int ce_stage;
-
- /* Find the first name in the input. */
-
- first = NULL;
- cache_name = NULL;
-
- /* Check the cache */
- if (merge && *indpos < active_nr) {
- /* This is a bit tricky: */
- /* If the index has a subdirectory (with
- * contents) as the first name, it'll get a
- * filename like "foo/bar". But that's after
- * "foo", so the entry in trees will get
- * handled first, at which point we'll go into
- * "foo", and deal with "bar" from the index,
- * because the base will be "foo/". The only
- * way we can actually have "foo/bar" first of
- * all the things is if the trees don't
- * contain "foo" at all, in which case we'll
- * handle "foo/bar" without going into the
- * directory, but that's fine (and will return
- * an error anyway, with the added unknown
- * file case.
- */
-
- cache_name = active_cache[*indpos]->name;
- if (strlen(cache_name) > baselen &&
- !memcmp(cache_name, base, baselen)) {
- cache_name += baselen;
- first = cache_name;
- } else {
- cache_name = NULL;
- }
- }
-
-#if DBRT_DEBUG > 1
- if (first)
- printf("index %s\n", first);
-#endif
- for (i = 0; i < len; i++) {
- if (!posns[i] || posns[i] == &df_conflict_list)
- continue;
-#if DBRT_DEBUG > 1
- printf("%d %s\n", i + 1, posns[i]->name);
-#endif
- if (!first || entcmp(first, firstdir,
- posns[i]->name,
- posns[i]->directory) > 0) {
- first = posns[i]->name;
- firstdir = posns[i]->directory;
- }
- }
- /* No name means we're done */
- if (!first)
- return 0;
-
- pathlen = strlen(first);
- ce_size = cache_entry_size(baselen + pathlen);
-
- src = xcalloc(src_size, sizeof(struct cache_entry *));
-
- subposns = xcalloc(len, sizeof(struct tree_list_entry *));
-
- if (cache_name && !strcmp(cache_name, first)) {
- any_files = 1;
- src[0] = active_cache[*indpos];
- remove_cache_entry_at(*indpos);
- }
-
- for (i = 0; i < len; i++) {
- struct cache_entry *ce;
-
- if (!posns[i] ||
- (posns[i] != &df_conflict_list &&
- strcmp(first, posns[i]->name))) {
- continue;
- }
-
- if (posns[i] == &df_conflict_list) {
- src[i + merge] = &df_conflict_entry;
- continue;
- }
-
- if (posns[i]->directory) {
- struct tree *tree = lookup_tree(posns[i]->sha1);
- any_dirs = 1;
- parse_tree(tree);
- subposns[i] = create_tree_entry_list(tree);
- posns[i] = posns[i]->next;
- src[i + merge] = &df_conflict_entry;
- continue;
- }
-
- if (!merge)
- ce_stage = 0;
- else if (i + 1 < head_idx)
- ce_stage = 1;
- else if (i + 1 > head_idx)
- ce_stage = 3;
- else
- ce_stage = 2;
-
- ce = xcalloc(1, ce_size);
- ce->ce_mode = create_ce_mode(posns[i]->mode);
- ce->ce_flags = create_ce_flags(baselen + pathlen,
- ce_stage);
- memcpy(ce->name, base, baselen);
- memcpy(ce->name + baselen, first, pathlen + 1);
-
- any_files = 1;
-
- memcpy(ce->sha1, posns[i]->sha1, 20);
- src[i + merge] = ce;
- subposns[i] = &df_conflict_list;
- posns[i] = posns[i]->next;
- }
- if (any_files) {
- if (merge) {
- int ret;
-
-#if DBRT_DEBUG > 1
- printf("%s:\n", first);
- for (i = 0; i < src_size; i++) {
- printf(" %d ", i);
- if (src[i])
- printf("%s\n", sha1_to_hex(src[i]->sha1));
- else
- printf("\n");
- }
-#endif
- ret = fn(src);
-
-#if DBRT_DEBUG > 1
- printf("Added %d entries\n", ret);
-#endif
- *indpos += ret;
- } else {
- for (i = 0; i < src_size; i++) {
- if (src[i]) {
- add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
- }
- }
- }
- }
- if (any_dirs) {
- char *newbase = xmalloc(baselen + 2 + pathlen);
- memcpy(newbase, base, baselen);
- memcpy(newbase + baselen, first, pathlen);
- newbase[baselen + pathlen] = '/';
- newbase[baselen + pathlen + 1] = '\0';
- if (unpack_trees_rec(subposns, len, newbase, fn,
- indpos))
- return -1;
- free(newbase);
- }
- free(subposns);
- free(src);
- } while (1);
-}
-
static void reject_merge(struct cache_entry *ce)
{
die("Entry '%s' would be overwritten by merge. Cannot merge.",
ce->name);
}
-/* Unlink the last component and attempt to remove leading
- * directories, in case this unlink is the removal of the
- * last entry in the directory -- empty directories are removed.
- */
-static void unlink_entry(char *name)
-{
- char *cp, *prev;
-
- if (unlink(name))
- return;
- prev = NULL;
- while (1) {
- int status;
- cp = strrchr(name, '/');
- if (prev)
- *prev = '/';
- if (!cp)
- break;
-
- *cp = 0;
- status = rmdir(name);
- if (status) {
- *cp = '/';
- break;
- }
- prev = cp;
- }
-}
-
-static void progress_interval(int signum)
-{
- progress_update = 1;
-}
-
-static void setup_progress_signal(void)
-{
- struct sigaction sa;
- struct itimerval v;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = progress_interval;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sigaction(SIGALRM, &sa, NULL);
-
- v.it_interval.tv_sec = 1;
- v.it_interval.tv_usec = 0;
- v.it_value = v.it_interval;
- setitimer(ITIMER_REAL, &v, NULL);
-}
-
-static struct checkout state;
-static void check_updates(struct cache_entry **src, int nr)
-{
- unsigned short mask = htons(CE_UPDATE);
- unsigned last_percent = 200, cnt = 0, total = 0;
-
- if (update && verbose_update) {
- for (total = cnt = 0; cnt < nr; cnt++) {
- struct cache_entry *ce = src[cnt];
- if (!ce->ce_mode || ce->ce_flags & mask)
- total++;
- }
-
- /* Don't bother doing this for very small updates */
- if (total < 250)
- total = 0;
-
- if (total) {
- fprintf(stderr, "Checking files out...\n");
- setup_progress_signal();
- progress_update = 1;
- }
- cnt = 0;
- }
-
- while (nr--) {
- struct cache_entry *ce = *src++;
-
- if (total) {
- if (!ce->ce_mode || ce->ce_flags & mask) {
- unsigned percent;
- cnt++;
- percent = (cnt * 100) / total;
- if (percent != last_percent ||
- progress_update) {
- fprintf(stderr, "%4u%% (%u/%u) done\r",
- percent, cnt, total);
- last_percent = percent;
- progress_update = 0;
- }
- }
- }
- if (!ce->ce_mode) {
- if (update)
- unlink_entry(ce->name);
- continue;
- }
- if (ce->ce_flags & mask) {
- ce->ce_flags &= ~mask;
- if (update)
- checkout_entry(ce, &state, NULL);
- }
- }
- if (total) {
- signal(SIGALRM, SIG_IGN);
- fputc('\n', stderr);
- }
-}
-
-static int unpack_trees(merge_fn_t fn)
-{
- int indpos = 0;
- unsigned len = object_list_length(trees);
- struct tree_entry_list **posns;
- int i;
- struct object_list *posn = trees;
- merge_size = len;
-
- if (len) {
- posns = xmalloc(len * sizeof(struct tree_entry_list *));
- for (i = 0; i < len; i++) {
- posns[i] = create_tree_entry_list((struct tree *) posn->item);
- posn = posn->next;
- }
- if (unpack_trees_rec(posns, len, prefix ? prefix : "",
- fn, &indpos))
- return -1;
- }
-
- if (trivial_merges_only && nontrivial_merge)
- die("Merge requires file-level merging");
-
- check_updates(active_cache, active_nr);
- return 0;
-}
-
static int list_tree(unsigned char *sha1)
{
struct tree *tree = parse_tree_indirect(sha1);
@@ -440,11 +46,12 @@ static int same(struct cache_entry *a, s
* When a CE gets turned into an unmerged entry, we
* want it to be up-to-date
*/
-static void verify_uptodate(struct cache_entry *ce)
+static void verify_uptodate(struct cache_entry *ce,
+ struct unpack_trees_options *o)
{
struct stat st;
- if (index_only || reset)
+ if (o->index_only || o->reset)
return;
if (!lstat(ce->name, &st)) {
@@ -453,7 +60,7 @@ static void verify_uptodate(struct cache
return;
errno = 0;
}
- if (reset) {
+ if (o->reset) {
ce->ce_flags |= htons(CE_UPDATE);
return;
}
@@ -472,18 +79,20 @@ static void invalidate_ce_path(struct ca
* We do not want to remove or overwrite a working tree file that
* is not tracked.
*/
-static void verify_absent(const char *path, const char *action)
+static void verify_absent(const char *path, const char *action,
+ struct unpack_trees_options *o)
{
struct stat st;
- if (index_only || reset || !update)
+ if (o->index_only || o->reset || !o->update)
return;
if (!lstat(path, &st))
die("Untracked working tree file '%s' "
"would be %s by merge.", path, action);
}
-static int merged_entry(struct cache_entry *merge, struct cache_entry *old)
+static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
+ struct unpack_trees_options *o)
{
merge->ce_flags |= htons(CE_UPDATE);
if (old) {
@@ -497,12 +106,12 @@ static int merged_entry(struct cache_ent
if (same(old, merge)) {
*merge = *old;
} else {
- verify_uptodate(old);
+ verify_uptodate(old, o);
invalidate_ce_path(old);
}
}
else {
- verify_absent(merge->name, "overwritten");
+ verify_absent(merge->name, "overwritten", o);
invalidate_ce_path(merge);
}
@@ -511,12 +120,13 @@ static int merged_entry(struct cache_ent
return 1;
}
-static int deleted_entry(struct cache_entry *ce, struct cache_entry *old)
+static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
+ struct unpack_trees_options *o)
{
if (old)
- verify_uptodate(old);
+ verify_uptodate(old, o);
else
- verify_absent(ce->name, "removed");
+ verify_absent(ce->name, "removed", o);
ce->ce_mode = 0;
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
invalidate_ce_path(ce);
@@ -545,11 +155,12 @@ static void show_stage_entry(FILE *o,
}
#endif
-static int threeway_merge(struct cache_entry **stages)
+static int threeway_merge(struct cache_entry **stages,
+ struct unpack_trees_options *o)
{
struct cache_entry *index;
struct cache_entry *head;
- struct cache_entry *remote = stages[head_idx + 1];
+ struct cache_entry *remote = stages[o->head_idx + 1];
int count;
int head_match = 0;
int remote_match = 0;
@@ -562,7 +173,7 @@ static int threeway_merge(struct cache_e
int no_anc_exists = 1;
int i;
- for (i = 1; i < head_idx; i++) {
+ for (i = 1; i < o->head_idx; i++) {
if (!stages[i])
any_anc_missing = 1;
else {
@@ -573,14 +184,14 @@ static int threeway_merge(struct cache_e
}
index = stages[0];
- head = stages[head_idx];
+ head = stages[o->head_idx];
- if (head == &df_conflict_entry) {
+ if (head == &o->df_conflict_entry) {
df_conflict_head = 1;
head = NULL;
}
- if (remote == &df_conflict_entry) {
+ if (remote == &o->df_conflict_entry) {
df_conflict_remote = 1;
remote = NULL;
}
@@ -596,7 +207,7 @@ static int threeway_merge(struct cache_e
* and #14.
*/
if (!same(remote, head)) {
- for (i = 1; i < head_idx; i++) {
+ for (i = 1; i < o->head_idx; i++) {
if (same(stages[i], head)) {
head_match = i;
}
@@ -614,7 +225,7 @@ static int threeway_merge(struct cache_e
if (remote && !df_conflict_head && head_match && !remote_match) {
if (index && !same(index, remote) && !same(index, head))
reject_merge(index);
- return merged_entry(remote, index);
+ return merged_entry(remote, index, o);
}
/*
* If we have an entry in the index cache, then we want to
@@ -627,10 +238,10 @@ static int threeway_merge(struct cache_e
if (head) {
/* #5ALT, #15 */
if (same(head, remote))
- return merged_entry(head, index);
+ return merged_entry(head, index, o);
/* #13, #3ALT */
if (!df_conflict_remote && remote_match && !head_match)
- return merged_entry(head, index);
+ return merged_entry(head, index, o);
}
/* #1 */
@@ -640,7 +251,7 @@ static int threeway_merge(struct cache_e
/* Under the new "aggressive" rule, we resolve mostly trivial
* cases that we historically had git-merge-one-file resolve.
*/
- if (aggressive) {
+ if (o->aggressive) {
int head_deleted = !head && !df_conflict_head;
int remote_deleted = !remote && !df_conflict_remote;
/*
@@ -651,16 +262,16 @@ static int threeway_merge(struct cache_e
(head_deleted && remote && remote_match) ||
(remote_deleted && head && head_match)) {
if (index)
- return deleted_entry(index, index);
+ return deleted_entry(index, index, o);
else if (path)
- verify_absent(path, "removed");
+ verify_absent(path, "removed", o);
return 0;
}
/*
* Added in both, identically.
*/
if (no_anc_exists && head && remote && same(head, remote))
- return merged_entry(head, index);
+ return merged_entry(head, index, o);
}
@@ -669,17 +280,17 @@ static int threeway_merge(struct cache_e
* conflict resolution files.
*/
if (index) {
- verify_uptodate(index);
+ verify_uptodate(index, o);
}
else if (path)
- verify_absent(path, "overwritten");
+ verify_absent(path, "overwritten", o);
- nontrivial_merge = 1;
+ o->nontrivial_merge = 1;
/* #2, #3, #4, #6, #7, #9, #11. */
count = 0;
if (!head_match || !remote_match) {
- for (i = 1; i < head_idx; i++) {
+ for (i = 1; i < o->head_idx; i++) {
if (stages[i]) {
keep_entry(stages[i]);
count++;
@@ -708,14 +319,15 @@ #endif
* "carry forward" rule, please see <Documentation/git-read-tree.txt>.
*
*/
-static int twoway_merge(struct cache_entry **src)
+static int twoway_merge(struct cache_entry **src,
+ struct unpack_trees_options *o)
{
struct cache_entry *current = src[0];
struct cache_entry *oldtree = src[1], *newtree = src[2];
- if (merge_size != 2)
+ if (o->merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
- merge_size);
+ o->merge_size);
if (current) {
if ((!oldtree && !newtree) || /* 4 and 5 */
@@ -730,12 +342,12 @@ static int twoway_merge(struct cache_ent
}
else if (oldtree && !newtree && same(current, oldtree)) {
/* 10 or 11 */
- return deleted_entry(oldtree, current);
+ return deleted_entry(oldtree, current, o);
}
else if (oldtree && newtree &&
same(current, oldtree) && !same(current, newtree)) {
/* 20 or 21 */
- return merged_entry(newtree, current);
+ return merged_entry(newtree, current, o);
}
else {
/* all other failures */
@@ -749,9 +361,9 @@ static int twoway_merge(struct cache_ent
}
}
else if (newtree)
- return merged_entry(newtree, current);
+ return merged_entry(newtree, current, o);
else
- return deleted_entry(oldtree, current);
+ return deleted_entry(oldtree, current, o);
}
/*
@@ -760,20 +372,21 @@ static int twoway_merge(struct cache_ent
* Keep the index entries at stage0, collapse stage1 but make sure
* stage0 does not have anything there.
*/
-static int bind_merge(struct cache_entry **src)
+static int bind_merge(struct cache_entry **src,
+ struct unpack_trees_options *o)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
- if (merge_size != 1)
+ if (o->merge_size != 1)
return error("Cannot do a bind merge of %d trees\n",
- merge_size);
+ o->merge_size);
if (a && old)
die("Entry '%s' overlaps. Cannot bind.", a->name);
if (!a)
return keep_entry(old);
else
- return merged_entry(a, NULL);
+ return merged_entry(a, NULL, o);
}
/*
@@ -782,19 +395,20 @@ static int bind_merge(struct cache_entry
* The rule is:
* - take the stat information from stage0, take the data from stage1
*/
-static int oneway_merge(struct cache_entry **src)
+static int oneway_merge(struct cache_entry **src,
+ struct unpack_trees_options *o)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
- if (merge_size != 1)
+ if (o->merge_size != 1)
return error("Cannot do a oneway merge of %d trees",
- merge_size);
+ o->merge_size);
if (!a)
- return deleted_entry(old, old);
+ return deleted_entry(old, old, o);
if (old && same(old, a)) {
- if (reset) {
+ if (o->reset) {
struct stat st;
if (lstat(old->name, &st) ||
ce_match_stat(old, &st, 1))
@@ -802,7 +416,7 @@ static int oneway_merge(struct cache_ent
}
return keep_entry(old);
}
- return merged_entry(a, old);
+ return merged_entry(a, old, o);
}
static int read_cache_unmerged(void)
@@ -874,14 +488,12 @@ int cmd_read_tree(int argc, const char *
{
int i, newfd, stage = 0;
unsigned char sha1[20];
- merge_fn_t fn = NULL;
+ struct unpack_trees_options opts;
- df_conflict_list.next = &df_conflict_list;
- state.base_dir = "";
- state.force = 1;
- state.quiet = 1;
- state.refresh_cache = 1;
+ memset(&opts, 0, sizeof(opts));
+ opts.head_idx = -1;
+ setup_git_directory();
git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file());
@@ -890,8 +502,6 @@ int cmd_read_tree(int argc, const char *
git_config(git_default_config);
- merge = 0;
- reset = 0;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -899,12 +509,12 @@ int cmd_read_tree(int argc, const char *
* the working tree.
*/
if (!strcmp(arg, "-u")) {
- update = 1;
+ opts.update = 1;
continue;
}
if (!strcmp(arg, "-v")) {
- verbose_update = 1;
+ opts.verbose_update = 1;
continue;
}
@@ -912,7 +522,7 @@ int cmd_read_tree(int argc, const char *
* not even look at the working tree.
*/
if (!strcmp(arg, "-i")) {
- index_only = 1;
+ opts.index_only = 1;
continue;
}
@@ -921,10 +531,10 @@ int cmd_read_tree(int argc, const char *
* given subdirectory.
*/
if (!strncmp(arg, "--prefix=", 9)) {
- if (stage || merge || prefix)
+ if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
- prefix = arg + 9;
- merge = 1;
+ opts.prefix = arg + 9;
+ opts.merge = 1;
stage = 1;
if (read_cache_unmerged())
die("you need to resolve your current index first");
@@ -936,38 +546,38 @@ int cmd_read_tree(int argc, const char *
* correspond to them.
*/
if (!strcmp(arg, "--reset")) {
- if (stage || merge || prefix)
+ if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
- reset = 1;
- merge = 1;
+ opts.reset = 1;
+ opts.merge = 1;
stage = 1;
read_cache_unmerged();
continue;
}
if (!strcmp(arg, "--trivial")) {
- trivial_merges_only = 1;
+ opts.trivial_merges_only = 1;
continue;
}
if (!strcmp(arg, "--aggressive")) {
- aggressive = 1;
+ opts.aggressive = 1;
continue;
}
/* "-m" stands for "merge", meaning we start in stage 1 */
if (!strcmp(arg, "-m")) {
- if (stage || merge || prefix)
+ if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
if (read_cache_unmerged())
die("you need to resolve your current index first");
stage = 1;
- merge = 1;
+ opts.merge = 1;
continue;
}
/* using -u and -i at the same time makes no sense */
- if (1 < index_only + update)
+ if (1 < opts.index_only + opts.update)
usage(read_tree_usage);
if (get_sha1(arg, sha1))
@@ -976,52 +586,53 @@ int cmd_read_tree(int argc, const char *
die("failed to unpack tree object %s", arg);
stage++;
}
- if ((update||index_only) && !merge)
+ if ((opts.update||opts.index_only) && !opts.merge)
usage(read_tree_usage);
- if (prefix) {
- int pfxlen = strlen(prefix);
+ if (opts.prefix) {
+ int pfxlen = strlen(opts.prefix);
int pos;
- if (prefix[pfxlen-1] != '/')
+ if (opts.prefix[pfxlen-1] != '/')
die("prefix must end with /");
if (stage != 2)
die("binding merge takes only one tree");
- pos = cache_name_pos(prefix, pfxlen);
+ pos = cache_name_pos(opts.prefix, pfxlen);
if (0 <= pos)
die("corrupt index file");
pos = -pos-1;
if (pos < active_nr &&
- !strncmp(active_cache[pos]->name, prefix, pfxlen))
- die("subdirectory '%s' already exists.", prefix);
- pos = cache_name_pos(prefix, pfxlen-1);
+ !strncmp(active_cache[pos]->name, opts.prefix, pfxlen))
+ die("subdirectory '%s' already exists.", opts.prefix);
+ pos = cache_name_pos(opts.prefix, pfxlen-1);
if (0 <= pos)
- die("file '%.*s' already exists.", pfxlen-1, prefix);
+ die("file '%.*s' already exists.",
+ pfxlen-1, opts.prefix);
}
- if (merge) {
+ if (opts.merge) {
if (stage < 2)
die("just how do you expect me to merge %d trees?", stage-1);
switch (stage - 1) {
case 1:
- fn = prefix ? bind_merge : oneway_merge;
+ opts.fn = opts.prefix ? bind_merge : oneway_merge;
break;
case 2:
- fn = twoway_merge;
+ opts.fn = twoway_merge;
break;
case 3:
default:
- fn = threeway_merge;
+ opts.fn = threeway_merge;
cache_tree_free(&active_cache_tree);
break;
}
if (stage - 1 >= 3)
- head_idx = stage - 2;
+ opts.head_idx = stage - 2;
else
- head_idx = 1;
+ opts.head_idx = 1;
}
- unpack_trees(fn);
+ unpack_trees(trees, &opts);
/*
* When reading only one tree (either the most basic form,
@@ -1029,7 +640,7 @@ int cmd_read_tree(int argc, const char *
* valid cache-tree because the index must match exactly
* what came from the tree.
*/
- if (trees && trees->item && !prefix && (!merge || (stage == 2))) {
+ if (trees && trees->item && !opts.prefix && (!opts.merge || (stage == 2))) {
cache_tree_free(&active_cache_tree);
prime_cache_tree();
}
diff --git a/unpack-trees.c b/unpack-trees.c
new file mode 100644
index 0000000..ecff92d
--- /dev/null
+++ b/unpack-trees.c
@@ -0,0 +1,394 @@
+#include <signal.h>
+#include <sys/time.h>
+#include "cache.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "unpack-trees.h"
+
+struct tree_entry_list {
+ struct tree_entry_list *next;
+ unsigned directory : 1;
+ unsigned executable : 1;
+ unsigned symlink : 1;
+ unsigned int mode;
+ const char *name;
+ const unsigned char *sha1;
+};
+
+static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
+{
+ struct tree_desc desc;
+ struct name_entry one;
+ struct tree_entry_list *ret = NULL;
+ struct tree_entry_list **list_p = &ret;
+
+ desc.buf = tree->buffer;
+ desc.size = tree->size;
+
+ while (tree_entry(&desc, &one)) {
+ struct tree_entry_list *entry;
+
+ entry = xmalloc(sizeof(struct tree_entry_list));
+ entry->name = one.path;
+ entry->sha1 = one.sha1;
+ entry->mode = one.mode;
+ entry->directory = S_ISDIR(one.mode) != 0;
+ entry->executable = (one.mode & S_IXUSR) != 0;
+ entry->symlink = S_ISLNK(one.mode) != 0;
+ entry->next = NULL;
+
+ *list_p = entry;
+ list_p = &entry->next;
+ }
+ return ret;
+}
+
+static int entcmp(const char *name1, int dir1, const char *name2, int dir2)
+{
+ int len1 = strlen(name1);
+ int len2 = strlen(name2);
+ int len = len1 < len2 ? len1 : len2;
+ int ret = memcmp(name1, name2, len);
+ unsigned char c1, c2;
+ if (ret)
+ return ret;
+ c1 = name1[len];
+ c2 = name2[len];
+ if (!c1 && dir1)
+ c1 = '/';
+ if (!c2 && dir2)
+ c2 = '/';
+ ret = (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
+ if (c1 && c2 && !ret)
+ ret = len1 - len2;
+ return ret;
+}
+
+static int unpack_trees_rec(struct tree_entry_list **posns, int len,
+ const char *base, struct unpack_trees_options *o,
+ int *indpos,
+ struct tree_entry_list *df_conflict_list)
+{
+ int baselen = strlen(base);
+ int src_size = len + 1;
+ do {
+ int i;
+ const char *first;
+ int firstdir = 0;
+ int pathlen;
+ unsigned ce_size;
+ struct tree_entry_list **subposns;
+ struct cache_entry **src;
+ int any_files = 0;
+ int any_dirs = 0;
+ char *cache_name;
+ int ce_stage;
+
+ /* Find the first name in the input. */
+
+ first = NULL;
+ cache_name = NULL;
+
+ /* Check the cache */
+ if (o->merge && *indpos < active_nr) {
+ /* This is a bit tricky: */
+ /* If the index has a subdirectory (with
+ * contents) as the first name, it'll get a
+ * filename like "foo/bar". But that's after
+ * "foo", so the entry in trees will get
+ * handled first, at which point we'll go into
+ * "foo", and deal with "bar" from the index,
+ * because the base will be "foo/". The only
+ * way we can actually have "foo/bar" first of
+ * all the things is if the trees don't
+ * contain "foo" at all, in which case we'll
+ * handle "foo/bar" without going into the
+ * directory, but that's fine (and will return
+ * an error anyway, with the added unknown
+ * file case.
+ */
+
+ cache_name = active_cache[*indpos]->name;
+ if (strlen(cache_name) > baselen &&
+ !memcmp(cache_name, base, baselen)) {
+ cache_name += baselen;
+ first = cache_name;
+ } else {
+ cache_name = NULL;
+ }
+ }
+
+#if DBRT_DEBUG > 1
+ if (first)
+ printf("index %s\n", first);
+#endif
+ for (i = 0; i < len; i++) {
+ if (!posns[i] || posns[i] == df_conflict_list)
+ continue;
+#if DBRT_DEBUG > 1
+ printf("%d %s\n", i + 1, posns[i]->name);
+#endif
+ if (!first || entcmp(first, firstdir,
+ posns[i]->name,
+ posns[i]->directory) > 0) {
+ first = posns[i]->name;
+ firstdir = posns[i]->directory;
+ }
+ }
+ /* No name means we're done */
+ if (!first)
+ return 0;
+
+ pathlen = strlen(first);
+ ce_size = cache_entry_size(baselen + pathlen);
+
+ src = xcalloc(src_size, sizeof(struct cache_entry *));
+
+ subposns = xcalloc(len, sizeof(struct tree_list_entry *));
+
+ if (cache_name && !strcmp(cache_name, first)) {
+ any_files = 1;
+ src[0] = active_cache[*indpos];
+ remove_cache_entry_at(*indpos);
+ }
+
+ for (i = 0; i < len; i++) {
+ struct cache_entry *ce;
+
+ if (!posns[i] ||
+ (posns[i] != df_conflict_list &&
+ strcmp(first, posns[i]->name))) {
+ continue;
+ }
+
+ if (posns[i] == df_conflict_list) {
+ src[i + o->merge] = &o->df_conflict_entry;
+ continue;
+ }
+
+ if (posns[i]->directory) {
+ struct tree *tree = lookup_tree(posns[i]->sha1);
+ any_dirs = 1;
+ parse_tree(tree);
+ subposns[i] = create_tree_entry_list(tree);
+ posns[i] = posns[i]->next;
+ src[i + o->merge] = &o->df_conflict_entry;
+ continue;
+ }
+
+ if (!o->merge)
+ ce_stage = 0;
+ else if (i + 1 < o->head_idx)
+ ce_stage = 1;
+ else if (i + 1 > o->head_idx)
+ ce_stage = 3;
+ else
+ ce_stage = 2;
+
+ ce = xcalloc(1, ce_size);
+ ce->ce_mode = create_ce_mode(posns[i]->mode);
+ ce->ce_flags = create_ce_flags(baselen + pathlen,
+ ce_stage);
+ memcpy(ce->name, base, baselen);
+ memcpy(ce->name + baselen, first, pathlen + 1);
+
+ any_files = 1;
+
+ memcpy(ce->sha1, posns[i]->sha1, 20);
+ src[i + o->merge] = ce;
+ subposns[i] = df_conflict_list;
+ posns[i] = posns[i]->next;
+ }
+ if (any_files) {
+ if (o->merge) {
+ int ret;
+
+#if DBRT_DEBUG > 1
+ printf("%s:\n", first);
+ for (i = 0; i < src_size; i++) {
+ printf(" %d ", i);
+ if (src[i])
+ printf("%s\n", sha1_to_hex(src[i]->sha1));
+ else
+ printf("\n");
+ }
+#endif
+ ret = o->fn(src, o);
+
+#if DBRT_DEBUG > 1
+ printf("Added %d entries\n", ret);
+#endif
+ *indpos += ret;
+ } else {
+ for (i = 0; i < src_size; i++) {
+ if (src[i]) {
+ add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+ }
+ }
+ }
+ }
+ if (any_dirs) {
+ char *newbase = xmalloc(baselen + 2 + pathlen);
+ memcpy(newbase, base, baselen);
+ memcpy(newbase + baselen, first, pathlen);
+ newbase[baselen + pathlen] = '/';
+ newbase[baselen + pathlen + 1] = '\0';
+ if (unpack_trees_rec(subposns, len, newbase, o,
+ indpos, df_conflict_list))
+ return -1;
+ free(newbase);
+ }
+ free(subposns);
+ free(src);
+ } while (1);
+}
+
+/* Unlink the last component and attempt to remove leading
+ * directories, in case this unlink is the removal of the
+ * last entry in the directory -- empty directories are removed.
+ */
+static void unlink_entry(char *name)
+{
+ char *cp, *prev;
+
+ if (unlink(name))
+ return;
+ prev = NULL;
+ while (1) {
+ int status;
+ cp = strrchr(name, '/');
+ if (prev)
+ *prev = '/';
+ if (!cp)
+ break;
+
+ *cp = 0;
+ status = rmdir(name);
+ if (status) {
+ *cp = '/';
+ break;
+ }
+ prev = cp;
+ }
+}
+
+static volatile int progress_update = 0;
+
+static void progress_interval(int signum)
+{
+ progress_update = 1;
+}
+
+static void setup_progress_signal(void)
+{
+ struct sigaction sa;
+ struct itimerval v;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = progress_interval;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGALRM, &sa, NULL);
+
+ v.it_interval.tv_sec = 1;
+ v.it_interval.tv_usec = 0;
+ v.it_value = v.it_interval;
+ setitimer(ITIMER_REAL, &v, NULL);
+}
+
+static struct checkout state;
+static void check_updates(struct cache_entry **src, int nr,
+ struct unpack_trees_options *o)
+{
+ unsigned short mask = htons(CE_UPDATE);
+ unsigned last_percent = 200, cnt = 0, total = 0;
+
+ if (o->update && o->verbose_update) {
+ for (total = cnt = 0; cnt < nr; cnt++) {
+ struct cache_entry *ce = src[cnt];
+ if (!ce->ce_mode || ce->ce_flags & mask)
+ total++;
+ }
+
+ /* Don't bother doing this for very small updates */
+ if (total < 250)
+ total = 0;
+
+ if (total) {
+ fprintf(stderr, "Checking files out...\n");
+ setup_progress_signal();
+ progress_update = 1;
+ }
+ cnt = 0;
+ }
+
+ while (nr--) {
+ struct cache_entry *ce = *src++;
+
+ if (total) {
+ if (!ce->ce_mode || ce->ce_flags & mask) {
+ unsigned percent;
+ cnt++;
+ percent = (cnt * 100) / total;
+ if (percent != last_percent ||
+ progress_update) {
+ fprintf(stderr, "%4u%% (%u/%u) done\r",
+ percent, cnt, total);
+ last_percent = percent;
+ progress_update = 0;
+ }
+ }
+ }
+ if (!ce->ce_mode) {
+ if (o->update)
+ unlink_entry(ce->name);
+ continue;
+ }
+ if (ce->ce_flags & mask) {
+ ce->ce_flags &= ~mask;
+ if (o->update)
+ checkout_entry(ce, &state, NULL);
+ }
+ }
+ if (total) {
+ signal(SIGALRM, SIG_IGN);
+ fputc('\n', stderr);
+ }
+}
+
+int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
+{
+ int indpos = 0;
+ unsigned len = object_list_length(trees);
+ struct tree_entry_list **posns;
+ int i;
+ struct object_list *posn = trees;
+ struct tree_entry_list df_conflict_list;
+
+ df_conflict_list.next = &df_conflict_list;
+ state.base_dir = "";
+ state.force = 1;
+ state.quiet = 1;
+ state.refresh_cache = 1;
+
+ o->merge_size = len;
+
+ if (len) {
+ posns = xmalloc(len * sizeof(struct tree_entry_list *));
+ for (i = 0; i < len; i++) {
+ posns[i] = create_tree_entry_list((struct tree *) posn->item);
+ posn = posn->next;
+ }
+ if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
+ o, &indpos, &df_conflict_list))
+ return -1;
+ }
+
+ if (o->trivial_merges_only && o->nontrivial_merge)
+ die("Merge requires file-level merging");
+
+ check_updates(active_cache, active_nr, o);
+ return 0;
+}
+
+
diff --git a/unpack-trees.h b/unpack-trees.h
new file mode 100644
index 0000000..babfcd7
--- /dev/null
+++ b/unpack-trees.h
@@ -0,0 +1,30 @@
+#ifndef UNPACK_TREES_H
+#define UNPACK_TREES_H
+
+struct unpack_trees_options;
+
+typedef int (*merge_fn_t)(struct cache_entry **src,
+ struct unpack_trees_options *options);
+
+struct unpack_trees_options {
+ int reset;
+ int merge;
+ int update;
+ int index_only;
+ int nontrivial_merge;
+ int trivial_merges_only;
+ int verbose_update;
+ int aggressive;
+ const char *prefix;
+ merge_fn_t fn;
+
+ int head_idx;
+ int merge_size;
+
+ struct cache_entry df_conflict_entry;
+};
+
+extern int unpack_trees(struct object_list *trees,
+ struct unpack_trees_options *options);
+
+#endif
--
1.4.2.rc2.g76b2-dirty
^ permalink raw reply related
* [PATCH 0/3] merge-recur: get rid of external call to read-tree
From: Johannes Schindelin @ 2006-07-30 18:24 UTC (permalink / raw)
To: git, junkio
Hi,
these three patches refactor the read-tree functionality into
unpack-trees.[ch], and then use them in merge-recur.
I did not do any benchmarks yet, so this task is up for grabs.
Ciao,
Dscho
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox