git question: sync branch with master

4 views
Skip to first unread message

Greg Ercolano

unread,
Dec 18, 2021, 8:49:54 AM12/18/21
to fltkc...@googlegroups.com

So if you're working on a branch, and occassionally want to keep up with
current development on origin/master to continue working, what's the best way to sync up?

I believe albrecht said this one command would do the job
if you run into trouble pushing a branch:

    git pull --rebase

Is that also sufficient to keep an "in progress" branch synced with origin/master?
The net seems to recommend the following for resync'ing an in progress branch:

    git checkout master         -- switch from your branch to master
    git pull                    -- get the latest from the remote. If your local master is clean, this shouldn't fail
    git checkout <local-branch> -- switch back to your branch
    git rebase master           -- rebase your branch to master

..or is that pretty much the same thing that 'git pull --rebase' does while you're
on your branch?


Albrecht Schlosser

unread,
Dec 18, 2021, 10:40:47 AM12/18/21
to fltkc...@googlegroups.com
On 12/18/21 2:49 PM Greg Ercolano wrote:
>
> So if you're working on a branch, and occassionally want to keep up with
> current development on origin/master to continue working, what's the
> best way to sync up?
>
> I believe albrecht said this one command would do the job
> if you run into trouble pushing a branch:
>
>     git pull --rebase
>

This is correct if you want to sync the branch you're working on with
the remote repository where someone else (or even you, e.g. from another
system) may have pushed branches to.

This is often the case with FLTK development in the main branch if the
remote branch (e.g. origin/master) got pushes while you were working
with your local copy of 'master' and committed in master. This can also
be the case after you merged your development branch into master.

Assume remote/master got a commit from Manolo, say commit A.

You were working on your local master and committed B. Now you can't
push because Git(Hub) tells you that the branches have diverged and you
should 'git pull'. As I wrote you shouldn't do this because it would
merge the remote branchThe situation is:

remote: origin/master - A
local:  master        - B

after git pull --rebase:

remote: origin/master - A
local:  master        - A - B'

Note that I wrote B' because this is formally another commit than B
because it was rebased (it has another hash).

Now it is safe to `git push' because it would append your commit B' to
the remote commit A. The new situation after `git push' is:

remote: origin/master - A - B'
local:  master        - A - B'

which is what you want.

Now, after you rebased your local branch and everything looks fine you
try to push again. It can happen that git tells you again that your
local and the remote branch diverged. What's going on? Well, someone
else pushed commit C in the meantime. Don't worry, just go back to `git
pull --rebase' and try again...

> Is that also sufficient to keep an "in progress" branch synced with
> origin/master?
> The net seems to recommend the following for resync'ing an in progress
> branch:
>
>     git checkout master         -- switch from your branch to master
>     git pull                    -- get the latest from the remote. If
> your local master is clean, this shouldn't fail
>     git checkout <local-branch> -- switch back to your branch
>     git rebase master           -- rebase your branch to master
>
> ..or is that pretty much the same thing that 'git pull --rebase' does
> while you're
> on your branch?
>

It's different because you want to "move your local branch forward on
top of another branch". I'm calling your local branch "working" in the
following graphs (use a fixed font if the HTML mail I'm sending doesn't
do this for you):

Current situation:

remote: origin/master - A - B - C - D
local:  master        - A
                         \
local:  working . . . .   E - F - G

What you want to achieve is that your commits E - F - G are "rebased"
onto the tip of remote branch origin/master after commit D, like this:

remote: origin/master - A - B - C - D
local:  master        - A - B - C - D
                                     \
local:  working . . . . . . . . . .   E' - F' - G'

The recipe above does exactly that (replace "<local-branch>") with
"working". Again, commits E' - F' - G' differ from your original E - F -
G in that they have different hashes.

Note: although Git is good at doing such things it can happen that you
need to resolve merge conflicts when doing a rebase. Then it is obvious
that you should test your updated branch and/or verify with tools like
`gitk' that your commits and the result of the merge are consistent and
what you wanted to do.

However, even if Git does not flag merge conflicts it is still possible
that merging two branches (or rebasing one on top of another one) may
introduce bugs. A simple example is if two changes to fix a bug in
different places of the code merge silently but create another bug
(think of adding 1 in two different places of the code which git does
not notice as a conflict).

Hint for advanced git users: the commands can be "simplified" if you
remember the correct syntax (be careful not to flip arguments). Assume
your local branch is "working":
                                -- (on branch working)
    git checkout master         -- switch from your branch (working) to
master
    git pull                    -- get the latest from the remote. If
your local master is clean, this shouldn't fail
    git rebase master working   -- rebase your branch 'working' on
'master' and checkout 'working'

Greg Ercolano

unread,
Dec 18, 2021, 12:06:10 PM12/18/21
to fltkc...@googlegroups.com


On 12/18/21 7:40 AM, Albrecht Schlosser wrote:
Current situation:

remote: origin/master - A - B - C - D
local:  master        - A
                         \
local:  working . . . .   E - F - G

What you want to achieve is that your commits E - F - G are "rebased" onto the tip of remote branch origin/master after commit D, like this:

remote: origin/master - A - B - C - D
local:  master        - A - B - C - D
                                     \
local:  working . . . . . . . . . .   E' - F' - G'


    Yes, pretty sure that's what I want to achieve, as I'm working on a branch, "issue_332",
    which I'll want to push in an early state for folks to see (but not use), then make subsequent
    tweaks and keep pushing new changes that can then be tested by others in that branch.

    So I take it then I can use this slightly simpler form you mentioned at the end:


        git checkout master         -- switch from your branch (working) to master
        git pull                    -- get the latest from the remote. If your local master is clean, this shouldn't fail
        git rebase master working   -- rebase your branch 'working' on 'master' and checkout 'working'

    ..and use that to keep sync'ed during branch development.

    Then when everything works, close out the issue by merging the branch to master
    and deleting the no-longer needed branch, which I think ends up being something like:

        git checkout master     -- checkout master
        git pull                -- get latest
        git merge issue_332     -- merge in my branch to master (assuming I've squashed my branch down to some minimal history)
        git push origin master  -- push the result


    ..and after that, delete the branch from both local and remote:

        git branch -d issue_332             -- delete unused branch from local
        git push origin --delete issue_332  -- delete unused branch from origin


    I think others may still see the issue_332 branch in their copies after a pull,
    even though I deleted it, unless they do a "git fetch -prune".


The recipe above does exactly that (replace "<local-branch>") with "working". Again, commits E' - F' - G' differ from your original E - F - G in that they have different hashes.

    Right, that makes sense.

    Where that might get interesting is if devs make "github code comments" on my branch commits,
    i.e. they go into my branch's commit and use "+" on the code diffs to add a code comment).
    If I later do a rebase and push to show my latest branch changes, I wonder if github is smart enough
    to carry those code comments along with the rebased hashes.. hrm.

Albrecht Schlosser

unread,
Dec 18, 2021, 1:02:25 PM12/18/21
to fltkc...@googlegroups.com
On 12/18/21 6:05 PM Greg Ercolano wrote:
> On 12/18/21 7:40 AM, Albrecht Schlosser wrote:
>> Current situation:
>>
>> remote: origin/master - A - B - C - D
>> local:  master        - A
>>                          \
>> local:  working . . . .   E - F - G
>>
>> What you want to achieve is that your commits E - F - G are "rebased"
>> onto the tip of remote branch origin/master after commit D, like this:
>>
>> remote: origin/master - A - B - C - D
>> local:  master        - A - B - C - D
>>                                      \
>> local:  working . . . . . . . . . .   E' - F' - G'
>>
>
>     Yes, pretty sure that's what I want to achieve, as I'm working on
> a branch, "issue_332",
>     which I'll want to push in an early state for folks to see (but
> not use), then make subsequent
>     tweaks and keep pushing new changes that can then be tested by
> others in that branch.

You can do this w/o rebasing for some time, knowing that your branch is
not up-to-date with current (remote) master if the latest changes don't
affect your branch, but if you rebase from time to time (which is IMHO
okay) then others need to follow your changes (rebase). This makes it
harder for others but if it's useful to rebase, feel free to do it, at
least before the final merge.

>     So I take it then I can use this slightly simpler form you
> mentioned at the end:
>
>         git checkout master         -- switch from your branch
> (working) to master
>         git pull                    -- get the latest from the remote.
> If your local master is clean, this shouldn't fail
>         git rebase master working   -- rebase your branch 'working' on
> 'master' and checkout 'working'
>
>     ..and use that to keep sync'ed during branch development.
>

Yes, you can do this. But as soon as you push your commits to the remote
repo (your fork) after a rebase you will need to use --force for pushing
(which is why I wrote it will make it harder for others to follow).

>     Then when everything works, close out the issue by merging the
> branch to master
>     and deleting the no-longer needed branch, which I think ends up
> being something like:
>
>         git checkout master     -- checkout master
>         git pull                -- get latest
>         git merge issue_332     -- merge in my branch to master
> (assuming I've squashed my branch down to some minimal history)
>         git push origin master  -- push the result

I hope you can still follow me ... "assuming I've squashed my branch
down to some minimal history" doesn't include "and rebased on top of
master" which may have been changed by `git pull'.

At this point it may be more convenient to use a PR and GitHub's "merge
button" which lets you rebase and squash with one click. But if you want
to do it manually you can combine both "recipes" like this:

    git checkout master             -- checkout master
    git pull                        -- get latest
    git rebase -i master issue_332  -- rebase and squash development branch
    git checkout master             -- prepare for final merge
    git merge --ff-only issue_332   -- merge in my branch to master
(assuming ... (see above))
    git push origin master          -- push the result

Note that I added '--ff-only' (fast forward only) to the merge command
to make sure that you don't get a real "merge commit" and that your
commits are all in a clean order on top of master. You may want to do a
"real" merge (w/o '--ff-only') if you leave more than one commit in your
branch or if your branch does not branch off the tip of master (remember
the "knuckle"?).

> ..and after that, delete the branch from both local and remote:
>
>         git branch -d issue_332             -- delete unused branch
> from local
>         git push origin --delete issue_332  -- delete unused branch
> from origin
>
>     I think others may still see the issue_332 branch in their copies
> after a pull,
>     even though I deleted it, unless they do a "git fetch -prune".

That's correct. I didn't know "git fetch --prune" (note: either double
dash or "-p"). What I'm using in such a case is "git remote prune
origin" or any other remote than 'origin'. This does obviously the same.

Before you do that it's interesting to execute "git remote show
<remote-name>" to get status info about remote and related local branches.

>> The recipe above does exactly that (replace "<local-branch>") with
>> "working". Again, commits E' - F' - G' differ from your original E -
>> F - G in that they have different hashes.
>
>     Right, that makes sense.
>
>     Where that might get interesting is if devs make "github code
> comments" on my branch commits,
>     i.e. they go into my branch's commit and use "+" on the code diffs
> to add a code comment).
>     If I later do a rebase and push to show my latest branch changes,
> I wonder if github is smart enough
>     to carry those code comments along with the rebased hashes.. hrm.

I don't know the answer, but would that be smart? I would assume that
you replied to those comments (and "closed" each issue/comment) and
fixed any issues related to the comments before you rebased your branch.
How would GitHub "know" whether the code comments still apply to the
rebased and modified branch?

Reply all
Reply to author
Forward
0 new messages