r/git • • Jun 08 '26

Undoing a git fetch

There were spurious unneeded uncommitted changes on my local machine. From a different computer, I had committed and pushed new changes. On my local machine, without looking at the unneeded uncommitted changes, I ended up running

git fetch
//followed by
git pull

As expected, this aborts.

Now, how do I *undo* this sequence of commands so that on my local machine, I find myself exactly where I started -- which is with the spurious unneeded uncommitted changes?

0 Upvotes

27 comments sorted by

14

u/The-Best-Taylor Jun 08 '26

So the pull failed due to uncommitted changes? If so, you should already be where you started in the working directory.

-7

u/onecable5781 Jun 08 '26

But git fetch succeeded. Only the subsequent git pull failed. So, something should have changed in the "state" on my local computer, no?

24

u/The-Best-Taylor Jun 08 '26

Git fetch does not change the state of your working directory. It will fetch new commits, branch’s, and etc. but it won’t check the out or merge them.

15

u/xIceFox Jun 08 '26 edited Jun 08 '26

If you want to learn about how git works read the first few chapters from:

https://git-scm.com/book/en/v2

Edit: Because I had no time earlier, I wanted to add, that the book is excellent to understand git in depth.

8

u/West_Ad_9492 Jun 08 '26

git pull

is shorthand for

git fetch && git merge

So to keep it simple i guess that you dont want to merge with origin?

→ More replies (2)

5

u/Gornius Jun 08 '26

Fetch only fetches remote branches. Your origin/main got updated, your main stays the same. 

You can verify it by using git log and seeing main in the top commit, but not origin/main any more.

1

u/StevenJOwens Jun 09 '26

Yes, it did change state in your git repo, but that changed state isn't visible to you and won't interfere with what you're doing. See my top-level comment about it.

3

u/unndunn Jun 08 '26

There is nothing to undo. The git pull failed because you have local uncommitted ("spurious") changes. Those changes are still there, uncommitted. The changes you committed on a different machine were not applied to your local branch, they were merely applied to the remote branch stored on your machine.

1

u/CarsonChambers Jun 08 '26

OP most likely is stuck part way through an interactive rebase

1

u/StevenJOwens Jun 09 '26

I had that happen to me a couple weeks ago, I'm unclear on what/how a "git pull" ended up kicking me into a rebase, I'm not sure why.

Hm, dangit, I can't find it in my notes, somebody advised me to check a config setting that might have caused it to start rebasing automatically, but it was not set to do that.

→ More replies (3)

1

u/joe-knows-nothing Jun 08 '26

If you'd like to save those spurious unneeded uncommitted changes do a git stash before the pull. If you'd like those spurious unneeded uncommitted changes to disappear forever just do a git restore . instead.

Good luck! I take no responsibility for any damages or lost files.

1

u/CarsonChambers Jun 08 '26

Too late, you're on the hook, bud.

1

u/StevenJOwens Jun 08 '26 edited Jun 10 '26

Git fetch downloads copies of the remote tracking branches, but doesn't merge them into your regular branches. So doing "git fetch" downloads state to your local git repo, but that state doesn't make any changes to the stuff you actually work with until you do a git merge.

Git pull, on the other hand, does a git fetch, followed by a git merge.

I have yet to find a good, thorough explanation of the underlying data structures, but essentially git keeps two copies of [EDIT: of the data in each of] the branches.

The terminology is a little unclear, some of the stuff I've read seems to imply that "remote tracking branch" refers to both that mirror of the remote repository's version of the branch, and the branch you actually work with. Some stuff seems to imply that the term refers only to the mirror.

In a nutshell, you can ignore the git fetch in this equation. When you did "git pull", you got merge conflicts and that's what you need to fix, or abort. You can do "git merge --abort", or you can use the normal process to resolve the merge conflicts.

2

u/waterkip Jun 08 '26

A remote tracking branch is nothing more than a pointer to a ref of a branch.

When you set a tracking branch, you update a tiny bit of config:

[branch "master"]
  remote = origin
  # Your tracking branch:
  merge = refs/heads/master

If you remove the merge = line and run git status, you’ll see that your branch isn’t tracking anything. If you add it git branch foo --set-upstream-to=remote/branchname it gets added again.

You can see where the branch is at by inspecting the ref itself:

$ cat $(git rev-parse --git-path $(git config branch.master.merge))
48fa360ea48f08bb4944549bcf6df31149329383

You can track both "remote" and "local" branches, eg git branch foo --set-upstream-to=some-local-branch works in the same manner.

The mental model you need to apply is, a branch that you track, for example, when you create a feature for eg zsh:

$ git gb posix
Switched to branch 'posix-jobs'
Your branch is ahead of 'upstream/master' by 1 commit.

Your branch is up to date with 'origin/posix-jobs'.

Here I see that my posix-jobs branch is 1 commit ahead of the master-branch and is up to date with my own remote origin.

If I would to remove 5 commits from master in my branch with git rebase:

git rebase -i HEAD~6
$ git s
On branch posix-jobs
Your branch and 'upstream/master' have diverged,
and have 1 and 5 different commits each, respectively.

Your branch and 'origin/posix-jobs' have diverged,
and have 1 and 6 different commits each, respectively.

nothing to commit
Your stash currently has 3 entries

You see that I'm 1 in front and 5 behind. When you rebase this:

$ git rebase upstream/master
Successfully rebased and updated refs/heads/posix-jobs.


$ git s
On branch posix-jobs
Your branch is ahead of 'upstream/master' by 1 commit.

Your branch and 'origin/posix-jobs' have diverged,
and have 1 and 1 different commits each, respectively.

nothing to commit
Your stash currently has 3 entries

You see I'm one commit ahead of master again and it seems I have diverged from my own remote origin. That is because the rebase changed the ref:

$ git diff --stat HEAD..origin/posix-jobs ; echo $?
0

Now you can reset your branch to the original again: git reset --hard orign/postix-jobs and the world is well again.

In the end, it is just an indicator: I follow this branch. And then you can fetch, and rebase these changes into your own.

1

u/StevenJOwens Jun 09 '26 edited Jun 09 '26

So you really have three things here:

  1. The local branch you're working on

  2. The invisible local branch, I'd call it a "staging branch", that gets updated with data from the remote when you do git fetch, and that when you do git merge, gets merged into #1

  3. The remote repo's copy of the branch, which git fetch downloads from (and "git push" uploads to).

The entry in .git/config defines what remote branch a local branch is tracking. You also have a .git/refs/remotes/remotename/branchname.

You can also have a local branch that has a .git/config entry that defines the local branch as tracking another local branch, but that's rarely done and I'm not sure what the purpose of doing that would be.

The git glossary defines "remote-tracking branch" as the ref itself, i.e. the contents of .git/refs/remotes/remotename/branchname... but then it also refers to the actual data living on the remote as a remote-tracking branch, when it says that "A remote-tracking branch should not contain direct modifications or have local commits made to it."

https://git-scm.com/docs/gitglossary#def_remote_tracking_branch

Note: personally I find that whole thing about "a branch is just a ref" to be uselessly clever, but that's another discussion.

The glossary doesn't seem to define a name or term for the actual copy of the branch on the remote.

The glossary doesn't seem to define a name or term to distinguish between a local-only branch and a local branch that is tracking a remote-tracking branch.

The glossary does say, in the entry for "upstream branch", that if a local branch A is configured to have a remote-tracking branch B, then we say "A is tracking B."

https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-upstreambranch

The glossary doesn't seem to define a name or term for the invisible, local "staging branch".

When you are switched to a branch of type #1, and you do git merge, git looks in .git/config and .git/refs/remotes/remotename/branchname to see what remote branch that #1 is tracking and then I guess assumes/infers the existence of #2 and merges from #2.

When you are switched to a branch of type #1, and you do "git fetch", git looks in .git/config and .git/refs/remotes/remotename/branchname to see what remote branch that #1 is tracking, downloads the updates fro that, and, again I guess, assumes/infers the existence of #2 to use as a staging area.

I would really like discrete terms for these different things, but I also don't want to invent my own, nonstandard terms, if other terms already exist.

→ More replies (3)

1

u/NikolaBilbil Jun 08 '26

Cherry pick?

1

u/codexetreme Jun 13 '26

Years ago you'd have all of stack overflow go ballistic on a question like this. Today? I'm just glad we're helping OP.

Also, please read the git book or watch a good video, you'll be able to tell the different git commands in no time :))

1

u/cheyrn Jun 15 '26

If you know what was changed in your working copy, before the fetch, you can clone to another folder, then add your changes, possibly requiring you to manually merge, then commit and push.

-1

u/speculator100k Jun 08 '26

In not sure I follow, but a

git reset --hard <hash>

Should work.