* Re: [PATCH 5/8] push, send-pack: support pushing HEAD to real ref name
From: Daniel Barkalow @ 2007-10-27 22:03 UTC (permalink / raw)
To: Steffen Prohaska; +Cc: git
In-Reply-To: <11935038084055-git-send-email-prohaska@zib.de>
On Sat, 27 Oct 2007, Steffen Prohaska wrote:
> This teaches "push <remote> HEAD" to resolve HEAD on the local
> side to its real ref name, e.g. refs/heads/master, and then
> use the real ref name on the remote side to search a matching
> remote ref.
I'd prefer this to be in set_refspecs in builtin-push. That way, it only
applies to command-line arguments and matches your description better. (If
you use a symbolic name on the command line, it follows it, and acts
exactly as if you used the name it points to).
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH 4/8] rev-parse: teach "git rev-parse --symbolic" to print the full ref name
From: Daniel Barkalow @ 2007-10-27 21:53 UTC (permalink / raw)
To: Steffen Prohaska; +Cc: git
In-Reply-To: <11935038083369-git-send-email-prohaska@zib.de>
On Sat, 27 Oct 2007, Steffen Prohaska wrote:
> "git rev-parse --symbolic" used to return the ref name as it was
> specified on the command line. This is changed to returning the
> full matched ref name, i.e. "git rev-parse --symbolic master"
> now typically returns "refs/heads/master".
>
> Note, this changes output of an established command. It might
> break existing setups. I checked that it does not break scripts
> in git.git.
I think this makes the --create option to push unnecessary, as interactive
users could use a suggested explicit value (or whatever they actually
meant), while scripts could replace $name with $(git rev-parse --symbolic
$name) as easily as they could add --create, and by more explicit as to
what they're doing.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH 1/8] push: change push to fail if short ref name does not exist
From: Daniel Barkalow @ 2007-10-27 21:42 UTC (permalink / raw)
To: Steffen Prohaska; +Cc: git
In-Reply-To: <11935038081211-git-send-email-prohaska@zib.de>
On Sat, 27 Oct 2007, Steffen Prohaska wrote:
> You can use a branch's shortname to push it. Push used to create
> the branch on the remote side if it did not yet exist. If you
> specified the wrong branch accidentally it was created. A safety
> valve that pushes only existing branches may help to avoid
> errors.
>
> This commit changes push to fail if the remote ref does not yet
> exist and the refspec does not start with refs/. Remote refs must
> explicitly be created with their full name.
I agree with the change (and I think it's appropriate for master or next),
but your implementation is a bit too clever for my tastes.
> Signed-off-by: Steffen Prohaska <prohaska@zib.de>
> ---
> remote.c | 5 +++--
> t/t5516-fetch-push.sh | 34 ++++++++++++++++++++++++++++++++--
> 2 files changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/remote.c b/remote.c
> index 170015a..ec992c9 100644
> --- a/remote.c
> +++ b/remote.c
> @@ -611,6 +611,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
> struct ref *matched_src, *matched_dst;
>
> const char *dst_value = rs->dst;
> + const char * const orig_dst_value = rs->dst ? rs->dst : rs->src;
"lit_dst_value" would probably be a better description, and it might be
worth handling the rs->dst == NULL case where it's handled for dst_value.
Technically, this variable, when it doesn't match the final value of
dst_value, has a value that dst_value never had.
>
> if (rs->pattern)
> return errs;
> @@ -647,12 +648,12 @@ static int match_explicit(struct ref *src, struct ref *dst,
> case 1:
> break;
> case 0:
> - if (!memcmp(dst_value, "refs/", 5))
> + if (!memcmp(orig_dst_value , "refs/", 5))
> matched_dst = make_linked_ref(dst_value, dst_tail);
This should also be orig_dst_value, too. I know that dst_value and
orig_dst_value must be the same in this case, but it takes a bunch of
analysis to demonstrate that, and it's more intuitive to use the value
you've just checked anyway, and also to have all of case 0 use the
differently-computed destination.
> else
> error("dst refspec %s does not match any "
> "existing ref on the remote and does "
> - "not start with refs/.", dst_value);
> + "not start with refs/.", orig_dst_value);
Maybe the error should provide a hint if dst_value is not the same as
orig_dst_value? (if (!rs->dst) error("Did you mean %s?\n", dst_value);)
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: merge vs rebase: Is visualization in gitk the only problem?
From: Daniel Barkalow @ 2007-10-27 20:59 UTC (permalink / raw)
To: Steffen Prohaska; +Cc: Git Mailing List
In-Reply-To: <8E86BDBA-A49A-49BB-8E00-8BF6DD7237E9@zib.de>
On Sat, 27 Oct 2007, Steffen Prohaska wrote:
> There are some discussions going on about merge vs. rebase. The
> suggestions by Dscho is to prefer rebase over merge in a
> CVS-style workflow.
>
> Rebase has definitely benefits but not all of its details
> are obvious at a first glance. Tell a newbie to read the
> git rebase man page and explain what git reabase does and
> you know what I mean. Rebase definitely can help to create a
> cleaner history. But it rewrites history and therefore destroys
> information, for example information about the original code
> base a patch was developed against, or merge conflicts that
> were resolved. You also need to decide when to use rebase and
> when to use merge. So you need to make a choice.
>
> Why not always use git merge?
>
> Is the only problem of git merge that it might create loops
> in the history with potentially long running parallel lines
> that are insufficiently visualized in gitk?
>
> If so, why not improve the visualization?
>
> Or is there any other deficiency of always using merge and
> never using rebase that I don't see?
Not all possible upstream systems support non-linear history. If upstream
is actually svn or cvs, you need to rebase in order for the other system
to be able to represent the result.
I think it's easier for someone from the future trying to figure out the
historical reason for some code to be a certain way if that code isn't
touched by a merge conflict resolution. If there is a conflict, the
resulting content is most directly due to a commit that has no explanation
aside from a note that there was a conflict there; it's somewhat easier to
understand if the code is entirely attributable to the commit that
logically introduces the change. (Although maybe we could make the display
take care of this; linearize the history using the rerere info in the
merge commit, and show that as the history, annotated suitably to indicate
that the blame for some of it falls partially on the merge commit.)
It's also more familiar for many users to be asked to place their changes
after all other committed changes, rather than leaving the ancestry pegged
at the last time they updated before starting to work.
> Obviously you can use git merge only if you want to have _all_
> changes from the other branch. But this is often what you
> want. In a CVS-style workflow you want to merge all changes
> from the shared branch before pushing. Why going through the
> hassel of git rebase?
Unless you've got a series of changes to a section that the upstream also
changed, it's the same amount of resolution, but rebase lets you resolve
logical collections of conflicts (i.e., those due to a single one of your
commits) individually. IIRC, merging my builtin-fetch topic after 1.5.3
had 3 scattered conflicts, and rebasing had 4 conflicts, with no more than
one per commit (so that I could test the resolutions independantly), and
the rebase was easier.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: remote#branch
From: Jan Hudec @ 2007-10-27 20:47 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Petr Baudis, Paolo Ciarrocchi, git
In-Reply-To: <Pine.LNX.4.64.0710162228560.25221@racer.site>
[-- Attachment #1: Type: text/plain, Size: 1671 bytes --]
On Tue, Oct 16, 2007 at 22:35:25 +0100, Johannes Schindelin wrote:
> Hi,
>
> On Tue, 16 Oct 2007, Jan Hudec wrote:
>
> > If it is a fragment, than "#" is the only correct separator and should
> > stay that way.
>
> You did not listen, did you? '#' is allowed in ref names. Therefore this
> character really would lock us in to only ever reference _one_ and _only_
> one remote branch at a time. This might have worked for cogito, but it
> does not for git.
>
> So, I say it again, '#' is _out_.
That does not imply it can't separate the ref from the repository...
> > If it is not a true fragment, than we might want to phase it out in
> > favor of something else. But I would strongly prefer staying within
> > characters allowed in URI (as per rfc2396).
>
> If you do that, "http://<xyz-with-branch>" would be ambiguous, wouldn't
> it? This would already reference an HTTP resource, and you could not
> embed refnames into the URL.
... and because of this actually has to. You are right.
> > As for multiple branches, separating them with "," feels logical to me,
> > no matter what separates them from the repository path. On the other
> > hand given that neither ":" nor "@" is allowed in refnames, reusing the
> > same separator would make sense especially if git switched to either of
> > those.
>
> ',' is allowed in ref names, so ',' is out.
Actually since many characters that are allowed in ref name are not allowed
in URL at all, the ref-name has to be url-escaped. Which brings all
characters back in, because they can always be specified escaped.
--
Jan 'Bulb' Hudec <bulb@ucw.cz>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: recent change in git.git/master broke my repos
From: Daniel Barkalow @ 2007-10-27 20:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Randal L. Schwartz
In-Reply-To: <7vejfhulzn.fsf@gitster.siamese.dyndns.org>
On Fri, 26 Oct 2007, Junio C Hamano wrote:
> Daniel Barkalow <barkalow@iabervon.org> writes:
>
> > On Thu, 25 Oct 2007, Jeff King wrote:
> >
> >> On Thu, Oct 25, 2007 at 07:32:36AM -0700, Randal L. Schwartz wrote:
> >>
> >> > I have echo "ref: refs/remotes/origin/master" >.git/refs/heads/upstream
> >> > so that my daily update script can go:
> >> >
> >> > git-fetch
> >> > if [ repo is on master, and is not dirty ];
> >> > git-merge upstream
> >> > fi
> >> >
> >> > Yesterday that worked.
> >> >
> >> > Today I get a rash of:
> >> >
> >> > fatal: Couldn't find remote ref refs/remotes/origin/master
> >> >
> >> > from my git-fetch.
> >>
> >> Randal and I discussed this a bit on IRC, and it turns out not to be
> >> related to the 'upstream' symref. Instead, he had a broken
> >> branch.master.merge config that pointed to "refs/remotes/origin/master"
> >> (which you can see from his script above doesn't actually get used).
> >>
> >> So presumably the old git-fetch didn't care that the contents of
> >> branch.*.master didn't exist (it's just that nothing got marked for
> >> merging), but the one just merged from the db/fetch-pack topic does.
> >>
> >> Is this behavior change intentional?
> >
> > It's not exactly intentional; it's just that nobody seems to have tested
> > this particular misconfiguration. It should probably report an error
> > (since the configuration is, in fact, broken and potentially misleading),
> > but it probably shouldn't be fatal and certainly shouldn't be so
> > uninformative.
>
> How would we proceed from here, then?
>
> If you had "branch.master.merge = refs/heads/foobar", kept
> running happily, and suddenly the remote stopped carrying that
> foobar branch, you would get a configuration that uses
> nonexistent remote branch name, so this is not purely a
> configuration error on the fetcher's side.
True, although I'd consider that a matter of configuration rot rather than
it being an okay configuration; the user probably still needs to figure
out what happened to it and what to use instead. Maybe we want to output a
message to stderr (although higher than the die() used to be, so that we
can report the reason that it was looking for the missing remote ref).
> Older git used to enumerate remote tracking branches explicitly,
> and one of the remote.origin.fetch entries would have said
> "refs/heads/foobar:refs/remotes/origin/foobar", and that would
> have made git-fetch fail with the error, complaining that such a
> branch does not exist.
>
> You are suggesting that git-fetch should not fail if
> remote.origin.fetch is refs/heads/*:refs/remotes/origin/*
> wildcard, and I think I can agree with that; "git pull" however
> should notice and and exit with an error.
>
> Perhaps something like this?
That looks like what I was going to write when I got to it (although I
would have had the flag inverted, which is less git style, I guess).
Acked-By: Daniel Barkalow <barkalow@iabervon.org>
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH] Allow git-runstatus to limit its scope to a set of files/directories.
From: Michel Marti @ 2007-10-27 18:44 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0710271922340.4362@racer.site>
Johannes Schindelin wrote:
> On Sat, 27 Oct 2007, Michel Marti wrote:
>
>> Signed-off-by: Michel Marti <mma@objectxp.com>
>> ---
>> IMO, the next step should be to tweak git-status/git-commit: I suggest
>> introducing a new option '--what-if' to 'git-commit' that behaves like current
>> 'git-status [<path>...]' and in return stop 'git-status' from displaying
>> '[<path>...]' as "Changes to commit".
>
> I am not sure this is the correct way to go, since "git status" as a "git
> commit --dry-run" has worked well so far.
Maybe, but current git-status behaviour is somewhat illogical and I'm
pretty sure there are more than a few git-users that were puzzled after
calling "git-status some-dir" for the first time.
> Besides, I would like to see builtin-commit go in as soon as possible, and
> this patch would delay that.
Hmmm, why is that? The patch only touches git-runstatus, invoking
"git-status <path>" will behave as usual.
- Michel
^ permalink raw reply
* Re: [PATCH] Allow git-runstatus to limit its scope to a set of files/directories.
From: Johannes Schindelin @ 2007-10-27 18:24 UTC (permalink / raw)
To: Michel Marti; +Cc: git
In-Reply-To: <1193508519-14140-1-git-send-email-mma@objectxp.com>
Hi,
On Sat, 27 Oct 2007, Michel Marti wrote:
> Signed-off-by: Michel Marti <mma@objectxp.com>
> ---
> IMO, the next step should be to tweak git-status/git-commit: I suggest
> introducing a new option '--what-if' to 'git-commit' that behaves like current
> 'git-status [<path>...]' and in return stop 'git-status' from displaying
> '[<path>...]' as "Changes to commit".
I am not sure this is the correct way to go, since "git status" as a "git
commit --dry-run" has worked well so far.
Besides, I would like to see builtin-commit go in as soon as possible, and
this patch would delay that.
Ciao,
Dscho
^ permalink raw reply
* [PATCH] Allow git-runstatus to limit its scope to a set of files/directories.
From: Michel Marti @ 2007-10-27 18:08 UTC (permalink / raw)
To: git; +Cc: Michel Marti
In-Reply-To: <ffofbm@ger.gmane.org>
Signed-off-by: Michel Marti <mma@objectxp.com>
---
IMO, the next step should be to tweak git-status/git-commit: I suggest
introducing a new option '--what-if' to 'git-commit' that behaves like current
'git-status [<path>...]' and in return stop 'git-status' from displaying
'[<path>...]' as "Changes to commit".
Documentation/git-runstatus.txt | 6 +++++-
builtin-runstatus.c | 5 ++++-
wt-status.c | 13 ++++++++++++-
wt-status.h | 1 +
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-runstatus.txt b/Documentation/git-runstatus.txt
index dee5d0d..ddf83ae 100644
--- a/Documentation/git-runstatus.txt
+++ b/Documentation/git-runstatus.txt
@@ -8,7 +8,7 @@ git-runstatus - A helper for git-status and git-commit
SYNOPSIS
--------
-'git-runstatus' [--color|--nocolor] [--amend] [--verbose] [--untracked]
+'git-runstatus' [--color|--nocolor] [--amend] [--verbose] [--untracked] [<path>...]
DESCRIPTION
@@ -47,6 +47,10 @@ OPTIONS
option only its name and a trailing slash are displayed
for each untracked directory.
+<path>...::
+ The <path> parameters, when given, are used to limit
+ the status to the named path(s).
+
OUTPUT
------
diff --git a/builtin-runstatus.c b/builtin-runstatus.c
index 2db25c8..6acc92f 100644
--- a/builtin-runstatus.c
+++ b/builtin-runstatus.c
@@ -5,7 +5,7 @@
extern int wt_status_use_color;
static const char runstatus_usage[] =
-"git-runstatus [--color|--nocolor] [--amend] [--verbose] [--untracked]";
+"git-runstatus [--color|--nocolor] [--amend] [--verbose] [--untracked] [<path>...]";
int cmd_runstatus(int argc, const char **argv, const char *prefix)
{
@@ -16,6 +16,8 @@ int cmd_runstatus(int argc, const char **argv, const char *prefix)
wt_status_prepare(&s);
for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-')
+ break;
if (!strcmp(argv[i], "--color"))
wt_status_use_color = 1;
else if (!strcmp(argv[i], "--nocolor"))
@@ -32,6 +34,7 @@ int cmd_runstatus(int argc, const char **argv, const char *prefix)
usage(runstatus_usage);
}
+ s.pathspec = argc > i ? get_pathspec(prefix, argv+i) : NULL;
wt_status_print(&s);
return s.commitable ? 0 : 1;
}
diff --git a/wt-status.c b/wt-status.c
index 10ce6ee..e40e0d2 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -228,6 +228,7 @@ static void wt_status_print_updated(struct wt_status *s)
rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 100;
+ rev.prune_data = s->pathspec;
wt_read_cache(s);
run_diff_index(&rev, 1);
}
@@ -240,6 +241,7 @@ static void wt_status_print_changed(struct wt_status *s)
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_print_changed_cb;
rev.diffopt.format_callback_data = s;
+ rev.prune_data = s->pathspec;
wt_read_cache(s);
run_diff_files(&rev, 0);
}
@@ -248,7 +250,8 @@ static void wt_status_print_untracked(struct wt_status *s)
{
struct dir_struct dir;
const char *x;
- int i;
+ int i, specs;
+ char *seen;
int shown_header = 0;
memset(&dir, 0, sizeof(dir));
@@ -264,11 +267,19 @@ static void wt_status_print_untracked(struct wt_status *s)
if (excludes_file && file_exists(excludes_file))
add_excludes_from_file(&dir, excludes_file);
+ for (specs = 0; s->pathspec && s->pathspec[specs]; specs++)
+ /* nothing */;
+ if (specs)
+ seen = xcalloc(specs, 1);
+
read_directory(&dir, ".", "", 0, NULL);
for(i = 0; i < dir.nr; i++) {
/* check for matching entry, which is unmerged; lifted from
* builtin-ls-files:show_other_files */
struct dir_entry *ent = dir.entries[i];
+ if (specs &&
+ !match_pathspec(s->pathspec, ent->name, ent->len, 0, seen))
+ continue;
int pos = cache_name_pos(ent->name, ent->len);
struct cache_entry *ce;
if (0 <= pos)
diff --git a/wt-status.h b/wt-status.h
index cfea4ae..1153e87 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -15,6 +15,7 @@ struct wt_status {
int verbose;
int amend;
int untracked;
+ const char **pathspec;
/* These are computed during processing of the individual sections */
int commitable;
int workdir_dirty;
--
1.5.3.4.316.g8a37e
^ permalink raw reply related
* [PATCH] Remove outdated references to cogito in documentation
From: Dan McGee @ 2007-10-27 16:53 UTC (permalink / raw)
To: git; +Cc: Dan McGee
Signed-off-by: Dan McGee <dpmcgee@gmail.com>
---
Documentation/core-tutorial.txt | 10 ----------
Documentation/git-tools.txt | 3 ++-
2 files changed, 2 insertions(+), 11 deletions(-)
diff --git a/Documentation/core-tutorial.txt b/Documentation/core-tutorial.txt
index 6b2590d..58ac8c1 100644
--- a/Documentation/core-tutorial.txt
+++ b/Documentation/core-tutorial.txt
@@ -551,16 +551,6 @@ a bit more interesting.
With that, you should now be having some inkling of what git does, and
can explore on your own.
-[NOTE]
-Most likely, you are not directly using the core
-git Plumbing commands, but using Porcelain like Cogito on top
-of it. Cogito works a bit differently and you usually do not
-have to run `git-update-index` yourself for changed files (you
-do tell underlying git about additions and removals via
-`cg-add` and `cg-rm` commands). Just before you make a commit
-with `cg-commit`, Cogito figures out which files you modified,
-and runs `git-update-index` on them for you.
-
Tagging a version
-----------------
diff --git a/Documentation/git-tools.txt b/Documentation/git-tools.txt
index 10653ff..480c557 100644
--- a/Documentation/git-tools.txt
+++ b/Documentation/git-tools.txt
@@ -20,7 +20,8 @@ Alternative/Augmentative Porcelains
Cogito is a version control system layered on top of the git tree history
storage system. It aims at seamless user interface and ease of use,
providing generally smoother user experience than the "raw" Core GIT
- itself and indeed many other version control systems.
+ itself and indeed many other version control systems. Cogito is no longer
+ maintained as most of its functionality is now in core GIT.
- *pg* (http://www.spearce.org/category/projects/scm/pg/)
--
1.5.3.4
^ permalink raw reply related
* [PATCH 4/8] rev-parse: teach "git rev-parse --symbolic" to print the full ref name
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <1193503808519-git-send-email-prohaska@zib.de>
"git rev-parse --symbolic" used to return the ref name as it was
specified on the command line. This is changed to returning the
full matched ref name, i.e. "git rev-parse --symbolic master"
now typically returns "refs/heads/master".
Note, this changes output of an established command. It might
break existing setups. I checked that it does not break scripts
in git.git.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
builtin-rev-parse.c | 27 +++++++++++++++++----------
1 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 8d78b69..e64abeb 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -93,7 +93,7 @@ static void show(const char *arg)
}
/* Output a revision, only if filter allows it */
-static void show_rev(int type, const unsigned char *sha1, const char *name)
+static void show_rev(int type, const unsigned char *sha1, const char *name, const char* real_name)
{
if (!(filter & DO_REVS))
return;
@@ -102,7 +102,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
if (type != show_type)
putchar('^');
- if (symbolic && name)
+ if (symbolic && real_name)
+ show(real_name);
+ else if (symbolic && name)
show(name);
else if (abbrev)
show(find_unique_abbrev(sha1, abbrev));
@@ -131,7 +133,7 @@ static void show_default(void)
def = NULL;
if (!get_sha1(s, sha1)) {
- show_rev(NORMAL, sha1, s);
+ show_rev(NORMAL, sha1, s, 0);
return;
}
}
@@ -139,7 +141,7 @@ static void show_default(void)
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
- show_rev(NORMAL, sha1, refname);
+ show_rev(NORMAL, sha1, refname, 0);
return 0;
}
@@ -187,8 +189,8 @@ static int try_difference(const char *arg)
if (dotdot == arg)
this = "HEAD";
if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
- show_rev(NORMAL, end, next);
- show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
+ show_rev(NORMAL, end, next, 0);
+ show_rev(symmetric ? NORMAL : REVERSED, sha1, this, 0);
if (symmetric) {
struct commit_list *exclude;
struct commit *a, *b;
@@ -198,7 +200,7 @@ static int try_difference(const char *arg)
while (exclude) {
struct commit_list *n = exclude->next;
show_rev(REVERSED,
- exclude->item->object.sha1,NULL);
+ exclude->item->object.sha1, NULL, 0);
free(exclude);
exclude = n;
}
@@ -213,6 +215,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
int i, as_is = 0, verify = 0;
unsigned char sha1[20];
+ char* real_name = 0;
git_config(git_default_config);
@@ -393,12 +396,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
/* Not a flag argument */
if (try_difference(arg))
continue;
- if (!get_sha1(arg, sha1)) {
- show_rev(NORMAL, sha1, arg);
+ if (!get_sha1_with_real_ref(arg, sha1, &real_name)) {
+ show_rev(NORMAL, sha1, arg, real_name);
+ if(real_name) {
+ free(real_name);
+ real_name = 0;
+ }
continue;
}
if (*arg == '^' && !get_sha1(arg+1, sha1)) {
- show_rev(REVERSED, sha1, arg+1);
+ show_rev(REVERSED, sha1, arg+1, 0);
continue;
}
as_is = 1;
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 1/8] push: change push to fail if short ref name does not exist
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <119350380778-git-send-email-prohaska@zib.de>
You can use a branch's shortname to push it. Push used to create
the branch on the remote side if it did not yet exist. If you
specified the wrong branch accidentally it was created. A safety
valve that pushes only existing branches may help to avoid
errors.
This commit changes push to fail if the remote ref does not yet
exist and the refspec does not start with refs/. Remote refs must
explicitly be created with their full name.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
remote.c | 5 +++--
t/t5516-fetch-push.sh | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/remote.c b/remote.c
index 170015a..ec992c9 100644
--- a/remote.c
+++ b/remote.c
@@ -611,6 +611,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
struct ref *matched_src, *matched_dst;
const char *dst_value = rs->dst;
+ const char * const orig_dst_value = rs->dst ? rs->dst : rs->src;
if (rs->pattern)
return errs;
@@ -647,12 +648,12 @@ static int match_explicit(struct ref *src, struct ref *dst,
case 1:
break;
case 0:
- if (!memcmp(dst_value, "refs/", 5))
+ if (!memcmp(orig_dst_value , "refs/", 5))
matched_dst = make_linked_ref(dst_value, dst_tail);
else
error("dst refspec %s does not match any "
"existing ref on the remote and does "
- "not start with refs/.", dst_value);
+ "not start with refs/.", orig_dst_value);
break;
default:
matched_dst = NULL;
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 4fbd5b1..5ba09e2 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -126,6 +126,36 @@ test_expect_success 'push with wildcard' '
)
'
+test_expect_success 'push nonexisting (1)' '
+
+ mk_test &&
+ if git push testrepo master
+ then
+ echo "Oops, should have failed"
+ false
+ fi
+
+'
+
+test_expect_success 'push nonexisting (2)' '
+
+ mk_test &&
+ if git push testrepo heads/master
+ then
+ echo "Oops, should have failed"
+ false
+ fi
+
+'
+
+test_expect_success 'push nonexisting (3)' '
+
+ mk_test &&
+ git push testrepo refs/heads/master &&
+ check_push_result $the_commit heads/master
+
+'
+
test_expect_success 'push with matching heads' '
mk_test heads/master &&
@@ -225,7 +255,7 @@ test_expect_success 'push with colon-less refspec (3)' '
git tag -d frotz
fi &&
git branch -f frotz master &&
- git push testrepo frotz &&
+ git push testrepo refs/heads/frotz &&
check_push_result $the_commit heads/frotz &&
test 1 = $( cd testrepo && git show-ref | wc -l )
'
@@ -238,7 +268,7 @@ test_expect_success 'push with colon-less refspec (4)' '
git branch -D frotz
fi &&
git tag -f frotz &&
- git push testrepo frotz &&
+ git push testrepo refs/tags/frotz &&
check_push_result $the_commit tags/frotz &&
test 1 = $( cd testrepo && git show-ref | wc -l )
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 3/8] add get_sha1_with_real_ref() returning full name of ref on demand
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <11935038081650-git-send-email-prohaska@zib.de>
Deep inside get_sha1() the name of the requested ref is matched
according to the rules documented in git-rev-parse. This patch
introduces a function that returns the full name of the matched
ref to the outside.
For example 'master' is typically returned as 'refs/heads/master'.
The new function can be used by "git rev-parse" to print the full
name of the matched ref and can be used by "git send-pack" to expand
a local ref to its full name.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
cache.h | 1 +
sha1_name.c | 38 +++++++++++++++++++++++++++-----------
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/cache.h b/cache.h
index 27485d3..726948b 100644
--- a/cache.h
+++ b/cache.h
@@ -401,6 +401,7 @@ static inline unsigned int hexval(unsigned char c)
extern int get_sha1(const char *str, unsigned char *sha1);
extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
+extern int get_sha1_with_real_ref(const char *str, unsigned char *sha1, char **real_ref);
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/sha1_name.c b/sha1_name.c
index 2d727d5..b820909 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -306,7 +306,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
return logs_found;
}
-static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
+static int get_sha1_basic(const char *str, int len, unsigned char *sha1, char **real_ref_out)
{
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
char *real_ref = NULL;
@@ -378,17 +378,21 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
}
}
- free(real_ref);
+ if (real_ref_out) {
+ *real_ref_out = real_ref;
+ } else {
+ free(real_ref);
+ }
return 0;
}
-static int get_sha1_1(const char *name, int len, unsigned char *sha1);
+static int get_sha1_1(const char *name, int len, unsigned char *sha1, char **real_ref);
static int get_parent(const char *name, int len,
unsigned char *result, int idx)
{
unsigned char sha1[20];
- int ret = get_sha1_1(name, len, sha1);
+ int ret = get_sha1_1(name, len, sha1, /*real_ref=*/ 0);
struct commit *commit;
struct commit_list *p;
@@ -418,7 +422,7 @@ static int get_nth_ancestor(const char *name, int len,
unsigned char *result, int generation)
{
unsigned char sha1[20];
- int ret = get_sha1_1(name, len, sha1);
+ int ret = get_sha1_1(name, len, sha1, /*real_ref=*/ 0);
if (ret)
return ret;
@@ -471,7 +475,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
else
return -1;
- if (get_sha1_1(name, sp - name - 2, outer))
+ if (get_sha1_1(name, sp - name - 2, outer, /*real_ref=*/ 0))
return -1;
o = parse_object(outer);
@@ -531,7 +535,7 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
return -1;
}
-static int get_sha1_1(const char *name, int len, unsigned char *sha1)
+static int get_sha1_1(const char *name, int len, unsigned char *sha1, char **real_ref)
{
int ret, has_suffix;
const char *cp;
@@ -569,7 +573,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
if (!ret)
return 0;
- ret = get_sha1_basic(name, len, sha1);
+ ret = get_sha1_basic(name, len, sha1, real_ref);
if (!ret)
return 0;
@@ -651,14 +655,14 @@ 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)
+int get_sha1_with_mode_real_ref(const char *name, unsigned char *sha1, unsigned *mode, char** real_ref)
{
int ret, bracket_depth;
int namelen = strlen(name);
const char *cp;
*mode = S_IFINVALID;
- ret = get_sha1_1(name, namelen, sha1);
+ ret = get_sha1_1(name, namelen, sha1, real_ref);
if (!ret)
return ret;
/* sha1:path --> object name of path in ent sha1
@@ -709,9 +713,21 @@ 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))
+ if (!get_sha1_1(name, cp-name, tree_sha1, real_ref))
return get_tree_entry(tree_sha1, cp+1, sha1,
mode);
}
return ret;
}
+
+int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
+{
+ return get_sha1_with_mode_real_ref(name, sha1, mode, 0);
+}
+
+int get_sha1_with_real_ref(const char *name, unsigned char *sha1, char **real_ref)
+{
+ unsigned unused;
+ return get_sha1_with_mode_real_ref(name, sha1, &unused, real_ref);
+}
+
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 6/8] add ref_cmp_full_short() comparing full ref name with a short name
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <11935038084055-git-send-email-prohaska@zib.de>
ref_cmp_full_short(full_name, short_name) expands short_name according
to the rules documented in git-rev-parse and compares the expanded
name with full_name. It reports a match by returning 0.
This function makes the rules for resolving refs to sha1s available
for string comparison. Before this change, the rules were buried in
get_sha1*() and dwim_ref().
ref_cmp_full_short() will be used for matching refspecs in git-send-pack.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
cache.h | 1 +
sha1_name.c | 14 ++++++++++++++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/cache.h b/cache.h
index 726948b..e1385ac 100644
--- a/cache.h
+++ b/cache.h
@@ -406,6 +406,7 @@ 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);
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
+extern int ref_cmp_full_short(const char *full_name, const char *short_name);
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
diff --git a/sha1_name.c b/sha1_name.c
index b820909..2a1e093 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -249,6 +249,20 @@ static const char *ref_fmt[] = {
NULL
};
+int ref_cmp_full_short(const char *full_name, const char *short_name)
+{
+ const char **p;
+ const int short_name_len = strlen(short_name);
+
+ for (p = ref_fmt; *p; p++) {
+ if (strcmp(full_name, mkpath(*p, short_name_len, short_name)) == 0) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
{
const char **p, *r;
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 7/8] push: use same rules as git-rev-parse to resolve refspecs
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <11935038084130-git-send-email-prohaska@zib.de>
This commit changes the rules for resolving refspecs to match the
rules for resolving refs in rev-parse. git-rev-parse uses clear rules
to resolve a short ref to its full name, which are well documented.
The rules for resolving refspecs documented in git-send-pack were
less strict and harder to understand. This commit replaces them by
the rules of git-rev-parse.
The unified rules are easier to understand and better resolve ambiguous
cases. You can now push from a repository containing several branches
ending on the same short name.
Note, this breaks existing setups. For example "master" will no longer
resolve to "origin/master".
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
Documentation/git-send-pack.txt | 4 +++-
remote.c | 5 +----
t/t5516-fetch-push.sh | 12 +++++++++++-
3 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 01495df..08bcc25 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -91,7 +91,9 @@ Each pattern pair consists of the source side (before the colon)
and the destination side (after the colon). The ref to be
pushed is determined by finding a match that matches the source
side, and where it is pushed is determined by using the
-destination side.
+destination side. The rules used to match a ref are the same
+rules used by gitlink:git-rev-parse[1] to resolve a symbolic ref
+name.
- It is an error if <src> does not match exactly one of the
local refs.
diff --git a/remote.c b/remote.c
index 1c96659..176457c 100644
--- a/remote.c
+++ b/remote.c
@@ -519,10 +519,7 @@ static int count_refspec_match(const char *pattern,
char *name = refs->name;
int namelen = strlen(name);
- if (namelen < patlen ||
- memcmp(name + namelen - patlen, pattern, patlen))
- continue;
- if (namelen != patlen && name[namelen - patlen - 1] != '/')
+ if (ref_cmp_full_short(name, pattern))
continue;
/* A match is "weak" if it is with refs outside
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 0ff791a..9ec8216 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -183,11 +183,21 @@ test_expect_success 'push with no ambiguity (1)' '
test_expect_success 'push with no ambiguity (2)' '
mk_test remotes/origin/master &&
- git push testrepo master:master &&
+ git push testrepo master:origin/master &&
check_push_result $the_commit remotes/origin/master
'
+test_expect_success 'push with colon-less refspec, no ambiguity' '
+
+ mk_test heads/master heads/t/master &&
+ git branch -f t/master master &&
+ git push testrepo master &&
+ check_push_result $the_commit heads/master &&
+ check_push_result $the_first_commit heads/t/master
+
+'
+
test_expect_success 'push with weak ambiguity (1)' '
mk_test heads/master remotes/origin/master &&
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 8/8] push: teach push to be quiet if local ref is strict subset of remote ref
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <11935038083116-git-send-email-prohaska@zib.de>
git push reports errors if a remote ref is not a strict subset
of a local ref. The push wouldn't be a fast-forward and is
therefore refused. This is in general a good idea.
But these messages can be annoying if you work with a shared
remote repository. Branches at the remote may have advanced and
you haven't pulled to all of your local branches. In this
situation, local branches may be strict subsets of the remote
heads. Pushing such branches wouldn't add any information to the
remote. It would only reset the remote to an ancestor. A merge
between the remote and the local branch is not very interested
either because it would just be a fast forward of the local
branch. In these cases you're not interested in the error
message.
This commit teaches git push to be quiet if the local is a strict
subset of the remote and no refspec is explicitly specified on
the command line. If the --verbose flag is used a "note:" is
printed for each ignored branch.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
send-pack.c | 61 +++++++++++++++++++++++++++++++++++++------------
t/t5516-fetch-push.sh | 44 +++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 15 deletions(-)
diff --git a/send-pack.c b/send-pack.c
index 77acae1..b95bed9 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -259,24 +259,55 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha
!will_delete_ref &&
!is_null_sha1(ref->old_sha1) &&
!ref->force) {
- if (!has_sha1_file(ref->old_sha1) ||
- !ref_newer(ref->peer_ref->new_sha1,
- ref->old_sha1)) {
- /* We do not have the remote ref, or
- * we know that the remote ref is not
- * an ancestor of what we are trying to
- * push. Either way this can be losing
- * commits at the remote end and likely
- * we were not up to date to begin with.
+ if (!has_sha1_file(ref->old_sha1)) {
+ /* We do not have the remote ref.
+ * This can be losing commits at
+ * the remote end.
*/
- error("remote '%s' is not a strict "
- "subset of local ref '%s'. "
- "maybe you are not up-to-date and "
- "need to pull first?",
- ref->name,
- ref->peer_ref->name);
+ error("You don't have the commit"
+ "for the remote ref '%s'."
+ "This may cause losing commits"
+ "that cannot be recovered.",
+ ref->name);
ret = -2;
continue;
+ } else if (!ref_newer(ref->peer_ref->new_sha1,
+ ref->old_sha1)) {
+ /* We know that the remote ref is not
+ * an ancestor of what we are trying to
+ * push. This can be losing commits at
+ * the remote end and likely we were not
+ * up to date to begin with.
+ *
+ * Therefore, we don't push.
+ *
+ * If no explicit refspec was passed on the
+ * commandline, then we only report an error
+ * if the local is not a strict subset of the
+ * remote. If the local is a strict subset we
+ * don't have new commits for the remote.
+ * Pulling and pushing wouldn't add anything to
+ * the remote.
+ *
+ */
+ if (nr_refspec ||
+ !ref_newer(ref->old_sha1, ref->peer_ref->new_sha1)) {
+ error("remote '%s' is not a strict "
+ "subset of local ref '%s'. "
+ "maybe you are not up-to-date and "
+ "need to pull first?",
+ ref->name,
+ ref->peer_ref->name);
+ ret = -2;
+ } else if (verbose) {
+ fprintf(stderr,
+ "note: ignoring local ref '%s' "
+ "because it is a strict "
+ "subset of remote '%s'.\n",
+ ref->peer_ref->name,
+ ref->name);
+ }
+ continue;
}
}
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 9ec8216..c8493f9 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -331,4 +331,48 @@ test_expect_success 'push with dry-run' '
check_push_result $old_commit heads/master
'
+test_expect_success 'push with local is strict subset (must not report error)' '
+
+ mk_test heads/foo &&
+ git push testrepo $the_commit:refs/heads/foo &&
+ git branch -f foo $old_commit &&
+ if git push testrepo 2>&1 | grep ^error
+ then
+ echo "Oops, should not report error"
+ false
+ fi
+
+'
+
+test_expect_success 'push with explicit refname, local is strict subset (must report error)' '
+
+ mk_test heads/foo &&
+ git push testrepo $the_commit:refs/heads/foo &&
+ git branch -f foo $old_commit &&
+ if ! git push testrepo foo 2>&1 | grep ^error
+ then
+ echo "Oops, should have reported error"
+ false
+ fi
+
+'
+
+test_expect_success 'push with neither local nor remote is strict subset (must report error)' '
+
+ mk_test heads/foo &&
+ git push testrepo $the_commit:refs/heads/foo &&
+ git branch -f foo $old_commit &&
+ git checkout foo &&
+ : >path3 &&
+ git add path3 &&
+ test_tick &&
+ git commit -a -m branched &&
+ if ! git push testrepo 2>&1 | grep ^error
+ then
+ echo "Oops, should have reported error"
+ false
+ fi
+
+'
+
test_done
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 2/8] push: teach push new flag --create
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <11935038081211-git-send-email-prohaska@zib.de>
Refs that do not start with 'refs/' will only be created
at the remote if --create is used.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
Documentation/git-http-push.txt | 6 ++++++
Documentation/git-push.txt | 8 +++++++-
Documentation/git-send-pack.txt | 14 +++++++++++---
builtin-push.c | 6 +++++-
http-push.c | 9 +++++++--
remote.c | 18 +++++++++++++-----
remote.h | 2 +-
send-pack.c | 9 +++++++--
t/t5516-fetch-push.sh | 8 ++++++++
transport.c | 8 ++++++--
transport.h | 1 +
11 files changed, 72 insertions(+), 17 deletions(-)
diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt
index 3a69b71..8753611 100644
--- a/Documentation/git-http-push.txt
+++ b/Documentation/git-http-push.txt
@@ -30,6 +30,12 @@ OPTIONS
the remote repository can lose commits; use it with
care.
+\--create::
+ Usually, the command refuses to create a remote ref that is
+ not specified by its full name, i.e. starting with 'refs/'.
+ This flag tells the command to create the remote ref under
+ the full name of the local matching ref.
+
--dry-run::
Do everything except actually send the updates.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index e5dd4c1..67b354b 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git-push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
+'git-push' [--all] [--dry-run] [--create] [--tags] [--receive-pack=<git-receive-pack>]
[--repo=all] [-f | --force] [-v] [<repository> <refspec>...]
DESCRIPTION
@@ -86,6 +86,12 @@ the remote repository.
This flag disables the check. This can cause the
remote repository to lose commits; use it with care.
+\--create::
+ Usually, the command refuses to create a remote ref that is
+ not specified by its full name, i.e. starting with 'refs/'.
+ This flag tells the command to create the remote ref under
+ the full name of the local matching ref.
+
\--repo=<repo>::
When no repository is specified the command defaults to
"origin"; this overrides it.
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 2fa01d4..01495df 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -44,6 +44,12 @@ OPTIONS
the remote repository can lose commits; use it with
care.
+\--create::
+ Usually, the command refuses to create a remote ref that is
+ not specified by its full name, i.e. starting with 'refs/'.
+ This flag tells the command to create the remote ref under
+ the full name of the local matching ref.
+
\--verbose::
Run verbosely.
@@ -97,9 +103,11 @@ destination side.
* it has to start with "refs/"; <dst> is used as the
destination literally in this case.
- * <src> == <dst> and the ref that matched the <src> must not
- exist in the set of remote refs; the ref matched <src>
- locally is used as the name of the destination.
+ * Only <src> is specified and the ref that matched
+ <src> must not exist in the set of remote refs;
+ and the '--create' flag is used;
+ the ref matched <src> locally is used as the name of
+ the destination.
Without '--force', the <src> ref is stored at the remote only if
<dst> does not exist, or <dst> is a proper subset (i.e. an
diff --git a/builtin-push.c b/builtin-push.c
index 4b39ef3..4ab1401 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -8,7 +8,7 @@
#include "remote.h"
#include "transport.h"
-static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
+static const char push_usage[] = "git-push [--all] [--dry-run] [--create] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
static int thin, verbose;
static const char *receivepack;
@@ -113,6 +113,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
flags |= TRANSPORT_PUSH_DRY_RUN;
continue;
}
+ if (!strcmp(arg, "--create")) {
+ flags |= TRANSPORT_PUSH_CREATE;
+ continue;
+ }
if (!strcmp(arg, "--tags")) {
add_refspec("refs/tags/*");
continue;
diff --git a/http-push.c b/http-push.c
index c02a3af..4ad9f26 100644
--- a/http-push.c
+++ b/http-push.c
@@ -13,7 +13,7 @@
#include <expat.h>
static const char http_push_usage[] =
-"git-http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
+"git-http-push [--all] [--dry-run] [--create] [--force] [--verbose] <remote> [<head>...]\n";
#ifndef XML_STATUS_OK
enum XML_Status {
@@ -81,6 +81,7 @@ static int push_verbosely;
static int push_all;
static int force_all;
static int dry_run;
+static int create;
static struct object_list *objects;
@@ -2307,6 +2308,10 @@ int main(int argc, char **argv)
dry_run = 1;
continue;
}
+ if (!strcmp(arg, "--create")) {
+ create = 1;
+ continue;
+ }
if (!strcmp(arg, "--verbose")) {
push_verbosely = 1;
continue;
@@ -2389,7 +2394,7 @@ int main(int argc, char **argv)
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspec, refspec, push_all))
+ nr_refspec, refspec, push_all, create))
return -1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
diff --git a/remote.c b/remote.c
index ec992c9..8908a19 100644
--- a/remote.c
+++ b/remote.c
@@ -606,7 +606,7 @@ static struct ref *make_linked_ref(const char *name, struct ref ***tail)
static int match_explicit(struct ref *src, struct ref *dst,
struct ref ***dst_tail,
struct refspec *rs,
- int errs)
+ int errs, int create)
{
struct ref *matched_src, *matched_dst;
@@ -650,6 +650,14 @@ static int match_explicit(struct ref *src, struct ref *dst,
case 0:
if (!memcmp(orig_dst_value , "refs/", 5))
matched_dst = make_linked_ref(dst_value, dst_tail);
+ else if (!memcmp(dst_value, "refs/", 5))
+ if (create)
+ matched_dst = make_linked_ref(dst_value, dst_tail);
+ else
+ error("dst refspec %s does not match any "
+ "existing ref on the remote. "
+ "If you want to create is use --create.",
+ orig_dst_value);
else
error("dst refspec %s does not match any "
"existing ref on the remote and does "
@@ -677,11 +685,11 @@ static int match_explicit(struct ref *src, struct ref *dst,
static int match_explicit_refs(struct ref *src, struct ref *dst,
struct ref ***dst_tail, struct refspec *rs,
- int rs_nr)
+ int rs_nr, int create)
{
int i, errs;
for (i = errs = 0; i < rs_nr; i++)
- errs |= match_explicit(src, dst, dst_tail, &rs[i], errs);
+ errs |= match_explicit(src, dst, dst_tail, &rs[i], errs, create);
return -errs;
}
@@ -711,12 +719,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
* without thinking.
*/
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, char **refspec, int all)
+ int nr_refspec, char **refspec, int all, int create)
{
struct refspec *rs =
parse_ref_spec(nr_refspec, (const char **) refspec);
- if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
+ if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec, create))
return -1;
/* pick the remainder */
diff --git a/remote.h b/remote.h
index c62636d..7d731b1 100644
--- a/remote.h
+++ b/remote.h
@@ -57,7 +57,7 @@ void ref_remove_duplicates(struct ref *ref_map);
struct refspec *parse_ref_spec(int nr_refspec, const char **refspec);
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, char **refspec, int all);
+ int nr_refspec, char **refspec, int all, int create);
/*
* Given a list of the remote refs and the specification of things to
diff --git a/send-pack.c b/send-pack.c
index e9b9a39..77acae1 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -7,7 +7,7 @@
#include "remote.h"
static const char send_pack_usage[] =
-"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
+"git-send-pack [--all] [--dry-run] [--create] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive.";
static const char *receivepack = "git-receive-pack";
static int verbose;
@@ -15,6 +15,7 @@ static int send_all;
static int force_update;
static int use_thin_pack;
static int dry_run;
+static int create;
/*
* Make a pack stream and spit it out into file descriptor fd
@@ -201,7 +202,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspec, refspec, send_all))
+ nr_refspec, refspec, send_all, create))
return -1;
if (!remote_refs) {
@@ -398,6 +399,10 @@ int main(int argc, char **argv)
dry_run = 1;
continue;
}
+ if (!strcmp(arg, "--create")) {
+ create = 1;
+ continue;
+ }
if (!strcmp(arg, "--force")) {
force_update = 1;
continue;
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 5ba09e2..42ca0ff 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -156,6 +156,14 @@ test_expect_success 'push nonexisting (3)' '
'
+test_expect_success 'push nonexisting (4)' '
+
+ mk_test &&
+ git push testrepo --create master &&
+ check_push_result $the_commit heads/master
+
+'
+
test_expect_success 'push with matching heads' '
mk_test heads/master &&
diff --git a/transport.c b/transport.c
index 400af71..fbdbd0d 100644
--- a/transport.c
+++ b/transport.c
@@ -385,7 +385,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
int argc;
int err;
- argv = xmalloc((refspec_nr + 11) * sizeof(char *));
+ argv = xmalloc((refspec_nr + 12) * sizeof(char *));
argv[0] = "http-push";
argc = 1;
if (flags & TRANSPORT_PUSH_ALL)
@@ -394,6 +394,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
argv[argc++] = "--force";
if (flags & TRANSPORT_PUSH_DRY_RUN)
argv[argc++] = "--dry-run";
+ if (flags & TRANSPORT_PUSH_CREATE)
+ argv[argc++] = "--create";
argv[argc++] = transport->url;
while (refspec_nr--)
argv[argc++] = *refspec++;
@@ -658,7 +660,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
int argc;
int err;
- argv = xmalloc((refspec_nr + 11) * sizeof(char *));
+ argv = xmalloc((refspec_nr + 12) * sizeof(char *));
argv[0] = "send-pack";
argc = 1;
if (flags & TRANSPORT_PUSH_ALL)
@@ -667,6 +669,8 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
argv[argc++] = "--force";
if (flags & TRANSPORT_PUSH_DRY_RUN)
argv[argc++] = "--dry-run";
+ if (flags & TRANSPORT_PUSH_CREATE)
+ argv[argc++] = "--create";
if (data->receivepack) {
char *rp = xmalloc(strlen(data->receivepack) + 16);
sprintf(rp, "--receive-pack=%s", data->receivepack);
diff --git a/transport.h b/transport.h
index df12ea7..1d6a926 100644
--- a/transport.h
+++ b/transport.h
@@ -30,6 +30,7 @@ struct transport {
#define TRANSPORT_PUSH_ALL 1
#define TRANSPORT_PUSH_FORCE 2
#define TRANSPORT_PUSH_DRY_RUN 4
+#define TRANSPORT_PUSH_CREATE 8
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* [PATCH 0/8 v2] improve push's refspec handling
From: Steffen Prohaska @ 2007-10-27 16:49 UTC (permalink / raw)
To: git
This patch series improves the refspec handling in push.
It is a replacement for the series in sp/push-refspec
(666df53d6868bf56ca6c9ed0a927d612c67fe68c).
The series addresses some issues that were recently discussed on the
mailing list.
- creating remote refs requires a more explicit command [1].
- the current branch can be pushed as "git push HEAD" [2].
- matching of refs use same rules as git rev-parse [3].
- annoying error messages when working with shared repos are supressed [4].
[1] http://marc.info/?l=git&m=119286893014690&w=2
[2] http://marc.info/?l=git&m=119089831513994&w=2
[3] http://marc.info/?l=git&m=119224567631084&w=2
[4] http://marc.info/?t=119305127000001&r=1&w=2
Note, existing setups may break. Therefore, we need to decide if this
series can be applied before git 1.6.
All tests pass.
Steffen
Documentation/git-http-push.txt | 6 ++
Documentation/git-push.txt | 8 ++-
Documentation/git-send-pack.txt | 18 ++++-
builtin-push.c | 6 ++-
builtin-rev-parse.c | 27 +++++---
cache.h | 2 +
http-push.c | 9 ++-
remote.c | 41 ++++++++----
remote.h | 2 +-
send-pack.c | 70 ++++++++++++++++-----
sha1_name.c | 52 +++++++++++++----
t/t5516-fetch-push.sh | 127 ++++++++++++++++++++++++++++++++++++++-
transport.c | 8 ++-
transport.h | 1 +
14 files changed, 311 insertions(+), 66 deletions(-)
[PATCH 1/8] push: change push to fail if short ref name does not exist
[PATCH 2/8] push: teach push new flag --create
these two should be kept together.
[PATCH 3/8] add get_sha1_with_real_ref() returning full name of ref on demand
[PATCH 4/8] rev-parse: teach "git rev-parse --symbolic" to print the full ref name
This one is a bit off-topic and could be skipped.
[PATCH 5/8] push, send-pack: support pushing HEAD to real ref name
[PATCH 6/8] add ref_cmp_full_short() comparing full ref name with a short name
[PATCH 7/8] push: use same rules as git-rev-parse to resolve refspecs
[PATCH 8/8] push: teach push to be quiet if local ref is strict subset of remote ref
^ permalink raw reply
* [PATCH 5/8] push, send-pack: support pushing HEAD to real ref name
From: Steffen Prohaska @ 2007-10-27 16:50 UTC (permalink / raw)
To: git; +Cc: Steffen Prohaska
In-Reply-To: <11935038083369-git-send-email-prohaska@zib.de>
This teaches "push <remote> HEAD" to resolve HEAD on the local
side to its real ref name, e.g. refs/heads/master, and then
use the real ref name on the remote side to search a matching
remote ref.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
remote.c | 13 ++++++++++---
t/t5516-fetch-push.sh | 29 +++++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/remote.c b/remote.c
index 8908a19..1c96659 100644
--- a/remote.c
+++ b/remote.c
@@ -575,6 +575,8 @@ static struct ref *try_explicit_object_name(const char *name)
unsigned char sha1[20];
struct ref *ref;
int len;
+ char *real_name = 0;
+ const char *best_name;
if (!*name) {
ref = alloc_ref(20);
@@ -582,12 +584,17 @@ static struct ref *try_explicit_object_name(const char *name)
hashclr(ref->new_sha1);
return ref;
}
- if (get_sha1(name, sha1))
+ if (get_sha1_with_real_ref(name, sha1, &real_name))
return NULL;
- len = strlen(name) + 1;
+ best_name = real_name ? real_name : name;
+ len = strlen(best_name) + 1;
ref = alloc_ref(len);
- memcpy(ref->name, name, len);
+ memcpy(ref->name, best_name, len);
hashcpy(ref->new_sha1, sha1);
+
+ if (real_name) {
+ free(real_name);
+ }
return ref;
}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 42ca0ff..0ff791a 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -282,6 +282,35 @@ test_expect_success 'push with colon-less refspec (4)' '
'
+test_expect_success 'push with HEAD' '
+
+ mk_test heads/master &&
+ git push testrepo HEAD &&
+ check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'push with HEAD (--create)' '
+
+ mk_test &&
+ git push --create testrepo HEAD &&
+ check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'push with HEAD nonexisting at remote' '
+
+ mk_test heads/master &&
+ git checkout -b local master &&
+ if git push testrepo HEAD
+ then
+ echo "Oops, should have failed"
+ false
+ else
+ check_push_result $the_first_commit heads/master
+ fi
+'
+
test_expect_success 'push with dry-run' '
mk_test heads/master &&
--
1.5.3.4.1261.g626eb
^ permalink raw reply related
* Remove reference to cogito from core-tutorial.txt?
From: Sergei Organov @ 2007-10-27 15:10 UTC (permalink / raw)
To: git
Hello,
In Documentation/core-tutorial.txt at line 554 there is a note that
begins with
"Most likely, you are not directly using the core git Plumbing
commands, but using Porcelain like Cogito..."
As stated on <http://git.or.cz/index.html>, "Cogito was a popular
version control system on top of Git, aiming at seamless user interface
and ease of use. It provided much better user interface in the past days
of Git but by now it is mostly obsolete and currently unmaintained."
I think it's not a good idea to have this in the tutorial. Should this
entire note be removed, or rewritten using git porcelain commands? If
the former, I can make a patch, if the latter, I'm afraid I'm not yet
comfortable enough with git to do it right.
--
Sergei.
^ permalink raw reply
* [MinGW PATCH] Rework quote_arg()
From: Nguyễn Thái Ngọc Duy @ 2007-10-27 13:30 UTC (permalink / raw)
To: git, Johannes Sixt
MS Windows command line is handled in a weird way. This patch addresses:
- Quote empty arguments
- Only escape backslashes and double quotation marks inside quoted arguments
- Quote arguments if they have asterisk or question marks to prevent expansion
The last one is not documented in the link provided in the patch. I encountered
that behavior on cmd.exe, Windows XP. MSYS not tested.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
compat/mingw.c | 31 ++++++++++++++++++++++++++++---
1 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/compat/mingw.c b/compat/mingw.c
index 22b5e10..90dc080 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -303,6 +303,7 @@ void openlog(const char *ident, int option, int facility)
{
}
+/* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx (Parsing C++ Command-Line Arguments */
static const char *quote_arg(const char *arg)
{
/* count chars to quote */
@@ -310,11 +311,23 @@ static const char *quote_arg(const char *arg)
int force_quotes = 0;
char *q, *d;
const char *p = arg;
+ if (!*p) force_quotes = 1;
while (*p) {
- if (isspace(*p))
+ if (isspace(*p) || *p == '*' || *p == '?')
force_quotes = 1;
- else if (*p == '"' || *p == '\\')
+ else if (*p == '"')
n++;
+ else if (*p == '\\') {
+ int count = 0;
+ while (*p == '\\') {
+ count++;
+ p++;
+ len++;
+ }
+ if (*p == '"')
+ n += count*2 + 1;
+ continue;
+ }
len++;
p++;
}
@@ -325,8 +338,20 @@ static const char *quote_arg(const char *arg)
d = q = xmalloc(len+n+3);
*d++ = '"';
while (*arg) {
- if (*arg == '"' || *arg == '\\')
+ if (*arg == '"')
*d++ = '\\';
+ else if (*arg == '\\') {
+ int count = 0;
+ while (*arg == '\\') {
+ count++;
+ *d++ = *arg++;
+ }
+ if (*arg == '"') {
+ while (count-- > 0)
+ *d++ = '\\';
+ *d++ = '\\';
+ }
+ }
*d++ = *arg++;
}
*d++ = '"';
--
1.5.3.rc4.3.gab089
^ permalink raw reply related
* git-show-branch doesn't work as advertised?
From: Sergei Organov @ 2007-10-27 13:26 UTC (permalink / raw)
To: git
Hello,
I'm rather new to git. I'm reading Documentation/core-tutorial.txt from
git repository cloned yesterday [no, it's not the first git manual I
read], and I'm stuck at the example beginning at line 938 of the
tutorial:
------------------------------------------------
$ git show-branch --topo-order master mybranch
* [master] Merge work in mybranch
! [mybranch] Some work.
--
- [master] Merge work in mybranch
*+ [mybranch] Some work.
------------------------------------------------
The problem is that even though the output of git matches the above
output (after I've replayed all the commands to this point), both the
state of the repo and the text below the example in the tutorial suggest
that one commit is missing from the output. In particular, the tutorial
says: "Three commits are shown along with their log messages." and
later "'master~1' is the first parent of 'master' branch head.", while
there are only 2 commits shown and there is no 'master~1' in the output.
The behavior is the same with git version 1.5.2.2 and 1.5.3.4.
For reference, from gitk output, the history looks like this:
. [master]
. o Merge work in mybranch
. |\[mybranch]
. | o Some work
. | |
. o | Some fun
. \|
. o Commit message
. |
. o Initial commit
Why "[master~1] Some fun." is not shown by git-show-branch?
Another issue. After above confusion I turned to the manual page and
decided to try --independent option, expecting an output similar to the
above, but missing all the common commits. However, to my surprise I've
got just:
$ git show-branch --topo-order --independent master mybranch
715ec06a744a801237c7233f3fb87ad583653c3a
instead. Nowhere the manual page says that this particular option
changes the format of the output so dramatically. And back to the first
issue, there is still only 1 commit shown, while it seems there should
be 2 of them, one from master, and one from mybranch.
--
Sergei.
^ permalink raw reply
* Re: [PATCH] Add test case for running from a subdirectory with GIT_WORK_TREE
From: Johannes Schindelin @ 2007-10-27 13:27 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <fcaeb9bf0710270557n48a01ba2w3a89f65680b946d@mail.gmail.com>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1270 bytes --]
Hi,
On Sat, 27 Oct 2007, Nguyen Thai Ngoc Duy wrote:
> On 10/27/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > Hi,
> >
> > On Sat, 27 Oct 2007, Nguyễn Thái Ngọc Duy wrote:
> >
> > > +mkdir -p work/sub/dir || exit 1
> > > +mv .git work
> > > +if test "$1" = --normal; then
> > > + say "Normal case"
> > > +else
> > > + say "Worktree case"
> > > +fi
> > > +test "$1" = --normal || mv work/.git repo.git || exit 1
> > > +
> > > +test "$1" = --normal || export GIT_DIR=$(pwd)/repo.git
> > > +export GIT_CONFIG="$(pwd)"/$GIT_DIR/config
> > > +test "$1" = --normal || export GIT_WORK_TREE=$(pwd)/work
> > > +
> > > +cd work/sub || exit 1
> >
> > Why don't you put this block into a test_expect_success? And then just
> > make a
> >
> > for mode in normal worktree
> > do
> >
> > ...
> >
> > done
> >
> > Hmm? I would like to see this test case in the official git.git.
>
> Because after normal iteration, the test repository is no longer in
> clean state that the second iteration needs. Maybe I should just
> create another repo then set parameters properly in test_expect_*
Yes, you can do that:
test_create_repo other-repo
Another option would be that you clean up at the end of the loop.
Ciao,
Dscho
^ permalink raw reply
* [MinGW PATCH] spawnvppe_pipe: Don't overwrite argv[0]
From: Nguyễn Thái Ngọc Duy @ 2007-10-27 13:26 UTC (permalink / raw)
To: git, Johannes Sixt
Because caller expects it so
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
spawn-pipe.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/spawn-pipe.c b/spawn-pipe.c
index c8f0452..3df7e22 100644
--- a/spawn-pipe.c
+++ b/spawn-pipe.c
@@ -123,6 +123,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env,
int pin[], int pout[])
{
const char *cmd_basename = strrchr(cmd, '/');
+ const char *argv0 = argv[0];
pid_t pid;
#ifdef __MINGW32__
@@ -214,6 +215,8 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env,
}
#endif
+ argv[0] = argv0;
+
return pid;
}
--
1.5.3.rc4.3.gab089
^ permalink raw reply related
* Re: Minor inconsistency: "git tag" requires space after -m.
From: Sergei Organov @ 2007-10-27 13:14 UTC (permalink / raw)
To: git
In-Reply-To: <Pine.LNX.4.64.0710271347510.4362@racer.site>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> Hi,
>
> On Sat, 27 Oct 2007, Sergei Organov wrote:
>
>> It seems options parsing is somewhat broken in git-tag:
>>
>> $ git tag -a -m"Annotated tag" annotated-tag
>> usage: git-tag [-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>] <tagname> [<head>]
>> $ git tag -a -m "Annotated tag" annotated-tag
>> $ git --version
>> git version 1.5.3.4
>>
>> This is inconsistent with, say, "git commit", that groks -m"Message"
>> (without space after -m) just fine.
>
> As it happens, we are in the middle of adding our own option parser which
> probably solves the issue. Can you please retest when we have that, and
> use it in builtin-tag?
I'm 100% sure there will be no inconsistencies once you unify options
parsing among the tools, but I won't refrain from re-testing this
anyway.
--
Sergei.
^ 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