On Mon, 2 Sep 2013 21:43:26 -0700 (PDT)
Juha Aaltonen <turbosc...@gmail.com> wrote:

> I guess I described the problem.

I guess I explained the reason for `git fetch` reporting everything is
up-to-date and `git pull` complaining about conflicts.

> I don't seem to be able to update my working tree from the remote
> repo using Giteye.
> The pull complains about masses of conflicts (even if I know that not
> that much has changed) and
> the fetch just says the SW is the same (nothing to merge).
> Maybe the problem is in Giteye, not in the repo clones. It's hard to 
> understand why the different results.
> (everything changed / nothing changed)

In your case, it seems, the root problem is that people are taught Git
by making them memorize several simple commands which should "just do
this", without explaining what actually happens.  So someone told you
"use git-pull to bring the changes from remote repos"; that someone
failed to explain in detail what `git pull` actually does, and why it
may legitimately fail.

So let me try to explain the situation in more detail...

When you clone a repository, Git:

1) Creates or initalizes a local repo.

2) In its configuration, creates a single "remote" named "origin".

3) Fetches all the branches from the remote repository, creating
   a single "remote branch" for each branch that repository has.
   You can enumerate these branches by running `git branch -r`.

4) Creates a single normal branch which tracks one of the created
   remote branches -- matching that which is currently "main"
   in the repository being cloned, this is "master" most of the time.

Recently I explained to someone here these concepts in detail, so
please refer to [1] for more info.

Now the `git fetch origin` (or just `git fetch` in your case) contacts
the repository pointed to by the remote named "origin" in the
configuration of your local clone and fetches all the branches from it
-- updating the matching *remote branches* for that repository, and
creating new, if needed.  The crucial thing to understand is that none
of your personal local branches is ever updated by this command.
Of course, if you call `git fetch` twice in a row, it's likely that the
first call brings some changes in and the second one reports that
everything is up-to-date, because the state of the remote repository
stored locally in the form of remote branches for it is the same as the
state of branches in that remote repository.

The usual course of action when you want to reconcile the changes
someone did to the branch of interest located in some remote repository
and your changes you did to a branch in your local repository is to

1) Fetch from the remote repository to update its remote branches in
   your local repository.

2) Check out the necessary local branch.

3) Inspect what changes the relevant remote branch has compared to your
   branch, and in reverse.

For instance, if you have a local branch named "master" which tracks
the same named branch in a remote repository named "origin", you'd do:

git fetch origin
git checkout master
# What the remote "master" has our local "master" hasn't?
git log master..origin/master
# What changes our local "master" has which the remote "master" hasn't?
git log origin/master..master

Now we can merge:

git merge origin/master

This operation might rightfully result in conflicts if both sides
changed the same portions of the same files.

Now let's move to `git pull`.  It has much magic built in, and that's
why it really sucks to ever tell Git newcomers this command exists (but
everyone does this, unfortunately).

When you have a branch named "master" checked out and do `git pull`,
it goes like this:

1) Reads the branch.master.remote configuration variable to learn which
   remote this local branch named "master" "tracks".

   In a typical setup:

   $ git config --get branch.master.remote

   If you call `git pull <remotename>` this step is skipped and the
   name of the remote is taken from the command line.

2) Reads the branch.master.merge configuration variable to learn which
   branch this local branch named "master" "tracks" in the remote
   repository learned on step (1).

   In a typical setup:

   $ git config --get branch.master.merge

   If you call `git pull <remotename> <branchname>` this step is skipped
   and the name of the branch is taken from the command line.

3) Fetches a branch which name was obtained on step (2) from the
   repository whose location was obtained on step (1). No remote
   branches are updated, and that's why you don't see "Everything
   up-to-date" message when doing `git pull`.

   The objects fetched are stored in the local object database and the
   tip commit of the branch fetched is saved.

4) Now Git attempts to merge that saved tip commit into the branch you
   currently have checked out.  As this is just a normal merge, this
   might result in conflicts.

By now you should see that it's perfectly okay to have `git fetch`
report that everything is up-to-date and `git pull` failing at the
merge step: `git fetch` merely tells you that the state of the branches
of the remote repository matches the state of its branches maintained
in your local repository -- in the form of remote branches.

But you *work* with normal local branches, not with remote branches --
they are just sort of bookmarks into the remote repository, and
`git fetch` (normally) updates only these "bookmark" branches only,
it's `git merge` which brings changes from one branch into another, and
it's what `git pull` finally calls.

So most probably you have just had "a fork".  Suppose you and your
colleague Joe cloned the same repository and created a local branch
"master" tracked the same-named branch in the origin repository.
Let's say it had a commit A at its tip in all these tree repositories.
Now Joe recorded a number of commits on top of it and so "master" in
its repository points at commit M in his repository.  Now he updates
"master" in the origin repository with its own "master".
Meanwhile, you recorded another series of commits on top of your
"master" so this branch in your repository points at commit X.
Now you do `git pull`, it fetches the commit M and everything down the
line not including A and brings them into your local repository and
tries to merge M into your X, and fails -- because you have a fork:

   /-----...-->N->M (tip of "master" in the origin repo)
   \-----...-->W->X (tip of your "master")

If lines M and X have overlapping changes into the same pieces of the
same files, a conflict or conflicts will occur.

Let's recap.

`git fetch` just update locally what your repository knows about the
state of branches in the remote repository.

You might then run `git merge` to merge an (updated) remote branch into
appropriate local one.  But plain call to `git fetch` does not
normally do anything to your private local branches.

`git pull` fetches updates, if any, to the configured remote branch and
then tries to merge them into the currently checked out branch.  That
is it *does* try to modify your current branch.


You received this message because you are subscribed to the Google Groups "Git 
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to git-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to