Git development
 help / color / mirror / Atom feed
* Re: git push requires a subsequent git reset --hard ?
From: Jeff King @ 2008-07-01 17:19 UTC (permalink / raw)
  To: Neshama Parhoti; +Cc: git
In-Reply-To: <912ec82a0807010951j9e970f2k9624682b33c8af7d@mail.gmail.com>

On Tue, Jul 01, 2008 at 07:51:26PM +0300, Neshama Parhoti wrote:

> On my return, I just "git push myuser@my-station:/my/git/repo" from my laptop.
> It seemed to work with no probs.
> On my station the git repo got the new commits, as I can see in
> git-log, but the actual files were left untouched.
> 
> So I need to do something like "git reset --hard HEAD" to get
> the changes into the local files.
> 
> Is that considered normal ?
> 
> or did I do something wrong ?

See:

  http://git.or.cz/gitwiki/GitFaq#head-b96f48bc9c925074be9f95c0fce69bcece5f6e73

  and

  http://git.or.cz/gitwiki/GitFaq#head-46de97a5ac549d3adf406c22674b3325ae25d09c

What you did is OK, but there is a better way to do it.

-Peff

^ permalink raw reply

* Re: [PATCH] Teach "git apply" to prepend a prefix with "--root=<root>"
From: H. Peter Anvin @ 2008-07-01 16:57 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, git
In-Reply-To: <alpine.LSU.1.00.0807011835090.32725@wbgn129.biozentrum.uni-wuerzburg.de>

Johannes Schindelin wrote:
> Hi,
> 
> On Tue, 1 Jul 2008, H. Peter Anvin wrote:
> 
>> Junio C Hamano wrote:
>>> The -p<num> came from patch where it is also called --strip=num.  
>>> This new option --root is about the reverse operation and it is about 
>>> inserting at the beginning --- it is rerooting, in other words, but 
>>> then --root is good enough and shorter.  mkisofs uses the word "graft" 
>>> when it allows tree shifting (enabled with --graft-points), but the 
>>> word "graft" means a totally different thing to us, so we would not 
>>> want to use that word.
>>>
>>> I am not complaining (--root is fine by me), but just thinking aloud, 
>>> hoping somebody's brainwave is provoked while reading this babbling 
>>> and comes up with a better wording ;-).
>>>
>> There is an analogous concept in patch(1), it's just implemented by 
>> cd'ing to a subdirectory first.  ;)
> 
> Hey, "--cd=" is free!  And it would make explaining easier why -p is 
> applied first.
> 

Although that could imply cd'ing into another git repository to some people.

	-hpa

^ permalink raw reply

* git push requires a subsequent git reset --hard ?
From: Neshama Parhoti @ 2008-07-01 16:51 UTC (permalink / raw)
  To: git

Hi all,

I took with me a copy of a local repository to a week away from my station
(just rsync'ed it to my laptop).

On my return, I just "git push myuser@my-station:/my/git/repo" from my laptop.
It seemed to work with no probs.
On my station the git repo got the new commits, as I can see in
git-log, but the actual files were left untouched.

So I need to do something like "git reset --hard HEAD" to get
the changes into the local files.

Is that considered normal ?

or did I do something wrong ?

Thanks,
pnesh

^ permalink raw reply

* Re: [PATCH] git-add--interactive: manual hunk editing mode
From: Johannes Schindelin @ 2008-07-01 16:48 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, Jeff King, Junio C Hamano
In-Reply-To: <1214912674-9443-1-git-send-email-trast@student.ethz.ch>

Hi,

On Tue, 1 Jul 2008, Thomas Rast wrote:

> (Dscho mentioned in passing he might repost "add -e" himself.)

He will not :-)

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH?] Fix 'git show' on signed tag of signed tag of commit
From: Johannes Schindelin @ 2008-07-01 16:39 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git, gitster
In-Reply-To: <1214905624-29517-1-git-send-email-trast@student.ethz.ch>

Hi,

On Tue, 1 Jul 2008, Thomas Rast wrote:

> The cmd_show loop resolves tags by showing them, then pointing the
> object to the 'tagged' member.  However, this object is not fully
> initialized; it only contains the SHA1.  (This resulted in a segfault
> if there were two levels of tags.)  We apply parse_object to get a
> full object.
> 
> Noticed by Kalle Olavi Niemitalo on IRC.
> 
> Signed-off-by: Thomas Rast <trast@student.ethz.ch>
> ---
> 
> I'm not 100% sure this is the right fix; I just had a quick stab at the 
> code, made a fix and tested it.  It probably leaks memory too, not sure 
> if this is a problem.

AFAICT this is the correct way to solve the problem.

We do not "leak" memory here, since we just assume objects to be 
singletons (they are immutable, after all).

FWIW I had a "release_all_objects()" function in my personal fork for a 
long time, which was quite painful to write.  But maintaining the "move 
all builtins into libgit.a and avoid fork()&&exec()ing them" patch was the 
only user, and since it became way too painful to maintain out of the 
tree, I dropped both.

Ciao,
Dscho

^ permalink raw reply

* Re: How do I stop git enumerating my working directory
From: Matthieu Moy @ 2008-07-01 16:37 UTC (permalink / raw)
  To: Paul Gardiner; +Cc: git
In-Reply-To: <486A53CC.4020803@glidos.net>

Paul Gardiner <lists@glidos.net> writes:

> I don't think I can make .gitignore files do the job, because
> it seems that you can set up to ignore a whole directory,
> and then partially countermand that by placing a .gitignore
> file (containing ! commands) inside the directory.

To me, it seems the opposite ;-).

I just tried to "git init" my $HOME, then "git status" takes forever,
but "echo '*' > .gitignore; git status" completes immediately.

So, an option is to put "*" in your .gitignore, and then "git add -f"
files explicitely, or to work your .gitignore finer.

-- 
Matthieu

^ permalink raw reply

* Re: [PATCH] Teach "git apply" to prepend a prefix with "--root=<root>"
From: Johannes Schindelin @ 2008-07-01 16:36 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Junio C Hamano, git
In-Reply-To: <486A55B0.9050404@zytor.com>

Hi,

On Tue, 1 Jul 2008, H. Peter Anvin wrote:

> Junio C Hamano wrote:
> > 
> > The -p<num> came from patch where it is also called --strip=num.  
> > This new option --root is about the reverse operation and it is about 
> > inserting at the beginning --- it is rerooting, in other words, but 
> > then --root is good enough and shorter.  mkisofs uses the word "graft" 
> > when it allows tree shifting (enabled with --graft-points), but the 
> > word "graft" means a totally different thing to us, so we would not 
> > want to use that word.
> > 
> > I am not complaining (--root is fine by me), but just thinking aloud, 
> > hoping somebody's brainwave is provoked while reading this babbling 
> > and comes up with a better wording ;-).
> > 
> 
> There is an analogous concept in patch(1), it's just implemented by 
> cd'ing to a subdirectory first.  ;)

Hey, "--cd=" is free!  And it would make explaining easier why -p is 
applied first.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] Teach "git apply" to prepend a prefix with "--root=<root>"
From: Johannes Schindelin @ 2008-07-01 16:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: H. Peter Anvin, git
In-Reply-To: <7vvdzqnemk.fsf@gitster.siamese.dyndns.org>

Hi,

On Tue, 1 Jul 2008, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > With "git apply --root=<root>", all file names in the patch are prepended
> > with <root>.  If a "-p" value was given, the paths are stripped _before_
> > prepending <root>.
> 
> > @@ -182,6 +182,10 @@ behavior:
> >  	by inspecting the patch (e.g. after editing the patch without
> >  	adjusting the hunk headers appropriately).
> >  
> > +--root=<root>::
> > +	Prepend <root> to all filenames.  If a "-p" argument was passed, too,
> > +	it is applied before prepending the new root.
> > +
> 
> I looked for precedence of this concept outside git but did not find
> anything that exactly matched.
> 
> The -p<num> came from patch where it is also called --strip=num.  This 
> new option --root is about the reverse operation and it is about 
> inserting at the beginning --- it is rerooting, in other words, but then 
> --root is good enough and shorter.  mkisofs uses the word "graft" when 
> it allows tree shifting (enabled with --graft-points), but the word 
> "graft" means a totally different thing to us, so we would not want to 
> use that word.
> 
> I am not complaining (--root is fine by me), but just thinking aloud, 
> hoping somebody's brainwave is provoked while reading this babbling and 
> comes up with a better wording ;-).

Yeah, I am not too happy, but I saw you and hpa on IRC agreeing on that 
option name.  I would have said "--prefix", but that is too ambiguous, 
what with "prefix" already meaning "path relative to the working directory 
root".

> > diff --git a/builtin-apply.c b/builtin-apply.c
> > index 9fcfe39..d56d913 100644
> > --- a/builtin-apply.c
> > +++ b/builtin-apply.c
> > @@ -58,6 +58,8 @@ static int whitespace_error;
> > @@ -3240,6 +3252,18 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
> >  			options |= RECOUNT;
> >  			continue;
> >  		}
> > +		if (!strncmp(arg, "--root=", strlen("--root="))) {
> 
> prefixcmp()?

D'oh.

I mean, thanks!

> > +			arg += strlen("--root=");
> > +			root_len = strlen(arg);
> > +			if (root_len && arg[root_len + 1] != '/') {
> 
> Ah, being nice not to force trailing slash on users --- how unlike you 
> ;-)

Seems to be the new favorite sports, Dscho bashing.

> but I think you meant "arg[root_len - 1]" there...

I did.  An earlier version (as I found out by using the reflogs, as I tend 
to do a lot these last couple of weeks) even had a "-".  Musta been late.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH 3/7] Documentation: complicate example of "man git-command"
From: J. Bruce Fields @ 2008-07-01 16:23 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: git, Junio C Hamano, Christian Couder, Nguyen Thai Ngoc Duy,
	Jon Loeliger
In-Reply-To: <Pine.GSO.4.62.0806301706090.7190@harper.uchicago.edu>

On Mon, Jun 30, 2008 at 05:10:25PM -0500, Jonathan Nieder wrote:
> The manual page for the command invoked as "git clone" is named
> git-clone(1), and similarly for the rest of the git commands.
> Make sure our first example of this in tutorials makes it clear
> that it is the first two words of a command line that make up the
> command's name (that is: for example, the effect of "git svn
> dcommit" is described in git-svn(1)).

Is this confusion really common?

I can see how it might be possible in the case of a subcommand that
itself has subcommands, but it seems less likely in the two examples you
add below (where the third token is an option or a url).  I like your
"git svn" example better.  Or "git remote" might be good.

--b.

> 
> Signed-off-by: Jonathan Nieder <jrnieder@uchicago.edu>
> ---
> 	If I didn't make this change, consistency would mean
> 	saying "you can get documentation for a command such
> 	as `git-diff` with `man git-diff`", which might not be
> 	very enlightening.
> 
>  Documentation/gittutorial.txt |    4 ++--
>  Documentation/user-manual.txt |    2 +-
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
> index 3d16e3d..b833167 100644
> --- a/Documentation/gittutorial.txt
> +++ b/Documentation/gittutorial.txt
> @@ -20,10 +20,10 @@ for example, to test the latest version, you may prefer to start with
>  the first two chapters of link:user-manual.html[The Git User's Manual].
>  
>  First, note that you can get documentation for a command such as "git
> -diff" with:
> +log --graph" with:
>  
>  ------------------------------------------------
> -$ man git-diff
> +$ man git-log
>  ------------------------------------------------
>  
>  It is a good idea to introduce yourself to git with your name and
> diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
> index ca4363f..36ab372 100644
> --- a/Documentation/user-manual.txt
> +++ b/Documentation/user-manual.txt
> @@ -18,7 +18,7 @@ People needing to do actual development will also want to read
>  Further chapters cover more specialized topics.
>  
>  Comprehensive reference documentation is available through the man
> -pages.  For a command such as "git clone", just use
> +pages.  For a command such as "git clone <repo>", just use
>  
>  ------------------------------------------------
>  $ man git-clone
> -- 
> 1.5.5.GIT
> 
> 

^ permalink raw reply

* How do I stop git enumerating my working directory
From: Paul Gardiner @ 2008-07-01 15:57 UTC (permalink / raw)
  To: git; +Cc: lists

Hi,

I'm a recent convert to git. I've been swapping over my projects
from cvs to git. The latest candidate for conversion is the
config files for my Linux server. I've been using cvs to record
all the config changes, and - mostly-automatically - to setup
new servers. Git will do a far better job, I think, but
I think I'm going to run into a problem: the root directory
of the server will be the working directory. Only relatively
few files will be under version control. How do I stop git
enumerating the whole drive whenever I do things like git-diff?

I don't think I can make .gitignore files do the job, because
it seems that you can set up to ignore a whole directory,
and then partially countermand that by placing a .gitignore
file (containing ! commands) inside the directory. That
makes me think that ignoring doesn't prevent the
enumeration.

Any help most appreciated. I really want to use git for
this.

Cheers,
	Paul.

^ permalink raw reply

* Re: [PATCH] Teach "git apply" to prepend a prefix with "--root=<root>"
From: H. Peter Anvin @ 2008-07-01 16:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7vvdzqnemk.fsf@gitster.siamese.dyndns.org>

Junio C Hamano wrote:
> 
> The -p<num> came from patch where it is also called --strip=num.  This new
> option --root is about the reverse operation and it is about inserting at
> the beginning --- it is rerooting, in other words, but then --root is good
> enough and shorter.  mkisofs uses the word "graft" when it allows tree
> shifting (enabled with --graft-points), but the word "graft" means a
> totally different thing to us, so we would not want to use that word.
> 
> I am not complaining (--root is fine by me), but just thinking aloud,
> hoping somebody's brainwave is provoked while reading this babbling and
> comes up with a better wording ;-).
> 

There is an analogous concept in patch(1), it's just implemented by 
cd'ing to a subdirectory first.  ;)

I think --root makes sense as the root of the patch.  The other 
alternative would be --add (by analogy with --strip); the biggest 
advantage there is that -a, as a short option, isn't used for anything 
either by git-am, git-apply, or patch.

Incidentally, has anyone talked to the patch(1) maintainers about adding 
support for the git extensions, like binary patches?  The main reason is 
that patch(1) is still useful when you have to suffer though fuzzy errors.

	-hpa

^ permalink raw reply

* Re: [RFC/PATCH 2/4] Add git-sequencer prototype documentation
From: Stephan Beyer @ 2008-07-01 16:03 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git, Junio C Hamano, Johannes Schindelin
In-Reply-To: <m34p79hhy9.fsf@localhost.localdomain>

Hi,

On Tue, Jul 01, 2008 at 06:02:54AM -0700,
Jakub Narebski <jnareb@gmail.com> wrote:
> > +git-sequencer will usually be called by another git porcelain, like
> > +linkgit:git-am[1] or linkgit:git-rebase[1].
> 
> I hope that it could be also used by git-cherry-pick and git-revert,
> so it would be possible to pick more than one commit...

Right, you've already mentioned it several times. ;-)
But I haven't included it currently, because git-sequencer currently *uses*
cherry-pick/revert to pick/revert commits, and I think this can lead to
some confusion.
And, I think there also has to be some discussion, e.g.
if even the single cherry-pick/revert uses sequencer, then the behavior
changes for the user: currently you have to "git commit" after a
conflict on cherry-pick. When it uses sequencer, you have to
git-sequencer --continue (or --skip or --abort) ;)

So I'm only concentrating on rebase and am users until the builtin sequencer
is in good shape.

> > +After resolving the conflict manually and updating the index with the
> > +desired resolution, you can continue the sequencing process with
> > +
> > +    git sequencer --continue
> 
> Does it run pre-commit hooks, for example checking for merge markers
> (but also whitespace errors), and can those checks be disabled?

It only commits (git commit) staged changes (if the working tree is
clean) and the pre-commit hooks are bypassed (as in rebase-i).

> > +-B::
> > +--batch::
> > +	Run in batch mode. If unexpected user intervention is needed
> > +	(e.g. a conflict or the need to run an editor), git-sequencer fails.
> > ++
> > +Note that the sanity check fails, if you use this option
> > +and an instruction like `edit` or `pause`.
> 
> s/.$/ is in the TODO file./

Agreed.

diff --git a/Documentation/git-sequencer.txt b/Documentation/git-sequencer.txt
index e0c6410..1a9eda4 100644
--- a/Documentation/git-sequencer.txt
+++ b/Documentation/git-sequencer.txt
@@ -62,7 +62,7 @@ OPTIONS
 	(e.g. a conflict or the need to run an editor), git-sequencer fails.
 +
 Note that the sanity check fails, if you use this option
-and an instruction like `edit` or `pause`.
+and an instruction like `edit` or `pause` is in the TODO file.
 
 --onto=<base>::
 	Checkout given commit or branch before sequencing.
##

> > +--edit::
> > +	Invoke editor to edit the undone rest of the TODO file.
> 
> Does it mean that editor will be invoked with only _unprocessed_
> part of the TODO file?  It looks like it, but it might be not
> obvious to some.

Thanks, this sounds better.

@@ -83,7 +83,7 @@ and an instruction like `edit` or `pause`.
 	operations can be done to change that status.
 
 --edit::
-	Invoke editor to edit the undone rest of the TODO file.
+	Invoke editor to edit the unprocessed part of the TODO file.
 +
 The file is syntax- and sanity-checked afterwards, so that you can
 safely run `git sequencer --skip` or `--continue` after editing.
##

> > +merge [options] <commit-ish1> <commit-ish2> ... <commit-ishN>::
> > +	Merge commits into HEAD.
> 
> Nice.
> 
> "HEAD" mean last picked up / created commit, isn't it?

Right. This is used throughout the document...
I thought it is clear and better to use than always describing around it
by "last created commit".
But currently I'm unsure about it :)

> > ++
> > +A commit can also be given by a mark, if prefixed with a colon.
> 
> "You can refer to commit by mark", perhaps?

Hm, is "by" the right preposition?

@@ -150,7 +150,7 @@ The set marks are removed after the sequencer has completed.
 merge [options] <commit-ish1> <commit-ish2> ... <commit-ishN>::
 	Merge commits into HEAD.
 +
-A commit can also be given by a mark, if prefixed with a colon.
+You can refer to a commit by a mark.
 +
 If you do not provide a commit message (using `-F`, `-m`, `-C`, `-M`,
 or `--standard`), an editor will be invoked.
##

> > +	--standard;;
> > +		Generates a commit message like 'Merge ... into HEAD'.
> > +		See also linkgit:git-fmt-merge-msg[1].
> 
> Is it short for `--standard-message`?

Do you think it should?
Semantically it is less ambiguous, right, but
as there is not short option, I think we should not make
the long options too long...

Perhaps --std-msg?

> > +pick [options] <commit>::
> > +	Pick (see linkgit:git-cherry-pick[1]) a commit.
> > +	Sequencer will pause on conflicts.
> > ++
> > +See the following list and 'GENERAL OPTIONS' for values of `options`:
> > +
> > +	-R;;
> > +	--reverse;;
> > +		Revert the changes introduced by pick <commit>.
> > +
> > +	--mainline=<n>;;
> > +		Allows you to pick merge commits by specifying the
> > +		parent number (beginning from 1) to let sequencer
> > +		replay the changes relative to the specified parent.
> > +		+
> > +This option does not work together with `-R`.
> 
> Why?  I would have thought that it would work...

git-revert has no --mainline option.
When sequencer won't use cherry-pick/revert anymore, we can add that.

> > +patch [options] <file>::
> [...]
> > +	-*;;
> > +		Any other dash-prefixed option is passed to
> > +		linkgit:git-apply[1].
> > +		This is especially useful for flags like
> > +		`--reverse`, `-C<n>`, `-p<n>` or `--whitespace=<action>`.
> 
> Do all options make sense?  What about `--index' and `--cached',
> or about different no-apply options?

No, not all make sense and in fact the "any other dash-prefixed option"
was true some weeks ago, but now it's a lie. Now it is just a definite
subset and -C was renamed to --context due a conflict with the general
option -C.

This is better:    (Lot of text copy&pasted from git-apply.txt)

@@ -208,11 +208,50 @@ See the following list and 'GENERAL OPTIONS' for values of `options`:
 	-n;;
 		Pass `-n` flag to `git-mailinfo` (see linkgit:git-mailinfo[1]).
 
-	-*;;
-		Any other dash-prefixed option is passed to
-		linkgit:git-apply[1].
-		This is especially useful for flags like
-		`--reverse`, `-C<n>`, `-p<n>` or `--whitespace=<action>`.
+	--exclude=<path-pattern>;;
+		Do not apply changes to files matching the given path pattern.
+		This can be useful when importing patchsets, where you want to
+		exclude certain files or directories.
+
+	-R;;
+	--reverse;;
+		Apply the patch in reverse.
+
+	--no-add;;
+		When applying a patch, ignore additions made by the
+		patch.  This can be used to extract the common part between
+		two files by first running `diff` on them and applying
+		the result with this option, which would apply the
+		deletion part but not addition part.
+
+	--whitespace=<action>;;
+		Specify behavior on whitespace errors.
+		See linkgit:git-apply[1] for a detailed description.
+
+	--context=<n>;;
+		Ensure at least <n> lines of surrounding context match before
+		and after each change.  When fewer lines of surrounding
+		context exist they all must match.  By default no context is
+		ever ignored.
+
+	--inaccurate-eof;;
+		Under certain circumstances, some versions of diff do not
+		correctly detect a missing new-line at the end of the file.
+		As a result, patches created by such diff programs do not
+		record incomplete lines correctly.
+		This option adds support for applying such patches by
+		working around this bug.
+
+	-p<n>;;
+		Remove <n> leading slashes from traditional diff paths.
+		The default is 1.
+
+	--unidiff-zero;;
+		By default, linkgit:git-apply[1] expects that the patch being
+		applied is a unified diff with at least one line of context.
+		This provides good safety measures, but breaks down when
+		applying a diff generated with --unified=0. To bypass these
+		checks use '--unidiff-zero'.
 
 
 pause::
##

> > +ref <ref>::
> > +	Set ref `<ref>` to the current HEAD, see also
> > +	linkgit:git-update-ref[1].
> 
> So this functions like "git reset --soft <ref>", isn't it?

No. Why do you think that? `ref` is set, and not HEAD.
I think the description makes that clear.

> > +squash [options] --from <mark>::
> > +	Squash all commits from the given mark into one commit.
> > +	There must not be any `merge` instructions between the
> > +	`mark` instruction and this `squash --from` instruction.
> 
> Can you use <commit> instead of <mark> here?

I wanted to make it clear that you can only specify a mark:
a commit that has been somehow used in this sequencer session.

Or have you meant that you think it is a bad restriction to only
allow marks and no commits?
I think this is a useful thing, because it's user-safe and I
cannot imagine a case where you want to give a sha1 or a
tag or branch or something.

Here an example why it is useful for user-editing:

(on commit f00babe)
	mark :1
	pick badcebab
	patch foo
	pick dadadada
	squash -m "Foo the cebab" --signoff --from :1

This squashes all between the mark and the squash into one commit,
on top of f00babe.

If we allow commits, the user could think that

	pick badcebab
	patch foo
	pick dadadada
	squash -m "Foo the cebab" --signoff --from badcebab

does the same, but this leads to:
 f00babe, picked-badcebab, squash-of-foo-and-dadadada

So
	squash -m "Foo the cebab" --signoff --from f00babe
would be correct.  But this is unintuitive.
So it's safer if we restrict this to marks.

> > +	--include-merges;;
> > +		Sanity check does not fail if you have merges
> > +		between HEAD and <mark>.
> 
> How do you squash merges?  Creating merge with an union of parents,
> excluding commits which got squashed?

My squashes are realized using git reset --soft ... and then commit.
I think this makes only sense when there are no merges in between,
so I added the check, but if someone wants to squash merges, he should
be able to do it.
To somehow answer your question: I do not care what the result is,
because I do not know what the result "should be".
IIRC the "other" parents of the merge commit are not kept, so it seems
that you have a commit that contains the changes after the merge, but
not the meta information like the right parents.

> It means
> 
>   ...a---b---c---d         ...[abcd]
>             /        ==>        /
>       ...x-/               ..x-/
> 
> but
> 
>   ...a---b---c---d          ...[abcd]
>       \     /        ==>
>        \-x-/ 
> 

I think it will be ...[abcdx].

But as I said, "I don't care". And the help description shows that.

> > +RETURN VALUES
> > +-------------
> > +* any other value on error, e.g.
> > +  running git-sequencer on a bare repository.
> 
> Don't you enumerate those return values?

In one of the very first spec versions, it was value 1, but:

	$ grep -A 3 ^die git-sh-setup
	die() {
		echo >&2 "$@"
		exit 1
	}

	$ grep -m 1 -A 4 die_builtin usage.c
	static NORETURN void die_builtin(const char *err, va_list params)
	{
		report("fatal: ", err, params);
		exit(128);
	}


Regards,
  Stephan

-- 
Stephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F

^ permalink raw reply related

* Re: What's cooking in git.git (topics)
From: Kristian Høgsberg @ 2008-07-01 15:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, akpm, Stephen Rothwell, pasky
In-Reply-To: <7vabh2vaav.fsf@gitster.siamese.dyndns.org>

On Mon, 2008-06-30 at 15:15 -0700, Junio C Hamano wrote:
> Kristian Høgsberg <krh@redhat.com> writes:
> 
> > On Mon, 2008-06-30 at 02:08 -0700, Junio C Hamano wrote:
> > ...
> >> It already is beginning to become clear what 1.6.0 will look like.  What's
> >> already in 'next' all are well intentioned (I do not guarantee they are
> >> already bug-free --- that is what cooking them in 'next' is for) and are
> >> good set of feature enhancements.  Bigger changes will be:
> > ...
> > A small detail I've suggested scheduling for 1.6 before is removing (or
> > rather, stop creating) the empty .git/branches directory.  How does that
> > sound?
> 
> What's the benefit of the removal that outweighs the downside?  I can
> imagine two contradicting voices from new end users.
> 
>  (1) With current git, I ran "git init" and I have an empty
>      .git/branches/, but my remote information created with "git clone"
>      and "git remote add" all go to .git/config these days.  Why do I have
>      to have this empty directory that I do not use?

Yeah, that's one reason, my main problem with .git/branches is that for
a user that wants to learn about git and peeks into .git it's pretty
confusing.  "I wonder where and how git stores the information about
branches... oh look, .git/branches, that must it... hmm, wait no..."
Git is still getting a lot of bad-mouthing for being hard to learn and
inconsitent.  I think it makes sense to push git towards consistency and
simplicity (where is doesn't affect the flexibility) and this seemed
like a tiny step towards that.  As Dscho mentioned we have two other
ways of accomplishing what .git/branches did, so maybe it makes sense to
retire this one?

>  (2) It is documented that "git fetch" can use files in .git/branches/ as
>      the source specification, but when I ran "git init", it does not
>      create the directory with Kristian's git. I need to do an extra
>      "mkdir .git/branches/" myself.  Why?

We could just change the documentation to ask the user to create
the .git/branches directory if they want to use that feature.

> You are obviously coming from the former camp, but do you have a good
> answer to people from the other camp?
> 
> I do not recall if Cogito required to have .git/branches created by us or
> it can create it on demand if we don't.  If the latter, that would be
> great, otherwise remaining users would be in the latter camp as well, and
> we may have to make sure Cogito is really dead already (or wait for it to
> die), or Cogito gets updated for its remaining users to tolerate the
> initial lack of the directory (and wait for that version percolates down
> to the users).
> 
> Some people rely on (or at least "like") the convenience of being able to
> create a single-liner file in .git/branches/ to easily add, and remove
> such a file to easily remove where they integrate from.  This is
> especially so when they have dozens of source repositories to fetch from.
> I do not think we want to remove support for .git/branches as a way to
> specify fetch sources (this is why I am CC'ing Andrew who I know uses
> branches, and Stephen who is also a heavy integrator even though I do not
> know if he is in branches camp or uses more modern style), but they now
> have to do an extra "mkdir .git/branches" after "git init" to continue
> their workflow if we adopt the change you are proposing here.  It is not a
> big deal, but it still is a backward incompatible change.

Yeah... I have to confess, that when I suggested removing it, I was
under the impression that git didn't use .git/branches, but only created
it to be nice to cogito.  I just read the code in remote.c that deals
with .git/branches and understand that it's still used by git.  From the
feedback from Stephen, Andrew and Pasky, it looks like we can drop
the .git/branches from the template for 1.6 and maybe in the future, we
could drop the .git/branches support entirely.  Dunno.

cheers,
Kristian

^ permalink raw reply

* [PATCH] fix "git-submodule add a/b/c/repository"
From: Sylvain Joyeux @ 2008-07-01 15:00 UTC (permalink / raw)
  To: git

The 'master' version of git-submodule.sh fails to see that
a/b/c/repository is an already existing repository and messes up the
whole thing. The following patch fixes that.
-- 
Sylvain

>From 2bca2e17a01cd81ce30f81750583ab943ab57ff0 Mon Sep 17 00:00:00 2001
From: Sylvain Joyeux <sylvain.joyeux@dfki.de>
Date: Tue, 1 Jul 2008 16:45:04 +0200
Subject: [PATCH] fix submodule add for non-toplevel in-project directories

This patch fixes git-submodule add for submodules that
already exist in the current package tree, in a folder
which is not at toplevel, i.e.:

  git submodule add a/b/c/repository

Signed-off-by: Sylvain Joyeux <sylvain.joyeux@dfki.de>
---
 git-submodule.sh           |    6 +++++-
 t/t7400-submodule-basic.sh |    9 +++++++++
 2 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index e2b91f6..3fa8ff3 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -156,7 +156,11 @@ cmd_add()
 
 	# Guess path from repo if not specified or strip trailing slashes
 	if test -z "$path"; then
-		path=$(echo "$repo" | sed -e 's|/*$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
+                if echo "$repo" | grep -q "^\(\.\.\|\/\)"; then
+                        path=$(echo "$repo" | sed -e 's|/*$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
+                else
+                        path=$(echo "$repo" | sed -e 's|/*$||')
+                fi
 	else
 		path=$(echo "$path" | sed -e 's|/*$||')
 	fi
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index ffaa932..84ea6e9 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -215,4 +215,13 @@ test_expect_success 'update --init' '
 
 '
 
+test_expect_success 'adding an already-existing repository deep in the directory hierarchy' '
+
+        mkdir dir0 &&
+        mkdir dir0/dir1 &&
+        git clone init dir0/dir1/init &&
+        git-submodule add dir0/dir1/init &&
+        git-submodule status | grep "dir0/dir1/init"
+'
+
 test_done
-- 
1.5.6

^ permalink raw reply related

* [PATCH] better git-submodule status output
From: Sylvain Joyeux @ 2008-07-01 15:01 UTC (permalink / raw)
  To: git

Oups.. sorry for the patch-as-attachment in the previous mail

This patch makes the output of git-submodule more useful to handle the
management of a repository using multiple submodules. Namely, it
displays informations about how the current checked out version relates
to the registered one (i.e. direct parent, direct child, "just
different", registered revision does not exist), and displays if the
submodules contain uncommitted changes.

This (among other things) allows to do git-submodule update while
knowing exactly what will happen.
--
Sylvain

>From 16553a9b210a956b0af961d55a9cf06f1b9b8114 Mon Sep 17 00:00:00 2001
From: Sylvain Joyeux <sylvain.joyeux@dfki.de>
Date: Tue, 1 Jul 2008 16:01:01 +0200
Subject: [PATCH] more information in git-submodule status output

This commit adds more information in the 'status' output of
git-submodule. More specifically, it displays different flags if the
submodule and the registered revision are direct parents (> and <,
depending on which is the ancestor), if they are not direct parents (+)
or if the registered revision cannot be found (i.e. if submodule update
would fail, '!')

Finally, it shows if the submodule contains uncommitted changes (M flag)

Signed-off-by: Sylvain Joyeux <sylvain.joyeux@dfki.de>
---
 Documentation/git-submodule.txt |   23 ++++++++++++++++++-----
 git-submodule.sh                |   32 ++++++++++++++++++++++++++++----
 t/t7400-submodule-basic.sh      |   20 +++++++++++++-------
 3 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 441ae14..3820002 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -33,10 +33,23 @@ status::
 	Show the status of the submodules. This will print the SHA-1 of the
 	currently checked out commit for each submodule, along with the
 	submodule path and the output of linkgit:git-describe[1] for the
-	SHA-1. Each SHA-1 will be prefixed with `-` if the submodule is not
-	initialized and `+` if the currently checked out submodule commit
-	does not match the SHA-1 found in the index of the containing
-	repository. This command is the default command for git-submodule.
+	SHA-1. Each SHA-1 will be prefixed with the following codes:
+	* `-` if the submodule is not initialized
+	* `<` if the current submodule HEAD is a direct ancestor of the
+	    revision registered in the containing repository.  I.e. a `git
+	    submodule update` would lead to a fast forward.
+	* `>` if the current submodule HEAD is a direct ancestor of the
+	    revision registered in the containing repository.
+	* `+` if the current submodule HEAD and the revision registered in
+	    the containing repository do not match, and there is no direct
+	    relationship between the two commits.
+	* `!` if the SHA-1 found in the index of the containing repository is
+	    not present in the the currently checked out submodule commit,
+	    nor be fetched from the associated remote.
+	
+	Additionally, a 'M' is displayed if the currently checked out
+	submodule contains uncommitted changes.
+	This command is the default command for git-submodule.
 
 init::
 	Initialize the submodules, i.e. register in .git/config each submodule
@@ -97,7 +110,7 @@ for details.
 
 AUTHOR
 ------
-Written by Lars Hjemli <hjemli@gmail.com>
+Written by Lars Hjemli <hjemli@gmail.com> and Sylvain Joyeux <sylvain.joyeux@m4x.org>
 
 GIT
 ---
diff --git a/git-submodule.sh b/git-submodule.sh
index 3eb78cc..e2b91f6 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -522,7 +522,11 @@ cmd_summary() {
 #
 # List all submodules, prefixed with:
 #  - submodule not initialized
-#  + different revision checked out
+#  > the checked out version is in advance with the current version (fast-forward)
+#  < the checked out version is late w.r.t the current version (fast-forward)
+#  + different revisions checked out, no fast-forward relationship
+#  ! the checked out version does not exist and cannot be fetched
+#  M submodule contains uncommitted changes
 #
 # If --cached was specified the revision in the index will be printed
 # instead of the currently checked out revision.
@@ -562,20 +566,40 @@ cmd_status()
 		url=$(git config submodule."$name".url)
 		if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
 		then
-			say "-$sha1 $path"
+			say "-  $sha1 $path"
 			continue;
 		fi
+                unclean=" "
+                if ! ( unset GIT_DIR; cd "$path" && git diff --quiet HEAD ); then
+                    unclean="M"
+                fi
 		set_name_rev "$path" "$sha1"
 		if git diff-files --quiet -- "$path"
 		then
-			say " $sha1 $path$revname"
+			say " $unclean $sha1 $path$revname"
 		else
+                        head=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
+                        common=$(unset GIT_DIR; cd "$path" && git merge-base HEAD $sha1)
+                        if test -z "$common"; then
+                            common=$(unset GIT_DIR; cd "$path" && git-fetch -q &&
+                                    git merge-base HEAD $sha1)
+                        fi
+                        if test "$common" = "$sha1"; then
+                            modflag=">"
+                        elif test "$common" = "$head"; then
+                            modflag="<"
+                        elif test "$common" = ""; then
+                            modflag="!"
+                        else
+                            modflag="+"
+                        fi
+
 			if test -z "$cached"
 			then
 				sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
 				set_name_rev "$path" "$sha1"
 			fi
-			say "+$sha1 $path$revname"
+			say "$modflag$unclean $sha1 $path$revname"
 		fi
 	done
 }
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 6c7b902..ffaa932 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -65,7 +65,7 @@ test_expect_success 'status should only print one line' '
 '
 
 test_expect_success 'status should initially be "missing"' '
-	git-submodule status | grep "^-$rev1"
+	git-submodule status | grep "^-  $rev1"
 '
 
 test_expect_success 'init should register submodule url in .git/config' '
@@ -130,13 +130,19 @@ test_expect_success 'update should work when path is an empty dir' '
 '
 
 test_expect_success 'status should be "up-to-date" after update' '
-	git-submodule status | grep "^ $rev1"
+	git-submodule status | grep "^   $rev1"
 '
 
-test_expect_success 'status should be "modified" after submodule commit' '
+test_expect_success 'status should be "modified" after submodule change' '
 	cd init &&
 	echo b >b &&
-	git add b &&
+        git add b &&
+        cd .. &&
+	git-submodule status | grep "^ M $rev1"
+'
+
+test_expect_success 'status should be "in advance" after submodule commit' '
+	cd init &&
 	git-commit -m "submodule commit 2" &&
 	rev2=$(git rev-parse HEAD) &&
 	cd .. &&
@@ -145,11 +151,11 @@ test_expect_success 'status should be "modified" after submodule commit' '
 		echo "[OOPS] submodule git rev-parse returned nothing"
 		false
 	fi &&
-	git-submodule status | grep "^+$rev2"
+	git-submodule status | grep "^>  $rev2"
 '
 
 test_expect_success 'the --cached sha1 should be rev1' '
-	git-submodule --cached status | grep "^+$rev1"
+	git-submodule --cached status | grep "^>  $rev1"
 '
 
 test_expect_success 'git diff should report the SHA1 of the new submodule commit' '
@@ -171,7 +177,7 @@ test_expect_success 'update should checkout rev1' '
 '
 
 test_expect_success 'status should be "up-to-date" after update' '
-	git-submodule status | grep "^ $rev1"
+	git-submodule status | grep "^   $rev1"
 '
 
 test_expect_success 'checkout superproject with subproject already present' '
-- 
1.5.6

^ permalink raw reply related

* [PATCH] better git-submodule status output
From: Sylvain Joyeux @ 2008-07-01 14:57 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 491 bytes --]

This patch makes the output of git-submodule more useful to handle the
management of a repository using multiple submodules. Namely, it
displays informations about how the current checked out version relates
to the registered one (i.e. direct parent, direct child, "just
different", registered revision does not exist), and displays if the
submodules contain uncommitted changes.

This (among other things) allows to do git-submodule update while
knowing exactly what will happen.

Sylvain


[-- Attachment #2: 0001-more-information-in-git-submodule-status-output.patch --]
[-- Type: text/x-diff, Size: 7218 bytes --]

>From 16553a9b210a956b0af961d55a9cf06f1b9b8114 Mon Sep 17 00:00:00 2001
From: Sylvain Joyeux <sylvain.joyeux@dfki.de>
Date: Tue, 1 Jul 2008 16:01:01 +0200
Subject: [PATCH] more information in git-submodule status output

This commit adds more information in the 'status' output of
git-submodule. More specifically, it displays different flags if the
submodule and the registered revision are direct parents (> and <,
depending on which is the ancestor), if they are not direct parents (+)
or if the registered revision cannot be found (i.e. if submodule update
would fail, '!')

Finally, it shows if the submodule contains uncommitted changes (M flag)

Signed-off-by: Sylvain Joyeux <sylvain.joyeux@dfki.de>
---
 Documentation/git-submodule.txt |   23 ++++++++++++++++++-----
 git-submodule.sh                |   32 ++++++++++++++++++++++++++++----
 t/t7400-submodule-basic.sh      |   20 +++++++++++++-------
 3 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 441ae14..3820002 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -33,10 +33,23 @@ status::
 	Show the status of the submodules. This will print the SHA-1 of the
 	currently checked out commit for each submodule, along with the
 	submodule path and the output of linkgit:git-describe[1] for the
-	SHA-1. Each SHA-1 will be prefixed with `-` if the submodule is not
-	initialized and `+` if the currently checked out submodule commit
-	does not match the SHA-1 found in the index of the containing
-	repository. This command is the default command for git-submodule.
+	SHA-1. Each SHA-1 will be prefixed with the following codes:
+	* `-` if the submodule is not initialized
+	* `<` if the current submodule HEAD is a direct ancestor of the
+	    revision registered in the containing repository.  I.e. a `git
+	    submodule update` would lead to a fast forward.
+	* `>` if the current submodule HEAD is a direct ancestor of the
+	    revision registered in the containing repository.
+	* `+` if the current submodule HEAD and the revision registered in
+	    the containing repository do not match, and there is no direct
+	    relationship between the two commits.
+	* `!` if the SHA-1 found in the index of the containing repository is
+	    not present in the the currently checked out submodule commit,
+	    nor be fetched from the associated remote.
+	
+	Additionally, a 'M' is displayed if the currently checked out
+	submodule contains uncommitted changes.
+	This command is the default command for git-submodule.
 
 init::
 	Initialize the submodules, i.e. register in .git/config each submodule
@@ -97,7 +110,7 @@ for details.
 
 AUTHOR
 ------
-Written by Lars Hjemli <hjemli@gmail.com>
+Written by Lars Hjemli <hjemli@gmail.com> and Sylvain Joyeux <sylvain.joyeux@m4x.org>
 
 GIT
 ---
diff --git a/git-submodule.sh b/git-submodule.sh
index 3eb78cc..e2b91f6 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -522,7 +522,11 @@ cmd_summary() {
 #
 # List all submodules, prefixed with:
 #  - submodule not initialized
-#  + different revision checked out
+#  > the checked out version is in advance with the current version (fast-forward)
+#  < the checked out version is late w.r.t the current version (fast-forward)
+#  + different revisions checked out, no fast-forward relationship
+#  ! the checked out version does not exist and cannot be fetched
+#  M submodule contains uncommitted changes
 #
 # If --cached was specified the revision in the index will be printed
 # instead of the currently checked out revision.
@@ -562,20 +566,40 @@ cmd_status()
 		url=$(git config submodule."$name".url)
 		if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
 		then
-			say "-$sha1 $path"
+			say "-  $sha1 $path"
 			continue;
 		fi
+                unclean=" "
+                if ! ( unset GIT_DIR; cd "$path" && git diff --quiet HEAD ); then
+                    unclean="M"
+                fi
 		set_name_rev "$path" "$sha1"
 		if git diff-files --quiet -- "$path"
 		then
-			say " $sha1 $path$revname"
+			say " $unclean $sha1 $path$revname"
 		else
+                        head=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
+                        common=$(unset GIT_DIR; cd "$path" && git merge-base HEAD $sha1)
+                        if test -z "$common"; then
+                            common=$(unset GIT_DIR; cd "$path" && git-fetch -q &&
+                                    git merge-base HEAD $sha1)
+                        fi
+                        if test "$common" = "$sha1"; then
+                            modflag=">"
+                        elif test "$common" = "$head"; then
+                            modflag="<"
+                        elif test "$common" = ""; then
+                            modflag="!"
+                        else
+                            modflag="+"
+                        fi
+
 			if test -z "$cached"
 			then
 				sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
 				set_name_rev "$path" "$sha1"
 			fi
-			say "+$sha1 $path$revname"
+			say "$modflag$unclean $sha1 $path$revname"
 		fi
 	done
 }
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 6c7b902..ffaa932 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -65,7 +65,7 @@ test_expect_success 'status should only print one line' '
 '
 
 test_expect_success 'status should initially be "missing"' '
-	git-submodule status | grep "^-$rev1"
+	git-submodule status | grep "^-  $rev1"
 '
 
 test_expect_success 'init should register submodule url in .git/config' '
@@ -130,13 +130,19 @@ test_expect_success 'update should work when path is an empty dir' '
 '
 
 test_expect_success 'status should be "up-to-date" after update' '
-	git-submodule status | grep "^ $rev1"
+	git-submodule status | grep "^   $rev1"
 '
 
-test_expect_success 'status should be "modified" after submodule commit' '
+test_expect_success 'status should be "modified" after submodule change' '
 	cd init &&
 	echo b >b &&
-	git add b &&
+        git add b &&
+        cd .. &&
+	git-submodule status | grep "^ M $rev1"
+'
+
+test_expect_success 'status should be "in advance" after submodule commit' '
+	cd init &&
 	git-commit -m "submodule commit 2" &&
 	rev2=$(git rev-parse HEAD) &&
 	cd .. &&
@@ -145,11 +151,11 @@ test_expect_success 'status should be "modified" after submodule commit' '
 		echo "[OOPS] submodule git rev-parse returned nothing"
 		false
 	fi &&
-	git-submodule status | grep "^+$rev2"
+	git-submodule status | grep "^>  $rev2"
 '
 
 test_expect_success 'the --cached sha1 should be rev1' '
-	git-submodule --cached status | grep "^+$rev1"
+	git-submodule --cached status | grep "^>  $rev1"
 '
 
 test_expect_success 'git diff should report the SHA1 of the new submodule commit' '
@@ -171,7 +177,7 @@ test_expect_success 'update should checkout rev1' '
 '
 
 test_expect_success 'status should be "up-to-date" after update' '
-	git-submodule status | grep "^ $rev1"
+	git-submodule status | grep "^   $rev1"
 '
 
 test_expect_success 'checkout superproject with subproject already present' '
-- 
1.5.6


^ permalink raw reply related

* Re: git sequencer prototype
From: Stephan Beyer @ 2008-07-01 14:53 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin
In-Reply-To: <7vabh2oulb.fsf@gitster.siamese.dyndns.org>

Hi,

> > The migration patches are a little hard to code-review in the diff-form,
> > but feel free to apply, test, and then look at the code ;)
> 
> Heh, these three typically come in different order.  Look at the log
> message and docs to see if the design is sound, then look at the code, and
> if things overall look Ok, then finally apply and test.

Hmm, I usually prefer testing first (on such large patches), because I think
I value things different after I've tested them.

> I unfortunately ran out of time tonight and will look at them probably
> Thursday evening.

Don't hurry.

> It seems that another GSoC topic is finally nearing
> completion and I can shift my attention to other topics now.

Yes, the builtin merge should perhaps get some more priority first.

> By the way Christian is not CC'ed?

Shame on me, I forgot to Cc my mentors ;-)

Regards,
  Stephan

-- 
Stephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F

^ permalink raw reply

* [PATCH v2] gitcli: Document meaning of --cached and --index
From: Nanako Shiraishi @ 2008-07-01 14:02 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

We saw this explanation repeated on the mailing list a few times.  Even
though the description of individual options to particular commands are
explained in their manual pages, the reason behind choosing which is which
has not been clearly explained in any of the documentation.

Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
---
Here is a resend with updates that fix the mistakes you pointed out in
the previous version.  Includes an update to the Documentation section
(Sverre Rabbelier pointed out that it is more common to say "and the
git-list").

 Documentation/gitcli.txt |   38 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 2316049..7a9a625 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -133,9 +133,45 @@ $ git describe --abbrev 10 HEAD  # NOT WHAT YOU MEANT
 ----------------------------
 
 
+NOTES ON FREQUENTLY CONFUSED OPTIONS
+------------------------------------
+
+Many commands that can work on files in the working tree
+and/or in the index can take `--cached` and/or `--index`
+options.  Sometimes people incorrectly think that, because
+the index was originally called cache, these two are
+synonyms.  They are *not* -- these two options mean very
+different things.
+
+ * The `--cached` option is used to ask a command that
+   usually works on files in the working tree to *only* work
+   with the index.  For example, `git grep`, when used
+   without a commit to specify from which commit to look for
+   strings in, usually works on files in the working tree,
+   but with the `--cached` option, it looks for strings in
+   the index.
+
+ * The `--index` option is used to ask a command that
+   usually works on files in the working tree to *also*
+   affect the index.  For example, `git stash apply` usually
+   merges changes recorded in a stash to the working tree,
+   but with the `--index` option, it also merges changes to
+   the index as well.
+
+`git apply` command can be used with `--cached` and
+`--index` (but not at the same time).  Usually the command
+only affects the files in the working tree, but with
+`--index`, it patches both the files and their index
+entries, and with `--cached`, it modifies only the index
+entries.
+
+See also http://marc.info/?l=git&m=116563135620359 and
+http://marc.info/?l=git&m=119150393620273 for further
+information.
+
 Documentation
 -------------
-Documentation by Pierre Habouzit.
+Documentation by Pierre Habouzit and the git-list <git@vger.kernel.org>.
 
 GIT
 ---
-- 
1.5.6

-- 
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/

^ permalink raw reply related

* [PATCH 14/14] Build in merge
From: Miklos Vajna @ 2008-07-01 13:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin, Olivier Marin
In-Reply-To: <20080701125023.GW4729@genesis.frugalware.org>

Mentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---

Interdiff: git diff 01a7dae..7709df7

Individual commits (there is only one change this time): git log 7709df7

Ah and please don't forget to apply the testsuite fix I sent in
$gmane/86981. (Or is it easier if I resend the whole series?)

 Makefile                                      |    2 +-
 builtin-merge.c                               | 1158 +++++++++++++++++++++++++
 builtin.h                                     |    1 +
 git-merge.sh => contrib/examples/git-merge.sh |    0 
 git.c                                         |    1 +
 5 files changed, 1161 insertions(+), 1 deletions(-)
 create mode 100644 builtin-merge.c
 rename git-merge.sh => contrib/examples/git-merge.sh (100%)

diff --git a/Makefile b/Makefile
index bf77292..fbc53e9 100644
--- a/Makefile
+++ b/Makefile
@@ -240,7 +240,6 @@ SCRIPT_SH += git-lost-found.sh
 SCRIPT_SH += git-merge-octopus.sh
 SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
-SCRIPT_SH += git-merge.sh
 SCRIPT_SH += git-merge-stupid.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-parse-remote.sh
@@ -515,6 +514,7 @@ BUILTIN_OBJS += builtin-ls-remote.o
 BUILTIN_OBJS += builtin-ls-tree.o
 BUILTIN_OBJS += builtin-mailinfo.o
 BUILTIN_OBJS += builtin-mailsplit.o
+BUILTIN_OBJS += builtin-merge.o
 BUILTIN_OBJS += builtin-merge-base.o
 BUILTIN_OBJS += builtin-merge-file.o
 BUILTIN_OBJS += builtin-merge-ours.o
diff --git a/builtin-merge.c b/builtin-merge.c
new file mode 100644
index 0000000..b261993
--- /dev/null
+++ b/builtin-merge.c
@@ -0,0 +1,1158 @@
+/*
+ * Builtin "git merge"
+ *
+ * Copyright (c) 2008 Miklos Vajna <vmiklos@frugalware.org>
+ *
+ * Based on git-merge.sh by Junio C Hamano.
+ */
+
+#include "cache.h"
+#include "parse-options.h"
+#include "builtin.h"
+#include "run-command.h"
+#include "path-list.h"
+#include "diff.h"
+#include "refs.h"
+#include "commit.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "unpack-trees.h"
+#include "cache-tree.h"
+#include "dir.h"
+#include "utf8.h"
+#include "log-tree.h"
+#include "color.h"
+
+enum strategy {
+	DEFAULT_TWOHEAD = 1,
+	DEFAULT_OCTOPUS = 2,
+	NO_FAST_FORWARD = 4,
+	NO_TRIVIAL = 8
+};
+
+static const char * const builtin_merge_usage[] = {
+	"git-merge [options] <remote>...",
+	"git-merge [options] <msg> HEAD <remote>",
+	NULL
+};
+
+static int show_diffstat = 1, option_log, squash;
+static int option_commit = 1, allow_fast_forward = 1;
+static int allow_trivial = 1, have_message;
+static struct strbuf merge_msg;
+static struct commit_list *remoteheads;
+static unsigned char head[20], stash[20];
+static struct path_list use_strategies;
+static const char *branch;
+
+static struct path_list_item strategy_items[] = {
+	{ "recur",      (void *)NO_TRIVIAL },
+	{ "recursive",  (void *)(DEFAULT_TWOHEAD | NO_TRIVIAL) },
+	{ "octopus",    (void *)DEFAULT_OCTOPUS },
+	{ "resolve",    (void *)0 },
+	{ "stupid",     (void *)0 },
+	{ "ours",       (void *)(NO_FAST_FORWARD | NO_TRIVIAL) },
+	{ "subtree",    (void *)(NO_FAST_FORWARD | NO_TRIVIAL) },
+};
+static struct path_list strategies = { strategy_items,
+	ARRAY_SIZE(strategy_items), 0, 0 };
+
+static const char *pull_twohead, *pull_octopus;
+
+static int option_parse_message(const struct option *opt,
+	const char *arg, int unset)
+{
+	struct strbuf *buf = opt->value;
+
+	if (unset)
+		strbuf_setlen(buf, 0);
+	else {
+		strbuf_addf(buf, "%s\n\n", arg);
+		have_message = 1;
+	}
+	return 0;
+}
+
+static struct path_list_item *unsorted_path_list_lookup(const char *path,
+	struct path_list *list)
+{
+	int i;
+
+	if (!path)
+		return NULL;
+
+	for (i = 0; i < list->nr; i++)
+		if (!strcmp(path, list->items[i].path))
+			return &list->items[i];
+	return NULL;
+}
+
+static inline void path_list_append_strategy(struct path_list_item *item)
+{
+	path_list_append(item->path, &use_strategies)->util = item->util;
+}
+
+static int option_parse_strategy(const struct option *opt,
+	const char *arg, int unset)
+{
+	int i;
+	struct path_list_item *item = unsorted_path_list_lookup(arg, &strategies);
+
+	if (unset)
+		return 0;
+
+	if (item)
+		path_list_append_strategy(item);
+	else {
+		struct strbuf err;
+		strbuf_init(&err, 0);
+		for (i = 0; i < strategies.nr; i++)
+			strbuf_addf(&err, " %s", strategies.items[i].path);
+		fprintf(stderr, "Could not find merge strategy '%s'.\n", arg);
+		fprintf(stderr, "Available strategies are:%s.\n", err.buf);
+		exit(1);
+	}
+	return 0;
+}
+
+static int option_parse_n(const struct option *opt,
+		const char *arg, int unset)
+{
+	show_diffstat = unset;
+	return 0;
+}
+
+static struct option builtin_merge_options[] = {
+	{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,
+		"do not show a diffstat at the end of the merge",
+		PARSE_OPT_NOARG, option_parse_n },
+	OPT_BOOLEAN(0, "stat", &show_diffstat,
+		"show a diffstat at the end of the merge"),
+	OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"),
+	OPT_BOOLEAN(0, "log", &option_log,
+		"add list of one-line log to merge commit message"),
+	OPT_BOOLEAN(0, "squash", &squash,
+		"create a single commit instead of doing a merge"),
+	OPT_BOOLEAN(0, "commit", &option_commit,
+		"perform a commit if the merge succeeds (default)"),
+	OPT_BOOLEAN(0, "ff", &allow_fast_forward,
+		"allow fast forward (default)"),
+	OPT_CALLBACK('s', "strategy", &use_strategies, "strategy",
+		"merge strategy to use", option_parse_strategy),
+	OPT_CALLBACK('m', "message", &merge_msg, "message",
+		"message to be used for the merge commit (if any)",
+		option_parse_message),
+	OPT_END()
+};
+
+/* Cleans up metadata that is uninteresting after a succeeded merge. */
+static void drop_save(void)
+{
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+}
+
+static void save_state(void)
+{
+	int len;
+	struct child_process cp;
+	struct strbuf buffer = STRBUF_INIT;
+	const char *argv[] = {"stash", "create", NULL};
+
+	memset(&cp, 0, sizeof(cp));
+	cp.argv = argv;
+	cp.out = -1;
+	cp.git_cmd = 1;
+
+	if (start_command(&cp))
+		die("could not run stash.");
+	len = strbuf_read(&buffer, cp.out, 1024);
+	close(cp.out);
+
+	if (finish_command(&cp) || len < 0)
+		die("stash failed");
+	else if (!len)
+		return;
+	strbuf_setlen(&buffer, buffer.len-1);
+	if (get_sha1(buffer.buf, stash))
+		die("not a valid object: %s", buffer.buf);
+}
+
+static void reset_hard(unsigned const char *sha1, int verbose)
+{
+	int i = 0;
+	const char *args[6];
+
+	args[i++] = "read-tree";
+	if (verbose)
+		args[i++] = "-v";
+	args[i++] = "--reset";
+	args[i++] = "-u";
+	args[i++] = sha1_to_hex(sha1);
+	args[i] = NULL;
+
+	if (run_command_v_opt(args, RUN_GIT_CMD))
+		die("read-tree failed");
+}
+
+static void restore_state(void)
+{
+	struct strbuf sb;
+	const char *args[] = { "stash", "apply", NULL, NULL };
+
+	if (is_null_sha1(stash))
+		return;
+
+	reset_hard(head, 1);
+
+	strbuf_init(&sb, 0);
+	args[2] = sha1_to_hex(stash);
+
+	/*
+	 * It is OK to ignore error here, for example when there was
+	 * nothing to restore.
+	 */
+	run_command_v_opt(args, RUN_GIT_CMD);
+
+	strbuf_release(&sb);
+	refresh_cache(REFRESH_QUIET);
+}
+
+/* This is called when no merge was necessary. */
+static void finish_up_to_date(const char *msg)
+{
+	printf("%s%s\n", squash ? " (nothing to squash)" : "", msg);
+	drop_save();
+}
+
+static void squash_message(void)
+{
+	struct rev_info rev;
+	struct commit *commit;
+	struct strbuf out;
+	struct commit_list *j;
+	int fd;
+
+	printf("Squash commit -- not updating HEAD\n");
+	fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
+	if (fd < 0)
+		die("Could not write to %s", git_path("SQUASH_MSG"));
+
+	init_revisions(&rev, NULL);
+	rev.ignore_merges = 1;
+	rev.commit_format = CMIT_FMT_MEDIUM;
+
+	commit = lookup_commit(head);
+	commit->object.flags |= UNINTERESTING;
+	add_pending_object(&rev, &commit->object, NULL);
+
+	for (j = remoteheads; j; j = j->next)
+		add_pending_object(&rev, &j->item->object, NULL);
+
+	setup_revisions(0, NULL, &rev, NULL);
+	if (prepare_revision_walk(&rev))
+		die("revision walk setup failed");
+
+	strbuf_init(&out, 0);
+	strbuf_addstr(&out, "Squashed commit of the following:\n");
+	while ((commit = get_revision(&rev)) != NULL) {
+		strbuf_addch(&out, '\n');
+		strbuf_addf(&out, "commit %s\n",
+			sha1_to_hex(commit->object.sha1));
+		pretty_print_commit(rev.commit_format, commit, &out, rev.abbrev,
+			NULL, NULL, rev.date_mode, 0);
+	}
+	write(fd, out.buf, out.len);
+	close(fd);
+	strbuf_release(&out);
+}
+
+static int run_hook(const char *name)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", get_index_file());
+	env[0] = index;
+	env[1] = NULL;
+
+	if (squash)
+		argv[1] = "1";
+	else
+		argv[1] = "0";
+	argv[2] = NULL;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void finish(const unsigned char *new_head, const char *msg)
+{
+	struct strbuf reflog_message;
+
+	strbuf_init(&reflog_message, 0);
+	if (!msg)
+		strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
+	else {
+		printf("%s\n", msg);
+		strbuf_addf(&reflog_message, "%s: %s",
+			getenv("GIT_REFLOG_ACTION"), msg);
+	}
+	if (squash) {
+		squash_message();
+	} else {
+		if (!merge_msg.len)
+			printf("No merge message -- not updating HEAD\n");
+		else {
+			const char *argv_gc_auto[] = { "gc", "--auto", NULL };
+			update_ref(reflog_message.buf, "HEAD",
+				new_head, head, 0,
+				DIE_ON_ERR);
+			/*
+			 * We ignore errors in 'gc --auto', since the
+			 * user should see them.
+			 */
+			run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+		}
+	}
+	if (new_head && show_diffstat) {
+		struct diff_options opts;
+		diff_setup(&opts);
+		opts.output_format |=
+			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+		opts.detect_rename = DIFF_DETECT_RENAME;
+		if (diff_use_color_default > 0)
+			DIFF_OPT_SET(&opts, COLOR_DIFF);
+		if (diff_setup_done(&opts) < 0)
+			die("diff_setup_done failed");
+		diff_tree_sha1(head, new_head, "", &opts);
+		diffcore_std(&opts);
+		diff_flush(&opts);
+	}
+
+	/* Run a post-merge hook */
+	run_hook("post-merge");
+
+	strbuf_release(&reflog_message);
+}
+
+/* Get the name for the merge commit's message. */
+static void merge_name(const char *remote, struct strbuf *msg)
+{
+	struct object *remote_head;
+	unsigned char branch_head[20], buf_sha[20];
+	struct strbuf buf;
+	const char *ptr;
+	int len, early;
+
+	memset(branch_head, 0, sizeof(branch_head));
+	remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
+	if (!remote_head)
+		die("'%s' does not point to a commit", remote);
+
+	strbuf_init(&buf, 0);
+	strbuf_addstr(&buf, "refs/heads/");
+	strbuf_addstr(&buf, remote);
+	resolve_ref(buf.buf, branch_head, 0, 0);
+
+	if (!hashcmp(remote_head->sha1, branch_head)) {
+		strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
+			sha1_to_hex(branch_head), remote);
+		return;
+	}
+
+	/* See if remote matches <name>^^^.. or <name>~<number> */
+	for (len = 0, ptr = remote + strlen(remote);
+	     remote < ptr && ptr[-1] == '^';
+	     ptr--)
+		len++;
+	if (len)
+		early = 1;
+	else {
+		early = 0;
+		ptr = strrchr(remote, '~');
+		if (ptr) {
+			int seen_nonzero = 0;
+
+			len++; /* count ~ */
+			while (*++ptr && isdigit(*ptr)) {
+				seen_nonzero |= (*ptr != '0');
+				len++;
+			}
+			if (*ptr)
+				len = 0; /* not ...~<number> */
+			else if (seen_nonzero)
+				early = 1;
+			else if (len == 1)
+				early = 1; /* "name~" is "name~1"! */
+		}
+	}
+	if (len) {
+		struct strbuf truname = STRBUF_INIT;
+		strbuf_addstr(&truname, "refs/heads/");
+		strbuf_addstr(&truname, remote);
+		strbuf_setlen(&truname, len+11);
+		if (resolve_ref(truname.buf, buf_sha, 0, 0)) {
+			strbuf_addf(msg,
+				    "%s\t\tbranch '%s'%s of .\n",
+				    sha1_to_hex(remote_head->sha1),
+				    truname.buf,
+				    (early ? " (early part)" : ""));
+			return;
+		}
+	}
+
+	if (!strcmp(remote, "FETCH_HEAD") &&
+			!access(git_path("FETCH_HEAD"), R_OK)) {
+		FILE *fp;
+		struct strbuf line;
+		char *ptr;
+
+		strbuf_init(&line, 0);
+		fp = fopen(git_path("FETCH_HEAD"), "r");
+		if (!fp)
+			die("could not open %s for reading: %s",
+				git_path("FETCH_HEAD"), strerror(errno));
+		strbuf_getline(&line, fp, '\n');
+		fclose(fp);
+		ptr = strstr(line.buf, "\tnot-for-merge\t");
+		if (ptr)
+			strbuf_remove(&line, ptr-line.buf+1, 13);
+		strbuf_addbuf(msg, &line);
+		strbuf_release(&line);
+		return;
+	}
+	strbuf_addf(msg, "%s\t\tcommit '%s'\n",
+		sha1_to_hex(remote_head->sha1), remote);
+}
+
+int git_merge_config(const char *k, const char *v, void *cb)
+{
+	if (branch && !prefixcmp(k, "branch.") &&
+		!prefixcmp(k + 7, branch) &&
+		!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
+		const char **argv;
+		int argc;
+		char *buf;
+
+		buf = xstrdup(v);
+		argc = split_cmdline(buf, &argv);
+		argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
+		memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
+		argc++;
+		parse_options(argc, argv, builtin_merge_options,
+			      builtin_merge_usage, 0);
+		free(buf);
+	}
+
+	if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
+		show_diffstat = git_config_bool(k, v);
+	else if (!strcmp(k, "pull.twohead"))
+		return git_config_string(&pull_twohead, k, v);
+	else if (!strcmp(k, "pull.octopus"))
+		return git_config_string(&pull_octopus, k, v);
+	return git_diff_ui_config(k, v, cb);
+}
+
+static int read_tree_trivial(unsigned char *common, unsigned char *head,
+	unsigned char *one)
+{
+	int i, nr_trees = 0;
+	struct tree *trees[MAX_UNPACK_TREES];
+	struct tree_desc t[MAX_UNPACK_TREES];
+	struct unpack_trees_options opts;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = 2;
+	opts.src_index = &the_index;
+	opts.dst_index = &the_index;
+	opts.update = 1;
+	opts.verbose_update = 1;
+	opts.trivial_merges_only = 1;
+	opts.merge = 1;
+	trees[nr_trees] = parse_tree_indirect(common);
+	if (!trees[nr_trees++])
+		return -1;
+	trees[nr_trees] = parse_tree_indirect(head);
+	if (!trees[nr_trees++])
+		return -1;
+	trees[nr_trees] = parse_tree_indirect(one);
+	if (!trees[nr_trees++])
+		return -1;
+	opts.fn = threeway_merge;
+	cache_tree_free(&active_cache_tree);
+	for (i = 0; i < nr_trees; i++) {
+		parse_tree(trees[i]);
+		init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+	}
+	if (unpack_trees(nr_trees, t, &opts))
+		return -1;
+	return 0;
+}
+
+static void write_tree_trivial(unsigned char *sha1)
+{
+	if (write_cache_as_tree(sha1, 0, NULL))
+		die("git write-tree failed to write a tree");
+}
+
+static int try_merge_strategy(char *strategy, struct commit_list *common,
+	const char *head_arg)
+{
+	const char **args;
+	int i = 0, ret;
+	struct commit_list *j;
+	struct strbuf buf;
+
+	args = xmalloc((4 + commit_list_count(common) +
+			commit_list_count(remoteheads)) * sizeof(char *));
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "merge-%s", strategy);
+	args[i++] = buf.buf;
+	for (j = common; j; j = j->next)
+		args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+	args[i++] = "--";
+	args[i++] = head_arg;
+	for (j = remoteheads; j; j = j->next)
+		args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+	args[i] = NULL;
+	ret = run_command_v_opt(args, RUN_GIT_CMD);
+	strbuf_release(&buf);
+	i = 1;
+	for (j = common; j; j = j->next)
+		free((void *)args[i++]);
+	i += 2;
+	for (j = remoteheads; j; j = j->next)
+		free((void *)args[i++]);
+	free(args);
+	return -ret;
+}
+
+static void count_diff_files(struct diff_queue_struct *q,
+		struct diff_options *opt, void *data)
+{
+	int *count = data;
+
+	(*count) += q->nr;
+}
+
+static int count_unmerged_entries(void)
+{
+	const struct index_state *state = &the_index;
+	int i, ret = 0;
+
+	for (i = 0; i < state->cache_nr; i++)
+		if (ce_stage(state->cache[i]))
+			ret++;
+
+	return ret;
+}
+
+static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
+{
+	struct tree *trees[MAX_UNPACK_TREES];
+	struct unpack_trees_options opts;
+	struct tree_desc t[MAX_UNPACK_TREES];
+	int i, fd, nr_trees = 0;
+	struct dir_struct dir;
+	struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+	if (read_cache_unmerged())
+		die("you need to resolve your current index first");
+
+	fd = hold_locked_index(lock_file, 1);
+
+	memset(&trees, 0, sizeof(trees));
+	memset(&opts, 0, sizeof(opts));
+	memset(&t, 0, sizeof(t));
+	dir.show_ignored = 1;
+	dir.exclude_per_dir = ".gitignore";
+	opts.dir = &dir;
+
+	opts.head_idx = 1;
+	opts.src_index = &the_index;
+	opts.dst_index = &the_index;
+	opts.update = 1;
+	opts.verbose_update = 1;
+	opts.merge = 1;
+	opts.fn = twoway_merge;
+
+	trees[nr_trees] = parse_tree_indirect(head);
+	if (!trees[nr_trees++])
+		return -1;
+	trees[nr_trees] = parse_tree_indirect(remote);
+	if (!trees[nr_trees++])
+		return -1;
+	for (i = 0; i < nr_trees; i++) {
+		parse_tree(trees[i]);
+		init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+	}
+	if (unpack_trees(nr_trees, t, &opts))
+		return -1;
+	if (write_cache(fd, active_cache, active_nr) ||
+		commit_locked_index(lock_file))
+		die("unable to write new index file");
+	return 0;
+}
+
+static void split_merge_strategies(const char *string, struct path_list *list)
+{
+	char *p, *q, *buf;
+
+	if (!string)
+		return;
+
+	list->strdup_paths = 1;
+	buf = xstrdup(string);
+	q = buf;
+	for (;;) {
+		p = strchr(q, ' ');
+		if (!p) {
+			path_list_append(q, list);
+			free(buf);
+			return;
+		} else {
+			*p = '\0';
+			path_list_append(q, list);
+			q = ++p;
+		}
+	}
+}
+
+static void add_strategies(const char *string, enum strategy strategy)
+{
+	struct path_list list;
+	int i;
+
+	memset(&list, 0, sizeof(list));
+	split_merge_strategies(string, &list);
+	if (list.nr) {
+		for (i = 0; i < list.nr; i++) {
+			struct path_list_item *item;
+
+			item = unsorted_path_list_lookup(list.items[i].path,
+				&strategies);
+			if (item)
+				path_list_append_strategy(item);
+		}
+		return;
+	}
+	for (i = 0; i < strategies.nr; i++)
+		if ((enum strategy)strategies.items[i].util & strategy)
+			path_list_append_strategy(&strategies.items[i]);
+}
+
+static int merge_trivial(void)
+{
+	unsigned char result_tree[20], result_commit[20];
+	struct commit_list parent;
+
+	write_tree_trivial(result_tree);
+	printf("Wonderful.\n");
+	parent.item = remoteheads->item;
+	parent.next = NULL;
+	commit_tree(merge_msg.buf, result_tree, &parent, result_commit);
+	finish(result_commit, "In-index merge");
+	drop_save();
+	return 0;
+}
+
+static int finish_automerge(struct commit_list *common,
+	unsigned char *result_tree,
+	struct path_list_item *wt_strategy)
+{
+	struct commit_list *parents = NULL, *j;
+	struct strbuf buf = STRBUF_INIT;
+	unsigned char result_commit[20];
+
+	free_commit_list(common);
+	if (allow_fast_forward) {
+		parents = remoteheads;
+		commit_list_insert(lookup_commit(head), &parents);
+		parents = reduce_heads(parents);
+	} else {
+		struct commit_list **pptr = &parents;
+
+		pptr = &commit_list_insert(lookup_commit(head),
+				pptr)->next;
+		for (j = remoteheads; j; j = j->next)
+			pptr = &commit_list_insert(j->item, pptr)->next;
+	}
+	free_commit_list(remoteheads);
+	strbuf_addch(&merge_msg, '\n');
+	commit_tree(merge_msg.buf, result_tree, parents, result_commit);
+	strbuf_addf(&buf, "Merge made by %s.", wt_strategy->path);
+	finish(result_commit, buf.buf);
+	strbuf_release(&buf);
+	drop_save();
+	return 0;
+}
+
+static int suggest_conflicts(void)
+{
+	FILE *fp;
+	int pos;
+
+	fp = fopen(git_path("MERGE_MSG"), "a");
+	if (!fp)
+		die("Could open %s for writing", git_path("MERGE_MSG"));
+	fprintf(fp, "\nConflicts:\n");
+	for (pos = 0; pos < active_nr; pos++) {
+		struct cache_entry *ce = active_cache[pos];
+
+		if (ce_stage(ce)) {
+			fprintf(fp, "\t%s\n", ce->name);
+			while (pos + 1 < active_nr &&
+					!strcmp(ce->name,
+						active_cache[pos + 1]->name))
+				pos++;
+		}
+	}
+	fclose(fp);
+	rerere();
+	printf("Automatic merge failed; "
+			"fix conflicts and then commit the result.\n");
+	return 1;
+}
+
+static inline unsigned nth_strategy_flags(struct path_list *s, int nth)
+{
+	return (unsigned) s->items[nth].util;
+}
+
+static struct commit *is_old_style_invocation(int argc, const char **argv)
+{
+	struct commit *second_token = NULL;
+	if (argc > 1) {
+		unsigned char second_sha1[20];
+
+		if (get_sha1(argv[1], second_sha1))
+			return NULL;
+		second_token = lookup_commit_reference_gently(second_sha1, 0);
+		if (!second_token)
+			die("'%s' is not a commit", argv[1]);
+		if (hashcmp(second_token->object.sha1, head))
+			return NULL;
+	}
+	return second_token;
+}
+
+static int evaluate_result(void)
+{
+	int cnt = 0;
+	struct rev_info rev;
+
+	if (read_cache() < 0)
+		die("failed to read the cache");
+
+	/* Check how many files differ. */
+	init_revisions(&rev, "");
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.diffopt.output_format |=
+		DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = count_diff_files;
+	rev.diffopt.format_callback_data = &cnt;
+	run_diff_files(&rev, 0);
+
+	/*
+	 * Check how many unmerged entries are
+	 * there.
+	 */
+	cnt += count_unmerged_entries();
+
+	return cnt;
+}
+
+int cmd_merge(int argc, const char **argv, const char *prefix)
+{
+	unsigned char result_tree[20];
+	struct strbuf buf;
+	const char *head_arg;
+	int flag, head_invalid = 0, i;
+	int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
+	struct commit_list *common = NULL;
+	struct path_list_item *best_strategy = NULL, *wt_strategy = NULL;
+	struct commit_list **remotes = &remoteheads;
+
+	setup_work_tree();
+	if (unmerged_cache())
+		die("You are in the middle of a conflicted merge.");
+
+	/*
+	 * Check if we are _not_ on a detached HEAD, i.e. if there is a
+	 * current branch.
+	 */
+	branch = resolve_ref("HEAD", head, 0, &flag);
+	if (branch && !prefixcmp(branch, "refs/heads/"))
+		branch += 11;
+	if (is_null_sha1(head))
+		head_invalid = 1;
+
+	git_config(git_merge_config, NULL);
+
+	/* for color.ui */
+	if (diff_use_color_default == -1)
+		diff_use_color_default = git_use_color_default;
+
+	argc = parse_options(argc, argv, builtin_merge_options,
+			builtin_merge_usage, 0);
+
+	if (squash) {
+		if (!allow_fast_forward)
+			die("You cannot combine --squash with --no-ff.");
+		option_commit = 0;
+	}
+
+	if (!argc)
+		usage_with_options(builtin_merge_usage,
+			builtin_merge_options);
+
+	/*
+	 * This could be traditional "merge <msg> HEAD <commit>..."  and
+	 * the way we can tell it is to see if the second token is HEAD,
+	 * but some people might have misused the interface and used a
+	 * committish that is the same as HEAD there instead.
+	 * Traditional format never would have "-m" so it is an
+	 * additional safety measure to check for it.
+	 */
+	strbuf_init(&buf, 0);
+
+	if (!have_message && is_old_style_invocation(argc, argv)) {
+		strbuf_addstr(&merge_msg, argv[0]);
+		head_arg = argv[1];
+		argv += 2;
+		argc -= 2;
+	} else if (head_invalid) {
+		struct object *remote_head;
+		/*
+		 * If the merged head is a valid one there is no reason
+		 * to forbid "git merge" into a branch yet to be born.
+		 * We do the same for "git pull".
+		 */
+		if (argc != 1)
+			die("Can merge only exactly one commit into "
+				"empty head");
+		remote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT);
+		if (!remote_head)
+			die("%s - not something we can merge", argv[0]);
+		update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0,
+				DIE_ON_ERR);
+		reset_hard(remote_head->sha1, 0);
+		return 0;
+	} else {
+		struct strbuf msg;
+
+		/* We are invoked directly as the first-class UI. */
+		head_arg = "HEAD";
+
+		/*
+		 * All the rest are the commits being merged;
+		 * prepare the standard merge summary message to
+		 * be appended to the given message.  If remote
+		 * is invalid we will die later in the common
+		 * codepath so we discard the error in this
+		 * loop.
+		 */
+		strbuf_init(&msg, 0);
+		for (i = 0; i < argc; i++)
+			merge_name(argv[i], &msg);
+		fmt_merge_msg(option_log, &msg, &merge_msg);
+		if (merge_msg.len)
+			strbuf_setlen(&merge_msg, merge_msg.len-1);
+	}
+
+	if (head_invalid || !argc)
+		usage_with_options(builtin_merge_usage,
+			builtin_merge_options);
+
+	strbuf_addstr(&buf, "merge");
+	for (i = 0; i < argc; i++)
+		strbuf_addf(&buf, " %s", argv[i]);
+	setenv("GIT_REFLOG_ACTION", buf.buf, 0);
+	strbuf_reset(&buf);
+
+	for (i = 0; i < argc; i++) {
+		struct object *o;
+
+		o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT);
+		if (!o)
+			die("%s - not something we can merge", argv[i]);
+		remotes = &commit_list_insert(lookup_commit(o->sha1),
+			remotes)->next;
+
+		strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
+		setenv(buf.buf, argv[i], 1);
+		strbuf_reset(&buf);
+	}
+
+	if (!use_strategies.nr) {
+		if (!remoteheads->next)
+			add_strategies(pull_twohead, DEFAULT_TWOHEAD);
+		else
+			add_strategies(pull_octopus, DEFAULT_OCTOPUS);
+	}
+
+	for (i = 0; i < use_strategies.nr; i++) {
+		if (nth_strategy_flags(&use_strategies, i) & NO_FAST_FORWARD)
+			allow_fast_forward = 0;
+		if (nth_strategy_flags(&use_strategies, i) & NO_TRIVIAL)
+			allow_trivial = 0;
+	}
+
+	if (!remoteheads->next)
+		common = get_merge_bases(lookup_commit(head),
+				remoteheads->item, 1);
+	else {
+		struct commit_list *list = remoteheads;
+		commit_list_insert(lookup_commit(head), &list);
+		common = get_octopus_merge_bases(list);
+		free(list);
+	}
+
+	update_ref("updating ORIG_HEAD", "ORIG_HEAD", head, NULL, 0,
+		DIE_ON_ERR);
+
+	if (!common)
+		; /* No common ancestors found. We need a real merge. */
+	else if (!remoteheads->next && !common->next &&
+			common->item == remoteheads->item) {
+		/*
+		 * If head can reach all the merge then we are up to date.
+		 * but first the most common case of merging one remote.
+		 */
+		finish_up_to_date("Already up-to-date.");
+		return 0;
+	} else if (allow_fast_forward && !remoteheads->next &&
+			!common->next &&
+			!hashcmp(common->item->object.sha1, head)) {
+		/* Again the most common case of merging one remote. */
+		struct strbuf msg;
+		struct object *o;
+		char hex[41];
+
+		strcpy(hex, find_unique_abbrev(remoteheads->item->object.sha1,
+			DEFAULT_ABBREV));
+
+		printf("Updating %s..%s\n",
+			find_unique_abbrev(head, DEFAULT_ABBREV),
+			hex);
+		refresh_cache(REFRESH_QUIET);
+		strbuf_init(&msg, 0);
+		strbuf_addstr(&msg, "Fast forward");
+		if (have_message)
+			strbuf_addstr(&msg,
+				" (no commit created; -m option ignored)");
+		o = peel_to_type(sha1_to_hex(remoteheads->item->object.sha1),
+			0, NULL, OBJ_COMMIT);
+		if (!o) {
+			error("%s is not a commit", hex);
+			return 1;
+		}
+
+		if (checkout_fast_forward(head, remoteheads->item->object.sha1)) {
+			error("failed to fast-forward to %s", hex);
+			return 1;
+		}
+
+		finish(o->sha1, msg.buf);
+		drop_save();
+		return 0;
+	} else if (!remoteheads->next && common->next)
+		;
+		/*
+		 * We are not doing octopus and not fast forward.  Need
+		 * a real merge.
+		 */
+	else if (!remoteheads->next && !common->next && option_commit) {
+		/*
+		 * We are not doing octopus, not fast forward, and have
+		 * only one common.
+		 */
+		refresh_cache(REFRESH_QUIET);
+		if (allow_trivial) {
+			/* See if it is really trivial. */
+			git_committer_info(IDENT_ERROR_ON_NO_NAME);
+			printf("Trying really trivial in-index merge...\n");
+			if (!read_tree_trivial(common->item->object.sha1,
+					head, remoteheads->item->object.sha1))
+				return merge_trivial();
+			printf("Nope.\n");
+		}
+	} else {
+		/*
+		 * An octopus.  If we can reach all the remote we are up
+		 * to date.
+		 */
+		int up_to_date = 1;
+		struct commit_list *j;
+
+		for (j = remoteheads; j; j = j->next) {
+			struct commit_list *common_one;
+
+			/*
+			 * Here we *have* to calculate the individual
+			 * merge_bases again, otherwise "git merge HEAD^
+			 * HEAD^^" would be missed.
+			 */
+			common_one = get_merge_bases(lookup_commit(head),
+				j->item, 1);
+			if (hashcmp(common_one->item->object.sha1,
+				j->item->object.sha1)) {
+				up_to_date = 0;
+				break;
+			}
+		}
+		if (up_to_date) {
+			finish_up_to_date("Already up-to-date. Yeeah!");
+			return 0;
+		}
+	}
+
+	/* We are going to make a new commit. */
+	git_committer_info(IDENT_ERROR_ON_NO_NAME);
+
+	/*
+	 * At this point, we need a real merge.  No matter what strategy
+	 * we use, it would operate on the index, possibly affecting the
+	 * working tree, and when resolved cleanly, have the desired
+	 * tree in the index -- this means that the index must be in
+	 * sync with the head commit.  The strategies are responsible
+	 * to ensure this.
+	 */
+	if (use_strategies.nr != 1) {
+		/*
+		 * Stash away the local changes so that we can try more
+		 * than one.
+		 */
+		save_state();
+	} else {
+		memcpy(stash, null_sha1, 20);
+	}
+
+	for (i = 0; i < use_strategies.nr; i++) {
+		int ret;
+		if (i) {
+			printf("Rewinding the tree to pristine...\n");
+			restore_state();
+		}
+		if (use_strategies.nr != 1)
+			printf("Trying merge strategy %s...\n",
+				use_strategies.items[i].path);
+		/*
+		 * Remember which strategy left the state in the working
+		 * tree.
+		 */
+		wt_strategy = &use_strategies.items[i];
+
+		ret = try_merge_strategy(use_strategies.items[i].path,
+			common, head_arg);
+		if (!option_commit && !ret) {
+			merge_was_ok = 1;
+			/*
+			 * This is necessary here just to avoid writing
+			 * the tree, but later we will *not* exit with
+			 * status code 1 because merge_was_ok is set.
+			 */
+			ret = 1;
+		}
+
+		if (ret) {
+			/*
+			 * The backend exits with 1 when conflicts are
+			 * left to be resolved, with 2 when it does not
+			 * handle the given merge at all.
+			 */
+			if (ret == 1) {
+				int cnt = evaluate_result();
+
+				if (best_cnt <= 0 || cnt <= best_cnt) {
+					best_strategy =
+						&use_strategies.items[i];
+					best_cnt = cnt;
+				}
+			}
+			if (merge_was_ok)
+				break;
+			else
+				continue;
+		}
+
+		/* Automerge succeeded. */
+		write_tree_trivial(result_tree);
+		automerge_was_ok = 1;
+		break;
+	}
+
+	/*
+	 * If we have a resulting tree, that means the strategy module
+	 * auto resolved the merge cleanly.
+	 */
+	if (automerge_was_ok)
+		return finish_automerge(common, result_tree, wt_strategy);
+
+	/*
+	 * Pick the result from the best strategy and have the user fix
+	 * it up.
+	 */
+	if (!best_strategy) {
+		restore_state();
+		if (use_strategies.nr > 1)
+			fprintf(stderr,
+				"No merge strategy handled the merge.\n");
+		else
+			fprintf(stderr, "Merge with strategy %s failed.\n",
+				use_strategies.items[0].path);
+		return 2;
+	} else if (best_strategy == wt_strategy)
+		; /* We already have its result in the working tree. */
+	else {
+		printf("Rewinding the tree to pristine...\n");
+		restore_state();
+		printf("Using the %s to prepare resolving by hand.\n",
+			best_strategy->path);
+		try_merge_strategy(best_strategy->path, common, head_arg);
+	}
+
+	if (squash)
+		finish(NULL, NULL);
+	else {
+		int fd;
+		struct commit_list *j;
+
+		for (j = remoteheads; j; j = j->next)
+			strbuf_addf(&buf, "%s\n",
+				sha1_to_hex(j->item->object.sha1));
+		fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
+		if (fd < 0)
+			die("Could open %s for writing",
+				git_path("MERGE_HEAD"));
+		if (write_in_full(fd, buf.buf, buf.len) != buf.len)
+			die("Could not write to %s", git_path("MERGE_HEAD"));
+		close(fd);
+		strbuf_addch(&merge_msg, '\n');
+		fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
+		if (fd < 0)
+			die("Could open %s for writing", git_path("MERGE_MSG"));
+		if (write_in_full(fd, merge_msg.buf, merge_msg.len) !=
+			merge_msg.len)
+			die("Could not write to %s", git_path("MERGE_MSG"));
+		close(fd);
+	}
+
+	if (merge_was_ok) {
+		fprintf(stderr, "Automatic merge went well; "
+			"stopped before committing as requested\n");
+		return 0;
+	} else
+		return suggest_conflicts();
+}
diff --git a/builtin.h b/builtin.h
index 05ee56f..0e605d4 100644
--- a/builtin.h
+++ b/builtin.h
@@ -64,6 +64,7 @@ extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_remote(int argc, const char **argv, const char *prefix);
 extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
 extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
+extern int cmd_merge(int argc, const char **argv, const char *prefix);
 extern int cmd_merge_base(int argc, const char **argv, const char *prefix);
 extern int cmd_merge_ours(int argc, const char **argv, const char *prefix);
 extern int cmd_merge_file(int argc, const char **argv, const char *prefix);
diff --git a/git-merge.sh b/contrib/examples/git-merge.sh
similarity index 100%
rename from git-merge.sh
rename to contrib/examples/git-merge.sh
diff --git a/git.c b/git.c
index 2fbe96b..770aadd 100644
--- a/git.c
+++ b/git.c
@@ -271,6 +271,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "ls-remote", cmd_ls_remote },
 		{ "mailinfo", cmd_mailinfo },
 		{ "mailsplit", cmd_mailsplit },
+		{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
 		{ "merge-base", cmd_merge_base, RUN_SETUP },
 		{ "merge-file", cmd_merge_file },
 		{ "merge-ours", cmd_merge_ours, RUN_SETUP },
-- 
1.5.6.1

^ permalink raw reply related

* Re: [RFC/PATCH 7/7] Documentation formatting and cleanup
From: Olivier Marin @ 2008-07-01 13:09 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: git, Junio C Hamano, Christian Couder, Jon Loeliger
In-Reply-To: <Pine.GSO.4.62.0806301730230.7190@harper.uchicago.edu>

Jonathan Nieder a écrit :
> [184 KB patch online at
> <http://home.uchicago.edu/~jrnieder/20080701-git-doc-style.txt>]
> 
> Following what appears to be the predominant style, format
> names of commands and commandlines both as `teletype text`.
> 
> While we're at it, add articles ("a" and "the") in some
> places, italicize the name of the command in the manual page
> synopsis line, and add a comma or two where it seems appropriate.
> 
> Signed-off-by: Jonathan Nieder <jrnieder@uchicago.edu>
> 
> 	1) I am using `teletype text` both for command names and
> 	   for command lines. Probably I should be using italics
> 	   for the command names.

You did a lot of:

> -replaced; you need to use a tool such as linkgit:git-diff[1] or the "pickaxe"
> +replaced; you need to use a tool such as `git-diff` or the "pickaxe"

Are those kind of changes really an improvement?

Also, in Documentation/gitdiffcore.txt, you did:

> -These are applied in sequence.  The set of filepairs git-diff-\*
> +These are applied in sequence.  The set of filepairs `git-diff-*`

but the file does not compile, now.

Olivier.

^ permalink raw reply

* Re: Multiple remote.<...>.fetch and .push patterns
From: Jakub Narebski @ 2008-07-01 13:04 UTC (permalink / raw)
  To: Adr3nal D0S; +Cc: git
In-Reply-To: <308083c30806301158i1100c84dqe7f50daad417934c@mail.gmail.com>

"Adr3nal D0S" <adr3nald0s@gmail.com> writes:

> How can I do something like what is shown in Everyday git using git-config?
> 
> $ cat .git/remotes/ko
> URL: kernel.org:/pub/scm/git/git.git
> Pull: master:refs/tags/ko-master
> Pull: next:refs/tags/ko-next
> Pull: maint:refs/tags/ko-maint
> Push: master
> Push: next
> Push: +pu
> Push: maint
> 
> I know I can do:
> 
> git config remote.ko.fetch refs/heads/*:refs/tags/ko-*
> 
> but that will get all KO heads.  And I have no clue about the push version.

remote.<name>.fetch in config is equivalent of "Pull:" line in 
$GIT_DIR/remotes/<name>, while remote.<name>.push in config is
eqiovalent of "Push:" line in $GIT_DIR/remotes/<name>.

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [RFC/PATCH 2/4] Add git-sequencer prototype documentation
From: Jakub Narebski @ 2008-07-01 13:02 UTC (permalink / raw)
  To: Stephan Beyer; +Cc: git, Junio C Hamano, Johannes Schindelin
In-Reply-To: <1214879914-17866-3-git-send-email-s-beyer@gmx.net>

Stephan Beyer <s-beyer@gmx.net> writes:

> Mentored-by: Christian Couder <chriscool@tuxfamily.org>
> Mentored-by: Daniel Barkalow <barkalow@iabervon.org>

Cc mentors?

> +git-sequencer will usually be called by another git porcelain, like
> +linkgit:git-am[1] or linkgit:git-rebase[1].

I hope that it could be also used by git-cherry-pick and git-revert,
so it would be possible to pick more than one commit...

> +In case of a conflict or request in the TODO file, git-sequencer will
> +pause. On conflict you can use git-diff to locate the markers (`<<<<<<<`)
> +and make edits to resolve the conflict.
> +
> +For each file you edit, you need to tell git the changes by doing
> +
> +    git add <file>
> +
> +After resolving the conflict manually and updating the index with the
> +desired resolution, you can continue the sequencing process with
> +
> +    git sequencer --continue

Does it run pre-commit hooks, for example checking for merge markers
(but also whitespace errors), and can those checks be disabled?

> +-B::
> +--batch::
> +	Run in batch mode. If unexpected user intervention is needed
> +	(e.g. a conflict or the need to run an editor), git-sequencer fails.
> ++
> +Note that the sanity check fails, if you use this option
> +and an instruction like `edit` or `pause`.

s/.$/ is in the TODO file./

> +--edit::
> +	Invoke editor to edit the undone rest of the TODO file.

Does it mean that editor will be invoked with only _unprocessed_
part of the TODO file?  It looks like it, but it might be not
obvious to some.

> +merge [options] <commit-ish1> <commit-ish2> ... <commit-ishN>::
> +	Merge commits into HEAD.

Nice.

"HEAD" mean last picked up / created commit, isn't it?

> ++
> +A commit can also be given by a mark, if prefixed with a colon.

"You can refer to commit by mark", perhaps?

> +	--standard;;
> +		Generates a commit message like 'Merge ... into HEAD'.
> +		See also linkgit:git-fmt-merge-msg[1].

Is it short for `--standard-message`?

> +pick [options] <commit>::
> +	Pick (see linkgit:git-cherry-pick[1]) a commit.
> +	Sequencer will pause on conflicts.
> ++
> +See the following list and 'GENERAL OPTIONS' for values of `options`:
> +
> +	-R;;
> +	--reverse;;
> +		Revert the changes introduced by pick <commit>.
> +
> +	--mainline=<n>;;
> +		Allows you to pick merge commits by specifying the
> +		parent number (beginning from 1) to let sequencer
> +		replay the changes relative to the specified parent.
> +		+
> +This option does not work together with `-R`.

Why?  I would have thought that it would work...

> +patch [options] <file>::
[...]
> +	-*;;
> +		Any other dash-prefixed option is passed to
> +		linkgit:git-apply[1].
> +		This is especially useful for flags like
> +		`--reverse`, `-C<n>`, `-p<n>` or `--whitespace=<action>`.

Do all options make sense?  What about `--index' and `--cached',
or about different no-apply options?

> +ref <ref>::
> +	Set ref `<ref>` to the current HEAD, see also
> +	linkgit:git-update-ref[1].

So this functions like "git reset --soft <ref>", isn't it?

> +squash [options] --from <mark>::
> +	Squash all commits from the given mark into one commit.
> +	There must not be any `merge` instructions between the
> +	`mark` instruction and this `squash --from` instruction.

Can you use <commit> instead of <mark> here?

> +	--include-merges;;
> +		Sanity check does not fail if you have merges
> +		between HEAD and <mark>.

How do you squash merges?  Creating merge with an union of parents,
excluding commits which got squashed?

It means

  ...a---b---c---d         ...[abcd]
            /        ==>        /
      ...x-/               ..x-/

but

  ...a---b---c---d          ...[abcd]
      \     /        ==>
       \-x-/ 

> +RETURN VALUES
> +-------------
> +* any other value on error, e.g.
> +  running git-sequencer on a bare repository.

Don't you enumerate those return values?

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [PATCH 14/14] Build in merge
From: Miklos Vajna @ 2008-07-01 12:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin, Olivier Marin
In-Reply-To: <7vzlp2oyh7.fsf@gitster.siamese.dyndns.org>

[-- Attachment #1: Type: text/plain, Size: 991 bytes --]

On Tue, Jul 01, 2008 at 12:27:48AM -0700, Junio C Hamano <gitster@pobox.com> wrote:
> I'll queue the fixed-up result in 'pu', but I have to tend to other topics
> before I can actually publish.  Together with the fix to "head_invalid"
> confusion I mentioned in another message squashed in to this commit, all
> the tests now finally seem to pass on the topic branch.
> 
> Oh, by the way, you sent this and the previous round without marking them
> as RFC nor WIP, even though they obviously did not even pass the test
> suite.  For example, without the head_invalid fix, anything that runs
> merge on detached head, most notably "git rebase -i", would not work at
> all.

Thanks for pointing that out. I remember I used to run 'make test'
before sending a patch, but that took a lot of time and then I used to
run only t*merge*.sh, which - it turns out - was a bad idea, since I
haven't noticed breaking t3404.

I'm now running a full 'make test' before I send the patch.

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: [PATCH 14/14] Build in merge
From: Miklos Vajna @ 2008-07-01 12:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin, Olivier Marin
In-Reply-To: <7vtzfaqg16.fsf@gitster.siamese.dyndns.org>

[-- Attachment #1: Type: text/plain, Size: 4040 bytes --]

On Mon, Jun 30, 2008 at 11:23:17PM -0700, Junio C Hamano <gitster@pobox.com> wrote:
> Miklos Vajna <vmiklos@frugalware.org> writes:
> 
> > +static int read_tree_trivial(unsigned char *common, unsigned char *head,
> > +	unsigned char *one)
> > +{
> > +	int i, nr_trees = 0;
> > +	struct tree *trees[MAX_UNPACK_TREES];
> > +	struct tree_desc t[MAX_UNPACK_TREES];
> > +	struct unpack_trees_options opts;
> > +
> > +	memset(&opts, 0, sizeof(opts));
> > +	opts.head_idx = 2;
> 
> Do you still need this assignment here?

No, it was duplicated.

> > +int cmd_merge(int argc, const char **argv, const char *prefix)
> > +{
> > +	unsigned char result_tree[20];
> > +	struct strbuf buf;
> > +	const char *head_arg;
> > +	int flag, head_invalid = 0, i;
> > +	int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
> > +	struct commit_list *common = NULL;
> > +	struct path_list_item *best_strategy = NULL, *wt_strategy = NULL;
> > +	struct commit_list **remotes = &remoteheads;
> > +
> > +	setup_work_tree();
> > +	if (unmerged_cache())
> > +		die("You are in the middle of a conflicted merge.");
> > +
> > +	/*
> > +	 * Check if we are _not_ on a detached HEAD, i.e. if there is a
> > +	 * current branch.
> > +	 */
> > +	branch = resolve_ref("HEAD", head, 0, &flag);
> > +	if (branch && flag & REF_ISSYMREF) {
> > +		const char *ptr = skip_prefix(branch, "refs/heads/");
> > +		if (ptr)
> > +			branch = ptr;
> > +	} else
> > +		head_invalid = 1;
> 
> Wait a minute...  Are you calling a detached HEAD as head_invalid here?  I
> am not too much worried about variable naming, but you later do ...
> 
> > +	if (!have_message && is_old_style_invocation(argc, argv)) {
> > ...
> > +	} else if (head_invalid) {
> > +		struct object *remote_head;
> > +		/*
> > +		 * If the merged head is a valid one there is no reason
> > +		 * to forbid "git merge" into a branch yet to be born.
> > +		 * We do the same for "git pull".
> > +		 */
> > +		if (argc != 1)
> > +			die("Can merge only exactly one commit into "
> > +				"empty head");
> 
> Which is about HEAD pointing at a branch that isn't born yet.  They are
> two very different concepts.
> 
> Either the above "else if (head_invalid)" is wrong, or more likely the
> setting of head_invalid we saw earlier is wrong.
> 
> Probably what you meant was:
> 
> 	- "char *branch" points at either "HEAD" (when detached) or
>           the name of the branch (e.g. "master" when "refs/heads/master");
> 
> 	- "unsigned char head[]" stores the commit object name of the
>           current HEAD (or 0{40} if the current branch is unborn);
> 
>         - set head_invalid to true only when the current branch is unborn.
> 
> So perhaps...
> 
> 	branch = resolve_ref("HEAD", head, 0, &flag);
>         if (branch && (flag & REF_ISSYMREF) && !prefixcmp(branch, "refs/heads/"))
> 		branch += 11;
>         head_invalid = is_null_sha1(head);
> 
> And probably we can even drop (flag & REF_ISSYMREF) from the above safely.
> Do we even care if the head is detached in this program?  I doubt it.

You are right. I though we care about it, but now I realized such a
comment was only in git-merge.annotated (in Dscho's fork), not in
git-merge.sh. And yes, I mixed up head_invalid for two purposes. Thanks
for clearing the situation.

> > +		strbuf_init(&msg, 0);
> > +		strbuf_addstr(&msg, "Fast forward");
> > +		if (have_message)
> > +			strbuf_addstr(&msg,
> > +				" (no commit created; -m option ignored)");
> > +		o = peel_to_type(sha1_to_hex(remoteheads->item->object.sha1),
> > +			0, NULL, OBJ_COMMIT);
> > +		if (!o)
> > +			return 1;
> > +
> > +		if (checkout_fast_forward(head, remoteheads->item->object.sha1))
> > +			return 1;
> 
> Not exiting with 0 status from around here upon error is an improvement,
> but does the user see sensible error messages in addition to the exit
> status?

Now he/she does. :-)

(I updated my working branch on repo.or.cz, will send a patch soon, as
well.)

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: [OT] Your branch is ahead of the tracked remote branch 'origin/master' by 50 commits.
From: Jakub Narebski @ 2008-07-01 12:47 UTC (permalink / raw)
  To: SZEDER Gábor; +Cc: Ingo Molnar, Bruce Stephens, git
In-Reply-To: <20080701114149.GB6662@neumann>

SZEDER Gábor <szeder@ira.uka.de> writes:

> how about displaying the current branch in the command prompt?
> 
> >From contrib/completion/git-completion.bash:
> 
>   #    4) Consider changing your PS1 to also show the current branch:
>   #        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
>   #
>   #       The argument to __git_ps1 will be displayed only if you
>   #       are currently in a git repository.  The %s token will be
>   #       the name of the current branch.

Because I alos use StGit, I have added to my prompt visual
differentiation if the branch is under StGit control.

But I have my own git prompt function, based on git-completion.bash
but different.  It shows current branch (or "HEAD" if on detached
HEAD), current repository, and current working directory.  It laso has
number of command in history, the same as in my ordinary prompt.

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ 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