* Re: Make more commands builtin
From: Peter Eriksen @ 2006-05-23 12:54 UTC (permalink / raw)
To: git
In-Reply-To: <e4uvku$o28$1@sea.gmane.org>
On Tue, May 23, 2006 at 02:36:54PM +0200, Jakub Narebski wrote:
> Peter Eriksen wrote:
>
> > Btw.
> >
> > I used these commands to produce the patch series:
> >
> > git diff --stat -C 24b65a30015aedd..pe/builtin
> > git-send-email --no-chain-reply-to --compose \
> > --from=s022018@student.dtu.dk --not-signed-off-by-cc \
> > --quiet \
> > --subject="Make more commands builtin" \
> > --to=git@vger.kernel.org Patches/*
>
> I wonder why the patches themselves are not replies to the main/summary
> email, i.e. "Make more commands builtin" email...
It seems thay are:
Subject: Make more commands builtin
Message-Id: <11483865361243-git-send-email-1>
Subject: [PATCH 1/8] Builtin git-ls-files.
Message-Id: <11483865362613-git-send-email-1>
In-Reply-To: <11483865361243-git-send-email-1>
Subject: [PATCH 2/8] Builtin git-ls-tree.
Message-Id: <11483865362923-git-send-email-1>
In-Reply-To: <11483865361243-git-send-email-1>
Peter
^ permalink raw reply
* Re: Make more commands builtin
From: Jakub Narebski @ 2006-05-23 12:36 UTC (permalink / raw)
To: git
In-Reply-To: <20060523122056.GA5777@bohr.gbar.dtu.dk>
Peter Eriksen wrote:
> Btw.
>
> I used these commands to produce the patch series:
>
> git diff --stat -C 24b65a30015aedd..pe/builtin
> git-send-email --no-chain-reply-to --compose \
> --from=s022018@student.dtu.dk --not-signed-off-by-cc \
> --quiet \
> --subject="Make more commands builtin" \
> --to=git@vger.kernel.org Patches/*
I wonder why the patches themselves are not replies to the main/summary
email, i.e. "Make more commands builtin" email...
--
Jakub Narebski
Warsaw, Poland
^ permalink raw reply
* Re: Make more commands builtin
From: Peter Eriksen @ 2006-05-23 12:20 UTC (permalink / raw)
To: git
In-Reply-To: <11483865361243-git-send-email-1>
Btw.
I used these commands to produce the patch series:
git diff --stat -C 24b65a30015aedd..pe/builtin
git-send-email --no-chain-reply-to --compose \
--from=s022018@student.dtu.dk --not-signed-off-by-cc \
--quiet \
--subject="Make more commands builtin" \
--to=git@vger.kernel.org Patches/*
Is this a reasonable way to do it?
Peter
^ permalink raw reply
* [PATCH 3/8] Builtin git-tar-tree.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
9860ed2d4a598ad100c3b4f6b07dd0a88a4547a6
Makefile | 8 +++++---
tar-tree.c => builtin-tar-tree.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 10 insertions(+), 5 deletions(-)
rename tar-tree.c => builtin-tar-tree.c (99%)
9860ed2d4a598ad100c3b4f6b07dd0a88a4547a6
diff --git a/Makefile b/Makefile
index 9b02264..966f7ee 100644
--- a/Makefile
+++ b/Makefile
@@ -161,7 +161,7 @@ PROGRAMS = \
git-receive-pack$X git-rev-parse$X \
git-send-pack$X git-show-branch$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
- git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
+ git-ssh-upload$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X \
@@ -171,7 +171,8 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
- git-init-db$X git-ls-files$X git-ls-tree$X
+ git-init-db$X git-ls-files$X git-ls-tree$X \
+ git-tar-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -220,7 +221,8 @@ LIB_OBJS = \
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o
+ builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
+ builtin-tar-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/tar-tree.c b/builtin-tar-tree.c
similarity index 99%
rename from tar-tree.c
rename to builtin-tar-tree.c
index 3308736..6ada04c 100644
--- a/tar-tree.c
+++ b/builtin-tar-tree.c
@@ -7,6 +7,7 @@ #include "tree-walk.h"
#include "commit.h"
#include "strbuf.h"
#include "tar.h"
+#include "builtin.h"
#define RECORDSIZE (512)
#define BLOCKSIZE (RECORDSIZE * 20)
@@ -301,7 +302,7 @@ static void traverse_tree(struct tree_de
}
}
-int main(int argc, char **argv)
+int cmd_tar_tree(int argc, const char **argv, char** envp)
{
unsigned char sha1[20], tree_sha1[20];
struct commit *commit;
diff --git a/builtin.h b/builtin.h
index 951f206..d210543 100644
--- a/builtin.h
+++ b/builtin.h
@@ -29,5 +29,6 @@ extern int cmd_check_ref_format(int argc
extern int cmd_init_db(int argc, const char **argv, char **envp);
extern int cmd_ls_files(int argc, const char **argv, char **envp);
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
+extern int cmd_tar_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 8574775..c253e60 100644
--- a/git.c
+++ b/git.c
@@ -54,7 +54,8 @@ static void handle_internal_command(int
{ "init-db", cmd_init_db },
{ "check-ref-format", cmd_check_ref_format },
{ "ls-files", cmd_ls_files },
- { "ls-tree", cmd_ls_tree }
+ { "ls-tree", cmd_ls_tree },
+ { "tar-tree", cmd_tar_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* Make more commands builtin
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git
Makefile | 26 +++++++++++++++-----------
apply.c => builtin-apply.c | 3 ++-
commit-tree.c => builtin-commit-tree.c | 3 ++-
diff-files.c => builtin-diff-files.c | 3 ++-
diff-index.c => builtin-diff-index.c | 3 ++-
diff-stages.c => builtin-diff-stages.c | 3 ++-
diff-tree.c => builtin-diff-tree.c | 3 ++-
ls-files.c => builtin-ls-files.c | 3 ++-
ls-tree.c => builtin-ls-tree.c | 3 ++-
read-tree.c => builtin-read-tree.c | 3 ++-
show-branch.c => builtin-show-branch.c | 3 ++-
tar-tree.c => builtin-tar-tree.c | 3 ++-
builtin.h | 12 ++++++++++++
git.c | 13 ++++++++++++-
14 files changed, 61 insertions(+), 23 deletions(-)
Junio, I've formatted this batch of patches with -M, so
they are easier to read. It seems there were some problems
with sending the last batch (patch 1 and 6 hasn't arrived),
but this should work, since I tested it by sending the
batch to myself first.
Sorry for the noise.
Regards,
Peter Eriksen
^ permalink raw reply
* [PATCH 1/8] Builtin git-ls-files.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
bc0dc50a3e9208011a39adc653e3463aa3ab4886
Makefile | 6 +++---
ls-files.c => builtin-ls-files.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 8 insertions(+), 5 deletions(-)
rename ls-files.c => builtin-ls-files.c (100%)
bc0dc50a3e9208011a39adc653e3463aa3ab4886
diff --git a/Makefile b/Makefile
index efe6b12..e522730 100644
--- a/Makefile
+++ b/Makefile
@@ -155,7 +155,7 @@ PROGRAMS = \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
- git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \
+ git-ls-tree$X git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-read-tree$X \
git-receive-pack$X git-rev-parse$X \
@@ -171,7 +171,7 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
- git-init-db$X
+ git-init-db$X git-ls-files$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -220,7 +220,7 @@ LIB_OBJS = \
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-init-db.o
+ builtin-init-db.o builtin-ls-files.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/ls-files.c b/builtin-ls-files.c
similarity index 100%
rename from ls-files.c
rename to builtin-ls-files.c
index 4a4af1c..3a0c5f2 100644
--- a/ls-files.c
+++ b/builtin-ls-files.c
@@ -10,6 +10,7 @@ #include <fnmatch.h>
#include "cache.h"
#include "quote.h"
+#include "builtin.h"
static int abbrev = 0;
static int show_deleted = 0;
@@ -648,7 +649,7 @@ static const char ls_files_usage[] =
"[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] "
"[--] [<file>]*";
-int main(int argc, const char **argv)
+int cmd_ls_files(int argc, const char **argv, char** envp)
{
int i;
int exc_given = 0;
diff --git a/builtin.h b/builtin.h
index 6054126..a0713d3 100644
--- a/builtin.h
+++ b/builtin.h
@@ -27,5 +27,6 @@ extern int cmd_grep(int argc, const char
extern int cmd_rev_list(int argc, const char **argv, char **envp);
extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
extern int cmd_init_db(int argc, const char **argv, char **envp);
+extern int cmd_ls_files(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 3216d31..9cfa9eb 100644
--- a/git.c
+++ b/git.c
@@ -52,7 +52,8 @@ static void handle_internal_command(int
{ "grep", cmd_grep },
{ "rev-list", cmd_rev_list },
{ "init-db", cmd_init_db },
- { "check-ref-format", cmd_check_ref_format }
+ { "check-ref-format", cmd_check_ref_format },
+ { "ls-files", cmd_ls_files }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 4/8] Builtin git-read-tree.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
baba8c18d8a5fff876d16a434b49677cd3ebbdb0
Makefile | 6 +++---
read-tree.c => builtin-read-tree.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 8 insertions(+), 5 deletions(-)
rename read-tree.c => builtin-read-tree.c (100%)
baba8c18d8a5fff876d16a434b49677cd3ebbdb0
diff --git a/Makefile b/Makefile
index 966f7ee..667fa5d 100644
--- a/Makefile
+++ b/Makefile
@@ -157,7 +157,7 @@ PROGRAMS = \
git-hash-object$X git-index-pack$X git-local-fetch$X \
git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
- git-peek-remote$X git-prune-packed$X git-read-tree$X \
+ git-peek-remote$X git-prune-packed$X \
git-receive-pack$X git-rev-parse$X \
git-send-pack$X git-show-branch$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
@@ -172,7 +172,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
- git-tar-tree$X
+ git-tar-tree$X git-read-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -222,7 +222,7 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o
+ builtin-tar-tree.o builtin-read-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/read-tree.c b/builtin-read-tree.c
similarity index 100%
rename from read-tree.c
rename to builtin-read-tree.c
index 82e2a9a..ec40d01 100644
--- a/read-tree.c
+++ b/builtin-read-tree.c
@@ -11,6 +11,7 @@ #include "object.h"
#include "tree.h"
#include <sys/time.h>
#include <signal.h>
+#include "builtin.h"
static int reset = 0;
static int merge = 0;
@@ -763,7 +764,7 @@ static const char read_tree_usage[] = "g
static struct cache_file cache_file;
-int main(int argc, char **argv)
+int cmd_read_tree(int argc, const char **argv, char **envp)
{
int i, newfd, stage = 0;
unsigned char sha1[20];
diff --git a/builtin.h b/builtin.h
index d210543..88b3523 100644
--- a/builtin.h
+++ b/builtin.h
@@ -30,5 +30,6 @@ extern int cmd_init_db(int argc, const c
extern int cmd_ls_files(int argc, const char **argv, char **envp);
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
extern int cmd_tar_tree(int argc, const char **argv, char **envp);
+extern int cmd_read_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index c253e60..300e2b2 100644
--- a/git.c
+++ b/git.c
@@ -55,7 +55,8 @@ static void handle_internal_command(int
{ "check-ref-format", cmd_check_ref_format },
{ "ls-files", cmd_ls_files },
{ "ls-tree", cmd_ls_tree },
- { "tar-tree", cmd_tar_tree }
+ { "tar-tree", cmd_tar_tree },
+ { "read-tree", cmd_read_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 7/8] Builtin git-show-branch.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
d0d1cfb7985fa90442e423a55ca23e6bc83f912d
Makefile | 6 +++---
show-branch.c => builtin-show-branch.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 8 insertions(+), 5 deletions(-)
rename show-branch.c => builtin-show-branch.c (100%)
d0d1cfb7985fa90442e423a55ca23e6bc83f912d
diff --git a/Makefile b/Makefile
index eeb4fdb..b438a90 100644
--- a/Makefile
+++ b/Makefile
@@ -159,7 +159,7 @@ PROGRAMS = \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X \
git-receive-pack$X git-rev-parse$X \
- git-send-pack$X git-show-branch$X git-shell$X \
+ git-send-pack$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
@@ -173,7 +173,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
git-tar-tree$X git-read-tree$X git-commit-tree$X \
- git-apply$X
+ git-apply$X git-show-branch$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -224,7 +224,7 @@ BUILTIN_OBJS = \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
- builtin-apply.o
+ builtin-apply.o builtin-show-branch.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/show-branch.c b/builtin-show-branch.c
similarity index 100%
rename from show-branch.c
rename to builtin-show-branch.c
index 268c57b..d1be8bb 100644
--- a/show-branch.c
+++ b/builtin-show-branch.c
@@ -3,6 +3,7 @@ #include <fnmatch.h>
#include "cache.h"
#include "commit.h"
#include "refs.h"
+#include "builtin.h"
static const char show_branch_usage[] =
"git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
@@ -548,7 +549,7 @@ static int omit_in_dense(struct commit *
return 0;
}
-int main(int ac, char **av)
+int cmd_show_branch(int ac, const char **av, char **envp)
{
struct commit *rev[MAX_REVS], *commit;
struct commit_list *list = NULL, *seen = NULL;
diff --git a/builtin.h b/builtin.h
index d6ff88e..01882ec 100644
--- a/builtin.h
+++ b/builtin.h
@@ -33,5 +33,6 @@ extern int cmd_tar_tree(int argc, const
extern int cmd_read_tree(int argc, const char **argv, char **envp);
extern int cmd_commit_tree(int argc, const char **argv, char **envp);
extern int cmd_apply(int argc, const char **argv, char **envp);
+extern int cmd_show_branch(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index f44e08b..d29505c 100644
--- a/git.c
+++ b/git.c
@@ -58,7 +58,8 @@ static void handle_internal_command(int
{ "tar-tree", cmd_tar_tree },
{ "read-tree", cmd_read_tree },
{ "commit-tree", cmd_commit_tree },
- { "apply", cmd_apply }
+ { "apply", cmd_apply },
+ { "show-branch", cmd_show_branch }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 6/8] Builtin git-apply.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
104e34d8d562584d212f141b7ce736d47016b60a
Makefile | 8 +++++---
apply.c => builtin-apply.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 10 insertions(+), 5 deletions(-)
rename apply.c => builtin-apply.c (100%)
104e34d8d562584d212f141b7ce736d47016b60a
diff --git a/Makefile b/Makefile
index a5efbc7..eeb4fdb 100644
--- a/Makefile
+++ b/Makefile
@@ -149,7 +149,7 @@ SIMPLE_PROGRAMS = \
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
- git-apply$X git-cat-file$X \
+ git-cat-file$X \
git-checkout-index$X git-clone-pack$X \
git-convert-objects$X git-diff-files$X \
git-diff-index$X git-diff-stages$X \
@@ -172,7 +172,8 @@ BUILT_INS = git-log$X git-whatchanged$X
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
- git-tar-tree$X git-read-tree$X git-commit-tree$X
+ git-tar-tree$X git-read-tree$X git-commit-tree$X \
+ git-apply$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -222,7 +223,8 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o
+ builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
+ builtin-apply.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/apply.c b/builtin-apply.c
similarity index 100%
rename from apply.c
rename to builtin-apply.c
index 0ed9d13..4056b9d 100644
--- a/apply.c
+++ b/builtin-apply.c
@@ -11,6 +11,7 @@ #include "cache.h"
#include "quote.h"
#include "blob.h"
#include "delta.h"
+#include "builtin.h"
// --check turns on checking that the working tree matches the
// files that are being modified, but doesn't apply the patch
@@ -2151,7 +2152,7 @@ static int git_apply_config(const char *
}
-int main(int argc, char **argv)
+int cmd_apply(int argc, const char **argv, char **envp)
{
int i;
int read_stdin = 1;
diff --git a/builtin.h b/builtin.h
index c6b07d9..d6ff88e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -32,5 +32,6 @@ extern int cmd_ls_tree(int argc, const c
extern int cmd_tar_tree(int argc, const char **argv, char **envp);
extern int cmd_read_tree(int argc, const char **argv, char **envp);
extern int cmd_commit_tree(int argc, const char **argv, char **envp);
+extern int cmd_apply(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 4c2c062..f44e08b 100644
--- a/git.c
+++ b/git.c
@@ -57,7 +57,8 @@ static void handle_internal_command(int
{ "ls-tree", cmd_ls_tree },
{ "tar-tree", cmd_tar_tree },
{ "read-tree", cmd_read_tree },
- { "commit-tree", cmd_commit_tree }
+ { "commit-tree", cmd_commit_tree },
+ { "apply", cmd_apply }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 5/8] Builtin git-commit-tree.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
762e5a2efcde796d84c573fe8bf3224c9fbf3588
Makefile | 6 +++---
commit-tree.c => builtin-commit-tree.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 8 insertions(+), 5 deletions(-)
rename commit-tree.c => builtin-commit-tree.c (98%)
762e5a2efcde796d84c573fe8bf3224c9fbf3588
diff --git a/Makefile b/Makefile
index 667fa5d..a5efbc7 100644
--- a/Makefile
+++ b/Makefile
@@ -150,7 +150,7 @@ SIMPLE_PROGRAMS = \
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
git-apply$X git-cat-file$X \
- git-checkout-index$X git-clone-pack$X git-commit-tree$X \
+ git-checkout-index$X git-clone-pack$X \
git-convert-objects$X git-diff-files$X \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
@@ -172,7 +172,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
- git-tar-tree$X git-read-tree$X
+ git-tar-tree$X git-read-tree$X git-commit-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -222,7 +222,7 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o builtin-read-tree.o
+ builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/commit-tree.c b/builtin-commit-tree.c
similarity index 98%
rename from commit-tree.c
rename to builtin-commit-tree.c
index 0320036..4ccdbec 100644
--- a/commit-tree.c
+++ b/builtin-commit-tree.c
@@ -6,6 +6,7 @@
#include "cache.h"
#include "commit.h"
#include "tree.h"
+#include "builtin.h"
#define BLOCKING (1ul << 14)
@@ -76,7 +77,7 @@ static int new_parent(int idx)
return 1;
}
-int main(int argc, char **argv)
+int cmd_commit_tree(int argc, const char **argv, char **envp)
{
int i;
int parents = 0;
diff --git a/builtin.h b/builtin.h
index 88b3523..c6b07d9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -31,5 +31,6 @@ extern int cmd_ls_files(int argc, const
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
extern int cmd_tar_tree(int argc, const char **argv, char **envp);
extern int cmd_read_tree(int argc, const char **argv, char **envp);
+extern int cmd_commit_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 300e2b2..4c2c062 100644
--- a/git.c
+++ b/git.c
@@ -56,7 +56,8 @@ static void handle_internal_command(int
{ "ls-files", cmd_ls_files },
{ "ls-tree", cmd_ls_tree },
{ "tar-tree", cmd_tar_tree },
- { "read-tree", cmd_read_tree }
+ { "read-tree", cmd_read_tree },
+ { "commit-tree", cmd_commit_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 2/8] Builtin git-ls-tree.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
419257801e5bc91fc435bd4ff9eb42aa8063ffbb
Makefile | 6 +++---
ls-tree.c => builtin-ls-tree.c | 3 ++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 8 insertions(+), 5 deletions(-)
rename ls-tree.c => builtin-ls-tree.c (98%)
419257801e5bc91fc435bd4ff9eb42aa8063ffbb
diff --git a/Makefile b/Makefile
index e522730..9b02264 100644
--- a/Makefile
+++ b/Makefile
@@ -155,7 +155,7 @@ PROGRAMS = \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
- git-ls-tree$X git-mailinfo$X git-merge-base$X \
+ git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-read-tree$X \
git-receive-pack$X git-rev-parse$X \
@@ -171,7 +171,7 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
- git-init-db$X git-ls-files$X
+ git-init-db$X git-ls-files$X git-ls-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -220,7 +220,7 @@ LIB_OBJS = \
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-init-db.o builtin-ls-files.o
+ builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/ls-tree.c b/builtin-ls-tree.c
similarity index 98%
rename from ls-tree.c
rename to builtin-ls-tree.c
index f2b3bc1..b515307 100644
--- a/ls-tree.c
+++ b/builtin-ls-tree.c
@@ -7,6 +7,7 @@ #include "cache.h"
#include "blob.h"
#include "tree.h"
#include "quote.h"
+#include "builtin.h"
static int line_termination = '\n';
#define LS_RECURSIVE 1
@@ -84,7 +85,7 @@ static int show_tree(unsigned char *sha1
return retval;
}
-int main(int argc, const char **argv)
+int cmd_ls_tree(int argc, const char **argv, char **envp)
{
unsigned char sha1[20];
struct tree *tree;
diff --git a/builtin.h b/builtin.h
index a0713d3..951f206 100644
--- a/builtin.h
+++ b/builtin.h
@@ -28,5 +28,6 @@ extern int cmd_rev_list(int argc, const
extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
extern int cmd_init_db(int argc, const char **argv, char **envp);
extern int cmd_ls_files(int argc, const char **argv, char **envp);
+extern int cmd_ls_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 9cfa9eb..8574775 100644
--- a/git.c
+++ b/git.c
@@ -53,7 +53,8 @@ static void handle_internal_command(int
{ "rev-list", cmd_rev_list },
{ "init-db", cmd_init_db },
{ "check-ref-format", cmd_check_ref_format },
- { "ls-files", cmd_ls_files }
+ { "ls-files", cmd_ls_files },
+ { "ls-tree", cmd_ls_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 8/8] Builtin git-diff-files, git-diff-index, git-diff-stages, and git-diff-tree.
From: Peter Eriksen @ 2006-05-23 12:15 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483865361243-git-send-email-1>
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
e2d2468b8550f2760b46a2eb461b051abfef4dff
Makefile | 12 ++++++------
diff-files.c => builtin-diff-files.c | 3 ++-
diff-index.c => builtin-diff-index.c | 3 ++-
diff-stages.c => builtin-diff-stages.c | 3 ++-
diff-tree.c => builtin-diff-tree.c | 3 ++-
builtin.h | 5 +++++
git.c | 6 +++++-
7 files changed, 24 insertions(+), 11 deletions(-)
rename diff-files.c => builtin-diff-files.c (94%)
rename diff-index.c => builtin-diff-index.c (91%)
rename diff-stages.c => builtin-diff-stages.c (97%)
rename diff-tree.c => builtin-diff-tree.c (98%)
e2d2468b8550f2760b46a2eb461b051abfef4dff
diff --git a/Makefile b/Makefile
index b438a90..9dc1326 100644
--- a/Makefile
+++ b/Makefile
@@ -151,9 +151,7 @@ # ... and all the rest that could be mov
PROGRAMS = \
git-cat-file$X \
git-checkout-index$X git-clone-pack$X \
- git-convert-objects$X git-diff-files$X \
- git-diff-index$X git-diff-stages$X \
- git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
+ git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
@@ -173,7 +171,8 @@ BUILT_INS = git-log$X git-whatchanged$X
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
git-tar-tree$X git-read-tree$X git-commit-tree$X \
- git-apply$X git-show-branch$X
+ git-apply$X git-show-branch$X git-diff-files$X \
+ git-diff-index$X git-diff-stages$X git-diff-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -223,8 +222,9 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
- builtin-apply.o builtin-show-branch.o
+ builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
+ builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
+ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/diff-files.c b/builtin-diff-files.c
similarity index 94%
rename from diff-files.c
rename to builtin-diff-files.c
index b9d193d..cebda82 100644
--- a/diff-files.c
+++ b/builtin-diff-files.c
@@ -7,12 +7,13 @@ #include "cache.h"
#include "diff.h"
#include "commit.h"
#include "revision.h"
+#include "builtin.h"
static const char diff_files_usage[] =
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int cmd_diff_files(int argc, const char **argv, char **envp)
{
struct rev_info rev;
int silent = 0;
diff --git a/diff-index.c b/builtin-diff-index.c
similarity index 91%
rename from diff-index.c
rename to builtin-diff-index.c
index 8c9f601..1958580 100644
--- a/diff-index.c
+++ b/builtin-diff-index.c
@@ -2,13 +2,14 @@ #include "cache.h"
#include "diff.h"
#include "commit.h"
#include "revision.h"
+#include "builtin.h"
static const char diff_cache_usage[] =
"git-diff-index [-m] [--cached] "
"[<common diff options>] <tree-ish> [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int cmd_diff_index(int argc, const char **argv, char **envp)
{
struct rev_info rev;
int cached = 0;
diff --git a/diff-stages.c b/builtin-diff-stages.c
similarity index 97%
rename from diff-stages.c
rename to builtin-diff-stages.c
index dcd20e7..7c157ca 100644
--- a/diff-stages.c
+++ b/builtin-diff-stages.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "diff.h"
+#include "builtin.h"
static struct diff_options diff_options;
@@ -54,7 +55,7 @@ static void diff_stages(int stage1, int
}
}
-int main(int ac, const char **av)
+int cmd_diff_stages(int ac, const char **av, char **envp)
{
int stage1, stage2;
const char *prefix = setup_git_directory();
diff --git a/diff-tree.c b/builtin-diff-tree.c
similarity index 98%
rename from diff-tree.c
rename to builtin-diff-tree.c
index 69bb74b..cc53b81 100644
--- a/diff-tree.c
+++ b/builtin-diff-tree.c
@@ -2,6 +2,7 @@ #include "cache.h"
#include "diff.h"
#include "commit.h"
#include "log-tree.h"
+#include "builtin.h"
static struct rev_info log_tree_opt;
@@ -58,7 +59,7 @@ static const char diff_tree_usage[] =
" --root include the initial commit as diff against /dev/null\n"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int cmd_diff_tree(int argc, const char **argv, char **envp)
{
int nr_sha1;
char line[1000];
diff --git a/builtin.h b/builtin.h
index 01882ec..7620984 100644
--- a/builtin.h
+++ b/builtin.h
@@ -34,5 +34,10 @@ extern int cmd_read_tree(int argc, const
extern int cmd_commit_tree(int argc, const char **argv, char **envp);
extern int cmd_apply(int argc, const char **argv, char **envp);
extern int cmd_show_branch(int argc, const char **argv, char **envp);
+extern int cmd_diff_files(int argc, const char **argv, char **envp);
+extern int cmd_diff_index(int argc, const char **argv, char **envp);
+extern int cmd_diff_stages(int argc, const char **argv, char **envp);
+extern int cmd_diff_tree(int argc, const char **argv, char **envp);
+
#endif
diff --git a/git.c b/git.c
index d29505c..8749748 100644
--- a/git.c
+++ b/git.c
@@ -59,7 +59,11 @@ static void handle_internal_command(int
{ "read-tree", cmd_read_tree },
{ "commit-tree", cmd_commit_tree },
{ "apply", cmd_apply },
- { "show-branch", cmd_show_branch }
+ { "show-branch", cmd_show_branch },
+ { "diff-files", cmd_diff_files },
+ { "diff-index", cmd_diff_index },
+ { "diff-stages", cmd_diff_stages },
+ { "diff-tree", cmd_diff_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* Re: Git 1.3.2 on Solaris
From: Stefan Pfetzing @ 2006-05-23 12:04 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <8157.1148359875@lotus.CS.Berkeley.EDU>
Hi Jason,
2006/5/23, Jason Riedy <ejr@eecs.berkeley.edu>:
> This is explicitly allowed by the SUS, even for non-root:
> http://www.opengroup.org/onlinepubs/000095399/functions/access.html
> For non-root, some ACL systems could allow you to execute
> the file even if there are no execute bits. What a joy
> ACLs are. Or NFS uid mappings could play tricks on you,
> or... And as you've noticed, this kills [ -x ]. (Failing
> to run the hooks in receive-pack.c is noisy but not fatal.
> It's the shell scripts that stop.)
Yup, but this breaks test t5400 - I think because of the post-update
hook is failing.
> I think you're stuck. To disable the hooks for all possible
> users, OSes, file systems, etc., you need to remove them.
>
> Or just don't run as root, and hope that the OS isn't
> completely insane.
As non-root it works fine.
> BTW, ERR_RUN_COMMAND_EXEC is never returned. Any failure
> to exec will produce an exit code of 128 from die. This
> will be an issue when commit becomes a built-in, right?
Think so.
bye
Stefan
--
http://www.dreamind.de/
Oroborus and Debian GNU/Linux Developer.
^ permalink raw reply
* Q: xasprintf
From: Dmitry V. Levin @ 2006-05-23 11:28 UTC (permalink / raw)
To: git
In-Reply-To: <7vzmh98seo.fsf@assigned-by-dhcp.cox.net>
[-- Attachment #1: Type: text/plain, Size: 519 bytes --]
Hi,
On Mon, May 22, 2006 at 06:02:39PM -0700, Junio C Hamano wrote:
> Sean <seanlkml@sympatico.ca> writes:
[...]
> > - name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7);
> > + name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7);
> > sprintf(name, "%.*s{%.*s => %.*s}%s",
>
> Obviously correct given what the sprintf() that immediately
> follows does. Sheesh, what was I smoking back then. *BLUSH*
What about introducing xasprintf() to eliminate such issues?
--
ldv
[-- Attachment #2: Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply
* Re: [PATCH 0/2] tagsize < 8kb restriction
From: Sean @ 2006-05-23 9:59 UTC (permalink / raw)
To: Linus Torvalds; +Cc: junkio, BjEngelmann, git
In-Reply-To: <Pine.LNX.4.64.0605221646540.3697@g5.osdl.org>
On Mon, 22 May 2006 17:02:41 -0700 (PDT)
Linus Torvalds <torvalds@osdl.org> wrote:
> That said, I think that what you actually want to do may be totally
> different.
>
> If _each_ commit has some extra information associated with it, you don't
> want to create a tag that points to the commit, you more likely want to
> create an object that is indexed by the commit ID rather than the other
> way around.
>
> IOW, I _think_ that what you described would be that if you have the
> commit ID, you want to find the data based on that ID. No?
Correct. But even though there isn't currently an efficient way to do
the reverse lookup, many of the visual tools do it. So for instance, if
you embed some metadata in the name of a tag, it will actually be nicely
shown to you associated with the proper commit in qgit/gitk/gitweb. So
you _can_ abuse tags and get modest results. And of course the low level
tools let you do.. git name-rev --tags to lookup the meta data as well.
So you can do git log | git name-rev --tags --stdin and see which tags
are associated with each commit.
I'm not arguing that this makes tags well designed for the these types
of things, just that there is no other option built in to the low level
git that comes as close.
> And that you can do quite easily, while _also_ using git to distribute the
> extra per-commit meta-data. Just create a separate branch that has the
> data indexed by commit ID. That could be as simple as having one file per
> commit (using, perhaps, a similar directory layout as the .git/objects/
> directory itself), and then you could do something like
>
> # Get the SHA1 of the named commit
> commit=$(git-rev-parse --verify "$cmitname"^0)
>
> # turn it into a filename (slash between two first chars and the rest)
> filename=$(echo $commit | sed 's:^\(..\)\(.*\):\1/\2:')
>
> # look it up in the "annotations" branch
> git cat-file blob "annotations:$filename"
>
> which gets the data from the "annotations" branch, indexed by the SHA1
> name.
>
> Now, everybody can track your "annotations" branch using git, and get your
> per-commit annotations for the main branch.
>
> See?
Sure, makes a lot of sense. Although the one file per commit thing doesn't
scale well. It's already a problem when trying to use a lot of tags for
instance.
More than the technical details of the implementation though, i'm trying to
make a case that git would do well to codify something like the above and
provide a _standard_ method of associating meta data with commits. This
would allow all the tools to start displaying meta data etc and have a
defined way to efficiently query and manipulate it.
Sean
^ permalink raw reply
* [PATCH] --summary output should print immediately after stats.
From: Sean @ 2006-05-23 9:34 UTC (permalink / raw)
To: git
Currently the summary is displayed after the patch. Fix this so
that the output order is stat-summary-patch. As a consequence of
the way this is coded, the --summary option will only actually
display summary data if combined with either the --stat or
--patch-with-stat option.
Signed-off-by: Sean Estabrooks <seanlkml@sympatico.ca>
---
3060faeb9c9320e12895cb33d25edb4aa4ba072e
diff.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
3060faeb9c9320e12895cb33d25edb4aa4ba072e
diff --git a/diff.c b/diff.c
index e16e0bf..fa36366 100644
--- a/diff.c
+++ b/diff.c
@@ -1867,6 +1867,9 @@ void diff_flush(struct diff_options *opt
show_stats(diffstat);
free(diffstat);
diffstat = NULL;
+ if (options->summary)
+ for (i = 0; i < q->nr; i++)
+ diff_summary(q->queue[i]);
putchar(options->line_termination);
}
for (i = 0; i < q->nr; i++) {
@@ -1880,7 +1883,7 @@ void diff_flush(struct diff_options *opt
}
for (i = 0; i < q->nr; i++) {
- if (options->summary)
+ if (diffstat && options->summary)
diff_summary(q->queue[i]);
diff_free_filepair(q->queue[i]);
}
--
1.3.GIT
^ permalink raw reply related
* Re: Make more commands builtin
From: Junio C Hamano @ 2006-05-23 8:41 UTC (permalink / raw)
To: Peter Eriksen; +Cc: git
In-Reply-To: <35036.1277036884$1148372628@news.gmane.org>
"Peter Eriksen" <s022018@student.dtu.dk> writes:
> Makefile | 26 +++++++++++++++-----------
> apply.c => builtin-apply.c | 3 ++-
> commit-tree.c => builtin-commit-tree.c | 3 ++-
> diff-files.c => builtin-diff-files.c | 3 ++-
> diff-index.c => builtin-diff-index.c | 3 ++-
> diff-stages.c => builtin-diff-stages.c | 3 ++-
> diff-tree.c => builtin-diff-tree.c | 3 ++-
> ls-files.c => builtin-ls-files.c | 3 ++-
> ls-tree.c => builtin-ls-tree.c | 3 ++-
> read-tree.c => builtin-read-tree.c | 3 ++-
> show-branch.c => builtin-show-branch.c | 3 ++-
> tar-tree.c => builtin-tar-tree.c | 3 ++-
> builtin.h | 12 ++++++++++++
> git.c | 13 ++++++++++++-
>
> I've tried to follow the trend of making commands builtin.
> All patches have the same form. This is my first use
> of git-send-email, so this might come out wrong.
>
> Peter Eriksen <s022018@student.dtu.dk>
Was this intentional?
Reply-To: Patches/@bohr.gbar.dtu.dk
Reply-To: Patches/0001-Builtin-git-ls-files.txt@bohr.gbar.dtu.dk
Otherwise the form looks OK, except that with this particular
series, I would have much preferred to see these with
"format-patch -M"; it is really hard to review otherwise.
BTW, I already have tar-tree built-in in "next" branch.
I'll go to bed now, so please expect review Ack/Nack until
evening my time (it is 01:40 here) from me.
^ permalink raw reply
* Re: [PATCH] Set the executable bit on gitMergeCommon.py.
From: Junio C Hamano @ 2006-05-23 8:34 UTC (permalink / raw)
To: Peter Eriksen; +Cc: git
In-Reply-To: <20060523081238.GB4038@bohr.gbar.dtu.dk>
"Peter Eriksen" <s022018@student.dtu.dk> writes:
> From: Peter Eriksen <s022018@student.dtu.dk>
> Date: Mon, 22 May 2006 15:35:42 +0200
>
> Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
It makes some sense to make git-merge-recursive.py executable,
just in case somebody wants to run it without preprocessing.
However, gitMergeCommon.py is a module without the main program.
It does not even have the usual "primarily meant to be a library
but you could run it standalone" idiom at the end:
if __name__ == '__main__': test()
So I am not sure if this patch makes sense -- does it misbehave
on your system when installed without +x bit?
^ permalink raw reply
* [PATCH 8/8] Builtin git-diff-files, git-diff-index, git-diff-stages, and git-diff-tree.
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483730813930-git-send-email->
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
e2d2468b8550f2760b46a2eb461b051abfef4dff
Makefile | 12 ++--
builtin-diff-files.c | 55 ++++++++++++++++++
builtin-diff-index.c | 39 +++++++++++++
builtin-diff-stages.c | 105 +++++++++++++++++++++++++++++++++++
builtin-diff-tree.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 5 ++
diff-files.c | 54 ------------------
diff-index.c | 38 -------------
diff-stages.c | 104 ----------------------------------
diff-tree.c | 147 -------------------------------------------------
git.c | 6 ++
11 files changed, 363 insertions(+), 350 deletions(-)
create mode 100644 builtin-diff-files.c
create mode 100644 builtin-diff-index.c
create mode 100644 builtin-diff-stages.c
create mode 100644 builtin-diff-tree.c
delete mode 100644 diff-files.c
delete mode 100644 diff-index.c
delete mode 100644 diff-stages.c
delete mode 100644 diff-tree.c
e2d2468b8550f2760b46a2eb461b051abfef4dff
diff --git a/Makefile b/Makefile
index b438a90..9dc1326 100644
--- a/Makefile
+++ b/Makefile
@@ -151,9 +151,7 @@ # ... and all the rest that could be mov
PROGRAMS = \
git-cat-file$X \
git-checkout-index$X git-clone-pack$X \
- git-convert-objects$X git-diff-files$X \
- git-diff-index$X git-diff-stages$X \
- git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
+ git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
@@ -173,7 +171,8 @@ BUILT_INS = git-log$X git-whatchanged$X
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
git-tar-tree$X git-read-tree$X git-commit-tree$X \
- git-apply$X git-show-branch$X
+ git-apply$X git-show-branch$X git-diff-files$X \
+ git-diff-index$X git-diff-stages$X git-diff-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -223,8 +222,9 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
- builtin-apply.o builtin-show-branch.o
+ builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
+ builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
+ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
new file mode 100644
index 0000000..cebda82
--- /dev/null
+++ b/builtin-diff-files.c
@@ -0,0 +1,55 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "cache.h"
+#include "diff.h"
+#include "commit.h"
+#include "revision.h"
+#include "builtin.h"
+
+static const char diff_files_usage[] =
+"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+COMMON_DIFF_OPTIONS_HELP;
+
+int cmd_diff_files(int argc, const char **argv, char **envp)
+{
+ struct rev_info rev;
+ int silent = 0;
+
+ git_config(git_diff_config);
+ init_revisions(&rev);
+ rev.abbrev = 0;
+
+ argc = setup_revisions(argc, argv, &rev, NULL);
+ while (1 < argc && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "--base"))
+ rev.max_count = 1;
+ else if (!strcmp(argv[1], "--ours"))
+ rev.max_count = 2;
+ else if (!strcmp(argv[1], "--theirs"))
+ rev.max_count = 3;
+ else if (!strcmp(argv[1], "-q"))
+ silent = 1;
+ else
+ usage(diff_files_usage);
+ argv++; argc--;
+ }
+ /*
+ * Make sure there are NO revision (i.e. pending object) parameter,
+ * rev.max_count is reasonable (0 <= n <= 3),
+ * there is no other revision filtering parameters.
+ */
+ if (rev.pending_objects ||
+ rev.min_age != -1 || rev.max_age != -1)
+ usage(diff_files_usage);
+ /*
+ * Backward compatibility wart - "diff-files -s" used to
+ * defeat the common diff option "-s" which asked for
+ * DIFF_FORMAT_NO_OUTPUT.
+ */
+ if (rev.diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
+ rev.diffopt.output_format = DIFF_FORMAT_RAW;
+ return run_diff_files(&rev, silent);
+}
diff --git a/builtin-diff-index.c b/builtin-diff-index.c
new file mode 100644
index 0000000..1958580
--- /dev/null
+++ b/builtin-diff-index.c
@@ -0,0 +1,39 @@
+#include "cache.h"
+#include "diff.h"
+#include "commit.h"
+#include "revision.h"
+#include "builtin.h"
+
+static const char diff_cache_usage[] =
+"git-diff-index [-m] [--cached] "
+"[<common diff options>] <tree-ish> [<path>...]"
+COMMON_DIFF_OPTIONS_HELP;
+
+int cmd_diff_index(int argc, const char **argv, char **envp)
+{
+ struct rev_info rev;
+ int cached = 0;
+ int i;
+
+ git_config(git_diff_config);
+ init_revisions(&rev);
+ rev.abbrev = 0;
+
+ argc = setup_revisions(argc, argv, &rev, NULL);
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (!strcmp(arg, "--cached"))
+ cached = 1;
+ else
+ usage(diff_cache_usage);
+ }
+ /*
+ * Make sure there is one revision (i.e. pending object),
+ * and there is no revision filtering parameters.
+ */
+ if (!rev.pending_objects || rev.pending_objects->next ||
+ rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
+ usage(diff_cache_usage);
+ return run_diff_index(&rev, cached);
+}
diff --git a/builtin-diff-stages.c b/builtin-diff-stages.c
new file mode 100644
index 0000000..7c157ca
--- /dev/null
+++ b/builtin-diff-stages.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005 Junio C Hamano
+ */
+
+#include "cache.h"
+#include "diff.h"
+#include "builtin.h"
+
+static struct diff_options diff_options;
+
+static const char diff_stages_usage[] =
+"git-diff-stages [<common diff options>] <stage1> <stage2> [<path>...]"
+COMMON_DIFF_OPTIONS_HELP;
+
+static void diff_stages(int stage1, int stage2, const char **pathspec)
+{
+ int i = 0;
+ while (i < active_nr) {
+ struct cache_entry *ce, *stages[4] = { NULL, };
+ struct cache_entry *one, *two;
+ const char *name;
+ int len, skip;
+
+ ce = active_cache[i];
+ skip = !ce_path_match(ce, pathspec);
+ len = ce_namelen(ce);
+ name = ce->name;
+ for (;;) {
+ int stage = ce_stage(ce);
+ stages[stage] = ce;
+ if (active_nr <= ++i)
+ break;
+ ce = active_cache[i];
+ if (ce_namelen(ce) != len ||
+ memcmp(name, ce->name, len))
+ break;
+ }
+ one = stages[stage1];
+ two = stages[stage2];
+
+ if (skip || (!one && !two))
+ continue;
+ if (!one)
+ diff_addremove(&diff_options, '+', ntohl(two->ce_mode),
+ two->sha1, name, NULL);
+ else if (!two)
+ diff_addremove(&diff_options, '-', ntohl(one->ce_mode),
+ one->sha1, name, NULL);
+ else if (memcmp(one->sha1, two->sha1, 20) ||
+ (one->ce_mode != two->ce_mode) ||
+ diff_options.find_copies_harder)
+ diff_change(&diff_options,
+ ntohl(one->ce_mode), ntohl(two->ce_mode),
+ one->sha1, two->sha1, name, NULL);
+ }
+}
+
+int cmd_diff_stages(int ac, const char **av, char **envp)
+{
+ int stage1, stage2;
+ const char *prefix = setup_git_directory();
+ const char **pathspec = NULL;
+
+ git_config(git_diff_config);
+ read_cache();
+ diff_setup(&diff_options);
+ while (1 < ac && av[1][0] == '-') {
+ const char *arg = av[1];
+ if (!strcmp(arg, "-r"))
+ ; /* as usual */
+ else {
+ int diff_opt_cnt;
+ diff_opt_cnt = diff_opt_parse(&diff_options,
+ av+1, ac-1);
+ if (diff_opt_cnt < 0)
+ usage(diff_stages_usage);
+ else if (diff_opt_cnt) {
+ av += diff_opt_cnt;
+ ac -= diff_opt_cnt;
+ continue;
+ }
+ else
+ usage(diff_stages_usage);
+ }
+ ac--; av++;
+ }
+
+ if (ac < 3 ||
+ sscanf(av[1], "%d", &stage1) != 1 ||
+ ! (0 <= stage1 && stage1 <= 3) ||
+ sscanf(av[2], "%d", &stage2) != 1 ||
+ ! (0 <= stage2 && stage2 <= 3))
+ usage(diff_stages_usage);
+
+ av += 3; /* The rest from av[0] are for paths restriction. */
+ pathspec = get_pathspec(prefix, av);
+
+ if (diff_setup_done(&diff_options) < 0)
+ usage(diff_stages_usage);
+
+ diff_stages(stage1, stage2, pathspec);
+ diffcore_std(&diff_options);
+ diff_flush(&diff_options);
+ return 0;
+}
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
new file mode 100644
index 0000000..cc53b81
--- /dev/null
+++ b/builtin-diff-tree.c
@@ -0,0 +1,148 @@
+#include "cache.h"
+#include "diff.h"
+#include "commit.h"
+#include "log-tree.h"
+#include "builtin.h"
+
+static struct rev_info log_tree_opt;
+
+static int diff_tree_commit_sha1(const unsigned char *sha1)
+{
+ struct commit *commit = lookup_commit_reference(sha1);
+ if (!commit)
+ return -1;
+ return log_tree_commit(&log_tree_opt, commit);
+}
+
+static int diff_tree_stdin(char *line)
+{
+ int len = strlen(line);
+ unsigned char sha1[20];
+ struct commit *commit;
+
+ if (!len || line[len-1] != '\n')
+ return -1;
+ line[len-1] = 0;
+ if (get_sha1_hex(line, sha1))
+ return -1;
+ commit = lookup_commit(sha1);
+ if (!commit || parse_commit(commit))
+ return -1;
+ if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) {
+ /* Graft the fake parents locally to the commit */
+ int pos = 41;
+ struct commit_list **pptr, *parents;
+
+ /* Free the real parent list */
+ for (parents = commit->parents; parents; ) {
+ struct commit_list *tmp = parents->next;
+ free(parents);
+ parents = tmp;
+ }
+ commit->parents = NULL;
+ pptr = &(commit->parents);
+ while (line[pos] && !get_sha1_hex(line + pos, sha1)) {
+ struct commit *parent = lookup_commit(sha1);
+ if (parent) {
+ pptr = &commit_list_insert(parent, pptr)->next;
+ }
+ pos += 41;
+ }
+ }
+ return log_tree_commit(&log_tree_opt, commit);
+}
+
+static const char diff_tree_usage[] =
+"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
+"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+" -r diff recursively\n"
+" --root include the initial commit as diff against /dev/null\n"
+COMMON_DIFF_OPTIONS_HELP;
+
+int cmd_diff_tree(int argc, const char **argv, char **envp)
+{
+ int nr_sha1;
+ char line[1000];
+ struct object *tree1, *tree2;
+ static struct rev_info *opt = &log_tree_opt;
+ struct object_list *list;
+ int read_stdin = 0;
+
+ git_config(git_diff_config);
+ nr_sha1 = 0;
+ init_revisions(opt);
+ opt->abbrev = 0;
+ opt->diff = 1;
+ argc = setup_revisions(argc, argv, opt, NULL);
+
+ while (--argc > 0) {
+ const char *arg = *++argv;
+
+ if (!strcmp(arg, "--stdin")) {
+ read_stdin = 1;
+ continue;
+ }
+ usage(diff_tree_usage);
+ }
+
+ /*
+ * NOTE! "setup_revisions()" will have inserted the revisions
+ * it parsed in reverse order. So if you do
+ *
+ * git-diff-tree a b
+ *
+ * the commit list will be "b" -> "a" -> NULL, so we reverse
+ * the order of the objects if the first one is not marked
+ * UNINTERESTING.
+ */
+ nr_sha1 = 0;
+ list = opt->pending_objects;
+ if (list) {
+ nr_sha1++;
+ tree1 = list->item;
+ list = list->next;
+ if (list) {
+ nr_sha1++;
+ tree2 = tree1;
+ tree1 = list->item;
+ if (list->next)
+ usage(diff_tree_usage);
+ /* Switch them around if the second one was uninteresting.. */
+ if (tree2->flags & UNINTERESTING) {
+ struct object *tmp = tree2;
+ tree2 = tree1;
+ tree1 = tmp;
+ }
+ }
+ }
+
+ switch (nr_sha1) {
+ case 0:
+ if (!read_stdin)
+ usage(diff_tree_usage);
+ break;
+ case 1:
+ diff_tree_commit_sha1(tree1->sha1);
+ break;
+ case 2:
+ diff_tree_sha1(tree1->sha1,
+ tree2->sha1,
+ "", &opt->diffopt);
+ log_tree_diff_flush(opt);
+ break;
+ }
+
+ if (!read_stdin)
+ return 0;
+
+ if (opt->diffopt.detect_rename)
+ opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
+ DIFF_SETUP_USE_CACHE);
+ while (fgets(line, sizeof(line), stdin))
+ if (line[0] == '\n')
+ fflush(stdout);
+ else
+ diff_tree_stdin(line);
+
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index 01882ec..7620984 100644
--- a/builtin.h
+++ b/builtin.h
@@ -34,5 +34,10 @@ extern int cmd_read_tree(int argc, const
extern int cmd_commit_tree(int argc, const char **argv, char **envp);
extern int cmd_apply(int argc, const char **argv, char **envp);
extern int cmd_show_branch(int argc, const char **argv, char **envp);
+extern int cmd_diff_files(int argc, const char **argv, char **envp);
+extern int cmd_diff_index(int argc, const char **argv, char **envp);
+extern int cmd_diff_stages(int argc, const char **argv, char **envp);
+extern int cmd_diff_tree(int argc, const char **argv, char **envp);
+
#endif
diff --git a/diff-files.c b/diff-files.c
deleted file mode 100644
index b9d193d..0000000
--- a/diff-files.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include "cache.h"
-#include "diff.h"
-#include "commit.h"
-#include "revision.h"
-
-static const char diff_files_usage[] =
-"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
-COMMON_DIFF_OPTIONS_HELP;
-
-int main(int argc, const char **argv)
-{
- struct rev_info rev;
- int silent = 0;
-
- git_config(git_diff_config);
- init_revisions(&rev);
- rev.abbrev = 0;
-
- argc = setup_revisions(argc, argv, &rev, NULL);
- while (1 < argc && argv[1][0] == '-') {
- if (!strcmp(argv[1], "--base"))
- rev.max_count = 1;
- else if (!strcmp(argv[1], "--ours"))
- rev.max_count = 2;
- else if (!strcmp(argv[1], "--theirs"))
- rev.max_count = 3;
- else if (!strcmp(argv[1], "-q"))
- silent = 1;
- else
- usage(diff_files_usage);
- argv++; argc--;
- }
- /*
- * Make sure there are NO revision (i.e. pending object) parameter,
- * rev.max_count is reasonable (0 <= n <= 3),
- * there is no other revision filtering parameters.
- */
- if (rev.pending_objects ||
- rev.min_age != -1 || rev.max_age != -1)
- usage(diff_files_usage);
- /*
- * Backward compatibility wart - "diff-files -s" used to
- * defeat the common diff option "-s" which asked for
- * DIFF_FORMAT_NO_OUTPUT.
- */
- if (rev.diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
- rev.diffopt.output_format = DIFF_FORMAT_RAW;
- return run_diff_files(&rev, silent);
-}
diff --git a/diff-index.c b/diff-index.c
deleted file mode 100644
index 8c9f601..0000000
--- a/diff-index.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "cache.h"
-#include "diff.h"
-#include "commit.h"
-#include "revision.h"
-
-static const char diff_cache_usage[] =
-"git-diff-index [-m] [--cached] "
-"[<common diff options>] <tree-ish> [<path>...]"
-COMMON_DIFF_OPTIONS_HELP;
-
-int main(int argc, const char **argv)
-{
- struct rev_info rev;
- int cached = 0;
- int i;
-
- git_config(git_diff_config);
- init_revisions(&rev);
- rev.abbrev = 0;
-
- argc = setup_revisions(argc, argv, &rev, NULL);
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
-
- if (!strcmp(arg, "--cached"))
- cached = 1;
- else
- usage(diff_cache_usage);
- }
- /*
- * Make sure there is one revision (i.e. pending object),
- * and there is no revision filtering parameters.
- */
- if (!rev.pending_objects || rev.pending_objects->next ||
- rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
- usage(diff_cache_usage);
- return run_diff_index(&rev, cached);
-}
diff --git a/diff-stages.c b/diff-stages.c
deleted file mode 100644
index dcd20e7..0000000
--- a/diff-stages.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2005 Junio C Hamano
- */
-
-#include "cache.h"
-#include "diff.h"
-
-static struct diff_options diff_options;
-
-static const char diff_stages_usage[] =
-"git-diff-stages [<common diff options>] <stage1> <stage2> [<path>...]"
-COMMON_DIFF_OPTIONS_HELP;
-
-static void diff_stages(int stage1, int stage2, const char **pathspec)
-{
- int i = 0;
- while (i < active_nr) {
- struct cache_entry *ce, *stages[4] = { NULL, };
- struct cache_entry *one, *two;
- const char *name;
- int len, skip;
-
- ce = active_cache[i];
- skip = !ce_path_match(ce, pathspec);
- len = ce_namelen(ce);
- name = ce->name;
- for (;;) {
- int stage = ce_stage(ce);
- stages[stage] = ce;
- if (active_nr <= ++i)
- break;
- ce = active_cache[i];
- if (ce_namelen(ce) != len ||
- memcmp(name, ce->name, len))
- break;
- }
- one = stages[stage1];
- two = stages[stage2];
-
- if (skip || (!one && !two))
- continue;
- if (!one)
- diff_addremove(&diff_options, '+', ntohl(two->ce_mode),
- two->sha1, name, NULL);
- else if (!two)
- diff_addremove(&diff_options, '-', ntohl(one->ce_mode),
- one->sha1, name, NULL);
- else if (memcmp(one->sha1, two->sha1, 20) ||
- (one->ce_mode != two->ce_mode) ||
- diff_options.find_copies_harder)
- diff_change(&diff_options,
- ntohl(one->ce_mode), ntohl(two->ce_mode),
- one->sha1, two->sha1, name, NULL);
- }
-}
-
-int main(int ac, const char **av)
-{
- int stage1, stage2;
- const char *prefix = setup_git_directory();
- const char **pathspec = NULL;
-
- git_config(git_diff_config);
- read_cache();
- diff_setup(&diff_options);
- while (1 < ac && av[1][0] == '-') {
- const char *arg = av[1];
- if (!strcmp(arg, "-r"))
- ; /* as usual */
- else {
- int diff_opt_cnt;
- diff_opt_cnt = diff_opt_parse(&diff_options,
- av+1, ac-1);
- if (diff_opt_cnt < 0)
- usage(diff_stages_usage);
- else if (diff_opt_cnt) {
- av += diff_opt_cnt;
- ac -= diff_opt_cnt;
- continue;
- }
- else
- usage(diff_stages_usage);
- }
- ac--; av++;
- }
-
- if (ac < 3 ||
- sscanf(av[1], "%d", &stage1) != 1 ||
- ! (0 <= stage1 && stage1 <= 3) ||
- sscanf(av[2], "%d", &stage2) != 1 ||
- ! (0 <= stage2 && stage2 <= 3))
- usage(diff_stages_usage);
-
- av += 3; /* The rest from av[0] are for paths restriction. */
- pathspec = get_pathspec(prefix, av);
-
- if (diff_setup_done(&diff_options) < 0)
- usage(diff_stages_usage);
-
- diff_stages(stage1, stage2, pathspec);
- diffcore_std(&diff_options);
- diff_flush(&diff_options);
- return 0;
-}
diff --git a/diff-tree.c b/diff-tree.c
deleted file mode 100644
index 69bb74b..0000000
--- a/diff-tree.c
+++ /dev/null
@@ -1,147 +0,0 @@
-#include "cache.h"
-#include "diff.h"
-#include "commit.h"
-#include "log-tree.h"
-
-static struct rev_info log_tree_opt;
-
-static int diff_tree_commit_sha1(const unsigned char *sha1)
-{
- struct commit *commit = lookup_commit_reference(sha1);
- if (!commit)
- return -1;
- return log_tree_commit(&log_tree_opt, commit);
-}
-
-static int diff_tree_stdin(char *line)
-{
- int len = strlen(line);
- unsigned char sha1[20];
- struct commit *commit;
-
- if (!len || line[len-1] != '\n')
- return -1;
- line[len-1] = 0;
- if (get_sha1_hex(line, sha1))
- return -1;
- commit = lookup_commit(sha1);
- if (!commit || parse_commit(commit))
- return -1;
- if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) {
- /* Graft the fake parents locally to the commit */
- int pos = 41;
- struct commit_list **pptr, *parents;
-
- /* Free the real parent list */
- for (parents = commit->parents; parents; ) {
- struct commit_list *tmp = parents->next;
- free(parents);
- parents = tmp;
- }
- commit->parents = NULL;
- pptr = &(commit->parents);
- while (line[pos] && !get_sha1_hex(line + pos, sha1)) {
- struct commit *parent = lookup_commit(sha1);
- if (parent) {
- pptr = &commit_list_insert(parent, pptr)->next;
- }
- pos += 41;
- }
- }
- return log_tree_commit(&log_tree_opt, commit);
-}
-
-static const char diff_tree_usage[] =
-"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
-" -r diff recursively\n"
-" --root include the initial commit as diff against /dev/null\n"
-COMMON_DIFF_OPTIONS_HELP;
-
-int main(int argc, const char **argv)
-{
- int nr_sha1;
- char line[1000];
- struct object *tree1, *tree2;
- static struct rev_info *opt = &log_tree_opt;
- struct object_list *list;
- int read_stdin = 0;
-
- git_config(git_diff_config);
- nr_sha1 = 0;
- init_revisions(opt);
- opt->abbrev = 0;
- opt->diff = 1;
- argc = setup_revisions(argc, argv, opt, NULL);
-
- while (--argc > 0) {
- const char *arg = *++argv;
-
- if (!strcmp(arg, "--stdin")) {
- read_stdin = 1;
- continue;
- }
- usage(diff_tree_usage);
- }
-
- /*
- * NOTE! "setup_revisions()" will have inserted the revisions
- * it parsed in reverse order. So if you do
- *
- * git-diff-tree a b
- *
- * the commit list will be "b" -> "a" -> NULL, so we reverse
- * the order of the objects if the first one is not marked
- * UNINTERESTING.
- */
- nr_sha1 = 0;
- list = opt->pending_objects;
- if (list) {
- nr_sha1++;
- tree1 = list->item;
- list = list->next;
- if (list) {
- nr_sha1++;
- tree2 = tree1;
- tree1 = list->item;
- if (list->next)
- usage(diff_tree_usage);
- /* Switch them around if the second one was uninteresting.. */
- if (tree2->flags & UNINTERESTING) {
- struct object *tmp = tree2;
- tree2 = tree1;
- tree1 = tmp;
- }
- }
- }
-
- switch (nr_sha1) {
- case 0:
- if (!read_stdin)
- usage(diff_tree_usage);
- break;
- case 1:
- diff_tree_commit_sha1(tree1->sha1);
- break;
- case 2:
- diff_tree_sha1(tree1->sha1,
- tree2->sha1,
- "", &opt->diffopt);
- log_tree_diff_flush(opt);
- break;
- }
-
- if (!read_stdin)
- return 0;
-
- if (opt->diffopt.detect_rename)
- opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
- DIFF_SETUP_USE_CACHE);
- while (fgets(line, sizeof(line), stdin))
- if (line[0] == '\n')
- fflush(stdout);
- else
- diff_tree_stdin(line);
-
- return 0;
-}
diff --git a/git.c b/git.c
index d29505c..8749748 100644
--- a/git.c
+++ b/git.c
@@ -59,7 +59,11 @@ static void handle_internal_command(int
{ "read-tree", cmd_read_tree },
{ "commit-tree", cmd_commit_tree },
{ "apply", cmd_apply },
- { "show-branch", cmd_show_branch }
+ { "show-branch", cmd_show_branch },
+ { "diff-files", cmd_diff_files },
+ { "diff-index", cmd_diff_index },
+ { "diff-stages", cmd_diff_stages },
+ { "diff-tree", cmd_diff_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 7/8] Builtin git-show-branch.
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <1148373081381-git-send-email->
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
d0d1cfb7985fa90442e423a55ca23e6bc83f912d
Makefile | 6
builtin-show-branch.c | 789 +++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1
git.c | 3
show-branch.c | 788 -------------------------------------------------
5 files changed, 795 insertions(+), 792 deletions(-)
create mode 100644 builtin-show-branch.c
delete mode 100644 show-branch.c
d0d1cfb7985fa90442e423a55ca23e6bc83f912d
diff --git a/Makefile b/Makefile
index eeb4fdb..b438a90 100644
--- a/Makefile
+++ b/Makefile
@@ -159,7 +159,7 @@ PROGRAMS = \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X \
git-receive-pack$X git-rev-parse$X \
- git-send-pack$X git-show-branch$X git-shell$X \
+ git-send-pack$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
@@ -173,7 +173,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
git-tar-tree$X git-read-tree$X git-commit-tree$X \
- git-apply$X
+ git-apply$X git-show-branch$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -224,7 +224,7 @@ BUILTIN_OBJS = \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o \
- builtin-apply.o
+ builtin-apply.o builtin-show-branch.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
new file mode 100644
index 0000000..d1be8bb
--- /dev/null
+++ b/builtin-show-branch.c
@@ -0,0 +1,789 @@
+#include <stdlib.h>
+#include <fnmatch.h>
+#include "cache.h"
+#include "commit.h"
+#include "refs.h"
+#include "builtin.h"
+
+static const char show_branch_usage[] =
+"git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
+
+static int default_num = 0;
+static int default_alloc = 0;
+static char **default_arg = NULL;
+
+#define UNINTERESTING 01
+
+#define REV_SHIFT 2
+#define MAX_REVS 29 /* should not exceed bits_per_int - REV_SHIFT */
+
+static struct commit *interesting(struct commit_list *list)
+{
+ while (list) {
+ struct commit *commit = list->item;
+ list = list->next;
+ if (commit->object.flags & UNINTERESTING)
+ continue;
+ return commit;
+ }
+ return NULL;
+}
+
+static struct commit *pop_one_commit(struct commit_list **list_p)
+{
+ struct commit *commit;
+ struct commit_list *list;
+ list = *list_p;
+ commit = list->item;
+ *list_p = list->next;
+ free(list);
+ return commit;
+}
+
+struct commit_name {
+ const char *head_name; /* which head's ancestor? */
+ int generation; /* how many parents away from head_name */
+};
+
+/* Name the commit as nth generation ancestor of head_name;
+ * we count only the first-parent relationship for naming purposes.
+ */
+static void name_commit(struct commit *commit, const char *head_name, int nth)
+{
+ struct commit_name *name;
+ if (!commit->object.util)
+ commit->object.util = xmalloc(sizeof(struct commit_name));
+ name = commit->object.util;
+ name->head_name = head_name;
+ name->generation = nth;
+}
+
+/* Parent is the first parent of the commit. We may name it
+ * as (n+1)th generation ancestor of the same head_name as
+ * commit is nth generation ancestor of, if that generation
+ * number is better than the name it already has.
+ */
+static void name_parent(struct commit *commit, struct commit *parent)
+{
+ struct commit_name *commit_name = commit->object.util;
+ struct commit_name *parent_name = parent->object.util;
+ if (!commit_name)
+ return;
+ if (!parent_name ||
+ commit_name->generation + 1 < parent_name->generation)
+ name_commit(parent, commit_name->head_name,
+ commit_name->generation + 1);
+}
+
+static int name_first_parent_chain(struct commit *c)
+{
+ int i = 0;
+ while (c) {
+ struct commit *p;
+ if (!c->object.util)
+ break;
+ if (!c->parents)
+ break;
+ p = c->parents->item;
+ if (!p->object.util) {
+ name_parent(c, p);
+ i++;
+ }
+ c = p;
+ }
+ return i;
+}
+
+static void name_commits(struct commit_list *list,
+ struct commit **rev,
+ char **ref_name,
+ int num_rev)
+{
+ struct commit_list *cl;
+ struct commit *c;
+ int i;
+
+ /* First give names to the given heads */
+ for (cl = list; cl; cl = cl->next) {
+ c = cl->item;
+ if (c->object.util)
+ continue;
+ for (i = 0; i < num_rev; i++) {
+ if (rev[i] == c) {
+ name_commit(c, ref_name[i], 0);
+ break;
+ }
+ }
+ }
+
+ /* Then commits on the first parent ancestry chain */
+ do {
+ i = 0;
+ for (cl = list; cl; cl = cl->next) {
+ i += name_first_parent_chain(cl->item);
+ }
+ } while (i);
+
+ /* Finally, any unnamed commits */
+ do {
+ i = 0;
+ for (cl = list; cl; cl = cl->next) {
+ struct commit_list *parents;
+ struct commit_name *n;
+ int nth;
+ c = cl->item;
+ if (!c->object.util)
+ continue;
+ n = c->object.util;
+ parents = c->parents;
+ nth = 0;
+ while (parents) {
+ struct commit *p = parents->item;
+ char newname[1000], *en;
+ parents = parents->next;
+ nth++;
+ if (p->object.util)
+ continue;
+ en = newname;
+ switch (n->generation) {
+ case 0:
+ en += sprintf(en, "%s", n->head_name);
+ break;
+ case 1:
+ en += sprintf(en, "%s^", n->head_name);
+ break;
+ default:
+ en += sprintf(en, "%s~%d",
+ n->head_name, n->generation);
+ break;
+ }
+ if (nth == 1)
+ en += sprintf(en, "^");
+ else
+ en += sprintf(en, "^%d", nth);
+ name_commit(p, strdup(newname), 0);
+ i++;
+ name_first_parent_chain(p);
+ }
+ }
+ } while (i);
+}
+
+static int mark_seen(struct commit *commit, struct commit_list **seen_p)
+{
+ if (!commit->object.flags) {
+ insert_by_date(commit, seen_p);
+ return 1;
+ }
+ return 0;
+}
+
+static void join_revs(struct commit_list **list_p,
+ struct commit_list **seen_p,
+ int num_rev, int extra)
+{
+ int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+ int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+
+ while (*list_p) {
+ struct commit_list *parents;
+ int still_interesting = !!interesting(*list_p);
+ struct commit *commit = pop_one_commit(list_p);
+ int flags = commit->object.flags & all_mask;
+
+ if (!still_interesting && extra <= 0)
+ break;
+
+ mark_seen(commit, seen_p);
+ if ((flags & all_revs) == all_revs)
+ flags |= UNINTERESTING;
+ parents = commit->parents;
+
+ while (parents) {
+ struct commit *p = parents->item;
+ int this_flag = p->object.flags;
+ parents = parents->next;
+ if ((this_flag & flags) == flags)
+ continue;
+ if (!p->object.parsed)
+ parse_commit(p);
+ if (mark_seen(p, seen_p) && !still_interesting)
+ extra--;
+ p->object.flags |= flags;
+ insert_by_date(p, list_p);
+ }
+ }
+
+ /*
+ * Postprocess to complete well-poisoning.
+ *
+ * At this point we have all the commits we have seen in
+ * seen_p list (which happens to be sorted chronologically but
+ * it does not really matter). Mark anything that can be
+ * reached from uninteresting commits not interesting.
+ */
+ for (;;) {
+ int changed = 0;
+ struct commit_list *s;
+ for (s = *seen_p; s; s = s->next) {
+ struct commit *c = s->item;
+ struct commit_list *parents;
+
+ if (((c->object.flags & all_revs) != all_revs) &&
+ !(c->object.flags & UNINTERESTING))
+ continue;
+
+ /* The current commit is either a merge base or
+ * already uninteresting one. Mark its parents
+ * as uninteresting commits _only_ if they are
+ * already parsed. No reason to find new ones
+ * here.
+ */
+ parents = c->parents;
+ while (parents) {
+ struct commit *p = parents->item;
+ parents = parents->next;
+ if (!(p->object.flags & UNINTERESTING)) {
+ p->object.flags |= UNINTERESTING;
+ changed = 1;
+ }
+ }
+ }
+ if (!changed)
+ break;
+ }
+}
+
+static void show_one_commit(struct commit *commit, int no_name)
+{
+ char pretty[256], *cp;
+ struct commit_name *name = commit->object.util;
+ if (commit->object.parsed)
+ pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
+ pretty, sizeof(pretty), 0);
+ else
+ strcpy(pretty, "(unavailable)");
+ if (!strncmp(pretty, "[PATCH] ", 8))
+ cp = pretty + 8;
+ else
+ cp = pretty;
+
+ if (!no_name) {
+ if (name && name->head_name) {
+ printf("[%s", name->head_name);
+ if (name->generation) {
+ if (name->generation == 1)
+ printf("^");
+ else
+ printf("~%d", name->generation);
+ }
+ printf("] ");
+ }
+ else
+ printf("[%s] ",
+ find_unique_abbrev(commit->object.sha1, 7));
+ }
+ puts(cp);
+}
+
+static char *ref_name[MAX_REVS + 1];
+static int ref_name_cnt;
+
+static const char *find_digit_prefix(const char *s, int *v)
+{
+ const char *p;
+ int ver;
+ char ch;
+
+ for (p = s, ver = 0;
+ '0' <= (ch = *p) && ch <= '9';
+ p++)
+ ver = ver * 10 + ch - '0';
+ *v = ver;
+ return p;
+}
+
+
+static int version_cmp(const char *a, const char *b)
+{
+ while (1) {
+ int va, vb;
+
+ a = find_digit_prefix(a, &va);
+ b = find_digit_prefix(b, &vb);
+ if (va != vb)
+ return va - vb;
+
+ while (1) {
+ int ca = *a;
+ int cb = *b;
+ if ('0' <= ca && ca <= '9')
+ ca = 0;
+ if ('0' <= cb && cb <= '9')
+ cb = 0;
+ if (ca != cb)
+ return ca - cb;
+ if (!ca)
+ break;
+ a++;
+ b++;
+ }
+ if (!*a && !*b)
+ return 0;
+ }
+}
+
+static int compare_ref_name(const void *a_, const void *b_)
+{
+ const char * const*a = a_, * const*b = b_;
+ return version_cmp(*a, *b);
+}
+
+static void sort_ref_range(int bottom, int top)
+{
+ qsort(ref_name + bottom, top - bottom, sizeof(ref_name[0]),
+ compare_ref_name);
+}
+
+static int append_ref(const char *refname, const unsigned char *sha1)
+{
+ struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+ int i;
+
+ if (!commit)
+ return 0;
+ /* Avoid adding the same thing twice */
+ for (i = 0; i < ref_name_cnt; i++)
+ if (!strcmp(refname, ref_name[i]))
+ return 0;
+
+ if (MAX_REVS <= ref_name_cnt) {
+ fprintf(stderr, "warning: ignoring %s; "
+ "cannot handle more than %d refs\n",
+ refname, MAX_REVS);
+ return 0;
+ }
+ ref_name[ref_name_cnt++] = strdup(refname);
+ ref_name[ref_name_cnt] = NULL;
+ return 0;
+}
+
+static int append_head_ref(const char *refname, const unsigned char *sha1)
+{
+ unsigned char tmp[20];
+ int ofs = 11;
+ if (strncmp(refname, "refs/heads/", ofs))
+ return 0;
+ /* If both heads/foo and tags/foo exists, get_sha1 would
+ * get confused.
+ */
+ if (get_sha1(refname + ofs, tmp) || memcmp(tmp, sha1, 20))
+ ofs = 5;
+ return append_ref(refname + ofs, sha1);
+}
+
+static int append_tag_ref(const char *refname, const unsigned char *sha1)
+{
+ if (strncmp(refname, "refs/tags/", 10))
+ return 0;
+ return append_ref(refname + 5, sha1);
+}
+
+static const char *match_ref_pattern = NULL;
+static int match_ref_slash = 0;
+static int count_slash(const char *s)
+{
+ int cnt = 0;
+ while (*s)
+ if (*s++ == '/')
+ cnt++;
+ return cnt;
+}
+
+static int append_matching_ref(const char *refname, const unsigned char *sha1)
+{
+ /* we want to allow pattern hold/<asterisk> to show all
+ * branches under refs/heads/hold/, and v0.99.9? to show
+ * refs/tags/v0.99.9a and friends.
+ */
+ const char *tail;
+ int slash = count_slash(refname);
+ for (tail = refname; *tail && match_ref_slash < slash; )
+ if (*tail++ == '/')
+ slash--;
+ if (!*tail)
+ return 0;
+ if (fnmatch(match_ref_pattern, tail, 0))
+ return 0;
+ if (!strncmp("refs/heads/", refname, 11))
+ return append_head_ref(refname, sha1);
+ if (!strncmp("refs/tags/", refname, 10))
+ return append_tag_ref(refname, sha1);
+ return append_ref(refname, sha1);
+}
+
+static void snarf_refs(int head, int tag)
+{
+ if (head) {
+ int orig_cnt = ref_name_cnt;
+ for_each_ref(append_head_ref);
+ sort_ref_range(orig_cnt, ref_name_cnt);
+ }
+ if (tag) {
+ int orig_cnt = ref_name_cnt;
+ for_each_ref(append_tag_ref);
+ sort_ref_range(orig_cnt, ref_name_cnt);
+ }
+}
+
+static int rev_is_head(char *head_path, int headlen, char *name,
+ unsigned char *head_sha1, unsigned char *sha1)
+{
+ int namelen;
+ if ((!head_path[0]) ||
+ (head_sha1 && sha1 && memcmp(head_sha1, sha1, 20)))
+ return 0;
+ namelen = strlen(name);
+ if ((headlen < namelen) ||
+ memcmp(head_path + headlen - namelen, name, namelen))
+ return 0;
+ if (headlen == namelen ||
+ head_path[headlen - namelen - 1] == '/')
+ return 1;
+ return 0;
+}
+
+static int show_merge_base(struct commit_list *seen, int num_rev)
+{
+ int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+ int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+ int exit_status = 1;
+
+ while (seen) {
+ struct commit *commit = pop_one_commit(&seen);
+ int flags = commit->object.flags & all_mask;
+ if (!(flags & UNINTERESTING) &&
+ ((flags & all_revs) == all_revs)) {
+ puts(sha1_to_hex(commit->object.sha1));
+ exit_status = 0;
+ commit->object.flags |= UNINTERESTING;
+ }
+ }
+ return exit_status;
+}
+
+static int show_independent(struct commit **rev,
+ int num_rev,
+ char **ref_name,
+ unsigned int *rev_mask)
+{
+ int i;
+
+ for (i = 0; i < num_rev; i++) {
+ struct commit *commit = rev[i];
+ unsigned int flag = rev_mask[i];
+
+ if (commit->object.flags == flag)
+ puts(sha1_to_hex(commit->object.sha1));
+ commit->object.flags |= UNINTERESTING;
+ }
+ return 0;
+}
+
+static void append_one_rev(const char *av)
+{
+ unsigned char revkey[20];
+ if (!get_sha1(av, revkey)) {
+ append_ref(av, revkey);
+ return;
+ }
+ if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
+ /* glob style match */
+ int saved_matches = ref_name_cnt;
+ match_ref_pattern = av;
+ match_ref_slash = count_slash(av);
+ for_each_ref(append_matching_ref);
+ if (saved_matches == ref_name_cnt &&
+ ref_name_cnt < MAX_REVS)
+ error("no matching refs with %s", av);
+ if (saved_matches + 1 < ref_name_cnt)
+ sort_ref_range(saved_matches, ref_name_cnt);
+ return;
+ }
+ die("bad sha1 reference %s", av);
+}
+
+static int git_show_branch_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "showbranch.default")) {
+ if (default_alloc <= default_num + 1) {
+ default_alloc = default_alloc * 3 / 2 + 20;
+ default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
+ }
+ default_arg[default_num++] = strdup(value);
+ default_arg[default_num] = NULL;
+ return 0;
+ }
+
+ return git_default_config(var, value);
+}
+
+static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
+{
+ /* If the commit is tip of the named branches, do not
+ * omit it.
+ * Otherwise, if it is a merge that is reachable from only one
+ * tip, it is not that interesting.
+ */
+ int i, flag, count;
+ for (i = 0; i < n; i++)
+ if (rev[i] == commit)
+ return 0;
+ flag = commit->object.flags;
+ for (i = count = 0; i < n; i++) {
+ if (flag & (1u << (i + REV_SHIFT)))
+ count++;
+ }
+ if (count == 1)
+ return 1;
+ return 0;
+}
+
+int cmd_show_branch(int ac, const char **av, char **envp)
+{
+ struct commit *rev[MAX_REVS], *commit;
+ struct commit_list *list = NULL, *seen = NULL;
+ unsigned int rev_mask[MAX_REVS];
+ int num_rev, i, extra = 0;
+ int all_heads = 0, all_tags = 0;
+ int all_mask, all_revs;
+ int lifo = 1;
+ char head_path[128];
+ const char *head_path_p;
+ int head_path_len;
+ unsigned char head_sha1[20];
+ int merge_base = 0;
+ int independent = 0;
+ int no_name = 0;
+ int sha1_name = 0;
+ int shown_merge_point = 0;
+ int with_current_branch = 0;
+ int head_at = -1;
+ int topics = 0;
+ int dense = 1;
+
+ setup_git_directory();
+ git_config(git_show_branch_config);
+
+ /* If nothing is specified, try the default first */
+ if (ac == 1 && default_num) {
+ ac = default_num + 1;
+ av = default_arg - 1; /* ick; we would not address av[0] */
+ }
+
+ while (1 < ac && av[1][0] == '-') {
+ char *arg = av[1];
+ if (!strcmp(arg, "--")) {
+ ac--; av++;
+ break;
+ }
+ else if (!strcmp(arg, "--all"))
+ all_heads = all_tags = 1;
+ else if (!strcmp(arg, "--heads"))
+ all_heads = 1;
+ else if (!strcmp(arg, "--tags"))
+ all_tags = 1;
+ else if (!strcmp(arg, "--more"))
+ extra = 1;
+ else if (!strcmp(arg, "--list"))
+ extra = -1;
+ else if (!strcmp(arg, "--no-name"))
+ no_name = 1;
+ else if (!strcmp(arg, "--current"))
+ with_current_branch = 1;
+ else if (!strcmp(arg, "--sha1-name"))
+ sha1_name = 1;
+ else if (!strncmp(arg, "--more=", 7))
+ extra = atoi(arg + 7);
+ else if (!strcmp(arg, "--merge-base"))
+ merge_base = 1;
+ else if (!strcmp(arg, "--independent"))
+ independent = 1;
+ else if (!strcmp(arg, "--topo-order"))
+ lifo = 1;
+ else if (!strcmp(arg, "--topics"))
+ topics = 1;
+ else if (!strcmp(arg, "--sparse"))
+ dense = 0;
+ else if (!strcmp(arg, "--date-order"))
+ lifo = 0;
+ else
+ usage(show_branch_usage);
+ ac--; av++;
+ }
+ ac--; av++;
+
+ /* Only one of these is allowed */
+ if (1 < independent + merge_base + (extra != 0))
+ usage(show_branch_usage);
+
+ /* If nothing is specified, show all branches by default */
+ if (ac + all_heads + all_tags == 0)
+ all_heads = 1;
+
+ if (all_heads + all_tags)
+ snarf_refs(all_heads, all_tags);
+ while (0 < ac) {
+ append_one_rev(*av);
+ ac--; av++;
+ }
+
+ head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
+ if (head_path_p) {
+ head_path_len = strlen(head_path_p);
+ memcpy(head_path, head_path_p, head_path_len + 1);
+ }
+ else {
+ head_path_len = 0;
+ head_path[0] = 0;
+ }
+
+ if (with_current_branch && head_path_p) {
+ int has_head = 0;
+ for (i = 0; !has_head && i < ref_name_cnt; i++) {
+ /* We are only interested in adding the branch
+ * HEAD points at.
+ */
+ if (rev_is_head(head_path,
+ head_path_len,
+ ref_name[i],
+ head_sha1, NULL))
+ has_head++;
+ }
+ if (!has_head) {
+ int pfxlen = strlen(git_path("refs/heads/"));
+ append_one_rev(head_path + pfxlen);
+ }
+ }
+
+ if (!ref_name_cnt) {
+ fprintf(stderr, "No revs to be shown.\n");
+ exit(0);
+ }
+
+ for (num_rev = 0; ref_name[num_rev]; num_rev++) {
+ unsigned char revkey[20];
+ unsigned int flag = 1u << (num_rev + REV_SHIFT);
+
+ if (MAX_REVS <= num_rev)
+ die("cannot handle more than %d revs.", MAX_REVS);
+ if (get_sha1(ref_name[num_rev], revkey))
+ die("'%s' is not a valid ref.", ref_name[num_rev]);
+ commit = lookup_commit_reference(revkey);
+ if (!commit)
+ die("cannot find commit %s (%s)",
+ ref_name[num_rev], revkey);
+ parse_commit(commit);
+ mark_seen(commit, &seen);
+
+ /* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
+ * and so on. REV_SHIFT bits from bit 0 are used for
+ * internal bookkeeping.
+ */
+ commit->object.flags |= flag;
+ if (commit->object.flags == flag)
+ insert_by_date(commit, &list);
+ rev[num_rev] = commit;
+ }
+ for (i = 0; i < num_rev; i++)
+ rev_mask[i] = rev[i]->object.flags;
+
+ if (0 <= extra)
+ join_revs(&list, &seen, num_rev, extra);
+
+ if (merge_base)
+ return show_merge_base(seen, num_rev);
+
+ if (independent)
+ return show_independent(rev, num_rev, ref_name, rev_mask);
+
+ /* Show list; --more=-1 means list-only */
+ if (1 < num_rev || extra < 0) {
+ for (i = 0; i < num_rev; i++) {
+ int j;
+ int is_head = rev_is_head(head_path,
+ head_path_len,
+ ref_name[i],
+ head_sha1,
+ rev[i]->object.sha1);
+ if (extra < 0)
+ printf("%c [%s] ",
+ is_head ? '*' : ' ', ref_name[i]);
+ else {
+ for (j = 0; j < i; j++)
+ putchar(' ');
+ printf("%c [%s] ",
+ is_head ? '*' : '!', ref_name[i]);
+ }
+ /* header lines never need name */
+ show_one_commit(rev[i], 1);
+ if (is_head)
+ head_at = i;
+ }
+ if (0 <= extra) {
+ for (i = 0; i < num_rev; i++)
+ putchar('-');
+ putchar('\n');
+ }
+ }
+ if (extra < 0)
+ exit(0);
+
+ /* Sort topologically */
+ sort_in_topological_order(&seen, lifo);
+
+ /* Give names to commits */
+ if (!sha1_name && !no_name)
+ name_commits(seen, rev, ref_name, num_rev);
+
+ all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+ all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+
+ while (seen) {
+ struct commit *commit = pop_one_commit(&seen);
+ int this_flag = commit->object.flags;
+ int is_merge_point = ((this_flag & all_revs) == all_revs);
+
+ shown_merge_point |= is_merge_point;
+
+ if (1 < num_rev) {
+ int is_merge = !!(commit->parents &&
+ commit->parents->next);
+ if (topics &&
+ !is_merge_point &&
+ (this_flag & (1u << REV_SHIFT)))
+ continue;
+ if (dense && is_merge &&
+ omit_in_dense(commit, rev, num_rev))
+ continue;
+ for (i = 0; i < num_rev; i++) {
+ int mark;
+ if (!(this_flag & (1u << (i + REV_SHIFT))))
+ mark = ' ';
+ else if (is_merge)
+ mark = '-';
+ else if (i == head_at)
+ mark = '*';
+ else
+ mark = '+';
+ putchar(mark);
+ }
+ putchar(' ');
+ }
+ show_one_commit(commit, no_name);
+
+ if (shown_merge_point && --extra < 0)
+ break;
+ }
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index d6ff88e..01882ec 100644
--- a/builtin.h
+++ b/builtin.h
@@ -33,5 +33,6 @@ extern int cmd_tar_tree(int argc, const
extern int cmd_read_tree(int argc, const char **argv, char **envp);
extern int cmd_commit_tree(int argc, const char **argv, char **envp);
extern int cmd_apply(int argc, const char **argv, char **envp);
+extern int cmd_show_branch(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index f44e08b..d29505c 100644
--- a/git.c
+++ b/git.c
@@ -58,7 +58,8 @@ static void handle_internal_command(int
{ "tar-tree", cmd_tar_tree },
{ "read-tree", cmd_read_tree },
{ "commit-tree", cmd_commit_tree },
- { "apply", cmd_apply }
+ { "apply", cmd_apply },
+ { "show-branch", cmd_show_branch }
};
int i;
diff --git a/show-branch.c b/show-branch.c
deleted file mode 100644
index 268c57b..0000000
--- a/show-branch.c
+++ /dev/null
@@ -1,788 +0,0 @@
-#include <stdlib.h>
-#include <fnmatch.h>
-#include "cache.h"
-#include "commit.h"
-#include "refs.h"
-
-static const char show_branch_usage[] =
-"git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
-
-static int default_num = 0;
-static int default_alloc = 0;
-static char **default_arg = NULL;
-
-#define UNINTERESTING 01
-
-#define REV_SHIFT 2
-#define MAX_REVS 29 /* should not exceed bits_per_int - REV_SHIFT */
-
-static struct commit *interesting(struct commit_list *list)
-{
- while (list) {
- struct commit *commit = list->item;
- list = list->next;
- if (commit->object.flags & UNINTERESTING)
- continue;
- return commit;
- }
- return NULL;
-}
-
-static struct commit *pop_one_commit(struct commit_list **list_p)
-{
- struct commit *commit;
- struct commit_list *list;
- list = *list_p;
- commit = list->item;
- *list_p = list->next;
- free(list);
- return commit;
-}
-
-struct commit_name {
- const char *head_name; /* which head's ancestor? */
- int generation; /* how many parents away from head_name */
-};
-
-/* Name the commit as nth generation ancestor of head_name;
- * we count only the first-parent relationship for naming purposes.
- */
-static void name_commit(struct commit *commit, const char *head_name, int nth)
-{
- struct commit_name *name;
- if (!commit->object.util)
- commit->object.util = xmalloc(sizeof(struct commit_name));
- name = commit->object.util;
- name->head_name = head_name;
- name->generation = nth;
-}
-
-/* Parent is the first parent of the commit. We may name it
- * as (n+1)th generation ancestor of the same head_name as
- * commit is nth generation ancestor of, if that generation
- * number is better than the name it already has.
- */
-static void name_parent(struct commit *commit, struct commit *parent)
-{
- struct commit_name *commit_name = commit->object.util;
- struct commit_name *parent_name = parent->object.util;
- if (!commit_name)
- return;
- if (!parent_name ||
- commit_name->generation + 1 < parent_name->generation)
- name_commit(parent, commit_name->head_name,
- commit_name->generation + 1);
-}
-
-static int name_first_parent_chain(struct commit *c)
-{
- int i = 0;
- while (c) {
- struct commit *p;
- if (!c->object.util)
- break;
- if (!c->parents)
- break;
- p = c->parents->item;
- if (!p->object.util) {
- name_parent(c, p);
- i++;
- }
- c = p;
- }
- return i;
-}
-
-static void name_commits(struct commit_list *list,
- struct commit **rev,
- char **ref_name,
- int num_rev)
-{
- struct commit_list *cl;
- struct commit *c;
- int i;
-
- /* First give names to the given heads */
- for (cl = list; cl; cl = cl->next) {
- c = cl->item;
- if (c->object.util)
- continue;
- for (i = 0; i < num_rev; i++) {
- if (rev[i] == c) {
- name_commit(c, ref_name[i], 0);
- break;
- }
- }
- }
-
- /* Then commits on the first parent ancestry chain */
- do {
- i = 0;
- for (cl = list; cl; cl = cl->next) {
- i += name_first_parent_chain(cl->item);
- }
- } while (i);
-
- /* Finally, any unnamed commits */
- do {
- i = 0;
- for (cl = list; cl; cl = cl->next) {
- struct commit_list *parents;
- struct commit_name *n;
- int nth;
- c = cl->item;
- if (!c->object.util)
- continue;
- n = c->object.util;
- parents = c->parents;
- nth = 0;
- while (parents) {
- struct commit *p = parents->item;
- char newname[1000], *en;
- parents = parents->next;
- nth++;
- if (p->object.util)
- continue;
- en = newname;
- switch (n->generation) {
- case 0:
- en += sprintf(en, "%s", n->head_name);
- break;
- case 1:
- en += sprintf(en, "%s^", n->head_name);
- break;
- default:
- en += sprintf(en, "%s~%d",
- n->head_name, n->generation);
- break;
- }
- if (nth == 1)
- en += sprintf(en, "^");
- else
- en += sprintf(en, "^%d", nth);
- name_commit(p, strdup(newname), 0);
- i++;
- name_first_parent_chain(p);
- }
- }
- } while (i);
-}
-
-static int mark_seen(struct commit *commit, struct commit_list **seen_p)
-{
- if (!commit->object.flags) {
- insert_by_date(commit, seen_p);
- return 1;
- }
- return 0;
-}
-
-static void join_revs(struct commit_list **list_p,
- struct commit_list **seen_p,
- int num_rev, int extra)
-{
- int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
- int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
-
- while (*list_p) {
- struct commit_list *parents;
- int still_interesting = !!interesting(*list_p);
- struct commit *commit = pop_one_commit(list_p);
- int flags = commit->object.flags & all_mask;
-
- if (!still_interesting && extra <= 0)
- break;
-
- mark_seen(commit, seen_p);
- if ((flags & all_revs) == all_revs)
- flags |= UNINTERESTING;
- parents = commit->parents;
-
- while (parents) {
- struct commit *p = parents->item;
- int this_flag = p->object.flags;
- parents = parents->next;
- if ((this_flag & flags) == flags)
- continue;
- if (!p->object.parsed)
- parse_commit(p);
- if (mark_seen(p, seen_p) && !still_interesting)
- extra--;
- p->object.flags |= flags;
- insert_by_date(p, list_p);
- }
- }
-
- /*
- * Postprocess to complete well-poisoning.
- *
- * At this point we have all the commits we have seen in
- * seen_p list (which happens to be sorted chronologically but
- * it does not really matter). Mark anything that can be
- * reached from uninteresting commits not interesting.
- */
- for (;;) {
- int changed = 0;
- struct commit_list *s;
- for (s = *seen_p; s; s = s->next) {
- struct commit *c = s->item;
- struct commit_list *parents;
-
- if (((c->object.flags & all_revs) != all_revs) &&
- !(c->object.flags & UNINTERESTING))
- continue;
-
- /* The current commit is either a merge base or
- * already uninteresting one. Mark its parents
- * as uninteresting commits _only_ if they are
- * already parsed. No reason to find new ones
- * here.
- */
- parents = c->parents;
- while (parents) {
- struct commit *p = parents->item;
- parents = parents->next;
- if (!(p->object.flags & UNINTERESTING)) {
- p->object.flags |= UNINTERESTING;
- changed = 1;
- }
- }
- }
- if (!changed)
- break;
- }
-}
-
-static void show_one_commit(struct commit *commit, int no_name)
-{
- char pretty[256], *cp;
- struct commit_name *name = commit->object.util;
- if (commit->object.parsed)
- pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
- pretty, sizeof(pretty), 0);
- else
- strcpy(pretty, "(unavailable)");
- if (!strncmp(pretty, "[PATCH] ", 8))
- cp = pretty + 8;
- else
- cp = pretty;
-
- if (!no_name) {
- if (name && name->head_name) {
- printf("[%s", name->head_name);
- if (name->generation) {
- if (name->generation == 1)
- printf("^");
- else
- printf("~%d", name->generation);
- }
- printf("] ");
- }
- else
- printf("[%s] ",
- find_unique_abbrev(commit->object.sha1, 7));
- }
- puts(cp);
-}
-
-static char *ref_name[MAX_REVS + 1];
-static int ref_name_cnt;
-
-static const char *find_digit_prefix(const char *s, int *v)
-{
- const char *p;
- int ver;
- char ch;
-
- for (p = s, ver = 0;
- '0' <= (ch = *p) && ch <= '9';
- p++)
- ver = ver * 10 + ch - '0';
- *v = ver;
- return p;
-}
-
-
-static int version_cmp(const char *a, const char *b)
-{
- while (1) {
- int va, vb;
-
- a = find_digit_prefix(a, &va);
- b = find_digit_prefix(b, &vb);
- if (va != vb)
- return va - vb;
-
- while (1) {
- int ca = *a;
- int cb = *b;
- if ('0' <= ca && ca <= '9')
- ca = 0;
- if ('0' <= cb && cb <= '9')
- cb = 0;
- if (ca != cb)
- return ca - cb;
- if (!ca)
- break;
- a++;
- b++;
- }
- if (!*a && !*b)
- return 0;
- }
-}
-
-static int compare_ref_name(const void *a_, const void *b_)
-{
- const char * const*a = a_, * const*b = b_;
- return version_cmp(*a, *b);
-}
-
-static void sort_ref_range(int bottom, int top)
-{
- qsort(ref_name + bottom, top - bottom, sizeof(ref_name[0]),
- compare_ref_name);
-}
-
-static int append_ref(const char *refname, const unsigned char *sha1)
-{
- struct commit *commit = lookup_commit_reference_gently(sha1, 1);
- int i;
-
- if (!commit)
- return 0;
- /* Avoid adding the same thing twice */
- for (i = 0; i < ref_name_cnt; i++)
- if (!strcmp(refname, ref_name[i]))
- return 0;
-
- if (MAX_REVS <= ref_name_cnt) {
- fprintf(stderr, "warning: ignoring %s; "
- "cannot handle more than %d refs\n",
- refname, MAX_REVS);
- return 0;
- }
- ref_name[ref_name_cnt++] = strdup(refname);
- ref_name[ref_name_cnt] = NULL;
- return 0;
-}
-
-static int append_head_ref(const char *refname, const unsigned char *sha1)
-{
- unsigned char tmp[20];
- int ofs = 11;
- if (strncmp(refname, "refs/heads/", ofs))
- return 0;
- /* If both heads/foo and tags/foo exists, get_sha1 would
- * get confused.
- */
- if (get_sha1(refname + ofs, tmp) || memcmp(tmp, sha1, 20))
- ofs = 5;
- return append_ref(refname + ofs, sha1);
-}
-
-static int append_tag_ref(const char *refname, const unsigned char *sha1)
-{
- if (strncmp(refname, "refs/tags/", 10))
- return 0;
- return append_ref(refname + 5, sha1);
-}
-
-static const char *match_ref_pattern = NULL;
-static int match_ref_slash = 0;
-static int count_slash(const char *s)
-{
- int cnt = 0;
- while (*s)
- if (*s++ == '/')
- cnt++;
- return cnt;
-}
-
-static int append_matching_ref(const char *refname, const unsigned char *sha1)
-{
- /* we want to allow pattern hold/<asterisk> to show all
- * branches under refs/heads/hold/, and v0.99.9? to show
- * refs/tags/v0.99.9a and friends.
- */
- const char *tail;
- int slash = count_slash(refname);
- for (tail = refname; *tail && match_ref_slash < slash; )
- if (*tail++ == '/')
- slash--;
- if (!*tail)
- return 0;
- if (fnmatch(match_ref_pattern, tail, 0))
- return 0;
- if (!strncmp("refs/heads/", refname, 11))
- return append_head_ref(refname, sha1);
- if (!strncmp("refs/tags/", refname, 10))
- return append_tag_ref(refname, sha1);
- return append_ref(refname, sha1);
-}
-
-static void snarf_refs(int head, int tag)
-{
- if (head) {
- int orig_cnt = ref_name_cnt;
- for_each_ref(append_head_ref);
- sort_ref_range(orig_cnt, ref_name_cnt);
- }
- if (tag) {
- int orig_cnt = ref_name_cnt;
- for_each_ref(append_tag_ref);
- sort_ref_range(orig_cnt, ref_name_cnt);
- }
-}
-
-static int rev_is_head(char *head_path, int headlen, char *name,
- unsigned char *head_sha1, unsigned char *sha1)
-{
- int namelen;
- if ((!head_path[0]) ||
- (head_sha1 && sha1 && memcmp(head_sha1, sha1, 20)))
- return 0;
- namelen = strlen(name);
- if ((headlen < namelen) ||
- memcmp(head_path + headlen - namelen, name, namelen))
- return 0;
- if (headlen == namelen ||
- head_path[headlen - namelen - 1] == '/')
- return 1;
- return 0;
-}
-
-static int show_merge_base(struct commit_list *seen, int num_rev)
-{
- int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
- int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
- int exit_status = 1;
-
- while (seen) {
- struct commit *commit = pop_one_commit(&seen);
- int flags = commit->object.flags & all_mask;
- if (!(flags & UNINTERESTING) &&
- ((flags & all_revs) == all_revs)) {
- puts(sha1_to_hex(commit->object.sha1));
- exit_status = 0;
- commit->object.flags |= UNINTERESTING;
- }
- }
- return exit_status;
-}
-
-static int show_independent(struct commit **rev,
- int num_rev,
- char **ref_name,
- unsigned int *rev_mask)
-{
- int i;
-
- for (i = 0; i < num_rev; i++) {
- struct commit *commit = rev[i];
- unsigned int flag = rev_mask[i];
-
- if (commit->object.flags == flag)
- puts(sha1_to_hex(commit->object.sha1));
- commit->object.flags |= UNINTERESTING;
- }
- return 0;
-}
-
-static void append_one_rev(const char *av)
-{
- unsigned char revkey[20];
- if (!get_sha1(av, revkey)) {
- append_ref(av, revkey);
- return;
- }
- if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
- /* glob style match */
- int saved_matches = ref_name_cnt;
- match_ref_pattern = av;
- match_ref_slash = count_slash(av);
- for_each_ref(append_matching_ref);
- if (saved_matches == ref_name_cnt &&
- ref_name_cnt < MAX_REVS)
- error("no matching refs with %s", av);
- if (saved_matches + 1 < ref_name_cnt)
- sort_ref_range(saved_matches, ref_name_cnt);
- return;
- }
- die("bad sha1 reference %s", av);
-}
-
-static int git_show_branch_config(const char *var, const char *value)
-{
- if (!strcmp(var, "showbranch.default")) {
- if (default_alloc <= default_num + 1) {
- default_alloc = default_alloc * 3 / 2 + 20;
- default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
- }
- default_arg[default_num++] = strdup(value);
- default_arg[default_num] = NULL;
- return 0;
- }
-
- return git_default_config(var, value);
-}
-
-static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
-{
- /* If the commit is tip of the named branches, do not
- * omit it.
- * Otherwise, if it is a merge that is reachable from only one
- * tip, it is not that interesting.
- */
- int i, flag, count;
- for (i = 0; i < n; i++)
- if (rev[i] == commit)
- return 0;
- flag = commit->object.flags;
- for (i = count = 0; i < n; i++) {
- if (flag & (1u << (i + REV_SHIFT)))
- count++;
- }
- if (count == 1)
- return 1;
- return 0;
-}
-
-int main(int ac, char **av)
-{
- struct commit *rev[MAX_REVS], *commit;
- struct commit_list *list = NULL, *seen = NULL;
- unsigned int rev_mask[MAX_REVS];
- int num_rev, i, extra = 0;
- int all_heads = 0, all_tags = 0;
- int all_mask, all_revs;
- int lifo = 1;
- char head_path[128];
- const char *head_path_p;
- int head_path_len;
- unsigned char head_sha1[20];
- int merge_base = 0;
- int independent = 0;
- int no_name = 0;
- int sha1_name = 0;
- int shown_merge_point = 0;
- int with_current_branch = 0;
- int head_at = -1;
- int topics = 0;
- int dense = 1;
-
- setup_git_directory();
- git_config(git_show_branch_config);
-
- /* If nothing is specified, try the default first */
- if (ac == 1 && default_num) {
- ac = default_num + 1;
- av = default_arg - 1; /* ick; we would not address av[0] */
- }
-
- while (1 < ac && av[1][0] == '-') {
- char *arg = av[1];
- if (!strcmp(arg, "--")) {
- ac--; av++;
- break;
- }
- else if (!strcmp(arg, "--all"))
- all_heads = all_tags = 1;
- else if (!strcmp(arg, "--heads"))
- all_heads = 1;
- else if (!strcmp(arg, "--tags"))
- all_tags = 1;
- else if (!strcmp(arg, "--more"))
- extra = 1;
- else if (!strcmp(arg, "--list"))
- extra = -1;
- else if (!strcmp(arg, "--no-name"))
- no_name = 1;
- else if (!strcmp(arg, "--current"))
- with_current_branch = 1;
- else if (!strcmp(arg, "--sha1-name"))
- sha1_name = 1;
- else if (!strncmp(arg, "--more=", 7))
- extra = atoi(arg + 7);
- else if (!strcmp(arg, "--merge-base"))
- merge_base = 1;
- else if (!strcmp(arg, "--independent"))
- independent = 1;
- else if (!strcmp(arg, "--topo-order"))
- lifo = 1;
- else if (!strcmp(arg, "--topics"))
- topics = 1;
- else if (!strcmp(arg, "--sparse"))
- dense = 0;
- else if (!strcmp(arg, "--date-order"))
- lifo = 0;
- else
- usage(show_branch_usage);
- ac--; av++;
- }
- ac--; av++;
-
- /* Only one of these is allowed */
- if (1 < independent + merge_base + (extra != 0))
- usage(show_branch_usage);
-
- /* If nothing is specified, show all branches by default */
- if (ac + all_heads + all_tags == 0)
- all_heads = 1;
-
- if (all_heads + all_tags)
- snarf_refs(all_heads, all_tags);
- while (0 < ac) {
- append_one_rev(*av);
- ac--; av++;
- }
-
- head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
- if (head_path_p) {
- head_path_len = strlen(head_path_p);
- memcpy(head_path, head_path_p, head_path_len + 1);
- }
- else {
- head_path_len = 0;
- head_path[0] = 0;
- }
-
- if (with_current_branch && head_path_p) {
- int has_head = 0;
- for (i = 0; !has_head && i < ref_name_cnt; i++) {
- /* We are only interested in adding the branch
- * HEAD points at.
- */
- if (rev_is_head(head_path,
- head_path_len,
- ref_name[i],
- head_sha1, NULL))
- has_head++;
- }
- if (!has_head) {
- int pfxlen = strlen(git_path("refs/heads/"));
- append_one_rev(head_path + pfxlen);
- }
- }
-
- if (!ref_name_cnt) {
- fprintf(stderr, "No revs to be shown.\n");
- exit(0);
- }
-
- for (num_rev = 0; ref_name[num_rev]; num_rev++) {
- unsigned char revkey[20];
- unsigned int flag = 1u << (num_rev + REV_SHIFT);
-
- if (MAX_REVS <= num_rev)
- die("cannot handle more than %d revs.", MAX_REVS);
- if (get_sha1(ref_name[num_rev], revkey))
- die("'%s' is not a valid ref.", ref_name[num_rev]);
- commit = lookup_commit_reference(revkey);
- if (!commit)
- die("cannot find commit %s (%s)",
- ref_name[num_rev], revkey);
- parse_commit(commit);
- mark_seen(commit, &seen);
-
- /* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
- * and so on. REV_SHIFT bits from bit 0 are used for
- * internal bookkeeping.
- */
- commit->object.flags |= flag;
- if (commit->object.flags == flag)
- insert_by_date(commit, &list);
- rev[num_rev] = commit;
- }
- for (i = 0; i < num_rev; i++)
- rev_mask[i] = rev[i]->object.flags;
-
- if (0 <= extra)
- join_revs(&list, &seen, num_rev, extra);
-
- if (merge_base)
- return show_merge_base(seen, num_rev);
-
- if (independent)
- return show_independent(rev, num_rev, ref_name, rev_mask);
-
- /* Show list; --more=-1 means list-only */
- if (1 < num_rev || extra < 0) {
- for (i = 0; i < num_rev; i++) {
- int j;
- int is_head = rev_is_head(head_path,
- head_path_len,
- ref_name[i],
- head_sha1,
- rev[i]->object.sha1);
- if (extra < 0)
- printf("%c [%s] ",
- is_head ? '*' : ' ', ref_name[i]);
- else {
- for (j = 0; j < i; j++)
- putchar(' ');
- printf("%c [%s] ",
- is_head ? '*' : '!', ref_name[i]);
- }
- /* header lines never need name */
- show_one_commit(rev[i], 1);
- if (is_head)
- head_at = i;
- }
- if (0 <= extra) {
- for (i = 0; i < num_rev; i++)
- putchar('-');
- putchar('\n');
- }
- }
- if (extra < 0)
- exit(0);
-
- /* Sort topologically */
- sort_in_topological_order(&seen, lifo);
-
- /* Give names to commits */
- if (!sha1_name && !no_name)
- name_commits(seen, rev, ref_name, num_rev);
-
- all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
- all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
-
- while (seen) {
- struct commit *commit = pop_one_commit(&seen);
- int this_flag = commit->object.flags;
- int is_merge_point = ((this_flag & all_revs) == all_revs);
-
- shown_merge_point |= is_merge_point;
-
- if (1 < num_rev) {
- int is_merge = !!(commit->parents &&
- commit->parents->next);
- if (topics &&
- !is_merge_point &&
- (this_flag & (1u << REV_SHIFT)))
- continue;
- if (dense && is_merge &&
- omit_in_dense(commit, rev, num_rev))
- continue;
- for (i = 0; i < num_rev; i++) {
- int mark;
- if (!(this_flag & (1u << (i + REV_SHIFT))))
- mark = ' ';
- else if (is_merge)
- mark = '-';
- else if (i == head_at)
- mark = '*';
- else
- mark = '+';
- putchar(mark);
- }
- putchar(' ');
- }
- show_one_commit(commit, no_name);
-
- if (shown_merge_point && --extra < 0)
- break;
- }
- return 0;
-}
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 4/8] Builtin git-read-tree.
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483730801352-git-send-email->
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
baba8c18d8a5fff876d16a434b49677cd3ebbdb0
Makefile | 6
builtin-read-tree.c | 882 +++++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1
git.c | 3
read-tree.c | 881 ---------------------------------------------------
5 files changed, 888 insertions(+), 885 deletions(-)
create mode 100644 builtin-read-tree.c
delete mode 100644 read-tree.c
baba8c18d8a5fff876d16a434b49677cd3ebbdb0
diff --git a/Makefile b/Makefile
index 966f7ee..667fa5d 100644
--- a/Makefile
+++ b/Makefile
@@ -157,7 +157,7 @@ PROGRAMS = \
git-hash-object$X git-index-pack$X git-local-fetch$X \
git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
- git-peek-remote$X git-prune-packed$X git-read-tree$X \
+ git-peek-remote$X git-prune-packed$X \
git-receive-pack$X git-rev-parse$X \
git-send-pack$X git-show-branch$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
@@ -172,7 +172,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
- git-tar-tree$X
+ git-tar-tree$X git-read-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -222,7 +222,7 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o
+ builtin-tar-tree.o builtin-read-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
new file mode 100644
index 0000000..ec40d01
--- /dev/null
+++ b/builtin-read-tree.c
@@ -0,0 +1,882 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#define DBRT_DEBUG 1
+
+#include "cache.h"
+
+#include "object.h"
+#include "tree.h"
+#include <sys/time.h>
+#include <signal.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 int head_idx = -1;
+static int merge_size = 0;
+
+static struct object_list *trees = NULL;
+
+static struct cache_entry df_conflict_entry = {
+};
+
+static struct tree_entry_list df_conflict_list = {
+ .name = NULL,
+ .next = &df_conflict_list
+};
+
+typedef int (*merge_fn_t)(struct cache_entry **src);
+
+static int entcmp(char *name1, int dir1, 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;
+ 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) {
+ any_dirs = 1;
+ parse_tree(posns[i]->item.tree);
+ subposns[i] = posns[i]->item.tree->entries;
+ 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]->item.any->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 void check_updates(struct cache_entry **src, int nr)
+{
+ static struct checkout state = {
+ .base_dir = "",
+ .force = 1,
+ .quiet = 1,
+ .refresh_cache = 1,
+ };
+ 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;
+ }
+ }
+ }
+ 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] = ((struct tree *) posn->item)->entries;
+ posn = posn->next;
+ }
+ if (unpack_trees_rec(posns, len, "", 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);
+ if (!tree)
+ return -1;
+ object_list_append(&tree->object, &trees);
+ 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 stat st;
+
+ if (index_only || reset)
+ return;
+
+ if (!lstat(ce->name, &st)) {
+ unsigned changed = ce_match_stat(ce, &st, 1);
+ if (!changed)
+ return;
+ errno = 0;
+ }
+ if (reset) {
+ ce->ce_flags |= htons(CE_UPDATE);
+ return;
+ }
+ if (errno == ENOENT)
+ return;
+ die("Entry '%s' not uptodate. Cannot merge.", 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 stat st;
+
+ if (index_only || reset || !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)
+{
+ 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);
+ }
+ }
+ else
+ verify_absent(merge->name, "overwritten");
+
+ merge->ce_flags &= ~htons(CE_STAGEMASK);
+ add_cache_entry(merge, ADD_CACHE_OK_TO_ADD);
+ return 1;
+}
+
+static int deleted_entry(struct cache_entry *ce, struct cache_entry *old)
+{
+ if (old)
+ verify_uptodate(old);
+ else
+ verify_absent(ce->name, "removed");
+ ce->ce_mode = 0;
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
+ 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 cache_entry *index;
+ struct cache_entry *head;
+ struct cache_entry *remote = stages[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 < 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[head_idx];
+
+ if (head == &df_conflict_entry) {
+ df_conflict_head = 1;
+ head = NULL;
+ }
+
+ if (remote == &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 < 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);
+ }
+ /*
+ * 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);
+ /* #13, #3ALT */
+ if (!df_conflict_remote && remote_match && !head_match)
+ return merged_entry(head, index);
+ }
+
+ /* #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 (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);
+ else if (path)
+ verify_absent(path, "removed");
+ return 0;
+ }
+ /*
+ * Added in both, identically.
+ */
+ if (no_anc_exists && head && remote && same(head, remote))
+ return merged_entry(head, index);
+
+ }
+
+ /* 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);
+ }
+ else if (path)
+ verify_absent(path, "overwritten");
+
+ nontrivial_merge = 1;
+
+ /* #2, #3, #4, #6, #7, #9, #11. */
+ count = 0;
+ if (!head_match || !remote_match) {
+ for (i = 1; i < 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 cache_entry *current = src[0];
+ struct cache_entry *oldtree = src[1], *newtree = src[2];
+
+ if (merge_size != 2)
+ return error("Cannot do a twoway merge of %d trees",
+ 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);
+ }
+ else if (oldtree && newtree &&
+ same(current, oldtree) && !same(current, newtree)) {
+ /* 20 or 21 */
+ return merged_entry(newtree, current);
+ }
+ 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);
+ else
+ return deleted_entry(oldtree, current);
+}
+
+/*
+ * 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 cache_entry *old = src[0];
+ struct cache_entry *a = src[1];
+
+ if (merge_size != 1)
+ return error("Cannot do a oneway merge of %d trees",
+ merge_size);
+
+ if (!a)
+ return deleted_entry(old, old);
+ if (old && same(old, a)) {
+ if (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);
+}
+
+static int read_cache_unmerged(void)
+{
+ int i, deleted;
+ struct cache_entry **dst;
+
+ read_cache();
+ dst = active_cache;
+ deleted = 0;
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ if (ce_stage(ce)) {
+ deleted++;
+ continue;
+ }
+ if (deleted)
+ *dst = ce;
+ dst++;
+ }
+ active_nr -= deleted;
+ return deleted;
+}
+
+static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive] [-u | -i] <sha1> [<sha2> [<sha3>]])";
+
+static struct cache_file cache_file;
+
+int cmd_read_tree(int argc, const char **argv, char **envp)
+{
+ int i, newfd, stage = 0;
+ unsigned char sha1[20];
+ merge_fn_t fn = NULL;
+
+ setup_git_directory();
+ git_config(git_default_config);
+
+ newfd = hold_index_file_for_update(&cache_file, get_index_file());
+ if (newfd < 0)
+ die("unable to create new cachefile");
+
+ git_config(git_default_config);
+
+ merge = 0;
+ reset = 0;
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ /* "-u" means "update", meaning that a merge will update
+ * the working tree.
+ */
+ if (!strcmp(arg, "-u")) {
+ update = 1;
+ continue;
+ }
+
+ if (!strcmp(arg, "-v")) {
+ verbose_update = 1;
+ continue;
+ }
+
+ /* "-i" means "index only", meaning that a merge will
+ * not even look at the working tree.
+ */
+ if (!strcmp(arg, "-i")) {
+ index_only = 1;
+ continue;
+ }
+
+ /* This differs from "-m" in that we'll silently ignore unmerged entries */
+ if (!strcmp(arg, "--reset")) {
+ if (stage || merge)
+ usage(read_tree_usage);
+ reset = 1;
+ merge = 1;
+ stage = 1;
+ read_cache_unmerged();
+ continue;
+ }
+
+ if (!strcmp(arg, "--trivial")) {
+ trivial_merges_only = 1;
+ continue;
+ }
+
+ if (!strcmp(arg, "--aggressive")) {
+ aggressive = 1;
+ continue;
+ }
+
+ /* "-m" stands for "merge", meaning we start in stage 1 */
+ if (!strcmp(arg, "-m")) {
+ if (stage || merge)
+ usage(read_tree_usage);
+ if (read_cache_unmerged())
+ die("you need to resolve your current index first");
+ stage = 1;
+ merge = 1;
+ continue;
+ }
+
+ /* using -u and -i at the same time makes no sense */
+ if (1 < index_only + update)
+ usage(read_tree_usage);
+
+ if (get_sha1(arg, sha1))
+ die("Not a valid object name %s", arg);
+ if (list_tree(sha1) < 0)
+ die("failed to unpack tree object %s", arg);
+ stage++;
+ }
+ if ((update||index_only) && !merge)
+ usage(read_tree_usage);
+
+ if (merge) {
+ if (stage < 2)
+ die("just how do you expect me to merge %d trees?", stage-1);
+ switch (stage - 1) {
+ case 1:
+ fn = oneway_merge;
+ break;
+ case 2:
+ fn = twoway_merge;
+ break;
+ case 3:
+ fn = threeway_merge;
+ break;
+ default:
+ fn = threeway_merge;
+ break;
+ }
+
+ if (stage - 1 >= 3)
+ head_idx = stage - 2;
+ else
+ head_idx = 1;
+ }
+
+ unpack_trees(fn);
+ if (write_cache(newfd, active_cache, active_nr) ||
+ commit_index_file(&cache_file))
+ die("unable to write new index file");
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index d210543..88b3523 100644
--- a/builtin.h
+++ b/builtin.h
@@ -30,5 +30,6 @@ extern int cmd_init_db(int argc, const c
extern int cmd_ls_files(int argc, const char **argv, char **envp);
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
extern int cmd_tar_tree(int argc, const char **argv, char **envp);
+extern int cmd_read_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index c253e60..300e2b2 100644
--- a/git.c
+++ b/git.c
@@ -55,7 +55,8 @@ static void handle_internal_command(int
{ "check-ref-format", cmd_check_ref_format },
{ "ls-files", cmd_ls_files },
{ "ls-tree", cmd_ls_tree },
- { "tar-tree", cmd_tar_tree }
+ { "tar-tree", cmd_tar_tree },
+ { "read-tree", cmd_read_tree }
};
int i;
diff --git a/read-tree.c b/read-tree.c
deleted file mode 100644
index 82e2a9a..0000000
--- a/read-tree.c
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#define DBRT_DEBUG 1
-
-#include "cache.h"
-
-#include "object.h"
-#include "tree.h"
-#include <sys/time.h>
-#include <signal.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 int head_idx = -1;
-static int merge_size = 0;
-
-static struct object_list *trees = NULL;
-
-static struct cache_entry df_conflict_entry = {
-};
-
-static struct tree_entry_list df_conflict_list = {
- .name = NULL,
- .next = &df_conflict_list
-};
-
-typedef int (*merge_fn_t)(struct cache_entry **src);
-
-static int entcmp(char *name1, int dir1, 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;
- 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) {
- any_dirs = 1;
- parse_tree(posns[i]->item.tree);
- subposns[i] = posns[i]->item.tree->entries;
- 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]->item.any->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 void check_updates(struct cache_entry **src, int nr)
-{
- static struct checkout state = {
- .base_dir = "",
- .force = 1,
- .quiet = 1,
- .refresh_cache = 1,
- };
- 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;
- }
- }
- }
- 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] = ((struct tree *) posn->item)->entries;
- posn = posn->next;
- }
- if (unpack_trees_rec(posns, len, "", 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);
- if (!tree)
- return -1;
- object_list_append(&tree->object, &trees);
- 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 stat st;
-
- if (index_only || reset)
- return;
-
- if (!lstat(ce->name, &st)) {
- unsigned changed = ce_match_stat(ce, &st, 1);
- if (!changed)
- return;
- errno = 0;
- }
- if (reset) {
- ce->ce_flags |= htons(CE_UPDATE);
- return;
- }
- if (errno == ENOENT)
- return;
- die("Entry '%s' not uptodate. Cannot merge.", 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 stat st;
-
- if (index_only || reset || !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)
-{
- 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);
- }
- }
- else
- verify_absent(merge->name, "overwritten");
-
- merge->ce_flags &= ~htons(CE_STAGEMASK);
- add_cache_entry(merge, ADD_CACHE_OK_TO_ADD);
- return 1;
-}
-
-static int deleted_entry(struct cache_entry *ce, struct cache_entry *old)
-{
- if (old)
- verify_uptodate(old);
- else
- verify_absent(ce->name, "removed");
- ce->ce_mode = 0;
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
- 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 cache_entry *index;
- struct cache_entry *head;
- struct cache_entry *remote = stages[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 < 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[head_idx];
-
- if (head == &df_conflict_entry) {
- df_conflict_head = 1;
- head = NULL;
- }
-
- if (remote == &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 < 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);
- }
- /*
- * 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);
- /* #13, #3ALT */
- if (!df_conflict_remote && remote_match && !head_match)
- return merged_entry(head, index);
- }
-
- /* #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 (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);
- else if (path)
- verify_absent(path, "removed");
- return 0;
- }
- /*
- * Added in both, identically.
- */
- if (no_anc_exists && head && remote && same(head, remote))
- return merged_entry(head, index);
-
- }
-
- /* 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);
- }
- else if (path)
- verify_absent(path, "overwritten");
-
- nontrivial_merge = 1;
-
- /* #2, #3, #4, #6, #7, #9, #11. */
- count = 0;
- if (!head_match || !remote_match) {
- for (i = 1; i < 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 cache_entry *current = src[0];
- struct cache_entry *oldtree = src[1], *newtree = src[2];
-
- if (merge_size != 2)
- return error("Cannot do a twoway merge of %d trees",
- 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);
- }
- else if (oldtree && newtree &&
- same(current, oldtree) && !same(current, newtree)) {
- /* 20 or 21 */
- return merged_entry(newtree, current);
- }
- 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);
- else
- return deleted_entry(oldtree, current);
-}
-
-/*
- * 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 cache_entry *old = src[0];
- struct cache_entry *a = src[1];
-
- if (merge_size != 1)
- return error("Cannot do a oneway merge of %d trees",
- merge_size);
-
- if (!a)
- return deleted_entry(old, old);
- if (old && same(old, a)) {
- if (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);
-}
-
-static int read_cache_unmerged(void)
-{
- int i, deleted;
- struct cache_entry **dst;
-
- read_cache();
- dst = active_cache;
- deleted = 0;
- for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce = active_cache[i];
- if (ce_stage(ce)) {
- deleted++;
- continue;
- }
- if (deleted)
- *dst = ce;
- dst++;
- }
- active_nr -= deleted;
- return deleted;
-}
-
-static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive] [-u | -i] <sha1> [<sha2> [<sha3>]])";
-
-static struct cache_file cache_file;
-
-int main(int argc, char **argv)
-{
- int i, newfd, stage = 0;
- unsigned char sha1[20];
- merge_fn_t fn = NULL;
-
- setup_git_directory();
- git_config(git_default_config);
-
- newfd = hold_index_file_for_update(&cache_file, get_index_file());
- if (newfd < 0)
- die("unable to create new cachefile");
-
- git_config(git_default_config);
-
- merge = 0;
- reset = 0;
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
-
- /* "-u" means "update", meaning that a merge will update
- * the working tree.
- */
- if (!strcmp(arg, "-u")) {
- update = 1;
- continue;
- }
-
- if (!strcmp(arg, "-v")) {
- verbose_update = 1;
- continue;
- }
-
- /* "-i" means "index only", meaning that a merge will
- * not even look at the working tree.
- */
- if (!strcmp(arg, "-i")) {
- index_only = 1;
- continue;
- }
-
- /* This differs from "-m" in that we'll silently ignore unmerged entries */
- if (!strcmp(arg, "--reset")) {
- if (stage || merge)
- usage(read_tree_usage);
- reset = 1;
- merge = 1;
- stage = 1;
- read_cache_unmerged();
- continue;
- }
-
- if (!strcmp(arg, "--trivial")) {
- trivial_merges_only = 1;
- continue;
- }
-
- if (!strcmp(arg, "--aggressive")) {
- aggressive = 1;
- continue;
- }
-
- /* "-m" stands for "merge", meaning we start in stage 1 */
- if (!strcmp(arg, "-m")) {
- if (stage || merge)
- usage(read_tree_usage);
- if (read_cache_unmerged())
- die("you need to resolve your current index first");
- stage = 1;
- merge = 1;
- continue;
- }
-
- /* using -u and -i at the same time makes no sense */
- if (1 < index_only + update)
- usage(read_tree_usage);
-
- if (get_sha1(arg, sha1))
- die("Not a valid object name %s", arg);
- if (list_tree(sha1) < 0)
- die("failed to unpack tree object %s", arg);
- stage++;
- }
- if ((update||index_only) && !merge)
- usage(read_tree_usage);
-
- if (merge) {
- if (stage < 2)
- die("just how do you expect me to merge %d trees?", stage-1);
- switch (stage - 1) {
- case 1:
- fn = oneway_merge;
- break;
- case 2:
- fn = twoway_merge;
- break;
- case 3:
- fn = threeway_merge;
- break;
- default:
- fn = threeway_merge;
- break;
- }
-
- if (stage - 1 >= 3)
- head_idx = stage - 2;
- else
- head_idx = 1;
- }
-
- unpack_trees(fn);
- if (write_cache(newfd, active_cache, active_nr) ||
- commit_index_file(&cache_file))
- die("unable to write new index file");
- return 0;
-}
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 5/8] Builtin git-commit-tree.
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483730804133-git-send-email->
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
762e5a2efcde796d84c573fe8bf3224c9fbf3588
Makefile | 6 +-
builtin-commit-tree.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1
commit-tree.c | 139 -------------------------------------------------
git.c | 3 +
5 files changed, 146 insertions(+), 143 deletions(-)
create mode 100644 builtin-commit-tree.c
delete mode 100644 commit-tree.c
762e5a2efcde796d84c573fe8bf3224c9fbf3588
diff --git a/Makefile b/Makefile
index 667fa5d..a5efbc7 100644
--- a/Makefile
+++ b/Makefile
@@ -150,7 +150,7 @@ SIMPLE_PROGRAMS = \
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
git-apply$X git-cat-file$X \
- git-checkout-index$X git-clone-pack$X git-commit-tree$X \
+ git-checkout-index$X git-clone-pack$X \
git-convert-objects$X git-diff-files$X \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
@@ -172,7 +172,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
git-init-db$X git-ls-files$X git-ls-tree$X \
- git-tar-tree$X git-read-tree$X
+ git-tar-tree$X git-read-tree$X git-commit-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -222,7 +222,7 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
- builtin-tar-tree.o builtin-read-tree.o
+ builtin-tar-tree.o builtin-read-tree.o builtin-commit-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
new file mode 100644
index 0000000..4ccdbec
--- /dev/null
+++ b/builtin-commit-tree.c
@@ -0,0 +1,140 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "cache.h"
+#include "commit.h"
+#include "tree.h"
+#include "builtin.h"
+
+#define BLOCKING (1ul << 14)
+
+/*
+ * FIXME! Share the code with "write-tree.c"
+ */
+static void init_buffer(char **bufp, unsigned int *sizep)
+{
+ char *buf = xmalloc(BLOCKING);
+ *sizep = 0;
+ *bufp = buf;
+}
+
+static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
+{
+ char one_line[2048];
+ va_list args;
+ int len;
+ unsigned long alloc, size, newsize;
+ char *buf;
+
+ va_start(args, fmt);
+ len = vsnprintf(one_line, sizeof(one_line), fmt, args);
+ va_end(args);
+ size = *sizep;
+ newsize = size + len;
+ alloc = (size + 32767) & ~32767;
+ buf = *bufp;
+ if (newsize > alloc) {
+ alloc = (newsize + 32767) & ~32767;
+ buf = xrealloc(buf, alloc);
+ *bufp = buf;
+ }
+ *sizep = newsize;
+ memcpy(buf + size, one_line, len);
+}
+
+static void check_valid(unsigned char *sha1, const char *expect)
+{
+ char type[20];
+
+ if (sha1_object_info(sha1, type, NULL))
+ die("%s is not a valid object", sha1_to_hex(sha1));
+ if (expect && strcmp(type, expect))
+ die("%s is not a valid '%s' object", sha1_to_hex(sha1),
+ expect);
+}
+
+/*
+ * Having more than two parents is not strange at all, and this is
+ * how multi-way merges are represented.
+ */
+#define MAXPARENT (16)
+static unsigned char parent_sha1[MAXPARENT][20];
+
+static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog";
+
+static int new_parent(int idx)
+{
+ int i;
+ unsigned char *sha1 = parent_sha1[idx];
+ for (i = 0; i < idx; i++) {
+ if (!memcmp(parent_sha1[i], sha1, 20)) {
+ error("duplicate parent %s ignored", sha1_to_hex(sha1));
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int cmd_commit_tree(int argc, const char **argv, char **envp)
+{
+ int i;
+ int parents = 0;
+ unsigned char tree_sha1[20];
+ unsigned char commit_sha1[20];
+ char comment[1000];
+ char *buffer;
+ unsigned int size;
+
+ setup_ident();
+ setup_git_directory();
+
+ git_config(git_default_config);
+
+ if (argc < 2)
+ usage(commit_tree_usage);
+ if (get_sha1(argv[1], tree_sha1))
+ die("Not a valid object name %s", argv[1]);
+
+ check_valid(tree_sha1, tree_type);
+ for (i = 2; i < argc; i += 2) {
+ char *a, *b;
+ a = argv[i]; b = argv[i+1];
+ if (!b || strcmp(a, "-p"))
+ usage(commit_tree_usage);
+ if (get_sha1(b, parent_sha1[parents]))
+ die("Not a valid object name %s", b);
+ check_valid(parent_sha1[parents], commit_type);
+ if (new_parent(parents))
+ parents++;
+ }
+ if (!parents)
+ fprintf(stderr, "Committing initial tree %s\n", argv[1]);
+
+ init_buffer(&buffer, &size);
+ add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
+
+ /*
+ * NOTE! This ordering means that the same exact tree merged with a
+ * different order of parents will be a _different_ changeset even
+ * if everything else stays the same.
+ */
+ for (i = 0; i < parents; i++)
+ add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
+
+ /* Person/date information */
+ add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
+ add_buffer(&buffer, &size, "committer %s\n\n", git_committer_info(1));
+
+ /* And add the comment */
+ while (fgets(comment, sizeof(comment), stdin) != NULL)
+ add_buffer(&buffer, &size, "%s", comment);
+
+ if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
+ printf("%s\n", sha1_to_hex(commit_sha1));
+ return 0;
+ }
+ else
+ return 1;
+}
diff --git a/builtin.h b/builtin.h
index 88b3523..c6b07d9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -31,5 +31,6 @@ extern int cmd_ls_files(int argc, const
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
extern int cmd_tar_tree(int argc, const char **argv, char **envp);
extern int cmd_read_tree(int argc, const char **argv, char **envp);
+extern int cmd_commit_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/commit-tree.c b/commit-tree.c
deleted file mode 100644
index 0320036..0000000
--- a/commit-tree.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include "cache.h"
-#include "commit.h"
-#include "tree.h"
-
-#define BLOCKING (1ul << 14)
-
-/*
- * FIXME! Share the code with "write-tree.c"
- */
-static void init_buffer(char **bufp, unsigned int *sizep)
-{
- char *buf = xmalloc(BLOCKING);
- *sizep = 0;
- *bufp = buf;
-}
-
-static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
-{
- char one_line[2048];
- va_list args;
- int len;
- unsigned long alloc, size, newsize;
- char *buf;
-
- va_start(args, fmt);
- len = vsnprintf(one_line, sizeof(one_line), fmt, args);
- va_end(args);
- size = *sizep;
- newsize = size + len;
- alloc = (size + 32767) & ~32767;
- buf = *bufp;
- if (newsize > alloc) {
- alloc = (newsize + 32767) & ~32767;
- buf = xrealloc(buf, alloc);
- *bufp = buf;
- }
- *sizep = newsize;
- memcpy(buf + size, one_line, len);
-}
-
-static void check_valid(unsigned char *sha1, const char *expect)
-{
- char type[20];
-
- if (sha1_object_info(sha1, type, NULL))
- die("%s is not a valid object", sha1_to_hex(sha1));
- if (expect && strcmp(type, expect))
- die("%s is not a valid '%s' object", sha1_to_hex(sha1),
- expect);
-}
-
-/*
- * Having more than two parents is not strange at all, and this is
- * how multi-way merges are represented.
- */
-#define MAXPARENT (16)
-static unsigned char parent_sha1[MAXPARENT][20];
-
-static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog";
-
-static int new_parent(int idx)
-{
- int i;
- unsigned char *sha1 = parent_sha1[idx];
- for (i = 0; i < idx; i++) {
- if (!memcmp(parent_sha1[i], sha1, 20)) {
- error("duplicate parent %s ignored", sha1_to_hex(sha1));
- return 0;
- }
- }
- return 1;
-}
-
-int main(int argc, char **argv)
-{
- int i;
- int parents = 0;
- unsigned char tree_sha1[20];
- unsigned char commit_sha1[20];
- char comment[1000];
- char *buffer;
- unsigned int size;
-
- setup_ident();
- setup_git_directory();
-
- git_config(git_default_config);
-
- if (argc < 2)
- usage(commit_tree_usage);
- if (get_sha1(argv[1], tree_sha1))
- die("Not a valid object name %s", argv[1]);
-
- check_valid(tree_sha1, tree_type);
- for (i = 2; i < argc; i += 2) {
- char *a, *b;
- a = argv[i]; b = argv[i+1];
- if (!b || strcmp(a, "-p"))
- usage(commit_tree_usage);
- if (get_sha1(b, parent_sha1[parents]))
- die("Not a valid object name %s", b);
- check_valid(parent_sha1[parents], commit_type);
- if (new_parent(parents))
- parents++;
- }
- if (!parents)
- fprintf(stderr, "Committing initial tree %s\n", argv[1]);
-
- init_buffer(&buffer, &size);
- add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
-
- /*
- * NOTE! This ordering means that the same exact tree merged with a
- * different order of parents will be a _different_ changeset even
- * if everything else stays the same.
- */
- for (i = 0; i < parents; i++)
- add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
-
- /* Person/date information */
- add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
- add_buffer(&buffer, &size, "committer %s\n\n", git_committer_info(1));
-
- /* And add the comment */
- while (fgets(comment, sizeof(comment), stdin) != NULL)
- add_buffer(&buffer, &size, "%s", comment);
-
- if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
- printf("%s\n", sha1_to_hex(commit_sha1));
- return 0;
- }
- else
- return 1;
-}
diff --git a/git.c b/git.c
index 300e2b2..4c2c062 100644
--- a/git.c
+++ b/git.c
@@ -56,7 +56,8 @@ static void handle_internal_command(int
{ "ls-files", cmd_ls_files },
{ "ls-tree", cmd_ls_tree },
{ "tar-tree", cmd_tar_tree },
- { "read-tree", cmd_read_tree }
+ { "read-tree", cmd_read_tree },
+ { "commit-tree", cmd_commit_tree }
};
int i;
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 3/8] Builtin git-tar-tree.
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483730803527-git-send-email->
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
9860ed2d4a598ad100c3b4f6b07dd0a88a4547a6
Makefile | 8 +
builtin-tar-tree.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1
git.c | 3
tar-tree.c | 350 ----------------------------------------------------
5 files changed, 359 insertions(+), 354 deletions(-)
create mode 100644 builtin-tar-tree.c
delete mode 100644 tar-tree.c
9860ed2d4a598ad100c3b4f6b07dd0a88a4547a6
diff --git a/Makefile b/Makefile
index 9b02264..966f7ee 100644
--- a/Makefile
+++ b/Makefile
@@ -161,7 +161,7 @@ PROGRAMS = \
git-receive-pack$X git-rev-parse$X \
git-send-pack$X git-show-branch$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
- git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
+ git-ssh-upload$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X \
@@ -171,7 +171,8 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
- git-init-db$X git-ls-files$X git-ls-tree$X
+ git-init-db$X git-ls-files$X git-ls-tree$X \
+ git-tar-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -220,7 +221,8 @@ LIB_OBJS = \
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o
+ builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
+ builtin-tar-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
new file mode 100644
index 0000000..6ada04c
--- /dev/null
+++ b/builtin-tar-tree.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2005, 2006 Rene Scharfe
+ */
+#include <time.h>
+#include "cache.h"
+#include "tree-walk.h"
+#include "commit.h"
+#include "strbuf.h"
+#include "tar.h"
+#include "builtin.h"
+
+#define RECORDSIZE (512)
+#define BLOCKSIZE (RECORDSIZE * 20)
+
+static const char tar_tree_usage[] = "git-tar-tree <key> [basedir]";
+
+static char block[BLOCKSIZE];
+static unsigned long offset;
+
+static time_t archive_time;
+
+/* tries hard to write, either succeeds or dies in the attempt */
+static void reliable_write(void *buf, unsigned long size)
+{
+ while (size > 0) {
+ long ret = xwrite(1, buf, size);
+ if (ret < 0) {
+ if (errno == EPIPE)
+ exit(0);
+ die("git-tar-tree: %s", strerror(errno));
+ } else if (!ret) {
+ die("git-tar-tree: disk full?");
+ }
+ size -= ret;
+ buf += ret;
+ }
+}
+
+/* writes out the whole block, but only if it is full */
+static void write_if_needed(void)
+{
+ if (offset == BLOCKSIZE) {
+ reliable_write(block, BLOCKSIZE);
+ offset = 0;
+ }
+}
+
+/* acquire the next record from the buffer; user must call write_if_needed() */
+static char *get_record(void)
+{
+ char *p = block + offset;
+ memset(p, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ return p;
+}
+
+/*
+ * The end of tar archives is marked by 1024 nul bytes and after that
+ * follows the rest of the block (if any).
+ */
+static void write_trailer(void)
+{
+ get_record();
+ write_if_needed();
+ get_record();
+ write_if_needed();
+ while (offset) {
+ get_record();
+ write_if_needed();
+ }
+}
+
+/*
+ * queues up writes, so that all our write(2) calls write exactly one
+ * full block; pads writes to RECORDSIZE
+ */
+static void write_blocked(void *buf, unsigned long size)
+{
+ unsigned long tail;
+
+ if (offset) {
+ unsigned long chunk = BLOCKSIZE - offset;
+ if (size < chunk)
+ chunk = size;
+ memcpy(block + offset, buf, chunk);
+ size -= chunk;
+ offset += chunk;
+ buf += chunk;
+ write_if_needed();
+ }
+ while (size >= BLOCKSIZE) {
+ reliable_write(buf, BLOCKSIZE);
+ size -= BLOCKSIZE;
+ buf += BLOCKSIZE;
+ }
+ if (size) {
+ memcpy(block + offset, buf, size);
+ offset += size;
+ }
+ tail = offset % RECORDSIZE;
+ if (tail) {
+ memset(block + offset, 0, RECORDSIZE - tail);
+ offset += RECORDSIZE - tail;
+ }
+ write_if_needed();
+}
+
+static void strbuf_append_string(struct strbuf *sb, const char *s)
+{
+ int slen = strlen(s);
+ int total = sb->len + slen;
+ if (total > sb->alloc) {
+ sb->buf = xrealloc(sb->buf, total);
+ sb->alloc = total;
+ }
+ memcpy(sb->buf + sb->len, s, slen);
+ sb->len = total;
+}
+
+/*
+ * pax extended header records have the format "%u %s=%s\n". %u contains
+ * the size of the whole string (including the %u), the first %s is the
+ * keyword, the second one is the value. This function constructs such a
+ * string and appends it to a struct strbuf.
+ */
+static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
+ const char *value, unsigned int valuelen)
+{
+ char *p;
+ int len, total, tmp;
+
+ /* "%u %s=%s\n" */
+ len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
+ for (tmp = len; tmp > 9; tmp /= 10)
+ len++;
+
+ total = sb->len + len;
+ if (total > sb->alloc) {
+ sb->buf = xrealloc(sb->buf, total);
+ sb->alloc = total;
+ }
+
+ p = sb->buf;
+ p += sprintf(p, "%u %s=", len, keyword);
+ memcpy(p, value, valuelen);
+ p += valuelen;
+ *p = '\n';
+ sb->len = total;
+}
+
+static unsigned int ustar_header_chksum(const struct ustar_header *header)
+{
+ char *p = (char *)header;
+ unsigned int chksum = 0;
+ while (p < header->chksum)
+ chksum += *p++;
+ chksum += sizeof(header->chksum) * ' ';
+ p += sizeof(header->chksum);
+ while (p < (char *)header + sizeof(struct ustar_header))
+ chksum += *p++;
+ return chksum;
+}
+
+static int get_path_prefix(const struct strbuf *path, int maxlen)
+{
+ int i = path->len;
+ if (i > maxlen)
+ i = maxlen;
+ while (i > 0 && path->buf[i] != '/')
+ i--;
+ return i;
+}
+
+static void write_entry(const unsigned char *sha1, struct strbuf *path,
+ unsigned int mode, void *buffer, unsigned long size)
+{
+ struct ustar_header header;
+ struct strbuf ext_header;
+
+ memset(&header, 0, sizeof(header));
+ ext_header.buf = NULL;
+ ext_header.len = ext_header.alloc = 0;
+
+ if (!sha1) {
+ *header.typeflag = TYPEFLAG_GLOBAL_HEADER;
+ mode = 0100666;
+ strcpy(header.name, "pax_global_header");
+ } else if (!path) {
+ *header.typeflag = TYPEFLAG_EXT_HEADER;
+ mode = 0100666;
+ sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
+ } else {
+ if (S_ISDIR(mode)) {
+ *header.typeflag = TYPEFLAG_DIR;
+ mode |= 0777;
+ } else if (S_ISLNK(mode)) {
+ *header.typeflag = TYPEFLAG_LNK;
+ mode |= 0777;
+ } else if (S_ISREG(mode)) {
+ *header.typeflag = TYPEFLAG_REG;
+ mode |= (mode & 0100) ? 0777 : 0666;
+ } else {
+ error("unsupported file mode: 0%o (SHA1: %s)",
+ mode, sha1_to_hex(sha1));
+ return;
+ }
+ if (path->len > sizeof(header.name)) {
+ int plen = get_path_prefix(path, sizeof(header.prefix));
+ int rest = path->len - plen - 1;
+ if (plen > 0 && rest <= sizeof(header.name)) {
+ memcpy(header.prefix, path->buf, plen);
+ memcpy(header.name, path->buf + plen + 1, rest);
+ } else {
+ sprintf(header.name, "%s.data",
+ sha1_to_hex(sha1));
+ strbuf_append_ext_header(&ext_header, "path",
+ path->buf, path->len);
+ }
+ } else
+ memcpy(header.name, path->buf, path->len);
+ }
+
+ if (S_ISLNK(mode) && buffer) {
+ if (size > sizeof(header.linkname)) {
+ sprintf(header.linkname, "see %s.paxheader",
+ sha1_to_hex(sha1));
+ strbuf_append_ext_header(&ext_header, "linkpath",
+ buffer, size);
+ } else
+ memcpy(header.linkname, buffer, size);
+ }
+
+ sprintf(header.mode, "%07o", mode & 07777);
+ sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
+ sprintf(header.mtime, "%011lo", archive_time);
+
+ /* XXX: should we provide more meaningful info here? */
+ sprintf(header.uid, "%07o", 0);
+ sprintf(header.gid, "%07o", 0);
+ strncpy(header.uname, "git", 31);
+ strncpy(header.gname, "git", 31);
+ sprintf(header.devmajor, "%07o", 0);
+ sprintf(header.devminor, "%07o", 0);
+
+ memcpy(header.magic, "ustar", 6);
+ memcpy(header.version, "00", 2);
+
+ sprintf(header.chksum, "%07o", ustar_header_chksum(&header));
+
+ if (ext_header.len > 0) {
+ write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
+ free(ext_header.buf);
+ }
+ write_blocked(&header, sizeof(header));
+ if (S_ISREG(mode) && buffer && size > 0)
+ write_blocked(buffer, size);
+}
+
+static void write_global_extended_header(const unsigned char *sha1)
+{
+ struct strbuf ext_header;
+ ext_header.buf = NULL;
+ ext_header.len = ext_header.alloc = 0;
+ strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
+ write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
+ free(ext_header.buf);
+}
+
+static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
+{
+ int pathlen = path->len;
+
+ while (tree->size) {
+ const char *name;
+ const unsigned char *sha1;
+ unsigned mode;
+ void *eltbuf;
+ char elttype[20];
+ unsigned long eltsize;
+
+ sha1 = tree_entry_extract(tree, &name, &mode);
+ update_tree_entry(tree);
+
+ eltbuf = read_sha1_file(sha1, elttype, &eltsize);
+ if (!eltbuf)
+ die("cannot read %s", sha1_to_hex(sha1));
+
+ path->len = pathlen;
+ strbuf_append_string(path, name);
+ if (S_ISDIR(mode))
+ strbuf_append_string(path, "/");
+
+ write_entry(sha1, path, mode, eltbuf, eltsize);
+
+ if (S_ISDIR(mode)) {
+ struct tree_desc subtree;
+ subtree.buf = eltbuf;
+ subtree.size = eltsize;
+ traverse_tree(&subtree, path);
+ }
+ free(eltbuf);
+ }
+}
+
+int cmd_tar_tree(int argc, const char **argv, char** envp)
+{
+ unsigned char sha1[20], tree_sha1[20];
+ struct commit *commit;
+ struct tree_desc tree;
+ struct strbuf current_path;
+
+ current_path.buf = xmalloc(PATH_MAX);
+ current_path.alloc = PATH_MAX;
+ current_path.len = current_path.eof = 0;
+
+ setup_git_directory();
+ git_config(git_default_config);
+
+ switch (argc) {
+ case 3:
+ strbuf_append_string(¤t_path, argv[2]);
+ strbuf_append_string(¤t_path, "/");
+ /* FALLTHROUGH */
+ case 2:
+ if (get_sha1(argv[1], sha1))
+ die("Not a valid object name %s", argv[1]);
+ break;
+ default:
+ usage(tar_tree_usage);
+ }
+
+ commit = lookup_commit_reference_gently(sha1, 1);
+ if (commit) {
+ write_global_extended_header(commit->object.sha1);
+ archive_time = commit->date;
+ } else
+ archive_time = time(NULL);
+
+ tree.buf = read_object_with_reference(sha1, tree_type, &tree.size,
+ tree_sha1);
+ if (!tree.buf)
+ die("not a reference to a tag, commit or tree object: %s",
+ sha1_to_hex(sha1));
+
+ if (current_path.len > 0)
+ write_entry(tree_sha1, ¤t_path, 040777, NULL, 0);
+ traverse_tree(&tree, ¤t_path);
+ write_trailer();
+ free(current_path.buf);
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index 951f206..d210543 100644
--- a/builtin.h
+++ b/builtin.h
@@ -29,5 +29,6 @@ extern int cmd_check_ref_format(int argc
extern int cmd_init_db(int argc, const char **argv, char **envp);
extern int cmd_ls_files(int argc, const char **argv, char **envp);
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
+extern int cmd_tar_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 8574775..c253e60 100644
--- a/git.c
+++ b/git.c
@@ -54,7 +54,8 @@ static void handle_internal_command(int
{ "init-db", cmd_init_db },
{ "check-ref-format", cmd_check_ref_format },
{ "ls-files", cmd_ls_files },
- { "ls-tree", cmd_ls_tree }
+ { "ls-tree", cmd_ls_tree },
+ { "tar-tree", cmd_tar_tree }
};
int i;
diff --git a/tar-tree.c b/tar-tree.c
deleted file mode 100644
index 3308736..0000000
--- a/tar-tree.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (c) 2005, 2006 Rene Scharfe
- */
-#include <time.h>
-#include "cache.h"
-#include "tree-walk.h"
-#include "commit.h"
-#include "strbuf.h"
-#include "tar.h"
-
-#define RECORDSIZE (512)
-#define BLOCKSIZE (RECORDSIZE * 20)
-
-static const char tar_tree_usage[] = "git-tar-tree <key> [basedir]";
-
-static char block[BLOCKSIZE];
-static unsigned long offset;
-
-static time_t archive_time;
-
-/* tries hard to write, either succeeds or dies in the attempt */
-static void reliable_write(void *buf, unsigned long size)
-{
- while (size > 0) {
- long ret = xwrite(1, buf, size);
- if (ret < 0) {
- if (errno == EPIPE)
- exit(0);
- die("git-tar-tree: %s", strerror(errno));
- } else if (!ret) {
- die("git-tar-tree: disk full?");
- }
- size -= ret;
- buf += ret;
- }
-}
-
-/* writes out the whole block, but only if it is full */
-static void write_if_needed(void)
-{
- if (offset == BLOCKSIZE) {
- reliable_write(block, BLOCKSIZE);
- offset = 0;
- }
-}
-
-/* acquire the next record from the buffer; user must call write_if_needed() */
-static char *get_record(void)
-{
- char *p = block + offset;
- memset(p, 0, RECORDSIZE);
- offset += RECORDSIZE;
- return p;
-}
-
-/*
- * The end of tar archives is marked by 1024 nul bytes and after that
- * follows the rest of the block (if any).
- */
-static void write_trailer(void)
-{
- get_record();
- write_if_needed();
- get_record();
- write_if_needed();
- while (offset) {
- get_record();
- write_if_needed();
- }
-}
-
-/*
- * queues up writes, so that all our write(2) calls write exactly one
- * full block; pads writes to RECORDSIZE
- */
-static void write_blocked(void *buf, unsigned long size)
-{
- unsigned long tail;
-
- if (offset) {
- unsigned long chunk = BLOCKSIZE - offset;
- if (size < chunk)
- chunk = size;
- memcpy(block + offset, buf, chunk);
- size -= chunk;
- offset += chunk;
- buf += chunk;
- write_if_needed();
- }
- while (size >= BLOCKSIZE) {
- reliable_write(buf, BLOCKSIZE);
- size -= BLOCKSIZE;
- buf += BLOCKSIZE;
- }
- if (size) {
- memcpy(block + offset, buf, size);
- offset += size;
- }
- tail = offset % RECORDSIZE;
- if (tail) {
- memset(block + offset, 0, RECORDSIZE - tail);
- offset += RECORDSIZE - tail;
- }
- write_if_needed();
-}
-
-static void strbuf_append_string(struct strbuf *sb, const char *s)
-{
- int slen = strlen(s);
- int total = sb->len + slen;
- if (total > sb->alloc) {
- sb->buf = xrealloc(sb->buf, total);
- sb->alloc = total;
- }
- memcpy(sb->buf + sb->len, s, slen);
- sb->len = total;
-}
-
-/*
- * pax extended header records have the format "%u %s=%s\n". %u contains
- * the size of the whole string (including the %u), the first %s is the
- * keyword, the second one is the value. This function constructs such a
- * string and appends it to a struct strbuf.
- */
-static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
- const char *value, unsigned int valuelen)
-{
- char *p;
- int len, total, tmp;
-
- /* "%u %s=%s\n" */
- len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
- for (tmp = len; tmp > 9; tmp /= 10)
- len++;
-
- total = sb->len + len;
- if (total > sb->alloc) {
- sb->buf = xrealloc(sb->buf, total);
- sb->alloc = total;
- }
-
- p = sb->buf;
- p += sprintf(p, "%u %s=", len, keyword);
- memcpy(p, value, valuelen);
- p += valuelen;
- *p = '\n';
- sb->len = total;
-}
-
-static unsigned int ustar_header_chksum(const struct ustar_header *header)
-{
- char *p = (char *)header;
- unsigned int chksum = 0;
- while (p < header->chksum)
- chksum += *p++;
- chksum += sizeof(header->chksum) * ' ';
- p += sizeof(header->chksum);
- while (p < (char *)header + sizeof(struct ustar_header))
- chksum += *p++;
- return chksum;
-}
-
-static int get_path_prefix(const struct strbuf *path, int maxlen)
-{
- int i = path->len;
- if (i > maxlen)
- i = maxlen;
- while (i > 0 && path->buf[i] != '/')
- i--;
- return i;
-}
-
-static void write_entry(const unsigned char *sha1, struct strbuf *path,
- unsigned int mode, void *buffer, unsigned long size)
-{
- struct ustar_header header;
- struct strbuf ext_header;
-
- memset(&header, 0, sizeof(header));
- ext_header.buf = NULL;
- ext_header.len = ext_header.alloc = 0;
-
- if (!sha1) {
- *header.typeflag = TYPEFLAG_GLOBAL_HEADER;
- mode = 0100666;
- strcpy(header.name, "pax_global_header");
- } else if (!path) {
- *header.typeflag = TYPEFLAG_EXT_HEADER;
- mode = 0100666;
- sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
- } else {
- if (S_ISDIR(mode)) {
- *header.typeflag = TYPEFLAG_DIR;
- mode |= 0777;
- } else if (S_ISLNK(mode)) {
- *header.typeflag = TYPEFLAG_LNK;
- mode |= 0777;
- } else if (S_ISREG(mode)) {
- *header.typeflag = TYPEFLAG_REG;
- mode |= (mode & 0100) ? 0777 : 0666;
- } else {
- error("unsupported file mode: 0%o (SHA1: %s)",
- mode, sha1_to_hex(sha1));
- return;
- }
- if (path->len > sizeof(header.name)) {
- int plen = get_path_prefix(path, sizeof(header.prefix));
- int rest = path->len - plen - 1;
- if (plen > 0 && rest <= sizeof(header.name)) {
- memcpy(header.prefix, path->buf, plen);
- memcpy(header.name, path->buf + plen + 1, rest);
- } else {
- sprintf(header.name, "%s.data",
- sha1_to_hex(sha1));
- strbuf_append_ext_header(&ext_header, "path",
- path->buf, path->len);
- }
- } else
- memcpy(header.name, path->buf, path->len);
- }
-
- if (S_ISLNK(mode) && buffer) {
- if (size > sizeof(header.linkname)) {
- sprintf(header.linkname, "see %s.paxheader",
- sha1_to_hex(sha1));
- strbuf_append_ext_header(&ext_header, "linkpath",
- buffer, size);
- } else
- memcpy(header.linkname, buffer, size);
- }
-
- sprintf(header.mode, "%07o", mode & 07777);
- sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
- sprintf(header.mtime, "%011lo", archive_time);
-
- /* XXX: should we provide more meaningful info here? */
- sprintf(header.uid, "%07o", 0);
- sprintf(header.gid, "%07o", 0);
- strncpy(header.uname, "git", 31);
- strncpy(header.gname, "git", 31);
- sprintf(header.devmajor, "%07o", 0);
- sprintf(header.devminor, "%07o", 0);
-
- memcpy(header.magic, "ustar", 6);
- memcpy(header.version, "00", 2);
-
- sprintf(header.chksum, "%07o", ustar_header_chksum(&header));
-
- if (ext_header.len > 0) {
- write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
- free(ext_header.buf);
- }
- write_blocked(&header, sizeof(header));
- if (S_ISREG(mode) && buffer && size > 0)
- write_blocked(buffer, size);
-}
-
-static void write_global_extended_header(const unsigned char *sha1)
-{
- struct strbuf ext_header;
- ext_header.buf = NULL;
- ext_header.len = ext_header.alloc = 0;
- strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
- write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
- free(ext_header.buf);
-}
-
-static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
-{
- int pathlen = path->len;
-
- while (tree->size) {
- const char *name;
- const unsigned char *sha1;
- unsigned mode;
- void *eltbuf;
- char elttype[20];
- unsigned long eltsize;
-
- sha1 = tree_entry_extract(tree, &name, &mode);
- update_tree_entry(tree);
-
- eltbuf = read_sha1_file(sha1, elttype, &eltsize);
- if (!eltbuf)
- die("cannot read %s", sha1_to_hex(sha1));
-
- path->len = pathlen;
- strbuf_append_string(path, name);
- if (S_ISDIR(mode))
- strbuf_append_string(path, "/");
-
- write_entry(sha1, path, mode, eltbuf, eltsize);
-
- if (S_ISDIR(mode)) {
- struct tree_desc subtree;
- subtree.buf = eltbuf;
- subtree.size = eltsize;
- traverse_tree(&subtree, path);
- }
- free(eltbuf);
- }
-}
-
-int main(int argc, char **argv)
-{
- unsigned char sha1[20], tree_sha1[20];
- struct commit *commit;
- struct tree_desc tree;
- struct strbuf current_path;
-
- current_path.buf = xmalloc(PATH_MAX);
- current_path.alloc = PATH_MAX;
- current_path.len = current_path.eof = 0;
-
- setup_git_directory();
- git_config(git_default_config);
-
- switch (argc) {
- case 3:
- strbuf_append_string(¤t_path, argv[2]);
- strbuf_append_string(¤t_path, "/");
- /* FALLTHROUGH */
- case 2:
- if (get_sha1(argv[1], sha1))
- die("Not a valid object name %s", argv[1]);
- break;
- default:
- usage(tar_tree_usage);
- }
-
- commit = lookup_commit_reference_gently(sha1, 1);
- if (commit) {
- write_global_extended_header(commit->object.sha1);
- archive_time = commit->date;
- } else
- archive_time = time(NULL);
-
- tree.buf = read_object_with_reference(sha1, tree_type, &tree.size,
- tree_sha1);
- if (!tree.buf)
- die("not a reference to a tag, commit or tree object: %s",
- sha1_to_hex(sha1));
-
- if (current_path.len > 0)
- write_entry(tree_sha1, ¤t_path, 040777, NULL, 0);
- traverse_tree(&tree, ¤t_path);
- write_trailer();
- free(current_path.buf);
- return 0;
-}
--
1.3.3.g288c
^ permalink raw reply related
* [PATCH 2/8] Builtin git-ls-tree.
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git; +Cc: Peter Eriksen
In-Reply-To: <11483730802025-git-send-email->
From: Peter Eriksen <s022018@student.dtu.dk>
Signed-off-by: Peter Eriksen <s022018@student.dtu.dk>
---
419257801e5bc91fc435bd4ff9eb42aa8063ffbb
Makefile | 6 +-
builtin-ls-tree.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1
git.c | 3 +
ls-tree.c | 155 -----------------------------------------------------
5 files changed, 162 insertions(+), 159 deletions(-)
create mode 100644 builtin-ls-tree.c
delete mode 100644 ls-tree.c
419257801e5bc91fc435bd4ff9eb42aa8063ffbb
diff --git a/Makefile b/Makefile
index e522730..9b02264 100644
--- a/Makefile
+++ b/Makefile
@@ -155,7 +155,7 @@ PROGRAMS = \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
- git-ls-tree$X git-mailinfo$X git-merge-base$X \
+ git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-read-tree$X \
git-receive-pack$X git-rev-parse$X \
@@ -171,7 +171,7 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
- git-init-db$X git-ls-files$X
+ git-init-db$X git-ls-files$X git-ls-tree$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -220,7 +220,7 @@ LIB_OBJS = \
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-init-db.o builtin-ls-files.o
+ builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
new file mode 100644
index 0000000..b515307
--- /dev/null
+++ b/builtin-ls-tree.c
@@ -0,0 +1,156 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#include "cache.h"
+#include "blob.h"
+#include "tree.h"
+#include "quote.h"
+#include "builtin.h"
+
+static int line_termination = '\n';
+#define LS_RECURSIVE 1
+#define LS_TREE_ONLY 2
+#define LS_SHOW_TREES 4
+#define LS_NAME_ONLY 8
+static int abbrev = 0;
+static int ls_options = 0;
+const char **pathspec;
+static int chomp_prefix = 0;
+static const char *prefix;
+
+static const char ls_tree_usage[] =
+ "git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
+
+static int show_recursive(const char *base, int baselen, const char *pathname)
+{
+ const char **s;
+
+ if (ls_options & LS_RECURSIVE)
+ return 1;
+
+ s = pathspec;
+ if (!s)
+ return 0;
+
+ for (;;) {
+ const char *spec = *s++;
+ int len, speclen;
+
+ if (!spec)
+ return 0;
+ if (strncmp(base, spec, baselen))
+ continue;
+ len = strlen(pathname);
+ spec += baselen;
+ speclen = strlen(spec);
+ if (speclen <= len)
+ continue;
+ if (memcmp(pathname, spec, len))
+ continue;
+ return 1;
+ }
+}
+
+static int show_tree(unsigned char *sha1, const char *base, int baselen,
+ const char *pathname, unsigned mode, int stage)
+{
+ int retval = 0;
+ const char *type = blob_type;
+
+ if (S_ISDIR(mode)) {
+ if (show_recursive(base, baselen, pathname)) {
+ retval = READ_TREE_RECURSIVE;
+ if (!(ls_options & LS_SHOW_TREES))
+ return retval;
+ }
+ type = tree_type;
+ }
+ else if (ls_options & LS_TREE_ONLY)
+ return 0;
+
+ if (chomp_prefix &&
+ (baselen < chomp_prefix || memcmp(prefix, base, chomp_prefix)))
+ return 0;
+
+ if (!(ls_options & LS_NAME_ONLY))
+ printf("%06o %s %s\t", mode, type,
+ abbrev ? find_unique_abbrev(sha1,abbrev)
+ : sha1_to_hex(sha1));
+ write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
+ pathname,
+ line_termination, stdout);
+ putchar(line_termination);
+ return retval;
+}
+
+int cmd_ls_tree(int argc, const char **argv, char **envp)
+{
+ unsigned char sha1[20];
+ struct tree *tree;
+
+ prefix = setup_git_directory();
+ git_config(git_default_config);
+ if (prefix && *prefix)
+ chomp_prefix = strlen(prefix);
+ while (1 < argc && argv[1][0] == '-') {
+ switch (argv[1][1]) {
+ case 'z':
+ line_termination = 0;
+ break;
+ case 'r':
+ ls_options |= LS_RECURSIVE;
+ break;
+ case 'd':
+ ls_options |= LS_TREE_ONLY;
+ break;
+ case 't':
+ ls_options |= LS_SHOW_TREES;
+ break;
+ case '-':
+ if (!strcmp(argv[1]+2, "name-only") ||
+ !strcmp(argv[1]+2, "name-status")) {
+ ls_options |= LS_NAME_ONLY;
+ break;
+ }
+ if (!strcmp(argv[1]+2, "full-name")) {
+ chomp_prefix = 0;
+ break;
+ }
+ if (!strncmp(argv[1]+2, "abbrev=",7)) {
+ abbrev = strtoul(argv[1]+9, NULL, 10);
+ if (abbrev && abbrev < MINIMUM_ABBREV)
+ abbrev = MINIMUM_ABBREV;
+ else if (abbrev > 40)
+ abbrev = 40;
+ break;
+ }
+ if (!strcmp(argv[1]+2, "abbrev")) {
+ abbrev = DEFAULT_ABBREV;
+ break;
+ }
+ /* otherwise fallthru */
+ default:
+ usage(ls_tree_usage);
+ }
+ argc--; argv++;
+ }
+ /* -d -r should imply -t, but -d by itself should not have to. */
+ if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
+ ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
+ ls_options |= LS_SHOW_TREES;
+
+ if (argc < 2)
+ usage(ls_tree_usage);
+ if (get_sha1(argv[1], sha1))
+ die("Not a valid object name %s", argv[1]);
+
+ pathspec = get_pathspec(prefix, argv + 2);
+ tree = parse_tree_indirect(sha1);
+ if (!tree)
+ die("not a tree object");
+ read_tree_recursive(tree, "", 0, 0, pathspec, show_tree);
+
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index a0713d3..951f206 100644
--- a/builtin.h
+++ b/builtin.h
@@ -28,5 +28,6 @@ extern int cmd_rev_list(int argc, const
extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
extern int cmd_init_db(int argc, const char **argv, char **envp);
extern int cmd_ls_files(int argc, const char **argv, char **envp);
+extern int cmd_ls_tree(int argc, const char **argv, char **envp);
#endif
diff --git a/git.c b/git.c
index 9cfa9eb..8574775 100644
--- a/git.c
+++ b/git.c
@@ -53,7 +53,8 @@ static void handle_internal_command(int
{ "rev-list", cmd_rev_list },
{ "init-db", cmd_init_db },
{ "check-ref-format", cmd_check_ref_format },
- { "ls-files", cmd_ls_files }
+ { "ls-files", cmd_ls_files },
+ { "ls-tree", cmd_ls_tree }
};
int i;
diff --git a/ls-tree.c b/ls-tree.c
deleted file mode 100644
index f2b3bc1..0000000
--- a/ls-tree.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * GIT - The information manager from hell
- *
- * Copyright (C) Linus Torvalds, 2005
- */
-#include "cache.h"
-#include "blob.h"
-#include "tree.h"
-#include "quote.h"
-
-static int line_termination = '\n';
-#define LS_RECURSIVE 1
-#define LS_TREE_ONLY 2
-#define LS_SHOW_TREES 4
-#define LS_NAME_ONLY 8
-static int abbrev = 0;
-static int ls_options = 0;
-const char **pathspec;
-static int chomp_prefix = 0;
-static const char *prefix;
-
-static const char ls_tree_usage[] =
- "git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
-
-static int show_recursive(const char *base, int baselen, const char *pathname)
-{
- const char **s;
-
- if (ls_options & LS_RECURSIVE)
- return 1;
-
- s = pathspec;
- if (!s)
- return 0;
-
- for (;;) {
- const char *spec = *s++;
- int len, speclen;
-
- if (!spec)
- return 0;
- if (strncmp(base, spec, baselen))
- continue;
- len = strlen(pathname);
- spec += baselen;
- speclen = strlen(spec);
- if (speclen <= len)
- continue;
- if (memcmp(pathname, spec, len))
- continue;
- return 1;
- }
-}
-
-static int show_tree(unsigned char *sha1, const char *base, int baselen,
- const char *pathname, unsigned mode, int stage)
-{
- int retval = 0;
- const char *type = blob_type;
-
- if (S_ISDIR(mode)) {
- if (show_recursive(base, baselen, pathname)) {
- retval = READ_TREE_RECURSIVE;
- if (!(ls_options & LS_SHOW_TREES))
- return retval;
- }
- type = tree_type;
- }
- else if (ls_options & LS_TREE_ONLY)
- return 0;
-
- if (chomp_prefix &&
- (baselen < chomp_prefix || memcmp(prefix, base, chomp_prefix)))
- return 0;
-
- if (!(ls_options & LS_NAME_ONLY))
- printf("%06o %s %s\t", mode, type,
- abbrev ? find_unique_abbrev(sha1,abbrev)
- : sha1_to_hex(sha1));
- write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
- pathname,
- line_termination, stdout);
- putchar(line_termination);
- return retval;
-}
-
-int main(int argc, const char **argv)
-{
- unsigned char sha1[20];
- struct tree *tree;
-
- prefix = setup_git_directory();
- git_config(git_default_config);
- if (prefix && *prefix)
- chomp_prefix = strlen(prefix);
- while (1 < argc && argv[1][0] == '-') {
- switch (argv[1][1]) {
- case 'z':
- line_termination = 0;
- break;
- case 'r':
- ls_options |= LS_RECURSIVE;
- break;
- case 'd':
- ls_options |= LS_TREE_ONLY;
- break;
- case 't':
- ls_options |= LS_SHOW_TREES;
- break;
- case '-':
- if (!strcmp(argv[1]+2, "name-only") ||
- !strcmp(argv[1]+2, "name-status")) {
- ls_options |= LS_NAME_ONLY;
- break;
- }
- if (!strcmp(argv[1]+2, "full-name")) {
- chomp_prefix = 0;
- break;
- }
- if (!strncmp(argv[1]+2, "abbrev=",7)) {
- abbrev = strtoul(argv[1]+9, NULL, 10);
- if (abbrev && abbrev < MINIMUM_ABBREV)
- abbrev = MINIMUM_ABBREV;
- else if (abbrev > 40)
- abbrev = 40;
- break;
- }
- if (!strcmp(argv[1]+2, "abbrev")) {
- abbrev = DEFAULT_ABBREV;
- break;
- }
- /* otherwise fallthru */
- default:
- usage(ls_tree_usage);
- }
- argc--; argv++;
- }
- /* -d -r should imply -t, but -d by itself should not have to. */
- if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
- ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
- ls_options |= LS_SHOW_TREES;
-
- if (argc < 2)
- usage(ls_tree_usage);
- if (get_sha1(argv[1], sha1))
- die("Not a valid object name %s", argv[1]);
-
- pathspec = get_pathspec(prefix, argv + 2);
- tree = parse_tree_indirect(sha1);
- if (!tree)
- die("not a tree object");
- read_tree_recursive(tree, "", 0, 0, pathspec, show_tree);
-
- return 0;
-}
--
1.3.3.g288c
^ permalink raw reply related
* Make more commands builtin
From: Peter Eriksen @ 2006-05-23 8:31 UTC (permalink / raw)
To: git
Makefile | 26 +++++++++++++++-----------
apply.c => builtin-apply.c | 3 ++-
commit-tree.c => builtin-commit-tree.c | 3 ++-
diff-files.c => builtin-diff-files.c | 3 ++-
diff-index.c => builtin-diff-index.c | 3 ++-
diff-stages.c => builtin-diff-stages.c | 3 ++-
diff-tree.c => builtin-diff-tree.c | 3 ++-
ls-files.c => builtin-ls-files.c | 3 ++-
ls-tree.c => builtin-ls-tree.c | 3 ++-
read-tree.c => builtin-read-tree.c | 3 ++-
show-branch.c => builtin-show-branch.c | 3 ++-
tar-tree.c => builtin-tar-tree.c | 3 ++-
builtin.h | 12 ++++++++++++
git.c | 13 ++++++++++++-
I've tried to follow the trend of making commands builtin.
All patches have the same form. This is my second use
of git-send-email, so this might come out wrong.
Peter Eriksen <s022018@student.dtu.dk>
^ 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