Git development
 help / color / mirror / Atom feed
* Re: is rebase the same as merging every commit?
From: Junio C Hamano @ 2008-06-27  1:08 UTC (permalink / raw)
  To: David Jeske; +Cc: git
In-Reply-To: <7vzlp7n1j4.fsf@gitster.siamese.dyndns.org>

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

> "David Jeske" <jeske@willowmail.com> writes:
> ...
>> (2) From the documentation diagrams, it looks like the rebased A' has
>> only (G) as a parent, not (A,G). If this is the case, why?  (i.e. not
>> connecting those nodes throws away useful information)
>
> You would rebase ONLY WHEN the project as the whole (either "other people
> in the project", or "yourself down the road one year from now") is
> interested mostly in the progress of 'master' D-E-F-G, and nobody cares
> whether you developed your A (or B or C) on top of E or G.  So the answer
> is definite "no" --- the line you drew between A and A' is a useless
> information.  Nobody cares you did it first on top of E but then you have
> redone the patches based on G (because things changed between E and G).

The last sentence came out in somewhat inappropriate way.

	In the situation "rebase" (which is a way to help you pretend you
	did not start building on a stale codebase) is appropriate, nobody
	wants to know you did it first on E

is what I meant.  More importantly, _you_ do not want anybody to know.
That is the whole reason you would rebase.

With that clarification in mind, the explanation would flow more smoothly
to this part...

> If the fact that parallel developments have happened is important, instead
> of the second picture like you drew, you will just do the real merge
> naturally to create a merge "M" like the picture I drew above.

So you have a choice between merging and rebasing.  And your extra parents
goes against the reason you chose rebasing in the first place.  That is
why we do not record the original parents anywhere.

^ permalink raw reply

* octopus limit
From: Len Brown @ 2008-06-27  2:44 UTC (permalink / raw)
  To: git

it would be nice if a merge of more than 16 branches failed
right at the start, rather than chunking along doing merges
and then giving up, leaving my repo in an intermediate state.

cheers,
-len

git merge test acpica bugzilla-10807-v2 bugzilla-10927 bugzilla-6217 
bugzilla-9684 bugzilla-9704 bugzilla-9772 compal-laptop debug-test 
dev-printk fujitsu-laptop gpe-debug misc per-cpu pnp-v3 suspend wmi-2.6.27
Already up-to-date with c4e6a2e64e948de42473e9c829181d768b1258c3
Trying simple merge with aa10d9f35361d3b260750f305ba8eb41c78e1a29
Trying simple merge with 23ac069d8be58c314af149dca2bb42dafdc38069
Trying simple merge with 60d40a50886415040888bde5133ccfeab40d945f
Trying simple merge with a7f34ae2abc9cb51a5b906f2da0aaa697f1a8883
Simple merge did not work, trying automatic merge.
Auto-merging drivers/acpi/events/evgpe.c
Trying simple merge with 009733ab59c05c4331c5504001587562e66a0d2b
Trying simple merge with 7004cf59cbfa54bc5ef0b3c5e0f81af410365e07
Trying simple merge with ad7f0d9feee6980a3ab3ea806854f56817d1da8e
Simple merge did not work, trying automatic merge.
Auto-merging drivers/acpi/processor_core.c
Auto-merging drivers/acpi/scan.c
Auto-merging kernel/cpu.c
Trying simple merge with 46c636862ee7e2f45e3369393f7c00761727e674
Simple merge did not work, trying automatic merge.
Auto-merging MAINTAINERS
Trying simple merge with 9e030ab0bffdc8b6d8be663b639bd5e2374537f0
Simple merge did not work, trying automatic merge.
Auto-merging drivers/acpi/namespace/nsxfeval.c
Auto-merging drivers/acpi/utilities/utmisc.c
Trying simple merge with 48e25157d315ec5fed3f5e1db88119dcde6175ea
Trying simple merge with 770c091f85a922d92505e2da8b30cf30dd6bc2f3
Simple merge did not work, trying automatic merge.
Auto-merging MAINTAINERS
Auto-merging drivers/misc/Kconfig
Trying simple merge with bb9babebc64541307d2eca41ed8e4c977f4beb10
Simple merge did not work, trying automatic merge.
Auto-merging drivers/acpi/hardware/hwgpe.c
Auto-merging include/acpi/achware.h
Auto-merging include/acpi/acpixf.h
Trying simple merge with eac9c2dc06e1ea25efebcd3d508c0ae40f4a9ece
Simple merge did not work, trying automatic merge.
Auto-merging include/acpi/aclocal.h
Trying simple merge with e1d755bbddba413c4050db1bfbe1f7e17dee3002
Simple merge did not work, trying automatic merge.
Auto-merging drivers/acpi/processor_core.c
Auto-merging drivers/acpi/processor_idle.c
Auto-merging drivers/acpi/processor_throttling.c
Auto-merging include/acpi/processor.h
Trying simple merge with f382348d43f80b6267a0881729366be2e5542ace
Trying simple merge with a143f92aca5eaf9a4ac608f7d208592e514574ed
Simple merge did not work, trying automatic merge.
Auto-merging drivers/acpi/sleep/main.c
Trying simple merge with 1a76b5a83e977cee4cd27c2f45a239a5faa9c1cc
fatal: Too many parents (16 max)

^ permalink raw reply

* Re: pread() over NFS (again) [1.5.5.4]
From: J. Bruce Fields @ 2008-06-27  2:54 UTC (permalink / raw)
  To: logank; +Cc: Junio C Hamano, Shawn O. Pearce, Christian Holtje, git
In-Reply-To: <65688C06-BB6A-4E95-A4B9-A1A7C206BE2E@sent.com>

On Thu, Jun 26, 2008 at 04:36:27PM -0700, logank@sent.com wrote:
> On Jun 26, 2008, at 1:56 PM, Junio C Hamano wrote:
>
>>> "The file shouldn't be short unless someone truncated it, or there
>>> is a bug in index-pack.  Neither is very likely, but I don't think
>>> we would want to retry pread'ing the same block forever.
>>
>> I don't think we would want to retry even once.  Return value of 0  
>> from
>> pread is defined to be an EOF, isn't it?
>
> No, it seems to be a simple error-out in this case. We have 2.4.20  
> systems

That version's for the client or the server?

--b.

> with nfs-utils 0.3.3 and used to frequently get the same error  
> while pushing. I made a similar change back in February and haven't had a 
> problem since:
>
> diff --git a/index-pack.c b/index-pack.c
> index 5ac91ba..85c8bdb 100644
> --- a/index-pack.c
> +++ b/index-pack.c
> @@ -313,7 +313,14 @@ static void *get_data_from_pack(struct object_entry 
> *obj)
> 	src = xmalloc(len);
> 	data = src;
> 	do {
> +		// It appears that if multiple threads read across NFS, the
> +		// second read will fail. I know this is awful, but we wait for
> +		// a little bit and try again.
> 		ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
> +		if (n <= 0) {
> +			sleep(1);
> +			n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
> +		}
> 		if (n <= 0)
> 			die("cannot pread pack file: %s", strerror(errno));
> 		rdy += n;
>
> I use a sleep request since it seems less likely that the other thread  
> will have an outstanding request after a second of waiting.
>
> -- 
>                                                         Logan Kennelly
>       ,,,
>      (. .)
> --ooO-(_)-Ooo--
>
>
>
> --
> 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

^ permalink raw reply

* Re: pread() over NFS (again) [1.5.5.4]
From: J. Bruce Fields @ 2008-06-27  2:57 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: logank, Shawn O. Pearce, Christian Holtje, git, Trond Myklebust
In-Reply-To: <7vhcbfojgf.fsf@gitster.siamese.dyndns.org>

On Thu, Jun 26, 2008 at 04:38:40PM -0700, Junio C Hamano wrote:
> logank@sent.com writes:
> 
> > On Jun 26, 2008, at 1:56 PM, Junio C Hamano wrote:
> >
> >>> "The file shouldn't be short unless someone truncated it, or there
> >>> is a bug in index-pack.  Neither is very likely, but I don't think
> >>> we would want to retry pread'ing the same block forever.
> >>
> >> I don't think we would want to retry even once.  Return value of 0
> >> from
> >> pread is defined to be an EOF, isn't it?
> >
> > No, it seems to be a simple error-out in this case. We have 2.4.20
> > systems with nfs-utils 0.3.3 and used to frequently get the same error
> > while pushing. I made a similar change back in February and haven't
> > had a problem since:
> >
> > diff --git a/index-pack.c b/index-pack.c
> > index 5ac91ba..85c8bdb 100644
> > --- a/index-pack.c
> > +++ b/index-pack.c
> > @@ -313,7 +313,14 @@ static void *get_data_from_pack(struct
> > object_entry *obj)
> > 	src = xmalloc(len);
> > 	data = src;
> > 	do {
> > +		// It appears that if multiple threads read across NFS, the
> > +		// second read will fail. I know this is awful, but we wait for
> > +		// a little bit and try again.
> > 		ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
> > +		if (n <= 0) {
> > +			sleep(1);
> > +			n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
> > +		}
> > 		if (n <= 0)
> > 			die("cannot pread pack file: %s", strerror(errno));
> > 		rdy += n;
> >
> > I use a sleep request since it seems less likely that the other thread
> > will have an outstanding request after a second of waiting.
> 
> Gaah.  Don't we have NFS experts in house?  Bruce, perhaps?

Trond, you don't have any idea why a 2.6.9-42.0.8.ELsmp client (2.4.28
server) might be returning spurious 0's from pread()?

Seems like everything is happening from that one client--the file isn't
being simultaneously accessed from the server or from another client.

--b.

^ permalink raw reply

* Re: bug related to branches using / in name
From: Jeff King @ 2008-06-27  3:02 UTC (permalink / raw)
  To: Simon Holm Thøgersen; +Cc: git, Ingo Molnar
In-Reply-To: <1214509350.28344.31.camel@odie.local>

On Thu, Jun 26, 2008 at 09:42:30PM +0200, Simon Holm Thøgersen wrote:

> The last command does not succeed, but produces the following output
> 
> error: unable to resolve reference refs/remotes/origin/sched/devel: Not
> a directory
> >From file:///tmp/git-bug
>  * [new branch]      sched/devel -> origin/sched/devel
> error: unable to resolve reference refs/remotes/origin/sched/urgent: Not
> a directory
>  * [new branch]      sched/urgent -> origin/sched/urgent

So to summarize, the problem is that you have an old tracking branch
"refs/remotes/sched" that exists on the client, but upstream has since
removed it in favor of "sched/devel", which you are now trying to fetch.
And of course there is a conflict, because of the ref naming rules.

This doesn't work seamlessly because git-fetch never removes old
tracking branches, even if they have been deleted upstream. And normally
there is no conflict; leaving the old branches means they don't
disappear from under you.

In this case, of course, it's inconvenient. The "right" way to solve it
is to tell git to clean up your tracking branches for "origin":

  git remote prune origin

which should delete the old "sched" tracking branch (since it no longer
exists on the remote), and then you are free to fetch.

It might be nicer if this were handled automatically, but it would
violate git-fetch's rule about never deleting branches. And presumably
this comes up infrequently enough that it isn't a problem. Perhaps a
better error message suggesting git-prune might make sense?

-Peff

^ permalink raw reply

* Re: bug related to branches using / in name
From: Jeff King @ 2008-06-27  3:04 UTC (permalink / raw)
  To: Simon Holm Thøgersen; +Cc: git, Ingo Molnar
In-Reply-To: <20080627030245.GA7144@sigill.intra.peff.net>

On Thu, Jun 26, 2008 at 11:02:46PM -0400, Jeff King wrote:

> So to summarize, the problem is that you have an old tracking branch
> "refs/remotes/sched" that exists on the client, but upstream has since
> removed it in favor of "sched/devel", which you are now trying to fetch.
> And of course there is a conflict, because of the ref naming rules.
> 
> This doesn't work seamlessly because git-fetch never removes old
> tracking branches, even if they have been deleted upstream. And normally
> there is no conflict; leaving the old branches means they don't
> disappear from under you.

BTW, you can get the opposite problem, too. If you have
"refs/remotes/origin/foo/bar", and then the remote removes "foo/bar" in
favor of "foo", you will have a conflict on fetch.

-Peff

^ permalink raw reply

* Re: bug related to branches using / in name
From: Jeff King @ 2008-06-27  3:57 UTC (permalink / raw)
  To: Simon Holm Thøgersen; +Cc: Junio C Hamano, git, Ingo Molnar
In-Reply-To: <20080627030245.GA7144@sigill.intra.peff.net>

On Thu, Jun 26, 2008 at 11:02:46PM -0400, Jeff King wrote:

> It might be nicer if this were handled automatically, but it would
> violate git-fetch's rule about never deleting branches. And presumably
> this comes up infrequently enough that it isn't a problem. Perhaps a
> better error message suggesting git-prune might make sense?

And here is a 2-patch series improving the error reporting for this
case (and it also helps with some other cases). I'm a little iffy on
2/2, since we don't actually _know_ that remote pruning will help. But
propagating specific errors up through the call chain would require
reasonably major surgery.

  1/2: fetch: give a hint to the user when local refs fail to update
  2/2: fetch: report local storage errors in status table

-Peff

^ permalink raw reply

* [PATCH] fetch: report local storage errors in status table
From: Jeff King @ 2008-06-27  3:59 UTC (permalink / raw)
  To: Simon Holm Thøgersen; +Cc: Junio C Hamano, git, Ingo Molnar
In-Reply-To: <20080627035747.GC7144@sigill.intra.peff.net>

Previously, if there was an error while storing a local
tracking ref, the low-level functions would report an error,
but fetch's status output wouldn't indicate any problem.
E.g., imagine you have an old "refs/remotes/origin/foo/bar" but
upstream has deleted "foo/bar" in favor of a new branch
"foo". You would get output like this:

  error: there are still refs under 'refs/remotes/origin/foo'
  From $url_of_repo
   * [new branch]      foo        -> origin/foo

With this patch, the output takes into account the status of
updating the local ref:

  error: there are still refs under 'refs/remotes/origin/foo'
  From $url_of_repo
   ! [new branch]      foo        -> origin/foo  (unable to update local ref)

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin-fetch.c |   36 ++++++++++++++++++++++++------------
 1 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/builtin-fetch.c b/builtin-fetch.c
index e81ee2d..7c16d38 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -233,10 +233,12 @@ static int update_local_ref(struct ref *ref,
 
 	if (!is_null_sha1(ref->old_sha1) &&
 	    !prefixcmp(ref->name, "refs/tags/")) {
-		sprintf(display, "- %-*s %-*s -> %s",
+		int r;
+		r = s_update_ref("updating tag", ref, 0);
+		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-',
 			SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
-			pretty_ref);
-		return s_update_ref("updating tag", ref, 0);
+			pretty_ref, r ? "  (unable to update local ref)" : "");
+		return r;
 	}
 
 	current = lookup_commit_reference_gently(ref->old_sha1, 1);
@@ -244,6 +246,7 @@ static int update_local_ref(struct ref *ref,
 	if (!current || !updated) {
 		const char *msg;
 		const char *what;
+		int r;
 		if (!strncmp(ref->name, "refs/tags/", 10)) {
 			msg = "storing tag";
 			what = "[new tag]";
@@ -253,27 +256,36 @@ static int update_local_ref(struct ref *ref,
 			what = "[new branch]";
 		}
 
-		sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what,
-			REFCOL_WIDTH, remote, pretty_ref);
-		return s_update_ref(msg, ref, 0);
+		r = s_update_ref(msg, ref, 0);
+		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
+			SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
+			r ? "  (unable to update local ref)" : "");
+		return r;
 	}
 
 	if (in_merge_bases(current, &updated, 1)) {
 		char quickref[83];
+		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "..");
 		strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-		sprintf(display, "  %-*s %-*s -> %s", SUMMARY_WIDTH, quickref,
-			REFCOL_WIDTH, remote, pretty_ref);
-		return s_update_ref("fast forward", ref, 1);
+		r = s_update_ref("fast forward", ref, 1);
+		sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
+			SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
+			pretty_ref, r ? "  (unable to update local ref)" : "");
+		return r;
 	} else if (force || ref->force) {
 		char quickref[84];
+		int r;
 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
 		strcat(quickref, "...");
 		strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-		sprintf(display, "+ %-*s %-*s -> %s  (forced update)",
-			SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref);
-		return s_update_ref("forced-update", ref, 1);
+		r = s_update_ref("forced-update", ref, 1);
+		sprintf(display, "%c %-*s %-*s -> %s  (%s)", r ? '!' : '+',
+			SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
+			pretty_ref,
+			r ? "unable to update local ref" : "forced update");
+		return r;
 	} else {
 		sprintf(display, "! %-*s %-*s -> %s  (non fast forward)",
 			SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
-- 
1.5.6.1.79.g7b3a7.dirty

^ permalink raw reply related

* [PATCH 2/2] fetch: give a hint to the user when local refs fail to update
From: Jeff King @ 2008-06-27  4:01 UTC (permalink / raw)
  To: Simon Holm Thøgersen; +Cc: Junio C Hamano, git, Ingo Molnar
In-Reply-To: <20080627035747.GC7144@sigill.intra.peff.net>

There are basically two categories of update failures for
local refs:

  1. problems outside of git, like disk full, bad
     permissions, etc.

  2. D/F conflicts on tracking branch ref names

In either case, there should already have been an error
message. In case '1', hopefully enough information has
already been given that the user can fix it. In the case of
'2', we can hint that the user can clean up their tracking
branch area by using 'git remote prune'.

Note that we don't actually know _which_ case we have, so
the user will receive the hint in case 1, as well. In this
case the suggestion won't do any good, but hopefully the
user is smart enough to figure out that it's just a hint.

Signed-off-by: Jeff King <peff@peff.net>
---
Actually, I think there might be a third category, "bad ref format".
But that would only come from a malicious remote trying to send you a
badly formatted ref, so I think that is rare enough not to worry about
showing the extra hint there.

 builtin-fetch.c |   15 +++++++++++----
 1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/builtin-fetch.c b/builtin-fetch.c
index 7c16d38..97fdc51 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -181,9 +181,9 @@ static int s_update_ref(const char *action,
 	lock = lock_any_ref_for_update(ref->name,
 				       check_old ? ref->old_sha1 : NULL, 0);
 	if (!lock)
-		return 1;
+		return 2;
 	if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
-		return 1;
+		return 2;
 	return 0;
 }
 
@@ -294,7 +294,8 @@ static int update_local_ref(struct ref *ref,
 	}
 }
 
-static int store_updated_refs(const char *url, struct ref *ref_map)
+static int store_updated_refs(const char *url, const char *remote_name,
+		struct ref *ref_map)
 {
 	FILE *fp;
 	struct commit *commit;
@@ -380,6 +381,10 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
 		}
 	}
 	fclose(fp);
+	if (rc & 2)
+		error("some local refs could not be updated; try running\n"
+		      " 'git remote prune %s' to remove any old, conflicting "
+		      "branches", remote_name);
 	return rc;
 }
 
@@ -450,7 +455,9 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 	if (ret)
 		ret = transport_fetch_refs(transport, ref_map);
 	if (!ret)
-		ret |= store_updated_refs(transport->url, ref_map);
+		ret |= store_updated_refs(transport->url,
+				transport->remote->name,
+				ref_map);
 	transport_unlock_pack(transport);
 	return ret;
 }
-- 
1.5.6.1.79.g7b3a7.dirty

^ permalink raw reply related

* Re: [PATCH v2] pre-commit hook should ignore carriage returns at EOL
From: Jeff King @ 2008-06-27  4:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Christian Holtje, Alex Riesen, git
In-Reply-To: <7vlk0rokxb.fsf@gitster.siamese.dyndns.org>

On Thu, Jun 26, 2008 at 04:06:56PM -0700, Junio C Hamano wrote:

> +if git-rev-parse --verify HEAD 2>/dev/null
> +then
> +	against=
> +else
> +	# Initial commit: diff against an empty tree object
> +	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
> +fi

Heh, I am happy that the virtual empty tree object is coming in handy
again.

>From quick review, the series looks good to me (and it was, btw, very
easy to read -- I think that you, as somebody who reviews a lot of
patches, have gotten very good at splitting up your own sensibly. :) ).

-Peff

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: Matthieu Moy @ 2008-06-27  6:30 UTC (permalink / raw)
  To: David Jeske; +Cc: git
In-Reply-To: <willow-jeske-01l78ZaEFEDjCZEG>

"David Jeske" <jeske@willowmail.com> writes:

> Rebasing is described in the docs I've read as turning this: (sorry for the
> dots)
>
> ..........A---B---C topic
> ........./
> ....D---E---F---G master
>
> Into this:
>
> ...................A'--B'--C' topic
> ................../
> .....D---E---F---G master
>
> If I understand it right (and that's a BIG if), it's the same as doing a merge
> of C into G where every individual commit in the C-line is individually
> committed into the new C' line.
>
> ...........-------------A---B---C
> ........../            /   /   /
> ........./        /---A'--B'--C'  topic
> ......../        /
> ....D---E---F---G - master

I'd draw that the other way:

  ...........---------A---B---C
  ........../          \   \   \
  ........./        /---A'--B'--C'  topic
  ......../        /
  ....D---E---F---G - master

> (1) Is the above model a valid explanation?

Sounds correct to me.

> (2) From the documentation diagrams, it looks like the rebased A' has only (G)
> as a parent, not (A,G). If this is the case, why?

Well, one could imagine a "rebase keeping ancestry" command, which
would keep A and G (indeed, you can do that by hand with multiple
calls to "merge"). The advantage being that further merges involving
both A and A' have better chance to succeed.

But philosophy of "rebase" is different: the idea is that you usually
rebase your private branches before submission, and the guys you
submit to are interested in your changes (i.e. the patch serie
diff(G,A'), diff(A',B'), ...), not the way you got this patch serie.

So, discarding this ancestry information is a bit like discarding your
*~ files (or whatever backup files your editor might create) after
some time: it has been valuable information, but at some point, it
becomes noise you don't want to hear.

> (i.e. not connecting those nodes throws away useful information)

For the use-cases where this information is useful, "rebase" is not
for you. Indeed, in these cases, a plain "merge" is usually what you
want.

> (3) If it only has (G) as a parent, does the rebase explicitly remove the
> source A,B,C nodes from the repository?

Most commands, and this includes rebase, are "add-only". The objects
will remain unreferenced and will be pruned by the next git gc
--prune. Unreferenced objects do not harm, they just eat your disk
space.

Well, that was a first approximation. Indeed, the reflog still
references C, see "git reflog". For example, after the rebase, if you
realize that you actually didn't want this rebase, you can still
"git reset --hard HEAD@{1}" or something like that.

-- 
Matthieu

^ permalink raw reply

* An alternate model for preparing partial commits
From: Robert Anderson @ 2008-06-27  6:50 UTC (permalink / raw)
  To: Git Mailing List

Seems to me the concept of the "index" is a half-baked version of what
I really want, which is the ability to factor a working tree's changes
into its constituent parts in preparation for committing them.  The
index provides some very nice facilities to factor out changes in a
working tree into a "staging area", but the fundamental flaw of this
in my view is that this "staging area" is not instantiated as a tree,
so it cannot be compiled and/or tested before committing.

Consider a facility where the state you want to commit next is built
up in the current working directory, and the original set of changes
exists in some proto-space like the index currently inhabits, where
you can query and manipulate that state, but it isn't instantiated in
your working tree.

Imagine a session like this:

You've got a couple of conflated changes in your working tree, that
you think you can break up into two orthogonal changes, each of which
will compile and pass a set of tests you've got.  You think.  You'd
like to verify the build and test before you commit each piece.

git prep

where "prep" means "prepare commit".  Don't get hung up on command or
option names I'm using as placeholders, I just made that up without
much deep thought about what to call it.

Now my tree appears clean (and git diff returns nothing).  I can now
start adding the changes I had in my working tree that I want to
include in the next commit, using git add (which would know I am in
the "prep" mode).  I can examine those original working dir changes I
am choosing from with:

git diff --prep

which, at this point, shows the same output that "git diff" did before
I ran "git prep."  Now I want to add some subset of my original
changes:

git add newfile.c
git add -i
<add a couple of hunks of the changes from file modfile.c>

Now I have a working tree state that I think I want to commit.  I can
examine it with:

git diff

and I can compile and test it.  Yep, it works and passes my test suite
(an option I did not have if I had added these changes to the index).
So now I want to commit:

git commit -a -m "made change A"

I think the commit should probably "pop" the rest of the changes I did
not commit back into the working directory.  If I want to pull another
subset of changes again, I can repeat the process with another "git
prep".

Does this idea resonate with anyone else?

Thanks,
Bob Anderson

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: David Jeske @ 2008-06-27  6:46 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: git
In-Reply-To: <vpqfxqz5qzj.fsf@bauges.imag.fr>

-- Matthieu Moy wrote:

> > (3) If it only has (G) as a parent, does the rebase explicitly remove the
> > source A,B,C nodes from the repository?
>
> Most commands, and this includes rebase, are
> "add-only". The objects will remain unreferenced and
> will be pruned by the next git gc --prune. Unreferenced
> objects do not harm, they just eat your disk space.

I see. So it would be reasonable for the documentation to be altered slightly
to show that the original nodes are still there, and that the primary
difference between merging those changes one-by-one and rebasing is that rebase
does not connect the new to the old. If you want to keep the old, you can toss
a branch name on it, and if not, it still lives until the gc timeout.

The current docs showing those nodes missing tells me that they disappear,
which is both scarry, and apparently inaccurate.

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: David Jeske @ 2008-06-27  6:46 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: git
In-Reply-To: <vpqfxqz5qzj.fsf@bauges.imag.fr>

-- Matthieu Moy wrote:

> > (3) If it only has (G) as a parent, does the rebase explicitly remove the
> > source A,B,C nodes from the repository?
>
> Most commands, and this includes rebase, are
> "add-only". The objects will remain unreferenced and
> will be pruned by the next git gc --prune. Unreferenced
> objects do not harm, they just eat your disk space.

I see. So it would be reasonable for the documentation to be altered slightly
to show that the original nodes are still there, and that the primary
difference between merging those changes one-by-one and rebasing is that rebase
does not connect the new to the old. If you want to keep the old, you can toss
a branch name on it, and if not, it still lives until the gc timeout.

The current docs showing those nodes missing tells me that they disappear,
which is both scarry, and apparently inaccurate.

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: David Jeske @ 2008-06-27  6:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvdzvn0ql.fsf@gitster.siamese.dyndns.org>

Thanks for the explanation.

However, when considering an SCM perspective, I don't understand why I have to
make a tradeoff between personal reproducibility (which I get from the original
changes), and upstream readability (which the community gets from my rebase).

I could get both of these if the rebase kept both the old and new.

Is there some reason that losing personal reproducability, and personal/local
tracking back to those changes of A-B-C is necessary as part of the process?

Further, the rebase machinery seems like it would be great for operations that
are even more 'dangerous', where I would really really want the history of the
transitions in case I realized a problem later.

Consider this set of commits on a personal branch

0 - feature a
1 - feature b
2 - bugfix a
3 - feature c / d
4 - bugfix b
5 - bugfix a2

>From all I've read about rebase, bisect, and the big tree management, it seems
like the three steps are Reorder, combine, rebase.  (In a more complicated
situation, i'd want to split a commit into pieces)

(1'')
0' - feature A
1' - bugfix a
2' - bugfix a2
(2'')
3' - feature b
4' - bugfix b
(3'')
5' - feature c (split)
(4'')
6' - feature d (split)

Frankly, I'm super impressed, because I can imagine how I might do this in git.
I'm guessing some of you are already doing this. But how do you do it? Can you
rebase a patch back into it's own history? (such as bugfix a from 2, to 1')

I want to mess around and try this stuff out, but I'm scared of doing bad
things to the tree and them being unrecoverable because rebase tosses the old
stuff. I don't understand why I have to lose my original work and/or the
connection to my original work, in order to reorder/combine/split for public
consumption. What is the argument for that? (other than the fact that the
current dag link propagation model would force others to get these changes if
they remained connected together. Something easily remidied by out of band
metadata, or different link types)

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: David Jeske @ 2008-06-27  6:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvdzvn0ql.fsf@gitster.siamese.dyndns.org>

Thanks for the explanation.

However, when considering an SCM perspective, I don't understand why I have to
make a tradeoff between personal reproducibility (which I get from the original
changes), and upstream readability (which the community gets from my rebase).

I could get both of these if the rebase kept both the old and new.

Is there some reason that losing personal reproducability, and personal/local
tracking back to those changes of A-B-C is necessary as part of the process?

Further, the rebase machinery seems like it would be great for operations that
are even more 'dangerous', where I would really really want the history of the
transitions in case I realized a problem later.

Consider this set of commits on a personal branch

0 - feature a
1 - feature b
2 - bugfix a
3 - feature c / d
4 - bugfix b
5 - bugfix a2

>From all I've read about rebase, bisect, and the big tree management, it seems
like the three steps are Reorder, combine, rebase.  (In a more complicated
situation, i'd want to split a commit into pieces)

(1'')
0' - feature A
1' - bugfix a
2' - bugfix a2
(2'')
3' - feature b
4' - bugfix b
(3'')
5' - feature c (split)
(4'')
6' - feature d (split)

Frankly, I'm super impressed, because I can imagine how I might do this in git.
I'm guessing some of you are already doing this. But how do you do it? Can you
rebase a patch back into it's own history? (such as bugfix a from 2, to 1')

I want to mess around and try this stuff out, but I'm scared of doing bad
things to the tree and them being unrecoverable because rebase tosses the old
stuff. I don't understand why I have to lose my original work and/or the
connection to my original work, in order to reorder/combine/split for public
consumption. What is the argument for that? (other than the fact that the
current dag link propagation model would force others to get these changes if
they remained connected together. Something easily remidied by out of band
metadata, or different link types)

^ permalink raw reply

* Re: octopus limit
From: Matthieu Moy @ 2008-06-27  6:33 UTC (permalink / raw)
  To: Len Brown; +Cc: git
In-Reply-To: <alpine.LFD.1.10.0806262243130.2988@localhost.localdomain>

Len Brown <lenb@kernel.org> writes:

> it would be nice if a merge of more than 16 branches failed
> right at the start, rather than chunking along doing merges
> and then giving up, leaving my repo in an intermediate state.

There's a patch around which should remove this limitation (I think
it's the builtin-ification of merge).

-- 
Matthieu

^ permalink raw reply

* Re: An alternate model for preparing partial commits
From: Björn Steinbrink @ 2008-06-27  7:10 UTC (permalink / raw)
  To: Robert Anderson; +Cc: Git Mailing List
In-Reply-To: <9af502e50806262350t6e794a92g7751147f1882965@mail.gmail.com>

On 2008.06.26 23:50:06 -0700, Robert Anderson wrote:
> Seems to me the concept of the "index" is a half-baked version of what
> I really want, which is the ability to factor a working tree's changes
> into its constituent parts in preparation for committing them.  The
> index provides some very nice facilities to factor out changes in a
> working tree into a "staging area", but the fundamental flaw of this
> in my view is that this "staging area" is not instantiated as a tree,
> so it cannot be compiled and/or tested before committing.
> 
> Consider a facility where the state you want to commit next is built
> up in the current working directory, and the original set of changes
> exists in some proto-space like the index currently inhabits, where
> you can query and manipulate that state, but it isn't instantiated in
> your working tree.
> 
> Imagine a session like this:
> 
> You've got a couple of conflated changes in your working tree, that
> you think you can break up into two orthogonal changes, each of which
> will compile and pass a set of tests you've got.  You think.  You'd
> like to verify the build and test before you commit each piece.
> 
> git prep
> 
> where "prep" means "prepare commit".  Don't get hung up on command or
> option names I'm using as placeholders, I just made that up without
> much deep thought about what to call it.
> 
> Now my tree appears clean (and git diff returns nothing).  I can now
> start adding the changes I had in my working tree that I want to
> include in the next commit, using git add (which would know I am in
> the "prep" mode).  I can examine those original working dir changes I
> am choosing from with:
> 
> git diff --prep
> 
> which, at this point, shows the same output that "git diff" did before
> I ran "git prep."  Now I want to add some subset of my original
> changes:
> 
> git add newfile.c
> git add -i
> <add a couple of hunks of the changes from file modfile.c>
> 
> Now I have a working tree state that I think I want to commit.  I can
> examine it with:
> 
> git diff
> 
> and I can compile and test it.  Yep, it works and passes my test suite
> (an option I did not have if I had added these changes to the index).
> So now I want to commit:
> 
> git commit -a -m "made change A"
> 
> I think the commit should probably "pop" the rest of the changes I did
> not commit back into the working directory.  If I want to pull another
> subset of changes again, I can repeat the process with another "git
> prep".
> 
> Does this idea resonate with anyone else?

Hm, I use "stash" for that purpose, which leads to kind of the reverse
of your approach. So I do sth. like this:

 - hack hack hack
 - Notice that I want to make two commits out of what I have in my
   working tree
 - git add -p -- stage what I want in the first commit
 - git commit -m tmp -- temporary commit
 - git stash -- stash away what doesn't belong in the first commit
 - git reset HEAD^ -- drop the temporary commit, with the changes kept
   in the working tree
 - test, fix bugs, read the diff, whatever
 - git commit -- this time for good
 - git stash apply -- get back the changes for the second commit

Instead of using reset, you could also use "commit --amend" (I actually
used to do that), but that needs you to do "git diff HEAD^" to see the
full changes, and (IMHO) makes it a harder sometimes to review your
stuff, because you now have three places where the changes for one
commit might reside (HEAD, index and working tree).

Björn

^ permalink raw reply

* [PATCH] git-gui: Implement "Stage/Unstage Line"
From: Johannes Sixt @ 2008-06-27  7:22 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Git Mailing List

From: Johannes Sixt <johannes.sixt@telecom.at>

This adds a context menu entry below "Stage/Unstage Hunk" that stages or
unstages just the line under the mouse pointer.

This is by itself useful, for example, if there are unrelated changes in
the same hunk and the hunk cannot be split by reducing the context.

The feature can also be used to split a hunk by staging a number of
additions (or unstaging a number of removals) until there are enough
context lines that the hunk gets split.

The implementation reads the complete hunk that the line lives in, and
constructs a new hunk by picking existing context lines, removing unneeded
change lines and transforming other change lines to context lines. The
resulting hunk is fed through 'git apply' just like in the "Stage/Unstage
Hunk" case.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
---
	Disclaimer: I'm Tcl/Tk illiterate. Feel free to munge the patch
	to your taste.

	The 'do_rescan' is probably a bit heavy-weight. But editing the
	diff window like we do in "Stage Hunk" would be a bit complex, and
	just redisplaying the diff is easier.

	Furthermore, I don't know why I have to do the loop until
	"end - 1 chars". If it goes until "end", then the hunk contains
	an extra line, so that the patch in general does not apply.
	Is there an extra newline in the diff view that is not in the
	git diff output?

	-- Hannes

 git-gui.sh   |    8 +++++
 lib/diff.tcl |   87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 0 deletions(-)

diff --git a/git-gui.sh b/git-gui.sh
index 1bbae15..d89f156 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -2666,6 +2666,11 @@ $ctxm add command \
 	-command {apply_hunk $cursorX $cursorY}
 set ui_diff_applyhunk [$ctxm index last]
 lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
+$ctxm add command \
+	-label [mc "Apply/Reverse Line"] \
+	-command {apply_line $cursorX $cursorY; do_rescan}
+set ui_diff_applyline [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
 $ctxm add separator
 $ctxm add command \
 	-label [mc "Show Less Context"] \
@@ -2714,8 +2719,10 @@ proc popup_diff_menu {ctxm x y X Y} {
 	set ::cursorY $y
 	if {$::ui_index eq $::current_diff_side} {
 		set l [mc "Unstage Hunk From Commit"]
+		set t [mc "Unstage Line From Commit"]
 	} else {
 		set l [mc "Stage Hunk For Commit"]
+		set t [mc "Stage Line For Commit"]
 	}
 	if {$::is_3way_diff
 		|| $current_diff_path eq {}
@@ -2726,6 +2733,7 @@ proc popup_diff_menu {ctxm x y X Y} {
 		set s normal
 	}
 	$ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
+	$ctxm entryconf $::ui_diff_applyline -state $s -label $t
 	tk_popup $ctxm $X $Y
 }
 bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
diff --git a/lib/diff.tcl b/lib/diff.tcl
index d04f6db..96ba949 100644
--- a/lib/diff.tcl
+++ b/lib/diff.tcl
@@ -362,3 +362,90 @@ proc apply_hunk {x y} {
 		set current_diff_path $current_diff_path
 	}
 }
+
+proc apply_line {x y} {
+	global current_diff_path current_diff_header current_diff_side
+	global ui_diff ui_index file_states
+
+	if {$current_diff_path eq {} || $current_diff_header eq {}} return
+	if {![lock_index apply_hunk]} return
+
+	set apply_cmd {apply --cached --whitespace=nowarn}
+	set mi [lindex $file_states($current_diff_path) 0]
+	if {$current_diff_side eq $ui_index} {
+		set failed_msg [mc "Failed to unstage selected line."]
+		set to_context {+}
+		lappend apply_cmd --reverse
+		if {[string index $mi 0] ne {M}} {
+			unlock_index
+			return
+		}
+	} else {
+		set failed_msg [mc "Failed to stage selected line."]
+		set to_context {-}
+		if {[string index $mi 1] ne {M}} {
+			unlock_index
+			return
+		}
+	}
+
+	set the_l [$ui_diff index @$x,$y]
+
+	# operate only on change lines
+	set c1 [$ui_diff get "$the_l linestart"]
+	if {$c1 ne {+} && $c1 ne {-}} {
+		unlock_index
+		return
+	}
+	set sign $c1
+
+	set i_l [$ui_diff search -backwards -regexp ^@@ $the_l 0.0]
+	if {$i_l eq {}} {
+		unlock_index
+		return
+	}
+	# $i_l is now at the beginning of a line
+
+	# pick start line number from hunk header
+	set hh [$ui_diff get $i_l "$i_l + 1 lines"]
+	set hh [lindex [split $hh ,] 0]
+	set hln [lindex [split $hh -] 1]
+
+	set n 0
+	set i_l [$ui_diff index "$i_l + 1 lines"]
+	set patch {}
+	while {[$ui_diff compare $i_l < "end - 1 chars"] &&
+	       [$ui_diff get $i_l "$i_l + 2 chars"] ne {@@}} {
+		set next_l [$ui_diff index "$i_l + 1 lines"]
+		set c1 [$ui_diff get $i_l]
+		if {[$ui_diff compare $i_l <= $the_l] &&
+		    [$ui_diff compare $the_l < $next_l]} {
+			# the line to stage/unstage
+			set ln [$ui_diff get $i_l $next_l]
+			set patch "$patch$ln"
+		} elseif {$c1 ne {-} && $c1 ne {+}} {
+			# context line
+			set ln [$ui_diff get $i_l $next_l]
+			set patch "$patch$ln"
+			set n [expr $n+1]
+		} elseif {$c1 eq $to_context} {
+			# turn change line into context line
+			set ln [$ui_diff get "$i_l + 1 chars" $next_l]
+			set patch "$patch $ln"
+			set n [expr $n+1]
+		}
+		set i_l $next_l
+	}
+	set patch "@@ -$hln,$n +$hln,[eval expr $n $sign 1] @@\n$patch"
+
+	if {[catch {
+		set p [eval git_write $apply_cmd]
+		fconfigure $p -translation binary -encoding binary
+		puts -nonewline $p $current_diff_header
+		puts -nonewline $p $patch
+		close $p} err]} {
+		error_popup [append $failed_msg "\n\n$err"]
+	}
+
+	unlock_index
+}
-- 
1.5.6.918.g8a69

^ permalink raw reply related

* Re: is rebase the same as merging every commit?
From: Matthieu Moy @ 2008-06-27  7:34 UTC (permalink / raw)
  To: David Jeske; +Cc: Junio C Hamano, git
In-Reply-To: <willow-jeske-01l7GhRWFEDjChtB>

"David Jeske" <jeske@willowmail.com> writes:

> However, when considering an SCM perspective, I don't understand why I have to
> make a tradeoff between personal reproducibility (which I get from the original
> changes), and upstream readability (which the community gets from my rebase).

Well, look at the [PATCH] messages on this list, and how they evolve.
Patch series give a clean way to go from a point to another. That's
what you want to see in upstream history.

Then, patch series usually get reviewed, and the patches themselves
are modified. There's a kind of meta-history: the changes you make to
your own changes.

Suppose I send a patch containing

+	int * x = malloc(sizeof(char));

and someone notices how wrong it is. I send another patch with

+	int * x = malloc(sizeof(int));

The first version was basicaly a mistake, and if it hasn't been
released, no one want to bother with it longer that the time to resend
the patch. No one want to be hit by the bug while using bisect later
on the upstream repository. And no one wants to see both patches when
reviewing or "git blame"-ing.

Things you rebase in Git are just like things for which you don't make
intermediate commits in SVN.

>>From all I've read about rebase, bisect, and the big tree management, it seems
> like the three steps are Reorder, combine, rebase.  (In a more complicated
> situation, i'd want to split a commit into pieces)
>
> (1'')
> 0' - feature A
> 1' - bugfix a
> 2' - bugfix a2
> (2'')
> 3' - feature b
> 4' - bugfix b
> (3'')
> 5' - feature c (split)
> (4'')
> 6' - feature d (split)
>
> Frankly, I'm super impressed, because I can imagine how I might do
> this in git.

git rebase -i will help you to do that painlessly.

> I want to mess around and try this stuff out, but I'm scared of doing bad
> things to the tree and them being unrecoverable

They won't. The reflog is still there. Try it, an cancel it if you
don't like.

The huge difference between the reflog and the history is that the
reflog is local, it's your own mess, other people won't get disturbed
by how messy it can be.

> (other than the fact that the current dag
> link propagation model would force others to get these changes if
> they remained connected together. Something easily remidied by out
> of band metadata, or different link types)

No. One fundamental principle of Git is that objects are immutable. If
your objects have a link, of whatever kind, then the same object moved
in another repository have the same link.

But what's wrong with the reflog?

-- 
Matthieu

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: Pascal Obry @ 2008-06-27  6:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: David Jeske, git
In-Reply-To: <7vzlp7n1j4.fsf@gitster.siamese.dyndns.org>

Junio C Hamano a écrit :
> You would rebase ONLY WHEN the project as the whole (either "other people
> in the project", or "yourself down the road one year from now") is
> interested mostly in the progress of 'master' D-E-F-G, and nobody cares
> whether you developed your A (or B or C) on top of E or G.  So the answer

Or if you are using git-svn as nobody will ever see your local branches. 
So rebasing is just the right way to go when tracking a Subversion tree 
I would say.

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|              http://www.obry.net
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595

^ permalink raw reply

* Re: bug related to branches using / in name
From: Simon Holm Thøgersen @ 2008-06-27  8:32 UTC (permalink / raw)
  To: Jeff King; +Cc: git, Ingo Molnar
In-Reply-To: <20080627030422.GB7144@sigill.intra.peff.net>

Jeff King wrote:
> Jeff King wrote:
> 
> > So to summarize, the problem is that you have an old tracking branch
> > "refs/remotes/sched" that exists on the client, but upstream has since
> > removed it in favor of "sched/devel", which you are now trying to fetch.
> > And of course there is a conflict, because of the ref naming rules.
> > 
> > This doesn't work seamlessly because git-fetch never removes old
> > tracking branches, even if they have been deleted upstream. And normally
> > there is no conflict; leaving the old branches means they don't
> > disappear from under you.
> 
Your summary is correct, but I cannot entirely convince myself that
leaving old branches available is valid in any work flow. But what do I
know.

> BTW, you can get the opposite problem, too. If you have
> "refs/remotes/origin/foo/bar", and then the remote removes "foo/bar" in
> favor of "foo", you will have a conflict on fetch.
> 
Yes, and you can also hit a similar problem using git-push, but I guess
that the user is a bit more aware about what is going on in that case
and is able resolve the problem without hints.

I tested the two patches and they did indeed seem to do what you
intended them to for my test case. The solution is not exactly pretty,
but it is better than nothing and it is admittedly a corner case.

Thank you for your time on this Jeff.


Simon Holm Thøgersen

^ permalink raw reply

* Re: is rebase the same as merging every commit?
From: Petr Baudis @ 2008-06-27  8:34 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: David Jeske, git
In-Reply-To: <vpqfxqz5qzj.fsf@bauges.imag.fr>

On Fri, Jun 27, 2008 at 08:30:56AM +0200, Matthieu Moy wrote:
> "David Jeske" <jeske@willowmail.com> writes:
> 
> > Rebasing is described in the docs I've read as turning this: (sorry for the
> > dots)
> >
> > ..........A---B---C topic
> > ........./
> > ....D---E---F---G master
> >
> > Into this:
> >
> > ...................A'--B'--C' topic
> > ................../
> > .....D---E---F---G master
> >
> > If I understand it right (and that's a BIG if), it's the same as doing a merge
> > of C into G where every individual commit in the C-line is individually
> > committed into the new C' line.
> >
> > ...........-------------A---B---C
> > ........../            /   /   /
> > ........./        /---A'--B'--C'  topic
> > ......../        /
> > ....D---E---F---G - master
> 
> I'd draw that the other way:
> 
>   ...........---------A---B---C
>   ........../          \   \   \
>   ........./        /---A'--B'--C'  topic
>   ......../        /
>   ....D---E---F---G - master
> 
> > (1) Is the above model a valid explanation?
> 
> Sounds correct to me.

I don't think you can call it correct since it assumes !(2) while (2)
holds. Drawing the diagram this way is misleading; merging commits
one-by-one implies preserving the merge information in the history
graph; nothing like that is done by rebase.

Rebase is more like _cherry-picking_ all the patches on your branch on
top of the upstream branch. You just essentially take each patch (commit
message + diff to parent) growing on top of upstream's E and recommit it
on top of G.

> > (2) From the documentation diagrams, it looks like the rebased A' has only (G)
> > as a parent, not (A,G). If this is the case, why?
..snip..
> > (i.e. not connecting those nodes throws away useful information)
> 
> For the use-cases where this information is useful, "rebase" is not
> for you. Indeed, in these cases, a plain "merge" is usually what you
> want.

Indeed, noone forces you into the rebase workflow for your own projects.
I personally never ever rebase (I do use StGIT though, but it records
per-patch history and makes sure I'm always in some consistent state).

-- 
				Petr "Pasky" Baudis
The last good thing written in C++ was the Pachelbel Canon. -- J. Olson

^ permalink raw reply

* Re: An alternate model for preparing partial commits
From: Johannes Sixt @ 2008-06-27  8:35 UTC (permalink / raw)
  To: Robert Anderson; +Cc: Git Mailing List
In-Reply-To: <9af502e50806262350t6e794a92g7751147f1882965@mail.gmail.com>

Robert Anderson schrieb:
> Seems to me the concept of the "index" is a half-baked version of what
> I really want, which is the ability to factor a working tree's changes
> into its constituent parts in preparation for committing them.  The
> index provides some very nice facilities to factor out changes in a
> working tree into a "staging area", but the fundamental flaw of this
> in my view is that this "staging area" is not instantiated as a tree,
> so it cannot be compiled and/or tested before committing.

I do this all the time. After I have made $N commits out of my worktree, I
usually

	$ git rebase -i HEAD~$N

and turn all 'pick's into 'edit's and 'squash's. Then I can compile and
test each commit, perhaps add some fixups, in isolation.

-- Hannes

^ permalink raw reply

* Re: Errors building git-1.5.6 from source on Mac OS X 10.4.11
From: Ifejinelo Onyiah @ 2008-06-27  8:43 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git
In-Reply-To: <81b0412b0806261142r37f84187qf5ff043e1913b4fb@mail.gmail.com>

2008/6/26 Alex Riesen <raa.lkml@gmail.com>:
> 2008/6/26 Ifejinelo Onyiah <nelo.onyiah@googlemail.com>:
>> 2008/6/25 Alex Riesen <raa.lkml@gmail.com>:
>>> Ifejinelo Onyiah, Wed, Jun 25, 2008 15:20:39 +0200:
>>>>
>>>> They all run fine but when I issue the make test command, it dies at
>>>> the following:
>>>>
>>>> % make test
>>>>
>>>> ... TRUNCATED OUTPUT ...
>>>>
>>>> *** t2004-checkout-cache-temp.sh ***
>>>> * FAIL 1: preparation
>>>>
>>>
>>> If you don't mind helping the investigation a bit, could you please go
>>> into the t/ directory and run
>>>
>>>    bash -x t2004-checkout-cache-temp.sh -d -v -i
>>>
>>> and post the output here?
>>
>> I ran that command and it seemed to run with no problems. I have
>> provided the output in 2 attached text files. I hope that is ok.
>
> could you try the command _without_ "bash -x"?
> Like this:
>
>    cd t
>    ./t2004-checkout-cache-temp.sh -d -v -i
>

I've just done that and here's the output:

io1@mib19412i[00m:~/Desktop/git-1.5.6/t$ ./t2004-checkout-cache-temp.sh -d -v -i
* expecting success:
mkdir asubdir &&
echo tree1path0 >path0 &&
echo tree1path1 >path1 &&
echo tree1path3 >path3 &&
echo tree1path4 >path4 &&
echo tree1asubdir/path5 >asubdir/path5 &&
git update-index --add path0 path1 path3 path4 asubdir/path5 &&
t1=$(git write-tree) &&
rm -f path* .merge_* out .git/index &&
echo tree2path0 >path0 &&
echo tree2path1 >path1 &&
echo tree2path2 >path2 &&
echo tree2path4 >path4 &&
git update-index --add path0 path1 path2 path4 &&
t2=$(git write-tree) &&
rm -f path* .merge_* out .git/index &&
echo tree2path0 >path0 &&
echo tree3path1 >path1 &&
echo tree3path2 >path2 &&
echo tree3path3 >path3 &&
git update-index --add path0 path1 path2 path3 &&
t3=$(git write-tree)
*   ok 1: preparation

* expecting success:
rm -f path* .merge_* out .git/index &&
git read-tree $t1 &&
git checkout-index --temp -- path1 >out &&
test $(wc -l <out) = 1 &&
test $(cut "-d  " -f2 out) = path1 &&
p=$(cut "-d     " -f1 out) &&
test -f $p &&
test $(cat $p) = tree1path1
*   ok 2: checkout one stage 0 to temporary file

* expecting success:
rm -f path* .merge_* out .git/index &&
git read-tree $t1 &&
git checkout-index -a --temp >out &&
test $(wc -l <out) = 5 &&
for f in path0 path1 path3 path4 asubdir/path5
do
       test $(grep $f out | cut "-d    " -f2) = $f &&
       p=$(grep $f out | cut "-d       " -f1) &&
       test -f $p &&
       test $(cat $p) = tree1$f
done
*   ok 3: checkout all stage 0 to temporary files

* expecting success:
rm -f path* .merge_* out .git/index &&
git read-tree -m $t1 $t2 $t3
*   ok 4: prepare 3-way merge

* expecting success:
rm -f path* .merge_* out &&
git checkout-index --stage=2 --temp -- path1 >out &&
test $(wc -l <out) = 1 &&
test $(cut "-d  " -f2 out) = path1 &&
p=$(cut "-d     " -f1 out) &&
test -f $p &&
test $(cat $p) = tree2path1
*   ok 5: checkout one stage 2 to temporary file

* expecting success:
rm -f path* .merge_* out &&
git checkout-index --all --stage=2 --temp >out &&
test $(wc -l <out) = 3 &&
for f in path1 path2 path4
do
       test $(grep $f out | cut "-d    " -f2) = $f &&
       p=$(grep $f out | cut "-d       " -f1) &&
       test -f $p &&
       test $(cat $p) = tree2$f
done
*   ok 6: checkout all stage 2 to temporary files

* expecting success:
rm -f path* .merge_* out &&
git checkout-index --stage=all --temp -- path0 >out &&
test $(wc -l <out) = 0
git-checkout-index: path0 does not exist at stage 4
*   ok 7: checkout all stages/one file to nothing

* expecting success:
rm -f path* .merge_* out &&
git checkout-index --stage=all --temp -- path1 >out &&
test $(wc -l <out) = 1 &&
test $(cut "-d  " -f2 out) = path1 &&
cut "-d " -f1 out | (read s1 s2 s3 &&
test -f $s1 &&
test -f $s2 &&
test -f $s3 &&
test $(cat $s1) = tree1path1 &&
test $(cat $s2) = tree2path1 &&
test $(cat $s3) = tree3path1)
*   ok 8: checkout all stages/one file to temporary files

* expecting success:
rm -f path* .merge_* out &&
git checkout-index --stage=all --temp -- path2 >out &&
test $(wc -l <out) = 1 &&
test $(cut "-d  " -f2 out) = path2 &&
cut "-d " -f1 out | (read s1 s2 s3 &&
test $s1 = . &&
test -f $s2 &&
test -f $s3 &&
test $(cat $s2) = tree2path2 &&
test $(cat $s3) = tree3path2)
*   ok 9: checkout some stages/one file to temporary files

* expecting success:
rm -f path* .merge_* out &&
git checkout-index -a --stage=all --temp >out &&
test $(wc -l <out) = 5
*   ok 10: checkout all stages/all files to temporary files

* expecting success:
test x$(grep path0 out | cut "-d        " -f2) = x
*   ok 11: -- path0: no entry

* expecting success:
test $(grep path1 out | cut "-d " -f2) = path1 &&
grep path1 out | cut "-d        " -f1 | (read s1 s2 s3 &&
test -f $s1 &&
test -f $s2 &&
test -f $s3 &&
test $(cat $s1) = tree1path1 &&
test $(cat $s2) = tree2path1 &&
test $(cat $s3) = tree3path1)
*   ok 12: -- path1: all 3 stages

* expecting success:
test $(grep path2 out | cut "-d " -f2) = path2 &&
grep path2 out | cut "-d        " -f1 | (read s1 s2 s3 &&
test $s1 = . &&
test -f $s2 &&
test -f $s3 &&
test $(cat $s2) = tree2path2 &&
test $(cat $s3) = tree3path2)
*   ok 13: -- path2: no stage 1, have stage 2 and 3

* expecting success:
test $(grep path3 out | cut "-d " -f2) = path3 &&
grep path3 out | cut "-d        " -f1 | (read s1 s2 s3 &&
test -f $s1 &&
test $s2 = . &&
test -f $s3 &&
test $(cat $s1) = tree1path3 &&
test $(cat $s3) = tree3path3)
*   ok 14: -- path3: no stage 2, have stage 1 and 3

* expecting success:
test $(grep path4 out | cut "-d " -f2) = path4 &&
grep path4 out | cut "-d        " -f1 | (read s1 s2 s3 &&
test -f $s1 &&
test -f $s2 &&
test $s3 = . &&
test $(cat $s1) = tree1path4 &&
test $(cat $s2) = tree2path4)
*   ok 15: -- path4: no stage 3, have stage 1 and 3

* expecting success:
test $(grep asubdir/path5 out | cut "-d " -f2) = asubdir/path5 &&
grep asubdir/path5 out | cut "-d        " -f1 | (read s1 s2 s3 &&
test -f $s1 &&
test $s2 = . &&
test $s3 = . &&
test $(cat $s1) = tree1asubdir/path5)
*   ok 16: -- asubdir/path5: no stage 2 and 3 have stage 1

* expecting success:
(cd asubdir &&
git checkout-index -a --stage=all >out &&
test $(wc -l <out) = 1 &&
test $(grep path5 out | cut "-d        " -f2) = path5 &&
grep path5 out | cut "-d       " -f1 | (read s1 s2 s3 &&
test -f ../$s1 &&
test $s2 = . &&
test $s3 = . &&
test $(cat ../$s1) = tree1asubdir/path5)
)
*   ok 17: checkout --temp within subdir

* expecting success:
rm -f path* .merge_* out .git/index &&
ln -s b a &&
git update-index --add a &&
t4=$(git write-tree) &&
rm -f .git/index &&
git read-tree $t4 &&
git checkout-index --temp -a >out &&
test $(wc -l <out) = 1 &&
test $(cut "-d  " -f2 out) = a &&
p=$(cut "-d     " -f1 out) &&
test -f $p &&
test $(cat $p) = b
*   ok 18: checkout --temp symlink

* passed all 18 test(s)
io1@mib19412i[00m:~/Desktop/git-1.5.6/t$

^ permalink raw reply


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