[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Stupid git!

From: Stephen J. Turnbull
Subject: Re: Stupid git!
Date: Mon, 14 Sep 2015 12:11:32 +0900

Dmitry Gutov writes:
 > On 09/13/2015 12:51 AM, Alan Mackenzie wrote:

 > > :-).  OK, but the immediate problem is that _I_ didn't modify
 > > file-notify-tests.el.  Somebody else did, and git put his changes into
 > > my working directory and `git add'ed it.
 > Yes, it did. Have you done any non-trivial merges before? That's how 
 > they usually look.

@Dmitry: Weren't you here for the last "git is a screw" thread?  Yes,
he's seen this before.  He doesn't understand it yet.

@Alan:  In "DAGgy" systems that emphasize branching[1], the first step in
a "pull" to include external changes is to fetch them.  The changes are
stored in the local database and constitute a complete tree including all
your commits as well as those fetched from the other repo, but the
workspace doesn't change during the fetch.

Next the system conducts the merge.  Conceptually, the VCS traces each
branch back to a common ancestor, and checks that version out into the
workspace.  Then it applies your commits[2] and those of the external
branch to each file.  For each file with changes, if there are no
lines in common between your changes and the outside changes, the file
is marked "done".  If a conflict exists, the file is marked "pending".

Note that since no commit has take place but both branch's changes
have been applied, the other branch's changes will be present in your
workspace, as files needing commit (or conflicts).  This is normal,
and occurs in all DAGgy VCSes, including bzr.  What may differ is how
the situation is reported.

 > The merge commit shouldn't, generally, include any non-mergy changes, so 
 > you're not expected to stage any of the files you've been working on, 
 > before committing.

@Dmitry: I have no idea what you mean by this, especially not in the
context of helping someone who probably thinks[3] of a merge as
equivalent to

    git fetch origin
    git diff last-synced-rev > /tmp/patch
    git reset --hard origin/master
    patch -p1 < /tmp/patch

(that's my guess because that's like what CVS does, except that CVS's
patch is actually "git diff last-synced-rev origin/master" applied to
the current workspace).

@Alan: Back to the merge process.  After the process above, git does
the equivalent of

    if test -z "$CONFLICTED_FILES"; then
        git commit -m "Merge from origin/master."

Other systems (hg, bzr) require an explicit commit here, because
"review after commit and uncommit if bad" is philosophically
distasteful, so they recommend a careful review before committing a
merge.  git's philosophy is that if on review, you don't like the
commit, you can just reset to a commit you do like, with or without
reverting the the workspace.  (Of course you shouldn't do this after
pushing the merge commit!)

 > > I don't have the log entry for this change.  So am I supposed to
 > > just commit this, with my own log entry?
 > The log entry should describe the merge (you could leave the default 
 > message there, unless it's necessary to add more info).

There should be a file in .git/ named "MERGE_MSG" or something like
that with a preformatted message you can use with the -F option.
Lines beginning with "#" are comments, and stripped from the message
actually used.  In most cases, something like "merge from
origin/master" is sufficient.  If you found that you had to do "real
work" to resolve a conflict, that should be described here too.  Most
of the time conflicts are trivial, though (eg, somebody fixed a typo
in a comment you changed to reflect reality), and that kind of change
doesn't need to be mentioned, or can be disposed of en masse with
"fixed trivial conflicts."

 > > I don't really understand what "you are still merging" is
 > > supposed to mean.

It means that the workspace has not yet been committed to the
repository, and that you need to resolve any remaining conflicts
before git will allow you to commit.

 > > How do I get out of the "merging" state cleanly, without
 > > commiting somebody else's changes?
 > The merge commit is *supposed to* include all the changes that have
 > been merged in.

@Dmitry: This probably doesn't help Alan because his mental model of
merging differs from what git is reporting.  Alan seems to be thinking
of the post-merge commit as recording a diff of his workspace against
current upstream master.  The changes on master should *already be
there* (in some sense), and it doesn't make sense to Alan that changes
that are already in master are reported as changes in *his* workspace.

@Alan: But git doesn't think of master as "canonical" or whatever.
git puts your changes on an equal footing with the changes in master,
and so reports *all* changes on *both* branches since last-synced-rev.
Those files that were successfully merged from either branch will
already be in the "to be committed" list.  You primarily care about
the "conflicted" files.  You should also check "your" files to make
sure they all make sense -- in particular, other people may have made
changes to "your" files that conflict with what you're doing
semantically, but not syntactically.  If one of "your" files is listed
but you didn't change it, that should be a red flag.  (Of course I'm
sure you also review the diff, and should see it there.  Call YAGNI if
you like on this "feature".)  But you can ignore all the "other"
files, unless they're conflicted -- in that case something is odd in
*your* pre-merge workspace, because git thinks you changed that file
but you don't remember doing so.

(To be precise, git doesn't commit diffs, it commits snapshots of
workspaces.  To git, your workspace after merge is just a snapshot
that hasn't yet been recorded in the DAG.  From git's point of view,
there is no diff, only the revisions and the parent-child
relationships among them.  "diff" is a derived concept that humans
find useful in thinking about traversing the DAG, not a fundamental
part of the git machinery.[4]  But you may not need to think about
this; it may be sufficient to think of git as "unnecessarily" --
"stupidly", if you like -- reporting all changes since

[1]  These systems include git and hg.  bzr is also DAGgy, but it's
schizoid about branching.  It can be operated in a mode that tries to
hide the fact that multiple branches are present in your local repo
as much as possible, giving a UX like CVS and Subversion where
branches exist only in the server.

[2]  Note that this process implies you will lose any changes that you
haven't committed -- that's why it's best practice to be "committed up"
before merging.

[3]  @Alan: Here and below I am *guessing* what you think in order to
phrase things consistently with what you think is happening, or what I
call your "model" of the merge process.  I'm not telling you what to
think, I'm trying to give you a reference point to understand what I'm
saying.  If I'm wrong, but close enough, good.  If not, tell me where
I'm wrong and maybe I can come up with a better way to express what's
actually happening and how to interpret what you are seeing.

[4]  Of course git provides the "diff" subcommand, and uses "diff
compression" when packing objects.  But neither is necessary to the
fundamental processes of commit and checkout.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]