Steve Hill
Steve Hill

Reputation: 35

What exactly does "git fetch" do. Does a subsequent fetch overwrite the previous fetch?

While on my master branch I did a "git fetch" for another branch.

How do I undo that?

My question is strictly about git fetch, and what operation is needed to undo it and then if possible verify that the local repo branch matches the remote repo branch. The answer I'm looking for will shed some light on what exactly git fetch is downloading into the repo. My first assumption is that it's only downloading and updating data in the repo's .git directory. What I would really like to know is, is "git fetch" completely overwriting data that it downloads for a branch (and so would then match the remote branch perfectly) or does it update with remote change/delta data into the my local repo?

For additional clarification: I'll call the other branch, "devbranch". The problem was; instead of first switching git to the devbranch and then fetching devbranch, I fetched devbranch into the master branch.

If I just do "git fetch" on master does that overwrite the devbranch fetch I did on master or does it just add to the mess on my master branch? Or should I do something like (git reset --hard HEAD).

Thank you for you help.

= = = = = = = = = = = =

Editing after several comments:

[--1--] Most importantly I'm trying to understand exactly what "git fetch" does. My initial question explains what caused me to realize I don't really understanding it very well. If you can explain what "git fetch" updates in a repo, please do, thanks. And more important, does a subsequent fetch just overwrite the previous fetch?

[--2--] Assuming we all agree that "git fetch" does in fact add or update something into a local repo from the remote (not the local files but in the .git directory) -and- that not specifying the correct branch or being switched to the correct branch (e.g. like in my initial question) that it could(?) cause something to get corrupted if a "git merge" is applied. How then does someone undo a fetch.

Would a second "git fetch" on the correct branch and with the correct branch specified do the trick? e.g. * git checkout * git fetch origin

The text from the following git manual page talks about specifying a branch on the command. Also note that the fetch command has a "--dry-run" implying that something is getting updated. It seems to me that it's pretty important to know what is getting updated and how to undo a fetch made on the wrong branch. What am I missing, Thank for your help.

http://git-scm.com/docs/git-fetch

When no remote is specified, by default the origin remote will be used, unless there’s an upstream branch configured for the current branch.

--dry-run Show what would be done, without making any changes.

Upvotes: 1

Views: 1958

Answers (2)

Schwern
Schwern

Reputation: 165268

Assuming we all agree that "git fetch" does in fact add or update something into a local repo from the remote (not the local files but in the .git directory) -and- that not specifying the correct branch or being switched to the correct branch (e.g. like in my initial question) that it could(?) cause something to get corrupted if a "git merge" is applied. How then does someone undo a fetch.

This mixes up fetching and merging. There is no danger running git fetch even if you specify the wrong branch. I would advise you don't bother fetching specific branches and just git fetch everything. It's simpler, safe, and unless your repository has lots of enormous branches it's efficient.

However, merging the wrong branch is a problem. It won't "corrupt" anything in the sense that the repository isn't broken, but you'll end up with the wrong code and probably a lot of conflicts. Fortunately, a bad merge can be undone.

Fetching and merging as two separate steps and specifying the branch to be fetched and merged is unnecessary and leads to exactly the sort of mistake you've made. It's simpler to just git pull (which is fetch + merge) and let Git figure out what to fetch and merge. Git has a concept of a tracking branch which is what remote branch to merge with when git pull is run. For example, master normally tracks origin/master. When you run git pull, Git will fetch and then merge with the current branch's tracking branch. This avoids mistakenly merging with the wrong branch.

git fetch does these things.

  1. Get all the references (a branch name plus the commit it points at) in the remote repository, or the specific branch you request.
  2. Download all the objects (commits and files/blobs) necessary to fill in the complete history of each reference. It also gets any tags along the way.
  3. Update your remote tracking branches (such as origin/blah) to match.

git fetch does not change any of your local branches. This is why running git fetch is usually harmless and there's little need to undo it.

For example, let's say you had this...

LOCAL
A - B - C - D - E [origin/master] - H - I [master]
             \
              F - G [my-branch]

ORIGIN
                      3 - 4 [origin/other-branch]
                     /
A - B - C - D - E - 1 - 2 [master]

After running git fetch you'd have this.

LOCAL
                    3 - 4 [origin/other-branch]
                   /
                  1 - 2 [origin/master]
                 /
A - B - C - D - E - H - I [master]
             \
              F - G [my-branch]

ORIGIN
                      3 - 4 [other-branch]
                     /
A - B - C - D - E - 1 - 2 [master]

Your local branches remain unchanged. Git only added new commits and moved (or added) remote branches. None of your local branches are affected. master and mybranch stay where they are. There's no merging or fast-forwarding or rebasing done. That all happens as part of a git-pull. A pull is really just a fetch plus a merge.

git-fetch went something like this...

  • origin's master is at commit 2.
    • I don't have commit 2, download it.
    • Commit 2's parent is commit 1. I don't have that, download it.
    • Commit 1's parent is commit E. I have that, we're done.
    • Move origin/master to commit 2.
  • There's a new branch called other-branch at commit 4.
    • I don't have commit 4, download it.
    • Commit 4's parent is commit 3. I don't have that, download it.
    • Commit 3's parent is commit 1. I have that, we're done.
    • Create origin/other-branch at commit 4.

This is known as "the dumb protocol". Most Git installations use a much more efficient technique called "the smart protocol" which reduces the number of queries by doing most of the work of figuring out what commits need to be fetched on the server side and delivering them in bulk. Git will only use the dumb protocol when it's using a server with no special Git support, such as a plain HTTP server. The dumb protocol is still useful for understanding what's going on.

There is no single command to undo a git-fetch, but you can move origin/master back to its previous location using the technique in this answer to manually move references around.

git update-ref refs/remotes/origin/master refs/remotes/origin/master@{1}

Git maintains a history of branch locations (branches are just labels on commits) using the branch@{#} syntax. origin/master@{1} is the previous location of origin/master.

Upvotes: 3

Michael Durrant
Michael Durrant

Reputation: 96554

Git fetch only affects the "remote" branches that are held locally.

This concept leads to a great deal of confusion.
It is important to understand that there are 4 main "places" where your code is stored:

  1. Locally as regular files (Your 'workspace').
  2. Locally as branches within .git/ (Your 'index').
  3. Locally as branches in the remote area with .git/ (Your local repository).
  4. Remotely on the server (which probably is "bare" - no .git directory, with files just placed in the top-level directory where the working directory would normally be.

So when you do a fetch you are updating 3)

When you do a pull on the other hand, those branches are:

retrieved from the remote to your local repository(3) placed (or updated) in your local branches (2) processed to get the actual files in the commit created or updated locally o your file system.

You may find that https://stackoverflow.com/a/9204499/631619 is helpful

The fears you have are more appropriate for git pull where, if you are in a different branch, you can accidentally merge in code from the wrong branch. I have done that.

Upvotes: 3

Related Questions