I have clone an android project from git and I have created a local branch called devBranch
from master
.
I have done many changes in devBranch
and I have pushed it remotely as well.
Now once I've finished with all the changes in devBranch
I have merged those changes to the master local branch.
Now I want to push those new changes in local master to remote master.
What is the appropriate approach? shall I use push or merge and why?
Comparing git push
to git merge
is not very sensible:
The git push
command is about sending some commit(s) to some other Git that is in charge of some other repository, so that the other repository gets the new commit(s), then asking that other Git to adjust some branch and/or other names in that other repository.
The git merge
command is complicated, but when used in one of its typical ways, is about making a new commit in the current branch of your own repository. This new commit is typically a merge commit , with two parents, instead of the more common ordinary commit with one parent.
Now, there are occasions where git merge
doesn't make a new commit, and instead performs a fast-forward operation . A fast-forward operation is a change in a branch name such that the new commit hash ID stored in that name identifies a descendant of the commit whose hash ID was previously stored in that name. (That's a pretty jargon-heavy statement that requires a bit of graph theory to understand. See below for a simple example.)
The git push
command can also be used to send no new commits, yet still request that the other Git repository make a change to one of its branch names. This change can be a fast-forward operation, whether or not your Git sends over any new commits. In fact, if the branch-name change is a non-fast-forward operation, the git push
command needs the --force
or --force-with-lease
option.
Since both git merge
and git push
can engage in this kind of fast-forward action, there is at least one case where the two are somewhat comparable. The key difference for this particular case, though, is that git merge
performs the fast-forward in your repository, and git push
performs the fast-forward in some other Git repository.
The bottom line, as it were, is simple enough:
git push
command cannot do that. git push
.Remember that repositories share commits (by hash IDs), but have their own private branch names . Your names are not anyone else's names, and need not be used the same way—but with humans being humans, we tend to use the same names the same way, because it's too confusing if I call you Fred and your co-workers call you Piotr when your name is actually Rahul.
To understand Git's notion of fast-forwards, let's start with the fact that branch names hold commit hash IDs, and commits also hold commit hash IDs. Whenever something holds a commit hash ID, we say that that something—whatever it is— points to that commit. So a commit points to another commit, and a branch name points to a commit.
The actual name of any given commit is some big ugly hash ID, like faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
for instance. These are too annoying to type in, and too tricky for humans to remember, so let's draw our own Git commit graph fragments using uppercase letters to stand in for each commit. Here, we have three commits in a row, with the last (latest) one being commit H
:
... <-F <-G <-H
Since H
is the latest commit, we'll have a branch name point to it:
... <-F <-G <-H <--master
Meanwhile, commit H
itself actually stores the raw (and real) hash ID of earlier commit G
. So H
points to G
. Commit G
, in turn, stores inside it the hash ID of yet-earlier commit F
: G
points to F
. This is what we have drawn here.
No part of any commit, once it is made, can ever be changed. This means we don't really have to draw the internal, backwards-pointing, arrows between commits as arrows: we can just draw them as connecting lines. This is useful when we start adding more commits beyond H
, using another name to find them:
...--F--G--H <-- master
\
I--J <-- dev
Here, the branch name dev
points to commit J
, which points backwards to commit I
, which points backwards to commit H
, and so on. Meanwhile the name master
still points to existing commit H
.
We can now ask Git to "slide the name master
forward". If we move forward just one commit, master
ends up pointing to I
, like this:
...--F--G--H--I <-- master
\
J <-- dev
Note how the commits have not changed: we've just drawn commit I
one row higher because there's no other good way to draw them on StackOverflow. The names changed, or more precisely, the values stored in the name master
changed, so that master
now points to I
.
If we slide master
all the way forward, we get:
...--F--G--H
\
I--J <-- dev, master
and there's now no reason to keep drawing in the kink at all:
...--H--I--J <-- dev, master
suffices.
This operation—moving master "forward" one or more commits—is what Git calls a fast forward , because even though master
now points to I
or J
, we can, by starting at whatever commit we find now through that name, work our way backwards to where master
was before. It was at commit H
, and J
points to I
which points to H
. So commit H
remains on the branch named master
.
But what if we start with this:
...--F--G <-- master
then add a new name dev
also pointing to existing commit G
:
...--F--G <-- dev, master
and then make one new commit on master
, so that it points to this new commit H
, but then check out branch dev
and make one new commit on dev
, so that dev
points to new commit I
? We will now have:
H <-- master
/
...--F--G
\
I <-- dev
From master
(which locates commit H
), we can work our way back to commit G
, then commit F
, and so on. From dev
—commit I
—we can work back to G
and F
and so on as well. But these arrows that connect commits are exclusively backwards arrows. We cannot go "forwards" from G
to H
. Git's connections only point backwards . We need the name master
so as to find commit H
, before we go back.
If we force Git to move the name master
to point to commit I
, we end up with:
H ???
/
...--F--G
\
I <-- dev, master
The commit still exists, but we have no way to find its hash ID. Commit H
is lost: it's still there (for a while) but unless we force Git to recover it reasonably quickly, Git will eventually remove it entirely as unnecessary. 1 This kind of forced name motion, where commit H
is lost, is a non-fast-forward .
If we'd like to join commits H
and I
and keep the work done in both, we'll need to use git merge
(or something similar).
1 In a normal repository, Git leaves traces that will let us recover the commit for at least another 30 days. In a bare repository on a server, the recovery time is much shorter.
The appropriate approach is to do a git push
Why? Because you have a remote and you want to save your current working state to that remote repository. A remote simply helps you save your different commits and current working state. This serves two good purposes: 1. You are able to collaborate with other team members using the same remote and 2. You can access your repository anywhere even without your local machine.
git merge
creates a unified branch of the two branches merged. If you do a git merge the files you have on your remote will be merged with your current working files on your local machine. a git merge
gets more complicated and mainly works on files on your local machine
Udacity has a free good course on the basics of git and git hub
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.