* Re: git-name-rev off-by-one bug
From: Junio C Hamano @ 2005-11-30 5:51 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0511292031280.3099@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> Whaddaya think? I really like it.
Yes. Maybe split this into 3 pieces. I do not want to waste
your time with that, so will take the liberty to do so myself,
with appropriate commit log messages, if you do not mind.
1. give diff-files -[012] flags.
2. merge-one-file leaves unmerged index entries.
3. always use -M -p in git-diff.
I do not have any issue against #1.
Regarding #2, in an earlier message you said something about
"patch to do that was just broken" which I did not understand; I
think your patch I am replying to is doing the right thing. That
case arm is dealing with a path that exists in "our" branch and
the working tree blob should be the same as recorded in the
HEAD, so I did not have to do the unpack-cat-chmod like I did in
mine. Am I simply confused?
About #3, I am not quite sure. I often use --name-status and I
do _not_ want -p to kick in when I do so. How about something
like this?
---
diff --git a/git-diff.sh b/git-diff.sh
index b3ec84b..8e0fe34 100755
--- a/git-diff.sh
+++ b/git-diff.sh
@@ -7,8 +7,6 @@ rev=$(git-rev-parse --revs-only --no-fla
flags=$(git-rev-parse --no-revs --flags --sq "$@")
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
-: ${flags:="'-M' '-p'"}
-
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
# obviously I mean 'git diff --cached -p HEAD' in that case.
case "$rev" in
@@ -20,6 +18,21 @@ case "$rev" in
esac
esac
+# If we do not have --name-status, --name-only nor -r, default to -p.
+# If we do not have -B nor -C, default to -M.
+case " $flags " in
+*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* )
+ ;;
+*)
+ flags="$flags '-p'" ;;
+esac
+case " $flags " in
+*" '-"[BCM]* | *" '--find-copies-harder' "*)
+ ;; # something like -M50.
+*)
+ flags="$flags '-M'" ;;
+esac
+
case "$rev" in
?*' '?*' '?*)
echo >&2 "I don't understand"
^ permalink raw reply related
* Re: git-name-rev off-by-one bug
From: Linus Torvalds @ 2005-11-30 5:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: linux, git, pasky
In-Reply-To: <Pine.LNX.4.64.0511291852530.3099@g5.osdl.org>
On Tue, 29 Nov 2005, Linus Torvalds wrote:
>
> Something like this (untested, of course).
>
> It _should_ write out
>
> * Unmerged path <filename>
>
> followed by a regular diff, exactly like you'd want.
The more I thinking about this, the more I think this is a wonderful
approach, but it would be even better to add a flag to let it choose
between diffing against stage2 by default or diffing against stage3 (and
hey, maybe even diffing against the original).
In fact, here's a patch that does that, and also makes the "resolve" merge
create these kinds of merges. As usual, my python knowledge is useless,
since the only thing I know about python is that thou shalt not count to
four. As a result, the standard recursive merge doesn't do this yet ;(
The magic incantation is to just do
git diff
and you'll get a diff against the first branch. If you want a diff against
the second branch, just use the "-2" option, and if you want a diff
against the common base (which is actually surprisingly useful, I noticed,
when I tried this with a conflict), use "-0".
I've also changed "git diff" to _not_ drop the "-M" and "-p" options just
because you give some other diff option. That was always a mistake. If you
really want the raw git diff format, use the raw "git-diff-xyz" programs
directly.
Whaddaya think? I really like it. Here's an example, where I merged two
branches that had the file "hello" in it, and the first branch had:
Hi there
This is the master branch
and the second one had
Hi there
This is the 'other' branch
and the base version had just the "Hi there", of course.
The default (or "-1" arg) behaviour is:
[torvalds@g5 test-merge]$ git diff
* Unmerged path hello
diff --git a/hello b/hello
index 7cebcf8..3fa4697 100644
--- a/hello
+++ b/hello
@@ -1,2 +1,6 @@
Hi there
+<<<<<<< hello
This is the master branch
+=======
+This is the 'other' branch
+>>>>>>> .merge_file_fJWiNf
which is obvious enough. You see exactly the conflict, and you see the
part of the first branch that is unchanged.
Diffing against the original gives you
[torvalds@g5 test-merge]$ git diff -0
* Unmerged path hello
diff --git a/hello b/hello
index 6530b63..3fa4697 100644
--- a/hello
+++ b/hello
@@ -1 +1,6 @@
Hi there
+<<<<<<< hello
+This is the master branch
+=======
+This is the 'other' branch
+>>>>>>> .merge_file_fJWiNf
which I actually found really readable. I realize that this is a really
stupid example, but for a lot of trivial merges, this won't be _that_ far
off, and it basically shows what happened in both branches, and ignores
what neither side changed.
The "-2" in this case is just the same as "-1" except obviously the "+"
characters are situated differently. Still useful (especially if the
changes were more complex).
Me likee. Hope you guys do too.
(And this is quite independently of the advantage that you can't commit an
unmerged state by mistake, which is perhaps an even bigger one).
Linus
---
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 6b496ed..afc7334 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -18,6 +18,12 @@
object name of pre- and post-image blob on the "index"
line when generating a patch format output.
+-0 -1 -2::
+ When an unmerged entry is seen, diff against the base version,
+ the "first branch" or the "second branch" respectively.
+
+ The default is to diff against the first branch.
+
-B::
Break complete rewrite changes into pairs of delete and create.
diff --git a/diff-files.c b/diff-files.c
index 38599b5..d744636 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -13,6 +13,7 @@ COMMON_DIFF_OPTIONS_HELP;
static struct diff_options diff_options;
static int silent = 0;
+static int diff_unmerged_stage = 2;
static void show_unmerge(const char *path)
{
@@ -46,7 +47,13 @@ int main(int argc, const char **argv)
argc--;
break;
}
- if (!strcmp(argv[1], "-q"))
+ if (!strcmp(argv[1], "-0"))
+ diff_unmerged_stage = 1;
+ else if (!strcmp(argv[1], "-1"))
+ diff_unmerged_stage = 2;
+ else if (!strcmp(argv[1], "-2"))
+ diff_unmerged_stage = 3;
+ else if (!strcmp(argv[1], "-q"))
silent = 1;
else if (!strcmp(argv[1], "-r"))
; /* no-op */
@@ -95,11 +102,23 @@ int main(int argc, const char **argv)
if (ce_stage(ce)) {
show_unmerge(ce->name);
- while (i < entries &&
- !strcmp(ce->name, active_cache[i]->name))
+ while (i < entries) {
+ struct cache_entry *nce = active_cache[i];
+
+ if (strcmp(ce->name, nce->name))
+ break;
+ /* Prefer to diff against the proper unmerged stage */
+ if (ce_stage(nce) == diff_unmerged_stage)
+ ce = nce;
i++;
- i--; /* compensate for loop control increments */
- continue;
+ }
+ /*
+ * Compensate for loop update
+ */
+ i--;
+ /*
+ * Show the diff for the 'ce' we chose
+ */
}
if (lstat(ce->name, &st) < 0) {
diff --git a/git-diff.sh b/git-diff.sh
index b3ec84b..efe8f75 100755
--- a/git-diff.sh
+++ b/git-diff.sh
@@ -3,12 +3,13 @@
# Copyright (c) 2005 Linus Torvalds
# Copyright (c) 2005 Junio C Hamano
+# Some way to turn these off?
+default_flags="-M -p"
+
rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
-flags=$(git-rev-parse --no-revs --flags --sq "$@")
+flags=$(git-rev-parse --no-revs --flags --sq $default_flags "$@")
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
-: ${flags:="'-M' '-p'"}
-
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
# obviously I mean 'git diff --cached -p HEAD' in that case.
case "$rev" in
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index c3eca8b..739a072 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -79,11 +79,7 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
esac
- # We reset the index to the first branch, making
- # git-diff-file useful
- git-update-index --add --cacheinfo "$6" "$2" "$4"
- git-checkout-index -u -f -- "$4" &&
- merge "$4" "$orig" "$src2"
+ merge "$4" "$orig" "$src2"
ret=$?
rm -f -- "$orig" "$src2"
^ permalink raw reply related
* Re: [PATCH] SVN import: Use one log call
From: Nicolas Pitre @ 2005-11-30 3:54 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Matthias Urlichs, git
In-Reply-To: <7vhd9vdx1o.fsf@assigned-by-dhcp.cox.net>
On Tue, 29 Nov 2005, Junio C Hamano wrote:
> BTW, I've never successfully managed to run svnimport from my
> private svn repository.
Same here, with the following public repo: svn://mielke.cc/main/brltty
> $ git svnimport -v -i -t photocat http://127.0.0.1/svn/private main/sources
> 1: Unrecognized path: /main/sources
> 1: Unrecognized path: /main/in-place
> 1: Unrecognized path: /main
> ...
> 1500: Unrecognized path: /main/sources/photocat/db/catalog.sql
> 1501: Unrecognized path: /main/sources/photocat/data/035-maribon-making.yaml
> DONE; creating master branch
> cp: cannot stat `/var/tmp/try0/.git/refs/heads/origin': No such file or directory
> fatal: master: not a valid SHA1
> $
And I only get similar results.
> If your answer is "your repository layout is too weird and
> nonstandard, you are screwed", that is perfectly fine. I do not
> want you to bend over backwards to butcher the import script to
> support it, if it is too nonstandard.
Thing is the above repository is not _that_ weird. And with the real
svn it produces a proper source tree of course, without any special
options. So I would think git-svnimport should be able to do the same.
No?
Nicolas
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: linux @ 2005-11-30 3:15 UTC (permalink / raw)
To: junkio, torvalds; +Cc: git, linux, pasky
In-Reply-To: <7v4q5u50gp.fsf@assigned-by-dhcp.cox.net>
> This one is done with the updated merge-one-file, which leaves
> unmerged entries in the index file to prevent unresolved merge
> from getting committed by mistake.
>
> After "git pull ..." fails, earlier the user said:
>
> $ git-diff
>
> to see half-merged state. Now git-diff just says:
>
> $ git-diff
> * Unmerged path ls-tree.c
>
> In order to get the earlier "show me the failed merge relative
> to my HEAD", you can say:
>
> $ git-diff HEAD ls-tree.c
Cool! You all know I like this change, mostly because it makes git's
merging conceptually cleaner and easier to explain.
Looking at git, the difference between it and other SCMs is the emphasis
on merging over editing. The tools for local development are a bit
primitive in core git, but that's a well-understood problem and the
tools can be implemented as needed.
What makes git special is the assumption that a patch is going to pass
through several people on its way from the text editor to the release,
so merging is actually more important than initial writing.
Rather than saying "Linus doesn't scale" and giving up, it's seen as an
Amdahl's law problem - the goal is to remove as much work from Linus as
possible and thus make him scale. (The shorter and earther way to say
this is that Linus is a lazy bastard, which is no surprise to anyone
who's seen him try to hide behind a podium. ;-) )
And an essential part of making that work is a good toolkit for dealing
with merging, and particularly in-progress merges. By having the
concept of an unmerged index, git lets you develop merging algorithms
in a modular way, as opposed to "one big hairy pile of magic DWIMmery"
that people are afraid to touch.
For example, one thing I'm sure will arrive fairly soon is file-type
specific merge algorithms. For something like a .po file where the
order of sections doesn't matter, merging ad->abd and ad->acd can be
fully automated.
There are a number of good idea in git, but from what I've seen so far,
"git-read-tree -m" is the most important one.
Making git-diff Do The Right Thing is a relatively minor matter.
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: Linus Torvalds @ 2005-11-30 3:12 UTC (permalink / raw)
To: Junio C Hamano; +Cc: linux, git, pasky
In-Reply-To: <7v4q5u50gp.fsf@assigned-by-dhcp.cox.net>
On Tue, 29 Nov 2005, Junio C Hamano wrote:
>
> I have actually resolved one conflicting merge with this and it
> was OK, except that it was a bit unpleasant when I first did
> "git-diff-index HEAD" without giving any path ;-),
What does "git-diff-files" do? Just output a lot of nasty "unmerged"
messages?
The _nice_ thing to do would be to output one "unmerged" message, but
then diff against stage2 if it exists (and it basically always should,
since otherwise we wouldn't have gotten a merge error).
If it did that, then you'd have the best of both world: the old nice "git
diff" behaviour _and_ being safe (and saying that it's unmerged).
Something like this (untested, of course).
It _should_ write out
* Unmerged path <filename>
followed by a regular diff, exactly like you'd want.
[ This all assumes that merge-one-file leaves the stages right. I think my
patch to do that was just broken. Yours was probably not. ]
Linus
---
diff --git a/diff-files.c b/diff-files.c
index 38599b5..8a78326 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -95,11 +95,23 @@ int main(int argc, const char **argv)
if (ce_stage(ce)) {
show_unmerge(ce->name);
- while (i < entries &&
- !strcmp(ce->name, active_cache[i]->name))
+ while (i < entries) {
+ struct cache_entry *nce = active_cache[i];
+
+ if (strcmp(ce->name, nce->name))
+ break;
+ /* Prefer to diff against stage 2 (original branch) */
+ if (ce_stage(nce) == 2)
+ ce = nce;
i++;
- i--; /* compensate for loop control increments */
- continue;
+ }
+ /*
+ * Compensate for loop update
+ */
+ i--;
+ /*
+ * Show the diff for the 'ce' we chose
+ */
}
if (lstat(ce->name, &st) < 0) {
^ permalink raw reply related
* Re: [PATCH] SVN import: Use one log call
From: Matthias Urlichs @ 2005-11-30 2:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vhd9vdx1o.fsf@assigned-by-dhcp.cox.net>
Hi,
Junio C Hamano:
> $ git svnimport -v -i -t photocat http://127.0.0.1/svn/private main/sources
> ...
> 1500: Unrecognized path: /main/sources/photocat/db/catalog.sql
Hmmm, "git-svnimport -T main/sources" should work. Somewhat.
>>/
>> utils/
>> calc/
>> trunk/
>> tags/
>> branches/
>> calendar/
>> trunk/
>> tags/
>> branches/
>> …
> but I wonder if we want to
> support importing from "utils" level.
>
That'd require somewhat more flexible support for reordering the
repository path elements than we have now, I'm afraid, thus the answer
to that particular question is "import both separately, then merge
into a common git repo if you really need to". We *can* do that, after
all. ;-)
--
Matthias Urlichs | {M:U} IT Design @ m-u-it.de | smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
- -
You goddamn cornhuskers are all alike.
-- Jim Thompson
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: Junio C Hamano @ 2005-11-30 2:33 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux, junkio, git, pasky
In-Reply-To: <Pine.LNX.4.64.0511291742000.3135@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> Junio?
>
> The problem (I think) was that "git-diff-file" did bad things with
> unmerged entries. That's what the comment in git-merge-one-file implies.
> But otherwise this should just make it so..
>
> Do you want to test this out?
I have actually resolved one conflicting merge with this and it
was OK, except that it was a bit unpleasant when I first did
"git-diff-index HEAD" without giving any path ;-), but the users
will get used to it. Pushed out as a part of the proposed
updates collection.
Here is what I wrote as the commit log message for the
hand-resolved merge using this updated merge-one-file.
commit 6b48f6ff7ffff6ca0f9da53d9423a0474dd008fd
Merge: b4f40b90ed1d9e1f3c0557e1ba064d169ba03a1c 99e01692063cc48adee19e1f738472a579c14ca2
Author: Junio C Hamano <junkio@cox.net>
Date: Tue Nov 29 18:25:29 2005 -0800
Merge branch 'jc/subdir'
This one is done with the updated merge-one-file, which leaves
unmerged entries in the index file to prevent unresolved merge
from getting committed by mistake.
After "git pull ..." fails, earlier the user said:
$ git-diff
to see half-merged state. Now git-diff just says:
$ git-diff
* Unmerged path ls-tree.c
In order to get the earlier "show me the failed merge relative
to my HEAD", you can say:
$ git-diff HEAD ls-tree.c
Signed-off-by: Junio C Hamano <junkio@cox.net>
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: Junio C Hamano @ 2005-11-30 2:06 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0511291742000.3135@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> If we left things in the index in an unmerged state, we'd be guaranteed to
> either _fail_ that git commit unless somebody has done the
> git-update-index (or names the files specifically on the commit command
> line, which will do it for you).
>
> So I think I agree.
I suspect we are saying the same thing. Funny.
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: Linus Torvalds @ 2005-11-30 1:51 UTC (permalink / raw)
To: linux; +Cc: junkio, git, pasky
In-Reply-To: <20051130001503.28498.qmail@science.horizon.com>
On Tue, 29 Nov 2005, linux@horizon.com wrote:
>
> You seem to be saying that producing a merge with conflict markers is
> what you (almost) always want, so it's the default. No objections.
>
> But why collapse the index and only keep stage2? Why not leave all
> stages in the index *and* the merge-with-conflict-markers in the working
> directory?
That may actually work really well. It would also avoid one bug that we
have right now: if you fix things up by hand, but forget to explicitly do
a "git-update-index filename" or "git commit filename", a plain regular
"git commit" will happily commit all the changes _except_ for the ones you
have merged manually. It's happened once to me.
If we left things in the index in an unmerged state, we'd be guaranteed to
either _fail_ that git commit unless somebody has done the
git-update-index (or names the files specifically on the commit command
line, which will do it for you).
So I think I agree.
Junio?
The problem (I think) was that "git-diff-file" did bad things with
unmerged entries. That's what the comment in git-merge-one-file implies.
But otherwise this should just make it so..
Do you want to test this out?
Linus
---
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index c3eca8b..739a072 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -79,11 +79,7 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
esac
- # We reset the index to the first branch, making
- # git-diff-file useful
- git-update-index --add --cacheinfo "$6" "$2" "$4"
- git-checkout-index -u -f -- "$4" &&
- merge "$4" "$orig" "$src2"
+ merge "$4" "$orig" "$src2"
ret=$?
rm -f -- "$orig" "$src2"
^ permalink raw reply related
* Re: git-name-rev off-by-one bug
From: Junio C Hamano @ 2005-11-30 1:27 UTC (permalink / raw)
To: linux; +Cc: git
In-Reply-To: <7v4q5v5536.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> linux@horizon.com writes:
>
>> I'm wondering if this isn't a philosophical issue.
>
> I do not think so....
> ...
> This is the message from Linus that announced the current
> behaviour:
>
> http://marc.theaimsgroup.com/?l=git&m=111826424425624
Replying to myself. In the message, Linus talks about being
able to do (diff-cache is an old name for diff-index):
git-diff-files -p xyzzy ;# to compare with our version
git-diff-cache -p MERGE_HEAD xyzzy ;# to compare with his
But because of the "index before merge has to match HEAD" rule,
the first one could have been written as:
git-diff-index -p HEAD xyzzy ;# to compare with ours
So in that sense, I suspect it may not be too bad if we just
changed merge-one-file with the patch at the end.
However, git-diff-index HEAD without paths restriction would
show everything the merge brought in, not just the conflicting
path, so in that sense it may make things slightly harder for
the end user to use.
---
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index c3eca8b..df6dd67 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -79,11 +79,12 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
esac
- # We reset the index to the first branch, making
- # git-diff-file useful
- git-update-index --add --cacheinfo "$6" "$2" "$4"
- git-checkout-index -u -f -- "$4" &&
- merge "$4" "$orig" "$src2"
+ # Leave the conflicts in stages; failed merge result can be
+ # seen by "git-diff-index HEAD" or "git-diff-index MERGE_HEAD"
+ rm -fr "$4" &&
+ git-cat-file blob "$2" >"$4" &&
+ case "$6" in *?7??) chmod +x "$4" ;; esac &&
+ merge "$4" "$orig" "$src2"
ret=$?
rm -f -- "$orig" "$src2"
^ permalink raw reply related
* Re: git-name-rev off-by-one bug
From: Junio C Hamano @ 2005-11-30 0:53 UTC (permalink / raw)
To: linux; +Cc: junkio, git, pasky
In-Reply-To: <20051130001503.28498.qmail@science.horizon.com>
linux@horizon.com writes:
> I'm wondering if this isn't a philosophical issue.
I do not think so. I have to admit I did not exactly agree with
the current behaviour when it was changed from the previous one,
but at the same time I did not have anything concrete against
it, and I did not care too much about the details back then. I
suspect it was primarily be done to make things easier for the
end user without changing already existing tools (i.e.,
git-diff-files did not have to start taking --stage=2 flag to
tell it to compare stage2 and working tree).
This is the message from Linus that announced the current
behaviour:
http://marc.theaimsgroup.com/?l=git&m=111826424425624
^ permalink raw reply
* Re: [PROBE] cg-commit: show and enable editing of changes with --review
From: Junio C Hamano @ 2005-11-30 0:30 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: git
In-Reply-To: <20051130000131.GC5365@diku.dk>
Jonas Fonseca <fonseca@diku.dk> writes:
> Show changes being commited as a patch appended to the commit message
> buffer. If the original patch is different from the patch extracted from
> the commit message file the original patch will be reverted and the edited
> patch applied before completing the commit.
>
> Due to limitations with cg-patch this can only be used when commiting
> from the project root directory. The error handling if the either the
> original patch or the edited patch does not apply is not optimal, since
> cg-patch will not report errors properly.
I do not do Porcelains, I am not a Cogito user, and I generally
do not like encouraging people who are playing an individual
developer role to commit something that has never existed in
their working tree (hence by definition never been tested),
but...
> + echo "Updating changes to edited patch"
> + # FIXME: Can only be run from the top level
> + # FIXME: Is very 'fragile' error handling. We should probably
> + # save the original patch in a local file for recovery?
> + if ! cg-patch -R < $PATCH; then
> + backup=$(mktemp commit-backup.XXXXXX)
> + cp $PATCH $backup
> + error_msg="unable to revert original patch, backup saved to $backup"
I suspect at least you should be able to use checkout-index for
the first one instead of cg-patch.
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: linux @ 2005-11-30 0:15 UTC (permalink / raw)
To: junkio; +Cc: git, linux, pasky
In-Reply-To: <7vsltf6o8f.fsf@assigned-by-dhcp.cox.net>
> It is not silly. Actually we have "been there, done that".
Um, okay, but I don't see why you changed...
> We used to leave the higher stages around in the index after
> automerge failure. Note that you would not just have stage2 in
> such a case. stage1 keeps the common ancestor, stage2 has what
> you started with, and stage3 holds the version from other
> branch. diff-stages can be used to diff between these stages.
> We _could_ have added feature to either diff-stages or
> diff-files to compare between stageN and working tree.
Yes, exactly. This is what I expected.
> However, this turned out to be not so convenient as we wished
> initially. What you would do after inspecting diffs between
> stage1 and stage3, between stage2 and stage3 and between stage1
> and stage2 typically ends up doing what "merge" have tried (and
> failed) manually anyway, and being able to find the conflict
> markers by simply running "git diff" was just as good, except
> that we risk getting still-unresolved files checked in if the
> user is not careful.
You seem to be saying that producing a merge with conflict markers is
what you (almost) always want, so it's the default. No objections.
But why collapse the index and only keep stage2? Why not leave all
stages in the index *and* the merge-with-conflict-markers in the working
directory?
They you could, for example, try alternate single-file merge algorithms
on the conflict, or regenerate the conflict markers if you wanted.
By keeping all of the source material around until the user has decided
on a resolution, you achieve maximal flexibility.
This is no more effort for the user to use in the common case (edit the
conflicts and git-update-index), but lets you try various things in the
working directory and eaily back out of them. ("git-merge-index -s manual
-a" would regenerate all of the conflict markers.) And it prevents a
checkin until the matter has been resolved.
I'm wondering if this isn't a philosophical issue. One side says that,
since all automated merging is complete, the stages should be collapsed.
To me, it makes more sense to leave out the adjective "automated" and
consider the merge to be incomplete; we're just putting the user in the
loop when software fails.
^ permalink raw reply
* [PROBE] cg-commit: show and enable editing of changes with --review
From: Jonas Fonseca @ 2005-11-30 0:01 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Show changes being commited as a patch appended to the commit message
buffer. If the original patch is different from the patch extracted from
the commit message file the original patch will be reverted and the edited
patch applied before completing the commit.
Due to limitations with cg-patch this can only be used when commiting
from the project root directory. The error handling if the either the
original patch or the edited patch does not apply is not optimal, since
cg-patch will not report errors properly.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
commit 5031c74c4716793784314f836f4ceb6bcfa6698a
tree d01b7a66054352a89c637d58c7ab6454a26ba700
parent dd872816a04f6462686e282b00d3e1523e3ecf4c
author Jonas Fonseca <fonseca@diku.dk> Wed, 30 Nov 2005 00:41:06 +0100
committer Jonas Fonseca <fonseca@antimatter.localdomain> Wed, 30 Nov 2005 00:41:06 +0100
TODO | 4 ----
cg-commit | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/TODO b/TODO
index 777c728..cffa753 100644
--- a/TODO
+++ b/TODO
@@ -79,10 +79,6 @@ cg-*patch should be pre-1.0.)
whitespace errors and stuff; hooks are good for this too,
but I think it's good to have internal support for the
basic stuff.
- -- post 1.0 --
- * Patch-altering cg-commit
- You can already alter the list of files to be committed,
- let's optionally show the patch and let you alter it, too.
* cg-push over HTTP
diff --git a/cg-commit b/cg-commit
index 9f8d5d5..1a3c361 100755
--- a/cg-commit
+++ b/cg-commit
@@ -63,6 +63,12 @@
# Optionally, specify the exact name and email to sign off with by
# passing: `--signoff="Author Name <user@example.com>"`.
#
+# --review:: Show and enable editing of changes being committed
+# Show changes being commited as a patch appended to the commit message
+# buffer. Changes made to the patch will be reapplied before completing
+# the commit. Only makes sense with interactive commit message editing.
+# Note, can only be used when commiting from the project root directory.
+#
# FILES
# -----
# $GIT_DIR/author::
@@ -153,6 +159,7 @@ ignorecache=
infoonly=
commitalways=
missingok=
+review=
signoff=
copy_commit=
msgs=()
@@ -172,6 +179,9 @@ while optparse; do
force=1
elif optparse -q; then
quiet=1
+ elif optparse --review; then
+ [ "$_git_relpath" ] && die "--review can only be used when run from project root"
+ review=1
elif optparse -s || optparse --signoff; then
[ "$signoff" ] || signoff="$(git-var GIT_AUTHOR_IDENT | sed 's/> .*/>/')"
elif optparse --signoff=; then
@@ -187,6 +197,11 @@ done
[ "$ignorecache" ] || cg-object-id HEAD >/dev/null 2>&1 || die "no previous commit; use -C for the initial commit"
+if [ "$review" ]; then
+ PATCH=$(mktemp -t gitci.XXXXXX)
+ PATCH2=$(mktemp -t gitci.XXXXXX)
+fi
+
if [ "$ARGS" -o "$_git_relpath" ]; then
[ "$ignorecache" ] && die "-C and listing files to commit does not make sense"
[ -s $_git/merging ] && die "cannot commit individual files when merging"
@@ -201,6 +216,7 @@ if [ "$ARGS" -o "$_git_relpath" ]; then
sed 's/^\([^ ]*\)\(. .*\)\( .*\)*$/"\2"/'))
customfiles=1
+ [ "$review" ] && < $filter | path_xargs git-diff-index -r -p HEAD > $PATCH
rm $filter
else
@@ -227,6 +243,8 @@ else
fi
fi
+ [ "$review" ] && git-diff-index -r -p HEAD > $PATCH
+
merging=
[ -s $_git/merging ] && merging=$(cat $_git/merging | sed 's/^/-p /')
fi
@@ -347,7 +365,21 @@ if [ ! "$ignorecache" ]; then
fi
fi
echo "CG: -----------------------------------------------------------------------" >>$LOGMSG
-echo "CG: vim: textwidth=75" >>$LOGMSG
+
+if [ "$review" ]; then
+ {
+ echo "CG:"
+ echo "CG: Change summary:"
+ echo "CG:"
+ git-apply --stat --summary < $PATCH | sed 's/^/CG: /'
+ echo "CG:"
+ cat $PATCH
+ } >>$LOGMSG
+
+ ftdiff="filetype=diff"
+fi
+
+echo "CG: vim: textwidth=75 $ftdiff" >>$LOGMSG
cp $LOGMSG $LOGMSG2
if tty -s; then
@@ -359,6 +391,7 @@ if tty -s; then
read -p 'Abort or commit? [ac] ' choice
if [ "$choice" = "a" ] || [ "$choice" = "q" ]; then
rm $LOGMSG $LOGMSG2
+ [ "$review" ] && rm $PATCH $PATCH2
echo "Commit message not modified, commit aborted" >&2
if [ "$merging" ]; then
cat >&2 <<__END__
@@ -400,9 +433,35 @@ else
cat >$LOGMSG2
fi
# Remove heading and trailing blank lines.
-grep -v ^CG: $LOGMSG2 | git-stripspace >$LOGMSG
+if [ ! "$review" ]; then
+ grep -v ^CG: $LOGMSG2 | git-stripspace >$LOGMSG
+else
+ sed '/^CG: Change summary:/,$d' < $LOGMSG2 | grep -v ^CG: | git-stripspace >$LOGMSG
+ sed -n '/^CG: Change summary:/,$p' < $LOGMSG2 | grep -v ^CG: > $PATCH2
+fi
rm $LOGMSG2
+if [ "$review" ]; then
+ error_msg=
+ if ! cmp -s $PATCH $PATCH2; then
+ echo "Updating changes to edited patch"
+ # FIXME: Can only be run from the top level
+ # FIXME: Is very 'fragile' error handling. We should probably
+ # save the original patch in a local file for recovery?
+ if ! cg-patch -R < $PATCH; then
+ backup=$(mktemp commit-backup.XXXXXX)
+ cp $PATCH $backup
+ error_msg="unable to revert original patch, backup saved to $backup"
+ elif ! cg-patch < $PATCH2; then
+ backup=$(mktemp commit-backup.XXXXXX)
+ cp $PATCH2 $backup
+ error_msg="unable to apply edited patch, backup saved to $backup"
+ fi
+ fi
+ rm $PATCH $PATCH2
+ [ "$error_msg" ] && { rm $LOGMSG; die "$error_msg" }
+fi
+
precommit_update()
{
--
Jonas Fonseca
^ permalink raw reply related
* [PATCH] cg-commit: append sign off line when passed -s or --signoff
From: Jonas Fonseca @ 2005-11-29 23:58 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
No sign off line is appended if it already is signed off. By default the
identity reported by 'git-var GIT_AUTHOR_IDENT' is used for signing off.
Optionally, specify the name and email to sign off with by doing:
cg-commit --signoff='Author Name <user@example.com>
If the commit message specified on the command line already contains
signed off lines no empty line is inserted between the message and the
sign off line.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
commit dd872816a04f6462686e282b00d3e1523e3ecf4c
tree a8487566085727636a5782e2edb270190b9f3916
parent c0a9b8feb79d72f7c02f37392da840dbad446dbd
author Jonas Fonseca <fonseca@diku.dk> Mon, 28 Nov 2005 04:42:05 +0100
committer Jonas Fonseca <fonseca@antimatter.localdomain> Mon, 28 Nov 2005 04:42:05 +0100
TODO | 2 --
cg-commit | 17 ++++++++++++++++-
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/TODO b/TODO
index 5193d08..777c728 100644
--- a/TODO
+++ b/TODO
@@ -79,8 +79,6 @@ cg-*patch should be pre-1.0.)
whitespace errors and stuff; hooks are good for this too,
but I think it's good to have internal support for the
basic stuff.
- * -s,--signoff to automatically append a signoff line of
- yours to the patch.
-- post 1.0 --
* Patch-altering cg-commit
You can already alter the list of files to be committed,
diff --git a/cg-commit b/cg-commit
index d084c24..9f8d5d5 100755
--- a/cg-commit
+++ b/cg-commit
@@ -58,6 +58,11 @@
# Be quiet in case there's "nothing to commit", and silently exit
# returning success. In a sense, this is the opposite to '-f'.
#
+# -s, --signoff:: Automatically append a sign off line
+# Add Signed-off-by line at the end of the commit message.
+# Optionally, specify the exact name and email to sign off with by
+# passing: `--signoff="Author Name <user@example.com>"`.
+#
# FILES
# -----
# $GIT_DIR/author::
@@ -119,7 +124,7 @@
# EDITOR::
# The editor used for entering revision log information.
-USAGE="cg-commit [-m MESSAGE]... [-C] [-e | -E] [-c COMMIT_ID] [FILE]... [< MESSAGE]"
+USAGE="cg-commit [-m MESSAGE]... [-C] [-e | -E] [-s | --signoff] [-c COMMIT_ID] [FILE]... [< MESSAGE]"
. ${COGITO_LIB}cg-Xlib || exit 1
@@ -148,6 +153,7 @@ ignorecache=
infoonly=
commitalways=
missingok=
+signoff=
copy_commit=
msgs=()
quiet=
@@ -166,6 +172,10 @@ while optparse; do
force=1
elif optparse -q; then
quiet=1
+ elif optparse -s || optparse --signoff; then
+ [ "$signoff" ] || signoff="$(git-var GIT_AUTHOR_IDENT | sed 's/> .*/>/')"
+ elif optparse --signoff=; then
+ signoff="$OPTARG"
elif optparse -m=; then
msgs[${#msgs[@]}]="$OPTARG"
elif optparse -c=; then
@@ -292,6 +302,11 @@ fi >> $LOGMSG
# the poor people whose text editor has no 'O' command.
[ "$written" ] || echo >>$LOGMSG
+if [ "$signoff" ] && ! grep -q -i "signed-off-by: $signoff" $LOGMSG; then
+ grep -q -i sign-off-by $LOGMSG || echo
+ echo "Signed-off-by: $signoff"
+fi >> $LOGMSG
+
if [ -e "$_git/commit-template" ]; then
cat $_git/commit-template >>$LOGMSG
else
--
Jonas Fonseca
^ permalink raw reply related
* [PATCH] cg-object-id: accept $id when .git/refs/$id exists
From: Jonas Fonseca @ 2005-11-29 23:57 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Makes the (universal) -r argument work better with tools like bisect.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
... until cg-object-id will use git-rev-parse.
commit c0a9b8feb79d72f7c02f37392da840dbad446dbd
tree 8a44e96d29c2171ce1915165ce84d1b1f3e27807
parent f3576824058588cf3fdeca0a8b5ae46b9d37a812
author Jonas Fonseca <fonseca@diku.dk> Mon, 28 Nov 2005 03:49:11 +0100
committer Jonas Fonseca <fonseca@antimatter.localdomain> Mon, 28 Nov 2005 03:49:11 +0100
cg-object-id | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/cg-object-id b/cg-object-id
index f2cb54e..ec0362a 100755
--- a/cg-object-id
+++ b/cg-object-id
@@ -59,6 +59,9 @@ normalize_id()
elif [ -r "$_git/refs/heads/$id" ]; then
read id < "$_git/refs/heads/$id"
+ elif [ -r "$_git/refs/$id" ]; then
+ read id < "$_git/refs/$id"
+
# Short id's must be lower case and at least 4 digits.
elif [[ "$id" == [0-9a-f][0-9a-f][0-9a-f][0-9a-f]* ]]; then
idpref=${id:0:2}
--
Jonas Fonseca
^ permalink raw reply related
* Re: [OT] Activision (Re: use binmode(STDOUT) in git-status)
From: Johannes Schindelin @ 2005-11-29 23:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Alex Riesen, H. Peter Anvin, git
In-Reply-To: <7vwtir846o.fsf_-_@assigned-by-dhcp.cox.net>
Hi,
On Tue, 29 Nov 2005, Junio C Hamano wrote:
> Alex Riesen <raa.lkml@gmail.com> writes:
>
> > Johannes Schindelin, Mon, Nov 28, 2005 17:56:58 +0100:
> >> > if you're running Cygwin, wouldn't Cygwin's Perl make a lot more sense?
> >>
> >> I thought so, too, but I guess there's a reason that Activision's perl was
> >> used.
> >
> > the reason were incompatible scripts (notably, the ones expecting crlf).
>
> I wonder why people keep saying Activision ;-). Taken with my
> use of frotz and nitfol in the examples [*1*], somebody might
> confuse us with a group of old Infocom [*2*] fans.
Hey, you 0wn3d me there.
^ permalink raw reply
* Re: git-name-rev off-by-one bug
From: Junio C Hamano @ 2005-11-29 23:14 UTC (permalink / raw)
To: linux; +Cc: junkio, pasky, git
In-Reply-To: <20051129214055.8689.qmail@science.horizon.com>
linux@horizon.com writes:
> This seems odd to me. There's an alternate implementation that
> I described that makes a lot more sense to me, based on my current
> state of knowledge. Can someone explain why my idea is silly?
It is not silly. Actually we have "been there, done that".
We used to leave the higher stages around in the index after
automerge failure. Note that you would not just have stage2 in
such a case. stage1 keeps the common ancestor, stage2 has what
you started with, and stage3 holds the version from other
branch. diff-stages can be used to diff between these stages.
We _could_ have added feature to either diff-stages or
diff-files to compare between stageN and working tree.
However, this turned out to be not so convenient as we wished
initially. What you would do after inspecting diffs between
stage1 and stage3, between stage2 and stage3 and between stage1
and stage2 typically ends up doing what "merge" have tried (and
failed) manually anyway, and being able to find the conflict
markers by simply running "git diff" was just as good, except
that we risk getting still-unresolved files checked in if the
user is not careful.
If you want to be clever about an automated merge, you could
write a new merge strategy to take the three trees and produce a
better automerge result. That is what Fredrik has done in his
git-merge-recursive (now default). Or you could "improve"
git-merge-one-file to take three blob object names and leave
file~1 file~2 file~3 in the working tree, instead of (or in
addition to) leaving a "merge" result with conflict markers, to
give the user ready access to the version from each stage.
^ permalink raw reply
* [OT] Activision (Re: use binmode(STDOUT) in git-status)
From: Junio C Hamano @ 2005-11-29 22:44 UTC (permalink / raw)
To: Alex Riesen; +Cc: Johannes Schindelin, H. Peter Anvin, git
In-Reply-To: <20051129221221.GC3033@steel.home>
Alex Riesen <raa.lkml@gmail.com> writes:
> Johannes Schindelin, Mon, Nov 28, 2005 17:56:58 +0100:
>> > if you're running Cygwin, wouldn't Cygwin's Perl make a lot more sense?
>>
>> I thought so, too, but I guess there's a reason that Activision's perl was
>> used.
>
> the reason were incompatible scripts (notably, the ones expecting crlf).
I wonder why people keep saying Activision ;-). Taken with my
use of frotz and nitfol in the examples [*1*], somebody might
confuse us with a group of old Infocom [*2*] fans.
[1] http://en.wikipedia.org/wiki/Nitfol
[2] http://web.mit.edu/6.933/www/Fall2000/infocom/
^ permalink raw reply
* Re: use binmode(STDOUT) in git-status
From: Alex Riesen @ 2005-11-29 22:12 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: H. Peter Anvin, git, Junio C Hamano
In-Reply-To: <Pine.LNX.4.63.0511281756001.11697@wbgn013.biozentrum.uni-wuerzburg.de>
Johannes Schindelin, Mon, Nov 28, 2005 17:56:58 +0100:
> > if you're running Cygwin, wouldn't Cygwin's Perl make a lot more sense?
>
> I thought so, too, but I guess there's a reason that Activision's perl was
> used.
the reason were incompatible scripts (notably, the ones expecting crlf).
^ permalink raw reply
* Re: [PATCH] Make git-mv work in subdirectories, too
From: Alex Riesen @ 2005-11-29 22:10 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7vmzjsdt3z.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano, Sat, Nov 26, 2005 03:45:52 +0100:
> > Turns out, all git programs git-mv uses are capable of operating in
> > a subdirectory just fine. So don't complain about it.
> >
> > Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> >
> > ---
> >
> > I am no Perl guru, so this might not be the best way to go
> > about it. Also, if people agree, I would like to remove the
> > extra check for GIT_DIR validity, since git-rev-parse --git-dir
> > does that already.
>
> I think that sounds sane. You need to grab the exit status from
> `git-rev-parse --git-dir`, so the patch would become something
> like the attached. I haven't seriously used git-mv myself, so
> somebody needs to test it, and if it actually works and Ack on
> it, please.
It actually works in subdirs.
--- t/t4007-mv.sh
#!/bin/sh
test_description='git-mv in subdirs'
. ./test-lib.sh
test_expect_success \
'prepare reference tree' \
'mkdir path0 path1 &&
cp ../../COPYING path0/COPYING &&
git-add path0/COPYING &&
git-commit -m add -a'
test_expect_success \
'moving the file' \
'cd path0 && git-mv COPYING ../path1/COPYING'
# in path0 currently
test_expect_success \
'commiting the change' \
'cd .. && git-commit -m move -a'
test_expect_success \
'checking the commit' \
'git-diff-tree -r -M --name-status HEAD^ HEAD | \
grep -E "^R100.+path0/COPYING.+path1/COPYING"'
test_done
^ permalink raw reply
* [PATCH 2/7] Use git-rev-parse to find the local GIT repository
From: Chuck Lever @ 2005-11-29 22:09 UTC (permalink / raw)
To: catalin.marinas; +Cc: git
In-Reply-To: <20051129220552.9885.41086.stgit@dexter.citi.umich.edu>
Use the latest git-rev-parse technology to allow some StGIT commands to
function correctly in subdirectories of the working directory.
Any command that relies on git-read-tree still doesn't work (changes to
GIT forthcoming).
Signed-off-by: Chuck Lever <cel@netapp.com>
---
stgit/commands/branch.py | 2 +-
stgit/commands/common.py | 4 ++--
stgit/commands/export.py | 2 +-
stgit/commands/mail.py | 4 ++--
stgit/commands/resolved.py | 4 ++--
stgit/git.py | 35 ++++++++++++++++++-----------------
stgit/stack.py | 9 +++++----
7 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/stgit/commands/branch.py b/stgit/commands/branch.py
index 9bf6cdb..c3f7944 100644
--- a/stgit/commands/branch.py
+++ b/stgit/commands/branch.py
@@ -136,7 +136,7 @@ def func(parser, options, args):
if len(args) != 0:
parser.error('incorrect number of arguments')
- branches = os.listdir(os.path.join(git.base_dir, 'refs', 'heads'))
+ branches = os.listdir(os.path.join(git.get_base_dir(), 'refs', 'heads'))
branches.sort()
print 'Available branches:'
diff --git a/stgit/commands/common.py b/stgit/commands/common.py
index e437111..8084cbd 100644
--- a/stgit/commands/common.py
+++ b/stgit/commands/common.py
@@ -96,7 +96,7 @@ def check_head_top_equal():
' are doing, use the "refresh -f" command'
def check_conflicts():
- if os.path.exists(os.path.join(git.base_dir, 'conflicts')):
+ if os.path.exists(os.path.join(git.get_base_dir(), 'conflicts')):
raise CmdException, 'Unsolved conflicts. Please resolve them first'
def print_crt_patch(branch = None):
@@ -130,7 +130,7 @@ def resolved_all(reset = None):
if conflicts:
for filename in conflicts:
resolved(filename, reset)
- os.remove(os.path.join(git.base_dir, 'conflicts'))
+ os.remove(os.path.join(git.get_base_dir(), 'conflicts'))
def name_email(address):
"""Return a tuple consisting of the name and email parsed from a
diff --git a/stgit/commands/export.py b/stgit/commands/export.py
index 167a8d3..c93ab6e 100644
--- a/stgit/commands/export.py
+++ b/stgit/commands/export.py
@@ -132,7 +132,7 @@ def func(parser, options, args):
else:
patch_tmpl_list = []
- patch_tmpl_list += [os.path.join(git.base_dir, 'patchexport.tmpl'),
+ patch_tmpl_list += [os.path.join(git.get_base_dir(), 'patchexport.tmpl'),
os.path.join(sys.prefix,
'share/stgit/templates/patchexport.tmpl')]
tmpl = ''
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index 7cc18bc..b3b7b49 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -419,7 +419,7 @@ def func(parser, options, args):
if options.cover:
tfile_list = [options.cover]
else:
- tfile_list = [os.path.join(git.base_dir, 'covermail.tmpl'),
+ tfile_list = [os.path.join(git.get_base_dir(), 'covermail.tmpl'),
os.path.join(sys.prefix,
'share/stgit/templates/covermail.tmpl')]
@@ -450,7 +450,7 @@ def func(parser, options, args):
if options.template:
tfile_list = [options.template]
else:
- tfile_list = [os.path.join(git.base_dir, 'patchmail.tmpl'),
+ tfile_list = [os.path.join(git.get_base_dir(), 'patchmail.tmpl'),
os.path.join(sys.prefix,
'share/stgit/templates/patchmail.tmpl')]
tmpl = None
diff --git a/stgit/commands/resolved.py b/stgit/commands/resolved.py
index d21ecc9..585c51b 100644
--- a/stgit/commands/resolved.py
+++ b/stgit/commands/resolved.py
@@ -65,8 +65,8 @@ def func(parser, options, args):
# save or remove the conflicts file
if conflicts == []:
- os.remove(os.path.join(git.base_dir, 'conflicts'))
+ os.remove(os.path.join(git.get_base_dir(), 'conflicts'))
else:
- f = file(os.path.join(git.base_dir, 'conflicts'), 'w+')
+ f = file(os.path.join(git.get_base_dir(), 'conflicts'), 'w+')
f.writelines([line + '\n' for line in conflicts])
f.close()
diff --git a/stgit/git.py b/stgit/git.py
index b19f75f..2cedeaa 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -27,12 +27,6 @@ class GitException(Exception):
pass
-# Different start-up variables read from the environment
-if 'GIT_DIR' in os.environ:
- base_dir = os.environ['GIT_DIR']
-else:
- base_dir = '.git'
-
#
# Classes
@@ -87,6 +81,15 @@ __commits = dict()
#
# Functions
#
+
+def get_base_dir():
+ """Different start-up variables read from the environment
+ """
+ if 'GIT_DIR' in os.environ:
+ return os.environ['GIT_DIR']
+ else:
+ return _output_one_line('git-rev-parse --git-dir')
+
def get_commit(id_hash):
"""Commit objects factory. Save/look-up them in the __commits
dictionary
@@ -103,7 +106,7 @@ def get_commit(id_hash):
def get_conflicts():
"""Return the list of file conflicts
"""
- conflicts_file = os.path.join(base_dir, 'conflicts')
+ conflicts_file = os.path.join(get_base_dir(), 'conflicts')
if os.path.isfile(conflicts_file):
f = file(conflicts_file)
names = [line.strip() for line in f.readlines()]
@@ -167,9 +170,6 @@ def __run(cmd, args=None):
return r
return 0
-def __check_base_dir():
- return os.path.isdir(base_dir)
-
def __tree_status(files = None, tree_id = 'HEAD', unknown = False,
noexclude = True):
"""Returns a list of pairs - [status, filename]
@@ -182,7 +182,7 @@ def __tree_status(files = None, tree_id
# unknown files
if unknown:
- exclude_file = os.path.join(base_dir, 'info', 'exclude')
+ exclude_file = os.path.join(get_base_dir(), 'info', 'exclude')
base_exclude = ['--exclude=%s' % s for s in
['*.[ao]', '*.pyc', '.*', '*~', '#*', 'TAGS', 'tags']]
base_exclude.append('--exclude-per-directory=.gitignore')
@@ -296,8 +296,8 @@ def create_branch(new_branch, tree_id =
if tree_id:
switch(tree_id)
- if os.path.isfile(os.path.join(base_dir, 'MERGE_HEAD')):
- os.remove(os.path.join(base_dir, 'MERGE_HEAD'))
+ if os.path.isfile(os.path.join(get_base_dir(), 'MERGE_HEAD')):
+ os.remove(os.path.join(get_base_dir(), 'MERGE_HEAD'))
def switch_branch(name):
"""Switch to a git branch
@@ -316,8 +316,8 @@ def switch_branch(name):
__head = tree_id
set_head_file(new_head)
- if os.path.isfile(os.path.join(base_dir, 'MERGE_HEAD')):
- os.remove(os.path.join(base_dir, 'MERGE_HEAD'))
+ if os.path.isfile(os.path.join(get_base_dir(), 'MERGE_HEAD')):
+ os.remove(os.path.join(get_base_dir(), 'MERGE_HEAD'))
def delete_branch(name):
"""Delete a git branch
@@ -325,7 +325,7 @@ def delete_branch(name):
branch_head = os.path.join('refs', 'heads', name)
if not branch_exists(branch_head):
raise GitException, 'Branch "%s" does not exist' % name
- os.remove(os.path.join(base_dir, branch_head))
+ os.remove(os.path.join(get_base_dir(), branch_head))
def rename_branch(from_name, to_name):
"""Rename a git branch
@@ -339,7 +339,8 @@ def rename_branch(from_name, to_name):
if get_head_file() == from_name:
set_head_file(to_head)
- os.rename(os.path.join(base_dir, from_head), os.path.join(base_dir, to_head))
+ os.rename(os.path.join(get_base_dir(), from_head), \
+ os.path.join(get_base_dir(), to_head))
def add(names):
"""Add the files or recursively add the directory contents
diff --git a/stgit/stack.py b/stgit/stack.py
index 18b4c6e..dc7c19f 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -66,7 +66,7 @@ def __clean_comments(f):
def edit_file(series, line, comment, show_patch = True):
fname = '.stgit.msg'
- tmpl = os.path.join(git.base_dir, 'patchdescr.tmpl')
+ tmpl = os.path.join(git.get_base_dir(), 'patchdescr.tmpl')
f = file(fname, 'w+')
if line:
@@ -263,9 +263,10 @@ class Series:
self.__name = git.get_head_file()
if self.__name:
- self.__patch_dir = os.path.join(git.base_dir, 'patches',
+ base_dir = git.get_base_dir()
+ self.__patch_dir = os.path.join(base_dir, 'patches',
self.__name)
- self.__base_file = os.path.join(git.base_dir, 'refs', 'bases',
+ self.__base_file = os.path.join(base_dir, 'refs', 'bases',
self.__name)
self.__applied_file = os.path.join(self.__patch_dir, 'applied')
self.__unapplied_file = os.path.join(self.__patch_dir, 'unapplied')
@@ -386,7 +387,7 @@ class Series:
def init(self):
"""Initialises the stgit series
"""
- bases_dir = os.path.join(git.base_dir, 'refs', 'bases')
+ bases_dir = os.path.join(git.get_base_dir(), 'refs', 'bases')
if self.is_initialised():
raise StackException, self.__patch_dir + ' already exists'
^ permalink raw reply related
* [PATCH 7/7] Use a separate directory for patches under each branch subdir
From: Chuck Lever @ 2005-11-29 22:09 UTC (permalink / raw)
To: catalin.marinas; +Cc: git
In-Reply-To: <20051129220552.9885.41086.stgit@dexter.citi.umich.edu>
Currently you can't specify a patch name that matches the name of one of
the stgit special files under .git/patches/<branch-name>. Let's use a
new subdirectory under .git/patches/<branch-name> to contain just the
patch directories to remove this limitation.
Signed-off-by: Chuck Lever <cel@netapp.com>
---
stgit/stack.py | 24 +++++++++++++++---------
1 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/stgit/stack.py b/stgit/stack.py
index 2866121..46b404c 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -264,14 +264,19 @@ class Series:
if self.__name:
base_dir = git.get_base_dir()
- self.__patch_dir = os.path.join(base_dir, 'patches',
- self.__name)
self.__base_file = os.path.join(base_dir, 'refs', 'bases',
self.__name)
- self.__applied_file = os.path.join(self.__patch_dir, 'applied')
- self.__unapplied_file = os.path.join(self.__patch_dir, 'unapplied')
- self.__current_file = os.path.join(self.__patch_dir, 'current')
- self.__descr_file = os.path.join(self.__patch_dir, 'description')
+ self.__series_dir = os.path.join(base_dir, 'patches',
+ self.__name)
+
+ self.__applied_file = os.path.join(self.__series_dir, 'applied')
+ self.__unapplied_file = os.path.join(self.__series_dir, 'unapplied')
+ self.__current_file = os.path.join(self.__series_dir, 'current')
+ self.__descr_file = os.path.join(self.__series_dir, 'description')
+
+ self.__patch_dir = os.path.join(self.__series_dir, 'patches')
+ if not os.path.isdir(self.__patch_dir):
+ self.__patch_dir = self.__series_dir
def get_branch(self):
"""Return the branch name for the Series object
@@ -323,15 +328,15 @@ class Series:
return self.__base_file
def get_protected(self):
- return os.path.isfile(os.path.join(self.__patch_dir, 'protected'))
+ return os.path.isfile(os.path.join(self.__series_dir, 'protected'))
def protect(self):
- protect_file = os.path.join(self.__patch_dir, 'protected')
+ protect_file = os.path.join(self.__series_dir, 'protected')
if not os.path.isfile(protect_file):
create_empty_file(protect_file)
def unprotect(self):
- protect_file = os.path.join(self.__patch_dir, 'protected')
+ protect_file = os.path.join(self.__series_dir, 'protected')
if os.path.isfile(protect_file):
os.remove(protect_file)
@@ -399,6 +404,7 @@ class Series:
create_empty_file(self.__applied_file)
create_empty_file(self.__unapplied_file)
create_empty_file(self.__descr_file)
+ os.makedirs(os.path.join(self.__series_dir, 'patches'))
self.__begin_stack_check()
def rename(self, to_name):
^ permalink raw reply related
* [PATCH 6/7] Add a "--clone" option to "stg branch"
From: Chuck Lever @ 2005-11-29 22:09 UTC (permalink / raw)
To: catalin.marinas; +Cc: git
In-Reply-To: <20051129220552.9885.41086.stgit@dexter.citi.umich.edu>
Cloning a branch means creating a new branch and copying all of the
original branch's patches and its base to it. Like creating a tag,
but this also preserves all the StGIT patches as well.
Signed-off-by: Chuck Lever <cel@netapp.com>
---
stgit/commands/branch.py | 28 +++++++++++++++++++++++++---
stgit/stack.py | 35 ++++++++++++++++++++++++++++++++++-
2 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/stgit/commands/branch.py b/stgit/commands/branch.py
index ccf1f6b..5bc5e94 100644
--- a/stgit/commands/branch.py
+++ b/stgit/commands/branch.py
@@ -18,7 +18,7 @@ along with this program; if not, write t
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-import sys, os
+import sys, os, time
from optparse import OptionParser, make_option
from stgit.commands.common import *
@@ -29,10 +29,10 @@ from stgit import stack, git
help = 'manage development branches'
usage = """%prog [options] branch-name [commit-id]
-Create, list, switch between, rename, or delete development branches
+Create, clone, switch between, rename, or delete development branches
within a git repository. By default, a single branch called 'master'
is always created in a new repository. This subcommand allows you to
-manage several patch series in the same repository.
+manage several patch series in the same repository via GIT branches.
When displaying the branches, the names can be prefixed with
's' (StGIT managed) or 'p' (protected)."""
@@ -40,6 +40,9 @@ When displaying the branches, the names
options = [make_option('-c', '--create',
help = 'create a new development branch',
action = 'store_true'),
+ make_option('--clone',
+ help = 'copy the contents of a branch',
+ action = 'store_true'),
make_option('--delete',
help = 'delete an existing development branch',
action = 'store_true'),
@@ -124,6 +127,25 @@ def func(parser, options, args):
print 'Branch "%s" created.' % args[0]
return
+ elif options.clone:
+
+ if len(args) == 0:
+ clone = crt_series.get_branch() + \
+ time.strftime('-%C%y%m%d-%H%M%S')
+ elif len(args) == 1:
+ clone = args[0]
+ else:
+ parser.error('incorrect number of arguments')
+
+ check_local_changes()
+ check_conflicts()
+ check_head_top_equal()
+
+ print 'Cloning current branch to "%s"...' % clone
+ crt_series.clone(clone)
+ print 'done'
+ return
+
elif options.delete:
if len(args) != 1:
diff --git a/stgit/stack.py b/stgit/stack.py
index dc7c19f..2866121 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -18,7 +18,7 @@ along with this program; if not, write t
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-import sys, os
+import sys, os, shutil
from stgit.utils import *
from stgit import git
@@ -420,6 +420,39 @@ class Series:
self.__init__(to_name)
+ def clone(self, target_series):
+ """Clones a series
+ """
+ base = read_string(self.get_base_file())
+ git.create_branch(target_series, tree_id = base)
+ Series(target_series).init()
+
+ new_series = Series(target_series)
+
+ if os.path.exists(self.__descr_file):
+ shutil.copyfile(self.__descr_file, new_series.__descr_file)
+
+ for p in self.get_applied():
+ patch = self.get_patch(p)
+ new_series.new_patch(p, message = patch.get_description(),
+ can_edit = False, unapplied = True,
+ bottom = patch.get_bottom(),
+ top = patch.get_top(),
+ author_name = patch.get_authname(),
+ author_email = patch.get_authemail(),
+ author_date = patch.get_authdate())
+ modified = new_series.push_patch(p)
+
+ for p in self.get_unapplied():
+ patch = self.get_patch(p)
+ new_series.new_patch(p, message = patch.get_description(),
+ can_edit = False, unapplied = True,
+ bottom = patch.get_bottom(),
+ top = patch.get_top(),
+ author_name = patch.get_authname(),
+ author_email = patch.get_authemail(),
+ author_date = patch.get_authdate())
+
def delete(self, force = False):
"""Deletes an stgit series
"""
^ permalink raw reply related
* [PATCH 4/7] "stg series" option to show patch summary descriptions
From: Chuck Lever @ 2005-11-29 22:09 UTC (permalink / raw)
To: catalin.marinas; +Cc: git
In-Reply-To: <20051129220552.9885.41086.stgit@dexter.citi.umich.edu>
Optionally show each patch's short description when listing a series.
Signed-off-by: Chuck Lever <cel@netapp.com>
---
stgit/commands/series.py | 48 +++++++++++++++++++++++++++++++---------------
1 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/stgit/commands/series.py b/stgit/commands/series.py
index 032b89e..a843307 100644
--- a/stgit/commands/series.py
+++ b/stgit/commands/series.py
@@ -33,12 +33,31 @@ prefixed with a '>'. Empty patches are p
options = [make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
+ make_option('-d', '--description',
+ help = 'show a show description for each patch',
+ action = 'store_true'),
make_option('-e', '--empty',
help = 'check whether patches are empty '
'(much slower)',
action = 'store_true') ]
+def __get_description(patch):
+ """Extract and return a patch's short description
+ """
+ p = crt_series.get_patch(patch)
+ descr = p.get_description().strip()
+ descr_lines = descr.split('\n')
+ return descr_lines[0].rstrip()
+
+def __print_patch(patch, prefix, empty_prefix, length, options):
+ if options.empty and crt_series.empty_patch(patch):
+ prefix = empty_prefix
+ if options.description:
+ print prefix + patch.ljust(length) + ' | ' + __get_description(patch)
+ else:
+ print prefix + patch
+
def func(parser, options, args):
"""Show the patch series
"""
@@ -46,21 +65,18 @@ def func(parser, options, args):
parser.error('incorrect number of arguments')
applied = crt_series.get_applied()
+ unapplied = crt_series.get_unapplied()
+ patches = applied + unapplied
+
+ max_len = 0
+ if len(patches) > 0:
+ max_len = max([len(i) for i in patches])
+
if len(applied) > 0:
for p in applied [0:-1]:
- if options.empty and crt_series.empty_patch(p):
- print '0', p
- else:
- print '+', p
- p = applied[-1]
-
- if options.empty and crt_series.empty_patch(p):
- print '0>%s' % p
- else:
- print '> %s' % p
-
- for p in crt_series.get_unapplied():
- if options.empty and crt_series.empty_patch(p):
- print '0', p
- else:
- print '-', p
+ __print_patch(p, '+ ', '0 ', max_len, options)
+
+ __print_patch(applied[-1], '> ', '0>', max_len, options)
+
+ for p in unapplied:
+ __print_patch(p, '- ', '0 ', max_len, options)
^ permalink raw reply related
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