Re: can't commit files that have been git add'ed because "fatal: you need to resolve your current index first"
From: Bill Priest <hidden>
Date: 2016-06-15 22:43:54
On Wed, 28 Nov 2007 12:08:40 -0800 Junio C Hamano [off-list ref] wrote:
Bill Priest [off-list ref] writes:quoted
I merged from one branch to another and had lots
of
quoted
conflicts. I've resolved a set of files from the conflicts (in a directory) and did a git-add on
this
quoted
set of files. I wasn't able to commit these
files.
quoted
On IRC I was told that all files must be resolved before I can commit any of them. This seems
pretty
quoted
limiting.You have two parallel development lines that lead to
A and B and trying
to come up with a "merge" M:
o---o---A
/ \
---o---o---B---M
What property should the merge commit "M" have? Itmust keep the
changes made on the upper line to make it better
than B, and it must
keep the changes made on the lower line to make it
better than A. Ok. One thing I probably wasn't clear on is these are two distinct product lines that share a great amount of code; however, much of the code is "incompatible". The two branches will never be "merged" into one "mainline" as the underlying hardware is by definition incompatible. In theory I could use a bunch of conditional compilation to unify the two lines; however, this means that every time I make a change to one branch I have to make sure that it doesn't break the other one. It would have been better if the code was modularized better to just include different files for the two versions; unfortunately this is easier said than done. I guess you could think of it line a 2.4 kernel vs. a 2.6 kernel; but in the same repository. So to sum it up there are changes in branch A that will never go into branch B (and vice versa); however, there are a number of changes that need to go into both. Unfortunately the rest of my team uses subversion and isn't even aware that I am using git (we recently switch to subversion from cvs, so it is a hard sell to management to switch again). I'm responsible for keeping bug fixes and new features in both product lines and I found subversion's merging to be utterly useless.
Let's say both upper and lower lines of development
touched files frotz
and xyzzy in overlapping, different ways. You try
to merge A while you
are at B and see conflicts in these two files. Let's say you resolved frotz; the contents in frotz
is in a desired
shape, i.e you have the changes you want from the
line led to A and the
other line led to B. But you haven't resolved xyzzy
yet.
You seem to want to make this half-resolved state as
a commit. First
question: what contents would you want to commit for
xyzzy? As an example there is a directory in the tree that is a program that runs on a PC (vs. the other stuff that runs on embedded processors) it shares a handful of include files w/ the embedded side for packet definition but it is otherwise completely separate from the programs that run on the embedded processors. Once I complete merging of this directory and it builds it is ready to go. The remaining merges have no effect on this PC based program. I'm not sure if it is possible or not but if I could merge this directory and below (does git support this??) it might be one way of handling it or if I cherry-pick'ed it that could also work. This isn't always feasible as the other users often check in wholesale changes into subversion as one change set (remember that these are former cvs users that have lots of bad habits to lose). It would be great if branches were created for each "logical" change and checked in in one changeset; this seems to be what git is expecting (in a perfect world this would always be the case).
If you commit the contents from B (because you
started from it), then it
should not be recorded as a proper merge. If you
did so, merging that
back to A would obliterate all the work done up to A
to file xyzzy:
o---o---A...X
/ \ .
---o---o---B---*
because merge base of A and * (I am marking itdifferently because such
an incomplete merge should not be made) is A, so the
result (X) will be
the half-merge * itself (fast forward). That's not
a merge as it is not
better than A -- you discarded improvements made to
xyzzy by people who
built up to A. This is inherent to what a merge is. With proper
understanding of what
a merge is, you would not feel this limiting at all.
I've used clearcase in the past and although there were many things I didn't like about it (big, slow, costs $$$$, network pig, needs a super server, etc.) it did allow commits of files at any time and tracked the files that were merged independently. I know that git tracks changes and not files; but in the end you have to pick file(s) or pieces of them to be committed; having the tool restrict me from committing files because of the way it tracks merges IS limiting IMHO. I guess the big difference is that in kernel land you can reject patches until they are broken up into "atomic" pieces (I don't really have the option of reversing the subversion commit and turning it into "atomic" commits).
Having said that, I think something like the
following _could_ be done,
although I do not know if it makes much sense. (1) Try merge, see it conflict, resolve only a part
of it, and record
the result as "WIP to merge in A". Do not
record it as a merge, as
it is not. diff between B and M will contain a
squash merge of A on
top of B minus the changes to the path xyzzy.
o---o---A
/
---o---o---B---M
(2) Fix up the conflicts in xyzzy to resolve theconflicts fully, and
record the result as "Final merge of A into B".
This should be
recorded as a merge, as the result is "keeping
changes done on both
branches to come up with something better than
either of them."
o---o---A---,
/ \
---o---o---B---M---N
If you look at the topology a bit differently, theabove actually makes
some sense:
.---o---o---A
/ \
---o---o---B---M---N
That is, instead of merging A into B, you made"preparatory changes" to
branch B in order to make it easier to merge A.
That's what the commit
M is about. Then you merge A on top of M. In reality, because
the difference
between B to M contains most of the squash merge of
A into B, such a
merge N will contain many accidental clean merges.
But in git,
accidental clean merges are not a problem (people
can apply the same
patch to their trees and later their branches can be
merged).
But "git commit" after a conflicted merge will
always create a merge,
and there is no canned option to do multi-step merge
like the above.
You can still do that by hand, by doing something
like:
$ git merge --squash A
$ resolve only partly
$ git commit -m 'Prepare to merge A'
$ git reset --hard
$ git merge A
$ resolve the rest
$ git commit -m 'Fully merged A'Ok. I did a git merge --squash. So I should be able to try this. After I resolve only partly; I'm assuming that I git checkout HEAD any files that I don't want yet and then do the commit? Assuming that I commit the partial after throwing away any merges that I wasn't ready to do (via git checkout HEAD); what does the "git reset --hard" do?
For such a multi-step merge to make sense, the
change between B---M
should make sense by itself for people who have to
read such a history
later. Such a half-a-squash-merge may probably not
make sense by itself
in most cases, so I suspect the above workflow would
not be useful in
general.
I would agree for the case where in the end you really
only have one
product; but again think like you have a 2.4 kernel
and a 2.6 kernel in
the same repository. For most embedded development
(I've been doing it
for 20+ years) there is always newer hardware that
changes processors,
add features, gets all the new development while the
"old" production
board is still shipping and in customers hands and
needs bug fixes and
the occassional new feature. It doesn't make sense to
have two
separate repositories when much of the code is the
same and is likely
to need the same fixes.
Junio,
Thanks for your time and insight; git has already
saved me
countless hours and has certainly come a long way in a
very short
time. I'll give your multi-step merge a shot and see
how well it works
for my code base. I'm sure there are better ways to
structure my code
base to get what I am looking for; but as is usually
the case the rules
of the game have changed as I have been playing it
(the old hardware
was supposed to die and never be touched again; HA
HA).
Regards,
Bill
____________________________________________________________________________________
Be a better pen pal.
Text or chat with friends inside Yahoo! Mail. See how. http://overview.mail.yahoo.com/