On Wed, 16 Nov 2016 14:18:10 -0800 (PST)
Walt Feasel <[email protected]> wrote:

> I am having a really tough time determining which procedure I should
> use to update my branches. I see conflicting advise on which is
> better for situations cause of the log changes made.
> 
> I think if I explain my situation it may help to guide me to the
> correct procedure to use.
> 
> I cloned a repository staging-testing
> 
> I made another branch from that called style that I make all of my
> patches from.
> 
> So my question is which is the best way for me to update my local 
> staging-testing and my local style.

OK, let's try to approach this all piecemeal.

The first thing to understand is that to apply any (well, almost [*])
approach to incorporating remote and local changes to the same line of
development you first need to get the updated history from the remote
repository to your local one.  This should be obvious once you think
about the next step: no matter whether you want to use merging or
rebasing, you will need to have "both sides" of the diverged histories
available locally.  OK, so the command which obtains the changes from a
remote repository is called `git fetch`, and that's what you should
generally use as the first step.

As everything in Git, `git fetch` is very flexible in what it fetches
and what it updates locally with what it obtains.  Let's not dive into
these complexities now; your setup is typical, and when you run

  git fetch origin

this command will update the so-called "remote branches" for the remote
repository known as "origin" locally.  If you're not sure what "remote
branches" are please read [1] first.

After running the above command, you will have one or more remote
branches updated.  None of your local branches, including "style", will
not have been touched.  You did not tell what branch you forked your
"style" off, so let's pretend it was "whatever".  By now you have
history which looks like this:

            /->D->E->F "style"
...->A->B->C
            \->X->Y->Z "origin/whatever"

The commit C is what the remote branch "whatever" pointed to when you
forked "style" off it; now both you committed D..F atop of it, and
other folks updated that branch remotely with the series of commits
X..Z.

OK, so we're approaching `git merge` and `git rebase`.

Which one to use depends on many things, but two main questions to
answer are:

1) Are you done with the changes on your "style" branch and want them
   integrated into "whatever" or you just want the changes made to
   "whatever" in the meantime be available on your "style" as well to be
   up-to-date with the upstream's progression?

2) What is your project's policy regarding merging and rebasing?

Unfortunately, what to do really depends on both of them; let me
explain why.

Consider that the answer to (1) is «yes, I want "style" integrated
upstream» and the answer to (2) is «merging are OK» or «merging is
required».  In this case you use `git merge`:

  git checkout -b whatever origin/whatever
  git merge style

The history will look like this:

            /->X->Y->Z-->M "whatever"
...->A->B->C            /
            \->D->E->F-/ "style"

The merge commit M brings what you've done on "style" back into
"whatever" -- creating a so-called "diamond" in the history.

You can now push "whatever" back into the remote repository -- updating
the same-named branch there:

  git push origin whatever

Now condider that the answer to (2) is «no, we need linear history».

You'd then use rebasing:

  git checkout -b whatever origin/whatever
  git rebase whatever style

would produce

...->A->B->C->X->Y-Z->D'->E'->F' "style"
                    \- "origin/whatever" and "whatever"

And then you would "fast-forward" the "whatever" branch with the
rebased commits on "style":

  git checkout whatever
  git merge style

producing

...->A->B->C->X->Y-Z->D'->E'->F' "style" and "whatever"
                    \- "origin/whatever"

"Fast-forward" merge happens when the branch you're merging into is
completely contained in the branch you're merging.

As before, you'd now push "whatever" back to the remote repository.


Now consider the case you'd like to just want your "style" updated to
incorporate the changes made upstream to "whatever" in the meantime,
and you intend to continue working on "style" and not incorporate its
changes back upstream yet.

In this case the two approaches are the same -- merging and rebasing.

With rebasing, you do

  git checkout -b whatever origin/whatever
  git rebase whatever style

as explained above, and that would produce

...->A->B->C->X->Y-Z->D'->E'->F' "style"
                    \- "origin/whatever" and "whatever"

so that your "style" now has the X..Z commits from its upstream branch.

With merging, you need to "swap" the branches -- as you need to merge
"whatever" into "style" and not vice-versa:

  git checkout style
  git merge origin/whatever

producing

            /->D->F->F-->M "style"
...->A->B->C            /
            \->X->Y->Z-/ "origin/whatever"

In both cases, "style" now has the changes from upstream.

Which one to pick really depends on the answer to the question (2)
above, and quickly becomes philosophical once we dive deeper into it.

We can try discuss thig philosophic things but it's better to get grasp
on the concepts first; get back when you'll feel the need to know
more. ;-)


OK, covering `git pull` is now easy: it combines `git fetch` with `git
merge` or `git rebase`.  I'd recommend not use `git pull` as of now:
it's too magic.  Please read [2] which details why.

To contrast rebasing and merging, consider reading [3] and [4] it links
to.  [5] explains what can be bad about periodical bringing in upstream
changes via normal merging.


[*] Except for simply throwing away changes in a remote repository
    by doing the so-called "forced push".


1. https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches
2. https://longair.net/blog/2009/04/16/git-fetch-and-merge/
3. https://lwn.net/Articles/328436/
4. https://lwn.net/Articles/328438/
5. https://git-blame.blogspot.ru/2012/03/fun-with-first-parent.html

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to