Reputation: 683
I am confused between git pull
, git fetch
+ git merge
and git rebase
.
They all seem to do same function then what is the difference between them specially in terms of commit logs.
If there are changes in both remote and local branch then whose commit will appear first in all three cases.
Upvotes: 4
Views: 6270
Reputation: 11719
As you imply in your question, the most confusing part of this is understanding the impact on your local repo compared to the remote repo, and partly also the impact on everyone else working with the remote repo.
First off, as the other answers indicate, git pull
is literally the same as git fetch
+ git merge
. Both of these commands are from the perspective of your local repo pulling / fetching + merging from the remote to the local repo. This occurs from the same branch you have checked out locally on the remote to that branch locally. I'll discuss those first, then squashing and rebasing.
Let's assume you have master
checked out locally, and you will then be fetching master
from the remote (unless you use some more advanced syntax or flaggs on these commands). Let's call the remote branch as origin/master
.
Fetching from origin/master
means you want to get new commits from origin/master
and update your local tracking reference for origin/master
to match where master
actually is on the remote. If master
has diverged between local and remote, then there will be commits branching out from your master branch until they reach the current location of the origin/master
reference. Your recent commits that haven't been pushed will be on a local master
branch that may be different.
Then when the merge happens, you are basically asking to merge origin/master
into your local master
branch. If you do a normal merge command, that will cause a new commit to your local master
branch that pulls in all of the recent changes from the origin/master
into your local master
branch. If there are conflicts you will resolve them first before committing. However, if you haven't committed anything locally, then the merge can just fast-forward to the new origin/master
location without needing to do anything else (your master
will just jump forward to match origin/master
).
At this point, if you push before anybody else pushes anything more to the remote, then your new merge commit will be pushed with both your separate commits (they will look like a separate, unnamed branch), and the original remote commits, plus a new merge commit at the end.
You did ask about this, but if you merge with --squash then it will add the merge commit, but remove the other local commits, so that there is no extra unnamed branch in the history. Some people prefer this as it's "more clean", while others prefer to see all the history (i.e. that the code diverged and what exactly was brought together in the merge commit).
When you rebase, you are basically taking all of your local commits, and replaying them onto the remote master branch, so they don't show up as a separate branch. This keeps the local history intact, without showing that the code diverged, which, again, some people prefer and consider it to be more "clean". This is independent of whether any of that history is important, etc.
If someone else ninja committed (well, just committed...) since you fetched, then your push will fail. You can use --force
, but then you would completely overwrite their commit, so that is generally frowned upon, as it creates all sorts of problems for other people. In this case, if everyone agreed that his commit should go first, then you would need to go through the process again (if there are no conflicts, then this is quick and easy), but in general, the team needs to have a policy on this type of thing, and often pull requests and reviews are used to manage pushes in a more orderly fashion, once the team gets big enough.
It might be easy to understand what's happening by thinking about your local master branch as a separate branch from the remote - that's basically what's going on from Git's perspective.
In fact, in my mind you are always better working in your own separate branch until you are ready to merge something to a remote branch. Git makes it so easy, quick, and painless to have a separate branch, that's what I do.
Upvotes: 3
Reputation: 2400
From git documentation
git pull
incorporates changes from a remote repository into the current branch. In its default mode,git pull
is shorthand forgit fetch
followed bygit merge FETCH_HEAD
rebase
reapplies commits on top of another base tip.
So you could do git rebase FETCH_HEAD
after you fetch
ed
So if you have
(*) <-- HEAD
|
(*) <-- commit B
\ (*) <-- origin/master
\ /
(*) <-- commit A
If you use rebase
, git will rewind your HEAD to commit A and apply all commits ordered by date
If you use merge
, git will merge both branches into a single one, applying your commits at the top of origin/head
Upvotes: 0
Reputation: 26005
Use some google. git pull
=git fetch
followed by git merge
. First hit when googling git pull
: https://git-scm.com/docs/git-pull:
In its default mode, git pull is shorthand for git fetch followed by git merge FETCH_HEAD.
git rebase
is something different entirely, and has nothing to do with remotes. Again, google could solve your problem, but a short graphical explanation, when standing on branch A, and rebasing on top of B (which is different then standing on A, and merging B into it):
c1-c2-c3<-A
\-c4-c5<-B
Becomes
c1-c4-c5-c2-c3<-A
^
B
What we did here is take the divergent commits on A (which we are on) and applied them on top of B, removing essentially the branch structure. There will never be a "rebase commit" like a "merge commit". This has nothing to do with remotes, except that git pull --rebase
will fetch and then rebase your local changes on top of the remote ones, instead of merging the remote ones into your local commit. Again, google.com or git-scm.com/docs.
Upvotes: 1