* Re: [RFC] teamGIT bonjour support
From: Abhijit Bhopatkar @ 2009-08-28 8:39 UTC (permalink / raw)
To: John Tapsell; +Cc: git, teamgit
In-Reply-To: <43d8ce650908280105x70327db0p7fce1bd6575297d2@mail.gmail.com>
>> good. But it has its usual problems of forcing everyone to religiously
>> publish _AND_ keep rebasing on main branch every so often. Also my
>> major problem is that we discover conflicts only _after_ a developer
>> tries to rebase his work, typically (by design) after he has fully
>> coded and tested a feature.
>
> What sort of time frame are you talking about? How long are your
> sprints, or however you partition your work.
>
> I can't help but feel the problem should be solved elsewhere. Do you
> have daily scrums? Everyone should know, roughly, what everyone is
> doing. If you are using 2-3 week sprints (or however you partition
> the time) and everyone is roughly aware of what everyone else around
> them is doing, there shouldn't really be so much of a problem.
Well as i said in informal way we do shout out loud (managers: read as
'daily meetings') when we want to make changes that might conflict
with some one else and i have been blessed with a rather good dev team
who can spot this right, and it works well for now for these short
sprints. However see below for my itch.
>> The current way to get around this is shouting aloud before you start
>> working on a new feature/file/section.
>
> How do you allocate the features in the first place? At the start of
> a sprint? If so, it should be the person in charge of that that
> should see if there are going to be conflicts. If you don't have
> sprints, then how do you divide up tasks?
Yes as i said this generally works.
But and this is a big BUT, this essentially makes the developer the
point of failure (in reporting the conflict). And in my view (exactly
contrary to yours) the problem should be solved else where.
Also we are working on many porting projects which need changes to the
same file but not essentially logically conflicting, which if,
everyone is aware of at the moment the change is made (commited?) is
trivial to resolve.
However when you have 100 such changes at the end of a sprint thats a
problem. Yes git makes it extremely easy to merge i can't even begin
to think about the current style of development in svn deployment. And
we can resolve those conflicts fairly easy. Its just that I have to
depend then on individual's ability to persist through what seems like
million merge conflicts.
And no its not avoidable, we _have_ to do those conflicting changes in
order to keep the pace of development. Its just about reporting them
sanely and quickly which is ok to be done manually, but it pains me
that the info can be available with some tool as well with obvious
benifits of automation.
So the idea is sort of local linux-next style automation for small teams.
BAIN
> John
^ permalink raw reply
* Re: Using git to track my PhD thesis, couple of questions
From: Paolo Bonzini @ 2009-08-28 8:34 UTC (permalink / raw)
To: Matthieu Moy; +Cc: seanh, git
In-Reply-To: <vpqk50pasek.fsf@bauges.imag.fr>
On 08/27/2009 10:55 PM, Matthieu Moy wrote:
> seanh<seanh.nospam@gmail.com> writes:
>
>> I'm planning to use git to track my PhD thesis as I work on it and to
>> let my supervisors track it. I've setup a git repository and a gitweb
>> instance showing it. There are a couple of specific requirements.
>>
>> 1. My supervisors don't want to see all the little commits that I make
>> day by day.
>
> I'm not sure I understand why you want that. From what you say, your
> supervisors won't be looking at the LaTeX source, so they won't read
> the diffs for the commits. Instead, they will be looking at regular
> snapshots in PDF. So, how is that disturbing to keep the intermediate
> commits ?
>
>> So I'll commit to a dev branch, then whenever I've made
>> significant progress will merge it into a trunk branch. I want the trunk
>> branch to get all the changes but as one big commit, not inherit all the
>> little commits like a normal merge would do. I think this is a `git
>> merge --squash`.
>
> It is, but this also means _you_ will somehow lose your intermediate
> commits. Well, you may not really lose them, but after a merge
> --squash, you have two options to continue working: work on top of the
> squashed commit (and then your ancestry doesn't contain the small
> ones), or work on top of your previous branches (and then, you don't
> have a proper merge tracking, and you'll get spurious conflicts if you
> try another merge --squash).
You can also merge from the master to your working branch after every
merge --squash.
... work on local ...
git commit
... work on local ...
git commit
git checkout master
git merge --squash local; git commit -m'day 1'
git checkout local
git merge master
> I also used a revision control system to write my Ph.D (Git was born
> after I started writting, so it wasn't Git yet), and my reviewing
> system has been all the more simple: when a chapter is done, send an
> email with the PDF attached, and "Hi, chapter $n is done, can you have
> a look?". That just works.
That's the same I did. I used git, but only locally. I never published
the repository for my supervisor, she didn't care.
>> Normally I wouldn't commit the PDF files into the repo because
>> they're compiled files not source files, but it seems that just
>> building a PDF and committing it along with each commit to trunk
>> would be by far the easiest way to achieve this. But will git store
>> the PDFs efficiently, or will the repo start to get really big?
>
> Git will do delta-compression as it can, but I don't think PDFs will
> delta-compress very well, so your repository may grow rather quickly,
> yes. If possible, commit the PDFs on a separate branch so that you can
> easily keep your clean history small in disk space, and discard the
> PDFs if needed.
That's a good advice. Remember to delete the branch reflog too if you
want to clean the history.
You can also try \pdfcompresslevel=0, which would probably make
delta-compression behave better at the expense of distributing bigger
files to your supervisor. If you use hyperref, see this:
http://www.tug.org/pipermail/pdftex/2003-August/004402.html
Best of all would be to have filters doing/undoing the PDF compression,
but I know of no free program doing this.
Paolo
^ permalink raw reply
* Re: [PATCH 08/14] Test for WIN32 instead of __MINGW32_
From: Paolo Bonzini @ 2009-08-28 8:15 UTC (permalink / raw)
To: Marius Storm-Olsen; +Cc: Johannes.Schindelin, msysgit, git, lznuaa
In-Reply-To: <1e623b19b2df001919c83418fef89ef04d7b8dfe.1250860247.git.mstormo@gmail.com>
Since you are doing this, you may as well change patch 3 from
+#if (defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4) ||
defined(_MSC_VER)
to this:
#if defined WIN32 && (!defined (__GNUC__) || __GNUC__ < 4))
Paolo
^ permalink raw reply
* Re: git-svn intermittent issues with absent_file
From: Matthias Andree @ 2009-08-28 8:14 UTC (permalink / raw)
To: Eric Wong; +Cc: git
In-Reply-To: <op.uzc1njug3myrm3@merlin.emma.line.org>
Am 28.08.2009, 08:58 Uhr, schrieb Matthias Andree
<matthias.andree@uni-paderborn.de>:
> The other question is how many arcane APR or Subversion binding issues we
> hit here. Subversion 1.6 + bindings surely is rather picky on Cygwin 1.5,
> as discussed earlier on this list.
As an update, Git-SVN 1.6.4.0 and 1.6.4.1 haven't seen such problems last
night when run on Ubuntu Linux.
So, the common idea set is apparently down to (a) intermittent server
issues (I've asked for the relevant log excerpts) and (b) Cygwin issues,
and we should keep in mind (c) git-svn, or svn bindings/libraries, losing
the causes error conditions from (a) or (b) and git-svn just reporting
later symptoms (absent files). More on the other experiments once I get
around to them.
Thanks
Matthias
^ permalink raw reply
* Re: [RFC] teamGIT bonjour support
From: John Tapsell @ 2009-08-28 8:05 UTC (permalink / raw)
To: git, teamgit
In-Reply-To: <2fcfa6df0908280002y221a22e6md27db56865472144@mail.gmail.com>
2009/8/28 Abhijit Bhopatkar <bain@devslashzero.com>:
> Hi,
>
> After a long pause in the development, i am back to drawing boards for teamGit.
>
> Ever since i adopted git as my preferred version control system for my
> teams, I had this tough time keeping up with every one. Of course this
> is a GoodThing(TM) since this means pace of development is rather
> good. But it has its usual problems of forcing everyone to religiously
> publish _AND_ keep rebasing on main branch every so often. Also my
> major problem is that we discover conflicts only _after_ a developer
> tries to rebase his work, typically (by design) after he has fully
> coded and tested a feature.
What sort of time frame are you talking about? How long are your
sprints, or however you partition your work.
I can't help but feel the problem should be solved elsewhere. Do you
have daily scrums? Everyone should know, roughly, what everyone is
doing. If you are using 2-3 week sprints (or however you partition
the time) and everyone is roughly aware of what everyone else around
them is doing, there shouldn't really be so much of a problem.
> The current way to get around this is shouting aloud before you start
> working on a new feature/file/section.
How do you allocate the features in the first place? At the start of
a sprint? If so, it should be the person in charge of that that
should see if there are going to be conflicts. If you don't have
sprints, then how do you divide up tasks?
John
^ permalink raw reply
* Re: [PATCH] Round-down years in "years+months" relative date view
From: Alex Riesen @ 2009-08-28 7:58 UTC (permalink / raw)
To: Jeff King; +Cc: David Reiss, git
In-Reply-To: <20090828060538.GA22416@coredump.intra.peff.net>
On Fri, Aug 28, 2009 at 08:05, Jeff King<peff@peff.net> wrote:
> On Thu, Aug 27, 2009 at 04:39:38PM -0700, David Reiss wrote:
>
>> Previously, a commit from 1 year and 7 months ago would display as
>> "2 years, 7 months ago".
>
> Wow, embarrassing.
>
> Acked-by: Jeff King <peff@peff.net>
>
>> Here's my test script. Let me know if you'd rather have it as part
>> of the test suite.
>
> I couldn't find any tests related to relative date processing, so it
> would be really nice to have some. But I'm not sure of the best way to
> do it without dealing with race conditions. Annoyingly, show_date calls
> gettimeofday at a pretty low level, so there isn't a way of
> instrumenting it short of LD_PRELOAD trickery (which is probably not
> very portable).
Maybe better prepare the _test_ so that it uses current time and time
arithmetics then put yet another cludge in operational code? Especially
when we already have a greate number of GIT_ environment variables,
documented nowhere, with effects not immediately obvious:
$ git grep -n '"GIT_'| perl -ne '/"(GIT_\w+)/ && print "$1\n"' |
sort |uniq | wc -l
49
$ git grep -n '"GIT_'|grep ^Documentation
$
GIT_FLUSH? GIT_SEND_EMAIL_NOTTY?! GIT_CHERRY_PICK_HELP?!!
^ permalink raw reply
* [RFC] teamGIT bonjour support
From: Abhijit Bhopatkar @ 2009-08-28 7:02 UTC (permalink / raw)
To: git, teamgit
Hi,
After a long pause in the development, i am back to drawing boards for teamGit.
Ever since i adopted git as my preferred version control system for my
teams, I had this tough time keeping up with every one. Of course this
is a GoodThing(TM) since this means pace of development is rather
good. But it has its usual problems of forcing everyone to religiously
publish _AND_ keep rebasing on main branch every so often. Also my
major problem is that we discover conflicts only _after_ a developer
tries to rebase his work, typically (by design) after he has fully
coded and tested a feature.
The current way to get around this is shouting aloud before you start
working on a new feature/file/section.
However a. this is not scalable
b. pron to human errors
c. pron to inhumane erros and after fights ;).
So in this regards, I have on my drawing boards a rough design to
1. Publish the current selected topic trees info on local lan.
2. Keep track of interesting topic branches and add alerts when
conflicts bet. selected trees reach alarming levels.
3. Possibly later add authentication mechanism to restrict access.
I plan to do this on LAN using bonjour service discovery, and rest
completely being handled inside teamGIT running as a daemon(may be in
widely abused systray?). (Git will handle actual fetch/conflict
checking etc.)
On a side note i also plan to generate daily reports and configurable
notifications.
So I ask you people, is there a solution already cooking someplace?
may be something i can integrate with teamGIT? (e.g. bonjour plugin
for git dameon)
Any thoughts or comment?
Am i just too stupid to not manage it with documented company wide policies?
BAIN
^ permalink raw reply
* Re: git-svn intermittent issues with absent_file
From: Matthias Andree @ 2009-08-28 6:58 UTC (permalink / raw)
To: Eric Wong; +Cc: git
In-Reply-To: <20090827191902.GA3185@dcvr.yhbt.net>
Am 27.08.2009, 21:19 Uhr, schrieb Eric Wong <normalperson@yhbt.net>:
> Matthias Andree <matthias.andree@uni-paderborn.de> wrote:
>> Greetings,
>>
>> we seem to have issues with checking out files from an SVN server via
>> https://. The problem is hard to reproduce, and shows as "absent_file"
>> warnings, i. e. files that are in the SVN checkout don't make it to the
>> Git checkin.
>>
>> Perhaps this rings a bell with someone or there are similar reports that
>> relate to our issues...
>
> Hi Matthias,
>
> I don't recall any issues with the "absent_file" callback ever being
> reported to me. I don't think I've ever touched a repo that triggered
> it, either...
Hi Eric,
thank you for the prompt reply.
>> ## ISSUE ## Once in a while, a git-svn clone or rebase fails with files
>> missing from commits, as mentioned above. We haven't been able to figure
>> out under what circumstances this happens. If we try to reproduce this
>> (i. e. kill the directory completely and re-run the git svn clone),
>> another revision (for instance 170) might show this, or the clone may
>> succeed.
>> This was observed with Git 1.6.0.4 under Ubuntu Linux Jaunty Jackalope
>> (9.04) and on a different computer with Git 1.6.4.1.196.g31f0b (from the
>> master branch) under a fully updated Cygwin 1.5.
>
> I assume this happens with the latest git under Ubuntu Linux, too; but
> can you give that a try just in case?
The latest git was on Cygwin, but we'll see to trying it on Linux.
> There have been a few odd bugs fixed since 1.6.0.4, but nothing rings a
> bell here. This doesn't seem to be a Cygwin/Win32-related issue, but
> I'd like to minimize the number of variables since I can't support
> Cygwin/Win32 directly.
The other question is how many arcane APR or Subversion binding issues we
hit here. Subversion 1.6 + bindings surely is rather picky on Cygwin 1.5,
as discussed earlier on this list.
>> Questions:
>>
>> 1. What causes these absent_file issues? How can we assist with
>> debugging
>> this?
>
> Permissions would be my first (and only) guess as I have no experience
> with this condition...
Hm. In that case: who writes the file that goes missing, and why isn't the
error logged then? Is there a way to have the SVN bindings or the
interfacing code in Git-SVN log file creation/write errors with decoded
errno? That might help a big deal already.
> Are you using anything weird in ~/.subversion/config by any chance?
Not to my knowledge.
> And you're sure you're using the same user/account in all cases?
Yes indeed. All under the same account.
> Are the files you're hitting absent_file on unusually large and
> hitting some limit on the server side?
The files aren't, the whole changeset might. We haven't yet observed this
on small (as in one .tex file) commits.
>> 2. What does "Delta source ended unexpectedly" mean? (the line number is
>> bogus, it's just the finish_report call)
>
> Sometimes the server can just shut down/drop connections. Do you have
> access to the server logs? How many simultaneous connections can
> it accept? Which version of the Subversion server is running?
The server doesn't permit user logins, so we need to ask the support
staff. Answer times are unpredictable.
> How reliable is your network connection to the server?
> Anything weird with the network configuration? Mismatched MTU, odd
> firewall rules, non-standard TCP stack configuration, VPN, proxies...
Uncritical. Company network, "direct connection" (through switches).
>> 3. Is this or a similar issue known? Is this an issue with the SVN
>> server, the SVN bindings, or the git svn adaptor?
>
> The "Incomplete data: Delta source ended unexpectedly" happens
> from time to time on a few odd servers, but I've never found it
> reproducible and retrying "git svn fetch" always fixes it.
> This is more than likely the fault of the network or server.
Seems plausible, but...
> The "absent_file" issue I've never seen...
...in such a case, some part of the overall system (I'm not saying it's
git-svn though) must ignore an error and continue.
>> We're happy to test patches.
>
> Cool. I don't have any ideas for patches right now, but does this
> problem happen with other SVN clients? Even svk/svm could be
> worth a shot for testing...
I can try svk, but what's svm?
--
Matthias Andree
^ permalink raw reply
* Re: [PATCH v4 04/15] sequencer: add "reset_almost_hard()" and related functions
From: Eric Raible @ 2009-08-28 6:08 UTC (permalink / raw)
To: git
In-Reply-To: <20090828044746.4307.88742.chriscool@tuxfamily.org>
Christian Couder <chriscool <at> tuxfamily.org> writes:
> "reset_almost_hard()" can be used to do a "git reset --hard". It
> should be faster as it calls "unpack_trees()" directly, and it can
> optionnaly preserve changes in the work tree if the "allow_dirty"
> global is set. Preserving changes in the work tree can be usefull
> if for example you want to get rid of the last commit but keep
> your current not yet commited work.
s/optionnaly/optionally/
s/usefull/useful/
^ permalink raw reply
* Re: [PATCH] Round-down years in "years+months" relative date view
From: Jeff King @ 2009-08-28 6:05 UTC (permalink / raw)
To: David Reiss; +Cc: git
In-Reply-To: <4A97193A.8090502@facebook.com>
On Thu, Aug 27, 2009 at 04:39:38PM -0700, David Reiss wrote:
> Previously, a commit from 1 year and 7 months ago would display as
> "2 years, 7 months ago".
Wow, embarrassing.
Acked-by: Jeff King <peff@peff.net>
> Here's my test script. Let me know if you'd rather have it as part
> of the test suite.
I couldn't find any tests related to relative date processing, so it
would be really nice to have some. But I'm not sure of the best way to
do it without dealing with race conditions. Annoyingly, show_date calls
gettimeofday at a pretty low level, so there isn't a way of
instrumenting it short of LD_PRELOAD trickery (which is probably not
very portable).
But maybe a patch like this is worth doing, which would allow us to test
in a repeatable fashion:
---
diff --git a/date.c b/date.c
index e848d96..db2f831 100644
--- a/date.c
+++ b/date.c
@@ -86,6 +86,33 @@ static int local_tzoffset(unsigned long time)
return offset * eastwest;
}
+static int current_time(struct timeval *now)
+{
+ static struct timeval fake_time;
+ static int use_fake_time = -1;
+
+ if (use_fake_time == -1) {
+ const char *x = getenv("GIT_FAKE_TIME");
+ if (x) {
+ char buf[50];
+ if (parse_date(x, buf, sizeof(buf)) <= 0)
+ die("unable to parse GIT_FAKE_TIME");
+ fake_time.tv_sec = strtoul(buf, NULL, 10);
+ fake_time.tv_usec = 0;
+ use_fake_time = 1;
+ }
+ else
+ use_fake_time = 0;
+ }
+
+ if (use_fake_time == 1) {
+ memcpy(now, &fake_time, sizeof(*now));
+ return 0;
+ }
+
+ return gettimeofday(now, NULL);
+}
+
const char *show_date(unsigned long time, int tz, enum date_mode mode)
{
struct tm *tm;
@@ -99,7 +126,7 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
if (mode == DATE_RELATIVE) {
unsigned long diff;
struct timeval now;
- gettimeofday(&now, NULL);
+ current_time(&now);
if (now.tv_sec < time)
return "in the future";
diff = now.tv_sec - time;
@@ -929,7 +956,7 @@ unsigned long approxidate(const char *date)
if (parse_date(date, buffer, sizeof(buffer)) > 0)
return strtoul(buffer, NULL, 10);
- gettimeofday(&tv, NULL);
+ current_time(&tv);
time_sec = tv.tv_sec;
localtime_r(&time_sec, &tm);
now = tm;
^ permalink raw reply related
* Re: [PATCH] git-bisect: call the found commit "*the* first bad commit"
From: Christian Couder @ 2009-08-28 5:31 UTC (permalink / raw)
To: Nanako Shiraishi; +Cc: git, Junio C Hamano
In-Reply-To: <20090826173850.6117@nanako3.lavabit.com>
On Wednesday 26 August 2009, Nanako Shiraishi wrote:
> .. as we learned in the school ;-)
>
> Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
> ---
> bisect.c | 2 +-
> git-bisect.sh | 2 +-
> t/t6030-bisect-porcelain.sh | 18 +++++++++---------
> 3 files changed, 11 insertions(+), 11 deletions(-)
>
> diff --git a/bisect.c b/bisect.c
> index 7f20acb..dc18db8 100644
> --- a/bisect.c
> +++ b/bisect.c
> @@ -991,7 +991,7 @@ int bisect_next_all(const char *prefix)
>
> if (!hashcmp(bisect_rev, current_bad_sha1)) {
> exit_if_skipped_commits(tried, current_bad_sha1);
> - printf("%s is first bad commit\n", bisect_rev_hex);
> + printf("%s is the first bad commit\n", bisect_rev_hex);
> show_diff_tree(prefix, revs.commits->item);
> /* This means the bisection process succeeded. */
> exit(10);
Thanks, but I wonder if this could give the false impression that there can
only be one "first bad commit". Because it's possible that a bug appears in
one commit say A, then get fixed in another one say B, and eventually
reappears in a third one say C. So if the bisection range contains all
these commits, the result from bisecting could be A or C.
Best regards,
Christian.
^ permalink raw reply
* [PATCH v4 08/15] sequencer: add "--fast-forward" option to "git sequencer--helper"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
This new option uses the "do_fast_forward()" function to perform
a fast forward.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-sequencer--helper.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index 0cd7e98..bd72f65 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -19,6 +19,7 @@ static unsigned char head_sha1[20];
static const char * const git_sequencer_helper_usage[] = {
"git sequencer--helper --make-patch <commit>",
"git sequencer--helper --reset-hard <commit> <reflog-msg> <verbosity>",
+ "git sequencer--helper --fast-forward <commit> <reflog-msg> <verbosity>",
NULL
};
@@ -218,11 +219,14 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
{
char *patch_commit = NULL;
char *reset_commit = NULL;
+ char *ff_commit = NULL;
struct option options[] = {
OPT_STRING(0, "make-patch", &patch_commit, "commit",
"create a patch from commit"),
OPT_STRING(0, "reset-hard", &reset_commit, "commit",
"reset to commit"),
+ OPT_STRING(0, "fast-forward", &ff_commit, "commit",
+ "fast forward to commit"),
OPT_END()
};
@@ -239,15 +243,16 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
return 0;
}
- if (reset_commit) {
+ if (ff_commit || reset_commit) {
unsigned char sha1[20];
+ char *commit = ff_commit ? ff_commit : reset_commit;
if (argc != 2)
usage_with_options(git_sequencer_helper_usage,
options);
- if (get_sha1(reset_commit, sha1)) {
- error("Could not find '%s'", reset_commit);
+ if (get_sha1(commit, sha1)) {
+ error("Could not find '%s'", commit);
return 1;
}
@@ -258,7 +263,10 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
return 1;
}
- return reset_almost_hard(sha1);
+ if (ff_commit)
+ return do_fast_forward(sha1);
+ else
+ return reset_almost_hard(sha1);
}
usage_with_options(git_sequencer_helper_usage, options);
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 07/15] sequencer: add "do_fast_forward()" to perform a fast forward
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
This function is a thin wrapper around "reset_almost_hard()".
It is usefull because it will help reduce a little the shell
code line count.
This code is taken from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
but the messages have been changed a little to be the same as
those displayed by "git-rebase--interactive.sh".
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-sequencer--helper.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index be030bc..0cd7e98 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -171,6 +171,15 @@ static struct commit *get_commit(const char *arg)
return lookup_commit_reference(sha1);
}
+static int do_fast_forward(const unsigned char *sha)
+{
+ if (reset_almost_hard(sha))
+ return error("Cannot fast forward to %s", sha1_to_hex(sha));
+ if (verbosity > 1)
+ printf("Fast forward to %s\n", sha1_to_hex(sha));
+ return 0;
+}
+
static int set_verbosity(int verbose)
{
char tmp[] = "0";
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 03/15] rebase -i: use "git sequencer--helper --make-patch"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
to simplify the "make_patch" function.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
git-rebase--interactive.sh | 13 +------------
1 files changed, 1 insertions(+), 12 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 23ded48..c9c75c0 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -117,18 +117,7 @@ mark_action_done () {
}
make_patch () {
- sha1_and_parents="$(git rev-list --parents -1 "$1")"
- case "$sha1_and_parents" in
- ?*' '?*' '?*)
- git diff --cc $sha1_and_parents
- ;;
- ?*' '?*)
- git diff-tree -p "$1^!"
- ;;
- *)
- echo "Root commit"
- ;;
- esac > "$DOTEST"/patch
+ git sequencer--helper --make-patch "$1"
test -f "$DOTEST"/message ||
git cat-file commit "$1" | sed "1,/^$/d" > "$DOTEST"/message
test -f "$DOTEST"/author-script ||
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 09/15] sequencer: let "git sequencer--helper" callers set "allow_dirty"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
This flag can be set when using --reset-hard or --fast-forward, and
in this case changes in the work tree will be kept.
This change is usefull to let people play with the "allow_dirty"
feature.
Suggested-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-sequencer--helper.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index bd72f65..71a7fef 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -18,8 +18,10 @@ static unsigned char head_sha1[20];
static const char * const git_sequencer_helper_usage[] = {
"git sequencer--helper --make-patch <commit>",
- "git sequencer--helper --reset-hard <commit> <reflog-msg> <verbosity>",
- "git sequencer--helper --fast-forward <commit> <reflog-msg> <verbosity>",
+ "git sequencer--helper --reset-hard <commit> <reflog-msg> "
+ "<verbosity> [<allow-dirty>]",
+ "git sequencer--helper --fast-forward <commit> <reflog-msg> "
+ "<verbosity> [<allow-dirty>]",
NULL
};
@@ -247,7 +249,7 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
unsigned char sha1[20];
char *commit = ff_commit ? ff_commit : reset_commit;
- if (argc != 2)
+ if (argc != 2 && argc != 3)
usage_with_options(git_sequencer_helper_usage,
options);
@@ -263,6 +265,9 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
return 1;
}
+ if (argc == 3 && *argv[2] && strcmp(argv[2], "0"))
+ allow_dirty = 1;
+
if (ff_commit)
return do_fast_forward(sha1);
else
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 10/15] rebase -i: use "git sequencer--helper --fast-forward"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
when fast forwarding, as it removes a few more lines of shell
code.
Note that in the first hunk of this patch, there was this line:
test "a$1" = a-n && output git reset --soft $current_sha1
but the test always failed.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
git-rebase--interactive.sh | 11 +++--------
1 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 0041994..7651fd6 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -154,11 +154,8 @@ pick_one () {
die "Could not get the parent of $sha1"
current_sha1=$(git rev-parse --verify HEAD)
if test "$no_ff$current_sha1" = "$parent_sha1"; then
- git sequencer--helper --reset-hard $sha1 \
+ git sequencer--helper --fast-forward $sha1 \
"$GIT_REFLOG_ACTION" "$VERBOSE"
- test "a$1" = a-n && output git reset --soft $current_sha1
- sha1=$(git rev-parse --short $sha1)
- output warn Fast forward to $sha1
else
output git cherry-pick "$@"
fi
@@ -238,10 +235,8 @@ pick_one_preserving_merges () {
done
case $fast_forward in
t)
- output warn "Fast forward to $sha1"
- git sequencer--helper --reset-hard $sha1 \
- "$GIT_REFLOG_ACTION" "$VERBOSE" ||
- die "Cannot fast forward to $sha1"
+ git sequencer--helper --fast-forward $sha1 \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" || exit
;;
f)
first_parent=$(expr "$new_parents" : ' \([^ ]*\)')
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 14/15] sequencer: add "--cherry-pick" option to "git sequencer--helper"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
This patch implements a new "do_cherry_pick()" function using the
previously libified "pick_commit()" function and some other functions
(like "do_commit()") previously added to "builtin-sequencer--helper.c".
Like in the "do_commit()" function, the "next_commit" global is
used to store commit related information, so we cannot easily reuse
existing code to perform what "do_cherry_pick()" does.
This patch adds some code that comes from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
Most of the code from do_cherry_pick() is taken from the
sequencer insn_pick_act() function.
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-sequencer--helper.c | 70 +++++++++++++++++++++++++++++++++++++-----
1 files changed, 61 insertions(+), 9 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index 014e4ce..291ba18 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -60,6 +60,8 @@ static const char * const git_sequencer_helper_usage[] = {
"<verbosity> [<allow-dirty>]",
"git sequencer--helper --fast-forward <commit> <reflog-msg> "
"<verbosity> [<allow-dirty>]",
+ "git sequencer--helper --cherry-pick <commit> <reflog-msg> "
+ "<verbosity> [<do-not-commit>]",
NULL
};
@@ -287,7 +289,7 @@ static int do_commit(unsigned char *parent_sha1)
if (update_ref(reflog, "HEAD", commit_sha1, NULL, 0, 0))
return error("Could not update HEAD to %s.",
- sha1_to_hex(commit_sha1));
+ sha1_to_hex(commit_sha1));
return 0;
}
@@ -407,6 +409,46 @@ static int write_commit_summary_into(const char *filename)
return 0;
}
+static int do_cherry_pick(char *cp_commit, int no_commit)
+{
+ struct commit *commit;
+ int failed;
+ const char *author;
+
+ if (get_sha1("HEAD", head_sha1))
+ return error("You do not have a valid HEAD.");
+
+ commit = get_commit(cp_commit);
+ if (!commit)
+ return 1;
+
+ set_pick_subject(cp_commit, commit);
+
+ failed = pick_commit(commit, 0, 0, &next_commit.summary);
+
+ set_message_source(sha1_to_hex(commit->object.sha1));
+ author = strstr(commit->buffer, "\nauthor ");
+ if (author)
+ set_author_info(author + 8);
+
+ /* We do not want extra Conflicts: lines on cherry-pick,
+ so just take the old commit message. */
+ if (failed) {
+ strbuf_setlen(&next_commit.summary, 0);
+ strbuf_addstr(&next_commit.summary,
+ strstr(commit->buffer, "\n\n") + 2);
+ rerere();
+ make_patch(commit);
+ write_commit_summary_into(MERGE_MSG);
+ return error(pick_help_msg(commit->object.sha1, 0));
+ }
+
+ if (!no_commit && do_commit(head_sha1))
+ return error("Could not commit.");
+
+ return 0;
+}
+
/**********************************************************************
* Builtin sequencer helper functions
*/
@@ -435,6 +477,7 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
char *patch_commit = NULL;
char *reset_commit = NULL;
char *ff_commit = NULL;
+ char *cp_commit = NULL;
struct option options[] = {
OPT_STRING(0, "make-patch", &patch_commit, "commit",
"create a patch from commit"),
@@ -442,6 +485,8 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
"reset to commit"),
OPT_STRING(0, "fast-forward", &ff_commit, "commit",
"fast forward to commit"),
+ OPT_STRING(0, "cherry-pick", &cp_commit, "commit",
+ "cherry pick commit"),
OPT_END()
};
@@ -458,19 +503,15 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
return 0;
}
- if (ff_commit || reset_commit) {
+ if (cp_commit || ff_commit || reset_commit) {
unsigned char sha1[20];
- char *commit = ff_commit ? ff_commit : reset_commit;
+ char *commit;
+ int opt_arg = 0;
if (argc != 2 && argc != 3)
usage_with_options(git_sequencer_helper_usage,
options);
- if (get_sha1(commit, sha1)) {
- error("Could not find '%s'", commit);
- return 1;
- }
-
reflog = (char *)argv[0];
if (parse_verbosity(argv[1])) {
@@ -479,7 +520,18 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
}
if (argc == 3 && *argv[2] && strcmp(argv[2], "0"))
- allow_dirty = 1;
+ opt_arg = 1;
+
+ if (cp_commit)
+ return do_cherry_pick(cp_commit, opt_arg);
+
+ allow_dirty = opt_arg;
+
+ commit = ff_commit ? ff_commit : reset_commit;
+ if (get_sha1(commit, sha1)) {
+ error("Could not find '%s'", commit);
+ return 1;
+ }
if (ff_commit)
return do_fast_forward(sha1);
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 12/15] pick: libify "pick_help_msg()"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
This function gives an help message when pick or revert failed.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-revert.c | 23 +----------------------
pick.c | 22 ++++++++++++++++++++++
pick.h | 1 +
3 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/builtin-revert.c b/builtin-revert.c
index 4797ac5..e5250bd 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -142,27 +142,6 @@ static void set_author_ident_env(const char *message)
sha1_to_hex(commit->object.sha1));
}
-static char *help_msg(const unsigned char *sha1)
-{
- static char helpbuf[1024];
- char *msg = getenv("GIT_CHERRY_PICK_HELP");
-
- if (msg)
- return msg;
-
- strcpy(helpbuf, " After resolving the conflicts,\n"
- "mark the corrected paths with 'git add <paths>' "
- "or 'git rm <paths>' and commit the result.");
-
- if (!(flags & PICK_REVERSE)) {
- sprintf(helpbuf + strlen(helpbuf),
- "\nWhen commiting, use the option "
- "'-c %s' to retain authorship and message.",
- find_unique_abbrev(sha1, DEFAULT_ABBREV));
- }
- return helpbuf;
-}
-
static void write_message(struct strbuf *msgbuf, const char *filename)
{
struct lock_file msg_file;
@@ -211,7 +190,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
exit(1);
} else if (failed > 0) {
fprintf(stderr, "Automatic %s failed.%s\n",
- me, help_msg(commit->object.sha1));
+ me, pick_help_msg(commit->object.sha1, flags));
write_message(&msgbuf, git_path("MERGE_MSG"));
rerere();
exit(1);
diff --git a/pick.c b/pick.c
index bb04c68..e1242f6 100644
--- a/pick.c
+++ b/pick.c
@@ -216,3 +216,25 @@ int pick_commit(struct commit *pick_commit, int mainline, int flags,
return ret;
}
+
+char *pick_help_msg(const unsigned char *sha1, int flags)
+{
+ static char helpbuf[1024];
+ char *msg = getenv("GIT_CHERRY_PICK_HELP");
+
+ if (msg)
+ return msg;
+
+ strcpy(helpbuf, " After resolving the conflicts,\n"
+ "mark the corrected paths with 'git add <paths>' "
+ "or 'git rm <paths>' and commit the result.");
+
+ if (!(flags & PICK_REVERSE)) {
+ sprintf(helpbuf + strlen(helpbuf),
+ "\nWhen commiting, use the option "
+ "'-c %s' to retain authorship and message.",
+ find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ }
+ return helpbuf;
+}
+
diff --git a/pick.h b/pick.h
index 7a74ad8..115541a 100644
--- a/pick.h
+++ b/pick.h
@@ -9,5 +9,6 @@
/* We don't need a PICK_QUIET. This is done by
* setenv("GIT_MERGE_VERBOSITY", "0", 1); */
extern int pick_commit(struct commit *commit, int mainline, int flags, struct strbuf *msg);
+extern char *pick_help_msg(const unsigned char *sha1, int flags);
#endif
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 13/15] sequencer: add "do_commit()" and related functions working on "next_commit"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
This patch adds "struct commit_info", the "next_commit" static variable
and the following functions:
- do_commit()
- set_author_info()
- set_message_source()
- set_pick_subject()
- write_commit_summary_into()
This makes it possible to prepare and perform a commit (without forking
and execing "git commit"), and this will be used in a following patch to
perform a cherry-pick.
All these functions work on the "struct commit_info next_commit" global.
This variable will eventually be saved between the different calls to
"git rebase" (or "git sequencer"). So we cannot easily reuse existing
functions from "builtin-commit.c" or "builtin-commit-tree.c" and we need
these special functions.
This patch adds some code that comes from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
Compared to the sequencer project, the only change is that "mark"
related (3 lines long) code has been removed from do_commit().
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
builtin-sequencer--helper.c | 213 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 213 insertions(+), 0 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index 71a7fef..014e4ce 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -5,17 +5,55 @@
#include "refs.h"
#include "diff.h"
#include "unpack-trees.h"
+#include "string-list.h"
+#include "pick.h"
+#include "rerere.h"
+#include "dir.h"
+#include "cache-tree.h"
+#include "utf8.h"
#define SEQ_DIR "rebase-merge"
#define PATCH_FILE git_path(SEQ_DIR "/patch")
+#define MERGE_MSG git_path("MERGE_MSG")
+#define SQUASH_MSG git_path("SQUASH_MSG")
+
+/**********************************************************************
+ * Data structures
+ */
+
+struct user_info {
+ const char *name;
+ const char *mail;
+ const char *time; /* "<timestamp> <timezone>" */
+};
+
+struct commit_info {
+ struct user_info author; /* author info */
+ struct user_info committer; /* not used, but for easy extendability */
+ const char *encoding; /* encoding */
+ char *subject; /* basically the first line of the summary */
+ struct strbuf summary; /* the commit message */
+ char *source; /* source of the commit message, either
+ * "message", "merge", "squash" or a commit SHA1 */
+ char *patch; /* a patch */
+ struct string_list parents; /* list of parents' hex'ed sha1 ids */
+};
+
+/**********************************************************************
+ * Global variables
+ */
static char *reflog;
+static int squash_count = 0;
+
static int allow_dirty = 0, verbosity = 1, advice = 1;
static unsigned char head_sha1[20];
+static struct commit_info next_commit;
+
static const char * const git_sequencer_helper_usage[] = {
"git sequencer--helper --make-patch <commit>",
"git sequencer--helper --reset-hard <commit> <reflog-msg> "
@@ -25,6 +63,10 @@ static const char * const git_sequencer_helper_usage[] = {
NULL
};
+/**********************************************************************
+ * Sequencer functions
+ */
+
static int parse_and_init_tree_desc(const unsigned char *sha1,
struct tree_desc *desc)
{
@@ -162,6 +204,157 @@ static void make_patch(struct commit *commit)
free(args);
}
+/* Commit current index with information next_commit onto parent_sha1. */
+static int do_commit(unsigned char *parent_sha1)
+{
+ int failed;
+ unsigned char tree_sha1[20];
+ unsigned char commit_sha1[20];
+ struct strbuf sbuf;
+ const char *reencoded = NULL;
+
+ if (squash_count) {
+ squash_count = 0;
+ if (file_exists(SQUASH_MSG))
+ unlink(SQUASH_MSG);
+ }
+
+ if (!index_differs_from("HEAD", 0) &&
+ !next_commit.parents.nr)
+ return error("No changes! Do you really want an empty commit?");
+
+ if (!next_commit.author.name || !next_commit.author.mail)
+ return error("Internal error: Author information not set properly.");
+
+ if (write_cache_as_tree(tree_sha1, 0, NULL))
+ return 1;
+
+ if (!next_commit.encoding)
+ next_commit.encoding = xstrdup("utf-8");
+ if (!git_commit_encoding)
+ git_commit_encoding = "utf-8";
+
+ strbuf_init(&sbuf, 8192); /* should avoid reallocs for the headers */
+ strbuf_addf(&sbuf, "tree %s\n", sha1_to_hex(tree_sha1));
+ if (parent_sha1)
+ strbuf_addf(&sbuf, "parent %s\n", sha1_to_hex(parent_sha1));
+ if (next_commit.parents.nr) {
+ int i;
+ for (i = 0; i < next_commit.parents.nr; ++i)
+ strbuf_addf(&sbuf, "parent %s\n",
+ next_commit.parents.items[i].string);
+ }
+ if (!next_commit.author.time) {
+ char time[50];
+ datestamp(time, sizeof(time));
+ next_commit.author.time = xstrdup(time);
+ }
+
+ stripspace(&next_commit.summary, 1);
+
+ /* if encodings differ, reencode whole buffer */
+ if (strcasecmp(git_commit_encoding, next_commit.encoding)) {
+ if ((reencoded = reencode_string(next_commit.author.name,
+ git_commit_encoding, next_commit.encoding))) {
+ free((void *)next_commit.author.name);
+ next_commit.author.name = reencoded;
+ }
+ if ((reencoded = reencode_string(next_commit.summary.buf,
+ git_commit_encoding, next_commit.encoding))) {
+ strbuf_reset(&next_commit.summary);
+ strbuf_addstr(&next_commit.summary, reencoded);
+ }
+ }
+ strbuf_addf(&sbuf, "author %s <%s> %s\n", next_commit.author.name,
+ next_commit.author.mail, next_commit.author.time);
+ strbuf_addf(&sbuf, "committer %s\n", git_committer_info(0));
+ if (!is_encoding_utf8(git_commit_encoding))
+ strbuf_addf(&sbuf, "encoding %s\n", git_commit_encoding);
+ strbuf_addch(&sbuf, '\n');
+ strbuf_addbuf(&sbuf, &next_commit.summary);
+ if (sbuf.buf[sbuf.len-1] != '\n')
+ strbuf_addch(&sbuf, '\n');
+
+ failed = write_sha1_file(sbuf.buf, sbuf.len, commit_type, commit_sha1);
+ strbuf_release(&sbuf);
+ if (failed)
+ return 1;
+
+ if (verbosity > 1)
+ printf("Created %scommit %s\n",
+ parent_sha1 || next_commit.parents.nr ? "" : "initial ",
+ sha1_to_hex(commit_sha1));
+
+ if (update_ref(reflog, "HEAD", commit_sha1, NULL, 0, 0))
+ return error("Could not update HEAD to %s.",
+ sha1_to_hex(commit_sha1));
+
+ return 0;
+}
+
+/*
+ * Fill next_commit.author according to ident.
+ * Ident may have one of the following forms:
+ * "name <e-mail> timestamp timezone\n..."
+ * "name <e-mail> timestamp timezone"
+ * "name <e-mail>"
+ */
+static void set_author_info(const char *ident)
+{
+ const char *tmp1 = strstr(ident, " <");
+ const char *tmp2;
+ char *data;
+ if (!tmp1)
+ return;
+ tmp2 = strstr(tmp1+2, ">");
+ if (!tmp2)
+ return;
+ if (tmp2[1] != 0 && tmp2[1] != ' ')
+ return;
+
+ data = xmalloc(strlen(ident)); /* a trivial upper bound */
+
+ snprintf(data, tmp1-ident+1, "%s", ident);
+ next_commit.author.name = xstrdup(data);
+ snprintf(data, tmp2-tmp1-1, "%s", tmp1+2);
+ next_commit.author.mail = xstrdup(data);
+
+ if (tmp2[1] == 0) {
+ free(data);
+ return;
+ }
+
+ tmp1 = strpbrk(tmp2+2, "\r\n");
+ if (!tmp1)
+ tmp1 = tmp2 + strlen(tmp2);
+
+ snprintf(data, tmp1-tmp2-1, "%s", tmp2+2);
+ next_commit.author.time = xstrdup(data);
+ free(data);
+}
+
+static void set_message_source(const char *source)
+{
+ if (next_commit.source)
+ free(next_commit.source);
+ next_commit.source = xstrdup(source);
+}
+
+/* Set subject, an information for the case of conflict */
+static void set_pick_subject(const char *hex, struct commit *commit)
+{
+ const char *tmp = strstr(commit->buffer, "\n\n");
+ if (tmp) {
+ const char *eol;
+ int len = strlen(hex);
+ tmp += 2;
+ eol = strchrnul(tmp, '\n');
+ next_commit.subject = xmalloc(eol - tmp + len + 5);
+ snprintf(next_commit.subject, eol - tmp + len + 5, "%s... %s",
+ hex, tmp);
+ }
+}
+
/* Return a commit object of "arg" */
static struct commit *get_commit(const char *arg)
{
@@ -198,6 +391,26 @@ static int set_verbosity(int verbose)
return 0;
}
+static int write_commit_summary_into(const char *filename)
+{
+ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+ int fd = hold_lock_file_for_update(lock, filename, 0);
+ if (fd < 0)
+ return error("Unable to create '%s.lock': %s", filename,
+ strerror(errno));
+ if (write_in_full(fd, next_commit.summary.buf,
+ next_commit.summary.len) < 0)
+ return error("Could not write to %s: %s",
+ filename, strerror(errno));
+ if (commit_lock_file(lock) < 0)
+ return error("Error wrapping up %s", filename);
+ return 0;
+}
+
+/**********************************************************************
+ * Builtin sequencer helper functions
+ */
+
/* v should be "" or "t" or "\d" */
static int parse_verbosity(const char *v)
{
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 15/15] rebase -i: use "git sequencer--helper --cherry-pick"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
instead of "git cherry-pick", as this will make it easier to
port "git-rebase--interactive.sh" to C.
This is because we will be able to use the "do_cherry_pick()" added
by a previous patch.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
git-rebase--interactive.sh | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 7651fd6..349ca50 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -147,7 +147,8 @@ pick_one () {
pick_one_preserving_merges "$@" && return
if test ! -z "$REBASE_ROOT"
then
- output git cherry-pick "$@"
+ git sequencer--helper --cherry-pick $sha1 \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" $no_ff
return
fi
parent_sha1=$(git rev-parse --verify $sha1^) ||
@@ -157,7 +158,8 @@ pick_one () {
git sequencer--helper --fast-forward $sha1 \
"$GIT_REFLOG_ACTION" "$VERBOSE"
else
- output git cherry-pick "$@"
+ git sequencer--helper --cherry-pick $sha1 \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" $no_ff
fi
}
@@ -269,7 +271,10 @@ pick_one_preserving_merges () {
fi
;;
*)
- output git cherry-pick "$@" ||
+ no_commit=
+ test "a$1" = "a-n" && no_commit=t
+ git sequencer--helper --cherry-pick $sha1 \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" $no_commit ||
die_with_patch $sha1 "Could not pick $sha1"
;;
esac
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 11/15] revert: libify cherry-pick and revert functionnality
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
The goal of this commit is to abstract out "git cherry-pick" and
"git revert" functionnality into a new pick_commit() function made
of code from "builtin-revert.c".
The new pick_commit() function is in a new "pick.c" file with an
associated "pick.h".
This function starts from the current index (not HEAD), and allow
the effect of one commit replayed (either forward or backward) to
that state, leaving the result in the index. So it makes it
possible to replay many commits to the index in sequence without
commiting in between.
This commit is made of code from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
And it contains some changes and comments suggested by Junio.
The original commit in the sequencer project that introduced
this change is: 94a568a78d243d7a6c13778bc6b7ac1eb46e48cc
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
Makefile | 2 +
builtin-revert.c | 272 +++++++++---------------------------------------------
pick.c | 218 +++++++++++++++++++++++++++++++++++++++++++
pick.h | 13 +++
4 files changed, 277 insertions(+), 228 deletions(-)
create mode 100644 pick.c
create mode 100644 pick.h
diff --git a/Makefile b/Makefile
index 4aab6bc..372b263 100644
--- a/Makefile
+++ b/Makefile
@@ -432,6 +432,7 @@ LIB_H += pack-refs.h
LIB_H += pack-revindex.h
LIB_H += parse-options.h
LIB_H += patch-ids.h
+LIB_H += pick.h
LIB_H += pkt-line.h
LIB_H += progress.h
LIB_H += quote.h
@@ -519,6 +520,7 @@ LIB_OBJS += parse-options.o
LIB_OBJS += patch-delta.o
LIB_OBJS += patch-ids.o
LIB_OBJS += path.o
+LIB_OBJS += pick.o
LIB_OBJS += pkt-line.o
LIB_OBJS += preload-index.o
LIB_OBJS += pretty.o
diff --git a/builtin-revert.c b/builtin-revert.c
index 151aa6a..4797ac5 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -1,18 +1,14 @@
#include "cache.h"
#include "builtin.h"
-#include "object.h"
#include "commit.h"
#include "tag.h"
-#include "wt-status.h"
-#include "run-command.h"
#include "exec_cmd.h"
#include "utf8.h"
#include "parse-options.h"
-#include "cache-tree.h"
#include "diff.h"
#include "revision.h"
#include "rerere.h"
-#include "merge-recursive.h"
+#include "pick.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -35,25 +31,23 @@ static const char * const cherry_pick_usage[] = {
NULL
};
-static int edit, no_replay, no_commit, mainline, signoff;
-static enum { REVERT, CHERRY_PICK } action;
+static int edit, no_commit, mainline, signoff;
+static int flags;
static struct commit *commit;
-static const char *me;
-
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
static void parse_args(int argc, const char **argv)
{
const char * const * usage_str =
- action == REVERT ? revert_usage : cherry_pick_usage;
+ flags & PICK_REVERSE ? revert_usage : cherry_pick_usage;
unsigned char sha1[20];
const char *arg;
int noop;
struct option options[] = {
OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"),
OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"),
- OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"),
+ OPT_BIT('x', NULL, &flags, "append commit name when cherry-picking", PICK_ADD_NOTE),
OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"),
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
OPT_INTEGER('m', "mainline", &mainline, "parent number"),
@@ -77,42 +71,12 @@ static void parse_args(int argc, const char **argv)
die ("'%s' does not point to a commit", arg);
}
-static char *get_oneline(const char *message)
-{
- char *result;
- const char *p = message, *abbrev, *eol;
- int abbrev_len, oneline_len;
-
- if (!p)
- die ("Could not read commit message of %s",
- sha1_to_hex(commit->object.sha1));
- while (*p && (*p != '\n' || p[1] != '\n'))
- p++;
-
- if (*p) {
- p += 2;
- for (eol = p + 1; *eol && *eol != '\n'; eol++)
- ; /* do nothing */
- } else
- eol = p;
- abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
- abbrev_len = strlen(abbrev);
- oneline_len = eol - p;
- result = xmalloc(abbrev_len + 5 + oneline_len);
- memcpy(result, abbrev, abbrev_len);
- memcpy(result + abbrev_len, "... ", 4);
- memcpy(result + abbrev_len + 4, p, oneline_len);
- result[abbrev_len + 4 + oneline_len] = '\0';
- return result;
-}
-
static char *get_encoding(const char *message)
{
const char *p = message, *eol;
if (!p)
- die ("Could not read commit message of %s",
- sha1_to_hex(commit->object.sha1));
+ return NULL;
while (*p && *p != '\n') {
for (eol = p + 1; *eol && *eol != '\n'; eol++)
; /* do nothing */
@@ -128,30 +92,6 @@ static char *get_encoding(const char *message)
return NULL;
}
-static struct lock_file msg_file;
-static int msg_fd;
-
-static void add_to_msg(const char *string)
-{
- int len = strlen(string);
- if (write_in_full(msg_fd, string, len) < 0)
- die_errno ("Could not write to MERGE_MSG");
-}
-
-static void add_message_to_msg(const char *message)
-{
- const char *p = message;
- while (*p && (*p != '\n' || p[1] != '\n'))
- p++;
-
- if (!*p)
- add_to_msg(sha1_to_hex(commit->object.sha1));
-
- p += 2;
- add_to_msg(p);
- return;
-}
-
static void set_author_ident_env(const char *message)
{
const char *p = message;
@@ -214,7 +154,7 @@ static char *help_msg(const unsigned char *sha1)
"mark the corrected paths with 'git add <paths>' "
"or 'git rm <paths>' and commit the result.");
- if (action == CHERRY_PICK) {
+ if (!(flags & PICK_REVERSE)) {
sprintf(helpbuf + strlen(helpbuf),
"\nWhen commiting, use the option "
"'-c %s' to retain authorship and message.",
@@ -223,187 +163,68 @@ static char *help_msg(const unsigned char *sha1)
return helpbuf;
}
-static struct tree *empty_tree(void)
+static void write_message(struct strbuf *msgbuf, const char *filename)
{
- struct tree *tree = xcalloc(1, sizeof(struct tree));
-
- tree->object.parsed = 1;
- tree->object.type = OBJ_TREE;
- pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
- return tree;
+ struct lock_file msg_file;
+ int msg_fd;
+ msg_fd = hold_lock_file_for_update(&msg_file, filename,
+ LOCK_DIE_ON_ERROR);
+ if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
+ die_errno("Could not write to %s.", filename);
+ strbuf_release(msgbuf);
+ if (commit_lock_file(&msg_file) < 0)
+ die("Error wrapping up %s", filename);
}
static int revert_or_cherry_pick(int argc, const char **argv)
{
- unsigned char head[20];
- struct commit *base, *next, *parent;
- int i, index_fd, clean;
- char *oneline, *reencoded_message = NULL;
- const char *message, *encoding;
- char *defmsg = git_pathdup("MERGE_MSG");
- struct merge_options o;
- struct tree *result, *next_tree, *base_tree, *head_tree;
- static struct lock_file index_lock;
+ const char *me;
+ struct strbuf msgbuf;
+ char *reencoded_message = NULL;
+ const char *encoding;
+ int failed;
git_config(git_default_config, NULL);
- me = action == REVERT ? "revert" : "cherry-pick";
+ me = flags & PICK_REVERSE ? "revert" : "cherry-pick";
setenv(GIT_REFLOG_ACTION, me, 0);
parse_args(argc, argv);
- /* this is copied from the shell script, but it's never triggered... */
- if (action == REVERT && !no_replay)
- die("revert is incompatible with replay");
-
if (read_cache() < 0)
die("git %s: failed to read the index", me);
- if (no_commit) {
- /*
- * We do not intend to commit immediately. We just want to
- * merge the differences in, so let's compute the tree
- * that represents the "current" state for merge-recursive
- * to work on.
- */
- if (write_cache_as_tree(head, 0, NULL))
- die ("Your index file is unmerged.");
- } else {
- if (get_sha1("HEAD", head))
- die ("You do not have a valid HEAD");
- if (index_differs_from("HEAD", 0))
- die ("Dirty index: cannot %s", me);
- }
- discard_cache();
-
- index_fd = hold_locked_index(&index_lock, 1);
+ if (!no_commit && index_differs_from("HEAD", 0))
+ die ("Dirty index: cannot %s", me);
- if (!commit->parents) {
- if (action == REVERT)
- die ("Cannot revert a root commit");
- parent = NULL;
- }
- else if (commit->parents->next) {
- /* Reverting or cherry-picking a merge commit */
- int cnt;
- struct commit_list *p;
-
- if (!mainline)
- die("Commit %s is a merge but no -m option was given.",
- sha1_to_hex(commit->object.sha1));
-
- for (cnt = 1, p = commit->parents;
- cnt != mainline && p;
- cnt++)
- p = p->next;
- if (cnt != mainline || !p)
- die("Commit %s does not have parent %d",
- sha1_to_hex(commit->object.sha1), mainline);
- parent = p->item;
- } else if (0 < mainline)
- die("Mainline was specified but commit %s is not a merge.",
- sha1_to_hex(commit->object.sha1));
- else
- parent = commit->parents->item;
-
- if (!(message = commit->buffer))
- die ("Cannot get commit message for %s",
+ if (!commit->buffer)
+ return error("Cannot get commit message for %s",
sha1_to_hex(commit->object.sha1));
-
- if (parent && parse_commit(parent) < 0)
- die("%s: cannot parse parent commit %s",
- me, sha1_to_hex(parent->object.sha1));
-
- /*
- * "commit" is an existing commit. We would want to apply
- * the difference it introduces since its first parent "prev"
- * on top of the current HEAD if we are cherry-pick. Or the
- * reverse of it if we are revert.
- */
-
- msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
- LOCK_DIE_ON_ERROR);
-
- encoding = get_encoding(message);
+ encoding = get_encoding(commit->buffer);
if (!encoding)
encoding = "UTF-8";
if (!git_commit_encoding)
git_commit_encoding = "UTF-8";
- if ((reencoded_message = reencode_string(message,
+ if ((reencoded_message = reencode_string(commit->buffer,
git_commit_encoding, encoding)))
- message = reencoded_message;
-
- oneline = get_oneline(message);
-
- if (action == REVERT) {
- char *oneline_body = strchr(oneline, ' ');
+ commit->buffer = reencoded_message;
- base = commit;
- next = parent;
- add_to_msg("Revert \"");
- add_to_msg(oneline_body + 1);
- add_to_msg("\"\n\nThis reverts commit ");
- add_to_msg(sha1_to_hex(commit->object.sha1));
-
- if (commit->parents->next) {
- add_to_msg(", reversing\nchanges made to ");
- add_to_msg(sha1_to_hex(parent->object.sha1));
- }
- add_to_msg(".\n");
- } else {
- base = parent;
- next = commit;
- set_author_ident_env(message);
- add_message_to_msg(message);
- if (no_replay) {
- add_to_msg("(cherry picked from commit ");
- add_to_msg(sha1_to_hex(commit->object.sha1));
- add_to_msg(")\n");
- }
- }
-
- read_cache();
- init_merge_options(&o);
- o.branch1 = "HEAD";
- o.branch2 = oneline;
-
- head_tree = parse_tree_indirect(head);
- next_tree = next ? next->tree : empty_tree();
- base_tree = base ? base->tree : empty_tree();
-
- clean = merge_trees(&o,
- head_tree,
- next_tree, base_tree, &result);
-
- if (active_cache_changed &&
- (write_cache(index_fd, active_cache, active_nr) ||
- commit_locked_index(&index_lock)))
- die("%s: Unable to write new index file", me);
- rollback_lock_file(&index_lock);
-
- if (!clean) {
- add_to_msg("\nConflicts:\n\n");
- for (i = 0; i < active_nr;) {
- struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- add_to_msg("\t");
- add_to_msg(ce->name);
- add_to_msg("\n");
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
- }
- if (commit_lock_file(&msg_file) < 0)
- die ("Error wrapping up %s", defmsg);
+ failed = pick_commit(commit, mainline, flags, &msgbuf);
+ if (failed < 0) {
+ exit(1);
+ } else if (failed > 0) {
fprintf(stderr, "Automatic %s failed.%s\n",
me, help_msg(commit->object.sha1));
+ write_message(&msgbuf, git_path("MERGE_MSG"));
rerere();
exit(1);
}
- if (commit_lock_file(&msg_file) < 0)
- die ("Error wrapping up %s", defmsg);
+ if (!(flags & PICK_REVERSE))
+ set_author_ident_env(commit->buffer);
+ free(reencoded_message);
+
fprintf(stderr, "Finished one %s.\n", me);
+ write_message(&msgbuf, git_path("MERGE_MSG"));
+
/*
- *
* If we are cherry-pick, and if the merge did not result in
* hand-editing, we will hit this commit and inherit the original
* author date and name.
@@ -421,14 +242,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
args[i++] = "-s";
if (!edit) {
args[i++] = "-F";
- args[i++] = defmsg;
+ args[i++] = git_path("MERGE_MSG");
}
args[i] = NULL;
return execv_git_cmd(args);
}
- free(reencoded_message);
- free(defmsg);
-
return 0;
}
@@ -436,14 +254,12 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
{
if (isatty(0))
edit = 1;
- no_replay = 1;
- action = REVERT;
+ flags = PICK_REVERSE | PICK_ADD_NOTE;
return revert_or_cherry_pick(argc, argv);
}
int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
{
- no_replay = 0;
- action = CHERRY_PICK;
+ flags = 0;
return revert_or_cherry_pick(argc, argv);
}
diff --git a/pick.c b/pick.c
new file mode 100644
index 0000000..bb04c68
--- /dev/null
+++ b/pick.c
@@ -0,0 +1,218 @@
+#include "cache.h"
+#include "commit.h"
+#include "run-command.h"
+#include "cache-tree.h"
+#include "pick.h"
+#include "merge-recursive.h"
+
+static struct commit *commit;
+
+static char *get_oneline(const char *message)
+{
+ char *result;
+ const char *p = message, *abbrev, *eol;
+ int abbrev_len, oneline_len;
+
+ if (!p)
+ return NULL;
+ while (*p && (*p != '\n' || p[1] != '\n'))
+ p++;
+
+ if (*p) {
+ p += 2;
+ for (eol = p + 1; *eol && *eol != '\n'; eol++)
+ ; /* do nothing */
+ } else
+ eol = p;
+ abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
+ abbrev_len = strlen(abbrev);
+ oneline_len = eol - p;
+ result = xmalloc(abbrev_len + 5 + oneline_len);
+ memcpy(result, abbrev, abbrev_len);
+ memcpy(result + abbrev_len, "... ", 4);
+ memcpy(result + abbrev_len + 4, p, oneline_len);
+ result[abbrev_len + 4 + oneline_len] = '\0';
+ return result;
+}
+
+static void add_message_to_msg(struct strbuf *msg, const char *message)
+{
+ const char *p = message;
+ while (*p && (*p != '\n' || p[1] != '\n'))
+ p++;
+
+ if (!*p)
+ strbuf_addstr(msg, sha1_to_hex(commit->object.sha1));
+
+ p += 2;
+ strbuf_addstr(msg, p);
+ return;
+}
+
+static struct tree *empty_tree(void)
+{
+ struct tree *tree = xcalloc(1, sizeof(struct tree));
+
+ tree->object.parsed = 1;
+ tree->object.type = OBJ_TREE;
+ pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
+ return tree;
+}
+
+/*
+ * Pick changes introduced by "commit" argument into current working
+ * tree and index.
+ *
+ * It starts from the current index (not HEAD), and allow the effect
+ * of one commit replayed (either forward or backward) to that state,
+ * leaving the result in the index.
+ *
+ * You do not have to start from a commit, so you can replay many commits
+ * to the index in sequence without commiting in between to squash multiple
+ * steps if you wanted to.
+ *
+ * Return 0 on success.
+ * Return negative value on error before picking,
+ * and a positive value after picking,
+ * and return 1 if and only if a conflict occurs but no other error.
+ */
+int pick_commit(struct commit *pick_commit, int mainline, int flags,
+ struct strbuf *msg)
+{
+ unsigned char head[20];
+ struct commit *base, *next, *parent;
+ int i, index_fd, clean;
+ int ret = 0;
+ char *oneline;
+ const char *message;
+ struct merge_options o;
+ struct tree *result, *next_tree, *base_tree, *head_tree;
+ static struct lock_file index_lock;
+
+ strbuf_init(msg, 0);
+ commit = pick_commit;
+
+ /*
+ * Let's compute the tree that represents the "current" state
+ * for merge-recursive to work on.
+ */
+ if (write_cache_as_tree(head, 0, NULL))
+ return error("Your index file is unmerged.");
+ discard_cache();
+
+ index_fd = hold_locked_index(&index_lock, 0);
+ if (index_fd < 0)
+ return error("Unable to create locked index: %s",
+ strerror(errno));
+
+ if (!commit->parents) {
+ if (flags & PICK_REVERSE)
+ return error("Cannot revert a root commit");
+ parent = NULL;
+ }
+ else if (commit->parents->next) {
+ /* Reverting or cherry-picking a merge commit */
+ int cnt;
+ struct commit_list *p;
+
+ if (!mainline)
+ return error("Commit %s is a merge but no mainline was given.",
+ sha1_to_hex(commit->object.sha1));
+
+ for (cnt = 1, p = commit->parents;
+ cnt != mainline && p;
+ cnt++)
+ p = p->next;
+ if (cnt != mainline || !p)
+ return error("Commit %s does not have parent %d",
+ sha1_to_hex(commit->object.sha1),
+ mainline);
+ parent = p->item;
+ } else if (0 < mainline)
+ return error("Mainline was specified but commit %s is not a merge.",
+ sha1_to_hex(commit->object.sha1));
+ else
+ parent = commit->parents->item;
+
+ if (!(message = commit->buffer))
+ return error("Cannot get commit message for %s",
+ sha1_to_hex(commit->object.sha1));
+
+ if (parent && parse_commit(parent) < 0)
+ return error("Cannot parse parent commit %s",
+ sha1_to_hex(parent->object.sha1));
+
+ oneline = get_oneline(message);
+
+ if (flags & PICK_REVERSE) {
+ char *oneline_body = strchr(oneline, ' ');
+
+ base = commit;
+ next = parent;
+ strbuf_addstr(msg, "Revert \"");
+ strbuf_addstr(msg, oneline_body + 1);
+ strbuf_addstr(msg, "\"\n\nThis reverts commit ");
+ strbuf_addstr(msg, sha1_to_hex(commit->object.sha1));
+
+ if (commit->parents->next) {
+ strbuf_addstr(msg, ", reversing\nchanges made to ");
+ strbuf_addstr(msg, sha1_to_hex(parent->object.sha1));
+ }
+ strbuf_addstr(msg, ".\n");
+ } else {
+ base = parent;
+ next = commit;
+ add_message_to_msg(msg, message);
+ if (flags & PICK_ADD_NOTE) {
+ strbuf_addstr(msg, "(cherry picked from commit ");
+ strbuf_addstr(msg, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(msg, ")\n");
+ }
+ }
+
+ read_cache();
+ init_merge_options(&o);
+ o.branch1 = "HEAD";
+ o.branch2 = oneline;
+
+ head_tree = parse_tree_indirect(head);
+ next_tree = next ? next->tree : empty_tree();
+ base_tree = base ? base->tree : empty_tree();
+
+ clean = merge_trees(&o,
+ head_tree,
+ next_tree, base_tree, &result);
+
+ if (active_cache_changed &&
+ (write_cache(index_fd, active_cache, active_nr) ||
+ commit_locked_index(&index_lock))) {
+ error("Unable to write new index file");
+ return 2;
+ }
+ rollback_lock_file(&index_lock);
+
+ if (!clean) {
+ strbuf_addstr(msg, "\nConflicts:\n\n");
+ for (i = 0; i < active_nr;) {
+ struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_addstr(msg, "\t");
+ strbuf_addstr(msg, ce->name);
+ strbuf_addstr(msg, "\n");
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
+ ret = 1;
+ }
+ free(oneline);
+
+ discard_cache();
+ if (read_cache() < 0) {
+ error("Cannot read the index");
+ return 2;
+ }
+
+ return ret;
+}
diff --git a/pick.h b/pick.h
new file mode 100644
index 0000000..7a74ad8
--- /dev/null
+++ b/pick.h
@@ -0,0 +1,13 @@
+#ifndef PICK_H
+#define PICK_H
+
+#include "commit.h"
+
+/* Pick flags: */
+#define PICK_REVERSE 1 /* pick the reverse changes ("revert") */
+#define PICK_ADD_NOTE 2 /* add note about original commit (unless conflict) */
+/* We don't need a PICK_QUIET. This is done by
+ * setenv("GIT_MERGE_VERBOSITY", "0", 1); */
+extern int pick_commit(struct commit *commit, int mainline, int flags, struct strbuf *msg);
+
+#endif
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 06/15] rebase -i: use "git sequencer--helper --reset-hard"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
instead of "git reset --hard"
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
git-rebase--interactive.sh | 13 +++++++++----
1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index c9c75c0..0041994 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -154,7 +154,8 @@ pick_one () {
die "Could not get the parent of $sha1"
current_sha1=$(git rev-parse --verify HEAD)
if test "$no_ff$current_sha1" = "$parent_sha1"; then
- output git reset --hard $sha1
+ git sequencer--helper --reset-hard $sha1 \
+ "$GIT_REFLOG_ACTION" "$VERBOSE"
test "a$1" = a-n && output git reset --soft $current_sha1
sha1=$(git rev-parse --short $sha1)
output warn Fast forward to $sha1
@@ -238,7 +239,8 @@ pick_one_preserving_merges () {
case $fast_forward in
t)
output warn "Fast forward to $sha1"
- output git reset --hard $sha1 ||
+ git sequencer--helper --reset-hard $sha1 \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" ||
die "Cannot fast forward to $sha1"
;;
f)
@@ -536,7 +538,8 @@ first and then run 'git rebase --continue' again."
git symbolic-ref HEAD $HEADNAME
;;
esac &&
- output git reset --hard $HEAD &&
+ git sequencer--helper --reset-hard $HEAD \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" &&
rm -rf "$DOTEST"
exit
;;
@@ -548,7 +551,9 @@ first and then run 'git rebase --continue' again."
git rerere clear
test -d "$DOTEST" || die "No interactive rebase running"
- output git reset --hard && do_rest
+ git sequencer--helper --reset-hard HEAD \
+ "$GIT_REFLOG_ACTION" "$VERBOSE" &&
+ do_rest
;;
-s)
case "$#,$1" in
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 05/15] sequencer: add "--reset-hard" option to "git sequencer--helper"
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
This new option uses the "reset_almost_hard()" function to perform
a reset.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-sequencer--helper.c | 65 ++++++++++++++++++++++++++++++++++++------
1 files changed, 55 insertions(+), 10 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index a15139c..be030bc 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -18,6 +18,7 @@ static unsigned char head_sha1[20];
static const char * const git_sequencer_helper_usage[] = {
"git sequencer--helper --make-patch <commit>",
+ "git sequencer--helper --reset-hard <commit> <reflog-msg> <verbosity>",
NULL
};
@@ -185,27 +186,71 @@ static int set_verbosity(int verbose)
return 0;
}
+/* v should be "" or "t" or "\d" */
+static int parse_verbosity(const char *v)
+{
+ /* "" means verbosity = 1 */
+ if (!v[0])
+ return set_verbosity(1);
+
+ if (v[1])
+ return 1;
+
+ if (v[0] == 't')
+ return set_verbosity(2);
+
+ if (!isdigit(v[0]))
+ return 1;
+
+ return set_verbosity(v[0] - '0');
+}
+
int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
{
- char *commit = NULL;
- struct commit *c;
+ char *patch_commit = NULL;
+ char *reset_commit = NULL;
struct option options[] = {
- OPT_STRING(0, "make-patch", &commit, "commit",
+ OPT_STRING(0, "make-patch", &patch_commit, "commit",
"create a patch from commit"),
+ OPT_STRING(0, "reset-hard", &reset_commit, "commit",
+ "reset to commit"),
OPT_END()
};
argc = parse_options(argc, argv, prefix, options,
git_sequencer_helper_usage, 0);
- if (!commit)
- usage_with_options(git_sequencer_helper_usage, options);
+ if (patch_commit) {
+ struct commit *c = get_commit(patch_commit);
+ if (!c)
+ return 1;
- c = get_commit(commit);
- if (!c)
- return 1;
+ make_patch(c);
- make_patch(c);
+ return 0;
+ }
- return 0;
+ if (reset_commit) {
+ unsigned char sha1[20];
+
+ if (argc != 2)
+ usage_with_options(git_sequencer_helper_usage,
+ options);
+
+ if (get_sha1(reset_commit, sha1)) {
+ error("Could not find '%s'", reset_commit);
+ return 1;
+ }
+
+ reflog = (char *)argv[0];
+
+ if (parse_verbosity(argv[1])) {
+ error("bad verbosity '%s'", argv[1]);
+ return 1;
+ }
+
+ return reset_almost_hard(sha1);
+ }
+
+ usage_with_options(git_sequencer_helper_usage, options);
}
--
1.6.4.271.ge010d
^ permalink raw reply related
* [PATCH v4 00/15] complete reroll of my "port rebase -i to C" series
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
So unlike previous series, this is a complete reroll of all my previous
patches to port rebase -i to C using code from the sequencer project.
The main changes are in the commit messages that I tried to improve
according to Junio's feedback. But some patches were also squashed
together and there are a few minor changes too:
- comments have been added before the pick_commit() function (patch
11/15: revert: libify cherry-pick and revert functionnality),
- and a line in the usage message as been removed from patch 13/15
(sequencer: add "do_commit()" and related functions) because it should
be added by the next patch instead.
Christian Couder (9):
sequencer: add "builtin-sequencer--helper.c"
rebase -i: use "git sequencer--helper --make-patch"
sequencer: add "--reset-hard" option to "git sequencer--helper"
rebase -i: use "git sequencer--helper --reset-hard"
sequencer: add "--fast-forward" option to "git sequencer--helper"
sequencer: let "git sequencer--helper" callers set "allow_dirty"
rebase -i: use "git sequencer--helper --fast-forward"
pick: libify "pick_help_msg()"
rebase -i: use "git sequencer--helper --cherry-pick"
Stephan Beyer (6):
sequencer: add "make_patch" function to save a patch
sequencer: add "reset_almost_hard()" and related functions
sequencer: add "do_fast_forward()" to perform a fast forward
revert: libify cherry-pick and revert functionnality
sequencer: add "do_commit()" and related functions working on
"next_commit"
sequencer: add "--cherry-pick" option to "git sequencer--helper"
.gitignore | 1 +
Makefile | 3 +
builtin-revert.c | 293 ++++--------------------
builtin-sequencer--helper.c | 543 +++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1 +
git-rebase--interactive.sh | 42 ++--
git.c | 1 +
pick.c | 240 +++++++++++++++++++
pick.h | 14 ++
9 files changed, 865 insertions(+), 273 deletions(-)
create mode 100644 builtin-sequencer--helper.c
create mode 100644 pick.c
create mode 100644 pick.h
^ permalink raw reply
* [PATCH v4 04/15] sequencer: add "reset_almost_hard()" and related functions
From: Christian Couder @ 2009-08-28 4:47 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Johannes Schindelin, Stephan Beyer, Daniel Barkalow,
Jakub Narebski
In-Reply-To: <20090828043913.4307.34708.chriscool@tuxfamily.org>
From: Stephan Beyer <s-beyer@gmx.net>
This patch adds the "reset_almost_hard()" function, some related
static variables and the related following functions:
- parse_and_init_tree_desc()
- reset_index_file()
- set_verbosity()
"reset_almost_hard()" can be used to do a "git reset --hard". It
should be faster as it calls "unpack_trees()" directly, and it can
optionnaly preserve changes in the work tree if the "allow_dirty"
global is set. Preserving changes in the work tree can be usefull
if for example you want to get rid of the last commit but keep
your current not yet commited work.
In this patch the "allow_dirty" global is not used but a following
patch will make it possible to set it, and in the end the code
should be simpler with a global.
The code comes as is from the sequencer GSoC project:
git://repo.or.cz/git/sbeyer.git
(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)
Mentored-by: Daniel Barkalow <barkalow@iabervon.org>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-sequencer--helper.c | 107 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 107 insertions(+), 0 deletions(-)
diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c
index 1dda525..a15139c 100644
--- a/builtin-sequencer--helper.c
+++ b/builtin-sequencer--helper.c
@@ -2,16 +2,108 @@
#include "cache.h"
#include "parse-options.h"
#include "run-command.h"
+#include "refs.h"
+#include "diff.h"
+#include "unpack-trees.h"
#define SEQ_DIR "rebase-merge"
#define PATCH_FILE git_path(SEQ_DIR "/patch")
+static char *reflog;
+
+static int allow_dirty = 0, verbosity = 1, advice = 1;
+
+static unsigned char head_sha1[20];
+
static const char * const git_sequencer_helper_usage[] = {
"git sequencer--helper --make-patch <commit>",
NULL
};
+static int parse_and_init_tree_desc(const unsigned char *sha1,
+ struct tree_desc *desc)
+{
+ struct tree *tree = parse_tree_indirect(sha1);
+ if (!tree)
+ return 1;
+ init_tree_desc(desc, tree->buffer, tree->size);
+ return 0;
+}
+
+static int reset_index_file(const unsigned char *sha1, int update, int dirty)
+{
+ int nr = 1;
+ int newfd;
+ struct tree_desc desc[2];
+ struct unpack_trees_options opts;
+ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+
+ memset(&opts, 0, sizeof(opts));
+ opts.head_idx = 1;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
+ opts.reset = 1; /* ignore unmerged entries and overwrite wt files */
+ opts.merge = 1;
+ opts.fn = oneway_merge;
+ if (verbosity > 2)
+ opts.verbose_update = 1;
+ if (update) /* update working tree */
+ opts.update = 1;
+
+ newfd = hold_locked_index(lock, 1);
+
+ read_cache_unmerged();
+
+ if (dirty) {
+ if (get_sha1("HEAD", head_sha1))
+ return error("You do not have a valid HEAD.");
+ if (parse_and_init_tree_desc(head_sha1, desc))
+ return error("Failed to find tree of HEAD.");
+ nr++;
+ opts.fn = twoway_merge;
+ }
+
+ if (parse_and_init_tree_desc(sha1, desc + nr - 1))
+ return error("Failed to find tree of %s.", sha1_to_hex(sha1));
+ if (unpack_trees(nr, desc, &opts))
+ return -1;
+ if (write_cache(newfd, active_cache, active_nr) ||
+ commit_locked_index(lock))
+ return error("Could not write new index file.");
+
+ return 0;
+}
+
+/*
+ * Realize reset --hard behavior.
+ * If allow_dirty is set and there is a dirty work tree,
+ * then the changes in the work tree are to be kept.
+ *
+ * This should be faster than calling "git reset --hard" because
+ * this calls "unpack_trees()" directly (instead of forking and
+ * execing "git read-tree").
+ *
+ * Unmerged entries in the index will be discarded.
+ *
+ * If allow_dirty is set and fast forwarding the work tree
+ * fails because it is dirty, then the work tree will not be
+ * updated.
+ *
+ * No need to read or discard the index before calling this
+ * function.
+ */
+static int reset_almost_hard(const unsigned char *sha)
+{
+ int err = allow_dirty ?
+ (reset_index_file(sha, 1, 1) || reset_index_file(sha, 0, 0)) :
+ reset_index_file(sha, 1, 0);
+ if (err)
+ return error("Could not reset index.");
+
+ return update_ref(reflog, "HEAD", sha, NULL, 0, MSG_ON_ERR);
+}
+
/* Generate purely informational patch file */
static void make_patch(struct commit *commit)
{
@@ -78,6 +170,21 @@ static struct commit *get_commit(const char *arg)
return lookup_commit_reference(sha1);
}
+static int set_verbosity(int verbose)
+{
+ char tmp[] = "0";
+ verbosity = verbose;
+ if (verbosity <= 0) {
+ verbosity = 0;
+ advice = 0;
+ } else if (verbosity > 5)
+ verbosity = 5;
+ /* Git does not run on EBCDIC, so we rely on ASCII: */
+ tmp[0] += verbosity;
+ setenv("GIT_MERGE_VERBOSITY", tmp, 1);
+ return 0;
+}
+
int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)
{
char *commit = NULL;
--
1.6.4.271.ge010d
^ 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