Reputation: 9355
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
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.
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.)
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
.
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:
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