* Re: [RFC/PATCH 1/6] revert: libify cherry-pick and revert functionnality
From: Johannes Schindelin @ 2010-02-01 10:26 UTC (permalink / raw)
To: Christian Couder
Cc: Junio C Hamano, git, Linus Torvalds, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201075542.3929.38404.chriscool@tuxfamily.org>
Hi,
On Mon, 1 Feb 2010, Christian Couder wrote:
> From: Stephan Beyer <s-beyer@gmx.net>
>
> The goal of this commit is to abstract out "git cherry-pick" and
> "git revert" functionnality into a new pick_commit() function made
> of code from "builtin-revert.c".
>
> The new pick_commit() function is in a new "pick.c" file with an
> associated "pick.h".
>
> This function starts from the current index (not HEAD), and allow
> the effect of one commit replayed (either forward or backward) to
> that state, leaving the result in the index. So it makes it
> possible to replay many commits to the index in sequence without
> commiting in between.
>
> This commit is made of code from the sequencer GSoC project:
>
> git://repo.or.cz/git/sbeyer.git
>
> (at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
>
> And it contains some changes and comments suggested by Junio.
>
> The original commit in the sequencer project that introduced
> this change is: 94a568a78d243d7a6c13778bc6b7ac1eb46e48cc
>
> Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
> Mentored-by: Christian Couder <chriscool@tuxfamily.org>
> Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
> ---
I guess that this patch would look nicer using --patience. In its current
form, it would put too big a dent in my Git time budget, sorry, I will not
review it.
Ciao,
Dscho
^ permalink raw reply
* pack.packSizeLimit, safety checks
From: Sergio @ 2010-02-01 9:20 UTC (permalink / raw)
To: git
Hi,
documentation about pack.packSizeLimit
says:
The default maximum size of a pack. This setting only affects packing to a file,
i.e. the git:// protocol is unaffected. It can be overridden by the
--max-pack-size option of git-repack(1).
I would suggest clarifying it into
The default maximum size of a pack in bytes. This setting only affects packing
to a file, i.e. the git:// protocol is unaffected. It can be overridden by the
--max-pack-size option of git-repack(1).
Since --max-pack-size takes MB and one might be tempted to assume that the same
is valid for pack.packSizeLimit.
Also note that some safety check on pack.packSizeLimit could probably be
desirable to avoid an unreasonably small limit. For instance:
Assume that pack.packSizeLimit is set to 1 (believing it would be 1MB, but it is
in fact 1B). With this at the first git gc every object goes in its own pack.
You realize the mistake, you fix pack.packSizeLimit to 1000000, but at this
point you cannot go back since git gc cannot run anymore (too many open files).
Maybe, considering all the possible use cases of pack.packSizeLimit could help
finding a reasonable lower bound.
^ permalink raw reply
* Re: Wishlist for branch management
From: Petr Baudis @ 2010-02-01 9:19 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: Git Mailing List
In-Reply-To: <4B662BEF.7040503@zytor.com>
On Sun, Jan 31, 2010 at 05:18:39PM -0800, H. Peter Anvin wrote:
> A wishlist for better handling of branches:
>
> git clone --branches
>
> ... git clone, with the additional step of setting up local branches for
> each one of the remote branches.
Yes please! ;-) However, there should be a corresponding command to do
this with a remote within existing repository. Perhaps something like
git remote populate
(stealing some syntax from topgit ;-).
> git branch --current
>
> ... list the current branch name, for use in scripts. Equivalent to:
> "git branch | grep '^\*' | cut -c3-"
I'm used to git symbolic-ref HEAD. I like the fact that human-friendly
and scripting interfaces are mostly separated to different commands.
This also has saner behaviour when HEAD is not on a branch. (Which is
also a reason why operation like this should be done only when there's
a damn good reason to need to know the branch name.)
> git push --current
>
> ... push the current branch, and only the current branch...
Yes. Even in the HEAD form, it would be nice to have something that does
not require me to write out 'origin' or whatever my remote default is.
Perhaps `git push - HEAD`. There's certain disparity, we have an alias
for the current branch (HEAD) but not for the current remote.
P.S.: I know. It's all just bikeshedding without patches...
--
Petr "Pasky" Baudis
If you can't see the value in jet powered ants you should turn in
your nerd card. -- Dunbal (464142)
^ permalink raw reply
* [PATCH 2/2] upload-pack: Add a pre-upload-pack hook
From: Arun Raghavan @ 2010-02-01 8:32 UTC (permalink / raw)
To: git; +Cc: ford_prefect
In-Reply-To: <1265013127-12589-2-git-send-email-ford_prefect@gentoo.org>
This hook is run after want/have are communicated and before the actual
upload operation is begun. It is passed the set of want and have, as
well as the type of operation (fetch/clone). The intended use for this
hook is to reject large uploads (such as very large initial clones).
---
Documentation/git-upload-pack.txt | 5 +-
Documentation/githooks.txt | 37 ++++++++++--
t/Makefile | 1 +
t/t5507-pre-upload-pack.sh | 93 +++++++++++++++++++++++++++++++
templates/hooks--pre-upload-pack.sample | 11 ++++
upload-pack.c | 20 +++++--
6 files changed, 153 insertions(+), 14 deletions(-)
create mode 100644 t/t5507-pre-upload-pack.sh
create mode 100644 templates/hooks--pre-upload-pack.sample
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index 63f3b5c..5c9474d 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -20,8 +20,11 @@ The UI for the protocol is on the 'git-fetch-pack' side, and the
program pair is meant to be used to pull updates from a remote
repository. For push operations, see 'git-send-pack'.
+Before starting the upload operation, `pre-upload-pack`hook may be
+called (see linkgit:githooks[5]).
+
After finishing the operation successfully, `post-upload-pack`
-hook is called (see linkgit:githooks[5]).
+hook may be called (see linkgit:githooks[5]).
OPTIONS
-------
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 47bcfd1..99f8882 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -310,16 +310,18 @@ Both standard output and standard error output are forwarded to
'git-send-pack' on the other end, so you can simply `echo` messages
for the user.
-post-upload-pack
-----------------
+pre-upload-pack
+---------------
-Note that this hook is POTENTIALLY INSECURE. It is run as the user who
+Note that this hook is POTENTIALLY INSECURE on shared systems where
+the owner of the repository is not trusted. It is run as the user who
is pulling, so an attacker can make a victim run arbitrary code by
-convincing him to clone a repository. To enable this hook, git must be
-compiled with the ALLOW_INSECURE_HOOKS option.
+convincing him to clone a repository. To enable this hook, git must
+be compiled with the ALLOW_INSECURE_HOOKS option.
-After upload-pack successfully finishes its operation, this hook is called
-for logging purposes.
+Before the upload-pack is started (but after want/have have been
+communicated), this hook is be called. It can be used, for example,
+to deny very large uploads.
The hook is passed various pieces of information, one per line, from its
standard input. Currently the following items can be fed to the hook, but
@@ -334,6 +336,27 @@ have SHA-1::
the resulting pack, claiming to have them already. Can occur zero
or more times in the input.
+kind string:
+ Either "clone" (when the client did not give us any "have", and asked
+ for all our refs with "want"), or "fetch" (otherwise).
+
+post-upload-pack
+----------------
+
+The same SECURITY CONCERNS as pre-upload-pack apply here.
+
+After upload-pack successfully finishes its operation, this hook is called
+(for example, for logging).
+
+want SHA-1::
+ 40-byte hexadecimal object name the client asked to include in the
+ resulting pack. Can occur one or more times in the input.
+
+have SHA-1::
+ 40-byte hexadecimal object name the client asked to exclude from
+ the resulting pack, claiming to have them already. Can occur zero
+ or more times in the input.
+
time float::
Number of seconds spent for creating the packfile.
diff --git a/t/Makefile b/t/Makefile
index af3c99e..a884e75 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -18,6 +18,7 @@ TSVN = $(wildcard t91[0-9][0-9]-*.sh)
ifndef ALLOW_INSECURE_HOOKS
T := $(filter-out t5501-post-upload-pack.sh,$(T))
+ T := $(filter-out t5507-pre-upload-pack.sh,$(T))
endif
all: pre-clean
diff --git a/t/t5507-pre-upload-pack.sh b/t/t5507-pre-upload-pack.sh
new file mode 100644
index 0000000..d3a7ba7
--- /dev/null
+++ b/t/t5507-pre-upload-pack.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+test_description='pre upload-hook'
+
+. ./test-lib.sh
+
+LOGFILE=".git/pre-upload-pack-log"
+
+test_expect_success setup '
+ test_commit A &&
+ test_commit B &&
+ git reset --hard A &&
+ test_commit C &&
+ git branch prev B &&
+ mkdir -p .git/hooks &&
+ {
+ echo "#!$SHELL_PATH" &&
+ echo "cat >pre-upload-pack-log"
+ } >".git/hooks/pre-upload-pack" &&
+ chmod +x .git/hooks/pre-upload-pack
+'
+
+test_expect_success initial '
+ rm -fr sub &&
+ git init sub &&
+ (
+ cd sub &&
+ git fetch --no-tags .. prev
+ ) &&
+ want=$(sed -n "s/^want //p" "$LOGFILE") &&
+ test "$want" = "$(git rev-parse --verify B)" &&
+ ! grep "^have " "$LOGFILE" &&
+ kind=$(sed -n "s/^kind //p" "$LOGFILE") &&
+ test "$kind" = fetch
+'
+
+test_expect_success second '
+ rm -fr sub &&
+ git init sub &&
+ (
+ cd sub &&
+ git fetch --no-tags .. prev:refs/remotes/prev &&
+ git fetch --no-tags .. master
+ ) &&
+ want=$(sed -n "s/^want //p" "$LOGFILE") &&
+ test "$want" = "$(git rev-parse --verify C)" &&
+ have=$(sed -n "s/^have //p" "$LOGFILE") &&
+ test "$have" = "$(git rev-parse --verify B)" &&
+ kind=$(sed -n "s/^kind //p" "$LOGFILE") &&
+ test "$kind" = fetch
+'
+
+test_expect_success all '
+ rm -fr sub &&
+ HERE=$(pwd) &&
+ git init sub &&
+ (
+ cd sub &&
+ git clone "file://$HERE/.git" new
+ ) &&
+ sed -n "s/^want //p" "$LOGFILE" | sort >actual &&
+ git rev-parse A B C | sort >expect &&
+ test_cmp expect actual &&
+ ! grep "^have " "$LOGFILE" &&
+ kind=$(sed -n "s/^kind //p" "$LOGFILE") &&
+ test "$kind" = clone
+'
+
+cat > pre-upload-pack <<EOF
+#!$SHELL_PATH
+kind=\$(awk '/^kind /{print \$2; exit}' -)
+if test "\$kind" = "clone"; then
+ echo "Sorry, no cloning!"
+exit 1; fi
+EOF
+
+test_expect_success 'with failing hook' '
+ rm -fr .git
+ test_create_repo src &&
+ (
+ cd src &&
+ mkdir .git/hooks &&
+ mv ../pre-upload-pack ".git/hooks/pre-upload-pack" &&
+ chmod +x .git/hooks/pre-upload-pack &&
+ echo foo > file &&
+ git add file &&
+ git commit -m initial
+ ) &&
+ test_must_fail git clone -n "file://$(pwd)/src" dst
+
+'
+
+test_done
diff --git a/templates/hooks--pre-upload-pack.sample b/templates/hooks--pre-upload-pack.sample
new file mode 100644
index 0000000..7342d23
--- /dev/null
+++ b/templates/hooks--pre-upload-pack.sample
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# This sample shows how one may reject an upload-pack where the client is
+# trying to perform an initial clone clone
+
+kind=$(awk '/^kind /{print $2; exit}' -)
+
+if test "$kind" = "clone"; then
+ echo "Sorry, the clone operation is not allowed"
+ exit 1
+fi
diff --git a/upload-pack.c b/upload-pack.c
index c992cb4..9c33e63 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -171,14 +171,19 @@ static int feed_obj_to_hook(const char *label, struct object_array *oa, int i, i
sha1_to_hex(oa->objects[i].item->sha1));
}
-static int run_post_upload_pack_hook(size_t total, struct timeval *tv)
+static int run_upload_pack_hook(int post, size_t total, struct timeval *tv)
{
const char *argv[2];
struct child_process proc;
int err, i;
- argv[0] = "hooks/post-upload-pack";
- argv[1] = NULL;
+ if (!post) {
+ argv[0] = "hooks/pre-upload-pack";
+ argv[1] = NULL;
+ } else {
+ argv[0] = "hooks/post-upload-pack";
+ argv[1] = NULL;
+ }
if (access(argv[0], X_OK) < 0)
return 0;
@@ -197,10 +202,10 @@ static int run_post_upload_pack_hook(size_t total, struct timeval *tv)
err |= feed_obj_to_hook("want", &want_obj, i, proc.in);
for (i = 0; !err && i < have_obj.nr; i++)
err |= feed_obj_to_hook("have", &have_obj, i, proc.in);
- if (!err)
+ if (!err && post)
err |= feed_msg_to_hook(proc.in, "time %ld.%06ld\n",
(long)tv->tv_sec, (long)tv->tv_usec);
- if (!err)
+ if (!err && post)
err |= feed_msg_to_hook(proc.in, "size %ld\n", (long)total);
if (!err)
err |= feed_msg_to_hook(proc.in, "kind %s\n",
@@ -758,7 +763,10 @@ static void upload_pack(void)
receive_needs();
if (want_obj.nr) {
get_common_commits();
- create_pack_file();
+ if (run_upload_pack_hook(0, 0, NULL))
+ error("pre-upload hook aborted");
+ else
+ create_pack_file();
}
}
--
1.6.6.1
^ permalink raw reply related
* [PATCH 1/2] upload-pack: Reinstate the post-upload-pack hook
From: Arun Raghavan @ 2010-02-01 8:32 UTC (permalink / raw)
To: git; +Cc: ford_prefect
In-Reply-To: <1265013127-12589-1-git-send-email-ford_prefect@gentoo.org>
This time, we introduce a build-time flag (ALLOW_INSECURE_HOOKS) to make
sure that anybody who wants to use these hooks is adequately warned.
---
Documentation/git-upload-pack.txt | 2 +
Documentation/githooks.txt | 34 +++++++++++++++
Makefile | 8 ++++
config.mak.in | 1 +
t/Makefile | 4 ++
t/t5501-post-upload-pack.sh | 69 ++++++++++++++++++++++++++++++
upload-pack.c | 85 ++++++++++++++++++++++++++++++++++++-
7 files changed, 202 insertions(+), 1 deletions(-)
create mode 100644 t/t5501-post-upload-pack.sh
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index b8e49dc..63f3b5c 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -20,6 +20,8 @@ The UI for the protocol is on the 'git-fetch-pack' side, and the
program pair is meant to be used to pull updates from a remote
repository. For push operations, see 'git-send-pack'.
+After finishing the operation successfully, `post-upload-pack`
+hook is called (see linkgit:githooks[5]).
OPTIONS
-------
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 29eeae7..47bcfd1 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -310,6 +310,40 @@ Both standard output and standard error output are forwarded to
'git-send-pack' on the other end, so you can simply `echo` messages
for the user.
+post-upload-pack
+----------------
+
+Note that this hook is POTENTIALLY INSECURE. It is run as the user who
+is pulling, so an attacker can make a victim run arbitrary code by
+convincing him to clone a repository. To enable this hook, git must be
+compiled with the ALLOW_INSECURE_HOOKS option.
+
+After upload-pack successfully finishes its operation, this hook is called
+for logging purposes.
+
+The hook is passed various pieces of information, one per line, from its
+standard input. Currently the following items can be fed to the hook, but
+more types of information may be added in the future:
+
+want SHA-1::
+ 40-byte hexadecimal object name the client asked to include in the
+ resulting pack. Can occur one or more times in the input.
+
+have SHA-1::
+ 40-byte hexadecimal object name the client asked to exclude from
+ the resulting pack, claiming to have them already. Can occur zero
+ or more times in the input.
+
+time float::
+ Number of seconds spent for creating the packfile.
+
+size decimal::
+ Size of the resulting packfile in bytes.
+
+kind string:
+ Either "clone" (when the client did not give us any "have", and asked
+ for all our refs with "want"), or "fetch" (otherwise).
+
pre-auto-gc
~~~~~~~~~~~
diff --git a/Makefile b/Makefile
index 57045de..e29eb33 100644
--- a/Makefile
+++ b/Makefile
@@ -210,6 +210,10 @@ all::
# Define JSMIN to point to JavaScript minifier that functions as
# a filter to have gitweb.js minified.
#
+# Define ALLOW_INSECURE_HOOKS to enable hooks that have security implications
+# in some setups (such as pre-/post-upload hooks that run with the user id of
+# the user who is pulling).
+#
# Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
# you want to use something different. The value will be interpreted by the
# shell at runtime when it is used.
@@ -1366,6 +1370,10 @@ ifdef USE_NED_ALLOCATOR
COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
endif
+ifdef ALLOW_INSECURE_HOOKS
+ BASIC_CFLAGS += -DALLOW_INSECURE_HOOKS
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
endif
diff --git a/config.mak.in b/config.mak.in
index 67b12f7..c5bb125 100644
--- a/config.mak.in
+++ b/config.mak.in
@@ -58,3 +58,4 @@ SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@
NO_PTHREADS=@NO_PTHREADS@
THREADED_DELTA_SEARCH=@THREADED_DELTA_SEARCH@
PTHREAD_LIBS=@PTHREAD_LIBS@
+ALLOW_INSECURE_HOOKS=@ALLOW_INSECURE_HOOKS@
diff --git a/t/Makefile b/t/Makefile
index bd09390..af3c99e 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -16,6 +16,10 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
TSVN = $(wildcard t91[0-9][0-9]-*.sh)
+ifndef ALLOW_INSECURE_HOOKS
+ T := $(filter-out t5501-post-upload-pack.sh,$(T))
+endif
+
all: pre-clean
$(MAKE) aggregate-results-and-cleanup
diff --git a/t/t5501-post-upload-pack.sh b/t/t5501-post-upload-pack.sh
new file mode 100644
index 0000000..d89fb51
--- /dev/null
+++ b/t/t5501-post-upload-pack.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+test_description='post upload-hook'
+
+. ./test-lib.sh
+
+LOGFILE=".git/post-upload-pack-log"
+
+test_expect_success setup '
+ test_commit A &&
+ test_commit B &&
+ git reset --hard A &&
+ test_commit C &&
+ git branch prev B &&
+ mkdir -p .git/hooks &&
+ {
+ echo "#!$SHELL_PATH" &&
+ echo "cat >post-upload-pack-log"
+ } >".git/hooks/post-upload-pack" &&
+ chmod +x .git/hooks/post-upload-pack
+'
+
+test_expect_success initial '
+ rm -fr sub &&
+ git init sub &&
+ (
+ cd sub &&
+ git fetch --no-tags .. prev
+ ) &&
+ want=$(sed -n "s/^want //p" "$LOGFILE") &&
+ test "$want" = "$(git rev-parse --verify B)" &&
+ ! grep "^have " "$LOGFILE" &&
+ kind=$(sed -n "s/^kind //p" "$LOGFILE") &&
+ test "$kind" = fetch
+'
+
+test_expect_success second '
+ rm -fr sub &&
+ git init sub &&
+ (
+ cd sub &&
+ git fetch --no-tags .. prev:refs/remotes/prev &&
+ git fetch --no-tags .. master
+ ) &&
+ want=$(sed -n "s/^want //p" "$LOGFILE") &&
+ test "$want" = "$(git rev-parse --verify C)" &&
+ have=$(sed -n "s/^have //p" "$LOGFILE") &&
+ test "$have" = "$(git rev-parse --verify B)" &&
+ kind=$(sed -n "s/^kind //p" "$LOGFILE") &&
+ test "$kind" = fetch
+'
+
+test_expect_success all '
+ rm -fr sub &&
+ HERE=$(pwd) &&
+ git init sub &&
+ (
+ cd sub &&
+ git clone "file://$HERE/.git" new
+ ) &&
+ sed -n "s/^want //p" "$LOGFILE" | sort >actual &&
+ git rev-parse A B C | sort >expect &&
+ test_cmp expect actual &&
+ ! grep "^have " "$LOGFILE" &&
+ kind=$(sed -n "s/^kind //p" "$LOGFILE") &&
+ test "$kind" = clone
+'
+
+test_done
diff --git a/upload-pack.c b/upload-pack.c
index df15181..c992cb4 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -41,6 +41,11 @@ static int use_sideband;
static int debug_fd;
static int advertise_refs;
static int stateless_rpc;
+#ifdef ALLOW_INSECURE_HOOKS
+static int allow_insecure_hooks = 1;
+#else
+static int allow_insecure_hooks = 0;
+#endif
static void reset_timeout(void)
{
@@ -148,8 +153,69 @@ static int do_rev_list(int fd, void *create_full_pack)
return 0;
}
+static int feed_msg_to_hook(int fd, const char *fmt, ...)
+{
+ int cnt;
+ char buf[1024];
+ va_list params;
+
+ va_start(params, fmt);
+ cnt = vsprintf(buf, fmt, params);
+ va_end(params);
+ return write_in_full(fd, buf, cnt) != cnt;
+}
+
+static int feed_obj_to_hook(const char *label, struct object_array *oa, int i, int fd)
+{
+ return feed_msg_to_hook(fd, "%s %s\n", label,
+ sha1_to_hex(oa->objects[i].item->sha1));
+}
+
+static int run_post_upload_pack_hook(size_t total, struct timeval *tv)
+{
+ const char *argv[2];
+ struct child_process proc;
+ int err, i;
+
+ argv[0] = "hooks/post-upload-pack";
+ argv[1] = NULL;
+
+ if (access(argv[0], X_OK) < 0)
+ return 0;
+
+ if (!allow_insecure_hooks)
+ return 1;
+
+ memset(&proc, 0, sizeof(proc));
+ proc.argv = argv;
+ proc.in = -1;
+ proc.stdout_to_stderr = 1;
+ err = start_command(&proc);
+ if (err)
+ return err;
+ for (i = 0; !err && i < want_obj.nr; i++)
+ err |= feed_obj_to_hook("want", &want_obj, i, proc.in);
+ for (i = 0; !err && i < have_obj.nr; i++)
+ err |= feed_obj_to_hook("have", &have_obj, i, proc.in);
+ if (!err)
+ err |= feed_msg_to_hook(proc.in, "time %ld.%06ld\n",
+ (long)tv->tv_sec, (long)tv->tv_usec);
+ if (!err)
+ err |= feed_msg_to_hook(proc.in, "size %ld\n", (long)total);
+ if (!err)
+ err |= feed_msg_to_hook(proc.in, "kind %s\n",
+ (nr_our_refs == want_obj.nr && !have_obj.nr)
+ ? "clone" : "fetch");
+ if (close(proc.in))
+ err = 1;
+ if (finish_command(&proc))
+ err = 1;
+ return err;
+}
+
static void create_pack_file(void)
{
+ struct timeval start_tv, tv;
struct async rev_list;
struct child_process pack_objects;
int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr);
@@ -158,9 +224,13 @@ static void create_pack_file(void)
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
+ ssize_t total_sz;
const char *argv[10];
int arg = 0;
+ gettimeofday(&start_tv, NULL);
+ total_sz = 0;
+
if (shallow_nr) {
rev_list.proc = do_rev_list;
rev_list.data = 0;
@@ -286,7 +356,7 @@ static void create_pack_file(void)
sz = xread(pack_objects.out, cp,
sizeof(data) - outsz);
if (0 < sz)
- ;
+ total_sz += sz;
else if (sz == 0) {
close(pack_objects.out);
pack_objects.out = -1;
@@ -323,6 +393,19 @@ static void create_pack_file(void)
}
if (use_sideband)
packet_flush(1);
+
+ if (allow_insecure_hooks) {
+ gettimeofday(&tv, NULL);
+ tv.tv_sec -= start_tv.tv_sec;
+ if (tv.tv_usec < start_tv.tv_usec) {
+ tv.tv_sec--;
+ tv.tv_usec += 1000000;
+ }
+ tv.tv_usec -= start_tv.tv_usec;
+ if (run_upload_pack_hook(1, total_sz, &tv))
+ warning("Running post-upload-hook failed");
+ }
+
return;
fail:
--
1.6.6.1
^ permalink raw reply related
* [PATCH 0/2] upload-pack: pre- and post- hooks
From: Arun Raghavan @ 2010-02-01 8:32 UTC (permalink / raw)
To: git; +Cc: ford_prefect
In-Reply-To: <6f8b45101001150414r2661001ep10819b601953c05b@mail.gmail.com>
Hello!
This patch set reintroduces the post-upload-pack hook and adds a
pre-upload-pack hook. These are now only built if 'ALLOW_INSECURE_HOOKS' is set
at build time. The idea is that only system administrators who need this
functionality and are sure the potential insecurity is not relevant to their
system will enable it.
At some point if the future, if needed, this could also be made a part of the
negotiation between the client and server.
Cheers,
Arun
^ permalink raw reply
* Re: Partially private repository?
From: Johannes Sixt @ 2010-02-01 8:20 UTC (permalink / raw)
To: Daed Lee; +Cc: Avery Pennarun, git
In-Reply-To: <78d8a6b51001312059s1811b631y838679a3f63188b0@mail.gmail.com>
Daed Lee schrieb:
> On Fri, Jan 29, 2010 at 5:10 PM, Avery Pennarun <apenwarr@gmail.com> wrote:
>> On Fri, Jan 29, 2010 at 5:01 PM, Daed Lee <daed@thoughtsofcode.com> wrote:
>>> Hi, I'm wondering if git can handle the following use. I have a
>>> project that started as private experiment, but has morphed into
>>> something I'd like to release publicly. I want to give others access
>>> to the repository, but only to commits after a certain cutoff date.
>>> Commits prior to that date have things like hardcoded file paths,
>>> emails, etc. that I'd like to keep private.
>>>
>>> I suppose the easiest thing to do would be to create a new repository,
>>> add the project files to it, and make that public, however I'd like to
>>> keep my private commit history along with the public commit history
>>> going forward in a single repository if possible. Is there a way to do
>>> this with git?
>> You should probably split your history into two pieces: the "before"
>> and "after" parts. To split out the "after" part, you could use
>> git-filter-branch
>> (http://www.kernel.org/pub/software/scm/git/docs/v1.6.0.6/git-filter-branch.html).
Sidenote: http://www.kernel.org/pub/software/scm/git/docs/git.html is the
most up-to-date version with pointers to older versions. The page for
filter-branch has an example how to prune history with grafts.
>> Then, in your private copy of the repo, you could reattach the
>> "before" part of the history using git grafts.
That is, you use grafts twice: Once to split off the "after" part, again
to re-attach it locally.
> Going forward, if I made changes to my private repository (containing
> the "before" and "after" parts) and pushed to the public repository
> (containing only the "after" part), would this only push the commits
> in the "after" part? Essentially, I want to develop in my private
> repository and see my "before" and "after" changes when I "git
> log/show", but only push the "after" changes to the public repository.
The thing is that grafts are an old mechanism, and they do not always do
the right thing. In particular, when you push the "after" part that you
have spliced with the "before" part using a graft, then the objects in the
"before" part will be pushed as well. But since the remote repository does
not have the graft, these objects are inaccessible - *except* when offer
access via dumb protocols (rsync or dumb http).
There is a newer mechanism: 'git replace'. It does the right thing. That
is, after you have split the "before" and "after" parts (using a graft and
filter-branch), you splice them together using 'git replace'.
Here is a recipe that should do it (not tested, try it on a clone):
--- 8< ---
# interesting commits
first_after=first-commit-of-the-after-part # all 40 digits!
before=$first_after^
git tag first-after $first_after
# split using a graft
echo $first_after > .git/info/grafts
git filter-branch --tag-name-filter=cat -- --all --not $before
# reattach
git replace first-after $first_after
--- 8< ---
We know that the old $first_after has the right parenthood that we need to
re-attach the split histories. We tag $first_after, and make sure the tag
gets rewritten. Then we can use the tag name in the 'git replace' call:
The tag name points to the rewritten (parentless) commit, and $first_after
is the old commit whose parent points to "before".
> I've also been looking into private branches. Could I do something
> like keep my "before" changes on a private branch, and then do all
> future development on a public branch?
You can, and you *must* do that, i.e., you must have a branch (or tag)
that points to the last commit on the "before" part. Otherwise, it is all
too easy to garbage-collect this part.
But you must make sure that you never merge a private branch into the
public history.
-- Hannes
^ permalink raw reply
* [RFC/PATCH 1/6] revert: libify cherry-pick and revert functionnality
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201074835.3929.11509.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
The goal of this commit is to abstract out "git cherry-pick" and
"git revert" functionnality into a new pick_commit() function made
of code from "builtin-revert.c".
The new pick_commit() function is in a new "pick.c" file with an
associated "pick.h".
This function starts from the current index (not HEAD), and allow
the effect of one commit replayed (either forward or backward) to
that state, leaving the result in the index. So it makes it
possible to replay many commits to the index in sequence without
commiting in between.
This commit is made of code from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
And it contains some changes and comments suggested by Junio.
The original commit in the sequencer project that introduced
this change is: 94a568a78d243d7a6c13778bc6b7ac1eb46e48cc
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
Makefile | 2 +
builtin-revert.c | 272 +++++++++---------------------------------------------
pick.c | 218 +++++++++++++++++++++++++++++++++++++++++++
pick.h | 13 +++
4 files changed, 277 insertions(+), 228 deletions(-)
create mode 100644 pick.c
create mode 100644 pick.h
diff --git a/Makefile b/Makefile
index d624530..71901c8 100644
--- a/Makefile
+++ b/Makefile
@@ -458,6 +458,7 @@ LIB_H += pack-refs.h
LIB_H += pack-revindex.h
LIB_H += parse-options.h
LIB_H += patch-ids.h
+LIB_H += pick.h
LIB_H += pkt-line.h
LIB_H += progress.h
LIB_H += quote.h
@@ -550,6 +551,7 @@ LIB_OBJS += parse-options.o
LIB_OBJS += patch-delta.o
LIB_OBJS += patch-ids.o
LIB_OBJS += path.o
+LIB_OBJS += pick.o
LIB_OBJS += pkt-line.o
LIB_OBJS += preload-index.o
LIB_OBJS += pretty.o
diff --git a/builtin-revert.c b/builtin-revert.c
index 8ac86f0..3cbeab7 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -1,18 +1,14 @@
#include "cache.h"
#include "builtin.h"
-#include "object.h"
#include "commit.h"
#include "tag.h"
-#include "wt-status.h"
-#include "run-command.h"
#include "exec_cmd.h"
#include "utf8.h"
#include "parse-options.h"
-#include "cache-tree.h"
#include "diff.h"
#include "revision.h"
#include "rerere.h"
-#include "merge-recursive.h"
+#include "pick.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -35,26 +31,24 @@ static const char * const cherry_pick_usage[] = {
NULL
};
-static int edit, no_replay, no_commit, mainline, signoff;
-static enum { REVERT, CHERRY_PICK } action;
+static int edit, no_commit, mainline, signoff;
+static int flags;
static struct commit *commit;
static int allow_rerere_auto;
-static const char *me;
-
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
static void parse_args(int argc, const char **argv)
{
const char * const * usage_str =
- action == REVERT ? revert_usage : cherry_pick_usage;
+ flags & PICK_REVERSE ? revert_usage : cherry_pick_usage;
unsigned char sha1[20];
const char *arg;
int noop;
struct option options[] = {
OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"),
OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"),
- OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"),
+ OPT_BIT('x', NULL, &flags, "append commit name when cherry-picking", PICK_ADD_NOTE),
OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"),
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
OPT_INTEGER('m', "mainline", &mainline, "parent number"),
@@ -79,42 +73,12 @@ static void parse_args(int argc, const char **argv)
die ("'%s' does not point to a commit", arg);
}
-static char *get_oneline(const char *message)
-{
- char *result;
- const char *p = message, *abbrev, *eol;
- int abbrev_len, oneline_len;
-
- if (!p)
- die ("Could not read commit message of %s",
- sha1_to_hex(commit->object.sha1));
- while (*p && (*p != '\n' || p[1] != '\n'))
- p++;
-
- if (*p) {
- p += 2;
- for (eol = p + 1; *eol && *eol != '\n'; eol++)
- ; /* do nothing */
- } else
- eol = p;
- abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
- abbrev_len = strlen(abbrev);
- oneline_len = eol - p;
- result = xmalloc(abbrev_len + 5 + oneline_len);
- memcpy(result, abbrev, abbrev_len);
- memcpy(result + abbrev_len, "... ", 4);
- memcpy(result + abbrev_len + 4, p, oneline_len);
- result[abbrev_len + 4 + oneline_len] = '\0';
- return result;
-}
-
static char *get_encoding(const char *message)
{
const char *p = message, *eol;
if (!p)
- die ("Could not read commit message of %s",
- sha1_to_hex(commit->object.sha1));
+ return NULL;
while (*p && *p != '\n') {
for (eol = p + 1; *eol && *eol != '\n'; eol++)
; /* do nothing */
@@ -130,30 +94,6 @@ static char *get_encoding(const char *message)
return NULL;
}
-static struct lock_file msg_file;
-static int msg_fd;
-
-static void add_to_msg(const char *string)
-{
- int len = strlen(string);
- if (write_in_full(msg_fd, string, len) < 0)
- die_errno ("Could not write to MERGE_MSG");
-}
-
-static void add_message_to_msg(const char *message)
-{
- const char *p = message;
- while (*p && (*p != '\n' || p[1] != '\n'))
- p++;
-
- if (!*p)
- add_to_msg(sha1_to_hex(commit->object.sha1));
-
- p += 2;
- add_to_msg(p);
- return;
-}
-
static void set_author_ident_env(const char *message)
{
const char *p = message;
@@ -216,7 +156,7 @@ static char *help_msg(const unsigned char *sha1)
"mark the corrected paths with 'git add <paths>' "
"or 'git rm <paths>' and commit the result.");
- if (action == CHERRY_PICK) {
+ if (!(flags & PICK_REVERSE)) {
sprintf(helpbuf + strlen(helpbuf),
"\nWhen commiting, use the option "
"'-c %s' to retain authorship and message.",
@@ -225,14 +165,17 @@ static char *help_msg(const unsigned char *sha1)
return helpbuf;
}
-static struct tree *empty_tree(void)
+static void write_message(struct strbuf *msgbuf, const char *filename)
{
- struct tree *tree = xcalloc(1, sizeof(struct tree));
-
- tree->object.parsed = 1;
- tree->object.type = OBJ_TREE;
- pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
- return tree;
+ struct lock_file msg_file;
+ int msg_fd;
+ msg_fd = hold_lock_file_for_update(&msg_file, filename,
+ LOCK_DIE_ON_ERROR);
+ if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
+ die_errno("Could not write to %s.", filename);
+ strbuf_release(msgbuf);
+ if (commit_lock_file(&msg_file) < 0)
+ die("Error wrapping up %s", filename);
}
static NORETURN void die_dirty_index(const char *me)
@@ -250,175 +193,53 @@ static NORETURN void die_dirty_index(const char *me)
static int revert_or_cherry_pick(int argc, const char **argv)
{
- unsigned char head[20];
- struct commit *base, *next, *parent;
- int i, index_fd, clean;
- char *oneline, *reencoded_message = NULL;
- const char *message, *encoding;
- char *defmsg = git_pathdup("MERGE_MSG");
- struct merge_options o;
- struct tree *result, *next_tree, *base_tree, *head_tree;
- static struct lock_file index_lock;
+ const char *me;
+ struct strbuf msgbuf;
+ char *reencoded_message = NULL;
+ const char *encoding;
+ int failed;
git_config(git_default_config, NULL);
- me = action == REVERT ? "revert" : "cherry-pick";
+ me = flags & PICK_REVERSE ? "revert" : "cherry-pick";
setenv(GIT_REFLOG_ACTION, me, 0);
parse_args(argc, argv);
- /* this is copied from the shell script, but it's never triggered... */
- if (action == REVERT && !no_replay)
- die("revert is incompatible with replay");
-
if (read_cache() < 0)
die("git %s: failed to read the index", me);
- if (no_commit) {
- /*
- * We do not intend to commit immediately. We just want to
- * merge the differences in, so let's compute the tree
- * that represents the "current" state for merge-recursive
- * to work on.
- */
- if (write_cache_as_tree(head, 0, NULL))
- die ("Your index file is unmerged.");
- } else {
- if (get_sha1("HEAD", head))
- die ("You do not have a valid HEAD");
- if (index_differs_from("HEAD", 0))
- die_dirty_index(me);
- }
- discard_cache();
-
- index_fd = hold_locked_index(&index_lock, 1);
+ if (!no_commit && index_differs_from("HEAD", 0))
+ die_dirty_index(me);
- if (!commit->parents) {
- if (action == REVERT)
- die ("Cannot revert a root commit");
- parent = NULL;
- }
- else if (commit->parents->next) {
- /* Reverting or cherry-picking a merge commit */
- int cnt;
- struct commit_list *p;
-
- if (!mainline)
- die("Commit %s is a merge but no -m option was given.",
- sha1_to_hex(commit->object.sha1));
-
- for (cnt = 1, p = commit->parents;
- cnt != mainline && p;
- cnt++)
- p = p->next;
- if (cnt != mainline || !p)
- die("Commit %s does not have parent %d",
- sha1_to_hex(commit->object.sha1), mainline);
- parent = p->item;
- } else if (0 < mainline)
- die("Mainline was specified but commit %s is not a merge.",
- sha1_to_hex(commit->object.sha1));
- else
- parent = commit->parents->item;
-
- if (!(message = commit->buffer))
- die ("Cannot get commit message for %s",
+ if (!commit->buffer)
+ return error("Cannot get commit message for %s",
sha1_to_hex(commit->object.sha1));
-
- if (parent && parse_commit(parent) < 0)
- die("%s: cannot parse parent commit %s",
- me, sha1_to_hex(parent->object.sha1));
-
- /*
- * "commit" is an existing commit. We would want to apply
- * the difference it introduces since its first parent "prev"
- * on top of the current HEAD if we are cherry-pick. Or the
- * reverse of it if we are revert.
- */
-
- msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
- LOCK_DIE_ON_ERROR);
-
- encoding = get_encoding(message);
+ encoding = get_encoding(commit->buffer);
if (!encoding)
encoding = "UTF-8";
if (!git_commit_encoding)
git_commit_encoding = "UTF-8";
- if ((reencoded_message = reencode_string(message,
+ if ((reencoded_message = reencode_string(commit->buffer,
git_commit_encoding, encoding)))
- message = reencoded_message;
-
- oneline = get_oneline(message);
-
- if (action == REVERT) {
- char *oneline_body = strchr(oneline, ' ');
-
- base = commit;
- next = parent;
- add_to_msg("Revert \"");
- add_to_msg(oneline_body + 1);
- add_to_msg("\"\n\nThis reverts commit ");
- add_to_msg(sha1_to_hex(commit->object.sha1));
-
- if (commit->parents->next) {
- add_to_msg(", reversing\nchanges made to ");
- add_to_msg(sha1_to_hex(parent->object.sha1));
- }
- add_to_msg(".\n");
- } else {
- base = parent;
- next = commit;
- set_author_ident_env(message);
- add_message_to_msg(message);
- if (no_replay) {
- add_to_msg("(cherry picked from commit ");
- add_to_msg(sha1_to_hex(commit->object.sha1));
- add_to_msg(")\n");
- }
- }
-
- read_cache();
- init_merge_options(&o);
- o.branch1 = "HEAD";
- o.branch2 = oneline;
+ commit->buffer = reencoded_message;
- head_tree = parse_tree_indirect(head);
- next_tree = next ? next->tree : empty_tree();
- base_tree = base ? base->tree : empty_tree();
-
- clean = merge_trees(&o,
- head_tree,
- next_tree, base_tree, &result);
-
- if (active_cache_changed &&
- (write_cache(index_fd, active_cache, active_nr) ||
- commit_locked_index(&index_lock)))
- die("%s: Unable to write new index file", me);
- rollback_lock_file(&index_lock);
-
- if (!clean) {
- add_to_msg("\nConflicts:\n\n");
- for (i = 0; i < active_nr;) {
- struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- add_to_msg("\t");
- add_to_msg(ce->name);
- add_to_msg("\n");
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
- }
- if (commit_lock_file(&msg_file) < 0)
- die ("Error wrapping up %s", defmsg);
+ failed = pick_commit(commit, mainline, flags, &msgbuf);
+ if (failed < 0) {
+ exit(1);
+ } else if (failed > 0) {
fprintf(stderr, "Automatic %s failed.%s\n",
me, help_msg(commit->object.sha1));
+ write_message(&msgbuf, git_path("MERGE_MSG"));
rerere(allow_rerere_auto);
exit(1);
}
- if (commit_lock_file(&msg_file) < 0)
- die ("Error wrapping up %s", defmsg);
+ if (!(flags & PICK_REVERSE))
+ set_author_ident_env(commit->buffer);
+ free(reencoded_message);
+
fprintf(stderr, "Finished one %s.\n", me);
+ write_message(&msgbuf, git_path("MERGE_MSG"));
+
/*
- *
* If we are cherry-pick, and if the merge did not result in
* hand-editing, we will hit this commit and inherit the original
* author date and name.
@@ -436,14 +257,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
args[i++] = "-s";
if (!edit) {
args[i++] = "-F";
- args[i++] = defmsg;
+ args[i++] = git_path("MERGE_MSG");
}
args[i] = NULL;
return execv_git_cmd(args);
}
- free(reencoded_message);
- free(defmsg);
-
return 0;
}
@@ -451,14 +269,12 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
{
if (isatty(0))
edit = 1;
- no_replay = 1;
- action = REVERT;
+ flags = PICK_REVERSE | PICK_ADD_NOTE;
return revert_or_cherry_pick(argc, argv);
}
int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
{
- no_replay = 0;
- action = CHERRY_PICK;
+ flags = 0;
return revert_or_cherry_pick(argc, argv);
}
diff --git a/pick.c b/pick.c
new file mode 100644
index 0000000..bb04c68
--- /dev/null
+++ b/pick.c
@@ -0,0 +1,218 @@
+#include "cache.h"
+#include "commit.h"
+#include "run-command.h"
+#include "cache-tree.h"
+#include "pick.h"
+#include "merge-recursive.h"
+
+static struct commit *commit;
+
+static char *get_oneline(const char *message)
+{
+ char *result;
+ const char *p = message, *abbrev, *eol;
+ int abbrev_len, oneline_len;
+
+ if (!p)
+ return NULL;
+ while (*p && (*p != '\n' || p[1] != '\n'))
+ p++;
+
+ if (*p) {
+ p += 2;
+ for (eol = p + 1; *eol && *eol != '\n'; eol++)
+ ; /* do nothing */
+ } else
+ eol = p;
+ abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
+ abbrev_len = strlen(abbrev);
+ oneline_len = eol - p;
+ result = xmalloc(abbrev_len + 5 + oneline_len);
+ memcpy(result, abbrev, abbrev_len);
+ memcpy(result + abbrev_len, "... ", 4);
+ memcpy(result + abbrev_len + 4, p, oneline_len);
+ result[abbrev_len + 4 + oneline_len] = '\0';
+ return result;
+}
+
+static void add_message_to_msg(struct strbuf *msg, const char *message)
+{
+ const char *p = message;
+ while (*p && (*p != '\n' || p[1] != '\n'))
+ p++;
+
+ if (!*p)
+ strbuf_addstr(msg, sha1_to_hex(commit->object.sha1));
+
+ p += 2;
+ strbuf_addstr(msg, p);
+ return;
+}
+
+static struct tree *empty_tree(void)
+{
+ struct tree *tree = xcalloc(1, sizeof(struct tree));
+
+ tree->object.parsed = 1;
+ tree->object.type = OBJ_TREE;
+ pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
+ return tree;
+}
+
+/*
+ * Pick changes introduced by "commit" argument into current working
+ * tree and index.
+ *
+ * It starts from the current index (not HEAD), and allow the effect
+ * of one commit replayed (either forward or backward) to that state,
+ * leaving the result in the index.
+ *
+ * You do not have to start from a commit, so you can replay many commits
+ * to the index in sequence without commiting in between to squash multiple
+ * steps if you wanted to.
+ *
+ * Return 0 on success.
+ * Return negative value on error before picking,
+ * and a positive value after picking,
+ * and return 1 if and only if a conflict occurs but no other error.
+ */
+int pick_commit(struct commit *pick_commit, int mainline, int flags,
+ struct strbuf *msg)
+{
+ unsigned char head[20];
+ struct commit *base, *next, *parent;
+ int i, index_fd, clean;
+ int ret = 0;
+ char *oneline;
+ const char *message;
+ struct merge_options o;
+ struct tree *result, *next_tree, *base_tree, *head_tree;
+ static struct lock_file index_lock;
+
+ strbuf_init(msg, 0);
+ commit = pick_commit;
+
+ /*
+ * Let's compute the tree that represents the "current" state
+ * for merge-recursive to work on.
+ */
+ if (write_cache_as_tree(head, 0, NULL))
+ return error("Your index file is unmerged.");
+ discard_cache();
+
+ index_fd = hold_locked_index(&index_lock, 0);
+ if (index_fd < 0)
+ return error("Unable to create locked index: %s",
+ strerror(errno));
+
+ if (!commit->parents) {
+ if (flags & PICK_REVERSE)
+ return error("Cannot revert a root commit");
+ parent = NULL;
+ }
+ else if (commit->parents->next) {
+ /* Reverting or cherry-picking a merge commit */
+ int cnt;
+ struct commit_list *p;
+
+ if (!mainline)
+ return error("Commit %s is a merge but no mainline was given.",
+ sha1_to_hex(commit->object.sha1));
+
+ for (cnt = 1, p = commit->parents;
+ cnt != mainline && p;
+ cnt++)
+ p = p->next;
+ if (cnt != mainline || !p)
+ return error("Commit %s does not have parent %d",
+ sha1_to_hex(commit->object.sha1),
+ mainline);
+ parent = p->item;
+ } else if (0 < mainline)
+ return error("Mainline was specified but commit %s is not a merge.",
+ sha1_to_hex(commit->object.sha1));
+ else
+ parent = commit->parents->item;
+
+ if (!(message = commit->buffer))
+ return error("Cannot get commit message for %s",
+ sha1_to_hex(commit->object.sha1));
+
+ if (parent && parse_commit(parent) < 0)
+ return error("Cannot parse parent commit %s",
+ sha1_to_hex(parent->object.sha1));
+
+ oneline = get_oneline(message);
+
+ if (flags & PICK_REVERSE) {
+ char *oneline_body = strchr(oneline, ' ');
+
+ base = commit;
+ next = parent;
+ strbuf_addstr(msg, "Revert \"");
+ strbuf_addstr(msg, oneline_body + 1);
+ strbuf_addstr(msg, "\"\n\nThis reverts commit ");
+ strbuf_addstr(msg, sha1_to_hex(commit->object.sha1));
+
+ if (commit->parents->next) {
+ strbuf_addstr(msg, ", reversing\nchanges made to ");
+ strbuf_addstr(msg, sha1_to_hex(parent->object.sha1));
+ }
+ strbuf_addstr(msg, ".\n");
+ } else {
+ base = parent;
+ next = commit;
+ add_message_to_msg(msg, message);
+ if (flags & PICK_ADD_NOTE) {
+ strbuf_addstr(msg, "(cherry picked from commit ");
+ strbuf_addstr(msg, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(msg, ")\n");
+ }
+ }
+
+ read_cache();
+ init_merge_options(&o);
+ o.branch1 = "HEAD";
+ o.branch2 = oneline;
+
+ head_tree = parse_tree_indirect(head);
+ next_tree = next ? next->tree : empty_tree();
+ base_tree = base ? base->tree : empty_tree();
+
+ clean = merge_trees(&o,
+ head_tree,
+ next_tree, base_tree, &result);
+
+ if (active_cache_changed &&
+ (write_cache(index_fd, active_cache, active_nr) ||
+ commit_locked_index(&index_lock))) {
+ error("Unable to write new index file");
+ return 2;
+ }
+ rollback_lock_file(&index_lock);
+
+ if (!clean) {
+ strbuf_addstr(msg, "\nConflicts:\n\n");
+ for (i = 0; i < active_nr;) {
+ struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_addstr(msg, "\t");
+ strbuf_addstr(msg, ce->name);
+ strbuf_addstr(msg, "\n");
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
+ ret = 1;
+ }
+ free(oneline);
+
+ discard_cache();
+ if (read_cache() < 0) {
+ error("Cannot read the index");
+ return 2;
+ }
+
+ return ret;
+}
diff --git a/pick.h b/pick.h
new file mode 100644
index 0000000..7a74ad8
--- /dev/null
+++ b/pick.h
@@ -0,0 +1,13 @@
+#ifndef PICK_H
+#define PICK_H
+
+#include "commit.h"
+
+/* Pick flags: */
+#define PICK_REVERSE 1 /* pick the reverse changes ("revert") */
+#define PICK_ADD_NOTE 2 /* add note about original commit (unless conflict) */
+/* We don't need a PICK_QUIET. This is done by
+ * setenv("GIT_MERGE_VERBOSITY", "0", 1); */
+extern int pick_commit(struct commit *commit, int mainline, int flags, struct strbuf *msg);
+
+#endif
--
1.6.6.1.557.g77031
^ permalink raw reply related
* [RFC/PATCH 6/6] rebase -i: use new --ff cherry-pick option
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201074835.3929.11509.chriscool@tuxfamily.org>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
git-rebase--interactive.sh | 15 +++------------
1 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index c2f6089..6b224a6 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -222,8 +222,8 @@ do_with_author () {
}
pick_one () {
- no_ff=
- case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac
+ ff=--ff
+ case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
test -d "$REWRITTEN" &&
pick_one_preserving_merges "$@" && return
@@ -232,16 +232,7 @@ pick_one () {
output git cherry-pick "$@"
return
fi
- parent_sha1=$(git rev-parse --verify $sha1^) ||
- die "Could not get the parent of $sha1"
- current_sha1=$(git rev-parse --verify HEAD)
- if test -z "$no_ff" && test "$current_sha1" = "$parent_sha1"
- then
- output git reset --hard $sha1
- output warn Fast-forward to $(git rev-parse --short $sha1)
- else
- output git cherry-pick "$@"
- fi
+ output git cherry-pick $ff "$@"
}
pick_one_preserving_merges () {
--
1.6.6.1.557.g77031
^ permalink raw reply related
* [RFC/PATCH 3/6] reset: refactor reseting in its own function
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201074835.3929.11509.chriscool@tuxfamily.org>
This splits the reseting logic away from the argument parsing.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-reset.c | 138 +++++++++++++++++++++++++++++-------------------------
1 files changed, 74 insertions(+), 64 deletions(-)
diff --git a/builtin-reset.c b/builtin-reset.c
index 3569695..bf97931 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -235,68 +235,13 @@ static int update_heads(unsigned char *sha1)
return update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
}
-int cmd_reset(int argc, const char **argv, const char *prefix)
+static int reset(const char *rev, const char *prefix,
+ int reset_type, int quiet, int patch_mode,
+ int argc, const char **argv)
{
- int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
- int patch_mode = 0;
- const char *rev = "HEAD";
- unsigned char sha1[20];
struct commit *commit;
- char *reflog_action;
- const struct option options[] = {
- OPT__QUIET(&quiet),
- OPT_SET_INT(0, "mixed", &reset_type,
- "reset HEAD and index", MIXED),
- OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
- OPT_SET_INT(0, "hard", &reset_type,
- "reset HEAD, index and working tree", HARD),
- OPT_SET_INT(0, "merge", &reset_type,
- "reset HEAD, index and working tree", MERGE),
- OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
- OPT_END()
- };
-
- git_config(git_default_config, NULL);
-
- argc = parse_options(argc, argv, prefix, options, git_reset_usage,
- PARSE_OPT_KEEP_DASHDASH);
- reflog_action = args_to_str(argv);
- setenv("GIT_REFLOG_ACTION", reflog_action, 0);
-
- /*
- * Possible arguments are:
- *
- * git reset [-opts] <rev> <paths>...
- * git reset [-opts] <rev> -- <paths>...
- * git reset [-opts] -- <paths>...
- * git reset [-opts] <paths>...
- *
- * At this point, argv[i] points immediately after [-opts].
- */
-
- if (i < argc) {
- if (!strcmp(argv[i], "--")) {
- i++; /* reset to HEAD, possibly with paths */
- } else if (i + 1 < argc && !strcmp(argv[i+1], "--")) {
- rev = argv[i];
- i += 2;
- }
- /*
- * Otherwise, argv[i] could be either <rev> or <paths> and
- * has to be unambiguous.
- */
- else if (!get_sha1(argv[i], sha1)) {
- /*
- * Ok, argv[i] looks like a rev; it should not
- * be a filename.
- */
- verify_non_filename(prefix, argv[i]);
- rev = argv[i++];
- } else {
- /* Otherwise we treat this as a filename */
- verify_filename(prefix, argv[i]);
- }
- }
+ unsigned char sha1[20];
+ int update_ref_status;
if (get_sha1(rev, sha1))
die("Failed to resolve '%s' as a valid ref.", rev);
@@ -309,19 +254,19 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (patch_mode) {
if (reset_type != NONE)
die("--patch is incompatible with --{hard,mixed,soft}");
- return interactive_reset(rev, argv + i, prefix);
+ return interactive_reset(rev, argv, prefix);
}
/* git reset tree [--] paths... can be used to
* load chosen paths from the tree into the index without
* affecting the working tree nor HEAD. */
- if (i < argc) {
+ if (argc > 0) {
if (reset_type == MIXED)
warning("--mixed option is deprecated with paths.");
else if (reset_type != NONE)
die("Cannot do %s reset with paths.",
reset_type_names[reset_type]);
- return read_from_tree(prefix, argv + i, sha1,
+ return read_from_tree(prefix, argv, sha1,
quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
}
if (reset_type == NONE)
@@ -361,7 +306,72 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
remove_branch_state();
+ return update_ref_status;
+}
+
+int cmd_reset(int argc, const char **argv, const char *prefix)
+{
+ int i = 0, reset_type = NONE, quiet = 0;
+ int patch_mode = 0;
+ const char *rev = "HEAD";
+ unsigned char sha1[20];
+ char *reflog_action;
+ const struct option options[] = {
+ OPT__QUIET(&quiet),
+ OPT_SET_INT(0, "mixed", &reset_type,
+ "reset HEAD and index", MIXED),
+ OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
+ OPT_SET_INT(0, "hard", &reset_type,
+ "reset HEAD, index and working tree", HARD),
+ OPT_SET_INT(0, "merge", &reset_type,
+ "reset HEAD, index and working tree", MERGE),
+ OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+ OPT_END()
+ };
+
+ git_config(git_default_config, NULL);
+
+ argc = parse_options(argc, argv, prefix, options, git_reset_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+ reflog_action = args_to_str(argv);
+ setenv("GIT_REFLOG_ACTION", reflog_action, 0);
free(reflog_action);
- return update_ref_status;
+ /*
+ * Possible arguments are:
+ *
+ * git reset [-opts] <rev> <paths>...
+ * git reset [-opts] <rev> -- <paths>...
+ * git reset [-opts] -- <paths>...
+ * git reset [-opts] <paths>...
+ *
+ * At this point, argv[i] points immediately after [-opts].
+ */
+
+ if (i < argc) {
+ if (!strcmp(argv[i], "--")) {
+ i++; /* reset to HEAD, possibly with paths */
+ } else if (i + 1 < argc && !strcmp(argv[i+1], "--")) {
+ rev = argv[i];
+ i += 2;
+ }
+ /*
+ * Otherwise, argv[i] could be either <rev> or <paths> and
+ * has to be unambiguous.
+ */
+ else if (!get_sha1(argv[i], sha1)) {
+ /*
+ * Ok, argv[i] looks like a rev; it should not
+ * be a filename.
+ */
+ verify_non_filename(prefix, argv[i]);
+ rev = argv[i++];
+ } else {
+ /* Otherwise we treat this as a filename */
+ verify_filename(prefix, argv[i]);
+ }
+ }
+
+ return reset(rev, prefix, reset_type, quiet, patch_mode,
+ argc - i, argv + i);
}
--
1.6.6.1.557.g77031
^ permalink raw reply related
* [RFC/PATCH 5/6] revert: add --ff option to allow fast forward when cherry-picking
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201074835.3929.11509.chriscool@tuxfamily.org>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-revert.c | 25 +++++++++++++++++++++----
1 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/builtin-revert.c b/builtin-revert.c
index 3cbeab7..3f92515 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -9,6 +9,7 @@
#include "revision.h"
#include "rerere.h"
#include "pick.h"
+#include "reset.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -31,7 +32,7 @@ static const char * const cherry_pick_usage[] = {
NULL
};
-static int edit, no_commit, mainline, signoff;
+static int edit, no_commit, mainline, signoff, ff_ok;
static int flags;
static struct commit *commit;
static int allow_rerere_auto;
@@ -51,6 +52,7 @@ static void parse_args(int argc, const char **argv)
OPT_BIT('x', NULL, &flags, "append commit name when cherry-picking", PICK_ADD_NOTE),
OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"),
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
+ OPT_BOOLEAN(0, "ff", &ff_ok, "allow fast forward"),
OPT_INTEGER('m', "mainline", &mainline, "parent number"),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_END(),
@@ -71,6 +73,8 @@ static void parse_args(int argc, const char **argv)
}
if (commit->object.type != OBJ_COMMIT)
die ("'%s' does not point to a commit", arg);
+ if (ff_ok && no_commit)
+ die ("options --ff and --no-commit are incompatible");
}
static char *get_encoding(const char *message)
@@ -191,7 +195,7 @@ static NORETURN void die_dirty_index(const char *me)
}
}
-static int revert_or_cherry_pick(int argc, const char **argv)
+static int revert_or_cherry_pick(int argc, const char **argv, const char *prefix)
{
const char *me;
struct strbuf msgbuf;
@@ -209,6 +213,19 @@ static int revert_or_cherry_pick(int argc, const char **argv)
if (!no_commit && index_differs_from("HEAD", 0))
die_dirty_index(me);
+ if (!(flags & PICK_REVERSE) && ff_ok && commit->parents) {
+ unsigned char head_sha1[20];
+ if (get_sha1("HEAD", head_sha1))
+ die("You do not have a valid HEAD.");
+ if (!hashcmp(commit->parents->item->object.sha1, head_sha1)) {
+ char *hex = sha1_to_hex(commit->object.sha1);
+ int res = reset(hex, prefix, HARD, 0, 0, 0, NULL);
+ if (!res)
+ fprintf(stderr, "Fast-forward to %s\n", hex);
+ return res;
+ }
+ }
+
if (!commit->buffer)
return error("Cannot get commit message for %s",
sha1_to_hex(commit->object.sha1));
@@ -270,11 +287,11 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
if (isatty(0))
edit = 1;
flags = PICK_REVERSE | PICK_ADD_NOTE;
- return revert_or_cherry_pick(argc, argv);
+ return revert_or_cherry_pick(argc, argv, prefix);
}
int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
{
flags = 0;
- return revert_or_cherry_pick(argc, argv);
+ return revert_or_cherry_pick(argc, argv, prefix);
}
--
1.6.6.1.557.g77031
^ permalink raw reply related
* [RFC/PATCH 4/6] reset: make reset function non static and declare it in "reset.h"
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201074835.3929.11509.chriscool@tuxfamily.org>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-reset.c | 8 ++++----
reset.h | 10 ++++++++++
2 files changed, 14 insertions(+), 4 deletions(-)
create mode 100644 reset.h
diff --git a/builtin-reset.c b/builtin-reset.c
index bf97931..b004f9a 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -20,6 +20,7 @@
#include "parse-options.h"
#include "unpack-trees.h"
#include "cache-tree.h"
+#include "reset.h"
static const char * const git_reset_usage[] = {
"git reset [--mixed | --soft | --hard | --merge] [-q] [<commit>]",
@@ -27,7 +28,6 @@ static const char * const git_reset_usage[] = {
NULL
};
-enum reset_type { MIXED, SOFT, HARD, MERGE, NONE };
static const char *reset_type_names[] = { "mixed", "soft", "hard", "merge", NULL };
static char *args_to_str(const char **argv)
@@ -235,9 +235,9 @@ static int update_heads(unsigned char *sha1)
return update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
}
-static int reset(const char *rev, const char *prefix,
- int reset_type, int quiet, int patch_mode,
- int argc, const char **argv)
+int reset(const char *rev, const char *prefix,
+ int reset_type, int quiet, int patch_mode,
+ int argc, const char **argv)
{
struct commit *commit;
unsigned char sha1[20];
diff --git a/reset.h b/reset.h
new file mode 100644
index 0000000..c8497e4
--- /dev/null
+++ b/reset.h
@@ -0,0 +1,10 @@
+#ifndef RESET_H
+#define RESET_H
+
+enum reset_type { MIXED, SOFT, HARD, MERGE, NONE };
+
+int reset(const char *rev, const char *prefix,
+ int reset_type, int quiet, int patch_mode,
+ int argc, const char **argv);
+
+#endif
--
1.6.6.1.557.g77031
^ permalink raw reply related
* [RFC/PATCH 0/6] add --ff option to cherry-pick
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
The goal of this series is to add a --ff fast forward otion to cherry-pick
and use it in "rebase -i".
There is no documentation yet and the commit messages are too short but
this will be improved if the series looks worthwhile.
The first patch in this series is a refactoring patch that is not really
needed, but as it looks like a good refactoring/cleanup anyway I left it in.
Christian Couder (5):
reset: refactor updating heads into a static function
reset: refactor reseting in its own function
reset: make reset function non static and declare it in "reset.h"
revert: add --ff option to allow fast forward when cherry-picking
rebase -i: use new --ff cherry-pick option
Stephan Beyer (1):
revert: libify cherry-pick and revert functionnality
Makefile | 2 +
builtin-reset.c | 175 +++++++++++++++------------
builtin-revert.c | 293 ++++++++++----------------------------------
git-rebase--interactive.sh | 15 +--
pick.c | 218 ++++++++++++++++++++++++++++++++
pick.h | 13 ++
reset.h | 10 ++
7 files changed, 407 insertions(+), 319 deletions(-)
create mode 100644 pick.c
create mode 100644 pick.h
create mode 100644 reset.h
^ permalink raw reply
* [RFC/PATCH 2/6] reset: refactor updating heads into a static function
From: Christian Couder @ 2010-02-01 7:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Linus Torvalds, Johannes Schindelin, Stephan Beyer,
Daniel Barkalow
In-Reply-To: <20100201074835.3929.11509.chriscool@tuxfamily.org>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-reset.c | 43 +++++++++++++++++++++++++++----------------
1 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/builtin-reset.c b/builtin-reset.c
index 0f5022e..3569695 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -211,15 +211,38 @@ static void prepend_reflog_action(const char *action, char *buf, size_t size)
warning("Reflog action message too long: %.*s...", 50, buf);
}
+/*
+ * Any resets update HEAD to the head being switched to,
+ * saving the previous head in ORIG_HEAD before.
+ */
+static int update_heads(unsigned char *sha1)
+{
+ unsigned char sha1_orig[20], *orig = NULL,
+ sha1_old_orig[20], *old_orig = NULL;
+ char msg[1024];
+
+ if (!get_sha1("ORIG_HEAD", sha1_old_orig))
+ old_orig = sha1_old_orig;
+ if (!get_sha1("HEAD", sha1_orig)) {
+ orig = sha1_orig;
+ prepend_reflog_action("updating ORIG_HEAD", msg, sizeof(msg));
+ update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
+ }
+ else if (old_orig)
+ delete_ref("ORIG_HEAD", old_orig, 0);
+ prepend_reflog_action("updating HEAD", msg, sizeof(msg));
+
+ return update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
+}
+
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
int patch_mode = 0;
const char *rev = "HEAD";
- unsigned char sha1[20], *orig = NULL, sha1_orig[20],
- *old_orig = NULL, sha1_old_orig[20];
+ unsigned char sha1[20];
struct commit *commit;
- char *reflog_action, msg[1024];
+ char *reflog_action;
const struct option options[] = {
OPT__QUIET(&quiet),
OPT_SET_INT(0, "mixed", &reset_type,
@@ -321,19 +344,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
else if (reset_index_file(sha1, reset_type, quiet))
die("Could not reset index file to revision '%s'.", rev);
- /* Any resets update HEAD to the head being switched to,
- * saving the previous head in ORIG_HEAD before. */
- if (!get_sha1("ORIG_HEAD", sha1_old_orig))
- old_orig = sha1_old_orig;
- if (!get_sha1("HEAD", sha1_orig)) {
- orig = sha1_orig;
- prepend_reflog_action("updating ORIG_HEAD", msg, sizeof(msg));
- update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
- }
- else if (old_orig)
- delete_ref("ORIG_HEAD", old_orig, 0);
- prepend_reflog_action("updating HEAD", msg, sizeof(msg));
- update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
+ update_ref_status = update_heads(sha1);
switch (reset_type) {
case HARD:
--
1.6.6.1.557.g77031
^ permalink raw reply related
* Re: GIT_WORK_TREE environment variable not working
From: Ron Garret @ 2010-02-01 7:09 UTC (permalink / raw)
To: git
In-Reply-To: <20100201051942.GA7761@coredump.intra.peff.net>
In article <20100201051942.GA7761@coredump.intra.peff.net>,
Jeff King <peff@peff.net> wrote:
> On Sun, Jan 31, 2010 at 05:33:47PM -0800, Ron Garret wrote:
>
> > What am I doing wrong here?
> >
> > [ron@mickey:~/devel/gittest]$ pwd
> > /Users/ron/devel/gittest
> > [ron@mickey:~/devel/gittest]$ git status
> > # On branch master
> > # Untracked files:
> > # (use "git add <file>..." to include in what will be committed)
> > #
> > # git/
> > nothing added to commit but untracked files present (use "git add" to
> > track)
> > [ron@mickey:~/devel/gittest]$ cd
> > [ron@mickey:~]$ export GIT_WORK_TREE=/Users/ron/devel/gittest
> > [ron@mickey:~]$ git status
> > fatal: Not a git repository (or any of the parent directories): .git
> > [ron@mickey:~]$ git status --work-tree=/Users/ron/devel/gittest
> > fatal: Not a git repository (or any of the parent directories): .git
> > [ron@mickey:~]$
>
> You haven't told git where to find the repository itself. GIT_WORK_TREE
> is about saying "here are my work tree files", but it is explicitly not
> about "here is where my .git directory is". That lets you keep the two
> in totally separate locations. E.g., you could do something like
> tracking /etc, but keep your .git directory in /var.
>
> For your case above, you would want to also
>
> export GIT_DIR=/Users/ron/devel/gittest/.git
Ah. Thanks!
> though since you have a fully formed repository, I don't think there is
> really any advantage over just doing:
>
> cd /Users/ron/devel/gittest && git $whatever
>
> though perhaps that is because this is not a real use case, but rather
> just you trying to figure out the feature. :)
It's a real use case. The situation is that I'm using git as a back end
for an IDE, so I can't rely on the cwd.
rg
^ permalink raw reply
* Re: the workflow (from your POV) of managing git
From: Jeff King @ 2010-02-01 5:46 UTC (permalink / raw)
To: layer; +Cc: git
In-Reply-To: <20375.1265000441@relay.known.net>
On Sun, Jan 31, 2010 at 09:00:41PM -0800, layer wrote:
> Have you written anything up that tells people how you manage the git
> project? Something that could be used by other project leaders? I've
> been googling and haven't been able to find anything other than
> documents which describe the process from the other side (people
> submitting patches).
Try Documentation/howto/maintain-git.txt.
> could learn from by seeing a document on the process you use. For
> example, do you have a script that generates the "what's cooking
> in..." emails?
Check out the 'todo' branch in git.git.
-Peff
^ permalink raw reply
* Re: [PATCH] rebase: don't invoke the pager for each commit summary
From: Stephen Boyd @ 2010-02-01 5:39 UTC (permalink / raw)
To: Markus Heidelberg; +Cc: Junio C Hamano, git
In-Reply-To: <1264868617-18547-1-git-send-email-markus.heidelberg@web.de>
On Sat, Jan 30, 2010 at 8:23 AM, Markus Heidelberg
<markus.heidelberg@web.de> wrote:
> This regression was introduced by commit 0aa958d (rebase: replace
> antiquated sed invocation, 2010-01-24), which changed the invocation of
> "git rev-list | sed" to "git log".
>
> It can be reproduced by something like this:
> $ git rebase -s recursive origin/master
>
> Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de>
>
Thanks. Maybe you can use git show too instead of git log -1?
^ permalink raw reply
* Re: GIT_WORK_TREE environment variable not working
From: Jeff King @ 2010-02-01 5:19 UTC (permalink / raw)
To: Ron Garret; +Cc: git
In-Reply-To: <ron1-8E7697.17334731012010@news.gmane.org>
On Sun, Jan 31, 2010 at 05:33:47PM -0800, Ron Garret wrote:
> What am I doing wrong here?
>
> [ron@mickey:~/devel/gittest]$ pwd
> /Users/ron/devel/gittest
> [ron@mickey:~/devel/gittest]$ git status
> # On branch master
> # Untracked files:
> # (use "git add <file>..." to include in what will be committed)
> #
> # git/
> nothing added to commit but untracked files present (use "git add" to
> track)
> [ron@mickey:~/devel/gittest]$ cd
> [ron@mickey:~]$ export GIT_WORK_TREE=/Users/ron/devel/gittest
> [ron@mickey:~]$ git status
> fatal: Not a git repository (or any of the parent directories): .git
> [ron@mickey:~]$ git status --work-tree=/Users/ron/devel/gittest
> fatal: Not a git repository (or any of the parent directories): .git
> [ron@mickey:~]$
You haven't told git where to find the repository itself. GIT_WORK_TREE
is about saying "here are my work tree files", but it is explicitly not
about "here is where my .git directory is". That lets you keep the two
in totally separate locations. E.g., you could do something like
tracking /etc, but keep your .git directory in /var.
For your case above, you would want to also
export GIT_DIR=/Users/ron/devel/gittest/.git
though since you have a fully formed repository, I don't think there is
really any advantage over just doing:
cd /Users/ron/devel/gittest && git $whatever
though perhaps that is because this is not a real use case, but rather
just you trying to figure out the feature. :)
-Peff
^ permalink raw reply
* the workflow (from your POV) of managing git
From: layer @ 2010-02-01 5:00 UTC (permalink / raw)
To: git
Junio, greetings.
Have you written anything up that tells people how you manage the git
project? Something that could be used by other project leaders? I've
been googling and haven't been able to find anything other than
documents which describe the process from the other side (people
submitting patches).
A lot can be gleaned by looking at it from the patch-submitter side,
but I'm guessing there are lots of little tips that project leads
could learn from by seeing a document on the process you use. For
example, do you have a script that generates the "what's cooking
in..." emails?
Thanks!
Kevin
^ permalink raw reply
* Re: Partially private repository?
From: Daed Lee @ 2010-02-01 4:59 UTC (permalink / raw)
To: Avery Pennarun; +Cc: git
In-Reply-To: <32541b131001291410g252ddff4lbf04ac7c1d2d33fc@mail.gmail.com>
On Fri, Jan 29, 2010 at 5:10 PM, Avery Pennarun <apenwarr@gmail.com> wrote:
> On Fri, Jan 29, 2010 at 5:01 PM, Daed Lee <daed@thoughtsofcode.com> wrote:
>> Hi, I'm wondering if git can handle the following use. I have a
>> project that started as private experiment, but has morphed into
>> something I'd like to release publicly. I want to give others access
>> to the repository, but only to commits after a certain cutoff date.
>> Commits prior to that date have things like hardcoded file paths,
>> emails, etc. that I'd like to keep private.
>>
>> I suppose the easiest thing to do would be to create a new repository,
>> add the project files to it, and make that public, however I'd like to
>> keep my private commit history along with the public commit history
>> going forward in a single repository if possible. Is there a way to do
>> this with git?
>
> You should probably split your history into two pieces: the "before"
> and "after" parts. To split out the "after" part, you could use
> git-filter-branch
> (http://www.kernel.org/pub/software/scm/git/docs/v1.6.0.6/git-filter-branch.html).
> Then, in your private copy of the repo, you could reattach the
> "before" part of the history using git grafts.
Going forward, if I made changes to my private repository (containing
the "before" and "after" parts) and pushed to the public repository
(containing only the "after" part), would this only push the commits
in the "after" part? Essentially, I want to develop in my private
repository and see my "before" and "after" changes when I "git
log/show", but only push the "after" changes to the public repository.
I've also been looking into private branches. Could I do something
like keep my "before" changes on a private branch, and then do all
future development on a public branch?
Thanks for the pointer to git grafts, I'll have to read up on it further.
^ permalink raw reply
* Re: [PATCH] git-svn: persistent memoization
From: Eric Wong @ 2010-02-01 4:03 UTC (permalink / raw)
To: Andrew Myrick; +Cc: git, sam
In-Reply-To: <1264821262-28322-1-git-send-email-amyrick@apple.com>
Andrew Myrick <amyrick@apple.com> wrote:
> Make memoization of the svn:mergeinfo processing functions persistent with
> Memoize::Storable so that the memoization tables don't need to be regenerated
> every time the user runs git-svn fetch.
>
> The Memoize::Storable hashes are stored in ENV{GIT_DIR}/svn/caches.
Hi Andrew,
Perhaps "$ENV{GIT_DIR}/svn/.caches" is better here since older versions
of git svn used "$ENV{GIT_DIR}/svn/$refname" in the top-level and
"caches" may conflict with existing repos.
> -use File::Path qw/mkpath/;
> +use File::Path qw/mkpath make_path/;
File::Path::make_path is very recent not in Perls distributed by most
vendors. My 5.10.0 installation (Debian stable) doesn't have it, and I
also don't see a good reason to use it over the traditional mkpath.
I think I'll squash the following patch and Ack. Let me know if
you have any objections, thanks.!
(also wraps long lines to 80 chars)
diff --git a/git-svn.perl b/git-svn.perl
index 0153439..265852f 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1652,7 +1652,7 @@ use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
$_use_svnsync_props $no_reuse_existing $_minimize_url
$_use_log_author $_add_author_from $_localtime/;
use Carp qw/croak/;
-use File::Path qw/mkpath make_path/;
+use File::Path qw/mkpath/;
use File::Copy qw/copy/;
use IPC::Open3;
use Memoize; # core since 5.8.0, Jul 2002
@@ -3126,25 +3126,25 @@ sub has_no_changes {
return if $memoized;
$memoized = 1;
- my $cache_path = "$ENV{GIT_DIR}/svn/caches/";
- make_path($cache_path) unless -d $cache_path;
+ my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+ mkpath([$cache_path]) unless -d $cache_path;
- tie my %lookup_svn_merge_cache =>
- 'Memoize::Storable',"$cache_path/lookup_svn_merge.db", 'nstore';
+ tie my %lookup_svn_merge_cache => 'Memoize::Storable',
+ "$cache_path/lookup_svn_merge.db", 'nstore';
memoize 'lookup_svn_merge',
SCALAR_CACHE => 'FAULT',
LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache],
;
- tie my %check_cherry_pick_cache =>
- 'Memoize::Storable',"$cache_path/check_cherry_pick.db", 'nstore';
+ tie my %check_cherry_pick_cache => 'Memoize::Storable',
+ "$cache_path/check_cherry_pick.db", 'nstore';
memoize 'check_cherry_pick',
SCALAR_CACHE => 'FAULT',
LIST_CACHE => ['HASH' => \%check_cherry_pick_cache],
;
- tie my %has_no_changes_cache =>
- 'Memoize::Storable',"$cache_path/has_no_changes.db", 'nstore';
+ tie my %has_no_changes_cache => 'Memoize::Storable',
+ "$cache_path/has_no_changes.db", 'nstore';
memoize 'has_no_changes',
SCALAR_CACHE => ['HASH' => \%has_no_changes_cache],
LIST_CACHE => 'FAULT',
--
Eric Wong
^ permalink raw reply related
* What's cooking in git.git (Jan 2010, #10; Sun, 31)
From: Junio C Hamano @ 2010-02-01 3:35 UTC (permalink / raw)
To: git
Here are the topics that have been cooking. Commits prefixed with '-' are
only in 'pu' while commits prefixed with '+' are in 'next'. The ones
marked with '.' do not appear in any of the integration branches, but I am
still holding onto them.
We are passed 1.7.0-rc1; please test "master" branch to avoid giving
regressions to end users. Thanks.
--------------------------------------------------
[Graduated to "master"]
* jl/diff-submodule-ignore (2010-01-24) 2 commits
(merged to 'next' on 2010-01-25 at fbe713d)
+ Teach diff --submodule that modified submodule directory is dirty
+ git diff: Don't test submodule dirtiness with --ignore-submodules
(this branch uses jc/ce-uptodate.)
* jc/ce-uptodate (2010-01-24) 1 commit
(merged to 'next' on 2010-01-25 at fbe713d)
+ Make ce_uptodate() trustworthy again
(this branch is used by jl/diff-submodule-ignore.)
* gp/maint-cvsserver (2010-01-26) 1 commit
+ git-cvsserver: allow regex metacharacters in CVSROOT
* fk/threaded-grep (2010-01-25) 1 commit
(merged to 'next' on 2010-01-26 at 687b2a6)
+ Threaded grep
(this branch uses jc/grep-q.)
400% performance gain on a 4-core box ;-)
* jc/grep-q (2010-01-25) 1 commit
(merged to 'next' on 2010-01-26 at 687b2a6)
+ grep: expose "status-only" feature via -q
(this branch is used by fk/threaded-grep.)
--------------------------------------------------
[New Topics]
* jn/maint-makedepend (2010-01-26) 5 commits
- Makefile: drop dependency on $(wildcard */*.h)
- Makefile: clean up http-walker.o dependency rules
- Makefile: remove wt-status.h from LIB_H
- Makefile: make sure test helpers are rebuilt when headers change
- Makefile: add missing header file dependencies
(this branch is used by jn/makedepend and jn/master-makedepend.)
These look sensible clean-up that could go to maint.
* jn/master-makedepend (2010-01-26) 0 commits
(this branch uses jn/maint-makedepend; is used by jn/makedepend.)
This is to help merging the clean-up to "master".
* jn/makedepend (2010-01-31) 9 commits
- Makefile: always remove .depend directories on 'make clean'
- Makefile: tuck away generated makefile fragments in .depend
- Teach Makefile to check header dependencies
- Makefile: list standalone program object files in PROGRAM_OBJS
- Makefile: lazily compute header dependencies
- Makefile: list generated object files in OBJECTS
- Makefile: disable default implicit rules
- Makefile: rearrange dependency rules
- Makefile: transport.o depends on branch.h now
(this branch uses jn/maint-makedepend and jn/master-makedepend.)
And this is to build on top.
* ms/filter-branch-submodule (2010-01-28) 2 commits
(merged to 'next' on 2010-01-28 at 226cbf8)
+ filter-branch: Add tests for submodules in tree-filter
+ filter-branch: Fix to allow replacing submodules with another content
* jc/checkout-detached (2010-01-29) 1 commit
- Reword "detached HEAD" notification
* jc/maint-fix-test-perm (2010-01-30) 2 commits
- lib-patch-mode.sh: Fix permission
- t6000lib: Fix permission
* jh/gitweb-caching (2010-01-30) 8 commits
- gitweb: Add an option to force version match
- gitweb: Add optional extra parameter to die_error, for extended explanation
- gitweb: add a "string" variant of print_sort_th
- gitweb: add a "string" variant of print_local_time
- gitweb: Check that $site_header etc. are defined before using them
- gitweb: Makefile improvements
- gitweb: Load checking
- gitweb: Make running t9501 test with '--debug' reliable and usable
* jn/makefile-script-lib (2010-01-31) 1 commit
- Do not install shell libraries executable
* mv/request-pull-modernize (2010-01-29) 1 commit
- request-pull: avoid mentioning that the start point is a single commit
* sp/maint-fast-import-large-blob (2010-01-29) 1 commit
- fast-import: Stream very large blobs directly to pack
(this branch is used by sp/fast-import-large-blob.)
Importing a large blob via fast-import may bust the pack size limit (or
2GB filesize limit found on some filesystems).
* sp/fast-import-large-blob (2010-01-29) 0 commits
(this branch uses sp/maint-fast-import-large-blob.)
And this is to help merging the topic to newer codebase.
--------------------------------------------------
[Cooking]
* cc/reset-keep (2010-01-19) 5 commits
- reset: disallow using --keep when there are unmerged entries
- reset: disallow "reset --keep" outside a work tree
- Documentation: reset: describe new "--keep" option
- reset: add test cases for "--keep" option
- reset: add option "--keep" to "git reset"
I do not think I'd ever use this, and I am not convinced I can sell this
to users as a great new feature without confusing them unnecessarily, but
perhaps queuing it to pu to give it wider visibility may help somebody
coming up with a better way to defend the feature and introduce it to
users without confusing them than Christan nor I managed to.
* jh/notes (2010-01-27) 23 commits
- builtin-notes: Add "add" subcommand for appending to note objects
- builtin-notes: Add "list" subcommand for listing note objects
- Documentation: Generalize git-notes docs to 'objects' instead of 'commits'
- builtin-notes: Add "prune" subcommand for removing notes for missing objects
- Notes API: prune_notes(): Prune notes that belong to non-existing objects
- t3305: Verify that removing notes triggers automatic fanout consolidation
- builtin-notes: Add "remove" subcommand for removing existing notes
- Teach builtin-notes to remove empty notes
- Teach notes code to properly preserve non-notes in the notes tree
- t3305: Verify that adding many notes with git-notes triggers increased fanout
- t3301: Verify successful annotation of non-commits
- Builtin-ify git-notes
- Refactor notes concatenation into a flexible interface for combining notes
- Notes API: Allow multiple concurrent notes trees with new struct notes_tree
- Notes API: write_notes_tree(): Store the notes tree in the database
- Notes API: for_each_note(): Traverse the entire notes tree with a callback
- Notes API: get_note(): Return the note annotating the given object
- Notes API: remove_note(): Remove note objects from the notes tree structure
- Notes API: add_note(): Add note objects to the internal notes tree structure
- Notes API: init_notes(): Initialize the notes tree from the given notes ref
- Add tests for checking correct handling of $GIT_NOTES_REF and core.notesRef
- Notes API: get_commit_notes() -> format_note() + remove the commit restriction
- Cosmetic fixes to notes.c
* jc/grep-author-all-match-implicit (2010-01-17) 1 commit
- "log --author=me --grep=it" should find intersection, not union
^ permalink raw reply
* Re: Wishlist for branch management
From: H. Peter Anvin @ 2010-02-01 3:22 UTC (permalink / raw)
To: Björn Steinbrink; +Cc: Git Mailing List
In-Reply-To: <20100201013155.GA11832@atjola.homenet>
On 01/31/2010 05:31 PM, Björn Steinbrink wrote:
>
>> git push --current
>>
>> ... push the current branch, and only the current branch...
>
> Unless you want to push to a different ref remotely, e.g. pushing
> refs/heads/master-public to refs/heads/master, you can use:
> git push <remote> HEAD
>
> For example, when refs/heads/master is checked out, then:
> git push origin HEAD
> acts the same as:
> git push origin refs/heads/master
>
Whatever is used, it should respect the configuration. This requires
knowing what the configuration is set up as.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
^ permalink raw reply
* [PATCH 2/2] configure: Allow --without-python
From: Ben Walton @ 2010-02-01 2:15 UTC (permalink / raw)
To: git, gitster; +Cc: Ben Walton
In-Reply-To: <1264990505-29578-2-git-send-email-bwalton@artsci.utoronto.ca>
This patch allows someone to use configure to build git while at the
same time disabling the python remote helper code. It leverages the
ability of GIT_ARG_SET_PATH to accept an optional second argument
indicating that --without-$PROGRAM is acceptable.
Signed-off-by: Ben Walton <bwalton@artsci.utoronto.ca>
---
configure.ac | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/configure.ac b/configure.ac
index 9eaae7d..914ae57 100644
--- a/configure.ac
+++ b/configure.ac
@@ -288,7 +288,7 @@ GIT_ARG_SET_PATH(shell)
GIT_ARG_SET_PATH(perl)
#
# Define PYTHON_PATH to provide path to Python.
-GIT_ARG_SET_PATH(python)
+GIT_ARG_SET_PATH(python, allow-without)
#
# Define ZLIB_PATH to provide path to zlib.
GIT_ARG_SET_PATH(zlib)
--
1.6.5.3
^ permalink raw reply related
* [PATCH 0/2] configure tweaks for NO_PYTHON
From: Ben Walton @ 2010-02-01 2:15 UTC (permalink / raw)
To: git, gitster; +Cc: Ben Walton
The following patches enable a user to ./configure git with python
disabled. There is nothing using the remote helper libraries yet. I
noticed this missing capability after the recent rpm .spec thread.
Ben Walton (2):
configure: Allow GIT_ARG_SET_PATH to handle --without-PROGRAM
configure: Allow --without-python
configure.ac | 17 ++++++++++++++---
1 files changed, 14 insertions(+), 3 deletions(-)
^ 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