* [PATCH] git-send-email: Change the prompt for the subject of the initial message.
From: Benoit Sigoure @ 2007-11-08 18:56 UTC (permalink / raw)
To: git; +Cc: gitster, Benoit Sigoure
I never understood what this prompt was asking for until I read the actual
source code. I think this wording is much more understandable.
Signed-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>
---
git-send-email.perl | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/git-send-email.perl b/git-send-email.perl
index f4b8f96..f9bd2e5 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -352,7 +352,7 @@ sub expand_aliases {
if (!defined $initial_subject && $compose) {
do {
- $_ = $term->readline("What subject should the emails start with? ",
+ $_ = $term->readline("What subject should the initial email start with? ",
$initial_subject);
} while (!defined $_);
$initial_subject = $_;
--
1.5.3.4.398.g859b
^ permalink raw reply related
* Re: git rebase --skip
From: Daniel Barkalow @ 2007-11-08 18:43 UTC (permalink / raw)
To: Björn Steinbrink; +Cc: Jeff King, Mike Hommey, git
In-Reply-To: <20071108102412.GA31187@atjola.homenet>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1662 bytes --]
On Thu, 8 Nov 2007, Björn Steinbrink wrote:
> On 2007.11.07 22:23:10 -0500, Jeff King wrote:
> > On Wed, Nov 07, 2007 at 11:21:05PM +0100, Mike Hommey wrote:
> >
> > > I use git-rebase quite regularly, and I haven't used git-rebase --skip
> > > after a failed merge without first resetting the working tree. I was
> > > wondering if it wouldn't make sense to automatically do the reset when
> > > running git-rebase --skip.
> >
> > I have often been annoyed by this behavior, too, and I can't think of
> > any situation where you _wouldn't_ want the reset to happen. But I
> > would be more comfortable hearing confirmation from others that they
> > can't think of such a situation.
>
> Let's take this history:
>
> C---D---E topic
> /
> A---B master
>
> You then do:
> git rebase master topic
>
> Now D causes conflicts, because B did a similar change, but not quite
> the same, maybe having a bug. So you want to keep parts of D, but it's
> no longer the same commit semantically and the original commit message
> would be bogus. So you resolve the conflicts and do:
>
> git commit
> git rebase --skip
I guess that works, and nothing else presently does. But I don't think
that's at all intuitive as the correct thing to do (plus it feels too easy
to get into losing your commit message). Maybe we should have a "git
rebase --amend", which does the obvious thing (acts like --continue, but
lets you edit the message). It's not like you just did something totally
different; the commit is still the replacement for D, it's just less the
same.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH v2] user-manual: add advanced topic "bisecting merges"
From: Brian Gernhardt @ 2007-11-08 18:38 UTC (permalink / raw)
To: Benoit Sigoure
Cc: Steffen Prohaska, Johannes Sixt, Andreas Ericsson,
Ralf Wildenhues, Git Mailing List
In-Reply-To: <5498B368-053A-424E-B901-A55B66FF5801@lrde.epita.fr>
On Nov 8, 2007, at 9:51 AM, Benoit Sigoure wrote:
> You're missing the point. Johannes suggested that you rebase *only*
> for bisecting purpose. Once you find the culprit commit, throw away
> your rebased stuff. I've never thought about doing this myself, but
> it's a very clever way of tackling this problem. It's slightly less
> convenient if you need to bisect a large portion of the history
> (that involves many branches and merges) because in this case we'd
> like to have a magic git-linearize-history <start-treeish> <end-
> treeish>. Unless this is already easily doable with git-rebase?
I don't think you have to linearize it before bisecting. If you
bisect and discover that it was due to a merge, then you can rebase
*that merge* to discover what part of the merge caused the issue.
~~ Brian
^ permalink raw reply
* Re: [PATCH] rebase: operate on a detached HEAD
From: Nicolas Pitre @ 2007-11-08 18:28 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git, Junio C Hamano
In-Reply-To: <Pine.LNX.4.64.0711081818330.4362@racer.site>
On Thu, 8 Nov 2007, Johannes Schindelin wrote:
>
> The interactive version of rebase does all the operations on a detached
> HEAD, so that after a successful rebase, <branch>@{1} is the pre-rebase
> state. The reflogs of "HEAD" still show all the actions in detail.
>
> This teaches the non-interactive version to do the same.
I like this.
Nicolas
^ permalink raw reply
* Re: Inconsistencies with git log
From: Daniel Barkalow @ 2007-11-08 18:28 UTC (permalink / raw)
To: Jon Smirl; +Cc: Johannes Schindelin, Git Mailing List
In-Reply-To: <9e4733910711071529m604f3b12v29b3a040074ea4e@mail.gmail.com>
On Wed, 7 Nov 2007, Jon Smirl wrote:
> On 11/7/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > Hi,
> >
> > On Wed, 7 Nov 2007, Jon Smirl wrote:
> >
> > > On 11/7/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > >
> > > > We also tend to take the approach of viewing the history as that of
> > > > the whole project.
> > >
> > > But if you type 'git log' while cd'd into a subdirectory the whole log
> > > is almost never what you want. It's this kind of thing that makes git
> > > harder to use.
> >
> > When I am working in a subdirectory, I often want the whole history. For
> > example, when I am working on the documentation, sometimes I need to look
> > up a commit real quick, that touched other parts.
> >
> > Besides, adding a space and a dot is not what qualifies for "harder to
> > use" with this developer.
>
> So if git log is always whole tree, why doesn't this work?
>
> cd arch/powerpc/platforms/52xx
> git log arch/powerpc/platforms/52xx
> fatal: ambiguous argument 'arch/powerpc/platforms/52xx': unknown
> revision or path not in the working tree.
> Use '--' to separate paths from revisions
>
> It's not consistent. git log with no parameters is relative to the
> project root, git log with a parameter is relative to the current
> directory.
git log with no parameters is still relative to the current directory.
It's just not limited by paths at all, so what it's relative to doesn't
matter.
Since it shows is commits that change any of the given paths, the
perfectly consistant thing to do without any paths would be to show no
commits. Of course, that's totally useless, so we default to making no
limitation instead.
If there were any other options that took paths or filenames, they'd be
relative to the subdirectory, regardless of whether there were any paths,
and having no paths would still show history for the project without
regard to whether commits touch paths.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* [PATCH] rebase: operate on a detached HEAD
From: Johannes Schindelin @ 2007-11-08 18:19 UTC (permalink / raw)
To: git, gitster
The interactive version of rebase does all the operations on a detached
HEAD, so that after a successful rebase, <branch>@{1} is the pre-rebase
state. The reflogs of "HEAD" still show all the actions in detail.
This teaches the non-interactive version to do the same.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
git-rebase.sh | 56 ++++++++++++++++++++++++++++++++++++++++++----
t/t3402-rebase-merge.sh | 7 +++++-
2 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/git-rebase.sh b/git-rebase.sh
index 8814be9..3684a31 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -88,7 +88,7 @@ call_merge () {
cmt="$(cat "$dotest/cmt.$1")"
echo "$cmt" > "$dotest/current"
hd=$(git rev-parse --verify HEAD)
- cmt_name=$(git symbolic-ref HEAD)
+ cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
msgnum=$(cat "$dotest/msgnum")
end=$(cat "$dotest/end")
eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -116,7 +116,24 @@ call_merge () {
esac
}
+move_to_original_branch () {
+ test -z "$head_name" &&
+ head_name="$(cat "$dotest"/head-name)" &&
+ onto="$(cat "$dotest"/onto)" &&
+ orig_head="$(cat "$dotest"/orig-head)"
+ case "$head_name" in
+ refs/*)
+ message="rebase finished: $head_name onto $onto"
+ git update-ref -m "$message" \
+ $head_name $(git rev-parse HEAD) $orig_head &&
+ git symbolic-ref HEAD $head_name ||
+ die "Could not move back to $head_name"
+ ;;
+ esac
+}
+
finish_rb_merge () {
+ move_to_original_branch
rm -r "$dotest"
echo "All done."
}
@@ -175,16 +192,23 @@ do
finish_rb_merge
exit
fi
- git am -3 --skip --resolvemsg="$RESOLVEMSG"
+ head_name=$(cat .dotest/head-name) &&
+ onto=$(cat .dotest/onto) &&
+ orig_head=$(cat .dotest/orig-head) &&
+ git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
+ move_to_original_branch
exit
;;
--abort)
git rerere clear
if test -d "$dotest"
then
+ move_to_original_branch
rm -r "$dotest"
elif test -d .dotest
then
+ dotest=.dotest
+ move_to_original_branch
rm -r .dotest
else
die "No rebase in progress?"
@@ -320,6 +344,19 @@ then
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
fi
+# move to a detached HEAD
+orig_head=$(git rev-parse HEAD^0)
+head_name=$(git symbolic-ref HEAD 2> /dev/null)
+case "$head_name" in
+'')
+ head_name="detached HEAD"
+ ;;
+*)
+ git checkout "$orig_head" > /dev/null 2>&1 ||
+ die "could not detach HEAD"
+ ;;
+esac
+
# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
echo "First, rewinding head to replay your work on top of it..."
git-reset --hard "$onto"
@@ -329,14 +366,21 @@ git-reset --hard "$onto"
if test "$mb" = "$branch"
then
echo >&2 "Fast-forwarded $branch_name to $onto_name."
+ move_to_original_branch
exit 0
fi
if test -z "$do_merge"
then
git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
- git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG"
- exit $?
+ git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG" &&
+ move_to_original_branch
+ ret=$?
+ test 0 != $ret -a -d .dotest &&
+ echo $head_name > .dotest/head-name &&
+ echo $onto > .dotest/onto &&
+ echo $orig_head > .dotest/orig-head
+ exit $ret
fi
# start doing a rebase with git-merge
@@ -345,8 +389,10 @@ fi
mkdir -p "$dotest"
echo "$onto" > "$dotest/onto"
echo "$onto_name" > "$dotest/onto_name"
-prev_head=`git rev-parse HEAD^0`
+prev_head=$orig_head
echo "$prev_head" > "$dotest/prev_head"
+echo "$orig_head" > "$dotest/orig-head"
+echo "$head_name" > "$dotest/head-name"
msgnum=0
for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index 0779aaa..7b7d072 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -48,9 +48,14 @@ test_expect_success 'reference merge' '
git merge -s recursive "reference merge" HEAD master
'
+PRE_REBASE=$(git rev-parse test-rebase)
test_expect_success rebase '
git checkout test-rebase &&
- git rebase --merge master
+ GIT_TRACE=1 git rebase --merge master
+'
+
+test_expect_success 'test-rebase@{1} is pre rebase' '
+ test $PRE_REBASE = $(git rev-parse test-rebase@{1})
'
test_expect_success 'merge and rebase should match' '
--
1.5.3.5.1634.g0fa78
^ permalink raw reply related
* [PATCH 3/4] git-push: plumb in --mirror mode
From: Andy Whitcroft @ 2007-11-08 17:01 UTC (permalink / raw)
To: git
In-Reply-To: <20071108165801.GM9736@shadowen.org>
Plumb in the --mirror mode for git-push.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
builtin-push.c | 14 ++++++++++++--
transport.c | 7 +++++++
transport.h | 1 +
3 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/builtin-push.c b/builtin-push.c
index 2c56195..d49157c 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const push_usage[] = {
- "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
+ "git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
NULL,
};
@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
{
int flags = 0;
int all = 0;
+ int mirror = 0;
int dry_run = 0;
int force = 0;
int tags = 0;
@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT__VERBOSE(&verbose),
OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
OPT_BOOLEAN( 0 , "all", &all, "push all refs"),
+ OPT_BOOLEAN( 0 , "mirror", &mirror, "mirror all refs"),
OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
OPT_BOOLEAN( 0 , "dry-run", &dry_run, "dry run"),
OPT_BOOLEAN('f', "force", &force, "force updates"),
@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)
add_refspec("refs/tags/*");
if (all)
flags |= TRANSPORT_PUSH_ALL;
+ if (mirror)
+ flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
if (argc > 0) {
repo = argv[0];
set_refspecs(argv + 1, argc - 1);
}
- if ((flags & TRANSPORT_PUSH_ALL) && refspec)
+ if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec)
usage_with_options(push_usage, options);
+ if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
+ (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
+ error("--all and --mirror are incompatible");
+ usage_with_options(push_usage, options);
+ }
+
return do_push(repo, flags);
}
diff --git a/transport.c b/transport.c
index f4577b7..08e62b1 100644
--- a/transport.c
+++ b/transport.c
@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,
struct child_process rsync;
const char *args[10];
+ if (flags & TRANSPORT_PUSH_MIRROR)
+ return error("rsync transport does not support mirror mode");
+
/* first push the objects */
strbuf_addstr(&buf, transport->url);
@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
int argc;
int err;
+ if (flags & TRANSPORT_PUSH_MIRROR)
+ return error("http transport does not support mirror mode");
+
argv = xmalloc((refspec_nr + 11) * sizeof(char *));
argv[0] = "http-push";
argc = 1;
@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
args.receivepack = data->receivepack;
args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
+ args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
args.use_thin_pack = data->thin;
args.verbose = transport->verbose;
diff --git a/transport.h b/transport.h
index d27f562..7f337d2 100644
--- a/transport.h
+++ b/transport.h
@@ -30,6 +30,7 @@ struct transport {
#define TRANSPORT_PUSH_ALL 1
#define TRANSPORT_PUSH_FORCE 2
#define TRANSPORT_PUSH_DRY_RUN 4
+#define TRANSPORT_PUSH_MIRROR 8
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
^ permalink raw reply related
* [PATCH 4/4] tests: git push mirror mode tests
From: Andy Whitcroft @ 2007-11-08 17:01 UTC (permalink / raw)
To: git
In-Reply-To: <20071108165801.GM9736@shadowen.org>
Add some basic tests for git push --mirror mode.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
t/t5517-push-mirror.sh | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 101 insertions(+), 0 deletions(-)
diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh
new file mode 100755
index 0000000..1a285d4
--- /dev/null
+++ b/t/t5517-push-mirror.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+test_description='pushing to a mirror repository'
+
+. ./test-lib.sh
+
+D=`pwd`
+
+mk_repo_pair () {
+ rm -rf master mirror &&
+ mkdir mirror && cd mirror &&
+ git init &&
+ cd .. &&
+ mkdir master && cd master &&
+ git init &&
+ git config remote.up.url ../mirror &&
+ cd ..
+}
+
+test_expect_success 'push mirror does not create new branches' '
+
+ mk_repo_pair &&
+ cd master &&
+ echo one >foo && git add foo && git commit -m one &&
+ master_master=$(git show-ref -s --verify refs/heads/master) &&
+ git push --mirror up &&
+ cd ../mirror &&
+ mirror_master=$(git show-ref -s --verify refs/heads/master) &&
+ test "$master_master" = "$mirror_master"
+
+'
+
+test_expect_success 'push mirror does not update existing branches' '
+
+ mk_repo_pair &&
+ cd master &&
+ echo one >foo && git add foo && git commit -m one &&
+ git push --mirror up &&
+ echo two >foo && git add foo && git commit -m two &&
+ master_master=$(git show-ref -s --verify refs/heads/master) &&
+ git push --mirror up &&
+ cd ../mirror &&
+ mirror_master=$(git show-ref -s --verify refs/heads/master) &&
+ test "$master_master" = "$mirror_master"
+
+'
+
+test_expect_success 'push mirror does not force update existing branches' '
+
+ mk_repo_pair &&
+ cd master &&
+ echo one >foo && git add foo && git commit -m one &&
+ git push --mirror up &&
+ echo two >foo && git add foo && git commit -m two &&
+ git push --mirror up &&
+ git reset --hard HEAD^
+ master_master=$(git show-ref -s --verify refs/heads/master) &&
+ git push --mirror up &&
+ cd ../mirror &&
+ mirror_master=$(git show-ref -s --verify refs/heads/master) &&
+ test "$master_master" = "$mirror_master"
+
+'
+
+test_expect_failure 'push mirror does not remove branches' '
+
+ mk_repo_pair &&
+ cd master &&
+ echo one >foo && git add foo && git commit -m one &&
+ git branch remove master &&
+ git push --mirror up &&
+ git branch -D remove
+ git push --mirror up &&
+ cd ../mirror &&
+ git show-ref -s --verify refs/heads/remove
+
+'
+
+test_expect_success 'push mirror does not add, update and remove together' '
+
+ mk_repo_pair &&
+ cd master &&
+ echo one >foo && git add foo && git commit -m one &&
+ git branch remove master &&
+ git push --mirror up &&
+ git branch -D remove &&
+ git branch add master &&
+ echo two >foo && git add foo && git commit -m two &&
+ master_master=$(git show-ref -s --verify refs/heads/master) &&
+ master_add=$(git show-ref -s --verify refs/heads/add) &&
+ git push --mirror up &&
+ cd ../mirror &&
+ mirror_master=$(git show-ref -s --verify refs/heads/master) &&
+ mirror_add=$(git show-ref -s --verify refs/heads/add) &&
+ test "$master_master" = "$mirror_master" &&
+ test "$master_add" = "$mirror_add" &&
+ ! git show-ref -s --verify refs/heads/remove
+
+'
+
+test_done
^ permalink raw reply related
* [PATCH 2/4] mirror pushing -- clean up match_refs flags
From: Andy Whitcroft @ 2007-11-08 17:01 UTC (permalink / raw)
To: git
In-Reply-To: <20071108165801.GM9736@shadowen.org>
Add a new enum to define the match_refs flags field and switch
all callers to it.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
builtin-send-pack.c | 8 +++++++-
http-push.c | 4 ++--
remote.c | 4 ++--
remote.h | 7 +++++++
4 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index d5ead97..d42164e 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -227,6 +227,12 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
int allow_deleting_refs = 0;
int expect_status_report = 0;
int shown_dest = 0;
+ int flags = MATCH_REFS_NONE;
+
+ if (args.send_all)
+ flags |= MATCH_REFS_ALL;
+ if (args.send_mirror)
+ flags |= MATCH_REFS_MIRROR;
/* No funny business with the matcher */
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
@@ -242,7 +248,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))
+ nr_refspec, refspec, flags))
return -1;
if (!remote_refs) {
diff --git a/http-push.c b/http-push.c
index 99328f5..66b81f1 100644
--- a/http-push.c
+++ b/http-push.c
@@ -78,7 +78,7 @@ static struct curl_slist *no_pragma_header;
static struct curl_slist *default_headers;
static int push_verbosely;
-static int push_all;
+static int push_all = MATCH_REFS_NONE;
static int force_all;
static int dry_run;
@@ -2300,7 +2300,7 @@ int main(int argc, char **argv)
if (*arg == '-') {
if (!strcmp(arg, "--all")) {
- push_all = 1;
+ push_all = MATCH_REFS_ALL;
continue;
}
if (!strcmp(arg, "--force")) {
diff --git a/remote.c b/remote.c
index 45dd59b..09b7aad 100644
--- a/remote.c
+++ b/remote.c
@@ -726,8 +726,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
{
struct refspec *rs =
parse_ref_spec(nr_refspec, (const char **) refspec);
- int send_all = flags & 01;
- int send_mirror = flags & 02;
+ int send_all = flags & MATCH_REFS_ALL;
+ int send_mirror = flags & MATCH_REFS_MIRROR;
if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
return -1;
diff --git a/remote.h b/remote.h
index 6a4c7a0..b10036c 100644
--- a/remote.h
+++ b/remote.h
@@ -102,4 +102,11 @@ struct branch *branch_get(const char *name);
int branch_has_merge_config(struct branch *branch);
int branch_merge_matches(struct branch *, int n, const char *);
+/* Flags to match_refs. */
+enum match_refs_flags {
+ MATCH_REFS_NONE = 0,
+ MATCH_REFS_ALL = (1 << 0),
+ MATCH_REFS_MIRROR = (1 << 1),
+};
+
#endif
^ permalink raw reply related
* [PATCH 1/4] mirror pushing
From: Andy Whitcroft @ 2007-11-08 17:00 UTC (permalink / raw)
To: git
In-Reply-To: <20071108165801.GM9736@shadowen.org>
From: Junio C Hamano <gitster@pobox.com>
Existing "git push --all" is almost perfect for backing up to
another repository, except that "--all" only means "all
branches" in modern git, and it does not delete old branches and
tags that exist at the back-up repository that you have removed
from your local repository.
This teaches "git-send-pack" a new "--mirror" option. The
difference from the "--all" option are that (1) it sends all
refs, not just branches, and (2) it deletes old refs you no
longer have on the local side from the remote side.
[apw@shadowen.org: rebase to next post arguments update]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
builtin-send-pack.c | 40 ++++++++++++++++++++++++++++------------
remote.c | 15 ++++++++++-----
send-pack.h | 1 +
3 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 5a0f5c6..d5ead97 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -8,7 +8,7 @@
#include "send-pack.h"
static const char send_pack_usage[] =
-"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
+"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive.";
static struct send_pack_args args = {
@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspec, refspec, args.send_all))
+ nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))
return -1;
if (!remote_refs) {
@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
char old_hex[60], *new_hex;
int will_delete_ref;
const char *pretty_ref;
- const char *pretty_peer;
+ const char *pretty_peer = NULL; /* only used when not deleting */
+ const unsigned char *new_sha1;
- if (!ref->peer_ref)
- continue;
+ if (!ref->peer_ref) {
+ if (!args.send_mirror)
+ continue;
+ new_sha1 = null_sha1;
+ }
+ else
+ new_sha1 = ref->peer_ref->new_sha1;
if (!shown_dest) {
fprintf(stderr, "To %s\n", dest);
shown_dest = 1;
}
+ will_delete_ref = is_null_sha1(new_sha1);
+
pretty_ref = prettify_ref(ref->name);
- pretty_peer = prettify_ref(ref->peer_ref->name);
+ if (!will_delete_ref)
+ pretty_peer = prettify_ref(ref->peer_ref->name);
- will_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);
if (will_delete_ref && !allow_deleting_refs) {
fprintf(stderr, " ! %-*s %s (remote does not support deleting refs)\n",
SUMMARY_WIDTH, "[rejected]", pretty_ref);
@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
continue;
}
if (!will_delete_ref &&
- !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
+ !hashcmp(ref->old_sha1, new_sha1)) {
if (args.verbose)
fprintf(stderr, " = %-*s %s -> %s\n",
SUMMARY_WIDTH, "[up to date]",
@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
!is_null_sha1(ref->old_sha1) &&
!ref->force) {
if (!has_sha1_file(ref->old_sha1) ||
- !ref_newer(ref->peer_ref->new_sha1,
- ref->old_sha1)) {
+ !ref_newer(new_sha1, ref->old_sha1)) {
/* We do not have the remote ref, or
* we know that the remote ref is not
* an ancestor of what we are trying to
@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
continue;
}
}
- hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
+ hashcpy(ref->new_sha1, new_sha1);
if (!will_delete_ref)
new_refs++;
strcpy(old_hex, sha1_to_hex(ref->old_sha1));
@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.dry_run = 1;
continue;
}
+ if (!strcmp(arg, "--mirror")) {
+ args.send_mirror = 1;
+ continue;
+ }
if (!strcmp(arg, "--force")) {
args.force_update = 1;
continue;
@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
}
if (!dest)
usage(send_pack_usage);
- if (heads && args.send_all)
+ /*
+ * --all and --mirror are incompatible; neither makes sense
+ * with any refspecs.
+ */
+ if ((heads && (args.send_all || args.send_mirror)) ||
+ (args.send_all && args.send_mirror))
usage(send_pack_usage);
if (remote_name) {
diff --git a/remote.c b/remote.c
index 59defdb..45dd59b 100644
--- a/remote.c
+++ b/remote.c
@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
* without thinking.
*/
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, const char **refspec, int all)
+ int nr_refspec, const char **refspec, int flags)
{
struct refspec *rs =
parse_ref_spec(nr_refspec, (const char **) refspec);
+ int send_all = flags & 01;
+ int send_mirror = flags & 02;
if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
return -1;
@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
if (!pat)
continue;
}
- else if (prefixcmp(src->name, "refs/heads/"))
+ else if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
/*
* "matching refs"; traditionally we pushed everything
* including refs outside refs/heads/ hierarchy, but
@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
if (dst_peer && dst_peer->peer_ref)
/* We're already sending something to this ref. */
goto free_name;
- if (!dst_peer && !nr_refspec && !all)
- /* Remote doesn't have it, and we have no
+
+ if (!dst_peer && !nr_refspec && !(send_all || send_mirror))
+ /*
+ * Remote doesn't have it, and we have no
* explicit pattern, and we don't have
- * --all. */
+ * --all nor --mirror.
+ */
goto free_name;
if (!dst_peer) {
/* Create a new one and link it */
diff --git a/send-pack.h b/send-pack.h
index 7a24f71..8ff1dc3 100644
--- a/send-pack.h
+++ b/send-pack.h
@@ -5,6 +5,7 @@ struct send_pack_args {
const char *receivepack;
unsigned verbose:1,
send_all:1,
+ send_mirror:1,
force_update:1,
use_thin_pack:1,
dry_run:1;
^ permalink raw reply related
* git push mirror mode V3
From: Andy Whitcroft @ 2007-11-08 16:58 UTC (permalink / raw)
To: git
In-Reply-To: <20071108121136.GG9736@shadowen.org>
Ok, here is an update based on feedback from the list. I bit the bullet
and added some basic tests. The stack passes the test suite. Hopefully
the attribution is ok on the first patch now. I have kept my
modifications to it a separate patch for the time being to keep
attribution simple.
-apw
^ permalink raw reply
* [PATCH] SubmittingPatches: improve the 'Patch:' section of the checklist
From: Sergei Organov @ 2007-11-08 16:40 UTC (permalink / raw)
To: git; +Cc: gitster
There were 2 items "send patch to..." but having different set of
addresses to send patch to. Merge them together and move the resulting
item to the end of checklist.
Signed-off-by: Sergei Organov <osv@javad.com>
---
Documentation/SubmittingPatches | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 61635bf..83bf54c 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -20,9 +20,6 @@ Checklist (and a short version for the impatient):
Patch:
- use "git format-patch -M" to create the patch
- - send your patch to <git@vger.kernel.org>. If you use
- git-send-email(1), please test it first by sending
- email to yourself.
- do not PGP sign your patch
- do not attach your patch, but read in the mail
body, unless you cannot teach your mailer to
@@ -31,13 +28,15 @@ Checklist (and a short version for the impatient):
corrupt whitespaces.
- provide additional information (which is unsuitable for
the commit message) between the "---" and the diffstat
- - send the patch to the list (git@vger.kernel.org) and the
- maintainer (gitster@pobox.com).
- if you change, add, or remove a command line option or
make some other user interface change, the associated
documentation should be updated as well.
- if your name is not writable in ASCII, make sure that
you send off a message in the correct encoding.
+ - send the patch to the list (git@vger.kernel.org) and the
+ maintainer (gitster@pobox.com). If you use
+ git-send-email(1), please test it first by sending
+ email to yourself.
Long version:
--
1.5.3.5.529.ge3d6d
^ permalink raw reply related
* [PATCH] Port git commit to C.
From: Kristian Høgsberg @ 2007-11-08 16:59 UTC (permalink / raw)
To: gitster; +Cc: git, Kristian Høgsberg
This makes git commit a builtin and moves git-commit.sh to
contrib/examples. This also removes the git-runstatus
helper, which was mostly just a git-status.sh implementation detail.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
This has Johannes' updates and Bjoerns command line parsing fixes.
Also fixes the author date problem on amend commits, so this replaces
Johannes' recent [PATCH 3/3] author fix.
cheers,
Kristian
Makefile | 9 +-
builtin-commit.c | 615 +++++++++++++++++++++++++++++++++++++++
builtin.h | 3 +-
contrib/examples/git-commit.sh | 628 ++++++++++++++++++++++++++++++++++++++++
git-commit.sh | 628 ----------------------------------------
git.c | 3 +-
strbuf.h | 1 +
7 files changed, 1251 insertions(+), 636 deletions(-)
create mode 100644 builtin-commit.c
create mode 100755 contrib/examples/git-commit.sh
delete mode 100755 git-commit.sh
diff --git a/Makefile b/Makefile
index 3ec1876..e4c51c6 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ BASIC_LDFLAGS =
SCRIPT_SH = \
git-bisect.sh git-checkout.sh \
- git-clean.sh git-clone.sh git-commit.sh \
+ git-clean.sh git-clone.sh \
git-ls-remote.sh \
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
@@ -256,7 +256,7 @@ EXTRA_PROGRAMS =
BUILT_INS = \
git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
git-get-tar-commit-id$X git-init$X git-repo-config$X \
- git-fsck-objects$X git-cherry-pick$X \
+ git-fsck-objects$X git-cherry-pick$X git-status$X\
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
# what 'all' will build and 'install' will install, in gitexecdir
@@ -326,6 +326,7 @@ BUILTIN_OBJS = \
builtin-check-attr.o \
builtin-checkout-index.o \
builtin-check-ref-format.o \
+ builtin-commit.o \
builtin-commit-tree.o \
builtin-count-objects.o \
builtin-describe.o \
@@ -366,7 +367,6 @@ BUILTIN_OBJS = \
builtin-rev-parse.o \
builtin-revert.o \
builtin-rm.o \
- builtin-runstatus.o \
builtin-shortlog.o \
builtin-show-branch.o \
builtin-stripspace.o \
@@ -832,9 +832,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
chmod +x $@+ && \
mv $@+ $@
-git-status: git-commit
- $(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
gitweb/gitweb.cgi: gitweb/gitweb.perl
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..ae4ca4e
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,615 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include "git-compat-util.h"
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+#include "strbuf.h"
+#include "utf8.h"
+#include "parse-options.h"
+
+static const char * const builtin_commit_usage[] = {
+ "git-commit [options] [--] <filepattern>...",
+ NULL
+};
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static char *use_message_buffer;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+static char *logfile, *force_author, *message, *template_file;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, amend, signoff;
+static int quiet, verbose, untracked_files, no_verify;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option builtin_commit_options[] = {
+ OPT__QUIET(&quiet),
+ OPT__VERBOSE(&verbose),
+ OPT_GROUP("Commit message options"),
+
+ OPT_STRING('F', "file", &logfile, "FILE", "read log from file"),
+ OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
+ OPT_STRING('m', "message", &message, "MESSAGE", "specify commit message"),
+ OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
+ OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
+ OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"),
+ OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"),
+ OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
+
+ OPT_GROUP("Commit contents options"),
+ OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
+ OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
+ OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
+ OPT_BOOLEAN('o', "only", &only, ""),
+ OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
+ OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
+ OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"),
+
+ OPT_END()
+};
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+ int fd;
+ struct tree *tree;
+ struct lock_file *next_index_lock;
+
+ if (interactive) {
+ interactive_add();
+ return get_index_file();
+ }
+
+ fd = hold_locked_index(&lock_file, 1);
+ if (read_cache() < 0)
+ die("index file corrupt");
+
+ if (all || also) {
+ add_files_to_cache(verbose, also ? prefix : NULL, files);
+ if (write_cache(fd, active_cache, active_nr) || close(fd))
+ die("unable to write new_index file");
+ return lock_file.filename;
+ }
+
+ if (*files == NULL) {
+ /* Commit index as-is. */
+ rollback_lock_file(&lock_file);
+ return get_index_file();
+ }
+
+ /* update the user index file */
+ add_files_to_cache(verbose, prefix, files);
+ if (write_cache(fd, active_cache, active_nr) || close(fd))
+ die("unable to write new_index file");
+
+ if (!initial_commit) {
+ tree = parse_tree_indirect(head_sha1);
+ if (!tree)
+ die("failed to unpack HEAD tree object");
+ if (read_tree(tree, 0, NULL))
+ die("failed to read HEAD tree object");
+ }
+
+ /* Use a lock file to garbage collect the temporary index file. */
+ next_index_lock = xmalloc(sizeof(*next_index_lock));
+ fd = hold_lock_file_for_update(next_index_lock,
+ git_path("next-index-%d", getpid()), 1);
+ add_files_to_cache(verbose, prefix, files);
+ if (write_cache(fd, active_cache, active_nr) || close(fd))
+ die("unable to write new_index file");
+
+ return next_index_lock->filename;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+ struct wt_status s;
+
+ wt_status_prepare(&s);
+
+ if (amend) {
+ s.amend = 1;
+ s.reference = "HEAD^1";
+ }
+ s.verbose = verbose;
+ s.untracked = untracked_files;
+ s.index_file = index_file;
+ s.fp = fp;
+
+ wt_status_print(&s);
+
+ return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+ struct stat statbuf;
+ int commitable;
+ struct strbuf sb;
+ char *buffer;
+ FILE *fp;
+
+ strbuf_init(&sb, 0);
+ if (message) {
+ strbuf_add(&sb, message, strlen(message));
+ } else if (logfile && !strcmp(logfile, "-")) {
+ if (isatty(0))
+ fprintf(stderr, "(reading log message from standard input)\n");
+ if (strbuf_read(&sb, 0, 0) < 0)
+ die("could not read log from standard input");
+ } else if (logfile) {
+ if (strbuf_read_file(&sb, logfile, 0) < 0)
+ die("could not read log file '%s': %s",
+ logfile, strerror(errno));
+ } else if (use_message) {
+ buffer = strstr(use_message_buffer, "\n\n");
+ if (!buffer || buffer[2] == '\0')
+ die("commit has empty message");
+ strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+ } else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
+ die("could not read MERGE_MSG: %s", strerror(errno));
+ } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
+ die("could not read SQUASH_MSG: %s", strerror(errno));
+ } else if (template_file && !stat(template_file, &statbuf)) {
+ if (strbuf_read_file(&sb, template_file, 0) < 0)
+ die("could not read %s: %s",
+ template_file, strerror(errno));
+ }
+
+ fp = fopen(git_path(commit_editmsg), "w");
+ if (fp == NULL)
+ die("could not open %s\n", git_path(commit_editmsg));
+
+ stripspace(&sb, 0);
+ if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+ die("could not write commit template: %s\n",
+ strerror(errno));
+
+ if (signoff) {
+ const char *info, *bol;
+
+ info = git_committer_info(1);
+ strbuf_addch(&sb, '\0');
+ bol = strrchr(sb.buf + sb.len - 1, '\n');
+ if (!bol || prefixcmp(bol, sign_off_header))
+ fprintf(fp, "\n");
+ fprintf(fp, "%s%s\n", sign_off_header, git_committer_info(1));
+ }
+
+ strbuf_release(&sb);
+
+ if (in_merge && !no_edit) {
+ fprintf(fp,
+ "#\n"
+ "# It looks like you may be committing a MERGE.\n"
+ "# If this is not correct, please remove the file\n"
+ "# %s\n"
+ "# and try again.\n"
+ "#\n",
+ git_path("MERGE_HEAD"));
+ }
+
+ fprintf(fp,
+ "\n"
+ "# Please enter the commit message for your changes.\n"
+ "# (Comment lines starting with '#' will not be included)\n");
+ if (only_include_assumed)
+ fprintf(fp, "# %s\n", only_include_assumed);
+
+ commitable = run_status(fp, index_file);
+
+ fclose(fp);
+
+ return commitable;
+}
+
+/* Find out if the message starting at position 'start' in the strbuf
+ * contains only whitespace and Signed-off-by lines. */
+static int message_is_empty(struct strbuf *sb, int start)
+{
+ struct strbuf tmpl;
+ const char *nl;
+ int eol, i;
+
+ /* See if the template is just a prefix of the message. */
+ strbuf_init(&tmpl, 0);
+ if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
+ stripspace(&tmpl, 1);
+ if (start + tmpl.len <= sb->len &&
+ memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
+ start += tmpl.len;
+ strbuf_release(&tmpl);
+ }
+
+ /* Check if the rest is just whitespace and Signed-of-by's. */
+ for (i = start; i < sb->len; i++) {
+ nl = memchr(sb->buf + i, '\n', sb->len - i);
+ if (nl)
+ eol = nl - sb->buf;
+ else
+ eol = sb->len;
+
+ if (strlen(sign_off_header) <= eol - i &&
+ !prefixcmp(sb->buf + i, sign_off_header)) {
+ i = eol;
+ continue;
+ }
+ while (i < eol)
+ if (!isspace(sb->buf[i++]))
+ return 0;
+ }
+
+ return 1;
+}
+
+static void determine_author_info(struct strbuf *sb)
+{
+ char *name, *email, *date;
+
+ name = getenv("GIT_AUTHOR_NAME");
+ email = getenv("GIT_AUTHOR_EMAIL");
+ date = getenv("GIT_AUTHOR_DATE");
+
+ if (use_message) {
+ const char *a, *lb, *rb, *eol;
+
+ a = strstr(use_message_buffer, "\nauthor ");
+ if (!a)
+ die("invalid commit: %s\n", use_message);
+
+ lb = strstr(a + 8, " <");
+ rb = strstr(a + 8, "> ");
+ eol = strchr(a + 8, '\n');
+ if (!lb || !rb || !eol)
+ die("invalid commit: %s\n", use_message);
+
+ name = xstrndup(a + 8, lb - (a + 8));
+ email = xstrndup(lb + 2, rb - (lb + 2));
+ date = xstrndup(rb + 2, eol - (rb + 2));
+ }
+
+ if (force_author) {
+ const char *lb = strstr(force_author, " <");
+ const char *rb = strchr(force_author, '>');
+
+ if (!lb || !rb)
+ die("malformed --author parameter\n");
+ name = xstrndup(force_author, lb - force_author);
+ email = xstrndup(lb + 2, rb - (lb + 2));
+ }
+
+ strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, 1));
+}
+
+static int parse_and_validate_options(int argc, const char *argv[])
+{
+ int f = 0;
+
+ argc = parse_options(argc, argv, builtin_commit_options,
+ builtin_commit_usage, 0);
+
+ if (logfile || message || use_message)
+ no_edit = 1;
+ if (edit_flag)
+ no_edit = 0;
+
+ if (get_sha1("HEAD", head_sha1))
+ initial_commit = 1;
+
+ if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+ in_merge = 1;
+
+ /* Sanity check options */
+ if (amend && initial_commit)
+ die("You have nothing to amend.");
+ if (amend && in_merge)
+ die("You are in the middle of a merger -- cannot amend.");
+
+ if (use_message)
+ f++;
+ if (edit_message)
+ f++;
+ if (logfile)
+ f++;
+ if (f > 1)
+ die("Only one of -c/-C/-F can be used.");
+ if (message && f > 0)
+ die("Option -m cannot be combined with -c/-C/-F.");
+ if (edit_message)
+ use_message = edit_message;
+ if (amend)
+ use_message = "HEAD";
+ if (use_message) {
+ unsigned char sha1[20];
+ static char utf8[] = "UTF-8";
+ const char *out_enc;
+ char *enc, *end;
+ struct commit *commit;
+
+ if (get_sha1(use_message, sha1))
+ die("could not lookup commit %s", use_message);
+ commit = lookup_commit(sha1);
+ if (!commit || parse_commit(commit))
+ die("could not parse commit %s", use_message);
+
+ enc = strstr(commit->buffer, "\nencoding");
+ if (enc) {
+ end = strchr(enc + 10, '\n');
+ enc = xstrndup(enc + 10, end - (enc + 10));
+ } else {
+ enc = utf8;
+ }
+ out_enc = git_commit_encoding ? git_commit_encoding : utf8;
+
+ if (strcmp(out_enc, enc))
+ use_message_buffer =
+ reencode_string(commit->buffer, out_enc, enc);
+
+ /* If we failed to reencode the buffer, just copy it
+ * byte for byte so the user can try to fix it up.
+ * This also handles the case where input and output
+ * encodings are identical. */
+ if (use_message_buffer == NULL)
+ use_message_buffer = xstrdup(commit->buffer);
+ if (enc != utf8)
+ free(enc);
+ }
+
+ if (!!also + !!only + !!all + !!interactive > 1)
+ die("Only one of --include/--only/--all/--interactive can be used.");
+ if (argc == 0 && (also || (only && !amend)))
+ die("No paths with --include/--only does not make sense.");
+ if (argc == 0 && only && amend)
+ only_include_assumed = "Clever... amending the last one with dirty index.";
+ if (argc > 0 && !also && !only) {
+ only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+ also = 0;
+ }
+
+ if (all && argc > 0)
+ die("Paths with -a does not make sense.");
+ else if (interactive && argc > 0)
+ die("Paths with --interactive does not make sense.");
+
+ return argc;
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+ const char *index_file;
+ int commitable;
+
+ git_config(git_status_config);
+
+ argc = parse_and_validate_options(argc, argv);
+
+ index_file = prepare_index(argv, prefix);
+
+ commitable = run_status(stdout, index_file);
+
+ rollback_lock_file(&lock_file);
+
+ return commitable ? 0 : 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+ struct child_process hook;
+ const char *argv[3], *env[2];
+ char index[PATH_MAX];
+
+ argv[0] = git_path("hooks/%s", name);
+ argv[1] = arg;
+ argv[2] = NULL;
+ snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+ env[0] = index;
+ env[1] = NULL;
+
+ if (access(argv[0], X_OK) < 0)
+ return 0;
+
+ memset(&hook, 0, sizeof(hook));
+ hook.argv = argv;
+ hook.no_stdin = 1;
+ hook.stdout_to_stderr = 1;
+ hook.env = env;
+
+ return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+ struct rev_info rev;
+ struct commit *commit;
+
+ commit = lookup_commit(sha1);
+ if (!commit)
+ die("couldn't look up newly created commit\n");
+ if (!commit || parse_commit(commit))
+ die("could not parse newly created commit");
+
+ init_revisions(&rev, prefix);
+ setup_revisions(0, NULL, &rev, NULL);
+
+ rev.abbrev = 0;
+ rev.diff = 1;
+ rev.diffopt.output_format =
+ DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+ rev.verbose_header = 1;
+ rev.show_root_diff = 1;
+ rev.commit_format = get_commit_format("format:%h: %s");
+ rev.always_show_header = 1;
+
+ printf("Created %scommit ", initial_commit ? "initial " : "");
+
+ log_tree_commit(&rev, commit);
+}
+
+int git_commit_config(const char *k, const char *v)
+{
+ if (!strcmp(k, "commit.template")) {
+ template_file = xstrdup(v);
+ return 0;
+ }
+
+ return git_status_config(k, v);
+}
+
+static const char commit_utf8_warn[] =
+"Warning: commit message does not conform to UTF-8.\n"
+"You may want to amend it after fixing the message, or set the config\n"
+"variable i18n.commitencoding to the encoding your project uses.\n";
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+ int header_len, parent_count = 0;
+ struct strbuf sb;
+ const char *index_file, *reflog_msg;
+ char *nl, *header_line;
+ unsigned char commit_sha1[20];
+ struct ref_lock *ref_lock;
+
+ git_config(git_commit_config);
+
+ argc = parse_and_validate_options(argc, argv);
+
+ index_file = prepare_index(argv, prefix);
+
+ if (!no_verify && run_hook(index_file, "pre-commit", NULL))
+ exit(1);
+
+ if (!prepare_log_message(index_file) && !in_merge) {
+ run_status(stdout, index_file);
+ unlink(commit_editmsg);
+ return 1;
+ }
+
+ strbuf_init(&sb, 0);
+
+ /* Start building up the commit header */
+ read_cache_from(index_file);
+ active_cache_tree = cache_tree();
+ if (cache_tree_update(active_cache_tree,
+ active_cache, active_nr, 0, 0) < 0)
+ die("Error building trees");
+ strbuf_addf(&sb, "tree %s\n",
+ sha1_to_hex(active_cache_tree->sha1));
+
+ /* Determine parents */
+ if (initial_commit) {
+ reflog_msg = "commit (initial)";
+ parent_count = 0;
+ } else if (amend) {
+ struct commit_list *c;
+ struct commit *commit;
+
+ reflog_msg = "commit (amend)";
+ commit = lookup_commit(head_sha1);
+ if (!commit || parse_commit(commit))
+ die("could not parse HEAD commit");
+
+ for (c = commit->parents; c; c = c->next)
+ strbuf_addf(&sb, "parent %s\n",
+ sha1_to_hex(c->item->object.sha1));
+ } else if (in_merge) {
+ struct strbuf m;
+ FILE *fp;
+
+ reflog_msg = "commit (merge)";
+ strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+ strbuf_init(&m, 0);
+ fp = fopen(git_path("MERGE_HEAD"), "r");
+ if (fp == NULL)
+ die("could not open %s for reading: %s",
+ git_path("MERGE_HEAD"), strerror(errno));
+ while (strbuf_getline(&m, fp, '\n') != EOF)
+ strbuf_addf(&sb, "parent %s\n", m.buf);
+ fclose(fp);
+ strbuf_release(&m);
+ } else {
+ reflog_msg = "commit";
+ strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+ }
+
+ determine_author_info(&sb);
+ strbuf_addf(&sb, "committer %s\n", git_committer_info(1));
+ if (!is_encoding_utf8(git_commit_encoding))
+ strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
+ strbuf_addch(&sb, '\n');
+
+ /* Get the commit message and validate it */
+ header_len = sb.len;
+ if (!no_edit) {
+ fprintf(stderr, "launching editor, log %s\n", logfile);
+ launch_editor(git_path(commit_editmsg), &sb);
+ }
+ else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0)
+ die("could not read commit message\n");
+ if (run_hook(index_file, "commit-msg", commit_editmsg))
+ exit(1);
+ stripspace(&sb, 1);
+ if (sb.len < header_len ||
+ message_is_empty(&sb, header_len))
+ die("* no commit message? aborting commit.");
+ strbuf_addch(&sb, '\0');
+ if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
+ fprintf(stderr, commit_utf8_warn);
+
+ if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))
+ die("failed to write commit object");
+
+ ref_lock = lock_any_ref_for_update("HEAD",
+ initial_commit ? NULL : head_sha1,
+ 0);
+
+ nl = strchr(sb.buf + header_len, '\n');
+ header_line = xstrndup(sb.buf + header_len,
+ nl - (sb.buf + header_len));
+ strbuf_release(&sb);
+ strbuf_addf(&sb, "%s: %s\n", reflog_msg, header_line);
+ strbuf_addch(&sb, '\0');
+ free(header_line);
+
+ if (!ref_lock)
+ die("cannot lock HEAD ref");
+ if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0)
+ die("cannot update HEAD ref");
+
+ unlink(git_path("MERGE_HEAD"));
+ unlink(git_path("MERGE_MSG"));
+
+ if (lock_file.filename[0] && commit_locked_index(&lock_file))
+ die("failed to write new index");
+
+ rerere();
+
+ run_hook(index_file, "post-commit", NULL);
+
+ if (!quiet)
+ print_summary(prefix, commit_sha1);
+
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index 2335c01..3d2de27 100644
--- a/builtin.h
+++ b/builtin.h
@@ -24,6 +24,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
extern int cmd_cherry(int argc, const char **argv, const char *prefix);
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -69,11 +70,11 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
extern int cmd_revert(int argc, const char **argv, const char *prefix);
extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
extern int cmd_send_pack(int argc, const char **argv, const char *prefix);
extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
extern int cmd_show(int argc, const char **argv, const char *prefix);
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
extern int cmd_tag(int argc, const char **argv, const char *prefix);
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
new file mode 100755
index 0000000..fcb8443
--- /dev/null
+++ b/contrib/examples/git-commit.sh
@@ -0,0 +1,628 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+# Copyright (c) 2006 Junio C Hamano
+
+USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+
+case "$0" in
+*status)
+ status_only=t
+ ;;
+*commit)
+ status_only=
+ ;;
+esac
+
+refuse_partial () {
+ echo >&2 "$1"
+ echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
+ exit 1
+}
+
+TMP_INDEX=
+THIS_INDEX="$GIT_DIR/index"
+NEXT_INDEX="$GIT_DIR/next-index$$"
+rm -f "$NEXT_INDEX"
+save_index () {
+ cp -p "$THIS_INDEX" "$NEXT_INDEX"
+}
+
+run_status () {
+ # If TMP_INDEX is defined, that means we are doing
+ # "--only" partial commit, and that index file is used
+ # to build the tree for the commit. Otherwise, if
+ # NEXT_INDEX exists, that is the index file used to
+ # make the commit. Otherwise we are using as-is commit
+ # so the regular index file is what we use to compare.
+ if test '' != "$TMP_INDEX"
+ then
+ GIT_INDEX_FILE="$TMP_INDEX"
+ export GIT_INDEX_FILE
+ elif test -f "$NEXT_INDEX"
+ then
+ GIT_INDEX_FILE="$NEXT_INDEX"
+ export GIT_INDEX_FILE
+ fi
+
+ if test "$status_only" = "t" -o "$use_status_color" = "t"; then
+ color=
+ else
+ color=--nocolor
+ fi
+ git runstatus ${color} \
+ ${verbose:+--verbose} \
+ ${amend:+--amend} \
+ ${untracked_files:+--untracked}
+}
+
+trap '
+ test -z "$TMP_INDEX" || {
+ test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
+ }
+ rm -f "$NEXT_INDEX"
+' 0
+
+################################################################
+# Command line argument parsing and sanity checking
+
+all=
+also=
+interactive=
+only=
+logfile=
+use_commit=
+amend=
+edit_flag=
+no_edit=
+log_given=
+log_message=
+verify=t
+quiet=
+verbose=
+signoff=
+force_author=
+only_include_assumed=
+untracked_files=
+templatefile="`git config commit.template`"
+while test $# != 0
+do
+ case "$1" in
+ -F|--F|-f|--f|--fi|--fil|--file)
+ case "$#" in 1) usage ;; esac
+ shift
+ no_edit=t
+ log_given=t$log_given
+ logfile="$1"
+ ;;
+ -F*|-f*)
+ no_edit=t
+ log_given=t$log_given
+ logfile="${1#-[Ff]}"
+ ;;
+ --F=*|--f=*|--fi=*|--fil=*|--file=*)
+ no_edit=t
+ log_given=t$log_given
+ logfile="${1#*=}"
+ ;;
+ -a|--a|--al|--all)
+ all=t
+ ;;
+ --au=*|--aut=*|--auth=*|--autho=*|--author=*)
+ force_author="${1#*=}"
+ ;;
+ --au|--aut|--auth|--autho|--author)
+ case "$#" in 1) usage ;; esac
+ shift
+ force_author="$1"
+ ;;
+ -e|--e|--ed|--edi|--edit)
+ edit_flag=t
+ ;;
+ -i|--i|--in|--inc|--incl|--inclu|--includ|--include)
+ also=t
+ ;;
+ --int|--inte|--inter|--intera|--interac|--interact|--interacti|\
+ --interactiv|--interactive)
+ interactive=t
+ ;;
+ -o|--o|--on|--onl|--only)
+ only=t
+ ;;
+ -m|--m|--me|--mes|--mess|--messa|--messag|--message)
+ case "$#" in 1) usage ;; esac
+ shift
+ log_given=m$log_given
+ log_message="${log_message:+${log_message}
+
+}$1"
+ no_edit=t
+ ;;
+ -m*)
+ log_given=m$log_given
+ log_message="${log_message:+${log_message}
+
+}${1#-m}"
+ no_edit=t
+ ;;
+ --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+ log_given=m$log_given
+ log_message="${log_message:+${log_message}
+
+}${1#*=}"
+ no_edit=t
+ ;;
+ -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
+ --no-verify)
+ verify=
+ ;;
+ --a|--am|--ame|--amen|--amend)
+ amend=t
+ use_commit=HEAD
+ ;;
+ -c)
+ case "$#" in 1) usage ;; esac
+ shift
+ log_given=t$log_given
+ use_commit="$1"
+ no_edit=
+ ;;
+ --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
+ --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
+ --reedit-messag=*|--reedit-message=*)
+ log_given=t$log_given
+ use_commit="${1#*=}"
+ no_edit=
+ ;;
+ --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
+ --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
+ --reedit-message)
+ case "$#" in 1) usage ;; esac
+ shift
+ log_given=t$log_given
+ use_commit="$1"
+ no_edit=
+ ;;
+ -C)
+ case "$#" in 1) usage ;; esac
+ shift
+ log_given=t$log_given
+ use_commit="$1"
+ no_edit=t
+ ;;
+ --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
+ --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
+ --reuse-message=*)
+ log_given=t$log_given
+ use_commit="${1#*=}"
+ no_edit=t
+ ;;
+ --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
+ --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
+ case "$#" in 1) usage ;; esac
+ shift
+ log_given=t$log_given
+ use_commit="$1"
+ no_edit=t
+ ;;
+ -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
+ signoff=t
+ ;;
+ -t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
+ case "$#" in 1) usage ;; esac
+ shift
+ templatefile="$1"
+ no_edit=
+ ;;
+ -q|--q|--qu|--qui|--quie|--quiet)
+ quiet=t
+ ;;
+ -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+ verbose=t
+ ;;
+ -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
+ --untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
+ --untracked-file|--untracked-files)
+ untracked_files=t
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+case "$edit_flag" in t) no_edit= ;; esac
+
+################################################################
+# Sanity check options
+
+case "$amend,$initial_commit" in
+t,t)
+ die "You do not have anything to amend." ;;
+t,)
+ if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+ die "You are in the middle of a merge -- cannot amend."
+ fi ;;
+esac
+
+case "$log_given" in
+tt*)
+ die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+ die "Option -m cannot be combined with -c/-C/-F." ;;
+esac
+
+case "$#,$also,$only,$amend" in
+*,t,t,*)
+ die "Only one of --include/--only can be used." ;;
+0,t,,* | 0,,t,)
+ die "No paths with --include/--only does not make sense." ;;
+0,,t,t)
+ only_include_assumed="# Clever... amending the last one with dirty index." ;;
+0,,,*)
+ ;;
+*,,,*)
+ only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
+ also=
+ ;;
+esac
+unset only
+case "$all,$interactive,$also,$#" in
+*t,*t,*)
+ die "Cannot use -a, --interactive or -i at the same time." ;;
+t,,[1-9]*)
+ die "Paths with -a does not make sense." ;;
+,t,[1-9]*)
+ die "Paths with --interactive does not make sense." ;;
+,,t,0)
+ die "No paths with -i does not make sense." ;;
+esac
+
+if test ! -z "$templatefile" -a -z "$log_given"
+then
+ if test ! -f "$templatefile"
+ then
+ die "Commit template file does not exist."
+ fi
+fi
+
+################################################################
+# Prepare index to have a tree to be committed
+
+case "$all,$also" in
+t,)
+ if test ! -f "$THIS_INDEX"
+ then
+ die 'nothing to commit (use "git add file1 file2" to include for commit)'
+ fi
+ save_index &&
+ (
+ cd_to_toplevel &&
+ GIT_INDEX_FILE="$NEXT_INDEX" &&
+ export GIT_INDEX_FILE &&
+ git diff-files --name-only -z |
+ git update-index --remove -z --stdin
+ ) || exit
+ ;;
+,t)
+ save_index &&
+ git ls-files --error-unmatch -- "$@" >/dev/null || exit
+
+ git diff-files --name-only -z -- "$@" |
+ (
+ cd_to_toplevel &&
+ GIT_INDEX_FILE="$NEXT_INDEX" &&
+ export GIT_INDEX_FILE &&
+ git update-index --remove -z --stdin
+ ) || exit
+ ;;
+,)
+ if test "$interactive" = t; then
+ git add --interactive || exit
+ fi
+ case "$#" in
+ 0)
+ ;; # commit as-is
+ *)
+ if test -f "$GIT_DIR/MERGE_HEAD"
+ then
+ refuse_partial "Cannot do a partial commit during a merge."
+ fi
+
+ TMP_INDEX="$GIT_DIR/tmp-index$$"
+ W=
+ test -z "$initial_commit" && W=--with-tree=HEAD
+ commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
+
+ # Build a temporary index and update the real index
+ # the same way.
+ if test -z "$initial_commit"
+ then
+ GIT_INDEX_FILE="$THIS_INDEX" \
+ git read-tree --index-output="$TMP_INDEX" -i -m HEAD
+ else
+ rm -f "$TMP_INDEX"
+ fi || exit
+
+ printf '%s\n' "$commit_only" |
+ GIT_INDEX_FILE="$TMP_INDEX" \
+ git update-index --add --remove --stdin &&
+
+ save_index &&
+ printf '%s\n' "$commit_only" |
+ (
+ GIT_INDEX_FILE="$NEXT_INDEX"
+ export GIT_INDEX_FILE
+ git update-index --add --remove --stdin
+ ) || exit
+ ;;
+ esac
+ ;;
+esac
+
+################################################################
+# If we do as-is commit, the index file will be THIS_INDEX,
+# otherwise NEXT_INDEX after we make this commit. We leave
+# the index as is if we abort.
+
+if test -f "$NEXT_INDEX"
+then
+ USE_INDEX="$NEXT_INDEX"
+else
+ USE_INDEX="$THIS_INDEX"
+fi
+
+case "$status_only" in
+t)
+ # This will silently fail in a read-only repository, which is
+ # what we want.
+ GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
+ run_status
+ exit $?
+ ;;
+'')
+ GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
+ ;;
+esac
+
+################################################################
+# Grab commit message, write out tree and make commit.
+
+if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
+then
+ GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
+ || exit
+fi
+
+if test "$log_message" != ''
+then
+ printf '%s\n' "$log_message"
+elif test "$logfile" != ""
+then
+ if test "$logfile" = -
+ then
+ test -t 0 &&
+ echo >&2 "(reading log message from standard input)"
+ cat
+ else
+ cat <"$logfile"
+ fi
+elif test "$use_commit" != ""
+then
+ encoding=$(git config i18n.commitencoding || echo UTF-8)
+ git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
+ sed -e '1,/^$/d' -e 's/^ //'
+elif test -f "$GIT_DIR/MERGE_MSG"
+then
+ cat "$GIT_DIR/MERGE_MSG"
+elif test -f "$GIT_DIR/SQUASH_MSG"
+then
+ cat "$GIT_DIR/SQUASH_MSG"
+elif test "$templatefile" != ""
+then
+ cat "$templatefile"
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+
+case "$signoff" in
+t)
+ sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+ s/>.*/>/
+ s/^/Signed-off-by: /
+ ')
+ blank_before_signoff=
+ tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+ grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+ tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+ grep "$sign"$ >/dev/null ||
+ printf '%s%s\n' "$blank_before_signoff" "$sign" \
+ >>"$GIT_DIR"/COMMIT_EDITMSG
+ ;;
+esac
+
+if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
+ echo "#"
+ echo "# It looks like you may be committing a MERGE."
+ echo "# If this is not correct, please remove the file"
+ printf '%s\n' "# $GIT_DIR/MERGE_HEAD"
+ echo "# and try again"
+ echo "#"
+fi >>"$GIT_DIR"/COMMIT_EDITMSG
+
+# Author
+if test '' != "$use_commit"
+then
+ eval "$(get_author_ident_from_commit "$use_commit")"
+ export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+fi
+if test '' != "$force_author"
+then
+ GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+ GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
+ test '' != "$GIT_AUTHOR_NAME" &&
+ test '' != "$GIT_AUTHOR_EMAIL" ||
+ die "malformed --author parameter"
+ export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+fi
+
+PARENTS="-p HEAD"
+if test -z "$initial_commit"
+then
+ rloga='commit'
+ if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+ rloga='commit (merge)'
+ PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
+ elif test -n "$amend"; then
+ rloga='commit (amend)'
+ PARENTS=$(git cat-file commit HEAD |
+ sed -n -e '/^$/q' -e 's/^parent /-p /p')
+ fi
+ current="$(git rev-parse --verify HEAD)"
+else
+ if [ -z "$(git ls-files)" ]; then
+ echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
+ exit 1
+ fi
+ PARENTS=""
+ rloga='commit (initial)'
+ current=''
+fi
+set_reflog_action "$rloga"
+
+if test -z "$no_edit"
+then
+ {
+ echo ""
+ echo "# Please enter the commit message for your changes."
+ echo "# (Comment lines starting with '#' will not be included)"
+ test -z "$only_include_assumed" || echo "$only_include_assumed"
+ run_status
+ } >>"$GIT_DIR"/COMMIT_EDITMSG
+else
+ # we need to check if there is anything to commit
+ run_status >/dev/null
+fi
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
+then
+ rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+ use_status_color=t
+ run_status
+ exit 1
+fi
+
+case "$no_edit" in
+'')
+ git-var GIT_AUTHOR_IDENT > /dev/null || die
+ git-var GIT_COMMITTER_IDENT > /dev/null || die
+ git_editor "$GIT_DIR/COMMIT_EDITMSG"
+ ;;
+esac
+
+case "$verify" in
+t)
+ if test -x "$GIT_DIR"/hooks/commit-msg
+ then
+ "$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
+ fi
+esac
+
+if test -z "$no_edit"
+then
+ sed -e '
+ /^diff --git a\/.*/{
+ s///
+ q
+ }
+ /^#/d
+ ' "$GIT_DIR"/COMMIT_EDITMSG
+else
+ cat "$GIT_DIR"/COMMIT_EDITMSG
+fi |
+git stripspace >"$GIT_DIR"/COMMIT_MSG
+
+# Test whether the commit message has any content we didn't supply.
+have_commitmsg=
+grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
+ git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
+
+# Is the commit message totally empty?
+if test -s "$GIT_DIR"/COMMIT_BAREMSG
+then
+ if test "$templatefile" != ""
+ then
+ # Test whether this is just the unaltered template.
+ if cnt=`sed -e '/^#/d' < "$templatefile" |
+ git stripspace |
+ diff "$GIT_DIR"/COMMIT_BAREMSG - |
+ wc -l` &&
+ test 0 -lt $cnt
+ then
+ have_commitmsg=t
+ fi
+ else
+ # No template, so the content in the commit message must
+ # have come from the user.
+ have_commitmsg=t
+ fi
+fi
+
+rm -f "$GIT_DIR"/COMMIT_BAREMSG
+
+if test "$have_commitmsg" = "t"
+then
+ if test -z "$TMP_INDEX"
+ then
+ tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
+ else
+ tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
+ rm -f "$TMP_INDEX"
+ fi &&
+ commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
+ rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
+ git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+ rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
+ if test -f "$NEXT_INDEX"
+ then
+ mv "$NEXT_INDEX" "$THIS_INDEX"
+ else
+ : ;# happy
+ fi
+else
+ echo >&2 "* no commit message? aborting commit."
+ false
+fi
+ret="$?"
+rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+
+cd_to_toplevel
+
+git rerere
+
+if test "$ret" = 0
+then
+ git gc --auto
+ if test -x "$GIT_DIR"/hooks/post-commit
+ then
+ "$GIT_DIR"/hooks/post-commit
+ fi
+ if test -z "$quiet"
+ then
+ commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
+ --summary --root HEAD --`
+ echo "Created${initial_commit:+ initial} commit $commit"
+ fi
+fi
+
+exit "$ret"
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index fcb8443..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,628 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
- status_only=t
- ;;
-*commit)
- status_only=
- ;;
-esac
-
-refuse_partial () {
- echo >&2 "$1"
- echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
- exit 1
-}
-
-TMP_INDEX=
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
- cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
- # If TMP_INDEX is defined, that means we are doing
- # "--only" partial commit, and that index file is used
- # to build the tree for the commit. Otherwise, if
- # NEXT_INDEX exists, that is the index file used to
- # make the commit. Otherwise we are using as-is commit
- # so the regular index file is what we use to compare.
- if test '' != "$TMP_INDEX"
- then
- GIT_INDEX_FILE="$TMP_INDEX"
- export GIT_INDEX_FILE
- elif test -f "$NEXT_INDEX"
- then
- GIT_INDEX_FILE="$NEXT_INDEX"
- export GIT_INDEX_FILE
- fi
-
- if test "$status_only" = "t" -o "$use_status_color" = "t"; then
- color=
- else
- color=--nocolor
- fi
- git runstatus ${color} \
- ${verbose:+--verbose} \
- ${amend:+--amend} \
- ${untracked_files:+--untracked}
-}
-
-trap '
- test -z "$TMP_INDEX" || {
- test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
- }
- rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-templatefile="`git config commit.template`"
-while test $# != 0
-do
- case "$1" in
- -F|--F|-f|--f|--fi|--fil|--file)
- case "$#" in 1) usage ;; esac
- shift
- no_edit=t
- log_given=t$log_given
- logfile="$1"
- ;;
- -F*|-f*)
- no_edit=t
- log_given=t$log_given
- logfile="${1#-[Ff]}"
- ;;
- --F=*|--f=*|--fi=*|--fil=*|--file=*)
- no_edit=t
- log_given=t$log_given
- logfile="${1#*=}"
- ;;
- -a|--a|--al|--all)
- all=t
- ;;
- --au=*|--aut=*|--auth=*|--autho=*|--author=*)
- force_author="${1#*=}"
- ;;
- --au|--aut|--auth|--autho|--author)
- case "$#" in 1) usage ;; esac
- shift
- force_author="$1"
- ;;
- -e|--e|--ed|--edi|--edit)
- edit_flag=t
- ;;
- -i|--i|--in|--inc|--incl|--inclu|--includ|--include)
- also=t
- ;;
- --int|--inte|--inter|--intera|--interac|--interact|--interacti|\
- --interactiv|--interactive)
- interactive=t
- ;;
- -o|--o|--on|--onl|--only)
- only=t
- ;;
- -m|--m|--me|--mes|--mess|--messa|--messag|--message)
- case "$#" in 1) usage ;; esac
- shift
- log_given=m$log_given
- log_message="${log_message:+${log_message}
-
-}$1"
- no_edit=t
- ;;
- -m*)
- log_given=m$log_given
- log_message="${log_message:+${log_message}
-
-}${1#-m}"
- no_edit=t
- ;;
- --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
- log_given=m$log_given
- log_message="${log_message:+${log_message}
-
-}${1#*=}"
- no_edit=t
- ;;
- -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
- --no-verify)
- verify=
- ;;
- --a|--am|--ame|--amen|--amend)
- amend=t
- use_commit=HEAD
- ;;
- -c)
- case "$#" in 1) usage ;; esac
- shift
- log_given=t$log_given
- use_commit="$1"
- no_edit=
- ;;
- --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
- --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
- --reedit-messag=*|--reedit-message=*)
- log_given=t$log_given
- use_commit="${1#*=}"
- no_edit=
- ;;
- --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
- --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
- --reedit-message)
- case "$#" in 1) usage ;; esac
- shift
- log_given=t$log_given
- use_commit="$1"
- no_edit=
- ;;
- -C)
- case "$#" in 1) usage ;; esac
- shift
- log_given=t$log_given
- use_commit="$1"
- no_edit=t
- ;;
- --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
- --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
- --reuse-message=*)
- log_given=t$log_given
- use_commit="${1#*=}"
- no_edit=t
- ;;
- --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
- --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
- case "$#" in 1) usage ;; esac
- shift
- log_given=t$log_given
- use_commit="$1"
- no_edit=t
- ;;
- -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
- signoff=t
- ;;
- -t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
- case "$#" in 1) usage ;; esac
- shift
- templatefile="$1"
- no_edit=
- ;;
- -q|--q|--qu|--qui|--quie|--quiet)
- quiet=t
- ;;
- -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
- verbose=t
- ;;
- -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
- --untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
- --untracked-file|--untracked-files)
- untracked_files=t
- ;;
- --)
- shift
- break
- ;;
- -*)
- usage
- ;;
- *)
- break
- ;;
- esac
- shift
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
- die "You do not have anything to amend." ;;
-t,)
- if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
- die "You are in the middle of a merge -- cannot amend."
- fi ;;
-esac
-
-case "$log_given" in
-tt*)
- die "Only one of -c/-C/-F can be used." ;;
-*tm*|*mt*)
- die "Option -m cannot be combined with -c/-C/-F." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
- die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
- die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
- only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
- ;;
-*,,,*)
- only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
- also=
- ;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
- die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
- die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
- die "Paths with --interactive does not make sense." ;;
-,,t,0)
- die "No paths with -i does not make sense." ;;
-esac
-
-if test ! -z "$templatefile" -a -z "$log_given"
-then
- if test ! -f "$templatefile"
- then
- die "Commit template file does not exist."
- fi
-fi
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
- if test ! -f "$THIS_INDEX"
- then
- die 'nothing to commit (use "git add file1 file2" to include for commit)'
- fi
- save_index &&
- (
- cd_to_toplevel &&
- GIT_INDEX_FILE="$NEXT_INDEX" &&
- export GIT_INDEX_FILE &&
- git diff-files --name-only -z |
- git update-index --remove -z --stdin
- ) || exit
- ;;
-,t)
- save_index &&
- git ls-files --error-unmatch -- "$@" >/dev/null || exit
-
- git diff-files --name-only -z -- "$@" |
- (
- cd_to_toplevel &&
- GIT_INDEX_FILE="$NEXT_INDEX" &&
- export GIT_INDEX_FILE &&
- git update-index --remove -z --stdin
- ) || exit
- ;;
-,)
- if test "$interactive" = t; then
- git add --interactive || exit
- fi
- case "$#" in
- 0)
- ;; # commit as-is
- *)
- if test -f "$GIT_DIR/MERGE_HEAD"
- then
- refuse_partial "Cannot do a partial commit during a merge."
- fi
-
- TMP_INDEX="$GIT_DIR/tmp-index$$"
- W=
- test -z "$initial_commit" && W=--with-tree=HEAD
- commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
-
- # Build a temporary index and update the real index
- # the same way.
- if test -z "$initial_commit"
- then
- GIT_INDEX_FILE="$THIS_INDEX" \
- git read-tree --index-output="$TMP_INDEX" -i -m HEAD
- else
- rm -f "$TMP_INDEX"
- fi || exit
-
- printf '%s\n' "$commit_only" |
- GIT_INDEX_FILE="$TMP_INDEX" \
- git update-index --add --remove --stdin &&
-
- save_index &&
- printf '%s\n' "$commit_only" |
- (
- GIT_INDEX_FILE="$NEXT_INDEX"
- export GIT_INDEX_FILE
- git update-index --add --remove --stdin
- ) || exit
- ;;
- esac
- ;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit. We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
- USE_INDEX="$NEXT_INDEX"
-else
- USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
- # This will silently fail in a read-only repository, which is
- # what we want.
- GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
- run_status
- exit $?
- ;;
-'')
- GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
- ;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
- GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
- || exit
-fi
-
-if test "$log_message" != ''
-then
- printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
- if test "$logfile" = -
- then
- test -t 0 &&
- echo >&2 "(reading log message from standard input)"
- cat
- else
- cat <"$logfile"
- fi
-elif test "$use_commit" != ""
-then
- encoding=$(git config i18n.commitencoding || echo UTF-8)
- git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
- sed -e '1,/^$/d' -e 's/^ //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
- cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
- cat "$GIT_DIR/SQUASH_MSG"
-elif test "$templatefile" != ""
-then
- cat "$templatefile"
-fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
- sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
- s/>.*/>/
- s/^/Signed-off-by: /
- ')
- blank_before_signoff=
- tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
- grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
-'
- tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
- grep "$sign"$ >/dev/null ||
- printf '%s%s\n' "$blank_before_signoff" "$sign" \
- >>"$GIT_DIR"/COMMIT_EDITMSG
- ;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
- echo "#"
- echo "# It looks like you may be committing a MERGE."
- echo "# If this is not correct, please remove the file"
- printf '%s\n' "# $GIT_DIR/MERGE_HEAD"
- echo "# and try again"
- echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
- eval "$(get_author_ident_from_commit "$use_commit")"
- export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
- GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
- GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
- test '' != "$GIT_AUTHOR_NAME" &&
- test '' != "$GIT_AUTHOR_EMAIL" ||
- die "malformed --author parameter"
- export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
- rloga='commit'
- if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
- rloga='commit (merge)'
- PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
- elif test -n "$amend"; then
- rloga='commit (amend)'
- PARENTS=$(git cat-file commit HEAD |
- sed -n -e '/^$/q' -e 's/^parent /-p /p')
- fi
- current="$(git rev-parse --verify HEAD)"
-else
- if [ -z "$(git ls-files)" ]; then
- echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
- exit 1
- fi
- PARENTS=""
- rloga='commit (initial)'
- current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
- {
- echo ""
- echo "# Please enter the commit message for your changes."
- echo "# (Comment lines starting with '#' will not be included)"
- test -z "$only_include_assumed" || echo "$only_include_assumed"
- run_status
- } >>"$GIT_DIR"/COMMIT_EDITMSG
-else
- # we need to check if there is anything to commit
- run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
-then
- rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
- use_status_color=t
- run_status
- exit 1
-fi
-
-case "$no_edit" in
-'')
- git-var GIT_AUTHOR_IDENT > /dev/null || die
- git-var GIT_COMMITTER_IDENT > /dev/null || die
- git_editor "$GIT_DIR/COMMIT_EDITMSG"
- ;;
-esac
-
-case "$verify" in
-t)
- if test -x "$GIT_DIR"/hooks/commit-msg
- then
- "$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
- fi
-esac
-
-if test -z "$no_edit"
-then
- sed -e '
- /^diff --git a\/.*/{
- s///
- q
- }
- /^#/d
- ' "$GIT_DIR"/COMMIT_EDITMSG
-else
- cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git stripspace >"$GIT_DIR"/COMMIT_MSG
-
-# Test whether the commit message has any content we didn't supply.
-have_commitmsg=
-grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
- git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
-
-# Is the commit message totally empty?
-if test -s "$GIT_DIR"/COMMIT_BAREMSG
-then
- if test "$templatefile" != ""
- then
- # Test whether this is just the unaltered template.
- if cnt=`sed -e '/^#/d' < "$templatefile" |
- git stripspace |
- diff "$GIT_DIR"/COMMIT_BAREMSG - |
- wc -l` &&
- test 0 -lt $cnt
- then
- have_commitmsg=t
- fi
- else
- # No template, so the content in the commit message must
- # have come from the user.
- have_commitmsg=t
- fi
-fi
-
-rm -f "$GIT_DIR"/COMMIT_BAREMSG
-
-if test "$have_commitmsg" = "t"
-then
- if test -z "$TMP_INDEX"
- then
- tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
- else
- tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
- rm -f "$TMP_INDEX"
- fi &&
- commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
- rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
- git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
- rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
- if test -f "$NEXT_INDEX"
- then
- mv "$NEXT_INDEX" "$THIS_INDEX"
- else
- : ;# happy
- fi
-else
- echo >&2 "* no commit message? aborting commit."
- false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-git rerere
-
-if test "$ret" = 0
-then
- git gc --auto
- if test -x "$GIT_DIR"/hooks/post-commit
- then
- "$GIT_DIR"/hooks/post-commit
- fi
- if test -z "$quiet"
- then
- commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
- --summary --root HEAD --`
- echo "Created${initial_commit:+ initial} commit $commit"
- fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index 19a2172..1016e04 100644
--- a/git.c
+++ b/git.c
@@ -298,6 +298,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
{ "cherry", cmd_cherry, RUN_SETUP },
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+ { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "config", cmd_config },
{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -347,11 +348,11 @@ static void handle_internal_command(int argc, const char **argv)
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
- { "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
{ "send-pack", cmd_send_pack, RUN_SETUP },
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+ { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
{ "stripspace", cmd_stripspace },
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
{ "tag", cmd_tag, RUN_SETUP },
diff --git a/strbuf.h b/strbuf.h
index 9b9e861..9720826 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -113,5 +113,6 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
extern int strbuf_getline(struct strbuf *, FILE *, int);
extern void stripspace(struct strbuf *buf, int skip_comments);
+extern void launch_editor(const char *path, struct strbuf *buffer);
#endif /* STRBUF_H */
--
1.5.3.4
^ permalink raw reply related
* Re: [PATCH 4/4] Implement git commit and status as a builtin commands.
From: Kristian Høgsberg @ 2007-11-08 16:01 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.64.0711031328500.4362@racer.site>
On Sat, 2007-11-03 at 13:56 +0000, Johannes Schindelin wrote:
> Hi,
Hi, wanted to send this out earlier, but I punted it and a couple of
days went by...
> On Fri, 2 Nov 2007, Kristian Høgsberg wrote:
>
> > +static char *
> > +prepare_index(const char **files, const char *prefix)
> > +{
> > + int fd;
> > + struct tree *tree;
> > + struct lock_file *next_index_lock;
> > +
> > + fd = hold_locked_index(&lock_file, 1);
> > + if (read_cache() < 0)
> > + die("index file corrupt");
> > +
> > + if (all) {
> > + add_files_to_cache(verbose, NULL, files);
> > + if (write_cache(fd, active_cache, active_nr) || close(fd))
> > + die("unable to write new_index file");
> > + return lock_file.filename;
> > + } else if (also) {
> > + add_files_to_cache(verbose, prefix, files);
> > + if (write_cache(fd, active_cache, active_nr) || close(fd))
> > + die("unable to write new_index file");
> > + return lock_file.filename;
> > + }
>
> Unless something slips by my mind, this could be written as
>
> if (all || also) {
> add_files_to_cache(verbose, also ? prefix : NULL, files);
> ...
> }
Yup, that looks right.
> > +
> > + if (interactive)
> > + interactive_add();
> > +
> > + if (*files == NULL) {
> > + /* Commit index as-is. */
> > + rollback_lock_file(&lock_file);
> > + return get_index_file();
> > + }
>
> Would an interactive add not conflict with this rollback? And indeed with
> the locked index to begin with?
Yes, I've moved the interactive case up to the beginning of
prepare_index() and made it return get_index_file() after running
interactive_add().
> > + /* update the user index file */
> > + add_files_to_cache(verbose, prefix, files);
> > + if (write_cache(fd, active_cache, active_nr) || close(fd))
> > + die("unable to write new_index file");
>
> Does that mean that the index is _always_ written? Even when not
> specifying and paths on the command line?
Do you mean "not specifying any options and paths..."? In that case we
add the files to the index and create a temporary index from HEAD and
add the files there too, which we then commit. So we have to write the
index in that case. If there are no files on the command line, we roll
back the lock and bail out just above the part you quoted.
> > + /* Uh oh, abusing lock_file to create a garbage collected file */
>
> It's not that bad. But I would mention that it is a temporary index which
> you are building.
Heh, yeah, I toned it down a bit :)
> > +static const char sign_off_header[] = "Signed-off-by: ";
>
> Funny, I thought it was a footer ;-)
>
> > + } else if (!stat(template_file, &statbuf)) {
>
> Should this not test "if (template_file && " first?
Yup, added.
> > +/* Find out if the message starting at position 'start' in the strbuf
> > + * contains only whitespace and Signed-off-by lines. */
> > +static int message_is_empty(struct strbuf *sb, int start)
> > +{
> > + struct strbuf tmpl;
> > + const char *nl;
> > + int eol, i;
> > +
> > + /* See if the template is just a prefix of the message. */
> > + strbuf_init(&tmpl, 0);
> > + if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
> > + stripspace(&tmpl, 1);
> > + if (start + tmpl.len <= sb->len &&
> > + memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
> > + start += tmpl.len;
> > + }
> > + strbuf_release(&tmpl);
>
> The release could go inside the if block, no?
Sure, not a big deal, though.
> > +static int run_hook(const char *index_file, const char *name, const char *arg)
>
> Would this function not prefer to live in run-command.c?
Yeah, we can move it later, though.
> > +{
> > + struct child_process hook;
> > + const char *argv[3], *env[2];
> > + char index[PATH_MAX];
> > +
> > + argv[0] = git_path("hooks/%s", name);
> > + argv[1] = arg;
> > + argv[2] = NULL;
> > + snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
> > + env[0] = index;
> > + env[1] = NULL;
> > +
> > + if (access(argv[0], X_OK) < 0)
> > + return 0;
>
> That check logically belongs 6 lines higher...
You mean you want to do it right after the argv[0] assignment? I'd like
to keep the block of assignments together so it's easy to see how the
array is set up. Don't tell me you worry about performance here... ;)
> > + rev.abbrev = 0;
> > + rev.diff = 1;
> > + rev.diffopt.output_format =
> > + DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
> > +
> > + rev.verbose_header = 1;
> > + rev.show_root_diff = 1;
> > + rev.commit_format = get_commit_format("format:%h: %s");
>
> That's interesting. Wouldn't have thought of that. Reusing the log_tree
> machinery to output the summary. Cute.
Heh, I just did what the shell script did. It uses git diff-tree for
this, and the above is just the relevant bits from builtin-diff-tree.c.
cheers,
Kristian
^ permalink raw reply
* [PATCH] Drop deprecated commands from git(7) and update deprecation notices
From: Jonas Fonseca @ 2007-11-08 16:01 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Johannes Schindelin, Junio C Hamano, git
In-Reply-To: <4733249B.9020504@op5.se>
Also remove manpages of commands that no longer exist.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
Documentation/cmd-list.perl | 5 ---
Documentation/git-local-fetch.txt | 66 -------------------------------------
Documentation/git-ssh-fetch.txt | 52 -----------------------------
Documentation/git-ssh-upload.txt | 48 ---------------------------
Documentation/git-tar-tree.txt | 2 +-
Documentation/git-var.txt | 5 ++-
6 files changed, 4 insertions(+), 174 deletions(-)
delete mode 100644 Documentation/git-local-fetch.txt
delete mode 100644 Documentation/git-ssh-fetch.txt
delete mode 100644 Documentation/git-ssh-upload.txt
Andreas Ericsson <ae@op5.se> wrote Thu, Nov 08, 2007:
> Jonas Fonseca wrote:
> >... and remove manpages of commands that no longer exists.
> >
> >diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
> >index 8139423..73c37b0 100644
> >--- a/Documentation/git-var.txt
> >+++ b/Documentation/git-var.txt
> >@@ -20,7 +20,8 @@ OPTIONS
> > Cause the logical variables to be listed. In addition, all the
> > variables of the git configuration file .git/config are listed
> > as well. (However, the configuration variables listing functionality
> >- is deprecated in favor of `git-config -l`.)
> >+ is deprecated. Use gitlink:git-config[1] with the option '-l'
> >+ instead.)
> >
>
> Skip the parentheses. It reads better without it.
Yes, you are right. Also updated the commit message to be less
misleading (git-var is not removed but the deprecation notice is
updated).
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index 8d21d42..7f1f5d2 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -124,9 +124,7 @@ git-index-pack plumbingmanipulators
git-init mainporcelain
git-instaweb ancillaryinterrogators
gitk mainporcelain
-git-local-fetch synchingrepositories
git-log mainporcelain
-git-lost-found ancillarymanipulators
git-ls-files plumbinginterrogators
git-ls-remote plumbinginterrogators
git-ls-tree plumbinginterrogators
@@ -178,8 +176,6 @@ git-show-branch ancillaryinterrogators
git-show-index plumbinginterrogators
git-show-ref plumbinginterrogators
git-sh-setup purehelpers
-git-ssh-fetch synchingrepositories
-git-ssh-upload synchingrepositories
git-stash mainporcelain
git-status mainporcelain
git-stripspace purehelpers
@@ -187,7 +183,6 @@ git-submodule mainporcelain
git-svn foreignscminterface
git-symbolic-ref plumbingmanipulators
git-tag mainporcelain
-git-tar-tree plumbinginterrogators
git-unpack-file plumbinginterrogators
git-unpack-objects plumbingmanipulators
git-update-index plumbingmanipulators
diff --git a/Documentation/git-local-fetch.txt b/Documentation/git-local-fetch.txt
deleted file mode 100644
index e830dee..0000000
--- a/Documentation/git-local-fetch.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-git-local-fetch(1)
-==================
-
-NAME
-----
-git-local-fetch - Duplicate another git repository on a local system
-
-
-SYNOPSIS
---------
-[verse]
-'git-local-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [-l] [-s] [-n]
- commit-id path
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED.
-
-Duplicates another git repository on a local system.
-
-OPTIONS
--------
--c::
- Get the commit objects.
--t::
- Get trees associated with the commit objects.
--a::
- Get all the objects.
--v::
- Report what is downloaded.
--s::
- Instead of regular file-to-file copying use symbolic links to the objects
- in the remote repository.
--l::
- Before attempting symlinks (if -s is specified) or file-to-file copying the
- remote objects, try to hardlink the remote objects into the local
- repository.
--n::
- Never attempt to file-to-file copy remote objects. Only useful with
- -s or -l command-line options.
-
--w <filename>::
- Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
- the local end after the transfer is complete.
-
---stdin::
- Instead of a commit id on the command line (which is not expected in this
- case), 'git-local-fetch' expects lines on stdin in the format
-
- <commit-id>['\t'<filename-as-in--w>]
-
---recover::
- Verify that everything reachable from target is fetched. Used after
- an earlier fetch is interrupted.
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
diff --git a/Documentation/git-ssh-fetch.txt b/Documentation/git-ssh-fetch.txt
deleted file mode 100644
index 8d3e2ff..0000000
--- a/Documentation/git-ssh-fetch.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-git-ssh-fetch(1)
-================
-
-NAME
-----
-git-ssh-fetch - Fetch from a remote repository over ssh connection
-
-
-
-SYNOPSIS
---------
-'git-ssh-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED.
-
-Pulls from a remote repository over ssh connection, invoking
-git-ssh-upload on the other end. It functions identically to
-git-ssh-upload, aside from which end you run it on.
-
-
-OPTIONS
--------
-commit-id::
- Either the hash or the filename under [URL]/refs/ to
- pull.
-
--c::
- Get the commit objects.
--t::
- Get trees associated with the commit objects.
--a::
- Get all the objects.
--v::
- Report what is downloaded.
--w::
- Writes the commit-id into the filename under $GIT_DIR/refs/ on
- the local end after the transfer is complete.
-
-
-Author
-------
-Written by Daniel Barkalow <barkalow@iabervon.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
diff --git a/Documentation/git-ssh-upload.txt b/Documentation/git-ssh-upload.txt
deleted file mode 100644
index 5e2ca8d..0000000
--- a/Documentation/git-ssh-upload.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-git-ssh-upload(1)
-=================
-
-NAME
-----
-git-ssh-upload - Push to a remote repository over ssh connection
-
-
-SYNOPSIS
---------
-'git-ssh-upload' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED.
-
-Pushes from a remote repository over ssh connection, invoking
-git-ssh-fetch on the other end. It functions identically to
-git-ssh-fetch, aside from which end you run it on.
-
-OPTIONS
--------
-commit-id::
- Id of commit to push.
-
--c::
- Get the commit objects.
--t::
- Get tree associated with the requested commit object.
--a::
- Get all the objects.
--v::
- Report what is uploaded.
--w::
- Writes the commit-id into the filename under [URL]/refs/ on
- the remote end after the transfer is complete.
-
-Author
-------
-Written by Daniel Barkalow <barkalow@iabervon.org>
-
-Documentation
---------------
-Documentation by Daniel Barkalow
-
-GIT
----
-Part of the gitlink:git[7] suite
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 434607b..4aaf813 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -12,7 +12,7 @@ SYNOPSIS
DESCRIPTION
-----------
-THIS COMMAND IS DEPRECATED. Use `git-archive` with `--format=tar`
+THIS COMMAND IS DEPRECATED. Use gitlink:git-archive[1] with `--format=tar`
option instead (and move the <base> argument to `--prefix=base/`).
Creates a tar archive containing the tree structure for the named tree.
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 8139423..7e90a95 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -19,8 +19,9 @@ OPTIONS
-l::
Cause the logical variables to be listed. In addition, all the
variables of the git configuration file .git/config are listed
- as well. (However, the configuration variables listing functionality
- is deprecated in favor of `git-config -l`.)
+ as well. However, the configuration variables listing functionality
+ is deprecated. Use gitlink:git-config[1] with the option '-l'
+ instead.
EXAMPLE
--------
--
1.5.3.5.1622.g41d10
--
Jonas Fonseca
^ permalink raw reply related
* [PATCH] instaweb: Minor cleanups and fixes for potential problems
From: Jonas Fonseca @ 2007-11-08 15:49 UTC (permalink / raw)
To: git, Junio C Hamano
Fix path quoting and test of empty values that some shells do not like.
Remove duplicate check and setting of $browser.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
git-instaweb.sh | 11 +++++------
1 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/git-instaweb.sh b/git-instaweb.sh
index f05884c..fbacfb1 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -44,7 +44,7 @@ start_httpd () {
httpd_only="`echo $httpd | cut -f1 -d' '`"
if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac
then
- $httpd $fqgitdir/gitweb/httpd.conf
+ $httpd "$fqgitdir/gitweb/httpd.conf"
else
# many httpds are installed in /usr/sbin or /usr/local/sbin
# these days and those are not in most users $PATHs
@@ -158,7 +158,7 @@ EOF
:DirectoryIndex: ["gitweb.cgi"]
:PidFile: "$fqgitdir/pid"
EOF
- test "$local" = true && echo ':BindAddress: "127.0.0.1"' >> "$conf"
+ test x"$local" = xtrue && echo ':BindAddress: "127.0.0.1"' >> "$conf"
}
lighttpd_conf () {
@@ -171,14 +171,14 @@ server.pid-file = "$fqgitdir/pid"
cgi.assign = ( ".cgi" => "" )
mimetype.assign = ( ".css" => "text/css" )
EOF
- test "$local" = true && echo 'server.bind = "127.0.0.1"' >> "$conf"
+ test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
}
apache2_conf () {
test -z "$module_path" && module_path=/usr/lib/apache2/modules
mkdir -p "$GIT_DIR/gitweb/logs"
bind=
- test "$local" = true && bind='127.0.0.1:'
+ test x"$local" = xtrue && bind='127.0.0.1:'
echo 'text/css css' > $fqgitdir/mime.types
cat > "$conf" <<EOF
ServerName "git-instaweb"
@@ -271,6 +271,5 @@ webrick)
esac
start_httpd
-test -z "$browser" && browser=echo
url=http://127.0.0.1:$port
-$browser $url || echo $url
+"$browser" $url || echo $url
--
1.5.3.5.1623.g4aab495-dirty
--
Jonas Fonseca
^ permalink raw reply related
* Re: [PATCH MISC 1/1] Make gcc warning about empty if body go away.
From: Andreas Ericsson @ 2007-11-08 15:47 UTC (permalink / raw)
To: Jon Loeliger; +Cc: Junio C Hamano, Pierre Habouzit, git
In-Reply-To: <47332957.5050308@freescale.com>
Jon Loeliger wrote:
> Andreas Ericsson wrote:
>
>>> + if (active_cache_changed &&
>>> + !write_cache(fd, active_cache, active_nr) && !close(fd))
>>> + commit_locked_index(lock_file);
>>> rollback_lock_file(lock_file);
>>> }
>>>
>>
>> Ack, obviously, as it no longer requires a comment to explain it,
>> although
>> I'd prefer an empty line after commit_locked_index(lock_file); so as
>> to not
>> confuse the rollback_lock_file() statement as being part of the
>> conditional
>> path.
>>
>> First I thought the rollback_lock_file() was the *only* statement to the
>> condition, and everyone who uses 4 for tabsize) will have double trouble
>> since commit_locked_index(lock_file) aligns with the second line of the
>> condition.
>>
>
> It's too bad this was confusing due to the lack of braces. :-)
>
I found that slightly ironic too, since I really don't like overly bracey
code either. Just goes to show there are no rules without exceptions, I
guess.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: [PATCH] Allow git-instaweb to be run from bare repositories
From: Jonas Fonseca @ 2007-11-08 15:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vodec31k0.fsf@gitster.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> wrote Fri, Nov 02, 2007:
> Jonas Fonseca <fonseca@diku.dk> writes:
>
> > Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
> > ---
> > git-instaweb.sh | 1 +
> > 1 files changed, 1 insertions(+), 0 deletions(-)
> >
> > On IRC yesterday, two were asking for this and it seems simply enough.
> > Apparently, git-instaweb is a great way to see if you've set up a
> > remote repository correctly.
> >
> > diff --git a/git-instaweb.sh b/git-instaweb.sh
> > index 95c3e5a..14917ac 100755
> > --- a/git-instaweb.sh
> > +++ b/git-instaweb.sh
> > @@ -6,6 +6,7 @@ USAGE='[--start] [--stop] [--restart]
> > [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
> > [--module-path=<path> (for Apache2 only)]'
> >
> > +SUBDIRECTORY_OK=Yes
> > . git-sh-setup
> >
> > fqgitdir="$GIT_DIR"
>
> I'd agree with the goal of the patch, and I would not doubt the
> patch worked for you, but it somewhat feels wrong that you can
> say "It is Ok to run this script from a subdirectory" and that
> is the magic to allow something to work in a bare repository.
>
> Care to share your insights on what is going on?
After disecting the source code in more depth as well as the trace of
running git-instaweb inside a bare repository, the command relies on
git-sh-setup (which is assumed to be safe in bare repos) to initialize a
sane value of GIT_DIR. It uses GIT_DIR to initialize:
+ fqgitdir=/tmp/git.git
which is never touched later (and could possibly be changed to just use
the GIT_DIR variable instead, since either is used interchangably
throughout the script. In fact, it later does:
GIT_DIR="$fqgitdir"
which could be removed. Anyway, this fqgitdir variable is used for
creating a place for gitweb and HTTP server configuration files under
"$fqgitdir/gitweb".
+ mkdir -p /tmp/git.git/gitweb/tmp
The remaining things in the script is option handling and setting up the
HTTP server configuration. The only place where I see it possibly
"spilling out" into the parent directory is this sequence:
+ dirname /tmp/git.git
+ script=
s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "/tmp";#
s#\(my\|our\) $gitbin =.*#\1 $gitbin = "/home/fonseca/bin";#
s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;#
s#\(my\|our\) $git_temp =.*#\1 $git_temp = "/tmp/git.git/gitweb/tmp";#
Where it creates gitweb.cgi. This might make gitweb try to look for .git
directories in subdirectories. Maybe it should create a projects_list
file to explicitly list that only "$barerepo.git" is exported?
--
Jonas Fonseca
^ permalink raw reply
* Re: [PATCH 4/3] t3700: avoid racy git situation
From: Johannes Sixt @ 2007-11-08 15:45 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git, krh, gitster
In-Reply-To: <Pine.LNX.4.64.0711081511440.4362@racer.site>
Johannes Schindelin schrieb:
> The problem is that the index has the same timestamp as the file "foo".
>
> Therefore, git cannot tell if "foo" is up-to-date in the index, since it
> could have been modified (and indeed is) just a fraction of a second later
> than the index was last updated.
The test goes like this:
>foo && git add foo && git commit -a -m "commit all" &&
test -z "`git diff-index HEAD -- foo`" &&
git read-tree HEAD &&
case "`git diff-index HEAD -- foo`" in
:100644" "*"M foo") echo ok;;
*) echo fail; (exit 1);;
esac &&
git add --refresh -- foo &&
test -z "`git diff-index HEAD -- foo`"
I'm pretty sure that this test completed within one second even before
git-commit was a builtin. (I assume that timestamps don't have sub-second
resolution.) Why then didn't this racy-git problem occur with the scripted
git-commit?
-- Hannes
^ permalink raw reply
* Re: [PATCH 4/3] t3700: avoid racy git situation
From: Kristian Høgsberg @ 2007-11-08 15:27 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Johannes Sixt, git, gitster
In-Reply-To: <Pine.LNX.4.64.0711081511440.4362@racer.site>
On Thu, 2007-11-08 at 15:16 +0000, Johannes Schindelin wrote:
> Hi,
>
> On Thu, 8 Nov 2007, Johannes Sixt wrote:
>
> > Johannes Schindelin schrieb:
> > > Wow, the builtin commit is fast. It sometimes triggers a racy
> > > situation in the test case for "git add --refresh -- foo".
> > >
> > > So when that test fails, simply sleep one second and try again.
> >
> > [/me looks at the calender - no, it's not April Fool's day]
>
> No. The builtin commit is really that fast.
>
> > Wouldn't it be better to fix git-commit (or git-add)? I would like to
> > help, but you already seem to have done the analysis, so...
>
> The problem is that the index has the same timestamp as the file "foo".
>
> Therefore, git cannot tell if "foo" is up-to-date in the index, since it
> could have been modified (and indeed is) just a fraction of a second later
> than the index was last updated.
>
> And since diff-index, as called from the test script, does not generate a
> diff, but really only determines if the index information suggests that
> the files are up-to-date, there is not really much you can do.
>
> This is our good old friend, the racy git problem.
>
> NOTE: other scms do not have this problem, mostly because they are too
> slow to trigger it.
Ah, so that's what that was. Thanks for fixing that, I wasn't sure what
was going on and didn't have the time to dig into it. I have a patch
that fixes the author date for commit in determine_author_info() instead
and fixes some of the option validation problems mentioned by Björn. I
have an updated launch_editor patch too, but what you sent out looks
good, so I'll just send the latest builtin-commit.
cheers,
Kristian
^ permalink raw reply
* Re: [PATCH MISC 1/1] Make gcc warning about empty if body go away.
From: Jon Loeliger @ 2007-11-08 15:20 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Junio C Hamano, Pierre Habouzit, git
In-Reply-To: <4732CBD3.503@op5.se>
Andreas Ericsson wrote:
>> + if (active_cache_changed &&
>> + !write_cache(fd, active_cache, active_nr) && !close(fd))
>> + commit_locked_index(lock_file);
>> rollback_lock_file(lock_file);
>> }
>>
>
> Ack, obviously, as it no longer requires a comment to explain it, although
> I'd prefer an empty line after commit_locked_index(lock_file); so as to not
> confuse the rollback_lock_file() statement as being part of the conditional
> path.
>
> First I thought the rollback_lock_file() was the *only* statement to the
> condition, and everyone who uses 4 for tabsize) will have double trouble
> since commit_locked_index(lock_file) aligns with the second line of the
> condition.
>
It's too bad this was confusing due to the lack of braces. :-)
jdl
^ permalink raw reply
* Re: git pull opinion
From: Johannes Schindelin @ 2007-11-08 15:27 UTC (permalink / raw)
To: Aghiles; +Cc: Linus Torvalds, Bill Lear, Junio C Hamano, git
In-Reply-To: <3abd05a90711071325y397434efq7d4e50cb7a1cf07e@mail.gmail.com>
Hi,
On Wed, 7 Nov 2007, Aghiles wrote:
> On 11/6/07, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>
> > Now, I do think that we could relax the rule so that "files that are
> > modified must be clean in the working tree" could instead become
> > "files that actually don't merge _trivially_ must be clean in the
> > working tree". But basically, if it's not a trivial merge, then since
> > it's done in the working tree, the working tree has to be clean (or
> > the merge would overwrite it).
>
> I really think this is a good idea. It seems to me that the first "bad"
> surprise a svn/cvs/bk user will have is the result of a "git pull" command
> on a dirty tree. With the proposed change, and if I understand correctly:
> - users that are used to commit often and fetch into clean trees
> will never be bothered by this change.
> - users that are used to "update" often are expecting to resolve
> conflicts in their working copy anyway.
But the latter ones will likely not understand why all of a sudden their
working tree has to be clean sometimes (when there was no trivial
merge possible).
Besides, I think it is not trivial to implement.
Not my itch,
Dscho
^ permalink raw reply
* Re: [PATCH v2] user-manual: add advanced topic "bisecting merges"
From: Johannes Schindelin @ 2007-11-08 15:23 UTC (permalink / raw)
To: Benoit Sigoure
Cc: Steffen Prohaska, Johannes Sixt, Andreas Ericsson,
Ralf Wildenhues, Git Mailing List
In-Reply-To: <5498B368-053A-424E-B901-A55B66FF5801@lrde.epita.fr>
Hi,
On Thu, 8 Nov 2007, Benoit Sigoure wrote:
> On Nov 8, 2007, at 1:54 PM, Steffen Prohaska wrote:
>
> > Do you use rebase like this in real life?
> >
> > I thought of the text as background information that might be helpful
> > for users who want do decide wether to merge or to rebase. The problem
> > described may be valuable information supporting a decision about a
> > recommended workflow for a group of users.
>
> You're missing the point. Johannes suggested that you rebase *only* for
> bisecting purpose. Once you find the culprit commit, throw away your
> rebased stuff.
Just to clear things up: it was the other Johannes who suggested it.
But I strongly advise not to rebase before bisecting, since you could very
well end up changing the behaviour of the program by rebasing it. Even to
a point where you cannot bisect it any longer, for example when the merge
of two branches contains an important fix without which the combined
branches (or even parts of them) will not even compile.
Last time I checked, however, bisect worked like a charm even on
a history with complicated ancestry.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] Remove deprecated commands from command list and update manpages
From: Johannes Schindelin @ 2007-11-08 15:19 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.64.0711081517230.4362@racer.site>
Hi,
On Thu, 8 Nov 2007, Johannes Schindelin wrote:
> On Thu, 8 Nov 2007, Jonas Fonseca wrote:
>
> > ... and remove manpages of commands that no longer exists.
> >
> > Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
> > ---
> > Documentation/cmd-list.perl | 5 ---
>
> Maybe keep git-lost-found?
>
> > Documentation/git-local-fetch.txt | 66 -------------------------------------
> > Documentation/git-ssh-fetch.txt | 52 -----------------------------
> > Documentation/git-ssh-upload.txt | 48 ---------------------------
> > Documentation/git-tar-tree.txt | 2 +-
> > Documentation/git-var.txt | 3 +-
>
> Last time I checked, git-var was still alive.
Oops. Please ignore that one.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] Remove deprecated commands from command list and update manpages
From: Johannes Schindelin @ 2007-11-08 15:18 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Junio C Hamano, git
In-Reply-To: <20071108145435.GA18727@diku.dk>
Hi,
On Thu, 8 Nov 2007, Jonas Fonseca wrote:
> ... and remove manpages of commands that no longer exists.
>
> Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
> ---
> Documentation/cmd-list.perl | 5 ---
Maybe keep git-lost-found?
> Documentation/git-local-fetch.txt | 66 -------------------------------------
> Documentation/git-ssh-fetch.txt | 52 -----------------------------
> Documentation/git-ssh-upload.txt | 48 ---------------------------
> Documentation/git-tar-tree.txt | 2 +-
> Documentation/git-var.txt | 3 +-
Last time I checked, git-var was still alive.
Ciao,
Dscho
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox