* Re: equal-tree-merges as way to make rebases fast-forward-able
From: Johannes Schindelin @ 2009-11-30 17:19 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
In-Reply-To: <cover.1259524136.git.brlink@debian.org>
Hi,
On Mon, 30 Nov 2009, Bernhard R. Link wrote:
> The itch this idea is supposed to scratch is the problem that a rebase
> or a amended commit is no longer a fast-forward, so cannot be easily
> pulled.
Actually, I did something like this without any new tool:
git rebase origin/master
git merge -s ours master@{1}
The effect is that there is a merge commit which really merges the old
state.
OTOH I can see that there is merit in trying to avoid to _require_ the
whole history of the rebased branch. But then, would it not be more in
line with Git's ideas if there was a tool trying to identify, say,
from the commit message which commits in HEAD...MERGE_HEAD are
supposed to be identical?
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] tests: handle NO_PYTHON setting
From: Junio C Hamano @ 2009-11-30 17:27 UTC (permalink / raw)
To: Johan Herland; +Cc: git, Sverre Rabbelier, Jeff King, Daniel Barkalow
In-Reply-To: <200911301159.23383.johan@herland.net>
Johan Herland <johan@herland.net> writes:
> ... Hence, this subdir is
> meant to contain the support scripts for remote helper written in Python,
> both common support scripts, and support scripts specific to each remote
> helper. So far, only the common code is there, but we expect the Hg and CVS
> helpers to add scripts to the "hg" and "cvs" subsubdirs, respectively.
Ahh, Ok, that clarifies it. The packager (not me) can package what is
(in|built from) remote_helpers directory into one package, and declare
that as a dependency to each of the individual remote helper packages that
uses the common stuff found in there, if the distro wants to have "one
end-user feature per package" granularity.
Just to make sure you didn't misunderstand me, I wasn't complaining that
the directory was not further split for each helper. I wanted to know the
reason behind wanting to have _one_ directory that is common across
multiple helpers that are supposed to be independent. "A common library"
is a good reason to have that organization.
> We _could_ split up the "git_remote_helpers" package into a "git-remote-hg"-
> specific package, and a "git-remote-cvs"-specific package, but that would
> mean either having two copies of the current support code. Alternately, we
> could create a _third_ package containing the common support code, that each
> of our hg/cvs support packages would in turn depend on. I don't think we
> want to go there, at least not yet.
I think that is typically done by the distros; in the longer term it would
be nicer to them if we did so in our build structure, but I do not think
we are there yet.
> Also, to prevent this misunderstanding, we could create a "python" subdir in
> git.git, and move the "git_remote_helpers" into there.
If (and this is a big if, as we are not migrating to Python) the use of
Python proliferates over time, a single "python" subdir to hold "a common
library" to create the third package will not make sense in the longer
term, as different services written in Python will have different set of
common supporting code, so there will be multiple common libraries and you
would need multiple third packages. You would probably need multiple
directories there, perhaps as subdirectories of that single toplevel
directory you called "python", so that scripts written in Python would say
"import pythonGit.remoteHelper" or something like that.
^ permalink raw reply
* [RFC/PATCH] Detailed diagnostic when parsing an object name fails.
From: Matthieu Moy @ 2009-11-30 17:50 UTC (permalink / raw)
To: git; +Cc: Matthieu Moy
The previous error message was the same in many situations (unknown
revision or path not in the working tree). We try to help the user as
much as possible to understand the error, especially with the
sha1:filename notation. In this case, we say whether the sha1 or the
filename is problematic, and diagnose the confusion between
relative-to-root and relative-to-$PWD confusion precisely.
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
The original motivation is actually to anwser the FAQ of "git show
HEAD:foo.txt" being relative to the root, while some users would
expect it relative to $PWD but the patch ended up being far more
general. At least,
$ cd git
$ cd t
$ ../git show HEAD:test-lib.sh
fatal: Path 't/test-lib.sh' exists, but not 'test-lib.sh'.
Did you mean 'HEAD:t/test-lib.sh'?
A few remarks/RFH:
* It's my first time playing with the index API, so my
diagnose_invalid_index_path may be incorrect/suboptimal/...
* This definitely requires a few test-cases, but I don't have time for
it right now.
* Is my way of having default arguments for get_sha1_with_mode OK with
the usual coding style of Git?
cache.h | 6 +++-
setup.c | 15 +++++++++-
sha1_name.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 101 insertions(+), 7 deletions(-)
diff --git a/cache.h b/cache.h
index 0e69384..5c8cb5f 100644
--- a/cache.h
+++ b/cache.h
@@ -708,7 +708,11 @@ static inline unsigned int hexval(unsigned char c)
#define DEFAULT_ABBREV 7
extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
+static inline get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
+{
+ return get_sha1_with_mode_1(str, sha1, mode, 0, NULL);
+}
+extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int fatal, const char *prefix);
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern int read_ref(const char *filename, unsigned char *sha1);
diff --git a/setup.c b/setup.c
index f67250b..3094e8b 100644
--- a/setup.c
+++ b/setup.c
@@ -74,6 +74,18 @@ int check_filename(const char *prefix, const char *arg)
die_errno("failed to stat '%s'", arg);
}
+static void NORETURN die_verify_filename(const char *prefix, const char *arg)
+{
+ unsigned char sha1[20];
+ unsigned mode;
+ /* try a detailed diagnostic ... */
+ get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);
+ /* ... or fall back the most general message. */
+ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
+ "Use '--' to separate paths from revisions", arg);
+
+}
+
/*
* Verify a filename that we got as an argument for a pathspec
* entry. Note that a filename that begins with "-" never verifies
@@ -87,8 +99,7 @@ void verify_filename(const char *prefix, const char *arg)
die("bad flag '%s' used after filename", arg);
if (check_filename(prefix, arg))
return;
- die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
- "Use '--' to separate paths from revisions", arg);
+ die_verify_filename(prefix, arg);
}
/*
diff --git a/sha1_name.c b/sha1_name.c
index 44bb62d..172c128 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -804,7 +804,69 @@ int get_sha1(const char *name, unsigned char *sha1)
return get_sha1_with_mode(name, sha1, &unused);
}
-int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
+static void diagnose_invalid_sha1_path(const char *prefix,
+ const char *filename,
+ const char *tree_sha1,
+ const char *object_name)
+{
+ struct stat st;
+ unsigned char sha1[20];
+ unsigned mode;
+
+ if (!lstat(filename, &st))
+ die("Path '%s' exists on disk, but not in '%s'.",
+ filename, object_name);
+ if (errno == ENOENT || errno == ENOTDIR) {
+ char *fullname = malloc(strlen(filename)
+ + strlen(prefix) + 1);
+ strcpy(fullname, prefix);
+ strcat(fullname, filename);
+
+ if (!get_tree_entry(tree_sha1, fullname,
+ sha1, &mode)) {
+ die("Path '%s' exists, but not '%s'.\n"
+ "Did you mean '%s:%s'?",
+ fullname,
+ filename,
+ object_name,
+ fullname);
+ }
+ die("Path '%s' does not exist in '%s'",
+ filename, object_name);
+ }
+}
+
+static void diagnose_invalid_index_path(int stage,
+ const char *prefix,
+ const char *filename)
+{
+ struct stat st;
+ if (!lstat(filename, &st))
+ die("Path '%s' exists on disk, but not in the index.", filename);
+ if (errno == ENOENT || errno == ENOTDIR) {
+ struct cache_entry *ce;
+ int pos;
+ int namelen = strlen(filename) + strlen(prefix);
+ char *fullname = malloc(namelen + 1);
+ strcpy(fullname, prefix);
+ strcat(fullname, filename);
+ pos = cache_name_pos(fullname, namelen);
+ if (pos < 0)
+ pos = -pos - 1;
+ ce = active_cache[pos];
+ if (ce_namelen(ce) == namelen &&
+ !memcmp(ce->name, fullname, namelen))
+ die("Path '%s' is in the index, but not '%s'.\n"
+ "Did you mean ':%d:%s'?",
+ fullname, filename,
+ stage, fullname);
+
+ die("Path '%s' does not exist (either on disk or in the index).", filename);
+ }
+}
+
+
+int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int fatal, const char *prefix)
{
int ret, bracket_depth;
int namelen = strlen(name);
@@ -850,6 +912,8 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
}
pos++;
}
+ if (fatal)
+ diagnose_invalid_index_path(stage, prefix, cp);
return -1;
}
for (cp = name, bracket_depth = 0; *cp; cp++) {
@@ -862,9 +926,24 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
}
if (*cp == ':') {
unsigned char tree_sha1[20];
- if (!get_sha1_1(name, cp-name, tree_sha1))
- return get_tree_entry(tree_sha1, cp+1, sha1,
- mode);
+ char *object_name;
+ if (fatal) {
+ object_name = malloc(cp-name+1);
+ strncpy(object_name, name, cp-name);
+ object_name[cp-name] = '\0';
+ }
+ if (!get_sha1_1(name, cp-name, tree_sha1)) {
+ const char *filename = cp+1;
+ ret = get_tree_entry(tree_sha1, filename, sha1, mode);
+ if (fatal)
+ diagnose_invalid_sha1_path(prefix, filename,
+ tree_sha1, object_name);
+
+ return ret;
+ } else {
+ if (fatal)
+ die("Invalid object name '%s'.", object_name);
+ }
}
return ret;
}
--
1.6.6.rc0.256.g6060
^ permalink raw reply related
* Re: [PATCH] tests: handle NO_PYTHON setting
From: Johan Herland @ 2009-11-30 18:01 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Sverre Rabbelier, Jeff King, Daniel Barkalow
In-Reply-To: <7vvdgrordj.fsf@alter.siamese.dyndns.org>
On Monday 30 November 2009, Junio C Hamano wrote:
> Johan Herland <johan@herland.net> writes:
> > We _could_ split up the "git_remote_helpers" package into a
> > "git-remote-hg"- specific package, and a "git-remote-cvs"-specific
> > package, but that would mean either having two copies of the
> > current support code. Alternately, we could create a _third_
> > package containing the common support code, that each of our hg/cvs
> > support packages would in turn depend on. I don't think we want to
> > go there, at least not yet.
>
> I think that is typically done by the distros; in the longer term it
> would be nicer to them if we did so in our build structure, but I do
> not think we are there yet.
Agreed.
> > Also, to prevent this misunderstanding, we could create a "python"
> > subdir in git.git, and move the "git_remote_helpers" into there.
>
> If (and this is a big if, as we are not migrating to Python) the use
> of Python proliferates over time, a single "python" subdir to hold "a
> common library" to create the third package will not make sense in
> the longer term, as different services written in Python will have
> different set of common supporting code, so there will be multiple
> common libraries and you would need multiple third packages. You
> would probably need multiple directories there, perhaps as
> subdirectories of that single toplevel directory you called "python",
> so that scripts written in Python would say "import
> pythonGit.remoteHelper" or something like that.
Yes, I agree that if we get multiple Python support packages, it makes
sense to create a "python" subdir, and store each package as a
subsubdir of "python". Still, I don't think we need to plan that far
ahead now. We can do that restructuring when it becomes necessary. If
there are no more objections, I vote for keeping the current structure
for now.
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply
* Re: [PATCH] tests: handle NO_PYTHON setting
From: Brandon Casey @ 2009-11-30 18:07 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Sverre Rabbelier, git
In-Reply-To: <20091130075221.GA5421@coredump.intra.peff.net>
Jeff King wrote:
> Without this, test-lib checks that the git_remote_helpers
> directory has been built. However, if we are building
> without python, we will not have done anything at all in
> that directory, and test-lib's sanity check will fail.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> On top of sr/vcs-helper.
>
> This feels a little funny for NO_PYTHON to mean "no remote helpers at
> all". But that is the way the Makefile is set up, since we seem to have
> only python helpers.
>
> Makefile | 1 +
> t/test-lib.sh | 2 +-
> 2 files changed, 2 insertions(+), 1 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index 42744a4..443565e 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1743,6 +1743,7 @@ GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
> @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
> @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
> @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
> + @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
>
> ### Detect Tck/Tk interpreter path changes
> ifndef NO_TCLTK
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index 4a40520..ca0839c 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -638,7 +638,7 @@ test -d ../templates/blt || {
> error "You haven't built things yet, have you?"
> }
>
> -if test -z "$GIT_TEST_INSTALLED"
> +if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON"
> then
> GITPYTHONLIB="$(pwd)/../git_remote_helpers/build/lib"
> export GITPYTHONLIB
Shouldn't this section be moved down below the sourcing of ../GIT-BUILD-OPTIONS
on line 656 so that the value of NO_PYTHON will be available when running the
test scripts directly?
-brandon
ps. There's something eerily familiar about this patch.
^ permalink raw reply
* Re: [PATCH 3/8] git-merge-recursive-{ours,theirs}
From: Avery Pennarun @ 2009-11-30 18:08 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvdgs1qip.fsf@alter.siamese.dyndns.org>
On Mon, Nov 30, 2009 at 1:21 AM, Junio C Hamano <gitster@pobox.com> wrote:
> As long as you choose the default "no-op" value carefully enough so that
> existing callers will naturally use it without modification, the old code
> will work the way they did before the new optional feature was added. In
> other words, "let's implement this as purely an opt-in feature" is often
> preferrable over "let's force semantic conflict and compilation failure,
> just in case existing callsites may also want to trigger this new
> feature".
>
> That is why [1/8] patch in your series uses 0 to mean "don't do the funny
> 'favor' trick, but just leave the conflicts there".
There's just one bit to add to this: when converting a non-bitfield
int into a bitfield, really odd things can happen. That was my main
rationale for avoiding the change to bitfield without changing the
signature. That said, the amount of code isn't really that big so
this point doesn't matter much.
> I've queued the series with minor fixes to 'pu' and pushed it out.
Since I see you didn't change a couple of things you mentioned in
earlier comments (the NEEDSWORK comment and the sq-then-eval trick) do
you still want me to respin this series?
Thanks,
Avery
^ permalink raw reply
* Re: "git merge" merges too much!
From: Greg A. Woods @ 2009-11-30 18:12 UTC (permalink / raw)
To: Jeff King; +Cc: The Git Mailing List
In-Reply-To: <20091129051427.GA6104@coredump.intra.peff.net>
[-- Attachment #1: Type: text/plain, Size: 3740 bytes --]
Thank you very much for confirming my understanding of why "git merge"
was merging more changes than I had desired it to merge.
The way "git merge" works does concern me somewhat though as I try to
figure out how I might use "topic" branches to develop local features
and then merge them onto each supported release branch. Some guides
I've read suggest this methodology, but I'm sure how well this will
work, even when the remote project uses release branches to manage
official releases. Perhaps I really should look at StGit, but I'm not
sure about it either.
At Sun, 29 Nov 2009 00:14:27 -0500, Jeff King <peff@peff.net> wrote:
Subject: Re: "git merge" merges too much!
>
> On Sat, Nov 28, 2009 at 10:21:25PM -0500, Greg A. Woods wrote:
> >
> > master branch to represent release points -- is there any way to get
> > "git log" to show which tags are associated with a given commit and/or
>
> Try "git log --decorate".
Excellent! That's exactly what I was looking for.
(From a first pass through the documentation I would never have guessed
that "tags" were also a form of "refs". All these different names for
things in the Git vs. many other VCS's, like "ref names" _really_
confusing to anyone like me with too much experience using those other
revision control systems. Part of the problem is that Git documentation
seems to be two-or-more minded about several of its concepts and
features. Even the gitglossary(7) is somewhat inconsistent on how it
uses "ref" and "refs". Perhaps all that's needed is some firm editing
and clean-up of the manuals and documentation by a good strong technical
editor.)
> Yes, you must cherry-pick or use rebase (which is a more featureful
> version of the pipeline you mentioned).
"git rebase" will not work for me unless it grows a "copy" option ,
i.e. one which does not delete the original branch (i.e. avoids the
"reset" phase of its operation). This option would likely only make
sense when used with the "--onto" option, I would guess.
"git rebase -i" would certainly give me all the control I could possibly
want when copying changes from branch to branch.
It likely wouldn't make sense to base this new "copy" feature directly
on "git rebase" though, especially in light of all the warnings about
how "git rebase" isn't friendly when applied to already published
branches. I think in theory this "copy" feature won't cause problems
for already-published branches.
Perhaps it should be a whole new top-level command such as "git copy",
but then it's so much like "git merge" I'm not sure.... Ideally if "git
merge" could be taught how to work with just the changes from the base
of a branch then it would do what I'm looking for directly.
> The resulting commits will have different commit ids, but git generally
> does a good job at merging such things, because it looks only at the
> result state and not the intermediate commits. If both sides have made
> an equivalent change, then there is no conflict.
> > Is there any way to get "git log --graph" (and/or gitk) to show me all
> > the branch heads, not just the current/specified one?
>
> Try "--all" with either gitk or "git log". Or if you want a subset of
> heads, just name them.
Awsome! Those options provide just what I wanted to see!
(git-log(1) is worse than ls(1) for having too many options, but worst
of all in the release I'm still using it doesn't respond sensibly nor
consistently with other commands when given the "-?" option.)
--
Greg A. Woods
+1 416 218-0098 VE3TCP RoboHack <woods@robohack.ca>
Planix, Inc. <woods@planix.com> Secrets of the Weird <woods@weird.com>
[-- Attachment #2: Type: application/pgp-signature, Size: 186 bytes --]
^ permalink raw reply
* Re: equal-tree-merges as way to make rebases fast-forward-able
From: Junio C Hamano @ 2009-11-30 18:18 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
In-Reply-To: <cover.1259524136.git.brlink@debian.org>
"Bernhard R. Link" <brlink@debian.org> writes:
> My idea to solve this is combining both histories, the rebased/revised
> history and the actualy history, marking with some "equal-tree-merge"
> the point where they have the same result.
If you rewrite a series twice, your RFC will work like this, IIUC:
* You have commit 1 and rewrite it to 2. You record the difference
between 1 and 2 on top of 1 as commit X and record a same-tree merge as
A. Here, A^1 == 2, A^2 == X, and 2^{tree} == A^{tree}.
2-------A
/ /
0---1---X
* You then rewrite it to 3. You record the difference between A and 3
(which is the same as between 2 and 3, because 2^{tree} == A^{tree})
as commit Y, and record a same-tree merge as B. B^1 == 3, B^2 == Y and
3^{tree} == B^{tree}.
Y---------------B
/ /
2-------A-------3
/ /
0---1---X
It however might be easier to review what happened if you create a history
this way upon the second rewrite (forget the second picture above):
3-------.
/ \
0---2---W---B
\ /
1-------Z
That is, Z and W records the interdifff between 1 to 3 and 2 to 3
respectively, and B is a same-tree merge of 3, W and Z.
As you are giving some specific meaning to the order of merge parents of a
marker commit, namely, the first parent is the latest version of this
series (i.e. B^1 == 3), you can extend it to declare that the second
parent is the next to the latest incarnation (i.e. B^2 == W) and the third
one is one version older than the second one (i.e. B^3 == Z).
Doing it this way allows you to publish the final result "3" without any
cruft in the history.
In your code you have comment wondering if there is a better wording for
the fix-up commit you create during rebase when the trees do not match. I
would suggest calling it "interdiff". That is exactly what "git show W"
would show.
While I find the primary idea (i.e. keeping the old and new equivalents by
recording a merge of it, and using the first-parent to traverse when you
find such a special merge) reasonable (and as Dscho has pointed out, this
technique is widely used, I suspect---it is an obvious thing to do), I
think we need something stronger than just "this commit merges commits
that happen to have the same trees" as the marker.
Git is designed to work well in an environment where multiple people
produces identical result. A 3-way merge resolves cleanly when both
branches modified a path to the same result (at contents level as well at
path level). If you take this principle to the extreme, you should be
able to merge two branches that were developed independently but still
reached the same conclusion at the end, without marking such a merge as
anything funny. With your RFC code, one branch will be mistakenly treated
as "old cruft that was improved by the other branch by rewriting".
To avoid that, I think (1) the marker has to be more reliable than just
"happens to have the same tree", and (2) the traversal done by Porcelains
(your patches 3 thru 5) by default should be unaware of eqt.
I don't know what a suitable marker should look like, though. The marker
must be easily identifiable by the lowest level rev-list machinery, so it
needs to be a sign left somewhere in the commit object. Perhaps making it
require to have the same tree as all its parents _and_ a well-known marker
string in the log message (and nothing else) would be a good start.
In the longer term, if the line of this direction turns out to be a good
one, I do not mind adding a special header to the commit object separate
from the log message, but we should start without one until this proves to
be a useful ingredient in people's workflows. With a reliable marker, we
can obviously drop the "same-tree" ness from the definition of the marker
commit, which in turn means that you do not need "interdiff" commits while
rebasing.
The command to build such a merge could be an option to "git merge -s ours"
(perhaps something like "git merge -s ours -Xeqt").
^ permalink raw reply
* Re: "git merge" merges too much!
From: Greg A. Woods @ 2009-11-30 18:40 UTC (permalink / raw)
To: Junio C Hamano; +Cc: The Git Mailing List
In-Reply-To: <7vskbxewti.fsf@alter.siamese.dyndns.org>
[-- Attachment #1: Type: text/plain, Size: 4105 bytes --]
At Sat, 28 Nov 2009 21:15:05 -0800, Junio C Hamano <gitster@pobox.com> wrote:
Subject: Re: "git merge" merges too much!
>
> In order to make things smoother and easier in the future, you may want to
> learn "topic branch" workflows (found in many git tutorial material).
I was thinking hard about topic branches too, but I'm still having a
hard time figuring out how they might work best for my purposes.
One hard problem is how to create "clean" topic branches and use them
effectively when the local working environment requires all or many of
the whole set of local changes. Bootstrapping these local changes as
topic branches may be one thing; but going further with topic branches
to create local features or fixes, some of which are to be submitted
upstream for eventual inclusion in the origin/master branch, and others
of which will only ever be ported forward to future official releases,
is quite another thing all together.
These new-feature topic branches will have to be worked on from the
main (most well supported) local branch, which will be forked from the
main release branch (or based on the trunk at the main release tag), but
yet care will have to be taken to make sure the merge doesn't include
dependencies on local-only changes (i.e. so that it can be safely
submitted upstream).
Some projects also only wish to receive patches that work against their
trunk branch, so a given local topic branch will have to be merged onto
yet another branch forking from the trunk where it may likely encounter
conflicts (since the topic branch is based on older code from an
existing release). This isn't really a Git problem I suppose, except
for the fact that it means the lack of easy support for multiple working
directories that track different branches makes this kind of development
somewhat more difficult to do with Git than with, say, CVS.
While it may be quite convenient in small projects to quickly move a
single working directory from one branch to another and do various
builds and tests from the result, large projects (say where a compile
takes the better part of a working day or more and where testing
requires multi-day processes) demand that working directories remain
"stable", and multiple lines of development therefore demand multiple
working directories. Developing procedures around Git to manage this
with "push" and "pull" into multiple local copies of the repository,
each with their own working directory, is of course possible (though not
necessarily easy), but once again if the repositories are similarly huge
then it may not be possible to support multiple repo copies for each
developer in a given working environment.
So, ideally it seems from my understanding at this point that I want to
be able to repeatedly merge topic branch changes (as they are worked on)
into multiple local configuration branches (each of which perhaps
includes multiple local topics and other changes), each of which pushes
its changes out into possibly multiple working directories.
> But it is too late for the history you already created; "cherry-pick" is
> your friend to recover from the shape of your existing history.
The problem is that it's not _my_ existing history -- it's from the
remote project I'm trying to work with.
I think you'll agree there nothing wrong with a project using tags alone
to manage its releases.
However this means I've got to work out how to do merges of my local
changes onto multiple locally created branches which fork off from these
tags. Perhaps using this cherry-pick tool is truly the best I can do in
this situation.
(it makes me worry though about how I might manage a super-project which
pulls from many remote sub-projects (and which includes large amounts of
its own code) where some of those remote projects use release branches,
and some just use tags, etc.)
--
Greg A. Woods
+1 416 218-0098 VE3TCP RoboHack <woods@robohack.ca>
Planix, Inc. <woods@planix.com> Secrets of the Weird <woods@weird.com>
[-- Attachment #2: Type: application/pgp-signature, Size: 186 bytes --]
^ permalink raw reply
* Re: equal-tree-merges as way to make rebases fast-forward-able
From: Bernhard R. Link @ 2009-11-30 18:55 UTC (permalink / raw)
To: git
In-Reply-To: <7v8wdnooza.fsf@alter.siamese.dyndns.org>
* Junio C Hamano <gitster@pobox.com> [091130 19:19]:
> "Bernhard R. Link" <brlink@debian.org> writes:
>
> > My idea to solve this is combining both histories, the rebased/revised
> > history and the actualy history, marking with some "equal-tree-merge"
> > the point where they have the same result.
>
> If you rewrite a series twice, your RFC will work like this, IIUC:
>
> * You have commit 1 and rewrite it to 2. You record the difference
> between 1 and 2 on top of 1 as commit X and record a same-tree merge as
> A. Here, A^1 == 2, A^2 == X, and 2^{tree} == A^{tree}.
>
> 2-------A
> / /
> 0---1---X
>
> * You then rewrite it to 3. You record the difference between A and 3
> (which is the same as between 2 and 3, because 2^{tree} == A^{tree})
> as commit Y, and record a same-tree merge as B. B^1 == 3, B^2 == Y and
> 3^{tree} == B^{tree}.
>
> Y---------------B
> / /
> 2-------A-------3
> / /
> 0---1---X
I think it rather looks like this:
3---------------B
| /
| 2-------A---Y
|/ /
0---1---X
>
> 3-------.
> / \
> 0---2---W---B
> \ /
> 1-------Z
>
> That is, Z and W records the interdifff between 1 to 3 and 2 to 3
> respectively, and B is a same-tree merge of 3, W and Z.
I think changing it to get this would be easy (though only in the case
where the very last commit was such an equal tree merge), but I do not
think it would be actually better:
- it is no longer possible to see the history of changes by just walking
right on every equal-tree-merge.
- commit a no longer exists. If some downstream already has
cloned/pulled, no fast-forward is possible any more.
> While I find the primary idea (i.e. keeping the old and new equivalents by
> recording a merge of it, and using the first-parent to traverse when you
> find such a special merge) reasonable (and as Dscho has pointed out, this
> technique is widely used, I suspect---it is an obvious thing to do), I
> think we need something stronger than just "this commit merges commits
> that happen to have the same trees" as the marker.
I've considered adding a new header or only a magic description text for those
commits, but I think it is not necessary.
Because the actual programs making it useful to treat this special
(format-patch producing too many patches, rebases possibly showing conflicts
already resolved and bisect walking too many branches) will be the same when
two branches only resulting in the same tree by pure chance show up.
> To avoid that, I think (1) the marker has to be more reliable than just
> "happens to have the same tree", and (2) the traversal done by Porcelains
> (your patches 3 thru 5) by default should be unaware of eqt.
I think for patch 3 (format-patch) and 4 (rebase -i) it is always better to
have the new behaviour even when only hitting equal trees by chance.
I'm unsure about 5 (rebase -m), but guess it still is.
> I don't know what a suitable marker should look like, though. The marker
> must be easily identifiable by the lowest level rev-list machinery, so it
> needs to be a sign left somewhere in the commit object. Perhaps making it
> require to have the same tree as all its parents _and_ a well-known marker
> string in the log message (and nothing else) would be a good start.
It already does always create a unique log message. So one could also
have one more strict and one less strict mode (and some option to decide
on the default).
Hochachtungsvoll,
Bernhard R. Link
--
"Never contain programs so few bugs, as when no debugging tools are available!"
Niklaus Wirth
^ permalink raw reply
* Re: What is the best way to backport a feature?
From: Greg A. Woods @ 2009-11-30 19:08 UTC (permalink / raw)
To: Michael J Gruber; +Cc: Peter Weseloh, The Git Mailing List
In-Reply-To: <4B12A928.2000401@drmicha.warpmail.net>
[-- Attachment #1: Type: text/plain, Size: 3457 bytes --]
Hmmm.... this topic seems in part to be very close to my thread
"git merge" merges too much!
At Sun, 29 Nov 2009 18:02:32 +0100, Michael J Gruber <git@drmicha.warpmail.net> wrote:
Subject: Re: What is the best way to backport a feature?
>
> Seriously, I suggest reading up on "topic branches". Feature_A should
> have been based off the common merge base of Mainline and Release_1.0,
> and, even more importantly, there should not have been any merges from
> Mainline into Feature_A. So, that branch is not at all what one would
> call a feature branch/topic branch. Hopefully, this scenario is very
> uncommon :)
IFF I understand the original post correctly then actually in my
experience this scenario is VERY common in some environments!
This is exactly how large projects which use the likes of CVS (and SVN?)
manage longer-running development branches for important new features.
One excellent example is NetBSD (and perhaps the other BSDs too).
A developer creates a "working" branch from the trunk, then begins to
make changes and commits to that branch. Periodically the (entire)
trunk is merged again to the working branch. I think this is somewhat
equivalent to using "git rebase" to re-apply the feature branch to a new
fork point from the trunk. However the actual branch base point remains
at the original point -- it is only the delta between the last merge
from trunk and the current head of the trunk which is merged onto the
feature working branch. I think this is what people in the CVS world
mean when they say they want the tool to remember the point on the
source branch from where they did the last merge. They've got their
work-flow "backwards", but this is the best they can do with CVS.
These periodic merges from the trunk mean that once the feature is
finished the delta between the trunk and the new feature branch is going
to be just the new feature, and so merging that delta alone to the trunk
as one commit adds the new feature to the trunk with few or no
conflicts, and the feature working branch can finally be "closed".
I'm guessing that people moving to Git from CVS may choose to stick with
this pattern where they periodically merge-from-master to keep
long-running feature branches as close to in-sync with the master branch
as possible (to avoid final merge conflicts). Ideally, IIUC, perhaps
they should use rebase instead.
Perhaps this "mess" can indeed be cleaned up using "git rebase -i" so
that the final version of the feature branch can be back-ported more
easily (though one will still need to use git-cherry-pick or git-am to
do the back-port to the previous release branch). The result of the
cleanup, before the merge of Feature_A to 1.0 might look more like this:
o--o--o Release_1.0
/ \ \
o-o-o--o--o-o-o-o-o-o-o-o---------------o Mainline
\ /
F1'--F2'--F3' Feature_A
and then after the merge of Feature_A to Release_1.0:
o--o--o--F1''--F2''--F3'' Release_1.0
/ \ \
o-o-o--o--o-o-o-o-o-o-o-o---------------o Mainline
\ /
F1'--F2'--F3' Feature_A
--
Greg A. Woods
+1 416 218-0098 VE3TCP RoboHack <woods@robohack.ca>
Planix, Inc. <woods@planix.com> Secrets of the Weird <woods@weird.com>
[-- Attachment #2: Type: application/pgp-signature, Size: 186 bytes --]
^ permalink raw reply
* Re: "git merge" merges too much!
From: Dmitry Potapov @ 2009-11-30 19:22 UTC (permalink / raw)
To: The Git Mailing List; +Cc: Jeff King
In-Reply-To: <m1NFAji-000kn2C@most.weird.com>
On Mon, Nov 30, 2009 at 01:12:31PM -0500, Greg A. Woods wrote:
>
> The way "git merge" works does concern me somewhat though as I try to
> figure out how I might use "topic" branches to develop local features
> and then merge them onto each supported release branch.
The basic idea of using topic branches is development is done on
separate branches are merged to the release branch only when they are
ready to be released. These branches are based on the oldest branch in
what they may be included. It means that fixes are normally based on the
stable branch and new feature are based on the master branch, i.e. the
branch that contains changes for the next new feature release. Not all
branches got merged immediately into master. For instance, the git
project has 'pu' (proposed updates) and 'next' branches. Only when a new
feature proved itself to be useful and reliable, it is "graduated" to
the master branch. Thus the master branch is rather stable and it is
released on regular intervals (no need for a long stabilization period).
The key difference comparing to what you may got used is that branches
are normally based on the oldest branch in what this feature may be
included. Thus normally changes are not backported to old branches,
because you can merge them directly.
> > Yes, you must cherry-pick or use rebase (which is a more featureful
> > version of the pipeline you mentioned).
>
> "git rebase" will not work for me unless it grows a "copy" option ,
> i.e. one which does not delete the original branch (i.e. avoids the
> "reset" phase of its operation).
There is no reset phase... It is just reassigning the head of branch to
point to a different commit-id. If you want to copy a branch instead of
rebasing the old one, you create a new branch (a new name) that points
to the same commit as the branch that you want to copy, after that you
rebase this new branch. You can do that like this:
$ git branch new-foo foo
$ git rebase --onto newbase oldbase new-foo
> It likely wouldn't make sense to base this new "copy" feature directly
> on "git rebase" though, especially in light of all the warnings about
> how "git rebase" isn't friendly when applied to already published
> branches. I think in theory this "copy" feature won't cause problems
> for already-published branches.
The "copy" does not have the problem of rebase, but it has a different
problem: You have two series of commits instead of one. If you found
a bug in one of those commits, you will have to patch each series
separately. Also, git merge may produce additional conflicts... So,
copying commits is not something that I would recommend to do often.
Dmitry
^ permalink raw reply
* Re: equal-tree-merges as way to make rebases fast-forward-able
From: Johannes Sixt @ 2009-11-30 19:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Bernhard R. Link, git
In-Reply-To: <7v8wdnooza.fsf@alter.siamese.dyndns.org>
On Montag, 30. November 2009, Junio C Hamano wrote:
> To avoid that, I think (1) the marker has to be more reliable than just
> "happens to have the same tree", and (2) the traversal done by Porcelains
> (your patches 3 thru 5) by default should be unaware of eqt.
>
> I don't know what a suitable marker should look like, though. The marker
> must be easily identifiable by the lowest level rev-list machinery, so it
> needs to be a sign left somewhere in the commit object.
Wouldn't the pathspec . be the marker:
git rev-list HEAD -- .
follows only one of the branches that have identical trees.
-- Hannes
^ permalink raw reply
* Re: [PATCH 3/8] git-merge-recursive-{ours,theirs}
From: Junio C Hamano @ 2009-11-30 19:56 UTC (permalink / raw)
To: Avery Pennarun; +Cc: git
In-Reply-To: <32541b130911301008v4156f0c6ge9f30952565392f9@mail.gmail.com>
Avery Pennarun <apenwarr@gmail.com> writes:
>> I've queued the series with minor fixes to 'pu' and pushed it out.
>
> Since I see you didn't change a couple of things you mentioned in
> earlier comments (the NEEDSWORK comment and the sq-then-eval trick) do
> you still want me to respin this series?
The commit still is NEEDSWORK and shouldn't be in 'next' in its current
shape. I don't think the topic is 1.6.6 material yet, and we will be in
pre-release feature freeze any minute now, so there is no urgency.
As I did the sq-then-eval in many places in our Porcelain scripts (and
many of them are converted to C and lost the need for the trick), I may
get tempted to fix it up when I am bored ;-). But no promises.
Thanks.
^ permalink raw reply
* Re: [PATCH 3/8] git-merge-recursive-{ours,theirs}
From: Junio C Hamano @ 2009-11-30 20:01 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Avery Pennarun, git
In-Reply-To: <7viqcrlrb8.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
> Avery Pennarun <apenwarr@gmail.com> writes:
>
>>> I've queued the series with minor fixes to 'pu' and pushed it out.
>>
>> Since I see you didn't change a couple of things you mentioned in
>> earlier comments (the NEEDSWORK comment and the sq-then-eval trick) do
>> you still want me to respin this series?
>
> The commit still is NEEDSWORK and shouldn't be in 'next' in its current
> shape.
Oh, I think you meant the "NEEDSWORK -- we limit to depth 2 when we
guess" and that has been with us ever since we added subtree merge, and it
is no reason to block the topic. I had the sq-then-eval stuff in mind
when I wrote above.
Sorry for the confusion.
^ permalink raw reply
* Re: [PATCH 3/8] git-merge-recursive-{ours,theirs}
From: Avery Pennarun @ 2009-11-30 20:02 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7viqcrlrb8.fsf@alter.siamese.dyndns.org>
On Mon, Nov 30, 2009 at 2:56 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Avery Pennarun <apenwarr@gmail.com> writes:
>>> I've queued the series with minor fixes to 'pu' and pushed it out.
>>
>> Since I see you didn't change a couple of things you mentioned in
>> earlier comments (the NEEDSWORK comment and the sq-then-eval trick) do
>> you still want me to respin this series?
>
> The commit still is NEEDSWORK and shouldn't be in 'next' in its current
> shape. I don't think the topic is 1.6.6 material yet, and we will be in
> pre-release feature freeze any minute now, so there is no urgency.
>
> As I did the sq-then-eval in many places in our Porcelain scripts (and
> many of them are converted to C and lost the need for the trick), I may
> get tempted to fix it up when I am bored ;-). But no promises.
I'll interpret that as "no, I should not respin the series because
Junio plans to deal with it" :)
Do let me know if there's anything I should do to help this advance
from pu->next sooner (if they delay is not simply because of the code
freeze).
Have fun,
Avery
^ permalink raw reply
* Re: [RFC/PATCH] Detailed diagnostic when parsing an object name fails.
From: Junio C Hamano @ 2009-11-30 20:12 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <1259603421-10055-1-git-send-email-Matthieu.Moy@imag.fr>
Matthieu Moy <Matthieu.Moy@imag.fr> writes:
> The original motivation is actually to anwser the FAQ of "git show
> HEAD:foo.txt" being relative to the root, while some users would
> expect it relative to $PWD but the patch ended up being far more
> general. At least,
>
> $ cd git
> $ cd t
> $ ../git show HEAD:test-lib.sh
> fatal: Path 't/test-lib.sh' exists, but not 'test-lib.sh'.
> Did you mean 'HEAD:t/test-lib.sh'?
The first thought that comes to mind is that if it makes more sense to
just fall back to the interpretation of the input when the tool has
already figured out to second guess the intention of the user like the
above message does.
That would obviously break scripts that try to make sure the _absense_ of
a path in a tree-ish (or in the index if you lack "HEAD" in your example),
expecting:
git rev-parse HEAD:test-lib.sh ||
echo "test-lib.sh shouldn't be at the top level"
to work regardless of where you are in the work tree, so it won't fly
well.
Perhaps the second step would be to teach the machinery to understand a
syntax like "<tree-ish>:./<path>" and have it prefix the path to the
current subdirectory from the root of the work tree, and with such an
enhancement, the suggestion given by this patch would probably change to
"Did you mean 'HEAD:./test-lib.sh'?", but that would be a separate topic.
^ permalink raw reply
* Re: equal-tree-merges as way to make rebases fast-forward-able
From: Junio C Hamano @ 2009-11-30 20:32 UTC (permalink / raw)
To: Johannes Sixt; +Cc: Junio C Hamano, Bernhard R. Link, git
In-Reply-To: <200911302026.53933.j6t@kdbg.org>
Johannes Sixt <j6t@kdbg.org> writes:
> On Montag, 30. November 2009, Junio C Hamano wrote:
>> To avoid that, I think (1) the marker has to be more reliable than just
>> "happens to have the same tree", and (2) the traversal done by Porcelains
>> (your patches 3 thru 5) by default should be unaware of eqt.
>>
>> I don't know what a suitable marker should look like, though. The marker
>> must be easily identifiable by the lowest level rev-list machinery, so it
>> needs to be a sign left somewhere in the commit object.
>
> Wouldn't the pathspec . be the marker:
>
> git rev-list HEAD -- .
>
> follows only one of the branches that have identical trees.
Because I am saying that "this commit has two parents and they record the
identical trees" is a condition that is too weak to mark a special-purpose
merge to bind the latest and an earlier version of a series, your rev-list
example command line should not be the way to identify such a mark commit
and act differently upon seeing one.
Actually your command line is even weaker, I think, although it would not
make much difference in real-life. The marker as currently Bernhard
implements not only has parents with identical trees, but the tree it has
also matches those of its parents.
You can make a commit that merges two branches that independently reached
the same conclusion (which git is designed to handle as an ordinary event
in real life), and amend that commit into an evil merge that has different
contents from its parents (which, I suspect, does not have much use in
practice), and your rev-list will drop one of the branches for even such a
commit, mistaking it as a marker when it is clearly not one.
My "it would not make much difference in real-life" in the two paragraphs
above comes purely from "such an evil merge would not have much use in
practice". We should make sure that "two branches that reached the same
conclusion" is not mistaken with a marker this series introduces.
^ permalink raw reply
* Re: "git merge" merges too much!
From: Junio C Hamano @ 2009-11-30 20:50 UTC (permalink / raw)
To: The Git Mailing List; +Cc: Junio C Hamano
In-Reply-To: <m1NFBAx-000kmgC@most.weird.com>
"Greg A. Woods" <woods@planix.com> writes:
> .... This isn't really a Git problem I suppose, except
> for the fact that it means the lack of easy support for multiple working
> directories that track different branches makes this kind of development
> somewhat more difficult to do with Git than with, say, CVS.
You want to google for git-new-workdir then; it is found in
contrib/workdir and fairly widely used.
^ permalink raw reply
* Re: [PATCH] tests: handle NO_PYTHON setting
From: Jeff King @ 2009-11-30 20:54 UTC (permalink / raw)
To: Brandon Casey; +Cc: Junio C Hamano, Sverre Rabbelier, git
In-Reply-To: <0OMCWm31DRbUGCfPIS6SSJn59HQIM9AKtSDgVSNdiSR99clfmJ3D-Q@cipher.nrlssc.navy.mil>
On Mon, Nov 30, 2009 at 12:07:40PM -0600, Brandon Casey wrote:
> Shouldn't this section be moved down below the sourcing of ../GIT-BUILD-OPTIONS
> on line 656 so that the value of NO_PYTHON will be available when running the
> test scripts directly?
Oops, good catch. I stupidly tested with "make NO_PYTHON=1 test" instead
of actually checking that GIT-BUILD-OPTIONS was propagating it
correctly.
> ps. There's something eerily familiar about this patch.
Hmmm. Yes, I didn't search before writing it, but you probably mean:
http://article.gmane.org/gmane.comp.version-control.git/127172
But that is missing the NO-PYTHON bit in GIT-BUILD-OPTIONS (did you
forget it there, or was it part of some other patch that also didn't get
applied?).
Also, I am tempted to move the GIT-BUILD-OPTIONS invocation _up_. It
is about reading config and should probably come before we start doing
_anything_.
So maybe this instead:
-- >8 --
Subject: [PATCH] tests: handle NO_PYTHON setting
Without this, test-lib checks that the git_remote_helpers
directory has been built. However, if we are building
without python, we will not have done anything at all in
that directory, and test-lib's sanity check will fail.
We bump the inclusion of GIT-BUILD-OPTIONS further up in
test-lib; it contains configuration, and as such should be
read before we do any checks (and in this particular case,
we need its value to do our check properly).
Signed-off-by: Jeff King <peff@peff.net>
---
I moved the BUILD-OPTIONS thing to just above the beginning of the
"have you built anything" checks, but after all of the function
definitions. But perhaps it should simply go at the very top of the
script. After all, in the case of "make NO_PYTHON=1 test", those
variables will already be defined at the very beginning of the script.
Makefile | 1 +
t/test-lib.sh | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index 42744a4..443565e 100644
--- a/Makefile
+++ b/Makefile
@@ -1743,6 +1743,7 @@ GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
+ @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 4a40520..2d523fe 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -632,13 +632,15 @@ GIT_CONFIG_NOSYSTEM=1
GIT_CONFIG_NOGLOBAL=1
export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
+. ../GIT-BUILD-OPTIONS
+
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
export GITPERLLIB
test -d ../templates/blt || {
error "You haven't built things yet, have you?"
}
-if test -z "$GIT_TEST_INSTALLED"
+if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON"
then
GITPYTHONLIB="$(pwd)/../git_remote_helpers/build/lib"
export GITPYTHONLIB
@@ -653,8 +655,6 @@ if ! test -x ../test-chmtime; then
exit 1
fi
-. ../GIT-BUILD-OPTIONS
-
# Test repository
test="trash directory.$(basename "$0" .sh)"
test -n "$root" && test="$root/$test"
--
1.6.6.rc0.327.gd49b
^ permalink raw reply related
* Re: [RFC/PATCH] Detailed diagnostic when parsing an object name fails.
From: Matthieu Moy @ 2009-11-30 20:57 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vtywbkc05.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
>> $ ../git show HEAD:test-lib.sh
>> fatal: Path 't/test-lib.sh' exists, but not 'test-lib.sh'.
>> Did you mean 'HEAD:t/test-lib.sh'?
>
> The first thought that comes to mind is that if it makes more sense to
> just fall back to the interpretation of the input when the tool has
> already figured out to second guess the intention of the user like the
> above message does.
>
> That would obviously break scripts that try to make sure the _absense_ of
> a path in a tree-ish (or in the index if you lack "HEAD" in your example),
> expecting:
>
> git rev-parse HEAD:test-lib.sh ||
> echo "test-lib.sh shouldn't be at the top level"
There's another (more important IMO) problem: if HEAD contains both
file.txt and subdir/file.txt, then what should
cd subdir
git show HEAD:file.txt
do? Allowing HEAD:file-in-a-subdirectory.txt would indirectly mean
teaching users to use in, and they'd be bitten by an ambiguous
behavior one day or another ...
> Perhaps the second step would be to teach the machinery to understand a
> syntax like "<tree-ish>:./<path>" and have it prefix the path to the
> current subdirectory from the root of the work tree, and with such an
> enhancement, the suggestion given by this patch would probably change to
> "Did you mean 'HEAD:./test-lib.sh'?", but that would be a separate
> topic.
Exactly. I think this HEAD:./relative-path syntax has been discussed
here already, but I don't remember the outcome of the discussion. If
it's ever implemented, my patch, modified as you suggest will help
users to discover the feature ;-).
BTW, I finally had time to write a test. Current version below FYI
(fixed a segfault discovered by testing too), but I'll resend properly
when I get enough feedback.
>From 1bc1c8d114b538f57a5ba4a501436229d644d587 Mon Sep 17 00:00:00 2001
From: Matthieu Moy <Matthieu.Moy@imag.fr>
Date: Mon, 30 Nov 2009 17:32:39 +0100
Subject: [PATCH] Detailed diagnosis when parsing an object name fails.
The previous error message was the same in many situations (unknown
revision or path not in the working tree). We try to help the user as
much as possible to understand the error, especially with the
sha1:filename notation. In this case, we say whether the sha1 or the
filename is problematic, and diagnose the confusion between
relative-to-root and relative-to-$PWD confusion precisely.
The 6 new error messages are tested.
---
cache.h | 6 ++-
setup.c | 15 +++++-
sha1_name.c | 95 ++++++++++++++++++++++++++++++++++++++--
t/t1506-rev-parse-diagnosis.sh | 67 ++++++++++++++++++++++++++++
4 files changed, 176 insertions(+), 7 deletions(-)
create mode 100755 t/t1506-rev-parse-diagnosis.sh
diff --git a/cache.h b/cache.h
index 0e69384..5c8cb5f 100644
--- a/cache.h
+++ b/cache.h
@@ -708,7 +708,11 @@ static inline unsigned int hexval(unsigned char c)
#define DEFAULT_ABBREV 7
extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
+static inline get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
+{
+ return get_sha1_with_mode_1(str, sha1, mode, 0, NULL);
+}
+extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int fatal, const char *prefix);
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern int read_ref(const char *filename, unsigned char *sha1);
diff --git a/setup.c b/setup.c
index f67250b..3094e8b 100644
--- a/setup.c
+++ b/setup.c
@@ -74,6 +74,18 @@ int check_filename(const char *prefix, const char *arg)
die_errno("failed to stat '%s'", arg);
}
+static void NORETURN die_verify_filename(const char *prefix, const char *arg)
+{
+ unsigned char sha1[20];
+ unsigned mode;
+ /* try a detailed diagnostic ... */
+ get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);
+ /* ... or fall back the most general message. */
+ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
+ "Use '--' to separate paths from revisions", arg);
+
+}
+
/*
* Verify a filename that we got as an argument for a pathspec
* entry. Note that a filename that begins with "-" never verifies
@@ -87,8 +99,7 @@ void verify_filename(const char *prefix, const char *arg)
die("bad flag '%s' used after filename", arg);
if (check_filename(prefix, arg))
return;
- die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
- "Use '--' to separate paths from revisions", arg);
+ die_verify_filename(prefix, arg);
}
/*
diff --git a/sha1_name.c b/sha1_name.c
index 44bb62d..030e2ac 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -804,7 +804,77 @@ int get_sha1(const char *name, unsigned char *sha1)
return get_sha1_with_mode(name, sha1, &unused);
}
-int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
+static void diagnose_invalid_sha1_path(const char *prefix,
+ const char *filename,
+ const char *tree_sha1,
+ const char *object_name)
+{
+ struct stat st;
+ unsigned char sha1[20];
+ unsigned mode;
+
+ if (!prefix)
+ prefix = "";
+
+ if (!lstat(filename, &st))
+ die("Path '%s' exists on disk, but not in '%s'.",
+ filename, object_name);
+ if (errno == ENOENT || errno == ENOTDIR) {
+ char *fullname = malloc(strlen(filename)
+ + strlen(prefix) + 1);
+ strcpy(fullname, prefix);
+ strcat(fullname, filename);
+
+ if (!get_tree_entry(tree_sha1, fullname,
+ sha1, &mode)) {
+ die("Path '%s' exists, but not '%s'.\n"
+ "Did you mean '%s:%s'?",
+ fullname,
+ filename,
+ object_name,
+ fullname);
+ }
+ die("Path '%s' does not exist in '%s'",
+ filename, object_name);
+ }
+}
+
+static void diagnose_invalid_index_path(int stage,
+ const char *prefix,
+ const char *filename)
+{
+ struct stat st;
+
+ if (!prefix)
+ prefix = "";
+
+ if (!lstat(filename, &st))
+ die("Path '%s' exists on disk, but not in the index.", filename);
+ if (errno == ENOENT || errno == ENOTDIR) {
+ struct cache_entry *ce;
+ int pos;
+ int namelen = strlen(filename) + strlen(prefix);
+ char *fullname = malloc(namelen + 1);
+ strcpy(fullname, prefix);
+ strcat(fullname, filename);
+ pos = cache_name_pos(fullname, namelen);
+ if (pos < 0)
+ pos = -pos - 1;
+ ce = active_cache[pos];
+ if (ce_namelen(ce) == namelen &&
+ !memcmp(ce->name, fullname, namelen))
+ die("Path '%s' is in the index, but not '%s'.\n"
+ "Did you mean ':%d:%s'?",
+ fullname, filename,
+ stage, fullname);
+
+ die("Path '%s' does not exist (neither on disk nor in the index).",
+ filename);
+ }
+}
+
+
+int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int fatal, const char *prefix)
{
int ret, bracket_depth;
int namelen = strlen(name);
@@ -850,6 +920,8 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
}
pos++;
}
+ if (fatal)
+ diagnose_invalid_index_path(stage, prefix, cp);
return -1;
}
for (cp = name, bracket_depth = 0; *cp; cp++) {
@@ -862,9 +934,24 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
}
if (*cp == ':') {
unsigned char tree_sha1[20];
- if (!get_sha1_1(name, cp-name, tree_sha1))
- return get_tree_entry(tree_sha1, cp+1, sha1,
- mode);
+ char *object_name;
+ if (fatal) {
+ object_name = malloc(cp-name+1);
+ strncpy(object_name, name, cp-name);
+ object_name[cp-name] = '\0';
+ }
+ if (!get_sha1_1(name, cp-name, tree_sha1)) {
+ const char *filename = cp+1;
+ ret = get_tree_entry(tree_sha1, filename, sha1, mode);
+ if (fatal)
+ diagnose_invalid_sha1_path(prefix, filename,
+ tree_sha1, object_name);
+
+ return ret;
+ } else {
+ if (fatal)
+ die("Invalid object name '%s'.", object_name);
+ }
}
return ret;
}
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
new file mode 100755
index 0000000..8112d56
--- /dev/null
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+test_description='test git rev-parse diagnosis for invalid argument'
+
+exec </dev/null
+
+. ./test-lib.sh
+
+HASH_file=
+
+test_expect_success 'set up basic repo' '
+ echo one > file.txt &&
+ mkdir subdir &&
+ echo two > subdir/file.txt &&
+ echo three > subdir/file2.txt &&
+ git add . &&
+ git commit -m init &&
+ echo four > index-only.txt &&
+ git add index-only.txt &&
+ echo five > disk-only.txt
+'
+
+test_expect_success 'correct file objects' '
+ HASH_file=$(git rev-parse HEAD:file.txt) &&
+ git rev-parse HEAD:subdir/file.txt &&
+ git rev-parse :index-only.txt &&
+ cd subdir &&
+ git rev-parse HEAD:file.txt &&
+ git rev-parse HEAD:subdir/file2.txt &&
+ test $HASH_file = $(git rev-parse HEAD:file.txt) &&
+ test $HASH_file = $(git rev-parse :file.txt) &&
+ test $HASH_file = $(git rev-parse :0:file.txt) &&
+ cd ..
+'
+
+test_expect_success 'incorrect revision id' '
+ test_must_fail git rev-parse foobar:file.txt 2>&1 |
+ grep "Invalid object name '"'"'foobar'"'"'." &&
+ test_must_fail git rev-parse foobar 2>&1 |
+ grep "unknown revision or path not in the working tree."
+'
+
+test_expect_success 'incorrect file in sha1:path' '
+ test_must_fail git rev-parse HEAD:nothing.txt 2>&1 |
+ grep "fatal: Path '"'"'nothing.txt'"'"' does not exist in '"'"'HEAD'"'"'" &&
+ test_must_fail git rev-parse HEAD:index-only.txt 2>&1 |
+ grep "fatal: Path '"'"'index-only.txt'"'"' exists on disk, but not in '"'"'HEAD'"'"'." &&
+ cd subdir &&
+ test_must_fail git rev-parse HEAD:file2.txt 2>&1 |
+ grep "Did you mean '"'"'HEAD:subdir/file2.txt'"'"'?" &&
+ cd ..
+'
+
+test_expect_success 'incorrect file in :path and :0:path' '
+ test_must_fail git rev-parse :nothing.txt 2>&1 |
+ grep "fatal: Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." &&
+ test_must_fail git rev-parse :1:nothing.txt 2>&1 |
+ grep "Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." &&
+ cd subdir &&
+ test_must_fail git rev-parse :file2.txt 2>&1 |
+ grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" &&
+ cd .. &&
+ test_must_fail git rev-parse :disk-only.txt 2>&1 |
+ grep "fatal: Path '"'"'disk-only.txt'"'"' exists on disk, but not in the index."
+'
+
+test_done
--
1.6.6.rc0.256.g6060
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply related
* Re: [PATCH] tests: handle NO_PYTHON setting
From: Brandon Casey @ 2009-11-30 21:17 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Sverre Rabbelier, git
In-Reply-To: <20091130205453.GA20348@coredump.intra.peff.net>
Jeff King wrote:
> On Mon, Nov 30, 2009 at 12:07:40PM -0600, Brandon Casey wrote:
>> ps. There's something eerily familiar about this patch.
>
> Hmmm. Yes, I didn't search before writing it, but you probably mean:
>
> http://article.gmane.org/gmane.comp.version-control.git/127172
:) yeah, that was it, nbd.
> But that is missing the NO-PYTHON bit in GIT-BUILD-OPTIONS (did you
> forget it there, or was it part of some other patch that also didn't get
> applied?).
It was 1/2 of that series.
> Also, I am tempted to move the GIT-BUILD-OPTIONS invocation _up_. It
> is about reading config and should probably come before we start doing
> _anything_.
>
> So maybe this instead:
<snip the patch>
Looks fine to me.
No strong opinion on whether the BUILD-OPTIONS thing should be
at the beginning of the script, or in the place where you placed
it.
-brandon
^ permalink raw reply
* Re: "git merge" merges too much!
From: Dmitry Potapov @ 2009-11-30 21:17 UTC (permalink / raw)
To: The Git Mailing List; +Cc: Junio C Hamano
In-Reply-To: <m1NFBAx-000kmgC@most.weird.com>
On Mon, Nov 30, 2009 at 01:40:38PM -0500, Greg A. Woods wrote:
>
> While it may be quite convenient in small projects to quickly move a
> single working directory from one branch to another and do various
> builds and tests from the result, large projects (say where a compile
> takes the better part of a working day or more and where testing
> requires multi-day processes) demand that working directories remain
> "stable", and multiple lines of development therefore demand multiple
> working directories.
It depends on the project and what tools are used, but using ccache and
proper dependencies help a lot to reduce the cost of switching. In fact,
it may be faster to switch to another branch and have to recompile a few
files than to go into another working directory, because when you go to
another working directory, you hit cold cache and things get very slow.
And then if a project is huge and takes a lot of time to compile and
test everything, I do not think, it is a good idea to build that in your
work tree. Instead, you make a shanshot using git-archive and then run
full build and test on it. In this way, you know that you test exactly
what you have committed (you can amend any commit later until you
publish it).
Dmitry
^ permalink raw reply
* [PATCH/RFC] Add a --bouquet option to git rev-list
From: Nathan W. Panike @ 2009-11-30 20:55 UTC (permalink / raw)
To: git
Add a command line option to rev-list so the command 'git rev-list --bouquet'
shows all revisions that are ancestors of refs which share history with HEAD.
Signed-off-by: Nathan W. Panike <nathan.panike@gmail.com>
---
I have a repository with the following structure:
B
/
A'--A--C
\
D
E'--E
Thus the command 'git merge base E A' returns nothing, as there is no common
history. The E history contains stuff that is derived from the other history
(A, B, C, or D). Often I find myself doing the following:
git checkout C
gitk $(include_forks) &
<View history, make changes, merges, et cetera>
git checkout E
<go back to gitk, only see history for B, C, etc>
Now the 'include_forks' command is a bash function in my .bashrc:
include_forks ()
{
local head="$(git show -s --pretty=format:'%H' HEAD)";
echo "HEAD $(git for-each-ref --format='%(refname)' \
refs/heads refs/remotes | while read ref; do \
if test "$(git merge-base HEAD ${ref}^{commit})" != ""; \
then echo ${ref}; fi; done)"
}
The shell thus intercepts my command and I must restart gitk to see the history
of E.
With this patch, I can issue the command 'gitk --bouquet' and when I checkout
E, I can 'reload' in gitk and see the history of E automatically.
If there is an easier way to do this in git, please let me know. Otherwise,
please let me know how to improve this patch.
revision.c | 38 ++++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/revision.c b/revision.c
index a8a3c3a..ba367cc 100644
--- a/revision.c
+++ b/revision.c
@@ -699,6 +699,31 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,
return 0;
}
+static int handle_one_connected_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+{
+ struct all_refs_cb *cb = cb_data;
+ struct object *object = get_reference(cb->all_revs, path, sha1,
+ cb->all_flags);
+ struct commit *r;
+ static int got_head = 1;
+ static struct commit *head_commit;
+ static int head_nr = 0;
+ if(got_head) {
+ got_head=head_ref(handle_one_ref,cb);
+ if(got_head)
+ return 1;
+ if(cb && cb->all_revs && cb->all_revs->pending.nr > 0) {
+ head_nr = cb->all_revs->pending.nr - 1;
+ head_commit = (struct commit*)&cb->all_revs->pending.objects->item[head_nr];
+ }
+ }
+ r = lookup_commit_reference_gently(sha1,1);
+ if(r != NULL && head_commit)
+ if(get_merge_bases_many(head_commit,1,&r,1))
+ add_pending_object(cb->all_revs, object, path);
+ return 0;
+}
+
static void handle_refs(struct rev_info *revs, unsigned flags,
int (*for_each)(each_ref_fn, void *))
{
@@ -708,6 +733,15 @@ static void handle_refs(struct rev_info *revs, unsigned flags,
for_each(handle_one_ref, &cb);
}
+static void handle_connected_refs(struct rev_info *revs, unsigned flags,
+ int (*for_each)(each_ref_fn, void *))
+{
+ struct all_refs_cb cb;
+ cb.all_revs = revs;
+ cb.all_flags = flags;
+ for_each(handle_one_connected_ref, &cb);
+}
+
static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)
{
struct all_refs_cb *cb = cb_data;
@@ -1352,6 +1386,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
handle_refs(revs, flags, for_each_remote_ref);
continue;
}
+ if (!strcmp(arg, "--bouquet")) {
+ handle_connected_refs(revs, flags, for_each_ref);
+ continue;
+ }
if (!strcmp(arg, "--reflog")) {
handle_reflog(revs, flags);
continue;
--
1.6.5.3
^ permalink raw reply related
* Re: [PATCH] reset: add --quiet option
From: Stephen Boyd @ 2009-11-30 21:45 UTC (permalink / raw)
To: Felipe Contreras; +Cc: git
In-Reply-To: <94a0d4530911300219j51e21e2cwae17d4248400a345@mail.gmail.com>
On Mon, Nov 30, 2009 at 2:19 AM, Felipe Contreras
<felipe.contreras@gmail.com> wrote:
> I thought somebody would complain about loosing that string. In any
> case, first step is adding --query to 'git reset', second step is
> moving all OPT_BOOLEAN('q' to OPT__QUIET; there are other commands
> doing the same.
>
If you're already touching the line why not just do it once? I agree a
follow-up patch to cover the other commands would be good.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox