threads / discuss / 43146

Re: Stupid Git question

Subject: Re: Stupid Git question

## tl;dr

7 messages between Nov 21, 2006 and Nov 24, 2006.

replies: 6people: 4as markdown or json

Sean Kelley· Nov 21, 2006, 21:41 UTC · lore

Stupid Git question

Hi,

I have a stupid git question. We are doing embedded development using git for our kernel mods.

git clone git+ssh://git.example.com/git/kernel/mh.git kernel
git checkout -b fm-modulator
edit/add/commit
git checkout origin
git pull . fm-modulator
git push origin
Everything up-to-date  <<< It pushes nothing

My problem is that I don't understand why when I tell git to push the changes to our repository it says everything is up-to-date. It clearly hasn't pushed it yet to our server.

My git layout is like this:

A single repository representing our Monahans kernel "mh.git" hosted on a remote server accessed by git+ssh.

Four developers work on the kernel and drivers for the target platform.

Any suggestions much appreciated. My prior experience is with StarTeam and more recently Subversion.

Thanks,
Sean
-- 
Sean Kelley

-- 
Jakub Narebski· Nov 21, 2006, 21:49 UTC · re: Sean Kelley · lore
Sean Kelley wrote:
> git checkout origin

It should be "git checkout master". You shouldn't do work on tracking branches like origin branch.

> git pull . fm-modulator
> 
> git push origin

Here origin means origin remote (repository). Check out what you have in remotes/origin, or in [remote "origin"] section in git config.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Sean Kelley· Nov 22, 2006, 14:28 UTC · re: Jakub Narebski · lore
On 11/21/06, Jakub Narebski <jnareb@gmail.com> wrote:
Show 13 quoted lines
> Sean Kelley wrote:
>
> > git checkout origin
>
> It should be "git checkout master". You shouldn't do work on tracking
> branches like origin branch.
>
> > git pull . fm-modulator
> >
> > git push origin
>
> Here origin means origin remote (repository). Check out what you have in
> remotes/origin, or in [remote "origin"] section in git config.

Thanks! One more question. It appears that the problem that I am having is that people are comitting to origin and should be committing to master. Perhaps the names can be confusing. One suggestion made is that we give a branch on the remote server a more meaningful name.

If on my remote server I have:
  /data/git/kernel/mh.git

How do I add a branch to the remote repository that is visible to all team members. It seems like the git checkout -b commands just create local topic branches.

So I would have something like:

git clone git+ssh://git.example.com/data/git/kernel/mh.git kernel cd kernel git checkout Project git checkout -b fm-modulator edit/add/commit changes...

git checkout Project git pull . fm-modulator git push origin Project

So how do I create this Project branch on the remote repository such that it is visible to all? Do I log onto the remove server and do it manually? If so, how is that done?

Thanks!
Sean
Show 11 quoted lines
> --
> Jakub Narebski
> Warsaw, Poland
> ShadeHawk on #git
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Carl Worth· Nov 22, 2006, 16:44 UTC · re: Sean Kelley · lore
On Wed, 22 Nov 2006 08:28:58 -0600, "Sean Kelley" wrote:
> How do I add a branch to the remote repository that is visible to all
> team members.  It seems like the git checkout -b commands just create
> local topic branches.

Just push the branch out to the remote repository. You even gave the command sequence to do that:

> git checkout Project
> git pull . fm-modulator
> git push origin Project
-Carl
Sean Kelley· Nov 22, 2006, 21:28 UTC · re: Carl Worth · lore
Hi,
On 11/22/06, Carl Worth <cworth@cworth.org> wrote:
Show 12 quoted lines
> On Wed, 22 Nov 2006 08:28:58 -0600, "Sean Kelley" wrote:
> > How do I add a branch to the remote repository that is visible to all
> > team members.  It seems like the git checkout -b commands just create
> > local topic branches.
>
> Just push the branch out to the remote repository. You even gave the
> command sequence to do that:
>
> > git checkout Project
> > git pull . fm-modulator
> > git push origin Project
>

One other question - how do you rename a branch on the remote repository once you have created it?

Thanks,
Sean
> -Carl
>
>
>
Junio C Hamano· Nov 22, 2006, 22:43 UTC · re: Sean Kelley · lore
"Sean Kelley" <sean.v.kelley@gmail.com> writes:
> One other question - how do you rename a branch on the remote
> repository once you have created it?

Right now, there is no way to remove a ref, so even "create new and then remove" would not work. You need a way to ssh-in to the machine and run "branch -d" there.

You would need an access to run git tools on the remote site for:

 - repository creation and deletion
 - ref deletion
 - fsck, pruning and repacking
 - adding entries to objects/info/alternates
 - managing hook scripts

with the current set of tools, which pretty much means an account with a full shell access over SSH.

Earlier in another thread, Linus said that it is justifiable to treat repository creation as a special event and outside of git. For one thing you need to have the account on the site and arrange access permissions and authentication before you can create a repository, so it is an understandable position to take, and for people with full SSH access it is a minor nuisance that they have to first go there to perform the above operations instead of running "git-do-things-at-remote host:path" locally.

However, for sites that want to restrict the access via git-shell, after a repository owner secured such an account and access rights, not being able to allow the user to do some of the above things himself is a burden on site administrators. This _could_ be improved by allowing some common operations via git-shell.

Even under git-shell, the process'es user and group credentials are the primary means to control the access rights. So in that sense, letting the user to say things like the following might make sense:

   $ REPO=repo.example.com:/pub/scm/git/project.git
   $ git remote-admin $REPO create-repository
   $ git remote-admin $REPO delete-repository
   $ git remote-admin $REPO repack
   $ git remote-admin $REPO fsck-objects
   $ git remote-admin $REPO count-objects

And for the sake of both simplicity (which would lead to security) and to allow the site administrator to make policy decision, I think we do not have to (and we shouldn't) make the above commands to take any flags. The command's availability and what parameters to be passed to underlying commands such as git-repack are determined by the site administrator. For example, an administrator may give a restricted account to a user _and_ set up one repository for him but may not want to give him rights to create another repository nor delete that initial repository given to him, in which case create-repository and delete-repository actions would be disabled.

I have a feeling that the users should not be given full control over 'hook' scripts, but I am not sure. A site administator might want to forbid too expensive hooks from running, even the process spawned by the user would work only in directories that the user has access to. If we give the users a full control, then:

   $ git remote-admin $REPO get-hook $hookname >old-contents
   $ git remote-admin $REPO put-hook $hookname <new-contents
   $ git remote-admin $REPO remove-hook $hookname

would be the set of commands we could use (I am assuming put-hook installs the hook in "enabled" state, and get-hook would give a failure for nonexistent or disabled hooks).

The most straightforward extension of the above for ref deletion is to say:

   $ git remote-admin $REPO delete-refs refs/heads/foo refs/tags/v1.0

and that would be the simplest way to implement it if we were to go with "git remote-admin". However, I think people would find it more natural if manipulation of refs were part of "git push".

"git push $REPO $src:$dst" means "take what I have in $src in my local repository, and update the $REPO's $dst ref with that". So as a natural extension of that, we could make:

   $ git push $REPO '':$dst

to mean "store nothingness in $dst" and make that a way to express the desire to remove $dst ref.

Junio C Hamano· Nov 24, 2006, 08:31 UTC · re: Junio C Hamano · lore
Junio C Hamano <junkio@cox.net> writes:
Show 18 quoted lines
>...
> The most straightforward extension of the above for ref deletion
> is to say:
>
>    $ git remote-admin $REPO delete-refs refs/heads/foo refs/tags/v1.0
>
> and that would be the simplest way to implement it if we were to
> go with "git remote-admin".  However, I think people would find
> it more natural if manipulation of refs were part of "git push".
>
> "git push $REPO $src:$dst" means "take what I have in $src in my
> local repository, and update the $REPO's $dst ref with that".
> So as a natural extension of that, we could make:
>
>    $ git push $REPO '':$dst
>
> to mean "store nothingness in $dst" and make that a way to
> express the desire to remove $dst ref.
And here is an attempt to do so.  Only lightly tested...
	Whenever I say "only lightly tested", I am hoping that
	interested people on the list to test it and possibly
	enhance it with follow-up patches.  Or at least respond
	with "Hey, that sucks" or "Ok, it seems to work for your
	test case but here is a breakage".

-- >8 -- [PATCH] Allow git push to delete remote ref.

This allows you to say
	git send-pack $URL :refs/heads/$branch

to delete the named remote branch. The refspec $src:$dst means replace the destination ref with the object known as $src on the local side, so this is a natural extension to make an empty $src mean "No object" to delete the target.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 connect.c            |   11 ++++++++++-
 receive-pack.c       |   45 ++++++++++++++++++++++++++++++++++-----------
 send-pack.c          |   41 ++++++++++++++++++++++++++++++-----------
 t/t5400-send-pack.sh |   10 ++++++++++
 4 files changed, 84 insertions(+), 23 deletions(-)
diff --git a/connect.c b/connect.c
index b9666cc..f7edba8 100644
--- a/connect.c
+++ b/connect.c
@@ -144,6 +144,7 @@ struct refspec {
  * +A:B means overwrite remote B with local A.
  * +A is a shorthand for +A:A.
  * A is a shorthand for A:A.
+ * :B means delete remote B.
  */
 static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
 {
@@ -240,6 +241,13 @@ static struct ref *try_explicit_object_n
 	unsigned char sha1[20];
 	struct ref *ref;
 	int len;
+
+	if (!*name) {
+		ref = xcalloc(1, sizeof(*ref) + 20);
+		strcpy(ref->name, "(delete)");
+		hashclr(ref->new_sha1);
+		return ref;
+	}
 	if (get_sha1(name, sha1))
 		return NULL;
 	len = strlen(name) + 1;
@@ -262,7 +270,8 @@ static int match_explicit_refs(struct re
 			break;
 		case 0:
 			/* The source could be in the get_sha1() format
-			 * not a reference name.
+			 * not a reference name.  :refs/other is a
+			 * way to delete 'other' ref at the remote end.
 			 */
 			matched_src = try_explicit_object_name(rs[i].src);
 			if (matched_src)
diff --git a/receive-pack.c b/receive-pack.c
index d56898c..1a141dc 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -14,7 +14,7 @@ static int deny_non_fast_forwards = 0;
 static int unpack_limit = 5000;
 static int report_status;
 
-static char capabilities[] = "report-status";
+static char capabilities[] = " report-status delete-refs ";
 static int capabilities_sent;
 
 static int receive_pack_config(const char *var, const char *value)
@@ -113,12 +113,14 @@ static int update(struct command *cmd)
 
 	strcpy(new_hex, sha1_to_hex(new_sha1));
 	strcpy(old_hex, sha1_to_hex(old_sha1));
-	if (!has_sha1_file(new_sha1)) {
+
+	if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) {
 		cmd->error_string = "bad pack";
 		return error("unpack should have generated %s, "
 			     "but I can't find it!", new_hex);
 	}
-	if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
+	if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
+	    !is_null_sha1(old_sha1)) {
 		struct commit *old_commit, *new_commit;
 		struct commit_list *bases, *ent;
 
@@ -138,14 +140,22 @@ static int update(struct command *cmd)
 		return error("hook declined to update %s", name);
 	}
 
-	lock = lock_any_ref_for_update(name, old_sha1);
-	if (!lock) {
-		cmd->error_string = "failed to lock";
-		return error("failed to lock %s", name);
+	if (is_null_sha1(new_sha1)) {
+		if (delete_ref(name, old_sha1)) {
+			cmd->error_string = "failed to delete";
+			return error("failed to delete %s", name);
+		}
+		fprintf(stderr, "%s: %s -> deleted\n", name, old_hex);
+	}
+	else {
+		lock = lock_any_ref_for_update(name, old_sha1);
+		if (!lock) {
+			cmd->error_string = "failed to lock";
+			return error("failed to lock %s", name);
+		}
+		write_ref_sha1(lock, new_sha1, "push");
+		fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 	}
-	write_ref_sha1(lock, new_sha1, "push");
-
-	fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 	return 0;
 }
 
@@ -375,6 +385,16 @@ static void report(const char *unpack_st
 	packet_flush(1);
 }
 
+static int delete_only(struct command *cmd)
+{
+	while (cmd) {
+		if (!is_null_sha1(cmd->new_sha1))
+			return 0;
+		cmd = cmd->next;
+	}
+	return 1;
+}
+
 int main(int argc, char **argv)
 {
 	int i;
@@ -408,7 +428,10 @@ int main(int argc, char **argv)
 
 	read_head_info();
 	if (commands) {
-		const char *unpack_status = unpack();
+		const char *unpack_status = NULL;
+
+		if (!delete_only(commands))
+			unpack_status = unpack();
 		if (!unpack_status)
 			execute_commands();
 		if (pack_lockfile)
diff --git a/send-pack.c b/send-pack.c
index 4476666..328dbbc 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -271,6 +271,7 @@ static int send_pack(int in, int out, in
 	int new_refs;
 	int ret = 0;
 	int ask_for_status_report = 0;
+	int allow_deleting_refs = 0;
 	int expect_status_report = 0;
 
 	/* No funny business with the matcher */
@@ -280,6 +281,8 @@ static int send_pack(int in, int out, in
 	/* Does the other end support the reporting? */
 	if (server_supports("report-status"))
 		ask_for_status_report = 1;
+	if (server_supports("delete-refs"))
+		allow_deleting_refs = 1;
 
 	/* match them up */
 	if (!remote_tail)
@@ -299,9 +302,19 @@ static int send_pack(int in, int out, in
 	new_refs = 0;
 	for (ref = remote_refs; ref; ref = ref->next) {
 		char old_hex[60], *new_hex;
+		int delete_ref;
+
 		if (!ref->peer_ref)
 			continue;
-		if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
+
+		delete_ref = is_null_sha1(ref->peer_ref->new_sha1);
+		if (delete_ref && !allow_deleting_refs) {
+			error("remote does not support deleting refs");
+			ret = -2;
+			continue;
+		}
+		if (!delete_ref &&
+		    !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
 			if (verbose)
 				fprintf(stderr, "'%s': up-to-date\n", ref->name);
 			continue;
@@ -321,9 +334,13 @@ static int send_pack(int in, int out, in
 		 *
 		 * (3) if both new and old are commit-ish, and new is a
 		 *     descendant of old, it is OK.
+		 *
+		 * (4) regardless of all of the above, removing :B is
+		 *     always allowed.
 		 */
 
 		if (!force_update &&
+		    !delete_ref &&
 		    !is_zero_sha1(ref->old_sha1) &&
 		    !ref->force) {
 			if (!has_sha1_file(ref->old_sha1) ||
@@ -347,12 +364,8 @@ static int send_pack(int in, int out, in
 			}
 		}
 		hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
-		if (is_zero_sha1(ref->new_sha1)) {
-			error("cannot happen anymore");
-			ret = -3;
-			continue;
-		}
-		new_refs++;
+		if (!delete_ref)
+			new_refs++;
 		strcpy(old_hex, sha1_to_hex(ref->old_sha1));
 		new_hex = sha1_to_hex(ref->new_sha1);
 
@@ -366,10 +379,16 @@ static int send_pack(int in, int out, in
 		else
 			packet_write(out, "%s %s %s",
 				     old_hex, new_hex, ref->name);
-		fprintf(stderr, "updating '%s'", ref->name);
-		if (strcmp(ref->name, ref->peer_ref->name))
-			fprintf(stderr, " using '%s'", ref->peer_ref->name);
-		fprintf(stderr, "\n  from %s\n  to   %s\n", old_hex, new_hex);
+		if (delete_ref)
+			fprintf(stderr, "deleting '%s'\n", ref->name);
+		else {
+			fprintf(stderr, "updating '%s'", ref->name);
+			if (strcmp(ref->name, ref->peer_ref->name))
+				fprintf(stderr, " using '%s'",
+					ref->peer_ref->name);
+			fprintf(stderr, "\n  from %s\n  to   %s\n",
+				old_hex, new_hex);
+		}
 	}
 
 	packet_flush(out);
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 8afb899..28744b3 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -64,6 +64,16 @@ test_expect_success \
 	cmp victim/.git/refs/heads/master .git/refs/heads/master
 '
 
+test_expect_success \
+        'push can be used to delete a ref' '
+	cd victim &&
+	git branch extra master &&
+	cd .. &&
+	test -f victim/.git/refs/heads/extra &&
+	git-send-pack ./victim/.git/ :extra master &&
+	! test -f victim/.git/refs/heads/extra
+'
+
 unset GIT_CONFIG GIT_CONFIG_LOCAL
 HOME=`pwd`/no-such-directory
 export HOME ;# this way we force the victim/.git/config to be used.
-- 
1.4.4.1.g77614

← back to recent threads