1

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.

Steve Hill
  • 35
  • 7
  • try using git stash? – Josh Aug 07 '15 at 16:42
  • 6
    Sounds like XY-problem to me. What is the *real* problem? – Eugene Sh. Aug 07 '15 at 16:43
  • My observation is that when you do `git fetch` it fetches all changes (made in any branch). You are not just fetching stuff for the current branch. – Sunil D. Aug 07 '15 at 16:47
  • 3
    I honestly can't think of a reason that anybody would want to undo `git fetch`. This command has *no effect* on your local branches. It simply updates your remote tracking branches, and why wouldn't you want them to be updated? I agree with Eugene: What's the actual problem that you're trying to solve? – ChrisGPT was on strike Aug 07 '15 at 16:49
  • 1
    possible duplicate of [reverse a git fetch](http://stackoverflow.com/questions/15254480/reverse-a-git-fetch) – jthill Aug 07 '15 at 18:57
  • There might be dubious commits (bugs, or commits that should have been on another branch) in the fetch that lead you to suspect it's all going to be backed out. The fetch might have gotten you a lot of conflicts and resolving them is already assigned, to someone else, so you want to wait for the resolving commit before you pull. – jthill Aug 07 '15 at 19:03
  • @jthill , sometimes I don't want to fetch just yet because then origin/master moves and then it is less obvious in gitk when looking at my own branch which commits are already in origin/master and which aren't. After a fetch I'd have to rebase first which may not be want I want at that point. – Katjoek Aug 09 '15 at 09:27
  • "The problem was; instead of first switching git to the devbranch and then fetching devbranch, I fetched devbranch into the master branch." -- Do you mean you ran `git fetch origin devbranch`? That *should* be fine, regardless of which branch you were on. Did you actually see any problems, or are you asking just because you are concerned about possible problems you may be overlooking? –  Aug 10 '15 at 21:00
  • @jthill In that case you can wait until the remote is updated and fetch again. The fetch has no effect on your work until you decide it does (ie. until you start working with the remote branches). – Schwern Aug 10 '15 at 21:37
  • All these comments about what `git fetch` will do are more appropriate to what `git pull` might do. – Michael Durrant Aug 10 '15 at 22:18

2 Answers2

3

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.

Community
  • 1
  • 1
Schwern
  • 153,029
  • 25
  • 195
  • 336
  • So to be clear: If I incorrectly fetch "xyz-500commits" branch while checked-out on the "master" branch (instead of first "git checkout xyz-500commits"), when I really meant to fetch to the local xyz branch, you're saying that would be no problem? And you are also saying it would be perfectly cool to "git merge" the xyz branch into master branch instead of the intended local xyz branch? That doesn't seem okay to me. Are you sure you disagree? Seems to me I can't move forward with a merge, so I'm stuck. What do I do to go back? Is it simply another fetch done on the correct branch? Thx – Steve Hill Aug 10 '15 at 23:46
  • @Steve5202695 Yes, there is no problem with fetching the wrong branch. In fact, I would advise you just `git fetch` everything rather than specific branches, it's simpler and efficient. However, there *is* a problem with *merging* the wrong branch. Undoing a merge is a different question, it has nothing to do with fetching. It sounds like fetching is a red herring and your real problem with with a bad merge. Here's [one answer about how to undo a merge](https://stackoverflow.com/questions/2389361/undo-a-git-merge). – Schwern Aug 10 '15 at 23:51
  • @Steve5202695 P. S. I misread your "Assuming we all agree that" to be about `git fetch`, not `git merge`. I've updated my answer, but it only changes the first paragraph. – Schwern Aug 10 '15 at 23:59
  • @Steve5202695 I've gone a step further and added advise that you stop running `git fetch ` and `git merge ` separately. Manually entering the branch will lead you to make a mistake like you just did. Instead, run `git pull` and rely on tracking branches. – Schwern Aug 11 '15 at 00:10
  • Thanks, I will certainly stop fetching with a specified branch, and will probably start using **pull** more as well. I recently started working with branches more and I just thought it was better to specify the branch when working with branches. Can I please ask you another question. Does it matter what branch I'm currently checked-out on when I do a **pull** or **fetch**? It that something I should be careful of. Or maybe it only matters if you are specify the branch in the fetch or pull? Thanks. – Steve Hill Aug 12 '15 at 17:47
  • 1
    @Steve5202695 A fetch is always safe. `git pull` is "safe" in the sense that it will merge with the correct remote branch (or tell you that it doesn't know), but it's not good practice to be merging without realizing what you're merging. You should always be aware what branch you're on. Consider modifying your shell prompt to display it. – Schwern Aug 12 '15 at 19:02
  • 1
    http://unix.stackexchange.com/a/127800/10043 may be helpful for the PS1 prompt showing your git branch – Michael Durrant Aug 13 '15 at 10:35
3

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.

Community
  • 1
  • 1
Michael Durrant
  • 93,410
  • 97
  • 333
  • 497
  • "Get fetch only affects the "remote" branches that are held locally." I totally agree. FYI: Both of the branches are on the "local" repo and the "remote" repo. "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." So if I **do** go ahead and do "git merge" that would create a problem right? What is it that will correct the erroneous fetch, another fetch? Again the problem was, I was checkedout on the wrong branch (master) locally when I did the fetch of xyz branch. – Steve Hill Aug 10 '15 at 23:14
  • When you fetch a branch it only affects the local version under the remote. Your local branch itself remains unchanged until you `git pull` from within the branch or merge or rebase or `git reset origin/branch_name` to reset to the new changes. – Michael Durrant Aug 11 '15 at 00:49
  • Michael, I *really appreciate* your list of [4 main places where code is stored]. Thank you that helps. I have been thinking in terms of only [a] what is in the .git directory [b] what is NOT in the .git directory. I will start thinking in terms of your list though. Thanks. – Steve Hill Aug 12 '15 at 16:16
  • Michael, can you please let me ask you one more question: Suppose we have a local repo with branches abc and xyz for which there are **also** corresponding remote branches. Next supposed I'm **checked-out** on local branch "abc" and I then **fetch** branch "xyz" with command `git fetch origin xyz`. Would that not update storage place #3 in my local .git dir for branch "abc" with the remote's updates for branch "xyz"? And would you agree that doing a merge would not be advisable? If so, would a simple fetch, correct branch abc (in storage #3) by overwriting it with the latest abc branch data? – Steve Hill Aug 12 '15 at 16:53
  • You should pose that as a separate question. The answer is that is doesn't matter which branch you are on when you do git fetch xyz. What is updated is your locally held remote/ versions of files in the remote/xyz branch. Your working directory and your current local development branch will not be affected until your merge or rebase or reset. – Michael Durrant Aug 13 '15 at 20:43
  • Michael thanks for the reply. The point is that if someone does a fetch as I just described, they can't do a merge (right? yes/no?) Git allows you to merge one branch with another branch right? So will a simple `git fetch origin` put you back in a position to do a merge? This is actually the same as my original question, just restated. Thanks for the help. – Steve Hill Aug 14 '15 at 22:17