4

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.

Kirill
  • 7,580
  • 6
  • 44
  • 95
pjain
  • 663
  • 10
  • 21
  • "whose commit will appear first" - sounds like an experiment! – Sergio Tulentsev Sep 24 '17 at 17:25
  • That seems a job for http://learngitbranching.js.org/ – VonC Sep 24 '17 at 17:29
  • [Merging vs. Rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) – Alexan Sep 24 '17 at 17:40
  • 1
    Possible duplicate of [What is the difference between 'git pull' and 'git fetch'?](https://stackoverflow.com/questions/292357/what-is-the-difference-between-git-pull-and-git-fetch) – Andrew C Sep 24 '17 at 18:20
  • @AndrewC I disagree it's a duplicate, he's focusing more on the implications after understanding that, though the question could be narrowed to focus on the end result (how it affects the commit log and local/remote repo commit histories). – LightCC Sep 24 '17 at 22:49

3 Answers3

3

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.

Git Pull / Git Fetch + Git Merge

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.

What about Squashing?

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).

Rebasing

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.

What if someone else committed since I fetched?

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.

Another way to think about this

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.

LightCC
  • 9,804
  • 5
  • 52
  • 92
1

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.

kabanus
  • 24,623
  • 6
  • 41
  • 74
0

From git documentation

git pull incorporates changes from a remote repository into the current branch. In its default mode, git pull is shorthand for git fetch followed by git merge FETCH_HEAD

rebase reapplies commits on top of another base tip.

So you could do git rebase FETCH_HEAD after you fetched

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

Community
  • 1
  • 1
gogaz
  • 2,323
  • 2
  • 23
  • 31