* Re: best git practices, was Re: Git User's Survey 2007 unfinished summary continued
From: Johannes Schindelin @ 2007-10-23 10:58 UTC (permalink / raw)
To: Steffen Prohaska
Cc: Jakub Narebski, Andreas Ericsson, Federico Mena Quintero, git
In-Reply-To: <92320AA3-6D23-4967-818D-F7FA3962E88D@zib.de>
Hi,
On Tue, 23 Oct 2007, Steffen Prohaska wrote:
>
> On Oct 23, 2007, at 1:35 AM, Jakub Narebski wrote:
>
> > 2. Git can do a merge with conflicts _only_ if that branch is checked
> > out.
>
> Andreas' proposal contains an important requirement that avoids this
> problem. His proposal states "when they, prior to fetching, pointed to
> the same commit [the head in remotes pointed to]". That is only
> fast-forwards are needed, which never have merge conflicts.
You know what I do not like with this proposal? The whole _point_ of this
discussion is to make git _easier_. Go ahead, try to explain to a
complete git newbie the proposed behaviour. I have a pound here which
says that there is _no_ _way_ that this newbie says "well, that's easy".
Some people may not get this, but git has a reputation of being
complicated, and my "BS" argument was, is, and will be, that we should
keep clear and simple semantics, because they are the _only_ way to battle
that reputation.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] execv_git_cmd(): also try PATH if everything else fails.
From: Johannes Schindelin @ 2007-10-23 11:12 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Scott Parish, git
In-Reply-To: <20071023043405.GA14735@spearce.org>
Hi,
On Tue, 23 Oct 2007, Shawn O. Pearce wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > On Mon, 22 Oct 2007, Shawn O. Pearce wrote:
> > > Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > > > Earlier, we tried to find the git commands in several possible exec
> > > > dirs. Now, if all of these failed, try to find the git command in
> > > > PATH.
> > > ...
> > > > diff --git a/exec_cmd.c b/exec_cmd.c
> > > > index 9b74ed2..70b84b0 100644
> > > > --- a/exec_cmd.c
> > > > +++ b/exec_cmd.c
> > > > @@ -36,7 +36,8 @@ int execv_git_cmd(const char **argv)
> > > > int i;
> > > > const char *paths[] = { current_exec_path,
> > > > getenv(EXEC_PATH_ENVIRONMENT),
> > > > - builtin_exec_path };
> > > > + builtin_exec_path,
> > > > + "" };
> > >
> > > So if the user sets GIT_EXEC_PATH="" and exports it we'll search
> > > $PATH before the builtin exec path that Git was compiled with? Are
> > > we sure we want to do that?
> >
> > I thought the proper way to unset EXEC_PATH was to "unset
> > GIT_EXEC_PATH". In that case, getenv(EXEC_PATH_ENVIRONMENT) returns
> > NULL and we're fine, no?
>
> Sure. But can't you also export an environment variable that is set to
> the empty string? At least on UNIX. Windows thinks unset and empty
> string are the same thing.
Not here. I just tried (with msysGit, of course).
Anyway, I like the other patch Scott sent much more than mine, which
offloads the work to execvp().
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] Add color to git-add--interactive diffs (Total different idea to solve the problem)
From: Johannes Schindelin @ 2007-10-23 11:13 UTC (permalink / raw)
To: Peter Baumann
Cc: Tom Tobin, Dan Zwell, Jonathan del Strother, Shawn O. Pearce,
Git Mailing List
In-Reply-To: <20071023053401.GB9330@xp.machine.xx>
Hi,
On Tue, 23 Oct 2007, Peter Baumann wrote:
> On Tue, Oct 23, 2007 at 12:55:44AM +0100, Johannes Schindelin wrote:
>
> > On Mon, 22 Oct 2007, Peter Baumann wrote:
> >
> > > Wouldn't it make more sense to implement the diff coloring inside
> > > git apply so that you could use something like
> > >
> > > diff file1 file2|git apply --color
> > >
> > > to make the generated diff with colors [1]? It already implements
> > > the same semantic for generating a diffstat, using
> > >
> > > diff file1 file2|git apply --stat
> >
> > No. In both cases, "git diff" realises that the output is no terminal,
> > and switches off color generation. (Just try with diff.color=true instead
> > of =auto.)
> >
>
> I didn't mean git-diff here, instead I meant diff, so no coloring involved
> on the diff side. The git-apply would be enhanced to do the coloring on
> every diff it gets on its STDIN.
Ah! I completely misunderstood indeed. Clever...
Ciao,
Dscho
^ permalink raw reply
* Re: What's cooking in git/spearce.git (topics)
From: Theodore Tso @ 2007-10-23 12:03 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Junio C Hamano, Johannes Schindelin, git
In-Reply-To: <20071023054238.GE14735@spearce.org>
On Tue, Oct 23, 2007 at 01:42:38AM -0400, Shawn O. Pearce wrote:
> Yes. But you need the prior value of the branch so you can do
> something easy like:
>
> git checkout yourtopic
> git rebase --onto $newtopic $oldtopic
>
> which means you probably need to look through the logs for not just
> pu but also pu@{1}. A script to break out the topic branches from
> pu post fetch and store them as proper tracking branches would make
> this easier, but that much. If you plan ahead you can save that
> $oldtopic point so you can do something like this:
>
> git log pu ; # find $newtopic
> git checkout yourtopic
> git rebase --onto $newtopic base-yourtopic
> git tag -f base-yourtopic $newtopic
Yeah, I had thought about writing a little script that would take my
project's topic branches, and then push them out into the public
repository under topics/ad/extents-testcases or
topics/tt/badblocks-cleanup. That would make it easy to find the head
of your topic, and once you find that, the base of your-topic isn't
that hard to find, since it would just be the result of "git-rev-list
topic ^master | tail -1".
One of the reasons I was thinking the above is because most of the
patches are coming into my end as emailed patch series, and I end up
tweaking them a lot as I carry them around in the topics branch. So
if other people want to see what I've done to a branch after I've done
a git rebase --interactive, it's easier if they can get access to the
individual topics branch, so they can extract out the patch series
while it's being tweaked by me (and possibly others).
This is probably because my view of git has been colored by kernel
community practices, where patches are normally perfected and get
rebased a lot (normally in a sub-maintainer or maintainer's tree)
before they get pushed to Linus, and in my mental model a topic branch
represents the maintainer's git tree in the central repository.
The extreme end of this would be the classical BitKeeper model, where
Larry McVoy once argued to me that he didn't like history to *ever* be
rewound/rewritten, since not only did this interfere with other people
trees once they had been pushed, but it causes development history to
be lost, which is always valuable. (Of course, in the end he did
write "bk fold", which squashes the last N commits into 1, mainly due
to customer pressure.) The kernel viewpoint is to rebase all the
time, because the history is so huge that we don't *want* to see the
development history of the rough drafts of features before they get
merged into mainline.
> It keeps the history shorter in gitk. But otherwise it isn't bad.
> Unless you are running into a lot of conflicts every time you rebase
> and its wasting your time. ;-)
It sounds like what you are saying here is that the git.git tree takes
a viewpoint which is slightly between the extremes of the kernel model
(which does involve resolving rebasing a lot and resolving lots of
conflicts, but heh, that's not Linus's problem, that's been pushed out
to the leafs of the developer community, and besides, it strongly
encourages topics to get merged into the mainline fast), and the
classical Bitkeeper model, which says that philosophical goodness
means you should keep *all* development history once it enters the BK SCM.
With git.git, we are essentially throwing away development history
while it is in 'pu', but once a commit graduates to 'next', we do keep
the development history forever. The downside to this is that
development 'crud' can build up in next; even if all substantive
commits in 'next' end up graduating to 'master', there will still be
lots of merge commits that will only be in 'next'.
I have an emotional bias which tends to treat that excess history as
toxic waste to be avoided at all costs, but that's probably because
when you have a git tree as huge as the kernel, life is easier if the
history is kept as clean as possible.
Which I suppose is easy enough to do in the git.git model; if you
throw away the 'next' branch and then rewind it so it is forked off of
'master' all of that history essentially gets flushed. The downside
is that people maintaining topics branches which were forked against
the old 'next' will need to do some grotty work to rebase their
patches, so any attempt to rewind next would probably require the
central maintainer to give plenty of notice, and then on the flag day,
save 'next' as 'old-next' before rewinding to allow the other
developers to more easily rebase any private branches they might have.
Hmm, interesting. A lot of this is quite subtle, or at least the
impacts of different choices in the git workflow really didn't become
obvious to me until I started trying I stepped into the central
maintainer role for a project using git!
- Ted
^ permalink raw reply
* Re: [PATCH] execv_git_cmd(): also try PATH if everything else fails.
From: Andreas Ericsson @ 2007-10-23 11:12 UTC (permalink / raw)
To: Johannes Sixt; +Cc: Scott Parish, Johannes Schindelin, Shawn O. Pearce, git
In-Reply-To: <471CC380.5030603@viscovery.net>
Johannes Sixt wrote:
> Andreas Ericsson schrieb:
>> Scott Parish wrote:
>>> I'm tempted to try a different approach. What if instead of looping
>>> and building up strings of all the different absolute paths we want
>>> to try we just prepend to PATH with the correct extra precedence,
>>> and then call execvp on the command we want?
>>>
>>
>> That's how the original git --exec-dir feature got implemented.
>> There's even a nifty function for it in git.c; prepend_to_path(). It's
>> a provably workable solution.
>
> The reason that this was done is for the sake of shell scripts: They
> need to have the path that was finally decided as exec-path in $PATH.
>
> But I can't think of any negative side effect if *all* exec-path
> candidates are in $PATH. It's important, though, that all paths are
> absolute because the tools chdir every now and then.
>
So long as they're added in "success:failed:failed" order, I don't see
any issues either. Assuming we stop prepending once we find something
that works, that should be a non-issue.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: [PATCH] execv_git_cmd(): also try PATH if everything else fails.
From: Johannes Sixt @ 2007-10-23 15:29 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Scott Parish, Johannes Schindelin, Shawn O. Pearce, git
In-Reply-To: <471DD703.70608@op5.se>
Andreas Ericsson schrieb:
> Johannes Sixt wrote:
>> But I can't think of any negative side effect if *all* exec-path
>> candidates are in $PATH. It's important, though, that all paths are
>> absolute because the tools chdir every now and then.
>>
>
> So long as they're added in "success:failed:failed" order, I don't see
> any issues either. Assuming we stop prepending once we find something
> that works, that should be a non-issue.
No, the point is exactly to let execvp() do all the work and we don't care
which of the paths is the "success". And I don't think that this has any
negative side effects.
-- Hannes
^ permalink raw reply
* [PATCH] chdir() into list_commands() dir instead of building paths for stat()
From: Scott R Parish @ 2007-10-23 15:40 UTC (permalink / raw)
To: git
Signed-off-by: Scott R Parish <srp@srparish.net>
---
help.c | 18 +++---------------
1 files changed, 3 insertions(+), 15 deletions(-)
diff --git a/help.c b/help.c
index 950f62d..906f8f6 100644
--- a/help.c
+++ b/help.c
@@ -96,35 +96,23 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)
static void list_commands(const char *exec_path, const char *prefix)
{
unsigned int longest = 0;
- char path[PATH_MAX];
- int dirlen;
int prefix_len = strlen(prefix);
DIR *dir = opendir(exec_path);
struct dirent *de;
- if (!dir) {
+ if (!dir || chdir(exec_path)) {
fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
exit(1);
}
- dirlen = strlen(exec_path);
- if (PATH_MAX - 20 < dirlen) {
- fprintf(stderr, "git: insanely long exec-path '%s'\n",
- exec_path);
- exit(1);
- }
-
- memcpy(path, exec_path, dirlen);
- path[dirlen++] = '/';
-
while ((de = readdir(dir)) != NULL) {
struct stat st;
int entlen;
if (prefixcmp(de->d_name, prefix))
continue;
- strcpy(path+dirlen, de->d_name);
- if (stat(path, &st) || /* stat, not lstat */
+
+ if (stat(de->d_name, &st) || /* stat, not lstat */
!S_ISREG(st.st_mode) ||
!(st.st_mode & S_IXUSR))
continue;
--
gitgui.0.8.4.11178.g9a1bf-dirty
^ permalink raw reply related
* [PATCH] walk PATH to generate list of commands for "help -a"
From: Scott R Parish @ 2007-10-23 15:41 UTC (permalink / raw)
To: git
Signed-off-by: Scott R Parish <srp@srparish.net>
---
help.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/help.c b/help.c
index 906f8f6..3f8b4aa 100644
--- a/help.c
+++ b/help.c
@@ -64,6 +64,19 @@ static int cmdname_compare(const void *a_, const void *b_)
return strcmp(a->name, b->name);
}
+static void uniq(struct cmdname **cmdname)
+{
+ int i, j;
+
+ for (i = j = 1; i < cmdname_cnt; i++) {
+ if (strcmp(cmdname[i]->name, cmdname[i-1]->name)) {
+ cmdname[j++] = cmdname[i];
+ }
+ }
+
+ cmdname_cnt = j;
+}
+
static void pretty_print_string_list(struct cmdname **cmdname, int longest)
{
int cols = 1, rows;
@@ -71,12 +84,13 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)
int max_cols = term_columns() - 1; /* don't print *on* the edge */
int i, j;
+ qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
+ uniq(cmdname);
+
if (space < max_cols)
cols = max_cols / space;
rows = (cmdname_cnt + cols - 1) / cols;
- qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
-
for (i = 0; i < rows; i++) {
printf(" ");
@@ -93,19 +107,17 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)
}
}
-static void list_commands(const char *exec_path, const char *prefix)
+static unsigned int list_commands_in_dir(const char *dir, const char *prefix)
{
unsigned int longest = 0;
int prefix_len = strlen(prefix);
- DIR *dir = opendir(exec_path);
+ DIR *dirp = opendir(dir);
struct dirent *de;
- if (!dir || chdir(exec_path)) {
- fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
- exit(1);
- }
+ if (!dirp || chdir(dir))
+ return 0;
- while ((de = readdir(dir)) != NULL) {
+ while ((de = readdir(dirp)) != NULL) {
struct stat st;
int entlen;
@@ -126,12 +138,37 @@ static void list_commands(const char *exec_path, const char *prefix)
add_cmdname(de->d_name + prefix_len, entlen);
}
- closedir(dir);
+ closedir(dirp);
- printf("git commands available in '%s'\n", exec_path);
- printf("----------------------------");
- mput_char('-', strlen(exec_path));
- putchar('\n');
+ return longest;
+}
+
+static void list_commands(const char *prefix)
+{
+ unsigned int longest = 0;
+ unsigned int len;
+ const char *env_path = getenv("PATH");
+ char *paths, *path, *colon;
+
+ if (!env_path) {
+ fprintf(stderr, "PATH not set\n");
+ exit(1);
+ }
+
+ path = paths = xstrdup(env_path);
+ while ((char *)1 != path) {
+ if ((colon = strchr(path, ':')))
+ *colon = 0;
+
+ len = list_commands_in_dir(path, prefix);
+ longest = MAX(longest, len);
+
+ path = colon + 1;
+ }
+ free(paths);
+
+ printf("available git commands\n");
+ printf("----------------------\n");
pretty_print_string_list(cmdname, longest);
putchar('\n');
}
@@ -188,7 +225,6 @@ int cmd_version(int argc, const char **argv, const char *prefix)
int cmd_help(int argc, const char **argv, const char *prefix)
{
const char *help_cmd = argc > 1 ? argv[1] : NULL;
- const char *exec_path = git_exec_path();
if (!help_cmd) {
printf("usage: %s\n\n", git_usage_string);
@@ -198,8 +234,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) {
printf("usage: %s\n\n", git_usage_string);
- if(exec_path)
- list_commands(exec_path, "git-");
+ list_commands("git-");
exit(0);
}
--
gitgui.0.8.4.11178.g9a1bf-dirty
^ permalink raw reply related
* unmerging feature branches
From: martin f krafft @ 2007-10-23 15:24 UTC (permalink / raw)
To: git discussion list
[-- Attachment #1: Type: text/plain, Size: 1168 bytes --]
Dear list,
Let's say I developed a feature Foo on a branch off master, and at
some point I merged it back into master (commit M) and published the
repo. Since M, a number of commits have been made onto master.
Now I woul like to undo the merge.
I could rebase (M+1)..master onto M^ (on the former master branch),
but that would orphan the commits between the merge point and the
tip of master, which others are tracking.
I'd love to have git-revert, but that cannot undo a multi-parent
commit.
I could git-revert every commit on the feature branch between the
branch point and the merge point, even squash them into a single
commit, but that is a lot of work.
Are there any other methods? Is it conceivable to let git-revert
revert a merging commit if you tell it somehow which of the two (or
more) parents are the ones you want undone, meaning that you'd like
to keep the others?
--
martin | http://madduck.net/ | http://two.sentenc.es/
"a man who does not realise
that he is half an animal
is only half a man."
-- thornton wilder
spamtraps: madduck.bogus@madduck.net
[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: unmerging feature branches
From: Matthieu Moy @ 2007-10-23 16:19 UTC (permalink / raw)
To: martin f krafft; +Cc: git discussion list
In-Reply-To: <20071023152445.GA10070@piper.oerlikon.madduck.net>
martin f krafft <madduck@madduck.net> writes:
> Now I woul like to undo the merge.
Dirty solution: export the patch corresponding to the merge (diff
M..M^), and apply it on master. If you have no conflicts, it should be
doable. If you have conflicts, it will probably be painfull.
--
Matthieu
^ permalink raw reply
* Re: unmerging feature branches
From: Linus Torvalds @ 2007-10-23 16:50 UTC (permalink / raw)
To: martin f krafft; +Cc: git discussion list
In-Reply-To: <20071023152445.GA10070@piper.oerlikon.madduck.net>
On Tue, 23 Oct 2007, martin f krafft wrote:
>
> Are there any other methods? Is it conceivable to let git-revert
> revert a merging commit if you tell it somehow which of the two (or
> more) parents are the ones you want undone, meaning that you'd like
> to keep the others?
So let me get this straight.. You have a merge "M" that is the result of
merging (possibly multiple) topic branches, and you now want to undo the
part that *one* of them brought in?
First off, let me say that to some degree, what you ask for is not
possible. Why?
Since you have pushed out the stuff, and don't want to rewrite history
(which would result in trouble for down-streams - and I heartily approve),
whatever you do will always have that merge in the commit history.
And that means that while you can certainly undo the *data* that the merge
brought in, git will always know that you already merged up that branch.
Which means that if you later decide that you *do* want to do the merge
after all, you now really cannot - trying to merge the branch later on
will just be a fast-forward, and you'll never get the actual changes from
that merge (since git knows you already have them!).
So you can revert the data, but then if you want to get it back, you'll
need to revert the revert - you cannot just merge the branch again.
So the first thing you need to realize is that "revert" does not revert
history, it *only* reverts data. The fact that you did the merge will
always remain, although you could try to hack around even that by using
the 'grafts' file and trying to hide it (I really don't think it's a good
idea, but sure, everything is "possible" in that sense).
Now, that said, reverting the data is not that hard. There is not any
single-command "revert this arm of a merge", but on the other hand, git
can certainly help you.
The way to do it is:
# go back to just before the merge, create a "fixup" branch
#
git branch -b fixup M^
# merge all of it again, *except* the branch you didn't want to
# merge (this example assumes that you had a four-way octopus
# merge, and you now want to turn it into a three-way with the
# next-to-last parent skipped):
#
git merge -m "fixed merge" M^2 M^4
# You now have "fixup" containing what you *wanted* it to be
# after the original merge. Create a temporary branch that is
# based on the merge and contains that state instead, and
# apply the difference.
#
git branch -b temporary M
git diff ..fixup | git-apply
git commit -m "fixup commit"
# You now have the "temporary" branch that contains just the
# diff that effectively undoes that one merge. Go back to the
# tip of your development, and cherry-pick it to get git to
# help you do a good job merging it with all the subsequent
# development
#
git checkout master # or whatever branch you used
git cherry-pick temporary
.. do whatever you need to do to resolve it
.. if it didn't go cleanly
# Now, edit the commit message to talk about what you did
#
git commit --amend
or something to that effect.
Complicated? Yes. The above is strictly speaking more complex than you may
need, but if you do it like the above, you get maximum help from git (ie
you *could* have tried to just apply the patch with "git-apply" directly
on the top of master, but if you do it like the above, then it's
guaranteed that the patch that undoes the commit will apply cleanly, and
you then use "git cherry-pick" which uses the merge logic that can do a
proper three-way merge with renames etc, so if there are conflicts or
other things, the above will likely be the best way to do it)
So for simple cases, you can do the above more simply, but the above is
fairly brainless and scriptable except for the *one* place where you
actually move the changes forward (the single cherry-pick).
There are certainly other ways too. You could just "git revert -n" all the
commits that came in through the branch you didn't want to merge. That
doesn't work well if there were merges in that area, though, or of there
were changes that were common to all the branches (some of which also came
in through *other* merges).
So the above (UNTESTED! Caveat emptor!) sequence is *one* way of doing it,
and probably in the end the one that most closely represents what you want
to do.
Linus
^ permalink raw reply
* git-annotate - leaking hundrets of megabytes
From: Sven Herzberg @ 2007-10-23 17:00 UTC (permalink / raw)
To: git
Hey,
I just started to write a small tool that's supposed to provide a
graphical annotation view. It's supposed to display the information of
git-annotate and provide a way to browse through the history (so people
can click on links that refer to older revisions, etc.). According to
the man page of git-annotate, I looked into the incremental mode to make
sure the tool can load the information step by step.
However, to make sure the user interface doesn't block while
"git-annotate --incremental" is running, I decided to take a really slow
annotation while developing and then I saw that git-annotate leaks
*lots* of memory (at least in that use-case).
In my example, it used up to 450MB:
http://people.imendio.com/~sven/massif.18740.png
Reproduce:
1. git clone git://git.webkit.org/WebKit.git
2. cd WebKit/WebCore
3. git-annotate --incremental ChangeLog
Regards,
Sven
PS: Please CC me as I'm not on the list.
^ permalink raw reply
* Re: unmerging feature branches
From: martin f krafft @ 2007-10-23 17:16 UTC (permalink / raw)
To: Linus Torvalds, git discussion list
In-Reply-To: <alpine.LFD.0.999.0710230922240.30120@woody.linux-foundation.org>
[-- Attachment #1: Type: text/plain, Size: 1567 bytes --]
also sprach Linus Torvalds <torvalds@linux-foundation.org> [2007.10.23.1850 +0200]:
> First off, let me say that to some degree, what you ask for is not
> possible. Why?
>
> Since you have pushed out the stuff, and don't want to rewrite history
> (which would result in trouble for down-streams - and I heartily approve),
> whatever you do will always have that merge in the commit history.
>
> And that means that while you can certainly undo the *data* that the merge
> brought in, git will always know that you already merged up that branch.
This is precisely what I meant, sorry for not being clear. This is
what git-revert does...
> So you can revert the data, but then if you want to get it back, you'll
> need to revert the revert - you cannot just merge the branch again.
Ouch!
> # You now have the "temporary" branch that contains just the
> # diff that effectively undoes that one merge. Go back to the
> # tip of your development, and cherry-pick it to get git to
> # help you do a good job merging it with all the subsequent
> # development
Ah, that's a good idea.
Thanks for your time and input!
PS: this question of mine came out of a discussion on using Git for
Debian packaging: what happens when we actually need to remove
a feature from one package to the next:
http://lists.madduck.net/pipermail/vcs-pkg/2007-October/000059.html
--
martin | http://madduck.net/ | http://two.sentenc.es/
#define emacs eighty megabytes and constantly swapping.
spamtraps: madduck.bogus@madduck.net
[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: unmerging feature branches
From: Linus Torvalds @ 2007-10-23 17:40 UTC (permalink / raw)
To: martin f krafft; +Cc: git discussion list
In-Reply-To: <20071023171611.GA18783@piper.oerlikon.madduck.net>
On Tue, 23 Oct 2007, martin f krafft wrote:
>
> > So you can revert the data, but then if you want to get it back, you'll
> > need to revert the revert - you cannot just merge the branch again.
>
> Ouch!
Well, it's not necessarily "Ouch".
It actually depends on what you want to do. Sometimes this is a feature,
and the thing is, it actually works for other things that just merge
commits.
In other words, think of what happens when you merge some development
branch, and then "git revert" a single commit from that branch - the exact
same thing will happen - future merges of that branch will *not* re-do the
commit, because you "already have it", and you reverted it after-the-fact.
And in many ways, this is "obviously" what you want to happen!
Now, I say "obviously" in quotes, because it's not at all obvious in an
absolute sense - it may be that you reverted the commit not because it was
buggy, but because your stable branch wasn't ready for it yet, and maybe
in the future you do actually want the code that the revert reverted. So
in that sense, nothing is really "obvious", and this is simply how things
work. But I think that it's easier to explain why git does something like
this when you speak about normal commits, and it all makes sense.
When you revert the data from a merge, the exact same issue happens. A
revert (whether done by "git revert", or by the sequence of events I
described) very fundamentally undoes the *data* part, but leaves the
history intact, and that has implications for future events that think
about history - which is mostly "git merge", but there are other thigns
too.
As an example of "other things" that take history into account, think
about something like "git rebase". It's not a merge, but it also takes
history into account in certain ways: in particular, it may be effectively
a "series of cherry-picks", but it actually takes the history of both
branches into account, and will not re-apply a patch that already exists
in the target history.
What does that mean? Let's say that both histories contain a patch X (not
the same commit, but the same patch), but one history also contains the
revert of X. Again, the revert reverts the data, but it does *not* revert
the history, so when you cherry-pick all the stuff from the other branch,
X will *not* happen - even if it would apply cleanly, and even if a plain
"git cherry-pick" would have redone it!
Why? History, again. Because "git rebase" sees that the commit already
existed, it won't even try to apply it again, never mind that it could
have worked. The "revert" didn't undo the history, just the data.
So a "revert" is fundamentally different from a "undo". Most of the time
that's exactly what you want, and I'm not pointing this out as a problem,
I just wanted to point out that it has "effects". Sometimes the effects
are good, sometimes they are bad, and while they are always very reliable
and there's never any question about what git will do, people don't always
think like git, and whether the effects are "good" or "bad" is probably
entirely up to whether they match users expectations or not.
So sometimes the behaviour of "git revert" will be exactly what people
expected and wanted ("good, I'll never get that commit again when I pull,
because I told git that I don't want that commit"), and sometimes it will
_not_ be what people expected and wanted ("oh, I didn't get that commit,
even though I was now ready for it - because I had reverted it back when I
was *not* ready for it").
See? The logic is exactly the same in both cases, but one was good, the
other bad, and the only difference was really the mindset of the user.
A tool can't ever get "mindset of the user" differences right. At least
not until we add the "esp option" ;)
So I really don't want to push this as a problem or deficiency, I think
it's a good thing. But it's a good thing only when people are *aware* of
what "revert" really means.
Linus
^ permalink raw reply
* Re: What's cooking in git/spearce.git (topics)
From: Daniel Barkalow @ 2007-10-23 17:44 UTC (permalink / raw)
To: Theodore Tso; +Cc: Shawn O. Pearce, Junio C Hamano, Johannes Schindelin, git
In-Reply-To: <20071023120338.GG27132@thunk.org>
I keep thinking that there should be a better mechanism to use for "pu"
than a branch. Normally what you see in "pu" is a sequential merge of
"next" and a number of topic branches, where the series of merges is
either entirely uninteresting or only interesting in a schematic sense
(that is, it is interesting what topics appear, and in what order, but the
snapshot of each topic's head when it got merged isn't interesting).
That is, the work which "pu" consists of, and therefore the history is a
sequence of steps, each of which is one or more of: "add this topic",
"update this topic", "remove this topic", "update to a new next". And we
don't keep a record of this history, but it's not what's discarded by
rewinding anyway.
I think that, if we actually care about this sort of thing, we'd want to
make "pu" a series of commits, each with the previous "pu" as the sole
parent, with a series object given in a new header. The series object
would start with a "next" commit, and then list the topics merged by name
and head-as-merged. Of course, the "pu" commits would contain the
resulting tree as normal, so that people without a git that understands
this would see "pu" as consisting of a straight line of commits, each of
which simply shows the net effect of the changes. Or something like that.
I suppose "pu" could also be represented as a superproject where each
subproject is "next" or a topic branch, if we really want to avoid
introducing new objects, but that seems unweildy somehow.
Is this worth doing? It might be; I bet it would make debugging -mm a
whole lot nicer. (First bisect through -mm to find the action Andrew took
that accepted the breakage, then bisect the history within that action.) I
bet the status quo is a real pain when the feature that broke is only in
-mm and later in Andrew's list than the tree whose change triggered the
failure (i.e., -mm4 works; -mm5 doesn't work, and everything in -mm5 is
either broken or untestable).
And, of course, "origin/pu[db/builtin-fetch]" would be an easy thing to
build into git, and it could even generate extra magic, where it knows
what the topic was last rebased on, so git could lead people through
"rebase everything in a pu collection on the new base for the collection"
and "make my local topic branch agree with my topic branch as present in
origin/pu".
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: Howto request: going home in the middle of something?
From: Jing Xue @ 2007-10-23 17:56 UTC (permalink / raw)
To: Jan Wielemaker; +Cc: Petr Baudis, git
In-Reply-To: <200710221044.24191.wielemak@science.uva.nl>
Quoting Jan Wielemaker <wielemak@science.uva.nl>:
> Thanks for the replies. I think I can live with something like this
>
> <work, in the middle of something>
> $ git checkout -b home
> $ git commit
> $ git checkout master
> <arriving at home>
> $ git jan@work:repo fetch home:home (using ssh)
> $ git checkout home
> <continue editing>
> $ git commit --amend
> $ git checkout master
> $ git merge home
> $ git -d home
> $ git commit
> $ git push
> <arriving at work>
> $ git -d home
> $ git pull
>
> Its still a bit many commands and you have to be aware what you are
> doing for quite a while, but it does provide one single clean commit
> message, doesn't change the shared repo until all is finished and allows
> to abandon all work without leaving traces.
What does the extra branch gain for us here? That's not a rhetorical
question, I'm actually curious to learn, because I always just commit,
switch to another computer, pull, and reset HEAD^.
Thanks.
--
Jing Xue
^ permalink raw reply
* Re: unmerging feature branches
From: martin f krafft @ 2007-10-23 18:08 UTC (permalink / raw)
To: Linus Torvalds, git discussion list
In-Reply-To: <alpine.LFD.0.999.0710231026011.30120@woody.linux-foundation.org>
[-- Attachment #1: Type: text/plain, Size: 4097 bytes --]
also sprach Linus Torvalds <torvalds@linux-foundation.org> [2007.10.23.1940 +0200]:
> > > So you can revert the data, but then if you want to get it back, you'll
> > > need to revert the revert - you cannot just merge the branch again.
> >
> > Ouch!
>
> Well, it's not necessarily "Ouch".
I said "ouch" only because I can foresee the confusion this may
cause in collaborative package maintenance. One party merges the
feature branch, another reverts it, and a third (or the first)
wonders why the feature isn't present despite having merged the
branch and must go through history to find the reverting commit,
which is tied to the commit it reverts through nothing else than
a log message, at best.
> In other words, think of what happens when you merge some
> development branch, and then "git revert" a single commit from
> that branch - the exact same thing will happen - future merges of
> that branch will *not* re-do the commit, because you "already have
> it", and you reverted it after-the-fact.
[...]
> When you revert the data from a merge, the exact same issue
> happens. A revert (whether done by "git revert", or by the
> sequence of events I described) very fundamentally undoes the
> *data* part, but leaves the history intact, and that has
> implications for future events that think about history - which is
> mostly "git merge", but there are other thigns too.
While this makes perfect sense, I am a bit thrown off now wrt two
earlier posts by you (in another thread), where you said:
In other words, git never looks at individual commits when trying
to merge. It doesn't try to figure out what the "meaning" of the
changes are, it purely looks at the content.
-- http://marc.info/?l=git&m=119198488411957&w=2
Yes, history is interesting for historical reasons, and to explain
what the context was, but in many ways, history is exactly the
*wrong* thing to use when it comes to merging. You should look at
the end result, since people can - and do - come to the same
result through different ways.
-- http://marc.info/?l=git&m=119204501428555&w=2
I master merged branch Foo, then reverted a commit introduced by
Foo, and then Foo would be re-merged, the content *will* differ. So
Git *has to* look at the list of commits in history to properly
handle reverts and *not* redo commits which have since been
reverted.
Is this correct?
> As an example of "other things" that take history into account, think
> about something like "git rebase". It's not a merge, but it also takes
> history into account in certain ways: in particular, it may be effectively
> a "series of cherry-picks", but it actually takes the history of both
> branches into account, and will not re-apply a patch that already exists
> in the target history.
In the light of the discussion in
(http://marc.info/?t=119198137100002&r=1&w=2), I am now completely
confused. Or well, not confused, but I simply don't know anymore
what Git does, and I thought I did.
> What does that mean? Let's say that both histories contain a patch X (not
> the same commit, but the same patch), but one history also contains the
> revert of X. Again, the revert reverts the data, but it does *not* revert
> the history, so when you cherry-pick all the stuff from the other branch,
> X will *not* happen - even if it would apply cleanly, and even if a plain
> "git cherry-pick" would have redone it!
>
> Why? History, again. Because "git rebase" sees that the commit already
> existed, it won't even try to apply it again, never mind that it could
> have worked. The "revert" didn't undo the history, just the data.
How can rebase know that the commit already existed when you're
saying above that it's about patch X, *not* the same commit?
--
martin | http://madduck.net/ | http://two.sentenc.es/
"a woman begins by resisting a man's advances and ends by blocking
his retreat."
-- oscar wilde
spamtraps: madduck.bogus@madduck.net
[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: git-annotate - leaking hundrets of megabytes
From: Linus Torvalds @ 2007-10-23 18:14 UTC (permalink / raw)
To: Sven Herzberg; +Cc: git
In-Reply-To: <471E28B2.7020508@imendio.com>
On Tue, 23 Oct 2007, Sven Herzberg wrote:
>
> In my example, it used up to 450MB:
> http://people.imendio.com/~sven/massif.18740.png
>
> Reproduce:
> 1. git clone git://git.webkit.org/WebKit.git
> 2. cd WebKit/WebCore
> 3. git-annotate --incremental ChangeLog
Hmm. I'm not seeing this at all. I do
/usr/bin/time git-annotate --incremental ChangeLog > /dev/null
in WebCore, and it returns
0.16user 0.01system 0:00.18elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+8365minor)pagefaults 0swaps
where that minor pagefault count is a good estimate of total memory used.
8365 minor page faults implies it only ever got 32MB of memory total.
What git version do you have, or did you perhaps mean some other file or
other config that causes this?
(It does end up using lots more memory if you ask for "-C" to see if there
are copies from other sources, but even then I'm not seeing anything
close to 450MB!)
Linus
^ permalink raw reply
* Re: unmerging feature branches
From: Linus Torvalds @ 2007-10-23 18:24 UTC (permalink / raw)
To: martin f krafft; +Cc: git discussion list
In-Reply-To: <20071023180825.GA20343@piper.oerlikon.madduck.net>
On Tue, 23 Oct 2007, martin f krafft wrote:
>
> While this makes perfect sense, I am a bit thrown off now wrt two
> earlier posts by you (in another thread), where you said:
>
> In other words, git never looks at individual commits when trying
> to merge. It doesn't try to figure out what the "meaning" of the
> changes are, it purely looks at the content.
> -- http://marc.info/?l=git&m=119198488411957&w=2
This is still true.
Git never looks at individual commits when merging, it looks at the
*history*.
So it does look at the commits only in the sense that it uses the "shape"
of the history (which is obviously built up from many individual commits!)
but it never looks at any individual commit per se.
And the behaviour of "git revert" comes *exactly* from the fact that git
never even bothers to look at the revert as a "revert" of history! A
revert is a normal data commit, and has absolutely zero impact on history
itself. So the reason a merge will never give "back" the data over a
revert is that the data was already merged, since the history itself
didn't change!
> I master merged branch Foo, then reverted a commit introduced by
> Foo, and then Foo would be re-merged, the content *will* differ.
No. If you re-merge Foo, nothing at all happens! You're already merged.
It's a no-op.
If Foo has had *new* commits in the meantime, those new commits will show
up, of course, but the old commits have absolutely zero effect, because
they will be part of the common history.
> So Git *has to* look at the list of commits in history to properly
> handle reverts and *not* redo commits which have since been reverted.
>
> Is this correct?
No, that's absolutely incorrect. You didn't understand what I meant.
Git merge doesn't look at the revert at all, except (indorectly) when it
builds up the history and it passes over it in order to find the common
base for the history.
> > As an example of "other things" that take history into account, think
> > about something like "git rebase". It's not a merge, but it also takes
> > history into account in certain ways: in particular, it may be effectively
> > a "series of cherry-picks", but it actually takes the history of both
> > branches into account, and will not re-apply a patch that already exists
> > in the target history.
>
> In the light of the discussion in
> (http://marc.info/?t=119198137100002&r=1&w=2), I am now completely
> confused. Or well, not confused, but I simply don't know anymore
> what Git does, and I thought I did.
git-rebase is special. It really does look at each commit (obviously),
since it needs to *move* each commit.
So git-rebase has nothing at all to do with merges. They have similar
behaviour (quite often the end result is identical in the *data* - at
least that's the good case), but at the same time they are very different
indeed.
Git-merge *only* cares about the "shape of the history" (to find the
common commit(s) to use as a merge base) and the actual data, while "git
rebase" actually goes one commit at a time.
> How can rebase know that the commit already existed when you're
> saying above that it's about patch X, *not* the same commit?
Git-rebase looks at the patch itself, using the "patch fingerprint", and
when it goes through each commit, it skips commits that have already been
applied.
See the man-pages for "git-cherry" and "git-patch-id".
Linus
^ permalink raw reply
* Re: Howto request: going home in the middle of something?
From: Jan Wielemaker @ 2007-10-23 18:38 UTC (permalink / raw)
To: Jing Xue; +Cc: Petr Baudis, git
In-Reply-To: <20071023135655.x6g6mln1j4880wog@intranet.digizenstudio.com>
On Tuesday 23 October 2007 19:56:55 Jing Xue wrote:
> Quoting Jan Wielemaker <wielemak@science.uva.nl>:
> > Thanks for the replies. I think I can live with something like this
> >
> > <work, in the middle of something>
> > $ git checkout -b home
> > $ git commit
> > $ git checkout master
> > <arriving at home>
> > $ git jan@work:repo fetch home:home (using ssh)
> > $ git checkout home
> > <continue editing>
> > $ git commit --amend
> > $ git checkout master
> > $ git merge home
> > $ git -d home
> > $ git commit
> > $ git push
> > <arriving at work>
> > $ git -d home
> > $ git pull
> >
> > Its still a bit many commands and you have to be aware what you are
> > doing for quite a while, but it does provide one single clean commit
> > message, doesn't change the shared repo until all is finished and allows
> > to abandon all work without leaving traces.
>
> What does the extra branch gain for us here? That's not a rhetorical
> question, I'm actually curious to learn, because I always just commit,
> switch to another computer, pull, and reset HEAD^.
I'm just trying to learn. Sofar I like the idea to stash and use
git-fetch to get the stash from the other side. As stash is about
handling current work, it feels as the most appropriate solution
and is a lot shorter.
Cheers --- Jan
^ permalink raw reply
* Re: git.el fails on non-git managed files
From: Matthieu Lemerre @ 2007-10-23 18:30 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git
In-Reply-To: <20071023043107.GZ14735@spearce.org>
[-- Attachment #1: Type: text/plain, Size: 720 bytes --]
"Shawn O. Pearce" <spearce@spearce.org> writes:
> racin@free.fr wrote:
>> I found the following on the development version of git.el: saving
>> non-git-managed files in Emacs threw an error.
>>
>> It is due to a simple error in the call to condition-case in a
>> recently added function, git-update-save-file.
>>
>> I attached the patch for your convenience.
>
> I'm not sure what happened, but I didn't receive a patch with
> your email. Would you mind resending it to the list? You may
> also want to file a bug with your distribution to get the Emacs
> bindings included.
Sure; the SMTP server of my ISP behaved weirdly yesterday and I had to
use one of these webmail applications. This time it should be OK.
[-- Attachment #2: patch --]
[-- Type: application/octet-stream, Size: 624 bytes --]
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index 4286d16..ff55607 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -1353,7 +1353,7 @@ Commands:
"Update the corresponding git-status buffer when a file is saved.
Meant to be used in `after-save-hook'."
(let* ((file (expand-file-name buffer-file-name))
- (dir (condition-case nil (git-get-top-dir (file-name-directory file))))
+ (dir (condition-case nil (git-get-top-dir (file-name-directory file)) (error nil)))
(buffer (and dir (git-find-status-buffer dir))))
(when buffer
(with-current-buffer buffer
[-- Attachment #3: Type: text/plain, Size: 71 bytes --]
I'll also file a bug to debian, that's a good idea.
Matthieu Lemerre
^ permalink raw reply related
* Re: What's cooking in git/spearce.git (topics)
From: Junio C Hamano @ 2007-10-23 19:00 UTC (permalink / raw)
To: Theodore Tso; +Cc: Shawn O. Pearce, Johannes Schindelin, git
In-Reply-To: <20071023120338.GG27132@thunk.org>
Theodore Tso <tytso@mit.edu> writes:
> With git.git, we are essentially throwing away development history
> while it is in 'pu', but once a commit graduates to 'next', we do keep
> the development history forever. The downside to this is that
> development 'crud' can build up in next; even if all substantive
> commits in 'next' end up graduating to 'master', there will still be
> lots of merge commits that will only be in 'next'.
>
> I have an emotional bias which tends to treat that excess history as
> toxic waste to be avoided at all costs, but that's probably because
> when you have a git tree as huge as the kernel, life is easier if the
> history is kept as clean as possible.
>
> Which I suppose is easy enough to do in the git.git model; if you
> throw away the 'next' branch and then rewind it so it is forked off of
> 'master' all of that history essentially gets flushed.
You can view 'next' as if it is sort of -mm. Following 'master'
is like following Linus tree, whose development is without those
numerous 'merge improvements again' merges into 'next'.
> The downside
> is that people maintaining topics branches which were forked against
> the old 'next' will need to do some grotty work to rebase their
> patches, so any attempt to rewind next would probably require the
> central maintainer to give plenty of notice, and then on the flag day,
> save 'next' as 'old-next' before rewinding to allow the other
> developers to more easily rebase any private branches they might have.
An alternative is to give an easier access to the tips of
individual topic branch head, at least to the ones that have
been merged to 'next' as they will never be rewound once they
are in 'next', and encourage people to fork off of them, instead
of 'next' directly. Then 'next' will be more like 'pu'.
> Hmm, interesting. A lot of this is quite subtle, or at least the
> impacts of different choices in the git workflow really didn't become
> obvious to me until I started trying I stepped into the central
> maintainer role for a project using git!
Very true.
^ permalink raw reply
* Re: unmerging feature branches
From: martin f krafft @ 2007-10-23 19:17 UTC (permalink / raw)
To: Linus Torvalds, git discussion list
In-Reply-To: <alpine.LFD.0.999.0710231115060.30120@woody.linux-foundation.org>
[-- Attachment #1: Type: text/plain, Size: 2016 bytes --]
also sprach Linus Torvalds <torvalds@linux-foundation.org> [2007.10.23.2024 +0200]:
> So it does look at the commits only in the sense that it uses the "shape"
> of the history (which is obviously built up from many individual commits!)
> but it never looks at any individual commit per se.
I don't follow what you mean with "shape". The following is
a history:
o - x - o - o - o - m - o - A* - o - m2 - o - master
\ / /
`o - A - L -' - F - o - o - T' - branch
A is a commit, A* is the commit which reverts (the data change by)
A. L and F are to mark the last and first commits before and after
the first merge m. T is the tip of 'branch'
After merge point m2, the change introduced by A will *not* be in
master. This much makes sense.
What did not make sense is how Git determines to leave it out. But
I think that after drawing the above, it's now clear:
by shape you mean the actual graph, and when 'branch' is merged into
master at m2, Git goes back in time to conclude that master...L must
already be present in master due to the intersection of the two
lines at m, and thus finds commit F as the "oldest direct
descendant" of m2. L is an older descendant of m2, but it's not
direct in the sense that there are multiple paths from m2 to L. Thus
Git will only merge F..T at m2.
Or as you put it:
> If Foo has had *new* commits in the meantime, those new commits
> will show up, of course, but the old commits have absolutely zero
> effect, because they will be part of the common history.
I think I am (moderately) clear again on the inner working of Git.
Sorry for the confusion.
--
martin | http://madduck.net/ | http://two.sentenc.es/
"the search for the perfect martini is a fraud. the perfect martini
is a belt of gin from the bottle; anything else is the decadent
trappings of civilization."
-- t. k.
spamtraps: madduck.bogus@madduck.net
[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: gitk patch collection pull request
From: Linus Torvalds @ 2007-10-23 19:17 UTC (permalink / raw)
To: Paul Mackerras; +Cc: Shawn O. Pearce, git
In-Reply-To: <18205.15967.792413.775786@cargo.ozlabs.ibm.com>
On Tue, 23 Oct 2007, Paul Mackerras wrote:
>
> OK, done. The checkbox is in the Edit/Preferences window. It's
> called "Limit diffs to listed paths" and it's on by default.
Ok, the diff looks fine, but now the "list of files" pane on the right is
empty.
Even when you limit the diff output, you often have lots of files. At
least I do, because I often limit by subdirectory. So I'd still like to
see the file list on the right, so that I can jump to a particular part of
the diff.
(It would also be nice if it showed the *size* of the changes a'la
diffstat or something, but that's another and independent issue).
Linus
^ permalink raw reply
* Re: unmerging feature branches
From: Junio C Hamano @ 2007-10-23 19:33 UTC (permalink / raw)
To: Linus Torvalds; +Cc: martin f krafft, git discussion list
In-Reply-To: <alpine.LFD.0.999.0710230922240.30120@woody.linux-foundation.org>
Linus Torvalds <torvalds@linux-foundation.org> writes:
> Now, that said, reverting the data is not that hard. There is not any
> single-command "revert this arm of a merge", but on the other hand, git
> can certainly help you.
>
> The way to do it is:
>
> # go back to just before the merge, create a "fixup" branch
> #
> git branch -b fixup M^
>
> # merge all of it again, *except* the branch you didn't want to
> # merge (this example assumes that you had a four-way octopus
> # merge, and you now want to turn it into a three-way with the
> # next-to-last parent skipped):
> ...
Desire to revert an octopus would, as you demonstrated, often be
to revert only one arm, but I think allowing to revert a twohead
merge should be trivial. If we define "reverting a merge" to
always revert all arms, then this should suffice.
diff --git a/builtin-revert.c b/builtin-revert.c
index a655c8e..719e293 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -269,8 +269,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
if (!commit->parents)
die ("Cannot %s a root commit", me);
- if (commit->parents->next)
- die ("Cannot %s a multi-parent commit.", me);
+ if (action != REVERT && commit->parents->next)
+ die ("Cannot %s a merge commit.", me);
if (!(message = commit->buffer))
die ("Cannot get commit message for %s",
sha1_to_hex(commit->object.sha1));
Note that allowing cherry-pick by removing the above two lines
allow replaying the data of a merge similar to a squash merge.
^ 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