Git development
 help / color / mirror / Atom feed
* Re: master^ is not a local branch -- huh?!?
From: Junio C Hamano @ 2010-01-30  3:06 UTC (permalink / raw)
  To: Michael Witten; +Cc: Ron Garret, git
In-Reply-To: <b4087cc51001291633l68760880i340d12e865641077@mail.gmail.com>

Michael Witten <mfwitten@gmail.com> writes:

> Isn't the difference between 'checkout' and 'reset' almost essentially
> a matter of whether the branch reference (HEAD), index, and tree are
> modified? Couldn't these commands be merged into one command or make
> use of one command?

I don't think that reduces any confusion.

By exposing orthogonal options like --index, --head, etc., you are opening
yourself to nonsensical combinations that were never possible with the
existing command set, and I suspect it would make it even more confusing,
not less.

What does "git update --detach $commit" _really_ mean, for example?

You can of course say "it detaches the HEAD at $commit, but otherwise does
not change anything else", but such a mechanical description does not give
an answer that helps end users.  "What would I do after doing that?" and
"What would I use this for?" are the questions they need an answer to.

What matters is "after doing this, next commit will record _this_, which
is often what users want in _that_ situation, and that is why this
combination of options makes sense."  Do all (or majority) of option
combinations to your "update" think have _meaning_ in that sense?  I don't
think so.

Flexibility and orthogonality is often good, but uncontrolled flexibility
is not.  And I suspect your "git update" is just an uncontrolled mess that
would not help users [*1*].

[Footnote]

*1* It is a different matter to have something like that as an ingredient
to build Porcelain scripts out of.  Porcelain writers may appreciate the
flexibility and they will choose to use only combinations that make sense
for the situation they are trying to deal with.

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Junio C Hamano @ 2010-01-30  2:59 UTC (permalink / raw)
  To: Ron Garret; +Cc: git
In-Reply-To: <ron1-F006CF.18381129012010@news.gmane.org>

Ron Garret <ron1@flownet.com> writes:

> 1.  The term "detached HEAD" is inherently misleading.  A detached HEAD 
> isn't detached from anything, it's just pointing to the middle of a 
> branch, which is to say, to a commit that happens to already have 
> descendants.  For that matter, the name HEAD is itself misleading, since 
> HEAD need not be the head of a branch (though normally it is).  A better 
> name for HEAD would have been CURRENT or ACTIVE.  I recognize it's 
> probably too late to change it now.

This description, especially the phrase "middle of a branch" shows that
you don't understand git yet.  A git branch is _not_ a line (nor multiple
lines) of development.  It is merely a _point_ in the history.

"A commit that is in the middle of an ancestry chain with existing
descendants" can be at the tip of a branch and does not have anything to
do with detached HEAD state.

When HEAD points at a branch, making a commit advances _that_ branch.  And
we say you are "on that branch".  When HEAD is detached, because it is not
attached to anything, it advances no branch.  "detached HEAD" is detached
in the very real sense.  It is not attached to _any_ branch.

> 2.  There are a lot of things in the documentation that turn out, now 
> that I understand what is going on, to be subtly misleading.  For 
> example, "A single git repository can track development on multiple 
> branches. It does this by keeping a list of heads which reference the 
> latest commit on each branch."  That last part is only true if the heads 
> are not "detached".

This is from old terminology.  We used to use "head" (lowercase) and
"branches" pretty much interchangeably and the quoted description is from
the era _before_ detached HEAD was invented, as a way to quickly get a
temporary state where you can browse around freely and without having to
worry about having to clean up afterwards even if you made commits in that
state by simply going back to an attached state.

So do a "s/a list of heads/a list of branch pointers/" replacement and you
will be fine.

> Another example: "The HEAD then refers to the SHA-1 of the commit 
> instead of to a branch, and git branch shows that you are no longer on a 
> branch:"  But you *are* on a branch, you just aren't at the head of the 
> branch.

No, you are _literally_ not on _any_ branch at that point.

Making a commit from that state does not advance _any_ branch and doing
"reset --hard $commit" from that state does not affect _any_ branch.

^ permalink raw reply

* Re: unable to run gc (or git repack -Adl )
From: Jon Nelson @ 2010-01-30  2:45 UTC (permalink / raw)
  Cc: git
In-Reply-To: <alpine.LFD.2.00.1001292025260.1681@xanadu.home>

On Fri, Jan 29, 2010 at 8:14 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> On Fri, 29 Jan 2010, Jon Nelson wrote:
...
>> 1. I see the 'git-repack' shell process scanning for .keep files. I
>> don't have any. Is there a shortcut to this?
>>
>> It's also hugely inefficient. In this case, the code to identify non
>> .keep packs takes *4 minutes, 45 seconds*, lots of disk I/O, and lots
>> of CPU (it pegs one CPU at 100% for the entire duration). With a wee
>> bit of awk, I have reduced that to 2.3 seconds with VASTLY reduced I/O
>> and CPU requirements. Patch attached.
>
> Your patch will pick any .pack file in the repo not only from the
> .git/objects/pack directory.  There is no such thing as *.pack.keep
> either.

Ugh. Yep. Patch amended. Still fast. Still wrong?

>> 3. When git pack objects is running and counting up the number of
>> objects, it is stat'ing files that aren't in the working directly, and
>> should not be, according to the index. If I switch the repo to be a
>> "bare" repository, then it doesn't do that, however, why is it doing
>> that in the first place?
>
> A bare repository has no index.  When the index is present though, it is
> necessary to also pack objects it references.  Why working directory
> files would be stat()'d in that case I don't know.

Inquiring minds want to know.

>> 4. Should git-pack-objects be reading the pack.idx files for counting
>> objects instead of the .pack files themselves?
>
> No.  The whole point when "counting objects" is to perform a walk of the
> history graph and capture the set of objects that are actually
> referenced from your branches/tags and leave the unreferenced objects
> behind.  Also the order in which those objects are encountered during
> that history walk is very important for efficient object placement in
> the final pack.  So this is much more involved than only listing the
> objects contained in every packs.

Ah. For some reason I thought the .idx files contained not just a
straight listing but also the parent/child relationships as well.

> You could try:
>
>        git config core.packedGitLimit 256m
>        git config core.packedGitWindowSize 32m
>        git config pack.deltaCacheSize 1
>
> and try repacking again with 'git gc --prune=now'.  After the repack
> succeeds, you should be able to remove the above configs from your
> .git/config file.

I have since thrown out the repo and started over on this particular
experiment, issuing a 'git gc' rather more often. The config options
above are now dutifully scribbled down.  Thanks!

diff --git a/git-repack.sh b/git-repack.sh
index 1eb3bca..3cef57d 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -62,15 +62,7 @@ case ",$all_into_one," in
 ,t,)
        args= existing=
        if [ -d "$PACKDIR" ]; then
-               for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \
-                       | sed -e 's/^\.\///' -e 's/\.pack$//'`
-               do
-                       if [ -e "$PACKDIR/$e.keep" ]; then
-                               : keep
-                       else
-                               existing="$existing $e"
-                       fi
-               done
+               existing=$( cd "$PACKDIR" && find . -type f -name
'*.pack' -o -name '*.keep' | sed -e 's/^\.\///' | sort | awk '{ if ($0
~ /\.keep$/) { N=substr($0, 0, length($0)-4) "pack"; K[N]=0; } else {
if ($0 in K) { } else { K[$0]=1; } } } END { for (k in K) { if (K[k]
== 1) { printf "%s ", k; } } } ' )
                if test -n "$existing" -a -n "$unpack_unreachable" -a \
                        -n "$remove_redundant"
                then


-- 
Jon

^ permalink raw reply related

* Re: master^ is not a local branch -- huh?!?
From: Mark Lodato @ 2010-01-30  2:40 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Junio C Hamano, Sverre Rabbelier, Git List, Ron1, Jacob Helwig
In-Reply-To: <alpine.LFD.2.00.1001292013150.1681@xanadu.home>

On Fri, Jan 29, 2010 at 8:22 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> On Fri, 29 Jan 2010, Mark Lodato wrote:
>
>> Still, I find it slightly confusing and unfriendly.  How about the following?
>
> It is slightly inaccurate.

Is the following the only inaccuracy?  Do you have any other feedback?

>> Checking out commit 'master^0'.
>>
>> Since this is not a local branch head, any commits you make will be lost
>> when you check out another branch or commit.  (In git terminology, HEAD
>> is detached.)  If you just wish to look at files without committing,
>> this is fine.  If you wish to make commits and retain them, you may
>> create a new branch by running:
>>
>>   git checkout -b <new_branch_name>
>
> This gives the impression that any commit you make on a detached HEAD
> are going to be lost, unless you create a new branch first.

What about "...you may want to create..."?  This does not imply that
creating a new branch now is the *only* way, just the most likely.  If
a user knows another way, that user probably does not need this
warning in the first place.

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Ron Garret @ 2010-01-30  2:38 UTC (permalink / raw)
  To: git
In-Reply-To: <alpine.LFD.2.00.1001292013150.1681@xanadu.home>

In article <alpine.LFD.2.00.1001292013150.1681@xanadu.home>,
 Nicolas Pitre <nico@fluxnic.net> wrote:

> On Fri, 29 Jan 2010, Mark Lodato wrote:
> 
> > Still, I find it slightly confusing and unfriendly.  How about the 
> > following?
> 
> It is slightly inaccurate.
> 
> > Checking out commit 'master^0'.
> > 
> > Since this is not a local branch head, any commits you make will be lost
> > when you check out another branch or commit.  (In git terminology, HEAD
> > is detached.)  If you just wish to look at files without committing,
> > this is fine.  If you wish to make commits and retain them, you may
> > create a new branch by running:
> > 
> >   git checkout -b <new_branch_name>
> 
> This gives the impression that any commit you make on a detached HEAD 
> are going to be lost, unless you create a new branch first.
> 
> And again, it is a good thing to have "detached HEAD" in there so to 
> relate to existing documentation easily.
> 
> > I think the above wording is fine for both commits (e.g. master^0) and
> > remote branches (e.g. origin/pu).  With other wording, we may wish to
> > have two slightly different messages depending on what the user typed.
> 
> You could have tags too.  So instead of trying to be too smart, it is 
> best to simply display the provided name without qualifier.
> 
> > Also, I am not a big fan of "local branch head".  How about "not the
> > name of a local branch"?  I'm not sure...
> 
> The confusion that started this thread was about "master^" which might 
> be interpreted as the name of a local branch except for the fact that we 
> want one commit back.  So using "local commit head" is more precise.

Since it is my confusion that started this thread (and I suppose is in 
part responsible for continuing it) I should be clear that master^ was 
just an example.  My first attempt to roll back to an earlier version 
was actually "git checkout HEAD^".  That produced the same result, since 
HEAD was pointing to master at the time.  But one of the things I 
realized was that HEAD was a variable, and so I chose to frame my 
example in terms of master instead of HEAD in order to eliminate 
ambiguity.

FWIW, here are some observations based on my current understanding:

1.  The term "detached HEAD" is inherently misleading.  A detached HEAD 
isn't detached from anything, it's just pointing to the middle of a 
branch, which is to say, to a commit that happens to already have 
descendants.  For that matter, the name HEAD is itself misleading, since 
HEAD need not be the head of a branch (though normally it is).  A better 
name for HEAD would have been CURRENT or ACTIVE.  I recognize it's 
probably too late to change it now.

2.  There are a lot of things in the documentation that turn out, now 
that I understand what is going on, to be subtly misleading.  For 
example, "A single git repository can track development on multiple 
branches. It does this by keeping a list of heads which reference the 
latest commit on each branch."  That last part is only true if the heads 
are not "detached".

I do not yet understand enough about git to know if this is a reasonable 
suggestion, but one possibility is to separate the notion of a head from 
the notion of a pointer to a commit.  A head would be a pointer to a 
commit that can only point to a commit with no descendants, whereas a 
pointer could point anywhere.  What is now called HEAD would be a 
pointer, not a head under this ontology.

Another example: "The HEAD then refers to the SHA-1 of the commit 
instead of to a branch, and git branch shows that you are no longer on a 
branch:"  But you *are* on a branch, you just aren't at the head of the 
branch.  In fact, by the definition of branch the whole concept of "not 
being on a branch" is non-sensical.  (Isn't that part of the whole point 
of git?  That everything is a branch?)

3.  These observations suggest ways in which the situation could be 
improved.

First, I think Michael Witten is on the right track with his proposal 
for a redesign of git-checkout and the new git-update command (though I 
have not yet had time to think deeply about the details).  There are 
only a small number of things that are actually going on under the hood, 
and the closer the map between the command set and those primitive 
operations can be made the better.

Second, the real problem underlying the original warning that started 
all this is that if you do a commit from a "detached head" then you have 
effectively created a branch whether you meant to or not.  This suggests 
a very straightforward warning:

"WARNING: Your HEAD is now pointing to a commit that has descendants.
If you do a commit from here, you will be creating a branch.  If this
is not what you intend, read the documentation and achieve clarity before
proceeding.  If you just want to bail out of this situation without
doing your homework, do a 'git checkout master' or something like that."

Or something like that :-)

rg

^ permalink raw reply

* Re: [PATCH] Implement pthread_cond_broadcast on Windows
From: Johannes Schindelin @ 2010-01-30  2:28 UTC (permalink / raw)
  To: Johannes Sixt
  Cc: Junio C Hamano, Zoltán Füzesi, git, msysGit Mailinglist,
	Dmitry Potapov, Andrzej K. Haczewski, Erik Faye-Lund
In-Reply-To: <201001300054.05610.j6t@kdbg.org>

Hi,

On Sat, 30 Jan 2010, Johannes Sixt wrote:

> See http://www.cse.wustl.edu/~schmidt/win32-cv-1.html, section "The
> SignalObjectAndWait solution". But note that this implementation does not
> use SignalObjectAndWait (which is needed to achieve fairness, but we do
> not need fairness).
> 
> Note that our implementations of pthread_cond_broadcast and
> pthread_cond_signal require that they are invoked with the mutex held that
> is used in the pthread_cond_wait calls.
> 
> Signed-off-by: Johannes Sixt <j6t@kdbg.org>
> ---
>  Junio,
> 
>  please queue this patch for 1.7.0-rc1 even though it has not undergone
>  a lot of review - the result is better than a git that does not even
>  build on Windows.

As you Cc:ed the msysGit list, do you want this in 4msysgit.git, too?

Ciao,
Dscho

^ permalink raw reply

* Re: unable to run gc (or git repack -Adl )
From: Nicolas Pitre @ 2010-01-30  2:14 UTC (permalink / raw)
  To: Jon Nelson; +Cc: git
In-Reply-To: <cccedfc61001291429q7dfa2045x18134439ad1e7c94@mail.gmail.com>

On Fri, 29 Jan 2010, Jon Nelson wrote:

> Using 1.6.4.2 on openSUSE 11.2 (x86_64).
> 
> I have a beefy repo (du of 14GB) that I can't seem to run 'gc' on.
> 
> After running for over 2 hours, this is what I get:
> 
> Counting objects: 267676, done.
> Compressing objects: 100% (217424/217424), done.
> fatal: Unable to create temporary file: Too many open files
> error: failed to run repack

Ouch!!  Impressive.

> Ugh!

Indeed.

> I have 3 GB of memory (and 1GB of swap).
> When I strace the various processes, I see some things I don't understand:
> 
> 1. I see the 'git-repack' shell process scanning for .keep files. I
> don't have any. Is there a shortcut to this?
> 
> It's also hugely inefficient. In this case, the code to identify non
> .keep packs takes *4 minutes, 45 seconds*, lots of disk I/O, and lots
> of CPU (it pegs one CPU at 100% for the entire duration). With a wee
> bit of awk, I have reduced that to 2.3 seconds with VASTLY reduced I/O
> and CPU requirements. Patch attached.

Your patch will pick any .pack file in the repo not only from the 
.git/objects/pack directory.  There is no such thing as *.pack.keep 
either.

> 2. When git-pack-objects is being run, around the time it's 85% done
> "compressing" it's very very very slow. Like, 2-5 objects every
> second. The largest object in the repo is about 1MB.

You probably consumed all RAM and started swapping at that point.

Or... you have many of those 1MB objects.  If so try 
using --window-memory=8M or similar.

> 3. When git pack objects is running and counting up the number of
> objects, it is stat'ing files that aren't in the working directly, and
> should not be, according to the index. If I switch the repo to be a
> "bare" repository, then it doesn't do that, however, why is it doing
> that in the first place?

A bare repository has no index.  When the index is present though, it is 
necessary to also pack objects it references.  Why working directory 
files would be stat()'d in that case I don't know.

> 4. Should git-pack-objects be reading the pack.idx files for counting
> objects instead of the .pack files themselves?

No.  The whole point when "counting objects" is to perform a walk of the 
history graph and capture the set of objects that are actually 
referenced from your branches/tags and leave the unreferenced objects 
behind.  Also the order in which those objects are encountered during 
that history walk is very important for efficient object placement in 
the final pack.  So this is much more involved than only listing the 
objects contained in every packs.

> 5. There is no 5

I'm a flying buldozer.

> 6. Should git-pack-objects be closing .pack files after opening them?
> I have 6559 .pack files.

No wonder why you exhausted your file handles.  And your repository must 
be _horribly_ slow to work with, which might explain the 
slowness/swappiness.

> 7. Ultimately, how do I get "git gc" to work on this repo?

... because you really really want to repack this mess ASAP of course.

Having so many packs means they must be relatively small.  Yet, Git 
allows up to 8GB of pack data to be mmap()'d at once on x86_64.  This 
means that an average of 3700 packs might be mapped at once, plus their 
respective .idx files.

You could try:

	git config core.packedGitLimit 256m
	git config core.packedGitWindowSize 32m
	git config pack.deltaCacheSize 1

and try repacking again with 'git gc --prune=now'.  After the repack 
succeeds, you should be able to remove the above configs from your 
.git/config file.


Nicolas

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Johannes Schindelin @ 2010-01-30  2:13 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Junio C Hamano, Sverre Rabbelier, Git List, Ron1, Jacob Helwig
In-Reply-To: <alpine.LFD.2.00.1001291614550.1681@xanadu.home>

Hi,

On Fri, 29 Jan 2010, Nicolas Pitre wrote:

> With all due respects, I don't share Dscho's sentiment about Git's 
> alleged non user-friendliness.

Of course you don't.  You are a Git oldtimer.  Probably you do not even 
have much exposure to complete programming newbies.

Well, guess what.  I have.  And guess what even more: they are the 
majority, not you and me.

Ciao,
Dscho

^ permalink raw reply

* [PATCH v6] add --summary option to git-push and git-fetch
From: Larry D'Anna @ 2010-01-30  2:05 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20100130011056.GA20463@cthulhu>

--summary will cause git-push to output a one-line of each commit pushed.
--summary=n will display at most n commits for each ref pushed.

$ git push --dry-run --summary origin :
To /home/larry/gitsandbox/a
   80f0e50..5593a38  master -> master
    > 5593a38 foo
    > 81c03f8 bar

Fetch works the same way.

Signed-off-by: Larry D'Anna <larry@elder-gods.org>
---
 Changes since last version:
 
 * moved *quickref = 0 into update_local_ref
 * added tests to confirm failed pushes and fetches don't segfault

 Documentation/fetch-options.txt |    6 ++
 Documentation/git-push.txt      |    6 ++
 builtin-fetch.c                 |   22 +++++--
 builtin-log.c                   |   35 ++++++++++
 builtin-push.c                  |   17 +++--
 builtin.h                       |    2 +
 revision.c                      |   35 +++++++++--
 revision.h                      |    1 +
 t/t5516-fetch-push.sh           |  136 +++++++++++++++++++++++++++++++++++++++
 transport.c                     |   42 ++++++++----
 transport.h                     |    3 +-
 11 files changed, 274 insertions(+), 31 deletions(-)

diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index fe716b2..53bf049 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -25,6 +25,12 @@ endif::git-pull[]
 	fetches is a descendant of `<lbranch>`.  This option
 	overrides that check.
 
+--summary::
+	Print a one-line summary of each commit fetched.
+
+--summary=<n>::
+	Like --summary, but with a limit of <n> commits per ref.
+
 -k::
 --keep::
 	Keep downloaded pack.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 73a921c..25e0dec 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -86,6 +86,12 @@ nor in any Push line of the corresponding remotes file---see below).
 --dry-run::
 	Do everything except actually send the updates.
 
+--summary::
+	Print a one-line summary of each commit pushed.
+
+--summary=<n>::
+	Like --summary, but with a limit of <n> commits per ref.
+
 --porcelain::
 	Produce machine-readable output.  The output status line for each ref
 	will be tab-separated and sent to stdout instead of stderr.  The full
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 8654fa7..5e1e91b 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -32,6 +32,7 @@ static const char *depth;
 static const char *upload_pack;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *transport;
+static int summary;
 
 static struct option builtin_fetch_options[] = {
 	OPT__VERBOSITY(&verbosity),
@@ -58,6 +59,9 @@ static struct option builtin_fetch_options[] = {
 		    "allow updating of HEAD ref"),
 	OPT_STRING(0, "depth", &depth, "DEPTH",
 		   "deepen history of shallow clone"),
+	{ OPTION_INTEGER, 0, "summary", &summary, "n", "print a summary of [at most n] fetched commits",
+	  PARSE_OPT_OPTARG, NULL, 20
+	},
 	OPT_END()
 };
 
@@ -210,13 +214,15 @@ static int s_update_ref(const char *action,
 
 static int update_local_ref(struct ref *ref,
 			    const char *remote,
-			    char *display)
+			    char *display,
+			    char *quickref)
 {
 	struct commit *current = NULL, *updated;
 	enum object_type type;
 	struct branch *current_branch = branch_get(NULL);
 	const char *pretty_ref = prettify_refname(ref->name);
 
+	*quickref = 0;
 	*display = 0;
 	type = sha1_object_info(ref->new_sha1, NULL);
 	if (type < 0)
@@ -273,11 +279,12 @@ static int update_local_ref(struct ref *ref,
 		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
 			SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
 			r ? "  (unable to update local ref)" : "");
+		if (!r)
+			strcpy(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
 		return r;
 	}
 
 	if (in_merge_bases(current, &updated, 1)) {
-		char quickref[83];
 		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "..");
@@ -288,7 +295,6 @@ static int update_local_ref(struct ref *ref,
 			pretty_ref, r ? "  (unable to update local ref)" : "");
 		return r;
 	} else if (force || ref->force) {
-		char quickref[84];
 		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "...");
@@ -314,6 +320,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 	struct commit *commit;
 	int url_len, i, note_len, shown_url = 0, rc = 0;
 	char note[1024];
+	char quickref[84];
 	const char *what, *kind;
 	struct ref *rm;
 	char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
@@ -390,11 +397,13 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 		fputc('\n', fp);
 
 		if (ref)
-			rc |= update_local_ref(ref, what, note);
-		else
+			rc |= update_local_ref(ref, what, note, quickref);
+		else {
+			strcpy(quickref, find_unique_abbrev(rm->old_sha1, DEFAULT_ABBREV));
 			sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
 				SUMMARY_WIDTH, *kind ? kind : "branch",
 				 REFCOL_WIDTH, *what ? what : "HEAD");
+		}
 		if (*note) {
 			if (verbosity >= 0 && !shown_url) {
 				fprintf(stderr, "From %.*s\n",
@@ -404,6 +413,9 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 			if (verbosity >= 0)
 				fprintf(stderr, " %s\n", note);
 		}
+		if (summary && quickref[0])
+			print_summary_for_push_or_fetch(quickref, summary);
+
 	}
 	free(url);
 	fclose(fp);
diff --git a/builtin-log.c b/builtin-log.c
index 8d16832..55ac4e4 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -1350,3 +1350,38 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
 	free_patch_ids(&ids);
 	return 0;
 }
+
+
+void print_summary_for_push_or_fetch(const char *quickref, int limit)
+{
+	struct rev_info rev;
+	int i, max;
+	struct object *obj;
+	struct commit *commit;
+
+	init_revisions(&rev, NULL);
+	rev.prune = 0;
+	assert(!handle_revision_arg_clearing_flags(quickref, &rev, 0, ALL_REV_FLAGS, 1));
+	assert(!prepare_revision_walk(&rev));
+
+	while ((commit = get_revision(&rev)) != NULL) {
+		struct strbuf buf = STRBUF_INIT;
+		if (limit == 0) {
+			fprintf(stderr, "    ...\n");
+			break;
+		}
+		if (!commit->buffer) {
+			enum object_type type;
+			unsigned long size;
+			commit->buffer =
+				read_sha1_file(commit->object.sha1, &type, &size);
+			if (!commit->buffer)
+				die("Cannot read commit %s", sha1_to_hex(commit->object.sha1));
+		}
+		format_commit_message(commit, "    %m %h %s\n", &buf, 0);
+		fputs(buf.buf, stderr);
+		strbuf_release(&buf);
+		limit--;
+	}
+	fputs("\n", stderr);
+}
diff --git a/builtin-push.c b/builtin-push.c
index 5df6608..30f5a61 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -101,7 +101,7 @@ static void setup_default_push_refspecs(void)
 	}
 }
 
-static int push_with_options(struct transport *transport, int flags)
+static int push_with_options(struct transport *transport, int flags, int summary)
 {
 	int err;
 	int nonfastforward;
@@ -114,7 +114,7 @@ static int push_with_options(struct transport *transport, int flags)
 	if (flags & TRANSPORT_PUSH_VERBOSE)
 		fprintf(stderr, "Pushing to %s\n", transport->url);
 	err = transport_push(transport, refspec_nr, refspec, flags,
-			     &nonfastforward);
+						 summary, &nonfastforward);
 	if (err != 0)
 		error("failed to push some refs to '%s'", transport->url);
 
@@ -132,7 +132,7 @@ static int push_with_options(struct transport *transport, int flags)
 	return 1;
 }
 
-static int do_push(const char *repo, int flags)
+static int do_push(const char *repo, int flags, int summary)
 {
 	int i, errs;
 	struct remote *remote = remote_get(repo);
@@ -184,14 +184,14 @@ static int do_push(const char *repo, int flags)
 		for (i = 0; i < url_nr; i++) {
 			struct transport *transport =
 				transport_get(remote, url[i]);
-			if (push_with_options(transport, flags))
+			if (push_with_options(transport, flags, summary))
 				errs++;
 		}
 	} else {
 		struct transport *transport =
 			transport_get(remote, NULL);
 
-		if (push_with_options(transport, flags))
+ 		if (push_with_options(transport, flags, summary))
 			errs++;
 	}
 	return !!errs;
@@ -203,6 +203,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 	int tags = 0;
 	int rc;
 	const char *repo = NULL;	/* default repository */
+	int summary = 0;
+
 	struct option options[] = {
 		OPT_BIT('q', "quiet", &flags, "be quiet", TRANSPORT_PUSH_QUIET),
 		OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
@@ -218,6 +220,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
+		{ OPTION_INTEGER, 0, "summary", &summary, "n", "print a summary of [at most n] pushed commits",
+		  PARSE_OPT_OPTARG, NULL, 20
+		},
 		OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
 			TRANSPORT_PUSH_SET_UPSTREAM),
 		OPT_END()
@@ -239,7 +244,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		set_refspecs(argv + 1, argc - 1);
 	}
 
-	rc = do_push(repo, flags);
+	rc = do_push(repo, flags, summary);
 	if (rc == -1)
 		usage_with_options(push_usage, options);
 	else
diff --git a/builtin.h b/builtin.h
index e8202f3..ec411be 100644
--- a/builtin.h
+++ b/builtin.h
@@ -19,6 +19,7 @@ extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
 		const char *author);
 extern int check_pager_config(const char *cmd);
+extern void print_summary_for_push_or_fetch(const char *quickref, int limit);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
@@ -122,4 +123,5 @@ extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
 extern int cmd_replace(int argc, const char **argv, const char *prefix);
 
+
 #endif
diff --git a/revision.c b/revision.c
index 3ba6d99..cf3103a 100644
--- a/revision.c
+++ b/revision.c
@@ -768,7 +768,7 @@ static void handle_reflog(struct rev_info *revs, unsigned flags)
 	for_each_reflog(handle_one_reflog, &cb);
 }
 
-static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
+static int add_parents_only(struct rev_info *revs, const char *arg, int flags, int flags_to_clear)
 {
 	unsigned char sha1[20];
 	struct object *it;
@@ -792,6 +792,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
 	if (it->type != OBJ_COMMIT)
 		return 0;
 	commit = (struct commit *)it;
+	if (flags_to_clear)
+	    clear_commit_marks(commit, flags_to_clear); 
 	for (parents = commit->parents; parents; parents = parents->next) {
 		it = &parents->item->object;
 		it->flags |= flags;
@@ -887,9 +889,18 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 			int flags,
 			int cant_be_filename)
 {
+    return handle_revision_arg_clearing_flags (arg, revs, flags, 0, cant_be_filename); 
+}
+
+
+
+int handle_revision_arg_clearing_flags (const char *arg, struct rev_info *revs,
+					int flags,  int flags_to_clear, 
+					int cant_be_filename)
+{
 	unsigned mode;
 	char *dotdot;
-	struct object *object;
+	struct object *object, *object_deref;
 	unsigned char sha1[20];
 	int local_flags;
 
@@ -915,6 +926,10 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 
 			a = lookup_commit_reference(from_sha1);
 			b = lookup_commit_reference(sha1);
+			if (a && flags_to_clear) 
+			    clear_commit_marks(a, flags_to_clear); 
+			if (b && flags_to_clear)
+			    clear_commit_marks(b, flags_to_clear); 
 			if (!a || !b) {
 				die(symmetric ?
 				    "Invalid symmetric difference expression %s...%s" :
@@ -945,14 +960,14 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 	dotdot = strstr(arg, "^@");
 	if (dotdot && !dotdot[2]) {
 		*dotdot = 0;
-		if (add_parents_only(revs, arg, flags))
+		if (add_parents_only(revs, arg, flags, flags_to_clear))
 			return 0;
 		*dotdot = '^';
 	}
 	dotdot = strstr(arg, "^!");
 	if (dotdot && !dotdot[2]) {
 		*dotdot = 0;
-		if (!add_parents_only(revs, arg, flags ^ UNINTERESTING))
+		if (!add_parents_only(revs, arg, flags ^ UNINTERESTING, flags_to_clear))
 			*dotdot = '^';
 	}
 
@@ -965,7 +980,17 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 		return -1;
 	if (!cant_be_filename)
 		verify_non_filename(revs->prefix, arg);
-	object = get_reference(revs, arg, sha1, flags ^ local_flags);
+
+	object = parse_object(sha1); 
+	if (!object)
+	    die("bad object %s", arg);
+	
+	object_deref = deref_tag(object, NULL, 0); 
+	if (object_deref && object_deref->type == OBJ_COMMIT)
+	    if (flags_to_clear)
+		clear_commit_marks((struct commit *) object_deref, flags_to_clear); 
+
+	object->flags |= flags ^ local_flags; 
 	add_pending_object_with_mode(revs, object, arg, mode);
 	return 0;
 }
diff --git a/revision.h b/revision.h
index a14deef..36f78bb 100644
--- a/revision.h
+++ b/revision.h
@@ -143,6 +143,7 @@ extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ct
 				 const struct option *options,
 				 const char * const usagestr[]);
 extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename);
+extern int handle_revision_arg_clearing_flags(const char *arg, struct rev_info *revs,int flags, int flags_to_clear, int cant_be_filename);
 
 extern int prepare_revision_walk(struct rev_info *revs);
 extern struct commit *get_revision(struct rev_info *revs);
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 0f04b2e..9e49714 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -91,6 +91,80 @@ test_expect_success 'fetch without wildcard' '
 	)
 '
 
+
+test_expect_success 'fetch --summary branch update' '
+	mk_empty &&
+	(
+		cd testrepo &&
+
+		git fetch  .. refs/heads/master:refs/remotes/origin/master &&
+
+		git update-ref refs/remotes/origin/master refs/remotes/origin/master^ &&
+
+		git fetch --summary .. refs/heads/master:refs/remotes/origin/master 2>stderr &&
+
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l) &&
+
+		  egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+		! egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+	)
+	'
+
+test_expect_success 'fetch --summary bad ref' '
+	mk_empty &&
+	(
+		cd testrepo &&
+		! git fetch --summary .. foo:bar 2>stderr  &&
+		! grep "seg" stderr
+	)
+	'
+
+test_expect_success 'fetch --summary new branch' '
+	mk_empty &&
+	(
+		cd testrepo &&
+		git fetch --summary .. refs/heads/master:refs/remotes/origin/master 2>stderr &&
+
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l) &&
+
+		egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+		egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+	)
+        '
+
+test_expect_success 'fetch --summary forced update' '
+	mk_empty &&
+	(
+		cd testrepo &&
+		git fetch .. refs/heads/master:refs/remotes/origin/master &&
+
+		git checkout refs/remotes/origin/master^ &&
+		: >path3 &&
+		git add path3 &&
+		test_tick &&
+		git commit -a -m third &&
+		git update-ref refs/remotes/origin/master HEAD &&
+
+		git fetch .. -f --summary refs/heads/master:refs/remotes/origin/master 2>stderr &&
+
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l) &&
+
+		egrep  "^    < [a-fA-F0-9]+ third$" stderr &&
+		egrep  "^    > [a-fA-F0-9]+ second$" stderr
+	)
+
+'
+
 test_expect_success 'fetch with wildcard' '
 	mk_empty &&
 	(
@@ -153,6 +227,68 @@ test_expect_success 'push without wildcard' '
 	)
 '
 
+test_expect_success 'push --summary bad ref' '
+	mk_empty &&
+	! git push --summary testrepo foo:bar 2>stderr  &&
+	! grep "seg" stderr
+'
+
+test_expect_success 'push --summary new branch' '
+	mk_empty &&
+
+	git push --summary testrepo refs/heads/master:refs/remotes/origin/master 2>stderr &&
+	(
+		cd testrepo &&
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+	) &&
+
+	egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+	egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+'
+
+test_expect_success 'push --summary branch update' '
+	mk_empty &&
+
+	git push testrepo refs/heads/master:refs/remotes/origin/master &&
+
+	git --git-dir testrepo/.git update-ref refs/remotes/origin/master refs/remotes/origin/master^ &&
+
+	git push --summary testrepo refs/heads/master:refs/remotes/origin/master 2>stderr &&
+	(
+		cd testrepo &&
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+	) &&
+
+	  egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+	! egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+'
+
+
+test_expect_success 'push --summary forced update' '
+	mk_empty &&
+
+	git push testrepo refs/heads/master:refs/remotes/origin/master &&
+
+	git checkout master^ &&
+	: >path3 &&
+	git add path3 &&
+	test_tick &&
+	git commit -a -m third &&
+
+	git push --summary -f testrepo HEAD:refs/remotes/origin/master 2>stderr &&
+
+	egrep  "^    < [a-fA-F0-9]+ second$" stderr &&
+	egrep  "^    > [a-fA-F0-9]+ third$" stderr &&
+
+	git checkout master
+'
+
 test_expect_success 'push with wildcard' '
 	mk_empty &&
 
diff --git a/transport.c b/transport.c
index 3846aac..1e3fa7a 100644
--- a/transport.c
+++ b/transport.c
@@ -8,6 +8,7 @@
 #include "bundle.h"
 #include "dir.h"
 #include "refs.h"
+#include "builtin.h"
 #include "branch.h"
 
 /* rsync support */
@@ -642,17 +643,20 @@ static const char *status_abbrev(unsigned char sha1[20])
 	return find_unique_abbrev(sha1, DEFAULT_ABBREV);
 }
 
-static void print_ok_ref_status(struct ref *ref, int porcelain)
+static void print_ok_ref_status(struct ref *ref, int porcelain, int summary)
 {
+	char quickref[84];
+	int summary_impossible = 0;
+
 	if (ref->deletion)
 		print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
-	else if (is_null_sha1(ref->old_sha1))
+	else if (is_null_sha1(ref->old_sha1)) {
 		print_ref_status('*',
 			(!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
 			"[new branch]"),
 			ref, ref->peer_ref, NULL, porcelain);
-	else {
-		char quickref[84];
+		strcpy(quickref, status_abbrev(ref->new_sha1));
+	} else {
 		char type;
 		const char *msg;
 
@@ -661,6 +665,8 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
 			strcat(quickref, "...");
 			type = '+';
 			msg = "forced update";
+			if (!lookup_commit_reference_gently(ref->old_sha1, 1))
+				summary_impossible = 1;
 		} else {
 			strcat(quickref, "..");
 			type = ' ';
@@ -670,9 +676,17 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
 
 		print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
 	}
+
+	if (summary) {
+		if (summary_impossible) {
+			fprintf(stderr, "    %s is unavailable\n", status_abbrev(ref->old_sha1));
+		} else {
+			print_summary_for_push_or_fetch(quickref, summary);
+		}
+	}
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain, int summary)
 {
 	if (!count)
 		fprintf(stderr, "To %s\n", dest);
@@ -704,7 +718,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 						 "remote failed to report status", porcelain);
 		break;
 	case REF_STATUS_OK:
-		print_ok_ref_status(ref, porcelain);
+		print_ok_ref_status(ref, porcelain, summary);
 		break;
 	}
 
@@ -712,7 +726,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 }
 
 static void print_push_status(const char *dest, struct ref *refs,
-			      int verbose, int porcelain, int * nonfastforward)
+							  int verbose, int porcelain, int summary, int *nonfastforward)
 {
 	struct ref *ref;
 	int n = 0;
@@ -720,19 +734,19 @@ static void print_push_status(const char *dest, struct ref *refs,
 	if (verbose) {
 		for (ref = refs; ref; ref = ref->next)
 			if (ref->status == REF_STATUS_UPTODATE)
-				n += print_one_push_status(ref, dest, n, porcelain);
+				n += print_one_push_status(ref, dest, n, porcelain, summary);
 	}
 
 	for (ref = refs; ref; ref = ref->next)
 		if (ref->status == REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n, porcelain);
+			n += print_one_push_status(ref, dest, n, porcelain, summary);
 
 	*nonfastforward = 0;
 	for (ref = refs; ref; ref = ref->next) {
 		if (ref->status != REF_STATUS_NONE &&
 		    ref->status != REF_STATUS_UPTODATE &&
 		    ref->status != REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n, porcelain);
+			n += print_one_push_status(ref, dest, n, porcelain, summary);
 		if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
 			*nonfastforward = 1;
 	}
@@ -1014,8 +1028,8 @@ int transport_set_option(struct transport *transport,
 }
 
 int transport_push(struct transport *transport,
-		   int refspec_nr, const char **refspec, int flags,
-		   int *nonfastforward)
+				   int refspec_nr, const char **refspec,
+				   int flags, int summary, int *nonfastforward)
 {
 	*nonfastforward = 0;
 	verify_remote_names(refspec_nr, refspec);
@@ -1058,8 +1072,8 @@ int transport_push(struct transport *transport,
 
 		if (!quiet || err)
 			print_push_status(transport->url, remote_refs,
-					verbose | porcelain, porcelain,
-					nonfastforward);
+							  verbose | porcelain, porcelain,
+							  summary, nonfastforward);
 
 		if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
 			set_upstreams(transport, remote_refs, pretend);
diff --git a/transport.h b/transport.h
index 7cea5cc..f87b2e9 100644
--- a/transport.h
+++ b/transport.h
@@ -124,9 +124,10 @@ int transport_set_option(struct transport *transport, const char *name,
 			 const char *value);
 
 int transport_push(struct transport *connection,
-		   int refspec_nr, const char **refspec, int flags,
+		   int refspec_nr, const char **refspec, int flags, int summary,
 		   int * nonfastforward);
 
+
 const struct ref *transport_get_remote_refs(struct transport *transport);
 
 int transport_fetch_refs(struct transport *transport, struct ref *refs);
-- 
1.6.3.3.415.gbe1e

^ permalink raw reply related

* [PATCH] builtin-name-rev.c: remove the remaining "typedef struct rev_name" from git.
From: Thiago Farina @ 2010-01-30  1:32 UTC (permalink / raw)
  To: git

---
 builtin-name-rev.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index 06a38ac..6416f72 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -7,11 +7,11 @@
 
 #define CUTOFF_DATE_SLOP 86400 /* one day */
 
-typedef struct rev_name {
+struct rev_name {
 	const char *tip_name;
 	int generation;
 	int distance;
-} rev_name;
+};
 
 static long cutoff = LONG_MAX;
 
@@ -43,7 +43,7 @@ static void name_rev(struct commit *commit,
 	}
 
 	if (name == NULL) {
-		name = xmalloc(sizeof(rev_name));
+		name = xmalloc(sizeof(struct rev_name));
 		commit->util = name;
 		goto copy_data;
 	} else if (name->distance > distance) {
-- 
1.6.6.1.436.gaba7d

^ permalink raw reply related

* [PATCH] Make NO_PTHREADS the sole thread configuration variable
From: Dan McGee @ 2010-01-30  1:22 UTC (permalink / raw)
  To: git; +Cc: Dan McGee

When the first piece of threaded code was introduced in commit 8ecce684, it
came with its own THREADED_DELTA_SEARCH Makefile option. Since this time,
more threaded code has come into the codebase and a NO_PTHREADS option has
also been added. Get rid of the original option as the newer, more generic
option covers everything we need.

Signed-off-by: Dan McGee <dpmcgee@gmail.com>
---
From looking over the way we use these two variables, it doesn't appear we
have any cases where the two of these were out of sync. If I missed
something, feel free to let me know. I did see some recent discussion
regarding msys and threaded-grep, but that didn't come into play here. It
did make me shudder seeing yet another THREADED_* option get suggested,
however.

-Dan

 Makefile               |   24 ++----------------------
 builtin-pack-objects.c |   12 ++++++------
 configure.ac           |    9 ++-------
 3 files changed, 10 insertions(+), 35 deletions(-)

diff --git a/Makefile b/Makefile
index af08c8f..83383c3 100644
--- a/Makefile
+++ b/Makefile
@@ -180,9 +180,6 @@ all::
 # If not set it defaults to the bare 'wish'. If it is set to the empty
 # string then NO_TCLTK will be forced (this is used by configure script).
 #
-# Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit
-# parallel delta searching when packing objects.
-#
 # Define INTERNAL_QSORT to use Git's implementation of qsort(), which
 # is a simplified version of the merge sort used in glibc. This is
 # recommended if Git triggers O(n^2) behavior in your platform's qsort().
@@ -722,12 +719,10 @@ EXTLIBS =
 ifeq ($(uname_S),Linux)
 	NO_STRLCPY = YesPlease
 	NO_MKSTEMPS = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
 	NO_STRLCPY = YesPlease
 	NO_MKSTEMPS = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 endif
 ifeq ($(uname_S),UnixWare)
 	CC = cc
@@ -781,7 +776,6 @@ ifeq ($(uname_S),Darwin)
 		NO_STRLCPY = YesPlease
 	endif
 	NO_MEMMEM = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 	USE_ST_TIMESPEC = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
@@ -794,7 +788,6 @@ ifeq ($(uname_S),SunOS)
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease
 	NO_REGEX = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 	ifeq ($(uname_R),5.7)
 		NEEDS_RESOLV = YesPlease
 		NO_IPV6 = YesPlease
@@ -850,7 +843,6 @@ ifeq ($(uname_S),FreeBSD)
 	BASIC_LDFLAGS += -L/usr/local/lib
 	DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
 	USE_ST_TIMESPEC = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 	ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
 		PTHREAD_LIBS = -pthread
 		NO_UINTMAX_T = YesPlease
@@ -864,7 +856,6 @@ ifeq ($(uname_S),OpenBSD)
 	NEEDS_LIBICONV = YesPlease
 	BASIC_CFLAGS += -I/usr/local/include
 	BASIC_LDFLAGS += -L/usr/local/lib
-	THREADED_DELTA_SEARCH = YesPlease
 endif
 ifeq ($(uname_S),NetBSD)
 	ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
@@ -872,7 +863,6 @@ ifeq ($(uname_S),NetBSD)
 	endif
 	BASIC_CFLAGS += -I/usr/pkg/include
 	BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
-	THREADED_DELTA_SEARCH = YesPlease
 	USE_ST_TIMESPEC = YesPlease
 	NO_MKSTEMPS = YesPlease
 endif
@@ -887,9 +877,7 @@ ifeq ($(uname_S),AIX)
 	INTERNAL_QSORT = UnfortunatelyYes
 	NEEDS_LIBICONV=YesPlease
 	BASIC_CFLAGS += -D_LARGE_FILES
-	ifneq ($(shell expr "$(uname_V)" : '[1234]'),1)
-		THREADED_DELTA_SEARCH = YesPlease
-	else
+	ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
 		NO_PTHREADS = YesPlease
 	endif
 endif
@@ -915,7 +903,6 @@ ifeq ($(uname_S),IRIX)
 	SNPRINTF_RETURNS_BOGUS = YesPlease
 	SHELL_PATH = /usr/gnu/bin/bash
 	NEEDS_LIBGEN = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 endif
 ifeq ($(uname_S),IRIX64)
 	NO_SETENV=YesPlease
@@ -934,7 +921,6 @@ ifeq ($(uname_S),IRIX64)
 	SNPRINTF_RETURNS_BOGUS = YesPlease
 	SHELL_PATH=/usr/gnu/bin/bash
 	NEEDS_LIBGEN = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 endif
 ifeq ($(uname_S),HP-UX)
 	NO_IPV6=YesPlease
@@ -984,7 +970,6 @@ ifeq ($(uname_S),Windows)
 	NO_CURL = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 
 	CC = compat/vcbuild/scripts/clink.pl
 	AR = compat/vcbuild/scripts/lib.pl
@@ -1036,7 +1021,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_REGEX = YesPlease
 	NO_PYTHON = YesPlease
 	BLK_SHA1 = YesPlease
-	THREADED_DELTA_SEARCH = YesPlease
 	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
@@ -1334,16 +1318,12 @@ ifdef RUNTIME_PREFIX
 endif
 
 ifdef NO_PTHREADS
-	THREADED_DELTA_SEARCH =
 	BASIC_CFLAGS += -DNO_PTHREADS
 else
 	EXTLIBS += $(PTHREAD_LIBS)
-endif
-
-ifdef THREADED_DELTA_SEARCH
-	BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
 	LIB_OBJS += thread-utils.o
 endif
+
 ifdef DIR_HAS_BSD_GROUP_SEMANTICS
 	COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
 endif
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index b0887d7..4a41547 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -17,7 +17,7 @@
 #include "progress.h"
 #include "refs.h"
 
-#ifdef THREADED_DELTA_SEARCH
+#ifndef NO_PTHREADS
 #include "thread-utils.h"
 #include <pthread.h>
 #endif
@@ -1255,7 +1255,7 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
 	return 0;
 }
 
-#ifdef THREADED_DELTA_SEARCH
+#ifndef NO_PTHREADS
 
 static pthread_mutex_t read_mutex;
 #define read_lock()		pthread_mutex_lock(&read_mutex)
@@ -1380,7 +1380,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
 	/*
 	 * Handle memory allocation outside of the cache
 	 * accounting lock.  Compiler will optimize the strangeness
-	 * away when THREADED_DELTA_SEARCH is not defined.
+	 * away when NO_PTHREADS is defined.
 	 */
 	free(trg_entry->delta_data);
 	cache_lock();
@@ -1567,7 +1567,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
 	free(array);
 }
 
-#ifdef THREADED_DELTA_SEARCH
+#ifndef NO_PTHREADS
 
 /*
  * The main thread waits on the condition that (at least) one of the workers
@@ -1899,7 +1899,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
 		if (delta_search_threads < 0)
 			die("invalid number of threads specified (%d)",
 			    delta_search_threads);
-#ifndef THREADED_DELTA_SEARCH
+#ifdef NO_PTHREADS
 		if (delta_search_threads != 1)
 			warning("no threads support, ignoring %s", k);
 #endif
@@ -2227,7 +2227,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			delta_search_threads = strtoul(arg+10, &end, 0);
 			if (!arg[10] || *end || delta_search_threads < 0)
 				usage(pack_usage);
-#ifndef THREADED_DELTA_SEARCH
+#ifdef NO_PTHREADS
 			if (delta_search_threads != 1)
 				warning("no threads support, "
 					"ignoring %s", arg);
diff --git a/configure.ac b/configure.ac
index 78345eb..229140e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -762,10 +762,9 @@ AC_SUBST(NO_MKSTEMPS)
 # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
 # Enable it on Windows.  By default, symrefs are still used.
 #
-# Define NO_PTHREADS if we do not have pthreads
+# Define NO_PTHREADS if we do not have pthreads.
 #
-# Define PTHREAD_LIBS to the linker flag used for Pthread support and define
-# THREADED_DELTA_SEARCH if Pthreads are available.
+# Define PTHREAD_LIBS to the linker flag used for Pthread support.
 AC_DEFUN([PTHREADTEST_SRC], [
 #include <pthread.h>
 
@@ -782,7 +781,6 @@ dnl   [[pthread_mutex_t test_mutex;]]
 dnl )])
 
 NO_PTHREADS=UnfortunatelyYes
-THREADED_DELTA_SEARCH=
 PTHREAD_LIBS=
 
 if test -n "$USER_NOPTHREAD"; then
@@ -798,7 +796,6 @@ elif test -z "$PTHREAD_CFLAGS"; then
 	[AC_MSG_RESULT([yes])
 		NO_PTHREADS=
 		PTHREAD_LIBS="$opt"
-		THREADED_DELTA_SEARCH=YesPlease
 		break
 	],
 	[AC_MSG_RESULT([no])])
@@ -812,7 +809,6 @@ else
 	[AC_MSG_RESULT([yes])
 		NO_PTHREADS=
 		PTHREAD_LIBS="$PTHREAD_CFLAGS"
-		THREADED_DELTA_SEARCH=YesPlease
 	],
 	[AC_MSG_RESULT([no])])
 
@@ -823,7 +819,6 @@ CFLAGS="$old_CFLAGS"
 
 AC_SUBST(PTHREAD_LIBS)
 AC_SUBST(NO_PTHREADS)
-AC_SUBST(THREADED_DELTA_SEARCH)
 
 ## Output files
 AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"])
-- 
1.6.6.1

^ permalink raw reply related

* Re: [PATCH v4] add --summary option to git-push and git-fetch
From: Junio C Hamano @ 2010-01-30  1:25 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git
In-Reply-To: <7vzl3w9yst.fsf@alter.siamese.dyndns.org>

Junio C Hamano <gitster@pobox.com> writes:

>>> How would you know, when you asked 20 and you showed 20 here, that there
>>> is no more to come?
>>
>> If there's more it will print the "...", if there isn't then it won't.
>
> If your limit is 20 and if you unconditionally say "..." after pulling 20
> from the pool, the consumer of your output would think "Ah, I see 20 but
> that is only I asked for 20, and the ... means there are more".  But that
> is incorrect because your 21st call to get_revision() might have yielded
> NULL in which case you had only 20 after all.
>
> You cannot do "..." correctly without pulling one more than the limit from
> the pool.

Ah, I either misremembered the loop or didn't read it correctly.

Either way, the loop in your v5 looks correct ("read, check count to say
... and exit if limit goes down to zero, show one, decrement and go to
top").

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Nicolas Pitre @ 2010-01-30  1:22 UTC (permalink / raw)
  To: Mark Lodato
  Cc: Junio C Hamano, Sverre Rabbelier, Git List, Ron1, Jacob Helwig
In-Reply-To: <ca433831001291701m50b8c2b7p16bcc6fd4f3f3d55@mail.gmail.com>

On Fri, 29 Jan 2010, Mark Lodato wrote:

> Still, I find it slightly confusing and unfriendly.  How about the following?

It is slightly inaccurate.

> Checking out commit 'master^0'.
> 
> Since this is not a local branch head, any commits you make will be lost
> when you check out another branch or commit.  (In git terminology, HEAD
> is detached.)  If you just wish to look at files without committing,
> this is fine.  If you wish to make commits and retain them, you may
> create a new branch by running:
> 
>   git checkout -b <new_branch_name>

This gives the impression that any commit you make on a detached HEAD 
are going to be lost, unless you create a new branch first.

And again, it is a good thing to have "detached HEAD" in there so to 
relate to existing documentation easily.

> I think the above wording is fine for both commits (e.g. master^0) and
> remote branches (e.g. origin/pu).  With other wording, we may wish to
> have two slightly different messages depending on what the user typed.

You could have tags too.  So instead of trying to be too smart, it is 
best to simply display the provided name without qualifier.

> Also, I am not a big fan of "local branch head".  How about "not the
> name of a local branch"?  I'm not sure...

The confusion that started this thread was about "master^" which might 
be interpreted as the name of a local branch except for the fact that we 
want one commit back.  So using "local commit head" is more precise.


Nicolas

^ permalink raw reply

* Re: [PATCH v4] add --summary option to git-push and git-fetch
From: Junio C Hamano @ 2010-01-30  1:19 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git
In-Reply-To: <20100130005948.GA14938@cthulhu>

Larry D'Anna <larry@elder-gods.org> writes:

Please don't use M-F-T to deflect a direct response meant to you away from
you.  I also do not want people wasting _my_ time by following your M-F-T
and sending their comments meant to _you_ coming to me with my address on
To: line, as I prioritize incoming messages based on where my address is
in the header, and do not want you waste _other's_ time by making them
correct their "To:" like to avoid wasting my time.

>> > @@ -373,12 +379,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
>> >  				fputc(url[i], fp);
>> >  		fputc('\n', fp);
>> >  
>> > -		if (ref)
>> > -			rc |= update_local_ref(ref, what, note);
>> > -		else
>> > +		if (ref) {
>> > +			*quickref = 0;
>> > +			rc |= update_local_ref(ref, what, note, quickref);
>> 
>> Makes me wonder why update_local_ref() does not put that NUL upon entry.
>
> I'm not sure what you mean.  Could you elaborate?

Why is it necessary for the caller to do "*quickref = '\0'" before calling
update_local_ref()?  Shouldn't your updated u-l-r be doing that clearing,
so that the callers don't have to worry about it?

>> > +	init_revisions(&rev, NULL);
>> > +	rev.prune = 0;
>> > +	assert(!handle_revision_arg(quickref, &rev, 0, 1));
>> > +	assert(!prepare_revision_walk(&rev));
>> > +
>> > +	while ((commit = get_revision(&rev)) != NULL) {
>> > +		struct strbuf buf = STRBUF_INIT;
>> > +		if (limit == 0) {
>> > +			fprintf(stderr, "    ...\n");
>> 
>> How would you know, when you asked 20 and you showed 20 here, that there
>> is no more to come?
>
> If there's more it will print the "...", if there isn't then it won't.

If your limit is 20 and if you unconditionally say "..." after pulling 20
from the pool, the consumer of your output would think "Ah, I see 20 but
that is only I asked for 20, and the ... means there are more".  But that
is incorrect because your 21st call to get_revision() might have yielded
NULL in which case you had only 20 after all.

You cannot do "..." correctly without pulling one more than the limit from
the pool.

>> > +test_expect_success 'fetch --summary forced update' '
>> > +	mk_empty &&
>> > +	(
>> > ...
>> > +	)
>> > +
>> > +'
>> 
>> There are at least two missing combinations. (1) "fetch --summary" to
>> fetch a new branch, and (2) "fetch --summary" does not try segfaulting by
>> accessing unavailable information after a failed fetch.
>> 
>> The same comment applies to the push side of the tests.
>
> What would be a good way to induce a failed fetch for this test?

Not having a valid ref or repo, perhaps.  I dunno---it's been quite a
while since I saw the patch.

^ permalink raw reply

* Re: [PATCH v4] add --summary option to git-push and git-fetch
From: Junio C Hamano @ 2010-01-30  1:17 UTC (permalink / raw)
  To: Larry D'Anna; +Cc: git
In-Reply-To: <20100130005948.GA14938@cthulhu>

Larry D'Anna <larry@elder-gods.org> writes:

Please don't use M-F-T to deflect a direct response meant to you away from
you.  I also do not want people wasting _my_ time by following your M-F-T
and sending their comments meant to _you_ coming to me with my address on
To: line, as I prioritize incoming messages based on where my address is
in the header, and do not want you waste _other's_ time by making them
correct their "To:" like to avoid wasting my time.

>> > @@ -373,12 +379,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
>> >  				fputc(url[i], fp);
>> >  		fputc('\n', fp);
>> >  
>> > -		if (ref)
>> > -			rc |= update_local_ref(ref, what, note);
>> > -		else
>> > +		if (ref) {
>> > +			*quickref = 0;
>> > +			rc |= update_local_ref(ref, what, note, quickref);
>> 
>> Makes me wonder why update_local_ref() does not put that NUL upon entry.
>
> I'm not sure what you mean.  Could you elaborate?

Why is it necessary for the caller to do "*quickref = '\0'" before calling
update_local_ref()?  Shouldn't your updated u-l-r be doing that clearing,
so that the callers don't have to worry about it?

>> > +	init_revisions(&rev, NULL);
>> > +	rev.prune = 0;
>> > +	assert(!handle_revision_arg(quickref, &rev, 0, 1));
>> > +	assert(!prepare_revision_walk(&rev));
>> > +
>> > +	while ((commit = get_revision(&rev)) != NULL) {
>> > +		struct strbuf buf = STRBUF_INIT;
>> > +		if (limit == 0) {
>> > +			fprintf(stderr, "    ...\n");
>> 
>> How would you know, when you asked 20 and you showed 20 here, that there
>> is no more to come?
>
> If there's more it will print the "...", if there isn't then it won't.

If your limit is 20 and if you unconditionally say "..." after pulling 20
from the pool, the consumer of your output would think "Ah, I see 20 but
that is only I asked for 20, and the ... means there are more".  But that
is incorrect because your 21st call to get_revision() might have yielded
NULL in which case you had only 20 after all.

You cannot do "..." correctly without pulling one more than the limit from
the pool.

>> > +test_expect_success 'fetch --summary forced update' '
>> > +	mk_empty &&
>> > +	(
>> > ...
>> > +	)
>> > +
>> > +'
>> 
>> There are at least two missing combinations. (1) "fetch --summary" to
>> fetch a new branch, and (2) "fetch --summary" does not try segfaulting by
>> accessing unavailable information after a failed fetch.
>> 
>> The same comment applies to the push side of the tests.
>
> What would be a good way to induce a failed fetch for this test?

Not having a valid ref or repo, perhaps.  I dunno---it's been quite a
while since I saw the patch.

^ permalink raw reply

* [PATCH v5] add --summary option to git-push and git-fetch
From: Larry D'Anna @ 2010-01-30  1:10 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <7viqhzm454.fsf@alter.siamese.dyndns.org>

--summary will cause git-push to output a one-line of each commit pushed.
--summary=n will display at most n commits for each ref pushed.

$ git push --dry-run --summary origin :
To /home/larry/gitsandbox/a
   80f0e50..5593a38  master -> master
    > 5593a38 foo
    > 81c03f8 bar

Fetch works the same way.

Signed-off-by: Larry D'Anna <larry@elder-gods.org>
---
 Changes since last version: 

  * added more tests
  * use clear_commit_marks instead of sledgehammer
  * moved declaration of print_summary_for_push_or_fetch to the top of the header
  * use egrep instead of grep -E

 Documentation/fetch-options.txt |    6 ++
 Documentation/git-push.txt      |    6 ++
 builtin-fetch.c                 |   24 ++++++--
 builtin-log.c                   |   35 +++++++++++
 builtin-push.c                  |   17 ++++--
 builtin.h                       |    2 +
 revision.c                      |   35 ++++++++++--
 revision.h                      |    1 +
 t/t5516-fetch-push.sh           |  121 +++++++++++++++++++++++++++++++++++++++
 transport.c                     |   42 +++++++++-----
 transport.h                     |    3 +-
 11 files changed, 260 insertions(+), 32 deletions(-)

diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index fe716b2..53bf049 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -25,6 +25,12 @@ endif::git-pull[]
 	fetches is a descendant of `<lbranch>`.  This option
 	overrides that check.
 
+--summary::
+	Print a one-line summary of each commit fetched.
+
+--summary=<n>::
+	Like --summary, but with a limit of <n> commits per ref.
+
 -k::
 --keep::
 	Keep downloaded pack.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 73a921c..25e0dec 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -86,6 +86,12 @@ nor in any Push line of the corresponding remotes file---see below).
 --dry-run::
 	Do everything except actually send the updates.
 
+--summary::
+	Print a one-line summary of each commit pushed.
+
+--summary=<n>::
+	Like --summary, but with a limit of <n> commits per ref.
+
 --porcelain::
 	Produce machine-readable output.  The output status line for each ref
 	will be tab-separated and sent to stdout instead of stderr.  The full
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 8654fa7..4f56162 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -32,6 +32,7 @@ static const char *depth;
 static const char *upload_pack;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *transport;
+static int summary;
 
 static struct option builtin_fetch_options[] = {
 	OPT__VERBOSITY(&verbosity),
@@ -58,6 +59,9 @@ static struct option builtin_fetch_options[] = {
 		    "allow updating of HEAD ref"),
 	OPT_STRING(0, "depth", &depth, "DEPTH",
 		   "deepen history of shallow clone"),
+	{ OPTION_INTEGER, 0, "summary", &summary, "n", "print a summary of [at most n] fetched commits",
+	  PARSE_OPT_OPTARG, NULL, 20
+	},
 	OPT_END()
 };
 
@@ -210,7 +214,8 @@ static int s_update_ref(const char *action,
 
 static int update_local_ref(struct ref *ref,
 			    const char *remote,
-			    char *display)
+			    char *display,
+			    char *quickref)
 {
 	struct commit *current = NULL, *updated;
 	enum object_type type;
@@ -273,11 +278,12 @@ static int update_local_ref(struct ref *ref,
 		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
 			SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
 			r ? "  (unable to update local ref)" : "");
+		if (!r)
+			strcpy(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
 		return r;
 	}
 
 	if (in_merge_bases(current, &updated, 1)) {
-		char quickref[83];
 		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "..");
@@ -288,7 +294,6 @@ static int update_local_ref(struct ref *ref,
 			pretty_ref, r ? "  (unable to update local ref)" : "");
 		return r;
 	} else if (force || ref->force) {
-		char quickref[84];
 		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "...");
@@ -314,6 +319,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 	struct commit *commit;
 	int url_len, i, note_len, shown_url = 0, rc = 0;
 	char note[1024];
+	char quickref[84];
 	const char *what, *kind;
 	struct ref *rm;
 	char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
@@ -389,12 +395,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 				fputc(url[i], fp);
 		fputc('\n', fp);
 
-		if (ref)
-			rc |= update_local_ref(ref, what, note);
-		else
+		if (ref) {
+			*quickref = 0;
+			rc |= update_local_ref(ref, what, note, quickref);
+		} else {
+			strcpy(quickref, find_unique_abbrev(rm->old_sha1, DEFAULT_ABBREV));
 			sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
 				SUMMARY_WIDTH, *kind ? kind : "branch",
 				 REFCOL_WIDTH, *what ? what : "HEAD");
+		}
 		if (*note) {
 			if (verbosity >= 0 && !shown_url) {
 				fprintf(stderr, "From %.*s\n",
@@ -404,6 +413,9 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 			if (verbosity >= 0)
 				fprintf(stderr, " %s\n", note);
 		}
+		if (summary && quickref[0])
+			print_summary_for_push_or_fetch(quickref, summary);
+
 	}
 	free(url);
 	fclose(fp);
diff --git a/builtin-log.c b/builtin-log.c
index 8d16832..55ac4e4 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -1350,3 +1350,38 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
 	free_patch_ids(&ids);
 	return 0;
 }
+
+
+void print_summary_for_push_or_fetch(const char *quickref, int limit)
+{
+	struct rev_info rev;
+	int i, max;
+	struct object *obj;
+	struct commit *commit;
+
+	init_revisions(&rev, NULL);
+	rev.prune = 0;
+	assert(!handle_revision_arg_clearing_flags(quickref, &rev, 0, ALL_REV_FLAGS, 1));
+	assert(!prepare_revision_walk(&rev));
+
+	while ((commit = get_revision(&rev)) != NULL) {
+		struct strbuf buf = STRBUF_INIT;
+		if (limit == 0) {
+			fprintf(stderr, "    ...\n");
+			break;
+		}
+		if (!commit->buffer) {
+			enum object_type type;
+			unsigned long size;
+			commit->buffer =
+				read_sha1_file(commit->object.sha1, &type, &size);
+			if (!commit->buffer)
+				die("Cannot read commit %s", sha1_to_hex(commit->object.sha1));
+		}
+		format_commit_message(commit, "    %m %h %s\n", &buf, 0);
+		fputs(buf.buf, stderr);
+		strbuf_release(&buf);
+		limit--;
+	}
+	fputs("\n", stderr);
+}
diff --git a/builtin-push.c b/builtin-push.c
index 5df6608..30f5a61 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -101,7 +101,7 @@ static void setup_default_push_refspecs(void)
 	}
 }
 
-static int push_with_options(struct transport *transport, int flags)
+static int push_with_options(struct transport *transport, int flags, int summary)
 {
 	int err;
 	int nonfastforward;
@@ -114,7 +114,7 @@ static int push_with_options(struct transport *transport, int flags)
 	if (flags & TRANSPORT_PUSH_VERBOSE)
 		fprintf(stderr, "Pushing to %s\n", transport->url);
 	err = transport_push(transport, refspec_nr, refspec, flags,
-			     &nonfastforward);
+						 summary, &nonfastforward);
 	if (err != 0)
 		error("failed to push some refs to '%s'", transport->url);
 
@@ -132,7 +132,7 @@ static int push_with_options(struct transport *transport, int flags)
 	return 1;
 }
 
-static int do_push(const char *repo, int flags)
+static int do_push(const char *repo, int flags, int summary)
 {
 	int i, errs;
 	struct remote *remote = remote_get(repo);
@@ -184,14 +184,14 @@ static int do_push(const char *repo, int flags)
 		for (i = 0; i < url_nr; i++) {
 			struct transport *transport =
 				transport_get(remote, url[i]);
-			if (push_with_options(transport, flags))
+			if (push_with_options(transport, flags, summary))
 				errs++;
 		}
 	} else {
 		struct transport *transport =
 			transport_get(remote, NULL);
 
-		if (push_with_options(transport, flags))
+ 		if (push_with_options(transport, flags, summary))
 			errs++;
 	}
 	return !!errs;
@@ -203,6 +203,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 	int tags = 0;
 	int rc;
 	const char *repo = NULL;	/* default repository */
+	int summary = 0;
+
 	struct option options[] = {
 		OPT_BIT('q', "quiet", &flags, "be quiet", TRANSPORT_PUSH_QUIET),
 		OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
@@ -218,6 +220,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
+		{ OPTION_INTEGER, 0, "summary", &summary, "n", "print a summary of [at most n] pushed commits",
+		  PARSE_OPT_OPTARG, NULL, 20
+		},
 		OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
 			TRANSPORT_PUSH_SET_UPSTREAM),
 		OPT_END()
@@ -239,7 +244,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		set_refspecs(argv + 1, argc - 1);
 	}
 
-	rc = do_push(repo, flags);
+	rc = do_push(repo, flags, summary);
 	if (rc == -1)
 		usage_with_options(push_usage, options);
 	else
diff --git a/builtin.h b/builtin.h
index e8202f3..ec411be 100644
--- a/builtin.h
+++ b/builtin.h
@@ -19,6 +19,7 @@ extern int commit_tree(const char *msg, unsigned char *tree,
 		struct commit_list *parents, unsigned char *ret,
 		const char *author);
 extern int check_pager_config(const char *cmd);
+extern void print_summary_for_push_or_fetch(const char *quickref, int limit);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
@@ -122,4 +123,5 @@ extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
 extern int cmd_replace(int argc, const char **argv, const char *prefix);
 
+
 #endif
diff --git a/revision.c b/revision.c
index 3ba6d99..cf3103a 100644
--- a/revision.c
+++ b/revision.c
@@ -768,7 +768,7 @@ static void handle_reflog(struct rev_info *revs, unsigned flags)
 	for_each_reflog(handle_one_reflog, &cb);
 }
 
-static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
+static int add_parents_only(struct rev_info *revs, const char *arg, int flags, int flags_to_clear)
 {
 	unsigned char sha1[20];
 	struct object *it;
@@ -792,6 +792,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
 	if (it->type != OBJ_COMMIT)
 		return 0;
 	commit = (struct commit *)it;
+	if (flags_to_clear)
+	    clear_commit_marks(commit, flags_to_clear); 
 	for (parents = commit->parents; parents; parents = parents->next) {
 		it = &parents->item->object;
 		it->flags |= flags;
@@ -887,9 +889,18 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 			int flags,
 			int cant_be_filename)
 {
+    return handle_revision_arg_clearing_flags (arg, revs, flags, 0, cant_be_filename); 
+}
+
+
+
+int handle_revision_arg_clearing_flags (const char *arg, struct rev_info *revs,
+					int flags,  int flags_to_clear, 
+					int cant_be_filename)
+{
 	unsigned mode;
 	char *dotdot;
-	struct object *object;
+	struct object *object, *object_deref;
 	unsigned char sha1[20];
 	int local_flags;
 
@@ -915,6 +926,10 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 
 			a = lookup_commit_reference(from_sha1);
 			b = lookup_commit_reference(sha1);
+			if (a && flags_to_clear) 
+			    clear_commit_marks(a, flags_to_clear); 
+			if (b && flags_to_clear)
+			    clear_commit_marks(b, flags_to_clear); 
 			if (!a || !b) {
 				die(symmetric ?
 				    "Invalid symmetric difference expression %s...%s" :
@@ -945,14 +960,14 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 	dotdot = strstr(arg, "^@");
 	if (dotdot && !dotdot[2]) {
 		*dotdot = 0;
-		if (add_parents_only(revs, arg, flags))
+		if (add_parents_only(revs, arg, flags, flags_to_clear))
 			return 0;
 		*dotdot = '^';
 	}
 	dotdot = strstr(arg, "^!");
 	if (dotdot && !dotdot[2]) {
 		*dotdot = 0;
-		if (!add_parents_only(revs, arg, flags ^ UNINTERESTING))
+		if (!add_parents_only(revs, arg, flags ^ UNINTERESTING, flags_to_clear))
 			*dotdot = '^';
 	}
 
@@ -965,7 +980,17 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
 		return -1;
 	if (!cant_be_filename)
 		verify_non_filename(revs->prefix, arg);
-	object = get_reference(revs, arg, sha1, flags ^ local_flags);
+
+	object = parse_object(sha1); 
+	if (!object)
+	    die("bad object %s", arg);
+	
+	object_deref = deref_tag(object, NULL, 0); 
+	if (object_deref && object_deref->type == OBJ_COMMIT)
+	    if (flags_to_clear)
+		clear_commit_marks((struct commit *) object_deref, flags_to_clear); 
+
+	object->flags |= flags ^ local_flags; 
 	add_pending_object_with_mode(revs, object, arg, mode);
 	return 0;
 }
diff --git a/revision.h b/revision.h
index a14deef..36f78bb 100644
--- a/revision.h
+++ b/revision.h
@@ -143,6 +143,7 @@ extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ct
 				 const struct option *options,
 				 const char * const usagestr[]);
 extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename);
+extern int handle_revision_arg_clearing_flags(const char *arg, struct rev_info *revs,int flags, int flags_to_clear, int cant_be_filename);
 
 extern int prepare_revision_walk(struct rev_info *revs);
 extern struct commit *get_revision(struct rev_info *revs);
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 0f04b2e..3472aaa 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -91,6 +91,71 @@ test_expect_success 'fetch without wildcard' '
 	)
 '
 
+
+test_expect_success 'fetch --summary branch update' '
+	mk_empty &&
+	(
+		cd testrepo &&
+
+		git fetch  .. refs/heads/master:refs/remotes/origin/master &&
+
+		git update-ref refs/remotes/origin/master refs/remotes/origin/master^ &&
+
+		git fetch --summary .. refs/heads/master:refs/remotes/origin/master 2>stderr &&
+
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l) &&
+
+		  egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+		! egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+	)
+	'
+
+test_expect_success 'fetch --summary new branch' '
+	mk_empty &&p
+	(
+		cd testrepo &&
+		git fetch --summary .. refs/heads/master:refs/remotes/origin/master 2>stderr &&
+
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l) &&
+
+		egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+		egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+	)
+        '
+
+test_expect_success 'fetch --summary forced update' '
+	mk_empty &&
+	(
+		cd testrepo &&
+		git fetch .. refs/heads/master:refs/remotes/origin/master &&
+
+		git checkout refs/remotes/origin/master^ &&
+		: >path3 &&
+		git add path3 &&
+		test_tick &&
+		git commit -a -m third &&
+		git update-ref refs/remotes/origin/master HEAD &&
+
+		git fetch .. -f --summary refs/heads/master:refs/remotes/origin/master 2>stderr &&
+
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l) &&
+
+		egrep  "^    < [a-fA-F0-9]+ third$" stderr &&
+		egrep  "^    > [a-fA-F0-9]+ second$" stderr
+	)
+
+'
+
 test_expect_success 'fetch with wildcard' '
 	mk_empty &&
 	(
@@ -153,6 +218,62 @@ test_expect_success 'push without wildcard' '
 	)
 '
 
+test_expect_success 'push --summary new branch' '
+	mk_empty &&
+
+	git push --summary testrepo refs/heads/master:refs/remotes/origin/master 2>stderr &&
+	(
+		cd testrepo &&
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+	) &&
+
+	egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+	egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+'
+
+test_expect_success 'push --summary branch update' '
+	mk_empty &&
+
+	git push testrepo refs/heads/master:refs/remotes/origin/master &&
+
+	git --git-dir testrepo/.git update-ref refs/remotes/origin/master refs/remotes/origin/master^ &&
+
+	git push --summary testrepo refs/heads/master:refs/remotes/origin/master 2>stderr &&
+	(
+		cd testrepo &&
+		r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+		test "z$r" = "z$the_commit" &&
+
+		test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+	) &&
+
+	  egrep  "^    > [a-fA-F0-9]+ second$" stderr &&
+	! egrep  "^    > [a-fA-F0-9]+ repo$" stderr
+'
+
+
+test_expect_success 'push --summary forced update' '
+	mk_empty &&
+
+	git push testrepo refs/heads/master:refs/remotes/origin/master &&
+
+	git checkout master^ &&
+	: >path3 &&
+	git add path3 &&
+	test_tick &&
+	git commit -a -m third &&
+
+	git push --summary -f testrepo HEAD:refs/remotes/origin/master 2>stderr &&
+
+	egrep  "^    < [a-fA-F0-9]+ second$" stderr &&
+	egrep  "^    > [a-fA-F0-9]+ third$" stderr &&
+
+	git checkout master
+'
+
 test_expect_success 'push with wildcard' '
 	mk_empty &&
 
diff --git a/transport.c b/transport.c
index 3846aac..1e3fa7a 100644
--- a/transport.c
+++ b/transport.c
@@ -8,6 +8,7 @@
 #include "bundle.h"
 #include "dir.h"
 #include "refs.h"
+#include "builtin.h"
 #include "branch.h"
 
 /* rsync support */
@@ -642,17 +643,20 @@ static const char *status_abbrev(unsigned char sha1[20])
 	return find_unique_abbrev(sha1, DEFAULT_ABBREV);
 }
 
-static void print_ok_ref_status(struct ref *ref, int porcelain)
+static void print_ok_ref_status(struct ref *ref, int porcelain, int summary)
 {
+	char quickref[84];
+	int summary_impossible = 0;
+
 	if (ref->deletion)
 		print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
-	else if (is_null_sha1(ref->old_sha1))
+	else if (is_null_sha1(ref->old_sha1)) {
 		print_ref_status('*',
 			(!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
 			"[new branch]"),
 			ref, ref->peer_ref, NULL, porcelain);
-	else {
-		char quickref[84];
+		strcpy(quickref, status_abbrev(ref->new_sha1));
+	} else {
 		char type;
 		const char *msg;
 
@@ -661,6 +665,8 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
 			strcat(quickref, "...");
 			type = '+';
 			msg = "forced update";
+			if (!lookup_commit_reference_gently(ref->old_sha1, 1))
+				summary_impossible = 1;
 		} else {
 			strcat(quickref, "..");
 			type = ' ';
@@ -670,9 +676,17 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
 
 		print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
 	}
+
+	if (summary) {
+		if (summary_impossible) {
+			fprintf(stderr, "    %s is unavailable\n", status_abbrev(ref->old_sha1));
+		} else {
+			print_summary_for_push_or_fetch(quickref, summary);
+		}
+	}
 }
 
-static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain, int summary)
 {
 	if (!count)
 		fprintf(stderr, "To %s\n", dest);
@@ -704,7 +718,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 						 "remote failed to report status", porcelain);
 		break;
 	case REF_STATUS_OK:
-		print_ok_ref_status(ref, porcelain);
+		print_ok_ref_status(ref, porcelain, summary);
 		break;
 	}
 
@@ -712,7 +726,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
 }
 
 static void print_push_status(const char *dest, struct ref *refs,
-			      int verbose, int porcelain, int * nonfastforward)
+							  int verbose, int porcelain, int summary, int *nonfastforward)
 {
 	struct ref *ref;
 	int n = 0;
@@ -720,19 +734,19 @@ static void print_push_status(const char *dest, struct ref *refs,
 	if (verbose) {
 		for (ref = refs; ref; ref = ref->next)
 			if (ref->status == REF_STATUS_UPTODATE)
-				n += print_one_push_status(ref, dest, n, porcelain);
+				n += print_one_push_status(ref, dest, n, porcelain, summary);
 	}
 
 	for (ref = refs; ref; ref = ref->next)
 		if (ref->status == REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n, porcelain);
+			n += print_one_push_status(ref, dest, n, porcelain, summary);
 
 	*nonfastforward = 0;
 	for (ref = refs; ref; ref = ref->next) {
 		if (ref->status != REF_STATUS_NONE &&
 		    ref->status != REF_STATUS_UPTODATE &&
 		    ref->status != REF_STATUS_OK)
-			n += print_one_push_status(ref, dest, n, porcelain);
+			n += print_one_push_status(ref, dest, n, porcelain, summary);
 		if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
 			*nonfastforward = 1;
 	}
@@ -1014,8 +1028,8 @@ int transport_set_option(struct transport *transport,
 }
 
 int transport_push(struct transport *transport,
-		   int refspec_nr, const char **refspec, int flags,
-		   int *nonfastforward)
+				   int refspec_nr, const char **refspec,
+				   int flags, int summary, int *nonfastforward)
 {
 	*nonfastforward = 0;
 	verify_remote_names(refspec_nr, refspec);
@@ -1058,8 +1072,8 @@ int transport_push(struct transport *transport,
 
 		if (!quiet || err)
 			print_push_status(transport->url, remote_refs,
-					verbose | porcelain, porcelain,
-					nonfastforward);
+							  verbose | porcelain, porcelain,
+							  summary, nonfastforward);
 
 		if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
 			set_upstreams(transport, remote_refs, pretend);
diff --git a/transport.h b/transport.h
index 7cea5cc..f87b2e9 100644
--- a/transport.h
+++ b/transport.h
@@ -124,9 +124,10 @@ int transport_set_option(struct transport *transport, const char *name,
 			 const char *value);
 
 int transport_push(struct transport *connection,
-		   int refspec_nr, const char **refspec, int flags,
+		   int refspec_nr, const char **refspec, int flags, int summary,
 		   int * nonfastforward);
 
+
 const struct ref *transport_get_remote_refs(struct transport *transport);
 
 int transport_fetch_refs(struct transport *transport, struct ref *refs);
-- 
1.6.3.3.415.gbe1e

^ permalink raw reply related

* Re: [PATCH v4] add --summary option to git-push and git-fetch
From: Larry D'Anna @ 2010-01-30  0:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <7viqhzm454.fsf@alter.siamese.dyndns.org>

I know it's been a while but.....

> > @@ -373,12 +379,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
> >  				fputc(url[i], fp);
> >  		fputc('\n', fp);
> >  
> > -		if (ref)
> > -			rc |= update_local_ref(ref, what, note);
> > -		else
> > +		if (ref) {
> > +			*quickref = 0;
> > +			rc |= update_local_ref(ref, what, note, quickref);
> 
> Makes me wonder why update_local_ref() does not put that NUL upon entry.

I'm not sure what you mean.  Could you elaborate?

> > +	init_revisions(&rev, NULL);
> > +	rev.prune = 0;
> > +	assert(!handle_revision_arg(quickref, &rev, 0, 1));
> > +	assert(!prepare_revision_walk(&rev));
> > +
> > +	while ((commit = get_revision(&rev)) != NULL) {
> > +		struct strbuf buf = STRBUF_INIT;
> > +		if (limit == 0) {
> > +			fprintf(stderr, "    ...\n");
> 
> How would you know, when you asked 20 and you showed 20 here, that there
> is no more to come?

If there's more it will print the "...", if there isn't then it won't.

> > +			break;
> > +		}
> 
> > +		if (!commit->buffer) {
> > +			enum object_type type;
> > +			unsigned long size;
> > +			commit->buffer =
> > +				read_sha1_file(commit->object.sha1, &type, &size);
> > +			if (!commit->buffer)
> > +				die("Cannot read commit %s", sha1_to_hex(commit->object.sha1));
> > +		}
> > +		format_commit_message(commit, "    %m %h %s\n", &buf, 0);
> 
> Hmm, why so many spaces before %m and after %m?

So the summary lines are nicely indented with respect to the other output.

> > -static int do_push(const char *repo, int flags)
> > +static int do_push(const char *repo, int flags, int summary)
> 
> Couldn't this be just another bit in the flag?  I didn't check but I
> suspect you wouldn't have to touch the intermediate functions in the call
> chain that way.

It can't just be a bit because the "summary" parameter contains number of
summary lines to print.

> > +test_expect_success 'fetch --summary forced update' '
> > +	mk_empty &&
> > +	(
> > ...
> > +	)
> > +
> > +'
> 
> There are at least two missing combinations. (1) "fetch --summary" to
> fetch a new branch, and (2) "fetch --summary" does not try segfaulting by
> accessing unavailable information after a failed fetch.
> 
> The same comment applies to the push side of the tests.

What would be a good way to induce a failed fetch for this test?


     --larry

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Mark Lodato @ 2010-01-30  1:01 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Sverre Rabbelier, Nicolas Pitre, Git List, Ron1, Jacob Helwig
In-Reply-To: <7viqakcu56.fsf@alter.siamese.dyndns.org>

On Fri, Jan 29, 2010 at 7:29 PM, Junio C Hamano <gitster@pobox.com> wrote:
> How about this?
>
> -- >8 -- not a patch -- >8 --
> Note: 'master^0' isn't a local branch head;
>
> You are in 'detached HEAD' state. You can look around, make experimental
> changes and commit them, and you can discard any commits you make in this
> state without impacting any branches by checking out another branch.
>
> If you want to create a new branch to retain commits you create, you may
> do so (now or later) by using -b with the checkout command again. Example:
>
>  git checkout -b <new_branch_name>
>
> HEAD is now at a9d7c95... Merge branch 'maint'
> -- 8< -- not a patch -- 8< --

First off, I would like to voice support for such a warning.  This is
so much more clear than the current message.

Still, I find it slightly confusing and unfriendly.  How about the following?

-- >8 -- not a patch -- >8 --
Checking out commit 'master^0'.

Since this is not a local branch head, any commits you make will be lost
when you check out another branch or commit.  (In git terminology, HEAD
is detached.)  If you just wish to look at files without committing,
this is fine.  If you wish to make commits and retain them, you may
create a new branch by running:

  git checkout -b <new_branch_name>

HEAD is now at a9d7c95... Merge branch 'maint'
 - 8< -- not a patch -- 8< --

I think the above wording is fine for both commits (e.g. master^0) and
remote branches (e.g. origin/pu).  With other wording, we may wish to
have two slightly different messages depending on what the user typed.

Also, I am not a big fan of "local branch head".  How about "not the
name of a local branch"?  I'm not sure...

^ permalink raw reply

* Re: v1.7.0-rc0 shows lots of "unable to find <sha1>" on git-stash
From: Jonathan del Strother @ 2010-01-30  0:46 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List, Jens.Lehmann
In-Reply-To: <7vzl3wiz59.fsf@alter.siamese.dyndns.org>

On 29 January 2010 17:44, Junio C Hamano <gitster@pobox.com> wrote:
> Jonathan del Strother <maillist@steelskies.com> writes:
>
>> Heya,
>>
>> git-stash in v1.7.0-rc0 gives me several hundred lines of :
>> The previous build I was using -
>> 5b15950ac414a8a2d4f5eb480712abcc9fe176d2 from Jan 19th - didn't show
>> this problem.  Want me to try and bisect further?
>
> Yes, please.
>

ee6fc514f2df821c2719cc49499a56ef2fb136b0 (Show submodules as modified
when they contain a dirty work tree) seems to be the first bad commit.

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Nicolas Pitre @ 2010-01-30  0:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sverre Rabbelier, Git List, Ron1, Jacob Helwig
In-Reply-To: <7viqakcu56.fsf@alter.siamese.dyndns.org>

On Fri, 29 Jan 2010, Junio C Hamano wrote:

> How about this?
> 
> -- >8 -- not a patch -- >8 --
> Note: 'master^0' isn't a local branch head;
> 
> You are in 'detached HEAD' state. You can look around, make experimental
> changes and commit them, and you can discard any commits you make in this
> state without impacting any branches by checking out another branch.

s/checking out another branch/performing another checkout/

> If you want to create a new branch to retain commits you create, you may
> do so (now or later) by using -b with the checkout command again. Example:
> 
>   git checkout -b <new_branch_name>
> 
> HEAD is now at a9d7c95... Merge branch 'maint'
> -- 8< -- not a patch -- 8< --
> 
> Again, everything except for the last line would disappear by setting the
> advice.detachedHEAD configuration to false.

Looks fine to me.


Nicolas

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Michael Witten @ 2010-01-30  0:38 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Sverre Rabbelier, Nicolas Pitre, Git List, Ron1, Jacob Helwig
In-Reply-To: <7viqakcu56.fsf@alter.siamese.dyndns.org>

On Fri, Jan 29, 2010 at 6:29 PM, Junio C Hamano <gitster@pobox.com> wrote:
> The "state" was not about the work-tree state, but about the
> "detached HEAD" state, which I didn't make it clear.

Maybe we should just introduce people to a more explicit command like
the hypothetical 'update' command I sketch here:

    http://marc.info/?l=git&m=126481166426896&w=2

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Sverre Rabbelier @ 2010-01-30  0:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Nicolas Pitre, Git List, Ron1, Jacob Helwig
In-Reply-To: <7viqakcu56.fsf@alter.siamese.dyndns.org>

Heya,

On Sat, Jan 30, 2010 at 01:29, Junio C Hamano <gitster@pobox.com> wrote:
> True.  And I am a moron.

Not at all, you worded it very nicely I think.

> How about this?

Definitely a major improvement, nice.

-- 
Cheers,

Sverre Rabbelier

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Michael Witten @ 2010-01-30  0:33 UTC (permalink / raw)
  To: Ron Garret; +Cc: git, Junio C Hamano
In-Reply-To: <ron1-6C7BCB.14122429012010@news.gmane.org>

On Fri, Jan 29, 2010 at 4:12 PM, Ron Garret <ron1@flownet.com> wrote:
> In article <7vmxzwh906.fsf@alter.siamese.dyndns.org>,
>  Junio C Hamano <gitster@pobox.com> wrote:
>
>> Sverre Rabbelier <srabbelier@gmail.com> writes:
>>
>> > On Fri, Jan 29, 2010 at 22:24, Ron Garret <ron1@flownet.com> wrote:
>> >> Yes, I read that.  But what I'm trying to do is not just *look* at the
>> >> history, I want to restore my working tree to a previous version.  The
>> >> "Exploring History" section of the docs doesn't say how to do that.
>> >
>> > Do you want to restore your working tree only, or also throw away the
>> > history? If the former, you could look at 'git revert',...
>>
>> I think he wanted to check paths out of a commit and the set of paths
>> happened to be "everything".
>>
>> IOW, "checkout $commit ."
>
> Yes!!!  That's it exactly!

However, that updates the index and doesn't delete files that didn't
exist in $commit, and you said earlier that you don't want to update
the index (though perhaps you didn't really know what you wanted
there).

My idea:

Isn't the difference between 'checkout' and 'reset' almost essentially
a matter of whether the branch reference (HEAD), index, and tree are
modified? Couldn't these commands be merged into one command or make
use of one command?

Rather than relying on flags like --hard, --soft, and --mixed, why not
*also* provide flags for specifying at a finer granularity what is
desired for the index, working tree, and HEAD.

Then:
    git checkout $commit
does a lot of its work through something like:
    git update --index --tree --detach $commit

Also:
    git checkout $commit $f
translates:
    git update --index --tree --keep-tracked-files $commit $f

Also:
    git reset [--mixed] $commit
translates:
    git update --index --head $commit

Also:
    git reset --soft $commit
translates:
    git update --head $commit

Also:
    git reset --hard $commit
translates:
    git update --index --tree --head $commit

And so on.

In fact, with --no-* flags, you could modify 'reset' and 'checkout'
commands from their defaults. So, to update all of the paths
(including deleting tracked files not in $commit), but keep the index
untouched, we have:

    git checkout --no-update-index --no-update-keep-files $commit .

Of course, you might as well just use the hypothetical 'update'
command directly:

    git update --tree $commit .

Sincerely,
Michael Witten

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Junio C Hamano @ 2010-01-30  0:29 UTC (permalink / raw)
  To: Sverre Rabbelier; +Cc: Nicolas Pitre, Git List, Ron1, Jacob Helwig
In-Reply-To: <fabb9a1e1001291618m71f61209v4f26fb66c6ad99ae@mail.gmail.com>

Sverre Rabbelier <srabbelier@gmail.com> writes:

> I think the "this state" needs to be changed, it currently suggests
> what you mention earlier in you reply, that it's about the current
> state, even if you make commits on top of that. Maybe something in the
> spirit of "If you want to create a new branch from ?? where you are at
> the moment you follow these instructions ??".

True.  And I am a moron.

The "state" was not about the work-tree state, but about the
"detached HEAD" state, which I didn't make it clear.

I also didn't address "scariness" point from Nico.  And scariness can be
removed by describing things in a positive way.

How about this?

-- >8 -- not a patch -- >8 --
Note: 'master^0' isn't a local branch head;

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by checking out another branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new_branch_name>

HEAD is now at a9d7c95... Merge branch 'maint'
-- 8< -- not a patch -- 8< --

Again, everything except for the last line would disappear by setting the
advice.detachedHEAD configuration to false.

^ permalink raw reply

* Re: master^ is not a local branch -- huh?!?
From: Ron Garret @ 2010-01-30  0:18 UTC (permalink / raw)
  To: git
In-Reply-To: <ron1-A99355.16145629012010@news.gmane.org>

In article <ron1-A99355.16145629012010@news.gmane.org>,
 Ron Garret <ron1@flownet.com> wrote:

> In article <bd7fb2a884e55e176eea3002fd0c68dd@212.159.54.234>,
>  Julian Phillips <julian@quantumfyre.co.uk> wrote:
> 
> > On Fri, 29 Jan 2010 14:47:49 -0800, Ron Garret <ron1@flownet.com> wrote:
> > > My actual use case is very complicated, but here's a simplified version:
> > > 
> > > Suppose I'm using git as a back-end for a wiki.  I want to look at the 
> > > state of the entire wiki as it was in some point in the past, and I also
> > 
> > > want to be able to look at the diffs between individual pages as they 
> > > were then and as they are now.  The most straightforward way I can think
> > 
> > > of to do that is to simply copy an old commit into my working tree 
> > > without changing anything else.  Then I can look at the old version by 
> > > simply looking at the files, and I can get the diffs by simply doing a 
> > > git diff.
> > > 
> > > If I do a git reset --hard then I get the old version, but I lose my 
> > > HEAD pointer so that git diff doesn't give me what I want any more.
> > > 
> > > BTW, it turns out that git checkout [commit] . doesn't do the right 
> > > thing either.  Apparently, it still updates my index, so git diff still 
> > > doesn't do the right thing.
> > 
> > If I understand what you want correctly, then:
> > 
> > git diff --cached -R [path]
> > 
> > should be the appropriate command after the "git checkout <commit> .".
> 
> Yep, that works.  Alternatively, is there a way to clear the index?  
> Seems like that would be better.

Well, whaddyaknow: git reset without any arguments has a use after all 
:-)

rg

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox