anon_swe
anon_swe

Reputation: 9355

Git: Merge Remote Branch into Remote Master?

I'm trying to figure out the standard way of using Git to merge a remote branch (origin/develop) into my remote master branch (origin/master). I've taken a look at this:

Git - How to merge a remote branch into remote master

which suggests that I do the following:

1) Make changes on my local develop branch

2) Commit changes on develop

3) Merge local develop into local master

4) Push local master to origin/master

Here's my question: Do I never need to merge one remote branch into another? Is the standard approach just to keep updating a remote branch like origin/develop to save progress, ultimately merging those changes into local master and pushing to origin/master?

I think this will mess up the log of commits for my remote, as I'll eventually delete the remote branches I used to keep track of my local develop progress...

Thanks!

Upvotes: 0

Views: 4453

Answers (1)

torek
torek

Reputation: 489848

Do I never need to merge one remote branch into another?

In fact, you can't do that. Well, you can, sort of, but—well, it's confusing. Let's back up. :-)

Git has some rather poor terminology here. The word branch is ambiguous. Once you get used to all of its different meanings, it's not such a bad name: one says "work on branch X" or "checkout out branch Y" and we all know what we meant, but getting to that point is hard. For more about this, see What exactly do we mean by "branch"? But start with this: Git is mostly about commits. Branch names come in later.

Commits and branch names

The most basic way that Git (and you) can find a commit is by its hash ID, which is guaranteed to be unique to that particular commit. But these hash IDs appear to be random: 26e47e261 comes before 8b026edac but 1f1cddd55 comes after either of those, for instance (these are actual commits in the Git repository for Git). Names, like branch names and remote-tracking names, are there to let Git—and you—find the commits. Each such name remembers exactly one hash ID.

Almost every commit also remembers one or two hash IDs. These are the parent commits of that commit. Git can string these various hash IDs, starting with the one stored in a name and working backwards, into chains of commits:

A  <-B  <-C   <--master

The name master remembers the hash ID of commit C, which remembers the hash ID of commit B, which remembers the hash ID of commit A. A is the very first commit (in this tiny repository with only three commits) so it has no parent and thus ends the chain.

The process of adding a new commit consists of writing out the new commit, using the current end-of-branch-chain hash ID as its parent, and then making the name point to the new commit:

A--B--C--D   <-- master

(It's easier not to draw the internal arrows, which always point backwards by definition and—unlike branch names—can never be changed once made, so I generally don't draw them.)

Remote-tracking names

When you work with a Git repository, you generally start by getting all the commits from some other, existing, Git repository. The other Git is using its branch names to find these commits. Your Git collects those commits, but your Git is going to give you your branch names, independent of theirs. So your Git needs some other names—names that are not branch names—in order to find their commits. You clone their repository, and your Git renames their master to your origin/master—a remote-tracking name or remote-tracking branch name, which some people call a remote branch name.1

After the initial clone, which creates origin/*, a git fetch origin will call up the same URL—saved from when you did the clone—to talk to the same Git, collect from it any new commits it may have, and update all your remote-tracking names to match their branch names. So your remote-tracking names automatically follow their branch names. That's their main purpose: to remember which commit their branch names are remembering.


1"Remote branch name" is probably the worst of all these phrases, not that any of them are great, because Git uses the word remote to refer to a name like origin that you can use to identify the other Git repository. So if you were to go to the Git at the URL listed under your remote.origin.url, and ask it about its branches, you'd get their master, their develop, and so on. These are the branch names on the remote: the remote's branch names. Each one must necessarily be a remote branch name. But they're not in your Git, which has instead names like origin/master and origin/develop. I think calling origin/master a remote-tracking name is the best of these ambiguous phrases: it's your name for their (origin's) master.


Creating a branch name from another name

The last step of git clone is generally git checkout master.2 Your Git doesn't have a master yet, so your Git prowls through all the remote-tracking names it has (it just made them)—origin/develop and origin/master and so on—and finds their origin/master. This points to some specific commit, so your Git now creates your master, pointing to the same commit:

A--B--C--D   <-- master (HEAD), origin/master
          \
           E   <-- origin/develop

If you now run git checkout develop, that creates your own develop, pointing to the same commit as origin/develop:

A--B--C--D   <-- master, origin/master
          \
           E   <-- develop (HEAD), origin/develop

Note that HEAD is attached to one of your branch names—that's how Git knows which branch you're on, when you make a new commit.

Let's say you add your own commit to your own master, by doing git checkout master and doing some work. This creates a new, unique-hash-ID commit, and makes your master point to this new commit:

           F   <-- master (HEAD)
          /
A--B--C--D   <-- origin/master
          \
           E   <-- develop, origin/develop

This particular example does not use git merge, which has its own set of complications (I don't want to get into the details here), but the point is simple enough: you always do all your work on your own branches. When you have finished this work, you can then run git push to:

  • send commit(s) to the other Git, as necessary; and then
  • ask their Git to set their branch name based on what you just sent.

Hence you can now git push origin master to send your new commit F to them, and ask them to make their master point to commit F. If they agree to this, your Git records this update so that you now have:

           F   <-- master (HEAD), origin/master
          /
A--B--C--D
          \
           E   <-- develop, origin/develop

2You can tell your Git to use another name, and if you don't, the other Git tells your Git which name to use, but usually that's master.

Upvotes: 3

Related Questions